cpu.cc (8733:64a7bf8fa56c) | cpu.cc (8793:5f25086326ac) |
---|---|
1/* | 1/* |
2 * Copyright (c) 2011 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * | |
14 * Copyright (c) 2006 The Regents of The University of Michigan 15 * All rights reserved. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions are 19 * met: redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer; 21 * redistributions in binary form must reproduce the above copyright --- 11 unchanged lines hidden (view full) --- 33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 * 40 * Authors: Kevin Lim | 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 --- 11 unchanged lines hidden (view full) --- 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 |
41 * Geoffrey Blake | |
42 */ 43 44#include <list> 45#include <string> 46 | 29 */ 30 31#include <list> 32#include <string> 33 |
34#include "arch/kernel_stats.hh" 35#include "arch/vtophys.hh" |
|
47#include "cpu/checker/cpu.hh" 48#include "cpu/base.hh" 49#include "cpu/simple_thread.hh" 50#include "cpu/static_inst.hh" 51#include "cpu/thread_context.hh" | 36#include "cpu/checker/cpu.hh" 37#include "cpu/base.hh" 38#include "cpu/simple_thread.hh" 39#include "cpu/static_inst.hh" 40#include "cpu/thread_context.hh" |
52#include "params/CheckerCPU.hh" 53#include "sim/tlb.hh" | |
54 | 41 |
55#if FULL_SYSTEM 56#include "arch/kernel_stats.hh" 57#include "arch/vtophys.hh" 58#endif // FULL_SYSTEM 59 | |
60using namespace std; | 42using namespace std; |
61using namespace TheISA; | 43//The CheckerCPU does alpha only 44using namespace AlphaISA; |
62 63void 64CheckerCPU::init() 65{ 66} 67 68CheckerCPU::CheckerCPU(Params *p) 69 : BaseCPU(p), thread(NULL), tc(NULL) 70{ 71 memReq = NULL; | 45 46void 47CheckerCPU::init() 48{ 49} 50 51CheckerCPU::CheckerCPU(Params *p) 52 : BaseCPU(p), thread(NULL), tc(NULL) 53{ 54 memReq = NULL; |
72 curStaticInst = NULL; 73 curMacroStaticInst = NULL; | |
74 75 numInst = 0; 76 startNumInst = 0; 77 numLoad = 0; 78 startNumLoad = 0; 79 youngestSN = 0; 80 81 changedPC = willChangePC = changedNextPC = false; 82 83 exitOnError = p->exitOnError; 84 warnOnlyOnLoadError = p->warnOnlyOnLoadError; 85 itb = p->itb; 86 dtb = p->dtb; | 55 56 numInst = 0; 57 startNumInst = 0; 58 numLoad = 0; 59 startNumLoad = 0; 60 youngestSN = 0; 61 62 changedPC = willChangePC = changedNextPC = false; 63 64 exitOnError = p->exitOnError; 65 warnOnlyOnLoadError = p->warnOnlyOnLoadError; 66 itb = p->itb; 67 dtb = p->dtb; |
87#if FULL_SYSTEM | |
88 systemPtr = NULL; | 68 systemPtr = NULL; |
89#else 90 workload = p->workload; 91 // XXX: This is a hack to get this to work some 92 thread = new SimpleThread(this, /* thread_num */ 0, workload[0], itb, dtb); | 69 process = p->process; 70 thread = new SimpleThread(this, /* thread_num */ 0, process); |
93 94 tc = thread->getTC(); 95 threadContexts.push_back(tc); | 71 72 tc = thread->getTC(); 73 threadContexts.push_back(tc); |
96#endif | |
97 | 74 |
98 updateOnError = true; | 75 result.integer = 0; |
99} 100 101CheckerCPU::~CheckerCPU() 102{ 103} 104 105void 106CheckerCPU::setSystem(System *system) 107{ | 76} 77 78CheckerCPU::~CheckerCPU() 79{ 80} 81 82void 83CheckerCPU::setSystem(System *system) 84{ |
108#if FULL_SYSTEM | |
109 systemPtr = system; 110 111 thread = new SimpleThread(this, 0, systemPtr, itb, dtb, false); 112 113 tc = thread->getTC(); 114 threadContexts.push_back(tc); 115 delete thread->kernelStats; 116 thread->kernelStats = NULL; | 85 systemPtr = system; 86 87 thread = new SimpleThread(this, 0, systemPtr, itb, dtb, false); 88 89 tc = thread->getTC(); 90 threadContexts.push_back(tc); 91 delete thread->kernelStats; 92 thread->kernelStats = NULL; |
117#endif | |
118} 119 120void 121CheckerCPU::setIcachePort(Port *icache_port) 122{ 123 icachePort = icache_port; 124} 125 126void 127CheckerCPU::setDcachePort(Port *dcache_port) 128{ 129 dcachePort = dcache_port; 130} 131 132void 133CheckerCPU::serialize(ostream &os) 134{ | 93} 94 95void 96CheckerCPU::setIcachePort(Port *icache_port) 97{ 98 icachePort = icache_port; 99} 100 101void 102CheckerCPU::setDcachePort(Port *dcache_port) 103{ 104 dcachePort = dcache_port; 105} 106 107void 108CheckerCPU::serialize(ostream &os) 109{ |
110/* 111 BaseCPU::serialize(os); 112 SERIALIZE_SCALAR(inst); 113 nameOut(os, csprintf("%s.xc", name())); 114 thread->serialize(os); 115 cacheCompletionEvent.serialize(os); 116*/ |
|
135} 136 137void 138CheckerCPU::unserialize(Checkpoint *cp, const string §ion) 139{ | 117} 118 119void 120CheckerCPU::unserialize(Checkpoint *cp, const string §ion) 121{ |
122/* 123 BaseCPU::unserialize(cp, section); 124 UNSERIALIZE_SCALAR(inst); 125 thread->unserialize(cp, csprintf("%s.xc", section)); 126*/ |
|
140} 141 | 127} 128 |
129template <class T> |
|
142Fault | 130Fault |
143CheckerCPU::readMem(Addr addr, uint8_t *data, unsigned size, unsigned flags) | 131CheckerCPU::read(Addr addr, T &data, unsigned flags) |
144{ | 132{ |
145 Fault fault = NoFault; 146 unsigned blockSize = dcachePort->peerBlockSize(); 147 int fullSize = size; 148 Addr secondAddr = roundDown(addr + size - 1, blockSize); 149 bool checked_flags = false; 150 bool flags_match = true; 151 Addr pAddr = 0x0; | 133 // need to fill in CPU & thread IDs here 134 memReq = new Request(); |
152 | 135 |
136 memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC()); |
|
153 | 137 |
154 if (secondAddr > addr) 155 size = secondAddr - addr; | 138 // translate to physical address 139 dtb->translateAtomic(memReq, tc, false); |
156 | 140 |
157 // Need to account for multiple accesses like the Atomic and TimingSimple 158 while (1) { 159 memReq = new Request(); 160 memReq->setVirt(0, addr, size, flags, thread->pcState().instAddr()); | 141 PacketPtr pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast); |
161 | 142 |
162 // translate to physical address 163 fault = dtb->translateFunctional(memReq, tc, BaseTLB::Read); | 143 pkt->dataStatic(&data); |
164 | 144 |
165 if (!checked_flags && fault == NoFault && unverifiedReq) { 166 flags_match = checkFlags(unverifiedReq, memReq->getVaddr(), 167 memReq->getPaddr(), memReq->getFlags()); 168 pAddr = memReq->getPaddr(); 169 checked_flags = true; 170 } | 145 if (!(memReq->isUncacheable())) { 146 // Access memory to see if we have the same data 147 dcachePort->sendFunctional(pkt); 148 } else { 149 // Assume the data is correct if it's an uncached access 150 memcpy(&data, &unverifiedResult.integer, sizeof(T)); 151 } |
171 | 152 |
172 // Now do the access 173 if (fault == NoFault && 174 !memReq->getFlags().isSet(Request::NO_ACCESS)) { 175 PacketPtr pkt = new Packet(memReq, 176 memReq->isLLSC() ? 177 MemCmd::LoadLockedReq : MemCmd::ReadReq, 178 Packet::Broadcast); | 153 delete pkt; |
179 | 154 |
180 pkt->dataStatic(data); | 155 return NoFault; 156} |
181 | 157 |
182 if (!(memReq->isUncacheable() || memReq->isMmappedIpr())) { 183 // Access memory to see if we have the same data 184 dcachePort->sendFunctional(pkt); 185 } else { 186 // Assume the data is correct if it's an uncached access 187 memcpy(data, unverifiedMemData, size); 188 } | 158#ifndef DOXYGEN_SHOULD_SKIP_THIS |
189 | 159 |
190 delete memReq; 191 memReq = NULL; 192 delete pkt; 193 } | 160template 161Fault 162CheckerCPU::read(Addr addr, uint64_t &data, unsigned flags); |
194 | 163 |
195 if (fault != NoFault) { 196 if (memReq->isPrefetch()) { 197 fault = NoFault; 198 } 199 delete memReq; 200 memReq = NULL; 201 break; 202 } | 164template 165Fault 166CheckerCPU::read(Addr addr, uint32_t &data, unsigned flags); |
203 | 167 |
204 if (memReq != NULL) { 205 delete memReq; 206 } | 168template 169Fault 170CheckerCPU::read(Addr addr, uint16_t &data, unsigned flags); |
207 | 171 |
208 //If we don't need to access a second cache line, stop now. 209 if (secondAddr <= addr) 210 { 211 break; 212 } | 172template 173Fault 174CheckerCPU::read(Addr addr, uint8_t &data, unsigned flags); |
213 | 175 |
214 // Setup for accessing next cache line 215 data += size; 216 unverifiedMemData += size; 217 size = addr + fullSize - secondAddr; 218 addr = secondAddr; 219 } | 176#endif //DOXYGEN_SHOULD_SKIP_THIS |
220 | 177 |
221 if (!flags_match) { 222 warn("%lli: Flags do not match CPU:%#x %#x %#x Checker:%#x %#x %#x\n", 223 curTick(), unverifiedReq->getVaddr(), unverifiedReq->getPaddr(), 224 unverifiedReq->getFlags(), addr, pAddr, flags); 225 handleError(); 226 } | 178template<> 179Fault 180CheckerCPU::read(Addr addr, double &data, unsigned flags) 181{ 182 return read(addr, *(uint64_t*)&data, flags); 183} |
227 | 184 |
228 return fault; | 185template<> 186Fault 187CheckerCPU::read(Addr addr, float &data, unsigned flags) 188{ 189 return read(addr, *(uint32_t*)&data, flags); |
229} 230 | 190} 191 |
192template<> |
|
231Fault | 193Fault |
232CheckerCPU::writeMem(uint8_t *data, unsigned size, 233 Addr addr, unsigned flags, uint64_t *res) | 194CheckerCPU::read(Addr addr, int32_t &data, unsigned flags) |
234{ | 195{ |
235 Fault fault = NoFault; 236 bool checked_flags = false; 237 bool flags_match = true; 238 Addr pAddr = 0x0; | 196 return read(addr, (uint32_t&)data, flags); 197} |
239 | 198 |
240 unsigned blockSize = dcachePort->peerBlockSize(); 241 int fullSize = size; | 199template <class T> 200Fault 201CheckerCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 202{ 203 // need to fill in CPU & thread IDs here 204 memReq = new Request(); |
242 | 205 |
243 Addr secondAddr = roundDown(addr + size - 1, blockSize); | 206 memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC()); |
244 | 207 |
245 if (secondAddr > addr) 246 size = secondAddr - addr; | 208 // translate to physical address 209 dtb->translateAtomic(memReq, tc, true); |
247 | 210 |
248 // Need to account for a multiple access like Atomic and Timing CPUs 249 while (1) { 250 memReq = new Request(); 251 memReq->setVirt(0, addr, size, flags, thread->pcState().instAddr()); | 211 // Can compare the write data and result only if it's cacheable, 212 // not a store conditional, or is a store conditional that 213 // succeeded. 214 // @todo: Verify that actual memory matches up with these values. 215 // Right now it only verifies that the instruction data is the 216 // same as what was in the request that got sent to memory; there 217 // is no verification that it is the same as what is in memory. 218 // This is because the LSQ would have to be snooped in the CPU to 219 // verify this data. 220 if (unverifiedReq && 221 !(unverifiedReq->isUncacheable()) && 222 (!(unverifiedReq->isLLSC()) || 223 ((unverifiedReq->isLLSC()) && 224 unverifiedReq->getExtraData() == 1))) { 225 T inst_data; 226/* 227 // This code would work if the LSQ allowed for snooping. 228 PacketPtr pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast); 229 pkt.dataStatic(&inst_data); |
252 | 230 |
253 // translate to physical address 254 fault = dtb->translateFunctional(memReq, tc, BaseTLB::Write); | 231 dcachePort->sendFunctional(pkt); |
255 | 232 |
256 if (!checked_flags && fault == NoFault && unverifiedReq) { 257 flags_match = checkFlags(unverifiedReq, memReq->getVaddr(), 258 memReq->getPaddr(), memReq->getFlags()); 259 pAddr = memReq->getPaddr(); 260 checked_flags = true; | 233 delete pkt; 234*/ 235 memcpy(&inst_data, unverifiedMemData, sizeof(T)); 236 237 if (data != inst_data) { 238 warn("%lli: Store value does not match value in memory! " 239 "Instruction: %#x, memory: %#x", 240 curTick(), inst_data, data); 241 handleError(); |
261 } | 242 } |
243 } |
|
262 | 244 |
263 /* 264 * We don't actually check memory for the store because there 265 * is no guarantee it has left the lsq yet, and therefore we 266 * can't verify the memory on stores without lsq snooping 267 * enabled. This is left as future work for the Checker: LSQ snooping 268 * and memory validation after stores have committed. 269 */ | 245 // Assume the result was the same as the one passed in. This checker 246 // doesn't check if the SC should succeed or fail, it just checks the 247 // value. 248 if (res && unverifiedReq->scResultValid()) 249 *res = unverifiedReq->getExtraData(); |
270 | 250 |
271 delete memReq; | 251 return NoFault; 252} |
272 | 253 |
273 //If we don't need to access a second cache line, stop now. 274 if (fault != NoFault || secondAddr <= addr) 275 { 276 if (fault != NoFault && memReq->isPrefetch()) { 277 fault = NoFault; 278 } 279 break; 280 } | |
281 | 254 |
282 //Update size and access address 283 size = addr + fullSize - secondAddr; 284 //And access the right address. 285 addr = secondAddr; 286 } | 255#ifndef DOXYGEN_SHOULD_SKIP_THIS 256template 257Fault 258CheckerCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res); |
287 | 259 |
288 if (!flags_match) { 289 warn("%lli: Flags do not match CPU:%#x %#x Checker:%#x %#x %#x\n", 290 curTick(), unverifiedReq->getVaddr(), unverifiedReq->getPaddr(), 291 unverifiedReq->getFlags(), addr, pAddr, flags); 292 handleError(); 293 } | 260template 261Fault 262CheckerCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res); |
294 | 263 |
295 // Assume the result was the same as the one passed in. This checker 296 // doesn't check if the SC should succeed or fail, it just checks the 297 // value. 298 if (unverifiedReq && res && unverifiedReq->extraDataValid()) 299 *res = unverifiedReq->getExtraData(); | 264template 265Fault 266CheckerCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res); |
300 | 267 |
301 // Entire purpose here is to make sure we are getting the 302 // same data to send to the mem system as the CPU did. 303 // Cannot check this is actually what went to memory because 304 // there stores can be in ld/st queue or coherent operations 305 // overwriting values. 306 bool extraData; 307 if (unverifiedReq) { 308 extraData = unverifiedReq->extraDataValid() ? 309 unverifiedReq->getExtraData() : 1; 310 } | 268template 269Fault 270CheckerCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res); |
311 | 271 |
312 if (unverifiedReq && unverifiedMemData && 313 memcmp(data, unverifiedMemData, fullSize) && extraData) { 314 warn("%lli: Store value does not match value sent to memory!\ 315 data: %#x inst_data: %#x", curTick(), data, 316 unverifiedMemData); 317 handleError(); 318 } | 272#endif //DOXYGEN_SHOULD_SKIP_THIS |
319 | 273 |
320 return fault; | 274template<> 275Fault 276CheckerCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 277{ 278 return write(*(uint64_t*)&data, addr, flags, res); |
321} 322 | 279} 280 |
323#if FULL_SYSTEM | 281template<> 282Fault 283CheckerCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 284{ 285 return write(*(uint32_t*)&data, addr, flags, res); 286} 287 288template<> 289Fault 290CheckerCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 291{ 292 return write((uint32_t)data, addr, flags, res); 293} 294 295 |
324Addr 325CheckerCPU::dbg_vtophys(Addr addr) 326{ 327 return vtophys(tc, addr); 328} | 296Addr 297CheckerCPU::dbg_vtophys(Addr addr) 298{ 299 return vtophys(tc, addr); 300} |
329#endif // FULL_SYSTEM | |
330 | 301 |
331/** 332 * Checks if the flags set by the Checker and Checkee match. 333 */ | |
334bool | 302bool |
335CheckerCPU::checkFlags(Request *unverified_req, Addr vAddr, 336 Addr pAddr, int flags) | 303CheckerCPU::checkFlags(Request *req) |
337{ | 304{ |
338 Addr unverifiedVAddr = unverified_req->getVaddr(); 339 Addr unverifiedPAddr = unverified_req->getPaddr(); 340 int unverifiedFlags = unverified_req->getFlags(); 341 342 if (unverifiedVAddr != vAddr || 343 unverifiedPAddr != pAddr || 344 unverifiedFlags != flags) { | 305 // Remove any dynamic flags that don't have to do with the request itself. 306 unsigned flags = unverifiedReq->getFlags(); 307 unsigned mask = LOCKED | PHYSICAL | VPTE | ALTMODE | UNCACHEABLE | PREFETCH; 308 flags = flags & (mask); 309 if (flags == req->getFlags()) { |
345 return false; | 310 return false; |
311 } else { 312 return true; |
|
346 } | 313 } |
347 348 return true; | |
349} 350 351void 352CheckerCPU::dumpAndExit() 353{ | 314} 315 316void 317CheckerCPU::dumpAndExit() 318{ |
354 warn("%lli: Checker PC:%s", 355 curTick(), thread->pcState()); | 319 warn("%lli: Checker PC:%#x, next PC:%#x", 320 curTick(), thread->readPC(), thread->readNextPC()); |
356 panic("Checker found an error!"); 357} | 321 panic("Checker found an error!"); 322} |