Check.cc revision 8184
12SN/A/* 21762SN/A * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 32SN/A * Copyright (c) 2009 Advanced Micro Devices, Inc. 42SN/A * All rights reserved. 52SN/A * 62SN/A * Redistribution and use in source and binary forms, with or without 72SN/A * modification, are permitted provided that the following conditions are 82SN/A * met: redistributions of source code must retain the above copyright 92SN/A * notice, this list of conditions and the following disclaimer; 102SN/A * redistributions in binary form must reproduce the above copyright 112SN/A * notice, this list of conditions and the following disclaimer in the 122SN/A * documentation and/or other materials provided with the distribution; 132SN/A * neither the name of the copyright holders nor the names of its 142SN/A * contributors may be used to endorse or promote products derived from 152SN/A * this software without specific prior written permission. 162SN/A * 172SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 182SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 192SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 202SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 212SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 222SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 232SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 242SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 252SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 262SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 272665Ssaidi@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 282665Ssaidi@eecs.umich.edu */ 292665Ssaidi@eecs.umich.edu 302SN/A#include "cpu/testers/rubytest/Check.hh" 312SN/A#include "mem/ruby/common/SubBlock.hh" 322090SN/A#include "mem/ruby/system/Sequencer.hh" 332090SN/A#include "mem/ruby/system/System.hh" 342SN/A 353614Sgblack@eecs.umich.edutypedef RubyTester::SenderState SenderState; 363614Sgblack@eecs.umich.edu 373614Sgblack@eecs.umich.eduCheck::Check(const Address& address, const Address& pc, 383614Sgblack@eecs.umich.edu int _num_cpu_sequencers, RubyTester* _tester) 392984Sgblack@eecs.umich.edu : m_num_cpu_sequencers(_num_cpu_sequencers), m_tester_ptr(_tester) 403614Sgblack@eecs.umich.edu{ 412147SN/A m_status = TesterStatus_Idle; 422166SN/A 432147SN/A pickValue(); 442167SN/A pickInitiatingNode(); 452167SN/A changeAddress(address); 462167SN/A m_pc = pc; 472147SN/A m_access_mode = RubyAccessMode(random() % RubyAccessMode_NUM); 482090SN/A m_store_count = 0; 492222SN/A} 502090SN/A 512201SN/Avoid 522201SN/ACheck::initiate() 532201SN/A{ 542112SN/A DPRINTF(RubyTest, "initiating\n"); 552174SN/A debugPrint(); 562680Sktlim@umich.edu 572174SN/A // currently no protocols support prefetches 582175SN/A if (false && (random() & 0xf) == 0) { 592222SN/A initiatePrefetch(); // Prefetch from random processor 602SN/A } 612SN/A 622203SN/A if (m_tester_ptr->getCheckFlush() && (random() & 0xff) == 0) { 632166SN/A initiateFlush(); // issue a Flush request from random processor 642166SN/A } 652203SN/A 662166SN/A if (m_status == TesterStatus_Idle) { 672222SN/A initiateAction(); 682166SN/A } else if (m_status == TesterStatus_Ready) { 692203SN/A initiateCheck(); 702166SN/A } else { 712222SN/A // Pending - do nothing 722203SN/A DPRINTF(RubyTest, 732166SN/A "initiating action/check - failed: action/check is pending\n"); 742166SN/A } 752203SN/A} 762166SN/A 772166SN/Avoid 782203SN/ACheck::initiatePrefetch() 792166SN/A{ 802222SN/A DPRINTF(RubyTest, "initiating prefetch\n"); 812166SN/A 822203SN/A int index = random() % m_num_cpu_sequencers; 832166SN/A RubyTester::CpuPort* port = 842222SN/A safe_cast<RubyTester::CpuPort*>(m_tester_ptr->getCpuPort(index)); 852203SN/A 862166SN/A Request::Flags flags; 872166SN/A flags.set(Request::PREFETCH); 882166SN/A 892166SN/A Packet::Command cmd; 902203SN/A 912166SN/A // 1 in 8 chance this will be an exclusive prefetch 922166SN/A if ((random() & 0x7) != 0) { 932166SN/A cmd = MemCmd::ReadReq; 942166SN/A 952203SN/A // 50% chance that the request will be an instruction fetch 962166SN/A if ((random() & 0x1) == 0) { 972166SN/A flags.set(Request::INST_FETCH); 982147SN/A } 992090SN/A } else { 1002147SN/A cmd = MemCmd::WriteReq; 1012147SN/A flags.set(Request::PF_EXCLUSIVE); 1022147SN/A } 1032222SN/A 1042112SN/A // Prefetches are assumed to be 0 sized 1052147SN/A Request *req = new Request(m_address.getAddress(), 0, flags, curTick(), 1062147SN/A m_pc.getAddress()); 1072222SN/A 1082147SN/A PacketPtr pkt = new Packet(req, cmd, port->idx); 1092090SN/A 1102147SN/A // push the subblock onto the sender state. The sequencer will 1112090SN/A // update the subblock on the return 1122201SN/A pkt->senderState = 1132201SN/A new SenderState(m_address, req->getSize(), pkt->senderState); 1142147SN/A 1152147SN/A if (port->sendTiming(pkt)) { 1162147SN/A DPRINTF(RubyTest, "successfully initiated prefetch.\n"); 1172222SN/A } else { 1182112SN/A // If the packet did not issue, must delete 1192147SN/A SenderState* senderState = safe_cast<SenderState*>(pkt->senderState); 1202147SN/A pkt->senderState = senderState->saved; 1212222SN/A delete senderState; 1222203SN/A delete pkt->req; 1232680Sktlim@umich.edu delete pkt; 1242203SN/A 1252147SN/A DPRINTF(RubyTest, 1262090SN/A "prefetch initiation failed because Port was busy.\n"); 1272147SN/A } 1282090SN/A} 1292201SN/A 1302201SN/Avoid 1312147SN/ACheck::initiateFlush() 1322147SN/A{ 1332147SN/A 1342222SN/A DPRINTF(RubyTest, "initiating Flush\n"); 1352112SN/A 1362147SN/A int index = random() % m_num_cpu_sequencers; 1372147SN/A RubyTester::CpuPort* port = 1382222SN/A safe_cast<RubyTester::CpuPort*>(m_tester_ptr->getCpuPort(index)); 1392147SN/A 1402090SN/A Request::Flags flags; 1412502SN/A 1422502SN/A Request *req = new Request(m_address.getAddress(), CHECK_SIZE, flags, curTick(), 1432502SN/A m_pc.getAddress()); 1442502SN/A 1452502SN/A Packet::Command cmd; 1462502SN/A 1472502SN/A cmd = MemCmd::FlushReq; 1482502SN/A 1492502SN/A PacketPtr pkt = new Packet(req, cmd, port->idx); 1502502SN/A 1512502SN/A // push the subblock onto the sender state. The sequencer will 1522502SN/A // update the subblock on the return 1532502SN/A pkt->senderState = 1542502SN/A new SenderState(m_address, req->getSize(), pkt->senderState); 1552502SN/A 1562502SN/A if (port->sendTiming(pkt)) { 1572680Sktlim@umich.edu DPRINTF(RubyTest, "initiating Flush - successful\n"); 1582502SN/A } 1592502SN/A} 1602502SN/A 1612502SN/Avoid 1622090SN/ACheck::initiateAction() 1632147SN/A{ 1642147SN/A DPRINTF(RubyTest, "initiating Action\n"); 1652147SN/A assert(m_status == TesterStatus_Idle); 1662222SN/A 1672112SN/A int index = random() % m_num_cpu_sequencers; 1682502SN/A RubyTester::CpuPort* port = 1692502SN/A safe_cast<RubyTester::CpuPort*>(m_tester_ptr->getCpuPort(index)); 1702502SN/A 1712502SN/A Request::Flags flags; 1722502SN/A 1732147SN/A // Create the particular address for the next byte to be written 1742147SN/A Address writeAddr(m_address.getAddress() + m_store_count); 1752222SN/A 1762147SN/A // Stores are assumed to be 1 byte-sized 1772090SN/A Request *req = new Request(writeAddr.getAddress(), 1, flags, curTick(), 1782502SN/A m_pc.getAddress()); 1792090SN/A 1802147SN/A Packet::Command cmd; 1812147SN/A 1822147SN/A // 1 out of 8 chance, issue an atomic rather than a write 1832222SN/A // if ((random() & 0x7) == 0) { 1842112SN/A // cmd = MemCmd::SwapReq; 1852502SN/A // } else { 1862502SN/A cmd = MemCmd::WriteReq; 1872502SN/A // } 1882502SN/A 1892502SN/A PacketPtr pkt = new Packet(req, cmd, port->idx); 1902147SN/A uint8_t* writeData = new uint8_t; 1912147SN/A *writeData = m_value + m_store_count; 1922222SN/A pkt->dataDynamic(writeData); 1932147SN/A 1942090SN/A DPRINTF(RubyTest, "data 0x%x check 0x%x\n", 1952502SN/A *(pkt->getPtr<uint8_t>()), *writeData); 1962090SN/A 1972147SN/A // push the subblock onto the sender state. The sequencer will 1982147SN/A // update the subblock on the return 1992147SN/A pkt->senderState = 2002222SN/A new SenderState(writeAddr, req->getSize(), pkt->senderState); 2012112SN/A 2022502SN/A if (port->sendTiming(pkt)) { 2032502SN/A DPRINTF(RubyTest, "initiating action - successful\n"); 2042502SN/A DPRINTF(RubyTest, "status before action update: %s\n", 2052502SN/A (TesterStatus_to_string(m_status)).c_str()); 2062502SN/A m_status = TesterStatus_Action_Pending; 2072147SN/A } else { 2082147SN/A // If the packet did not issue, must delete 2092222SN/A // Note: No need to delete the data, the packet destructor 2102147SN/A // will delete it 2112090SN/A SenderState* senderState = safe_cast<SenderState*>(pkt->senderState); 2122502SN/A pkt->senderState = senderState->saved; 2132090SN/A delete senderState; 2142147SN/A delete pkt->req; 2152147SN/A delete pkt; 2162147SN/A 2172222SN/A DPRINTF(RubyTest, "failed to initiate action - sequencer not ready\n"); 2182112SN/A } 2192502SN/A 2202502SN/A DPRINTF(RubyTest, "status after action update: %s\n", 2212502SN/A (TesterStatus_to_string(m_status)).c_str()); 2222502SN/A} 2232502SN/A 2242147SN/Avoid 2252147SN/ACheck::initiateCheck() 2262222SN/A{ 2272147SN/A DPRINTF(RubyTest, "Initiating Check\n"); 2282090SN/A assert(m_status == TesterStatus_Ready); 2292502SN/A 2302090SN/A int index = random() % m_num_cpu_sequencers; 2312147SN/A RubyTester::CpuPort* port = 2322147SN/A safe_cast<RubyTester::CpuPort*>(m_tester_ptr->getCpuPort(index)); 2332147SN/A 2342222SN/A Request::Flags flags; 2352112SN/A 2362502SN/A // 50% chance that the request will be an instruction fetch 2372502SN/A if ((random() & 0x1) == 0) { 2382502SN/A flags.set(Request::INST_FETCH); 2392502SN/A } 2402502SN/A 2412147SN/A // Checks are sized depending on the number of bytes written 2422147SN/A Request *req = new Request(m_address.getAddress(), CHECK_SIZE, flags, 2432222SN/A curTick(), m_pc.getAddress()); 2442147SN/A 2452090SN/A PacketPtr pkt = new Packet(req, MemCmd::ReadReq, port->idx); 2462502SN/A uint8_t* dataArray = new uint8_t[CHECK_SIZE]; 2472502SN/A pkt->dataDynamicArray(dataArray); 2482502SN/A 2492502SN/A // push the subblock onto the sender state. The sequencer will 2502502SN/A // update the subblock on the return 2512502SN/A pkt->senderState = 2522502SN/A new SenderState(m_address, req->getSize(), pkt->senderState); 2532502SN/A 2542505SN/A if (port->sendTiming(pkt)) { 2552505SN/A DPRINTF(RubyTest, "initiating check - successful\n"); 2562505SN/A DPRINTF(RubyTest, "status before check update: %s\n", 2572502SN/A TesterStatus_to_string(m_status).c_str()); 2582680Sktlim@umich.edu m_status = TesterStatus_Check_Pending; 2592502SN/A } else { 2602502SN/A // If the packet did not issue, must delete 2612502SN/A // Note: No need to delete the data, the packet destructor 2622502SN/A // will delete it 2632090SN/A SenderState* senderState = safe_cast<SenderState*>(pkt->senderState); 2642147SN/A pkt->senderState = senderState->saved; 2652147SN/A delete senderState; 2662147SN/A delete pkt->req; 2672222SN/A delete pkt; 2682112SN/A 2692502SN/A DPRINTF(RubyTest, "failed to initiate check - cpu port not ready\n"); 2702502SN/A } 2712502SN/A 2722147SN/A DPRINTF(RubyTest, "status after check update: %s\n", 2732147SN/A TesterStatus_to_string(m_status).c_str()); 2742222SN/A} 2752147SN/A 2762090SN/Avoid 2772502SN/ACheck::performCallback(NodeID proc, SubBlock* data) 2782090SN/A{ 2792147SN/A Address address = data->getAddress(); 2802147SN/A 2812147SN/A // This isn't exactly right since we now have multi-byte checks 2822222SN/A // assert(getAddress() == address); 2832112SN/A 2842502SN/A assert(getAddress().getLineAddress() == address.getLineAddress()); 2852502SN/A assert(data != NULL); 2862502SN/A 2872502SN/A DPRINTF(RubyTest, "RubyTester Callback\n"); 2882502SN/A debugPrint(); 2892502SN/A 2902502SN/A if (m_status == TesterStatus_Action_Pending) { 2912502SN/A DPRINTF(RubyTest, "Action callback write value: %d, currently %d\n", 2922502SN/A (m_value + m_store_count), data->getByte(0)); 2932502SN/A // Perform store one byte at a time 2942502SN/A data->setByte(0, (m_value + m_store_count)); 2952502SN/A m_store_count++; 2962502SN/A if (m_store_count == CHECK_SIZE) { 2972502SN/A m_status = TesterStatus_Ready; 2982502SN/A } else { 2992502SN/A m_status = TesterStatus_Idle; 3002502SN/A } 3012502SN/A DPRINTF(RubyTest, "Action callback return data now %d\n", 3022147SN/A data->getByte(0)); 3032147SN/A } else if (m_status == TesterStatus_Check_Pending) { 3042222SN/A DPRINTF(RubyTest, "Check callback\n"); 3052147SN/A // Perform load/check 3062090SN/A for (int byte_number=0; byte_number<CHECK_SIZE; byte_number++) { 3072147SN/A if (uint8(m_value + byte_number) != data->getByte(byte_number)) { 3082090SN/A panic("Action/check failure: proc: %d address: %s data: %s " 3092147SN/A "byte_number: %d m_value+byte_number: %d byte: %d %s" 3102147SN/A "Time: %d\n", 3112147SN/A proc, address, data, byte_number, 3122222SN/A (int)m_value + byte_number, 3132112SN/A (int)data->getByte(byte_number), *this, 3142147SN/A g_eventQueue_ptr->getTime()); 3152147SN/A } 3162222SN/A } 3172147SN/A DPRINTF(RubyTest, "Action/check success\n"); 3182090SN/A debugPrint(); 3192147SN/A 3202090SN/A // successful check complete, increment complete 3212147SN/A m_tester_ptr->incrementCheckCompletions(); 3222147SN/A 3232147SN/A m_status = TesterStatus_Idle; 3242222SN/A pickValue(); 3252112SN/A 3262147SN/A } else { 3272147SN/A panic("Unexpected TesterStatus: %s proc: %d data: %s m_status: %s " 3282222SN/A "time: %d\n", 3292147SN/A *this, proc, data, m_status, g_eventQueue_ptr->getTime()); 3302090SN/A } 3312147SN/A 3322090SN/A DPRINTF(RubyTest, "proc: %d, Address: 0x%x\n", proc, 3332201SN/A getAddress().getLineAddress()); 3342201SN/A DPRINTF(RubyTest, "Callback done\n"); 3352147SN/A debugPrint(); 3362147SN/A} 3372147SN/A 3382222SN/Avoid 3392112SN/ACheck::changeAddress(const Address& address) 3402147SN/A{ 3412147SN/A assert(m_status == TesterStatus_Idle || m_status == TesterStatus_Ready); 3422222SN/A m_status = TesterStatus_Idle; 3432147SN/A m_address = address; 3442090SN/A m_store_count = 0; 3452147SN/A} 3462090SN/A 3472147SN/Avoid 3482147SN/ACheck::pickValue() 3492147SN/A{ 3502222SN/A assert(m_status == TesterStatus_Idle); 3512112SN/A m_status = TesterStatus_Idle; 3522147SN/A m_value = random() & 0xff; // One byte 3532147SN/A m_store_count = 0; 3542222SN/A} 3552147SN/A 3562090SN/Avoid 3572167SN/ACheck::pickInitiatingNode() 3582167SN/A{ 3592SN/A assert(m_status == TesterStatus_Idle || m_status == TesterStatus_Ready); 360 m_status = TesterStatus_Idle; 361 m_initiatingNode = (random() % m_num_cpu_sequencers); 362 DPRINTF(RubyTest, "picked initiating node %d\n", m_initiatingNode); 363 m_store_count = 0; 364} 365 366void 367Check::print(std::ostream& out) const 368{ 369 out << "[" 370 << m_address << ", value: " 371 << (int)m_value << ", status: " 372 << m_status << ", initiating node: " 373 << m_initiatingNode << ", store_count: " 374 << m_store_count 375 << "]" << std::flush; 376} 377 378void 379Check::debugPrint() 380{ 381 DPRINTF(RubyTest, 382 "[%#x, value: %d, status: %s, initiating node: %d, store_count: %d]\n", 383 m_address.getAddress(), (int)m_value, 384 TesterStatus_to_string(m_status).c_str(), 385 m_initiatingNode, m_store_count); 386} 387