1a2,13
> * Copyright (c) 2011 ARM Limited
> * All rights reserved
> *
> * The license below extends only to copyright in the software and shall
> * not be construed as granting a license to any other intellectual
> * property including but not limited to intellectual property relating
> * to a hardware implementation of the functionality of the software
> * licensed hereunder. You may use the software subject to the license
> * terms below provided that you ensure that this notice is replicated
> * unmodified and in its entirety in all distributions of the software,
> * modified or unmodified, in source code or in binary form.
> *
28a41
> * Geoffrey Blake
38a52,53
> #include "params/CheckerCPU.hh"
> #include "sim/tlb.hh"
46,47c61
< //The CheckerCPU does alpha only
< using namespace AlphaISA;
---
> using namespace TheISA;
57a72,73
> curStaticInst = NULL;
> curMacroStaticInst = NULL;
69d84
< #if FULL_SYSTEM
71a87
> #if FULL_SYSTEM
74,75c90,92
< process = p->process;
< thread = new SimpleThread(this, /* thread_num */ 0, process);
---
> workload = p->workload;
> // XXX: This is a hack to get this to work some
> thread = new SimpleThread(this, /* thread_num */ 0, workload[0], itb, dtb);
81c98
< result.integer = 0;
---
> updateOnError = true;
118,124d134
< /*
< BaseCPU::serialize(os);
< SERIALIZE_SCALAR(inst);
< nameOut(os, csprintf("%s.xc", name()));
< thread->serialize(os);
< cacheCompletionEvent.serialize(os);
< */
130,134d139
< /*
< BaseCPU::unserialize(cp, section);
< UNSERIALIZE_SCALAR(inst);
< thread->unserialize(cp, csprintf("%s.xc", section));
< */
137d141
< template <class T>
139c143
< CheckerCPU::read(Addr addr, T &data, unsigned flags)
---
> CheckerCPU::readMem(Addr addr, uint8_t *data, unsigned size, unsigned flags)
141,142c145,151
< // need to fill in CPU & thread IDs here
< memReq = new Request();
---
> Fault fault = NoFault;
> unsigned blockSize = dcachePort->peerBlockSize();
> int fullSize = size;
> Addr secondAddr = roundDown(addr + size - 1, blockSize);
> bool checked_flags = false;
> bool flags_match = true;
> Addr pAddr = 0x0;
144d152
< memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC());
146,147c154,155
< // translate to physical address
< dtb->translateAtomic(memReq, tc, false);
---
> if (secondAddr > addr)
> size = secondAddr - addr;
149c157,160
< PacketPtr pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast);
---
> // Need to account for multiple accesses like the Atomic and TimingSimple
> while (1) {
> memReq = new Request();
> memReq->setVirt(0, addr, size, flags, thread->pcState().instAddr());
151c162,163
< pkt->dataStatic(&data);
---
> // translate to physical address
> fault = dtb->translateFunctional(memReq, tc, BaseTLB::Read);
153,159c165,170
< if (!(memReq->isUncacheable())) {
< // Access memory to see if we have the same data
< dcachePort->sendFunctional(pkt);
< } else {
< // Assume the data is correct if it's an uncached access
< memcpy(&data, &unverifiedResult.integer, sizeof(T));
< }
---
> if (!checked_flags && fault == NoFault && unverifiedReq) {
> flags_match = checkFlags(unverifiedReq, memReq->getVaddr(),
> memReq->getPaddr(), memReq->getFlags());
> pAddr = memReq->getPaddr();
> checked_flags = true;
> }
161c172,178
< delete pkt;
---
> // Now do the access
> if (fault == NoFault &&
> !memReq->getFlags().isSet(Request::NO_ACCESS)) {
> PacketPtr pkt = new Packet(memReq,
> memReq->isLLSC() ?
> MemCmd::LoadLockedReq : MemCmd::ReadReq,
> Packet::Broadcast);
163,164c180
< return NoFault;
< }
---
> pkt->dataStatic(data);
166c182,188
< #ifndef DOXYGEN_SHOULD_SKIP_THIS
---
> if (!(memReq->isUncacheable() || memReq->isMmappedIpr())) {
> // Access memory to see if we have the same data
> dcachePort->sendFunctional(pkt);
> } else {
> // Assume the data is correct if it's an uncached access
> memcpy(data, unverifiedMemData, size);
> }
168,170c190,193
< template
< Fault
< CheckerCPU::read(Addr addr, uint64_t &data, unsigned flags);
---
> delete memReq;
> memReq = NULL;
> delete pkt;
> }
172,174c195,202
< template
< Fault
< CheckerCPU::read(Addr addr, uint32_t &data, unsigned flags);
---
> if (fault != NoFault) {
> if (memReq->isPrefetch()) {
> fault = NoFault;
> }
> delete memReq;
> memReq = NULL;
> break;
> }
176,178c204,206
< template
< Fault
< CheckerCPU::read(Addr addr, uint16_t &data, unsigned flags);
---
> if (memReq != NULL) {
> delete memReq;
> }
180,182c208,212
< template
< Fault
< CheckerCPU::read(Addr addr, uint8_t &data, unsigned flags);
---
> //If we don't need to access a second cache line, stop now.
> if (secondAddr <= addr)
> {
> break;
> }
184c214,219
< #endif //DOXYGEN_SHOULD_SKIP_THIS
---
> // Setup for accessing next cache line
> data += size;
> unverifiedMemData += size;
> size = addr + fullSize - secondAddr;
> addr = secondAddr;
> }
186,191c221,226
< template<>
< Fault
< CheckerCPU::read(Addr addr, double &data, unsigned flags)
< {
< return read(addr, *(uint64_t*)&data, flags);
< }
---
> if (!flags_match) {
> warn("%lli: Flags do not match CPU:%#x %#x %#x Checker:%#x %#x %#x\n",
> curTick(), unverifiedReq->getVaddr(), unverifiedReq->getPaddr(),
> unverifiedReq->getFlags(), addr, pAddr, flags);
> handleError();
> }
193,197c228
< template<>
< Fault
< CheckerCPU::read(Addr addr, float &data, unsigned flags)
< {
< return read(addr, *(uint32_t*)&data, flags);
---
> return fault;
200d230
< template<>
202c232,233
< CheckerCPU::read(Addr addr, int32_t &data, unsigned flags)
---
> CheckerCPU::writeMem(uint8_t *data, unsigned size,
> Addr addr, unsigned flags, uint64_t *res)
204,205c235,238
< return read(addr, (uint32_t&)data, flags);
< }
---
> Fault fault = NoFault;
> bool checked_flags = false;
> bool flags_match = true;
> Addr pAddr = 0x0;
207,212c240,241
< template <class T>
< Fault
< CheckerCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
< {
< // need to fill in CPU & thread IDs here
< memReq = new Request();
---
> unsigned blockSize = dcachePort->peerBlockSize();
> int fullSize = size;
214c243
< memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC());
---
> Addr secondAddr = roundDown(addr + size - 1, blockSize);
216,217c245,246
< // translate to physical address
< dtb->translateAtomic(memReq, tc, true);
---
> if (secondAddr > addr)
> size = secondAddr - addr;
219,237c248,251
< // Can compare the write data and result only if it's cacheable,
< // not a store conditional, or is a store conditional that
< // succeeded.
< // @todo: Verify that actual memory matches up with these values.
< // Right now it only verifies that the instruction data is the
< // same as what was in the request that got sent to memory; there
< // is no verification that it is the same as what is in memory.
< // This is because the LSQ would have to be snooped in the CPU to
< // verify this data.
< if (unverifiedReq &&
< !(unverifiedReq->isUncacheable()) &&
< (!(unverifiedReq->isLLSC()) ||
< ((unverifiedReq->isLLSC()) &&
< unverifiedReq->getExtraData() == 1))) {
< T inst_data;
< /*
< // This code would work if the LSQ allowed for snooping.
< PacketPtr pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast);
< pkt.dataStatic(&inst_data);
---
> // Need to account for a multiple access like Atomic and Timing CPUs
> while (1) {
> memReq = new Request();
> memReq->setVirt(0, addr, size, flags, thread->pcState().instAddr());
239c253,254
< dcachePort->sendFunctional(pkt);
---
> // translate to physical address
> fault = dtb->translateFunctional(memReq, tc, BaseTLB::Write);
241,249c256,260
< delete pkt;
< */
< memcpy(&inst_data, unverifiedMemData, sizeof(T));
<
< if (data != inst_data) {
< warn("%lli: Store value does not match value in memory! "
< "Instruction: %#x, memory: %#x",
< curTick(), inst_data, data);
< handleError();
---
> if (!checked_flags && fault == NoFault && unverifiedReq) {
> flags_match = checkFlags(unverifiedReq, memReq->getVaddr(),
> memReq->getPaddr(), memReq->getFlags());
> pAddr = memReq->getPaddr();
> checked_flags = true;
251d261
< }
253,257c263,269
< // Assume the result was the same as the one passed in. This checker
< // doesn't check if the SC should succeed or fail, it just checks the
< // value.
< if (res && unverifiedReq->scResultValid())
< *res = unverifiedReq->getExtraData();
---
> /*
> * We don't actually check memory for the store because there
> * is no guarantee it has left the lsq yet, and therefore we
> * can't verify the memory on stores without lsq snooping
> * enabled. This is left as future work for the Checker: LSQ snooping
> * and memory validation after stores have committed.
> */
259,260c271
< return NoFault;
< }
---
> delete memReq;
261a273,280
> //If we don't need to access a second cache line, stop now.
> if (fault != NoFault || secondAddr <= addr)
> {
> if (fault != NoFault && memReq->isPrefetch()) {
> fault = NoFault;
> }
> break;
> }
263,266c282,286
< #ifndef DOXYGEN_SHOULD_SKIP_THIS
< template
< Fault
< CheckerCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res);
---
> //Update size and access address
> size = addr + fullSize - secondAddr;
> //And access the right address.
> addr = secondAddr;
> }
268,270c288,293
< template
< Fault
< CheckerCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res);
---
> if (!flags_match) {
> warn("%lli: Flags do not match CPU:%#x %#x Checker:%#x %#x %#x\n",
> curTick(), unverifiedReq->getVaddr(), unverifiedReq->getPaddr(),
> unverifiedReq->getFlags(), addr, pAddr, flags);
> handleError();
> }
272,274c295,299
< template
< Fault
< CheckerCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res);
---
> // Assume the result was the same as the one passed in. This checker
> // doesn't check if the SC should succeed or fail, it just checks the
> // value.
> if (unverifiedReq && res && unverifiedReq->extraDataValid())
> *res = unverifiedReq->getExtraData();
276,278c301,310
< template
< Fault
< CheckerCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res);
---
> // Entire purpose here is to make sure we are getting the
> // same data to send to the mem system as the CPU did.
> // Cannot check this is actually what went to memory because
> // there stores can be in ld/st queue or coherent operations
> // overwriting values.
> bool extraData;
> if (unverifiedReq) {
> extraData = unverifiedReq->extraDataValid() ?
> unverifiedReq->getExtraData() : 1;
> }
280c312,318
< #endif //DOXYGEN_SHOULD_SKIP_THIS
---
> if (unverifiedReq && unverifiedMemData &&
> memcmp(data, unverifiedMemData, fullSize) && extraData) {
> warn("%lli: Store value does not match value sent to memory!\
> data: %#x inst_data: %#x", curTick(), data,
> unverifiedMemData);
> handleError();
> }
282,286c320
< template<>
< Fault
< CheckerCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
< {
< return write(*(uint64_t*)&data, addr, flags, res);
---
> return fault;
289,303d322
< template<>
< Fault
< CheckerCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
< {
< return write(*(uint32_t*)&data, addr, flags, res);
< }
<
< template<>
< Fault
< CheckerCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
< {
< return write((uint32_t)data, addr, flags, res);
< }
<
<
311a331,333
> /**
> * Checks if the flags set by the Checker and Checkee match.
> */
313c335,336
< CheckerCPU::checkFlags(Request *req)
---
> CheckerCPU::checkFlags(Request *unverified_req, Addr vAddr,
> Addr pAddr, int flags)
315,319c338,344
< // Remove any dynamic flags that don't have to do with the request itself.
< unsigned flags = unverifiedReq->getFlags();
< unsigned mask = LOCKED | PHYSICAL | VPTE | ALTMODE | UNCACHEABLE | PREFETCH;
< flags = flags & (mask);
< if (flags == req->getFlags()) {
---
> Addr unverifiedVAddr = unverified_req->getVaddr();
> Addr unverifiedPAddr = unverified_req->getPaddr();
> int unverifiedFlags = unverified_req->getFlags();
>
> if (unverifiedVAddr != vAddr ||
> unverifiedPAddr != pAddr ||
> unverifiedFlags != flags) {
321,322d345
< } else {
< return true;
323a347,348
>
> return true;
329,330c354,355
< warn("%lli: Checker PC:%#x, next PC:%#x",
< curTick(), thread->readPC(), thread->readNextPC());
---
> warn("%lli: Checker PC:%s",
> curTick(), thread->pcState());