ruby: Working M5 interface and updated Ruby interface.
authorDaniel Sanchez <sanchezd@stanford.edu>
Mon, 11 May 2009 17:38:46 +0000 (10:38 -0700)
committerDaniel Sanchez <sanchezd@stanford.edu>
Mon, 11 May 2009 17:38:46 +0000 (10:38 -0700)
This changeset also includes a lot of work from Derek Hower <drh5@cs.wisc.edu>

RubyMemory is now both a driver for Ruby and a port for M5.  Changed
makeRequest/hitCallback interface. Brought packets (superficially)
into the sequencer. Modified tester infrastructure to be packet based.
and Ruby can be used together through the example ruby_se.py
script. SPARC parallel applications work, and the timing *seems* right
from combined M5/Ruby debug traces. To run,
% build/ALPHA_SE/m5.debug configs/example/ruby_se.py -c
  tests/test-progs/hello/bin/alpha/linux/hello -n 4 -t

29 files changed:
configs/example/ruby.config [new file with mode: 0644]
configs/example/ruby_se.py [new file with mode: 0644]
src/mem/RubyMemory.py [new file with mode: 0644]
src/mem/SConscript
src/mem/gems_common/ioutil/initvar.hh
src/mem/ruby/common/Driver.hh
src/mem/ruby/init.cc
src/mem/ruby/init.hh
src/mem/ruby/interfaces/mf_api.hh [deleted file]
src/mem/ruby/recorder/TraceRecord.cc
src/mem/ruby/system/CacheMemory.hh
src/mem/ruby/system/Sequencer.cc
src/mem/ruby/system/Sequencer.hh
src/mem/ruby/system/StoreBuffer.cc
src/mem/ruby/system/StoreBuffer.hh
src/mem/ruby/system/System.cc
src/mem/ruby/system/System.hh
src/mem/ruby/tester/Check.cc
src/mem/ruby/tester/DetermGETXGenerator.cc
src/mem/ruby/tester/DetermInvGenerator.cc
src/mem/ruby/tester/DetermSeriesGETSGenerator.cc
src/mem/ruby/tester/DeterministicDriver.cc
src/mem/ruby/tester/DeterministicDriver.hh
src/mem/ruby/tester/RequestGenerator.cc
src/mem/ruby/tester/SyntheticDriver.cc
src/mem/ruby/tester/SyntheticDriver.hh
src/mem/ruby/tester/main.cc
src/mem/rubymem.cc [new file with mode: 0644]
src/mem/rubymem.hh [new file with mode: 0644]

diff --git a/configs/example/ruby.config b/configs/example/ruby.config
new file mode 100644 (file)
index 0000000..1297ae6
--- /dev/null
@@ -0,0 +1,190 @@
+//Default parameters, taken from /athitos/export/08spr_ee382a/sanchezd/runs/gen-scripts/ruby.defaults
+
+//General config
+g_DEADLOCK_THRESHOLD: 20000000
+RANDOMIZATION: false
+g_tester_length: 0
+SIMICS_RUBY_MULTIPLIER: 1
+OPAL_RUBY_MULTIPLIER: 1
+TRANSACTION_TRACE_ENABLED: false
+USER_MODE_DATA_ONLY: false
+PROFILE_HOT_LINES: false
+PROFILE_ALL_INSTRUCTIONS: false
+PRINT_INSTRUCTION_TRACE: false
+g_DEBUG_CYCLE: 0
+PERFECT_MEMORY_SYSTEM: false
+PERFECT_MEMORY_SYSTEM_LATENCY: 0
+DATA_BLOCK: false
+
+// Line, page sizes
+g_DATA_BLOCK_BYTES: 64
+g_PAGE_SIZE_BYTES: 8192
+
+
+g_REPLACEMENT_POLICY: PSEDUO_LRU
+// For all caches (sic)
+
+// L1 config
+//  32KB, 4-way SA
+L1_CACHE_ASSOC: 4
+L1_CACHE_NUM_SETS_BITS: 7
+//  Single-cycle latency, hits take fastpath
+SEQUENCER_TO_CONTROLLER_LATENCY: 1
+REMOVE_SINGLE_CYCLE_DCACHE_FAST_PATH: false
+//  L1->L2 delays
+L1_REQUEST_LATENCY: 1
+L1_RESPONSE_LATENCY: 1
+
+// L2 parameters
+//  4 MB, 16-way SA
+L2_CACHE_ASSOC: 16
+L2_CACHE_NUM_SETS_BITS: 12
+MAP_L2BANKS_TO_LOWEST_BITS: false
+//  Bank latencies
+L2_RESPONSE_LATENCY: 10
+L2_TAG_LATENCY: 5
+
+
+// Directory latencies
+//  The one that counts, we have perfect dirs
+DIRECTORY_CACHE_LATENCY: 6
+//  should not be used, but just in case...
+DIRECTORY_LATENCY: 6
+
+// Simple network parameters
+//  external links
+NETWORK_LINK_LATENCY: 1
+// intra-chip links
+ON_CHIP_LINK_LATENCY: 1
+
+// General latencies
+RECYCLE_LATENCY: 1
+//Used in MessageBuffer, also MSI_MOSI_CMP dir controller
+
+
+// Unused parameters, good to define them to really weird things just in case
+NULL_LATENCY: 100000
+// Only SMP and token CMP protocols
+ISSUE_LATENCY: 100000
+// Only SMP, example protocols
+CACHE_RESPONSE_LATENCY: 100000
+// Only SMP protocols
+COPY_HEAD_LATENCY: 100000
+// In no protocols or ruby code
+L2_RECYCLE_LATENCY: 100000
+// In no protocols or ruby code
+TIMER_LATENCY: 100000
+// Not used
+TBE_RESPONSE_LATENCY: 100000
+// Not used
+PERIODIC_TIMER_WAKEUPS: false
+// Not used
+BLOCK_STC: false
+// Not used
+SINGLE_ACCESS_L2_BANKS: false
+// Not used
+
+// Main memory latency
+MEMORY_RESPONSE_LATENCY_MINUS_2: 448 //not used in _m, see below
+
+PROFILE_EXCEPTIONS: false
+PROFILE_XACT: false
+PROFILE_NONXACT: true
+XACT_DEBUG: false
+XACT_DEBUG_LEVEL: 1
+XACT_MEMORY: false
+XACT_ENABLE_TOURMALINE: false
+XACT_NUM_CURRENT: 0
+XACT_LAST_UPDATE: 0
+XACT_ISOLATION_CHECK: false
+PERFECT_FILTER: true
+READ_WRITE_FILTER: Perfect_
+PERFECT_VIRTUAL_FILTER: true
+VIRTUAL_READ_WRITE_FILTER: Perfect_
+PERFECT_SUMMARY_FILTER: true
+SUMMARY_READ_WRITE_FILTER: Perfect_
+XACT_EAGER_CD: true
+XACT_LAZY_VM: false
+XACT_CONFLICT_RES: BASE
+XACT_COMMIT_TOKEN_LATENCY: 0
+XACT_NO_BACKOFF: false
+XACT_LOG_BUFFER_SIZE: 0
+XACT_STORE_PREDICTOR_HISTORY: 0
+XACT_STORE_PREDICTOR_ENTRIES: 0
+XACT_STORE_PREDICTOR_THRESHOLD: 0
+XACT_FIRST_ACCESS_COST: 0
+XACT_FIRST_PAGE_ACCESS_COST: 0
+ENABLE_MAGIC_WAITING: false
+ENABLE_WATCHPOINT: false
+XACT_ENABLE_VIRTUALIZATION_LOGTM_SE: false
+ATMTP_ENABLED: false
+ATMTP_ABORT_ON_NON_XACT_INST: false
+ATMTP_ALLOW_SAVE_RESTORE_IN_XACT: false
+ATMTP_XACT_MAX_STORES: 0
+ATMTP_DEBUG_LEVEL: 0
+XACT_LENGTH: 0
+XACT_SIZE: 0
+ABORT_RETRY_TIME: 0
+
+
+// Allowed parallelism in controllers
+L1CACHE_TRANSITIONS_PER_RUBY_CYCLE: 32
+L2CACHE_TRANSITIONS_PER_RUBY_CYCLE: 1000
+DIRECTORY_TRANSITIONS_PER_RUBY_CYCLE: 1000
+g_SEQUENCER_OUTSTANDING_REQUESTS: 16
+
+//TBEs == MSHRs (global)
+NUMBER_OF_TBES: 128
+NUMBER_OF_L1_TBES: 32
+// unused in CMP protocols
+NUMBER_OF_L2_TBES: 32
+// unused in CMP protocols
+
+
+// TSO & WBuffer params (unused)
+FINITE_BUFFERING: false
+FINITE_BUFFER_SIZE: 3
+PROCESSOR_BUFFER_SIZE: 10
+PROTOCOL_BUFFER_SIZE: 32
+TSO: false
+
+// General network params
+g_endpoint_bandwidth: 10000
+g_adaptive_routing: true
+NUMBER_OF_VIRTUAL_NETWORKS: 5
+FAN_OUT_DEGREE: 4
+//  for HIERARCHICAL_SWITCH
+
+
+// Detailed Memory Controller Params (only used in _m protocols)
+MEM_BUS_CYCLE_MULTIPLIER: 5
+BANKS_PER_RANK: 8
+RANKS_PER_DIMM: 2
+DIMMS_PER_CHANNEL: 2
+BANK_BIT_0: 8
+RANK_BIT_0: 11
+DIMM_BIT_0: 12
+
+BANK_QUEUE_SIZE: 12
+BANK_BUSY_TIME: 22
+RANK_RANK_DELAY: 2
+READ_WRITE_DELAY: 3
+BASIC_BUS_BUSY_TIME: 3
+MEM_CTL_LATENCY: 20
+REFRESH_PERIOD: 3120
+TFAW: 0
+//flip a coin to delay requests by one cycle, introduces non-determinism
+MEM_RANDOM_ARBITRATE: 50
+MEM_FIXED_DELAY: 0
+
+
+//Configuration-specific parameters
+g_NUM_PROCESSORS: 1
+g_NUM_CHIPS: 1
+g_PROCS_PER_CHIP: 1
+g_NUM_L2_BANKS: 1
+g_NUM_MEMORIES: 4
+g_PRINT_TOPOLOGY: true
+g_GARNET_NETWORK: true
+g_DETAIL_NETWORK: true
+g_FLIT_SIZE: 8
diff --git a/configs/example/ruby_se.py b/configs/example/ruby_se.py
new file mode 100644 (file)
index 0000000..488ccb6
--- /dev/null
@@ -0,0 +1,172 @@
+# Copyright (c) 2006-2008 The Regents of The University of Michigan
+# 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: Steve Reinhardt
+
+# Simple test script
+#
+# "m5 test.py"
+
+import m5
+
+if m5.build_env['FULL_SYSTEM']:
+    m5.panic("This script requires syscall emulation mode (*_SE).")
+
+from m5.objects import *
+import os, optparse, sys
+from os.path import join as joinpath
+m5.AddToPath('../common')
+import Simulation
+#from Caches import *
+from cpu2000 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("-c", "--cmd",
+    default=joinpath(m5_root, "tests/test-progs/hello/bin/alpha/linux/hello"),
+    help="The binary to run in syscall emulation mode.")
+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)")
+
+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.bench:
+    try:
+        if m5.build_env['TARGET_ISA'] != 'alpha':
+            print >>sys.stderr, "Simpoints code only works for Alpha ISA at this time"
+            sys.exit(1)
+        exec("workload = %s('alpha', 'tru64', 'ref')" % options.bench)
+        process = workload.makeLiveProcess()
+    except:
+        print >>sys.stderr, "Unable to find workload for %s" % options.bench
+        sys.exit(1)
+else:
+    process = LiveProcess()
+    process.executable = options.cmd
+    process.cmd = [options.cmd] + options.options.split()
+
+
+if options.input != "":
+    process.input = options.input
+if options.output != "":
+    process.output = options.output
+if options.errout != "":
+    process.errout = options.errout
+
+if options.detailed:
+    #check for SMT workload
+    workloads = options.cmd.split(';')
+    if len(workloads) > 1:
+        process = []
+        smt_idx = 0
+        inputs = []
+        outputs = []
+        errouts = []
+
+        if options.input != "":
+            inputs = options.input.split(';')
+        if options.output != "":
+            outputs = options.output.split(';')
+        if options.errout != "":
+            errouts = options.errout.split(';')
+
+        for wrkld in workloads:
+            smt_process = LiveProcess()
+            smt_process.executable = wrkld
+            smt_process.cmd = wrkld + " " + options.options
+            if inputs and inputs[smt_idx]:
+                smt_process.input = inputs[smt_idx]
+            if outputs and outputs[smt_idx]:
+                smt_process.output = outputs[smt_idx]
+            if errouts and errouts[smt_idx]:
+                smt_process.errout = errouts[smt_idx]
+            process += [smt_process, ]
+            smt_idx += 1
+
+(CPUClass, test_mem_mode, FutureClass) = Simulation.setCPUClass(options)
+
+CPUClass.clock = '1GHz'
+
+np = options.num_cpus
+
+rubymem = RubyMemory(
+  range = AddrRange("512MB"),
+  clock = "1GHz",
+  num_cpus = np,
+  libruby_file = "src/mem/ruby/amd64-linux/generated/MOESI_CMP_directory/bin/libruby.so",
+  config_file = "ruby.config",
+  stats_file = "m5out/ruby.stats"
+)
+
+if options.ruby_debug == True:
+  rubymem.debug = True
+  rubymem.debug_file = options.ruby_debug_file
+
+system = System(cpu = [CPUClass(cpu_id=i) for i in xrange(np)],
+                physmem = rubymem)
+
+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)
+
+
+    '''process = LiveProcess()
+    process.executable = options.cmd
+    process.cmd = [options.cmd, str(i)]
+    '''
+    system.cpu[i].workload = process
+
+    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
new file mode 100644 (file)
index 0000000..2daf820
--- /dev/null
@@ -0,0 +1,46 @@
+# Copyright (c) 2005-2008 The Regents of The University of Michigan
+# 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: Nathan Binkert
+
+from m5.params import *
+from m5.proxy import *
+
+from PhysicalMemory import PhysicalMemory
+
+class RubyMemory(PhysicalMemory):
+    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)")
+    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("",
+        "path to the Ruby debug output file (stdout if blank)")
+
index 0b0017f81b2b51d237c22e3f03102e227bb23174..87498d21dd982d4aa5979436a49fd1111366c4e9 100644 (file)
@@ -32,8 +32,9 @@ Import('*')
 
 SimObject('Bridge.py')
 SimObject('Bus.py')
