type = 'RubyMemory'
clock = Param.Clock('1t', "ruby clock speed")
phase = Param.Latency('0ns', "ruby clock phase")
- config_file = Param.String("", "path to the Ruby config file")
- config_options = Param.String("", "extra Ruby options (one per line)")
+ config_file = Param.String("path to the Ruby config file")
stats_file = Param.String("ruby.stats",
"file to which ruby dumps its stats")
num_cpus = Param.Int(1, "Number of CPUs connected to the Ruby memory")
debug = Param.Bool(False, "Use ruby debug")
- debug_file = Param.String("",
+ debug_file = Param.String("ruby.debug",
"path to the Ruby debug output file (stdout if blank)")
sticky_vars.AddVariables(
BoolVariable('NO_VECTOR_BOUNDS_CHECKS', "Don't do bounds checks", True),
BoolVariable('RUBY_DEBUG', "Add debugging stuff to Ruby", False),
- ('GEMS_ROOT', "Add debugging stuff to Ruby", Dir('..').srcnode().abspath))
+ ('GEMS_ROOT', "Add debugging stuff to Ruby", Dir('..').srcnode().abspath),
+ BoolVariable('RUBY_TSO_CHECKER', "Use the Ruby TSO Checker", False)
+ )
-export_vars += [ 'NO_VECTOR_BOUNDS_CHECKS', 'RUBY_DEBUG', 'GEMS_ROOT' ]
+export_vars += [ 'NO_VECTOR_BOUNDS_CHECKS', 'RUBY_DEBUG', 'GEMS_ROOT',
+ 'RUBY_TSO_CHECKER' ]
#include "mem/ruby/storebuffer/storebuffer.hh"
#include "mem/ruby/common/Global.hh"
-#ifdef RUBY_TSO_CHECKER
+#if RUBY_TSO_CHECKER
#include "TsoChecker.hh"
#endif
// global map of request id_s to map them back to storebuffer pointers
map <uint64_t, StoreBuffer *> request_map;
-#ifdef RUBY_TSO_CHECKER
+#if RUBY_TSO_CHECKER
Tso::TsoChecker * g_tsoChecker;
#endif
//*****************************************************************************************
StoreBuffer::StoreBuffer(uint32 id, uint32 block_bits, int storebuffer_size) {
-#ifdef RUBY_TSO_CHECKER
+#if RUBY_TSO_CHECKER
if (id == 0) {
g_tsoChecker = new Tso::TsoChecker();
g_tsoChecker->init(64);
//******************************************************************************************
StoreBuffer::~StoreBuffer(){
-#ifdef RUBY_TSO_CHECKER
+#if RUBY_TSO_CHECKER
if (m_id == 0) {
delete g_tsoChecker;
}
ASSERT(checkForLoadHit(request) != NO_MATCH);
physical_address_t lineaddr = physical_address & m_block_mask;
bool found = false;
-#ifdef RUBY_TSO_CHECKER
+#if RUBY_TSO_CHECKER
Tso::TsoCheckerCmd * cmd;
#endif
deque<struct SBEntry>::iterator satisfying_store;
if ((it->m_request.paddr & m_block_mask) == lineaddr) {
if (!found) {
found = true;
-#ifdef RUBY_TSO_CHECKER
+#if RUBY_TSO_CHECKER
satisfying_store = it;
cmd = new Tso::TsoCheckerCmd(m_id, // this thread id
iseq, // instruction sequence
}
}
-#ifdef RUBY_TSO_CHECKER
+#if RUBY_TSO_CHECKER
uint64_t tso_data = 0;
memcpy(&tso_data, request.data, request.len);
cmd->setData(tso_data);
m_buffer_size--;
ASSERT(m_buffer_size >= 0);
-#ifdef RUBY_TSO_CHECKER
+#if RUBY_TSO_CHECKER
int len = outstanding_requests.find(id)->second.len;
uint64_t data = 0;
memcpy(&data, from_buffer.m_request.data, 4);
#endif
} // end if (type == ST)
else if (type == RubyRequestType_LD) {
-#ifdef RUBY_TSO_CHECKER
+#if RUBY_TSO_CHECKER
RubyRequest request = outstanding_requests.find(id)->second;
uint64_t data = 0;
memcpy(&data, request.data, request.len);
}
}
-#ifdef RUBY_TSO_CHECKER
+#if RUBY_TSO_CHECKER
void StoreBuffer::insertTsoLL(Tso::TsoCheckerCmd * cmd) {
uint64_t count = cmd->getIseq();
Tso::TsoCheckerCmd * current = NULL;
#include "mem/ruby/storebuffer/hfa.hh"
#include "mem/ruby/libruby.hh"
-#ifdef RUBY_TSO_CHECKER
+#if RUBY_TSO_CHECKER
#include "TsoCheckerCmd.hh"
#endif
struct SBEntry {
struct RubyRequest m_request;
-#ifdef RUBY_TSO_CHECKER
+#if RUBY_TSO_CHECKER
Tso::TsoCheckerCmd * m_next_ptr;
#endif
SBEntry(struct RubyRequest request, void * ptr)
: m_request(request)
{
-#ifdef RUBY_TSO_CHECKER
+#if RUBY_TSO_CHECKER
m_next_ptr = (Tso::TsoCheckerCmd*) ptr;
#endif
}
/// prints out the contents of the Write Buffer
void print();
-#ifdef RUBY_TSO_CHECKER
+#if RUBY_TSO_CHECKER
/// if load completes before store, insert correctly to be issued to TSOChecker
void insertTsoLL(Tso::TsoCheckerCmd * cmd);
#endif
#include "arch/isa_traits.hh"
#include "base/output.hh"
+#include "base/str.hh"
#include "base/types.hh"
#include "mem/ruby/common/Debug.hh"
-#include "mem/ruby/init.hh"
+#include "mem/ruby/libruby.hh"
+#include "mem/ruby/system/RubyPort.hh"
#include "mem/ruby/system/Sequencer.hh"
#include "mem/ruby/system/System.hh"
#include "mem/rubymem.hh"
using namespace std;
using namespace TheISA;
+map<int64_t, PacketPtr> RubyMemory::pending_requests;
+
RubyMemory::RubyMemory(const Params *p)
: PhysicalMemory(p)
{
- config_file = p->config_file;
- config_options = p->config_options;
- stats_file = p->stats_file;
- num_cpus = p->num_cpus;
ruby_clock = p->clock;
ruby_phase = p->phase;
- debug = p->debug;
- debug_file = p->debug_file;
+ ifstream config(p->config_file.c_str());
+
+ vector<RubyObjConf> sys_conf;
+ while (!config.eof()) {
+ char buffer[4096];
+ config.getline(buffer, sizeof(buffer));
+ string line = buffer;
+ if (line.empty())
+ continue;
+ vector<string> tokens;
+ tokenize(tokens, line, ' ');
+ assert(tokens.size() >= 2);
+ vector<string> argv;
+ for (size_t i=2; i<tokens.size(); i++) {
+ std::replace(tokens[i].begin(), tokens[i].end(), '%', ' ');
+ std::replace(tokens[i].begin(), tokens[i].end(), '#', '\n');
+ argv.push_back(tokens[i]);
+ }
+ sys_conf.push_back(RubyObjConf(tokens[0], tokens[1], argv));
+ tokens.clear();
+ argv.clear();
+ }
+
+ RubySystem::create(sys_conf);
+
+ for (int i = 0; i < params()->num_cpus; i++) {
+ RubyPort *p = RubySystem::getPort(csprintf("Sequencer_%d", i),
+ ruby_hit_callback);
+ ruby_ports.push_back(p);
+ }
}
void
RubyMemory::init()
{
- init_variables();
- g_NUM_PROCESSORS = num_cpus;
-
- init_simulator(this);
-
- if (debug) {
+ if (params()->debug) {
g_debug_ptr->setVerbosityString("high");
g_debug_ptr->setDebugTime(1);
- if (debug_file != "") {
- g_debug_ptr->setDebugOutputFile("ruby.debug");
+ if (!params()->debug_file.empty()) {
+ g_debug_ptr->setDebugOutputFile(params()->debug_file.c_str());
}
}
}
//called by rubyTickEvent
-void RubyMemory::tick() {
- g_eventQueue_ptr->triggerEvents(g_eventQueue_ptr->getTime() + 1);
- schedule(rubyTickEvent, curTick + ruby_clock); //dsm: clock_phase was added here. This is wrong, the phase is only added on the first tick
+void
+RubyMemory::tick()
+{
+ RubyEventQueue *eq = RubySystem::getEventQueue();
+ eq->triggerEvents(eq->getTime() + 1);
+ schedule(rubyTickEvent, curTick + ruby_clock);
}
-
-RubyMemory::~RubyMemory() {
- delete g_system_ptr;
+RubyMemory::~RubyMemory()
+{
}
void
-RubyMemory::hitCallback(Packet* pkt)
+RubyMemory::hitCallback(PacketPtr pkt, Port *port)
{
- RubyMemoryPort* port = m_packet_to_port_map[pkt];
- assert(port != NULL);
- m_packet_to_port_map.erase(pkt);
-
DPRINTF(MemoryAccess, "Hit callback\n");
bool needsResponse = pkt->needsResponse();
// with places where this function is called from C++. I'd prefer
// to move all these into Python someday.
if (if_name == "functional") {
- return new RubyMemoryPort(csprintf("%s-functional", name()), this);
+ return new Port(csprintf("%s-functional", name()), this);
}
if (if_name != "port") {
panic("RubyMemory::getPort: port %d already assigned", idx);
}
- RubyMemoryPort *port =
- new RubyMemoryPort(csprintf("%s-port%d", name(), idx), this);
+ Port *port = new Port(csprintf("%s-port%d", name(), idx), this);
ports[idx] = port;
return port;
}
-RubyMemory::RubyMemoryPort::RubyMemoryPort(const std::string &_name,
- RubyMemory *_memory)
+RubyMemory::Port::Port(const std::string &_name, RubyMemory *_memory)
: PhysicalMemory::MemoryPort::MemoryPort(_name, _memory)
{
ruby_mem = _memory;
}
bool
-RubyMemory::RubyMemoryPort::recvTiming(PacketPtr pkt)
+RubyMemory::Port::recvTiming(PacketPtr pkt)
{
DPRINTF(MemoryAccess, "Timing access caught\n");
return true;
}
- ruby_mem->m_packet_to_port_map[pkt] = this;
-
- Sequencer* sequencer = g_system_ptr->getSequencer(pkt->req->contextId());
+ // Save the port in the sender state object
+ pkt->senderState = new SenderState(this, pkt->senderState);
+
+ RubyRequestType type = RubyRequestType_NULL;
+ Addr pc = 0;
+ if (pkt->isRead()) {
+ if (pkt->req->isInstFetch()) {
+ type = RubyRequestType_IFETCH;
+ pc = pkt->req->getPC();
+ } else {
+ type = RubyRequestType_LD;
+ }
+ } else if (pkt->isWrite()) {
+ type = RubyRequestType_ST;
+ } else if (pkt->isReadWrite()) {
+ type = RubyRequestType_RMW;
+ }
- if ( ! sequencer->isReady(pkt) ) {
- DPRINTF(MemoryAccess, "Sequencer isn't ready yet!!\n");
- return false;
+ RubyRequest ruby_request(pkt->getAddr(), pkt->getPtr<uint8_t>(),
+ pkt->getSize(), pc, type,
+ RubyAccessMode_Supervisor);
+
+ // Submit the ruby request
+ RubyPort *ruby_port = ruby_mem->ruby_ports[pkt->req->contextId()];
+ int64_t req_id = ruby_port->makeRequest(ruby_request);
+ if (req_id == -1) {
+ RubyMemory::SenderState *senderState =
+ safe_cast<RubyMemory::SenderState *>(pkt->senderState);
+
+ // pop the sender state from the packet
+ pkt->senderState = senderState->saved;
+ delete senderState;
+ return false;
}
- DPRINTF(MemoryAccess, "Issuing makeRequest\n");
+ // Save the request for the callback
+ RubyMemory::pending_requests[req_id] = pkt;
- sequencer->makeRequest(pkt);
return true;
}
void
-RubyMemory::RubyMemoryPort::sendTiming(PacketPtr pkt)
+ruby_hit_callback(int64_t req_id)
+{
+ typedef map<int64_t, PacketPtr> map_t;
+ map_t &prm = RubyMemory::pending_requests;
+
+ map_t::iterator i = prm.find(req_id);
+ if (i == prm.end())
+ panic("could not find pending request %d\n", req_id);
+
+ PacketPtr pkt = i->second;
+ prm.erase(i);
+
+ RubyMemory::SenderState *senderState =
+ safe_cast<RubyMemory::SenderState *>(pkt->senderState);
+ RubyMemory::Port *port = senderState->port;
+
+ // pop the sender state from the packet
+ pkt->senderState = senderState->saved;
+ delete senderState;
+
+ port->ruby_mem->hitCallback(pkt, port);
+}
+
+void
+RubyMemory::Port::sendTiming(PacketPtr pkt)
{
schedSendTiming(pkt, curTick + 1); //minimum latency, must be > 0
}
void RubyMemory::printConfigStats()
{
- std::ostream *os = simout.create(stats_file);
- g_system_ptr->printConfig(*os);
+ std::ostream *os = simout.create(params()->stats_file);
+ RubySystem::printConfig(*os);
*os << endl;
- g_system_ptr->printStats(*os);
+ RubySystem::printStats(*os);
}
#define __RUBY_MEMORY_HH__
#include <map>
+#include <vector>
+#include "base/callback.hh"
+#include "mem/packet.hh"
#include "mem/physical.hh"
+#include "mem/ruby/system/RubyPort.hh"
#include "params/RubyMemory.hh"
-#include "base/callback.hh"
-#include "mem/ruby/common/Driver.hh"
-class RubyMemory : public PhysicalMemory, public Driver
+class RubyMemory : public PhysicalMemory
{
- class RubyMemoryPort : public MemoryPort
+ public:
+ std::vector<RubyPort *> ruby_ports;
+ class Port : public MemoryPort
{
- RubyMemory* ruby_mem;
+ friend void ruby_hit_callback(int64_t req_id);
+
+ RubyMemory *ruby_mem;
public:
- RubyMemoryPort(const std::string &_name, RubyMemory *_memory);
+ Port(const std::string &_name, RubyMemory *_memory);
void sendTiming(PacketPtr pkt);
protected:
virtual const char *description() const { return "ruby tick"; }
};
+ struct SenderState : public Packet::SenderState
+ {
+ Port *port;
+ Packet::SenderState *saved;
+
+ SenderState(Port *p, Packet::SenderState *s = NULL)
+ : port(p), saved(s)
+ {}
+ };
private:
// prevent copying of a RubyMemory object
RubyMemory(const Params *p);
virtual ~RubyMemory();
+ const Params *
+ params() const
+ {
+ return safe_cast<const Params *>(_params);
+ }
+
public:
- virtual Port *getPort(const std::string &if_name, int idx = -1);
+ virtual ::Port *getPort(const std::string &if_name, int idx = -1);
void virtual init();
//Ruby-related specifics
- void printConfigStats(); //dsm: Maybe this function should disappear once the configuration options change & M5 determines the stats file to use
+ void printConfigStats(); //dsm: Maybe this function should
+ //disappear once the configuration
+ //options change & M5 determines the
+ //stats file to use
- void hitCallback(Packet* pkt); // called by the Ruby sequencer
+ void hitCallback(PacketPtr pkt, Port *port);
void printStats(std::ostream & out) const;
void clearStats();
void tick();
private:
- //Parameters passed
- std::string config_file, config_options, stats_file, debug_file;
- bool debug;
- int num_cpus;
- Tick ruby_clock, ruby_phase;
+ Tick ruby_clock;
+ Tick ruby_phase;
- std::map<Packet*, RubyMemoryPort*> m_packet_to_port_map;
+ public:
+ static std::map<int64_t, PacketPtr> pending_requests;
};
+void ruby_hit_callback(int64_t);
+
class RubyExitCallback : public Callback
{
private:
nb_cores = 8
cpus = [ MemTest() for i in xrange(nb_cores) ]
+import ruby_config
+ruby_memory = ruby_config.generate("MI_example-homogeneous.rb", nb_cores)
+
# system simulated
system = System(cpu = cpus, funcmem = PhysicalMemory(),
- physmem = RubyMemory(num_cpus=nb_cores),
+ physmem = ruby_memory,
membus = Bus(clock="500GHz", width=16))
for cpu in cpus:
nb_cores = 4
cpus = [ DerivO3CPU(cpu_id=i) for i in xrange(nb_cores) ]
+import ruby_config
+ruby_memory = ruby_config.generate("MI_example-homogeneous.rb", nb_cores)
+
# system simulated
-system = System(cpu = cpus, physmem = RubyMemory(num_cpus=nb_cores),
- membus = Bus())
+system = System(cpu = cpus, physmem = ruby_memory, membus = Bus())
for cpu in cpus:
cpu.connectMemPorts(system.membus)
m5.AddToPath('../configs/common')
+import ruby_config
+ruby_memory = ruby_config.generate("MI_example-homogeneous.rb", 1)
+
cpu = DerivO3CPU(cpu_id=0)
cpu.clock = '2GHz'
system = System(cpu = cpu,
- physmem = RubyMemory(),
+ physmem = ruby_memory,
membus = Bus())
system.physmem.port = system.membus.port
cpu.connectMemPorts(system.membus)
--- /dev/null
+import os
+import subprocess
+
+from os.path import dirname, join as joinpath
+
+import m5
+
+def generate(config_file, cores=1, memories=1, memory_size=1024):
+ default = joinpath(dirname(__file__), '../../src/mem/ruby/config')
+ ruby_config = os.environ.get('RUBY_CONFIG', default)
+ args = [ "ruby", "-I", ruby_config, joinpath(ruby_config, "print_cfg.rb"),
+ "-r", joinpath(ruby_config, config_file), "-p", str(cores),
+ "-m", str(memories), "-s", str(memory_size)]
+
+ temp_config = joinpath(m5.options.outdir, "ruby.config")
+ ret = subprocess.call(args, stdout=file(temp_config, "w"))
+ if ret != 0:
+ raise RuntimeError, "subprocess failed!"
+
+ return m5.objects.RubyMemory(config_file=temp_config, num_cpus=cores)
nb_cores = 4
cpus = [ AtomicSimpleCPU(cpu_id=i) for i in xrange(nb_cores) ]
+import ruby_config
+ruby_memory = ruby_config.generate("MI_example-homogeneous.rb", nb_cores)
+
# system simulated
-system = System(cpu = cpus, physmem = RubyMemory(num_cpus=nb_cores),
- membus = Bus())
+system = System(cpu = cpus, physmem = ruby_memory, membus = Bus())
# add L1 caches
for cpu in cpus:
import m5
from m5.objects import *
+import ruby_config
+ruby_memory = ruby_config.generate("MI_example-homogeneous.rb", 1)
+
system = System(cpu = AtomicSimpleCPU(cpu_id=0),
- physmem = RubyMemory(),
+ physmem = ruby_memory,
membus = Bus())
system.physmem.port = system.membus.port
system.cpu.connectMemPorts(system.membus)
nb_cores = 4
cpus = [ TimingSimpleCPU(cpu_id=i) for i in xrange(nb_cores) ]
+import ruby_config
+ruby_memory = ruby_config.generate("MI_example-homogeneous.rb", nb_cores)
+
# system simulated
-system = System(cpu = cpus, physmem = RubyMemory(num_cpus=nb_cores),
- membus = Bus())
+system = System(cpu = cpus, physmem = ruby_memory, membus = Bus())
# add L1 caches
for cpu in cpus:
import m5
from m5.objects import *
+import ruby_config
+ruby_memory = ruby_config.generate("MI_example-homogeneous.rb", 1)
+
cpu = TimingSimpleCPU(cpu_id=0)
system = System(cpu = cpu,
- physmem = RubyMemory(),
+ physmem = ruby_memory,
membus = Bus())
system.physmem.port = system.membus.port
cpu.connectMemPorts(system.membus)
import os
import sys
+
+from os.path import join as joinpath
+
import m5
# Since we're in batch mode, dont allow tcp socket connections
if os.path.isdir('/dist/m5/regression/test-progs'):
test_progs = '/dist/m5/regression/test-progs'
else:
- test_progs = os.path.join(tests_root, 'test-progs')
+ test_progs = joinpath(tests_root, 'test-progs')
# generate path to binary file
def binpath(app, file=None):
# executable has same name as app unless specified otherwise
if not file:
file = app
- return os.path.join(test_progs, app, 'bin', isa, opsys, file)
+ return joinpath(test_progs, app, 'bin', isa, opsys, file)
# generate path to input file
def inputpath(app, file=None):
# input file has same name as app unless specified otherwise
if not file:
file = app
- return os.path.join(test_progs, app, 'input', file)
+ return joinpath(test_progs, app, 'input', file)
# build configuration
-execfile(os.path.join(tests_root, 'configs', config + '.py'))
+sys.path.append(joinpath(tests_root, 'configs'))
+execfile(joinpath(tests_root, 'configs', config + '.py'))
# set default maxtick... script can override
# -1 means run forever
maxtick = m5.MaxTick
# tweak configuration for specific test
-
-execfile(os.path.join(tests_root, category, name, 'test.py'))
+sys.path.append(joinpath(tests_root, category, name))
+execfile(joinpath(tests_root, category, name, 'test.py'))
# instantiate configuration
m5.instantiate(root)