tsunami_cchip.cc revision 1290
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), 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->clockRatio; 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 case sizeof(uint16_t): 177 case sizeof(uint8_t): 178 default: 179 panic("invalid access size(?) for tsunami register!\n"); 180 } 181 DPRINTFN("Tsunami CChip ERROR: read regnum=%#x size=%d\n", regnum, req->size); 182 183 return No_Fault; 184} 185 186Fault 187TsunamiCChip::write(MemReqPtr &req, const uint8_t *data) 188{ 189 DPRINTF(Tsunami, "write - va=%#x value=%#x size=%d \n", 190 req->vaddr, *(uint64_t*)data, req->size); 191 192 Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); 193 Addr regnum = (req->paddr - (addr & EV5::PAddrImplMask)) >> 6; 194 195 bool supportedWrite = false; 196 197 switch (req->size) { 198 199 case sizeof(uint64_t): 200 if (daddr & TSDEV_CC_BDIMS) 201 { 202 int number = (daddr >> 4) & 0x3F; 203 204 uint64_t bitvector; 205 uint64_t olddim; 206 uint64_t olddir; 207 208 olddim = dim[number]; 209 olddir = dir[number]; 210 dim[number] = *(uint64_t*)data; 211 dir[number] = dim[number] & drir; 212 for(int x = 0; x < Tsunami::Max_CPUs; x++) 213 { 214 bitvector = ULL(1) << x; 215 // Figure out which bits have changed 216 if ((dim[number] & bitvector) != (olddim & bitvector)) 217 { 218 // The bit is now set and it wasn't before (set) 219 if((dim[number] & bitvector) && (dir[number] & bitvector)) 220 { 221 tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x); 222 DPRINTF(Tsunami, "dim write resulting in posting dir" 223 " interrupt to cpu %d\n", number); 224 } 225 else if ((olddir & bitvector) && 226 !(dir[number] & bitvector)) 227 { 228 // The bit was set and now its now clear and 229 // we were interrupting on that bit before 230 tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x); 231 DPRINTF(Tsunami, "dim write resulting in clear" 232 " dir interrupt to cpu %d\n", number); 233 234 } 235 236 237 } 238 } 239 return No_Fault; 240 } 241 242 switch(regnum) { 243 case TSDEV_CC_CSR: 244 panic("TSDEV_CC_CSR write\n"); 245 return No_Fault; 246 case TSDEV_CC_MTR: 247 panic("TSDEV_CC_MTR write not implemented\n"); 248 return No_Fault; 249 case TSDEV_CC_MISC: 250 uint64_t ipreq; 251 ipreq = (*(uint64_t*)data >> 12) & 0xF; 252 //If it is bit 12-15, this is an IPI post 253 if (ipreq) { 254 reqIPI(ipreq); 255 supportedWrite = true; 256 } 257 258 //If it is bit 8-11, this is an IPI clear 259 uint64_t ipintr; 260 ipintr = (*(uint64_t*)data >> 8) & 0xF; 261 if (ipintr) { 262 clearIPI(ipintr); 263 supportedWrite = true; 264 } 265 266 //If it is the 4-7th bit, clear the RTC interrupt 267 uint64_t itintr; 268 itintr = (*(uint64_t*)data >> 4) & 0xF; 269 if (itintr) { 270 clearITI(itintr); 271 supportedWrite = true; 272 } 273 274 // ignore NXMs 275 if (*(uint64_t*)data & 0x10000000) 276 supportedWrite = true; 277 278 if(!supportedWrite) 279 panic("TSDEV_CC_MISC write not implemented\n"); 280 281 return No_Fault; 282 case TSDEV_CC_AAR0: 283 case TSDEV_CC_AAR1: 284 case TSDEV_CC_AAR2: 285 case TSDEV_CC_AAR3: 286 panic("TSDEV_CC_AARx write not implemeted\n"); 287 return No_Fault; 288 case TSDEV_CC_DIM0: 289 case TSDEV_CC_DIM1: 290 case TSDEV_CC_DIM2: 291 case TSDEV_CC_DIM3: 292 int number; 293 if(regnum == TSDEV_CC_DIM0) 294 number = 0; 295 else if(regnum == TSDEV_CC_DIM1) 296 number = 1; 297 else if(regnum == TSDEV_CC_DIM2) 298 number = 2; 299 else 300 number = 3; 301 302 uint64_t bitvector; 303 uint64_t olddim; 304 uint64_t olddir; 305 306 olddim = dim[number]; 307 olddir = dir[number]; 308 dim[number] = *(uint64_t*)data; 309 dir[number] = dim[number] & drir; 310 for(int x = 0; x < 64; x++) 311 { 312 bitvector = ULL(1) << x; 313 // Figure out which bits have changed 314 if ((dim[number] & bitvector) != (olddim & bitvector)) 315 { 316 // The bit is now set and it wasn't before (set) 317 if((dim[number] & bitvector) && (dir[number] & bitvector)) 318 { 319 tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x); 320 DPRINTF(Tsunami, "posting dir interrupt to cpu 0\n"); 321 } 322 else if ((olddir & bitvector) && 323 !(dir[number] & bitvector)) 324 { 325 // The bit was set and now its now clear and 326 // we were interrupting on that bit before 327 tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x); 328 DPRINTF(Tsunami, "dim write resulting in clear" 329 " dir interrupt to cpu %d\n", 330 x); 331 332 } 333 334 335 } 336 } 337 return No_Fault; 338 case TSDEV_CC_DIR0: 339 case TSDEV_CC_DIR1: 340 case TSDEV_CC_DIR2: 341 case TSDEV_CC_DIR3: 342 panic("TSDEV_CC_DIR write not implemented\n"); 343 case TSDEV_CC_DRIR: 344 panic("TSDEV_CC_DRIR write not implemented\n"); 345 case TSDEV_CC_PRBEN: 346 panic("TSDEV_CC_PRBEN write not implemented\n"); 347 case TSDEV_CC_IIC0: 348 case TSDEV_CC_IIC1: 349 case TSDEV_CC_IIC2: 350 case TSDEV_CC_IIC3: 351 panic("TSDEV_CC_IICx write not implemented\n"); 352 case TSDEV_CC_MPR0: 353 case TSDEV_CC_MPR1: 354 case TSDEV_CC_MPR2: 355 case TSDEV_CC_MPR3: 356 panic("TSDEV_CC_MPRx write not implemented\n"); 357 case TSDEV_CC_IPIR: 358 clearIPI(*(uint64_t*)data); 359 return No_Fault; 360 case TSDEV_CC_ITIR: 361 clearITI(*(uint64_t*)data); 362 return No_Fault; 363 case TSDEV_CC_IPIQ: 364 reqIPI(*(uint64_t*)data); 365 return No_Fault; 366 default: 367 panic("default in cchip read reached, accessing 0x%x\n"); 368 } 369 370 break; 371 case sizeof(uint32_t): 372 case sizeof(uint16_t): 373 case sizeof(uint8_t): 374 default: 375 panic("invalid access size(?) for tsunami register!\n"); 376 } 377 378 DPRINTFN("Tsunami ERROR: write daddr=%#x size=%d\n", daddr, req->size); 379 380 return No_Fault; 381} 382 383void 384TsunamiCChip::clearIPI(uint64_t ipintr) 385{ 386 int numcpus = tsunami->intrctrl->cpu->system->execContexts.size(); 387 assert(numcpus <= Tsunami::Max_CPUs); 388 389 if (ipintr) { 390 for (int cpunum=0; cpunum < numcpus; cpunum++) { 391 // Check each cpu bit 392 uint64_t cpumask = ULL(1) << cpunum; 393 if (ipintr & cpumask) { 394 // Check if there is a pending ipi 395 if (ipint & cpumask) { 396 ipint &= ~cpumask; 397 tsunami->intrctrl->clear(cpunum, TheISA::INTLEVEL_IRQ3, 0); 398 DPRINTF(IPI, "clear IPI IPI cpu=%d\n", cpunum); 399 } 400 else 401 warn("clear IPI for CPU=%d, but NO IPI\n", cpunum); 402 } 403 } 404 } 405 else 406 panic("Big IPI Clear, but not processors indicated\n"); 407} 408 409void 410TsunamiCChip::clearITI(uint64_t itintr) 411{ 412 int numcpus = tsunami->intrctrl->cpu->system->execContexts.size(); 413 assert(numcpus <= Tsunami::Max_CPUs); 414 415 if (itintr) { 416 for (int i=0; i < numcpus; i++) { 417 uint64_t cpumask = ULL(1) << i; 418 if (itintr & cpumask & itint) { 419 tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ2, 0); 420 itint &= ~cpumask; 421 DPRINTF(Tsunami, "clearing rtc interrupt to cpu=%d\n", i); 422 } 423 } 424 } 425 else 426 panic("Big ITI Clear, but not processors indicated\n"); 427} 428 429void 430TsunamiCChip::reqIPI(uint64_t ipreq) 431{ 432 int numcpus = tsunami->intrctrl->cpu->system->execContexts.size(); 433 assert(numcpus <= Tsunami::Max_CPUs); 434 435 if (ipreq) { 436 for (int cpunum=0; cpunum < numcpus; cpunum++) { 437 // Check each cpu bit 438 uint64_t cpumask = ULL(1) << cpunum; 439 if (ipreq & cpumask) { 440 // Check if there is already an ipi (bits 8:11) 441 if (!(ipint & cpumask)) { 442 ipint |= cpumask; 443 tsunami->intrctrl->post(cpunum, TheISA::INTLEVEL_IRQ3, 0); 444 DPRINTF(IPI, "send IPI cpu=%d\n", cpunum); 445 } 446 else 447 warn("post IPI for CPU=%d, but IPI already\n", cpunum); 448 } 449 } 450 } 451 else 452 panic("Big IPI Request, but not processors indicated\n"); 453} 454 455 456void 457TsunamiCChip::postRTC() 458{ 459 int size = tsunami->intrctrl->cpu->system->execContexts.size(); 460 assert(size <= Tsunami::Max_CPUs); 461 462 for (int i = 0; i < size; i++) { 463 uint64_t cpumask = ULL(1) << i; 464 if (!(cpumask & itint)) { 465 itint |= cpumask; 466 tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ2, 0); 467 DPRINTF(Tsunami, "Posting RTC interrupt to cpu=%d", i); 468 } 469 } 470 471} 472 473void 474TsunamiCChip::postDRIR(uint32_t interrupt) 475{ 476 uint64_t bitvector = ULL(1) << interrupt; 477 uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size(); 478 assert(size <= Tsunami::Max_CPUs); 479 drir |= bitvector; 480 481 for(int i=0; i < size; i++) { 482 dir[i] = dim[i] & drir; 483 if (dim[i] & bitvector) { 484 tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ1, interrupt); 485 DPRINTF(Tsunami, "posting dir interrupt to cpu %d," 486 "interrupt %d\n",i, interrupt); 487 } 488 } 489} 490 491void 492TsunamiCChip::clearDRIR(uint32_t interrupt) 493{ 494 uint64_t bitvector = ULL(1) << interrupt; 495 uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size(); 496 assert(size <= Tsunami::Max_CPUs); 497 498 if (drir & bitvector) 499 { 500 drir &= ~bitvector; 501 for(int i=0; i < size; i++) { 502 if (dir[i] & bitvector) { 503 tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ1, interrupt); 504 DPRINTF(Tsunami, "clearing dir interrupt to cpu %d," 505 "interrupt %d\n",i, interrupt); 506 507 } 508 dir[i] = dim[i] & drir; 509 } 510 } 511 else 512 DPRINTF(Tsunami, "Spurrious clear? interrupt %d\n", interrupt); 513} 514 515Tick 516TsunamiCChip::cacheAccess(MemReqPtr &req) 517{ 518 return curTick + pioLatency; 519} 520 521 522void 523TsunamiCChip::serialize(std::ostream &os) 524{ 525 SERIALIZE_ARRAY(dim, Tsunami::Max_CPUs); 526 SERIALIZE_ARRAY(dir, Tsunami::Max_CPUs); 527 SERIALIZE_SCALAR(ipint); 528 SERIALIZE_SCALAR(itint); 529 SERIALIZE_SCALAR(drir); 530} 531 532void 533TsunamiCChip::unserialize(Checkpoint *cp, const std::string §ion) 534{ 535 UNSERIALIZE_ARRAY(dim, Tsunami::Max_CPUs); 536 UNSERIALIZE_ARRAY(dir, Tsunami::Max_CPUs); 537 UNSERIALIZE_SCALAR(ipint); 538 UNSERIALIZE_SCALAR(itint); 539 UNSERIALIZE_SCALAR(drir); 540} 541 542BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip) 543 544 SimObjectParam<Tsunami *> tsunami; 545 SimObjectParam<MemoryController *> mmu; 546 Param<Addr> addr; 547 SimObjectParam<Bus*> io_bus; 548 Param<Tick> pio_latency; 549 SimObjectParam<HierParams *> hier; 550 551END_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip) 552 553BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiCChip) 554 555 INIT_PARAM(tsunami, "Tsunami"), 556 INIT_PARAM(mmu, "Memory Controller"), 557 INIT_PARAM(addr, "Device Address"), 558 INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to", NULL), 559 INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), 560 INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams) 561 562END_INIT_SIM_OBJECT_PARAMS(TsunamiCChip) 563 564CREATE_SIM_OBJECT(TsunamiCChip) 565{ 566 return new TsunamiCChip(getInstanceName(), tsunami, addr, mmu, hier, 567 io_bus, pio_latency); 568} 569 570REGISTER_SIM_OBJECT("TsunamiCChip", TsunamiCChip) 571