ruby: Working M5 interface and updated Ruby interface.
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
This commit is contained in:
parent
ebf2f5aadd
commit
93f2f69657
29 changed files with 1149 additions and 301 deletions
190
configs/example/ruby.config
Normal file
190
configs/example/ruby.config
Normal file
|
@ -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
|
172
configs/example/ruby_se.py
Normal file
172
configs/example/ruby_se.py
Normal file
|
@ -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)
|
46
src/mem/RubyMemory.py
Normal file
46
src/mem/RubyMemory.py
Normal file
|
@ -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)")
|
||||||
|
|
|
@ -32,8 +32,9 @@ Import('*')
|
||||||
|
|
||||||
SimObject('Bridge.py')
|
SimObject('Bridge.py')
|
||||||
SimObject('Bus.py')
|
SimObject('Bus.py')
|
||||||
SimObject('PhysicalMemory.py')
|
|
||||||
SimObject('MemObject.py')
|
SimObject('MemObject.py')
|
||||||
|
SimObject('PhysicalMemory.py')
|
||||||
|
SimObject('RubyMemory.py')
|
||||||
|
|
||||||
Source('bridge.cc')
|
Source('bridge.cc')
|
||||||
Source('bus.cc')
|
Source('bus.cc')
|
||||||
|
@ -44,6 +45,7 @@ Source('physical.cc')
|
||||||
Source('port.cc')
|
Source('port.cc')
|
||||||
Source('tport.cc')
|
Source('tport.cc')
|
||||||
Source('mport.cc')
|
Source('mport.cc')
|
||||||
|
Source('rubymem.cc')
|
||||||
|
|
||||||
if env['FULL_SYSTEM']:
|
if env['FULL_SYSTEM']:
|
||||||
Source('vport.cc')
|
Source('vport.cc')
|
||||||
|
|
|
@ -64,8 +64,6 @@ public:
|
||||||
* @param initializingString A string (with value pairs) for initialization
|
* @param initializingString A string (with value pairs) for initialization
|
||||||
* @param allocate_f A ptr to the allocate function
|
* @param allocate_f A ptr to the allocate function
|
||||||
* @param generate_values A ptr to the generate values 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,
|
initvar_t( const char *name, const char *relativeIncludePath,
|
||||||
const char *initializingString,
|
const char *initializingString,
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "mem/ruby/common/Consumer.hh"
|
#include "mem/ruby/common/Consumer.hh"
|
||||||
#include "mem/ruby/system/NodeID.hh"
|
#include "mem/ruby/system/NodeID.hh"
|
||||||
#include "mem/protocol/CacheRequestType.hh"
|
#include "mem/protocol/CacheRequestType.hh"
|
||||||
|
#include "mem/packet.hh"
|
||||||
|
|
||||||
class RubySystem;
|
class RubySystem;
|
||||||
class SubBlock;
|
class SubBlock;
|
||||||
|
@ -51,27 +52,10 @@ public:
|
||||||
|
|
||||||
// Public Methods
|
// Public Methods
|
||||||
virtual void get_network_config() {}
|
virtual void get_network_config() {}
|
||||||
virtual void hitCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread) = 0; // Called by sequencer
|
virtual void hitCallback(Packet* pkt) = 0;
|
||||||
virtual void conflictCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread) { assert(0); } // Called by sequencer
|
|
||||||
virtual integer_t getInstructionCount(int procID) const { return 1; }
|
virtual integer_t getInstructionCount(int procID) const { return 1; }
|
||||||
virtual integer_t getCycleCount(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 printDebug(){} //called by Sequencer
|
||||||
|
|
||||||
virtual void printStats(ostream& out) const = 0;
|
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 printConfig(ostream& out) const = 0;
|
||||||
|
|
||||||
//virtual void abortCallback(NodeID proc){}
|
|
||||||
|
|
||||||
virtual integer_t readPhysicalMemory(int procID, physical_address_t address,
|
virtual integer_t readPhysicalMemory(int procID, physical_address_t address,
|
||||||
int len ){ ASSERT(0); return 0; }
|
int len ){ ASSERT(0); return 0; }
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include "mem/ruby/eventqueue/RubyEventQueue.hh"
|
#include "mem/ruby/eventqueue/RubyEventQueue.hh"
|
||||||
#include "mem/ruby/system/System.hh"
|
#include "mem/ruby/system/System.hh"
|
||||||
#include "mem/ruby/common/Debug.hh"
|
#include "mem/ruby/common/Debug.hh"
|
||||||
|
#include "mem/ruby/common/Driver.hh"
|
||||||
#include "mem/ruby/profiler/Profiler.hh"
|
#include "mem/ruby/profiler/Profiler.hh"
|
||||||
#include "mem/ruby/tester/Tester.hh"
|
#include "mem/ruby/tester/Tester.hh"
|
||||||
#include "mem/ruby/init.hh"
|
#include "mem/ruby/init.hh"
|
||||||
|
@ -65,14 +66,27 @@ static void init_generate_values( void )
|
||||||
}
|
}
|
||||||
|
|
||||||
//***************************************************************************
|
//***************************************************************************
|
||||||
|
|
||||||
void init_variables( void )
|
void init_variables( void )
|
||||||
{
|
{
|
||||||
// allocate the "variable initialization" package
|
// allocate the "variable initialization" package
|
||||||
ruby_initvar_obj = new initvar_t( "ruby", "../../../ruby/",
|
ruby_initvar_obj = new initvar_t( "ruby", "../../../ruby/",
|
||||||
global_default_param,
|
global_default_param,
|
||||||
&init_simulator,
|
&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 );
|
&init_generate_values );
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
void init_simulator()
|
void init_simulator()
|
||||||
{
|
{
|
||||||
|
@ -104,6 +118,36 @@ void init_simulator()
|
||||||
cout << "Ruby initialization complete" << endl;
|
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()
|
void destroy_simulator()
|
||||||
{
|
{
|
||||||
cout << "Deleting system..." << endl;
|
cout << "Deleting system..." << endl;
|
||||||
|
@ -122,7 +166,8 @@ void destroy_simulator()
|
||||||
| M5 in phase 1 integration, and possibly afterwards, too. |
|
| M5 in phase 1 integration, and possibly afterwards, too. |
|
||||||
+-------------------------------------------------------------------------*/
|
+-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
extern "C"
|
//dsm: superfluous
|
||||||
|
/*extern "C"
|
||||||
int OnLoadRuby() {
|
int OnLoadRuby() {
|
||||||
init_variables();
|
init_variables();
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -138,7 +183,7 @@ extern "C"
|
||||||
int OnUnloadRuby() {
|
int OnUnloadRuby() {
|
||||||
destroy_simulator();
|
destroy_simulator();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
/* I have to put it somewhere for now */
|
/* I have to put it somewhere for now */
|
||||||
void tester_main(int argc, char **argv) {
|
void tester_main(int argc, char **argv) {
|
||||||
|
|
|
@ -39,8 +39,12 @@
|
||||||
#ifndef INIT_H
|
#ifndef INIT_H
|
||||||
#define INIT_H
|
#define INIT_H
|
||||||
|
|
||||||
|
class Driver;
|
||||||
|
|
||||||
extern void init_variables();
|
extern void init_variables();
|
||||||
|
//extern void init_variables(const char* config_str);
|
||||||
extern void init_simulator();
|
extern void init_simulator();
|
||||||
|
extern void init_simulator(Driver* _driver);
|
||||||
extern void destroy_simulator();
|
extern void destroy_simulator();
|
||||||
|
|
||||||
#endif //INIT_H
|
#endif //INIT_H
|
||||||
|
|
|
@ -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_
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include "mem/ruby/system/System.hh"
|
#include "mem/ruby/system/System.hh"
|
||||||
#include "mem/ruby/slicc_interface/AbstractChip.hh"
|
#include "mem/ruby/slicc_interface/AbstractChip.hh"
|
||||||
#include "mem/protocol/CacheMsg.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)
|
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());
|
Sequencer* sequencer_ptr = chip_ptr->getSequencer((m_node_num/RubyConfig::numberofSMTThreads())%RubyConfig::numberOfProcsPerChip());
|
||||||
assert(sequencer_ptr != NULL);
|
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
|
// Clear out the sequencer
|
||||||
while (!sequencer_ptr->empty()) {
|
while (!sequencer_ptr->empty()) {
|
||||||
g_eventQueue_ptr->triggerEvents(g_eventQueue_ptr->getTime() + 100);
|
g_eventQueue_ptr->triggerEvents(g_eventQueue_ptr->getTime() + 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
sequencer_ptr->makeRequest(request);
|
sequencer_ptr->makeRequest(&pkt);
|
||||||
|
|
||||||
// Clear out the sequencer
|
// Clear out the sequencer
|
||||||
while (!sequencer_ptr->empty()) {
|
while (!sequencer_ptr->empty()) {
|
||||||
|
|
|
@ -42,7 +42,9 @@
|
||||||
#include "mem/ruby/common/Global.hh"
|
#include "mem/ruby/common/Global.hh"
|
||||||
#include "mem/protocol/AccessPermission.hh"
|
#include "mem/protocol/AccessPermission.hh"
|
||||||
#include "mem/ruby/common/Address.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/protocol/CacheRequestType.hh"
|
||||||
#include "mem/gems_common/Vector.hh"
|
#include "mem/gems_common/Vector.hh"
|
||||||
#include "mem/ruby/common/DataBlock.hh"
|
#include "mem/ruby/common/DataBlock.hh"
|
||||||
|
@ -142,6 +144,8 @@ private:
|
||||||
int m_cache_num_sets;
|
int m_cache_num_sets;
|
||||||
int m_cache_num_set_bits;
|
int m_cache_num_set_bits;
|
||||||
int m_cache_assoc;
|
int m_cache_assoc;
|
||||||
|
|
||||||
|
bool is_locked; // for LL/SC
|
||||||
};
|
};
|
||||||
|
|
||||||
// Output operator declaration
|
// Output operator declaration
|
||||||
|
@ -489,7 +493,10 @@ template<class ENTRY>
|
||||||
inline
|
inline
|
||||||
void CacheMemory<ENTRY>::recordCacheContents(CacheRecorder& tr) const
|
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++) {
|
for (int j = 0; j < m_cache_assoc; j++) {
|
||||||
AccessPermission perm = m_cache[i][j].m_Permission;
|
AccessPermission perm = m_cache[i][j].m_Permission;
|
||||||
CacheRequestType request_type = CacheRequestType_NULL;
|
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));
|
Address(0), request_type, m_replacementPolicy_ptr->getLastAccess(i, j));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class ENTRY>
|
template<class ENTRY>
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
#include "mem/ruby/common/SubBlock.hh"
|
#include "mem/ruby/common/SubBlock.hh"
|
||||||
#include "mem/protocol/Protocol.hh"
|
#include "mem/protocol/Protocol.hh"
|
||||||
#include "mem/gems_common/Map.hh"
|
#include "mem/gems_common/Map.hh"
|
||||||
|
#include "mem/packet.hh"
|
||||||
|
|
||||||
Sequencer::Sequencer(AbstractChip* chip_ptr, int version) {
|
Sequencer::Sequencer(AbstractChip* chip_ptr, int version) {
|
||||||
m_chip_ptr = chip_ptr;
|
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_writeRequestTable_ptr = new Map<Address, CacheMsg>*[smt_threads];
|
||||||
m_readRequestTable_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){
|
for(int p=0; p < smt_threads; ++p){
|
||||||
m_writeRequestTable_ptr[p] = new Map<Address, CacheMsg>;
|
m_writeRequestTable_ptr[p] = new Map<Address, CacheMsg>;
|
||||||
m_readRequestTable_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);
|
(type == CacheRequestType_ATOMIC);
|
||||||
|
|
||||||
if (TSO && write) {
|
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 {
|
} else {
|
||||||
|
|
||||||
// Copy the correct bytes out of the cache line into the subblock
|
// 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
|
// 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
|
// 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)
|
// (This is only triggered for the non-TSO case)
|
||||||
|
@ -632,6 +652,7 @@ void Sequencer::printDebug(){
|
||||||
g_system_ptr->getDriver()->printDebug();
|
g_system_ptr->getDriver()->printDebug();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//dsm: breaks build, delayed
|
||||||
// Returns true if the sequencer already has a load or store outstanding
|
// Returns true if the sequencer already has a load or store outstanding
|
||||||
bool
|
bool
|
||||||
Sequencer::isReady(const Packet* pkt) const
|
Sequencer::isReady(const Packet* pkt) const
|
||||||
|
@ -665,7 +686,7 @@ Sequencer::isReady(const Packet* pkt) const
|
||||||
Address(logical_addr), // Virtual Address
|
Address(logical_addr), // Virtual Address
|
||||||
thread // SMT thread
|
thread // SMT thread
|
||||||
);
|
);
|
||||||
isReady(request);
|
return isReady(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -701,26 +722,36 @@ Sequencer::isReady(const CacheMsg& request) const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called by Driver
|
//dsm: breaks build, delayed
|
||||||
|
// Called by Driver (Simics or Tester).
|
||||||
void
|
void
|
||||||
Sequencer::makeRequest(const Packet* pkt, void* data)
|
Sequencer::makeRequest(Packet* pkt)
|
||||||
{
|
{
|
||||||
int cpu_number = pkt->req->contextId();
|
int cpu_number = pkt->req->contextId();
|
||||||
la_t logical_addr = pkt->req->getVaddr();
|
la_t logical_addr = pkt->req->getVaddr();
|
||||||
pa_t physical_addr = pkt->req->getPaddr();
|
pa_t physical_addr = pkt->req->getPaddr();
|
||||||
int request_size = pkt->getSize();
|
int request_size = pkt->getSize();
|
||||||
CacheRequestType type_of_request;
|
CacheRequestType type_of_request;
|
||||||
|
PrefetchBit prefetch;
|
||||||
|
bool write = false;
|
||||||
if ( pkt->req->isInstFetch() ) {
|
if ( pkt->req->isInstFetch() ) {
|
||||||
type_of_request = CacheRequestType_IFETCH;
|
type_of_request = CacheRequestType_IFETCH;
|
||||||
} else if ( pkt->req->isLocked() || pkt->req->isSwap() ) {
|
} else if ( pkt->req->isLocked() || pkt->req->isSwap() ) {
|
||||||
type_of_request = CacheRequestType_ATOMIC;
|
type_of_request = CacheRequestType_ATOMIC;
|
||||||
|
write = true;
|
||||||
} else if ( pkt->isRead() ) {
|
} else if ( pkt->isRead() ) {
|
||||||
type_of_request = CacheRequestType_LD;
|
type_of_request = CacheRequestType_LD;
|
||||||
} else if ( pkt->isWrite() ) {
|
} else if ( pkt->isWrite() ) {
|
||||||
type_of_request = CacheRequestType_ST;
|
type_of_request = CacheRequestType_ST;
|
||||||
|
write = true;
|
||||||
} else {
|
} else {
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
if (pkt->req->isPrefetch()) {
|
||||||
|
prefetch = PrefetchBit_Yes;
|
||||||
|
} else {
|
||||||
|
prefetch = PrefetchBit_No;
|
||||||
|
}
|
||||||
la_t virtual_pc = pkt->req->getPC();
|
la_t virtual_pc = pkt->req->getPC();
|
||||||
int isPriv = false; // TODO: get permission data
|
int isPriv = false; // TODO: get permission data
|
||||||
int thread = pkt->req->threadId();
|
int thread = pkt->req->threadId();
|
||||||
|
@ -733,28 +764,21 @@ Sequencer::makeRequest(const Packet* pkt, void* data)
|
||||||
Address(virtual_pc),
|
Address(virtual_pc),
|
||||||
access_mode, // User/supervisor mode
|
access_mode, // User/supervisor mode
|
||||||
request_size, // Size in bytes of request
|
request_size, // Size in bytes of request
|
||||||
PrefetchBit_No, // Not a prefetch
|
prefetch,
|
||||||
0, // Version number
|
0, // Version number
|
||||||
Address(logical_addr), // Virtual Address
|
Address(logical_addr), // Virtual Address
|
||||||
thread // SMT thread
|
thread // SMT thread
|
||||||
);
|
);
|
||||||
makeRequest(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
if ( TSO && write && !pkt->req->isPrefetch() ) {
|
||||||
Sequencer::makeRequest(const CacheMsg& request)
|
|
||||||
{
|
|
||||||
bool write = (request.getType() == CacheRequestType_ST) ||
|
|
||||||
(request.getType() == CacheRequestType_ATOMIC);
|
|
||||||
|
|
||||||
if (TSO && (request.getPrefetch() == PrefetchBit_No) && write) {
|
|
||||||
assert(m_chip_ptr->m_L1Cache_storeBuffer_vec[m_version]->isReady());
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hit = doRequest(request);
|
m_packetTable_ptr->insert(Address( physical_addr ), pkt);
|
||||||
|
|
||||||
|
doRequest(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Sequencer::doRequest(const CacheMsg& request) {
|
bool Sequencer::doRequest(const CacheMsg& request) {
|
||||||
|
|
|
@ -45,13 +45,13 @@
|
||||||
#include "mem/protocol/GenericMachineType.hh"
|
#include "mem/protocol/GenericMachineType.hh"
|
||||||
#include "mem/protocol/PrefetchBit.hh"
|
#include "mem/protocol/PrefetchBit.hh"
|
||||||
#include "mem/gems_common/Map.hh"
|
#include "mem/gems_common/Map.hh"
|
||||||
#include "mem/packet.hh"
|
|
||||||
|
|
||||||
class DataBlock;
|
class DataBlock;
|
||||||
class AbstractChip;
|
class AbstractChip;
|
||||||
class CacheMsg;
|
class CacheMsg;
|
||||||
class Address;
|
class Address;
|
||||||
class MachineID;
|
class MachineID;
|
||||||
|
class Packet;
|
||||||
|
|
||||||
class Sequencer : public Consumer {
|
class Sequencer : public Consumer {
|
||||||
public:
|
public:
|
||||||
|
@ -103,8 +103,7 @@ public:
|
||||||
void printDebug();
|
void printDebug();
|
||||||
|
|
||||||
// called by Tester or Simics
|
// called by Tester or Simics
|
||||||
void makeRequest(const Packet* pkt, void* data);
|
void makeRequest(Packet* pkt);
|
||||||
void makeRequest(const CacheMsg& request); // depricate this function
|
|
||||||
bool doRequest(const CacheMsg& request);
|
bool doRequest(const CacheMsg& request);
|
||||||
void issueRequest(const CacheMsg& request);
|
void issueRequest(const CacheMsg& request);
|
||||||
bool isReady(const Packet* pkt) const;
|
bool isReady(const Packet* pkt) const;
|
||||||
|
@ -143,6 +142,9 @@ private:
|
||||||
// One request table per SMT thread
|
// One request table per SMT thread
|
||||||
Map<Address, CacheMsg>** m_writeRequestTable_ptr;
|
Map<Address, CacheMsg>** m_writeRequestTable_ptr;
|
||||||
Map<Address, CacheMsg>** m_readRequestTable_ptr;
|
Map<Address, CacheMsg>** m_readRequestTable_ptr;
|
||||||
|
|
||||||
|
Map<Address, Packet*>* m_packetTable_ptr;
|
||||||
|
|
||||||
// Global outstanding request count, across all request tables
|
// Global outstanding request count, across all request tables
|
||||||
int m_outstanding_count;
|
int m_outstanding_count;
|
||||||
bool m_deadlock_check_scheduled;
|
bool m_deadlock_check_scheduled;
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include "mem/ruby/system/Sequencer.hh"
|
#include "mem/ruby/system/Sequencer.hh"
|
||||||
#include "mem/ruby/common/SubBlock.hh"
|
#include "mem/ruby/common/SubBlock.hh"
|
||||||
#include "mem/ruby/profiler/Profiler.hh"
|
#include "mem/ruby/profiler/Profiler.hh"
|
||||||
|
#include "mem/packet.hh"
|
||||||
|
|
||||||
// *** Begin Helper class ***
|
// *** Begin Helper class ***
|
||||||
struct StoreBufferEntry {
|
struct StoreBufferEntry {
|
||||||
|
@ -150,7 +151,8 @@ void StoreBuffer::printConfig(ostream& out)
|
||||||
|
|
||||||
// Handle an incoming store request, this method is responsible for
|
// Handle an incoming store request, this method is responsible for
|
||||||
// calling hitCallback as needed
|
// calling hitCallback as needed
|
||||||
void StoreBuffer::insertStore(const CacheMsg& request)
|
void
|
||||||
|
StoreBuffer::insertStore(Packet* pkt, const CacheMsg& request)
|
||||||
{
|
{
|
||||||
Address addr = request.getAddress();
|
Address addr = request.getAddress();
|
||||||
CacheRequestType type = request.getType();
|
CacheRequestType type = request.getType();
|
||||||
|
@ -173,7 +175,7 @@ void StoreBuffer::insertStore(const CacheMsg& request)
|
||||||
// Perform the hit-callback for the store
|
// Perform the hit-callback for the store
|
||||||
SubBlock subblock(addr, size);
|
SubBlock subblock(addr, size);
|
||||||
if(type == CacheRequestType_ST) {
|
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);
|
assert(subblock.getSize() != 0);
|
||||||
} else {
|
} else {
|
||||||
// wait to perform the hitCallback until later for Atomics
|
// wait to perform the hitCallback until later for Atomics
|
||||||
|
@ -181,9 +183,9 @@ void StoreBuffer::insertStore(const CacheMsg& request)
|
||||||
|
|
||||||
// Perform possible pre-fetch
|
// Perform possible pre-fetch
|
||||||
if(!isEmpty()) {
|
if(!isEmpty()) {
|
||||||
CacheMsg new_request = request;
|
Packet new_pkt(pkt);
|
||||||
new_request.getPrefetch() = PrefetchBit_Yes;
|
pkt->req->setFlags(Request::PREFETCH);
|
||||||
m_chip_ptr->getSequencer(m_version)->makeRequest(new_request);
|
m_chip_ptr->getSequencer(m_version)->makeRequest(&new_pkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the StoreCache
|
// Update the StoreCache
|
||||||
|
@ -200,7 +202,7 @@ void StoreBuffer::insertStore(const CacheMsg& request)
|
||||||
processHeadOfQueue();
|
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_MSG(STOREBUFFER_COMP, MedPrio, "callBack");
|
||||||
DEBUG_EXPR(STOREBUFFER_COMP, MedPrio, g_eventQueue_ptr->getTime());
|
DEBUG_EXPR(STOREBUFFER_COMP, MedPrio, g_eventQueue_ptr->getTime());
|
||||||
|
@ -220,7 +222,7 @@ void StoreBuffer::callBack(const Address& addr, DataBlock& data)
|
||||||
} else {
|
} else {
|
||||||
// We waited to perform the hitCallback until now for Atomics
|
// 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
|
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;
|
m_seen_atomic = false;
|
||||||
|
|
||||||
/// FIXME - record the time spent in the store buffer - split out ST vs ATOMIC
|
/// FIXME - record the time spent in the store buffer - split out ST vs ATOMIC
|
||||||
|
|
|
@ -49,6 +49,7 @@ class DataBlock;
|
||||||
class SubBlock;
|
class SubBlock;
|
||||||
class StoreBufferEntry;
|
class StoreBufferEntry;
|
||||||
class AbstractChip;
|
class AbstractChip;
|
||||||
|
class Packet;
|
||||||
|
|
||||||
template <class TYPE> class Vector;
|
template <class TYPE> class Vector;
|
||||||
|
|
||||||
|
@ -62,8 +63,8 @@ public:
|
||||||
|
|
||||||
// Public Methods
|
// Public Methods
|
||||||
void wakeup(); // Used only for deadlock detection
|
void wakeup(); // Used only for deadlock detection
|
||||||
void callBack(const Address& addr, DataBlock& data);
|
void callBack(const Address& addr, DataBlock& data, Packet* pkt);
|
||||||
void insertStore(const CacheMsg& request);
|
void insertStore(Packet* pkt, const CacheMsg& request);
|
||||||
void updateSubBlock(SubBlock& sub_block) const { m_store_cache.update(sub_block); }
|
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); }
|
bool trySubBlock(const SubBlock& sub_block) const { assert(isReady()); return m_store_cache.check(sub_block); }
|
||||||
void print(ostream& out) const;
|
void print(ostream& out) const;
|
||||||
|
|
|
@ -46,12 +46,48 @@
|
||||||
#include "mem/protocol/Chip.hh"
|
#include "mem/protocol/Chip.hh"
|
||||||
//#include "mem/ruby/recorder/Tracer.hh"
|
//#include "mem/ruby/recorder/Tracer.hh"
|
||||||
#include "mem/protocol/Protocol.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()
|
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");
|
DEBUG_MSG(SYSTEM_COMP, MedPrio,"initializing");
|
||||||
|
|
||||||
|
@ -101,44 +137,19 @@ RubySystem::RubySystem()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
DEBUG_MSG(SYSTEM_COMP, MedPrio,"finished initializing");
|
||||||
|
DEBUG_NEWLINE(SYSTEM_COMP, MedPrio);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RubySystem::createDriver()
|
||||||
|
{
|
||||||
if (g_SYNTHETIC_DRIVER && !g_DETERMINISTIC_DRIVER) {
|
if (g_SYNTHETIC_DRIVER && !g_DETERMINISTIC_DRIVER) {
|
||||||
cerr << "Creating Synthetic Driver" << endl;
|
cerr << "Creating Synthetic Driver" << endl;
|
||||||
m_driver_ptr = new SyntheticDriver(this);
|
m_driver_ptr = new SyntheticDriver(this);
|
||||||
} else if (!g_SYNTHETIC_DRIVER && g_DETERMINISTIC_DRIVER) {
|
} else if (!g_SYNTHETIC_DRIVER && g_DETERMINISTIC_DRIVER) {
|
||||||
cerr << "Creating Deterministic Driver" << endl;
|
cerr << "Creating Deterministic Driver" << endl;
|
||||||
m_driver_ptr = new DeterministicDriver(this);
|
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
|
void RubySystem::printConfig(ostream& out) const
|
||||||
|
|
|
@ -63,6 +63,7 @@ class RubySystem {
|
||||||
public:
|
public:
|
||||||
// Constructors
|
// Constructors
|
||||||
RubySystem();
|
RubySystem();
|
||||||
|
RubySystem(Driver* _driver); // used when driver is already instantiated (e.g. M5's RubyMem)
|
||||||
|
|
||||||
// Destructor
|
// Destructor
|
||||||
~RubySystem();
|
~RubySystem();
|
||||||
|
@ -98,6 +99,8 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Private Methods
|
// Private Methods
|
||||||
|
void init();
|
||||||
|
void createDriver();
|
||||||
|
|
||||||
// Private copy constructor and assignment operator
|
// Private copy constructor and assignment operator
|
||||||
RubySystem(const RubySystem& obj);
|
RubySystem(const RubySystem& obj);
|
||||||
|
@ -107,6 +110,7 @@ private:
|
||||||
Network* m_network_ptr;
|
Network* m_network_ptr;
|
||||||
Vector<AbstractChip*> m_chip_vector;
|
Vector<AbstractChip*> m_chip_vector;
|
||||||
Profiler* m_profiler_ptr;
|
Profiler* m_profiler_ptr;
|
||||||
|
bool m_preinitialized_driver;
|
||||||
Driver* m_driver_ptr;
|
Driver* m_driver_ptr;
|
||||||
Tracer* m_tracer_ptr;
|
Tracer* m_tracer_ptr;
|
||||||
XactIsolationChecker *m_xact_isolation_checker;
|
XactIsolationChecker *m_xact_isolation_checker;
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include "mem/ruby/system/System.hh"
|
#include "mem/ruby/system/System.hh"
|
||||||
#include "mem/ruby/common/SubBlock.hh"
|
#include "mem/ruby/common/SubBlock.hh"
|
||||||
#include "mem/protocol/Chip.hh"
|
#include "mem/protocol/Chip.hh"
|
||||||
|
#include "mem/packet.hh"
|
||||||
|
|
||||||
Check::Check(const Address& address, const Address& pc)
|
Check::Check(const Address& address, const Address& pc)
|
||||||
{
|
{
|
||||||
|
@ -84,10 +85,29 @@ void Check::initiatePrefetch(Sequencer* targetSequencer_ptr)
|
||||||
} else {
|
} else {
|
||||||
type = CacheRequestType_ST;
|
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);
|
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(&pkt)) {
|
||||||
if (targetSequencer_ptr->isReady(request)) {
|
targetSequencer_ptr->makeRequest(&pkt);
|
||||||
targetSequencer_ptr->makeRequest(request);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,15 +129,34 @@ void Check::initiateAction()
|
||||||
type = CacheRequestType_ATOMIC;
|
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();
|
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");
|
DEBUG_MSG(TESTER_COMP, MedPrio, "failed to initiate action - sequencer not ready\n");
|
||||||
} else {
|
} else {
|
||||||
DEBUG_MSG(TESTER_COMP, MedPrio, "initiating action - successful\n");
|
DEBUG_MSG(TESTER_COMP, MedPrio, "initiating action - successful\n");
|
||||||
DEBUG_EXPR(TESTER_COMP, MedPrio, m_status);
|
DEBUG_EXPR(TESTER_COMP, MedPrio, m_status);
|
||||||
m_status = TesterStatus_Action_Pending;
|
m_status = TesterStatus_Action_Pending;
|
||||||
sequencer_ptr->makeRequest(request);
|
|
||||||
|
sequencer_ptr->makeRequest(&pkt);
|
||||||
}
|
}
|
||||||
DEBUG_EXPR(TESTER_COMP, MedPrio, m_status);
|
DEBUG_EXPR(TESTER_COMP, MedPrio, m_status);
|
||||||
}
|
}
|
||||||
|
@ -132,15 +171,35 @@ void Check::initiateCheck()
|
||||||
type = CacheRequestType_IFETCH;
|
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();
|
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");
|
DEBUG_MSG(TESTER_COMP, MedPrio, "failed to initiate check - sequencer not ready\n");
|
||||||
} else {
|
} else {
|
||||||
DEBUG_MSG(TESTER_COMP, MedPrio, "initiating check - successful\n");
|
DEBUG_MSG(TESTER_COMP, MedPrio, "initiating check - successful\n");
|
||||||
DEBUG_MSG(TESTER_COMP, MedPrio, m_status);
|
DEBUG_MSG(TESTER_COMP, MedPrio, m_status);
|
||||||
m_status = TesterStatus_Check_Pending;
|
m_status = TesterStatus_Check_Pending;
|
||||||
sequencer_ptr->makeRequest(request);
|
|
||||||
|
sequencer_ptr->makeRequest(&pkt);
|
||||||
}
|
}
|
||||||
DEBUG_MSG(TESTER_COMP, MedPrio, m_status);
|
DEBUG_MSG(TESTER_COMP, MedPrio, m_status);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include "mem/ruby/common/SubBlock.hh"
|
#include "mem/ruby/common/SubBlock.hh"
|
||||||
#include "mem/ruby/tester/DeterministicDriver.hh"
|
#include "mem/ruby/tester/DeterministicDriver.hh"
|
||||||
#include "mem/protocol/Chip.hh"
|
#include "mem/protocol/Chip.hh"
|
||||||
|
#include "mem/packet.hh"
|
||||||
|
|
||||||
DetermGETXGenerator::DetermGETXGenerator(NodeID node, DeterministicDriver& driver) :
|
DetermGETXGenerator::DetermGETXGenerator(NodeID node, DeterministicDriver& driver) :
|
||||||
m_driver(driver)
|
m_driver(driver)
|
||||||
|
@ -137,7 +138,15 @@ void DetermGETXGenerator::pickAddress()
|
||||||
void DetermGETXGenerator::initiateStore()
|
void DetermGETXGenerator::initiateStore()
|
||||||
{
|
{
|
||||||
DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Store");
|
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
|
Sequencer* DetermGETXGenerator::sequencer() const
|
||||||
|
|
|
@ -179,13 +179,30 @@ void DetermInvGenerator::pickLoadAddress()
|
||||||
void DetermInvGenerator::initiateLoad()
|
void DetermInvGenerator::initiateLoad()
|
||||||
{
|
{
|
||||||
DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Load");
|
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()
|
void DetermInvGenerator::initiateStore()
|
||||||
{
|
{
|
||||||
DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Store");
|
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
|
Sequencer* DetermInvGenerator::sequencer() const
|
||||||
|
|
|
@ -135,7 +135,16 @@ void DetermSeriesGETSGenerator::pickAddress()
|
||||||
void DetermSeriesGETSGenerator::initiateLoad()
|
void DetermSeriesGETSGenerator::initiateLoad()
|
||||||
{
|
{
|
||||||
DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Load");
|
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
|
Sequencer* DetermSeriesGETSGenerator::sequencer() const
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#include "mem/ruby/tester/DetermSeriesGETSGenerator.hh"
|
#include "mem/ruby/tester/DetermSeriesGETSGenerator.hh"
|
||||||
#include "mem/ruby/common/SubBlock.hh"
|
#include "mem/ruby/common/SubBlock.hh"
|
||||||
#include "mem/protocol/Chip.hh"
|
#include "mem/protocol/Chip.hh"
|
||||||
|
#include "mem/packet.hh"
|
||||||
|
|
||||||
DeterministicDriver::DeterministicDriver(RubySystem* sys_ptr)
|
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);
|
m_generator_vector[proc]->performCallback(proc, data);
|
||||||
|
|
||||||
// Mark that we made progress
|
|
||||||
m_last_progress_vector[proc] = g_eventQueue_ptr->getTime();
|
m_last_progress_vector[proc] = g_eventQueue_ptr->getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
|
|
||||||
class RubySystem;
|
class RubySystem;
|
||||||
class SpecifiedGenerator;
|
class SpecifiedGenerator;
|
||||||
|
class Packet;
|
||||||
|
|
||||||
class DeterministicDriver : public Driver, public Consumer {
|
class DeterministicDriver : public Driver, public Consumer {
|
||||||
public:
|
public:
|
||||||
|
@ -69,7 +70,7 @@ public:
|
||||||
void recordLoadLatency(Time time);
|
void recordLoadLatency(Time time);
|
||||||
void recordStoreLatency(Time time);
|
void recordStoreLatency(Time time);
|
||||||
|
|
||||||
void hitCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread);
|
void hitCallback(Packet* pkt);
|
||||||
void wakeup();
|
void wakeup();
|
||||||
void printStats(ostream& out) const;
|
void printStats(ostream& out) const;
|
||||||
void clearStats() {}
|
void clearStats() {}
|
||||||
|
|
|
@ -169,19 +169,43 @@ void RequestGenerator::pickAddress()
|
||||||
void RequestGenerator::initiateTest()
|
void RequestGenerator::initiateTest()
|
||||||
{
|
{
|
||||||
DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Test");
|
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()
|
void RequestGenerator::initiateSwap()
|
||||||
{
|
{
|
||||||
DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Swap");
|
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()
|
void RequestGenerator::initiateRelease()
|
||||||
{
|
{
|
||||||
DEBUG_MSG(TESTER_COMP, MedPrio, "initiating Release");
|
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
|
Sequencer* RequestGenerator::sequencer() const
|
||||||
|
|
|
@ -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);
|
NodeID proc = pkt->req->contextId();
|
||||||
//cout << " " << proc << " in S.D. hitCallback" << endl;
|
SubBlock data(Address(pkt->getAddr()), pkt->req->getSize());
|
||||||
if(XACT_MEMORY){
|
if (pkt->hasData()) {
|
||||||
//XactRequestGenerator* reqGen = static_cast<XactRequestGenerator*>(m_request_generator_vector[proc]);
|
for (int i = 0; i < pkt->req->getSize(); i++) {
|
||||||
//reqGen->performCallback(proc, data);
|
data.setByte(i, *(pkt->getPtr<uint8>()+i));
|
||||||
} else {
|
|
||||||
m_request_generator_vector[proc]->performCallback(proc, data);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Mark that we made progress
|
m_request_generator_vector[proc]->performCallback(proc, data);
|
||||||
m_last_progress_vector[proc] = g_eventQueue_ptr->getTime();
|
m_last_progress_vector[proc] = g_eventQueue_ptr->getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ public:
|
||||||
void recordSwapLatency(Time time);
|
void recordSwapLatency(Time time);
|
||||||
void recordReleaseLatency(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 conflictCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread) {assert(0);}
|
||||||
void abortCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread);
|
void abortCallback(NodeID proc, SubBlock& data, CacheRequestType type, int thread);
|
||||||
void wakeup();
|
void wakeup();
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
#include "mem/ruby/tester/main.hh"
|
#include "mem/ruby/tester/main.hh"
|
||||||
#include "mem/ruby/eventqueue/RubyEventQueue.hh"
|
#include "mem/ruby/eventqueue/RubyEventQueue.hh"
|
||||||
#include "mem/ruby/config/RubyConfig.hh"
|
#include "mem/ruby/config/RubyConfig.hh"
|
||||||
#include "mem/ruby/tester/test_framework.hh"
|
//#include "mem/ruby/tester/test_framework.hh"
|
||||||
|
|
||||||
// *******************
|
// *******************
|
||||||
// *** tester main ***
|
// *** tester main ***
|
||||||
|
@ -43,5 +43,6 @@
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
tester_main(argc, argv);
|
//dsm: PRUNED
|
||||||
|
//tester_main(argc, argv);
|
||||||
}
|
}
|
||||||
|
|
256
src/mem/rubymem.cc
Normal file
256
src/mem/rubymem.cc
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
|
129
src/mem/rubymem.hh
Normal file
129
src/mem/rubymem.hh
Normal file
|
@ -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__
|
||||||
|
|
Loading…
Reference in a new issue