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