gem5 v24.0.0.0
Loading...
Searching...
No Matches
cpu.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2011,2013,2017-2018, 2020 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
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
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
41#include "cpu/checker/cpu.hh"
42
43#include <list>
44#include <string>
45
46#include "arch/generic/tlb.hh"
47#include "cpu/base.hh"
48#include "cpu/simple_thread.hh"
49#include "cpu/static_inst.hh"
50#include "cpu/thread_context.hh"
51#include "cpu/utils.hh"
52#include "params/CheckerCPU.hh"
53#include "sim/full_system.hh"
54
55namespace gem5
56{
57
58void
64
66 : BaseCPU(p, true),
67 systemPtr(NULL), icachePort(NULL), dcachePort(NULL),
68 tc(NULL), thread(NULL),
69 unverifiedReq(nullptr),
70 unverifiedMemData(nullptr)
71{
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 = false;
82
83 exitOnError = p.exitOnError;
84 warnOnlyOnLoadError = p.warnOnlyOnLoadError;
85 mmu = p.mmu;
86 workload = p.workload;
87
88 updateOnError = true;
89}
90
94
95void
97{
98 const Params &p = params();
99
101
102 if (FullSystem) {
103 thread = new SimpleThread(this, 0, systemPtr, mmu, p.isa[0],
104 p.decoder[0]);
105 } else {
106 thread = new SimpleThread(this, 0, systemPtr,
107 workload.size() ? workload[0] : NULL,
108 mmu, p.isa[0], p.decoder[0]);
109 }
110
111 tc = thread->getTC();
112 threadContexts.push_back(tc);
113 // Thread should never be null after this
114 assert(thread != NULL);
115}
116
117void
119{
120 icachePort = icache_port;
121}
122
123void
125{
126 dcachePort = dcache_port;
127}
128
129void
130CheckerCPU::serialize(std::ostream &os) const
131{
132}
133
134void
138
142 const std::vector<bool>& byte_enable,
143 int& frag_size, int& size_left) const
144{
145 frag_size = std::min(
147 (Addr) size_left);
148 size_left -= frag_size;
149
150 RequestPtr mem_req;
151
152 // Set up byte-enable mask for the current fragment
153 auto it_start = byte_enable.cbegin() + (size - (frag_size +
154 size_left));
155 auto it_end = byte_enable.cbegin() + (size - size_left);
156 if (isAnyActiveElement(it_start, it_end)) {
157 mem_req = std::make_shared<Request>(frag_addr, frag_size,
159 tc->contextId());
160 mem_req->setByteEnable(std::vector<bool>(it_start, it_end));
161 }
162
163 return mem_req;
164}
165
166Fault
167CheckerCPU::readMem(Addr addr, uint8_t *data, unsigned size,
169 const std::vector<bool>& byte_enable)
170{
171 assert(byte_enable.size() == size);
172
173 Fault fault = NoFault;
174 bool checked_flags = false;
175 bool flags_match = true;
176 Addr pAddr = 0x0;
177
178 Addr frag_addr = addr;
179 int frag_size = 0;
180 int size_left = size;
181 bool predicate;
182
183 // Need to account for multiple accesses like the Atomic and TimingSimple
184 while (1) {
185 RequestPtr mem_req = genMemFragmentRequest(frag_addr, size, flags,
186 byte_enable, frag_size,
187 size_left);
188
189 predicate = (mem_req != nullptr);
190
191 // translate to physical address
192 if (predicate) {
193 fault = mmu->translateFunctional(mem_req, tc, BaseMMU::Read);
194 }
195
196 if (predicate && !checked_flags && fault == NoFault && unverifiedReq) {
197 flags_match = checkFlags(unverifiedReq, mem_req->getVaddr(),
198 mem_req->getPaddr(), mem_req->getFlags());
199 pAddr = mem_req->getPaddr();
200 checked_flags = true;
201 }
202
203 // Now do the access
204 if (predicate && fault == NoFault &&
205 !mem_req->getFlags().isSet(Request::NO_ACCESS)) {
206 PacketPtr pkt = Packet::createRead(mem_req);
207
208 pkt->dataStatic(data);
209
210 if (!(mem_req->isUncacheable() || mem_req->isLocalAccess())) {
211 // Access memory to see if we have the same data
213 } else {
214 // Assume the data is correct if it's an uncached access
215 memcpy(data, unverifiedMemData, frag_size);
216 }
217
218 delete pkt;
219 }
220
221 if (fault != NoFault) {
222 if (mem_req->isPrefetch()) {
223 fault = NoFault;
224 }
225 break;
226 }
227
228 //If we don't need to access a second cache line, stop now.
229 if (size_left == 0)
230 {
231 break;
232 }
233
234 // Setup for accessing next cache line
235 frag_addr += frag_size;
236 data += frag_size;
237 unverifiedMemData += frag_size;
238 }
239
240 if (!flags_match) {
241 warn("%lli: Flags do not match CPU:%#x %#x %#x Checker:%#x %#x %#x\n",
242 curTick(), unverifiedReq->getVaddr(), unverifiedReq->getPaddr(),
243 unverifiedReq->getFlags(), frag_addr, pAddr, flags);
244 handleError();
245 }
246
247 return fault;
248}
249
250Fault
251CheckerCPU::writeMem(uint8_t *data, unsigned size,
252 Addr addr, Request::Flags flags, uint64_t *res,
253 const std::vector<bool>& byte_enable)
254{
255 assert(byte_enable.size() == size);
256
257 Fault fault = NoFault;
258 bool checked_flags = false;
259 bool flags_match = true;
260 Addr pAddr = 0x0;
261 static uint8_t zero_data[64] = {};
262
263 Addr frag_addr = addr;
264 int frag_size = 0;
265 int size_left = size;
266 bool predicate;
267
268 // Need to account for a multiple access like Atomic and Timing CPUs
269 while (1) {
270 RequestPtr mem_req = genMemFragmentRequest(frag_addr, size, flags,
271 byte_enable, frag_size,
272 size_left);
273
274 predicate = (mem_req != nullptr);
275
276 if (predicate) {
277 fault = mmu->translateFunctional(mem_req, tc, BaseMMU::Write);
278 }
279
280 if (predicate && !checked_flags && fault == NoFault && unverifiedReq) {
281 flags_match = checkFlags(unverifiedReq, mem_req->getVaddr(),
282 mem_req->getPaddr(), mem_req->getFlags());
283 pAddr = mem_req->getPaddr();
284 checked_flags = true;
285 }
286
287 /*
288 * We don't actually check memory for the store because there
289 * is no guarantee it has left the lsq yet, and therefore we
290 * can't verify the memory on stores without lsq snooping
291 * enabled. This is left as future work for the Checker: LSQ snooping
292 * and memory validation after stores have committed.
293 */
294 bool was_prefetch = mem_req->isPrefetch();
295
296 //If we don't need to access a second cache line, stop now.
297 if (fault != NoFault || size_left == 0)
298 {
299 if (fault != NoFault && was_prefetch) {
300 fault = NoFault;
301 }
302 break;
303 }
304
305 frag_addr += frag_size;
306 }
307
308 if (!flags_match) {
309 warn("%lli: Flags do not match CPU:%#x %#x Checker:%#x %#x %#x\n",
310 curTick(), unverifiedReq->getVaddr(), unverifiedReq->getPaddr(),
311 unverifiedReq->getFlags(), frag_addr, pAddr, flags);
312 handleError();
313 }
314
315 // Assume the result was the same as the one passed in. This checker
316 // doesn't check if the SC should succeed or fail, it just checks the
317 // value.
318 if (unverifiedReq && res && unverifiedReq->extraDataValid())
319 *res = unverifiedReq->getExtraData();
320
321 // Entire purpose here is to make sure we are getting the
322 // same data to send to the mem system as the CPU did.
323 // Cannot check this is actually what went to memory because
324 // there stores can be in ld/st queue or coherent operations
325 // overwriting values.
326 bool extraData = false;
327 if (unverifiedReq) {
328 extraData = unverifiedReq->extraDataValid() ?
329 unverifiedReq->getExtraData() : true;
330 }
331
332 // If the request is to ZERO a cache block, there is no data to check
333 // against, but it's all zero. We need something to compare to, so use a
334 // const set of zeros.
336 assert(!data);
337 assert(sizeof(zero_data) <= size);
338 data = zero_data;
339 }
340
342 memcmp(data, unverifiedMemData, size) && extraData) {
343 warn("%lli: Store value does not match value sent to memory! "
344 "data: %#x inst_data: %#x", curTick(), data,
346 handleError();
347 }
348
349 return fault;
350}
351
355bool
356CheckerCPU::checkFlags(const RequestPtr &unverified_req, Addr vAddr,
357 Addr pAddr, int flags)
358{
359 Addr unverifiedVAddr = unverified_req->getVaddr();
360 Addr unverifiedPAddr = unverified_req->getPaddr();
361 int unverifiedFlags = unverified_req->getFlags();
362
363 if (unverifiedVAddr != vAddr ||
364 unverifiedPAddr != pAddr ||
365 unverifiedFlags != flags) {
366 return false;
367 }
368
369 return true;
370}
371
372void
374{
375 warn("%lli: Checker PC:%s",
376 curTick(), thread->pcState());
377 panic("Checker found an error!");
378}
379
380} // namespace gem5
const char data[]
System * system
Definition base.hh:392
Addr cacheLineSize() const
Get the cache line size of the system.
Definition base.hh:397
std::vector< ThreadContext * > threadContexts
Definition base.hh:260
virtual void setThreadContext(ThreadContext *_tc)
Definition isa.hh:85
virtual Fault translateFunctional(const RequestPtr &req, ThreadContext *tc, Mode mode)
Definition mmu.cc:118
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition cpu.cc:59
Fault readMem(Addr addr, uint8_t *data, unsigned size, Request::Flags flags, const std::vector< bool > &byte_enable) override
Definition cpu.cc:167
Counter numInst
Definition cpu.hh:142
RequestPort * icachePort
Definition cpu.hh:127
StaticInstPtr curStaticInst
Definition cpu.hh:138
Counter numLoad
Definition cpu.hh:159
bool updateOnError
Definition cpu.hh:434
void serialize(CheckpointOut &cp) const override
Serialize this object to the given output stream.
Definition cpu.cc:130
bool exitOnError
Definition cpu.hh:433
void setIcachePort(RequestPort *icache_port)
Definition cpu.cc:118
bool willChangePC
Definition cpu.hh:431
CheckerCPU(const Params &p)
Definition cpu.cc:65
void setSystem(System *system)
Definition cpu.cc:96
ThreadContext * tc
Definition cpu.hh:130
std::vector< Process * > workload
Definition cpu.hh:123
SimpleThread * thread
Definition cpu.hh:150
bool warnOnlyOnLoadError
Definition cpu.hh:435
Fault writeMem(uint8_t *data, unsigned size, Addr addr, Request::Flags flags, uint64_t *res, const std::vector< bool > &byte_enable) override
Definition cpu.cc:251
Counter startNumLoad
Definition cpu.hh:160
RequestPort * dcachePort
Definition cpu.hh:128
void handleError()
Definition cpu.hh:412
RequestorID requestorId
id attached to all issued requests
Definition cpu.hh:88
void unserialize(CheckpointIn &cp) override
Reconstruct the state of this object from a checkpoint.
Definition cpu.cc:135
bool changedPC
Definition cpu.hh:430
bool checkFlags(const RequestPtr &unverified_req, Addr vAddr, Addr pAddr, int flags)
Checks if the flags set by the Checker and Checkee match.
Definition cpu.cc:356
System * systemPtr
Definition cpu.hh:125
uint8_t * unverifiedMemData
Definition cpu.hh:428
InstSeqNum youngestSN
Definition cpu.hh:437
RequestPtr genMemFragmentRequest(Addr frag_addr, int size, Request::Flags flags, const std::vector< bool > &byte_enable, int &frag_size, int &size_left) const
Helper function used to generate the request for a single fragment of a memory access.
Definition cpu.cc:140
BaseMMU * mmu
Definition cpu.hh:132
void dumpAndExit()
Definition cpu.cc:373
RequestPtr unverifiedReq
Definition cpu.hh:427
void setDcachePort(RequestPort *dcache_port)
Definition cpu.cc:124
Counter startNumInst
Definition cpu.hh:143
StaticInstPtr curMacroStaticInst
Definition cpu.hh:139
virtual ~CheckerCPU()
Definition cpu.cc:91
ClockedObjectParams Params
Parameters of ClockedObject.
Addr instAddr() const
Returns the memory address of the instruction this PC points to.
Definition pcstate.hh:108
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition packet.hh:295
void dataStatic(T *p)
Set the data pointer to the following value that should not be freed.
Definition packet.hh:1175
static PacketPtr createRead(const RequestPtr &req)
Constructor-like methods that return Packets based on Request objects.
Definition packet.hh:1038
A RequestPort is a specialisation of a Port, which implements the default protocol for the three diff...
Definition port.hh:136
void sendFunctional(PacketPtr pkt) const
Send a functional request packet, where the data is instantly updated everywhere in the memory system...
Definition port.hh:579
@ NO_ACCESS
The request should not cause a memory access.
Definition request.hh:146
static const FlagsType STORE_NO_DATA
Definition request.hh:260
The SimpleThread object provides a combination of the ThreadState object and the ThreadContext interf...
const PCStateBase & pcState() const override
ThreadContext * getTC()
Returns the pointer to this SimpleThread's ThreadContext.
RequestorID getRequestorId(const SimObject *requestor, std::string subrequestor={})
Request an id used to create a request object in the system.
Definition system.cc:475
virtual BaseISA * getIsaPtr() const =0
virtual ContextID contextId() const =0
STL vector class.
Definition stl.hh:37
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:188
const Params & params() const
uint8_t flags
Definition helpers.cc:87
#define warn(...)
Definition logging.hh:256
Bitfield< 0 > p
Bitfield< 15 > system
Definition misc.hh:1032
Bitfield< 17 > os
Definition misc.hh:838
Bitfield< 3 > addr
Definition types.hh:84
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Definition binary32.hh:36
std::shared_ptr< FaultBase > Fault
Definition types.hh:249
std::shared_ptr< Request > RequestPtr
Definition request.hh:94
Tick curTick()
The universal simulation clock.
Definition cur_tick.hh:46
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition types.hh:147
Addr addrBlockOffset(Addr addr, Addr block_size)
Calculates the offset of a given address wrt aligned fixed-size blocks.
Definition utils.hh:53
bool FullSystem
The FullSystem variable can be used to determine the current mode of simulation.
Definition root.cc:220
constexpr decltype(nullptr) NoFault
Definition types.hh:253
bool isAnyActiveElement(const std::vector< bool >::const_iterator &it_start, const std::vector< bool >::const_iterator &it_end)
Test if there is any active element in an enablement range.
Definition utils.hh:89

Generated on Tue Jun 18 2024 16:24:01 for gem5 by doxygen 1.11.0