From c86f849d5a1da1fc77f2fca43b82cb6760f68bc9 Mon Sep 17 00:00:00 2001 From: "Brad Beckmann ext:(%2C%20Nilay%20Vaish%20%3Cnilay%40cs.wisc.edu%3E)" Date: Thu, 30 Jun 2011 19:49:26 -0500 Subject: [PATCH] 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. --- configs/example/ruby_direct_test.py | 2 +- configs/example/ruby_fs.py | 5 +- configs/example/ruby_mem_test.py | 24 ++- configs/example/ruby_network_test.py | 2 +- configs/example/ruby_random_test.py | 8 +- configs/example/se.py | 2 +- configs/ruby/MESI_CMP_directory.py | 17 +- configs/ruby/MI_example.py | 11 +- configs/ruby/MOESI_CMP_directory.py | 19 +- configs/ruby/MOESI_CMP_token.py | 17 +- configs/ruby/MOESI_hammer.py | 13 +- configs/ruby/Ruby.py | 24 +-- src/cpu/testers/memtest/MemTest.py | 2 + src/cpu/testers/memtest/memtest.cc | 63 ++++--- src/cpu/testers/memtest/memtest.hh | 2 + src/mem/packet.cc | 6 +- src/mem/packet.hh | 19 ++ .../protocol/MESI_CMP_directory-L1cache.sm | 7 + .../protocol/MESI_CMP_directory-L2cache.sm | 9 +- src/mem/protocol/MESI_CMP_directory-dir.sm | 15 +- src/mem/protocol/MESI_CMP_directory-dma.sm | 4 + src/mem/protocol/MI_example-cache.sm | 4 + src/mem/protocol/MI_example-dir.sm | 10 +- src/mem/protocol/MI_example-dma.sm | 4 + .../protocol/MOESI_CMP_directory-L1cache.sm | 7 + .../protocol/MOESI_CMP_directory-L2cache.sm | 24 ++- src/mem/protocol/MOESI_CMP_directory-dir.sm | 18 +- src/mem/protocol/MOESI_CMP_directory-dma.sm | 4 + src/mem/protocol/MOESI_CMP_token-L1cache.sm | 4 + src/mem/protocol/MOESI_CMP_token-L2cache.sm | 4 + src/mem/protocol/MOESI_CMP_token-dir.sm | 14 +- src/mem/protocol/MOESI_CMP_token-dma.sm | 4 + src/mem/protocol/MOESI_hammer-cache.sm | 4 + src/mem/protocol/MOESI_hammer-dir.sm | 62 ++++--- src/mem/protocol/MOESI_hammer-dma.sm | 4 + src/mem/protocol/RubySlicc_Exports.sm | 7 + src/mem/ruby/network/Network.cc | 1 + src/mem/ruby/network/Network.py | 1 + src/mem/ruby/profiler/Profiler.cc | 2 + src/mem/ruby/profiler/Profiler.py | 1 + src/mem/ruby/recorder/Tracer.cc | 2 +- src/mem/ruby/recorder/Tracer.py | 1 + .../slicc_interface/AbstractController.hh | 9 +- src/mem/ruby/slicc_interface/Controller.py | 1 + src/mem/ruby/slicc_interface/SConscript | 1 + src/mem/ruby/system/Cache.py | 41 ---- src/mem/ruby/system/DirectoryMemory.cc | 4 +- src/mem/ruby/system/DirectoryMemory.py | 43 ----- src/mem/ruby/system/RubyPort.cc | 175 +++++++++++++++++- src/mem/ruby/system/RubyPort.hh | 7 +- src/mem/ruby/system/RubySystem.py | 3 - src/mem/ruby/system/SConscript | 3 +- src/mem/ruby/system/Sequencer.py | 1 + src/mem/ruby/system/System.cc | 28 ++- src/mem/ruby/system/System.hh | 13 +- src/mem/slicc/ast/MemberExprAST.py | 19 +- tests/configs/memtest-ruby.py | 12 +- tests/configs/rubytest-ruby.py | 8 +- tests/configs/simple-timing-mp-ruby.py | 2 +- tests/configs/simple-timing-ruby.py | 2 +- 60 files changed, 576 insertions(+), 249 deletions(-) delete mode 100644 src/mem/ruby/system/Cache.py delete mode 100644 src/mem/ruby/system/DirectoryMemory.py diff --git a/configs/example/ruby_direct_test.py b/configs/example/ruby_direct_test.py index 12585b8d5..55b1c85e6 100644 --- a/configs/example/ruby_direct_test.py +++ b/configs/example/ruby_direct_test.py @@ -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)) diff --git a/configs/example/ruby_fs.py b/configs/example/ruby_fs.py index 8c03e14cb..ba4671d6e 100644 --- a/configs/example/ruby_fs.py +++ b/configs/example/ruby_fs.py @@ -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)] diff --git a/configs/example/ruby_mem_test.py b/configs/example/ruby_mem_test.py index 154164919..684aeffcc 100644 --- a/configs/example/ruby_mem_test.py +++ b/configs/example/ruby_mem_test.py @@ -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 diff --git a/configs/example/ruby_network_test.py b/configs/example/ruby_network_test.py index fb2a642b8..d15206163 100644 --- a/configs/example/ruby_network_test.py +++ b/configs/example/ruby_network_test.py @@ -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: diff --git a/configs/example/ruby_random_test.py b/configs/example/ruby_random_test.py index b60afc192..7655e32fd 100644 --- a/configs/example/ruby_random_test.py +++ b/configs/example/ruby_random_test.py @@ -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 # ----------------------- diff --git a/configs/example/se.py b/configs/example/se.py index 9c35f80a0..be7d87bc6 100644 --- a/configs/example/se.py +++ b/configs/example/se.py @@ -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 diff --git a/configs/ruby/MESI_CMP_directory.py b/configs/ruby/MESI_CMP_directory.py index f0e072f90..fdb6ce0b0 100644 --- a/configs/ruby/MESI_CMP_directory.py +++ b/configs/ruby/MESI_CMP_directory.py @@ -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) diff --git a/configs/ruby/MI_example.py b/configs/ruby/MI_example.py index 5018f2c18..4ea5e5993 100644 --- a/configs/ruby/MI_example.py +++ b/configs/ruby/MI_example.py @@ -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) diff --git a/configs/ruby/MOESI_CMP_directory.py b/configs/ruby/MOESI_CMP_directory.py index c8b16fc5d..5da1cf310 100644 --- a/configs/ruby/MOESI_CMP_directory.py +++ b/configs/ruby/MOESI_CMP_directory.py @@ -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) diff --git a/configs/ruby/MOESI_CMP_token.py b/configs/ruby/MOESI_CMP_token.py index 36999be5d..c7f9dda11 100644 --- a/configs/ruby/MOESI_CMP_token.py +++ b/configs/ruby/MOESI_CMP_token.py @@ -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) diff --git a/configs/ruby/MOESI_hammer.py b/configs/ruby/MOESI_hammer.py index 7e789d8e3..6e46f3e0f 100644 --- a/configs/ruby/MOESI_hammer.py +++ b/configs/ruby/MOESI_hammer.py @@ -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 diff --git a/configs/ruby/Ruby.py b/configs/ruby/Ruby.py index 3c58dfd2f..9174709b4 100644 --- a/configs/ruby/Ruby.py +++ b/configs/ruby/Ruby.py @@ -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 diff --git a/src/cpu/testers/memtest/MemTest.py b/src/cpu/testers/memtest/MemTest.py index 957de8088..d5f456d69 100644 --- a/src/cpu/testers/memtest/MemTest.py +++ b/src/cpu/testers/memtest/MemTest.py @@ -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") diff --git a/src/cpu/testers/memtest/memtest.cc b/src/cpu/testers/memtest/memtest.cc index d75bcb845..ef23825cd 100644 --- a/src/cpu/testers/memtest/memtest.cc +++ b/src/cpu/testers/memtest/memtest.cc @@ -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(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 { diff --git a/src/cpu/testers/memtest/memtest.hh b/src/cpu/testers/memtest/memtest.hh index 4e489de5c..292e7d83d 100644 --- a/src/cpu/testers/memtest/memtest.hh +++ b/src/cpu/testers/memtest/memtest.hh @@ -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; diff --git a/src/mem/packet.cc b/src/mem/packet.cc index 0296e7f0b..5ec977ed4 100644 --- a/src/mem/packet.cc +++ b/src/mem/packet.cc @@ -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 diff --git a/src/mem/packet.hh b/src/mem/packet.hh index 5fcd9286e..be0c20d42 100644 --- a/src/mem/packet.hh +++ b/src/mem/packet.hh @@ -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 diff --git a/src/mem/protocol/MESI_CMP_directory-L1cache.sm b/src/mem/protocol/MESI_CMP_directory-L1cache.sm index ebbd09ae0..287bda004 100644 --- a/src/mem/protocol/MESI_CMP_directory-L1cache.sm +++ b/src/mem/protocol/MESI_CMP_directory-L1cache.sm @@ -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)); diff --git a/src/mem/protocol/MESI_CMP_directory-L2cache.sm b/src/mem/protocol/MESI_CMP_directory-L2cache.sm index 6044f5233..a8fcb07d1 100644 --- a/src/mem/protocol/MESI_CMP_directory-L2cache.sm +++ b/src/mem/protocol/MESI_CMP_directory-L2cache.sm @@ -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)); diff --git a/src/mem/protocol/MESI_CMP_directory-dir.sm b/src/mem/protocol/MESI_CMP_directory-dir.sm index 6e3e79641..423272905 100644 --- a/src/mem/protocol/MESI_CMP_directory-dir.sm +++ b/src/mem/protocol/MESI_CMP_directory-dir.sm @@ -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) { diff --git a/src/mem/protocol/MESI_CMP_directory-dma.sm b/src/mem/protocol/MESI_CMP_directory-dma.sm index aee2e467d..f32c73218 100644 --- a/src/mem/protocol/MESI_CMP_directory-dma.sm +++ b/src/mem/protocol/MESI_CMP_directory-dma.sm @@ -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="...") { diff --git a/src/mem/protocol/MI_example-cache.sm b/src/mem/protocol/MI_example-cache.sm index afc415b5a..b11fddd95 100644 --- a/src/mem/protocol/MI_example-cache.sm +++ b/src/mem/protocol/MI_example-cache.sm @@ -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) { // diff --git a/src/mem/protocol/MI_example-dir.sm b/src/mem/protocol/MI_example-dir.sm index baffe2412..2bd3afa44 100644 --- a/src/mem/protocol/MI_example-dir.sm +++ b/src/mem/protocol/MI_example-dir.sm @@ -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); diff --git a/src/mem/protocol/MI_example-dma.sm b/src/mem/protocol/MI_example-dma.sm index 8d79976fc..e13d247c7 100644 --- a/src/mem/protocol/MI_example-dma.sm +++ b/src/mem/protocol/MI_example-dma.sm @@ -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="...") { diff --git a/src/mem/protocol/MOESI_CMP_directory-L1cache.sm b/src/mem/protocol/MOESI_CMP_directory-L1cache.sm index 35832ee9c..2845d1ad1 100644 --- a/src/mem/protocol/MOESI_CMP_directory-L1cache.sm +++ b/src/mem/protocol/MOESI_CMP_directory-L1cache.sm @@ -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; diff --git a/src/mem/protocol/MOESI_CMP_directory-L2cache.sm b/src/mem/protocol/MOESI_CMP_directory-L2cache.sm index 8202a9c2f..eb9693ed9 100644 --- a/src/mem/protocol/MOESI_CMP_directory-L2cache.sm +++ b/src/mem/protocol/MOESI_CMP_directory-L2cache.sm @@ -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); diff --git a/src/mem/protocol/MOESI_CMP_directory-dir.sm b/src/mem/protocol/MOESI_CMP_directory-dir.sm index b13b56ffb..b71518b3f 100644 --- a/src/mem/protocol/MOESI_CMP_directory-dir.sm +++ b/src/mem/protocol/MOESI_CMP_directory-dir.sm @@ -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)) { diff --git a/src/mem/protocol/MOESI_CMP_directory-dma.sm b/src/mem/protocol/MOESI_CMP_directory-dma.sm index 0d99e354e..e3aefbe51 100644 --- a/src/mem/protocol/MOESI_CMP_directory-dma.sm +++ b/src/mem/protocol/MOESI_CMP_directory-dma.sm @@ -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="..."); diff --git a/src/mem/protocol/MOESI_CMP_token-L1cache.sm b/src/mem/protocol/MOESI_CMP_token-L1cache.sm index d557132fc..66789b594 100644 --- a/src/mem/protocol/MOESI_CMP_token-L1cache.sm +++ b/src/mem/protocol/MOESI_CMP_token-L1cache.sm @@ -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; diff --git a/src/mem/protocol/MOESI_CMP_token-L2cache.sm b/src/mem/protocol/MOESI_CMP_token-L2cache.sm index c9c729263..078b5c7a6 100644 --- a/src/mem/protocol/MOESI_CMP_token-L2cache.sm +++ b/src/mem/protocol/MOESI_CMP_token-L2cache.sm @@ -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; diff --git a/src/mem/protocol/MOESI_CMP_token-dir.sm b/src/mem/protocol/MOESI_CMP_token-dir.sm index 9ca0f1fc6..9e6c6c99b 100644 --- a/src/mem/protocol/MOESI_CMP_token-dir.sm +++ b/src/mem/protocol/MOESI_CMP_token-dir.sm @@ -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) { diff --git a/src/mem/protocol/MOESI_CMP_token-dma.sm b/src/mem/protocol/MOESI_CMP_token-dma.sm index 40b60490c..98666998a 100644 --- a/src/mem/protocol/MOESI_CMP_token-dma.sm +++ b/src/mem/protocol/MOESI_CMP_token-dma.sm @@ -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="...") { diff --git a/src/mem/protocol/MOESI_hammer-cache.sm b/src/mem/protocol/MOESI_hammer-cache.sm index 6fe12d561..edb1587e3 100644 --- a/src/mem/protocol/MOESI_hammer-cache.sm +++ b/src/mem/protocol/MOESI_hammer-cache.sm @@ -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; diff --git a/src/mem/protocol/MOESI_hammer-dir.sm b/src/mem/protocol/MOESI_hammer-dir.sm index 828c762cb..bb0a97ac4 100644 --- a/src/mem/protocol/MOESI_hammer-dir.sm +++ b/src/mem/protocol/MOESI_hammer-dir.sm @@ -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_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 @@ -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) { diff --git a/src/mem/protocol/MOESI_hammer-dma.sm b/src/mem/protocol/MOESI_hammer-dma.sm index f254c1633..bfb3cb98d 100644 --- a/src/mem/protocol/MOESI_hammer-dma.sm +++ b/src/mem/protocol/MOESI_hammer-dma.sm @@ -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="...") { diff --git a/src/mem/protocol/RubySlicc_Exports.sm b/src/mem/protocol/RubySlicc_Exports.sm index ccd3aeb7f..2e4a16784 100644 --- a/src/mem/protocol/RubySlicc_Exports.sm +++ b/src/mem/protocol/RubySlicc_Exports.sm @@ -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"; diff --git a/src/mem/ruby/network/Network.cc b/src/mem/ruby/network/Network.cc index caab89715..adb90eba9 100644 --- a/src/mem/ruby/network/Network.cc +++ b/src/mem/ruby/network/Network.cc @@ -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 diff --git a/src/mem/ruby/network/Network.py b/src/mem/ruby/network/Network.py index 909f2f727..9642b046e 100644 --- a/src/mem/ruby/network/Network.py +++ b/src/mem/ruby/network/Network.py @@ -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(""); diff --git a/src/mem/ruby/profiler/Profiler.cc b/src/mem/ruby/profiler/Profiler.cc index afb77f09f..08a4439db 100644 --- a/src/mem/ruby/profiler/Profiler.cc +++ b/src/mem/ruby/profiler/Profiler.cc @@ -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() diff --git a/src/mem/ruby/profiler/Profiler.py b/src/mem/ruby/profiler/Profiler.py index d15573aa4..3521911c2 100644 --- a/src/mem/ruby/profiler/Profiler.py +++ b/src/mem/ruby/profiler/Profiler.py @@ -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("") diff --git a/src/mem/ruby/recorder/Tracer.cc b/src/mem/ruby/recorder/Tracer.cc index bff59a832..fcfe5338c 100644 --- a/src/mem/ruby/recorder/Tracer.cc +++ b/src/mem/ruby/recorder/Tracer.cc @@ -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 diff --git a/src/mem/ruby/recorder/Tracer.py b/src/mem/ruby/recorder/Tracer.py index 7b6fd8421..7a689f9f7 100644 --- a/src/mem/ruby/recorder/Tracer.py +++ b/src/mem/ruby/recorder/Tracer.py @@ -34,3 +34,4 @@ class RubyTracer(SimObject): type = 'RubyTracer' cxx_class = 'Tracer' warmup_length = Param.Int(100000, "") + ruby_system = Param.RubySystem("") diff --git a/src/mem/ruby/slicc_interface/AbstractController.hh b/src/mem/ruby/slicc_interface/AbstractController.hh index eb8399af2..f1dac39ad 100644 --- a/src/mem/ruby/slicc_interface/AbstractController.hh +++ b/src/mem/ruby/slicc_interface/AbstractController.hh @@ -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__ diff --git a/src/mem/ruby/slicc_interface/Controller.py b/src/mem/ruby/slicc_interface/Controller.py index a5ad45145..44e08ecdc 100644 --- a/src/mem/ruby/slicc_interface/Controller.py +++ b/src/mem/ruby/slicc_interface/Controller.py @@ -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(""); diff --git a/src/mem/ruby/slicc_interface/SConscript b/src/mem/ruby/slicc_interface/SConscript index 256f8e64e..9d4e6fe3b 100644 --- a/src/mem/ruby/slicc_interface/SConscript +++ b/src/mem/ruby/slicc_interface/SConscript @@ -35,6 +35,7 @@ if not env['RUBY']: SimObject('Controller.py') +Source('AbstractController.cc') Source('AbstractEntry.cc') Source('AbstractCacheEntry.cc') Source('RubyRequest.cc') diff --git a/src/mem/ruby/system/Cache.py b/src/mem/ruby/system/Cache.py deleted file mode 100644 index ab3ec4b29..000000000 --- a/src/mem/ruby/system/Cache.py +++ /dev/null @@ -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"); diff --git a/src/mem/ruby/system/DirectoryMemory.cc b/src/mem/ruby/system/DirectoryMemory.cc index fe54c8d79..c461ce09b 100644 --- a/src/mem/ruby/system/DirectoryMemory.cc +++ b/src/mem/ruby/system/DirectoryMemory.cc @@ -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; } } diff --git a/src/mem/ruby/system/DirectoryMemory.py b/src/mem/ruby/system/DirectoryMemory.py deleted file mode 100644 index d3b6bc591..000000000 --- a/src/mem/ruby/system/DirectoryMemory.py +++ /dev/null @@ -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") diff --git a/src/mem/ruby/system/RubyPort.cc b/src/mem/ruby/system/RubyPort.cc index 40f893257..662f971f2 100644 --- a/src/mem/ruby/system/RubyPort.cc +++ b/src/mem/ruby/system/RubyPort.cc @@ -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(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(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) { diff --git a/src/mem/ruby/system/RubyPort.hh b/src/mem/ruby/system/RubyPort.hh index dc7a141c3..e1ba2f7d1 100644 --- a/src/mem/ruby/system/RubyPort.hh +++ b/src/mem/ruby/system/RubyPort.hh @@ -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 diff --git a/src/mem/ruby/system/RubySystem.py b/src/mem/ruby/system/RubySystem.py index 7878cec63..d66ada4b9 100644 --- a/src/mem/ruby/system/RubySystem.py +++ b/src/mem/ruby/system/RubySystem.py @@ -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"); diff --git a/src/mem/ruby/system/SConscript b/src/mem/ruby/system/SConscript index f1e7c425c..0820ef2c8 100644 --- a/src/mem/ruby/system/SConscript +++ b/src/mem/ruby/system/SConscript @@ -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') diff --git a/src/mem/ruby/system/Sequencer.py b/src/mem/ruby/system/Sequencer.py index 16fb795f8..5d56dc000 100644 --- a/src/mem/ruby/system/Sequencer.py +++ b/src/mem/ruby/system/Sequencer.py @@ -43,6 +43,7 @@ class RubyPort(MemObject): using_network_tester = Param.Bool(False, "") access_phys_mem = Param.Bool(True, "should the rubyport atomically update phys_mem") + ruby_system = Param.RubySystem("") class RubySequencer(RubyPort): type = 'RubySequencer' diff --git a/src/mem/ruby/system/System.cc b/src/mem/ruby/system/System.cc index d9c4fa821..81824b9b7 100644 --- a/src/mem/ruby/system/System.cc +++ b/src/mem/ruby/system/System.cc @@ -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; diff --git a/src/mem/ruby/system/System.hh b/src/mem/ruby/system/System.hh index 608aca1d8..88a0186c5 100644 --- a/src/mem/ruby/system/System.hh +++ b/src/mem/ruby/system/System.hh @@ -39,9 +39,12 @@ #include "mem/ruby/common/Global.hh" #include "mem/ruby/eventqueue/RubyEventQueue.hh" #include "mem/ruby/system/RubyPort.hh" +#include "mem/ruby/slicc_interface/AbstractController.hh" #include "params/RubySystem.hh" #include "sim/sim_object.hh" +class AbstractController; +class AbstractMemory; class CacheRecorder; class MemoryVector; class Network; @@ -128,6 +131,12 @@ class RubySystem : public SimObject virtual void serialize(std::ostream &os); virtual void unserialize(Checkpoint *cp, const std::string §ion); + void registerNetwork(Network*); + void registerProfiler(Profiler*); + void registerTracer(Tracer*); + void registerAbstractMemory(AbstractMemory*); + void registerAbstractController(AbstractController*); + private: // Private copy constructor and assignment operator RubySystem(const RubySystem& obj); @@ -153,6 +162,7 @@ class RubySystem : public SimObject static Profiler* m_profiler_ptr; static Tracer* m_tracer_ptr; static MemoryVector* m_mem_vec_ptr; + std::vector m_abs_cntrl_vec; }; inline std::ostream& @@ -180,6 +190,3 @@ class RubyExitCallback : public Callback }; #endif // __MEM_RUBY_SYSTEM_SYSTEM_HH__ - - - diff --git a/src/mem/slicc/ast/MemberExprAST.py b/src/mem/slicc/ast/MemberExprAST.py index a13205252..412c178d8 100644 --- a/src/mem/slicc/ast/MemberExprAST.py +++ b/src/mem/slicc/ast/MemberExprAST.py @@ -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)) diff --git a/tests/configs/memtest-ruby.py b/tests/configs/memtest-ruby.py index 8e66c7334..49f152017 100644 --- a/tests/configs/memtest-ruby.py +++ b/tests/configs/memtest-ruby.py @@ -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 # ----------------------- diff --git a/tests/configs/rubytest-ruby.py b/tests/configs/rubytest-ruby.py index 9c3207a90..b63833ccf 100644 --- a/tests/configs/rubytest-ruby.py +++ b/tests/configs/rubytest-ruby.py @@ -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 # ----------------------- diff --git a/tests/configs/simple-timing-mp-ruby.py b/tests/configs/simple-timing-mp-ruby.py index 56b7ae1eb..d57ccea15 100644 --- a/tests/configs/simple-timing-mp-ruby.py +++ b/tests/configs/simple-timing-mp-ruby.py @@ -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)) diff --git a/tests/configs/simple-timing-ruby.py b/tests/configs/simple-timing-ruby.py index c07881d24..1d67f6f97 100644 --- a/tests/configs/simple-timing-ruby.py +++ b/tests/configs/simple-timing-ruby.py @@ -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) -- 2.30.2