Ruby: Add support for functional accesses

This patch rpovides functional access support in Ruby. Currently only
the M5Port of RubyPort supports functional accesses. The support for
functional through the PioPort will be added as a separate patch.
This commit is contained in:
Brad Beckmann ext:(%2C%20Nilay%20Vaish%20%3Cnilay%40cs.wisc.edu%3E) 2011-06-30 19:49:26 -05:00
parent f4cfd65d29
commit c86f849d5a
60 changed files with 574 additions and 247 deletions

View file

@ -97,7 +97,7 @@ system.tester = RubyDirectedTester(requests_to_complete = \
options.requests, options.requests,
generator = generator) generator = generator)
system.ruby = Ruby.create_system(options, system) Ruby.create_system(options, system)
assert(options.num_cpus == len(system.ruby._cpu_ruby_ports)) assert(options.num_cpus == len(system.ruby._cpu_ruby_ports))

View file

@ -117,10 +117,7 @@ elif buildEnv['TARGET_ISA'] == "x86":
else: else:
fatal("incapable of building non-alpha or non-x86 full system!") fatal("incapable of building non-alpha or non-x86 full system!")
system.ruby = Ruby.create_system(options, Ruby.create_system(options, system, system.piobus, system._dma_devices)
system,
system.piobus,
system._dma_devices)
system.cpu = [CPUClass(cpu_id=i) for i in xrange(options.num_cpus)] system.cpu = [CPUClass(cpu_id=i) for i in xrange(options.num_cpus)]

View file

@ -55,6 +55,10 @@ parser.add_option("--progress", type="int", default=1000,
help="Progress message interval " help="Progress message interval "
"[default: %default]") "[default: %default]")
parser.add_option("--num-dmas", type="int", default=0, help="# of dma testers") parser.add_option("--num-dmas", type="int", default=0, help="# of dma testers")
parser.add_option("--functional", type="int", default=0,
help="percentage of accesses that should be functional")
parser.add_option("--suppress-func-warnings", action="store_true",
help="suppress warnings when functional accesses fail")
# #
# Add the ruby specific and protocol specific options # Add the ruby specific and protocol specific options
@ -90,14 +94,15 @@ if options.num_cpus > block_size:
sys.exit(1) sys.exit(1)
# #
# Currently ruby does not support atomic, functional, or uncacheable accesses # Currently ruby does not support atomic or uncacheable accesses
# #
cpus = [ MemTest(atomic = False, \ cpus = [ MemTest(atomic = False, \
max_loads = options.maxloads, \ max_loads = options.maxloads, \
issue_dmas = False, \ issue_dmas = False, \
percent_functional = 0, \ percent_functional = options.functional, \
percent_uncacheable = 0, \ percent_uncacheable = 0, \
progress_interval = options.progress) \ progress_interval = options.progress, \
suppress_func_warnings = options.suppress_func_warnings) \
for i in xrange(options.num_cpus) ] for i in xrange(options.num_cpus) ]
system = System(cpu = cpus, system = System(cpu = cpus,
@ -110,15 +115,14 @@ if options.num_dmas > 0:
issue_dmas = True, \ issue_dmas = True, \
percent_functional = 0, \ percent_functional = 0, \
percent_uncacheable = 0, \ percent_uncacheable = 0, \
progress_interval = options.progress) \ progress_interval = options.progress, \
warn_on_failure = options.warn_on_failure) \
for i in xrange(options.num_dmas) ] for i in xrange(options.num_dmas) ]
system.dma_devices = dmas system.dma_devices = dmas
else: else:
dmas = [] dmas = []
system.ruby = Ruby.create_system(options, \ Ruby.create_system(options, system, dma_devices = dmas)
system, \
dma_devices = dmas)
# #
# The tester is most effective when randomization is turned on and # The tester is most effective when randomization is turned on and
@ -141,6 +145,12 @@ for (i, cpu) in enumerate(cpus):
# #
system.ruby._cpu_ruby_ports[i].deadlock_threshold = 5000000 system.ruby._cpu_ruby_ports[i].deadlock_threshold = 5000000
#
# Ruby doesn't need the backing image of memory when running with
# the tester.
#
system.ruby._cpu_ruby_ports[i].access_phys_mem = False
for (i, dma) in enumerate(dmas): for (i, dma) in enumerate(dmas):
# #
# Tie the dma memtester ports to the correct functional port # Tie the dma memtester ports to the correct functional port

View file

@ -105,7 +105,7 @@ cpus = [ NetworkTest(fixed_pkts=options.fixed_pkts, \
system = System(cpu = cpus, system = System(cpu = cpus,
physmem = PhysicalMemory()) physmem = PhysicalMemory())
system.ruby = Ruby.create_system(options, system) Ruby.create_system(options, system)
i = 0 i = 0
for ruby_port in system.ruby._cpu_ruby_ports: for ruby_port in system.ruby._cpu_ruby_ports:

View file

@ -99,7 +99,7 @@ tester = RubyTester(check_flush = check_flush,
# #
system = System(tester = tester, physmem = PhysicalMemory()) system = System(tester = tester, physmem = PhysicalMemory())
system.ruby = Ruby.create_system(options, system) Ruby.create_system(options, system)
assert(options.num_cpus == len(system.ruby._cpu_ruby_ports)) assert(options.num_cpus == len(system.ruby._cpu_ruby_ports))
@ -121,6 +121,12 @@ for ruby_port in system.ruby._cpu_ruby_ports:
# #
ruby_port.using_ruby_tester = True ruby_port.using_ruby_tester = True
#
# Ruby doesn't need the backing image of memory when running with
# the tester.
#
ruby_port.access_phys_mem = False
# ----------------------- # -----------------------
# run simulation # run simulation
# ----------------------- # -----------------------

View file

@ -177,7 +177,7 @@ system = System(cpu = [CPUClass(cpu_id=i) for i in xrange(np)],
if options.ruby: if options.ruby:
options.use_map = True options.use_map = True
system.ruby = Ruby.create_system(options, system) Ruby.create_system(options, system)
assert(options.num_cpus == len(system.ruby._cpu_ruby_ports)) assert(options.num_cpus == len(system.ruby._cpu_ruby_ports))
else: else:
system.physmem.port = system.membus.port system.physmem.port = system.membus.port

View file

@ -47,7 +47,7 @@ class L2Cache(RubyCache):
def define_options(parser): def define_options(parser):
return return
def create_system(options, system, piobus, dma_devices): def create_system(options, system, piobus, dma_devices, ruby_system):
if buildEnv['PROTOCOL'] != 'MESI_CMP_directory': if buildEnv['PROTOCOL'] != 'MESI_CMP_directory':
panic("This script requires the MESI_CMP_directory protocol to be built.") panic("This script requires the MESI_CMP_directory protocol to be built.")
@ -88,13 +88,15 @@ def create_system(options, system, piobus, dma_devices):
cntrl_id = cntrl_count, cntrl_id = cntrl_count,
L1IcacheMemory = l1i_cache, L1IcacheMemory = l1i_cache,
L1DcacheMemory = l1d_cache, L1DcacheMemory = l1d_cache,
l2_select_num_bits = l2_bits) l2_select_num_bits = l2_bits,
ruby_system = ruby_system)
cpu_seq = RubySequencer(version = i, cpu_seq = RubySequencer(version = i,
icache = l1i_cache, icache = l1i_cache,
dcache = l1d_cache, dcache = l1d_cache,
physMemPort = system.physmem.port, physMemPort = system.physmem.port,
physmem = system.physmem) physmem = system.physmem,
ruby_system = ruby_system)
l1_cntrl.sequencer = cpu_seq l1_cntrl.sequencer = cpu_seq
@ -123,7 +125,8 @@ def create_system(options, system, piobus, dma_devices):
l2_cntrl = L2Cache_Controller(version = i, l2_cntrl = L2Cache_Controller(version = i,
cntrl_id = cntrl_count, cntrl_id = cntrl_count,
L2cacheMemory = l2_cache) L2cacheMemory = l2_cache,
ruby_system = ruby_system)
exec("system.l2_cntrl%d = l2_cntrl" % i) exec("system.l2_cntrl%d = l2_cntrl" % i)
l2_cntrl_nodes.append(l2_cntrl) l2_cntrl_nodes.append(l2_cntrl)
@ -148,9 +151,9 @@ def create_system(options, system, piobus, dma_devices):
cntrl_id = cntrl_count, cntrl_id = cntrl_count,
directory = \ directory = \
RubyDirectoryMemory(version = i, RubyDirectoryMemory(version = i,
size = \ size = dir_size),
dir_size), memBuffer = mem_cntrl,
memBuffer = mem_cntrl) ruby_system = ruby_system)
exec("system.dir_cntrl%d = dir_cntrl" % i) exec("system.dir_cntrl%d = dir_cntrl" % i)
dir_cntrl_nodes.append(dir_cntrl) dir_cntrl_nodes.append(dir_cntrl)

View file

@ -41,7 +41,7 @@ class Cache(RubyCache):
def define_options(parser): def define_options(parser):
return return
def create_system(options, system, piobus, dma_devices): def create_system(options, system, piobus, dma_devices, ruby_system):
if buildEnv['PROTOCOL'] != 'MI_example': if buildEnv['PROTOCOL'] != 'MI_example':
panic("This script requires the MI_example protocol to be built.") panic("This script requires the MI_example protocol to be built.")
@ -80,13 +80,15 @@ def create_system(options, system, piobus, dma_devices):
# #
l1_cntrl = L1Cache_Controller(version = i, l1_cntrl = L1Cache_Controller(version = i,
cntrl_id = cntrl_count, cntrl_id = cntrl_count,
cacheMemory = cache) cacheMemory = cache,
ruby_system = ruby_system)
cpu_seq = RubySequencer(version = i, cpu_seq = RubySequencer(version = i,
icache = cache, icache = cache,
dcache = cache, dcache = cache,
physMemPort = system.physmem.port, physMemPort = system.physmem.port,
physmem = system.physmem) physmem = system.physmem,
ruby_system = ruby_system)
l1_cntrl.sequencer = cpu_seq l1_cntrl.sequencer = cpu_seq
@ -125,7 +127,8 @@ def create_system(options, system, piobus, dma_devices):
use_map = options.use_map, use_map = options.use_map,
map_levels = \ map_levels = \
options.map_levels), options.map_levels),
memBuffer = mem_cntrl) memBuffer = mem_cntrl,
ruby_system = ruby_system)
exec("system.dir_cntrl%d = dir_cntrl" % i) exec("system.dir_cntrl%d = dir_cntrl" % i)
dir_cntrl_nodes.append(dir_cntrl) dir_cntrl_nodes.append(dir_cntrl)

View file

