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))
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)]
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
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,
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
#
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
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:
#
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))
#
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
# -----------------------
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
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.")
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
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)
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)
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.")
#
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
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)
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.")
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
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)
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)
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.")
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
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)
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)
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.")
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
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
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
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.
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
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")
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;
// set up counters
noResponseCycles = 0;
numReads = 0;
+ numWrites = 0;
schedule(tickEvent, 0);
accessRetry = false;
dmaOutstanding = false;
}
- DPRINTF(MemTest, "completing %s at address %x (blk %x)\n",
+ DPRINTF(MemTest, "completing %s at address %x (blk %x) %s\n",
pkt->isWrite() ? "write" : "read",
- req->getPaddr(), blockAddr(req->getPaddr()));
+ req->getPaddr(), blockAddr(req->getPaddr()),
+ pkt->isError() ? "error" : "success");
MemTestSenderState *state =
dynamic_cast<MemTestSenderState *>(pkt->senderState);
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;
pkt->senderState = state;
if (do_functional) {
+ assert(pkt->needsResponse());
+ pkt->setSuppressFuncError();
cachePort.sendFunctional(pkt);
completeRequest(pkt);
} else {
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 {
Tick noResponseCycles;
uint64_t numReads;
+ uint64_t numWrites;
uint64_t maxLoads;
bool atomic;
+ bool suppress_func_warnings;
Stats::Scalar numReadsStat;
Stats::Scalar numWritesStat;
{ 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
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
/// 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;
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
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
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));
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";
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));
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";
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) {
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="...") {
}
}
+ DataBlock getDataBlock(Address addr), return_by_ref="yes" {
+ return getCacheEntry(addr).DataBlk;
+ }
+
GenericMachineType getNondirectHitMachType(MachineID sender) {
if (machineIDToMachineType(sender) == MachineType:L1Cache) {
//
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) {
}
}
+ 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);
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="...") {
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;
}
}
}
+ 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;
// 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";
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;
}
}
}
+ DataBlock getDataBlock(Address addr), return_by_ref="yes" {
+ return getCacheEntry(addr).DataBlk;
+ }
+
MessageBuffer triggerQueue, ordered="true";
out_port(globalRequestNetwork_out, RequestMsg, GlobalRequestFromL2Cache);
// 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";
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;
}
}
}
+ 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)) {
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="...");
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;
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;
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
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;
return Directory_State_to_permission(tbe.TBEState);
}
- return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState);
+ if (directory.isPresent(addr)) {
+ DPRINTF(RubySlicc, "%s\n", Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState));
+ return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState);
+ }
+
+ DPRINTF(RubySlicc, "AccessPermission_NotPresent\n");
+ return AccessPermission:NotPresent;
}
void setAccessPermission(Address addr, State state) {
void setAccessPermission(Address addr, State state) {
}
+ 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="...") {
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;
// 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_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_F, AccessPermission:Invalid, desc="Blocked on a flush";
- NO_F_W, AccessPermission:Invalid, desc="Not Owner, Blocked, waiting for Dram";
+ NO_R, AccessPermission:Busy, desc="Was Not Owner or Sharer, replacing probe filter entry";
+
+ 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:Busy, desc="Blocked on a flush";
+ NO_F_W, AccessPermission:Busy, desc="Not Owner, Blocked, waiting for Dram";
}
// Events
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));
return Directory_State_to_permission(tbe.TBEState);
}
- return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState);
+ if(directory.isPresent(addr)) {
+ return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState);
+ }
+
+ return AccessPermission:NotPresent;
}
void setAccessPermission(PfEntry pf_entry, Address addr, State state) {
void setAccessPermission(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="...") {
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";
// Initialize the controller's network pointers
m_topology_ptr->initNetworkPtr(this);
+ p->ruby_system->registerNetwork(this);
}
void
number_of_virtual_networks = Param.Int(10, "");
topology = Param.Topology("");
control_msg_size = Param.Int(8, "");
+ ruby_system = Param.RubySystem("");
m_inst_profiler_ptr->setHotLines(m_hot_lines);
m_inst_profiler_ptr->setAllInstructions(m_all_instructions);
}
+
+ p->ruby_system->registerProfiler(this);
}
Profiler::~Profiler()
hot_lines = Param.Bool(False, "")
all_instructions = Param.Bool(False, "")
num_of_sequencers = Param.Int("")
+ ruby_system = Param.RubySystem("")
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
type = 'RubyTracer'
cxx_class = 'Tracer'
warmup_length = Param.Int(100000, "")
+ ruby_system = Param.RubySystem("")
#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"
{
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
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;
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__
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("");
SimObject('Controller.py')
+Source('AbstractController.cc')
Source('AbstractEntry.cc')
Source('AbstractCacheEntry.cc')
Source('RubyRequest.cc')
+++ /dev/null
-# 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");
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)) {
// 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);
if (entry == NULL) {
entry = new Directory_Entry();
entry->getDataBlk().assign(m_ram->getBlockPtr(address));
+ entry->changePermission(AccessPermission_Read_Only);
m_entries[idx] = entry;
}
}
+++ /dev/null
-# 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")
#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"
m_usingRubyTester = p->using_ruby_tester;
access_phys_mem = p->access_phys_mem;
+
+ ruby_system = p->ruby_system;
}
void
{
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") {
assert (physMemPort == NULL);
physMemPort = new M5Port(csprintf("%s-physMemPort", name()), this,
- access_phys_mem);
+ ruby_system, access_phys_mem);
return physMemPort;
}
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;
}
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)
{
{
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;
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;
M5Port* physMemPort;
PhysicalMemory* physmem;
+ RubySystem* ruby_system;
//
// Based on similar code in the M5 bus. Stores pointers to those ports
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");
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')
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'
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) {
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;
#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;
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);
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&
};
#endif // __MEM_RUBY_SYSTEM_SYSTEM_HH__
-
-
-
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))
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
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))
#
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
# -----------------------
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))
#
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
# -----------------------
# 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))
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)