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:
parent
f4cfd65d29
commit
c86f849d5a
60 changed files with 574 additions and 247 deletions
|
@ -97,7 +97,7 @@ system.tester = RubyDirectedTester(requests_to_complete = \
|
|||
options.requests,
|
||||
generator = generator)
|
||||
|
||||
system.ruby = Ruby.create_system(options, system)
|
||||
Ruby.create_system(options, system)
|
||||
|
||||
assert(options.num_cpus == len(system.ruby._cpu_ruby_ports))
|
||||
|
||||
|
|
|
@ -117,10 +117,7 @@ elif buildEnv['TARGET_ISA'] == "x86":
|
|||
else:
|
||||
fatal("incapable of building non-alpha or non-x86 full system!")
|
||||
|
||||
system.ruby = Ruby.create_system(options,
|
||||
system,
|
||||
system.piobus,
|
||||
system._dma_devices)
|
||||
Ruby.create_system(options, system, system.piobus, system._dma_devices)
|
||||
|
||||
system.cpu = [CPUClass(cpu_id=i) for i in xrange(options.num_cpus)]
|
||||
|
||||
|
|
|
@ -55,6 +55,10 @@ parser.add_option("--progress", type="int", default=1000,
|
|||
help="Progress message interval "
|
||||
"[default: %default]")
|
||||
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
|
||||
|
@ -90,14 +94,15 @@ if options.num_cpus > block_size:
|
|||
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, \
|
||||
max_loads = options.maxloads, \
|
||||
issue_dmas = False, \
|
||||
percent_functional = 0, \
|
||||
percent_functional = options.functional, \
|
||||
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) ]
|
||||
|
||||
system = System(cpu = cpus,
|
||||
|
@ -110,15 +115,14 @@ if options.num_dmas > 0:
|
|||
issue_dmas = True, \
|
||||
percent_functional = 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) ]
|
||||
system.dma_devices = dmas
|
||||
else:
|
||||
dmas = []
|
||||
|
||||
system.ruby = Ruby.create_system(options, \
|
||||
system, \
|
||||
dma_devices = dmas)
|
||||
Ruby.create_system(options, system, dma_devices = dmas)
|
||||
|
||||
#
|
||||
# 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
|
||||
|
||||
#
|
||||
# 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):
|
||||
#
|
||||
# Tie the dma memtester ports to the correct functional port
|
||||
|
|
|
@ -105,7 +105,7 @@ cpus = [ NetworkTest(fixed_pkts=options.fixed_pkts, \
|
|||
system = System(cpu = cpus,
|
||||
physmem = PhysicalMemory())
|
||||
|
||||
system.ruby = Ruby.create_system(options, system)
|
||||
Ruby.create_system(options, system)
|
||||
|
||||
i = 0
|
||||
for ruby_port in system.ruby._cpu_ruby_ports:
|
||||
|
|
|
@ -99,7 +99,7 @@ tester = RubyTester(check_flush = check_flush,
|
|||
#
|
||||
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))
|
||||
|
||||
|
@ -121,6 +121,12 @@ for ruby_port in system.ruby._cpu_ruby_ports:
|
|||
#
|
||||
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
|
||||
# -----------------------
|
||||
|
|
|
@ -177,7 +177,7 @@ system = System(cpu = [CPUClass(cpu_id=i) for i in xrange(np)],
|
|||
|
||||
if options.ruby:
|
||||
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))
|
||||
else:
|
||||
system.physmem.port = system.membus.port
|
||||
|
|
|
@ -47,7 +47,7 @@ class L2Cache(RubyCache):
|
|||
def define_options(parser):
|
||||
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':
|
||||
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,
|
||||
L1IcacheMemory = l1i_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,
|
||||
icache = l1i_cache,
|
||||
dcache = l1d_cache,
|
||||
physMemPort = system.physmem.port,
|
||||
physmem = system.physmem)
|
||||
physmem = system.physmem,
|
||||
ruby_system = ruby_system)
|
||||
|
||||
l1_cntrl.sequencer = cpu_seq
|
||||
|
||||
|
@ -123,7 +125,8 @@ def create_system(options, system, piobus, dma_devices):
|
|||
|
||||
l2_cntrl = L2Cache_Controller(version = i,
|
||||
cntrl_id = cntrl_count,
|
||||
L2cacheMemory = l2_cache)
|
||||
L2cacheMemory = l2_cache,
|
||||
ruby_system = ruby_system)
|
||||
|
||||
exec("system.l2_cntrl%d = l2_cntrl" % i)
|
||||
l2_cntrl_nodes.append(l2_cntrl)
|
||||
|
@ -148,9 +151,9 @@ def create_system(options, system, piobus, dma_devices):
|
|||
cntrl_id = cntrl_count,
|
||||
directory = \
|
||||
RubyDirectoryMemory(version = i,
|
||||
size = \
|
||||
dir_size),
|
||||
memBuffer = mem_cntrl)
|
||||
size = dir_size),
|
||||
memBuffer = mem_cntrl,
|
||||
ruby_system = ruby_system)
|
||||
|
||||
exec("system.dir_cntrl%d = dir_cntrl" % i)
|
||||
dir_cntrl_nodes.append(dir_cntrl)
|
||||
|
|
|
@ -41,7 +41,7 @@ class Cache(RubyCache):
|
|||
def define_options(parser):
|
||||
return
|
||||
|
||||
def create_system(options, system, piobus, dma_devices):
|
||||
def create_system(options, system, piobus, dma_devices, ruby_system):
|
||||
|
||||
if buildEnv['PROTOCOL'] != 'MI_example':
|
||||
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,
|
||||
cntrl_id = cntrl_count,
|
||||
cacheMemory = cache)
|
||||
cacheMemory = cache,
|
||||
ruby_system = ruby_system)
|
||||
|
||||
cpu_seq = RubySequencer(version = i,
|
||||
icache = cache,
|
||||
dcache = cache,
|
||||
physMemPort = system.physmem.port,
|
||||
physmem = system.physmem)
|
||||
physmem = system.physmem,
|
||||
ruby_system = ruby_system)
|
||||
|
||||
l1_cntrl.sequencer = cpu_seq
|
||||
|
||||
|
@ -125,7 +127,8 @@ def create_system(options, system, piobus, dma_devices):
|
|||
use_map = options.use_map,
|
||||
map_levels = \
|
||||
options.map_levels),
|
||||
memBuffer = mem_cntrl)
|
||||
memBuffer = mem_cntrl,
|
||||
ruby_system = ruby_system)
|
||||
|
||||
exec("system.dir_cntrl%d = dir_cntrl" % i)
|
||||
dir_cntrl_nodes.append(dir_cntrl)
|
||||
|
|
|
@ -47,8 +47,8 @@ class L2Cache(RubyCache):
|
|||
def define_options(parser):
|
||||
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':
|
||||
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,
|
||||
L1IcacheMemory = l1i_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,
|
||||
icache = l1i_cache,
|
||||
dcache = l1d_cache,
|
||||
physMemPort = system.physmem.port,
|
||||
physmem = system.physmem)
|
||||
physmem = system.physmem,
|
||||
ruby_system = ruby_system)
|
||||
|
||||
l1_cntrl.sequencer = cpu_seq
|
||||
|
||||
|
@ -122,7 +124,8 @@ def create_system(options, system, piobus, dma_devices):
|
|||
|
||||
l2_cntrl = L2Cache_Controller(version = i,
|
||||
cntrl_id = cntrl_count,
|
||||
L2cacheMemory = l2_cache)
|
||||
L2cacheMemory = l2_cache,
|
||||
ruby_system = ruby_system)
|
||||
|
||||
exec("system.l2_cntrl%d = l2_cntrl" % i)
|
||||
l2_cntrl_nodes.append(l2_cntrl)
|
||||
|
@ -147,9 +150,9 @@ def create_system(options, system, piobus, dma_devices):
|
|||
cntrl_id = cntrl_count,
|
||||
directory = \
|
||||
RubyDirectoryMemory(version = i,
|
||||
size = \
|
||||
dir_size),
|
||||
memBuffer = mem_cntrl)
|
||||
size = dir_size),
|
||||
memBuffer = mem_cntrl,
|
||||
ruby_system = ruby_system)
|
||||
|
||||
exec("system.dir_cntrl%d = dir_cntrl" % i)
|
||||
dir_cntrl_nodes.append(dir_cntrl)
|
||||
|
|
|
@ -54,7 +54,7 @@ def define_options(parser):
|
|||
parser.add_option("--allow-atomic-migration", action="store_true",
|
||||
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':
|
||||
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 = \
|
||||
not options.disable_dyn_timeouts,
|
||||
no_mig_atomic = not \
|
||||
options.allow_atomic_migration)
|
||||
options.allow_atomic_migration,
|
||||
ruby_system = ruby_system)
|
||||
|
||||
cpu_seq = RubySequencer(version = i,
|
||||
icache = l1i_cache,
|
||||
dcache = l1d_cache,
|
||||
physMemPort = system.physmem.port,
|
||||
physmem = system.physmem)
|
||||
physmem = system.physmem,
|
||||
ruby_system = ruby_system)
|
||||
|
||||
l1_cntrl.sequencer = cpu_seq
|
||||
|
||||
|
@ -145,7 +147,8 @@ def create_system(options, system, piobus, dma_devices):
|
|||
l2_cntrl = L2Cache_Controller(version = i,
|
||||
cntrl_id = cntrl_count,
|
||||
L2cacheMemory = l2_cache,
|
||||
N_tokens = n_tokens)
|
||||
N_tokens = n_tokens,
|
||||
ruby_system = ruby_system)
|
||||
|
||||
exec("system.l2_cntrl%d = l2_cntrl" % i)
|
||||
l2_cntrl_nodes.append(l2_cntrl)
|
||||
|
@ -170,10 +173,10 @@ def create_system(options, system, piobus, dma_devices):
|
|||
cntrl_id = cntrl_count,
|
||||
directory = \
|
||||
RubyDirectoryMemory(version = i,
|
||||
size = \
|
||||
dir_size),
|
||||
size = dir_size),
|
||||
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)
|
||||
dir_cntrl_nodes.append(dir_cntrl)
|
||||
|
|
|
@ -58,8 +58,8 @@ def define_options(parser):
|
|||
parser.add_option("--dir-on", action="store_true",
|
||||
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':
|
||||
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,
|
||||
L2cacheMemory = l2_cache,
|
||||
no_mig_atomic = not \
|
||||
options.allow_atomic_migration)
|
||||
options.allow_atomic_migration,
|
||||
ruby_system = ruby_system)
|
||||
|
||||
cpu_seq = RubySequencer(version = i,
|
||||
icache = l1i_cache,
|
||||
dcache = l1d_cache,
|
||||
physMemPort = system.physmem.port,
|
||||
physmem = system.physmem)
|
||||
physmem = system.physmem,
|
||||
ruby_system = ruby_system)
|
||||
|
||||
l1_cntrl.sequencer = cpu_seq
|
||||
|
||||
|
@ -181,7 +183,8 @@ def create_system(options, system, piobus, dma_devices):
|
|||
probeFilter = pf,
|
||||
memBuffer = mem_cntrl,
|
||||
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:
|
||||
dir_cntrl.recycle_latency = options.recycle_latency
|
||||
|
|
|
@ -62,11 +62,15 @@ def define_options(parser):
|
|||
|
||||
def create_system(options, system, piobus = None, dma_devices = []):
|
||||
|
||||
system.ruby = RubySystem(clock = options.clock)
|
||||
ruby = system.ruby
|
||||
|
||||
protocol = buildEnv['PROTOCOL']
|
||||
exec "import %s" % protocol
|
||||
try:
|
||||
(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)
|
||||
except:
|
||||
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
|
||||
raise
|
||||
|
||||
network = NetworkClass(topology = net_topology)
|
||||
network = NetworkClass(ruby_system = ruby, topology = net_topology)
|
||||
|
||||
#
|
||||
# Loop through the directory controlers.
|
||||
|
@ -137,15 +141,13 @@ def create_system(options, system, piobus = None, dma_devices = []):
|
|||
long(system.physmem.range.first) + 1
|
||||
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,
|
||||
network = network,
|
||||
profiler = ruby_profiler,
|
||||
tracer = RubyTracer(),
|
||||
mem_size = total_mem_size)
|
||||
|
||||
ruby.network = network
|
||||
ruby.profiler = ruby_profiler
|
||||
ruby.tracer = ruby_tracer
|
||||
ruby.mem_size = total_mem_size
|
||||
ruby._cpu_ruby_ports = cpu_sequencers
|
||||
ruby.random_seed = options.random_seed
|
||||
|
||||
return ruby
|
||||
|
|
|
@ -50,3 +50,5 @@ class MemTest(MemObject):
|
|||
|
||||
test = Port("Port to the memory system to test")
|
||||
functional = Port("Port to the functional memory used for verification")
|
||||
suppress_func_warnings = Param.Bool(False,
|
||||
"suppress warnings when functional accesses fail.\n")
|
||||
|
|
|
@ -146,7 +146,8 @@ MemTest::MemTest(const Params *p)
|
|||
percentSourceUnaligned(p->percent_source_unaligned),
|
||||
percentDestUnaligned(p->percent_dest_unaligned),
|
||||
maxLoads(p->max_loads),
|
||||
atomic(p->atomic)
|
||||
atomic(p->atomic),
|
||||
suppress_func_warnings(p->suppress_func_warnings)
|
||||
{
|
||||
cachePort.snoopRangeSent = false;
|
||||
funcPort.snoopRangeSent = true;
|
||||
|
@ -162,6 +163,7 @@ MemTest::MemTest(const Params *p)
|
|||
// set up counters
|
||||
noResponseCycles = 0;
|
||||
numReads = 0;
|
||||
numWrites = 0;
|
||||
schedule(tickEvent, 0);
|
||||
|
||||
accessRetry = false;
|
||||
|
@ -201,9 +203,10 @@ MemTest::completeRequest(PacketPtr pkt)
|
|||
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",
|
||||
req->getPaddr(), blockAddr(req->getPaddr()));
|
||||
req->getPaddr(), blockAddr(req->getPaddr()),
|
||||
pkt->isError() ? "error" : "success");
|
||||
|
||||
MemTestSenderState *state =
|
||||
dynamic_cast<MemTestSenderState *>(pkt->senderState);
|
||||
|
@ -217,28 +220,37 @@ MemTest::completeRequest(PacketPtr pkt)
|
|||
assert(removeAddr != outstandingAddrs.end());
|
||||
outstandingAddrs.erase(removeAddr);
|
||||
|
||||
if (pkt->isRead()) {
|
||||
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);
|
||||
if (pkt->isError()) {
|
||||
if (!suppress_func_warnings) {
|
||||
warn("Functional Access failed for %x at %x\n",
|
||||
pkt->isWrite() ? "write" : "read", req->getPaddr());
|
||||
}
|
||||
|
||||
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 {
|
||||
assert(pkt->isWrite());
|
||||
numWritesStat++;
|
||||
if (pkt->isRead()) {
|
||||
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;
|
||||
|
@ -361,6 +373,8 @@ MemTest::tick()
|
|||
pkt->senderState = state;
|
||||
|
||||
if (do_functional) {
|
||||
assert(pkt->needsResponse());
|
||||
pkt->setSuppressFuncError();
|
||||
cachePort.sendFunctional(pkt);
|
||||
completeRequest(pkt);
|
||||
} else {
|
||||
|
@ -392,9 +406,8 @@ MemTest::tick()
|
|||
MemTestSenderState *state = new MemTestSenderState(result);
|
||||
pkt->senderState = state;
|
||||
|
||||
funcPort.writeBlob(req->getPaddr(), pkt_data, req->getSize());
|
||||
|
||||
if (do_functional) {
|
||||
pkt->setSuppressFuncError();
|
||||
cachePort.sendFunctional(pkt);
|
||||
completeRequest(pkt);
|
||||
} else {
|
||||
|
|
|
@ -174,9 +174,11 @@ class MemTest : public MemObject
|
|||
Tick noResponseCycles;
|
||||
|
||||
uint64_t numReads;
|
||||
uint64_t numWrites;
|
||||
uint64_t maxLoads;
|
||||
|
||||
bool atomic;
|
||||
bool suppress_func_warnings;
|
||||
|
||||
Stats::Scalar numReadsStat;
|
||||
Stats::Scalar numWritesStat;
|
||||
|
|
|
@ -148,10 +148,14 @@ MemCmd::commandInfo[] =
|
|||
{ SET2(IsResponse, IsError), InvalidCmd, "InvalidDestError" },
|
||||
/* BadAddressError -- memory address invalid */
|
||||
{ SET2(IsResponse, IsError), InvalidCmd, "BadAddressError" },
|
||||
/* FunctionalReadError */
|
||||
{ SET3(IsRead, IsResponse, IsError), InvalidCmd, "FunctionalReadError" },
|
||||
/* FunctionalWriteError */
|
||||
{ SET3(IsWrite, IsResponse, IsError), InvalidCmd, "FunctionalWriteError" },
|
||||
/* PrintReq */
|
||||
{ SET2(IsRequest, IsPrint), InvalidCmd, "PrintReq" },
|
||||
/* Flush Request */
|
||||
{ SET3(IsRequest, IsFlush, NeedsExclusive), InvalidCmd, "FlushReq" }
|
||||
{ SET3(IsRequest, IsFlush, NeedsExclusive), InvalidCmd, "FlushReq" },
|
||||
};
|
||||
|
||||
bool
|
||||
|
|
|
@ -103,6 +103,8 @@ class MemCmd
|
|||
NetworkNackError, // nacked at network layer (not by protocol)
|
||||
InvalidDestError, // packet dest field invalid
|
||||
BadAddressError, // memory address invalid
|
||||
FunctionalReadError, // unable to fulfill functional read
|
||||
FunctionalWriteError, // unable to fulfill functional write
|
||||
// Fake simulator-only commands
|
||||
PrintReq, // Print state matching address
|
||||
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
|
||||
/// be called on it rather than simply delete.
|
||||
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;
|
||||
|
||||
|
@ -428,6 +433,8 @@ class Packet : public FastAlloc, public Printable
|
|||
void setSupplyExclusive() { flags.set(SUPPLY_EXCLUSIVE); }
|
||||
void clearSupplyExclusive() { flags.clear(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
|
||||
// their encoding keeps changing (from result field to command
|
||||
|
@ -617,6 +624,18 @@ class Packet : public FastAlloc, public Printable
|
|||
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
|
||||
* modify it so that it can be sent out again. Only packets that
|
||||
|
|
|
@ -186,17 +186,24 @@ machine(L1Cache, "MSI Directory L1 Cache CMP")
|
|||
AccessPermission getAccessPermission(Address addr) {
|
||||
TBE tbe := L1_TBEs[addr];
|
||||
if(is_valid(tbe)) {
|
||||
DPRINTF(RubySlicc, "%s\n", L1Cache_State_to_permission(tbe.TBEState));
|
||||
return L1Cache_State_to_permission(tbe.TBEState);
|
||||
}
|
||||
|
||||
Entry cache_entry := getCacheEntry(addr);
|
||||
if(is_valid(cache_entry)) {
|
||||
DPRINTF(RubySlicc, "%s\n", L1Cache_State_to_permission(cache_entry.CacheState));
|
||||
return L1Cache_State_to_permission(cache_entry.CacheState);
|
||||
}
|
||||
|
||||
DPRINTF(RubySlicc, "%s\n", 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) {
|
||||
if (is_valid(cache_entry)) {
|
||||
cache_entry.changePermission(L1Cache_State_to_permission(state));
|
||||
|
|
|
@ -56,7 +56,7 @@ machine(L2Cache, "MESI Directory L2 Cache CMP")
|
|||
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";
|
||||
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
|
||||
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) {
|
||||
TBE tbe := L2_TBEs[addr];
|
||||
if(is_valid(tbe)) {
|
||||
DPRINTF(RubySlicc, "%s\n", L2Cache_State_to_permission(tbe.TBEState));
|
||||
return L2Cache_State_to_permission(tbe.TBEState);
|
||||
}
|
||||
|
||||
Entry cache_entry := getCacheEntry(addr);
|
||||
if(is_valid(cache_entry)) {
|
||||
DPRINTF(RubySlicc, "%s\n", L2Cache_State_to_permission(cache_entry.CacheState));
|
||||
return L2Cache_State_to_permission(cache_entry.CacheState);
|
||||
}
|
||||
|
||||
DPRINTF(RubySlicc, "%s\n", 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) {
|
||||
if (is_valid(cache_entry)) {
|
||||
cache_entry.changePermission(L2Cache_State_to_permission(state));
|
||||
|
|
|
@ -55,7 +55,7 @@ machine(Directory, "MESI_CMP_filter_directory protocol")
|
|||
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";
|
||||
|
||||
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";
|
||||
MI, AccessPermission:Busy, desc="Intermediate State M>I";
|
||||
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) {
|
||||
TBE tbe := TBEs[addr];
|
||||
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(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) {
|
||||
|
|
|
@ -42,6 +42,10 @@ machine(DMA, "DMA Controller")
|
|||
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="...");
|
||||
|
||||
in_port(dmaRequestQueue_in, SequencerMsg, mandatoryQueue, desc="...") {
|
||||
|
|
|
@ -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) {
|
||||
if (machineIDToMachineType(sender) == MachineType:L1Cache) {
|
||||
//
|
||||
|
|
|
@ -122,7 +122,11 @@ machine(Directory, "Directory protocol")
|
|||
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) {
|
||||
|
@ -131,6 +135,10 @@ machine(Directory, "Directory protocol")
|
|||
}
|
||||
}
|
||||
|
||||
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
|
||||
return getDirectoryEntry(addr).DataBlk;
|
||||
}
|
||||
|
||||
// ** OUT_PORTS **
|
||||
out_port(forwardNetwork_out, RequestMsg, forwardFromDir);
|
||||
out_port(responseNetwork_out, ResponseMsg, responseFromDir);
|
||||
|
|
|
@ -37,6 +37,10 @@ machine(DMA, "DMA Controller")
|
|||
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="...");
|
||||
|
||||
in_port(dmaRequestQueue_in, SequencerMsg, mandatoryQueue, desc="...") {
|
||||
|
|
|
@ -197,14 +197,17 @@ machine(L1Cache, "Directory protocol")
|
|||
AccessPermission getAccessPermission(Address addr) {
|
||||
TBE tbe := TBEs[addr];
|
||||
if(is_valid(tbe)) {
|
||||
DPRINTF(RubySlicc, "%s\n", L1Cache_State_to_permission(tbe.TBEState));
|
||||
return L1Cache_State_to_permission(tbe.TBEState);
|
||||
}
|
||||
|
||||
Entry cache_entry := getCacheEntry(addr);
|
||||
if(is_valid(cache_entry)) {
|
||||
DPRINTF(RubySlicc, "%s\n", L1Cache_State_to_permission(cache_entry.CacheState));
|
||||
return L1Cache_State_to_permission(cache_entry.CacheState);
|
||||
}
|
||||
|
||||
DPRINTF(RubySlicc, "AccessPermission_NotPresent\n");
|
||||
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) {
|
||||
if (type == RubyRequestType:LD) {
|
||||
return Event:Load;
|
||||
|
|
|
@ -56,12 +56,12 @@ machine(L2Cache, "Token protocol")
|
|||
// Stable states
|
||||
NP, AccessPermission:Invalid, desc="Not Present";
|
||||
I, AccessPermission:Invalid, desc="Invalid";
|
||||
ILS, AccessPermission:Busy, desc="Idle/NP, but local sharers exist";
|
||||
ILX, AccessPermission:Busy, desc="Idle/NP, but local exclusive exists";
|
||||
ILO, AccessPermission:Busy, desc="Idle/NP, but local owner exists";
|
||||
ILOX, AccessPermission:Busy, 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";
|
||||
ILOSX, AccessPermission:Busy, desc="Idle/NP, but local owner exists, local sharers exist, chip is exclusive ";
|
||||
ILS, AccessPermission:Invalid, desc="Idle/NP, but local sharers exist";
|
||||
ILX, AccessPermission:Invalid, desc="Idle/NP, but local exclusive exists";
|
||||
ILO, AccessPermission:Invalid, desc="Idle/NP, but local owner exists";
|
||||
ILOX, AccessPermission:Invalid, desc="Idle/NP, but local owner exists and chip is exclusive";
|
||||
ILOS, AccessPermission:Invalid, desc="Idle/NP, but local owner exists and local sharers as well";
|
||||
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";
|
||||
O, AccessPermission:Read_Only, desc="Owned, no local sharers";
|
||||
OLS, AccessPermission:Read_Only, desc="Owned with local sharers";
|
||||
|
@ -502,14 +502,22 @@ machine(L2Cache, "Token protocol")
|
|||
AccessPermission getAccessPermission(Address addr) {
|
||||
TBE tbe := TBEs[addr];
|
||||
if(is_valid(tbe)) {
|
||||
DPRINTF(RubySlicc, "%s\n", L2Cache_State_to_permission(tbe.TBEState));
|
||||
return L2Cache_State_to_permission(tbe.TBEState);
|
||||
}
|
||||
|
||||
Entry cache_entry := getCacheEntry(addr);
|
||||
if(is_valid(cache_entry)) {
|
||||
DPRINTF(RubySlicc, "%s\n", 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;
|
||||
}
|
||||
|
||||
|
@ -519,6 +527,10 @@ machine(L2Cache, "Token protocol")
|
|||
}
|
||||
}
|
||||
|
||||
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
|
||||
return getCacheEntry(addr).DataBlk;
|
||||
}
|
||||
|
||||
MessageBuffer triggerQueue, ordered="true";
|
||||
|
||||
out_port(globalRequestNetwork_out, RequestMsg, GlobalRequestFromL2Cache);
|
||||
|
|
|
@ -50,16 +50,16 @@ machine(Directory, "Directory protocol")
|
|||
// STATES
|
||||
state_declaration(State, desc="Directory states", default="Directory_State_I") {
|
||||
// Base states
|
||||
I, AccessPermission:Invalid, desc="Invalid";
|
||||
I, AccessPermission:Read_Write, desc="Invalid";
|
||||
S, AccessPermission:Read_Only, desc="Shared";
|
||||
O, AccessPermission:Read_Only, desc="Owner";
|
||||
M, AccessPermission:Read_Write, desc="Modified";
|
||||
O, AccessPermission:Maybe_Stale, desc="Owner";
|
||||
M, AccessPermission:Maybe_Stale, desc="Modified";
|
||||
|
||||
IS, AccessPermission:Busy, desc="Blocked, was in idle";
|
||||
SS, AccessPermission:Read_Only, desc="Blocked, was in shared";
|
||||
OO, AccessPermission:Read_Only, desc="Blocked, was in owned";
|
||||
MO, AccessPermission:Read_Only, desc="Blocked, going to owner or maybe modified";
|
||||
MM, AccessPermission:Read_Only, desc="Blocked, going to modified";
|
||||
OO, AccessPermission:Busy, desc="Blocked, was in owned";
|
||||
MO, AccessPermission:Busy, desc="Blocked, going to owner or maybe modified";
|
||||
MM, AccessPermission:Busy, desc="Blocked, going to modified";
|
||||
MM_DMA, AccessPermission:Busy, desc="Blocked, going to I";
|
||||
|
||||
MI, AccessPermission:Busy, desc="Blocked on a writeback";
|
||||
|
@ -173,9 +173,11 @@ machine(Directory, "Directory protocol")
|
|||
|
||||
AccessPermission getAccessPermission(Address addr) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
bool isBlockShared(Address addr) {
|
||||
if (directory.isPresent(addr)) {
|
||||
|
|
|
@ -68,6 +68,10 @@ machine(DMA, "DMA Controller")
|
|||
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(respToDirectory_out, ResponseMsg, respToDir, desc="...");
|
||||
out_port(foo1_out, ResponseMsg, foo1, desc="...");
|
||||
|
|
|
@ -227,6 +227,10 @@ machine(L1Cache, "Token protocol")
|
|||
return L1Icache_entry;
|
||||
}
|
||||
|
||||
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
|
||||
return getCacheEntry(addr).DataBlk;
|
||||
}
|
||||
|
||||
Entry getL1DCacheEntry(Address addr), return_by_pointer="yes" {
|
||||
Entry L1Dcache_entry := static_cast(Entry, "pointer", L1DcacheMemory.lookup(addr));
|
||||
return L1Dcache_entry;
|
||||
|
|
|
@ -156,6 +156,10 @@ machine(L2Cache, "Token protocol")
|
|||
return cache_entry;
|
||||
}
|
||||
|
||||
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
|
||||
return getCacheEntry(addr).DataBlk;
|
||||
}
|
||||
|
||||
int getTokens(Entry cache_entry) {
|
||||
if (is_valid(cache_entry)) {
|
||||
return cache_entry.Tokens;
|
||||
|
|
|
@ -55,7 +55,7 @@ machine(Directory, "Token protocol")
|
|||
state_declaration(State, desc="Directory states", default="Directory_State_O") {
|
||||
// Base states
|
||||
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";
|
||||
|
||||
// Memory wait states - can block all messages including persistent requests
|
||||
|
@ -169,6 +169,10 @@ machine(Directory, "Token protocol")
|
|||
return static_cast(Entry, directory[addr]);
|
||||
}
|
||||
|
||||
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
|
||||
return getDirectoryEntry(addr).DataBlk;
|
||||
}
|
||||
|
||||
State getState(TBE tbe, Address addr) {
|
||||
if (is_valid(tbe)) {
|
||||
return tbe.TBEState;
|
||||
|
@ -206,7 +210,13 @@ machine(Directory, "Token protocol")
|
|||
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) {
|
||||
|
|
|
@ -70,6 +70,10 @@ machine(DMA, "DMA Controller")
|
|||
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="...");
|
||||
|
||||
in_port(dmaRequestQueue_in, SequencerMsg, mandatoryQueue, desc="...") {
|
||||
|
|
|
@ -189,6 +189,10 @@ machine(L1Cache, "AMD Hammer-like protocol")
|
|||
return L1Icache_entry;
|
||||
}
|
||||
|
||||
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
|
||||
return getCacheEntry(addr).DataBlk;
|
||||
}
|
||||
|
||||
Entry getL2CacheEntry(Address address), return_by_pointer="yes" {
|
||||
Entry L2cache_entry := static_cast(Entry, "pointer", L2cacheMemory.lookup(address));
|
||||
return L2cache_entry;
|
||||
|
|
|
@ -59,38 +59,38 @@ machine(Directory, "AMD Hammer-like protocol")
|
|||
// STATES
|
||||
state_declaration(State, desc="Directory states", default="Directory_State_E") {
|
||||
// Base states
|
||||
NX, AccessPermission:Invalid, 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";
|
||||
NX, AccessPermission:Maybe_Stale, desc="Not Owner, probe filter entry exists, block in O 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";
|
||||
O, AccessPermission:Read_Only, desc="Data clean, probe filter entry exists";
|
||||
E, AccessPermission:Read_Write, desc="Exclusive Owner, no 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";
|
||||
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_X, AccessPermission:Invalid, "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_W, AccessPermission:Invalid, "NO^B", desc="Not Owner, Blocked, forwarded merged GETS, waiting for responses";
|
||||
O_B, AccessPermission:Invalid, "O^B", desc="Owner, Blocked";
|
||||
NO_B_W, AccessPermission:Invalid, desc="Not Owner, Blocked, waiting for Dram";
|
||||
O_B_W, AccessPermission:Invalid, desc="Owner, Blocked, waiting for Dram";
|
||||
NO_W, AccessPermission:Invalid, desc="Not Owner, waiting for Dram";
|
||||
O_W, AccessPermission:Invalid, desc="Owner, waiting for Dram";
|
||||
NO_DW_B_W, AccessPermission:Invalid, 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_D, AccessPermission:Invalid, 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_DW_W, AccessPermission:Invalid, 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, AccessPermission:Invalid, desc="Owner, Dma Read waiting for cache responses";
|
||||
WB, AccessPermission:Invalid, desc="Blocked on a writeback";
|
||||
WB_O_W, AccessPermission:Invalid, desc="Blocked on memory write, will go to O";
|
||||
WB_E_W, AccessPermission:Invalid, desc="Blocked on memory write, will go to E";
|
||||
NO_B, AccessPermission:Busy, "NO^B", desc="Not Owner, Blocked";
|
||||
NO_B_X, AccessPermission:Busy, "NO^B", desc="Not Owner, Blocked, next queued request GETX";
|
||||
NO_B_S, AccessPermission:Busy, "NO^B", desc="Not Owner, Blocked, next queued request GETS";
|
||||
NO_B_S_W, AccessPermission:Busy, "NO^B", desc="Not Owner, Blocked, forwarded merged GETS, waiting for responses";
|
||||
O_B, AccessPermission:Busy, "O^B", desc="Owner, Blocked";
|
||||
NO_B_W, AccessPermission:Busy, desc="Not Owner, Blocked, waiting for Dram";
|
||||
O_B_W, AccessPermission:Busy, desc="Owner, Blocked, waiting for Dram";
|
||||
NO_W, AccessPermission:Busy, desc="Not Owner, waiting for Dram";
|
||||
O_W, AccessPermission:Busy, desc="Owner, waiting for Dram";
|
||||
NO_DW_B_W, AccessPermission:Busy, desc="Not Owner, Dma Write 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:Busy, desc="Not Owner, Dma Read waiting for cache responses including dirty data";
|
||||
NO_DR_B, AccessPermission:Busy, desc="Not Owner, Dma Read waiting for cache responses";
|
||||
NO_DW_W, AccessPermission:Busy, desc="Not Owner, Dma Write waiting for Dram";
|
||||
O_DR_B_W, AccessPermission:Busy, desc="Owner, Dma Read waiting for Dram and cache responses";
|
||||
O_DR_B, AccessPermission:Busy, desc="Owner, Dma Read waiting for cache responses";
|
||||
WB, AccessPermission:Busy, desc="Blocked on a writeback";
|
||||
WB_O_W, AccessPermission:Busy, desc="Blocked on memory write, will go to O";
|
||||
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_W, AccessPermission:Invalid, desc="Not Owner, Blocked, waiting for Dram";
|
||||
NO_F, AccessPermission:Busy, desc="Blocked on a flush";
|
||||
NO_F_W, AccessPermission:Busy, desc="Not Owner, Blocked, waiting for Dram";
|
||||
}
|
||||
|
||||
// Events
|
||||
|
@ -190,6 +190,10 @@ machine(Directory, "AMD Hammer-like protocol")
|
|||
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" {
|
||||
if (probe_filter_enabled || full_bit_dir_enabled) {
|
||||
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(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) {
|
||||
|
|
|
@ -67,6 +67,10 @@ machine(DMA, "DMA Controller")
|
|||
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="...");
|
||||
|
||||
in_port(dmaRequestQueue_in, SequencerMsg, mandatoryQueue, desc="...") {
|
||||
|
|
|
@ -57,6 +57,13 @@ enumeration(AccessPermission, desc="...", default="AccessPermission_NotPresent")
|
|||
Read_Only, desc="block is Read Only (modulo functional writes)";
|
||||
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, desc="block is in an Invalid base state";
|
||||
NotPresent, desc="block is NotPresent";
|
||||
|
|
|
@ -48,6 +48,7 @@ Network::Network(const Params *p)
|
|||
|
||||
// Initialize the controller's network pointers
|
||||
m_topology_ptr->initNetworkPtr(this);
|
||||
p->ruby_system->registerNetwork(this);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -48,3 +48,4 @@ class RubyNetwork(SimObject):
|
|||
number_of_virtual_networks = Param.Int(10, "");
|
||||
topology = Param.Topology("");
|
||||
control_msg_size = Param.Int(8, "");
|
||||
ruby_system = Param.RubySystem("");
|
||||
|
|
|
@ -92,6 +92,8 @@ Profiler::Profiler(const Params *p)
|
|||
m_inst_profiler_ptr->setHotLines(m_hot_lines);
|
||||
m_inst_profiler_ptr->setAllInstructions(m_all_instructions);
|
||||
}
|
||||
|
||||
p->ruby_system->registerProfiler(this);
|
||||
}
|
||||
|
||||
Profiler::~Profiler()
|
||||
|
|
|
@ -36,3 +36,4 @@ class RubyProfiler(SimObject):
|
|||
hot_lines = Param.Bool(False, "")
|
||||
all_instructions = Param.Bool(False, "")
|
||||
num_of_sequencers = Param.Int("")
|
||||
ruby_system = Param.RubySystem("")
|
||||
|
|
|
@ -40,7 +40,7 @@ Tracer::Tracer(const Params *p)
|
|||
m_enabled = false;
|
||||
m_warmup_length = p->warmup_length;
|
||||
assert(m_warmup_length > 0);
|
||||
RubySystem::m_tracer_ptr = this;
|
||||
p->ruby_system->registerTracer(this);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -34,3 +34,4 @@ class RubyTracer(SimObject):
|
|||
type = 'RubyTracer'
|
||||
cxx_class = 'Tracer'
|
||||
warmup_length = Param.Int(100000, "")
|
||||
ruby_system = Param.RubySystem("")
|
||||
|
|
|
@ -36,7 +36,9 @@
|
|||
#include "mem/protocol/MachineType.hh"
|
||||
#include "mem/ruby/common/Address.hh"
|
||||
#include "mem/ruby/common/Consumer.hh"
|
||||
#include "mem/ruby/common/DataBlock.hh"
|
||||
#include "mem/ruby/network/Network.hh"
|
||||
#include "mem/ruby/system/System.hh"
|
||||
#include "params/RubyController.hh"
|
||||
#include "sim/sim_object.hh"
|
||||
|
||||
|
@ -47,7 +49,7 @@ class AbstractController : public SimObject, public Consumer
|
|||
{
|
||||
public:
|
||||
typedef RubyControllerParams Params;
|
||||
AbstractController(const Params *p) : SimObject(p) {}
|
||||
AbstractController(const Params *p);
|
||||
const Params *params() const { return (const Params *)_params; }
|
||||
|
||||
// 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 unblock(Address) = 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 printStats(std::ostream & out) const = 0;
|
||||
|
@ -68,9 +72,6 @@ class AbstractController : public SimObject, public Consumer
|
|||
virtual void wakeup() = 0;
|
||||
// virtual void dumpStats(std::ostream & out) = 0;
|
||||
virtual void clearStats() = 0;
|
||||
|
||||
private:
|
||||
virtual AccessPermission getAccessPermission(Address addr) = 0;
|
||||
};
|
||||
|
||||
#endif // __MEM_RUBY_SLICC_INTERFACE_ABSTRACTCONTROLLER_HH__
|
||||
|
|
|
@ -41,3 +41,4 @@ class RubyController(SimObject):
|
|||
buffer_size = Param.Int(0, "max buffer size 0 means infinite")
|
||||
recycle_latency = Param.Int(10, "")
|
||||
number_of_TBEs = Param.Int(256, "")
|
||||
ruby_system = Param.RubySystem("");
|
||||
|
|
|
@ -35,6 +35,7 @@ if not env['RUBY']:
|
|||
|
||||
SimObject('Controller.py')
|
||||
|
||||
Source('AbstractController.cc')
|
||||
Source('AbstractEntry.cc')
|
||||
Source('AbstractCacheEntry.cc')
|
||||
Source('RubyRequest.cc')
|
||||
|
|
|
@ -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");
|
|
@ -156,7 +156,7 @@ DirectoryMemory::lookup(PhysAddress address)
|
|||
assert(isPresent(address));
|
||||
Directory_Entry* entry;
|
||||
uint64 idx;
|
||||
DPRINTF(RubyCache, "address: %s\n", address);
|
||||
DPRINTF(RubyCache, "Looking up address: %s\n", address);
|
||||
|
||||
if (m_use_map) {
|
||||
if (m_sparseMemory->exist(address)) {
|
||||
|
@ -166,6 +166,7 @@ DirectoryMemory::lookup(PhysAddress address)
|
|||
// Note: SparseMemory internally creates a new Directory Entry
|
||||
m_sparseMemory->add(address);
|
||||
entry = m_sparseMemory->lookup(address);
|
||||
entry->changePermission(AccessPermission_Read_Write);
|
||||
}
|
||||
} else {
|
||||
idx = mapAddressToLocalIdx(address);
|
||||
|
@ -175,6 +176,7 @@ DirectoryMemory::lookup(PhysAddress address)
|
|||
if (entry == NULL) {
|
||||
entry = new Directory_Entry();
|
||||
entry->getDataBlk().assign(m_ram->getBlockPtr(address));
|
||||
entry->changePermission(AccessPermission_Read_Only);
|
||||
m_entries[idx] = entry;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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")
|
|
@ -31,8 +31,8 @@
|
|||
#include "arch/x86/insts/microldstop.hh"
|
||||
#endif // X86_ISA
|
||||
#include "cpu/testers/rubytest/RubyTester.hh"
|
||||
#include "debug/MemoryAccess.hh"
|
||||
#include "debug/Ruby.hh"
|
||||
#include "mem/protocol/AccessPermission.hh"
|
||||
#include "mem/ruby/slicc_interface/AbstractController.hh"
|
||||
#include "mem/ruby/system/RubyPort.hh"
|
||||
#include "mem/physical.hh"
|
||||
|
@ -54,6 +54,8 @@ RubyPort::RubyPort(const Params *p)
|
|||
|
||||
m_usingRubyTester = p->using_ruby_tester;
|
||||
access_phys_mem = p->access_phys_mem;
|
||||
|
||||
ruby_system = p->ruby_system;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -68,7 +70,7 @@ RubyPort::getPort(const std::string &if_name, int idx)
|
|||
{
|
||||
if (if_name == "port") {
|
||||
return new M5Port(csprintf("%s-port%d", name(), idx), this,
|
||||
access_phys_mem);
|
||||
ruby_system, access_phys_mem);
|
||||
}
|
||||
|
||||
if (if_name == "pio_port") {
|
||||
|
@ -85,7 +87,7 @@ RubyPort::getPort(const std::string &if_name, int idx)
|
|||
assert (physMemPort == NULL);
|
||||
|
||||
physMemPort = new M5Port(csprintf("%s-physMemPort", name()), this,
|
||||
access_phys_mem);
|
||||
ruby_system, access_phys_mem);
|
||||
|
||||
return physMemPort;
|
||||
}
|
||||
|
@ -109,12 +111,13 @@ RubyPort::PioPort::PioPort(const std::string &_name,
|
|||
ruby_port = _port;
|
||||
}
|
||||
|
||||
RubyPort::M5Port::M5Port(const std::string &_name,
|
||||
RubyPort *_port, bool _access_phys_mem)
|
||||
RubyPort::M5Port::M5Port(const std::string &_name, RubyPort *_port,
|
||||
RubySystem *_system, bool _access_phys_mem)
|
||||
: SimpleTimingPort(_name, _port)
|
||||
{
|
||||
DPRINTF(RubyPort, "creating port from ruby sequcner to cpu %s\n", _name);
|
||||
ruby_port = _port;
|
||||
ruby_system = _system;
|
||||
_onRetryList = false;
|
||||
access_phys_mem = _access_phys_mem;
|
||||
}
|
||||
|
@ -289,6 +292,168 @@ RubyPort::M5Port::recvTiming(PacketPtr pkt)
|
|||
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
|
||||
RubyPort::ruby_hit_callback(PacketPtr pkt)
|
||||
{
|
||||
|
|
|
@ -50,12 +50,13 @@ class RubyPort : public MemObject
|
|||
{
|
||||
private:
|
||||
RubyPort *ruby_port;
|
||||
RubySystem* ruby_system;
|
||||
bool _onRetryList;
|
||||
bool access_phys_mem;
|
||||
|
||||
public:
|
||||
M5Port(const std::string &_name, RubyPort *_port,
|
||||
bool _access_phys_mem);
|
||||
RubySystem*_system, bool _access_phys_mem);
|
||||
bool sendTiming(PacketPtr pkt);
|
||||
void hitCallback(PacketPtr pkt);
|
||||
unsigned deviceBlockSize() const;
|
||||
|
@ -69,9 +70,12 @@ class RubyPort : public MemObject
|
|||
protected:
|
||||
virtual bool recvTiming(PacketPtr pkt);
|
||||
virtual Tick recvAtomic(PacketPtr pkt);
|
||||
virtual void recvFunctional(PacketPtr pkt);
|
||||
|
||||
private:
|
||||
bool isPhysMemAddress(Addr addr);
|
||||
bool doFunctionalRead(PacketPtr pkt);
|
||||
bool doFunctionalWrite(PacketPtr pkt);
|
||||
};
|
||||
|
||||
friend class M5Port;
|
||||
|
@ -145,6 +149,7 @@ class RubyPort : public MemObject
|
|||
M5Port* physMemPort;
|
||||
|
||||
PhysicalMemory* physmem;
|
||||
RubySystem* ruby_system;
|
||||
|
||||
//
|
||||
// Based on similar code in the M5 bus. Stores pointers to those ports
|
||||
|
|
|
@ -39,9 +39,6 @@ class RubySystem(SimObject):
|
|||
block_size_bytes = Param.Int(64,
|
||||
"default cache block size; must be a power of two");
|
||||
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",
|
||||
"file to which ruby dumps its stats")
|
||||
no_mem_vec = Param.Bool(False, "do not allocate Ruby's mem vector");
|
||||
|
|
|
@ -33,9 +33,8 @@ Import('*')
|
|||
if not env['RUBY']:
|
||||
Return()
|
||||
|
||||
SimObject('Cache.py')
|
||||
SimObject('AbstractMemory.py')
|
||||
SimObject('Sequencer.py')
|
||||
SimObject('DirectoryMemory.py')
|
||||
SimObject('MemoryControl.py')
|
||||
SimObject('WireBuffer.py')
|
||||
SimObject('RubySystem.py')
|
||||
|
|
|
@ -43,6 +43,7 @@ class RubyPort(MemObject):
|
|||
using_network_tester = Param.Bool(False, "")
|
||||
access_phys_mem = Param.Bool(True,
|
||||
"should the rubyport atomically update phys_mem")
|
||||
ruby_system = Param.RubySystem("")
|
||||
|
||||
class RubySequencer(RubyPort):
|
||||
type = 'RubySequencer'
|
||||
|
|
|
@ -74,10 +74,6 @@ RubySystem::RubySystem(const Params *p)
|
|||
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_system_ptr = this;
|
||||
if (p->no_mem_vec) {
|
||||
|
@ -100,6 +96,30 @@ RubySystem::init()
|
|||
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()
|
||||
{
|
||||
delete m_network_ptr;
|
||||
|
|
|
@ -39,9 +39,12 @@
|
|||
#include "mem/ruby/common/Global.hh"
|
||||
#include "mem/ruby/eventqueue/RubyEventQueue.hh"
|
||||
#include "mem/ruby/system/RubyPort.hh"
|
||||
#include "mem/ruby/slicc_interface/AbstractController.hh"
|
||||
#include "params/RubySystem.hh"
|
||||
#include "sim/sim_object.hh"
|
||||
|
||||
class AbstractController;
|
||||
class AbstractMemory;
|
||||
class CacheRecorder;
|
||||
class MemoryVector;
|
||||
class Network;
|
||||
|
@ -128,6 +131,12 @@ class RubySystem : public SimObject
|
|||
virtual void serialize(std::ostream &os);
|
||||
virtual void unserialize(Checkpoint *cp, const std::string §ion);
|
||||
|
||||
void registerNetwork(Network*);
|
||||
void registerProfiler(Profiler*);
|
||||
void registerTracer(Tracer*);
|
||||
void registerAbstractMemory(AbstractMemory*);
|
||||
void registerAbstractController(AbstractController*);
|
||||
|
||||
private:
|
||||
// Private copy constructor and assignment operator
|
||||
RubySystem(const RubySystem& obj);
|
||||
|
@ -153,6 +162,7 @@ class RubySystem : public SimObject
|
|||
static Profiler* m_profiler_ptr;
|
||||
static Tracer* m_tracer_ptr;
|
||||
static MemoryVector* m_mem_vec_ptr;
|
||||
std::vector<AbstractController*> m_abs_cntrl_vec;
|
||||
};
|
||||
|
||||
inline std::ostream&
|
||||
|
@ -180,6 +190,3 @@ class RubyExitCallback : public Callback
|
|||
};
|
||||
|
||||
#endif // __MEM_RUBY_SYSTEM_SYSTEM_HH__
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -49,10 +49,15 @@ class MemberExprAST(ExprAST):
|
|||
code.fix(fix)
|
||||
|
||||
# Verify that this is a valid field name for this type
|
||||
if self.field not in return_type.data_members:
|
||||
self.error("Invalid object field: " +
|
||||
"Type '%s' does not have data member %s" % \
|
||||
(return_type, self.field))
|
||||
|
||||
# Return the type of the field
|
||||
return return_type.data_members[self.field].type
|
||||
if self.field in return_type.data_members:
|
||||
# Return the type of the field
|
||||
return return_type.data_members[self.field].type
|
||||
else:
|
||||
if "interface" in return_type:
|
||||
interface_type = self.symtab.find(return_type["interface"]);
|
||||
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))
|
||||
|
|
|
@ -73,8 +73,8 @@ options.l3_assoc=2
|
|||
nb_cores = 8
|
||||
|
||||
# ruby does not support atomic, functional, or uncacheable accesses
|
||||
cpus = [ MemTest(atomic=False, percent_functional=0, \
|
||||
percent_uncacheable=0) \
|
||||
cpus = [ MemTest(atomic=False, percent_functional=50,
|
||||
percent_uncacheable=0, suppress_func_warnings=True) \
|
||||
for i in xrange(nb_cores) ]
|
||||
|
||||
# overwrite options.num_cpus with the nb_cores value
|
||||
|
@ -85,7 +85,7 @@ system = System(cpu = cpus,
|
|||
funcmem = PhysicalMemory(),
|
||||
physmem = PhysicalMemory())
|
||||
|
||||
system.ruby = Ruby.create_system(options, system)
|
||||
Ruby.create_system(options, system)
|
||||
|
||||
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 doesn't need the backing image of memory when running with
|
||||
# the tester.
|
||||
#
|
||||
ruby_port.access_phys_mem = False
|
||||
|
||||
# -----------------------
|
||||
# run simulation
|
||||
# -----------------------
|
||||
|
|
|
@ -77,7 +77,7 @@ tester = RubyTester(checks_to_complete = 100, wakeup_frequency = 10)
|
|||
|
||||
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))
|
||||
|
||||
|
@ -99,6 +99,12 @@ for ruby_port in system.ruby._cpu_ruby_ports:
|
|||
#
|
||||
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
|
||||
# -----------------------
|
||||
|
|
|
@ -77,7 +77,7 @@ options.num_cpus = nb_cores
|
|||
# system simulated
|
||||
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))
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ options.num_cpus = 1
|
|||
cpu = TimingSimpleCPU(cpu_id=0)
|
||||
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)
|
||||
|
||||
|
|
Loading…
Reference in a new issue