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,
generator = generator)
system.ruby = Ruby.create_system(options, system)
Ruby.create_system(options, system)
assert(options.num_cpus == len(system.ruby._cpu_ruby_ports))

View file

@ -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)]

View file

@ -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

View file

@ -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:

View file

@ -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
# -----------------------

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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")

View file

@ -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 {

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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));

View file

@ -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));

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_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) {

View file

@ -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="...") {

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) {
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(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);

View file

@ -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="...") {

View file

@ -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;

View file

@ -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);

View file

@ -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)) {

View file

@ -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="...");

View file

@ -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;

View file

@ -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;

View file

@ -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) {

View file

@ -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="...") {

View file

@ -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;

View file

@ -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) {

View file

@ -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="...") {

View file

@ -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";

View file

@ -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

View file

@ -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("");

View file

@ -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()

View file

@ -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("")

View file

@ -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

View file

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

View file

@ -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__

View file

@ -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("");

View file

@ -35,6 +35,7 @@ if not env['RUBY']:
SimObject('Controller.py')
Source('AbstractController.cc')
Source('AbstractEntry.cc')
Source('AbstractCacheEntry.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));
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;
}
}

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"
#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)
{

View file

@ -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

View file

@ -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");

View file

@ -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')

View file

@ -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'

View file

@ -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;

View file

@ -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 &section);
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__

View file

@ -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))

View file

@ -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
# -----------------------

View file

@ -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
# -----------------------

View file

@ -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))

View file

@ -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)