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