cpu.hh revision 5702
1/* 2 * Copyright (c) 2006 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: Kevin Lim 29 */ 30 31#ifndef __CPU_CHECKER_CPU_HH__ 32#define __CPU_CHECKER_CPU_HH__ 33 34#include <list> 35#include <queue> 36#include <map> 37 38#include "arch/types.hh" 39#include "base/statistics.hh" 40#include "config/full_system.hh" 41#include "cpu/base.hh" 42#include "cpu/base_dyn_inst.hh" 43#include "cpu/simple_thread.hh" 44#include "cpu/pc_event.hh" 45#include "cpu/static_inst.hh" 46#include "sim/eventq.hh" 47 48// forward declarations 49#if FULL_SYSTEM 50namespace TheISA 51{ 52 class ITB; 53 class DTB; 54} 55class Processor; 56class PhysicalMemory; 57 58class RemoteGDB; 59class GDBListener; 60 61#else 62 63class Process; 64 65#endif // FULL_SYSTEM 66template <class> 67class BaseDynInst; 68class CheckerCPUParams; 69class ThreadContext; 70class MemInterface; 71class Checkpoint; 72class Request; 73 74/** 75 * CheckerCPU class. Dynamically verifies instructions as they are 76 * completed by making sure that the instruction and its results match 77 * the independent execution of the benchmark inside the checker. The 78 * checker verifies instructions in order, regardless of the order in 79 * which instructions complete. There are certain results that can 80 * not be verified, specifically the result of a store conditional or 81 * the values of uncached accesses. In these cases, and with 82 * instructions marked as "IsUnverifiable", the checker assumes that 83 * the value from the main CPU's execution is correct and simply 84 * copies that value. It provides a CheckerThreadContext (see 85 * checker/thread_context.hh) that provides hooks for updating the 86 * Checker's state through any ThreadContext accesses. This allows the 87 * checker to be able to correctly verify instructions, even with 88 * external accesses to the ThreadContext that change state. 89 */ 90class CheckerCPU : public BaseCPU 91{ 92 protected: 93 typedef TheISA::MachInst MachInst; 94 typedef TheISA::FloatReg FloatReg; 95 typedef TheISA::FloatRegBits FloatRegBits; 96 typedef TheISA::MiscReg MiscReg; 97 public: 98 virtual void init(); 99 100 public: 101 typedef CheckerCPUParams Params; 102 const Params *params() const 103 { return reinterpret_cast<const Params *>(_params); } 104 CheckerCPU(Params *p); 105 virtual ~CheckerCPU(); 106 107 Process *process; 108 109 void setSystem(System *system); 110 111 System *systemPtr; 112 113 void setIcachePort(Port *icache_port); 114 115 Port *icachePort; 116 117 void setDcachePort(Port *dcache_port); 118 119 Port *dcachePort; 120 121 virtual Port *getPort(const std::string &name, int idx) 122 { 123 panic("Not supported on checker!"); 124 return NULL; 125 } 126 127 public: 128 // Primary thread being run. 129 SimpleThread *thread; 130 131 ThreadContext *tc; 132 133 TheISA::ITB *itb; 134 TheISA::DTB *dtb; 135 136#if FULL_SYSTEM 137 Addr dbg_vtophys(Addr addr); 138#endif 139 140 union Result { 141 uint64_t integer; 142// float fp; 143 double dbl; 144 }; 145 146 Result result; 147 148 // current instruction 149 MachInst machInst; 150 151 // Pointer to the one memory request. 152 RequestPtr memReq; 153 154 StaticInstPtr curStaticInst; 155 156 // number of simulated instructions 157 Counter numInst; 158 Counter startNumInst; 159 160 std::queue<int> miscRegIdxs; 161 162 virtual Counter totalInstructions() const 163 { 164 return 0; 165 } 166 167 // number of simulated loads 168 Counter numLoad; 169 Counter startNumLoad; 170 171 virtual void serialize(std::ostream &os); 172 virtual void unserialize(Checkpoint *cp, const std::string §ion); 173 174 template <class T> 175 Fault read(Addr addr, T &data, unsigned flags); 176 177 template <class T> 178 Fault write(T data, Addr addr, unsigned flags, uint64_t *res); 179 180 // These functions are only used in CPU models that split 181 // effective address computation from the actual memory access. 182 void setEA(Addr EA) { panic("SimpleCPU::setEA() not implemented\n"); } 183 Addr getEA() { panic("SimpleCPU::getEA() not implemented\n"); } 184 185 void prefetch(Addr addr, unsigned flags) 186 { 187 // need to do this... 188 } 189 190 void writeHint(Addr addr, int size, unsigned flags) 191 { 192 // need to do this... 193 } 194 195 Fault copySrcTranslate(Addr src); 196 197 Fault copy(Addr dest); 198 199 // The register accessor methods provide the index of the 200 // instruction's operand (e.g., 0 or 1), not the architectural 201 // register index, to simplify the implementation of register 202 // renaming. We find the architectural register index by indexing 203 // into the instruction's own operand index table. Note that a 204 // raw pointer to the StaticInst is provided instead of a 205 // ref-counted StaticInstPtr to redice overhead. This is fine as 206 // long as these methods don't copy the pointer into any long-term 207 // storage (which is pretty hard to imagine they would have reason 208 // to do). 209 210 uint64_t readIntRegOperand(const StaticInst *si, int idx) 211 { 212 return thread->readIntReg(si->srcRegIdx(idx)); 213 } 214 215 FloatReg readFloatRegOperand(const StaticInst *si, int idx, int width) 216 { 217 int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; 218 return thread->readFloatReg(reg_idx, width); 219 } 220 221 FloatReg readFloatRegOperand(const StaticInst *si, int idx) 222 { 223 int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; 224 return thread->readFloatReg(reg_idx); 225 } 226 227 FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx, 228 int width) 229 { 230 int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; 231 return thread->readFloatRegBits(reg_idx, width); 232 } 233 234 FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx) 235 { 236 int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; 237 return thread->readFloatRegBits(reg_idx); 238 } 239 240 void setIntRegOperand(const StaticInst *si, int idx, uint64_t val) 241 { 242 thread->setIntReg(si->destRegIdx(idx), val); 243 result.integer = val; 244 } 245 246 void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val, 247 int width) 248 { 249 int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; 250 thread->setFloatReg(reg_idx, val, width); 251 switch(width) { 252 case 32: 253 result.dbl = (double)val; 254 break; 255 case 64: 256 result.dbl = val; 257 break; 258 }; 259 } 260 261 void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val) 262 { 263 int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; 264 thread->setFloatReg(reg_idx, val); 265 result.dbl = (double)val; 266 } 267 268 void setFloatRegOperandBits(const StaticInst *si, int idx, 269 FloatRegBits val, int width) 270 { 271 int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; 272 thread->setFloatRegBits(reg_idx, val, width); 273 result.integer = val; 274 } 275 276 void setFloatRegOperandBits(const StaticInst *si, int idx, 277 FloatRegBits val) 278 { 279 int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; 280 thread->setFloatRegBits(reg_idx, val); 281 result.integer = val; 282 } 283 284 uint64_t readPC() { return thread->readPC(); } 285 286 uint64_t readNextPC() { return thread->readNextPC(); } 287 288 void setNextPC(uint64_t val) { 289 thread->setNextPC(val); 290 } 291 292 MiscReg readMiscRegNoEffect(int misc_reg) 293 { 294 return thread->readMiscRegNoEffect(misc_reg); 295 } 296 297 MiscReg readMiscReg(int misc_reg) 298 { 299 return thread->readMiscReg(misc_reg); 300 } 301 302 void setMiscRegNoEffect(int misc_reg, const MiscReg &val) 303 { 304 result.integer = val; 305 miscRegIdxs.push(misc_reg); 306 return thread->setMiscRegNoEffect(misc_reg, val); 307 } 308 309 void setMiscReg(int misc_reg, const MiscReg &val) 310 { 311 miscRegIdxs.push(misc_reg); 312 return thread->setMiscReg(misc_reg, val); 313 } 314 315 void recordPCChange(uint64_t val) { changedPC = true; newPC = val; } 316 void recordNextPCChange(uint64_t val) { changedNextPC = true; } 317 318 void demapPage(Addr vaddr, uint64_t asn) 319 { 320 this->itb->demapPage(vaddr, asn); 321 this->dtb->demapPage(vaddr, asn); 322 } 323 324 void demapInstPage(Addr vaddr, uint64_t asn) 325 { 326 this->itb->demapPage(vaddr, asn); 327 } 328 329 void demapDataPage(Addr vaddr, uint64_t asn) 330 { 331 this->dtb->demapPage(vaddr, asn); 332 } 333 334 bool translateInstReq(Request *req); 335 void translateDataWriteReq(Request *req); 336 void translateDataReadReq(Request *req); 337 338#if FULL_SYSTEM 339 Fault hwrei() { return thread->hwrei(); } 340 void ev5_trap(Fault fault) { fault->invoke(tc); } 341 bool simPalCheck(int palFunc) { return thread->simPalCheck(palFunc); } 342#else 343 // Assume that the normal CPU's call to syscall was successful. 344 // The checker's state would have already been updated by the syscall. 345 void syscall(uint64_t callnum) { } 346#endif 347 348 void handleError() 349 { 350 if (exitOnError) 351 dumpAndExit(); 352 } 353 354 bool checkFlags(Request *req); 355 356 void dumpAndExit(); 357 358 ThreadContext *tcBase() { return tc; } 359 SimpleThread *threadBase() { return thread; } 360 361 Result unverifiedResult; 362 Request *unverifiedReq; 363 uint8_t *unverifiedMemData; 364 365 bool changedPC; 366 bool willChangePC; 367 uint64_t newPC; 368 bool changedNextPC; 369 bool exitOnError; 370 bool updateOnError; 371 bool warnOnlyOnLoadError; 372 373 InstSeqNum youngestSN; 374}; 375 376/** 377 * Templated Checker class. This Checker class is templated on the 378 * DynInstPtr of the instruction type that will be verified. Proper 379 * template instantiations of the Checker must be placed at the bottom 380 * of checker/cpu.cc. 381 */ 382template <class DynInstPtr> 383class Checker : public CheckerCPU 384{ 385 public: 386 Checker(Params *p) 387 : CheckerCPU(p), updateThisCycle(false), unverifiedInst(NULL) 388 { } 389 390 void switchOut(); 391 void takeOverFrom(BaseCPU *oldCPU); 392 393 void verify(DynInstPtr &inst); 394 395 void validateInst(DynInstPtr &inst); 396 void validateExecution(DynInstPtr &inst); 397 void validateState(); 398 399 void copyResult(DynInstPtr &inst); 400 401 private: 402 void handleError(DynInstPtr &inst) 403 { 404 if (exitOnError) { 405 dumpAndExit(inst); 406 } else if (updateOnError) { 407 updateThisCycle = true; 408 } 409 } 410 411 void dumpAndExit(DynInstPtr &inst); 412 413 bool updateThisCycle; 414 415 DynInstPtr unverifiedInst; 416 417 std::list<DynInstPtr> instList; 418 typedef typename std::list<DynInstPtr>::iterator InstListIt; 419 void dumpInsts(); 420}; 421 422#endif // __CPU_CHECKER_CPU_HH__ 423