1/* 2 * Copyright (c) 2002-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; --- 227 unchanged lines hidden (view full) --- 236 237 // just change status to Idle... if status != Running, 238 // completeInst() will not initiate fetch of next instruction. 239 240 notIdleFraction--; 241 _status = Idle; 242} 243 |
244bool 245TimingSimpleCPU::handleReadPacket(PacketPtr pkt) 246{ 247 RequestPtr req = pkt->req; 248 if (req->isMmapedIpr()) { 249 Tick delay; 250 delay = TheISA::handleIprRead(thread->getTC(), pkt); 251 new IprEvent(pkt, this, nextCycle(curTick + delay)); 252 _status = DcacheWaitResponse; 253 dcache_pkt = NULL; 254 } else if (!dcachePort.sendTiming(pkt)) { 255 _status = DcacheRetry; 256 dcache_pkt = pkt; 257 } else { 258 _status = DcacheWaitResponse; 259 // memory system takes ownership of packet 260 dcache_pkt = NULL; 261 } 262 return dcache_pkt == NULL; 263} |
264 265template <class T> 266Fault 267TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) 268{ |
269 Fault fault; 270 const int asid = 0; 271 const int thread_id = 0; 272 const Addr pc = thread->readPC(); |
273 |
274 PacketPtr pkt; 275 RequestPtr req; |
276 |
277 int block_size = dcachePort.peerBlockSize(); 278 int data_size = sizeof(T); |
279 |
280 Addr second_addr = roundDown(addr + data_size - 1, block_size); |
281 |
282 if (second_addr > addr) { 283 Addr first_size = second_addr - addr; 284 Addr second_size = data_size - first_size; 285 // Make sure we'll only need two accesses. 286 assert(roundDown(second_addr + second_size - 1, block_size) == 287 second_addr); 288 289 /* 290 * Do the translations. If something isn't going to work, find out 291 * before we waste time setting up anything else. 292 */ 293 req = new Request(asid, addr, first_size, 294 flags, pc, _cpuId, thread_id); 295 fault = thread->translateDataReadReq(req); 296 if (fault != NoFault) { 297 delete req; 298 return fault; |
299 } |
300 Request *second_req = 301 new Request(asid, second_addr, second_size, 302 flags, pc, _cpuId, thread_id); 303 fault = thread->translateDataReadReq(second_req); 304 if (fault != NoFault) { 305 delete req; 306 delete second_req; 307 return fault; 308 } |
309 |
310 T * data_ptr = new T; 311 312 /* 313 * This is the big packet that will hold the data we've gotten so far, 314 * if any, and also act as the response we actually give to the 315 * instruction. 316 */ 317 Request *orig_req = 318 new Request(asid, addr, data_size, flags, pc, _cpuId, thread_id); 319 orig_req->setPhys(req->getPaddr(), data_size, flags); 320 PacketPtr big_pkt = 321 new Packet(orig_req, MemCmd::ReadResp, Packet::Broadcast); 322 big_pkt->dataDynamic<T>(data_ptr); 323 SplitMainSenderState * main_send_state = new SplitMainSenderState; 324 big_pkt->senderState = main_send_state; 325 main_send_state->outstanding = 2; 326 327 // This is the packet we'll process now. 328 pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast); 329 pkt->dataStatic<uint8_t>((uint8_t *)data_ptr); 330 pkt->senderState = new SplitFragmentSenderState(big_pkt, 0); 331 332 // This is the second half of the access we'll deal with later. 333 PacketPtr second_pkt = 334 new Packet(second_req, MemCmd::ReadReq, Packet::Broadcast); 335 second_pkt->dataStatic<uint8_t>((uint8_t *)data_ptr + first_size); 336 second_pkt->senderState = new SplitFragmentSenderState(big_pkt, 1); 337 if (!handleReadPacket(pkt)) { 338 main_send_state->fragments[1] = second_pkt; 339 } else { 340 handleReadPacket(second_pkt); 341 } |
342 } else { |
343 req = new Request(asid, addr, data_size, 344 flags, pc, _cpuId, thread_id); 345 346 // translate to physical address 347 Fault fault = thread->translateDataReadReq(req); 348 349 if (fault != NoFault) { 350 delete req; 351 return fault; 352 } 353 354 pkt = new Packet(req, 355 (req->isLocked() ? 356 MemCmd::LoadLockedReq : MemCmd::ReadReq), 357 Packet::Broadcast); 358 pkt->dataDynamic<T>(new T); 359 360 handleReadPacket(pkt); |
361 } 362 363 if (traceData) { 364 traceData->setData(data); |
365 traceData->setAddr(addr); |
366 } |
367 368 // This will need a new way to tell if it has a dcache attached. 369 if (req->isUncacheable()) 370 recordEvent("Uncached Read"); 371 372 return NoFault; |
373} 374 375Fault 376TimingSimpleCPU::translateDataReadAddr(Addr vaddr, Addr &paddr, 377 int size, unsigned flags) 378{ 379 Request *req = 380 new Request(0, vaddr, size, flags, thread->readPC(), _cpuId, 0); --- 56 unchanged lines hidden (view full) --- 437 438template<> 439Fault 440TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 441{ 442 return read(addr, (uint32_t&)data, flags); 443} 444 |
445bool 446TimingSimpleCPU::handleWritePacket() 447{ 448 RequestPtr req = dcache_pkt->req; 449 if (req->isMmapedIpr()) { 450 Tick delay; 451 delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt); 452 new IprEvent(dcache_pkt, this, nextCycle(curTick + delay)); 453 _status = DcacheWaitResponse; 454 dcache_pkt = NULL; 455 } else if (!dcachePort.sendTiming(dcache_pkt)) { 456 _status = DcacheRetry; 457 } else { 458 _status = DcacheWaitResponse; 459 // memory system takes ownership of packet 460 dcache_pkt = NULL; 461 } 462 return dcache_pkt == NULL; 463} |
464 465template <class T> 466Fault 467TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 468{ |
469 const int asid = 0; 470 const int thread_id = 0; 471 bool do_access = true; // flag to suppress cache access 472 const Addr pc = thread->readPC(); |
473 |
474 RequestPtr req; |
475 |
476 int block_size = dcachePort.peerBlockSize(); 477 int data_size = sizeof(T); |
478 |
479 Addr second_addr = roundDown(addr + data_size - 1, block_size); 480 481 if (second_addr > addr) { 482 Fault fault; 483 Addr first_size = second_addr - addr; 484 Addr second_size = data_size - first_size; 485 // Make sure we'll only need two accesses. 486 assert(roundDown(second_addr + second_size - 1, block_size) == 487 second_addr); 488 489 req = new Request(asid, addr, first_size, 490 flags, pc, _cpuId, thread_id); 491 fault = thread->translateDataWriteReq(req); 492 if (fault != NoFault) { 493 delete req; 494 return fault; 495 } 496 RequestPtr second_req = new Request(asid, second_addr, second_size, 497 flags, pc, _cpuId, thread_id); 498 fault = thread->translateDataWriteReq(second_req); 499 if (fault != NoFault) { 500 delete req; 501 delete second_req; 502 return fault; 503 } 504 505 if (req->isLocked() || req->isSwap() || 506 second_req->isLocked() || second_req->isSwap()) { 507 panic("LL/SCs and swaps can't be split."); 508 } 509 510 T * data_ptr = new T; 511 512 /* 513 * This is the big packet that will hold the data we've gotten so far, 514 * if any, and also act as the response we actually give to the 515 * instruction. 516 */ 517 RequestPtr orig_req = 518 new Request(asid, addr, data_size, flags, pc, _cpuId, thread_id); 519 orig_req->setPhys(req->getPaddr(), data_size, flags); 520 PacketPtr big_pkt = 521 new Packet(orig_req, MemCmd::WriteResp, Packet::Broadcast); 522 big_pkt->dataDynamic<T>(data_ptr); 523 big_pkt->set(data); 524 SplitMainSenderState * main_send_state = new SplitMainSenderState; 525 big_pkt->senderState = main_send_state; 526 main_send_state->outstanding = 2; 527 528 assert(dcache_pkt == NULL); 529 // This is the packet we'll process now. 530 dcache_pkt = new Packet(req, MemCmd::WriteReq, Packet::Broadcast); 531 dcache_pkt->dataStatic<uint8_t>((uint8_t *)data_ptr); 532 dcache_pkt->senderState = new SplitFragmentSenderState(big_pkt, 0); 533 534 // This is the second half of the access we'll deal with later. 535 PacketPtr second_pkt = 536 new Packet(second_req, MemCmd::WriteReq, Packet::Broadcast); 537 second_pkt->dataStatic<uint8_t>((uint8_t *)data_ptr + first_size); 538 second_pkt->senderState = new SplitFragmentSenderState(big_pkt, 1); 539 if (!handleWritePacket()) { 540 main_send_state->fragments[1] = second_pkt; 541 } else { 542 dcache_pkt = second_pkt; 543 handleWritePacket(); 544 } 545 } else { 546 req = new Request(asid, addr, data_size, flags, pc, _cpuId, thread_id); 547 548 // translate to physical address 549 Fault fault = thread->translateDataWriteReq(req); 550 if (fault != NoFault) { 551 delete req; 552 return fault; 553 } 554 |
555 MemCmd cmd = MemCmd::WriteReq; // default |
556 557 if (req->isLocked()) { 558 cmd = MemCmd::StoreCondReq; 559 do_access = TheISA::handleLockedWrite(thread, req); 560 } else if (req->isSwap()) { 561 cmd = MemCmd::SwapReq; 562 if (req->isCondSwap()) { 563 assert(res); 564 req->setExtraData(*res); 565 } 566 } 567 568 // Note: need to allocate dcache_pkt even if do_access is 569 // false, as it's used unconditionally to call completeAcc(). 570 assert(dcache_pkt == NULL); 571 dcache_pkt = new Packet(req, cmd, Packet::Broadcast); 572 dcache_pkt->allocate(); |
573 if (req->isMmapedIpr()) 574 dcache_pkt->set(htog(data)); 575 else 576 dcache_pkt->set(data); |
577 |
578 if (do_access) 579 handleWritePacket(); |
580 } 581 582 if (traceData) { |
583 traceData->setAddr(req->getVaddr()); |
584 traceData->setData(data); 585 } 586 |
587 // This will need a new way to tell if it's hooked up to a cache or not. 588 if (req->isUncacheable()) 589 recordEvent("Uncached Write"); 590 |
591 // If the write needs to have a fault on the access, consider calling 592 // changeStatus() and changing it to "bad addr write" or something. |
593 return NoFault; |
594} 595 596Fault 597TimingSimpleCPU::translateDataWriteAddr(Addr vaddr, Addr &paddr, 598 int size, unsigned flags) 599{ 600 Request *req = 601 new Request(0, vaddr, size, flags, thread->readPC(), _cpuId, 0); --- 272 unchanged lines hidden (view full) --- 874} 875 876void 877TimingSimpleCPU::completeDataAccess(PacketPtr pkt) 878{ 879 // received a response from the dcache: complete the load or store 880 // instruction 881 assert(!pkt->isError()); |
882 883 numCycles += tickToCycles(curTick - previousTick); 884 previousTick = curTick; 885 |
886 if (pkt->senderState) { 887 SplitFragmentSenderState * send_state = 888 dynamic_cast<SplitFragmentSenderState *>(pkt->senderState); 889 assert(send_state); 890 delete pkt->req; 891 delete pkt; 892 PacketPtr big_pkt = send_state->bigPkt; 893 delete send_state; 894 895 SplitMainSenderState * main_send_state = 896 dynamic_cast<SplitMainSenderState *>(big_pkt->senderState); 897 assert(main_send_state); 898 // Record the fact that this packet is no longer outstanding. 899 assert(main_send_state->outstanding != 0); 900 main_send_state->outstanding--; 901 902 if (main_send_state->outstanding) { 903 return; 904 } else { 905 delete main_send_state; 906 big_pkt->senderState = NULL; 907 pkt = big_pkt; 908 } 909 } 910 911 assert(_status == DcacheWaitResponse); 912 _status = Running; 913 |
914 Fault fault = curStaticInst->completeAcc(pkt, this, traceData); 915 916 // keep an instruction count 917 if (fault == NoFault) 918 countInst(); 919 else if (traceData) { 920 // If there was a fault, we shouldn't trace this instruction. 921 delete traceData; --- 44 unchanged lines hidden (view full) --- 966 967bool 968TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt) 969{ 970 if (pkt->isResponse() && !pkt->wasNacked()) { 971 // delay processing of returned data until next CPU clock edge 972 Tick next_tick = cpu->nextCycle(curTick); 973 |
974 if (next_tick == curTick) { |
975 cpu->completeDataAccess(pkt); |
976 } else { |
977 tickEvent.schedule(pkt, next_tick); |
978 } |
979 980 return true; 981 } 982 else if (pkt->wasNacked()) { 983 assert(cpu->_status == DcacheWaitResponse); 984 pkt->reinitNacked(); 985 if (!sendTiming(pkt)) { 986 cpu->_status = DcacheRetry; --- 13 unchanged lines hidden (view full) --- 1000void 1001TimingSimpleCPU::DcachePort::recvRetry() 1002{ 1003 // we shouldn't get a retry unless we have a packet that we're 1004 // waiting to transmit 1005 assert(cpu->dcache_pkt != NULL); 1006 assert(cpu->_status == DcacheRetry); 1007 PacketPtr tmp = cpu->dcache_pkt; |
1008 if (tmp->senderState) { 1009 // This is a packet from a split access. 1010 SplitFragmentSenderState * send_state = 1011 dynamic_cast<SplitFragmentSenderState *>(tmp->senderState); 1012 assert(send_state); 1013 PacketPtr big_pkt = send_state->bigPkt; 1014 1015 SplitMainSenderState * main_send_state = 1016 dynamic_cast<SplitMainSenderState *>(big_pkt->senderState); 1017 assert(main_send_state); 1018 1019 if (sendTiming(tmp)) { 1020 // If we were able to send without retrying, record that fact 1021 // and try sending the other fragment. 1022 send_state->clearFromParent(); 1023 int other_index = main_send_state->getPendingFragment(); 1024 if (other_index > 0) { 1025 tmp = main_send_state->fragments[other_index]; 1026 cpu->dcache_pkt = tmp; 1027 if ((big_pkt->isRead() && cpu->handleReadPacket(tmp)) || 1028 (big_pkt->isWrite() && cpu->handleWritePacket())) { 1029 main_send_state->fragments[other_index] = NULL; 1030 } 1031 } else { 1032 cpu->_status = DcacheWaitResponse; 1033 // memory system takes ownership of packet 1034 cpu->dcache_pkt = NULL; 1035 } 1036 } 1037 } else if (sendTiming(tmp)) { |
1038 cpu->_status = DcacheWaitResponse; 1039 // memory system takes ownership of packet 1040 cpu->dcache_pkt = NULL; 1041 } 1042} 1043 1044TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu, 1045 Tick t) --- 39 unchanged lines hidden --- |