@ -47,8 +47,8 @@ class L2Cache(RubyCache):
def define_options(parser): def define_options(parser):
return return
def create_system(options, system, piobus, dma_devices): def create_system(options, system, piobus, dma_devices, ruby_system):
if buildEnv['PROTOCOL'] != 'MOESI_CMP_directory': if buildEnv['PROTOCOL'] != 'MOESI_CMP_directory':
panic("This script requires the MOESI_CMP_directory protocol to be built.") panic("This script requires the MOESI_CMP_directory protocol to be built.")
@ -88,13 +88,15 @@ def create_system(options, system, piobus, dma_devices):
cntrl_id = cntrl_count, cntrl_id = cntrl_count,
L1IcacheMemory = l1i_cache, L1IcacheMemory = l1i_cache,
L1DcacheMemory = l1d_cache, L1DcacheMemory = l1d_cache,
l2_select_num_bits = l2_bits) l2_select_num_bits = l2_bits,
ruby_system = ruby_system)
cpu_seq = RubySequencer(version = i, cpu_seq = RubySequencer(version = i,
icache = l1i_cache, icache = l1i_cache,
dcache = l1d_cache, dcache = l1d_cache,
physMemPort = system.physmem.port, physMemPort = system.physmem.port,
physmem = system.physmem) physmem = system.physmem,
ruby_system = ruby_system)
l1_cntrl.sequencer = cpu_seq l1_cntrl.sequencer = cpu_seq
@ -122,7 +124,8 @@ def create_system(options, system, piobus, dma_devices):
l2_cntrl = L2Cache_Controller(version = i, l2_cntrl = L2Cache_Controller(version = i,
cntrl_id = cntrl_count, cntrl_id = cntrl_count,
L2cacheMemory = l2_cache) L2cacheMemory = l2_cache,
ruby_system = ruby_system)
exec("system.l2_cntrl%d = l2_cntrl" % i) exec("system.l2_cntrl%d = l2_cntrl" % i)
l2_cntrl_nodes.append(l2_cntrl) l2_cntrl_nodes.append(l2_cntrl)
@ -147,9 +150,9 @@ def create_system(options, system, piobus, dma_devices):
cntrl_id = cntrl_count, cntrl_id = cntrl_count,
directory = \ directory = \
RubyDirectoryMemory(version = i, RubyDirectoryMemory(version = i,
size = \ size = dir_size),
dir_size), memBuffer = mem_cntrl,
memBuffer = mem_cntrl) ruby_system = ruby_system)
exec("system.dir_cntrl%d = dir_cntrl" % i) exec("system.dir_cntrl%d = dir_cntrl" % i)
dir_cntrl_nodes.append(dir_cntrl) dir_cntrl_nodes.append(dir_cntrl)

View file

@ -54,7 +54,7 @@ def define_options(parser):
parser.add_option("--allow-atomic-migration", action="store_true", parser.add_option("--allow-atomic-migration", action="store_true",
help="allow migratory sharing for atomic only accessed blocks") help="allow migratory sharing for atomic only accessed blocks")
def create_system(options, system, piobus, dma_devices): def create_system(options, system, piobus, dma_devices, ruby_system):
if buildEnv['PROTOCOL'] != 'MOESI_CMP_token': if buildEnv['PROTOCOL'] != 'MOESI_CMP_token':
panic("This script requires the MOESI_CMP_token protocol to be built.") panic("This script requires the MOESI_CMP_token protocol to be built.")
@ -110,13 +110,15 @@ def create_system(options, system, piobus, dma_devices):
dynamic_timeout_enabled = \ dynamic_timeout_enabled = \
not options.disable_dyn_timeouts, not options.disable_dyn_timeouts,
no_mig_atomic = not \ no_mig_atomic = not \
options.allow_atomic_migration) options.allow_atomic_migration,
ruby_system = ruby_system)
cpu_seq = RubySequencer(version = i, cpu_seq = RubySequencer(version = i,
icache = l1i_cache, icache = l1i_cache,
dcache = l1d_cache, dcache = l1d_cache,
physMemPort = system.physmem.port, physMemPort = system.physmem.port,
physmem = system.physmem) physmem = system.physmem,
ruby_system = ruby_system)
l1_cntrl.sequencer = cpu_seq l1_cntrl.sequencer = cpu_seq
@ -145,7 +147,8 @@ def create_system(options, system, piobus, dma_devices):
l2_cntrl = L2Cache_Controller(version = i, l2_cntrl = L2Cache_Controller(version = i,
cntrl_id = cntrl_count, cntrl_id = cntrl_count,
L2cacheMemory = l2_cache, L2cacheMemory = l2_cache,
N_tokens = n_tokens) N_tokens = n_tokens,
ruby_system = ruby_system)
exec("system.l2_cntrl%d = l2_cntrl" % i) exec("system.l2_cntrl%d = l2_cntrl" % i)
l2_cntrl_nodes.append(l2_cntrl) l2_cntrl_nodes.append(l2_cntrl)
@ -170,10 +173,10 @@ def create_system(options, system, piobus, dma_devices):
cntrl_id = cntrl_count, cntrl_id = cntrl_count,
directory = \ directory = \
RubyDirectoryMemory(version = i, RubyDirectoryMemory(version = i,
size = \ size = dir_size),
dir_size),
memBuffer = mem_cntrl, memBuffer = mem_cntrl,
l2_select_num_bits = l2_bits) l2_select_num_bits = l2_bits,
ruby_system = ruby_system)
exec("system.dir_cntrl%d = dir_cntrl" % i) exec("system.dir_cntrl%d = dir_cntrl" % i)
dir_cntrl_nodes.append(dir_cntrl) dir_cntrl_nodes.append(dir_cntrl)

View file

@ -58,8 +58,8 @@ def define_options(parser):
parser.add_option("--dir-on", action="store_true", parser.add_option("--dir-on", action="store_true",
help="Hammer: enable Full-bit Directory") help="Hammer: enable Full-bit Directory")
def create_system(options, system, piobus, dma_devices): def create_system(options, system, piobus, dma_devices, ruby_system):
if buildEnv['PROTOCOL'] != 'MOESI_hammer': if buildEnv['PROTOCOL'] != 'MOESI_hammer':
panic("This script requires the MOESI_hammer protocol to be built.") panic("This script requires the MOESI_hammer protocol to be built.")
@ -102,13 +102,15 @@ def create_system(options, system, piobus, dma_devices):
L1DcacheMemory = l1d_cache, L1DcacheMemory = l1d_cache,
L2cacheMemory = l2_cache, L2cacheMemory = l2_cache,
no_mig_atomic = not \ no_mig_atomic = not \
options.allow_atomic_migration) options.allow_atomic_migration,
ruby_system = ruby_system)
cpu_seq = RubySequencer(version = i, cpu_seq = RubySequencer(version = i,
icache = l1i_cache, icache = l1i_cache,
dcache = l1d_cache, dcache = l1d_cache,
physMemPort = system.physmem.port, physMemPort = system.physmem.port,
physmem = system.physmem) physmem = system.physmem,
ruby_system = ruby_system)
l1_cntrl.sequencer = cpu_seq l1_cntrl.sequencer = cpu_seq
@ -181,7 +183,8 @@ def create_system(options, system, piobus, dma_devices):
probeFilter = pf, probeFilter = pf,
memBuffer = mem_cntrl, memBuffer = mem_cntrl,
probe_filter_enabled = options.pf_on, probe_filter_enabled = options.pf_on,
full_bit_dir_enabled = options.dir_on) full_bit_dir_enabled = options.dir_on,
ruby_system = ruby_system)
if options.recycle_latency: if options.recycle_latency:
dir_cntrl.recycle_latency = options.recycle_latency dir_cntrl.recycle_latency = options.recycle_latency

View file

@ -62,11 +62,15 @@ def define_options(parser):
def create_system(options, system, piobus = None, dma_devices = []): def create_system(options, system, piobus = None, dma_devices = []):
system.ruby = RubySystem(clock = options.clock)
ruby = system.ruby
protocol = buildEnv['PROTOCOL'] protocol = buildEnv['PROTOCOL']
exec "import %s" % protocol exec "import %s" % protocol
try: try:
(cpu_sequencers, dir_cntrls, all_cntrls) = \ (cpu_sequencers, dir_cntrls, all_cntrls) = \
eval("%s.create_system(options, system, piobus, dma_devices)" \ eval("%s.create_system(options, system, piobus, \
dma_devices, ruby)" \
% protocol) % protocol)
except: except:
print "Error: could not create sytem for ruby protocol %s" % protocol print "Error: could not create sytem for ruby protocol %s" % protocol
@ -105,7 +109,7 @@ def create_system(options, system, piobus = None, dma_devices = []):
print "Error: could not create topology %s" % options.topology print "Error: could not create topology %s" % options.topology
raise raise
network = NetworkClass(topology = net_topology) network = NetworkClass(ruby_system = ruby, topology = net_topology)
# #
# Loop through the directory controlers. # Loop through the directory controlers.
@ -137,15 +141,13 @@ def create_system(options, system, piobus = None, dma_devices = []):
long(system.physmem.range.first) + 1 long(system.physmem.range.first) + 1
assert(total_mem_size.value == physmem_size) assert(total_mem_size.value == physmem_size)
ruby_profiler = RubyProfiler(num_of_sequencers = len(cpu_sequencers)) ruby_profiler = RubyProfiler(ruby_system = ruby,
num_of_sequencers = len(cpu_sequencers))
ruby_tracer = RubyTracer(ruby_system = ruby)
ruby = RubySystem(clock = options.clock, ruby.network = network
network = network, ruby.profiler = ruby_profiler
profiler = ruby_profiler, ruby.tracer = ruby_tracer
tracer = RubyTracer(), ruby.mem_size = total_mem_size
mem_size = total_mem_size)
ruby._cpu_ruby_ports = cpu_sequencers ruby._cpu_ruby_ports = cpu_sequencers
ruby.random_seed = options.random_seed ruby.random_seed = options.random_seed
return ruby

View file

@ -50,3 +50,5 @@ class MemTest(MemObject):
test = Port("Port to the memory system to test") test = Port("Port to the memory system to test")
functional = Port("Port to the functional memory used for verification") functional = Port("Port to the functional memory used for verification")
suppress_func_warnings = Param.Bool(False,
"suppress warnings when functional accesses fail.\n")

View file