-SimObject('PhysicalMemory.py')
 SimObject('MemObject.py')
+SimObject('PhysicalMemory.py')
+SimObject('RubyMemory.py')
 
 Source('bridge.cc')
 Source('bus.cc')
@@ -44,6 +45,7 @@ Source('physical.cc')
 Source('port.cc')
 Source('tport.cc')
 Source('mport.cc')
+Source('rubymem.cc')
 
 if env['FULL_SYSTEM']:
     Source('vport.cc')
index f872e1cd84f7735ae9e07c9df63ea7b95348eb8f..ac261f1107663c5b4fe991de6c51a66c3f9b105d 100644 (file)
@@ -64,8 +64,6 @@ public:
    * @param initializingString  A string (with value pairs) for initialization
    * @param allocate_f        A ptr to the allocate function
    * @param generate_values   A ptr to the generate values function
-   * @param my_get_attr       A ptr to the get attribute function
-   * @param my_set_attr       A ptr to the set attribute function
    */
   initvar_t( const char *name, const char *relativeIncludePath,
              const char *initializingString,
index c527e7d2b5dfd445d07f313b8a7e1792945a309d..38bdbbf9116c9f4fe2976b2a92b61345b50e038e 100644 (file)
@@ -34,6 +34,7 @@
 #include "mem/ruby/common/Consumer.hh"
 #include "mem/ruby/system/NodeID.hh"
 #include "mem/protocol/CacheRequestType.hh"
+#include "mem/packet.hh"
 
 class RubySystem;
 class SubBlock;
@@ -51,27 +52,10 @@ public:
 
   // Public Methods
   virtual void get_network_config() {}
-  virtual void hitCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread) = 0; // Called by sequencer
-  virtual void conflictCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread) { assert(0); } // Called by sequencer
+  virtual void hitCallback(Packet* pkt) = 0;
   virtual integer_t getInstructionCount(int procID) const { return 1; }
   virtual integer_t getCycleCount(int procID) const { return 1; }
-  virtual SimicsHypervisor * getHypervisor() { return NULL; }
-  virtual void notifySendNack( int procID, const Address & addr, uint64 remote_timestamp, const MachineID & remote_id) { assert(0); };   //Called by Sequencer
-  virtual void notifyReceiveNack( int procID, const Address & addr, uint64 remote_timestamp, const MachineID & remote_id) { assert(0); };   //Called by Sequencer
-  virtual void notifyReceiveNackFinal( int procID, const Address & addr) { assert(0); }; // Called by Sequencer
-  virtual void notifyTrapStart( int procID, const Address & handlerPC, int threadID, int smtThread ) { assert(0); } //called by Sequencer
-  virtual void notifyTrapComplete( int procID, const Address & newPC, int smtThread ) {assert(0);  }  // called by Sequencer
-  virtual int getOpalTransactionLevel(int procID, int thread) const {
-    cout << "mem/ruby/common/Driver.hh getOpalTransactionLevel() " << endl;
-   return 0; }  //called by Sequencer
-  virtual void addThreadDependency(int procID, int requestor_thread, int conflict_thread) const { assert(0);}
-  virtual uint64 getOpalTime(int procID) const{ return 0; }  //called by Sequencer
-  virtual uint64 getOpalTimestamp(int procID, int thread) const{
-    cout << "mem/ruby/common/Driver.hh getOpalTimestamp " << endl;
- return 0; } // called by Sequencer
-  virtual int inTransaction(int procID, int thread ) const{
-    cout << "mem/ruby/common/Driver.hh inTransaction " << endl;
-return false; } //called by Sequencer
+
   virtual void printDebug(){}  //called by Sequencer
 
   virtual void printStats(ostream& out) const = 0;
