From 3cf24f9716eebab8c24fa645d02c636584033514 Mon Sep 17 00:00:00 2001 From: Brad Beckmann Date: Wed, 18 Nov 2009 13:55:58 -0800 Subject: 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. --- configs/common/FSConfig.py | 44 ++++++ configs/example/ruby_fs.py | 182 ++++++++++++++++++++++ src/mem/RubyMemory.py | 4 +- src/mem/SConscript | 1 + src/mem/ruby/config/MI_example-homogeneous.rb | 3 + src/mem/ruby/system/System.hh | 5 +- src/mem/rubymem.cc | 214 ++++++++++++++++++++++---- src/mem/rubymem.hh | 24 ++- tests/configs/ruby_config.py | 14 +- 9 files changed, 449 insertions(+), 42 deletions(-) create mode 100644 configs/example/ruby_fs.py diff --git a/configs/common/FSConfig.py b/configs/common/FSConfig.py index bd20a2bac..7ab7319cd 100644 --- a/configs/common/FSConfig.py +++ b/configs/common/FSConfig.py @@ -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), diff --git a/configs/example/ruby_fs.py b/configs/example/ruby_fs.py new file mode 100644 index 000000000..d27eae596 --- /dev/null +++ b/configs/example/ruby_fs.py @@ -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) diff --git a/src/mem/RubyMemory.py b/src/mem/RubyMemory.py index fbbbeebe4..ddd97572c 100644 --- a/src/mem/RubyMemory.py +++ b/src/mem/RubyMemory.py @@ -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") diff --git a/src/mem/SConscript b/src/mem/SConscript index 21335a709..2188850e0 100644 --- a/src/mem/SConscript +++ b/src/mem/SConscript @@ -63,3 +63,4 @@ TraceFlag('BusBridge') TraceFlag('LLSC') TraceFlag('MMU') TraceFlag('MemoryAccess') +TraceFlag('Ruby') diff --git a/src/mem/ruby/config/MI_example-homogeneous.rb b/src/mem/ruby/config/MI_example-homogeneous.rb index 2b416e647..b7842aaaf 100644 --- a/src/mem/ruby/config/MI_example-homogeneous.rb +++ b/src/mem/ruby/config/MI_example-homogeneous.rb @@ -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 diff --git a/src/mem/ruby/system/System.hh b/src/mem/ruby/system/System.hh index 38ef09177..1d36de878 100644 --- a/src/mem/ruby/system/System.hh +++ b/src/mem/ruby/system/System.hh @@ -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]; } diff --git a/src/mem/rubymem.cc b/src/mem/rubymem.cc index 14b2048a0..70077e7da 100644 --- a/src/mem/rubymem.cc +++ b/src/mem/rubymem.cc @@ -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 @@ -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 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(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 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 * diff --git a/src/mem/rubymem.hh b/src/mem/rubymem.hh index 1bfb135e8..dd0a492f5 100644 --- a/src/mem/rubymem.hh +++ b/src/mem/rubymem.hh @@ -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 ruby_ports; + std::vector 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 pending_requests; + RubyMemory::Port* pio_port; + + protected: + std::vector dma_ports; + + public: + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); }; void ruby_hit_callback(int64_t); diff --git a/tests/configs/ruby_config.py b/tests/configs/ruby_config.py index 7b8e27613..000b7d23f 100644 --- a/tests/configs/ruby_config.py +++ b/tests/configs/ruby_config.py @@ -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) -- cgit v1.2.3