@ -146,7 +146,8 @@ MemTest::MemTest(const Params *p)
percentSourceUnaligned(p->percent_source_unaligned), percentSourceUnaligned(p->percent_source_unaligned),
percentDestUnaligned(p->percent_dest_unaligned), percentDestUnaligned(p->percent_dest_unaligned),
maxLoads(p->max_loads), maxLoads(p->max_loads),
atomic(p->atomic) atomic(p->atomic),
suppress_func_warnings(p->suppress_func_warnings)
{ {
cachePort.snoopRangeSent = false; cachePort.snoopRangeSent = false;
funcPort.snoopRangeSent = true; funcPort.snoopRangeSent = true;
@ -162,6 +163,7 @@ MemTest::MemTest(const Params *p)
// set up counters // set up counters
noResponseCycles = 0; noResponseCycles = 0;
numReads = 0; numReads = 0;
numWrites = 0;
schedule(tickEvent, 0); schedule(tickEvent, 0);
accessRetry = false; accessRetry = false;
@ -201,9 +203,10 @@ MemTest::completeRequest(PacketPtr pkt)
dmaOutstanding = false; dmaOutstanding = false;
} }
DPRINTF(MemTest, "completing %s at address %x (blk %x)\n", DPRINTF(MemTest, "completing %s at address %x (blk %x) %s\n",
pkt->isWrite() ? "write" : "read", pkt->isWrite() ? "write" : "read",
req->getPaddr(), blockAddr(req->getPaddr())); req->getPaddr(), blockAddr(req->getPaddr()),
pkt->isError() ? "error" : "success");
MemTestSenderState *state = MemTestSenderState *state =
dynamic_cast<MemTestSenderState *>(pkt->senderState); dynamic_cast<MemTestSenderState *>(pkt->senderState);
@ -217,28 +220,37 @@ MemTest::completeRequest(PacketPtr pkt)
assert(removeAddr != outstandingAddrs.end()); assert(removeAddr != outstandingAddrs.end());
outstandingAddrs.erase(removeAddr); outstandingAddrs.erase(removeAddr);
if (pkt->isRead()) { if (pkt->isError()) {
if (memcmp(pkt_data, data, pkt->getSize()) != 0) { if (!suppress_func_warnings) {
panic("%s: read of %x (blk %x) @ cycle %d " warn("Functional Access failed for %x at %x\n",
"returns %x, expected %x\n", name(), pkt->isWrite() ? "write" : "read", req->getPaddr());
req->getPaddr(), blockAddr(req->getPaddr()), curTick(),
*pkt_data, *data);
} }
numReads++;
numReadsStat++;
if (numReads == (uint64_t)nextProgressMessage) {
ccprintf(cerr, "%s: completed %d read accesses @%d\n",
name(), numReads, curTick());
nextProgressMessage += progressInterval;
}
if (maxLoads != 0 && numReads >= maxLoads)
exitSimLoop("maximum number of loads reached");
} else { } else {
assert(pkt->isWrite()); if (pkt->isRead()) {
numWritesStat++; if (memcmp(pkt_data, data, pkt->getSize()) != 0) {
panic("%s: read of %x (blk %x) @ cycle %d "
"returns %x, expected %x\n", name(),
req->getPaddr(), blockAddr(req->getPaddr()), curTick(),
*pkt_data, *data);
}
numReads++;
numReadsStat++;
if (numReads == (uint64_t)nextProgressMessage) {
ccprintf(cerr, "%s: completed %d read, %d write accesses @%d\n",
name(), numReads, numWrites, curTick());
nextProgressMessage += progressInterval;
}
if (maxLoads != 0 && numReads >= maxLoads)
exitSimLoop("maximum number of loads reached");
} else {
assert(pkt->isWrite());
funcPort.writeBlob(req->getPaddr(), pkt_data, req->getSize());
numWrites++;
numWritesStat++;
}
} }
noResponseCycles = 0; noResponseCycles = 0;
@ -361,6 +373,8 @@ MemTest::tick()
pkt->senderState = state; pkt->senderState = state;
if (do_functional) { if (do_functional) {
assert(pkt->needsResponse());
pkt->setSuppressFuncError();
cachePort.sendFunctional(pkt); cachePort.sendFunctional(pkt);
completeRequest(pkt); completeRequest(pkt);
} else { } else {
@ -392,9 +406,8 @@ MemTest::tick()
MemTestSenderState *state = new MemTestSenderState(result); MemTestSenderState *state = new MemTestSenderState(result);
pkt->senderState = state; pkt->senderState = state;
funcPort.writeBlob(req->getPaddr(), pkt_data, req->getSize());
if (do_functional) { if (do_functional) {
pkt->setSuppressFuncError();
cachePort.sendFunctional(pkt); cachePort.sendFunctional(pkt);
completeRequest(pkt); completeRequest(pkt);
} else { } else {

View file

@ -174,9 +174,11 @@ class MemTest : public MemObject
Tick noResponseCycles; Tick noResponseCycles;
uint64_t numReads; uint64_t numReads;
uint64_t numWrites;
uint64_t maxLoads; uint64_t maxLoads;
bool atomic; bool atomic;
bool suppress_func_warnings;
Stats::Scalar numReadsStat; Stats::Scalar numReadsStat;
Stats::Scalar numWritesStat; Stats::Scalar numWritesStat;

View file

@ -148,10 +148,14 @@ MemCmd::commandInfo[] =
{ SET2(IsResponse, IsError), InvalidCmd, "InvalidDestError" }, { SET2(IsResponse, IsError), InvalidCmd, "InvalidDestError" },
/* BadAddressError -- memory address invalid */ /* BadAddressError -- memory address invalid */
{ SET2(IsResponse, IsError), InvalidCmd, "BadAddressError" }, { SET2(IsResponse, IsError), InvalidCmd, "BadAddressError" },
/* FunctionalReadError */
{ SET3(IsRead, IsResponse, IsError), InvalidCmd, "FunctionalReadError" },
/* FunctionalWriteError */
{ SET3(IsWrite, IsResponse, IsError), InvalidCmd, "FunctionalWriteError" },
/* PrintReq */ /* PrintReq */
{ SET2(IsRequest, IsPrint), InvalidCmd, "PrintReq" }, { SET2(IsRequest, IsPrint), InvalidCmd, "PrintReq" },
/* Flush Request */ /* Flush Request */
{ SET3(IsRequest, IsFlush, NeedsExclusive), InvalidCmd, "FlushReq" } { SET3(IsRequest, IsFlush, NeedsExclusive), InvalidCmd, "FlushReq" },
}; };
bool bool

View file

@ -103,6 +103,8 @@ class MemCmd
NetworkNackError, // nacked at network layer (not by protocol) NetworkNackError, // nacked at network layer (not by protocol)
InvalidDestError, // packet dest field invalid InvalidDestError, // packet dest field invalid
BadAddressError, // memory address invalid BadAddressError, // memory address invalid
FunctionalReadError, // unable to fulfill functional read
FunctionalWriteError, // unable to fulfill functional write
// Fake simulator-only commands // Fake simulator-only commands
PrintReq, // Print state matching address PrintReq, // Print state matching address
FlushReq, //request for a cache flush FlushReq, //request for a cache flush
@ -240,6 +242,9 @@ class Packet : public FastAlloc, public Printable
/// the data pointer points to an array (thus delete []) needs to /// the data pointer points to an array (thus delete []) needs to
/// be called on it rather than simply delete. /// be called on it rather than simply delete.
static const FlagsType ARRAY_DATA = 0x00004000; static const FlagsType ARRAY_DATA = 0x00004000;
/// suppress the error if this packet encounters a functional
/// access failure.
static const FlagsType SUPPRESS_FUNC_ERROR = 0x00008000;
Flags flags; Flags flags;
@ -428,6 +433,8 @@ class Packet : public FastAlloc, public Printable
void setSupplyExclusive() { flags.set(SUPPLY_EXCLUSIVE); } void setSupplyExclusive() { flags.set(SUPPLY_EXCLUSIVE); }
void clearSupplyExclusive() { flags.clear(SUPPLY_EXCLUSIVE); } void clearSupplyExclusive() { flags.clear(SUPPLY_EXCLUSIVE); }
bool isSupplyExclusive() { return flags.isSet(SUPPLY_EXCLUSIVE); } bool isSupplyExclusive() { return flags.isSet(SUPPLY_EXCLUSIVE); }
void setSuppressFuncError() { flags.set(SUPPRESS_FUNC_ERROR); }
bool suppressFuncError() { return flags.isSet(SUPPRESS_FUNC_ERROR); }
// Network error conditions... encapsulate them as methods since // Network error conditions... encapsulate them as methods since
// their encoding keeps changing (from result field to command // their encoding keeps changing (from result field to command
@ -617,6 +624,18 @@ class Packet : public FastAlloc, public Printable
makeResponse(); makeResponse();
} }
void
setFunctionalResponseStatus(bool success)
{
if (!success) {
if (isWrite()) {
cmd = MemCmd::FunctionalWriteError;
} else {
cmd = MemCmd::FunctionalReadError;
}
}
}
/** /**
* Take a request packet that has been returned as NACKED and * Take a request packet that has been returned as NACKED and
* modify it so that it can be sent out again. Only packets that * modify it so that it can be sent out again. Only packets that

View file

@ -186,17 +186,24 @@ machine(L1Cache, "MSI Directory L1 Cache CMP")
AccessPermission getAccessPermission(Address addr) { AccessPermission getAccessPermission(Address addr) {
TBE tbe := L1_TBEs[addr]; TBE tbe := L1_TBEs[addr];
if(is_valid(tbe)) { if(is_valid(tbe)) {
DPRINTF(RubySlicc, "%s\n", L1Cache_State_to_permission(tbe.TBEState));
return L1Cache_State_to_permission(tbe.TBEState); return L1Cache_State_to_permission(tbe.TBEState);
} }
Entry cache_entry := getCacheEntry(addr); Entry cache_entry := getCacheEntry(addr);
if(is_valid(cache_entry)) { if(is_valid(cache_entry)) {
DPRINTF(RubySlicc, "%s\n", L1Cache_State_to_permission(cache_entry.CacheState));
return L1Cache_State_to_permission(cache_entry.CacheState); return L1Cache_State_to_permission(cache_entry.CacheState);
} }
DPRINTF(RubySlicc, "%s\n", AccessPermission:NotPresent);
return AccessPermission:NotPresent; return AccessPermission:NotPresent;
} }
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
return getCacheEntry(addr).DataBlk;
}
void setAccessPermission(Entry cache_entry, Address addr, State state) { void setAccessPermission(Entry cache_entry, Address addr, State state) {
if (is_valid(cache_entry)) { if (is_valid(cache_entry)) {
cache_entry.changePermission(L1Cache_State_to_permission(state)); cache_entry.changePermission(L1Cache_State_to_permission(state));

View file

@ -56,7 +56,7 @@ machine(L2Cache, "MESI Directory L2 Cache CMP")
NP, AccessPermission:Invalid, desc="Not present in either cache"; NP, AccessPermission:Invalid, desc="Not present in either cache";
SS, AccessPermission:Read_Only, desc="L2 cache entry Shared, also present in one or more L1s"; SS, AccessPermission:Read_Only, desc="L2 cache entry Shared, also present in one or more L1s";
M, AccessPermission:Read_Write, desc="L2 cache entry Modified, not present in any L1s", format="!b"; M, AccessPermission:Read_Write, desc="L2 cache entry Modified, not present in any L1s", format="!b";
MT, AccessPermission:Invalid, desc="L2 cache entry Modified in a local L1, assume L2 copy stale", format="!b"; MT, AccessPermission:Maybe_Stale, desc="L2 cache entry Modified in a local L1, assume L2 copy stale", format="!b";
// L2 replacement // L2 replacement
M_I, AccessPermission:Busy, desc="L2 cache replacing, have all acks, sent dirty data to memory, waiting for ACK from memory"; M_I, AccessPermission:Busy, desc="L2 cache replacing, have all acks, sent dirty data to memory, waiting for ACK from memory";
@ -217,17 +217,24 @@ machine(L2Cache, "MESI Directory L2 Cache CMP")
AccessPermission getAccessPermission(Address addr) { AccessPermission getAccessPermission(Address addr) {
TBE tbe := L2_TBEs[addr]; TBE tbe := L2_TBEs[addr];
if(is_valid(tbe)) { if(is_valid(tbe)) {
DPRINTF(RubySlicc, "%s\n", L2Cache_State_to_permission(tbe.TBEState));
return L2Cache_State_to_permission(tbe.TBEState); return L2Cache_State_to_permission(tbe.TBEState);
} }
Entry cache_entry := getCacheEntry(addr); Entry cache_entry := getCacheEntry(addr);
if(is_valid(cache_entry)) { if(is_valid(cache_entry)) {
DPRINTF(RubySlicc, "%s\n", L2Cache_State_to_permission(cache_entry.CacheState));
return L2Cache_State_to_permission(cache_entry.CacheState); return L2Cache_State_to_permission(cache_entry.CacheState);
} }
DPRINTF(RubySlicc, "%s\n", AccessPermission:NotPresent);
return AccessPermission:NotPresent; return AccessPermission:NotPresent;
} }
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
return getCacheEntry(addr).DataBlk;
}
void setAccessPermission(Entry cache_entry, Address addr, State state) { void setAccessPermission(Entry cache_entry, Address addr, State state) {
if (is_valid(cache_entry)) { if (is_valid(cache_entry)) {
cache_entry.changePermission(L2Cache_State_to_permission(state)); cache_entry.changePermission(L2Cache_State_to_permission(state));

View file

@ -55,7 +55,7 @@ machine(Directory, "MESI_CMP_filter_directory protocol")
ID, AccessPermission:Busy, desc="Intermediate state for DMA_READ when in I"; ID, AccessPermission:Busy, desc="Intermediate state for DMA_READ when in I";
ID_W, AccessPermission:Busy, desc="Intermediate state for DMA_WRITE when in I"; ID_W, AccessPermission:Busy, desc="Intermediate state for DMA_WRITE when in I";
M, AccessPermission:Invalid, desc="memory copy may be stale, i.e. other modified copies may exist"; M, AccessPermission:Maybe_Stale, desc="memory copy may be stale, i.e. other modified copies may exist";
IM, AccessPermission:Busy, desc="Intermediate State I>M"; IM, AccessPermission:Busy, desc="Intermediate State I>M";
MI, AccessPermission:Busy, desc="Intermediate State M>I"; MI, AccessPermission:Busy, desc="Intermediate State M>I";
M_DRD, AccessPermission:Busy, desc="Intermediate State when there is a dma read"; M_DRD, AccessPermission:Busy, desc="Intermediate State when there is a dma read";
@ -147,10 +147,21 @@ machine(Directory, "MESI_CMP_filter_directory protocol")
AccessPermission getAccessPermission(Address addr) { AccessPermission getAccessPermission(Address addr) {
TBE tbe := TBEs[addr]; TBE tbe := TBEs[addr];
if(is_valid(tbe)) { if(is_valid(tbe)) {
DPRINTF(RubySlicc, "%s\n", Directory_State_to_permission(tbe.TBEState));
return Directory_State_to_permission(tbe.TBEState); return Directory_State_to_permission(tbe.TBEState);
} }
return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState); if(directory.isPresent(addr)) {
DPRINTF(RubySlicc, "%s\n", Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState));
return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState);
}
DPRINTF(RubySlicc, "%s\n", AccessPermission:NotPresent);
return AccessPermission:NotPresent;
}
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
return getDirectoryEntry(addr).DataBlk;
} }
void setAccessPermission(Address addr, State state) { void setAccessPermission(Address addr, State state) {

View file

@ -42,6 +42,10 @@ machine(DMA, "DMA Controller")
void setAccessPermission(Address addr, State state) { void setAccessPermission(Address addr, State state) {
} }
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
error("DMA does not support get data block.");
}
out_port(reqToDirectory_out, RequestMsg, reqToDirectory, desc="..."); out_port(reqToDirectory_out, RequestMsg, reqToDirectory, desc="...");
in_port(dmaRequestQueue_in, SequencerMsg, mandatoryQueue, desc="...") { in_port(dmaRequestQueue_in, SequencerMsg, mandatoryQueue, desc="...") {

View file

@ -140,6 +140,10 @@ machine(L1Cache, "MI Example L1 Cache")
} }
} }
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
return getCacheEntry(addr).DataBlk;
}
GenericMachineType getNondirectHitMachType(MachineID sender) { GenericMachineType getNondirectHitMachType(MachineID sender) {
if (machineIDToMachineType(sender) == MachineType:L1Cache) { if (machineIDToMachineType(sender) == MachineType:L1Cache) {
// //

View file

@ -122,7 +122,11 @@ machine(Directory, "Directory protocol")
return Directory_State_to_permission(tbe.TBEState); return Directory_State_to_permission(tbe.TBEState);
} }
return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState); if(directory.isPresent(addr)) {
return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState);
}
return AccessPermission:NotPresent;
} }
void setAccessPermission(Address addr, State state) { void setAccessPermission(Address addr, State state) {
@ -131,6 +135,10 @@ machine(Directory, "Directory protocol")
} }
} }
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
return getDirectoryEntry(addr).DataBlk;
}
// ** OUT_PORTS ** // ** OUT_PORTS **
out_port(forwardNetwork_out, RequestMsg, forwardFromDir); out_port(forwardNetwork_out, RequestMsg, forwardFromDir);
out_port(responseNetwork_out, ResponseMsg, responseFromDir); out_port(responseNetwork_out, ResponseMsg, responseFromDir);

View file

@ -37,6 +37,10 @@ machine(DMA, "DMA Controller")
void setAccessPermission(Address addr, State state) { void setAccessPermission(Address addr, State state) {
} }
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
error("DMA Controller does not support getDataBlock function.\n");
}
out_port(reqToDirectory_out, DMARequestMsg, reqToDirectory, desc="..."); out_port(reqToDirectory_out, DMARequestMsg, reqToDirectory, desc="...");
in_port(dmaRequestQueue_in, SequencerMsg, mandatoryQueue, desc="...") { in_port(dmaRequestQueue_in, SequencerMsg, mandatoryQueue, desc="...") {

View file

@ -197,14 +197,17 @@ machine(L1Cache, "Directory protocol")
AccessPermission getAccessPermission(Address addr) { AccessPermission getAccessPermission(Address addr) {
TBE tbe := TBEs[addr]; TBE tbe := TBEs[addr];
if(is_valid(tbe)) { if(is_valid(tbe)) {
DPRINTF(RubySlicc, "%s\n", L1Cache_State_to_permission(tbe.TBEState));
return L1Cache_State_to_permission(tbe.TBEState); return L1Cache_State_to_permission(tbe.TBEState);
} }
Entry cache_entry := getCacheEntry(addr); Entry cache_entry := getCacheEntry(addr);
if(is_valid(cache_entry)) { if(is_valid(cache_entry)) {
DPRINTF(RubySlicc, "%s\n", L1Cache_State_to_permission(cache_entry.CacheState));
return L1Cache_State_to_permission(cache_entry.CacheState); return L1Cache_State_to_permission(cache_entry.CacheState);
} }
DPRINTF(RubySlicc, "AccessPermission_NotPresent\n");
return AccessPermission:NotPresent; return AccessPermission:NotPresent;
} }
@ -214,6 +217,10 @@ machine(L1Cache, "Directory protocol")
} }
} }
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
return getCacheEntry(addr).DataBlk;
}
Event mandatory_request_type_to_event(RubyRequestType type) { Event mandatory_request_type_to_event(RubyRequestType type) {
if (type == RubyRequestType:LD) { if (type == RubyRequestType:LD) {
return Event:Load; return Event:Load;

View file

@ -56,12 +56,12 @@ machine(L2Cache, "Token protocol")
// Stable states // Stable states
NP, AccessPermission:Invalid, desc="Not Present"; NP, AccessPermission:Invalid, desc="Not Present";
I, AccessPermission:Invalid, desc="Invalid"; I, AccessPermission:Invalid, desc="Invalid";
ILS, AccessPermission:Busy, desc="Idle/NP, but local sharers exist"; ILS, AccessPermission:Invalid, desc="Idle/NP, but local sharers exist";
ILX, AccessPermission:Busy, desc="Idle/NP, but local exclusive exists"; ILX, AccessPermission:Invalid, desc="Idle/NP, but local exclusive exists";
ILO, AccessPermission:Busy, desc="Idle/NP, but local owner exists"; ILO, AccessPermission:Invalid, desc="Idle/NP, but local owner exists";
ILOX, AccessPermission:Busy, desc="Idle/NP, but local owner exists and chip is exclusive"; ILOX, AccessPermission:Invalid, desc="Idle/NP, but local owner exists and chip is exclusive";
ILOS, AccessPermission:Busy, desc="Idle/NP, but local owner exists and local sharers as well"; ILOS, AccessPermission:Invalid, desc="Idle/NP, but local owner exists and local sharers as well";
ILOSX, AccessPermission:Busy, desc="Idle/NP, but local owner exists, local sharers exist, chip is exclusive "; ILOSX, AccessPermission:Invalid, desc="Idle/NP, but local owner exists, local sharers exist, chip is exclusive ";
S, AccessPermission:Read_Only, desc="Shared, no local sharers"; S, AccessPermission:Read_Only, desc="Shared, no local sharers";
O, AccessPermission:Read_Only, desc="Owned, no local sharers"; O, AccessPermission:Read_Only, desc="Owned, no local sharers";
OLS, AccessPermission:Read_Only, desc="Owned with local sharers"; OLS, AccessPermission:Read_Only, desc="Owned with local sharers";
@ -502,14 +502,22 @@ machine(L2Cache, "Token protocol")
AccessPermission getAccessPermission(Address addr) { AccessPermission getAccessPermission(Address addr) {
TBE tbe := TBEs[addr]; TBE tbe := TBEs[addr];
if(is_valid(tbe)) { if(is_valid(tbe)) {
DPRINTF(RubySlicc, "%s\n", L2Cache_State_to_permission(tbe.TBEState));
return L2Cache_State_to_permission(tbe.TBEState); return L2Cache_State_to_permission(tbe.TBEState);
} }
Entry cache_entry := getCacheEntry(addr); Entry cache_entry := getCacheEntry(addr);
if(is_valid(cache_entry)) { if(is_valid(cache_entry)) {
DPRINTF(RubySlicc, "%s\n", L2Cache_State_to_permission(cache_entry.CacheState));
return L2Cache_State_to_permission(cache_entry.CacheState); return L2Cache_State_to_permission(cache_entry.CacheState);
} }
else if (localDirectory.isTagPresent(addr)) {
DPRINTF(RubySlicc, "%s\n", L2Cache_State_to_permission(localDirectory[addr].DirState));
return L2Cache_State_to_permission(localDirectory[addr].DirState);
}
DPRINTF(RubySlicc, "AccessPermission_NotPresent\n");
return AccessPermission:NotPresent; return AccessPermission:NotPresent;
} }
@ -519,6 +527,10 @@ machine(L2Cache, "Token protocol")
} }
} }
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
return getCacheEntry(addr).DataBlk;
}
MessageBuffer triggerQueue, ordered="true"; MessageBuffer triggerQueue, ordered="true";
out_port(globalRequestNetwork_out, RequestMsg, GlobalRequestFromL2Cache); out_port(globalRequestNetwork_out, RequestMsg, GlobalRequestFromL2Cache);

View file

@ -50,16 +50,16 @@ machine(Directory, "Directory protocol")
// STATES // STATES
state_declaration(State, desc="Directory states", default="Directory_State_I") { state_declaration(State, desc="Directory states", default="Directory_State_I") {
// Base states // Base states
I, AccessPermission:Invalid, desc="Invalid"; I, AccessPermission:Read_Write, desc="Invalid";
S, AccessPermission:Read_Only, desc="Shared"; S, AccessPermission:Read_Only, desc="Shared";
O, AccessPermission:Read_Only, desc="Owner"; O, AccessPermission:Maybe_Stale, desc="Owner";
M, AccessPermission:Read_Write, desc="Modified"; M, AccessPermission:Maybe_Stale, desc="Modified";
IS, AccessPermission:Busy, desc="Blocked, was in idle"; IS, AccessPermission:Busy, desc="Blocked, was in idle";
SS, AccessPermission:Read_Only, desc="Blocked, was in shared"; SS, AccessPermission:Read_Only, desc="Blocked, was in shared";
OO, AccessPermission:Read_Only, desc="Blocked, was in owned"; OO, AccessPermission:Busy, desc="Blocked, was in owned";
MO, AccessPermission:Read_Only, desc="Blocked, going to owner or maybe modified"; MO, AccessPermission:Busy, desc="Blocked, going to owner or maybe modified";
MM, AccessPermission:Read_Only, desc="Blocked, going to modified"; MM, AccessPermission:Busy, desc="Blocked, going to modified";
MM_DMA, AccessPermission:Busy, desc="Blocked, going to I"; MM_DMA, AccessPermission:Busy, desc="Blocked, going to I";
MI, AccessPermission:Busy, desc="Blocked on a writeback"; MI, AccessPermission:Busy, desc="Blocked on a writeback";
@ -173,9 +173,11 @@ machine(Directory, "Directory protocol")
AccessPermission getAccessPermission(Address addr) { AccessPermission getAccessPermission(Address addr) {
if (directory.isPresent(addr)) { if (directory.isPresent(addr)) {
DPRINTF(RubySlicc, "%s\n", Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState));
return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState); return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState);
} }
DPRINTF(RubySlicc, "AccessPermission_NotPresent\n");
return AccessPermission:NotPresent; return AccessPermission:NotPresent;
} }
@ -185,6 +187,10 @@ machine(Directory, "Directory protocol")
} }
} }
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
return getDirectoryEntry(addr).DataBlk;
}
// if no sharers, then directory can be considered both a sharer and exclusive w.r.t. coherence checking // if no sharers, then directory can be considered both a sharer and exclusive w.r.t. coherence checking
bool isBlockShared(Address addr) { bool isBlockShared(Address addr) {
if (directory.isPresent(addr)) { if (directory.isPresent(addr)) {

View file

@ -68,6 +68,10 @@ machine(DMA, "DMA Controller")
void setAccessPermission(Address addr, State state) { void setAccessPermission(Address addr, State state) {
} }
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
error("DMA Controller does not support getDataBlock().\n");
}
out_port(reqToDirectory_out, RequestMsg, reqToDir, desc="..."); out_port(reqToDirectory_out, RequestMsg, reqToDir, desc="...");
out_port(respToDirectory_out, ResponseMsg, respToDir, desc="..."); out_port(respToDirectory_out, ResponseMsg, respToDir, desc="...");
out_port(foo1_out, ResponseMsg, foo1, desc="..."); out_port(foo1_out, ResponseMsg, foo1, desc="...");

View file

@ -227,6 +227,10 @@ machine(L1Cache, "Token protocol")
return L1Icache_entry; return L1Icache_entry;
} }
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
return getCacheEntry(addr).DataBlk;
}
Entry getL1DCacheEntry(Address addr), return_by_pointer="yes" { Entry getL1DCacheEntry(Address addr), return_by_pointer="yes" {
Entry L1Dcache_entry := static_cast(Entry, "pointer", L1DcacheMemory.lookup(addr)); Entry L1Dcache_entry := static_cast(Entry, "pointer", L1DcacheMemory.lookup(addr));
return L1Dcache_entry; return L1Dcache_entry;

View file

@ -156,6 +156,10 @@ machine(L2Cache, "Token protocol")
return cache_entry; return cache_entry;
} }
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
return getCacheEntry(addr).DataBlk;
}
int getTokens(Entry cache_entry) { int getTokens(Entry cache_entry) {
if (is_valid(cache_entry)) { if (is_valid(cache_entry)) {
return cache_entry.Tokens; return cache_entry.Tokens;

View file

@ -55,7 +55,7 @@ machine(Directory, "Token protocol")
state_declaration(State, desc="Directory states", default="Directory_State_O") { state_declaration(State, desc="Directory states", default="Directory_State_O") {
// Base states // Base states
O, AccessPermission:Read_Only, desc="Owner, memory has valid data, but not necessarily all the tokens"; O, AccessPermission:Read_Only, desc="Owner, memory has valid data, but not necessarily all the tokens";
NO, AccessPermission:Invalid, desc="Not Owner"; NO, AccessPermission:Maybe_Stale, desc="Not Owner";
L, AccessPermission:Busy, desc="Locked"; L, AccessPermission:Busy, desc="Locked";
// Memory wait states - can block all messages including persistent requests // Memory wait states - can block all messages including persistent requests
@ -169,6 +169,10 @@ machine(Directory, "Token protocol")
return static_cast(Entry, directory[addr]); return static_cast(Entry, directory[addr]);
} }
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
return getDirectoryEntry(addr).DataBlk;
}
State getState(TBE tbe, Address addr) { State getState(TBE tbe, Address addr) {
if (is_valid(tbe)) { if (is_valid(tbe)) {
return tbe.TBEState; return tbe.TBEState;
@ -206,7 +210,13 @@ machine(Directory, "Token protocol")
return Directory_State_to_permission(tbe.TBEState); return Directory_State_to_permission(tbe.TBEState);
} }
return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState); if (directory.isPresent(addr)) {
DPRINTF(RubySlicc, "%s\n", Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState));
return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState);
}
DPRINTF(RubySlicc, "AccessPermission_NotPresent\n");
return AccessPermission:NotPresent;
} }
void setAccessPermission(Address addr, State state) { void setAccessPermission(Address addr, State state) {

View file

@ -70,6 +70,10 @@ machine(DMA, "DMA Controller")
void setAccessPermission(Address addr, State state) { void setAccessPermission(Address addr, State state) {
} }
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
error("DMA Controller does not support getDataBlock function.\n");
}
out_port(reqToDirectory_out, DMARequestMsg, reqToDirectory, desc="..."); out_port(reqToDirectory_out, DMARequestMsg, reqToDirectory, desc="...");
in_port(dmaRequestQueue_in, SequencerMsg, mandatoryQueue, desc="...") { in_port(dmaRequestQueue_in, SequencerMsg, mandatoryQueue, desc="...") {

View file

@ -189,6 +189,10 @@ machine(L1Cache, "AMD Hammer-like protocol")
return L1Icache_entry; return L1Icache_entry;
} }
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
return getCacheEntry(addr).DataBlk;
}
Entry getL2CacheEntry(Address address), return_by_pointer="yes" { Entry getL2CacheEntry(Address address), return_by_pointer="yes" {
Entry L2cache_entry := static_cast(Entry, "pointer", L2cacheMemory.lookup(address)); Entry L2cache_entry := static_cast(Entry, "pointer", L2cacheMemory.lookup(address));
return L2cache_entry; return L2cache_entry;

View file

@ -59,38 +59,38 @@ machine(Directory, "AMD Hammer-like protocol")
// STATES // STATES
state_declaration(State, desc="Directory states", default="Directory_State_E") { state_declaration(State, desc="Directory states", default="Directory_State_E") {
// Base states // Base states
NX, AccessPermission:Invalid, desc="Not Owner, probe filter entry exists, block in O at Owner"; NX, AccessPermission:Maybe_Stale, desc="Not Owner, probe filter entry exists, block in O at Owner";
NO, AccessPermission:Invalid, desc="Not Owner, probe filter entry exists, block in E/M at Owner"; NO, AccessPermission:Maybe_Stale, desc="Not Owner, probe filter entry exists, block in E/M at Owner";
S, AccessPermission:Read_Only, desc="Data clean, probe filter entry exists pointing to the current owner"; S, AccessPermission:Read_Only, desc="Data clean, probe filter entry exists pointing to the current owner";
O, AccessPermission:Read_Only, desc="Data clean, probe filter entry exists"; O, AccessPermission:Read_Only, desc="Data clean, probe filter entry exists";
E, AccessPermission:Read_Write, desc="Exclusive Owner, no probe filter entry"; E, AccessPermission:Read_Write, desc="Exclusive Owner, no probe filter entry";
O_R, AccessPermission:Read_Only, desc="Was data Owner, replacing probe filter entry"; O_R, AccessPermission:Read_Only, desc="Was data Owner, replacing probe filter entry";
S_R, AccessPermission:Read_Only, desc="Was Not Owner or Sharer, replacing probe filter entry"; S_R, AccessPermission:Read_Only, desc="Was Not Owner or Sharer, replacing probe filter entry";
NO_R, AccessPermission:Invalid, desc="Was Not Owner or Sharer, replacing probe filter entry"; NO_R, AccessPermission:Busy, desc="Was Not Owner or Sharer, replacing probe filter entry";
NO_B, AccessPermission:Invalid, "NO^B", desc="Not Owner, Blocked"; NO_B, AccessPermission:Busy, "NO^B", desc="Not Owner, Blocked";
NO_B_X, AccessPermission:Invalid, "NO^B", desc="Not Owner, Blocked, next queued request GETX"; NO_B_X, AccessPermission:Busy, "NO^B", desc="Not Owner, Blocked, next queued request GETX";
NO_B_S, AccessPermission:Invalid, "NO^B", desc="Not Owner, Blocked, next queued request GETS"; NO_B_S, AccessPermission:Busy, "NO^B", desc="Not Owner, Blocked, next queued request GETS";
NO_B_S_W, AccessPermission:Invalid, "NO^B", desc="Not Owner, Blocked, forwarded merged GETS, waiting for responses"; NO_B_S_W, AccessPermission:Busy, "NO^B", desc="Not Owner, Blocked, forwarded merged GETS, waiting for responses";
O_B, AccessPermission:Invalid, "O^B", desc="Owner, Blocked"; O_B, AccessPermission:Busy, "O^B", desc="Owner, Blocked";
NO_B_W, AccessPermission:Invalid, desc="Not Owner, Blocked, waiting for Dram"; NO_B_W, AccessPermission:Busy, desc="Not Owner, Blocked, waiting for Dram";
O_B_W, AccessPermission:Invalid, desc="Owner, Blocked, waiting for Dram"; O_B_W, AccessPermission:Busy, desc="Owner, Blocked, waiting for Dram";
NO_W, AccessPermission:Invalid, desc="Not Owner, waiting for Dram"; NO_W, AccessPermission:Busy, desc="Not Owner, waiting for Dram";
O_W, AccessPermission:Invalid, desc="Owner, waiting for Dram"; O_W, AccessPermission:Busy, desc="Owner, waiting for Dram";
NO_DW_B_W, AccessPermission:Invalid, desc="Not Owner, Dma Write waiting for Dram and cache responses"; NO_DW_B_W, AccessPermission:Busy, desc="Not Owner, Dma Write waiting for Dram and cache responses";
NO_DR_B_W, AccessPermission:Invalid, desc="Not Owner, Dma Read waiting for Dram and cache responses"; NO_DR_B_W, AccessPermission:Busy, desc="Not Owner, Dma Read waiting for Dram and cache responses";
NO_DR_B_D, AccessPermission:Invalid, desc="Not Owner, Dma Read waiting for cache responses including dirty data"; NO_DR_B_D, AccessPermission:Busy, desc="Not Owner, Dma Read waiting for cache responses including dirty data";
NO_DR_B, AccessPermission:Invalid, desc="Not Owner, Dma Read waiting for cache responses"; NO_DR_B, AccessPermission:Busy, desc="Not Owner, Dma Read waiting for cache responses";
NO_DW_W, AccessPermission:Invalid, desc="Not Owner, Dma Write waiting for Dram"; NO_DW_W, AccessPermission:Busy, desc="Not Owner, Dma Write waiting for Dram";
O_DR_B_W, AccessPermission:Invalid, desc="Owner, Dma Read waiting for Dram and cache responses"; O_DR_B_W, AccessPermission:Busy, desc="Owner, Dma Read waiting for Dram and cache responses";
O_DR_B, AccessPermission:Invalid, desc="Owner, Dma Read waiting for cache responses"; O_DR_B, AccessPermission:Busy, desc="Owner, Dma Read waiting for cache responses";
WB, AccessPermission:Invalid, desc="Blocked on a writeback"; WB, AccessPermission:Busy, desc="Blocked on a writeback";
WB_O_W, AccessPermission:Invalid, desc="Blocked on memory write, will go to O"; WB_O_W, AccessPermission:Busy, desc="Blocked on memory write, will go to O";
WB_E_W, AccessPermission:Invalid, desc="Blocked on memory write, will go to E"; WB_E_W, AccessPermission:Busy, desc="Blocked on memory write, will go to E";
NO_F, AccessPermission:Invalid, desc="Blocked on a flush"; NO_F, AccessPermission:Busy, desc="Blocked on a flush";
NO_F_W, AccessPermission:Invalid, desc="Not Owner, Blocked, waiting for Dram"; NO_F_W, AccessPermission:Busy, desc="Not Owner, Blocked, waiting for Dram";
} }
// Events // Events
@ -190,6 +190,10 @@ machine(Directory, "AMD Hammer-like protocol")
return static_cast(Entry, directory[addr]); return static_cast(Entry, directory[addr]);
} }
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
return getDirectoryEntry(addr).DataBlk;
}
PfEntry getProbeFilterEntry(Address addr), return_by_pointer="yes" { PfEntry getProbeFilterEntry(Address addr), return_by_pointer="yes" {
if (probe_filter_enabled || full_bit_dir_enabled) { if (probe_filter_enabled || full_bit_dir_enabled) {
PfEntry pfEntry := static_cast(PfEntry, "pointer", probeFilter.lookup(addr)); PfEntry pfEntry := static_cast(PfEntry, "pointer", probeFilter.lookup(addr));
@ -239,7 +243,11 @@ machine(Directory, "AMD Hammer-like protocol")
return Directory_State_to_permission(tbe.TBEState); return Directory_State_to_permission(tbe.TBEState);
} }
return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState); if(directory.isPresent(addr)) {
return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState);
}
return AccessPermission:NotPresent;
} }
void setAccessPermission(PfEntry pf_entry, Address addr, State state) { void setAccessPermission(PfEntry pf_entry, Address addr, State state) {

View file

@ -67,6 +67,10 @@ machine(DMA, "DMA Controller")
void setAccessPermission(Address addr, State state) { void setAccessPermission(Address addr, State state) {
} }
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
error("DMA Controller does not support getDataBlock function.\n");
}
out_port(reqToDirectory_out, DMARequestMsg, reqToDirectory, desc="..."); out_port(reqToDirectory_out, DMARequestMsg, reqToDirectory, desc="...");
in_port(dmaRequestQueue_in, SequencerMsg, mandatoryQueue, desc="...") { in_port(dmaRequestQueue_in, SequencerMsg, mandatoryQueue, desc="...") {

View file

@ -57,6 +57,13 @@ enumeration(AccessPermission, desc="...", default="AccessPermission_NotPresent")
Read_Only, desc="block is Read Only (modulo functional writes)"; Read_Only, desc="block is Read Only (modulo functional writes)";
Read_Write, desc="block is Read/Write"; Read_Write, desc="block is Read/Write";
// Possibly Invalid data
// The maybe stale permission indicates that accordingly to the protocol,
// there is no guarantee the block contains valid data. However, functional
// writes should update the block because a dataless PUT request may
// revalidate the block's data.
Maybe_Stale, desc="block can be stale or revalidated by a dataless PUT";
// Invalid data // Invalid data
Invalid, desc="block is in an Invalid base state"; Invalid, desc="block is in an Invalid base state";
NotPresent, desc="block is NotPresent"; NotPresent, desc="block is NotPresent";

View file

@ -48,6 +48,7 @@ Network::Network(const Params *p)
// Initialize the controller's network pointers // Initialize the controller's network pointers
m_topology_ptr->initNetworkPtr(this); m_topology_ptr->initNetworkPtr(this);
p->ruby_system->registerNetwork(this);
} }
void void

View file

@ -48,3 +48,4 @@ class RubyNetwork(SimObject):
number_of_virtual_networks = Param.Int(10, ""); number_of_virtual_networks = Param.Int(10, "");
topology = Param.Topology(""); topology = Param.Topology("");
control_msg_size = Param.Int(8, ""); control_msg_size = Param.Int(8, "");
ruby_system = Param.RubySystem("");

View file

@ -92,6 +92,8 @@ Profiler::Profiler(const Params *p)
m_inst_profiler_ptr->setHotLines(m_hot_lines); m_inst_profiler_ptr->setHotLines(m_hot_lines);
m_inst_profiler_ptr->setAllInstructions(m_all_instructions); m_inst_profiler_ptr->setAllInstructions(m_all_instructions);
} }
p->ruby_system->registerProfiler(this);
} }
Profiler::~Profiler() Profiler::~Profiler()

View file

@ -36,3 +36,4 @@ class RubyProfiler(SimObject):
hot_lines = Param.Bool(False, "") hot_lines = Param.Bool(False, "")
all_instructions = Param.Bool(False, "") all_instructions = Param.Bool(False, "")
num_of_sequencers = Param.Int("") num_of_sequencers = Param.Int("")
ruby_system = Param.RubySystem("")

View file

@ -40,7 +40,7 @@ Tracer::Tracer(const Params *p)
m_enabled = false; m_enabled = false;
m_warmup_length = p->warmup_length; m_warmup_length = p->warmup_length;
assert(m_warmup_length > 0); assert(m_warmup_length > 0);
RubySystem::m_tracer_ptr = this; p->ruby_system->registerTracer(this);
} }
void void

View file

@ -34,3 +34,4 @@ class RubyTracer(SimObject):
type = 'RubyTracer' type = 'RubyTracer'
cxx_class = 'Tracer' cxx_class = 'Tracer'
warmup_length = Param.Int(100000, "") warmup_length = Param.Int(100000, "")
ruby_system = Param.RubySystem("")

View file

@ -36,7 +36,9 @@
#include "mem/protocol/MachineType.hh" #include "mem/protocol/MachineType.hh"
#include "mem/ruby/common/Address.hh" #include "mem/ruby/common/Address.hh"
#include "mem/ruby/common/Consumer.hh" #include "mem/ruby/common/Consumer.hh"
#include "mem/ruby/common/DataBlock.hh"
#include "mem/ruby/network/Network.hh" #include "mem/ruby/network/Network.hh"
#include "mem/ruby/system/System.hh"
#include "params/RubyController.hh" #include "params/RubyController.hh"
#include "sim/sim_object.hh" #include "sim/sim_object.hh"
@ -47,7 +49,7 @@ class AbstractController : public SimObject, public Consumer
{ {
public: public:
typedef RubyControllerParams Params; typedef RubyControllerParams Params;
AbstractController(const Params *p) : SimObject(p) {} AbstractController(const Params *p);
const Params *params() const { return (const Params *)_params; } const Params *params() const { return (const Params *)_params; }
// returns the number of controllers created of the specific subtype // returns the number of controllers created of the specific subtype
@ -61,6 +63,8 @@ class AbstractController : public SimObject, public Consumer
virtual void blockOnQueue(Address, MessageBuffer*) = 0; virtual void blockOnQueue(Address, MessageBuffer*) = 0;
virtual void unblock(Address) = 0; virtual void unblock(Address) = 0;
virtual void initNetworkPtr(Network* net_ptr) = 0; virtual void initNetworkPtr(Network* net_ptr) = 0;
virtual AccessPermission getAccessPermission(Address addr) = 0;
virtual DataBlock& getDataBlock(Address addr) = 0;
virtual void print(std::ostream & out) const = 0; virtual void print(std::ostream & out) const = 0;
virtual void printStats(std::ostream & out) const = 0; virtual void printStats(std::ostream & out) const = 0;
@ -68,9 +72,6 @@ class AbstractController : public SimObject, public Consumer
virtual void wakeup() = 0; virtual void wakeup() = 0;
// virtual void dumpStats(std::ostream & out) = 0; // virtual void dumpStats(std::ostream & out) = 0;
virtual void clearStats() = 0; virtual void clearStats() = 0;
private:
virtual AccessPermission getAccessPermission(Address addr) = 0;
}; };
#endif // __MEM_RUBY_SLICC_INTERFACE_ABSTRACTCONTROLLER_HH__ #endif // __MEM_RUBY_SLICC_INTERFACE_ABSTRACTCONTROLLER_HH__

View file

@ -41,3 +41,4 @@ class RubyController(SimObject):
buffer_size = Param.Int(0, "max buffer size 0 means infinite") buffer_size = Param.Int(0, "max buffer size 0 means infinite")
recycle_latency = Param.Int(10, "") recycle_latency = Param.Int(10, "")
number_of_TBEs = Param.Int(256, "") number_of_TBEs = Param.Int(256, "")
ruby_system = Param.RubySystem("");

View file

@ -35,6 +35,7 @@ if not env['RUBY']:
SimObject('Controller.py') SimObject('Controller.py')
Source('AbstractController.cc')
Source('AbstractEntry.cc') Source('AbstractEntry.cc')
Source('AbstractCacheEntry.cc') Source('AbstractCacheEntry.cc')
Source('RubyRequest.cc') Source('RubyRequest.cc')

View file

@ -1,41 +0,0 @@
# Copyright (c) 2009 Advanced Micro Devices, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Steve Reinhardt
# Brad Beckmann
from m5.params import *
from m5.SimObject import SimObject
from Controller import RubyController
class RubyCache(SimObject):
type = 'RubyCache'
cxx_class = 'CacheMemory'
size = Param.MemorySize("capacity in bytes");
latency = Param.Int("");
assoc = Param.Int("");
replacement_policy = Param.String("PSEUDO_LRU", "");
start_index_bit = Param.Int(6, "index start, default 6 for 64-byte line");

View file

@ -156,7 +156,7 @@ DirectoryMemory::lookup(PhysAddress address)
assert(isPresent(address)); assert(isPresent(address));
Directory_Entry* entry; Directory_Entry* entry;
uint64 idx; uint64 idx;
DPRINTF(RubyCache, "address: %s\n", address); DPRINTF(RubyCache, "Looking up address: %s\n", address);
if (m_use_map) { if (m_use_map) {
if (m_sparseMemory->exist(address)) { if (m_sparseMemory->exist(address)) {
@ -166,6 +166,7 @@ DirectoryMemory::lookup(PhysAddress address)
// Note: SparseMemory internally creates a new Directory Entry // Note: SparseMemory internally creates a new Directory Entry
m_sparseMemory->add(address); m_sparseMemory->add(address);
entry = m_sparseMemory->lookup(address); entry = m_sparseMemory->lookup(address);
entry->changePermission(AccessPermission_Read_Write);
} }
} else { } else {
idx = mapAddressToLocalIdx(address); idx = mapAddressToLocalIdx(address);
@ -175,6 +176,7 @@ DirectoryMemory::lookup(PhysAddress address)
if (entry == NULL) { if (entry == NULL) {
entry = new Directory_Entry(); entry = new Directory_Entry();
entry->getDataBlk().assign(m_ram->getBlockPtr(address)); entry->getDataBlk().assign(m_ram->getBlockPtr(address));
entry->changePermission(AccessPermission_Read_Only);
m_entries[idx] = entry; m_entries[idx] = entry;
} }
} }

View file

@ -1,43 +0,0 @@
# Copyright (c) 2009 Advanced Micro Devices, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Steve Reinhardt
# Brad Beckmann
from m5.params import *
from m5.proxy import *
from m5.SimObject import SimObject
class RubyDirectoryMemory(SimObject):
type = 'RubyDirectoryMemory'
cxx_class = 'DirectoryMemory'
version = Param.Int(0, "")
size = Param.MemorySize("1GB", "capacity in bytes")
use_map = Param.Bool(False, "enable sparse memory")
map_levels = Param.Int(4, "sparse memory map levels")
# the default value of the numa high bit is specified in the command line
# option and must be passed into the directory memory sim object
numa_high_bit = Param.Int("numa high bit")

View file

@ -31,8 +31,8 @@
#include "arch/x86/insts/microldstop.hh" #include "arch/x86/insts/microldstop.hh"
#endif // X86_ISA #endif // X86_ISA
#include "cpu/testers/rubytest/RubyTester.hh" #include "cpu/testers/rubytest/RubyTester.hh"
#include "debug/MemoryAccess.hh"
#include "debug/Ruby.hh" #include "debug/Ruby.hh"
#include "mem/protocol/AccessPermission.hh"
#include "mem/ruby/slicc_interface/AbstractController.hh" #include "mem/ruby/slicc_interface/AbstractController.hh"
#include "mem/ruby/system/RubyPort.hh" #include "mem/ruby/system/RubyPort.hh"
#include "mem/physical.hh" #include "mem/physical.hh"
@ -54,6 +54,8 @@ RubyPort::RubyPort(const Params *p)
m_usingRubyTester = p->using_ruby_tester; m_usingRubyTester = p->using_ruby_tester;
access_phys_mem = p->access_phys_mem; access_phys_mem = p->access_phys_mem;
ruby_system = p->ruby_system;
} }
void void
@ -68,7 +70,7 @@ RubyPort::getPort(const std::string &if_name, int idx)
{ {
if (if_name == "port") { if (if_name == "port") {
return new M5Port(csprintf("%s-port%d", name(), idx), this, return new M5Port(csprintf("%s-port%d", name(), idx), this,
access_phys_mem); ruby_system, access_phys_mem);
} }
if (if_name == "pio_port") { if (if_name == "pio_port") {
@ -85,7 +87,7 @@ RubyPort::getPort(const std::string &if_name, int idx)
assert (physMemPort == NULL); assert (physMemPort == NULL);
physMemPort = new M5Port(csprintf("%s-physMemPort", name()), this, physMemPort = new M5Port(csprintf("%s-physMemPort", name()), this,
access_phys_mem); ruby_system, access_phys_mem);
return physMemPort; return physMemPort;
} }
@ -109,12 +111,13 @@ RubyPort::PioPort::PioPort(const std::string &_name,
ruby_port = _port; ruby_port = _port;
} }
RubyPort::M5Port::M5Port(const std::string &_name, RubyPort::M5Port::M5Port(const std::string &_name, RubyPort *_port,
RubyPort *_port, bool _access_phys_mem) RubySystem *_system, bool _access_phys_mem)
: SimpleTimingPort(_name, _port) : SimpleTimingPort(_name, _port)
{ {
DPRINTF(RubyPort, "creating port from ruby sequcner to cpu %s\n", _name); DPRINTF(RubyPort, "creating port from ruby sequcner to cpu %s\n", _name);
ruby_port = _port; ruby_port = _port;
ruby_system = _system;
_onRetryList = false; _onRetryList = false;
access_phys_mem = _access_phys_mem; access_phys_mem = _access_phys_mem;
} }
@ -289,6 +292,168 @@ RubyPort::M5Port::recvTiming(PacketPtr pkt)
return false; return false;
} }
bool
RubyPort::M5Port::doFunctionalRead(PacketPtr pkt)
{
Address address(pkt->getAddr());
Address line_address(address);
line_address.makeLineAddress();
AccessPermission accessPerm = AccessPermission_NotPresent;
int num_controllers = ruby_system->m_abs_cntrl_vec.size();
// In this loop, we try to figure which controller has a read only or
// a read write copy of the given address. Any valid copy would suffice
// for a functional read.
DPRINTF(RubyPort, "Functional Read request for %s\n",address);
for(int i = 0;i < num_controllers;++i)
{
accessPerm = ruby_system->m_abs_cntrl_vec[i]
->getAccessPermission(line_address);
if(accessPerm == AccessPermission_Read_Only ||
accessPerm == AccessPermission_Read_Write)
{
unsigned startByte = address.getAddress() - line_address.getAddress();
uint8* data = pkt->getPtr<uint8_t>(true);
unsigned int size_in_bytes = pkt->getSize();
DataBlock& block = ruby_system->m_abs_cntrl_vec[i]
->getDataBlock(line_address);
DPRINTF(RubyPort, "reading from %s block %s\n",
ruby_system->m_abs_cntrl_vec[i]->name(), block);
for (unsigned i = 0; i < size_in_bytes; ++i)
{
data[i] = block.getByte(i + startByte);
}
return true;
}
}
return false;
}
bool
RubyPort::M5Port::doFunctionalWrite(PacketPtr pkt)
{
Address addr(pkt->getAddr());
Address line_addr = line_address(addr);
AccessPermission accessPerm = AccessPermission_NotPresent;
int num_controllers = ruby_system->m_abs_cntrl_vec.size();
DPRINTF(RubyPort, "Functional Write request for %s\n",addr);
unsigned int num_ro = 0;
unsigned int num_rw = 0;
unsigned int num_busy = 0;
// In this loop we count the number of controllers that have the given
// address in read only, read write and busy states.
for(int i = 0;i < num_controllers;++i)
{
accessPerm = ruby_system->m_abs_cntrl_vec[i]->
getAccessPermission(line_addr);
if(accessPerm == AccessPermission_Read_Only) num_ro++;
else if(accessPerm == AccessPermission_Read_Write) num_rw++;
else if(accessPerm == AccessPermission_Busy) num_busy++;
}
// If the number of read write copies is more than 1, then there is bug in
// coherence protocol. Otherwise, if all copies are in stable states, i.e.
// num_busy == 0, we update all the copies. If there is at least one copy
// in busy state, then we check if there is read write copy. If yes, then
// also we let the access go through.
DPRINTF(RubyPort, "num_busy = %d, num_ro = %d, num_rw = %d\n",
num_busy, num_ro, num_rw);
assert(num_rw <= 1);
if((num_busy == 0 && num_ro > 0) || num_rw == 1)
{
uint8* data = pkt->getPtr<uint8_t>(true);
unsigned int size_in_bytes = pkt->getSize();
unsigned startByte = addr.getAddress() - line_addr.getAddress();
for(int i = 0; i < num_controllers;++i)
{
accessPerm = ruby_system->m_abs_cntrl_vec[i]->
getAccessPermission(line_addr);
if(accessPerm == AccessPermission_Read_Only ||
accessPerm == AccessPermission_Read_Write||
accessPerm == AccessPermission_Maybe_Stale)
{
DataBlock& block = ruby_system->m_abs_cntrl_vec[i]
->getDataBlock(line_addr);
DPRINTF(RubyPort, "%s\n",block);
for (unsigned i = 0; i < size_in_bytes; ++i)
{
block.setByte(i + startByte, data[i]);
}
DPRINTF(RubyPort, "%s\n",block);
}
}
return true;
}
return false;
}
void
RubyPort::M5Port::recvFunctional(PacketPtr pkt)
{
DPRINTF(RubyPort, "Functional access caught for address %#x\n",
pkt->getAddr());
// Check for pio requests and directly send them to the dedicated
// pio port.
if (!isPhysMemAddress(pkt->getAddr())) {
assert(ruby_port->pio_port != NULL);
DPRINTF(RubyPort, "Request for address 0x%#x is a pio request\n",
pkt->getAddr());
panic("RubyPort::PioPort::recvFunctional() not implemented!\n");
}
assert(pkt->getAddr() + pkt->getSize() <=
line_address(Address(pkt->getAddr())).getAddress() +
RubySystem::getBlockSizeBytes());
bool accessSucceeded = false;
bool needsResponse = pkt->needsResponse();
// Do the functional access on ruby memory
if (pkt->isRead()) {
accessSucceeded = doFunctionalRead(pkt);
} else if (pkt->isWrite()) {
accessSucceeded = doFunctionalWrite(pkt);
} else {
panic("RubyPort: unsupported functional command %s\n",
pkt->cmdString());
}
// Unless the requester explicitly said otherwise, generate an error if
// the functional request failed
if (!accessSucceeded && !pkt->suppressFuncError()) {
fatal("Ruby functional %s failed for address %#x\n",
pkt->isWrite() ? "write" : "read", pkt->getAddr());
}
if (access_phys_mem) {
// The attached physmem contains the official version of data.
// The following command performs the real functional access.
// This line should be removed once Ruby supplies the official version
// of data.
ruby_port->physMemPort->sendFunctional(pkt);
}
// turn packet around to go back to requester if response expected
if (needsResponse) {
pkt->setFunctionalResponseStatus(accessSucceeded);
DPRINTF(RubyPort, "Sending packet back over port\n");
sendFunctional(pkt);
}
DPRINTF(RubyPort, "Functional access %s!\n",
accessSucceeded ? "successful":"failed");
}
void void
RubyPort::ruby_hit_callback(PacketPtr pkt) RubyPort::ruby_hit_callback(PacketPtr pkt)
{ {

View file

@ -50,12 +50,13 @@ class RubyPort : public MemObject
{ {
private: private:
RubyPort *ruby_port; RubyPort *ruby_port;
RubySystem* ruby_system;
bool _onRetryList; bool _onRetryList;
bool access_phys_mem; bool access_phys_mem;
public: public:
M5Port(const std::string &_name, RubyPort *_port, M5Port(const std::string &_name, RubyPort *_port,
bool _access_phys_mem); RubySystem*_system, bool _access_phys_mem);
bool sendTiming(PacketPtr pkt); bool sendTiming(PacketPtr pkt);
void hitCallback(PacketPtr pkt); void hitCallback(PacketPtr pkt);
unsigned deviceBlockSize() const; unsigned deviceBlockSize() const;
@ -69,9 +70,12 @@ class RubyPort : public MemObject
protected: protected:
virtual bool recvTiming(PacketPtr pkt); virtual bool recvTiming(PacketPtr pkt);
virtual Tick recvAtomic(PacketPtr pkt); virtual Tick recvAtomic(PacketPtr pkt);
virtual void recvFunctional(PacketPtr pkt);
private: private:
bool isPhysMemAddress(Addr addr); bool isPhysMemAddress(Addr addr);
bool doFunctionalRead(PacketPtr pkt);
bool doFunctionalWrite(PacketPtr pkt);
}; };
friend class M5Port; friend class M5Port;
@ -145,6 +149,7 @@ class RubyPort : public MemObject
M5Port* physMemPort; M5Port* physMemPort;
PhysicalMemory* physmem; PhysicalMemory* physmem;
RubySystem* ruby_system;
// //
// Based on similar code in the M5 bus. Stores pointers to those ports // Based on similar code in the M5 bus. Stores pointers to those ports

View file

@ -39,9 +39,6 @@ class RubySystem(SimObject):
block_size_bytes = Param.Int(64, block_size_bytes = Param.Int(64,
"default cache block size; must be a power of two"); "default cache block size; must be a power of two");
mem_size = Param.MemorySize("total memory size of the system"); mem_size = Param.MemorySize("total memory size of the system");
network = Param.RubyNetwork("")
profiler = Param.RubyProfiler("");
tracer = Param.RubyTracer("");
stats_filename = Param.String("ruby.stats", stats_filename = Param.String("ruby.stats",
"file to which ruby dumps its stats") "file to which ruby dumps its stats")
no_mem_vec = Param.Bool(False, "do not allocate Ruby's mem vector"); no_mem_vec = Param.Bool(False, "do not allocate Ruby's mem vector");

View file

@ -33,9 +33,8 @@ Import('*')
if not env['RUBY']: if not env['RUBY']:
Return() Return()
SimObject('Cache.py') SimObject('AbstractMemory.py')
SimObject('Sequencer.py') SimObject('Sequencer.py')
SimObject('DirectoryMemory.py')
SimObject('MemoryControl.py') SimObject('MemoryControl.py')
SimObject('WireBuffer.py') SimObject('WireBuffer.py')
SimObject('RubySystem.py') SimObject('RubySystem.py')

View file

@ -43,6 +43,7 @@ class RubyPort(MemObject):
using_network_tester = Param.Bool(False, "") using_network_tester = Param.Bool(False, "")
access_phys_mem = Param.Bool(True, access_phys_mem = Param.Bool(True,
"should the rubyport atomically update phys_mem") "should the rubyport atomically update phys_mem")
ruby_system = Param.RubySystem("")
class RubySequencer(RubyPort): class RubySequencer(RubyPort):
type = 'RubySequencer' type = 'RubySequencer'

View file

@ -74,10 +74,6 @@ RubySystem::RubySystem(const Params *p)
m_memory_size_bits = floorLog2(m_memory_size_bytes); m_memory_size_bits = floorLog2(m_memory_size_bytes);
} }
m_network_ptr = p->network;
m_profiler_ptr = p->profiler;
m_tracer_ptr = p->tracer;
g_eventQueue_ptr = new RubyEventQueue(p->eventq, m_clock); g_eventQueue_ptr = new RubyEventQueue(p->eventq, m_clock);
g_system_ptr = this; g_system_ptr = this;
if (p->no_mem_vec) { if (p->no_mem_vec) {
@ -100,6 +96,30 @@ RubySystem::init()
m_profiler_ptr->clearStats(); m_profiler_ptr->clearStats();
} }
void
RubySystem::registerNetwork(Network* network_ptr)
{
m_network_ptr = network_ptr;
}
void
RubySystem::registerProfiler(Profiler* profiler_ptr)
{
m_profiler_ptr = profiler_ptr;
}
void
RubySystem::registerTracer(Tracer* tracer_ptr)
{
m_tracer_ptr = tracer_ptr;
}
void
RubySystem::registerAbstractController(AbstractController* cntrl)
{
m_abs_cntrl_vec.push_back(cntrl);
}
RubySystem::~RubySystem() RubySystem::~RubySystem()
{ {
delete m_network_ptr; delete m_network_ptr;

View file

@ -39,9 +39,12 @@
#include "mem/ruby/common/Global.hh" #include "mem/ruby/common/Global.hh"
#include "mem/ruby/eventqueue/RubyEventQueue.hh" #include "mem/ruby/eventqueue/RubyEventQueue.hh"
#include "mem/ruby/system/RubyPort.hh" #include "mem/ruby/system/RubyPort.hh"
#include "mem/ruby/slicc_interface/AbstractController.hh"
#include "params/RubySystem.hh" #include "params/RubySystem.hh"
#include "sim/sim_object.hh" #include "sim/sim_object.hh"
class AbstractController;
class AbstractMemory;
class CacheRecorder; class CacheRecorder;
class MemoryVector; class MemoryVector;
class Network; class Network;
@ -128,6 +131,12 @@ class RubySystem : public SimObject
virtual void serialize(std::ostream &os); virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section); virtual void unserialize(Checkpoint *cp, const std::string &section);
void registerNetwork(Network*);
void registerProfiler(Profiler*);
void registerTracer(Tracer*);
void registerAbstractMemory(AbstractMemory*);
void registerAbstractController(AbstractController*);
private: private:
// Private copy constructor and assignment operator // Private copy constructor and assignment operator
RubySystem(const RubySystem& obj); RubySystem(const RubySystem& obj);
@ -153,6 +162,7 @@ class RubySystem : public SimObject
static Profiler* m_profiler_ptr; static Profiler* m_profiler_ptr;
static Tracer* m_tracer_ptr; static Tracer* m_tracer_ptr;
static MemoryVector* m_mem_vec_ptr; static MemoryVector* m_mem_vec_ptr;
std::vector<AbstractController*> m_abs_cntrl_vec;
}; };
inline std::ostream& inline std::ostream&
@ -180,6 +190,3 @@ class RubyExitCallback : public Callback
}; };
#endif // __MEM_RUBY_SYSTEM_SYSTEM_HH__ #endif // __MEM_RUBY_SYSTEM_SYSTEM_HH__

View file

@ -49,10 +49,15 @@ class MemberExprAST(ExprAST):
code.fix(fix) code.fix(fix)
# Verify that this is a valid field name for this type # Verify that this is a valid field name for this type
if self.field not in return_type.data_members: if self.field in return_type.data_members:
self.error("Invalid object field: " + # Return the type of the field
"Type '%s' does not have data member %s" % \ return return_type.data_members[self.field].type
(return_type, self.field)) else:
if "interface" in return_type:
# Return the type of the field interface_type = self.symtab.find(return_type["interface"]);
return return_type.data_members[self.field].type if self.field in interface_type.data_members:
# Return the type of the field
return interface_type.data_members[self.field].type
self.error("Invalid object field: " +
"Type '%s' does not have data member %s" % \
(return_type, self.field))

View file

@ -73,8 +73,8 @@ options.l3_assoc=2
nb_cores = 8 nb_cores = 8
# ruby does not support atomic, functional, or uncacheable accesses # ruby does not support atomic, functional, or uncacheable accesses
cpus = [ MemTest(atomic=False, percent_functional=0, \ cpus = [ MemTest(atomic=False, percent_functional=50,
percent_uncacheable=0) \ percent_uncacheable=0, suppress_func_warnings=True) \
for i in xrange(nb_cores) ] for i in xrange(nb_cores) ]
# overwrite options.num_cpus with the nb_cores value # overwrite options.num_cpus with the nb_cores value
@ -85,7 +85,7 @@ system = System(cpu = cpus,
funcmem = PhysicalMemory(), funcmem = PhysicalMemory(),
physmem = PhysicalMemory()) physmem = PhysicalMemory())
system.ruby = Ruby.create_system(options, system) Ruby.create_system(options, system)
assert(len(cpus) == len(system.ruby._cpu_ruby_ports)) assert(len(cpus) == len(system.ruby._cpu_ruby_ports))
@ -103,6 +103,12 @@ for (i, ruby_port) in enumerate(system.ruby._cpu_ruby_ports):
# #
ruby_port.deadlock_threshold = 1000000 ruby_port.deadlock_threshold = 1000000
#
# Ruby doesn't need the backing image of memory when running with
# the tester.
#
ruby_port.access_phys_mem = False
# ----------------------- # -----------------------
# run simulation # run simulation
# ----------------------- # -----------------------

View file

@ -77,7 +77,7 @@ tester = RubyTester(checks_to_complete = 100, wakeup_frequency = 10)
system = System(tester = tester, physmem = PhysicalMemory()) system = System(tester = tester, physmem = PhysicalMemory())
system.ruby = Ruby.create_system(options, system) Ruby.create_system(options, system)
assert(options.num_cpus == len(system.ruby._cpu_ruby_ports)) assert(options.num_cpus == len(system.ruby._cpu_ruby_ports))
@ -99,6 +99,12 @@ for ruby_port in system.ruby._cpu_ruby_ports:
# #
ruby_port.using_ruby_tester = True ruby_port.using_ruby_tester = True
#
# Ruby doesn't need the backing image of memory when running with
# the tester.
#
ruby_port.access_phys_mem = False
# ----------------------- # -----------------------
# run simulation # run simulation
# ----------------------- # -----------------------

View file

@ -77,7 +77,7 @@ options.num_cpus = nb_cores
# system simulated # system simulated
system = System(cpu = cpus, physmem = PhysicalMemory()) system = System(cpu = cpus, physmem = PhysicalMemory())
system.ruby = Ruby.create_system(options, system) Ruby.create_system(options, system)
assert(options.num_cpus == len(system.ruby._cpu_ruby_ports)) assert(options.num_cpus == len(system.ruby._cpu_ruby_ports))

View file

@ -74,7 +74,7 @@ options.num_cpus = 1
cpu = TimingSimpleCPU(cpu_id=0) cpu = TimingSimpleCPU(cpu_id=0)
system = System(cpu = cpu, physmem = PhysicalMemory()) system = System(cpu = cpu, physmem = PhysicalMemory())
system.ruby = Ruby.create_system(options, system) Ruby.create_system(options, system)
assert(len(system.ruby._cpu_ruby_ports) == 1) assert(len(system.ruby._cpu_ruby_ports) == 1)