Check.cc revision 6899
1
2/*
3 * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
4 * Copyright (c) 2009 Advanced Micro Devices, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met: redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer;
11 * redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution;
14 * neither the name of the copyright holders nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31
32#include "cpu/rubytest/Check.hh"
33#include "mem/ruby/system/Sequencer.hh"
34#include "mem/ruby/system/System.hh"
35#include "mem/ruby/common/SubBlock.hh"
36
37Check::Check(const Address& address,
38             const Address& pc,
39             int _num_cpu_sequencers,
40             RubyTester* _tester)
41  : m_num_cpu_sequencers(_num_cpu_sequencers), m_tester_ptr(_tester)
42{
43  m_status = TesterStatus_Idle;
44
45  pickValue();
46  pickInitiatingNode();
47  changeAddress(address);
48  m_pc = pc;
49  m_access_mode = AccessModeType(random() % AccessModeType_NUM);
50  m_store_count = 0;
51}
52
53void Check::initiate()
54{
55  DPRINTF(RubyTest, "initiating\n");
56  debugPrint();
57
58  //
59  // currently no protocols support prefetches
60  //
61  if (false && (random() & 0xf) == 0) {
62    initiatePrefetch(); // Prefetch from random processor
63  }
64
65  if(m_status == TesterStatus_Idle) {
66    initiateAction();
67  } else if(m_status == TesterStatus_Ready) {
68    initiateCheck();
69  } else {
70    // Pending - do nothing
71    DPRINTF(RubyTest, "initiating action/check - failed: action/check is pending\n");
72  }
73}
74
75void Check::initiatePrefetch()
76{
77  DPRINTF(RubyTest, "initiating prefetch\n");
78
79  RubyTester::CpuPort* port
80    = safe_cast<RubyTester::CpuPort*> \
81    (m_tester_ptr->getCpuPort(random() % m_num_cpu_sequencers));
82
83  Request::Flags flags;
84  flags.set(Request::PREFETCH);
85
86  //
87  // Prefetches are assumed to be 0 sized
88  //
89  Request *req = new Request(m_address.getAddress(),
90                             0,
91                             flags,
92                             curTick,
93                             m_pc.getAddress());
94
95  Packet::Command cmd;
96
97  //
98  // 1 in 8 chance this will be an exclusive prefetch
99  //
100  if ((random() & 0x7) != 0) {
101    cmd = MemCmd::ReadReq;
102    //
103    // 50% chance that the request will be an instruction fetch
104    //
105    if ((random() & 0x1) == 0) {
106      flags.set(Request::INST_FETCH);
107    }
108  } else {
109    cmd = MemCmd::WriteReq;
110    flags.set(Request::PF_EXCLUSIVE);
111  }
112
113  PacketPtr pkt = new Packet(req, cmd, port->idx);
114
115  //
116  // push the subblock onto the sender state.  The sequencer will update the
117  // subblock on the return
118  //
119  pkt->senderState = new RubyTester::SenderState(m_address,
120                                                 req->getSize(),
121                                                 pkt->senderState);
122
123  if (port->sendTiming(pkt)) {
124    DPRINTF(RubyTest, "successfully initiated prefetch.\n");
125  } else {
126    //
127    // If the packet did not issue, must delete
128    //
129    RubyTester::SenderState* senderState =
130        safe_cast<RubyTester::SenderState*>(pkt->senderState);
131    pkt->senderState = senderState->saved;
132    delete senderState;
133    delete pkt->req;
134    delete pkt;
135
136    DPRINTF(RubyTest, "prefetch initiation failed because Port was busy.\n");
137  }
138}
139
140void Check::initiateAction()
141{
142  DPRINTF(RubyTest, "initiating Action\n");
143  assert(m_status == TesterStatus_Idle);
144
145  RubyTester::CpuPort* port
146    = safe_cast<RubyTester::CpuPort*> \
147    (m_tester_ptr->getCpuPort(random() % m_num_cpu_sequencers));
148
149  Request::Flags flags;
150
151  //
152  // Create the particular address for the next byte to be written
153  //
154  Address writeAddr(m_address.getAddress() + m_store_count);
155
156  //
157  // Stores are assumed to be 1 byte-sized
158  //
159  Request *req = new Request(writeAddr.getAddress(),
160                             1,
161                             flags,
162                             curTick,
163                             m_pc.getAddress());
164
165  Packet::Command cmd;
166
167  //
168  // 1 out of 8 chance, issue an atomic rather than a write
169  //
170//   if ((random() & 0x7) == 0) {
171//     cmd = MemCmd::SwapReq;
172//   } else {
173    cmd = MemCmd::WriteReq;
174//   }
175
176  PacketPtr pkt = new Packet(req, cmd, port->idx);
177  uint8_t* writeData = new uint8_t;
178  *writeData = m_value + m_store_count;
179  pkt->dataDynamic(writeData);
180
181  DPRINTF(RubyTest,
182          "data 0x%x check 0x%x\n",
183          *(pkt->getPtr<uint8_t>()),
184          *writeData);
185
186  //
187  // push the subblock onto the sender state.  The sequencer will update the
188  // subblock on the return
189  //
190  pkt->senderState = new RubyTester::SenderState(writeAddr,
191                                                 req->getSize(),
192                                                 pkt->senderState);
193
194  if (port->sendTiming(pkt)) {
195    DPRINTF(RubyTest, "initiating action - successful\n");
196    DPRINTF(RubyTest,
197            "status before action update: %s\n",
198            (TesterStatus_to_string(m_status)).c_str());
199    m_status = TesterStatus_Action_Pending;
200  } else {
201    //
202    // If the packet did not issue, must delete
203    // Note: No need to delete the data, the packet destructor will delete it
204    //
205    RubyTester::SenderState* senderState =
206        safe_cast<RubyTester::SenderState*>(pkt->senderState);
207    pkt->senderState = senderState->saved;
208    delete senderState;
209    delete pkt->req;
210    delete pkt;
211
212    DPRINTF(RubyTest, "failed to initiate action - sequencer not ready\n");
213  }
214
215  DPRINTF(RubyTest,
216          "status after action update: %s\n",
217          (TesterStatus_to_string(m_status)).c_str());
218}
219
220void Check::initiateCheck()
221{
222  DPRINTF(RubyTest, "Initiating Check\n");
223  assert(m_status == TesterStatus_Ready);
224
225  RubyTester::CpuPort* port
226    = safe_cast<RubyTester::CpuPort*> \
227    (m_tester_ptr->getCpuPort(random() % m_num_cpu_sequencers));
228
229  Request::Flags flags;
230
231  //
232  // Checks are sized depending on the number of bytes written
233  //
234  Request *req = new Request(m_address.getAddress(),
235                             CHECK_SIZE,
236                             flags,
237                             curTick,
238                             m_pc.getAddress());
239
240  //
241  // 50% chance that the request will be an instruction fetch
242  //
243  if ((random() & 0x1) == 0) {
244    flags.set(Request::INST_FETCH);
245  }
246
247  PacketPtr pkt = new Packet(req, MemCmd::ReadReq, port->idx);
248  uint8_t* dataArray = new uint8_t[CHECK_SIZE];
249  pkt->dataDynamicArray(dataArray);
250
251  //
252  // push the subblock onto the sender state.  The sequencer will update the
253  // subblock on the return
254  //
255  pkt->senderState = new RubyTester::SenderState(m_address,
256                                                 req->getSize(),
257                                                 pkt->senderState);
258
259  if (port->sendTiming(pkt)) {
260    DPRINTF(RubyTest, "initiating check - successful\n");
261    DPRINTF(RubyTest,
262            "status before check update: %s\n",
263            (TesterStatus_to_string(m_status)).c_str());
264    m_status = TesterStatus_Check_Pending;
265  } else {
266    //
267    // If the packet did not issue, must delete
268    // Note: No need to delete the data, the packet destructor will delete it
269    //
270    RubyTester::SenderState* senderState =
271        safe_cast<RubyTester::SenderState*>(pkt->senderState);
272    pkt->senderState = senderState->saved;
273    delete senderState;
274    delete pkt->req;
275    delete pkt;
276
277    DPRINTF(RubyTest, "failed to initiate check - cpu port not ready\n");
278  }
279
280  DPRINTF(RubyTest,
281          "status after check update: %s\n",
282          (TesterStatus_to_string(m_status)).c_str());
283}
284
285void Check::performCallback(NodeID proc, SubBlock* data)
286{
287  Address address = data->getAddress();
288  //  assert(getAddress() == address);  // This isn't exactly right since we now have multi-byte checks
289  assert(getAddress().getLineAddress() == address.getLineAddress());
290  assert(data != NULL);
291
292  DPRINTF(RubyTest, "RubyTester Callback\n");
293  debugPrint();
294
295  if (m_status == TesterStatus_Action_Pending) {
296    DPRINTF(RubyTest,
297            "Action callback write value: %d, currently %d\n",
298            (m_value + m_store_count),
299            data->getByte(0));
300    //
301    // Perform store one byte at a time
302    //
303    data->setByte(0, (m_value + m_store_count));
304    m_store_count++;
305    if (m_store_count == CHECK_SIZE) {
306      m_status = TesterStatus_Ready;
307    } else {
308      m_status = TesterStatus_Idle;
309    }
310    DPRINTF(RubyTest,
311            "Action callback return data now %d\n",
312            data->getByte(0));
313  } else if (m_status == TesterStatus_Check_Pending) {
314    DPRINTF(RubyTest, "Check callback\n");
315    // Perform load/check
316    for(int byte_number=0; byte_number<CHECK_SIZE; byte_number++) {
317      if (uint8(m_value+byte_number) != data->getByte(byte_number)) {
318        WARN_EXPR(proc);
319        WARN_EXPR(address);
320        WARN_EXPR(data);
321        WARN_EXPR(byte_number);
322        WARN_EXPR((int)m_value+byte_number);
323        WARN_EXPR((int)data->getByte(byte_number));
324        WARN_EXPR(*this);
325        WARN_EXPR(g_eventQueue_ptr->getTime());
326        ERROR_MSG("Action/check failure");
327      }
328    }
329    DPRINTF(RubyTest, "Action/check success\n");
330    debugPrint();
331
332    // successful check complete, increment complete
333    m_tester_ptr->incrementCheckCompletions();
334
335    m_status = TesterStatus_Idle;
336    pickValue();
337
338  } else {
339    WARN_EXPR(*this);
340    WARN_EXPR(proc);
341    WARN_EXPR(data);
342    WARN_EXPR(m_status);
343    WARN_EXPR(g_eventQueue_ptr->getTime());
344    ERROR_MSG("Unexpected TesterStatus");
345  }
346
347  DPRINTF(RubyTest, "proc: %d, Address: 0x%x\n", proc, getAddress().getLineAddress());
348  DPRINTF(RubyTest, "Callback done\n");
349  debugPrint();
350}
351
352void Check::changeAddress(const Address& address)
353{
354  assert((m_status == TesterStatus_Idle) || (m_status == TesterStatus_Ready));
355  m_status = TesterStatus_Idle;
356  m_address = address;
357  m_store_count = 0;
358}
359
360void Check::pickValue()
361{
362  assert(m_status == TesterStatus_Idle);
363  m_status = TesterStatus_Idle;
364  m_value = random() & 0xff; // One byte
365  m_store_count = 0;
366}
367
368void Check::pickInitiatingNode()
369{
370  assert((m_status == TesterStatus_Idle) || (m_status == TesterStatus_Ready));
371  m_status = TesterStatus_Idle;
372  m_initiatingNode = (random() % m_num_cpu_sequencers);
373  DPRINTF(RubyTest, "picked initiating node %d\n", m_initiatingNode);
374  m_store_count = 0;
375}
376
377void Check::print(ostream& out) const
378{
379  out << "["
380      << m_address << ", value: "
381      << (int) m_value << ", status: "
382      << m_status << ", initiating node: "
383      << m_initiatingNode << ", store_count: "
384      << m_store_count
385      << "]" << flush;
386}
387
388void Check::debugPrint()
389{
390  DPRINTF(RubyTest,
391        "[0x%x, value: %d, status: %s, initiating node: %d, store_count: %d]\n",
392          m_address.getAddress(),
393          (int)m_value,
394          (TesterStatus_to_string(m_status)).c_str(),
395          m_initiatingNode,
396          m_store_count);
397}
398