Major changes to how SimObjects are created and initialized. Almost all
[gem5.git] / src / dev / alpha / tsunami_cchip.cc
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 "params/TsunamiCChip.hh"
51 #include "sim/system.hh"
52
53 using namespace std;
54 //Should this be AlphaISA?
55 using namespace TheISA;
56
57 TsunamiCChip::TsunamiCChip(const 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
76 Tick
77 TsunamiCChip::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
188 Tick
189 TsunamiCChip::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
372 void
373 TsunamiCChip::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
398 void
399 TsunamiCChip::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
418 void
419 TsunamiCChip::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
445 void
446 TsunamiCChip::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
462 void
463 TsunamiCChip::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
480 void
481 TsunamiCChip::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
505 void
506 TsunamiCChip::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
515 void
516 TsunamiCChip::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
525 TsunamiCChip *
526 TsunamiCChipParams::create()
527 {
528 return new TsunamiCChip(this);
529 }