ruby: added the GEMS ruby tester
This commit is contained in:
parent
4eb3bfc31b
commit
45230a4f6b
16 changed files with 1355 additions and 8 deletions
126
configs/example/rubytest.py
Normal file
126
configs/example/rubytest.py
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
# Copyright (c) 2006-2007 The Regents of The University of Michigan
|
||||||
|
# Copyright (c) 2009 Advanced Micro Devices, Inc.
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are
|
||||||
|
# met: redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer;
|
||||||
|
# redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution;
|
||||||
|
# neither the name of the copyright holders nor the names of its
|
||||||
|
# contributors may be used to endorse or promote products derived from
|
||||||
|
# this software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#
|
||||||
|
# Authors: Ron Dreslinski
|
||||||
|
# Brad Beckmann
|
||||||
|
|
||||||
|
import m5
|
||||||
|
from m5.objects import *
|
||||||
|
from m5.defines import buildEnv
|
||||||
|
from m5.util import addToPath
|
||||||
|
import os, optparse, sys
|
||||||
|
addToPath('../common')
|
||||||
|
addToPath('../ruby')
|
||||||
|
|
||||||
|
import Ruby
|
||||||
|
|
||||||
|
if buildEnv['FULL_SYSTEM']:
|
||||||
|
panic("This script requires system-emulation mode (*_SE).")
|
||||||
|
|
||||||
|
# Get paths we might need. It's expected this file is in m5/configs/example.
|
||||||
|
config_path = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
config_root = os.path.dirname(config_path)
|
||||||
|
m5_root = os.path.dirname(config_root)
|
||||||
|
|
||||||
|
parser = optparse.OptionParser()
|
||||||
|
|
||||||
|
parser.add_option("-l", "--checks", metavar="N", default=100,
|
||||||
|
help="Stop after N checks (loads)")
|
||||||
|
parser.add_option("-f", "--wakeup_freq", metavar="N", default=10,
|
||||||
|
help="Wakeup every N cycles")
|
||||||
|
|
||||||
|
#
|
||||||
|
# Set the default cache size and associativity to be very small to encourage
|
||||||
|
# races between requests and writebacks.
|
||||||
|
#
|
||||||
|
parser.add_option("--l1d_size", type="string", default="256B")
|
||||||
|
parser.add_option("--l1i_size", type="string", default="256B")
|
||||||
|
parser.add_option("--l2_size", type="string", default="512B")
|
||||||
|
parser.add_option("--l1d_assoc", type="int", default=2)
|
||||||
|
parser.add_option("--l1i_assoc", type="int", default=2)
|
||||||
|
parser.add_option("--l2_assoc", type="int", default=2)
|
||||||
|
|
||||||
|
execfile(os.path.join(config_root, "common", "Options.py"))
|
||||||
|
|
||||||
|
(options, args) = parser.parse_args()
|
||||||
|
|
||||||
|
if args:
|
||||||
|
print "Error: script doesn't take any positional arguments"
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Create the ruby random tester
|
||||||
|
#
|
||||||
|
tester = RubyTester(checks_to_complete = options.checks,
|
||||||
|
wakeup_frequency = options.wakeup_freq)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Create the M5 system. Note that the PhysicalMemory Object isn't
|
||||||
|
# actually used by the rubytester, but is included to support the
|
||||||
|
# M5 memory size == Ruby memory size checks
|
||||||
|
#
|
||||||
|
system = System(physmem = PhysicalMemory())
|
||||||
|
|
||||||
|
system.ruby = Ruby.create_system(options, system.physmem)
|
||||||
|
|
||||||
|
assert(options.num_cpus == len(system.ruby.cpu_ruby_ports))
|
||||||
|
|
||||||
|
#
|
||||||
|
# The tester is most effective when randomization is turned on and
|
||||||
|
# artifical delay is randomly inserted on messages
|
||||||
|
#
|
||||||
|
system.ruby.randomization = True
|
||||||
|
|
||||||
|
for ruby_port in system.ruby.cpu_ruby_ports:
|
||||||
|
#
|
||||||
|
# Tie the ruby tester ports to the ruby cpu ports
|
||||||
|
#
|
||||||
|
tester.cpuPort = ruby_port.port
|
||||||
|
|
||||||
|
#
|
||||||
|
# Tell each sequencer this is the ruby tester so that it
|
||||||
|
# copies the subblock back to the checker
|
||||||
|
#
|
||||||
|
ruby_port.using_ruby_tester = True
|
||||||
|
|
||||||
|
# -----------------------
|
||||||
|
# run simulation
|
||||||
|
# -----------------------
|
||||||
|
|
||||||
|
root = Root( system = system )
|
||||||
|
root.system.mem_mode = 'timing'
|
||||||
|
|
||||||
|
# Not much point in this being higher than the L1 latency
|
||||||
|
m5.ticks.setGlobalFrequency('1ns')
|
||||||
|
|
||||||
|
# instantiate configuration
|
||||||
|
m5.instantiate(root)
|
||||||
|
|
||||||
|
# simulate until program terminates
|
||||||
|
exit_event = m5.simulate(options.maxtick)
|
||||||
|
|
||||||
|
print 'Exiting @ tick', m5.curTick(), 'because', exit_event.getCause()
|
397
src/cpu/rubytest/Check.cc
Normal file
397
src/cpu/rubytest/Check.cc
Normal file
|
@ -0,0 +1,397 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
|
||||||
|
* Copyright (c) 2009 Advanced Micro Devices, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met: redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer;
|
||||||
|
* redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution;
|
||||||
|
* neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "cpu/rubytest/Check.hh"
|
||||||
|
#include "mem/ruby/system/Sequencer.hh"
|
||||||
|
#include "mem/ruby/system/System.hh"
|
||||||
|
#include "mem/ruby/common/SubBlock.hh"
|
||||||
|
|
||||||
|
Check::Check(const Address& address,
|
||||||
|
const Address& pc,
|
||||||
|
int _num_cpu_sequencers,
|
||||||
|
RubyTester* _tester)
|
||||||
|
: m_num_cpu_sequencers(_num_cpu_sequencers), m_tester_ptr(_tester)
|
||||||
|
{
|
||||||
|
m_status = TesterStatus_Idle;
|
||||||
|
|
||||||
|
pickValue();
|
||||||
|
pickInitiatingNode();
|
||||||
|
changeAddress(address);
|
||||||
|
m_pc = pc;
|
||||||
|
m_access_mode = AccessModeType(random() % AccessModeType_NUM);
|
||||||
|
m_store_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Check::initiate()
|
||||||
|
{
|
||||||
|
DPRINTF(RubyTest, "initiating\n");
|
||||||
|
debugPrint();
|
||||||
|
|
||||||
|
//
|
||||||
|
// currently no protocols support prefetches
|
||||||
|
//
|
||||||
|
if (false && (random() & 0xf) == 0) {
|
||||||
|
initiatePrefetch(); // Prefetch from random processor
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_status == TesterStatus_Idle) {
|
||||||
|
initiateAction();
|
||||||
|
} else if(m_status == TesterStatus_Ready) {
|
||||||
|
initiateCheck();
|
||||||
|
} else {
|
||||||
|
// Pending - do nothing
|
||||||
|
DPRINTF(RubyTest, "initiating action/check - failed: action/check is pending\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Check::initiatePrefetch()
|
||||||
|
{
|
||||||
|
DPRINTF(RubyTest, "initiating prefetch\n");
|
||||||
|
|
||||||
|
RubyTester::CpuPort* port
|
||||||
|
= safe_cast<RubyTester::CpuPort*> \
|
||||||
|
(m_tester_ptr->getCpuPort(random() % m_num_cpu_sequencers));
|
||||||
|
|
||||||
|
Request::Flags flags;
|
||||||
|
flags.set(Request::PREFETCH);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Prefetches are assumed to be 0 sized
|
||||||
|
//
|
||||||
|
Request *req = new Request(m_address.getAddress(),
|
||||||
|
0,
|
||||||
|
flags,
|
||||||
|
curTick,
|
||||||
|
m_pc.getAddress());
|
||||||
|
|
||||||
|
Packet::Command cmd;
|
||||||
|
|
||||||
|
//
|
||||||
|
// 1 in 8 chance this will be an exclusive prefetch
|
||||||
|
//
|
||||||
|
if ((random() & 0x7) != 0) {
|
||||||
|
cmd = MemCmd::ReadReq;
|
||||||
|
//
|
||||||
|
// 50% chance that the request will be an instruction fetch
|
||||||
|
//
|
||||||
|
if ((random() & 0x1) == 0) {
|
||||||
|
flags.set(Request::INST_FETCH);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cmd = MemCmd::WriteReq;
|
||||||
|
flags.set(Request::PF_EXCLUSIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
PacketPtr pkt = new Packet(req, cmd, port->idx);
|
||||||
|
|
||||||
|
//
|
||||||
|
// push the subblock onto the sender state. The sequencer will update the
|
||||||
|
// subblock on the return
|
||||||
|
//
|
||||||
|
pkt->senderState = new RubyTester::SenderState(m_address,
|
||||||
|
req->getSize(),
|
||||||
|
pkt->senderState);
|
||||||
|
|
||||||
|
if (port->sendTiming(pkt)) {
|
||||||
|
DPRINTF(RubyTest, "successfully initiated prefetch.\n");
|
||||||
|
} else {
|
||||||
|
//
|
||||||
|
// If the packet did not issue, must delete
|
||||||
|
//
|
||||||
|
RubyTester::SenderState* senderState =
|
||||||
|
safe_cast<RubyTester::SenderState*>(pkt->senderState);
|
||||||
|
pkt->senderState = senderState->saved;
|
||||||
|
delete senderState;
|
||||||
|
delete pkt->req;
|
||||||
|
delete pkt;
|
||||||
|
|
||||||
|
DPRINTF(RubyTest, "prefetch initiation failed because Port was busy.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Check::initiateAction()
|
||||||
|
{
|
||||||
|
DPRINTF(RubyTest, "initiating Action\n");
|
||||||
|
assert(m_status == TesterStatus_Idle);
|
||||||
|
|
||||||
|
RubyTester::CpuPort* port
|
||||||
|
= safe_cast<RubyTester::CpuPort*> \
|
||||||
|
(m_tester_ptr->getCpuPort(random() % m_num_cpu_sequencers));
|
||||||
|
|
||||||
|
Request::Flags flags;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Create the particular address for the next byte to be written
|
||||||
|
//
|
||||||
|
Address writeAddr(m_address.getAddress() + m_store_count);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Stores are assumed to be 1 byte-sized
|
||||||
|
//
|
||||||
|
Request *req = new Request(writeAddr.getAddress(),
|
||||||
|
1,
|
||||||
|
flags,
|
||||||
|
curTick,
|
||||||
|
m_pc.getAddress());
|
||||||
|
|
||||||
|
Packet::Command cmd;
|
||||||
|
|
||||||
|
//
|
||||||
|
// 1 out of 8 chance, issue an atomic rather than a write
|
||||||
|
//
|
||||||
|
// if ((random() & 0x7) == 0) {
|
||||||
|
// cmd = MemCmd::SwapReq;
|
||||||
|
// } else {
|
||||||
|
cmd = MemCmd::WriteReq;
|
||||||
|
// }
|
||||||
|
|
||||||
|
PacketPtr pkt = new Packet(req, cmd, port->idx);
|
||||||
|
uint8_t* writeData = new uint8_t;
|
||||||
|
*writeData = m_value + m_store_count;
|
||||||
|
pkt->dataDynamic(writeData);
|
||||||
|
|
||||||
|
DPRINTF(RubyTest,
|
||||||
|
"data 0x%x check 0x%x\n",
|
||||||
|
*(pkt->getPtr<uint8_t>()),
|
||||||
|
*writeData);
|
||||||
|
|
||||||
|
//
|
||||||
|
// push the subblock onto the sender state. The sequencer will update the
|
||||||
|
// subblock on the return
|
||||||
|
//
|
||||||
|
pkt->senderState = new RubyTester::SenderState(writeAddr,
|
||||||
|
req->getSize(),
|
||||||
|
pkt->senderState);
|
||||||
|
|
||||||
|
if (port->sendTiming(pkt)) {
|
||||||
|
DPRINTF(RubyTest, "initiating action - successful\n");
|
||||||
|
DPRINTF(RubyTest,
|
||||||
|
"status before action update: %s\n",
|
||||||
|
(TesterStatus_to_string(m_status)).c_str());
|
||||||
|
m_status = TesterStatus_Action_Pending;
|
||||||
|
} else {
|
||||||
|
//
|
||||||
|
// If the packet did not issue, must delete
|
||||||
|
// Note: No need to delete the data, the packet destructor will delete it
|
||||||
|
//
|
||||||
|
RubyTester::SenderState* senderState =
|
||||||
|
safe_cast<RubyTester::SenderState*>(pkt->senderState);
|
||||||
|
pkt->senderState = senderState->saved;
|
||||||
|
delete senderState;
|
||||||
|
delete pkt->req;
|
||||||
|
delete pkt;
|
||||||
|
|
||||||
|
DPRINTF(RubyTest, "failed to initiate action - sequencer not ready\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINTF(RubyTest,
|
||||||
|
"status after action update: %s\n",
|
||||||
|
(TesterStatus_to_string(m_status)).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Check::initiateCheck()
|
||||||
|
{
|
||||||
|
DPRINTF(RubyTest, "Initiating Check\n");
|
||||||
|
assert(m_status == TesterStatus_Ready);
|
||||||
|
|
||||||
|
RubyTester::CpuPort* port
|
||||||
|
= safe_cast<RubyTester::CpuPort*> \
|
||||||
|
(m_tester_ptr->getCpuPort(random() % m_num_cpu_sequencers));
|
||||||
|
|
||||||
|
Request::Flags flags;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Checks are sized depending on the number of bytes written
|
||||||
|
//
|
||||||
|
Request *req = new Request(m_address.getAddress(),
|
||||||
|
CHECK_SIZE,
|
||||||
|
flags,
|
||||||
|
curTick,
|
||||||
|
m_pc.getAddress());
|
||||||
|
|
||||||
|
//
|
||||||
|
// 50% chance that the request will be an instruction fetch
|
||||||
|
//
|
||||||
|
if ((random() & 0x1) == 0) {
|
||||||
|
flags.set(Request::INST_FETCH);
|
||||||
|
}
|
||||||
|
|
||||||
|
PacketPtr pkt = new Packet(req, MemCmd::ReadReq, port->idx);
|
||||||
|
uint8_t* dataArray = new uint8_t[CHECK_SIZE];
|
||||||
|
pkt->dataDynamicArray(dataArray);
|
||||||
|
|
||||||
|
//
|
||||||
|
// push the subblock onto the sender state. The sequencer will update the
|
||||||
|
// subblock on the return
|
||||||
|
//
|
||||||
|
pkt->senderState = new RubyTester::SenderState(m_address,
|
||||||
|
req->getSize(),
|
||||||
|
pkt->senderState);
|
||||||
|
|
||||||
|
if (port->sendTiming(pkt)) {
|
||||||
|
DPRINTF(RubyTest, "initiating check - successful\n");
|
||||||
|
DPRINTF(RubyTest,
|
||||||
|
"status before check update: %s\n",
|
||||||
|
(TesterStatus_to_string(m_status)).c_str());
|
||||||
|
m_status = TesterStatus_Check_Pending;
|
||||||
|
} else {
|
||||||
|
//
|
||||||
|
// If the packet did not issue, must delete
|
||||||
|
// Note: No need to delete the data, the packet destructor will delete it
|
||||||
|
//
|
||||||
|
RubyTester::SenderState* senderState =
|
||||||
|
safe_cast<RubyTester::SenderState*>(pkt->senderState);
|
||||||
|
pkt->senderState = senderState->saved;
|
||||||
|
delete senderState;
|
||||||
|
delete pkt->req;
|
||||||
|
delete pkt;
|
||||||
|
|
||||||
|
DPRINTF(RubyTest, "failed to initiate check - cpu port not ready\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINTF(RubyTest,
|
||||||
|
"status after check update: %s\n",
|
||||||
|
(TesterStatus_to_string(m_status)).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Check::performCallback(NodeID proc, SubBlock* data)
|
||||||
|
{
|
||||||
|
Address address = data->getAddress();
|
||||||
|
// assert(getAddress() == address); // This isn't exactly right since we now have multi-byte checks
|
||||||
|
assert(getAddress().getLineAddress() == address.getLineAddress());
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
DPRINTF(RubyTest, "RubyTester Callback\n");
|
||||||
|
debugPrint();
|
||||||
|
|
||||||
|
if (m_status == TesterStatus_Action_Pending) {
|
||||||
|
DPRINTF(RubyTest,
|
||||||
|
"Action callback write value: %d, currently %d\n",
|
||||||
|
(m_value + m_store_count),
|
||||||
|
data->getByte(0));
|
||||||
|
//
|
||||||
|
// Perform store one byte at a time
|
||||||
|
//
|
||||||
|
data->setByte(0, (m_value + m_store_count));
|
||||||
|
m_store_count++;
|
||||||
|
if (m_store_count == CHECK_SIZE) {
|
||||||
|
m_status = TesterStatus_Ready;
|
||||||
|
} else {
|
||||||
|
m_status = TesterStatus_Idle;
|
||||||
|
}
|
||||||
|
DPRINTF(RubyTest,
|
||||||
|
"Action callback return data now %d\n",
|
||||||
|
data->getByte(0));
|
||||||
|
} else if (m_status == TesterStatus_Check_Pending) {
|
||||||
|
DPRINTF(RubyTest, "Check callback\n");
|
||||||
|
// Perform load/check
|
||||||
|
for(int byte_number=0; byte_number<CHECK_SIZE; byte_number++) {
|
||||||
|
if (uint8(m_value+byte_number) != data->getByte(byte_number)) {
|
||||||
|
WARN_EXPR(proc);
|
||||||
|
WARN_EXPR(address);
|
||||||
|
WARN_EXPR(data);
|
||||||
|
WARN_EXPR(byte_number);
|
||||||
|
WARN_EXPR((int)m_value+byte_number);
|
||||||
|
WARN_EXPR((int)data->getByte(byte_number));
|
||||||
|
WARN_EXPR(*this);
|
||||||
|
WARN_EXPR(g_eventQueue_ptr->getTime());
|
||||||
|
ERROR_MSG("Action/check failure");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DPRINTF(RubyTest, "Action/check success\n");
|
||||||
|
debugPrint();
|
||||||
|
|
||||||
|
// successful check complete, increment complete
|
||||||
|
m_tester_ptr->incrementCheckCompletions();
|
||||||
|
|
||||||
|
m_status = TesterStatus_Idle;
|
||||||
|
pickValue();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
WARN_EXPR(*this);
|
||||||
|
WARN_EXPR(proc);
|
||||||
|
WARN_EXPR(data);
|
||||||
|
WARN_EXPR(m_status);
|
||||||
|
WARN_EXPR(g_eventQueue_ptr->getTime());
|
||||||
|
ERROR_MSG("Unexpected TesterStatus");
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINTF(RubyTest, "proc: %d, Address: 0x%x\n", proc, getAddress().getLineAddress());
|
||||||
|
DPRINTF(RubyTest, "Callback done\n");
|
||||||
|
debugPrint();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Check::changeAddress(const Address& address)
|
||||||
|
{
|
||||||
|
assert((m_status == TesterStatus_Idle) || (m_status == TesterStatus_Ready));
|
||||||
|
m_status = TesterStatus_Idle;
|
||||||
|
m_address = address;
|
||||||
|
m_store_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Check::pickValue()
|
||||||
|
{
|
||||||
|
assert(m_status == TesterStatus_Idle);
|
||||||
|
m_status = TesterStatus_Idle;
|
||||||
|
m_value = random() & 0xff; // One byte
|
||||||
|
m_store_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Check::pickInitiatingNode()
|
||||||
|
{
|
||||||
|
assert((m_status == TesterStatus_Idle) || (m_status == TesterStatus_Ready));
|
||||||
|
m_status = TesterStatus_Idle;
|
||||||
|
m_initiatingNode = (random() % m_num_cpu_sequencers);
|
||||||
|
DPRINTF(RubyTest, "picked initiating node %d\n", m_initiatingNode);
|
||||||
|
m_store_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Check::print(ostream& out) const
|
||||||
|
{
|
||||||
|
out << "["
|
||||||
|
<< m_address << ", value: "
|
||||||
|
<< (int) m_value << ", status: "
|
||||||
|
<< m_status << ", initiating node: "
|
||||||
|
<< m_initiatingNode << ", store_count: "
|
||||||
|
<< m_store_count
|
||||||
|
<< "]" << flush;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Check::debugPrint()
|
||||||
|
{
|
||||||
|
DPRINTF(RubyTest,
|
||||||
|
"[0x%x, value: %d, status: %s, initiating node: %d, store_count: %d]\n",
|
||||||
|
m_address.getAddress(),
|
||||||
|
(int)m_value,
|
||||||
|
(TesterStatus_to_string(m_status)).c_str(),
|
||||||
|
m_initiatingNode,
|
||||||
|
m_store_count);
|
||||||
|
}
|
105
src/cpu/rubytest/Check.hh
Normal file
105
src/cpu/rubytest/Check.hh
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
|
||||||
|
* Copyright (c) 2009 Advanced Micro Devices, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met: redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer;
|
||||||
|
* redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution;
|
||||||
|
* neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CHECK_H
|
||||||
|
#define CHECK_H
|
||||||
|
|
||||||
|
#include "mem/ruby/common/Global.hh"
|
||||||
|
#include "mem/ruby/common/Address.hh"
|
||||||
|
#include "mem/ruby/system/NodeID.hh"
|
||||||
|
#include "mem/protocol/TesterStatus.hh"
|
||||||
|
#include "mem/protocol/AccessModeType.hh"
|
||||||
|
#include "cpu/rubytest/RubyTester.hh"
|
||||||
|
class SubBlock;
|
||||||
|
|
||||||
|
const int CHECK_SIZE_BITS = 2;
|
||||||
|
const int CHECK_SIZE = (1<<CHECK_SIZE_BITS);
|
||||||
|
|
||||||
|
class Check {
|
||||||
|
public:
|
||||||
|
// Constructors
|
||||||
|
Check(const Address& address,
|
||||||
|
const Address& pc,
|
||||||
|
int _num_cpu_sequencer,
|
||||||
|
RubyTester* _tester);
|
||||||
|
|
||||||
|
// Default Destructor
|
||||||
|
//~Check();
|
||||||
|
|
||||||
|
// Public Methods
|
||||||
|
|
||||||
|
void initiate(); // Does Action or Check or nether
|
||||||
|
void performCallback(NodeID proc, SubBlock* data);
|
||||||
|
const Address& getAddress() { return m_address; }
|
||||||
|
void changeAddress(const Address& address);
|
||||||
|
|
||||||
|
void print(ostream& out) const;
|
||||||
|
private:
|
||||||
|
// Private Methods
|
||||||
|
void initiatePrefetch();
|
||||||
|
void initiateAction();
|
||||||
|
void initiateCheck();
|
||||||
|
|
||||||
|
void pickValue();
|
||||||
|
void pickInitiatingNode();
|
||||||
|
|
||||||
|
void debugPrint();
|
||||||
|
|
||||||
|
// Using default copy constructor and assignment operator
|
||||||
|
// Check(const Check& obj);
|
||||||
|
// Check& operator=(const Check& obj);
|
||||||
|
|
||||||
|
// Data Members (m_ prefix)
|
||||||
|
TesterStatus m_status;
|
||||||
|
uint8 m_value;
|
||||||
|
int m_store_count;
|
||||||
|
NodeID m_initiatingNode;
|
||||||
|
Address m_address;
|
||||||
|
Address m_pc;
|
||||||
|
AccessModeType m_access_mode;
|
||||||
|
int m_num_cpu_sequencers;
|
||||||
|
RubyTester* m_tester_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Output operator declaration
|
||||||
|
ostream& operator<<(ostream& out, const Check& obj);
|
||||||
|
|
||||||
|
// ******************* Definitions *******************
|
||||||
|
|
||||||
|
// Output operator definition
|
||||||
|
extern inline
|
||||||
|
ostream& operator<<(ostream& out, const Check& obj)
|
||||||
|
{
|
||||||
|
obj.print(out);
|
||||||
|
out << flush;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //CHECK_H
|
130
src/cpu/rubytest/CheckTable.cc
Normal file
130
src/cpu/rubytest/CheckTable.cc
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
|
||||||
|
* Copyright (c) 2009 Advanced Micro Devices, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met: redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer;
|
||||||
|
* redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution;
|
||||||
|
* neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "cpu/rubytest/CheckTable.hh"
|
||||||
|
#include "cpu/rubytest/CheckTable.hh"
|
||||||
|
#include "cpu/rubytest/Check.hh"
|
||||||
|
#include "mem/gems_common/Map.hh"
|
||||||
|
|
||||||
|
CheckTable::CheckTable(int _num_cpu_sequencers, RubyTester* _tester)
|
||||||
|
: m_num_cpu_sequencers(_num_cpu_sequencers), m_tester_ptr(_tester)
|
||||||
|
{
|
||||||
|
m_lookup_map_ptr = new Map<Address, Check*>;
|
||||||
|
physical_address_t physical = 0;
|
||||||
|
Address address;
|
||||||
|
|
||||||
|
const int size1 = 32;
|
||||||
|
const int size2 = 100;
|
||||||
|
|
||||||
|
// The first set is to get some false sharing
|
||||||
|
physical = 1000;
|
||||||
|
for (int i=0; i<size1; i++) {
|
||||||
|
// Setup linear addresses
|
||||||
|
address.setAddress(physical);
|
||||||
|
addCheck(address);
|
||||||
|
physical += CHECK_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The next two sets are to get some limited false sharing and cache conflicts
|
||||||
|
physical = 1000;
|
||||||
|
for (int i=0; i<size2; i++) {
|
||||||
|
// Setup linear addresses
|
||||||
|
address.setAddress(physical);
|
||||||
|
addCheck(address);
|
||||||
|
physical += 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
physical = 1000 + CHECK_SIZE;
|
||||||
|
for (int i=0; i<size2; i++) {
|
||||||
|
// Setup linear addresses
|
||||||
|
address.setAddress(physical);
|
||||||
|
addCheck(address);
|
||||||
|
physical += 256;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckTable::~CheckTable()
|
||||||
|
{
|
||||||
|
int size = m_check_vector.size();
|
||||||
|
for (int i=0; i<size; i++) {
|
||||||
|
delete m_check_vector[i];
|
||||||
|
}
|
||||||
|
delete m_lookup_map_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckTable::addCheck(const Address& address)
|
||||||
|
{
|
||||||
|
if (log_int(CHECK_SIZE) != 0) {
|
||||||
|
if (address.bitSelect(0,CHECK_SIZE_BITS-1) != 0) {
|
||||||
|
ERROR_MSG("Check not aligned");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=0; i<CHECK_SIZE; i++) {
|
||||||
|
if (m_lookup_map_ptr->exist(Address(address.getAddress()+i))) {
|
||||||
|
// A mapping for this byte already existed, discard the entire check
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Check* check_ptr = new Check(address,
|
||||||
|
Address(100+m_check_vector.size()),
|
||||||
|
m_num_cpu_sequencers,
|
||||||
|
m_tester_ptr);
|
||||||
|
for (int i=0; i<CHECK_SIZE; i++) {
|
||||||
|
// Insert it once per byte
|
||||||
|
m_lookup_map_ptr->add(Address(address.getAddress()+i), check_ptr);
|
||||||
|
}
|
||||||
|
m_check_vector.insertAtBottom(check_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Check* CheckTable::getRandomCheck()
|
||||||
|
{
|
||||||
|
return m_check_vector[random() % m_check_vector.size()];
|
||||||
|
}
|
||||||
|
|
||||||
|
Check* CheckTable::getCheck(const Address& address)
|
||||||
|
{
|
||||||
|
DEBUG_MSG(TESTER_COMP, MedPrio, "Looking for check by address");
|
||||||
|
DEBUG_EXPR(TESTER_COMP, MedPrio, address);
|
||||||
|
|
||||||
|
if (m_lookup_map_ptr->exist(address)) {
|
||||||
|
Check* check = m_lookup_map_ptr->lookup(address);
|
||||||
|
assert(check != NULL);
|
||||||
|
return check;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckTable::print(ostream& out) const
|
||||||
|
{
|
||||||
|
}
|
91
src/cpu/rubytest/CheckTable.hh
Normal file
91
src/cpu/rubytest/CheckTable.hh
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
|
||||||
|
* Copyright (c) 2009 Advanced Micro Devices, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met: redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer;
|
||||||
|
* redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution;
|
||||||
|
* neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CHECKTABLE_H
|
||||||
|
#define CHECKTABLE_H
|
||||||
|
|
||||||
|
#include "mem/ruby/common/Global.hh"
|
||||||
|
#include "mem/gems_common/Vector.hh"
|
||||||
|
|
||||||
|
class Address;
|
||||||
|
class Check;
|
||||||
|
class RubyTester;
|
||||||
|
template <class KEY_TYPE, class VALUE_TYPE> class Map;
|
||||||
|
|
||||||
|
class CheckTable {
|
||||||
|
public:
|
||||||
|
// Constructors
|
||||||
|
CheckTable(int _num_cpu_sequencers, RubyTester* _tester);
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
~CheckTable();
|
||||||
|
|
||||||
|
// Public Methods
|
||||||
|
|
||||||
|
Check* getRandomCheck();
|
||||||
|
Check* getCheck(const Address& address);
|
||||||
|
|
||||||
|
// bool isPresent(const Address& address) const;
|
||||||
|
// void removeCheckFromTable(const Address& address);
|
||||||
|
// bool isTableFull() const;
|
||||||
|
// Need a method to select a check or retrieve a check
|
||||||
|
|
||||||
|
void print(ostream& out) const;
|
||||||
|
private:
|
||||||
|
// Private Methods
|
||||||
|
void addCheck(const Address& address);
|
||||||
|
|
||||||
|
// Private copy constructor and assignment operator
|
||||||
|
CheckTable(const CheckTable& obj);
|
||||||
|
CheckTable& operator=(const CheckTable& obj);
|
||||||
|
|
||||||
|
// Data Members (m_ prefix)
|
||||||
|
Vector<Check*> m_check_vector;
|
||||||
|
Map<Address, Check*>* m_lookup_map_ptr;
|
||||||
|
|
||||||
|
int m_num_cpu_sequencers;
|
||||||
|
RubyTester* m_tester_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Output operator declaration
|
||||||
|
ostream& operator<<(ostream& out, const CheckTable& obj);
|
||||||
|
|
||||||
|
// ******************* Definitions *******************
|
||||||
|
|
||||||
|
// Output operator definition
|
||||||
|
extern inline
|
||||||
|
ostream& operator<<(ostream& out, const CheckTable& obj)
|
||||||
|
{
|
||||||
|
obj.print(out);
|
||||||
|
out << flush;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //CHECKTABLE_H
|
202
src/cpu/rubytest/RubyTester.cc
Normal file
202
src/cpu/rubytest/RubyTester.cc
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
|
||||||
|
* Copyright (c) 2009 Advanced Micro Devices, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met: redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer;
|
||||||
|
* redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution;
|
||||||
|
* neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "mem/ruby/common/Global.hh"
|
||||||
|
#include "mem/ruby/system/System.hh"
|
||||||
|
#include "cpu/rubytest/RubyTester.hh"
|
||||||
|
#include "mem/ruby/eventqueue/RubyEventQueue.hh"
|
||||||
|
#include "mem/ruby/common/SubBlock.hh"
|
||||||
|
#include "cpu/rubytest/Check.hh"
|
||||||
|
#include "sim/sim_exit.hh"
|
||||||
|
|
||||||
|
RubyTester::RubyTester(const Params *p)
|
||||||
|
: MemObject(p),
|
||||||
|
checkStartEvent(this),
|
||||||
|
m_checks_to_complete(p->checks_to_complete),
|
||||||
|
m_deadlock_threshold(p->deadlock_threshold),
|
||||||
|
m_wakeup_frequency(p->wakeup_frequency)
|
||||||
|
{
|
||||||
|
m_checks_completed = 0;
|
||||||
|
|
||||||
|
// add the check start event to the event queue
|
||||||
|
schedule(checkStartEvent, 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
RubyTester::~RubyTester()
|
||||||
|
{
|
||||||
|
delete m_checkTable_ptr;
|
||||||
|
for (int i = 0; i < ports.size(); i++) {
|
||||||
|
delete ports[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RubyTester::init()
|
||||||
|
{
|
||||||
|
assert(ports.size() > 0);
|
||||||
|
|
||||||
|
m_last_progress_vector.setSize(ports.size());
|
||||||
|
for (int i = 0; i < m_last_progress_vector.size(); i++) {
|
||||||
|
m_last_progress_vector[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_num_cpu_sequencers = ports.size();
|
||||||
|
|
||||||
|
m_checkTable_ptr = new CheckTable(m_num_cpu_sequencers, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Port *
|
||||||
|
RubyTester::getPort(const std::string &if_name, int idx)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (if_name != "cpuPort") {
|
||||||
|
panic("RubyTester::getPort: unknown port %s requested", if_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx >= (int)ports.size()) {
|
||||||
|
ports.resize(idx + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ports[idx] != NULL) {
|
||||||
|
panic("RubyTester::getPort: port %d already assigned", idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
CpuPort *port = new CpuPort(csprintf("%s-port%d", name(), idx), this, idx);
|
||||||
|
|
||||||
|
ports[idx] = port;
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tick
|
||||||
|
RubyTester::CpuPort::recvAtomic(PacketPtr pkt)
|
||||||
|
{
|
||||||
|
panic("RubyTester::CpuPort::recvAtomic() not implemented!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
RubyTester::CpuPort::recvTiming(PacketPtr pkt)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// retrieve the subblock and call hitCallback
|
||||||
|
//
|
||||||
|
RubyTester::SenderState* senderState =
|
||||||
|
safe_cast<RubyTester::SenderState*>(pkt->senderState);
|
||||||
|
SubBlock* subblock = senderState->subBlock;
|
||||||
|
assert(subblock != NULL);
|
||||||
|
|
||||||
|
// pop the sender state from the packet
|
||||||
|
pkt->senderState = senderState->saved;
|
||||||
|
|
||||||
|
tester->hitCallback(idx, subblock);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Now that the tester has completed, delete the senderState
|
||||||
|
// (includes sublock) and the packet, then return
|
||||||
|
//
|
||||||
|
delete senderState;
|
||||||
|
delete pkt->req;
|
||||||
|
delete pkt;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Port*
|
||||||
|
RubyTester::getCpuPort(int idx)
|
||||||
|
{
|
||||||
|
assert(idx >= 0 && idx < ports.size());
|
||||||
|
|
||||||
|
return ports[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
void RubyTester::hitCallback(NodeID proc, SubBlock* data)
|
||||||
|
{
|
||||||
|
// Mark that we made progress
|
||||||
|
m_last_progress_vector[proc] = g_eventQueue_ptr->getTime();
|
||||||
|
|
||||||
|
DPRINTF(RubyTest, "completed request for proc: %d\n", proc);
|
||||||
|
DPRINTF(RubyTest,
|
||||||
|
"addr: 0x%x, size: %d, data: ",
|
||||||
|
data->getAddress(),
|
||||||
|
data->getSize());
|
||||||
|
for (int byte = 0; byte < data->getSize(); byte++) {
|
||||||
|
DPRINTF(RubyTest, "%d", data->getByte(byte));
|
||||||
|
}
|
||||||
|
DPRINTF(RubyTest, "\n");
|
||||||
|
|
||||||
|
//
|
||||||
|
// This tells us our store has 'completed' or for a load gives us
|
||||||
|
// back the data to make the check
|
||||||
|
//
|
||||||
|
Check* check_ptr = m_checkTable_ptr->getCheck(data->getAddress());
|
||||||
|
assert(check_ptr != NULL);
|
||||||
|
check_ptr->performCallback(proc, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RubyTester::wakeup()
|
||||||
|
{
|
||||||
|
if (m_checks_completed < m_checks_to_complete) {
|
||||||
|
// Try to perform an action or check
|
||||||
|
Check* check_ptr = m_checkTable_ptr->getRandomCheck();
|
||||||
|
assert(check_ptr != NULL);
|
||||||
|
check_ptr->initiate();
|
||||||
|
|
||||||
|
checkForDeadlock();
|
||||||
|
|
||||||
|
schedule(checkStartEvent, curTick + m_wakeup_frequency);
|
||||||
|
} else {
|
||||||
|
exitSimLoop("Ruby Tester completed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RubyTester::checkForDeadlock()
|
||||||
|
{
|
||||||
|
int size = m_last_progress_vector.size();
|
||||||
|
Time current_time = g_eventQueue_ptr->getTime();
|
||||||
|
for (int processor = 0; processor < size; processor++) {
|
||||||
|
if ((current_time - m_last_progress_vector[processor]) > m_deadlock_threshold) {
|
||||||
|
WARN_EXPR(current_time);
|
||||||
|
WARN_EXPR(m_last_progress_vector[processor]);
|
||||||
|
WARN_EXPR(current_time - m_last_progress_vector[processor]);
|
||||||
|
WARN_EXPR(processor);
|
||||||
|
ERROR_MSG("Deadlock detected.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RubyTester::print(ostream& out) const
|
||||||
|
{
|
||||||
|
out << "[RubyTester]" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
RubyTester *
|
||||||
|
RubyTesterParams::create()
|
||||||
|
{
|
||||||
|
return new RubyTester(this);
|
||||||
|
}
|
162
src/cpu/rubytest/RubyTester.hh
Normal file
162
src/cpu/rubytest/RubyTester.hh
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
|
||||||
|
* Copyright (c) 2009 Advanced Micro Devices, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met: redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer;
|
||||||
|
* redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution;
|
||||||
|
* neither the name of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RUBY_TESTER_H
|
||||||
|
#define RUBY_TESTER_H
|
||||||
|
|
||||||
|
#include "mem/ruby/common/Global.hh"
|
||||||
|
#include "mem/mem_object.hh"
|
||||||
|
#include "cpu/rubytest/CheckTable.hh"
|
||||||
|
#include "mem/ruby/system/RubyPort.hh"
|
||||||
|
#include "mem/ruby/common/SubBlock.hh"
|
||||||
|
#include "mem/ruby/common/DataBlock.hh"
|
||||||
|
#include "mem/packet.hh"
|
||||||
|
#include "params/RubyTester.hh"
|
||||||
|
|
||||||
|
class RubyTester : public MemObject
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
class CpuPort : public SimpleTimingPort
|
||||||
|
{
|
||||||
|
RubyTester *tester;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CpuPort(const std::string &_name,
|
||||||
|
RubyTester *_tester,
|
||||||
|
int _idx)
|
||||||
|
: SimpleTimingPort(_name, _tester), tester(_tester), idx(_idx)
|
||||||
|
{}
|
||||||
|
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
virtual bool recvTiming(PacketPtr pkt);
|
||||||
|
|
||||||
|
virtual Tick recvAtomic(PacketPtr pkt);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SenderState : public Packet::SenderState
|
||||||
|
{
|
||||||
|
SubBlock* subBlock;
|
||||||
|
Packet::SenderState *saved;
|
||||||
|
|
||||||
|
SenderState(Address addr,
|
||||||
|
int size,
|
||||||
|
Packet::SenderState *sender_state = NULL)
|
||||||
|
: saved(sender_state)
|
||||||
|
{subBlock = new SubBlock(addr, size);}
|
||||||
|
|
||||||
|
~SenderState() {delete subBlock;}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef RubyTesterParams Params;
|
||||||
|
// Constructors
|
||||||
|
RubyTester(const Params *p);
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
~RubyTester();
|
||||||
|
|
||||||
|
// Public Methods
|
||||||
|
|
||||||
|
virtual Port *getPort(const std::string &if_name, int idx = -1);
|
||||||
|
|
||||||
|
Port* getCpuPort(int idx);
|
||||||
|
|
||||||
|
void virtual init();
|
||||||
|
|
||||||
|
void wakeup();
|
||||||
|
|
||||||
|
void incrementCheckCompletions() { m_checks_completed++; }
|
||||||
|
|
||||||
|
void printStats(ostream& out) const {}
|
||||||
|
void clearStats() {}
|
||||||
|
void printConfig(ostream& out) const {}
|
||||||
|
|
||||||
|
void print(ostream& out) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
class CheckStartEvent : public Event
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
RubyTester *tester;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CheckStartEvent(RubyTester *_tester) : Event(CPU_Tick_Pri), tester(_tester) {}
|
||||||
|
void process() { tester->wakeup(); }
|
||||||
|
virtual const char *description() const { return "RubyTester tick"; }
|
||||||
|
};
|
||||||
|
|
||||||
|
CheckStartEvent checkStartEvent;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Private Methods
|
||||||
|
|
||||||
|
void hitCallback(NodeID proc, SubBlock* data);
|
||||||
|
|
||||||
|
void checkForDeadlock();
|
||||||
|
|
||||||
|
// Private copy constructor and assignment operator
|
||||||
|
RubyTester(const RubyTester& obj);
|
||||||
|
RubyTester& operator=(const RubyTester& obj);
|
||||||
|
|
||||||
|
// Data Members (m_ prefix)
|
||||||
|
|
||||||
|
CheckTable* m_checkTable_ptr;
|
||||||
|
Vector<Time> m_last_progress_vector;
|
||||||
|
|
||||||
|
uint64 m_checks_completed;
|
||||||
|
std::vector<CpuPort*> ports;
|
||||||
|
uint64 m_checks_to_complete;
|
||||||
|
int m_deadlock_threshold;
|
||||||
|
int m_num_cpu_sequencers;
|
||||||
|
int m_wakeup_frequency;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Output operator declaration
|
||||||
|
ostream& operator<<(ostream& out, const RubyTester& obj);
|
||||||
|
|
||||||
|
// ******************* Definitions *******************
|
||||||
|
|
||||||
|
// Output operator definition
|
||||||
|
extern inline
|
||||||
|
ostream& operator<<(ostream& out, const RubyTester& obj)
|
||||||
|
{
|
||||||
|
obj.print(out);
|
||||||
|
out << flush;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //RUBY_TESTER_H
|
38
src/cpu/rubytest/RubyTester.py
Normal file
38
src/cpu/rubytest/RubyTester.py
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
# Copyright (c) 2005-2007 The Regents of The University of Michigan
|
||||||
|
# Copyright (c) 2009 Advanced Micro Devices, Inc.
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are
|
||||||
|
# met: redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer;
|
||||||
|
# redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution;
|
||||||
|
# neither the name of the copyright holders nor the names of its
|
||||||
|
# contributors may be used to endorse or promote products derived from
|
||||||
|
# this software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#
|
||||||
|
|
||||||
|
from MemObject import MemObject
|
||||||
|
from m5.params import *
|
||||||
|
from m5.proxy import *
|
||||||
|
|
||||||
|
class RubyTester(MemObject):
|
||||||
|
type = 'RubyTester'
|
||||||
|
cpuPort = VectorPort("the cpu ports")
|
||||||
|
checks_to_complete = Param.Int(100, "checks to complete")
|
||||||
|
deadlock_threshold = Param.Int(50000, "how often to check for deadlock")
|
||||||
|
wakeup_frequency = Param.Int(10, "number of cycles between wakeups")
|
47
src/cpu/rubytest/SConscript
Normal file
47
src/cpu/rubytest/SConscript
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
# -*- mode:python -*-
|
||||||
|
|
||||||
|
# Copyright (c) 2006 The Regents of The University of Michigan
|
||||||
|
# Copyright (c) 2009 Advanced Micro Devices, Inc.
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are
|
||||||
|
# met: redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer;
|
||||||
|
# redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution;
|
||||||
|
# neither the name of the copyright holders nor the names of its
|
||||||
|
# contributors may be used to endorse or promote products derived from
|
||||||
|
# this software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#
|
||||||
|
|
||||||
|
Import('*')
|
||||||
|
|
||||||
|
#
|
||||||
|
# Currently the ruby testser relies on Ruby specific objects (SubBlock, etc.)
|
||||||
|
# When this dependency is removed, the ruby tester should be compiled
|
||||||
|
# independently from Ruby
|
||||||
|
#
|
||||||
|
if not env['RUBY']:
|
||||||
|
Return()
|
||||||
|
|
||||||
|
SimObject('RubyTester.py')
|
||||||
|
|
||||||
|
Source('RubyTester.cc')
|
||||||
|
Source('Check.cc')
|
||||||
|
Source('CheckTable.cc')
|
||||||
|
|
||||||
|
TraceFlag('RubyTest')
|
|
@ -194,6 +194,13 @@ class Request : public FastAlloc
|
||||||
setPhys(paddr, size, flags, time);
|
setPhys(paddr, size, flags, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Request(Addr paddr, int size, Flags flags, Tick time, Addr pc)
|
||||||
|
{
|
||||||
|
setPhys(paddr, size, flags, time);
|
||||||
|
privateFlags.set(VALID_PC);
|
||||||
|
_pc = pc;
|
||||||
|
}
|
||||||
|
|
||||||
Request(int asid, Addr vaddr, int size, Flags flags, Addr pc,
|
Request(int asid, Addr vaddr, int size, Flags flags, Addr pc,
|
||||||
int cid, ThreadID tid)
|
int cid, ThreadID tid)
|
||||||
{
|
{
|
||||||
|
|
|
@ -75,7 +75,7 @@ private:
|
||||||
|
|
||||||
// Data Members (m_ prefix)
|
// Data Members (m_ prefix)
|
||||||
Address m_address;
|
Address m_address;
|
||||||
Vector<uint> m_data;
|
Vector<uint8_t> m_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Output operator declaration
|
// Output operator declaration
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "mem/physical.hh"
|
#include "mem/physical.hh"
|
||||||
#include "mem/ruby/system/RubyPort.hh"
|
#include "mem/ruby/system/RubyPort.hh"
|
||||||
#include "mem/ruby/slicc_interface/AbstractController.hh"
|
#include "mem/ruby/slicc_interface/AbstractController.hh"
|
||||||
|
#include "cpu/rubytest/RubyTester.hh"
|
||||||
|
|
||||||
uint16_t RubyPort::m_num_ports = 0;
|
uint16_t RubyPort::m_num_ports = 0;
|
||||||
|
|
||||||
|
@ -205,11 +206,18 @@ RubyPort::M5Port::recvTiming(PacketPtr pkt)
|
||||||
// sending them to our assigned ruby port.
|
// sending them to our assigned ruby port.
|
||||||
//
|
//
|
||||||
RubyRequestType type = RubyRequestType_NULL;
|
RubyRequestType type = RubyRequestType_NULL;
|
||||||
|
|
||||||
|
//
|
||||||
|
// If valid, copy the pc to the ruby request
|
||||||
|
//
|
||||||
Addr pc = 0;
|
Addr pc = 0;
|
||||||
|
if (pkt->req->hasPC()) {
|
||||||
|
pc = pkt->req->getPC();
|
||||||
|
}
|
||||||
|
|
||||||
if (pkt->isRead()) {
|
if (pkt->isRead()) {
|
||||||
if (pkt->req->isInstFetch()) {
|
if (pkt->req->isInstFetch()) {
|
||||||
type = RubyRequestType_IFETCH;
|
type = RubyRequestType_IFETCH;
|
||||||
pc = pkt->req->getPC();
|
|
||||||
} else {
|
} else {
|
||||||
type = RubyRequestType_LD;
|
type = RubyRequestType_LD;
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,11 +152,10 @@ protected:
|
||||||
MessageBuffer* m_mandatory_q_ptr;
|
MessageBuffer* m_mandatory_q_ptr;
|
||||||
PioPort* pio_port;
|
PioPort* pio_port;
|
||||||
|
|
||||||
private:
|
//
|
||||||
static uint16_t m_num_ports;
|
// The pending request map is protected so that the Sequencer can access it.
|
||||||
uint16_t m_port_id;
|
// This is a temporary fix until the libruby inteface is cleaned
|
||||||
uint64_t m_request_cnt;
|
//
|
||||||
|
|
||||||
struct RequestCookie {
|
struct RequestCookie {
|
||||||
Packet *pkt;
|
Packet *pkt;
|
||||||
M5Port *m5Port;
|
M5Port *m5Port;
|
||||||
|
@ -167,6 +166,12 @@ private:
|
||||||
|
|
||||||
typedef std::map<int64_t, RequestCookie*> RequestMap;
|
typedef std::map<int64_t, RequestCookie*> RequestMap;
|
||||||
static RequestMap pending_cpu_requests;
|
static RequestMap pending_cpu_requests;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static uint16_t m_num_ports;
|
||||||
|
uint16_t m_port_id;
|
||||||
|
uint64_t m_request_cnt;
|
||||||
|
|
||||||
static void ruby_hit_callback(int64_t req_id);
|
static void ruby_hit_callback(int64_t req_id);
|
||||||
|
|
||||||
M5Port* physMemPort;
|
M5Port* physMemPort;
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include "mem/gems_common/Map.hh"
|
#include "mem/gems_common/Map.hh"
|
||||||
#include "mem/ruby/buffers/MessageBuffer.hh"
|
#include "mem/ruby/buffers/MessageBuffer.hh"
|
||||||
#include "mem/ruby/slicc_interface/AbstractController.hh"
|
#include "mem/ruby/slicc_interface/AbstractController.hh"
|
||||||
|
#include "cpu/rubytest/RubyTester.hh"
|
||||||
|
|
||||||
#include "params/RubySequencer.hh"
|
#include "params/RubySequencer.hh"
|
||||||
|
|
||||||
|
@ -74,7 +75,8 @@ Sequencer::Sequencer(const Params *p)
|
||||||
m_dataCache_ptr = p->dcache;
|
m_dataCache_ptr = p->dcache;
|
||||||
m_max_outstanding_requests = p->max_outstanding_requests;
|
m_max_outstanding_requests = p->max_outstanding_requests;
|
||||||
m_deadlock_threshold = p->deadlock_threshold;
|
m_deadlock_threshold = p->deadlock_threshold;
|
||||||
|
m_usingRubyTester = p->using_ruby_tester;
|
||||||
|
|
||||||
assert(m_max_outstanding_requests > 0);
|
assert(m_max_outstanding_requests > 0);
|
||||||
assert(m_deadlock_threshold > 0);
|
assert(m_deadlock_threshold > 0);
|
||||||
assert(m_instCache_ptr != NULL);
|
assert(m_instCache_ptr != NULL);
|
||||||
|
@ -344,6 +346,30 @@ void Sequencer::hitCallback(SequencerRequest* srequest, DataBlock& data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// If using the RubyTester, update the RubyTester sender state's subBlock
|
||||||
|
// with the recieved data. The tester will later access this state.
|
||||||
|
// Note: RubyPort will access it's sender state before the RubyTester.
|
||||||
|
//
|
||||||
|
if (m_usingRubyTester) {
|
||||||
|
//
|
||||||
|
// Since the hit callback func only takes a request id, we must iterate
|
||||||
|
// through the requests and update the packet's subBlock here.
|
||||||
|
// All this would be fixed if we could attach a M5 pkt pointer to the
|
||||||
|
// ruby request, however that change will break the libruby interface so
|
||||||
|
// we'll hold off on that for now.
|
||||||
|
//
|
||||||
|
RequestMap::iterator i = pending_cpu_requests.find(srequest->id);
|
||||||
|
if (i == pending_cpu_requests.end())
|
||||||
|
panic("could not find pending request %d\n", srequest->id);
|
||||||
|
RequestCookie *cookie = i->second;
|
||||||
|
Packet *pkt = cookie->pkt;
|
||||||
|
|
||||||
|
RubyTester::SenderState* testerSenderState;
|
||||||
|
testerSenderState = safe_cast<RubyTester::SenderState*>(pkt->senderState);
|
||||||
|
testerSenderState->subBlock->mergeFrom(data);
|
||||||
|
}
|
||||||
|
|
||||||
m_hit_callback(srequest->id);
|
m_hit_callback(srequest->id);
|
||||||
delete srequest;
|
delete srequest;
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,6 +129,8 @@ private:
|
||||||
int m_load_waiting_on_store_cycles;
|
int m_load_waiting_on_store_cycles;
|
||||||
int m_load_waiting_on_load_cycles;
|
int m_load_waiting_on_load_cycles;
|
||||||
|
|
||||||
|
bool m_usingRubyTester;
|
||||||
|
|
||||||
class SequencerWakeupEvent : public Event
|
class SequencerWakeupEvent : public Event
|
||||||
{
|
{
|
||||||
Sequencer *m_sequencer_ptr;
|
Sequencer *m_sequencer_ptr;
|
||||||
|
|
|
@ -20,6 +20,7 @@ class RubySequencer(RubyPort):
|
||||||
"max requests (incl. prefetches) outstanding")
|
"max requests (incl. prefetches) outstanding")
|
||||||
deadlock_threshold = Param.Int(500000,
|
deadlock_threshold = Param.Int(500000,
|
||||||
"max outstanding cycles for a request before deadlock/livelock declared")
|
"max outstanding cycles for a request before deadlock/livelock declared")
|
||||||
|
using_ruby_tester = Param.Bool(False, "")
|
||||||
|
|
||||||
class DMASequencer(RubyPort):
|
class DMASequencer(RubyPort):
|
||||||
type = 'DMASequencer'
|
type = 'DMASequencer'
|
||||||
|
|
Loading…
Reference in a new issue