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