x86: changes to apic, keyboard
[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 "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?
57 using namespace TheISA;
58
59 TsunamiCChip::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
78 Tick
79 TsunamiCChip::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
195 Tick
196 TsunamiCChip::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
379 void
380 TsunamiCChip::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
405 void
406 TsunamiCChip::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
425 void
426 TsunamiCChip::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
452 void
453 TsunamiCChip::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
469 void
470 TsunamiCChip::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
487 void
488 TsunamiCChip::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
512 void
513 TsunamiCChip::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
522 void
523 TsunamiCChip::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
532 TsunamiCChip *
533 TsunamiCChipParams::create()
534 {
535 return new TsunamiCChip(this);
536 }