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