@@ -79,8 +63,6 @@ return false; } //called by Sequencer
 
   virtual void printConfig(ostream& out) const = 0;
 
-  //virtual void abortCallback(NodeID proc){}
-
   virtual integer_t readPhysicalMemory(int procID, physical_address_t address,
                                        int len ){ ASSERT(0); return 0; }
 
index 6e29b1a416ea94d16930c8f779156d63455210b4..bf7fcf397bfb7f1c9934bf269ac68e1f1f334a7a 100644 (file)
@@ -40,6 +40,7 @@
 #include "mem/ruby/eventqueue/RubyEventQueue.hh"
 #include "mem/ruby/system/System.hh"
 #include "mem/ruby/common/Debug.hh"
+#include "mem/ruby/common/Driver.hh"
 #include "mem/ruby/profiler/Profiler.hh"
 #include "mem/ruby/tester/Tester.hh"
 #include "mem/ruby/init.hh"
@@ -65,14 +66,27 @@ static void init_generate_values( void )
 }
 
 //***************************************************************************
+
 void init_variables( void )
 {
-   // allocate the "variable initialization" package
-   ruby_initvar_obj = new initvar_t( "ruby", "../../../ruby/",
-                                     global_default_param,
-                                     &init_simulator,
-                                     &init_generate_values );
+  // allocate the "variable initialization" package
+  ruby_initvar_obj = new initvar_t( "ruby", "../../../ruby/",
+                                    global_default_param,
+                                    &init_simulator,
+                                    &init_generate_values);
+}
+
+
+ /*
+void init_variables(const char* config_str )
+{
+  // allocate the "variable initialization" package
+  ruby_initvar_obj = new initvar_t( "ruby", "../../../ruby/",
+                                    config_str,
+                                    &init_simulator,
+                                    &init_generate_values );
 }
+ */
 
 void init_simulator()
 {
@@ -104,6 +118,36 @@ void init_simulator()
     cout << "Ruby initialization complete" << endl;
 }
 
