RubyTester.cc revision 9475:736909f5c13b
112870Sgabeblack@google.com/*
212870Sgabeblack@google.com * Copyright (c) 2012 ARM Limited
312870Sgabeblack@google.com * All rights reserved
412870Sgabeblack@google.com *
512870Sgabeblack@google.com * The license below extends only to copyright in the software and shall
612870Sgabeblack@google.com * not be construed as granting a license to any other intellectual
712870Sgabeblack@google.com * property including but not limited to intellectual property relating
812870Sgabeblack@google.com * to a hardware implementation of the functionality of the software
912870Sgabeblack@google.com * licensed hereunder.  You may use the software subject to the license
1012870Sgabeblack@google.com * terms below provided that you ensure that this notice is replicated
1112870Sgabeblack@google.com * unmodified and in its entirety in all distributions of the software,
1212870Sgabeblack@google.com * modified or unmodified, in source code or in binary form.
1312870Sgabeblack@google.com *
1412870Sgabeblack@google.com * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
1512870Sgabeblack@google.com * Copyright (c) 2009 Advanced Micro Devices, Inc.
1612870Sgabeblack@google.com * All rights reserved.
1712870Sgabeblack@google.com *
1812870Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without
1912870Sgabeblack@google.com * modification, are permitted provided that the following conditions are
2012870Sgabeblack@google.com * met: redistributions of source code must retain the above copyright
2112870Sgabeblack@google.com * notice, this list of conditions and the following disclaimer;
2212870Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright
2312870Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the
2412870Sgabeblack@google.com * documentation and/or other materials provided with the distribution;
2512870Sgabeblack@google.com * neither the name of the copyright holders nor the names of its
2612870Sgabeblack@google.com * contributors may be used to endorse or promote products derived from
2712870Sgabeblack@google.com * this software without specific prior written permission.
2812870Sgabeblack@google.com *
2912870Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3012870Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3112870Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3212870Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3313003Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3413003Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3512870Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3612870Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3712870Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3812870Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3913000Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4012870Sgabeblack@google.com */
4113003Sgabeblack@google.com
4212870Sgabeblack@google.com#include "base/misc.hh"
4312870Sgabeblack@google.com#include "cpu/testers/rubytest/Check.hh"
4412870Sgabeblack@google.com#include "cpu/testers/rubytest/RubyTester.hh"
4512870Sgabeblack@google.com#include "debug/RubyTest.hh"
4612870Sgabeblack@google.com#include "mem/ruby/common/Global.hh"
4712870Sgabeblack@google.com#include "mem/ruby/common/SubBlock.hh"
4812870Sgabeblack@google.com#include "mem/ruby/system/System.hh"
4912870Sgabeblack@google.com#include "sim/sim_exit.hh"
5012870Sgabeblack@google.com#include "sim/system.hh"
5112870Sgabeblack@google.com
5212870Sgabeblack@google.comRubyTester::RubyTester(const Params *p)
5312870Sgabeblack@google.com  : MemObject(p), checkStartEvent(this),
5412870Sgabeblack@google.com    _masterId(p->system->getMasterId(name())),
5512870Sgabeblack@google.com    m_num_cpus(p->num_cpus),
5612870Sgabeblack@google.com    m_checks_to_complete(p->checks_to_complete),
5712870Sgabeblack@google.com    m_deadlock_threshold(p->deadlock_threshold),
5812870Sgabeblack@google.com    m_wakeup_frequency(p->wakeup_frequency),
5912870Sgabeblack@google.com    m_check_flush(p->check_flush),
6012870Sgabeblack@google.com    m_num_inst_ports(p->port_cpuInstPort_connection_count)
6112870Sgabeblack@google.com{
6212870Sgabeblack@google.com    m_checks_completed = 0;
6312870Sgabeblack@google.com
6412870Sgabeblack@google.com    //
6512870Sgabeblack@google.com    // Create the requested inst and data ports and place them on the
6613003Sgabeblack@google.com    // appropriate read and write port lists.  The reason for the subtle
6712870Sgabeblack@google.com    // difference between inst and data ports vs. read and write ports is
6812870Sgabeblack@google.com    // from the tester's perspective, it only needs to know whether a port
6913003Sgabeblack@google.com    // supports reads (checks) or writes (actions).  Meanwhile, the protocol
7013003Sgabeblack@google.com    // controllers have data ports (support read and writes) or inst ports
7113003Sgabeblack@google.com    // (support only reads).
7213003Sgabeblack@google.com    // Note: the inst ports are the lowest elements of the readPort vector,
7313003Sgabeblack@google.com    // then the data ports are added to the readPort vector
7412870Sgabeblack@google.com    //
7512870Sgabeblack@google.com    for (int i = 0; i < p->port_cpuInstPort_connection_count; ++i) {
7612870Sgabeblack@google.com        readPorts.push_back(new CpuPort(csprintf("%s-instPort%d", name(), i),
7712870Sgabeblack@google.com                                        this, i));
7812870Sgabeblack@google.com    }
7912897Sgabeblack@google.com    for (int i = 0; i < p->port_cpuDataPort_connection_count; ++i) {
8012870Sgabeblack@google.com        CpuPort *port = new CpuPort(csprintf("%s-dataPort%d", name(), i),
8112870Sgabeblack@google.com                                    this, i);
8212870Sgabeblack@google.com        readPorts.push_back(port);
8312870Sgabeblack@google.com        writePorts.push_back(port);
8412870Sgabeblack@google.com    }
8512870Sgabeblack@google.com
8612870Sgabeblack@google.com    // add the check start event to the event queue
8712870Sgabeblack@google.com    schedule(checkStartEvent, 1);
8812870Sgabeblack@google.com}
8912870Sgabeblack@google.com
9012870Sgabeblack@google.comRubyTester::~RubyTester()
9112870Sgabeblack@google.com{
9212870Sgabeblack@google.com    delete m_checkTable_ptr;
9313002Sgabeblack@google.com    // Only delete the readPorts since the writePorts are just a subset
9413002Sgabeblack@google.com    for (int i = 0; i < readPorts.size(); i++)
9513002Sgabeblack@google.com        delete readPorts[i];
9612870Sgabeblack@google.com}
9712870Sgabeblack@google.com
9812870Sgabeblack@google.comvoid
9912870Sgabeblack@google.comRubyTester::init()
10012870Sgabeblack@google.com{
10112870Sgabeblack@google.com    assert(writePorts.size() > 0 && readPorts.size() > 0);
10212870Sgabeblack@google.com
10312870Sgabeblack@google.com    m_last_progress_vector.resize(m_num_cpus);
10412870Sgabeblack@google.com    for (int i = 0; i < m_last_progress_vector.size(); i++) {
10512870Sgabeblack@google.com        m_last_progress_vector[i] = 0;
10612870Sgabeblack@google.com    }
10712870Sgabeblack@google.com
10812870Sgabeblack@google.com    m_num_writers = writePorts.size();
10912870Sgabeblack@google.com    m_num_readers = readPorts.size();
11012870Sgabeblack@google.com
11112870Sgabeblack@google.com    m_checkTable_ptr = new CheckTable(m_num_writers, m_num_readers, this);
11212870Sgabeblack@google.com}
11312870Sgabeblack@google.com
11412870Sgabeblack@google.comBaseMasterPort &
11512870Sgabeblack@google.comRubyTester::getMasterPort(const std::string &if_name, PortID idx)
11612870Sgabeblack@google.com{
11712870Sgabeblack@google.com    if (if_name != "cpuInstPort" && if_name != "cpuDataPort") {
11812870Sgabeblack@google.com        // pass it along to our super class
11912870Sgabeblack@google.com        return MemObject::getMasterPort(if_name, idx);
12012870Sgabeblack@google.com    } else {
12112870Sgabeblack@google.com        if (if_name == "cpuInstPort") {
12212870Sgabeblack@google.com            if (idx > m_num_inst_ports) {
12312870Sgabeblack@google.com                panic("RubyTester::getMasterPort: unknown inst port idx %d\n",
12413034Sgabeblack@google.com                      idx);
12512870Sgabeblack@google.com            }
12612870Sgabeblack@google.com            //
12712870Sgabeblack@google.com            // inst ports directly map to the lowest readPort elements
12812870Sgabeblack@google.com            //
12912870Sgabeblack@google.com            return *readPorts[idx];
13012870Sgabeblack@google.com        } else {
13112870Sgabeblack@google.com            assert(if_name == "cpuDataPort");
13213000Sgabeblack@google.com            //
13313000Sgabeblack@google.com            // add the inst port offset to translate to the correct read port
13413000Sgabeblack@google.com            // index
13513000Sgabeblack@google.com            //
13613000Sgabeblack@google.com            int read_idx = idx + m_num_inst_ports;
13713000Sgabeblack@google.com            if (read_idx >= static_cast<PortID>(readPorts.size())) {
13813000Sgabeblack@google.com                panic("RubyTester::getMasterPort: unknown data port idx %d\n",
13913000Sgabeblack@google.com                      idx);
14013000Sgabeblack@google.com            }
14113000Sgabeblack@google.com            return *readPorts[read_idx];
14213000Sgabeblack@google.com        }
14313000Sgabeblack@google.com    }
14413000Sgabeblack@google.com}
14513100Sgabeblack@google.com
14613000Sgabeblack@google.combool
14713000Sgabeblack@google.comRubyTester::CpuPort::recvTimingResp(PacketPtr pkt)
14813000Sgabeblack@google.com{
14913000Sgabeblack@google.com    // retrieve the subblock and call hitCallback
15013000Sgabeblack@google.com    RubyTester::SenderState* senderState =
15112870Sgabeblack@google.com        safe_cast<RubyTester::SenderState*>(pkt->senderState);
15213100Sgabeblack@google.com    SubBlock* subblock = senderState->subBlock;
15312870Sgabeblack@google.com    assert(subblock != NULL);
15413003Sgabeblack@google.com
15513100Sgabeblack@google.com    // pop the sender state from the packet
15613100Sgabeblack@google.com    pkt->senderState = senderState->saved;
15713100Sgabeblack@google.com
15813000Sgabeblack@google.com    tester->hitCallback(id, subblock);
15913002Sgabeblack@google.com
16013002Sgabeblack@google.com    // Now that the tester has completed, delete the senderState
16113002Sgabeblack@google.com    // (includes sublock) and the packet, then return
16213001Sgabeblack@google.com    delete senderState;
16313001Sgabeblack@google.com    delete pkt->req;
16413001Sgabeblack@google.com    delete pkt;
16513001Sgabeblack@google.com    return true;
16613001Sgabeblack@google.com}
16713001Sgabeblack@google.com
16813100Sgabeblack@google.combool
16913002Sgabeblack@google.comRubyTester::isInstReadableCpuPort(int idx)
17013001Sgabeblack@google.com{
17113000Sgabeblack@google.com    return idx < m_num_inst_ports;
17213000Sgabeblack@google.com}
17313000Sgabeblack@google.com
17413000Sgabeblack@google.comMasterPort*
17513000Sgabeblack@google.comRubyTester::getReadableCpuPort(int idx)
17613000Sgabeblack@google.com{
17713000Sgabeblack@google.com    assert(idx >= 0 && idx < readPorts.size());
17813000Sgabeblack@google.com
17913000Sgabeblack@google.com    return readPorts[idx];
18012870Sgabeblack@google.com}
18113003Sgabeblack@google.com
18213003Sgabeblack@google.comMasterPort*
18313003Sgabeblack@google.comRubyTester::getWritableCpuPort(int idx)
18413003Sgabeblack@google.com{
18513003Sgabeblack@google.com    assert(idx >= 0 && idx < writePorts.size());
18613003Sgabeblack@google.com
18713003Sgabeblack@google.com    return writePorts[idx];
18813003Sgabeblack@google.com}
18913003Sgabeblack@google.com
19013003Sgabeblack@google.comvoid
19113055Sgabeblack@google.comRubyTester::hitCallback(NodeID proc, SubBlock* data)
19213055Sgabeblack@google.com{
19313055Sgabeblack@google.com    // Mark that we made progress
19413055Sgabeblack@google.com    m_last_progress_vector[proc] = curCycle();
19513055Sgabeblack@google.com
19613055Sgabeblack@google.com    DPRINTF(RubyTest, "completed request for proc: %d\n", proc);
19713055Sgabeblack@google.com    DPRINTF(RubyTest, "addr: 0x%x, size: %d, data: ",
19813055Sgabeblack@google.com            data->getAddress(), data->getSize());
19913055Sgabeblack@google.com    for (int byte = 0; byte < data->getSize(); byte++) {
20013055Sgabeblack@google.com        DPRINTF(RubyTest, "%d", data->getByte(byte));
20113003Sgabeblack@google.com    }
20213003Sgabeblack@google.com    DPRINTF(RubyTest, "\n");
20313003Sgabeblack@google.com
20413003Sgabeblack@google.com    // This tells us our store has 'completed' or for a load gives us
20513003Sgabeblack@google.com    // back the data to make the check
20613003Sgabeblack@google.com    Check* check_ptr = m_checkTable_ptr->getCheck(data->getAddress());
20713003Sgabeblack@google.com    assert(check_ptr != NULL);
20813003Sgabeblack@google.com    check_ptr->performCallback(proc, data, curCycle());
20913004Sgabeblack@google.com}
21013055Sgabeblack@google.com
21113055Sgabeblack@google.comvoid
21213056Sgabeblack@google.comRubyTester::wakeup()
21313056Sgabeblack@google.com{
21413037Sgabeblack@google.com    if (m_checks_completed < m_checks_to_complete) {
21513037Sgabeblack@google.com        // Try to perform an action or check
21613010Sgabeblack@google.com        Check* check_ptr = m_checkTable_ptr->getRandomCheck();
21713055Sgabeblack@google.com        assert(check_ptr != NULL);
21813003Sgabeblack@google.com        check_ptr->initiate();
21913003Sgabeblack@google.com
22013055Sgabeblack@google.com        checkForDeadlock();
22113055Sgabeblack@google.com
22213003Sgabeblack@google.com        schedule(checkStartEvent, curTick() + m_wakeup_frequency);
22313003Sgabeblack@google.com    } else {
22413003Sgabeblack@google.com        exitSimLoop("Ruby Tester completed");
22513003Sgabeblack@google.com    }
22613003Sgabeblack@google.com}
22713003Sgabeblack@google.com
22813003Sgabeblack@google.comvoid
22913003Sgabeblack@google.comRubyTester::checkForDeadlock()
23013003Sgabeblack@google.com{
23113003Sgabeblack@google.com    int size = m_last_progress_vector.size();
23213003Sgabeblack@google.com    Time current_time = curCycle();
23313003Sgabeblack@google.com    for (int processor = 0; processor < size; processor++) {
23413003Sgabeblack@google.com        if ((current_time - m_last_progress_vector[processor]) >
23513003Sgabeblack@google.com                m_deadlock_threshold) {
23613003Sgabeblack@google.com            panic("Deadlock detected: current_time: %d last_progress_time: %d "
23713005Sgabeblack@google.com                  "difference:  %d processor: %d\n",
23813005Sgabeblack@google.com                  current_time, m_last_progress_vector[processor],
23913003Sgabeblack@google.com                  current_time - m_last_progress_vector[processor], processor);
24013003Sgabeblack@google.com        }
24113003Sgabeblack@google.com    }
24213003Sgabeblack@google.com}
24313003Sgabeblack@google.com
24413003Sgabeblack@google.comvoid
24513003Sgabeblack@google.comRubyTester::print(std::ostream& out) const
24613003Sgabeblack@google.com{
24713005Sgabeblack@google.com    out << "[RubyTester]" << std::endl;
24813005Sgabeblack@google.com}
24913005Sgabeblack@google.com
25013003Sgabeblack@google.comRubyTester *
25113003Sgabeblack@google.comRubyTesterParams::create()
25213009Sgabeblack@google.com{
25313009Sgabeblack@google.com    return new RubyTester(this);
25413009Sgabeblack@google.com}
25513009Sgabeblack@google.com