base.hh revision 2462
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 29#ifndef __CPU_SIMPLE_CPU_SIMPLE_CPU_HH__ 30#define __CPU_SIMPLE_CPU_SIMPLE_CPU_HH__ 31 32#include "base/statistics.hh" 33#include "config/full_system.hh" 34#include "cpu/base.hh" 35#include "cpu/cpu_exec_context.hh" 36#include "cpu/pc_event.hh" 37#include "cpu/sampler/sampler.hh" 38#include "cpu/static_inst.hh" 39#include "mem/packet.hh" 40#include "mem/port.hh" 41#include "mem/request.hh" 42#include "sim/eventq.hh" 43 44// forward declarations 45#if FULL_SYSTEM 46class Processor; 47class AlphaITB; 48class AlphaDTB; 49class MemObject; 50 51class RemoteGDB; 52class GDBListener; 53 54#else 55 56class Process; 57 58#endif // FULL_SYSTEM 59 60class ExecContext; 61class Checkpoint; 62 63namespace Trace { 64 class InstRecord; 65} 66 67 68// Set exactly one of these symbols to 1 to set the memory access 69// model. Probably should make these template parameters, or even 70// just fork the CPU models. 71// 72#define SIMPLE_CPU_MEM_TIMING 0 73#define SIMPLE_CPU_MEM_ATOMIC 0 74#define SIMPLE_CPU_MEM_IMMEDIATE 1 75 76 77class SimpleCPU : public BaseCPU 78{ 79 protected: 80 typedef TheISA::MachInst MachInst; 81 typedef TheISA::MiscReg MiscReg; 82 class CpuPort : public Port 83 { 84 85 SimpleCPU *cpu; 86 87 public: 88 89 CpuPort(SimpleCPU *_cpu) 90 : cpu(_cpu) 91 { } 92 93 protected: 94 95 virtual bool recvTiming(Packet &pkt); 96 97 virtual Tick recvAtomic(Packet &pkt); 98 99 virtual void recvFunctional(Packet &pkt); 100 101 virtual void recvStatusChange(Status status); 102 103 virtual Packet *recvRetry(); 104 }; 105 106 CpuPort icachePort; 107 CpuPort dcachePort; 108 109 public: 110 // main simulation loop (one cycle) 111 void tick(); 112 virtual void init(); 113 114 private: 115 struct TickEvent : public Event 116 { 117 SimpleCPU *cpu; 118 int width; 119 120 TickEvent(SimpleCPU *c, int w); 121 void process(); 122 const char *description(); 123 }; 124 125 TickEvent tickEvent; 126 127 /// Schedule tick event, regardless of its current state. 128 void scheduleTickEvent(int numCycles) 129 { 130 if (tickEvent.squashed()) 131 tickEvent.reschedule(curTick + cycles(numCycles)); 132 else if (!tickEvent.scheduled()) 133 tickEvent.schedule(curTick + cycles(numCycles)); 134 } 135 136 /// Unschedule tick event, regardless of its current state. 137 void unscheduleTickEvent() 138 { 139 if (tickEvent.scheduled()) 140 tickEvent.squash(); 141 } 142 143 private: 144 Trace::InstRecord *traceData; 145 146 public: 147 // 148 enum Status { 149 Running, 150 Idle, 151 IcacheRetry, 152 IcacheWaitResponse, 153 IcacheAccessComplete, 154 DcacheRetry, 155 DcacheWaitResponse, 156 DcacheWaitSwitch, 157 SwitchedOut 158 }; 159 160 private: 161 Status _status; 162 163 public: 164 void post_interrupt(int int_num, int index); 165 166 void zero_fill_64(Addr addr) { 167 static int warned = 0; 168 if (!warned) { 169 warn ("WH64 is not implemented"); 170 warned = 1; 171 } 172 }; 173 174 public: 175 struct Params : public BaseCPU::Params 176 { 177 int width; 178#if FULL_SYSTEM 179 AlphaITB *itb; 180 AlphaDTB *dtb; 181#else 182 MemObject *mem; 183 Process *process; 184#endif 185 }; 186 SimpleCPU(Params *params); 187 virtual ~SimpleCPU(); 188 189 public: 190 // execution context 191 CPUExecContext *cpuXC; 192 193 ExecContext *xcProxy; 194 195 void switchOut(Sampler *s); 196 void takeOverFrom(BaseCPU *oldCPU); 197 198#if FULL_SYSTEM 199 Addr dbg_vtophys(Addr addr); 200 201 bool interval_stats; 202#endif 203 204 // current instruction 205 MachInst inst; 206 207#if SIMPLE_CPU_MEM_TIMING 208 Packet *retry_pkt; 209#elif SIMPLE_CPU_MEM_ATOMIC || SIMPLE_CPU_MEM_IMMEDIATE 210 CpuRequest *ifetch_req; 211 Packet *ifetch_pkt; 212 CpuRequest *data_read_req; 213 Packet *data_read_pkt; 214 CpuRequest *data_write_req; 215 Packet *data_write_pkt; 216#endif 217 218 // Pointer to the sampler that is telling us to switchover. 219 // Used to signal the completion of the pipe drain and schedule 220 // the next switchover 221 Sampler *sampler; 222 223 StaticInstPtr curStaticInst; 224 225 Status status() const { return _status; } 226 227 virtual void activateContext(int thread_num, int delay); 228 virtual void suspendContext(int thread_num); 229 virtual void deallocateContext(int thread_num); 230 virtual void haltContext(int thread_num); 231 232 // statistics 233 virtual void regStats(); 234 virtual void resetStats(); 235 236 // number of simulated instructions 237 Counter numInst; 238 Counter startNumInst; 239 Stats::Scalar<> numInsts; 240 241 virtual Counter totalInstructions() const 242 { 243 return numInst - startNumInst; 244 } 245 246 // number of simulated memory references 247 Stats::Scalar<> numMemRefs; 248 249 // number of simulated loads 250 Counter numLoad; 251 Counter startNumLoad; 252 253 // number of idle cycles 254 Stats::Average<> notIdleFraction; 255 Stats::Formula idleFraction; 256 257 // number of cycles stalled for I-cache responses 258 Stats::Scalar<> icacheStallCycles; 259 Counter lastIcacheStall; 260 261 // number of cycles stalled for I-cache retries 262 Stats::Scalar<> icacheRetryCycles; 263 Counter lastIcacheRetry; 264 265 // number of cycles stalled for D-cache responses 266 Stats::Scalar<> dcacheStallCycles; 267 Counter lastDcacheStall; 268 269 // number of cycles stalled for D-cache retries 270 Stats::Scalar<> dcacheRetryCycles; 271 Counter lastDcacheRetry; 272 273 void sendIcacheRequest(Packet *pkt); 274 void sendDcacheRequest(Packet *pkt); 275 void processResponse(Packet &response); 276 277 Packet * processRetry(); 278 void recvStatusChange(Port::Status status) {} 279 280 virtual void serialize(std::ostream &os); 281 virtual void unserialize(Checkpoint *cp, const std::string §ion); 282 283 template <class T> 284 Fault read(Addr addr, T &data, unsigned flags); 285 286 template <class T> 287 Fault write(T data, Addr addr, unsigned flags, uint64_t *res); 288 289 // These functions are only used in CPU models that split 290 // effective address computation from the actual memory access. 291 void setEA(Addr EA) { panic("SimpleCPU::setEA() not implemented\n"); } 292 Addr getEA() { panic("SimpleCPU::getEA() not implemented\n"); } 293 294 void prefetch(Addr addr, unsigned flags) 295 { 296 // need to do this... 297 } 298 299 void writeHint(Addr addr, int size, unsigned flags) 300 { 301 // need to do this... 302 } 303 304 Fault copySrcTranslate(Addr src); 305 306 Fault copy(Addr dest); 307 308 // The register accessor methods provide the index of the 309 // instruction's operand (e.g., 0 or 1), not the architectural 310 // register index, to simplify the implementation of register 311 // renaming. We find the architectural register index by indexing 312 // into the instruction's own operand index table. Note that a 313 // raw pointer to the StaticInst is provided instead of a 314 // ref-counted StaticInstPtr to redice overhead. This is fine as 315 // long as these methods don't copy the pointer into any long-term 316 // storage (which is pretty hard to imagine they would have reason 317 // to do). 318 319 uint64_t readIntReg(const StaticInst *si, int idx) 320 { 321 return cpuXC->readIntReg(si->srcRegIdx(idx)); 322 } 323 324 float readFloatRegSingle(const StaticInst *si, int idx) 325 { 326 int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; 327 return cpuXC->readFloatRegSingle(reg_idx); 328 } 329 330 double readFloatRegDouble(const StaticInst *si, int idx) 331 { 332 int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; 333 return cpuXC->readFloatRegDouble(reg_idx); 334 } 335 336 uint64_t readFloatRegInt(const StaticInst *si, int idx) 337 { 338 int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; 339 return cpuXC->readFloatRegInt(reg_idx); 340 } 341 342 void setIntReg(const StaticInst *si, int idx, uint64_t val) 343 { 344 cpuXC->setIntReg(si->destRegIdx(idx), val); 345 } 346 347 void setFloatRegSingle(const StaticInst *si, int idx, float val) 348 { 349 int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; 350 cpuXC->setFloatRegSingle(reg_idx, val); 351 } 352 353 void setFloatRegDouble(const StaticInst *si, int idx, double val) 354 { 355 int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; 356 cpuXC->setFloatRegDouble(reg_idx, val); 357 } 358 359 void setFloatRegInt(const StaticInst *si, int idx, uint64_t val) 360 { 361 int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; 362 cpuXC->setFloatRegInt(reg_idx, val); 363 } 364 365 uint64_t readPC() { return cpuXC->readPC(); } 366 uint64_t readNextPC() { return cpuXC->readNextPC(); } 367 uint64_t readNextNPC() { return cpuXC->readNextNPC(); } 368 369 void setPC(uint64_t val) { cpuXC->setPC(val); } 370 void setNextPC(uint64_t val) { cpuXC->setNextPC(val); } 371 void setNextNPC(uint64_t val) { cpuXC->setNextNPC(val); } 372 373 MiscReg readMiscReg(int misc_reg) 374 { 375 return cpuXC->readMiscReg(misc_reg); 376 } 377 378 MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) 379 { 380 return cpuXC->readMiscRegWithEffect(misc_reg, fault); 381 } 382 383 Fault setMiscReg(int misc_reg, const MiscReg &val) 384 { 385 return cpuXC->setMiscReg(misc_reg, val); 386 } 387 388 Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) 389 { 390 return cpuXC->setMiscRegWithEffect(misc_reg, val); 391 } 392 393#if FULL_SYSTEM 394 Fault hwrei() { return cpuXC->hwrei(); } 395 int readIntrFlag() { return cpuXC->readIntrFlag(); } 396 void setIntrFlag(int val) { cpuXC->setIntrFlag(val); } 397 bool inPalMode() { return cpuXC->inPalMode(); } 398 void ev5_trap(Fault fault) { fault->invoke(xcProxy); } 399 bool simPalCheck(int palFunc) { return cpuXC->simPalCheck(palFunc); } 400#else 401 void syscall() { cpuXC->syscall(); } 402#endif 403 404 bool misspeculating() { return cpuXC->misspeculating(); } 405 ExecContext *xcBase() { return xcProxy; } 406}; 407 408#endif // __CPU_SIMPLE_CPU_SIMPLE_CPU_HH__ 409