+void init_simulator(Driver* _driver)
+{
+    // Set things to NULL to make sure we don't de-reference them
+    // without a seg. fault.
+    g_system_ptr = NULL;
+    g_debug_ptr = NULL;
+    g_eventQueue_ptr = NULL;
+
+    cout << "Ruby Timing Mode" << endl;
+
+
+    g_debug_ptr = new Debug( DEBUG_FILTER_STRING,
+                             DEBUG_VERBOSITY_STRING,
+                             DEBUG_START_TIME,
+                             DEBUG_OUTPUT_FILENAME );
+    RubyConfig::init();
+
+    cout << "Creating event queue..." << endl;
+    g_eventQueue_ptr = new RubyEventQueue;
+    cout << "Creating event queue done" << endl;
+
+    cout << "Creating system..." << endl;
+    cout << "  Processors: " << RubyConfig::numberOfProcessors() << endl;
+
+    g_system_ptr = new RubySystem(_driver);
+    cout << "Creating system done" << endl;
+
+    cout << "Ruby initialization complete" << endl;
+}
+
 void destroy_simulator()
 {
     cout << "Deleting system..." << endl;
@@ -122,7 +166,8 @@ void destroy_simulator()
  | M5 in phase 1 integration, and possibly afterwards, too.                |
  +-------------------------------------------------------------------------*/
 
-extern "C"
+//dsm: superfluous
+/*extern "C"
 int OnLoadRuby() {
     init_variables();
     return 0;
@@ -136,9 +181,9 @@ int OnInitRuby() {
 
 extern "C"
 int OnUnloadRuby() {
-    destroy_simulator();
-    return 0;
-}
+  destroy_simulator();
+  return 0;
+}*/
 
 /* I have to put it somewhere for now */
 void tester_main(int argc, char **argv) {
index 8fec5a7c8fc29f08f2f5c42936f436cd2e24fb41..3299f305b999a3c138fba2b3767db2813ad2bfb9 100644 (file)
 #ifndef INIT_H
 #define INIT_H
 
+class Driver;
+
 extern void init_variables();
+//extern void init_variables(const char* config_str);
 extern void init_simulator();
+extern void init_simulator(Driver* _driver);
 extern void destroy_simulator();
 
 #endif //INIT_H
diff --git a/src/mem/ruby/interfaces/mf_api.hh b/src/mem/ruby/interfaces/mf_api.hh
deleted file mode 100644 (file)
index c04a393..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-
-/*
- * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
- * 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.
- */
-
-/*------------------------------------------------------------------------*/
-/* Includes                                                               */
-/*------------------------------------------------------------------------*/
-
-/*------------------------------------------------------------------------*/
-/* Macro declarations                                                     */
-/*------------------------------------------------------------------------*/
-
-#ifndef _MF_MEMORY_API_H_
-#define _MF_MEMORY_API_H_
-
-#ifdef SIMICS30
-#ifndef pa_t
-typedef physical_address_t pa_t;
-typedef physical_address_t la_t;
-#endif
-#endif
-
-/**
- *  Defines types of memory requests
- */
-typedef enum OpalMemop {
-  OPAL_LOAD,
-  OPAL_STORE,
-  OPAL_IFETCH,
-  OPAL_ATOMIC,
-} OpalMemop_t;
-
-/*------------------------------------------------------------------------*/
-/* Class declaration(s)                                                   */
-/*------------------------------------------------------------------------*/
-
-/**
-* structure which provides an interface between ruby and opal.
-*/
-typedef struct mf_opal_api {
-  /**
-   * @name Methods
-   */
-  //@{
-  /**
-   * notify processor model that data from address address is available at proc
-   */
-  void (*hitCallback)( int cpuNumber, pa_t phys_address, OpalMemop_t type, int thread );
-
-  /**
-   * notify opal that ruby is loaded, or removed
-   */
-  void (*notifyCallback)( int status );
-
-  /**
-   * query for the number of instructions executed on a given processor.
-   */
-  integer_t (*getInstructionCount)( int cpuNumber );
-
-  // for printing out debug info on crash
-  void (*printDebug)();
-
-  /** query Opal for the current time */
-  uint64 (*getOpalTime)(int cpuNumber);
-
-  /** For WATTCH power stats */
-  // Called whenever L2 is accessed
-  void (*incrementL2Access)(int cpuNumber);
-  // Called whenever prefetcher is accessed
-  void (*incrementPrefetcherAccess)(int cpuNumber, int num_prefetches, int isinstr);
-
-  /* Called whenever there's an L2 miss */
-  void (*notifyL2Miss)(int cpuNumber, physical_address_t physicalAddr, OpalMemop_t type, int tagexists);
-
-  //@}
-} mf_opal_api_t;
-
-typedef struct mf_ruby_api {
-  /**
-   * @name Methods
-   */
-  //@{
-  /**
-   * Check to see if the system is ready for more requests
-   */
-  int  (*isReady)( int cpuNumber, la_t logicalAddr, pa_t physicalAddr, OpalMemop_t typeOfRequest, int thread );
-
-  /**
-   * Make a 'mandatory' request to the memory hierarchy
-   */
-  void (*makeRequest)( int cpuNumber, la_t logicalAddr, pa_t physicalAddr,
-                       int requestSize, OpalMemop_t typeOfRequest,
-                       la_t virtualPC, int isPriv, int thread);
-
-  /**
-   * Make a prefetch request to the memory hierarchy
-   */
-  void (*makePrefetch)( int cpuNumber, la_t logicalAddr, pa_t physicalAddr,
-                        int requestSize, OpalMemop_t typeOfRequest,
-                        la_t virtualPC, int isPriv, int thread);
-
-  /**
-   * Ask the memory hierarchy for 'stale' data that can be used for speculation
-   * Returns true (1) if the tag matches, false (0) if not.
-   */
-  int (*staleDataRequest)( int cpuNumber, pa_t physicalAddr,
-                           int requestSize, int8 *buffer );
-
-  /**
-   * Advance ruby's cycle time one step
-   */
-  void (*advanceTime)( void );
-
-  /**
-   * Get ruby's cycle time count.
-   */
-  uint64 (*getTime)( void );
-
-  /** prints Ruby's outstanding request table */
-  void (*printProgress)(int cpuNumber);
-
-  /**
-   * notify ruby that opal is loaded, or removed
-   */
-  void (*notifyCallback)( int status );
-
-  // Returns the number of outstanding request
-  int (*getNumberOutstanding)(int cpuNumber);
-
-  // Returns the number of outstanding demand requests
-  int (*getNumberOutstandingDemand)(int cpuNumber );
-
-  // Returns the number of outstanding prefetch request
-  int (*getNumberOutstandingPrefetch)(int cpuNumber );
-
-
-  //@}
-} mf_ruby_api_t;
-
-#endif //_MF_MEMORY_API_H_
index ab1069582cee9c8ad0b49d73bc3bf622839c3f47..31b83690e6ea05c0809773907956d54211e1cb0a 100644 (file)
@@ -37,6 +37,7 @@
 #include "mem/ruby/system/System.hh"
 #include "mem/ruby/slicc_interface/AbstractChip.hh"
 #include "mem/protocol/CacheMsg.hh"
+#include "mem/packet.hh"
 
 TraceRecord::TraceRecord(NodeID id, const Address& data_addr, const Address& pc_addr, CacheRequestType type, Time time)
 {
@@ -78,14 +79,27 @@ void TraceRecord::issueRequest() const
   Sequencer* sequencer_ptr = chip_ptr->getSequencer((m_node_num/RubyConfig::numberofSMTThreads())%RubyConfig::numberOfProcsPerChip());
   assert(sequencer_ptr != NULL);
 
-  CacheMsg request(m_data_address, m_data_address, m_type, m_pc_address, AccessModeType_UserMode, 0, PrefetchBit_Yes, 0, Address(0), 0 /* only 1 SMT thread */);
+  Addr data_addr = m_data_address.getAddress();
+  Addr pc_addr = m_pc_address.getAddress();
+  Request request(0, data_addr, 0, Flags<unsigned int>(Request::PREFETCH), pc_addr, m_node_num, 0);
+  MemCmd::Command command;
+  if (m_type == CacheRequestType_LD || m_type == CacheRequestType_IFETCH)
+    command = MemCmd::ReadReq;
+  else if (m_type == CacheRequestType_ST)
+    command = MemCmd::WriteReq;
+  else if (m_type == CacheRequestType_ATOMIC)
+    command = MemCmd::SwapReq; // TODO -- differentiate between atomic types
+  else
+    assert(false);
+
+  Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID
 
   // Clear out the sequencer
   while (!sequencer_ptr->empty()) {
     g_eventQueue_ptr->triggerEvents(g_eventQueue_ptr->getTime() + 100);
   }
 
-  sequencer_ptr->makeRequest(request);
+  sequencer_ptr->makeRequest(&pkt);
 
   // Clear out the sequencer
   while (!sequencer_ptr->empty()) {
index 4217a86853e1d454070db34d6e14645434eaf7f8..a8306c06f344a5bd9d983be1a84a9e55c6e03f20 100644 (file)
@@ -42,7 +42,9 @@
 #include "mem/ruby/common/Global.hh"
 #include "mem/protocol/AccessPermission.hh"
 #include "mem/ruby/common/Address.hh"
-#include "mem/ruby/recorder/CacheRecorder.hh"
+
+//dsm: PRUNED
+//#include "mem/ruby/recorder/CacheRecorder.hh"
 #include "mem/protocol/CacheRequestType.hh"
 #include "mem/gems_common/Vector.hh"
 #include "mem/ruby/common/DataBlock.hh"
@@ -142,6 +144,8 @@ private:
   int m_cache_num_sets;
   int m_cache_num_set_bits;
   int m_cache_assoc;
+
+  bool is_locked; // for LL/SC
 };
 
 // Output operator declaration
@@ -489,7 +493,10 @@ template<class ENTRY>
 inline
 void CacheMemory<ENTRY>::recordCacheContents(CacheRecorder& tr) const
 {
-  for (int i = 0; i < m_cache_num_sets; i++) {
+//dsm: Uses CacheRecorder, PRUNED
+assert(false);
+
+/*  for (int i = 0; i < m_cache_num_sets; i++) {
     for (int j = 0; j < m_cache_assoc; j++) {
       AccessPermission perm = m_cache[i][j].m_Permission;
       CacheRequestType request_type = CacheRequestType_NULL;
@@ -508,7 +515,7 @@ void CacheMemory<ENTRY>::recordCacheContents(CacheRecorder& tr) const
                      Address(0), request_type, m_replacementPolicy_ptr->getLastAccess(i, j));
       }
     }
-  }
+  }*/
 }
 
 template<class ENTRY>
index fa5b75eb38e2b79c7bc236c9d115a976654fefa4..82eef29017386eb5807da25928b885c060e1afe8 100644 (file)
@@ -46,6 +46,7 @@
 #include "mem/ruby/common/SubBlock.hh"
 #include "mem/protocol/Protocol.hh"
 #include "mem/gems_common/Map.hh"
+#include "mem/packet.hh"
 
 Sequencer::Sequencer(AbstractChip* chip_ptr, int version) {
   m_chip_ptr = chip_ptr;
@@ -58,6 +59,8 @@ Sequencer::Sequencer(AbstractChip* chip_ptr, int version) {
   m_writeRequestTable_ptr = new Map<Address, CacheMsg>*[smt_threads];
   m_readRequestTable_ptr = new Map<Address, CacheMsg>*[smt_threads];
 
+  m_packetTable_ptr = new Map<Address, Packet*>;
+
   for(int p=0; p < smt_threads; ++p){
     m_writeRequestTable_ptr[p] = new Map<Address, CacheMsg>;
     m_readRequestTable_ptr[p] = new Map<Address, CacheMsg>;
@@ -603,7 +606,8 @@ void Sequencer::hitCallback(const CacheMsg& request, DataBlock& data, GenericMac
     (type == CacheRequestType_ATOMIC);
 
   if (TSO && write) {
-    m_chip_ptr->m_L1Cache_storeBuffer_vec[m_version]->callBack(line_address(request.getAddress()), data);
+    m_chip_ptr->m_L1Cache_storeBuffer_vec[m_version]->callBack(line_address(request.getAddress()), data,
+                                                               m_packetTable_ptr->lookup(request.getAddress()));
   } else {
 
     // Copy the correct bytes out of the cache line into the subblock
@@ -616,7 +620,23 @@ void Sequencer::hitCallback(const CacheMsg& request, DataBlock& data, GenericMac
     }
 
     // Call into the Driver and let it read and/or modify the sub-block
-    g_system_ptr->getDriver()->hitCallback(m_chip_ptr->getID()*RubyConfig::numberOfProcsPerChip()+m_version, subblock, type, threadID);
+    Packet* pkt = m_packetTable_ptr->lookup(request.getAddress());
+
+    // update data if this is a store/atomic
+
+    /*
+    if (pkt->req->isCondSwap()) {
+      L1Cache_Entry entry = m_L1Cache_vec[m_version]->lookup(Address(pkt->req->physAddr()));
+      DataBlk datablk = entry->getDataBlk();
+      uint8_t *orig_data = datablk.getArray();
+      if ( datablk.equal(pkt->req->getExtraData()) )
+        datablk->setArray(pkt->getData());
+      pkt->setData(orig_data);
+    }
+    */
+
+    g_system_ptr->getDriver()->hitCallback(pkt);
+    m_packetTable_ptr->remove(request.getAddress());
 
     // If the request was a Store or Atomic, apply the changes in the SubBlock to the DataBlock
     // (This is only triggered for the non-TSO case)
@@ -632,6 +652,7 @@ void Sequencer::printDebug(){
   g_system_ptr->getDriver()->printDebug();
 }
 
+//dsm: breaks build, delayed
 // Returns true if the sequencer already has a load or store outstanding
 bool
 Sequencer::isReady(const Packet* pkt) const
@@ -665,7 +686,7 @@ Sequencer::isReady(const Packet* pkt) const
                    Address(logical_addr),   // Virtual Address
                    thread              // SMT thread
                    );
-  isReady(request);
+  return isReady(request);
 }
 
 bool
@@ -701,26 +722,36 @@ Sequencer::isReady(const CacheMsg& request) const
   return true;
 }
 
-// Called by Driver
+//dsm: breaks build, delayed
+// Called by Driver (Simics or Tester).
 void
-Sequencer::makeRequest(const Packet* pkt, void* data)
+Sequencer::makeRequest(Packet* pkt)
 {
   int cpu_number = pkt->req->contextId();
   la_t logical_addr = pkt->req->getVaddr();
   pa_t physical_addr = pkt->req->getPaddr();
   int request_size = pkt->getSize();
   CacheRequestType type_of_request;
+  PrefetchBit prefetch;
+  bool write = false;
   if ( pkt->req->isInstFetch() ) {
     type_of_request = CacheRequestType_IFETCH;
   } else if ( pkt->req->isLocked() || pkt->req->isSwap() ) {
     type_of_request = CacheRequestType_ATOMIC;
+    write = true;
   } else if ( pkt->isRead() ) {
     type_of_request = CacheRequestType_LD;
   } else if ( pkt->isWrite() ) {
     type_of_request = CacheRequestType_ST;
+    write = true;
   } else {
     assert(false);
   }
+  if (pkt->req->isPrefetch()) {
+    prefetch = PrefetchBit_Yes;
+  } else {
+    prefetch = PrefetchBit_No;
+  }
   la_t virtual_pc = pkt->req->getPC();
   int isPriv = false;  // TODO: get permission data
   int thread = pkt->req->threadId();
@@ -733,28 +764,21 @@ Sequencer::makeRequest(const Packet* pkt, void* data)
                    Address(virtual_pc),
                    access_mode,   // User/supervisor mode
                    request_size,   // Size in bytes of request
-                   PrefetchBit_No, // Not a prefetch
+                   prefetch,
                    0,              // Version number
                    Address(logical_addr),   // Virtual Address
                    thread         // SMT thread
                    );
-  makeRequest(request);
-}
-
-void
-Sequencer::makeRequest(const CacheMsg& request)
-{
-  bool write = (request.getType() == CacheRequestType_ST) ||
-    (request.getType() == CacheRequestType_ATOMIC);
 
-  if (TSO && (request.getPrefetch() == PrefetchBit_No) && write) {
+  if ( TSO && write && !pkt->req->isPrefetch() ) {
     assert(m_chip_ptr->m_L1Cache_storeBuffer_vec[m_version]->isReady());
-    m_chip_ptr->m_L1Cache_storeBuffer_vec[m_version]->insertStore(request);
+    m_chip_ptr->m_L1Cache_storeBuffer_vec[m_version]->insertStore(pkt, request);
     return;
   }
 
-  bool hit = doRequest(request);
+  m_packetTable_ptr->insert(Address( physical_addr ), pkt);
 
+  doRequest(request);
 }
 
 bool Sequencer::doRequest(const CacheMsg& request) {
index f4cc03131cf9f28f59cfc3263453d85db368a802..d34a2fd3e87a0be7744146827d3a4c739d8fa60e 100644 (file)
 #include "mem/protocol/GenericMachineType.hh"
 #include "mem/protocol/PrefetchBit.hh"
 #include "mem/gems_common/Map.hh"
-#include "mem/packet.hh"
 
 class DataBlock;
 class AbstractChip;
 class CacheMsg;
 class Address;
 class MachineID;
+class Packet;
 
 class Sequencer : public Consumer {
 public:
@@ -103,8 +103,7 @@ public:
   void printDebug();
 
   // called by Tester or Simics
-  void makeRequest(const Packet* pkt, void* data);
-  void makeRequest(const CacheMsg& request); // depricate this function
+  void makeRequest(Packet* pkt);
   bool doRequest(const CacheMsg& request);
   void issueRequest(const CacheMsg& request);
   bool isReady(const Packet* pkt) const;
@@ -143,6 +142,9 @@ private:
   // One request table per SMT thread
   Map<Address, CacheMsg>** m_writeRequestTable_ptr;
   Map<Address, CacheMsg>** m_readRequestTable_ptr;
+
+  Map<Address, Packet*>* m_packetTable_ptr;
+
   // Global outstanding request count, across all request tables
   int m_outstanding_count;
   bool m_deadlock_check_scheduled;
index 7f43771f3811770e6f1835993c14149593ecd3c5..280decdd80fe8f933825c831f12eb3aa89057733 100644 (file)
@@ -44,6 +44,7 @@
 #include "mem/ruby/system/Sequencer.hh"
 #include "mem/ruby/common/SubBlock.hh"
 #include "mem/ruby/profiler/Profiler.hh"
+#include "mem/packet.hh"
 
 // *** Begin Helper class ***
 struct StoreBufferEntry {
@@ -150,7 +151,8 @@ void StoreBuffer::printConfig(ostream& out)
 
 // Handle an incoming store request, this method is responsible for
 // calling hitCallback as needed
-void StoreBuffer::insertStore(const CacheMsg& request)
+void
+StoreBuffer::insertStore(Packet* pkt, const CacheMsg& request)
 {
   Address addr = request.getAddress();
   CacheRequestType type = request.getType();
@@ -173,7 +175,7 @@ void StoreBuffer::insertStore(const CacheMsg& request)
   // Perform the hit-callback for the store
   SubBlock subblock(addr, size);
   if(type == CacheRequestType_ST) {
-    g_system_ptr->getDriver()->hitCallback(m_chip_ptr->getID(), subblock, type, threadID);
+    g_system_ptr->getDriver()->hitCallback(pkt);
     assert(subblock.getSize() != 0);
   } else {
     // wait to perform the hitCallback until later for Atomics
@@ -181,9 +183,9 @@ void StoreBuffer::insertStore(const CacheMsg& request)
 
   // Perform possible pre-fetch
   if(!isEmpty()) {
-    CacheMsg new_request = request;
-    new_request.getPrefetch() = PrefetchBit_Yes;
-    m_chip_ptr->getSequencer(m_version)->makeRequest(new_request);
+    Packet new_pkt(pkt);
+    pkt->req->setFlags(Request::PREFETCH);
+    m_chip_ptr->getSequencer(m_version)->makeRequest(&new_pkt);
   }
 
   // Update the StoreCache
@@ -200,7 +202,7 @@ void StoreBuffer::insertStore(const CacheMsg& request)
   processHeadOfQueue();
 }
 
-void StoreBuffer::callBack(const Address& addr, DataBlock& data)
+void StoreBuffer::callBack(const Address& addr, DataBlock& data, Packet* pkt)
 {
   DEBUG_MSG(STOREBUFFER_COMP, MedPrio, "callBack");
   DEBUG_EXPR(STOREBUFFER_COMP, MedPrio, g_eventQueue_ptr->getTime());
@@ -220,7 +222,7 @@ void StoreBuffer::callBack(const Address& addr, DataBlock& data)
   } else {
     // We waited to perform the hitCallback until now for Atomics
     peek().m_subblock.mergeFrom(data);  // copy the correct bytes from DataBlock into the SubBlock for the Load part of the atomic Load/Store
-    g_system_ptr->getDriver()->hitCallback(m_chip_ptr->getID(), peek().m_subblock, type, threadID);
+    g_system_ptr->getDriver()->hitCallback(pkt);
     m_seen_atomic = false;
 
     /// FIXME - record the time spent in the store buffer - split out ST vs ATOMIC
index 2fae5264329b7ca5ff5fff5fcfb1e43a34b89deb..2c9283f4b44719f72dfd212f3789a925b27ff193 100644 (file)
@@ -49,6 +49,7 @@ class DataBlock;
 class SubBlock;
 class StoreBufferEntry;
 class AbstractChip;
+class Packet;
 
 template <class TYPE> class Vector;
 
@@ -62,8 +63,8 @@ public:
 
   // Public Methods
   void wakeup(); // Used only for deadlock detection
-  void callBack(const Address& addr, DataBlock& data);
-  void insertStore(const CacheMsg& request);
+  void callBack(const Address& addr, DataBlock& data, Packet* pkt);
+  void insertStore(Packet* pkt, const CacheMsg& request);
   void updateSubBlock(SubBlock& sub_block) const { m_store_cache.update(sub_block); }
   bool trySubBlock(const SubBlock& sub_block) const { assert(isReady()); return m_store_cache.check(sub_block); }
   void print(ostream& out) const;
index ae77d2a853a3a3306cab969575697e1399c7058a..877a894fc680281bbfce486afc2e681487485b02 100644 (file)
 #include "mem/protocol/Chip.hh"
 //#include "mem/ruby/recorder/Tracer.hh"
 #include "mem/protocol/Protocol.hh"
-//#include "XactIsolationChecker.hh"  // gem5:Arka for decomissioning of log_tm
-//#include "XactCommitArbiter.hh"
-//#include "XactVisualizer.hh"
-#include "mem/ruby/interfaces/M5Driver.hh"
 
 RubySystem::RubySystem()
+{
+  init();
+  m_preinitialized_driver = false;
+  createDriver();
+
+ /*  gem5:Binkert for decomissiong of tracer
+     m_tracer_ptr = new Tracer;
+ */
+
+ /*  gem5:Arka for decomissiong of log_tm
+  if (XACT_MEMORY) {
+    m_xact_isolation_checker = new XactIsolationChecker;
+    m_xact_commit_arbiter    = new XactCommitArbiter;
+    m_xact_visualizer        = new XactVisualizer;
+  }
+*/
+}
+
+RubySystem::RubySystem(Driver* _driver)
+{
+  init();
+  m_preinitialized_driver = true;
+  m_driver_ptr = _driver;
+}
+
+RubySystem::~RubySystem()
+{
+  for (int i = 0; i < m_chip_vector.size(); i++) {
+    delete m_chip_vector[i];
+  }
+  if (!m_preinitialized_driver)
+    delete m_driver_ptr;
+  delete m_network_ptr;
+  delete m_profiler_ptr;
+ /*  gem5:Binkert for decomissiong of tracer
+     delete m_tracer_ptr;
+ */
+}
+
+void RubySystem::init()
 {
   DEBUG_MSG(SYSTEM_COMP, MedPrio,"initializing");
 
@@ -101,44 +137,19 @@ RubySystem::RubySystem()
     }
   }
 #endif
+  DEBUG_MSG(SYSTEM_COMP, MedPrio,"finished initializing");
+  DEBUG_NEWLINE(SYSTEM_COMP, MedPrio);
+}
 
+void RubySystem::createDriver()
+{
     if (g_SYNTHETIC_DRIVER && !g_DETERMINISTIC_DRIVER) {
       cerr << "Creating Synthetic Driver" << endl;
       m_driver_ptr = new SyntheticDriver(this);
     } else if (!g_SYNTHETIC_DRIVER && g_DETERMINISTIC_DRIVER) {
       cerr << "Creating Deterministic Driver" << endl;
       m_driver_ptr = new DeterministicDriver(this);
-    } else {
-      cerr << "Creating M5 Driver" << endl;
-      m_driver_ptr = new M5Driver(this);
     }
- /*  gem5:Binkert for decomissiong of tracer
-     m_tracer_ptr = new Tracer;
- */
-
- /*  gem5:Arka for decomissiong of log_tm
-  if (XACT_MEMORY) {
-    m_xact_isolation_checker = new XactIsolationChecker;
-    m_xact_commit_arbiter    = new XactCommitArbiter;
-    m_xact_visualizer        = new XactVisualizer;
-  }
-*/
-  DEBUG_MSG(SYSTEM_COMP, MedPrio,"finished initializing");
-  DEBUG_NEWLINE(SYSTEM_COMP, MedPrio);
-
-}
-
-RubySystem::~RubySystem()
-{
-  for (int i = 0; i < m_chip_vector.size(); i++) {
-    delete m_chip_vector[i];
-  }
-  delete m_driver_ptr;
-  delete m_network_ptr;
-  delete m_profiler_ptr;
- /*  gem5:Binkert for decomissiong of tracer
-     delete m_tracer_ptr;
- */
 }
 
 void RubySystem::printConfig(ostream& out) const
index 12063eeedbc4ea0d8c1d2c79ee25795636241a8e..8679b55c3c6bd294b3e933b8446438b5803aabbf 100644 (file)
@@ -63,6 +63,7 @@ class RubySystem {
 public:
   // Constructors
   RubySystem();
+  RubySystem(Driver* _driver); // used when driver is already instantiated (e.g. M5's RubyMem)
 
   // Destructor
   ~RubySystem();
@@ -98,6 +99,8 @@ public:
 
 private:
   // Private Methods
+  void init();
+  void createDriver();
 
   // Private copy constructor and assignment operator
   RubySystem(const RubySystem& obj);
@@ -107,6 +110,7 @@ private:
   Network* m_network_ptr;
   Vector<AbstractChip*> m_chip_vector;
   Profiler* m_profiler_ptr;
+  bool m_preinitialized_driver;
   Driver* m_driver_ptr;
   Tracer* m_tracer_ptr;
   XactIsolationChecker *m_xact_isolation_checker;
index ea26489a3cf52af84cc13e73171f37ba25227330..b9e7e3c10d45d75bcd73f7f2d8ce1c47def8711e 100644 (file)
@@ -37,6 +37,7 @@
 #include "mem/ruby/system/System.hh"
 #include "mem/ruby/common/SubBlock.hh"
 #include "mem/protocol/Chip.hh"
+#include "mem/packet.hh"
 
 Check::Check(const Address& address, const Address& pc)
 {
@@ -84,10 +85,29 @@ void Check::initiatePrefetch(Sequencer* targetSequencer_ptr)
   } else {
     type = CacheRequestType_ST;
   }
+
+  Addr data_addr = m_address.getAddress();
+  Addr pc_addr = m_pc.getAddress();
+  Request request(0, data_addr, 0, Flags<unsigned int>(Request::PREFETCH), pc_addr, 0, 0);
+  MemCmd::Command command;
+  if (type == CacheRequestType_IFETCH) {
+    command = MemCmd::ReadReq;
+    request.setFlags(Request::INST_FETCH);
+  } else if (type == CacheRequestType_LD || type == CacheRequestType_IFETCH) {
+    command = MemCmd::ReadReq;
+  } else if (type == CacheRequestType_ST) {
+    command = MemCmd::WriteReq;
+  } else if (type == CacheRequestType_ATOMIC) {
+    command = MemCmd::SwapReq; // TODO -- differentiate between atomic types
+  } else {
+    assert(false);
+  }
+
+  Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID
+
   assert(targetSequencer_ptr != NULL);
-  CacheMsg request(m_address, m_address, type, m_pc, m_access_mode, 0, PrefetchBit_Yes, 0, Address(0), 0 /* only 1 SMT thread */);
-  if (targetSequencer_ptr->isReady(request)) {
-    targetSequencer_ptr->makeRequest(request);
+  if (targetSequencer_ptr->isReady(&pkt)) {
+    targetSequencer_ptr->makeRequest(&pkt);
   }
 }
 
@@ -109,15 +129,34 @@ void Check::initiateAction()
     type = CacheRequestType_ATOMIC;
   }
 
-  CacheMsg request(Address(m_address.getAddress()+m_store_count), Address(m_address.getAddress()+m_store_count), type, m_pc, m_access_mode, 1, PrefetchBit_No, 0, Address(0), 0 /* only 1 SMT thread */);
+  Addr data_addr = m_address.getAddress()+m_store_count;
+  Addr pc_addr = m_pc.getAddress();
+  Request request(0, data_addr, 1, Flags<unsigned int>(), pc_addr, 0, 0);
+  MemCmd::Command command;
+  if (type == CacheRequestType_IFETCH) {
+    command = MemCmd::ReadReq;
+    request.setFlags(Request::INST_FETCH);
+  } else if (type == CacheRequestType_LD || type == CacheRequestType_IFETCH) {
+    command = MemCmd::ReadReq;
+  } else if (type == CacheRequestType_ST) {
+    command = MemCmd::WriteReq;
+  } else if (type == CacheRequestType_ATOMIC) {
+    command = MemCmd::SwapReq; // TODO -- differentiate between atomic types
+  } else {
+    assert(false);
+  }
+
+  Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID
+
   Sequencer* sequencer_ptr = initiatingSequencer();
-  if (sequencer_ptr->isReady(request) == false) {
+  if (sequencer_ptr->isReady(&pkt) == false) {
     DEBUG_MSG(TESTER_COMP, MedPrio, "failed to initiate action - sequencer not ready\n");
   } else {
     DEBUG_MSG(TESTER_COMP, MedPrio, "initiating action - successful\n");
     DEBUG_EXPR(TESTER_COMP, MedPrio, m_status);
     m_status = TesterStatus_Action_Pending;
-    sequencer_ptr->makeRequest(request);
+
+    sequencer_ptr->makeRequest(&pkt);
   }
   DEBUG_EXPR(TESTER_COMP, MedPrio, m_status);
 }
@@ -132,15 +171,35 @@ void Check::initiateCheck()
     type = CacheRequestType_IFETCH;
   }
 
-  CacheMsg request(m_address, m_address, type, m_pc, m_access_mode, CHECK_SIZE, PrefetchBit_No, 0, Address(0), 0 /* only 1 SMT thread */);
+
+  Addr data_addr = m_address.getAddress()+m_store_count;
+  Addr pc_addr = m_pc.getAddress();
+  Request request(0, data_addr, CHECK_SIZE, Flags<unsigned int>(), pc_addr, 0, 0);
+  MemCmd::Command command;
+  if (type == CacheRequestType_IFETCH) {
+    command = MemCmd::ReadReq;
+    request.setFlags(Request::INST_FETCH);
+  } else if (type == CacheRequestType_LD || type == CacheRequestType_IFETCH) {
+    command = MemCmd::ReadReq;
+  } else if (type == CacheRequestType_ST) {
+    command = MemCmd::WriteReq;
+  } else if (type == CacheRequestType_ATOMIC) {
+    command = MemCmd::SwapReq; // TODO -- differentiate between atomic types
+  } else {
+    assert(false);
+  }
+
+  Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID
+
   Sequencer* sequencer_ptr = initiatingSequencer();
-  if (sequencer_ptr->isReady(request) == false) {
+  if (sequencer_ptr->isReady(&pkt) == false) {
     DEBUG_MSG(TESTER_COMP, MedPrio, "failed to initiate check - sequencer not ready\n");
   } else {
     DEBUG_MSG(TESTER_COMP, MedPrio, "initiating check - successful\n");
     DEBUG_MSG(TESTER_COMP, MedPrio, m_status);
     m_status = TesterStatus_Check_Pending;
-    sequencer_ptr->makeRequest(request);
+
+    sequencer_ptr->makeRequest(&pkt);
   }
   DEBUG_MSG(TESTER_COMP, MedPrio, m_status);
 }
index d496cbe3a1381306351d828dd9439c596f3e0776..e4d8addd2f94fac7e0f0f948a84b065f77b86034 100644 (file)
@@ -44,6 +44,7 @@
 #include "mem/ruby/common/SubBlock.hh"
 #include "mem/ruby/tester/DeterministicDriver.hh"
 #include "mem/protocol/Chip.hh"
+#include "mem/packet.hh"
 
 DetermGETXGenerator::DetermGETXGenerator(NodeID node, DeterministicDriver& driver) :
   m_driver(driver)
@@ -137,7 +138,15 @@ void DetermGETXGenerator::pickAddress()
 void DetermGETXGenerator::initiateStore()
 {
   DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Store");
-  sequencer()->makeRequest(CacheMsg(m_address, m_address, CacheRequestType_ST, Address(3), AccessModeType_UserMode, 1, PrefetchBit_No, 0, Address(0), 0 /* only 1 SMT thread */));
+
+  Addr data_addr = m_address.getAddress();
+  Request request(0, data_addr, 1, Flags<unsigned int>(), 3, 0, 0);
+  MemCmd::Command command;
+  command = MemCmd::WriteReq;
+
+  Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID
+
+  sequencer()->makeRequest(&pkt);
 }
 
 Sequencer* DetermGETXGenerator::sequencer() const
index 89d70d91a7a15d2466997e1f3dc17bc406c14c0c..bafaa18ae2f83b0a8c9b6446a0ed7623bab9b0c7 100644 (file)
@@ -179,13 +179,30 @@ void DetermInvGenerator::pickLoadAddress()
 void DetermInvGenerator::initiateLoad()
 {
   DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Load");
-  sequencer()->makeRequest(CacheMsg(m_address, m_address, CacheRequestType_LD, Address(1), AccessModeType_UserMode, 1, PrefetchBit_No, 0, Address(0), 0 /* only 1 SMT thread */));
+
+  Addr data_addr = m_address.getAddress();
+  Request request(0, data_addr, 1, Flags<unsigned int>(), 1, 0, 0);
+  MemCmd::Command command;
+  command = MemCmd::ReadReq;
+
+  Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID
+
+  sequencer()->makeRequest(&pkt);
+
 }
 
 void DetermInvGenerator::initiateStore()
 {
   DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Store");
-  sequencer()->makeRequest(CacheMsg(m_address, m_address, CacheRequestType_ST, Address(3), AccessModeType_UserMode, 1, PrefetchBit_No, 0, Address(0), 0 /* only 1 SMT thread */));
+
+  Addr data_addr = m_address.getAddress();
+  Request request(0, data_addr, 1, Flags<unsigned int>(), 3, 0, 0);
+  MemCmd::Command command;
+  command = MemCmd::WriteReq;
+
+  Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID
+
+  sequencer()->makeRequest(&pkt);
 }
 
 Sequencer* DetermInvGenerator::sequencer() const
index 67fca6fe0c7c593e3817f6aae1fec4744d254d12..5adc7aa5cea0e0f8e0e6bbf75da49aaa4f4548ad 100644 (file)
@@ -135,7 +135,16 @@ void DetermSeriesGETSGenerator::pickAddress()
 void DetermSeriesGETSGenerator::initiateLoad()
 {
   DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Load");
-  sequencer()->makeRequest(CacheMsg(m_address, m_address, CacheRequestType_IFETCH, Address(3), AccessModeType_UserMode, 1, PrefetchBit_No, 0, Address(0), 0 /* only 1 SMT thread */));
+
+  Addr data_addr = m_address.getAddress();
+  Request request(0, data_addr, 1, Flags<unsigned int>(), 3, 0, 0);
+  MemCmd::Command command;
+  command = MemCmd::ReadReq;
+  request.setFlags(Request::INST_FETCH);
+
+  Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID
+
+  sequencer()->makeRequest(&pkt);
 }
 
 Sequencer* DetermSeriesGETSGenerator::sequencer() const
index 7b7d0c9d2d44a613975ebe5974f1ab4a6d107835..76267211882fbf716b82c993f227d33dc69698c7 100644 (file)
@@ -42,6 +42,7 @@
 #include "mem/ruby/tester/DetermSeriesGETSGenerator.hh"
 #include "mem/ruby/common/SubBlock.hh"
 #include "mem/protocol/Chip.hh"
+#include "mem/packet.hh"
 
 DeterministicDriver::DeterministicDriver(RubySystem* sys_ptr)
 {
@@ -99,13 +100,17 @@ DeterministicDriver::~DeterministicDriver()
   }
 }
 
-void DeterministicDriver::hitCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread)
+void
+DeterministicDriver::hitCallback(Packet * pkt)
 {
-  DEBUG_EXPR(TESTER_COMP, MedPrio, data);
-
+  NodeID proc = pkt->req->contextId();
+  SubBlock data(Address(pkt->getAddr()), pkt->req->getSize());
+  if (pkt->hasData()) {
+    for (int i = 0; i < pkt->req->getSize(); i++) {
+      data.setByte(i, *(pkt->getPtr<uint8>()+i));
+    }
+  }
   m_generator_vector[proc]->performCallback(proc, data);
-
-  // Mark that we made progress
   m_last_progress_vector[proc] = g_eventQueue_ptr->getTime();
 }
 
index d253b7e51254744de1c2f8c93c791634af6bd1cb..710da79221f9cc6f968c49c49bc86183e50821aa 100644 (file)
@@ -44,6 +44,7 @@
 
 class RubySystem;
 class SpecifiedGenerator;
+class Packet;
 
 class DeterministicDriver : public Driver, public Consumer {
 public:
@@ -69,7 +70,7 @@ public:
   void recordLoadLatency(Time time);
   void recordStoreLatency(Time time);
 
-  void hitCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread);
+  void hitCallback(Packet* pkt);
   void wakeup();
   void printStats(ostream& out) const;
   void clearStats() {}
index c1772f90505f856535bc46220bf50932549a2ba0..4ee24544f41d08df9ce3c72ecb8948575eadd7e9 100644 (file)
@@ -169,19 +169,43 @@ void RequestGenerator::pickAddress()
 void RequestGenerator::initiateTest()
 {
   DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Test");
-  sequencer()->makeRequest(CacheMsg(m_address, m_address, CacheRequestType_LD, Address(1), AccessModeType_UserMode, 1, PrefetchBit_No, 0, Address(0), 0 /* only 1 SMT thread */));
+
+  Addr data_addr = m_address.getAddress();
+  Request request(0, data_addr, 1, Flags<unsigned int>(), 1, 0, 0);
+  MemCmd::Command command;
+  command = MemCmd::ReadReq;
+
+  Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID
+
+  sequencer()->makeRequest(&pkt);
 }
 
 void RequestGenerator::initiateSwap()
 {
   DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Swap");
-  sequencer()->makeRequest(CacheMsg(m_address, m_address, CacheRequestType_ATOMIC, Address(2), AccessModeType_UserMode, 1, PrefetchBit_No, 0, Address(0), 0 /* only 1 SMT thread */));
+
+  Addr data_addr = m_address.getAddress();
+  Request request(0, data_addr, 1, Flags<unsigned int>(), 2, 0, 0);
+  MemCmd::Command command;
+  command = MemCmd::SwapReq;
+
+  Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID
+
+  sequencer()->makeRequest(&pkt);
 }
 
 void RequestGenerator::initiateRelease()
 {
   DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Release");
-  sequencer()->makeRequest(CacheMsg(m_address, m_address, CacheRequestType_ST, Address(3), AccessModeType_UserMode, 1, PrefetchBit_No, 0, Address(0), 0 /* only 1 SMT thread */));
+
+  Addr data_addr = m_address.getAddress();
+  Request request(0, data_addr, 1, Flags<unsigned int>(), 3, 0, 0);
+  MemCmd::Command command;
+  command = MemCmd::WriteReq;
+
+  Packet pkt(&request, command, 0); // TODO -- make dest a real NodeID
+
+  sequencer()->makeRequest(&pkt);
 }
 
 Sequencer* RequestGenerator::sequencer() const
index 081fc9d5e3a98af9c5be2c23748af5ddc352d5e0..f19baa202e4327d81d63ca7dc48359ec90853a51 100644 (file)
@@ -75,18 +75,17 @@ SyntheticDriver::~SyntheticDriver()
   }
 }
 
-void SyntheticDriver::hitCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread)
+void
+SyntheticDriver::hitCallback(Packet * pkt)
 {
-  DEBUG_EXPR(TESTER_COMP, MedPrio, data);
-  //cout << "  " << proc << " in S.D. hitCallback" << endl;
-  if(XACT_MEMORY){
-    //XactRequestGenerator* reqGen = static_cast<XactRequestGenerator*>(m_request_generator_vector[proc]);
-    //reqGen->performCallback(proc, data);
-  } else {
-    m_request_generator_vector[proc]->performCallback(proc, data);
+  NodeID proc = pkt->req->contextId();
+  SubBlock data(Address(pkt->getAddr()), pkt->req->getSize());
+  if (pkt->hasData()) {
+    for (int i = 0; i < pkt->req->getSize(); i++) {
+      data.setByte(i, *(pkt->getPtr<uint8>()+i));
+    }
   }
-
-  // Mark that we made progress
+  m_request_generator_vector[proc]->performCallback(proc, data);
   m_last_progress_vector[proc] = g_eventQueue_ptr->getTime();
 }
 
index dc0f1be1d8acd1f6e1ed3e86a885b7a19d3b6b5e..18c463e884eb5f318ff5e353ab64cc064f63de8d 100644 (file)
@@ -60,7 +60,7 @@ public:
   void recordSwapLatency(Time time);
   void recordReleaseLatency(Time time);
 
-  void hitCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread);
+  void hitCallback(Packet* pkt);
   void conflictCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread) {assert(0);}
   void abortCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread);
   void wakeup();
index 5e77488e917f6ed8f7361b6479f2b0034b6873d6..ba835b488fa5bb9e979741927e8b5e3c1456afff 100644 (file)
@@ -35,7 +35,7 @@
 #include "mem/ruby/tester/main.hh"
 #include "mem/ruby/eventqueue/RubyEventQueue.hh"
 #include "mem/ruby/config/RubyConfig.hh"
-#include "mem/ruby/tester/test_framework.hh"
+//#include "mem/ruby/tester/test_framework.hh"
 
 // *******************
 // *** tester main ***
@@ -43,5 +43,6 @@
 
 int main(int argc, char *argv[])
 {
-  tester_main(argc, argv);
+    //dsm: PRUNED
+    //tester_main(argc, argv);
 }
diff --git a/src/mem/rubymem.cc b/src/mem/rubymem.cc
new file mode 100644 (file)
index 0000000..6a22830
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * 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: Daniel Sanchez
+ */
+
+
+#include "arch/isa_traits.hh"
+#include "mem/rubymem.hh"
+#include "sim/eventq.hh"
+#include "sim/host.hh"
+#include "base/output.hh"
+
+// Ruby includes
+#include "mem/ruby/system/System.hh"
+#include "mem/ruby/system/Sequencer.hh"
+#include "mem/ruby/init.hh"
+#include "mem/ruby/common/Debug.hh"
+
+#include "sim/sim_exit.hh"
+
+#include <iostream>
+#include <fstream>
+
+using namespace std;
+using namespace TheISA;
+
+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;
+}
+
+void
+RubyMemory::init()
+{
+    init_variables();
+    g_NUM_PROCESSORS = num_cpus;
+
+    init_simulator(this);
+
+    if (debug) {
+        g_debug_ptr->setVerbosityString("high");
+        g_debug_ptr->setDebugTime(1);
+        if (debug_file != "") {
+             g_debug_ptr->setDebugOutputFile("ruby.debug");
+        }
+    }
+
+    //You may want to set some other options...
+    //g_debug_ptr->setVerbosityString("med");
+    //g_debug_ptr->setFilterString("lsNqST");
+    //g_debug_ptr->setFilterString("lsNST");
+    //g_debug_ptr->setDebugTime(1);
+    //g_debug_ptr->setDebugOutputFile("ruby.debug");
+
+
+    g_system_ptr->clearStats();
+
+    if (ports.size() == 0) {
+        fatal("RubyMemory object %s is unconnected!", name());
+    }
+
+    for (PortIterator pi = ports.begin(); pi != ports.end(); ++pi) {
+        if (*pi)
+            (*pi)->sendStatusChange(Port::RangeChange);
+    }
+
+    //Print stats at exit
+    RubyExitCallback* rc = new RubyExitCallback(this);
+    registerExitCallback(rc);
+
+    //Sched RubyEvent, automatically reschedules to advance ruby cycles
+    rubyTickEvent = new RubyEvent(this);
+    schedule(rubyTickEvent, curTick + ruby_clock + ruby_phase);
+}
+
+//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
+}
+
+
+RubyMemory::~RubyMemory() {
+    delete g_system_ptr;
+}
+
+void
+RubyMemory::hitCallback(Packet* pkt)
+{
+    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();
+    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)
+{
+    // 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 RubyMemoryPort(csprintf("%s-functional", name()), this);
+    }
+
+    if (if_name != "port") {
+        panic("RubyMemory::getPort: unknown port %s requested", if_name);
+    }
+
+    if (idx >= ports.size()) {
+        ports.resize(idx+1);
+    }
+
+    if (ports[idx] != NULL) {
+        panic("RubyMemory::getPort: port %d already assigned", idx);
+    }
+
+    RubyMemoryPort *port =
+        new RubyMemoryPort(csprintf("%s-port%d", name(), idx), this);
+
+    ports[idx] = port;
+    return port;
+}
+
+RubyMemory::RubyMemoryPort::RubyMemoryPort(const std::string &_name,
+                                       RubyMemory *_memory)
+    : PhysicalMemory::MemoryPort::MemoryPort(_name, _memory)
+{
+    ruby_mem = _memory;
+}
+
+bool
+RubyMemory::RubyMemoryPort::recvTiming(PacketPtr pkt)
+{
+    DPRINTF(MemoryAccess, "Timing access caught\n");
+
+    //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.
+    assert(pkt->isRequest());
+
+    if (pkt->memInhibitAsserted()) {
+        warn("memInhibitAsserted???");
+        // snooper will supply based on copy of packet
+        // still target's responsibility to delete packet
+        delete pkt;
+        return true;
+    }
+
+    ruby_mem->m_packet_to_port_map[pkt] = this;
+
+    Sequencer* sequencer = g_system_ptr->getSequencer(pkt->req->contextId());
+
+    if ( ! sequencer->isReady(pkt) ) {
+      DPRINTF(MemoryAccess, "Sequencer isn't ready yet!!\n");
+      return false;
+    }
+
+    DPRINTF(MemoryAccess, "Issuing makeRequest\n");
+
+    sequencer->makeRequest(pkt);
+    return true;
+}
+
+void
+RubyMemory::RubyMemoryPort::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);
+    *os << endl;
+    g_system_ptr->printStats(*os);
+}
+
+
+//Right now these functions seem to be called by RubySystem. If they do calls
+// to RubySystem perform it intended actions, you'll get into an inf loop
+//FIXME what's the purpose of these here?
+void RubyMemory::printStats(std::ostream & out) const {
+    //g_system_ptr->printConfig(out);
+}
+
+void RubyMemory::clearStats() {
+    //g_system_ptr->clearStats();
+}
+
+void RubyMemory::printConfig(std::ostream & out) const {
+    //g_system_ptr->printConfig(out);
+}
+
+
+//Python-interface code
+RubyMemory *
+RubyMemoryParams::create()
+{
+    return new RubyMemory(this);
+}
+
diff --git a/src/mem/rubymem.hh b/src/mem/rubymem.hh
new file mode 100644 (file)
index 0000000..feb87ca
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * 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: Daniel Sanchez
+ */
+
+#ifndef __RUBY_MEMORY_HH__
+#define __RUBY_MEMORY_HH__
+
+#include <map>
+
+#include "mem/physical.hh"
+#include "params/RubyMemory.hh"
+#include "base/callback.hh"
+#include "mem/ruby/common/Driver.hh"
+
+class RubyMemory : public PhysicalMemory, public Driver
+{
+    class RubyMemoryPort : public MemoryPort
+    {
+        RubyMemory* ruby_mem;
+
+      public:
+        RubyMemoryPort(const std::string &_name, RubyMemory *_memory);
+        void sendTiming(PacketPtr pkt);
+
+      protected:
+        virtual bool recvTiming(PacketPtr pkt);
+    };
+
+    class RubyEvent : public Event
+    {
+        RubyMemory *ruby_ptr;
+      public:
+        RubyEvent(RubyMemory *p)
+            : Event(), ruby_ptr(p) {}
+
+        virtual void process() { ruby_ptr->tick(); }
+
+        virtual const char *description() const { return "ruby tick"; }
+    };
+
+
+  private:
+    // prevent copying of a RubyMemory object
+    RubyMemory(const RubyMemory &specmem);
+    const RubyMemory &operator=(const RubyMemory &specmem);
+
+    RubyEvent* rubyTickEvent;
+
+  public:
+    typedef RubyMemoryParams Params;
+    RubyMemory(const Params *p);
+    virtual ~RubyMemory();
+
+  public:
+    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 hitCallback(Packet* pkt);  // called by the Ruby sequencer
+
+    void printStats(std::ostream & out) const;
+    void clearStats();
+    void printConfig(std::ostream & out) const;
+
+    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;
+
+    std::map<Packet*, RubyMemoryPort*> m_packet_to_port_map;
+};
+
+class RubyExitCallback : public Callback
+{
+  private:
+   RubyMemory* ruby;
+
+  public:
+    /**
+     * virtualize the destructor to make sure that the correct one
+     * gets called.
+     */
+
+    virtual ~RubyExitCallback() {};
+
+    RubyExitCallback(RubyMemory* rm) {ruby=rm;};
+
+    /**
+     * virtual process function that is invoked when the callback
+     * queue is executed.
+     */
+    virtual void process() {ruby->printConfigStats();  /*delete ruby; was doing double delete...*/};
+};
+
+
+#endif //__RUBY_MEMORY_HH__
+