tsunami_cchip.cc revision 2539
1/*
2 * Copyright (c) 2004-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @file
30 * Emulation of the Tsunami CChip CSRs
31 */
32
33#include <deque>
34#include <string>
35#include <vector>
36
37#include "arch/alpha/ev5.hh"
38#include "base/trace.hh"
39#include "dev/tsunami_cchip.hh"
40#include "dev/tsunamireg.h"
41#include "dev/tsunami.hh"
42#include "mem/port.hh"
43#include "cpu/exec_context.hh"
44#include "cpu/intr_control.hh"
45#include "sim/builder.hh"
46#include "sim/system.hh"
47
48using namespace std;
49//Should this be AlphaISA?
50using namespace TheISA;
51
52TsunamiCChip::TsunamiCChip(Params *p)
53    : BasicPioDevice(p), tsunami(p->tsunami)
54{
55    pioSize = 0xfffffff;
56
57    drir = 0;
58    ipint = 0;
59    itint = 0;
60
61    for (int x = 0; x < Tsunami::Max_CPUs; x++)
62    {
63        dim[x] = 0;
64        dir[x] = 0;
65    }
66
67    //Put back pointer in tsunami
68    tsunami->cchip = this;
69}
70
71Tick
72TsunamiCChip::read(Packet &pkt)
73{
74    DPRINTF(Tsunami, "read  va=%#x size=%d\n", req->vaddr, req->size);
75
76    assert(pkt.result == Unknown);
77    assert(pkt.addr > pioAddr && pkt.addr < pioAddr + pioSize);
78
79    pkt.time = curTick + pioDelay;
80    Addr regnum = (req->paddr - pioAddr) >> 6;
81    Addr daddr = (req->paddr - pioAddr);
82
83    uint32_t *data32;
84    uint64_t *data64;
85
86    switch (pkt.size) {
87
88      case sizeof(uint64_t):
89          if (!pkt.data) {
90              data64 = new uint64_t;
91              pkt.data = (uint8_t*)data64;
92          } else
93              data64 = (uint64_t*)pkt.data;
94
95          if (daddr & TSDEV_CC_BDIMS)
96          {
97              *data64 = dim[(daddr >> 4) & 0x3F];
98              break;
99          }
100
101          if (daddr & TSDEV_CC_BDIRS)
102          {
103              *data64 = dir[(daddr >> 4) & 0x3F];
104              break;
105          }
106
107          switch(regnum) {
108              case TSDEV_CC_CSR:
109                  *data64 = 0x0;
110                  break;
111              case TSDEV_CC_MTR:
112                  panic("TSDEV_CC_MTR not implemeted\n");
113                   break;
114              case TSDEV_CC_MISC:
115                  *data64 = (ipint << 8) & 0xF | (itint << 4) & 0xF |
116                                     (pkt.req->cpuId & 0x3);
117                  break;
118              case TSDEV_CC_AAR0:
119              case TSDEV_CC_AAR1:
120              case TSDEV_CC_AAR2:
121              case TSDEV_CC_AAR3:
122                  *data64 = 0;
123                  break;
124              case TSDEV_CC_DIM0:
125                  *data64 = dim[0];
126                  break;
127              case TSDEV_CC_DIM1:
128                  *data64 = dim[1];
129                  break;
130              case TSDEV_CC_DIM2:
131                  *data64 = dim[2];
132                  break;
133              case TSDEV_CC_DIM3:
134                  *data64 = dim[3];
135                  break;
136              case TSDEV_CC_DIR0:
137                  *data64 = dir[0];
138                  break;
139              case TSDEV_CC_DIR1:
140                  *data64 = dir[1];
141                  break;
142              case TSDEV_CC_DIR2:
143                  *data64 = dir[2];
144                  break;
145              case TSDEV_CC_DIR3:
146                  *data64 = dir[3];
147                  break;
148              case TSDEV_CC_DRIR:
149                  *data64 = drir;
150                  break;
151              case TSDEV_CC_PRBEN:
152                  panic("TSDEV_CC_PRBEN not implemented\n");
153                  break;
154              case TSDEV_CC_IIC0:
155              case TSDEV_CC_IIC1:
156              case TSDEV_CC_IIC2:
157              case TSDEV_CC_IIC3:
158                  panic("TSDEV_CC_IICx not implemented\n");
159                  break;
160              case TSDEV_CC_MPR0:
161              case TSDEV_CC_MPR1:
162              case TSDEV_CC_MPR2:
163              case TSDEV_CC_MPR3:
164                  panic("TSDEV_CC_MPRx not implemented\n");
165                  break;
166              case TSDEV_CC_IPIR:
167                  *data64 = ipint;
168                  break;
169              case TSDEV_CC_ITIR:
170                  *data64 = itint;
171                  break;
172              default:
173                  panic("default in cchip read reached, accessing 0x%x\n");
174           } // uint64_t
175
176      break;
177      case sizeof(uint32_t):
178      case sizeof(uint16_t):
179      case sizeof(uint8_t):
180      default:
181        panic("invalid access size(?) for tsunami register!\n");
182    }
183    DPRINTFN("Tsunami CChip: read  regnum=%#x size=%d data=%lld\n", regnum,
184            req->size, *data);
185
186    pkt.result = Success;
187    return pioDelay;
188}
189
190Tick
191TsunamiCChip::write(Packet &pkt)
192{
193    pkt.time = curTick + pioDelay;
194
195
196    assert(pkt.addr >= pioAddr && pkt.addr < pioAddr + pioSize);
197    Addr daddr = pkt.addr - pioAddr;
198    Addr regnum = (pkt.addr - pioAddr) >> 6 ;
199
200
201    uint64_t val = *(uint64_t *)pkt.data;
202    assert(pkt.size == sizeof(uint64_t));
203
204    DPRINTF(Tsunami, "write - addr=%#x value=%#x\n", req->addr, val);
205
206    bool supportedWrite = false;
207
208
209    if (daddr & TSDEV_CC_BDIMS)
210    {
211        int number = (daddr >> 4) & 0x3F;
212
213        uint64_t bitvector;
214        uint64_t olddim;
215        uint64_t olddir;
216
217        olddim = dim[number];
218        olddir = dir[number];
219        dim[number] = val;
220        dir[number] = dim[number] & drir;
221        for(int x = 0; x < Tsunami::Max_CPUs; x++)
222        {
223            bitvector = ULL(1) << x;
224            // Figure out which bits have changed
225            if ((dim[number] & bitvector) != (olddim & bitvector))
226            {
227                // The bit is now set and it wasn't before (set)
228                if((dim[number] & bitvector) && (dir[number] & bitvector))
229                {
230                    tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x);
231                    DPRINTF(Tsunami, "dim write resulting in posting dir"
232                            " interrupt to cpu %d\n", number);
233                }
234                else if ((olddir & bitvector) &&
235                        !(dir[number] & bitvector))
236                {
237                    // The bit was set and now its now clear and
238                    // we were interrupting on that bit before
239                    tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x);
240                    DPRINTF(Tsunami, "dim write resulting in clear"
241                            " dir interrupt to cpu %d\n", number);
242
243                }
244
245
246            }
247        }
248    } else {
249        switch(regnum) {
250          case TSDEV_CC_CSR:
251              panic("TSDEV_CC_CSR write\n");
252          case TSDEV_CC_MTR:
253              panic("TSDEV_CC_MTR write not implemented\n");
254          case TSDEV_CC_MISC:
255            uint64_t ipreq;
256            ipreq = (val >> 12) & 0xF;
257            //If it is bit 12-15, this is an IPI post
258            if (ipreq) {
259                reqIPI(ipreq);
260                supportedWrite = true;
261            }
262
263            //If it is bit 8-11, this is an IPI clear
264            uint64_t ipintr;
265            ipintr = (val >> 8) & 0xF;
266            if (ipintr) {
267                clearIPI(ipintr);
268                supportedWrite = true;
269            }
270
271            //If it is the 4-7th bit, clear the RTC interrupt
272            uint64_t itintr;
273              itintr = (val >> 4) & 0xF;
274            if (itintr) {
275                  clearITI(itintr);
276                supportedWrite = true;
277            }
278
279              // ignore NXMs
280              if (val & 0x10000000)
281                  supportedWrite = true;
282
283            if(!supportedWrite)
284                  panic("TSDEV_CC_MISC write not implemented\n");
285
286
287            case TSDEV_CC_AAR0:
288            case TSDEV_CC_AAR1:
289            case TSDEV_CC_AAR2:
290            case TSDEV_CC_AAR3:
291                panic("TSDEV_CC_AARx write not implemeted\n");
292                return NoFault;
293            case TSDEV_CC_DIM0:
294            case TSDEV_CC_DIM1:
295            case TSDEV_CC_DIM2:
296            case TSDEV_CC_DIM3:
297                int number;
298                if(regnum == TSDEV_CC_DIM0)
299                    number = 0;
300                else if(regnum == TSDEV_CC_DIM1)
301                    number = 1;
302                else if(regnum == TSDEV_CC_DIM2)
303                    number = 2;
304                else
305                    number = 3;
306
307                uint64_t bitvector;
308                uint64_t olddim;
309                uint64_t olddir;
310
311                olddim = dim[number];
312                olddir = dir[number];
313                dim[number] = val;
314                dir[number] = dim[number] & drir;
315                for(int x = 0; x < 64; x++)
316                {
317                    bitvector = ULL(1) << x;
318                    // Figure out which bits have changed
319                    if ((dim[number] & bitvector) != (olddim & bitvector))
320                    {
321                        // The bit is now set and it wasn't before (set)
322                        if((dim[number] & bitvector) && (dir[number] & bitvector))
323                        {
324                          tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x);
325                          DPRINTF(Tsunami, "posting dir interrupt to cpu 0\n");
326                        }
327                        else if ((olddir & bitvector) &&
328                                !(dir[number] & bitvector))
329                        {
330                            // The bit was set and now its now clear and
331                            // we were interrupting on that bit before
332                            tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x);
333                          DPRINTF(Tsunami, "dim write resulting in clear"
334                                    " dir interrupt to cpu %d\n",
335                                    x);
336
337                        }
338
339
340                    }
341                }
342                break;
343            case TSDEV_CC_DIR0:
344            case TSDEV_CC_DIR1:
345            case TSDEV_CC_DIR2:
346            case TSDEV_CC_DIR3:
347                panic("TSDEV_CC_DIR write not implemented\n");
348            case TSDEV_CC_DRIR:
349                panic("TSDEV_CC_DRIR write not implemented\n");
350            case TSDEV_CC_PRBEN:
351                panic("TSDEV_CC_PRBEN write not implemented\n");
352            case TSDEV_CC_IIC0:
353            case TSDEV_CC_IIC1:
354            case TSDEV_CC_IIC2:
355            case TSDEV_CC_IIC3:
356                panic("TSDEV_CC_IICx write not implemented\n");
357            case TSDEV_CC_MPR0:
358            case TSDEV_CC_MPR1:
359            case TSDEV_CC_MPR2:
360            case TSDEV_CC_MPR3:
361                panic("TSDEV_CC_MPRx write not implemented\n");
362            case TSDEV_CC_IPIR:
363                clearIPI(val);
364                break;
365            case TSDEV_CC_ITIR:
366                clearITI(val);
367                break;
368            case TSDEV_CC_IPIQ:
369                reqIPI(val);
370                break;
371            default:
372              panic("default in cchip read reached, accessing 0x%x\n");
373        }  // swtich(regnum)
374    } // not BIG_TSUNAMI write
375    pkt.result = Success;
376    return pioDelay;
377}
378
379void
380TsunamiCChip::clearIPI(uint64_t ipintr)
381{
382    int numcpus = tsunami->intrctrl->cpu->system->execContexts.size();
383    assert(numcpus <= Tsunami::Max_CPUs);
384
385    if (ipintr) {
386        for (int cpunum=0; cpunum < numcpus; cpunum++) {
387            // Check each cpu bit
388            uint64_t cpumask = ULL(1) << cpunum;
389            if (ipintr & cpumask) {
390                // Check if there is a pending ipi
391                if (ipint & cpumask) {
392                    ipint &= ~cpumask;
393                    tsunami->intrctrl->clear(cpunum, TheISA::INTLEVEL_IRQ3, 0);
394                    DPRINTF(IPI, "clear IPI IPI cpu=%d\n", cpunum);
395                }
396                else
397                    warn("clear IPI for CPU=%d, but NO IPI\n", cpunum);
398            }
399        }
400    }
401    else
402        panic("Big IPI Clear, but not processors indicated\n");
403}
404
405void
406TsunamiCChip::clearITI(uint64_t itintr)
407{
408    int numcpus = tsunami->intrctrl->cpu->system->execContexts.size();
409    assert(numcpus <= Tsunami::Max_CPUs);
410
411    if (itintr) {
412        for (int i=0; i < numcpus; i++) {
413            uint64_t cpumask = ULL(1) << i;
414            if (itintr & cpumask & itint) {
415                tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ2, 0);
416                itint &= ~cpumask;
417                DPRINTF(Tsunami, "clearing rtc interrupt to cpu=%d\n", i);
418            }
419        }
420    }
421    else
422        panic("Big ITI Clear, but not processors indicated\n");
423}
424
425void
426TsunamiCChip::reqIPI(uint64_t ipreq)
427{
428    int numcpus = tsunami->intrctrl->cpu->system->execContexts.size();
429    assert(numcpus <= Tsunami::Max_CPUs);
430
431    if (ipreq) {
432        for (int cpunum=0; cpunum < numcpus; cpunum++) {
433            // Check each cpu bit
434            uint64_t cpumask = ULL(1) << cpunum;
435            if (ipreq & cpumask) {
436                // Check if there is already an ipi (bits 8:11)
437                if (!(ipint & cpumask)) {
438                    ipint  |= cpumask;
439                    tsunami->intrctrl->post(cpunum, TheISA::INTLEVEL_IRQ3, 0);
440                    DPRINTF(IPI, "send IPI cpu=%d\n", cpunum);
441                }
442                else
443                    warn("post IPI for CPU=%d, but IPI already\n", cpunum);
444            }
445        }
446    }
447    else
448        panic("Big IPI Request, but not processors indicated\n");
449}
450
451
452void
453TsunamiCChip::postRTC()
454{
455    int size = tsunami->intrctrl->cpu->system->execContexts.size();
456    assert(size <= Tsunami::Max_CPUs);
457
458    for (int i = 0; i < size; i++) {
459        uint64_t cpumask = ULL(1) << i;
460       if (!(cpumask & itint)) {
461           itint |= cpumask;
462           tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ2, 0);
463           DPRINTF(Tsunami, "Posting RTC interrupt to cpu=%d", i);
464       }
465    }
466
467}
468
469void
470TsunamiCChip::postDRIR(uint32_t interrupt)
471{
472    uint64_t bitvector = ULL(1) << interrupt;
473    uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size();
474    assert(size <= Tsunami::Max_CPUs);
475    drir |= bitvector;
476
477    for(int i=0; i < size; i++) {
478        dir[i] = dim[i] & drir;
479       if (dim[i] & bitvector) {
480              tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ1, interrupt);
481              DPRINTF(Tsunami, "posting dir interrupt to cpu %d,"
482                        "interrupt %d\n",i, interrupt);
483       }
484    }
485}
486
487void
488TsunamiCChip::clearDRIR(uint32_t interrupt)
489{
490    uint64_t bitvector = ULL(1) << interrupt;
491    uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size();
492    assert(size <= Tsunami::Max_CPUs);
493
494    if (drir & bitvector)
495    {
496        drir &= ~bitvector;
497        for(int i=0; i < size; i++) {
498           if (dir[i] & bitvector) {
499               tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ1, interrupt);
500               DPRINTF(Tsunami, "clearing dir interrupt to cpu %d,"
501                    "interrupt %d\n",i, interrupt);
502
503           }
504           dir[i] = dim[i] & drir;
505        }
506    }
507    else
508        DPRINTF(Tsunami, "Spurrious clear? interrupt %d\n", interrupt);
509}
510
511Tick
512TsunamiCChip::cacheAccess(MemReqPtr &req)
513{
514    return curTick + pioLatency;
515}
516
517
518void
519TsunamiCChip::serialize(std::ostream &os)
520{
521    SERIALIZE_ARRAY(dim, Tsunami::Max_CPUs);
522    SERIALIZE_ARRAY(dir, Tsunami::Max_CPUs);
523    SERIALIZE_SCALAR(ipint);
524    SERIALIZE_SCALAR(itint);
525    SERIALIZE_SCALAR(drir);
526}
527
528void
529TsunamiCChip::unserialize(Checkpoint *cp, const std::string &section)
530{
531    UNSERIALIZE_ARRAY(dim, Tsunami::Max_CPUs);
532    UNSERIALIZE_ARRAY(dir, Tsunami::Max_CPUs);
533    UNSERIALIZE_SCALAR(ipint);
534    UNSERIALIZE_SCALAR(itint);
535    UNSERIALIZE_SCALAR(drir);
536}
537
538BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip)
539
540    Param<Addr> pio_addr;
541    Param<Tick> pio_latency;
542    SimObjectParam<Platform *> platform;
543    SimObjectParam<System *> system;
544    SimObjectParam<Tsunami *> tsunami;
545
546END_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip)
547
548BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiCChip)
549
550    INIT_PARAM(pio_addr, "Device Address"),
551    INIT_PARAM(pio_latency, "Programmed IO latency"),
552    INIT_PARAM(platform, "platform"),
553    INIT_PARAM(system, "system object"),
554    INIT_PARAM(tsunami, "Tsunami")
555
556END_INIT_SIM_OBJECT_PARAMS(TsunamiCChip)
557
558CREATE_SIM_OBJECT(TsunamiCChip)
559{
560    TsunamiCChip::Params *p = new TsunamiCChip::Params;
561    p->name = getInstanceName();
562    p->pio_addr = pio_addr;
563    p->pio_delay = pio_latency;
564    p->platform = platform;
565    p->system = system;
566    p->tsunami = tsunami;
567    return new TsunamiCChip(p);
568}
569
570REGISTER_SIM_OBJECT("TsunamiCChip", TsunamiCChip)
571