cpu.cc revision 3172
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#include <list> 32#include <string> 33 34#include "cpu/base.hh" 35#include "cpu/checker/cpu.hh" 36#include "cpu/simple_thread.hh" 37#include "cpu/thread_context.hh" 38#include "cpu/static_inst.hh" 39#include "mem/packet_impl.hh" 40#include "sim/byteswap.hh" 41 42#if FULL_SYSTEM 43#include "arch/vtophys.hh" 44#include "kern/kernel_stats.hh" 45#endif // FULL_SYSTEM 46 47using namespace std; 48//The CheckerCPU does alpha only 49using namespace AlphaISA; 50 51void 52CheckerCPU::init() 53{ 54} 55 56CheckerCPU::CheckerCPU(Params *p) 57 : BaseCPU(p), thread(NULL), tc(NULL) 58{ 59 memReq = NULL; 60 61 numInst = 0; 62 startNumInst = 0; 63 numLoad = 0; 64 startNumLoad = 0; 65 youngestSN = 0; 66 67 changedPC = willChangePC = changedNextPC = false; 68 69 exitOnError = p->exitOnError; 70 warnOnlyOnLoadError = p->warnOnlyOnLoadError; 71#if FULL_SYSTEM 72 itb = p->itb; 73 dtb = p->dtb; 74 systemPtr = NULL; 75#else 76 process = p->process; 77#endif 78 79 result.integer = 0; 80} 81 82CheckerCPU::~CheckerCPU() 83{ 84} 85 86void 87CheckerCPU::setMemory(MemObject *mem) 88{ 89#if !FULL_SYSTEM 90 memPtr = mem; 91 thread = new SimpleThread(this, /* thread_num */ 0, process, 92 /* asid */ 0, mem); 93 94 thread->setStatus(ThreadContext::Suspended); 95 tc = thread->getTC(); 96 threadContexts.push_back(tc); 97#endif 98} 99 100void 101CheckerCPU::setSystem(System *system) 102{ 103#if FULL_SYSTEM 104 systemPtr = system; 105 106 thread = new SimpleThread(this, 0, systemPtr, itb, dtb, false); 107 108 thread->setStatus(ThreadContext::Suspended); 109 tc = thread->getTC(); 110 threadContexts.push_back(tc); 111 delete thread->kernelStats; 112 thread->kernelStats = NULL; 113#endif 114} 115 116void 117CheckerCPU::setIcachePort(Port *icache_port) 118{ 119 icachePort = icache_port; 120} 121 122void 123CheckerCPU::setDcachePort(Port *dcache_port) 124{ 125 dcachePort = dcache_port; 126} 127 128void 129CheckerCPU::serialize(ostream &os) 130{ 131/* 132 BaseCPU::serialize(os); 133 SERIALIZE_SCALAR(inst); 134 nameOut(os, csprintf("%s.xc", name())); 135 thread->serialize(os); 136 cacheCompletionEvent.serialize(os); 137*/ 138} 139 140void 141CheckerCPU::unserialize(Checkpoint *cp, const string §ion) 142{ 143/* 144 BaseCPU::unserialize(cp, section); 145 UNSERIALIZE_SCALAR(inst); 146 thread->unserialize(cp, csprintf("%s.xc", section)); 147*/ 148} 149 150Fault 151CheckerCPU::copySrcTranslate(Addr src) 152{ 153 panic("Unimplemented!"); 154} 155 156Fault 157CheckerCPU::copy(Addr dest) 158{ 159 panic("Unimplemented!"); 160} 161 162template <class T> 163Fault 164CheckerCPU::read(Addr addr, T &data, unsigned flags) 165{ 166 // need to fill in CPU & thread IDs here 167 memReq = new Request(); 168 169 memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC()); 170 171 // translate to physical address 172 translateDataReadReq(memReq); 173 174 Packet *pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast); 175 176 pkt->dataStatic(&data); 177 178 if (!(memReq->isUncacheable())) { 179 // Access memory to see if we have the same data 180 dcachePort->sendFunctional(pkt); 181 } else { 182 // Assume the data is correct if it's an uncached access 183 memcpy(&data, &unverifiedResult.integer, sizeof(T)); 184 } 185 186 delete pkt; 187 188 return NoFault; 189} 190 191#ifndef DOXYGEN_SHOULD_SKIP_THIS 192 193template 194Fault 195CheckerCPU::read(Addr addr, uint64_t &data, unsigned flags); 196 197template 198Fault 199CheckerCPU::read(Addr addr, uint32_t &data, unsigned flags); 200 201template 202Fault 203CheckerCPU::read(Addr addr, uint16_t &data, unsigned flags); 204 205template 206Fault 207CheckerCPU::read(Addr addr, uint8_t &data, unsigned flags); 208 209#endif //DOXYGEN_SHOULD_SKIP_THIS 210 211template<> 212Fault 213CheckerCPU::read(Addr addr, double &data, unsigned flags) 214{ 215 return read(addr, *(uint64_t*)&data, flags); 216} 217 218template<> 219Fault 220CheckerCPU::read(Addr addr, float &data, unsigned flags) 221{ 222 return read(addr, *(uint32_t*)&data, flags); 223} 224 225template<> 226Fault 227CheckerCPU::read(Addr addr, int32_t &data, unsigned flags) 228{ 229 return read(addr, (uint32_t&)data, flags); 230} 231 232template <class T> 233Fault 234CheckerCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 235{ 236 // need to fill in CPU & thread IDs here 237 memReq = new Request(); 238 239 memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC()); 240 241 // translate to physical address 242 thread->translateDataWriteReq(memReq); 243 244 // Can compare the write data and result only if it's cacheable, 245 // not a store conditional, or is a store conditional that 246 // succeeded. 247 // @todo: Verify that actual memory matches up with these values. 248 // Right now it only verifies that the instruction data is the 249 // same as what was in the request that got sent to memory; there 250 // is no verification that it is the same as what is in memory. 251 // This is because the LSQ would have to be snooped in the CPU to 252 // verify this data. 253 if (unverifiedReq && 254 !(unverifiedReq->isUncacheable()) && 255 (!(unverifiedReq->isLocked()) || 256 ((unverifiedReq->isLocked()) && 257 unverifiedReq->getScResult() == 1))) { 258 T inst_data; 259/* 260 // This code would work if the LSQ allowed for snooping. 261 Packet *pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast); 262 pkt.dataStatic(&inst_data); 263 264 dcachePort->sendFunctional(pkt); 265 266 delete pkt; 267*/ 268 memcpy(&inst_data, unverifiedMemData, sizeof(T)); 269 270 if (data != inst_data) { 271 warn("%lli: Store value does not match value in memory! " 272 "Instruction: %#x, memory: %#x", 273 curTick, inst_data, data); 274 handleError(); 275 } 276 } 277 278 // Assume the result was the same as the one passed in. This checker 279 // doesn't check if the SC should succeed or fail, it just checks the 280 // value. 281 if (res && unverifiedReq->scResultValid()) 282 *res = unverifiedReq->getScResult(); 283 284 return NoFault; 285} 286 287 288#ifndef DOXYGEN_SHOULD_SKIP_THIS 289template 290Fault 291CheckerCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res); 292 293template 294Fault 295CheckerCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res); 296 297template 298Fault 299CheckerCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res); 300 301template 302Fault 303CheckerCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res); 304 305#endif //DOXYGEN_SHOULD_SKIP_THIS 306 307template<> 308Fault 309CheckerCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 310{ 311 return write(*(uint64_t*)&data, addr, flags, res); 312} 313 314template<> 315Fault 316CheckerCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 317{ 318 return write(*(uint32_t*)&data, addr, flags, res); 319} 320 321template<> 322Fault 323CheckerCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 324{ 325 return write((uint32_t)data, addr, flags, res); 326} 327 328 329#if FULL_SYSTEM 330Addr 331CheckerCPU::dbg_vtophys(Addr addr) 332{ 333 return vtophys(tc, addr); 334} 335#endif // FULL_SYSTEM 336 337bool 338CheckerCPU::translateInstReq(Request *req) 339{ 340#if FULL_SYSTEM 341 return (thread->translateInstReq(req) == NoFault); 342#else 343 thread->translateInstReq(req); 344 return true; 345#endif 346} 347 348void 349CheckerCPU::translateDataReadReq(Request *req) 350{ 351 thread->translateDataReadReq(req); 352 353 if (req->getVaddr() != unverifiedReq->getVaddr()) { 354 warn("%lli: Request virtual addresses do not match! Inst: %#x, " 355 "checker: %#x", 356 curTick, unverifiedReq->getVaddr(), req->getVaddr()); 357 handleError(); 358 } 359 req->setPaddr(unverifiedReq->getPaddr()); 360 361 if (checkFlags(req)) { 362 warn("%lli: Request flags do not match! Inst: %#x, checker: %#x", 363 curTick, unverifiedReq->getFlags(), req->getFlags()); 364 handleError(); 365 } 366} 367 368void 369CheckerCPU::translateDataWriteReq(Request *req) 370{ 371 thread->translateDataWriteReq(req); 372 373 if (req->getVaddr() != unverifiedReq->getVaddr()) { 374 warn("%lli: Request virtual addresses do not match! Inst: %#x, " 375 "checker: %#x", 376 curTick, unverifiedReq->getVaddr(), req->getVaddr()); 377 handleError(); 378 } 379 req->setPaddr(unverifiedReq->getPaddr()); 380 381 if (checkFlags(req)) { 382 warn("%lli: Request flags do not match! Inst: %#x, checker: %#x", 383 curTick, unverifiedReq->getFlags(), req->getFlags()); 384 handleError(); 385 } 386} 387 388bool 389CheckerCPU::checkFlags(Request *req) 390{ 391 // Remove any dynamic flags that don't have to do with the request itself. 392 unsigned flags = unverifiedReq->getFlags(); 393 unsigned mask = LOCKED | PHYSICAL | VPTE | ALTMODE | UNCACHEABLE | NO_FAULT; 394 flags = flags & (mask); 395 if (flags == req->getFlags()) { 396 return false; 397 } else { 398 return true; 399 } 400} 401 402void 403CheckerCPU::dumpAndExit() 404{ 405 warn("%lli: Checker PC:%#x, next PC:%#x", 406 curTick, thread->readPC(), thread->readNextPC()); 407 panic("Checker found an error!"); 408} 409