gem5 [DEVELOP-FOR-25.0]
Loading...
Searching...
No Matches
Check.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
3 * Copyright (c) 2009 Advanced Micro Devices, Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met: redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer;
10 * redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution;
13 * neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
31
32#include "base/trace.hh"
33#include "debug/RubyTest.hh"
35
36namespace gem5
37{
38
40
41Check::Check(Addr address, Addr pc, int _num_writers, int _num_readers,
42 RubyTester* _tester)
43 : m_num_writers(_num_writers), m_num_readers(_num_readers),
44 m_tester_ptr(_tester)
45{
46 m_status = ruby::TesterStatus_Idle;
47
48 pickValue();
50 changeAddress(address);
51 m_pc = pc;
52 m_access_mode = ruby::RubyAccessMode(
53 rng->random(0, ruby::RubyAccessMode_NUM - 1));
54 m_store_count = 0;
55}
56
57void
59{
60 DPRINTF(RubyTest, "initiating\n");
61 debugPrint();
62
63 // currently no protocols support prefetches
64 if (false && (rng->random(0, 0xf) == 0)) {
65 // Prefetch from random processor
66 initiatePrefetch(current_time);
67 }
68
69 if (m_tester_ptr->getCheckFlush() && (rng->random(0, 0xff) == 0)) {
70 // issue a Flush request from random processor
71 initiateFlush(current_time);
72 }
73
74 if (m_status == ruby::TesterStatus_Idle) {
75 initiateAction(current_time);
76 } else if (m_status == ruby::TesterStatus_Ready) {
77 initiateCheck(current_time);
78 } else {
79 // Pending - do nothing
80 DPRINTF(RubyTest,
81 "initiating action/check - failed: action/check is pending\n");
82 }
83}
84
85void
87{
88 DPRINTF(RubyTest, "initiating prefetch\n");
89
90 int index = rng->random(0, m_num_readers - 1);
91 RequestPort* port = m_tester_ptr->getReadableCpuPort(index);
92
93 Request::Flags flags;
95
97
98 // 1 in 8 chance this will be an exclusive prefetch
99 if (rng->random(0, 0x7) != 0) {
100 cmd = MemCmd::ReadReq;
101
102 // if necessary, make the request an instruction fetch
103 if (m_tester_ptr->isInstOnlyCpuPort(index) ||
104 (m_tester_ptr->isInstDataCpuPort(index) &&
105 (rng->random(0, 0x1)))) {
107 }
108 } else {
109 cmd = MemCmd::WriteReq;
111 }
112
113 // Prefetches are assumed to be 0 sized
114 RequestPtr req = std::make_shared<Request>(
115 m_address, 0, flags, m_tester_ptr->requestorId());
116 req->setPC(m_pc);
117 req->setContext(index);
118
119 PacketPtr pkt = new Packet(req, cmd);
120 // despite the oddity of the 0 size (questionable if this should
121 // even be allowed), a prefetch is still a read and as such needs
122 // a place to store the result
123 uint8_t *data = new uint8_t[1];
124 pkt->dataDynamic(data);
125
126 // push the subblock onto the sender state. The sequencer will
127 // update the subblock on the return
128 pkt->senderState = new SenderState(m_address, req->getSize(),
130
131 if (port->sendTimingReq(pkt)) {
132 m_tester_ptr->updateProgress(index, m_address, current_time);
133 DPRINTF(RubyTest, "successfully initiated prefetch.\n");
134 } else {
135 // If the packet did not issue, must delete
136 delete pkt->senderState;
137 delete pkt;
138
139 DPRINTF(RubyTest,
140 "prefetch initiation failed because Port was busy.\n");
141 }
142}
143
144void
146{
147
148 DPRINTF(RubyTest, "initiating Flush\n");
149
150 int index = rng->random(0, m_num_writers - 1);
151 RequestPort* port = m_tester_ptr->getWritableCpuPort(index);
152
153 Request::Flags flags;
154
155 RequestPtr req = std::make_shared<Request>(
156 m_address, CHECK_SIZE, flags, m_tester_ptr->requestorId());
157 req->setPC(m_pc);
158
159 Packet::Command cmd;
160
161 cmd = MemCmd::FlushReq;
162
163 PacketPtr pkt = new Packet(req, cmd);
164
165 // push the subblock onto the sender state. The sequencer will
166 // update the subblock on the return
167 pkt->senderState = new SenderState(m_address, req->getSize(),
169
170 if (port->sendTimingReq(pkt)) {
171 m_tester_ptr->updateProgress(index, m_address, current_time);
172 DPRINTF(RubyTest, "initiating Flush - successful\n");
173 }
174}
175
176void
178{
179 DPRINTF(RubyTest, "initiating Action\n");
180 assert(m_status == ruby::TesterStatus_Idle);
181
182 int index = rng->random(0, m_num_writers - 1);
183 RequestPort* port = m_tester_ptr->getWritableCpuPort(index);
184
185 Request::Flags flags;
186
187 // Create the particular address for the next byte to be written
188 Addr writeAddr(m_address + m_store_count);
189
190 // Stores are assumed to be 1 byte-sized
191 RequestPtr req = std::make_shared<Request>(
192 writeAddr, 1, flags, m_tester_ptr->requestorId());
193 req->setPC(m_pc);
194
195 req->setContext(index);
196 Packet::Command cmd;
197
198 // 1 out of 8 chance, issue an atomic rather than a write
199 // if ((random() & 0x7) == 0) {
200 // cmd = MemCmd::SwapReq;
201 // } else {
202 cmd = MemCmd::WriteReq;
203 // }
204
205 PacketPtr pkt = new Packet(req, cmd);
206 uint8_t *writeData = new uint8_t[1];
207 *writeData = m_value + m_store_count;
208 pkt->dataDynamic(writeData);
209
210 DPRINTF(RubyTest, "Seq write: index %d data 0x%x check 0x%x\n", index,
211 *(pkt->getConstPtr<uint8_t>()), *writeData);
212
213 // push the subblock onto the sender state. The sequencer will
214 // update the subblock on the return
215 pkt->senderState = new SenderState(m_address, req->getSize(),
217
218 if (port->sendTimingReq(pkt)) {
219 DPRINTF(RubyTest, "initiating action - successful\n");
220 DPRINTF(RubyTest, "status before action update: %s\n",
221 (ruby::TesterStatus_to_string(m_status)).c_str());
222 m_status = ruby::TesterStatus_Action_Pending;
223 m_tester_ptr->updateProgress(index, m_address, current_time);
224 DPRINTF(RubyTest, "Check %#x, State=Action_Pending\n", m_address);
225 } else {
226 // If the packet did not issue, must delete
227 // Note: No need to delete the data, the packet destructor
228 // will delete it
229 delete pkt->senderState;
230 delete pkt;
231
232 DPRINTF(RubyTest, "failed to initiate action - sequencer not ready\n");
233 }
234
235 DPRINTF(RubyTest, "status after action update: %s\n",
236 (ruby::TesterStatus_to_string(m_status)).c_str());
237}
238
239void
241{
242 DPRINTF(RubyTest, "Initiating Check\n");
243 assert(m_status == ruby::TesterStatus_Ready);
244
245 int index = rng->random(0, m_num_readers - 1);
246 RequestPort* port = m_tester_ptr->getReadableCpuPort(index);
247
248 Request::Flags flags;
249
250 // If necessary, make the request an instruction fetch
251 if (m_tester_ptr->isInstOnlyCpuPort(index) ||
252 (m_tester_ptr->isInstDataCpuPort(index) &&
253 (rng->random(0, 0x1)))) {
255 }
256
257 // Checks are sized depending on the number of bytes written
258 RequestPtr req = std::make_shared<Request>(
259 m_address, CHECK_SIZE, flags, m_tester_ptr->requestorId());
260 req->setPC(m_pc);
261
262 req->setContext(index);
263 PacketPtr pkt = new Packet(req, MemCmd::ReadReq);
264 uint8_t *dataArray = new uint8_t[CHECK_SIZE];
265 pkt->dataDynamic(dataArray);
266
267 DPRINTF(RubyTest, "Seq read: index %d\n", index);
268
269 // push the subblock onto the sender state. The sequencer will
270 // update the subblock on the return
271 pkt->senderState = new SenderState(m_address, req->getSize(),
273
274 if (port->sendTimingReq(pkt)) {
275 DPRINTF(RubyTest, "initiating check - successful\n");
276 DPRINTF(RubyTest, "status before check update: %s\n",
277 ruby::TesterStatus_to_string(m_status).c_str());
278 m_status = ruby::TesterStatus_Check_Pending;
279 m_tester_ptr->updateProgress(index, m_address, current_time);
280 DPRINTF(RubyTest, "Check %#x, State=Check_Pending\n", m_address);
281 } else {
282 // If the packet did not issue, must delete
283 // Note: No need to delete the data, the packet destructor
284 // will delete it
285 delete pkt->senderState;
286 delete pkt;
287
288 DPRINTF(RubyTest, "failed to initiate check - cpu port not ready\n");
289 }
290
291 DPRINTF(RubyTest, "status after check update: %s\n",
292 ruby::TesterStatus_to_string(m_status).c_str());
293}
294
295void
297{
298 Addr address = data->getAddress();
299
300 // This isn't exactly right since we now have multi-byte checks
301 // assert(getAddress() == address);
302
303 int block_size_bits = CACHE_LINE_BITS;
304 assert(ruby::makeLineAddress(m_address, block_size_bits) ==
305 ruby::makeLineAddress(address, block_size_bits));
306 assert(data != NULL);
307
308 DPRINTF(RubyTest, "RubyTester Callback\n");
309 debugPrint();
310
311 if (m_status == ruby::TesterStatus_Action_Pending) {
312 DPRINTF(RubyTest, "Action callback write value: %d, currently %d\n",
313 (m_value + m_store_count), data->getByte(0));
314 // Perform store one byte at a time
315 data->setByte(0, (m_value + m_store_count));
317 if (m_store_count == CHECK_SIZE) {
318 m_status = ruby::TesterStatus_Ready;
319 DPRINTF(RubyTest, "Check %#x, State=Ready\n", m_address);
320 } else {
321 m_status = ruby::TesterStatus_Idle;
322 DPRINTF(RubyTest, "Check %#x, State=Idle store_count: %d\n",
324 }
325 DPRINTF(RubyTest, "Action callback return data now %d\n",
326 data->getByte(0));
327 } else if (m_status == ruby::TesterStatus_Check_Pending) {
328 DPRINTF(RubyTest, "Check callback\n");
329 // Perform load/check
330 for (int byte_number=0; byte_number<CHECK_SIZE; byte_number++) {
331 if (uint8_t(m_value + byte_number) != data->getByte(byte_number)) {
332 panic("Action/check failure: proc: %d address: %#x data: %s "
333 "byte_number: %d m_value+byte_number: %d byte: %d %s"
334 "Time: %d\n",
335 proc, address, data, byte_number,
336 (int)m_value + byte_number,
337 (int)data->getByte(byte_number), *this, curTime);
338 }
339 }
340 DPRINTF(RubyTest, "Action/check success\n");
341 debugPrint();
342
343 // successful check complete, increment complete
344 m_tester_ptr->incrementCheckCompletions();
345
346 m_status = ruby::TesterStatus_Idle;
347 DPRINTF(RubyTest, "Check %#x, State=Idle\n", m_address);
348 pickValue();
349
350 } else {
351 panic("Unexpected TesterStatus: %s proc: %d data: %s m_status: %s "
352 "time: %d\n", *this, proc, data, m_status, curTime);
353 }
354
355 DPRINTF(RubyTest, "proc: %d, Address: 0x%x\n", proc,
356 ruby::makeLineAddress(m_address, block_size_bits));
357 DPRINTF(RubyTest, "Callback done\n");
358 m_tester_ptr->eraseProgress(proc, m_address);
359 debugPrint();
360}
361
362void
364{
365 assert(m_status == ruby::TesterStatus_Idle ||
366 m_status == ruby::TesterStatus_Ready);
367 m_status = ruby::TesterStatus_Idle;
368 m_address = address;
369 DPRINTF(RubyTest, "Check %#x, State=Idle\n", m_address);
370 m_store_count = 0;
371}
372
373void
375{
376 assert(m_status == ruby::TesterStatus_Idle);
377 m_value = rng->random(0, 0xff); // One byte
378 m_store_count = 0;
379}
380
381void
383{
384 assert(m_status == ruby::TesterStatus_Idle ||
385 m_status == ruby::TesterStatus_Ready);
386 m_status = ruby::TesterStatus_Idle;
387 m_initiatingNode = (rng->random(0, m_num_writers - 1));
388 DPRINTF(RubyTest, "Check %#x, State=Idle, picked initiating node %d\n",
390 m_store_count = 0;
391}
392
393void
394Check::print(std::ostream& out) const
395{
396 out << "["
397 << m_address << ", value: "
398 << (int)m_value << ", status: "
399 << m_status << ", initiating node: "
400 << m_initiatingNode << ", store_count: "
402 << "]" << std::flush;
403}
404
405void
407{
408 DPRINTF(RubyTest,
409 "[%#x, value: %d, status: %s, initiating node: %d, store_count: %d]\n",
410 m_address, (int)m_value,
411 ruby::TesterStatus_to_string(m_status).c_str(),
413}
414
415} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:209
const char data[]
void initiateFlush(Cycles current_time)
Definition Check.cc:145
void changeAddress(Addr address)
Definition Check.cc:363
Addr m_pc
Definition Check.hh:83
ruby::RubyAccessMode m_access_mode
Definition Check.hh:84
void pickInitiatingNode()
Definition Check.cc:382
void print(std::ostream &out) const
Definition Check.cc:394
void initiatePrefetch(Cycles current_time)
Definition Check.cc:86
int m_store_count
Definition Check.hh:80
Random::RandomPtr rng
Definition Check.hh:88
void performCallback(ruby::NodeID proc, ruby::SubBlock *data, Cycles curTime)
Definition Check.cc:296
void pickValue()
Definition Check.cc:374
void initiate(Cycles current_time)
Definition Check.cc:58
Addr m_address
Definition Check.hh:82
void initiateCheck(Cycles current_time)
Definition Check.cc:240
RubyTester * m_tester_ptr
Definition Check.hh:87
ruby::NodeID m_initiatingNode
Definition Check.hh:81
void debugPrint()
Definition Check.cc:406
ruby::TesterStatus m_status
Definition Check.hh:78
uint8_t m_value
Definition Check.hh:79
Check(Addr address, Addr pc, int _num_writers, int _num_readers, RubyTester *_tester)
Definition Check.cc:41
int m_num_writers
Definition Check.hh:85
void initiateAction(Cycles current_time)
Definition Check.cc:177
int m_num_readers
Definition Check.hh:86
Cycles is a wrapper class for representing cycle counts, i.e.
Definition types.hh:79
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition packet.hh:295
SenderState * senderState
This packet's sender state.
Definition packet.hh:545
MemCmd::Command Command
Definition packet.hh:369
const T * getConstPtr() const
Definition packet.hh:1234
void dataDynamic(T *p)
Set the data pointer to a value that should have delete [] called on it.
Definition packet.hh:1213
A RequestPort is a specialisation of a Port, which implements the default protocol for the three diff...
Definition port.hh:136
bool sendTimingReq(PacketPtr pkt)
Attempt to send a timing request to the responder port by calling its corresponding receive function.
Definition port.hh:603
@ PF_EXCLUSIVE
The request should be prefetched into the exclusive state.
Definition request.hh:166
@ INST_FETCH
The request was an instruction fetch.
Definition request.hh:115
@ PREFETCH
The request is a prefetch.
Definition request.hh:164
gem5::Flags< FlagsType > Flags
Definition request.hh:102
void set(Type mask)
Set all flag's bits matching the given mask.
Definition flags.hh:116
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:220
Bitfield< 4 > pc
Bitfield< 30, 0 > index
Addr makeLineAddress(Addr addr, int cacheLineBits)
Definition Address.cc:61
unsigned int NodeID
Copyright (c) 2024 Arm Limited All rights reserved.
Definition binary32.hh:36
std::shared_ptr< Request > RequestPtr
Definition request.hh:94
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition types.hh:147
const int CHECK_SIZE
Definition Check.hh:50
Packet * PacketPtr
RubyTester::SenderState SenderState
Definition Check.cc:39
const int CACHE_LINE_BITS
Definition Check.hh:51

Generated on Mon May 26 2025 09:19:08 for gem5 by doxygen 1.13.2