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; 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 * Authors: Steve Reinhardt 29 */ 30 31#include "arch/locked_mem.hh" 32#include "arch/mmaped_ipr.hh" 33#include "arch/utility.hh" 34#include "base/bigint.hh" 35#include "cpu/exetrace.hh" 36#include "cpu/simple/timing.hh" 37#include "mem/packet.hh" 38#include "mem/packet_access.hh" 39#include "params/TimingSimpleCPU.hh" 40#include "sim/system.hh" 41 42using namespace std; 43using namespace TheISA; 44 45Port * 46TimingSimpleCPU::getPort(const std::string &if_name, int idx) 47{ 48 if (if_name == "dcache_port") 49 return &dcachePort; 50 else if (if_name == "icache_port") 51 return &icachePort; 52 else 53 panic("No Such Port\n"); 54} 55 56void 57TimingSimpleCPU::init() 58{ 59 BaseCPU::init(); 60 cpuId = tc->readCpuId(); 61#if FULL_SYSTEM 62 for (int i = 0; i < threadContexts.size(); ++i) { 63 ThreadContext *tc = threadContexts[i]; 64 65 // initialize CPU, including PC 66 TheISA::initCPU(tc, cpuId); 67 } 68#endif 69} 70 71Tick 72TimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt) 73{ 74 panic("TimingSimpleCPU doesn't expect recvAtomic callback!"); 75 return curTick; 76} 77 78void 79TimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt) 80{ 81 //No internal storage to update, jusst return 82 return; 83} 84 85void 86TimingSimpleCPU::CpuPort::recvStatusChange(Status status) 87{ 88 if (status == RangeChange) { 89 if (!snoopRangeSent) { 90 snoopRangeSent = true; 91 sendStatusChange(Port::RangeChange); 92 } 93 return; 94 } 95 96 panic("TimingSimpleCPU doesn't expect recvStatusChange callback!"); 97} 98 99 100void 101TimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t) 102{ 103 pkt = _pkt; 104 cpu->schedule(this, t); 105} 106 107TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p) 108 : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock) 109{ 110 _status = Idle; 111 112 icachePort.snoopRangeSent = false; 113 dcachePort.snoopRangeSent = false; 114 115 ifetch_pkt = dcache_pkt = NULL; 116 drainEvent = NULL; 117 fetchEvent = NULL; 118 previousTick = 0; 119 changeState(SimObject::Running); 120} 121 122 123TimingSimpleCPU::~TimingSimpleCPU() 124{ 125} 126 127void 128TimingSimpleCPU::serialize(ostream &os) 129{ 130 SimObject::State so_state = SimObject::getState(); 131 SERIALIZE_ENUM(so_state); 132 BaseSimpleCPU::serialize(os); 133} 134 135void 136TimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 137{ 138 SimObject::State so_state; 139 UNSERIALIZE_ENUM(so_state); 140 BaseSimpleCPU::unserialize(cp, section); 141} 142 143unsigned int 144TimingSimpleCPU::drain(Event *drain_event) 145{ 146 // TimingSimpleCPU is ready to drain if it's not waiting for 147 // an access to complete. 148 if (_status == Idle || _status == Running || _status == SwitchedOut) { 149 changeState(SimObject::Drained); 150 return 0; 151 } else { 152 changeState(SimObject::Draining); 153 drainEvent = drain_event; 154 return 1; 155 } 156} 157 158void 159TimingSimpleCPU::resume() 160{ 161 DPRINTF(SimpleCPU, "Resume\n"); 162 if (_status != SwitchedOut && _status != Idle) { 163 assert(system->getMemoryMode() == Enums::timing); 164 165 // Delete the old event if it existed. 166 if (fetchEvent) { 167 if (fetchEvent->scheduled()) 168 deschedule(fetchEvent); 169 170 delete fetchEvent; 171 } 172 173 fetchEvent = new FetchEvent(this, nextCycle()); 174 } 175 176 changeState(SimObject::Running); 177} 178 179void 180TimingSimpleCPU::switchOut() 181{ 182 assert(_status == Running || _status == Idle); 183 _status = SwitchedOut; 184 numCycles += tickToCycles(curTick - previousTick); 185 186 // If we've been scheduled to resume but are then told to switch out, 187 // we'll need to cancel it. 188 if (fetchEvent && fetchEvent->scheduled()) 189 deschedule(fetchEvent); 190} 191 192 193void 194TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 195{ 196 BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort); 197 198 // if any of this CPU's ThreadContexts are active, mark the CPU as 199 // running and schedule its tick event. 200 for (int i = 0; i < threadContexts.size(); ++i) { 201 ThreadContext *tc = threadContexts[i]; 202 if (tc->status() == ThreadContext::Active && _status != Running) { 203 _status = Running; 204 break; 205 } 206 } 207 208 if (_status != Running) { 209 _status = Idle; 210 } 211 assert(threadContexts.size() == 1); 212 cpuId = tc->readCpuId(); 213 previousTick = curTick; 214} 215 216 217void 218TimingSimpleCPU::activateContext(int thread_num, int delay) 219{ 220 DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay); 221 222 assert(thread_num == 0); 223 assert(thread); 224 225 assert(_status == Idle); 226 227 notIdleFraction++; 228 _status = Running; 229 230 // kick things off by initiating the fetch of the next instruction 231 fetchEvent = new FetchEvent(this); 232 schedule(fetchEvent, nextCycle(curTick + ticks(delay))); 233} 234 235 236void 237TimingSimpleCPU::suspendContext(int thread_num) 238{ 239 DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num); 240 241 assert(thread_num == 0); 242 assert(thread); 243 244 assert(_status == Running); 245 246 // just change status to Idle... if status != Running, 247 // completeInst() will not initiate fetch of next instruction. 248 249 notIdleFraction--; 250 _status = Idle; 251} 252 253 254template <class T> 255Fault 256TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) 257{ 258 Request *req = 259 new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), 260 cpuId, /* thread ID */ 0); 261 262 if (traceData) { 263 traceData->setAddr(req->getVaddr()); 264 } 265 266 // translate to physical address 267 Fault fault = thread->translateDataReadReq(req); 268 269 // Now do the access. 270 if (fault == NoFault) { 271 PacketPtr pkt = 272 new Packet(req, 273 (req->isLocked() ? 274 MemCmd::LoadLockedReq : MemCmd::ReadReq), 275 Packet::Broadcast); 276 pkt->dataDynamic<T>(new T); 277 278 if (req->isMmapedIpr()) { 279 Tick delay; 280 delay = TheISA::handleIprRead(thread->getTC(), pkt); 281 new IprEvent(pkt, this, nextCycle(curTick + delay)); 282 _status = DcacheWaitResponse; 283 dcache_pkt = NULL; 284 } else if (!dcachePort.sendTiming(pkt)) { 285 _status = DcacheRetry; 286 dcache_pkt = pkt; 287 } else { 288 _status = DcacheWaitResponse; 289 // memory system takes ownership of packet 290 dcache_pkt = NULL; 291 } 292 293 // This will need a new way to tell if it has a dcache attached. 294 if (req->isUncacheable()) 295 recordEvent("Uncached Read"); 296 } else { 297 delete req; 298 } 299 300 if (traceData) { 301 traceData->setData(data); 302 } 303 return fault; 304} 305 306Fault 307TimingSimpleCPU::translateDataReadAddr(Addr vaddr, Addr &paddr, 308 int size, unsigned flags) 309{ 310 Request *req = 311 new Request(0, vaddr, size, flags, thread->readPC(), cpuId, 0); 312 313 if (traceData) { 314 traceData->setAddr(vaddr); 315 } 316 317 Fault fault = thread->translateDataWriteReq(req); 318 319 if (fault == NoFault) 320 paddr = req->getPaddr(); 321 322 delete req; 323 return fault; 324} 325 326#ifndef DOXYGEN_SHOULD_SKIP_THIS 327 328template 329Fault 330TimingSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags); 331 332template 333Fault 334TimingSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags); 335 336template 337Fault 338TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 339 340template 341Fault 342TimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 343 344template 345Fault 346TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 347 348template 349Fault 350TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 351 352#endif //DOXYGEN_SHOULD_SKIP_THIS 353 354template<> 355Fault 356TimingSimpleCPU::read(Addr addr, double &data, unsigned flags) 357{ 358 return read(addr, *(uint64_t*)&data, flags); 359} 360 361template<> 362Fault 363TimingSimpleCPU::read(Addr addr, float &data, unsigned flags) 364{ 365 return read(addr, *(uint32_t*)&data, flags); 366} 367 368 369template<> 370Fault 371TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 372{ 373 return read(addr, (uint32_t&)data, flags); 374} 375 376 377template <class T> 378Fault 379TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 380{ 381 Request *req = 382 new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), 383 cpuId, /* thread ID */ 0); 384 385 if (traceData) { 386 traceData->setAddr(req->getVaddr()); 387 } 388 389 // translate to physical address 390 Fault fault = thread->translateDataWriteReq(req); 391 392 // Now do the access. 393 if (fault == NoFault) { 394 MemCmd cmd = MemCmd::WriteReq; // default 395 bool do_access = true; // flag to suppress cache access 396 397 if (req->isLocked()) { 398 cmd = MemCmd::StoreCondReq; 399 do_access = TheISA::handleLockedWrite(thread, req); 400 } else if (req->isSwap()) { 401 cmd = MemCmd::SwapReq; 402 if (req->isCondSwap()) { 403 assert(res); 404 req->setExtraData(*res); 405 } 406 } 407 408 // Note: need to allocate dcache_pkt even if do_access is 409 // false, as it's used unconditionally to call completeAcc(). 410 assert(dcache_pkt == NULL); 411 dcache_pkt = new Packet(req, cmd, Packet::Broadcast); 412 dcache_pkt->allocate(); 413 dcache_pkt->set(data); 414 415 if (do_access) { 416 if (req->isMmapedIpr()) { 417 Tick delay; 418 dcache_pkt->set(htog(data)); 419 delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt); 420 new IprEvent(dcache_pkt, this, nextCycle(curTick + delay)); 421 _status = DcacheWaitResponse; 422 dcache_pkt = NULL; 423 } else if (!dcachePort.sendTiming(dcache_pkt)) { 424 _status = DcacheRetry; 425 } else { 426 _status = DcacheWaitResponse; 427 // memory system takes ownership of packet 428 dcache_pkt = NULL; 429 } 430 } 431 // This will need a new way to tell if it's hooked up to a cache or not. 432 if (req->isUncacheable()) 433 recordEvent("Uncached Write"); 434 } else { 435 delete req; 436 } 437 438 if (traceData) { 439 traceData->setData(data); 440 } 441 442 // If the write needs to have a fault on the access, consider calling 443 // changeStatus() and changing it to "bad addr write" or something. 444 return fault; 445} 446 447Fault 448TimingSimpleCPU::translateDataWriteAddr(Addr vaddr, Addr &paddr, 449 int size, unsigned flags) 450{ 451 Request *req = 452 new Request(0, vaddr, size, flags, thread->readPC(), cpuId, 0); 453 454 if (traceData) { 455 traceData->setAddr(vaddr); 456 } 457 458 Fault fault = thread->translateDataWriteReq(req); 459 460 if (fault == NoFault) 461 paddr = req->getPaddr(); 462 463 delete req; 464 return fault; 465} 466 467 468#ifndef DOXYGEN_SHOULD_SKIP_THIS 469template 470Fault 471TimingSimpleCPU::write(Twin32_t data, Addr addr, 472 unsigned flags, uint64_t *res); 473 474template 475Fault 476TimingSimpleCPU::write(Twin64_t data, Addr addr, 477 unsigned flags, uint64_t *res); 478 479template 480Fault 481TimingSimpleCPU::write(uint64_t data, Addr addr, 482 unsigned flags, uint64_t *res); 483 484template 485Fault 486TimingSimpleCPU::write(uint32_t data, Addr addr, 487 unsigned flags, uint64_t *res); 488 489template 490Fault 491TimingSimpleCPU::write(uint16_t data, Addr addr, 492 unsigned flags, uint64_t *res); 493 494template 495Fault 496TimingSimpleCPU::write(uint8_t data, Addr addr, 497 unsigned flags, uint64_t *res); 498 499#endif //DOXYGEN_SHOULD_SKIP_THIS 500 501template<> 502Fault 503TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 504{ 505 return write(*(uint64_t*)&data, addr, flags, res); 506} 507 508template<> 509Fault 510TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 511{ 512 return write(*(uint32_t*)&data, addr, flags, res); 513} 514 515 516template<> 517Fault 518TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 519{ 520 return write((uint32_t)data, addr, flags, res); 521} 522 523 524void 525TimingSimpleCPU::fetch() 526{ 527 DPRINTF(SimpleCPU, "Fetch\n"); 528 529 if (!curStaticInst || !curStaticInst->isDelayedCommit()) 530 checkForInterrupts(); 531 532 checkPcEventQueue(); 533
| 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; 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 * Authors: Steve Reinhardt 29 */ 30 31#include "arch/locked_mem.hh" 32#include "arch/mmaped_ipr.hh" 33#include "arch/utility.hh" 34#include "base/bigint.hh" 35#include "cpu/exetrace.hh" 36#include "cpu/simple/timing.hh" 37#include "mem/packet.hh" 38#include "mem/packet_access.hh" 39#include "params/TimingSimpleCPU.hh" 40#include "sim/system.hh" 41 42using namespace std; 43using namespace TheISA; 44 45Port * 46TimingSimpleCPU::getPort(const std::string &if_name, int idx) 47{ 48 if (if_name == "dcache_port") 49 return &dcachePort; 50 else if (if_name == "icache_port") 51 return &icachePort; 52 else 53 panic("No Such Port\n"); 54} 55 56void 57TimingSimpleCPU::init() 58{ 59 BaseCPU::init(); 60 cpuId = tc->readCpuId(); 61#if FULL_SYSTEM 62 for (int i = 0; i < threadContexts.size(); ++i) { 63 ThreadContext *tc = threadContexts[i]; 64 65 // initialize CPU, including PC 66 TheISA::initCPU(tc, cpuId); 67 } 68#endif 69} 70 71Tick 72TimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt) 73{ 74 panic("TimingSimpleCPU doesn't expect recvAtomic callback!"); 75 return curTick; 76} 77 78void 79TimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt) 80{ 81 //No internal storage to update, jusst return 82 return; 83} 84 85void 86TimingSimpleCPU::CpuPort::recvStatusChange(Status status) 87{ 88 if (status == RangeChange) { 89 if (!snoopRangeSent) { 90 snoopRangeSent = true; 91 sendStatusChange(Port::RangeChange); 92 } 93 return; 94 } 95 96 panic("TimingSimpleCPU doesn't expect recvStatusChange callback!"); 97} 98 99 100void 101TimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t) 102{ 103 pkt = _pkt; 104 cpu->schedule(this, t); 105} 106 107TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p) 108 : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock) 109{ 110 _status = Idle; 111 112 icachePort.snoopRangeSent = false; 113 dcachePort.snoopRangeSent = false; 114 115 ifetch_pkt = dcache_pkt = NULL; 116 drainEvent = NULL; 117 fetchEvent = NULL; 118 previousTick = 0; 119 changeState(SimObject::Running); 120} 121 122 123TimingSimpleCPU::~TimingSimpleCPU() 124{ 125} 126 127void 128TimingSimpleCPU::serialize(ostream &os) 129{ 130 SimObject::State so_state = SimObject::getState(); 131 SERIALIZE_ENUM(so_state); 132 BaseSimpleCPU::serialize(os); 133} 134 135void 136TimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 137{ 138 SimObject::State so_state; 139 UNSERIALIZE_ENUM(so_state); 140 BaseSimpleCPU::unserialize(cp, section); 141} 142 143unsigned int 144TimingSimpleCPU::drain(Event *drain_event) 145{ 146 // TimingSimpleCPU is ready to drain if it's not waiting for 147 // an access to complete. 148 if (_status == Idle || _status == Running || _status == SwitchedOut) { 149 changeState(SimObject::Drained); 150 return 0; 151 } else { 152 changeState(SimObject::Draining); 153 drainEvent = drain_event; 154 return 1; 155 } 156} 157 158void 159TimingSimpleCPU::resume() 160{ 161 DPRINTF(SimpleCPU, "Resume\n"); 162 if (_status != SwitchedOut && _status != Idle) { 163 assert(system->getMemoryMode() == Enums::timing); 164 165 // Delete the old event if it existed. 166 if (fetchEvent) { 167 if (fetchEvent->scheduled()) 168 deschedule(fetchEvent); 169 170 delete fetchEvent; 171 } 172 173 fetchEvent = new FetchEvent(this, nextCycle()); 174 } 175 176 changeState(SimObject::Running); 177} 178 179void 180TimingSimpleCPU::switchOut() 181{ 182 assert(_status == Running || _status == Idle); 183 _status = SwitchedOut; 184 numCycles += tickToCycles(curTick - previousTick); 185 186 // If we've been scheduled to resume but are then told to switch out, 187 // we'll need to cancel it. 188 if (fetchEvent && fetchEvent->scheduled()) 189 deschedule(fetchEvent); 190} 191 192 193void 194TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 195{ 196 BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort); 197 198 // if any of this CPU's ThreadContexts are active, mark the CPU as 199 // running and schedule its tick event. 200 for (int i = 0; i < threadContexts.size(); ++i) { 201 ThreadContext *tc = threadContexts[i]; 202 if (tc->status() == ThreadContext::Active && _status != Running) { 203 _status = Running; 204 break; 205 } 206 } 207 208 if (_status != Running) { 209 _status = Idle; 210 } 211 assert(threadContexts.size() == 1); 212 cpuId = tc->readCpuId(); 213 previousTick = curTick; 214} 215 216 217void 218TimingSimpleCPU::activateContext(int thread_num, int delay) 219{ 220 DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay); 221 222 assert(thread_num == 0); 223 assert(thread); 224 225 assert(_status == Idle); 226 227 notIdleFraction++; 228 _status = Running; 229 230 // kick things off by initiating the fetch of the next instruction 231 fetchEvent = new FetchEvent(this); 232 schedule(fetchEvent, nextCycle(curTick + ticks(delay))); 233} 234 235 236void 237TimingSimpleCPU::suspendContext(int thread_num) 238{ 239 DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num); 240 241 assert(thread_num == 0); 242 assert(thread); 243 244 assert(_status == Running); 245 246 // just change status to Idle... if status != Running, 247 // completeInst() will not initiate fetch of next instruction. 248 249 notIdleFraction--; 250 _status = Idle; 251} 252 253 254template <class T> 255Fault 256TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) 257{ 258 Request *req = 259 new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), 260 cpuId, /* thread ID */ 0); 261 262 if (traceData) { 263 traceData->setAddr(req->getVaddr()); 264 } 265 266 // translate to physical address 267 Fault fault = thread->translateDataReadReq(req); 268 269 // Now do the access. 270 if (fault == NoFault) { 271 PacketPtr pkt = 272 new Packet(req, 273 (req->isLocked() ? 274 MemCmd::LoadLockedReq : MemCmd::ReadReq), 275 Packet::Broadcast); 276 pkt->dataDynamic<T>(new T); 277 278 if (req->isMmapedIpr()) { 279 Tick delay; 280 delay = TheISA::handleIprRead(thread->getTC(), pkt); 281 new IprEvent(pkt, this, nextCycle(curTick + delay)); 282 _status = DcacheWaitResponse; 283 dcache_pkt = NULL; 284 } else if (!dcachePort.sendTiming(pkt)) { 285 _status = DcacheRetry; 286 dcache_pkt = pkt; 287 } else { 288 _status = DcacheWaitResponse; 289 // memory system takes ownership of packet 290 dcache_pkt = NULL; 291 } 292 293 // This will need a new way to tell if it has a dcache attached. 294 if (req->isUncacheable()) 295 recordEvent("Uncached Read"); 296 } else { 297 delete req; 298 } 299 300 if (traceData) { 301 traceData->setData(data); 302 } 303 return fault; 304} 305 306Fault 307TimingSimpleCPU::translateDataReadAddr(Addr vaddr, Addr &paddr, 308 int size, unsigned flags) 309{ 310 Request *req = 311 new Request(0, vaddr, size, flags, thread->readPC(), cpuId, 0); 312 313 if (traceData) { 314 traceData->setAddr(vaddr); 315 } 316 317 Fault fault = thread->translateDataWriteReq(req); 318 319 if (fault == NoFault) 320 paddr = req->getPaddr(); 321 322 delete req; 323 return fault; 324} 325 326#ifndef DOXYGEN_SHOULD_SKIP_THIS 327 328template 329Fault 330TimingSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags); 331 332template 333Fault 334TimingSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags); 335 336template 337Fault 338TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 339 340template 341Fault 342TimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 343 344template 345Fault 346TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 347 348template 349Fault 350TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 351 352#endif //DOXYGEN_SHOULD_SKIP_THIS 353 354template<> 355Fault 356TimingSimpleCPU::read(Addr addr, double &data, unsigned flags) 357{ 358 return read(addr, *(uint64_t*)&data, flags); 359} 360 361template<> 362Fault 363TimingSimpleCPU::read(Addr addr, float &data, unsigned flags) 364{ 365 return read(addr, *(uint32_t*)&data, flags); 366} 367 368 369template<> 370Fault 371TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 372{ 373 return read(addr, (uint32_t&)data, flags); 374} 375 376 377template <class T> 378Fault 379TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 380{ 381 Request *req = 382 new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), 383 cpuId, /* thread ID */ 0); 384 385 if (traceData) { 386 traceData->setAddr(req->getVaddr()); 387 } 388 389 // translate to physical address 390 Fault fault = thread->translateDataWriteReq(req); 391 392 // Now do the access. 393 if (fault == NoFault) { 394 MemCmd cmd = MemCmd::WriteReq; // default 395 bool do_access = true; // flag to suppress cache access 396 397 if (req->isLocked()) { 398 cmd = MemCmd::StoreCondReq; 399 do_access = TheISA::handleLockedWrite(thread, req); 400 } else if (req->isSwap()) { 401 cmd = MemCmd::SwapReq; 402 if (req->isCondSwap()) { 403 assert(res); 404 req->setExtraData(*res); 405 } 406 } 407 408 // Note: need to allocate dcache_pkt even if do_access is 409 // false, as it's used unconditionally to call completeAcc(). 410 assert(dcache_pkt == NULL); 411 dcache_pkt = new Packet(req, cmd, Packet::Broadcast); 412 dcache_pkt->allocate(); 413 dcache_pkt->set(data); 414 415 if (do_access) { 416 if (req->isMmapedIpr()) { 417 Tick delay; 418 dcache_pkt->set(htog(data)); 419 delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt); 420 new IprEvent(dcache_pkt, this, nextCycle(curTick + delay)); 421 _status = DcacheWaitResponse; 422 dcache_pkt = NULL; 423 } else if (!dcachePort.sendTiming(dcache_pkt)) { 424 _status = DcacheRetry; 425 } else { 426 _status = DcacheWaitResponse; 427 // memory system takes ownership of packet 428 dcache_pkt = NULL; 429 } 430 } 431 // This will need a new way to tell if it's hooked up to a cache or not. 432 if (req->isUncacheable()) 433 recordEvent("Uncached Write"); 434 } else { 435 delete req; 436 } 437 438 if (traceData) { 439 traceData->setData(data); 440 } 441 442 // If the write needs to have a fault on the access, consider calling 443 // changeStatus() and changing it to "bad addr write" or something. 444 return fault; 445} 446 447Fault 448TimingSimpleCPU::translateDataWriteAddr(Addr vaddr, Addr &paddr, 449 int size, unsigned flags) 450{ 451 Request *req = 452 new Request(0, vaddr, size, flags, thread->readPC(), cpuId, 0); 453 454 if (traceData) { 455 traceData->setAddr(vaddr); 456 } 457 458 Fault fault = thread->translateDataWriteReq(req); 459 460 if (fault == NoFault) 461 paddr = req->getPaddr(); 462 463 delete req; 464 return fault; 465} 466 467 468#ifndef DOXYGEN_SHOULD_SKIP_THIS 469template 470Fault 471TimingSimpleCPU::write(Twin32_t data, Addr addr, 472 unsigned flags, uint64_t *res); 473 474template 475Fault 476TimingSimpleCPU::write(Twin64_t data, Addr addr, 477 unsigned flags, uint64_t *res); 478 479template 480Fault 481TimingSimpleCPU::write(uint64_t data, Addr addr, 482 unsigned flags, uint64_t *res); 483 484template 485Fault 486TimingSimpleCPU::write(uint32_t data, Addr addr, 487 unsigned flags, uint64_t *res); 488 489template 490Fault 491TimingSimpleCPU::write(uint16_t data, Addr addr, 492 unsigned flags, uint64_t *res); 493 494template 495Fault 496TimingSimpleCPU::write(uint8_t data, Addr addr, 497 unsigned flags, uint64_t *res); 498 499#endif //DOXYGEN_SHOULD_SKIP_THIS 500 501template<> 502Fault 503TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 504{ 505 return write(*(uint64_t*)&data, addr, flags, res); 506} 507 508template<> 509Fault 510TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 511{ 512 return write(*(uint32_t*)&data, addr, flags, res); 513} 514 515 516template<> 517Fault 518TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 519{ 520 return write((uint32_t)data, addr, flags, res); 521} 522 523 524void 525TimingSimpleCPU::fetch() 526{ 527 DPRINTF(SimpleCPU, "Fetch\n"); 528 529 if (!curStaticInst || !curStaticInst->isDelayedCommit()) 530 checkForInterrupts(); 531 532 checkPcEventQueue(); 533
|