tsunami_cchip.cc revision 1074
112771Sqtt2@cornell.edu/*
212771Sqtt2@cornell.edu * Copyright (c) 2004 The Regents of The University of Michigan
312771Sqtt2@cornell.edu * All rights reserved.
412771Sqtt2@cornell.edu *
512771Sqtt2@cornell.edu * Redistribution and use in source and binary forms, with or without
612771Sqtt2@cornell.edu * modification, are permitted provided that the following conditions are
712771Sqtt2@cornell.edu * met: redistributions of source code must retain the above copyright
812771Sqtt2@cornell.edu * notice, this list of conditions and the following disclaimer;
912771Sqtt2@cornell.edu * redistributions in binary form must reproduce the above copyright
1012771Sqtt2@cornell.edu * notice, this list of conditions and the following disclaimer in the
1112771Sqtt2@cornell.edu * documentation and/or other materials provided with the distribution;
1212771Sqtt2@cornell.edu * neither the name of the copyright holders nor the names of its
1312771Sqtt2@cornell.edu * contributors may be used to endorse or promote products derived from
1412771Sqtt2@cornell.edu * this software without specific prior written permission.
1512771Sqtt2@cornell.edu *
1612771Sqtt2@cornell.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1712771Sqtt2@cornell.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1812771Sqtt2@cornell.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1912771Sqtt2@cornell.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2012771Sqtt2@cornell.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2112771Sqtt2@cornell.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2212771Sqtt2@cornell.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2312771Sqtt2@cornell.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2412771Sqtt2@cornell.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2512771Sqtt2@cornell.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2612771Sqtt2@cornell.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2712771Sqtt2@cornell.edu */
2812771Sqtt2@cornell.edu
2912771Sqtt2@cornell.edu/* @file
3012771Sqtt2@cornell.edu * Emulation of the Tsunami CChip CSRs
3112771Sqtt2@cornell.edu */
3212771Sqtt2@cornell.edu
3312771Sqtt2@cornell.edu#include <deque>
3412771Sqtt2@cornell.edu#include <string>
3512771Sqtt2@cornell.edu#include <vector>
3612771Sqtt2@cornell.edu
3712771Sqtt2@cornell.edu#include "base/trace.hh"
3812771Sqtt2@cornell.edu#include "dev/tsunami_cchip.hh"
3912771Sqtt2@cornell.edu#include "dev/tsunamireg.h"
4012771Sqtt2@cornell.edu#include "dev/tsunami.hh"
4112771Sqtt2@cornell.edu#include "mem/bus/bus.hh"
4212771Sqtt2@cornell.edu#include "mem/bus/pio_interface.hh"
4312771Sqtt2@cornell.edu#include "mem/bus/pio_interface_impl.hh"
4412771Sqtt2@cornell.edu#include "mem/functional_mem/memory_control.hh"
4512771Sqtt2@cornell.edu#include "cpu/intr_control.hh"
4612771Sqtt2@cornell.edu#include "sim/builder.hh"
4712771Sqtt2@cornell.edu#include "sim/system.hh"
4812771Sqtt2@cornell.edu
49using namespace std;
50
51TsunamiCChip::TsunamiCChip(const string &name, Tsunami *t, Addr a,
52                           MemoryController *mmu, HierParams *hier, Bus* bus,
53                           Tick pio_latency)
54    : PioDevice(name), addr(a), tsunami(t)
55{
56    mmu->add_child(this, Range<Addr>(addr, addr + size));
57
58    for(int i=0; i < Tsunami::Max_CPUs; i++) {
59        dim[i] = 0;
60        dir[i] = 0;
61        dirInterrupting[i] = false;
62        ipiInterrupting[i] = false;
63        RTCInterrupting[i] = false;
64    }
65
66    if (bus) {
67        pioInterface = newPioInterface(name, hier, bus, this,
68                                      &TsunamiCChip::cacheAccess);
69        pioInterface->addAddrRange(addr, addr + size - 1);
70        pioLatency = pio_latency * bus->clockRatio;
71    }
72
73    drir = 0;
74    misc = 0;
75
76    //Put back pointer in tsunami
77    tsunami->cchip = this;
78}
79
80Fault
81TsunamiCChip::read(MemReqPtr &req, uint8_t *data)
82{
83    DPRINTF(Tsunami, "read  va=%#x size=%d\n",
84            req->vaddr, req->size);
85
86    Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)) >> 6;
87    ExecContext *xc = req->xc;
88
89    switch (req->size) {
90
91      case sizeof(uint64_t):
92          switch(daddr) {
93              case TSDEV_CC_CSR:
94                  *(uint64_t*)data = 0x0;
95                  return No_Fault;
96              case TSDEV_CC_MTR:
97                  panic("TSDEV_CC_MTR not implemeted\n");
98                   return No_Fault;
99              case TSDEV_CC_MISC:
100                *(uint64_t*)data = misc | (xc->cpu_id & 0x3);
101                  return No_Fault;
102              case TSDEV_CC_AAR0:
103              case TSDEV_CC_AAR1:
104              case TSDEV_CC_AAR2:
105              case TSDEV_CC_AAR3:
106                  *(uint64_t*)data = 0;
107                  return No_Fault;
108              case TSDEV_CC_DIM0:
109                  *(uint64_t*)data = dim[0];
110                  return No_Fault;
111              case TSDEV_CC_DIM1:
112                  *(uint64_t*)data = dim[1];
113                  return No_Fault;
114              case TSDEV_CC_DIM2:
115                  *(uint64_t*)data = dim[2];
116                  return No_Fault;
117              case TSDEV_CC_DIM3:
118                  *(uint64_t*)data = dim[3];
119                  return No_Fault;
120              case TSDEV_CC_DIR0:
121                  *(uint64_t*)data = dir[0];
122                  return No_Fault;
123              case TSDEV_CC_DIR1:
124                  *(uint64_t*)data = dir[1];
125                  return No_Fault;
126              case TSDEV_CC_DIR2:
127                  *(uint64_t*)data = dir[2];
128                  return No_Fault;
129              case TSDEV_CC_DIR3:
130                  *(uint64_t*)data = dir[3];
131                  return No_Fault;
132              case TSDEV_CC_DRIR:
133                  *(uint64_t*)data = drir;
134                  return No_Fault;
135              case TSDEV_CC_PRBEN:
136                  panic("TSDEV_CC_PRBEN not implemented\n");
137                  return No_Fault;
138              case TSDEV_CC_IIC0:
139              case TSDEV_CC_IIC1:
140              case TSDEV_CC_IIC2:
141              case TSDEV_CC_IIC3:
142                  panic("TSDEV_CC_IICx not implemented\n");
143                  return No_Fault;
144              case TSDEV_CC_MPR0:
145              case TSDEV_CC_MPR1:
146              case TSDEV_CC_MPR2:
147              case TSDEV_CC_MPR3:
148                  panic("TSDEV_CC_MPRx not implemented\n");
149                  return No_Fault;
150              default:
151                  panic("default in cchip read reached, accessing 0x%x\n");
152           } // uint64_t
153
154      break;
155      case sizeof(uint32_t):
156      case sizeof(uint16_t):
157      case sizeof(uint8_t):
158      default:
159        panic("invalid access size(?) for tsunami register!\n");
160    }
161    DPRINTFN("Tsunami CChip ERROR: read  daddr=%#x size=%d\n", daddr, req->size);
162
163    return No_Fault;
164}
165
166Fault
167TsunamiCChip::write(MemReqPtr &req, const uint8_t *data)
168{
169    DPRINTF(Tsunami, "write - va=%#x value=%#x size=%d \n",
170            req->vaddr, *(uint64_t*)data, req->size);
171
172    Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)) >> 6;
173
174    bool supportedWrite = false;
175    uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size();
176
177    switch (req->size) {
178
179      case sizeof(uint64_t):
180          switch(daddr) {
181            case TSDEV_CC_CSR:
182                  panic("TSDEV_CC_CSR write\n");
183                  return No_Fault;
184              case TSDEV_CC_MTR:
185                  panic("TSDEV_CC_MTR write not implemented\n");
186                   return No_Fault;
187              case TSDEV_CC_MISC:
188                uint64_t ipreq;
189                ipreq = (*(uint64_t*)data >> 12) & 0xF;
190                //If it is bit 12-15, this is an IPI post
191                if (ipreq) {
192                    for (int cpunum=0; cpunum < Tsunami::Max_CPUs; cpunum++) {
193                        // Check each cpu bit
194                        if (ipreq & (1 << cpunum)) {
195                            // Check if there is already an ipi (bits 8:11)
196                            if (!(misc & (0x100 << cpunum))) {
197                                misc |= (0x100 << cpunum);
198                                tsunami->intrctrl->post(cpunum,
199                                        TheISA::INTLEVEL_IRQ3, 0);
200                                DPRINTF(IPI, "send IPI cpu=%d from=%d\n",
201                                        cpunum, req->cpu_num);
202                            }
203                        }
204                    }
205                    supportedWrite = true;
206                }
207
208                //If it is bit 8-11, this is an IPI clear
209                uint64_t ipintr;
210                ipintr = (*(uint64_t*)data >> 8) & 0xF;
211                if (ipintr) {
212                    for (int cpunum=0; cpunum < Tsunami::Max_CPUs; cpunum++) {
213                        // Check each cpu bit
214                        if (ipintr & (1 << cpunum)) {
215                            // Check if there is a pending ipi (bits 8:11)
216                            if (misc & (0x100 << cpunum)) {
217                                misc &= ~(0x100 << cpunum);
218                                tsunami->intrctrl->clear(cpunum,
219                                        TheISA::INTLEVEL_IRQ3, 0);
220                                DPRINTF(IPI, "clear IPI IPI cpu=%d from=%d\n",
221                                        cpunum, req->cpu_num);
222                            }
223                        }
224                    }
225                    supportedWrite = true;
226                }
227
228
229
230                //If it is the 4-7th bit, clear the RTC interrupt
231                uint64_t itintr;
232                if ((itintr = (*(uint64_t*) data) & (0xf<<4))) {
233                    //Clear the bits in ITINTR
234                    misc &= ~(itintr);
235                    for (int i=0; i < size; i++) {
236                        if ((itintr & (1 << (i+4))) && RTCInterrupting[i]) {
237                            tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ2, 0);
238                            RTCInterrupting[i] = false;
239                            DPRINTF(Tsunami, "clearing rtc interrupt to cpu=%d\n", i);
240                        }
241                    }
242                    supportedWrite = true;
243                }
244
245                // ignore NXMs
246                if (*(uint64_t*)data & 0x10000000)
247                    supportedWrite = true;
248
249                if(!supportedWrite)
250                    panic("TSDEV_CC_MISC write not implemented\n");
251
252                return No_Fault;
253              case TSDEV_CC_AAR0:
254              case TSDEV_CC_AAR1:
255              case TSDEV_CC_AAR2:
256              case TSDEV_CC_AAR3:
257                  panic("TSDEV_CC_AARx write not implemeted\n");
258                  return No_Fault;
259              case TSDEV_CC_DIM0:
260              case TSDEV_CC_DIM1:
261              case TSDEV_CC_DIM2:
262              case TSDEV_CC_DIM3:
263                  int number;
264                  if(daddr == TSDEV_CC_DIM0)
265                      number = 0;
266                  else if(daddr == TSDEV_CC_DIM1)
267                      number = 1;
268                  else if(daddr == TSDEV_CC_DIM2)
269                      number = 2;
270                  else
271                      number = 3;
272
273                  uint64_t bitvector;
274                  uint64_t olddim;
275                  uint64_t olddir;
276
277                  olddim = dim[number];
278                  olddir = dir[number];
279                  dim[number] = *(uint64_t*)data;
280                  dir[number] = dim[number] & drir;
281                  for(int x = 0; x < 64; x++)
282                  {
283                      bitvector = (uint64_t)1 << x;
284                      // Figure out which bits have changed
285                      if ((dim[number] & bitvector) != (olddim & bitvector))
286                      {
287                          // The bit is now set and it wasn't before (set)
288                          if((dim[number] & bitvector) && (dir[number] & bitvector))
289                          {
290                              tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x);
291                              DPRINTF(Tsunami, "posting dir interrupt to cpu 0\n");
292                          }
293                          else if ((olddir & bitvector) &&
294                                  !(dir[number] & bitvector))
295                          {
296                              // The bit was set and now its now clear and
297                              // we were interrupting on that bit before
298                              tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x);
299                              DPRINTF(Tsunami, "dim write resulting in clear"
300                                      "dir interrupt to cpu 0\n");
301
302                          }
303
304
305                      }
306                  }
307                  return No_Fault;
308              case TSDEV_CC_DIR0:
309              case TSDEV_CC_DIR1:
310              case TSDEV_CC_DIR2:
311              case TSDEV_CC_DIR3:
312                  panic("TSDEV_CC_DIR write not implemented\n");
313              case TSDEV_CC_DRIR:
314                  panic("TSDEV_CC_DRIR write not implemented\n");
315              case TSDEV_CC_PRBEN:
316                  panic("TSDEV_CC_PRBEN write not implemented\n");
317              case TSDEV_CC_IIC0:
318              case TSDEV_CC_IIC1:
319              case TSDEV_CC_IIC2:
320              case TSDEV_CC_IIC3:
321                  panic("TSDEV_CC_IICx write not implemented\n");
322              case TSDEV_CC_MPR0:
323              case TSDEV_CC_MPR1:
324              case TSDEV_CC_MPR2:
325              case TSDEV_CC_MPR3:
326                  panic("TSDEV_CC_MPRx write not implemented\n");
327              default:
328                  panic("default in cchip read reached, accessing 0x%x\n");
329          }
330
331      break;
332      case sizeof(uint32_t):
333      case sizeof(uint16_t):
334      case sizeof(uint8_t):
335      default:
336        panic("invalid access size(?) for tsunami register!\n");
337    }
338
339    DPRINTFN("Tsunami ERROR: write daddr=%#x size=%d\n", daddr, req->size);
340
341    return No_Fault;
342}
343
344void
345TsunamiCChip::postRTC()
346{
347    int size = tsunami->intrctrl->cpu->system->execContexts.size();
348
349    for (int i = 0; i < size; i++) {
350        if (!RTCInterrupting[i]) {
351            misc |= 16 << i;
352            RTCInterrupting[i] = true;
353            tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ2, 0);
354            DPRINTF(Tsunami, "Posting RTC interrupt to cpu=%d", i);
355        }
356    }
357
358}
359
360void
361TsunamiCChip::postDRIR(uint32_t interrupt)
362{
363    uint64_t bitvector = (uint64_t)0x1 << interrupt;
364    drir |= bitvector;
365    uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size();
366    for(int i=0; i < size; i++) {
367        dir[i] = dim[i] & drir;
368        if (dim[i] & bitvector) {
369                tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ1, interrupt);
370                DPRINTF(Tsunami, "posting dir interrupt to cpu %d,"
371                        "interrupt %d\n",i, interrupt);
372        }
373    }
374}
375
376void
377TsunamiCChip::clearDRIR(uint32_t interrupt)
378{
379    uint64_t bitvector = (uint64_t)0x1 << interrupt;
380    uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size();
381    if (drir & bitvector)
382    {
383        drir &= ~bitvector;
384        for(int i=0; i < size; i++) {
385            if (dir[i] & bitvector) {
386                tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ1, interrupt);
387                DPRINTF(Tsunami, "clearing dir interrupt to cpu %d,"
388                    "interrupt %d\n",i, interrupt);
389
390            }
391            dir[i] = dim[i] & drir;
392        }
393    }
394    else
395        DPRINTF(Tsunami, "Spurrious clear? interrupt %d\n", interrupt);
396}
397
398Tick
399TsunamiCChip::cacheAccess(MemReqPtr &req)
400{
401    return curTick + pioLatency;
402}
403
404
405void
406TsunamiCChip::serialize(std::ostream &os)
407{
408    SERIALIZE_ARRAY(dim, Tsunami::Max_CPUs);
409    SERIALIZE_ARRAY(dir, Tsunami::Max_CPUs);
410    SERIALIZE_ARRAY(dirInterrupting, Tsunami::Max_CPUs);
411    SERIALIZE_ARRAY(ipiInterrupting, Tsunami::Max_CPUs);
412    SERIALIZE_SCALAR(drir);
413    SERIALIZE_SCALAR(misc);
414    SERIALIZE_ARRAY(RTCInterrupting, Tsunami::Max_CPUs);
415}
416
417void
418TsunamiCChip::unserialize(Checkpoint *cp, const std::string &section)
419{
420    UNSERIALIZE_ARRAY(dim, Tsunami::Max_CPUs);
421    UNSERIALIZE_ARRAY(dir, Tsunami::Max_CPUs);
422    UNSERIALIZE_ARRAY(dirInterrupting, Tsunami::Max_CPUs);
423    UNSERIALIZE_ARRAY(ipiInterrupting, Tsunami::Max_CPUs);
424    UNSERIALIZE_SCALAR(drir);
425    UNSERIALIZE_SCALAR(misc);
426    UNSERIALIZE_ARRAY(RTCInterrupting, Tsunami::Max_CPUs);
427}
428
429BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip)
430
431    SimObjectParam<Tsunami *> tsunami;
432    SimObjectParam<MemoryController *> mmu;
433    Param<Addr> addr;
434    SimObjectParam<Bus*> io_bus;
435    Param<Tick> pio_latency;
436    SimObjectParam<HierParams *> hier;
437
438END_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip)
439
440BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiCChip)
441
442    INIT_PARAM(tsunami, "Tsunami"),
443    INIT_PARAM(mmu, "Memory Controller"),
444    INIT_PARAM(addr, "Device Address"),
445    INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to", NULL),
446    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
447    INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams)
448
449END_INIT_SIM_OBJECT_PARAMS(TsunamiCChip)
450
451CREATE_SIM_OBJECT(TsunamiCChip)
452{
453    return new TsunamiCChip(getInstanceName(), tsunami, addr, mmu, hier,
454                            io_bus, pio_latency);
455}
456
457REGISTER_SIM_OBJECT("TsunamiCChip", TsunamiCChip)
458