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