Check.cc revision 6899
16145SN/A
28688SN/A/*
36145SN/A * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
46145SN/A * Copyright (c) 2009 Advanced Micro Devices, Inc.
56145SN/A * All rights reserved.
66145SN/A *
76145SN/A * Redistribution and use in source and binary forms, with or without
86145SN/A * modification, are permitted provided that the following conditions are
96145SN/A * met: redistributions of source code must retain the above copyright
106145SN/A * notice, this list of conditions and the following disclaimer;
116145SN/A * redistributions in binary form must reproduce the above copyright
126145SN/A * notice, this list of conditions and the following disclaimer in the
136145SN/A * documentation and/or other materials provided with the distribution;
146145SN/A * neither the name of the copyright holders nor the names of its
156145SN/A * contributors may be used to endorse or promote products derived from
166145SN/A * this software without specific prior written permission.
176145SN/A *
186145SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
196145SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
206145SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
216145SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
226145SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
236145SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
246145SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
256145SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
266145SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
276145SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
286145SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
296145SN/A */
307039SN/A
317039SN/A
327039SN/A#include "cpu/rubytest/Check.hh"
336145SN/A#include "mem/ruby/system/Sequencer.hh"
346145SN/A#include "mem/ruby/system/System.hh"
357039SN/A#include "mem/ruby/common/SubBlock.hh"
367039SN/A
376145SN/ACheck::Check(const Address& address,
387039SN/A             const Address& pc,
399350SN/A             int _num_cpu_sequencers,
4011108Sdavid.hashe@amd.com             RubyTester* _tester)
4110301SN/A  : m_num_cpu_sequencers(_num_cpu_sequencers), m_tester_ptr(_tester)
4210301SN/A{
4310301SN/A  m_status = TesterStatus_Idle;
447039SN/A
459206SN/A  pickValue();
466145SN/A  pickInitiatingNode();
477039SN/A  changeAddress(address);
4810920SN/A  m_pc = pc;
496285SN/A  m_access_mode = AccessModeType(random() % AccessModeType_NUM);
509206SN/A  m_store_count = 0;
517039SN/A}
527039SN/A
538688SN/Avoid Check::initiate()
548688SN/A{
558688SN/A  DPRINTF(RubyTest, "initiating\n");
568688SN/A  debugPrint();
578688SN/A
5810919SN/A  //
598688SN/A  // currently no protocols support prefetches
608688SN/A  //
618688SN/A  if (false && (random() & 0xf) == 0) {
628688SN/A    initiatePrefetch(); // Prefetch from random processor
6310919SN/A  }
648688SN/A
658688SN/A  if(m_status == TesterStatus_Idle) {
668688SN/A    initiateAction();
678688SN/A  } else if(m_status == TesterStatus_Ready) {
686876SN/A    initiateCheck();
696876SN/A  } else {
707039SN/A    // Pending - do nothing
716145SN/A    DPRINTF(RubyTest, "initiating action/check - failed: action/check is pending\n");
727039SN/A  }
737039SN/A}
749504SN/A
759504SN/Avoid Check::initiatePrefetch()
769504SN/A{
7710837SN/A  DPRINTF(RubyTest, "initiating prefetch\n");
7810837SN/A
796285SN/A  RubyTester::CpuPort* port
8010525SN/A    = safe_cast<RubyTester::CpuPort*> \
8110918SN/A    (m_tester_ptr->getCpuPort(random() % m_num_cpu_sequencers));
8211294Sandreas.hansson@arm.com
8310525SN/A  Request::Flags flags;
847039SN/A  flags.set(Request::PREFETCH);
857039SN/A
867039SN/A  //
877039SN/A  // Prefetches are assumed to be 0 sized
8810012SN/A  //
8910012SN/A  Request *req = new Request(m_address.getAddress(),
907039SN/A                             0,
916285SN/A                             flags,
9211169Sandreas.hansson@arm.com                             curTick,
9310012SN/A                             m_pc.getAddress());
9411169Sandreas.hansson@arm.com
956285SN/A  Packet::Command cmd;
9611169Sandreas.hansson@arm.com
9711168Sandreas.hansson@arm.com  //
9811168Sandreas.hansson@arm.com  // 1 in 8 chance this will be an exclusive prefetch
9911168Sandreas.hansson@arm.com  //
1008688SN/A  if ((random() & 0x7) != 0) {
10111169Sandreas.hansson@arm.com    cmd = MemCmd::ReadReq;
1029270SN/A    //
1039270SN/A    // 50% chance that the request will be an instruction fetch
1047562SN/A    //
1058436SN/A    if ((random() & 0x1) == 0) {
1068436SN/A      flags.set(Request::INST_FETCH);
1078436SN/A    }
1088937SN/A  } else {
1098937SN/A    cmd = MemCmd::WriteReq;
1108937SN/A    flags.set(Request::PF_EXCLUSIVE);
1118937SN/A  }
1128937SN/A
1138937SN/A  PacketPtr pkt = new Packet(req, cmd, port->idx);
1148937SN/A
1157039SN/A  //
1167039SN/A  // push the subblock onto the sender state.  The sequencer will update the
1177039SN/A  // subblock on the return
1187039SN/A  //
1196285SN/A  pkt->senderState = new RubyTester::SenderState(m_address,
12010991SN/A                                                 req->getSize(),
12111061SN/A                                                 pkt->senderState);
12211061SN/A
12310991SN/A  if (port->sendTiming(pkt)) {
12411060SN/A    DPRINTF(RubyTest, "successfully initiated prefetch.\n");
12511060SN/A  } else {
12611061SN/A    //
12711060SN/A    // If the packet did not issue, must delete
12811061SN/A    //
1297039SN/A    RubyTester::SenderState* senderState =
1307039SN/A        safe_cast<RubyTester::SenderState*>(pkt->senderState);
1317039SN/A    pkt->senderState = senderState->saved;
1327039SN/A    delete senderState;
1339504SN/A    delete pkt->req;
1349504SN/A    delete pkt;
1359504SN/A
13610919SN/A    DPRINTF(RubyTest, "prefetch initiation failed because Port was busy.\n");
13710837SN/A  }
13810837SN/A}
13910837SN/A
14010525SN/Avoid Check::initiateAction()
14110706SN/A{
1427039SN/A  DPRINTF(RubyTest, "initiating Action\n");
14310012SN/A  assert(m_status == TesterStatus_Idle);
1449300SN/A
14510918SN/A  RubyTester::CpuPort* port
1469103SN/A    = safe_cast<RubyTester::CpuPort*> \
1477039SN/A    (m_tester_ptr->getCpuPort(random() % m_num_cpu_sequencers));
14810012SN/A
1498688SN/A  Request::Flags flags;
15010920SN/A
1516145SN/A  //
1526145SN/A  // Create the particular address for the next byte to be written
15310012SN/A  //
1546895SN/A  Address writeAddr(m_address.getAddress() + m_store_count);
1556895SN/A
15610919SN/A  //
1576895SN/A  // Stores are assumed to be 1 byte-sized
1586895SN/A  //
15910012SN/A  Request *req = new Request(writeAddr.getAddress(),
16010919SN/A                             1,
16110919SN/A                             flags,
1626895SN/A                             curTick,
1636895SN/A                             m_pc.getAddress());
1647039SN/A
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