summaryrefslogtreecommitdiff
path: root/src/cpu
diff options
context:
space:
mode:
authorBrad Beckmann <Brad.Beckmann@amd.com>2012-04-06 13:47:06 -0700
committerBrad Beckmann <Brad.Beckmann@amd.com>2012-04-06 13:47:06 -0700
commit0a9f4b950fb52db3951ad1f7aafc674b505d2679 (patch)
tree033bfd48877875c00201058f1a60e679696c9cdf /src/cpu
parentb00949d88bb3185dfa2e27799de7f90e5a449be8 (diff)
downloadgem5-0a9f4b950fb52db3951ad1f7aafc674b505d2679.tar.xz
rubytest: seperated read and write ports.
This patch allows the ruby tester to support protocols where the i-cache and d-cache are managed by seperate controllers.
Diffstat (limited to 'src/cpu')
-rw-r--r--src/cpu/testers/rubytest/Check.cc31
-rw-r--r--src/cpu/testers/rubytest/Check.hh7
-rw-r--r--src/cpu/testers/rubytest/CheckTable.cc7
-rw-r--r--src/cpu/testers/rubytest/CheckTable.hh5
-rw-r--r--src/cpu/testers/rubytest/RubyTester.cc86
-rw-r--r--src/cpu/testers/rubytest/RubyTester.hh32
-rw-r--r--src/cpu/testers/rubytest/RubyTester.py4
7 files changed, 124 insertions, 48 deletions
diff --git a/src/cpu/testers/rubytest/Check.cc b/src/cpu/testers/rubytest/Check.cc
index 2444a14ab..6f119af06 100644
--- a/src/cpu/testers/rubytest/Check.cc
+++ b/src/cpu/testers/rubytest/Check.cc
@@ -36,8 +36,9 @@
typedef RubyTester::SenderState SenderState;
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)
+ int _num_writers, int _num_readers, RubyTester* _tester)
+ : m_num_writers(_num_writers), m_num_readers(_num_readers),
+ m_tester_ptr(_tester)
{
m_status = TesterStatus_Idle;
@@ -80,9 +81,9 @@ Check::initiatePrefetch()
{
DPRINTF(RubyTest, "initiating prefetch\n");
- int index = random() % m_num_cpu_sequencers;
+ int index = random() % m_num_readers;
RubyTester::CpuPort* port =
- safe_cast<RubyTester::CpuPort*>(m_tester_ptr->getCpuPort(index));
+ safe_cast<RubyTester::CpuPort*>(m_tester_ptr->getReadableCpuPort(index));
Request::Flags flags;
flags.set(Request::PREFETCH);
@@ -93,8 +94,8 @@ Check::initiatePrefetch()
if ((random() & 0x7) != 0) {
cmd = MemCmd::ReadReq;
- // 50% chance that the request will be an instruction fetch
- if ((random() & 0x1) == 0) {
+ // if necessary, make the request an instruction fetch
+ if (port->type == RubyTester::CpuPort::InstOnly) {
flags.set(Request::INST_FETCH);
}
} else {
@@ -135,9 +136,9 @@ Check::initiateFlush()
DPRINTF(RubyTest, "initiating Flush\n");
- int index = random() % m_num_cpu_sequencers;
+ int index = random() % m_num_writers;
RubyTester::CpuPort* port =
- safe_cast<RubyTester::CpuPort*>(m_tester_ptr->getCpuPort(index));
+ safe_cast<RubyTester::CpuPort*>(m_tester_ptr->getWritableCpuPort(index));
Request::Flags flags;
@@ -166,9 +167,9 @@ Check::initiateAction()
DPRINTF(RubyTest, "initiating Action\n");
assert(m_status == TesterStatus_Idle);
- int index = random() % m_num_cpu_sequencers;
+ int index = random() % m_num_writers;
RubyTester::CpuPort* port =
- safe_cast<RubyTester::CpuPort*>(m_tester_ptr->getCpuPort(index));
+ safe_cast<RubyTester::CpuPort*>(m_tester_ptr->getWritableCpuPort(index));
Request::Flags flags;
@@ -231,14 +232,14 @@ Check::initiateCheck()
DPRINTF(RubyTest, "Initiating Check\n");
assert(m_status == TesterStatus_Ready);
- int index = random() % m_num_cpu_sequencers;
+ int index = random() % m_num_readers;
RubyTester::CpuPort* port =
- safe_cast<RubyTester::CpuPort*>(m_tester_ptr->getCpuPort(index));
+ safe_cast<RubyTester::CpuPort*>(m_tester_ptr->getReadableCpuPort(index));
Request::Flags flags;
- // 50% chance that the request will be an instruction fetch
- if ((random() & 0x1) == 0) {
+ // If necessary, make the request an instruction fetch
+ if (port->type == RubyTester::CpuPort::InstOnly) {
flags.set(Request::INST_FETCH);
}
@@ -363,7 +364,7 @@ Check::pickInitiatingNode()
{
assert(m_status == TesterStatus_Idle || m_status == TesterStatus_Ready);
m_status = TesterStatus_Idle;
- m_initiatingNode = (random() % m_num_cpu_sequencers);
+ m_initiatingNode = (random() % m_num_writers);
DPRINTF(RubyTest, "picked initiating node %d\n", m_initiatingNode);
m_store_count = 0;
}
diff --git a/src/cpu/testers/rubytest/Check.hh b/src/cpu/testers/rubytest/Check.hh
index db1485548..1d84b446b 100644
--- a/src/cpu/testers/rubytest/Check.hh
+++ b/src/cpu/testers/rubytest/Check.hh
@@ -46,8 +46,8 @@ const int CHECK_SIZE = (1 << CHECK_SIZE_BITS);
class Check
{
public:
- Check(const Address& address, const Address& pc, int _num_cpu_sequencer,
- RubyTester* _tester);
+ Check(const Address& address, const Address& pc, int _num_writers,
+ int _num_readers, RubyTester* _tester);
void initiate(); // Does Action or Check or nether
void performCallback(NodeID proc, SubBlock* data);
@@ -74,7 +74,8 @@ class Check
Address m_address;
Address m_pc;
RubyAccessMode m_access_mode;
- int m_num_cpu_sequencers;
+ int m_num_writers;
+ int m_num_readers;
RubyTester* m_tester_ptr;
};
diff --git a/src/cpu/testers/rubytest/CheckTable.cc b/src/cpu/testers/rubytest/CheckTable.cc
index f3335b48c..b4860b62b 100644
--- a/src/cpu/testers/rubytest/CheckTable.cc
+++ b/src/cpu/testers/rubytest/CheckTable.cc
@@ -32,8 +32,9 @@
#include "cpu/testers/rubytest/CheckTable.hh"
#include "debug/RubyTest.hh"
-CheckTable::CheckTable(int _num_cpu_sequencers, RubyTester* _tester)
- : m_num_cpu_sequencers(_num_cpu_sequencers), m_tester_ptr(_tester)
+CheckTable::CheckTable(int _num_writers, int _num_readers, RubyTester* _tester)
+ : m_num_writers(_num_writers), m_num_readers(_num_readers),
+ m_tester_ptr(_tester)
{
physical_address_t physical = 0;
Address address;
@@ -94,7 +95,7 @@ CheckTable::addCheck(const Address& address)
}
Check* check_ptr = new Check(address, Address(100 + m_check_vector.size()),
- m_num_cpu_sequencers, m_tester_ptr);
+ m_num_writers, m_num_readers, m_tester_ptr);
for (int i = 0; i < CHECK_SIZE; i++) {
// Insert it once per byte
m_lookup_map[Address(address.getAddress() + i)] = check_ptr;
diff --git a/src/cpu/testers/rubytest/CheckTable.hh b/src/cpu/testers/rubytest/CheckTable.hh
index 5a4ead337..35ea7440a 100644
--- a/src/cpu/testers/rubytest/CheckTable.hh
+++ b/src/cpu/testers/rubytest/CheckTable.hh
@@ -43,7 +43,7 @@ class RubyTester;
class CheckTable
{
public:
- CheckTable(int _num_cpu_sequencers, RubyTester* _tester);
+ CheckTable(int _num_writers, int _num_readers, RubyTester* _tester);
~CheckTable();
Check* getRandomCheck();
@@ -66,7 +66,8 @@ class CheckTable
std::vector<Check*> m_check_vector;
m5::hash_map<Address, Check*> m_lookup_map;
- int m_num_cpu_sequencers;
+ int m_num_writers;
+ int m_num_readers;
RubyTester* m_tester_ptr;
};
diff --git a/src/cpu/testers/rubytest/RubyTester.cc b/src/cpu/testers/rubytest/RubyTester.cc
index e1942cf61..7cc892166 100644
--- a/src/cpu/testers/rubytest/RubyTester.cc
+++ b/src/cpu/testers/rubytest/RubyTester.cc
@@ -53,17 +53,37 @@
RubyTester::RubyTester(const Params *p)
: MemObject(p), checkStartEvent(this),
_masterId(p->system->getMasterId(name())),
+ m_num_cpus(p->num_cpus),
m_checks_to_complete(p->checks_to_complete),
m_deadlock_threshold(p->deadlock_threshold),
m_wakeup_frequency(p->wakeup_frequency),
- m_check_flush(p->check_flush)
+ m_check_flush(p->check_flush),
+ m_num_inst_ports(p->port_cpuInstPort_connection_count)
{
m_checks_completed = 0;
- // create the ports
- for (int i = 0; i < p->port_cpuPort_connection_count; ++i) {
- ports.push_back(new CpuPort(csprintf("%s-port%d", name(), i),
- this, i));
+ //
+ // Create the requested inst and data ports and place them on the
+ // appropriate read and write port lists. The reason for the subtle
+ // difference between inst and data ports vs. read and write ports is
+ // from the tester's perspective, it only needs to know whether a port
+ // supports reads (checks) or writes (actions). Meanwhile, the protocol
+ // controllers have data ports (support read and writes) or inst ports
+ // (support only reads).
+ // Note: the inst ports are the lowest elements of the readPort vector,
+ // then the data ports are added to the readPort vector
+ //
+ for (int i = 0; i < p->port_cpuInstPort_connection_count; ++i) {
+ readPorts.push_back(new CpuPort(csprintf("%s-instPort%d", name(), i),
+ this, i,
+ RubyTester::CpuPort::InstOnly));
+ }
+ for (int i = 0; i < p->port_cpuDataPort_connection_count; ++i) {
+ CpuPort *port = NULL;
+ port = new CpuPort(csprintf("%s-dataPort%d", name(), i), this, i,
+ RubyTester::CpuPort::DataOnly);
+ readPorts.push_back(port);
+ writePorts.push_back(port);
}
// add the check start event to the event queue
@@ -73,37 +93,57 @@ RubyTester::RubyTester(const Params *p)
RubyTester::~RubyTester()
{
delete m_checkTable_ptr;
- for (int i = 0; i < ports.size(); i++)
- delete ports[i];
+ // Only delete the readPorts since the writePorts are just a subset
+ for (int i = 0; i < readPorts.size(); i++)
+ delete readPorts[i];
}
void
RubyTester::init()
{
- assert(ports.size() > 0);
+ assert(writePorts.size() > 0 && readPorts.size() > 0);
- m_last_progress_vector.resize(ports.size());
+ m_last_progress_vector.resize(m_num_cpus);
for (int i = 0; i < m_last_progress_vector.size(); i++) {
m_last_progress_vector[i] = 0;
}
- m_num_cpu_sequencers = ports.size();
+ m_num_writers = writePorts.size();
+ m_num_readers = readPorts.size();
- m_checkTable_ptr = new CheckTable(m_num_cpu_sequencers, this);
+ m_checkTable_ptr = new CheckTable(m_num_writers, m_num_readers, this);
}
MasterPort &
RubyTester::getMasterPort(const std::string &if_name, int idx)
{
- if (if_name != "cpuPort") {
+ if (if_name != "cpuInstPort" && if_name != "cpuDataPort") {
// pass it along to our super class
return MemObject::getMasterPort(if_name, idx);
} else {
- if (idx >= static_cast<int>(ports.size())) {
- panic("RubyTester::getMasterPort: unknown index %d\n", idx);
+ if (if_name == "cpuInstPort") {
+ printf("print getting inst port %d\n", idx);
+ if (idx > m_num_inst_ports) {
+ panic("RubyTester::getMasterPort: unknown inst port idx %d\n",
+ idx);
+ }
+ //
+ // inst ports directly map to the lowest readPort elements
+ //
+ return *readPorts[idx];
+ } else {
+ assert(if_name == "cpuDataPort");
+ //
+ // add the inst port offset to translate to the correct read port
+ // index
+ //
+ int read_idx = idx + m_num_inst_ports;
+ if (read_idx >= static_cast<int>(readPorts.size())) {
+ panic("RubyTester::getMasterPort: unknown data port idx %d\n",
+ idx);
+ }
+ return *readPorts[read_idx];
}
-
- return *ports[idx];
}
}
@@ -137,11 +177,19 @@ RubyTester::CpuPort::recvTiming(PacketPtr pkt)
}
MasterPort*
-RubyTester::getCpuPort(int idx)
+RubyTester::getReadableCpuPort(int idx)
+{
+ assert(idx >= 0 && idx < readPorts.size());
+
+ return readPorts[idx];
+}
+
+MasterPort*
+RubyTester::getWritableCpuPort(int idx)
{
- assert(idx >= 0 && idx < ports.size());
+ assert(idx >= 0 && idx < writePorts.size());
- return ports[idx];
+ return writePorts[idx];
}
void
diff --git a/src/cpu/testers/rubytest/RubyTester.hh b/src/cpu/testers/rubytest/RubyTester.hh
index b24dddd83..82698f201 100644
--- a/src/cpu/testers/rubytest/RubyTester.hh
+++ b/src/cpu/testers/rubytest/RubyTester.hh
@@ -51,11 +51,28 @@ class RubyTester : public MemObject
RubyTester *tester;
public:
- CpuPort(const std::string &_name, RubyTester *_tester, int _idx)
- : MasterPort(_name, _tester), tester(_tester), idx(_idx)
+ //
+ // Currently, each instatiation of the RubyTester::CpuPort supports
+ // only instruction or data requests, not both. However, for those
+ // RubyPorts that support both types of requests, separate InstOnly
+ // and DataOnly CpuPorts will map to that RubyPort
+ //
+ enum Type
+ {
+ // Port supports only instruction requests
+ InstOnly,
+ // Port supports only data requests
+ DataOnly
+ };
+
+ CpuPort(const std::string &_name, RubyTester *_tester, int _idx,
+ Type _type)
+ : MasterPort(_name, _tester), tester(_tester), idx(_idx),
+ type(_type)
{}
int idx;
+ Type type;
protected:
virtual bool recvTiming(PacketPtr pkt);
@@ -90,7 +107,8 @@ class RubyTester : public MemObject
virtual MasterPort &getMasterPort(const std::string &if_name,
int idx = -1);
- MasterPort* getCpuPort(int idx);
+ MasterPort* getReadableCpuPort(int idx);
+ MasterPort* getWritableCpuPort(int idx);
virtual void init();
@@ -136,13 +154,17 @@ class RubyTester : public MemObject
CheckTable* m_checkTable_ptr;
std::vector<Time> m_last_progress_vector;
+ int m_num_cpus;
uint64 m_checks_completed;
- std::vector<CpuPort*> ports;
+ std::vector<CpuPort*> writePorts;
+ std::vector<CpuPort*> readPorts;
uint64 m_checks_to_complete;
int m_deadlock_threshold;
- int m_num_cpu_sequencers;
+ int m_num_writers;
+ int m_num_readers;
int m_wakeup_frequency;
bool m_check_flush;
+ int m_num_inst_ports;
};
inline std::ostream&
diff --git a/src/cpu/testers/rubytest/RubyTester.py b/src/cpu/testers/rubytest/RubyTester.py
index 6518862e9..2eaeb8efd 100644
--- a/src/cpu/testers/rubytest/RubyTester.py
+++ b/src/cpu/testers/rubytest/RubyTester.py
@@ -32,7 +32,9 @@ from m5.proxy import *
class RubyTester(MemObject):
type = 'RubyTester'
- cpuPort = VectorMasterPort("the cpu ports")
+ num_cpus = Param.Int("number of cpus / RubyPorts")
+ cpuDataPort = VectorMasterPort("the cpu data cache ports")
+ cpuInstPort = VectorMasterPort("the cpu inst cache 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")