tsunami_cchip.cc revision 909
16691Stjones1@inf.ed.ac.uk/*
26691Stjones1@inf.ed.ac.uk * Copyright (c) 2004 The Regents of The University of Michigan
36691Stjones1@inf.ed.ac.uk * All rights reserved.
46691Stjones1@inf.ed.ac.uk *
56691Stjones1@inf.ed.ac.uk * Redistribution and use in source and binary forms, with or without
66691Stjones1@inf.ed.ac.uk * modification, are permitted provided that the following conditions are
76691Stjones1@inf.ed.ac.uk * met: redistributions of source code must retain the above copyright
86691Stjones1@inf.ed.ac.uk * notice, this list of conditions and the following disclaimer;
96691Stjones1@inf.ed.ac.uk * redistributions in binary form must reproduce the above copyright
106691Stjones1@inf.ed.ac.uk * notice, this list of conditions and the following disclaimer in the
116691Stjones1@inf.ed.ac.uk * documentation and/or other materials provided with the distribution;
126691Stjones1@inf.ed.ac.uk * neither the name of the copyright holders nor the names of its
136691Stjones1@inf.ed.ac.uk * contributors may be used to endorse or promote products derived from
146691Stjones1@inf.ed.ac.uk * this software without specific prior written permission.
156691Stjones1@inf.ed.ac.uk *
166691Stjones1@inf.ed.ac.uk * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
176691Stjones1@inf.ed.ac.uk * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
186691Stjones1@inf.ed.ac.uk * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
196691Stjones1@inf.ed.ac.uk * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
206691Stjones1@inf.ed.ac.uk * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
216691Stjones1@inf.ed.ac.uk * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
226691Stjones1@inf.ed.ac.uk * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
236691Stjones1@inf.ed.ac.uk * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
246691Stjones1@inf.ed.ac.uk * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
256691Stjones1@inf.ed.ac.uk * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
266691Stjones1@inf.ed.ac.uk * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
276691Stjones1@inf.ed.ac.uk */
286691Stjones1@inf.ed.ac.uk
296691Stjones1@inf.ed.ac.uk/* @file
306691Stjones1@inf.ed.ac.uk * Emulation of the Tsunami CChip CSRs
316691Stjones1@inf.ed.ac.uk */
326691Stjones1@inf.ed.ac.uk
336691Stjones1@inf.ed.ac.uk#include <deque>
346691Stjones1@inf.ed.ac.uk#include <string>
356691Stjones1@inf.ed.ac.uk#include <vector>
366691Stjones1@inf.ed.ac.uk
376691Stjones1@inf.ed.ac.uk#include "base/trace.hh"
386691Stjones1@inf.ed.ac.uk#include "dev/console.hh"
396691Stjones1@inf.ed.ac.uk#include "dev/tsunami_cchip.hh"
406691Stjones1@inf.ed.ac.uk#include "dev/tsunamireg.h"
416691Stjones1@inf.ed.ac.uk#include "dev/tsunami.hh"
426691Stjones1@inf.ed.ac.uk#include "mem/bus/bus.hh"
436691Stjones1@inf.ed.ac.uk#include "mem/bus/pio_interface.hh"
446691Stjones1@inf.ed.ac.uk#include "mem/bus/pio_interface_impl.hh"
456691Stjones1@inf.ed.ac.uk#include "mem/functional_mem/memory_control.hh"
466691Stjones1@inf.ed.ac.uk#include "cpu/intr_control.hh"
477512Stjones1@inf.ed.ac.uk#include "sim/builder.hh"
487512Stjones1@inf.ed.ac.uk#include "sim/system.hh"
497512Stjones1@inf.ed.ac.uk
507512Stjones1@inf.ed.ac.ukusing namespace std;
517512Stjones1@inf.ed.ac.uk
527512Stjones1@inf.ed.ac.ukTsunamiCChip::TsunamiCChip(const string &name, Tsunami *t, Addr a,
536691Stjones1@inf.ed.ac.uk                           MemoryController *mmu, HierParams *hier, Bus* bus)
546691Stjones1@inf.ed.ac.uk    : PioDevice(name), addr(a), tsunami(t)
556691Stjones1@inf.ed.ac.uk{
566691Stjones1@inf.ed.ac.uk    mmu->add_child(this, Range<Addr>(addr, addr + size));
576691Stjones1@inf.ed.ac.uk
586691Stjones1@inf.ed.ac.uk    for(int i=0; i < Tsunami::Max_CPUs; i++) {
596691Stjones1@inf.ed.ac.uk        dim[i] = 0;
606691Stjones1@inf.ed.ac.uk        dir[i] = 0;
616691Stjones1@inf.ed.ac.uk        dirInterrupting[i] = false;
626691Stjones1@inf.ed.ac.uk        ipiInterrupting[i] = false;
636691Stjones1@inf.ed.ac.uk        RTCInterrupting[i] = false;
646691Stjones1@inf.ed.ac.uk    }
656691Stjones1@inf.ed.ac.uk
666691Stjones1@inf.ed.ac.uk    if (bus) {
676691Stjones1@inf.ed.ac.uk        pioInterface = newPioInterface(name, hier, bus, this,
686691Stjones1@inf.ed.ac.uk                                      &TsunamiCChip::cacheAccess);
696691Stjones1@inf.ed.ac.uk        pioInterface->addAddrRange(addr, addr + size - 1);
706691Stjones1@inf.ed.ac.uk    }
716691Stjones1@inf.ed.ac.uk
726691Stjones1@inf.ed.ac.uk    drir = 0;
736691Stjones1@inf.ed.ac.uk    misc = 0;
746691Stjones1@inf.ed.ac.uk
756691Stjones1@inf.ed.ac.uk    //Put back pointer in tsunami
766691Stjones1@inf.ed.ac.uk    tsunami->cchip = this;
776691Stjones1@inf.ed.ac.uk}
786691Stjones1@inf.ed.ac.uk
796691Stjones1@inf.ed.ac.ukFault
806691Stjones1@inf.ed.ac.ukTsunamiCChip::read(MemReqPtr &req, uint8_t *data)
816691Stjones1@inf.ed.ac.uk{
826691Stjones1@inf.ed.ac.uk    DPRINTF(Tsunami, "read  va=%#x size=%d\n",
836691Stjones1@inf.ed.ac.uk            req->vaddr, req->size);
846691Stjones1@inf.ed.ac.uk
856691Stjones1@inf.ed.ac.uk    Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)) >> 6;
866691Stjones1@inf.ed.ac.uk    ExecContext *xc = req->xc;
876691Stjones1@inf.ed.ac.uk
886691Stjones1@inf.ed.ac.uk    switch (req->size) {
896691Stjones1@inf.ed.ac.uk
906691Stjones1@inf.ed.ac.uk      case sizeof(uint64_t):
916691Stjones1@inf.ed.ac.uk          switch(daddr) {
926691Stjones1@inf.ed.ac.uk              case TSDEV_CC_CSR:
936691Stjones1@inf.ed.ac.uk                  *(uint64_t*)data = 0x0;
946691Stjones1@inf.ed.ac.uk                  return No_Fault;
956691Stjones1@inf.ed.ac.uk              case TSDEV_CC_MTR:
966691Stjones1@inf.ed.ac.uk                  panic("TSDEV_CC_MTR not implemeted\n");
976691Stjones1@inf.ed.ac.uk                   return No_Fault;
986691Stjones1@inf.ed.ac.uk              case TSDEV_CC_MISC:
996691Stjones1@inf.ed.ac.uk                *(uint64_t*)data = misc | (xc->cpu_id & 0x3);
1006691Stjones1@inf.ed.ac.uk                  return No_Fault;
101              case TSDEV_CC_AAR0:
102              case TSDEV_CC_AAR1:
103              case TSDEV_CC_AAR2:
104              case TSDEV_CC_AAR3:
105                  *(uint64_t*)data = 0;
106                  return No_Fault;
107              case TSDEV_CC_DIM0:
108                  *(uint64_t*)data = dim[0];
109                  return No_Fault;
110              case TSDEV_CC_DIM1:
111                  *(uint64_t*)data = dim[1];
112                  return No_Fault;
113              case TSDEV_CC_DIM2:
114                  *(uint64_t*)data = dim[2];
115                  return No_Fault;
116              case TSDEV_CC_DIM3:
117                  *(uint64_t*)data = dim[3];
118                  return No_Fault;
119              case TSDEV_CC_DIR0:
120                  *(uint64_t*)data = dir[0];
121                  return No_Fault;
122              case TSDEV_CC_DIR1:
123                  *(uint64_t*)data = dir[1];
124                  return No_Fault;
125              case TSDEV_CC_DIR2:
126                  *(uint64_t*)data = dir[2];
127                  return No_Fault;
128              case TSDEV_CC_DIR3:
129                  *(uint64_t*)data = dir[3];
130                  return No_Fault;
131              case TSDEV_CC_DRIR:
132                  *(uint64_t*)data = drir;
133                  return No_Fault;
134              case TSDEV_CC_PRBEN:
135                  panic("TSDEV_CC_PRBEN not implemented\n");
136                  return No_Fault;
137              case TSDEV_CC_IIC0:
138              case TSDEV_CC_IIC1:
139              case TSDEV_CC_IIC2:
140              case TSDEV_CC_IIC3:
141                  panic("TSDEV_CC_IICx not implemented\n");
142                  return No_Fault;
143              case TSDEV_CC_MPR0:
144              case TSDEV_CC_MPR1:
145              case TSDEV_CC_MPR2:
146              case TSDEV_CC_MPR3:
147                  panic("TSDEV_CC_MPRx not implemented\n");
148                  return No_Fault;
149              default:
150                  panic("default in cchip read reached, accessing 0x%x\n");
151           } // uint64_t
152
153      break;
154      case sizeof(uint32_t):
155      case sizeof(uint16_t):
156      case sizeof(uint8_t):
157      default:
158        panic("invalid access size(?) for tsunami register!\n");
159    }
160    DPRINTFN("Tsunami CChip ERROR: read  daddr=%#x size=%d\n", daddr, req->size);
161
162    return No_Fault;
163}
164
165Fault
166TsunamiCChip::write(MemReqPtr &req, const uint8_t *data)
167{
168    DPRINTF(Tsunami, "write - va=%#x value=%#x size=%d \n",
169            req->vaddr, *(uint64_t*)data, req->size);
170
171    Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)) >> 6;
172
173    bool supportedWrite = false;
174    uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size();
175
176    switch (req->size) {
177
178      case sizeof(uint64_t):
179          switch(daddr) {
180            case TSDEV_CC_CSR:
181                  panic("TSDEV_CC_CSR write\n");
182                  return No_Fault;
183              case TSDEV_CC_MTR:
184                  panic("TSDEV_CC_MTR write not implemented\n");
185                   return No_Fault;
186              case TSDEV_CC_MISC:
187                //If it is the 4-7th bit, clear the RTC interrupt
188                uint64_t itintr;
189                if ((itintr = (*(uint64_t*) data) & (0xf<<4))) {
190                    //Clear the bits in ITINTR
191                    misc &= ~(itintr);
192                    for (int i=0; i < size; i++) {
193                        if ((itintr & (1 << (i+4))) && RTCInterrupting[i]) {
194                            tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ2, 0);
195                            RTCInterrupting[i] = false;
196                            DPRINTF(Tsunami, "clearing rtc interrupt to cpu=%d\n", i);
197                        }
198                    }
199                    supportedWrite = true;
200                }
201                //If it is 12th-15th bit, IPI sent to Processor 1
202                uint64_t ipreq;
203                if ((ipreq = (*(uint64_t*) data) & (0xf << 12))) {
204                    //Set the bits in IPINTR
205                    misc |= (ipreq >> 4);
206                    for (int i=0; i < size; i++) {
207                        if ((ipreq & (1 << (i + 12)))) {
208                            if (!ipiInterrupting[i])
209                                tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ3, 0);
210                            ipiInterrupting[i]++;
211                            DPRINTF(IPI, "send cpu=%d pending=%d from=%d\n", i,
212                                    ipiInterrupting[i], req->cpu_num);
213                        }
214                    }
215                    supportedWrite = true;
216                }
217                //If it is bits 8-11, then clearing IPI's
218                uint64_t ipintr;
219                if ((ipintr = (*(uint64_t*) data) & (0xf << 8))) {
220                    //Clear the bits in IPINTR
221                    misc &= ~(ipintr);
222                    for (int i=0; i < size; i++) {
223                        if ((ipintr & (1 << (i + 8))) && ipiInterrupting[i]) {
224                            if (!(--ipiInterrupting[i]))
225                                tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ3, 0);
226                            DPRINTF(IPI, "clearing cpu=%d pending=%d from=%d\n", i,
227                                    ipiInterrupting[i] + 1, req->cpu_num);
228                        }
229                    }
230                    supportedWrite = true;
231                }
232
233        // ignore NXMs
234        if (*(uint64_t*)data & 0x10000000)
235            supportedWrite = true;
236
237                if(!supportedWrite) panic("TSDEV_CC_MISC write not implemented\n");
238                return No_Fault;
239              case TSDEV_CC_AAR0:
240              case TSDEV_CC_AAR1:
241              case TSDEV_CC_AAR2:
242              case TSDEV_CC_AAR3:
243                  panic("TSDEV_CC_AARx write not implemeted\n");
244                  return No_Fault;
245              case TSDEV_CC_DIM0:
246              case TSDEV_CC_DIM1:
247              case TSDEV_CC_DIM2:
248              case TSDEV_CC_DIM3:
249                  int number;
250                  if(daddr == TSDEV_CC_DIM0)
251                      number = 0;
252                  else if(daddr == TSDEV_CC_DIM1)
253                      number = 1;
254                  else if(daddr == TSDEV_CC_DIM2)
255                      number = 2;
256                  else
257                      number = 3;
258
259                  uint64_t bitvector;
260                  uint64_t olddim;
261                  uint64_t olddir;
262
263                  olddim = dim[number];
264                  olddir = dir[number];
265                  dim[number] = *(uint64_t*)data;
266                  dir[number] = dim[number] & drir;
267                  for(int x = 0; x < 64; x++)
268                  {
269                      bitvector = (uint64_t)1 << x;
270                      // Figure out which bits have changed
271                      if ((dim[number] & bitvector) != (olddim & bitvector))
272                      {
273                          // The bit is now set and it wasn't before (set)
274                          if((dim[number] & bitvector) && (dir[number] & bitvector))
275                          {
276                              tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x);
277                              DPRINTF(Tsunami, "posting dir interrupt to cpu 0\n");
278                          }
279                          else if ((olddir & bitvector) &&
280                                  !(dir[number] & bitvector))
281                          {
282                              // The bit was set and now its now clear and
283                              // we were interrupting on that bit before
284                              tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x);
285                              DPRINTF(Tsunami, "dim write resulting in clear"
286                                      "dir interrupt to cpu 0\n");
287
288                          }
289
290
291                      }
292                  }
293                  return No_Fault;
294              case TSDEV_CC_DIR0:
295              case TSDEV_CC_DIR1:
296              case TSDEV_CC_DIR2:
297              case TSDEV_CC_DIR3:
298                  panic("TSDEV_CC_DIR write not implemented\n");
299              case TSDEV_CC_DRIR:
300                  panic("TSDEV_CC_DRIR write not implemented\n");
301              case TSDEV_CC_PRBEN:
302                  panic("TSDEV_CC_PRBEN write not implemented\n");
303              case TSDEV_CC_IIC0:
304              case TSDEV_CC_IIC1:
305              case TSDEV_CC_IIC2:
306              case TSDEV_CC_IIC3:
307                  panic("TSDEV_CC_IICx write not implemented\n");
308              case TSDEV_CC_MPR0:
309              case TSDEV_CC_MPR1:
310              case TSDEV_CC_MPR2:
311              case TSDEV_CC_MPR3:
312                  panic("TSDEV_CC_MPRx write not implemented\n");
313              default:
314                  panic("default in cchip read reached, accessing 0x%x\n");
315          }
316
317      break;
318      case sizeof(uint32_t):
319      case sizeof(uint16_t):
320      case sizeof(uint8_t):
321      default:
322        panic("invalid access size(?) for tsunami register!\n");
323    }
324
325    DPRINTFN("Tsunami ERROR: write daddr=%#x size=%d\n", daddr, req->size);
326
327    return No_Fault;
328}
329
330void
331TsunamiCChip::postRTC()
332{
333    int size = tsunami->intrctrl->cpu->system->execContexts.size();
334
335    for (int i = 0; i < size; i++) {
336        if (!RTCInterrupting[i]) {
337            misc |= 16 << i;
338            RTCInterrupting[i] = true;
339            tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ2, 0);
340            DPRINTF(Tsunami, "Posting RTC interrupt to cpu=%d", i);
341        }
342    }
343
344}
345
346void
347TsunamiCChip::postDRIR(uint32_t interrupt)
348{
349    uint64_t bitvector = (uint64_t)0x1 << interrupt;
350    drir |= bitvector;
351    uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size();
352    for(int i=0; i < size; i++) {
353        dir[i] = dim[i] & drir;
354        if (dim[i] & bitvector) {
355                tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ1, interrupt);
356                DPRINTF(Tsunami, "posting dir interrupt to cpu %d,"
357                        "interrupt %d\n",i, interrupt);
358        }
359    }
360}
361
362void
363TsunamiCChip::clearDRIR(uint32_t interrupt)
364{
365    uint64_t bitvector = (uint64_t)0x1 << interrupt;
366    uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size();
367    if (drir & bitvector)
368    {
369        drir &= ~bitvector;
370        for(int i=0; i < size; i++) {
371            if (dir[i] & bitvector) {
372                tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ1, interrupt);
373                DPRINTF(Tsunami, "clearing dir interrupt to cpu %d,"
374                    "interrupt %d\n",i, interrupt);
375
376            }
377            dir[i] = dim[i] & drir;
378        }
379    }
380    else
381        DPRINTF(Tsunami, "Spurrious clear? interrupt %d\n", interrupt);
382}
383
384Tick
385TsunamiCChip::cacheAccess(MemReqPtr &req)
386{
387    return curTick + 1000;
388}
389
390
391void
392TsunamiCChip::serialize(std::ostream &os)
393{
394    SERIALIZE_ARRAY(dim, Tsunami::Max_CPUs);
395    SERIALIZE_ARRAY(dir, Tsunami::Max_CPUs);
396    SERIALIZE_ARRAY(dirInterrupting, Tsunami::Max_CPUs);
397    SERIALIZE_ARRAY(ipiInterrupting, Tsunami::Max_CPUs);
398    SERIALIZE_SCALAR(drir);
399    SERIALIZE_SCALAR(misc);
400    SERIALIZE_ARRAY(RTCInterrupting, Tsunami::Max_CPUs);
401}
402
403void
404TsunamiCChip::unserialize(Checkpoint *cp, const std::string &section)
405{
406    UNSERIALIZE_ARRAY(dim, Tsunami::Max_CPUs);
407    UNSERIALIZE_ARRAY(dir, Tsunami::Max_CPUs);
408    UNSERIALIZE_ARRAY(dirInterrupting, Tsunami::Max_CPUs);
409    UNSERIALIZE_ARRAY(ipiInterrupting, Tsunami::Max_CPUs);
410    UNSERIALIZE_SCALAR(drir);
411    UNSERIALIZE_SCALAR(misc);
412    UNSERIALIZE_ARRAY(RTCInterrupting, Tsunami::Max_CPUs);
413}
414
415BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip)
416
417    SimObjectParam<Tsunami *> tsunami;
418    SimObjectParam<MemoryController *> mmu;
419    Param<Addr> addr;
420    SimObjectParam<Bus*> io_bus;
421    SimObjectParam<HierParams *> hier;
422
423END_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip)
424
425BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiCChip)
426
427    INIT_PARAM(tsunami, "Tsunami"),
428    INIT_PARAM(mmu, "Memory Controller"),
429    INIT_PARAM(addr, "Device Address"),
430    INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to", NULL),
431    INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams)
432
433END_INIT_SIM_OBJECT_PARAMS(TsunamiCChip)
434
435CREATE_SIM_OBJECT(TsunamiCChip)
436{
437    return new TsunamiCChip(getInstanceName(), tsunami, addr, mmu, hier, io_bus);
438}
439
440REGISTER_SIM_OBJECT("TsunamiCChip", TsunamiCChip)
441