tsunami_cchip.cc revision 8737:770ccf3af571
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 * Authors: Ali Saidi
29 *          Ron Dreslinski
30 */
31
32/** @file
33 * Emulation of the Tsunami CChip CSRs
34 */
35
36#include <deque>
37#include <string>
38#include <vector>
39
40#include "arch/alpha/ev5.hh"
41#include "base/trace.hh"
42#include "config/the_isa.hh"
43#include "cpu/intr_control.hh"
44#include "cpu/thread_context.hh"
45#include "debug/IPI.hh"
46#include "debug/Tsunami.hh"
47#include "dev/alpha/tsunami.hh"
48#include "dev/alpha/tsunami_cchip.hh"
49#include "dev/alpha/tsunamireg.h"
50#include "mem/packet.hh"
51#include "mem/packet_access.hh"
52#include "mem/port.hh"
53#include "params/TsunamiCChip.hh"
54#include "sim/system.hh"
55
56//Should this be AlphaISA?
57using namespace TheISA;
58
59TsunamiCChip::TsunamiCChip(const Params *p)
60    : BasicPioDevice(p), tsunami(p->tsunami)
61{
62    pioSize = 0x10000000;
63
64    drir = 0;
65    ipint = 0;
66    itint = 0;
67
68    for (int x = 0; x < Tsunami::Max_CPUs; x++)
69    {
70        dim[x] = 0;
71        dir[x] = 0;
72    }
73
74    //Put back pointer in tsunami
75    tsunami->cchip = this;
76}
77
78Tick
79TsunamiCChip::read(PacketPtr pkt)
80{
81    DPRINTF(Tsunami, "read  va=%#x size=%d\n", pkt->getAddr(), pkt->getSize());
82
83    assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
84
85    Addr regnum = (pkt->getAddr() - pioAddr) >> 6;
86    Addr daddr = (pkt->getAddr() - pioAddr);
87
88    pkt->allocate();
89    switch (pkt->getSize()) {
90
91      case sizeof(uint64_t):
92          pkt->set<uint64_t>(0);
93
94          if (daddr & TSDEV_CC_BDIMS)
95          {
96              pkt->set(dim[(daddr >> 4) & 0x3F]);
97              break;
98          }
99
100          if (daddr & TSDEV_CC_BDIRS)
101          {
102              pkt->set(dir[(daddr >> 4) & 0x3F]);
103              break;
104          }
105
106          switch(regnum) {
107              case TSDEV_CC_CSR:
108                  pkt->set(0x0);
109                  break;
110              case TSDEV_CC_MTR:
111                  panic("TSDEV_CC_MTR not implemeted\n");
112                   break;
113              case TSDEV_CC_MISC:
114                  pkt->set(((ipint << 8) & 0xF) | ((itint << 4) & 0xF) |
115                                     (pkt->req->contextId() & 0x3));
116                  // currently, FS cannot handle MT so contextId and
117                  // cpuId are effectively the same, don't know if it will
118                  // matter if FS becomes MT enabled.  I suspect no because
119                  // we are currently able to boot up to 64 procs anyway
120                  // which would render the CPUID of this register useless
121                  // anyway
122                  break;
123              case TSDEV_CC_AAR0:
124              case TSDEV_CC_AAR1:
125              case TSDEV_CC_AAR2:
126              case TSDEV_CC_AAR3:
127                  pkt->set(0);
128                  break;
129              case TSDEV_CC_DIM0:
130                  pkt->set(dim[0]);
131                  break;
132              case TSDEV_CC_DIM1:
133                  pkt->set(dim[1]);
134                  break;
135              case TSDEV_CC_DIM2:
136                  pkt->set(dim[2]);
137                  break;
138              case TSDEV_CC_DIM3:
139                  pkt->set(dim[3]);
140                  break;
141              case TSDEV_CC_DIR0:
142                  pkt->set(dir[0]);
143                  break;
144              case TSDEV_CC_DIR1:
145                  pkt->set(dir[1]);
146                  break;
147              case TSDEV_CC_DIR2:
148                  pkt->set(dir[2]);
149                  break;
150              case TSDEV_CC_DIR3:
151                  pkt->set(dir[3]);
152                  break;
153              case TSDEV_CC_DRIR:
154                  pkt->set(drir);
155                  break;
156              case TSDEV_CC_PRBEN:
157                  panic("TSDEV_CC_PRBEN not implemented\n");
158                  break;
159              case TSDEV_CC_IIC0:
160              case TSDEV_CC_IIC1:
161              case TSDEV_CC_IIC2:
162              case TSDEV_CC_IIC3:
163                  panic("TSDEV_CC_IICx not implemented\n");
164                  break;
165              case TSDEV_CC_MPR0:
166              case TSDEV_CC_MPR1:
167              case TSDEV_CC_MPR2:
168              case TSDEV_CC_MPR3:
169                  panic("TSDEV_CC_MPRx not implemented\n");
170                  break;
171              case TSDEV_CC_IPIR:
172                  pkt->set(ipint);
173                  break;
174              case TSDEV_CC_ITIR:
175                  pkt->set(itint);
176                  break;
177              default:
178                  panic("default in cchip read reached, accessing 0x%x\n");
179           } // uint64_t
180
181      break;
182      case sizeof(uint32_t):
183      case sizeof(uint16_t):
184      case sizeof(uint8_t):
185      default:
186        panic("invalid access size(?) for tsunami register!\n");
187    }
188    DPRINTF(Tsunami, "Tsunami CChip: read  regnum=%#x size=%d data=%lld\n",
189            regnum, pkt->getSize(), pkt->get<uint64_t>());
190
191    pkt->makeAtomicResponse();
192    return pioDelay;
193}
194
195Tick
196TsunamiCChip::write(PacketPtr pkt)
197{
198    assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
199    Addr daddr = pkt->getAddr() - pioAddr;
200    Addr regnum = (pkt->getAddr() - pioAddr) >> 6 ;
201
202
203    assert(pkt->getSize() == sizeof(uint64_t));
204
205    DPRINTF(Tsunami, "write - addr=%#x value=%#x\n", pkt->getAddr(), pkt->get<uint64_t>());
206
207    bool supportedWrite = false;
208
209
210    if (daddr & TSDEV_CC_BDIMS)
211    {
212        int number = (daddr >> 4) & 0x3F;
213
214        uint64_t bitvector;
215        uint64_t olddim;
216        uint64_t olddir;
217
218        olddim = dim[number];
219        olddir = dir[number];
220        dim[number] = pkt->get<uint64_t>();
221        dir[number] = dim[number] & drir;
222        for(int x = 0; x < Tsunami::Max_CPUs; x++)
223        {
224            bitvector = ULL(1) << x;
225            // Figure out which bits have changed
226            if ((dim[number] & bitvector) != (olddim & bitvector))
227            {
228                // The bit is now set and it wasn't before (set)
229                if((dim[number] & bitvector) && (dir[number] & bitvector))
230                {
231                    tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x);
232                    DPRINTF(Tsunami, "dim write resulting in posting dir"
233                            " interrupt to cpu %d\n", number);
234                }
235                else if ((olddir & bitvector) &&
236                        !(dir[number] & bitvector))
237                {
238                    // The bit was set and now its now clear and
239                    // we were interrupting on that bit before
240                    tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x);
241                    DPRINTF(Tsunami, "dim write resulting in clear"
242                            " dir interrupt to cpu %d\n", number);
243
244                }
245
246
247            }
248        }
249    } else {
250        switch(regnum) {
251          case TSDEV_CC_CSR:
252              panic("TSDEV_CC_CSR write\n");
253          case TSDEV_CC_MTR:
254              panic("TSDEV_CC_MTR write not implemented\n");
255          case TSDEV_CC_MISC:
256            uint64_t ipreq;
257            ipreq = (pkt->get<uint64_t>() >> 12) & 0xF;
258            //If it is bit 12-15, this is an IPI post
259            if (ipreq) {
260                reqIPI(ipreq);
261                supportedWrite = true;
262            }
263
264            //If it is bit 8-11, this is an IPI clear
265            uint64_t ipintr;
266            ipintr = (pkt->get<uint64_t>() >> 8) & 0xF;
267            if (ipintr) {
268                clearIPI(ipintr);
269                supportedWrite = true;
270            }
271
272            //If it is the 4-7th bit, clear the RTC interrupt
273            uint64_t itintr;
274              itintr = (pkt->get<uint64_t>() >> 4) & 0xF;
275            if (itintr) {
276                  clearITI(itintr);
277                supportedWrite = true;
278            }
279
280              // ignore NXMs
281              if (pkt->get<uint64_t>() & 0x10000000)
282                  supportedWrite = true;
283
284            if(!supportedWrite)
285                  panic("TSDEV_CC_MISC write not implemented\n");
286
287            break;
288            case TSDEV_CC_AAR0:
289            case TSDEV_CC_AAR1:
290            case TSDEV_CC_AAR2:
291            case TSDEV_CC_AAR3:
292                panic("TSDEV_CC_AARx write not implemeted\n");
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] = pkt->get<uint64_t>();
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(pkt->get<uint64_t>());
364                break;
365            case TSDEV_CC_ITIR:
366                clearITI(pkt->get<uint64_t>());
367                break;
368            case TSDEV_CC_IPIQ:
369                reqIPI(pkt->get<uint64_t>());
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->makeAtomicResponse();
376    return pioDelay;
377}
378
379void
380TsunamiCChip::clearIPI(uint64_t ipintr)
381{
382    int numcpus = sys->threadContexts.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 = sys->threadContexts.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 = sys->threadContexts.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 = sys->threadContexts.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\n", i);
464       }
465    }
466
467}
468
469void
470TsunamiCChip::postDRIR(uint32_t interrupt)
471{
472    uint64_t bitvector = ULL(1) << interrupt;
473    uint64_t size = sys->threadContexts.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 = sys->threadContexts.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
511
512void
513TsunamiCChip::serialize(std::ostream &os)
514{
515    SERIALIZE_ARRAY(dim, Tsunami::Max_CPUs);
516    SERIALIZE_ARRAY(dir, Tsunami::Max_CPUs);
517    SERIALIZE_SCALAR(ipint);
518    SERIALIZE_SCALAR(itint);
519    SERIALIZE_SCALAR(drir);
520}
521
522void
523TsunamiCChip::unserialize(Checkpoint *cp, const std::string &section)
524{
525    UNSERIALIZE_ARRAY(dim, Tsunami::Max_CPUs);
526    UNSERIALIZE_ARRAY(dir, Tsunami::Max_CPUs);
527    UNSERIALIZE_SCALAR(ipint);
528    UNSERIALIZE_SCALAR(itint);
529    UNSERIALIZE_SCALAR(drir);
530}
531
532TsunamiCChip *
533TsunamiCChipParams::create()
534{
535    return new TsunamiCChip(this);
536}
537