ruby: Support for merging ALPHA_FS and ruby
Connects M5 cpu and dma ports directly to ruby sequencers and dma sequencers. Rubymem also includes a pio port so that pio requests and be forwarded to a special pio bus connecting to device pio ports.
This commit is contained in:
parent
d7a4f665ed
commit
3cf24f9716
9 changed files with 449 additions and 42 deletions
|
@ -79,6 +79,50 @@ def makeLinuxAlphaSystem(mem_mode, mdesc = None):
|
|||
|
||||
return self
|
||||
|
||||
def makeLinuxAlphaRubySystem(mem_mode, rubymem, mdesc = None):
|
||||
class BaseTsunami(Tsunami):
|
||||
ethernet = NSGigE(pci_bus=0, pci_dev=1, pci_func=0)
|
||||
ide = IdeController(disks=[Parent.disk0, Parent.disk2],
|
||||
pci_func=0, pci_dev=0, pci_bus=0)
|
||||
|
||||
|
||||
self = LinuxAlphaSystem(physmem = rubymem)
|
||||
if not mdesc:
|
||||
# generic system
|
||||
mdesc = SysConfig()
|
||||
self.readfile = mdesc.script()
|
||||
|
||||
# Create pio bus to connect all device pio ports to rubymem's pio port
|
||||
self.piobus = Bus(bus_id=0)
|
||||
|
||||
self.disk0 = CowIdeDisk(driveID='master')
|
||||
self.disk2 = CowIdeDisk(driveID='master')
|
||||
self.disk0.childImage(mdesc.disk())
|
||||
self.disk2.childImage(disk('linux-bigswap2.img'))
|
||||
self.tsunami = BaseTsunami()
|
||||
self.tsunami.attachIO(self.piobus)
|
||||
self.tsunami.ide.pio = self.piobus.port
|
||||
self.tsunami.ethernet.pio = self.piobus.port
|
||||
|
||||
# connect the dma ports directly to ruby dma ports
|
||||
self.tsunami.ide.dma = self.physmem.dma_port
|
||||
self.tsunami.ethernet.dma = self.physmem.dma_port
|
||||
|
||||
# connect the pio bus to rubymem
|
||||
self.physmem.pio_port = self.piobus.port
|
||||
|
||||
self.simple_disk = SimpleDisk(disk=RawDiskImage(image_file = mdesc.disk(),
|
||||
read_only = True))
|
||||
self.intrctrl = IntrControl()
|
||||
self.mem_mode = mem_mode
|
||||
self.terminal = Terminal()
|
||||
self.kernel = binary('vmlinux')
|
||||
self.pal = binary('ts_osfpal')
|
||||
self.console = binary('console')
|
||||
self.boot_osflags = 'root=/dev/hda1 console=ttyS0'
|
||||
|
||||
return self
|
||||
|
||||
def makeSparcSystem(mem_mode, mdesc = None):
|
||||
class CowMmDisk(MmDisk):
|
||||
image = CowDiskImage(child=RawDiskImage(read_only=True),
|
||||
|
|
182
configs/example/ruby_fs.py
Normal file
182
configs/example/ruby_fs.py
Normal file
|
@ -0,0 +1,182 @@
|
|||
# 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: Brad Beckmann
|
||||
|
||||
#
|
||||
# Full system configuraiton for ruby
|
||||
#
|
||||
|
||||
import os
|
||||
import optparse
|
||||
import sys
|
||||
from os.path import join as joinpath
|
||||
|
||||
import m5
|
||||
from m5.defines import buildEnv
|
||||
from m5.objects import *
|
||||
from m5.util import addToPath, panic
|
||||
|
||||
if not buildEnv['FULL_SYSTEM']:
|
||||
panic("This script requires full-system mode (*_FS).")
|
||||
|
||||
addToPath('../../tests/configs/')
|
||||
addToPath('../common')
|
||||
|
||||
import ruby_config
|
||||
|
||||
from FSConfig import *
|
||||
from SysPaths import *
|
||||
from Benchmarks import *
|
||||
import Simulation
|
||||
from Caches import *
|
||||
|
||||
# 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()
|
||||
|
||||
# Benchmark options
|
||||
parser.add_option("-b", "--benchmark", action="store", type="string",
|
||||
dest="benchmark",
|
||||
help="Specify the benchmark to run. Available benchmarks: %s"\
|
||||
% DefinedBenchmarks)
|
||||
parser.add_option("-o", "--options", default="",
|
||||
help='The options to pass to the binary, use " " around the entire string')
|
||||
parser.add_option("-i", "--input", default="", help="Read stdin from a file.")
|
||||
parser.add_option("--output", default="", help="Redirect stdout to a file.")
|
||||
parser.add_option("--errout", default="", help="Redirect stderr to a file.")
|
||||
parser.add_option("--ruby-debug", action="store_true")
|
||||
parser.add_option("--ruby-debug-file", default="", help="Ruby debug out file (stdout if blank)")
|
||||
|
||||
# ruby host memory experimentation
|
||||
parser.add_option("--cache_size", type="int")
|
||||
parser.add_option("--cache_assoc", type="int")
|
||||
parser.add_option("--map_levels", type="int")
|
||||
|
||||
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)
|
||||
|
||||
if options.benchmark:
|
||||
try:
|
||||
bm = Benchmarks[options.benchmark]
|
||||
except KeyError:
|
||||
print "Error benchmark %s has not been defined." % options.benchmark
|
||||
print "Valid benchmarks are: %s" % DefinedBenchmarks
|
||||
sys.exit(1)
|
||||
else:
|
||||
bm = [SysConfig()]
|
||||
|
||||
#
|
||||
# currently ruby fs only works in timing mode because ruby does not support
|
||||
# atomic accesses by devices
|
||||
#
|
||||
assert(options.timing)
|
||||
|
||||
(CPUClass, test_mem_mode, FutureClass) = Simulation.setCPUClass(options)
|
||||
|
||||
CPUClass.clock = '1GHz'
|
||||
|
||||
#
|
||||
# Since we are running in timing mode, set the number of M5 ticks to ruby ticks
|
||||
# to the cpu clock frequency
|
||||
#
|
||||
M5_to_ruby_tick = '1000t'
|
||||
|
||||
np = options.num_cpus
|
||||
|
||||
# check for max instruction count
|
||||
if options.max_inst:
|
||||
max_inst = options.max_inst
|
||||
else:
|
||||
max_inst = 0
|
||||
|
||||
# set cache size
|
||||
if options.cache_size:
|
||||
cache_size = options.cache_size
|
||||
else:
|
||||
cache_size = 32768 # 32 kB is default
|
||||
|
||||
# set cache assoc
|
||||
if options.cache_assoc:
|
||||
cache_assoc = options.cache_assoc
|
||||
else:
|
||||
cache_assoc = 8 # 8 is default
|
||||
|
||||
# set map levels
|
||||
if options.map_levels:
|
||||
map_levels = options.map_levels
|
||||
else:
|
||||
map_levels = 4 # 4 levels is the default
|
||||
|
||||
#
|
||||
# Currently, since ruby configuraiton is separate from m5, we need to manually
|
||||
# tell ruby that two dma ports are created by makeLinuxAlphaRubySystem().
|
||||
# Eventually, this will be fix with a unified configuration system.
|
||||
#
|
||||
rubymem = ruby_config.generate("MI_example-homogeneous.rb",
|
||||
np,
|
||||
np,
|
||||
128,
|
||||
False,
|
||||
cache_size,
|
||||
cache_assoc,
|
||||
map_levels,
|
||||
2,
|
||||
M5_to_ruby_tick)
|
||||
|
||||
if options.ruby_debug == True:
|
||||
rubymem.debug = True
|
||||
rubymem.debug_file = options.ruby_debug_file
|
||||
|
||||
system = makeLinuxAlphaRubySystem(test_mem_mode, rubymem, bm[0])
|
||||
|
||||
system.cpu = [CPUClass(cpu_id=i) for i in xrange(np)]
|
||||
|
||||
if options.l2cache:
|
||||
print "Error: -l2cache incompatible with ruby, must configure it ruby-style"
|
||||
sys.exit(1)
|
||||
|
||||
if options.caches:
|
||||
print "Error: -caches incompatible with ruby, must configure it ruby-style"
|
||||
sys.exit(1)
|
||||
|
||||
for i in xrange(np):
|
||||
system.cpu[i].connectMemPorts(system.physmem)
|
||||
|
||||
if options.fastmem:
|
||||
system.cpu[i].physmem_port = system.physmem.port
|
||||
|
||||
root = Root(system = system)
|
||||
|
||||
Simulation.run(options, root, system, FutureClass)
|
|
@ -42,4 +42,6 @@ class RubyMemory(PhysicalMemory):
|
|||
debug = Param.Bool(False, "Use ruby debug")
|
||||
debug_file = Param.String("ruby.debug",
|
||||
"path to the Ruby debug output file (stdout if blank)")
|
||||
|
||||
num_dmas = Param.Int(0, "Number of DMA ports connected to the Ruby memory")
|
||||
dma_port = VectorPort("Ruby_dma_ports")
|
||||
pio_port = Port("Ruby_pio_port")
|
||||
|
|
|
@ -63,3 +63,4 @@ TraceFlag('BusBridge')
|
|||
TraceFlag('LLSC')
|
||||
TraceFlag('MMU')
|
||||
TraceFlag('MemoryAccess')
|
||||
TraceFlag('Ruby')
|
||||
|
|
|
@ -37,6 +37,9 @@ for i in 0..$*.size-1 do
|
|||
elsif $*[i] == "-s"
|
||||
memory_size_mb = $*[i+1].to_i
|
||||
i = i + 1
|
||||
elsif $*[i] == "-D"
|
||||
num_dma = $*[i+1].to_i
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -107,7 +107,10 @@ public:
|
|||
if (m_ports.count(name) != 1){
|
||||
cerr << "Port " << name << " has " << m_ports.count(name) << " instances" << endl;
|
||||
}
|
||||
assert(m_ports.count(name) == 1); m_ports[name]->registerHitCallback(hit_callback); return m_ports[name]; }
|
||||
assert(m_ports.count(name) == 1);
|
||||
m_ports[name]->registerHitCallback(hit_callback);
|
||||
return m_ports[name];
|
||||
}
|
||||
static Network* getNetwork() { assert(m_network_ptr != NULL); return m_network_ptr; }
|
||||
static Topology* getTopology(const string & name) { assert(m_topologies.count(name) == 1); return m_topologies[name]; }
|
||||
static CacheMemory* getCache(const string & name) { assert(m_caches.count(name) == 1); return m_caches[name]; }
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2005 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
|
||||
|
@ -26,6 +27,7 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Authors: Daniel Sanchez
|
||||
* Brad Beckmann
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
@ -63,6 +65,7 @@ RubyMemory::RubyMemory(const Params *p)
|
|||
char buffer[65536];
|
||||
config.getline(buffer, sizeof(buffer));
|
||||
string line = buffer;
|
||||
DPRINTF(Ruby, "%s %d\n", line, line.empty());
|
||||
if (line.empty())
|
||||
continue;
|
||||
vector<string> tokens;
|
||||
|
@ -81,11 +84,27 @@ RubyMemory::RubyMemory(const Params *p)
|
|||
|
||||
RubySystem::create(sys_conf);
|
||||
|
||||
//
|
||||
// Create the necessary ruby_ports to connect to the sequencers.
|
||||
// This code should be fixed when the configuration systems are unified
|
||||
// and the ruby configuration text files no longer exist. Also,
|
||||
// it would be great to remove the single ruby_hit_callback func with
|
||||
// separate pointers to particular ports to rubymem. However, functional
|
||||
// access currently prevent the improvement.
|
||||
//
|
||||
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);
|
||||
}
|
||||
|
||||
for (int i = 0; i < params()->num_dmas; i++) {
|
||||
RubyPort *p = RubySystem::getPort(csprintf("DMASequencer_%d", i),
|
||||
ruby_hit_callback);
|
||||
ruby_dma_ports.push_back(p);
|
||||
}
|
||||
|
||||
pio_port = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -106,7 +125,6 @@ RubyMemory::init()
|
|||
//g_debug_ptr->setDebugTime(1);
|
||||
//g_debug_ptr->setDebugOutputFile("ruby.debug");
|
||||
|
||||
|
||||
g_system_ptr->clearStats();
|
||||
|
||||
if (ports.size() == 0) {
|
||||
|
@ -118,6 +136,15 @@ RubyMemory::init()
|
|||
(*pi)->sendStatusChange(Port::RangeChange);
|
||||
}
|
||||
|
||||
for (PortIterator pi = dma_ports.begin(); pi != dma_ports.end(); ++pi) {
|
||||
if (*pi)
|
||||
(*pi)->sendStatusChange(Port::RangeChange);
|
||||
}
|
||||
|
||||
if (pio_port != NULL) {
|
||||
pio_port->sendStatusChange(Port::RangeChange);
|
||||
}
|
||||
|
||||
//Print stats at exit
|
||||
rubyExitCB = new RubyExitCallback(this);
|
||||
registerExitCallback(rubyExitCB);
|
||||
|
@ -141,35 +168,45 @@ RubyMemory::~RubyMemory()
|
|||
delete g_system_ptr;
|
||||
}
|
||||
|
||||
void
|
||||
RubyMemory::hitCallback(PacketPtr pkt, Port *port)
|
||||
{
|
||||
DPRINTF(MemoryAccess, "Hit callback\n");
|
||||
|
||||
bool needsResponse = pkt->needsResponse();
|
||||
doAtomicAccess(pkt);
|
||||
|
||||
// turn packet around to go back to requester if response expected
|
||||
if (needsResponse) {
|
||||
// recvAtomic() should already have turned packet into
|
||||
// atomic response
|
||||
assert(pkt->isResponse());
|
||||
DPRINTF(MemoryAccess, "Sending packet back over port\n");
|
||||
port->sendTiming(pkt);
|
||||
} else {
|
||||
delete pkt;
|
||||
}
|
||||
DPRINTF(MemoryAccess, "Hit callback done!\n");
|
||||
}
|
||||
|
||||
Port *
|
||||
RubyMemory::getPort(const std::string &if_name, int idx)
|
||||
{
|
||||
DPRINTF(Ruby, "getting port %d %s\n", idx, if_name);
|
||||
DPRINTF(Ruby,
|
||||
"number of ruby ports %d and dma ports %d\n",
|
||||
ruby_ports.size(),
|
||||
ruby_dma_ports.size());
|
||||
|
||||
// Accept request for "functional" port for backwards compatibility
|
||||
// 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 Port(csprintf("%s-functional", name()), this);
|
||||
return new Port(csprintf("%s-functional", name()),
|
||||
this,
|
||||
ruby_ports[idx]);
|
||||
}
|
||||
|
||||
//
|
||||
// if dma port request, allocate the appropriate prot
|
||||
//
|
||||
if (if_name == "dma_port") {
|
||||
assert(idx < ruby_dma_ports.size());
|
||||
RubyMemory::Port* dma_port =
|
||||
new Port(csprintf("%s-dma_port%d", name(), idx),
|
||||
this,
|
||||
ruby_dma_ports[idx]);
|
||||
dma_ports.push_back(dma_port);
|
||||
return dma_port;
|
||||
}
|
||||
|
||||
//
|
||||
// if pio port, ensure that there is only one
|
||||
//
|
||||
if (if_name == "pio_port") {
|
||||
assert(pio_port == NULL);
|
||||
pio_port =
|
||||
new RubyMemory::Port("ruby_pio_port", this, NULL);
|
||||
return pio_port;
|
||||
}
|
||||
|
||||
if (if_name != "port") {
|
||||
|
@ -184,30 +221,68 @@ RubyMemory::getPort(const std::string &if_name, int idx)
|
|||
panic("RubyMemory::getPort: port %d already assigned", idx);
|
||||
}
|
||||
|
||||
Port *port = new Port(csprintf("%s-port%d", name(), idx), this);
|
||||
//
|
||||
// Currently this code assumes that each cpu has both a
|
||||
// icache and dcache port and therefore divides by two. This will be
|
||||
// fixed once we unify the configuration systems and Ruby sequencers
|
||||
// directly support M5 ports.
|
||||
//
|
||||
assert(idx/2 < ruby_ports.size());
|
||||
Port *port = new Port(csprintf("%s-port%d", name(), idx),
|
||||
this,
|
||||
ruby_ports[idx/2]);
|
||||
|
||||
ports[idx] = port;
|
||||
return port;
|
||||
}
|
||||
|
||||
RubyMemory::Port::Port(const std::string &_name, RubyMemory *_memory)
|
||||
RubyMemory::Port::Port(const std::string &_name,
|
||||
RubyMemory *_memory,
|
||||
RubyPort *_port)
|
||||
: PhysicalMemory::MemoryPort::MemoryPort(_name, _memory)
|
||||
{
|
||||
DPRINTF(Ruby, "creating port to ruby memory %s\n", _name);
|
||||
ruby_mem = _memory;
|
||||
ruby_port = _port;
|
||||
}
|
||||
|
||||
bool
|
||||
RubyMemory::Port::recvTiming(PacketPtr pkt)
|
||||
{
|
||||
DPRINTF(MemoryAccess, "Timing access caught\n");
|
||||
DPRINTF(MemoryAccess,
|
||||
"Timing access caught for address %#x\n",
|
||||
pkt->getAddr());
|
||||
|
||||
//dsm: based on SimpleTimingPort::recvTiming(pkt);
|
||||
|
||||
// If the device is only a slave, it should only be sending
|
||||
// responses, which should never get nacked. There used to be
|
||||
// code to hanldle nacks here, but I'm pretty sure it didn't work
|
||||
// correctly with the drain code, so that would need to be fixed
|
||||
// if we ever added it back.
|
||||
//
|
||||
// In FS mode, ruby memory will receive pio responses from devices and
|
||||
// it must forward these responses back to the particular CPU.
|
||||
//
|
||||
if (pkt->isResponse() != false && isPioAddress(pkt->getAddr()) != false) {
|
||||
DPRINTF(MemoryAccess,
|
||||
"Pio Response callback %#x\n",
|
||||
pkt->getAddr());
|
||||
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->sendTiming(pkt);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// After checking for pio responses, the remainder of packets
|
||||
// received by ruby should only be M5 requests, which should never
|
||||
// get nacked. There used to be code to hanldle nacks here, but
|
||||
// I'm pretty sure it didn't work correctly with the drain code,
|
||||
// so that would need to be fixed if we ever added it back.
|
||||
//
|
||||
assert(pkt->isRequest());
|
||||
|
||||
if (pkt->memInhibitAsserted()) {
|
||||
|
@ -221,6 +296,18 @@ RubyMemory::Port::recvTiming(PacketPtr pkt)
|
|||
// Save the port in the sender state object
|
||||
pkt->senderState = new SenderState(this, pkt->senderState);
|
||||
|
||||
//
|
||||
// Check for pio requests and directly send them to the dedicated
|
||||
// pio_port.
|
||||
//
|
||||
if (isPioAddress(pkt->getAddr()) != false) {
|
||||
return ruby_mem->pio_port->sendTiming(pkt);
|
||||
}
|
||||
|
||||
//
|
||||
// For DMA and CPU requests, translate them to ruby requests before
|
||||
// sending them to our assigned ruby port.
|
||||
//
|
||||
RubyRequestType type = RubyRequestType_NULL;
|
||||
Addr pc = 0;
|
||||
if (pkt->isRead()) {
|
||||
|
@ -241,7 +328,6 @@ RubyMemory::Port::recvTiming(PacketPtr pkt)
|
|||
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 =
|
||||
|
@ -262,6 +348,12 @@ RubyMemory::Port::recvTiming(PacketPtr pkt)
|
|||
void
|
||||
ruby_hit_callback(int64_t req_id)
|
||||
{
|
||||
//
|
||||
// Note: This single fuction can be called by cpu and dma ports,
|
||||
// as well as the functional port. The functional port prevents
|
||||
// us from replacing this single function with separate port
|
||||
// functions.
|
||||
//
|
||||
typedef map<int64_t, PacketPtr> map_t;
|
||||
map_t &prm = RubyMemory::pending_requests;
|
||||
|
||||
|
@ -280,13 +372,58 @@ ruby_hit_callback(int64_t req_id)
|
|||
pkt->senderState = senderState->saved;
|
||||
delete senderState;
|
||||
|
||||
port->ruby_mem->hitCallback(pkt, port);
|
||||
port->hitCallback(pkt);
|
||||
}
|
||||
|
||||
void
|
||||
RubyMemory::Port::hitCallback(PacketPtr pkt)
|
||||
{
|
||||
|
||||
bool needsResponse = pkt->needsResponse();
|
||||
|
||||
DPRINTF(MemoryAccess, "Hit callback needs response %d\n",
|
||||
needsResponse);
|
||||
|
||||
ruby_mem->doAtomicAccess(pkt);
|
||||
|
||||
// turn packet around to go back to requester if response expected
|
||||
if (needsResponse) {
|
||||
// recvAtomic() should already have turned packet into
|
||||
// atomic response
|
||||
assert(pkt->isResponse());
|
||||
DPRINTF(MemoryAccess, "Sending packet back over port\n");
|
||||
sendTiming(pkt);
|
||||
} else {
|
||||
delete pkt;
|
||||
}
|
||||
DPRINTF(MemoryAccess, "Hit callback done!\n");
|
||||
}
|
||||
|
||||
bool
|
||||
RubyMemory::Port::sendTiming(PacketPtr pkt)
|
||||
{
|
||||
schedSendTiming(pkt, curTick + 1); //minimum latency, must be > 0
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
RubyMemory::Port::isPioAddress(Addr addr)
|
||||
{
|
||||
AddrRangeList pioAddrList;
|
||||
bool snoop = false;
|
||||
if (ruby_mem->pio_port == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ruby_mem->pio_port->getPeerAddressRanges(pioAddrList, snoop);
|
||||
for(AddrRangeIter iter = pioAddrList.begin(); iter != pioAddrList.end(); iter++) {
|
||||
if (addr >= iter->start && addr <= iter->end) {
|
||||
DPRINTF(MemoryAccess, "Pio request found in %#llx - %#llx range\n",
|
||||
iter->start, iter->end);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RubyMemory::printConfigStats()
|
||||
|
@ -313,6 +450,17 @@ void RubyMemory::printConfig(std::ostream & out) const {
|
|||
//g_system_ptr->printConfig(out);
|
||||
}
|
||||
|
||||
void RubyMemory::serialize(ostream &os)
|
||||
{
|
||||
PhysicalMemory::serialize(os);
|
||||
}
|
||||
|
||||
void RubyMemory::unserialize(Checkpoint *cp, const string §ion)
|
||||
{
|
||||
DPRINTF(Config, "Ruby memory being restored\n");
|
||||
reschedule(rubyTickEvent, curTick + ruby_clock + ruby_phase);
|
||||
PhysicalMemory::unserialize(cp, section);
|
||||
}
|
||||
|
||||
//Python-interface code
|
||||
RubyMemory *
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2005 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
|
||||
|
@ -39,6 +40,7 @@
|
|||
#include "mem/physical.hh"
|
||||
#include "mem/ruby/system/RubyPort.hh"
|
||||
#include "params/RubyMemory.hh"
|
||||
#include "mem/port.hh"
|
||||
|
||||
class RubyExitCallback;
|
||||
|
||||
|
@ -46,18 +48,26 @@ class RubyMemory : public PhysicalMemory
|
|||
{
|
||||
public:
|
||||
std::vector<RubyPort *> ruby_ports;
|
||||
std::vector<RubyPort *> ruby_dma_ports;
|
||||
class Port : public MemoryPort
|
||||
{
|
||||
friend void ruby_hit_callback(int64_t req_id);
|
||||
|
||||
RubyMemory *ruby_mem;
|
||||
RubyPort *ruby_port;
|
||||
|
||||
public:
|
||||
Port(const std::string &_name, RubyMemory *_memory);
|
||||
void sendTiming(PacketPtr pkt);
|
||||
Port(const std::string &_name,
|
||||
RubyMemory *_memory,
|
||||
RubyPort *_port);
|
||||
bool sendTiming(PacketPtr pkt);
|
||||
void hitCallback(PacketPtr pkt);
|
||||
|
||||
protected:
|
||||
virtual bool recvTiming(PacketPtr pkt);
|
||||
|
||||
private:
|
||||
bool isPioAddress(Addr addr);
|
||||
};
|
||||
|
||||
class RubyEvent : public Event
|
||||
|
@ -110,8 +120,6 @@ class RubyMemory : public PhysicalMemory
|
|||
//options change & M5 determines the
|
||||
//stats file to use
|
||||
|
||||
void hitCallback(PacketPtr pkt, Port *port);
|
||||
|
||||
void printStats(std::ostream & out) const;
|
||||
void clearStats();
|
||||
void printConfig(std::ostream & out) const;
|
||||
|
@ -125,6 +133,14 @@ class RubyMemory : public PhysicalMemory
|
|||
|
||||
public:
|
||||
static std::map<int64_t, PacketPtr> pending_requests;
|
||||
RubyMemory::Port* pio_port;
|
||||
|
||||
protected:
|
||||
std::vector<MemoryPort*> dma_ports;
|
||||
|
||||
public:
|
||||
virtual void serialize(std::ostream &os);
|
||||
virtual void unserialize(Checkpoint *cp, const std::string §ion);
|
||||
};
|
||||
|
||||
void ruby_hit_callback(int64_t);
|
||||
|
|
|
@ -4,17 +4,25 @@ import subprocess
|
|||
from os.path import dirname, join as joinpath
|
||||
|
||||
import m5
|
||||
from m5.params import *
|
||||
|
||||
def generate(config_file, cores=1, memories=1, memory_size=1024):
|
||||
def generate(config_file, cores=1, memories=1, memory_size=1024, \
|
||||
cache_size=32768, cache_assoc=8, dmas=1,
|
||||
ruby_tick='1t'):
|
||||
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)]
|
||||
"-m", str(memories), "-s", str(memory_size), "-C", str(cache_size),
|
||||
"-A", str(cache_assoc), "-D", str(dmas)]
|
||||
|
||||
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)
|
||||
return m5.objects.RubyMemory(clock = ruby_tick,
|
||||
config_file = temp_config,
|
||||
num_cpus = cores,
|
||||
range = AddrRange(str(memory_size)+"MB"),
|
||||
num_dmas = dmas)
|
||||
|
|
Loading…
Reference in a new issue