tsunami_cchip.cc revision 4739:9f8edf47aeca
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 "cpu/intr_control.hh"
43#include "cpu/thread_context.hh"
44#include "dev/alpha/tsunami.hh"
45#include "dev/alpha/tsunami_cchip.hh"
46#include "dev/alpha/tsunamireg.h"
47#include "mem/packet.hh"
48#include "mem/packet_access.hh"
49#include "mem/port.hh"
50#include "sim/builder.hh"
51#include "sim/system.hh"
52
53using namespace std;
54//Should this be AlphaISA?
55using namespace TheISA;
56
57TsunamiCChip::TsunamiCChip(Params *p)
58    : BasicPioDevice(p), tsunami(p->tsunami)
59{
60    pioSize = 0x10000000;
61
62    drir = 0;
63    ipint = 0;
64    itint = 0;
65
66    for (int x = 0; x < Tsunami::Max_CPUs; x++)
67    {
68        dim[x] = 0;
69        dir[x] = 0;
70    }
71
72    //Put back pointer in tsunami
73    tsunami->cchip = this;
74}
75
76Tick
77TsunamiCChip::read(PacketPtr pkt)
78{
79    DPRINTF(Tsunami, "read  va=%#x size=%d\n", pkt->getAddr(), pkt->getSize());
80
81    assert(pkt->result == Packet::Unknown);
82    assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
83
84    Addr regnum = (pkt->getAddr() - pioAddr) >> 6;
85    Addr daddr = (pkt->getAddr() - pioAddr);
86
87    pkt->allocate();
88    switch (pkt->getSize()) {
89
90      case sizeof(uint64_t):
91          pkt->set<uint64_t>(0);
92
93          if (daddr & TSDEV_CC_BDIMS)
94          {
95              pkt->set(dim[(daddr >> 4) & 0x3F]);
96              break;
97          }
98
99          if (daddr & TSDEV_CC_BDIRS)
100          {
101              pkt->set(dir[(daddr >> 4) & 0x3F]);
102              break;
103          }
104
105          switch(regnum) {
106              case TSDEV_CC_CSR:
107                  pkt->set(0x0);
108                  break;
109              case TSDEV_CC_MTR:
110                  panic("TSDEV_CC_MTR not implemeted\n");
111                   break;
112              case TSDEV_CC_MISC:
113                  pkt->set((ipint << 8) & 0xF | (itint << 4) & 0xF |
114                                     (pkt->req->getCpuNum() & 0x3));
115                  break;
116              case TSDEV_CC_AAR0:
117              case TSDEV_CC_AAR1:
118              case TSDEV_CC_AAR2:
119              case TSDEV_CC_AAR3:
120                  pkt->set(0);
121                  break;
122              case TSDEV_CC_DIM0:
123                  pkt->set(dim[0]);
124                  break;
125              case TSDEV_CC_DIM1:
126                  pkt->set(dim[1]);
127                  break;
128              case TSDEV_CC_DIM2:
129                  pkt->set(dim[2]);
130                  break;
131              case TSDEV_CC_DIM3:
132                  pkt->set(dim[3]);
133                  break;
134              case TSDEV_CC_DIR0:
135                  pkt->set(dir[0]);
136                  break;
137              case TSDEV_CC_DIR1:
138                  pkt->set(dir[1]);
139                  break;
140              case TSDEV_CC_DIR2:
141                  pkt->set(dir[2]);
142                  break;
143              case TSDEV_CC_DIR3:
144                  pkt->set(dir[3]);
145                  break;
146              case TSDEV_CC_DRIR:
147                  pkt->set(drir);
148                  break;
149              case TSDEV_CC_PRBEN:
150                  panic("TSDEV_CC_PRBEN not implemented\n");
151                  break;
152              case TSDEV_CC_IIC0:
153              case TSDEV_CC_IIC1:
154              case TSDEV_CC_IIC2:
155              case TSDEV_CC_IIC3:
156                  panic("TSDEV_CC_IICx not implemented\n");
157                  break;
158              case TSDEV_CC_MPR0:
159              case TSDEV_CC_MPR1:
160              case TSDEV_CC_MPR2:
161              case TSDEV_CC_MPR3:
162                  panic("TSDEV_CC_MPRx not implemented\n");
163                  break;
164              case TSDEV_CC_IPIR:
165                  pkt->set(ipint);
166                  break;
167              case TSDEV_CC_ITIR:
168                  pkt->set(itint);
169                  break;
170              default:
171                  panic("default in cchip read reached, accessing 0x%x\n");
172           } // uint64_t
173
174      break;
175      case sizeof(uint32_t):
176      case sizeof(uint16_t):
177      case sizeof(uint8_t):
178      default:
179        panic("invalid access size(?) for tsunami register!\n");
180    }
181    DPRINTF(Tsunami, "Tsunami CChip: read  regnum=%#x size=%d data=%lld\n",
182            regnum, pkt->getSize(), pkt->get<uint64_t>());
183
184    pkt->result = Packet::Success;
185    return pioDelay;
186}
187
188Tick
189TsunamiCChip::write(PacketPtr pkt)
190{
191    assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
192    Addr daddr = pkt->getAddr() - pioAddr;
193    Addr regnum = (pkt->getAddr() - pioAddr) >> 6 ;
194
195
196    assert(pkt->getSize() == sizeof(uint64_t));
197
198    DPRINTF(Tsunami, "write - addr=%#x value=%#x\n", pkt->getAddr(), pkt->get<uint64_t>());
199
200    bool supportedWrite = false;
201
202
203    if (daddr & TSDEV_CC_BDIMS)
204    {
205        int number = (daddr >> 4) & 0x3F;
206
207        uint64_t bitvector;
208        uint64_t olddim;
209        uint64_t olddir;
210
211        olddim = dim[number];
212        olddir = dir[number];
213        dim[number] = pkt->get<uint64_t>();
214        dir[number] = dim[number] & drir;
215        for(int x = 0; x < Tsunami::Max_CPUs; x++)
216        {
217            bitvector = ULL(1) << x;
218            // Figure out which bits have changed
219            if ((dim[number] & bitvector) != (olddim & bitvector))
220            {
221                // The bit is now set and it wasn't before (set)
222                if((dim[number] & bitvector) && (dir[number] & bitvector))
223                {
224                    tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x);
225                    DPRINTF(Tsunami, "dim write resulting in posting dir"
226                            " interrupt to cpu %d\n", number);
227                }
228                else if ((olddir & bitvector) &&
229                        !(dir[number] & bitvector))
230                {
231                    // The bit was set and now its now clear and
232                    // we were interrupting on that bit before
233                    tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x);
234                    DPRINTF(Tsunami, "dim write resulting in clear"
235                            " dir interrupt to cpu %d\n", number);
236
237                }
238
239
240            }
241        }
242    } else {
243        switch(regnum) {
244          case TSDEV_CC_CSR:
245              panic("TSDEV_CC_CSR write\n");
246          case TSDEV_CC_MTR:
247              panic("TSDEV_CC_MTR write not implemented\n");
248          case TSDEV_CC_MISC:
249            uint64_t ipreq;
250            ipreq = (pkt->get<uint64_t>() >> 12) & 0xF;
251            //If it is bit 12-15, this is an IPI post
252            if (ipreq) {
253                reqIPI(ipreq);
254                supportedWrite = true;
255            }
256
257            //If it is bit 8-11, this is an IPI clear
258            uint64_t ipintr;
259            ipintr = (pkt->get<uint64_t>() >> 8) & 0xF;
260            if (ipintr) {
261                clearIPI(ipintr);
262                supportedWrite = true;
263            }
264
265            //If it is the 4-7th bit, clear the RTC interrupt
266            uint64_t itintr;
267              itintr = (pkt->get<uint64_t>() >> 4) & 0xF;
268            if (itintr) {
269                  clearITI(itintr);
270                supportedWrite = true;
271            }
272
273              // ignore NXMs
274              if (pkt->get<uint64_t>() & 0x10000000)
275                  supportedWrite = true;
276
277            if(!supportedWrite)
278                  panic("TSDEV_CC_MISC write not implemented\n");
279
280            break;
281            case TSDEV_CC_AAR0:
282            case TSDEV_CC_AAR1:
283            case TSDEV_CC_AAR2:
284            case TSDEV_CC_AAR3:
285                panic("TSDEV_CC_AARx write not implemeted\n");
286            case TSDEV_CC_DIM0:
287            case TSDEV_CC_DIM1:
288            case TSDEV_CC_DIM2:
289            case TSDEV_CC_DIM3:
290                int number;
291                if(regnum == TSDEV_CC_DIM0)
292                    number = 0;
293                else if(regnum == TSDEV_CC_DIM1)
294                    number = 1;
295                else if(regnum == TSDEV_CC_DIM2)
296                    number = 2;
297                else
298                    number = 3;
299
300                uint64_t bitvector;
301                uint64_t olddim;
302                uint64_t olddir;
303
304                olddim = dim[number];
305                olddir = dir[number];
306                dim[number] = pkt->get<uint64_t>();
307                dir[number] = dim[number] & drir;
308                for(int x = 0; x < 64; x++)
309                {
310                    bitvector = ULL(1) << x;
311                    // Figure out which bits have changed
312                    if ((dim[number] & bitvector) != (olddim & bitvector))
313                    {
314                        // The bit is now set and it wasn't before (set)
315                        if((dim[number] & bitvector) && (dir[number] & bitvector))
316                        {
317                          tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x);
318                          DPRINTF(Tsunami, "posting dir interrupt to cpu 0\n");
319                        }
320                        else if ((olddir & bitvector) &&
321                                !(dir[number] & bitvector))
322                        {
323                            // The bit was set and now its now clear and
324                            // we were interrupting on that bit before
325                            tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x);
326                          DPRINTF(Tsunami, "dim write resulting in clear"
327                                    " dir interrupt to cpu %d\n",
328                                    x);
329
330                        }
331
332
333                    }
334                }
335                break;
336            case TSDEV_CC_DIR0:
337            case TSDEV_CC_DIR1:
338            case TSDEV_CC_DIR2:
339            case TSDEV_CC_DIR3:
340                panic("TSDEV_CC_DIR write not implemented\n");
341            case TSDEV_CC_DRIR:
342                panic("TSDEV_CC_DRIR write not implemented\n");
343            case TSDEV_CC_PRBEN:
344                panic("TSDEV_CC_PRBEN write not implemented\n");
345            case TSDEV_CC_IIC0:
346            case TSDEV_CC_IIC1:
347            case TSDEV_CC_IIC2:
348            case TSDEV_CC_IIC3:
349                panic("TSDEV_CC_IICx write not implemented\n");
350            case TSDEV_CC_MPR0:
351            case TSDEV_CC_MPR1:
352            case TSDEV_CC_MPR2:
353            case TSDEV_CC_MPR3:
354                panic("TSDEV_CC_MPRx write not implemented\n");
355            case TSDEV_CC_IPIR:
356                clearIPI(pkt->get<uint64_t>());
357                break;
358            case TSDEV_CC_ITIR:
359                clearITI(pkt->get<uint64_t>());
360                break;
361            case TSDEV_CC_IPIQ:
362                reqIPI(pkt->get<uint64_t>());
363                break;
364            default:
365              panic("default in cchip read reached, accessing 0x%x\n");
366        }  // swtich(regnum)
367    } // not BIG_TSUNAMI write
368    pkt->result = Packet::Success;
369    return pioDelay;
370}
371
372void
373TsunamiCChip::clearIPI(uint64_t ipintr)
374{
375    int numcpus = sys->threadContexts.size();
376    assert(numcpus <= Tsunami::Max_CPUs);
377
378    if (ipintr) {
379        for (int cpunum=0; cpunum < numcpus; cpunum++) {
380            // Check each cpu bit
381            uint64_t cpumask = ULL(1) << cpunum;
382            if (ipintr & cpumask) {
383                // Check if there is a pending ipi
384                if (ipint & cpumask) {
385                    ipint &= ~cpumask;
386                    tsunami->intrctrl->clear(cpunum, TheISA::INTLEVEL_IRQ3, 0);
387                    DPRINTF(IPI, "clear IPI IPI cpu=%d\n", cpunum);
388                }
389                else
390                    warn("clear IPI for CPU=%d, but NO IPI\n", cpunum);
391            }
392        }
393    }
394    else
395        panic("Big IPI Clear, but not processors indicated\n");
396}
397
398void
399TsunamiCChip::clearITI(uint64_t itintr)
400{
401    int numcpus = sys->threadContexts.size();
402    assert(numcpus <= Tsunami::Max_CPUs);
403
404    if (itintr) {
405        for (int i=0; i < numcpus; i++) {
406            uint64_t cpumask = ULL(1) << i;
407            if (itintr & cpumask & itint) {
408                tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ2, 0);
409                itint &= ~cpumask;
410                DPRINTF(Tsunami, "clearing rtc interrupt to cpu=%d\n", i);
411            }
412        }
413    }
414    else
415        panic("Big ITI Clear, but not processors indicated\n");
416}
417
418void
419TsunamiCChip::reqIPI(uint64_t ipreq)
420{
421    int numcpus = sys->threadContexts.size();
422    assert(numcpus <= Tsunami::Max_CPUs);
423
424    if (ipreq) {
425        for (int cpunum=0; cpunum < numcpus; cpunum++) {
426            // Check each cpu bit
427            uint64_t cpumask = ULL(1) << cpunum;
428            if (ipreq & cpumask) {
429                // Check if there is already an ipi (bits 8:11)
430                if (!(ipint & cpumask)) {
431                    ipint  |= cpumask;
432                    tsunami->intrctrl->post(cpunum, TheISA::INTLEVEL_IRQ3, 0);
433                    DPRINTF(IPI, "send IPI cpu=%d\n", cpunum);
434                }
435                else
436                    warn("post IPI for CPU=%d, but IPI already\n", cpunum);
437            }
438        }
439    }
440    else
441        panic("Big IPI Request, but not processors indicated\n");
442}
443
444
445void
446TsunamiCChip::postRTC()
447{
448    int size = sys->threadContexts.size();
449    assert(size <= Tsunami::Max_CPUs);
450
451    for (int i = 0; i < size; i++) {
452        uint64_t cpumask = ULL(1) << i;
453       if (!(cpumask & itint)) {
454           itint |= cpumask;
455           tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ2, 0);
456           DPRINTF(Tsunami, "Posting RTC interrupt to cpu=%d\n", i);
457       }
458    }
459
460}
461
462void
463TsunamiCChip::postDRIR(uint32_t interrupt)
464{
465    uint64_t bitvector = ULL(1) << interrupt;
466    uint64_t size = sys->threadContexts.size();
467    assert(size <= Tsunami::Max_CPUs);
468    drir |= bitvector;
469
470    for(int i=0; i < size; i++) {
471        dir[i] = dim[i] & drir;
472       if (dim[i] & bitvector) {
473              tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ1, interrupt);
474              DPRINTF(Tsunami, "posting dir interrupt to cpu %d,"
475                        "interrupt %d\n",i, interrupt);
476       }
477    }
478}
479
480void
481TsunamiCChip::clearDRIR(uint32_t interrupt)
482{
483    uint64_t bitvector = ULL(1) << interrupt;
484    uint64_t size = sys->threadContexts.size();
485    assert(size <= Tsunami::Max_CPUs);
486
487    if (drir & bitvector)
488    {
489        drir &= ~bitvector;
490        for(int i=0; i < size; i++) {
491           if (dir[i] & bitvector) {
492               tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ1, interrupt);
493               DPRINTF(Tsunami, "clearing dir interrupt to cpu %d,"
494                    "interrupt %d\n",i, interrupt);
495
496           }
497           dir[i] = dim[i] & drir;
498        }
499    }
500    else
501        DPRINTF(Tsunami, "Spurrious clear? interrupt %d\n", interrupt);
502}
503
504
505void
506TsunamiCChip::serialize(std::ostream &os)
507{
508    SERIALIZE_ARRAY(dim, Tsunami::Max_CPUs);
509    SERIALIZE_ARRAY(dir, Tsunami::Max_CPUs);
510    SERIALIZE_SCALAR(ipint);
511    SERIALIZE_SCALAR(itint);
512    SERIALIZE_SCALAR(drir);
513}
514
515void
516TsunamiCChip::unserialize(Checkpoint *cp, const std::string &section)
517{
518    UNSERIALIZE_ARRAY(dim, Tsunami::Max_CPUs);
519    UNSERIALIZE_ARRAY(dir, Tsunami::Max_CPUs);
520    UNSERIALIZE_SCALAR(ipint);
521    UNSERIALIZE_SCALAR(itint);
522    UNSERIALIZE_SCALAR(drir);
523}
524
525BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip)
526
527    Param<Addr> pio_addr;
528    Param<Tick> pio_latency;
529    SimObjectParam<Platform *> platform;
530    SimObjectParam<System *> system;
531    SimObjectParam<Tsunami *> tsunami;
532
533END_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip)
534
535BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiCChip)
536
537    INIT_PARAM(pio_addr, "Device Address"),
538    INIT_PARAM(pio_latency, "Programmed IO latency"),
539    INIT_PARAM(platform, "platform"),
540    INIT_PARAM(system, "system object"),
541    INIT_PARAM(tsunami, "Tsunami")
542
543END_INIT_SIM_OBJECT_PARAMS(TsunamiCChip)
544
545CREATE_SIM_OBJECT(TsunamiCChip)
546{
547    TsunamiCChip::Params *p = new TsunamiCChip::Params;
548    p->name = getInstanceName();
549    p->pio_addr = pio_addr;
550    p->pio_delay = pio_latency;
551    p->platform = platform;
552    p->system = system;
553    p->tsunami = tsunami;
554    return new TsunamiCChip(p);
555}
556
557REGISTER_SIM_OBJECT("TsunamiCChip", TsunamiCChip)
558