tsunami_cchip.cc revision 2539
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 Addr regnum = (pkt.addr - pioAddr) >> 6 ; 199 200 201 uint64_t val = *(uint64_t *)pkt.data; 202 assert(pkt.size == sizeof(uint64_t)); 203 204 DPRINTF(Tsunami, "write - addr=%#x value=%#x\n", req->addr, val); 205 206 bool supportedWrite = false; 207 208 209 if (daddr & TSDEV_CC_BDIMS) 210 { 211 int number = (daddr >> 4) & 0x3F; 212 213 uint64_t bitvector; 214 uint64_t olddim; 215 uint64_t olddir; 216 217 olddim = dim[number]; 218 olddir = dir[number]; 219 dim[number] = val; 220 dir[number] = dim[number] & drir; 221 for(int x = 0; x < Tsunami::Max_CPUs; x++) 222 { 223 bitvector = ULL(1) << x; 224 // Figure out which bits have changed 225 if ((dim[number] & bitvector) != (olddim & bitvector)) 226 { 227 // The bit is now set and it wasn't before (set) 228 if((dim[number] & bitvector) && (dir[number] & bitvector)) 229 { 230 tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x); 231 DPRINTF(Tsunami, "dim write resulting in posting dir" 232 " interrupt to cpu %d\n", number); 233 } 234 else if ((olddir & bitvector) && 235 !(dir[number] & bitvector)) 236 { 237 // The bit was set and now its now clear and 238 // we were interrupting on that bit before 239 tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x); 240 DPRINTF(Tsunami, "dim write resulting in clear" 241 " dir interrupt to cpu %d\n", number); 242 243 } 244 245 246 } 247 } 248 } else { 249 switch(regnum) { 250 case TSDEV_CC_CSR: 251 panic("TSDEV_CC_CSR write\n"); 252 case TSDEV_CC_MTR: 253 panic("TSDEV_CC_MTR write not implemented\n"); 254 case TSDEV_CC_MISC: 255 uint64_t ipreq; 256 ipreq = (val >> 12) & 0xF; 257 //If it is bit 12-15, this is an IPI post 258 if (ipreq) { 259 reqIPI(ipreq); 260 supportedWrite = true; 261 } 262 263 //If it is bit 8-11, this is an IPI clear 264 uint64_t ipintr; 265 ipintr = (val >> 8) & 0xF; 266 if (ipintr) { 267 clearIPI(ipintr); 268 supportedWrite = true; 269 } 270 271 //If it is the 4-7th bit, clear the RTC interrupt 272 uint64_t itintr; 273 itintr = (val >> 4) & 0xF; 274 if (itintr) { 275 clearITI(itintr); 276 supportedWrite = true; 277 } 278 279 // ignore NXMs 280 if (val & 0x10000000) 281 supportedWrite = true; 282 283 if(!supportedWrite) 284 panic("TSDEV_CC_MISC write not implemented\n"); 285 286 287 case TSDEV_CC_AAR0: 288 case TSDEV_CC_AAR1: 289 case TSDEV_CC_AAR2: 290 case TSDEV_CC_AAR3: 291 panic("TSDEV_CC_AARx write not implemeted\n"); 292 return NoFault; 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] = val; 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(val); 364 break; 365 case TSDEV_CC_ITIR: 366 clearITI(val); 367 break; 368 case TSDEV_CC_IPIQ: 369 reqIPI(val); 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.result = Success; 376 return pioDelay; 377} 378 379void 380TsunamiCChip::clearIPI(uint64_t ipintr) 381{ 382 int numcpus = tsunami->intrctrl->cpu->system->execContexts.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 405void 406TsunamiCChip::clearITI(uint64_t itintr) 407{ 408 int numcpus = tsunami->intrctrl->cpu->system->execContexts.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 425void 426TsunamiCChip::reqIPI(uint64_t ipreq) 427{ 428 int numcpus = tsunami->intrctrl->cpu->system->execContexts.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 452void 453TsunamiCChip::postRTC() 454{ 455 int size = tsunami->intrctrl->cpu->system->execContexts.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", i); 464 } 465 } 466 467} 468 469void 470TsunamiCChip::postDRIR(uint32_t interrupt) 471{ 472 uint64_t bitvector = ULL(1) << interrupt; 473 uint64_t size = tsunami->intrctrl->cpu->system->execContexts.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 487void 488TsunamiCChip::clearDRIR(uint32_t interrupt) 489{ 490 uint64_t bitvector = ULL(1) << interrupt; 491 uint64_t size = tsunami->intrctrl->cpu->system->execContexts.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 511Tick 512TsunamiCChip::cacheAccess(MemReqPtr &req) 513{ 514 return curTick + pioLatency; 515} 516 517 518void 519TsunamiCChip::serialize(std::ostream &os) 520{ 521 SERIALIZE_ARRAY(dim, Tsunami::Max_CPUs); 522 SERIALIZE_ARRAY(dir, Tsunami::Max_CPUs); 523 SERIALIZE_SCALAR(ipint); 524 SERIALIZE_SCALAR(itint); 525 SERIALIZE_SCALAR(drir); 526} 527 528void 529TsunamiCChip::unserialize(Checkpoint *cp, const std::string §ion) 530{ 531 UNSERIALIZE_ARRAY(dim, Tsunami::Max_CPUs); 532 UNSERIALIZE_ARRAY(dir, Tsunami::Max_CPUs); 533 UNSERIALIZE_SCALAR(ipint); 534 UNSERIALIZE_SCALAR(itint); 535 UNSERIALIZE_SCALAR(drir); 536} 537 538BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip) 539 540 Param<Addr> pio_addr; 541 Param<Tick> pio_latency; 542 SimObjectParam<Platform *> platform; 543 SimObjectParam<System *> system; 544 SimObjectParam<Tsunami *> tsunami; 545 546END_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip) 547 548BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiCChip) 549 550 INIT_PARAM(pio_addr, "Device Address"), 551 INIT_PARAM(pio_latency, "Programmed IO latency"), 552 INIT_PARAM(platform, "platform"), 553 INIT_PARAM(system, "system object"), 554 INIT_PARAM(tsunami, "Tsunami") 555 556END_INIT_SIM_OBJECT_PARAMS(TsunamiCChip) 557 558CREATE_SIM_OBJECT(TsunamiCChip) 559{ 560 TsunamiCChip::Params *p = new TsunamiCChip::Params; 561 p->name = getInstanceName(); 562 p->pio_addr = pio_addr; 563 p->pio_delay = pio_latency; 564 p->platform = platform; 565 p->system = system; 566 p->tsunami = tsunami; 567 return new TsunamiCChip(p); 568} 569 570REGISTER_SIM_OBJECT("TsunamiCChip", TsunamiCChip) 571