diff --git a/configs/common/MemConfig.py b/configs/common/MemConfig.py index d203118aa..57066426f 100644 --- a/configs/common/MemConfig.py +++ b/configs/common/MemConfig.py @@ -54,7 +54,8 @@ _mem_aliases_all = [ ("lpddr2_s4_1066_x32", "LPDDR2_S4_1066_x32"), ("lpddr3_1600_x32", "LPDDR3_1600_x32"), ("wio_200_x128", "WideIO_200_x128"), - ("dramsim2", "DRAMSim2") + ("dramsim2", "DRAMSim2"), + ("ruby_memory", "RubyMemoryControl") ] # Filtered list of aliases. Only aliases for existing memory diff --git a/configs/example/fs.py b/configs/example/fs.py index abf8fe966..727f69339 100644 --- a/configs/example/fs.py +++ b/configs/example/fs.py @@ -137,8 +137,6 @@ def build_test_system(np): Ruby.create_system(options, True, test_sys, test_sys.iobus, test_sys._dma_ports) - test_sys.physmem = [SimpleMemory(range = r, null = True) - for r in test_sys.mem_ranges] # Create a seperate clock domain for Ruby test_sys.ruby.clk_domain = SrcClockDomain(clock = options.ruby_clock, diff --git a/configs/example/ruby_direct_test.py b/configs/example/ruby_direct_test.py index 6773aea6d..857909ba9 100644 --- a/configs/example/ruby_direct_test.py +++ b/configs/example/ruby_direct_test.py @@ -48,7 +48,7 @@ m5_root = os.path.dirname(config_root) parser = optparse.OptionParser() Options.addCommonOptions(parser) -parser.add_option("-l", "--requests", metavar="N", default=100, +parser.add_option("--requests", metavar="N", default=100, help="Stop after N requests") parser.add_option("-f", "--wakeup_freq", metavar="N", default=10, help="Wakeup every N cycles") @@ -87,13 +87,8 @@ else: print "Error: unknown direct test generator" sys.exit(1) -# -# Create the M5 system. Note that the Memory Object isn't -# actually used by the rubytester, but is included to support the -# M5 memory size == Ruby memory size checks -# -system = System(physmem = SimpleMemory(), - mem_ranges = [AddrRange(options.mem_size)]) +# Create the M5 system. +system = System(mem_ranges = [AddrRange(options.mem_size)]) # Create a top-level voltage domain and clock domain @@ -102,12 +97,9 @@ system.voltage_domain = VoltageDomain(voltage = options.sys_voltage) system.clk_domain = SrcClockDomain(clock = options.sys_clock, voltage_domain = system.voltage_domain) -# # Create the ruby random tester -# -system.cpu = RubyDirectedTester(requests_to_complete = \ - options.requests, - generator = generator) +system.cpu = RubyDirectedTester(requests_to_complete = options.requests, + generator = generator) Ruby.create_system(options, False, system) @@ -121,7 +113,7 @@ for ruby_port in system.ruby._cpu_ports: # # Tie the ruby tester ports to the ruby cpu ports # - system.tester.cpuPort = ruby_port.slave + system.cpu.cpuPort = ruby_port.slave # ----------------------- # run simulation diff --git a/configs/example/ruby_mem_test.py b/configs/example/ruby_mem_test.py index 15684d153..f5e6d2a82 100644 --- a/configs/example/ruby_mem_test.py +++ b/configs/example/ruby_mem_test.py @@ -107,7 +107,6 @@ cpus = [ MemTest(atomic = False, system = System(cpu = cpus, funcmem = SimpleMemory(in_addr_map = False), funcbus = NoncoherentXBar(), - physmem = SimpleMemory(), clk_domain = SrcClockDomain(clock = options.sys_clock), mem_ranges = [AddrRange(options.mem_size)]) diff --git a/configs/example/ruby_random_test.py b/configs/example/ruby_random_test.py index 7cde5b86c..225b3d23b 100644 --- a/configs/example/ruby_random_test.py +++ b/configs/example/ruby_random_test.py @@ -97,8 +97,7 @@ tester = RubyTester(check_flush = check_flush, # actually used by the rubytester, but is included to support the # M5 memory size == Ruby memory size checks # -system = System(cpu = tester, physmem = SimpleMemory(), - mem_ranges = [AddrRange(options.mem_size)]) +system = System(cpu = tester, mem_ranges = [AddrRange(options.mem_size)]) # Create a top-level voltage domain and clock domain system.voltage_domain = VoltageDomain(voltage = options.sys_voltage) diff --git a/configs/example/se.py b/configs/example/se.py index 461ebf11c..e0535c726 100644 --- a/configs/example/se.py +++ b/configs/example/se.py @@ -225,11 +225,6 @@ if options.ruby: print >> sys.stderr, "Ruby requires TimingSimpleCPU or O3CPU!!" sys.exit(1) - # Use SimpleMemory with the null option since this memory is only used - # for determining which addresses are within the range of the memory. - # No space allocation is required. - system.physmem = SimpleMemory(range=AddrRange(options.mem_size), - null = True) options.use_map = True Ruby.create_system(options, False, system) assert(options.num_cpus == len(system.ruby._cpu_ports)) diff --git a/configs/ruby/MESI_Three_Level.py b/configs/ruby/MESI_Three_Level.py index fe2e6aef5..f9ded25f1 100644 --- a/configs/ruby/MESI_Three_Level.py +++ b/configs/ruby/MESI_Three_Level.py @@ -182,22 +182,12 @@ def create_system(options, full_system, system, dma_ports, ruby_system): # # Create the Ruby objects associated with the directory controller # - - mem_cntrl = RubyMemoryControl( - clk_domain = ruby_system.memctrl_clk_domain, - version = i, - ruby_system = ruby_system) - dir_size = MemorySize('0B') dir_size.value = mem_module_size dir_cntrl = Directory_Controller(version = i, - directory = \ - RubyDirectoryMemory(version = i, - size = dir_size, - use_map = - options.use_map), - memBuffer = mem_cntrl, + directory = RubyDirectoryMemory( + version = i, size = dir_size), transitions_per_cycle = options.ports, ruby_system = ruby_system) diff --git a/configs/ruby/MESI_Two_Level.py b/configs/ruby/MESI_Two_Level.py index 6cc4efcb9..b7bdd1447 100644 --- a/configs/ruby/MESI_Two_Level.py +++ b/configs/ruby/MESI_Two_Level.py @@ -162,25 +162,12 @@ def create_system(options, full_system, system, dma_ports, ruby_system): clk_divider=3) for i in xrange(options.num_dirs): - # - # Create the Ruby objects associated with the directory controller - # - - mem_cntrl = RubyMemoryControl( - clk_domain = ruby_system.memctrl_clk_domain, - version = i, - ruby_system = ruby_system) - dir_size = MemorySize('0B') dir_size.value = mem_module_size dir_cntrl = Directory_Controller(version = i, - directory = \ - RubyDirectoryMemory(version = i, - size = dir_size, - use_map = - options.use_map), - memBuffer = mem_cntrl, + directory = RubyDirectoryMemory( + version = i, size = dir_size), transitions_per_cycle = options.ports, ruby_system = ruby_system) diff --git a/configs/ruby/MI_example.py b/configs/ruby/MI_example.py index de1f3e924..2dd064b55 100644 --- a/configs/ruby/MI_example.py +++ b/configs/ruby/MI_example.py @@ -117,27 +117,11 @@ def create_system(options, full_system, system, dma_ports, ruby_system): clk_divider=3) for i in xrange(options.num_dirs): - # - # Create the Ruby objects associated with the directory controller - # - - mem_cntrl = RubyMemoryControl( - clk_domain = ruby_system.memctrl_clk_domain, - version = i, - ruby_system = ruby_system) - dir_size = MemorySize('0B') dir_size.value = mem_module_size - dir_cntrl = Directory_Controller(version = i, - directory = \ - RubyDirectoryMemory( \ - version = i, - size = dir_size, - use_map = options.use_map, - map_levels = \ - options.map_levels), - memBuffer = mem_cntrl, + directory = RubyDirectoryMemory( + version = i, size = dir_size), transitions_per_cycle = options.ports, ruby_system = ruby_system) diff --git a/configs/ruby/MOESI_CMP_directory.py b/configs/ruby/MOESI_CMP_directory.py index 3fb9c55a7..9c4bab434 100644 --- a/configs/ruby/MOESI_CMP_directory.py +++ b/configs/ruby/MOESI_CMP_directory.py @@ -156,24 +156,12 @@ def create_system(options, full_system, system, dma_ports, ruby_system): clk_divider=3) for i in xrange(options.num_dirs): - # - # Create the Ruby objects associated with the directory controller - # - - mem_cntrl = RubyMemoryControl( - clk_domain = ruby_system.memctrl_clk_domain, - version = i, - ruby_system = ruby_system) - dir_size = MemorySize('0B') dir_size.value = mem_module_size dir_cntrl = Directory_Controller(version = i, - directory = \ - RubyDirectoryMemory(version = i, - size = dir_size, - use_map = options.use_map), - memBuffer = mem_cntrl, + directory = RubyDirectoryMemory( + version = i, size = dir_size), transitions_per_cycle = options.ports, ruby_system = ruby_system) diff --git a/configs/ruby/MOESI_CMP_token.py b/configs/ruby/MOESI_CMP_token.py index bedc444bf..26cd625b5 100644 --- a/configs/ruby/MOESI_CMP_token.py +++ b/configs/ruby/MOESI_CMP_token.py @@ -180,24 +180,12 @@ def create_system(options, full_system, system, dma_ports, ruby_system): clk_divider=3) for i in xrange(options.num_dirs): - # - # Create the Ruby objects associated with the directory controller - # - - mem_cntrl = RubyMemoryControl( - clk_domain = ruby_system.memctrl_clk_domain, - version = i, - ruby_system = ruby_system) - dir_size = MemorySize('0B') dir_size.value = mem_module_size dir_cntrl = Directory_Controller(version = i, - directory = \ - RubyDirectoryMemory(version = i, - use_map = options.use_map, - size = dir_size), - memBuffer = mem_cntrl, + directory = RubyDirectoryMemory( + version = i, size = dir_size), l2_select_num_bits = l2_bits, transitions_per_cycle = options.ports, ruby_system = ruby_system) diff --git a/configs/ruby/MOESI_hammer.py b/configs/ruby/MOESI_hammer.py index 2f9aaebc7..740c6783e 100644 --- a/configs/ruby/MOESI_hammer.py +++ b/configs/ruby/MOESI_hammer.py @@ -170,15 +170,6 @@ def create_system(options, full_system, system, dma_ports, ruby_system): clk_divider=3) for i in xrange(options.num_dirs): - # - # Create the Ruby objects associated with the directory controller - # - - mem_cntrl = RubyMemoryControl( - clk_domain = ruby_system.memctrl_clk_domain, - version = i, - ruby_system = ruby_system) - dir_size = MemorySize('0B') dir_size.value = mem_module_size @@ -186,17 +177,9 @@ def create_system(options, full_system, system, dma_ports, ruby_system): start_index_bit = pf_start_bit) dir_cntrl = Directory_Controller(version = i, - directory = \ - RubyDirectoryMemory( \ - version = i, - size = dir_size, - use_map = options.use_map, - map_levels = \ - options.map_levels, - numa_high_bit = \ - options.numa_high_bit), + directory = RubyDirectoryMemory( + version = i, size = dir_size), probeFilter = pf, - memBuffer = mem_cntrl, probe_filter_enabled = options.pf_on, full_bit_dir_enabled = options.dir_on, transitions_per_cycle = options.ports, diff --git a/configs/ruby/Ruby.py b/configs/ruby/Ruby.py index b7fd5078b..35ff66a0c 100644 --- a/configs/ruby/Ruby.py +++ b/configs/ruby/Ruby.py @@ -45,6 +45,7 @@ from m5.objects import * from m5.defines import buildEnv from m5.util import addToPath, fatal +import MemConfig addToPath('../topologies') def define_options(parser): @@ -75,22 +76,67 @@ def define_options(parser): help="high order address bit to use for numa mapping. " \ "0 = highest bit, not specified = lowest bit") - # ruby sparse memory options - parser.add_option("--use-map", action="store_true", default=False) - parser.add_option("--map-levels", type="int", default=4) - parser.add_option("--recycle-latency", type="int", default=10, help="Recycle latency for ruby controller input buffers") parser.add_option("--random_seed", type="int", default=1234, help="Used for seeding the random number generator") - parser.add_option("--ruby_stats", type="string", default="ruby.stats") - protocol = buildEnv['PROTOCOL'] exec "import %s" % protocol eval("%s.define_options(parser)" % protocol) +def setup_memory_controllers(system, ruby, dir_cntrls, options): + ruby.block_size_bytes = options.cacheline_size + ruby.memory_size_bits = 48 + block_size_bits = int(math.log(options.cacheline_size, 2)) + + if options.numa_high_bit: + numa_bit = options.numa_high_bit + else: + # if the numa_bit is not specified, set the directory bits as the + # lowest bits above the block offset bits, and the numa_bit as the + # highest of those directory bits + dir_bits = int(math.log(options.num_dirs, 2)) + numa_bit = block_size_bits + dir_bits - 1 + + index = 0 + mem_ctrls = [] + crossbars = [] + + # Sets bits to be used for interleaving. Creates memory controllers + # attached to a directory controller. A separate controller is created + # for each address range as the abstract memory can handle only one + # contiguous address range as of now. + for dir_cntrl in dir_cntrls: + dir_cntrl.directory.numa_high_bit = numa_bit + + crossbar = None + if len(system.mem_ranges) > 1: + crossbar = NoncoherentXBar() + crossbars.append(crossbar) + dir_cntrl.memory = crossbar.slave + + for r in system.mem_ranges: + mem_ctrl = MemConfig.create_mem_ctrl( + MemConfig.get(options.mem_type), r, index, options.num_dirs, + int(math.log(options.num_dirs, 2)), options.cacheline_size) + + mem_ctrls.append(mem_ctrl) + + if crossbar != None: + mem_ctrl.port = crossbar.master + else: + mem_ctrl.port = dir_cntrl.memory + + index += 1 + + system.mem_ctrls = mem_ctrls + + if len(crossbars) > 0: + ruby.crossbars = crossbars + + def create_topology(controllers, options): """ Called from create_system in configs/ruby/.py Must return an object which is a subclass of BaseTopology @@ -103,7 +149,7 @@ def create_topology(controllers, options): def create_system(options, full_system, system, piobus = None, dma_ports = []): - system.ruby = RubySystem(no_mem_vec = options.use_map) + system.ruby = RubySystem() ruby = system.ruby # Set the network classes based on the command line options @@ -169,33 +215,7 @@ def create_system(options, full_system, system, piobus = None, dma_ports = []): network.enable_fault_model = True network.fault_model = FaultModel() - # Loop through the directory controlers. - # Determine the total memory size of the ruby system and verify it is equal - # to physmem. However, if Ruby memory is using sparse memory in SE - # mode, then the system should not back-up the memory state with - # the Memory Vector and thus the memory size bytes should stay at 0. - # Also set the numa bits to the appropriate values. - total_mem_size = MemorySize('0B') - - ruby.block_size_bytes = options.cacheline_size - block_size_bits = int(math.log(options.cacheline_size, 2)) - - if options.numa_high_bit: - numa_bit = options.numa_high_bit - else: - # if the numa_bit is not specified, set the directory bits as the - # lowest bits above the block offset bits, and the numa_bit as the - # highest of those directory bits - dir_bits = int(math.log(options.num_dirs, 2)) - numa_bit = block_size_bits + dir_bits - 1 - - for dir_cntrl in dir_cntrls: - total_mem_size.value += dir_cntrl.directory.size.value - dir_cntrl.directory.numa_high_bit = numa_bit - - phys_mem_size = sum(map(lambda r: r.size(), system.mem_ranges)) - assert(total_mem_size.value == phys_mem_size) - ruby.mem_size = total_mem_size + setup_memory_controllers(system, ruby, dir_cntrls, options) # Connect the cpu sequencers and the piobus if piobus != None: diff --git a/src/mem/protocol/MESI_Two_Level-dir.sm b/src/mem/protocol/MESI_Two_Level-dir.sm index 939ae2a36..fa9d1f3d3 100644 --- a/src/mem/protocol/MESI_Two_Level-dir.sm +++ b/src/mem/protocol/MESI_Two_Level-dir.sm @@ -28,7 +28,6 @@ machine(Directory, "MESI Two Level directory protocol") : DirectoryMemory * directory; - MemoryControl * memBuffer; Cycles to_mem_ctrl_latency := 1; Cycles directory_latency := 6; @@ -154,17 +153,21 @@ machine(Directory, "MESI Two Level directory protocol") if(is_valid(tbe)) { testAndRead(addr, tbe.DataBlk, pkt); } else { - memBuffer.functionalRead(pkt); + functionalMemoryRead(pkt); } } int functionalWrite(Address addr, Packet *pkt) { + int num_functional_writes := 0; + TBE tbe := TBEs[addr]; if(is_valid(tbe)) { - testAndWrite(addr, tbe.DataBlk, pkt); + num_functional_writes := num_functional_writes + + testAndWrite(addr, tbe.DataBlk, pkt); } - return memBuffer.functionalWrite(pkt); + num_functional_writes := num_functional_writes + functionalMemoryWrite(pkt); + return num_functional_writes; } void setAccessPermission(Address addr, State state) { @@ -182,7 +185,6 @@ machine(Directory, "MESI Two Level directory protocol") // ** OUT_PORTS ** out_port(responseNetwork_out, ResponseMsg, responseFromDir); - out_port(memQueue_out, MemoryMsg, memBuffer); // ** IN_PORTS ** @@ -223,7 +225,7 @@ machine(Directory, "MESI Two Level directory protocol") } // off-chip memory request/response is done - in_port(memQueue_in, MemoryMsg, memBuffer, rank = 2) { + in_port(memQueue_in, MemoryMsg, responseFromMemory, rank = 2) { if (memQueue_in.isReady()) { peek(memQueue_in, MemoryMsg) { if (in_msg.Type == MemoryRequestType:MEMORY_READ) { @@ -300,46 +302,21 @@ machine(Directory, "MESI Two Level directory protocol") action(qf_queueMemoryFetchRequest, "qf", desc="Queue off-chip fetch request") { peek(requestNetwork_in, RequestMsg) { - enqueue(memQueue_out, MemoryMsg, to_mem_ctrl_latency) { - out_msg.Addr := address; - out_msg.Type := MemoryRequestType:MEMORY_READ; - out_msg.Sender := machineID; - out_msg.OriginalRequestorMachId := in_msg.Requestor; - out_msg.MessageSize := in_msg.MessageSize; - out_msg.Prefetch := in_msg.Prefetch; - - DPRINTF(RubySlicc, "%s\n", out_msg); - } + queueMemoryRead(in_msg.Requestor, address, to_mem_ctrl_latency); } } action(qw_queueMemoryWBRequest, "qw", desc="Queue off-chip writeback request") { peek(responseNetwork_in, ResponseMsg) { - enqueue(memQueue_out, MemoryMsg, to_mem_ctrl_latency) { - out_msg.Addr := address; - out_msg.Type := MemoryRequestType:MEMORY_WB; - out_msg.Sender := machineID; - out_msg.OriginalRequestorMachId := in_msg.Sender; - out_msg.DataBlk := in_msg.DataBlk; - out_msg.MessageSize := in_msg.MessageSize; - //out_msg.Prefetch := in_msg.Prefetch; - - DPRINTF(RubySlicc, "%s\n", out_msg); - } + queueMemoryWrite(in_msg.Sender, address, to_mem_ctrl_latency, + in_msg.DataBlk); } } //added by SS for dma action(qf_queueMemoryFetchRequestDMA, "qfd", desc="Queue off-chip fetch request") { peek(requestNetwork_in, RequestMsg) { - enqueue(memQueue_out, MemoryMsg, to_mem_ctrl_latency) { - out_msg.Addr := address; - out_msg.Type := MemoryRequestType:MEMORY_READ; - out_msg.Sender := machineID; - out_msg.OriginalRequestorMachId := machineID; - out_msg.MessageSize := in_msg.MessageSize; - DPRINTF(RubySlicc, "%s\n", out_msg); - } + queueMemoryRead(in_msg.Requestor, address, to_mem_ctrl_latency); } } @@ -359,16 +336,11 @@ machine(Directory, "MESI Two Level directory protocol") } } - action(qw_queueMemoryWBRequest_partial, "qwp", desc="Queue off-chip writeback request") { - peek(requestNetwork_in, RequestMsg) { - enqueue(memQueue_out, MemoryMsg, to_mem_ctrl_latency) { - out_msg.Addr := address; - out_msg.Type := MemoryRequestType:MEMORY_WB; - out_msg.OriginalRequestorMachId := machineID; - out_msg.DataBlk.copyPartial(in_msg.DataBlk, addressOffset(address), in_msg.Len); - out_msg.MessageSize := in_msg.MessageSize; - DPRINTF(RubySlicc, "%s\n", out_msg); - } + action(qw_queueMemoryWBRequest_partial, "qwp", + desc="Queue off-chip writeback request") { + peek(requestNetwork_in, RequestMsg) { + queueMemoryWritePartial(machineID, address, to_mem_ctrl_latency, + in_msg.DataBlk, in_msg.Len); } } @@ -424,22 +396,11 @@ machine(Directory, "MESI Two Level directory protocol") } } - action(qw_queueMemoryWBRequest_partialTBE, "qwt", desc="Queue off-chip writeback request") { + action(qw_queueMemoryWBRequest_partialTBE, "qwt", + desc="Queue off-chip writeback request") { peek(responseNetwork_in, ResponseMsg) { - enqueue(memQueue_out, MemoryMsg, to_mem_ctrl_latency) { - assert(is_valid(tbe)); - out_msg.Addr := address; - out_msg.Type := MemoryRequestType:MEMORY_WB; - out_msg.OriginalRequestorMachId := in_msg.Sender; - //out_msg.DataBlk := in_msg.DataBlk; - //out_msg.DataBlk.copyPartial(tbe.DataBlk, tbe.Offset, tbe.Len); - out_msg.DataBlk.copyPartial(tbe.DataBlk, addressOffset(tbe.PhysicalAddress), tbe.Len); - - out_msg.MessageSize := in_msg.MessageSize; - //out_msg.Prefetch := in_msg.Prefetch; - - DPRINTF(RubySlicc, "%s\n", out_msg); - } + queueMemoryWritePartial(in_msg.Sender, tbe.PhysicalAddress, + to_mem_ctrl_latency, tbe.DataBlk, tbe.Len); } } diff --git a/src/mem/protocol/MI_example-dir.sm b/src/mem/protocol/MI_example-dir.sm index 60662080a..def7053ea 100644 --- a/src/mem/protocol/MI_example-dir.sm +++ b/src/mem/protocol/MI_example-dir.sm @@ -29,8 +29,8 @@ machine(Directory, "Directory protocol") : DirectoryMemory * directory; - MemoryControl * memBuffer; Cycles directory_latency := 12; + Cycles to_memory_controller_latency := 1; MessageBuffer * forwardFromDir, network="To", virtual_network="3", ordered="false", vnet_type="forward"; @@ -178,17 +178,21 @@ machine(Directory, "Directory protocol") if(is_valid(tbe)) { testAndRead(addr, tbe.DataBlk, pkt); } else { - memBuffer.functionalRead(pkt); + functionalMemoryRead(pkt); } } int functionalWrite(Address addr, Packet *pkt) { + int num_functional_writes := 0; + TBE tbe := TBEs[addr]; if(is_valid(tbe)) { - testAndWrite(addr, tbe.DataBlk, pkt); + num_functional_writes := num_functional_writes + + testAndWrite(addr, tbe.DataBlk, pkt); } - return memBuffer.functionalWrite(pkt); + num_functional_writes := num_functional_writes + functionalMemoryWrite(pkt); + return num_functional_writes; } // ** OUT_PORTS ** @@ -197,10 +201,7 @@ machine(Directory, "Directory protocol") out_port(requestQueue_out, ResponseMsg, requestToDir); // For recycling requests out_port(dmaResponseNetwork_out, DMAResponseMsg, dmaResponseFromDir); -//added by SS - out_port(memQueue_out, MemoryMsg, memBuffer); // ** IN_PORTS ** - in_port(dmaRequestQueue_in, DMARequestMsg, dmaRequestToDir) { if (dmaRequestQueue_in.isReady()) { peek(dmaRequestQueue_in, DMARequestMsg) { @@ -239,7 +240,7 @@ machine(Directory, "Directory protocol") //added by SS // off-chip memory request/response is done - in_port(memQueue_in, MemoryMsg, memBuffer) { + in_port(memQueue_in, MemoryMsg, responseFromMemory) { if (memQueue_in.isReady()) { peek(memQueue_in, MemoryMsg) { TBE tbe := TBEs[in_msg.Addr]; @@ -440,73 +441,36 @@ machine(Directory, "Directory protocol") action(qf_queueMemoryFetchRequest, "qf", desc="Queue off-chip fetch request") { peek(requestQueue_in, RequestMsg) { - enqueue(memQueue_out, MemoryMsg, 1) { - out_msg.Addr := address; - out_msg.Type := MemoryRequestType:MEMORY_READ; - out_msg.Sender := machineID; - out_msg.OriginalRequestorMachId := in_msg.Requestor; - out_msg.MessageSize := in_msg.MessageSize; - DPRINTF(RubySlicc,"%s\n", out_msg); - } + queueMemoryRead(in_msg.Requestor, address, to_memory_controller_latency); } } action(qf_queueMemoryFetchRequestDMA, "qfd", desc="Queue off-chip fetch request") { peek(dmaRequestQueue_in, DMARequestMsg) { - enqueue(memQueue_out, MemoryMsg, 1) { - out_msg.Addr := address; - out_msg.Type := MemoryRequestType:MEMORY_READ; - out_msg.Sender := machineID; - //out_msg.OriginalRequestorMachId := machineID; - out_msg.MessageSize := in_msg.MessageSize; - DPRINTF(RubySlicc,"%s\n", out_msg); - } + queueMemoryRead(in_msg.Requestor, address, to_memory_controller_latency); } } action(qw_queueMemoryWBRequest_partial, "qwp", desc="Queue off-chip writeback request") { - peek(dmaRequestQueue_in, DMARequestMsg) { - enqueue(memQueue_out, MemoryMsg, 1) { - out_msg.Addr := address; - out_msg.Type := MemoryRequestType:MEMORY_WB; - out_msg.DataBlk.copyPartial( - in_msg.DataBlk, addressOffset(in_msg.PhysicalAddress), in_msg.Len); - out_msg.MessageSize := in_msg.MessageSize; - DPRINTF(RubySlicc,"%s\n", out_msg); - } + peek(dmaRequestQueue_in, DMARequestMsg) { + queueMemoryWritePartial(in_msg.Requestor, address, + to_memory_controller_latency, in_msg.DataBlk, + in_msg.Len); } } action(qw_queueMemoryWBRequest_partialTBE, "qwt", desc="Queue off-chip writeback request") { peek(requestQueue_in, RequestMsg) { - enqueue(memQueue_out, MemoryMsg, 1) { - assert(is_valid(tbe)); - out_msg.Addr := address; - out_msg.Type := MemoryRequestType:MEMORY_WB; - out_msg.OriginalRequestorMachId := in_msg.Requestor; - - // get incoming data - out_msg.DataBlk.copyPartial( - tbe.DataBlk, addressOffset(tbe.PhysicalAddress), tbe.Len); - out_msg.MessageSize := in_msg.MessageSize; - DPRINTF(RubySlicc,"%s\n", out_msg); - } + queueMemoryWritePartial(in_msg.Requestor, address, + to_memory_controller_latency, tbe.DataBlk, + tbe.Len); } } - action(l_queueMemoryWBRequest, "lq", desc="Write PUTX data to memory") { peek(requestQueue_in, RequestMsg) { - enqueue(memQueue_out, MemoryMsg, 1) { - out_msg.Addr := address; - out_msg.Type := MemoryRequestType:MEMORY_WB; - out_msg.Sender := machineID; - out_msg.OriginalRequestorMachId := in_msg.Requestor; - out_msg.DataBlk := in_msg.DataBlk; - out_msg.MessageSize := in_msg.MessageSize; - - DPRINTF(RubySlicc,"%s\n", out_msg); - } + queueMemoryWrite(in_msg.Requestor, address, to_memory_controller_latency, + in_msg.DataBlk); } } diff --git a/src/mem/protocol/MOESI_CMP_directory-dir.sm b/src/mem/protocol/MOESI_CMP_directory-dir.sm index a6b93fa54..3e19897f3 100644 --- a/src/mem/protocol/MOESI_CMP_directory-dir.sm +++ b/src/mem/protocol/MOESI_CMP_directory-dir.sm @@ -28,8 +28,8 @@ machine(Directory, "Directory protocol") : DirectoryMemory * directory; - MemoryControl * memBuffer; Cycles directory_latency := 6; + Cycles to_memory_controller_latency := 1; // Message Queues MessageBuffer * requestToDir, network="From", virtual_network="1", @@ -191,11 +191,13 @@ machine(Directory, "Directory protocol") } void functionalRead(Address addr, Packet *pkt) { - memBuffer.functionalRead(pkt); + functionalMemoryRead(pkt); } int functionalWrite(Address addr, Packet *pkt) { - return memBuffer.functionalWrite(pkt); + int num_functional_writes := 0; + num_functional_writes := num_functional_writes + functionalMemoryWrite(pkt); + return num_functional_writes; } // if no sharers, then directory can be considered @@ -222,7 +224,6 @@ machine(Directory, "Directory protocol") // ** OUT_PORTS ** out_port(forwardNetwork_out, RequestMsg, forwardFromDir); out_port(responseNetwork_out, ResponseMsg, responseFromDir); - out_port(memQueue_out, MemoryMsg, memBuffer); // ** IN_PORTS ** @@ -286,7 +287,7 @@ machine(Directory, "Directory protocol") } // off-chip memory request/response is done - in_port(memQueue_in, MemoryMsg, memBuffer) { + in_port(memQueue_in, MemoryMsg, responseFromMemory) { if (memQueue_in.isReady()) { peek(memQueue_in, MemoryMsg) { if (in_msg.Type == MemoryRequestType:MEMORY_READ) { @@ -465,41 +466,18 @@ machine(Directory, "Directory protocol") action(qf_queueMemoryFetchRequest, "qf", desc="Queue off-chip fetch request") { peek(requestQueue_in, RequestMsg) { - enqueue(memQueue_out, MemoryMsg, 1) { - out_msg.Addr := address; - out_msg.Type := MemoryRequestType:MEMORY_READ; - out_msg.Sender := machineID; - out_msg.OriginalRequestorMachId := in_msg.Requestor; - out_msg.MessageSize := in_msg.MessageSize; - //out_msg.Prefetch := false; - // These are not used by memory but are passed back here with the read data: - out_msg.ReadX := (in_msg.Type == CoherenceRequestType:GETS && - getDirectoryEntry(address).Sharers.count() == 0); - out_msg.Acks := getDirectoryEntry(address).Sharers.count(); - if (getDirectoryEntry(address).Sharers.isElement(in_msg.Requestor)) { - out_msg.Acks := out_msg.Acks - 1; - } - DPRINTF(RubySlicc, "%s\n", out_msg); - } + queueMemoryRead(in_msg.Requestor, address, to_memory_controller_latency); } } action(qw_queueMemoryWBRequest, "qw", desc="Queue off-chip writeback request") { peek(unblockNetwork_in, ResponseMsg) { - enqueue(memQueue_out, MemoryMsg, 1) { - out_msg.Addr := address; - out_msg.Type := MemoryRequestType:MEMORY_WB; - out_msg.Sender := machineID; - if (is_valid(tbe)) { - out_msg.OriginalRequestorMachId := tbe.Requestor; - } - out_msg.DataBlk := in_msg.DataBlk; - out_msg.MessageSize := in_msg.MessageSize; - //out_msg.Prefetch := false; - // Not used: - out_msg.ReadX := false; - out_msg.Acks := getDirectoryEntry(address).Sharers.count(); // for dma requests - DPRINTF(RubySlicc, "%s\n", out_msg); + if (is_valid(tbe)) { + queueMemoryWrite(tbe.Requestor, address, to_memory_controller_latency, + in_msg.DataBlk); + } else { + queueMemoryWrite(in_msg.Sender, address, to_memory_controller_latency, + in_msg.DataBlk); } } } @@ -507,41 +485,18 @@ machine(Directory, "Directory protocol") action(qw_queueMemoryWBRequestFromMessageAndTBE, "qwmt", desc="Queue off-chip writeback request") { peek(unblockNetwork_in, ResponseMsg) { - enqueue(memQueue_out, MemoryMsg, 1) { - out_msg.Addr := address; - out_msg.Type := MemoryRequestType:MEMORY_WB; - out_msg.Sender := machineID; - if (is_valid(tbe)) { - out_msg.OriginalRequestorMachId := tbe.Requestor; - } - out_msg.DataBlk := in_msg.DataBlk; - out_msg.DataBlk.copyPartial(tbe.DataBlk, - addressOffset(tbe.PhysicalAddress), tbe.Len); - - out_msg.MessageSize := in_msg.MessageSize; - // Not used: - out_msg.ReadX := false; - out_msg.Acks := getDirectoryEntry(address).Sharers.count(); // for dma requests - DPRINTF(RubySlicc, "%s\n", out_msg); - } + DataBlock DataBlk := in_msg.DataBlk; + DataBlk.copyPartial(tbe.DataBlk, addressOffset(tbe.PhysicalAddress), + tbe.Len); + queueMemoryWrite(tbe.Requestor, address, to_memory_controller_latency, + DataBlk); } } action(qw_queueMemoryWBRequest2, "/qw", desc="Queue off-chip writeback request") { peek(requestQueue_in, RequestMsg) { - enqueue(memQueue_out, MemoryMsg, 1) { - out_msg.Addr := address; - out_msg.Type := MemoryRequestType:MEMORY_WB; - out_msg.Sender := machineID; - out_msg.OriginalRequestorMachId := in_msg.Requestor; - out_msg.DataBlk := in_msg.DataBlk; - out_msg.MessageSize := in_msg.MessageSize; - //out_msg.Prefetch := false; - // Not used: - out_msg.ReadX := false; - out_msg.Acks := getDirectoryEntry(address).Sharers.count(); // for dma requests - DPRINTF(RubySlicc, "%s\n", out_msg); - } + queueMemoryWrite(in_msg.Requestor, address, to_memory_controller_latency, + in_msg.DataBlk); } } diff --git a/src/mem/protocol/MOESI_CMP_token-dir.sm b/src/mem/protocol/MOESI_CMP_token-dir.sm index 8d6abd93c..a70ef6073 100644 --- a/src/mem/protocol/MOESI_CMP_token-dir.sm +++ b/src/mem/protocol/MOESI_CMP_token-dir.sm @@ -28,12 +28,12 @@ machine(Directory, "Token protocol") : DirectoryMemory * directory; - MemoryControl * memBuffer; int l2_select_num_bits; Cycles directory_latency := 5; bool distributed_persistent := "True"; Cycles fixed_timeout_latency := 100; Cycles reissue_wakeup_latency := 10; + Cycles to_memory_controller_latency := 1; // Message Queues from dir to other controllers / network MessageBuffer * dmaResponseFromDir, network="To", virtual_network="5", @@ -148,8 +148,7 @@ machine(Directory, "Token protocol") structure(TBE, desc="TBE entries for outstanding DMA requests") { Address PhysicalAddress, desc="physical address"; State TBEState, desc="Transient State"; - DataBlock DmaDataBlk, desc="DMA Data to be written. Partial blocks need to merged with system memory"; - DataBlock DataBlk, desc="The current view of system memory"; + DataBlock DataBlk, desc="Current view of the associated address range"; int Len, desc="..."; MachineID DmaRequestor, desc="DMA requestor"; bool WentPersistent, desc="Did the DMA request require a persistent request"; @@ -250,17 +249,21 @@ machine(Directory, "Token protocol") if(is_valid(tbe)) { testAndRead(addr, tbe.DataBlk, pkt); } else { - memBuffer.functionalRead(pkt); + functionalMemoryRead(pkt); } } int functionalWrite(Address addr, Packet *pkt) { + int num_functional_writes := 0; + TBE tbe := TBEs[addr]; if(is_valid(tbe)) { - testAndWrite(addr, tbe.DataBlk, pkt); + num_functional_writes := num_functional_writes + + testAndWrite(addr, tbe.DataBlk, pkt); } - return memBuffer.functionalWrite(pkt); + num_functional_writes := num_functional_writes + functionalMemoryWrite(pkt); + return num_functional_writes; } // ** OUT_PORTS ** @@ -269,15 +272,9 @@ machine(Directory, "Token protocol") out_port(requestNetwork_out, RequestMsg, requestFromDir); out_port(dmaResponseNetwork_out, DMAResponseMsg, dmaResponseFromDir); - // - // Memory buffer for memory controller to DIMM communication - // - out_port(memQueue_out, MemoryMsg, memBuffer); - // ** IN_PORTS ** - // off-chip memory request/response is done - in_port(memQueue_in, MemoryMsg, memBuffer) { + in_port(memQueue_in, MemoryMsg, responseFromMemory) { if (memQueue_in.isReady()) { peek(memQueue_in, MemoryMsg) { if (in_msg.Type == MemoryRequestType:MEMORY_READ) { @@ -653,73 +650,39 @@ machine(Directory, "Token protocol") action(qf_queueMemoryFetchRequest, "qf", desc="Queue off-chip fetch request") { peek(requestNetwork_in, RequestMsg) { - enqueue(memQueue_out, MemoryMsg, 1) { - out_msg.Addr := address; - out_msg.Type := MemoryRequestType:MEMORY_READ; - out_msg.Sender := machineID; - out_msg.OriginalRequestorMachId := in_msg.Requestor; - out_msg.MessageSize := in_msg.MessageSize; - DPRINTF(RubySlicc, "%s\n", out_msg); - } + queueMemoryRead(in_msg.Requestor, address, to_memory_controller_latency); } } action(qp_queueMemoryForPersistent, "qp", desc="Queue off-chip fetch request") { - enqueue(memQueue_out, MemoryMsg, 1) { - out_msg.Addr := address; - out_msg.Type := MemoryRequestType:MEMORY_READ; - out_msg.Sender := machineID; - out_msg.OriginalRequestorMachId := persistentTable.findSmallest(address); - out_msg.MessageSize := MessageSizeType:Request_Control; - DPRINTF(RubySlicc, "%s\n", out_msg); - } + queueMemoryRead(persistentTable.findSmallest(address), address, + to_memory_controller_latency); } action(fd_memoryDma, "fd", desc="Queue off-chip fetch request") { peek(dmaRequestQueue_in, DMARequestMsg) { - enqueue(memQueue_out, MemoryMsg, 1) { - out_msg.Addr := address; - out_msg.Type := MemoryRequestType:MEMORY_READ; - out_msg.Sender := machineID; - out_msg.OriginalRequestorMachId := in_msg.Requestor; - out_msg.MessageSize := in_msg.MessageSize; - DPRINTF(RubySlicc, "%s\n", out_msg); - } + queueMemoryRead(in_msg.Requestor, address, to_memory_controller_latency); } } action(lq_queueMemoryWbRequest, "lq", desc="Write data to memory") { peek(responseNetwork_in, ResponseMsg) { - enqueue(memQueue_out, MemoryMsg, 1) { - out_msg.Addr := address; - out_msg.Type := MemoryRequestType:MEMORY_WB; - out_msg.MessageSize := in_msg.MessageSize; - out_msg.DataBlk := in_msg.DataBlk; - DPRINTF(RubySlicc, "%s\n", out_msg); - } + queueMemoryWrite(in_msg.Sender, address, to_memory_controller_latency, + in_msg.DataBlk); } } action(ld_queueMemoryDmaWriteFromTbe, "ld", desc="Write DMA data to memory") { - enqueue(memQueue_out, MemoryMsg, 1) { - out_msg.Addr := address; - out_msg.Type := MemoryRequestType:MEMORY_WB; - // first, initialize the data blk to the current version of system memory - out_msg.DataBlk := tbe.DataBlk; - // then add the dma write data - out_msg.DataBlk.copyPartial( - tbe.DmaDataBlk, addressOffset(tbe.PhysicalAddress), tbe.Len); - DPRINTF(RubySlicc, "%s\n", out_msg); - } + queueMemoryWritePartial(tbe.DmaRequestor, address, + to_memory_controller_latency, tbe.DataBlk, + tbe.Len); } - action(lr_queueMemoryDmaReadWriteback, "lr", desc="Write DMA data from read to memory") { - enqueue(memQueue_out, MemoryMsg, 1) { - out_msg.Addr := address; - out_msg.Type := MemoryRequestType:MEMORY_WB; - // first, initialize the data blk to the current version of system memory - out_msg.DataBlk := tbe.DataBlk; - DPRINTF(RubySlicc, "%s\n", out_msg); + action(lr_queueMemoryDmaReadWriteback, "lr", + desc="Write DMA data from read to memory") { + peek(responseNetwork_in, ResponseMsg) { + queueMemoryWrite(machineID, address, to_memory_controller_latency, + in_msg.DataBlk); } } @@ -727,7 +690,7 @@ machine(Directory, "Token protocol") peek(dmaRequestQueue_in, DMARequestMsg) { TBEs.allocate(address); set_tbe(TBEs[address]); - tbe.DmaDataBlk := in_msg.DataBlk; + tbe.DataBlk := in_msg.DataBlk; tbe.PhysicalAddress := in_msg.PhysicalAddress; tbe.Len := in_msg.Len; tbe.DmaRequestor := in_msg.Requestor; @@ -769,7 +732,10 @@ machine(Directory, "Token protocol") action(rd_recordDataInTbe, "rd", desc="Record data in TBE") { peek(responseNetwork_in, ResponseMsg) { + DataBlock DataBlk := tbe.DataBlk; tbe.DataBlk := in_msg.DataBlk; + tbe.DataBlk.copyPartial(DataBlk, addressOffset(tbe.PhysicalAddress), + tbe.Len); } } diff --git a/src/mem/protocol/MOESI_hammer-dir.sm b/src/mem/protocol/MOESI_hammer-dir.sm index 43d48c6d2..e04573128 100644 --- a/src/mem/protocol/MOESI_hammer-dir.sm +++ b/src/mem/protocol/MOESI_hammer-dir.sm @@ -36,8 +36,8 @@ machine(Directory, "AMD Hammer-like protocol") : DirectoryMemory * directory; CacheMemory * probeFilter; - MemoryControl * memBuffer; - Cycles memory_controller_latency := 2; + Cycles from_memory_controller_latency := 2; + Cycles to_memory_controller_latency := 1; bool probe_filter_enabled := "False"; bool full_bit_dir_enabled := "False"; @@ -271,17 +271,21 @@ machine(Directory, "AMD Hammer-like protocol") if(is_valid(tbe)) { testAndRead(addr, tbe.DataBlk, pkt); } else { - memBuffer.functionalRead(pkt); + functionalMemoryRead(pkt); } } int functionalWrite(Address addr, Packet *pkt) { + int num_functional_writes := 0; + TBE tbe := TBEs[addr]; if(is_valid(tbe)) { - testAndWrite(addr, tbe.DataBlk, pkt); + num_functional_writes := num_functional_writes + + testAndWrite(addr, tbe.DataBlk, pkt); } - return memBuffer.functionalWrite(pkt); + num_functional_writes := num_functional_writes + functionalMemoryWrite(pkt); + return num_functional_writes; } Event cache_request_to_event(CoherenceRequestType type) { @@ -305,11 +309,6 @@ machine(Directory, "AMD Hammer-like protocol") out_port(dmaResponseNetwork_out, DMAResponseMsg, dmaResponseFromDir); out_port(triggerQueue_out, TriggerMsg, triggerQueue); - // - // Memory buffer for memory controller to DIMM communication - // - out_port(memQueue_out, MemoryMsg, memBuffer); - // ** IN_PORTS ** // Trigger Queue @@ -389,7 +388,7 @@ machine(Directory, "AMD Hammer-like protocol") } // off-chip memory request/response is done - in_port(memQueue_in, MemoryMsg, memBuffer, rank=2) { + in_port(memQueue_in, MemoryMsg, responseFromMemory, rank=2) { if (memQueue_in.isReady()) { peek(memQueue_in, MemoryMsg) { PfEntry pf_entry := getProbeFilterEntry(in_msg.Addr); @@ -503,7 +502,7 @@ machine(Directory, "AMD Hammer-like protocol") action(a_sendWriteBackAck, "a", desc="Send writeback ack to requestor") { peek(requestQueue_in, RequestMsg) { - enqueue(forwardNetwork_out, RequestMsg, memory_controller_latency) { + enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) { out_msg.Addr := address; out_msg.Type := CoherenceRequestType:WB_ACK; out_msg.Requestor := in_msg.Requestor; @@ -516,7 +515,7 @@ machine(Directory, "AMD Hammer-like protocol") action(oc_sendBlockAck, "oc", desc="Send block ack to the owner") { peek(requestQueue_in, RequestMsg) { if (((probe_filter_enabled || full_bit_dir_enabled) && (in_msg.Requestor == cache_entry.Owner)) || machineCount(MachineType:L1Cache) == 1) { - enqueue(forwardNetwork_out, RequestMsg, memory_controller_latency) { + enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) { out_msg.Addr := address; out_msg.Type := CoherenceRequestType:BLOCK_ACK; out_msg.Requestor := in_msg.Requestor; @@ -529,7 +528,7 @@ machine(Directory, "AMD Hammer-like protocol") action(b_sendWriteBackNack, "b", desc="Send writeback nack to requestor") { peek(requestQueue_in, RequestMsg) { - enqueue(forwardNetwork_out, RequestMsg, memory_controller_latency) { + enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) { out_msg.Addr := address; out_msg.Type := CoherenceRequestType:WB_NACK; out_msg.Requestor := in_msg.Requestor; @@ -847,27 +846,13 @@ machine(Directory, "AMD Hammer-like protocol") action(qf_queueMemoryFetchRequest, "qf", desc="Queue off-chip fetch request") { peek(requestQueue_in, RequestMsg) { - enqueue(memQueue_out, MemoryMsg, 1) { - out_msg.Addr := address; - out_msg.Type := MemoryRequestType:MEMORY_READ; - out_msg.Sender := machineID; - out_msg.OriginalRequestorMachId := in_msg.Requestor; - out_msg.MessageSize := in_msg.MessageSize; - DPRINTF(RubySlicc, "%s\n", out_msg); - } + queueMemoryRead(in_msg.Requestor, address, to_memory_controller_latency); } } action(qd_queueMemoryRequestFromDmaRead, "qd", desc="Queue off-chip fetch request") { peek(dmaRequestQueue_in, DMARequestMsg) { - enqueue(memQueue_out, MemoryMsg, 1) { - out_msg.Addr := address; - out_msg.Type := MemoryRequestType:MEMORY_READ; - out_msg.Sender := machineID; - out_msg.OriginalRequestorMachId := in_msg.Requestor; - out_msg.MessageSize := in_msg.MessageSize; - DPRINTF(RubySlicc, "%s\n", out_msg); - } + queueMemoryRead(in_msg.Requestor, address, to_memory_controller_latency); } } @@ -880,7 +865,7 @@ machine(Directory, "AMD Hammer-like protocol") fwd_set := cache_entry.Sharers; fwd_set.remove(machineIDToNodeID(in_msg.Requestor)); if (fwd_set.count() > 0) { - enqueue(forwardNetwork_out, RequestMsg, memory_controller_latency) { + enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) { out_msg.Addr := address; out_msg.Type := in_msg.Type; out_msg.Requestor := in_msg.Requestor; @@ -895,7 +880,7 @@ machine(Directory, "AMD Hammer-like protocol") } } else { peek(requestQueue_in, RequestMsg) { - enqueue(forwardNetwork_out, RequestMsg, memory_controller_latency) { + enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) { out_msg.Addr := address; out_msg.Type := in_msg.Type; out_msg.Requestor := in_msg.Requestor; @@ -915,7 +900,7 @@ machine(Directory, "AMD Hammer-like protocol") if (full_bit_dir_enabled) { assert(cache_entry.Sharers.count() > 0); peek(requestQueue_in, RequestMsg) { - enqueue(forwardNetwork_out, RequestMsg, memory_controller_latency) { + enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) { out_msg.Addr := address; out_msg.Type := CoherenceRequestType:INV; out_msg.Requestor := machineID; @@ -924,7 +909,7 @@ machine(Directory, "AMD Hammer-like protocol") } } } else { - enqueue(forwardNetwork_out, RequestMsg, memory_controller_latency) { + enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) { out_msg.Addr := address; out_msg.Type := CoherenceRequestType:INV; out_msg.Requestor := machineID; @@ -937,7 +922,7 @@ machine(Directory, "AMD Hammer-like protocol") action(io_invalidateOwnerRequest, "io", desc="invalidate all copies") { if (machineCount(MachineType:L1Cache) > 1) { - enqueue(forwardNetwork_out, RequestMsg, memory_controller_latency) { + enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) { assert(is_valid(cache_entry)); out_msg.Addr := address; out_msg.Type := CoherenceRequestType:INV; @@ -956,7 +941,7 @@ machine(Directory, "AMD Hammer-like protocol") fwd_set := cache_entry.Sharers; fwd_set.remove(machineIDToNodeID(in_msg.Requestor)); if (fwd_set.count() > 0) { - enqueue(forwardNetwork_out, RequestMsg, memory_controller_latency) { + enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) { out_msg.Addr := address; out_msg.Type := in_msg.Type; out_msg.Requestor := in_msg.Requestor; @@ -969,7 +954,7 @@ machine(Directory, "AMD Hammer-like protocol") } } } else { - enqueue(forwardNetwork_out, RequestMsg, memory_controller_latency) { + enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) { out_msg.Addr := address; out_msg.Type := in_msg.Type; out_msg.Requestor := in_msg.Requestor; @@ -1005,7 +990,7 @@ machine(Directory, "AMD Hammer-like protocol") // decouple the two. // peek(unblockNetwork_in, ResponseMsg) { - enqueue(forwardNetwork_out, RequestMsg, memory_controller_latency) { + enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) { assert(is_valid(tbe)); out_msg.Addr := address; out_msg.Type := CoherenceRequestType:MERGED_GETS; @@ -1026,7 +1011,7 @@ machine(Directory, "AMD Hammer-like protocol") assert(machineCount(MachineType:L1Cache) > 1); if (probe_filter_enabled || full_bit_dir_enabled) { peek(requestQueue_in, RequestMsg) { - enqueue(forwardNetwork_out, RequestMsg, memory_controller_latency) { + enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) { assert(is_valid(cache_entry)); out_msg.Addr := address; out_msg.Type := in_msg.Type; @@ -1040,7 +1025,7 @@ machine(Directory, "AMD Hammer-like protocol") } } else { peek(requestQueue_in, RequestMsg) { - enqueue(forwardNetwork_out, RequestMsg, memory_controller_latency) { + enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) { out_msg.Addr := address; out_msg.Type := in_msg.Type; out_msg.Requestor := in_msg.Requestor; @@ -1060,7 +1045,7 @@ machine(Directory, "AMD Hammer-like protocol") if (probe_filter_enabled || full_bit_dir_enabled) { peek(requestQueue_in, RequestMsg) { if (in_msg.Requestor != cache_entry.Owner) { - enqueue(forwardNetwork_out, RequestMsg, memory_controller_latency) { + enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) { assert(is_valid(cache_entry)); out_msg.Addr := address; out_msg.Type := in_msg.Type; @@ -1075,7 +1060,7 @@ machine(Directory, "AMD Hammer-like protocol") } } else { peek(requestQueue_in, RequestMsg) { - enqueue(forwardNetwork_out, RequestMsg, memory_controller_latency) { + enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) { out_msg.Addr := address; out_msg.Type := in_msg.Type; out_msg.Requestor := in_msg.Requestor; @@ -1094,7 +1079,7 @@ machine(Directory, "AMD Hammer-like protocol") assert(is_valid(tbe)); if (tbe.NumPendingMsgs > 0) { peek(dmaRequestQueue_in, DMARequestMsg) { - enqueue(forwardNetwork_out, RequestMsg, memory_controller_latency) { + enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) { out_msg.Addr := address; out_msg.Type := CoherenceRequestType:GETX; // @@ -1113,7 +1098,7 @@ machine(Directory, "AMD Hammer-like protocol") assert(is_valid(tbe)); if (tbe.NumPendingMsgs > 0) { peek(dmaRequestQueue_in, DMARequestMsg) { - enqueue(forwardNetwork_out, RequestMsg, memory_controller_latency) { + enqueue(forwardNetwork_out, RequestMsg, from_memory_controller_latency) { out_msg.Addr := address; out_msg.Type := CoherenceRequestType:GETS; // @@ -1221,38 +1206,21 @@ machine(Directory, "AMD Hammer-like protocol") action(l_queueMemoryWBRequest, "lq", desc="Write PUTX data to memory") { peek(unblockNetwork_in, ResponseMsg) { - enqueue(memQueue_out, MemoryMsg, 1) { - assert(in_msg.Dirty); - assert(in_msg.MessageSize == MessageSizeType:Writeback_Data); - out_msg.Addr := address; - out_msg.Type := MemoryRequestType:MEMORY_WB; - out_msg.DataBlk := in_msg.DataBlk; - DPRINTF(RubySlicc, "%s\n", out_msg); - } + queueMemoryWrite(in_msg.Sender, address, to_memory_controller_latency, + in_msg.DataBlk); } } action(ld_queueMemoryDmaWrite, "ld", desc="Write DMA data to memory") { - enqueue(memQueue_out, MemoryMsg, 1) { - assert(is_valid(tbe)); - out_msg.Addr := address; - out_msg.Type := MemoryRequestType:MEMORY_WB; - // first, initialize the data blk to the current version of system memory - out_msg.DataBlk := tbe.DataBlk; - // then add the dma write data - out_msg.DataBlk.copyPartial(tbe.DmaDataBlk, addressOffset(tbe.PhysicalAddress), tbe.Len); - DPRINTF(RubySlicc, "%s\n", out_msg); - } + assert(is_valid(tbe)); + queueMemoryWritePartial(tbe.DmaRequestor, tbe.PhysicalAddress, + to_memory_controller_latency, tbe.DmaDataBlk, + tbe.Len); } action(ly_queueMemoryWriteFromTBE, "ly", desc="Write data to memory from TBE") { - enqueue(memQueue_out, MemoryMsg, 1) { - assert(is_valid(tbe)); - out_msg.Addr := address; - out_msg.Type := MemoryRequestType:MEMORY_WB; - out_msg.DataBlk := tbe.DataBlk; - DPRINTF(RubySlicc, "%s\n", out_msg); - } + queueMemoryWrite(machineID, address, to_memory_controller_latency, + tbe.DataBlk); } action(ll_checkIncomingWriteback, "\l", desc="Check PUTX/PUTO response message") { diff --git a/src/mem/protocol/RubySlicc_Defines.sm b/src/mem/protocol/RubySlicc_Defines.sm index 1480790bf..514a307df 100644 --- a/src/mem/protocol/RubySlicc_Defines.sm +++ b/src/mem/protocol/RubySlicc_Defines.sm @@ -31,3 +31,19 @@ NodeID version; MachineID machineID; NodeID clusterID; +MessageBuffer responseFromMemory, ordered="false"; + +// Functions implemented in the AbstractController class for +// making timing access to the memory maintained by the +// memory controllers. +void queueMemoryRead(MachineID id, Address addr, Cycles latency); +void queueMemoryWrite(MachineID id, Address addr, Cycles latency, + DataBlock block); +void queueMemoryWritePartial(MachineID id, Address addr, Cycles latency, + DataBlock block, int size); + +// Functions implemented in the AbstractController class for +// making functional access to the memory maintained by the +// memory controllers. +void functionalMemoryRead(Packet *pkt); +bool functionalMemoryWrite(Packet *pkt); diff --git a/src/mem/protocol/RubySlicc_Types.sm b/src/mem/protocol/RubySlicc_Types.sm index 2d0658e68..fb506781c 100644 --- a/src/mem/protocol/RubySlicc_Types.sm +++ b/src/mem/protocol/RubySlicc_Types.sm @@ -161,12 +161,6 @@ structure (WireBuffer, inport="yes", outport="yes", external = "yes") { } -structure (MemoryControl, inport="yes", outport="yes", external = "yes") { - void recordRequestType(CacheRequestType); - void functionalRead(Packet *pkt); - int functionalWrite(Packet *pkt); -} - structure (DMASequencer, external = "yes") { void ackCallback(); void dataCallback(DataBlock); diff --git a/src/mem/ruby/SConscript b/src/mem/ruby/SConscript index 4200ddaeb..8133820b9 100644 --- a/src/mem/ruby/SConscript +++ b/src/mem/ruby/SConscript @@ -126,7 +126,6 @@ MakeInclude('structures/Prefetcher.hh') MakeInclude('structures/CacheMemory.hh') MakeInclude('system/DMASequencer.hh') MakeInclude('structures/DirectoryMemory.hh') -MakeInclude('structures/MemoryControl.hh') MakeInclude('structures/WireBuffer.hh') MakeInclude('structures/PerfectCacheMemory.hh') MakeInclude('structures/PersistentTable.hh') diff --git a/src/mem/ruby/network/MessageBuffer.cc b/src/mem/ruby/network/MessageBuffer.cc index 1bc55c2c9..57a8d5519 100644 --- a/src/mem/ruby/network/MessageBuffer.cc +++ b/src/mem/ruby/network/MessageBuffer.cc @@ -144,16 +144,16 @@ random_time() void MessageBuffer::enqueue(MsgPtr message, Cycles delta) { - m_msg_counter++; + assert(m_ordering_set); // record current time incase we have a pop that also adjusts my size if (m_time_last_time_enqueue < m_sender->curCycle()) { m_msgs_this_cycle = 0; // first msg this cycle m_time_last_time_enqueue = m_sender->curCycle(); } - m_msgs_this_cycle++; - assert(m_ordering_set); + m_msg_counter++; + m_msgs_this_cycle++; // Calculate the arrival time of the message, that is, the first // cycle the message can be dequeued. diff --git a/src/mem/ruby/slicc_interface/AbstractController.cc b/src/mem/ruby/slicc_interface/AbstractController.cc index 366ea04ce..6bcbfbcbf 100644 --- a/src/mem/ruby/slicc_interface/AbstractController.cc +++ b/src/mem/ruby/slicc_interface/AbstractController.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 Mark D. Hill and David A. Wood + * Copyright (c) 2011-2014 Mark D. Hill and David A. Wood * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,21 +26,28 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "mem/protocol/MemoryMsg.hh" #include "mem/ruby/slicc_interface/AbstractController.hh" #include "mem/ruby/system/Sequencer.hh" #include "mem/ruby/system/System.hh" +#include "sim/system.hh" AbstractController::AbstractController(const Params *p) - : ClockedObject(p), Consumer(this) + : MemObject(p), Consumer(this), m_version(p->version), + m_clusterID(p->cluster_id), + m_masterId(p->system->getMasterId(name())), m_is_blocking(false), + m_number_of_TBEs(p->number_of_TBEs), + m_transitions_per_cycle(p->transitions_per_cycle), + m_buffer_size(p->buffer_size), m_recycle_latency(p->recycle_latency), + memoryPort(csprintf("%s.memory", name()), this, ""), + m_responseFromMemory_ptr(new MessageBuffer()) { - m_version = p->version; - m_clusterID = p->cluster_id; - - m_transitions_per_cycle = p->transitions_per_cycle; - m_buffer_size = p->buffer_size; - m_recycle_latency = p->recycle_latency; - m_number_of_TBEs = p->number_of_TBEs; - m_is_blocking = false; + // Set the sender pointer of the response message buffer from the + // memory controller. + // This pointer is used for querying for the current time. + m_responseFromMemory_ptr->setSender(this); + m_responseFromMemory_ptr->setReceiver(this); + m_responseFromMemory_ptr->setOrdering(false); if (m_version == 0) { // Combine the statistics from all controllers @@ -187,3 +194,140 @@ AbstractController::unblock(Address addr) m_is_blocking = false; } } + +BaseMasterPort & +AbstractController::getMasterPort(const std::string &if_name, + PortID idx) +{ + return memoryPort; +} + +void +AbstractController::queueMemoryRead(const MachineID &id, Address addr, + Cycles latency) +{ + RequestPtr req = new Request(addr.getAddress(), + RubySystem::getBlockSizeBytes(), 0, + m_masterId); + + PacketPtr pkt = Packet::createRead(req); + uint8_t *newData = new uint8_t[RubySystem::getBlockSizeBytes()]; + pkt->dataDynamic(newData); + + SenderState *s = new SenderState(id); + pkt->pushSenderState(s); + + memoryPort.schedTimingReq(pkt, clockEdge(latency)); +} + +void +AbstractController::queueMemoryWrite(const MachineID &id, Address addr, + Cycles latency, const DataBlock &block) +{ + RequestPtr req = new Request(addr.getAddress(), + RubySystem::getBlockSizeBytes(), 0, + m_masterId); + + PacketPtr pkt = Packet::createWrite(req); + uint8_t *newData = new uint8_t[RubySystem::getBlockSizeBytes()]; + pkt->dataDynamic(newData); + memcpy(newData, block.getData(0, RubySystem::getBlockSizeBytes()), + RubySystem::getBlockSizeBytes()); + + SenderState *s = new SenderState(id); + pkt->pushSenderState(s); + + // Create a block and copy data from the block. + memoryPort.schedTimingReq(pkt, clockEdge(latency)); +} + +void +AbstractController::queueMemoryWritePartial(const MachineID &id, Address addr, + Cycles latency, + const DataBlock &block, int size) +{ + RequestPtr req = new Request(addr.getAddress(), + RubySystem::getBlockSizeBytes(), 0, + m_masterId); + + PacketPtr pkt = Packet::createWrite(req); + uint8_t *newData = new uint8_t[size]; + pkt->dataDynamic(newData); + memcpy(newData, block.getData(addr.getOffset(), size), size); + + SenderState *s = new SenderState(id); + pkt->pushSenderState(s); + + // Create a block and copy data from the block. + memoryPort.schedTimingReq(pkt, clockEdge(latency)); +} + +void +AbstractController::functionalMemoryRead(PacketPtr pkt) +{ + memoryPort.sendFunctional(pkt); +} + +int +AbstractController::functionalMemoryWrite(PacketPtr pkt) +{ + int num_functional_writes = 0; + + // Check the message buffer that runs from the memory to the controller. + num_functional_writes += m_responseFromMemory_ptr->functionalWrite(pkt); + + // Check the buffer from the controller to the memory. + if (memoryPort.checkFunctional(pkt)) { + num_functional_writes++; + } + + // Update memory itself. + memoryPort.sendFunctional(pkt); + return num_functional_writes + 1; +} + +void +AbstractController::recvTimingResp(PacketPtr pkt) +{ + assert(pkt->isResponse()); + + std::shared_ptr msg = std::make_shared(clockEdge()); + (*msg).m_Addr.setAddress(pkt->getAddr()); + (*msg).m_Sender = m_machineID; + + SenderState *s = dynamic_cast(pkt->senderState); + (*msg).m_OriginalRequestorMachId = s->id; + delete s; + + if (pkt->isRead()) { + (*msg).m_Type = MemoryRequestType_MEMORY_READ; + (*msg).m_MessageSize = MessageSizeType_Response_Data; + + // Copy data from the packet + (*msg).m_DataBlk.setData(pkt->getPtr(), 0, + RubySystem::getBlockSizeBytes()); + } else if (pkt->isWrite()) { + (*msg).m_Type = MemoryRequestType_MEMORY_WB; + (*msg).m_MessageSize = MessageSizeType_Writeback_Control; + } else { + panic("Incorrect packet type received from memory controller!"); + } + + m_responseFromMemory_ptr->enqueue(msg); + delete pkt; +} + +bool +AbstractController::MemoryPort::recvTimingResp(PacketPtr pkt) +{ + controller->recvTimingResp(pkt); + return true; +} + +AbstractController::MemoryPort::MemoryPort(const std::string &_name, + AbstractController *_controller, + const std::string &_label) + : QueuedMasterPort(_name, _controller, _queue), + _queue(*_controller, *this, _label), controller(_controller) +{ +} diff --git a/src/mem/ruby/slicc_interface/AbstractController.hh b/src/mem/ruby/slicc_interface/AbstractController.hh index 98fce574f..45d355b3e 100644 --- a/src/mem/ruby/slicc_interface/AbstractController.hh +++ b/src/mem/ruby/slicc_interface/AbstractController.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009 Mark D. Hill and David A. Wood + * Copyright (c) 2009-2014 Mark D. Hill and David A. Wood * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -43,12 +43,13 @@ #include "mem/ruby/network/Network.hh" #include "mem/ruby/system/CacheRecorder.hh" #include "mem/packet.hh" +#include "mem/qport.hh" #include "params/RubyController.hh" -#include "sim/clocked_object.hh" +#include "mem/mem_object.hh" class Network; -class AbstractController : public ClockedObject, public Consumer +class AbstractController : public MemObject, public Consumer { public: typedef RubyControllerParams Params; @@ -79,10 +80,12 @@ class AbstractController : public ClockedObject, public Consumer //! These functions are used by ruby system to read/write the data blocks //! that exist with in the controller. virtual void functionalRead(const Address &addr, PacketPtr) = 0; + void functionalMemoryRead(PacketPtr); //! The return value indicates the number of messages written with the //! data from the packet. - virtual uint32_t functionalWriteBuffers(PacketPtr&) = 0; + virtual int functionalWriteBuffers(PacketPtr&) = 0; virtual int functionalWrite(const Address &addr, PacketPtr) = 0; + int functionalMemoryWrite(PacketPtr); //! Function for enqueuing a prefetch request virtual void enqueuePrefetch(const Address&, const RubyRequestType&) @@ -97,6 +100,17 @@ class AbstractController : public ClockedObject, public Consumer //! Set the message buffer with given name. virtual void setNetQueue(const std::string& name, MessageBuffer *b) = 0; + /** A function used to return the port associated with this bus object. */ + BaseMasterPort& getMasterPort(const std::string& if_name, + PortID idx = InvalidPortID); + + void queueMemoryRead(const MachineID &id, Address addr, Cycles latency); + void queueMemoryWrite(const MachineID &id, Address addr, Cycles latency, + const DataBlock &block); + void queueMemoryWritePartial(const MachineID &id, Address addr, Cycles latency, + const DataBlock &block, int size); + void recvTimingResp(PacketPtr pkt); + public: MachineID getMachineID() const { return m_machineID; } @@ -120,6 +134,9 @@ class AbstractController : public ClockedObject, public Consumer MachineID m_machineID; NodeID m_clusterID; + // MasterID used by some components of gem5. + MasterID m_masterId; + Network* m_net_ptr; bool m_is_blocking; std::map m_block_map; @@ -156,6 +173,46 @@ class AbstractController : public ClockedObject, public Consumer StatsCallback(AbstractController *_ctr) : ctr(_ctr) {} void process() {ctr->collateStats();} }; + + /** + * Port that forwards requests and receives responses from the + * memory controller. It has a queue of packets not yet sent. + */ + class MemoryPort : public QueuedMasterPort + { + private: + // Packet queue used to store outgoing requests and responses. + MasterPacketQueue _queue; + + // Controller that operates this port. + AbstractController *controller; + + public: + MemoryPort(const std::string &_name, AbstractController *_controller, + const std::string &_label); + + // Function for receiving a timing response from the peer port. + // Currently the pkt is handed to the coherence controller + // associated with this port. + bool recvTimingResp(PacketPtr pkt); + }; + + /* Master port to the memory controller. */ + MemoryPort memoryPort; + + // Message Buffer for storing the response received from the + // memory controller. + MessageBuffer *m_responseFromMemory_ptr; + + // State that is stored in packets sent to the memory controller. + struct SenderState : public Packet::SenderState + { + // Id of the machine from which the request originated. + MachineID id; + + SenderState(MachineID _id) : id(_id) + {} + }; }; #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 f82e0a70d..ba7d17c7c 100644 --- a/src/mem/ruby/slicc_interface/Controller.py +++ b/src/mem/ruby/slicc_interface/Controller.py @@ -28,9 +28,10 @@ # Brad Beckmann from m5.params import * -from ClockedObject import ClockedObject +from m5.proxy import * +from MemObject import MemObject -class RubyController(ClockedObject): +class RubyController(MemObject): type = 'RubyController' cxx_class = 'AbstractController' cxx_header = "mem/ruby/slicc_interface/AbstractController.hh" @@ -46,4 +47,5 @@ class RubyController(ClockedObject): number_of_TBEs = Param.Int(256, "") ruby_system = Param.RubySystem("") - peer = Param.RubyController(NULL, "") + memory = MasterPort("Port for attaching a memory controller") + system = Param.System(Parent.any, "system object parameter") diff --git a/src/mem/ruby/structures/Cache.py b/src/mem/ruby/structures/Cache.py index 14a359233..c6e165e3a 100644 --- a/src/mem/ruby/structures/Cache.py +++ b/src/mem/ruby/structures/Cache.py @@ -29,7 +29,6 @@ from m5.params import * from m5.SimObject import SimObject -from Controller import RubyController class RubyCache(SimObject): type = 'RubyCache' diff --git a/src/mem/ruby/structures/DirectoryMemory.py b/src/mem/ruby/structures/DirectoryMemory.py index c64439ce5..bb9765bdb 100644 --- a/src/mem/ruby/structures/DirectoryMemory.py +++ b/src/mem/ruby/structures/DirectoryMemory.py @@ -37,8 +37,6 @@ class RubyDirectoryMemory(SimObject): cxx_header = "mem/ruby/structures/DirectoryMemory.hh" 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/structures/MemoryControl.cc b/src/mem/ruby/structures/MemoryControl.cc deleted file mode 100644 index 6c933b4d4..000000000 --- a/src/mem/ruby/structures/MemoryControl.cc +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood - * Copyright (c) 2012 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. - */ - -#include "debug/RubyStats.hh" -#include "mem/ruby/common/Global.hh" -#include "mem/ruby/slicc_interface/RubySlicc_ComponentMapping.hh" -#include "mem/ruby/structures/MemoryControl.hh" -#include "mem/ruby/system/System.hh" - -using namespace std; -MemoryControl::MemoryControl(const Params *p) - : ClockedObject(p), Consumer(this), m_event(this) -{ - g_system_ptr->registerMemController(this); -} - -MemoryControl::~MemoryControl() {}; - -void -MemoryControl::recordRequestType(MemoryControlRequestType request) { - DPRINTF(RubyStats, "Recorded request: %s\n", - MemoryControlRequestType_to_string(request)); -} diff --git a/src/mem/ruby/structures/MemoryControl.hh b/src/mem/ruby/structures/MemoryControl.hh deleted file mode 100644 index b1cbe982f..000000000 --- a/src/mem/ruby/structures/MemoryControl.hh +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood - * Copyright (c) 2012 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. - */ - -#ifndef __MEM_RUBY_STRUCTURES_ABSTRACT_MEMORY_CONTROL_HH__ -#define __MEM_RUBY_STRUCTURES_ABSTRACT_MEMORY_CONTROL_HH__ - -#include -#include -#include - -#include "mem/protocol/MemoryControlRequestType.hh" -#include "mem/ruby/common/Consumer.hh" -#include "mem/ruby/slicc_interface/Message.hh" -#include "mem/ruby/structures/MemoryNode.hh" -#include "params/MemoryControl.hh" -#include "sim/clocked_object.hh" - -////////////////////////////////////////////////////////////////////////////// - -class MemoryControl : public ClockedObject, public Consumer -{ - public: - typedef MemoryControlParams Params; - const Params *params() const - { return dynamic_cast(_params); } - - MemoryControl(const Params *p); - virtual void init() = 0; - virtual void reset() = 0; - - ~MemoryControl(); - - virtual void wakeup() = 0; - - virtual void setConsumer(Consumer* consumer_ptr) = 0; - virtual Consumer* getConsumer() = 0; - virtual void setClockObj(ClockedObject* consumer_ptr) {} - - virtual void setDescription(const std::string& name) = 0; - virtual std::string getDescription() = 0; - - // Called from the directory: - virtual void enqueue(const MsgPtr& message, Cycles latency) = 0; - virtual void enqueueMemRef(MemoryNode *memRef) = 0; - virtual void dequeue() = 0; - virtual const Message* peek() = 0; - virtual MemoryNode *peekNode() = 0; - virtual bool isReady() = 0; - virtual bool areNSlotsAvailable(int n) = 0; // infinite queue length - - virtual void print(std::ostream& out) const = 0; - virtual void regStats() {}; - - virtual const int getChannel(const physical_address_t addr) const = 0; - virtual const int getBank(const physical_address_t addr) const = 0; - virtual const int getRank(const physical_address_t addr) const = 0; - virtual const int getRow(const physical_address_t addr) const = 0; - - //added by SS - virtual int getBanksPerRank() = 0; - virtual int getRanksPerDimm() = 0; - virtual int getDimmsPerChannel() = 0; - - virtual void recordRequestType(MemoryControlRequestType requestType); - - virtual bool functionalRead(Packet *pkt) - { fatal("Functional read access not implemented!");} - virtual uint32_t functionalWrite(Packet *pkt) - { fatal("Functional read access not implemented!");} - -protected: - class MemCntrlEvent : public Event - { - public: - MemCntrlEvent(MemoryControl* _mem_cntrl) - { - mem_cntrl = _mem_cntrl; - } - private: - void process() { mem_cntrl->wakeup(); } - - MemoryControl* mem_cntrl; - }; - - MemCntrlEvent m_event; -}; - -#endif // __MEM_RUBY_STRUCTURES_ABSTRACT_MEMORY_CONTROL_HH__ diff --git a/src/mem/ruby/structures/MemoryControl.py b/src/mem/ruby/structures/MemoryControl.py deleted file mode 100644 index 8a6879cb9..000000000 --- a/src/mem/ruby/structures/MemoryControl.py +++ /dev/null @@ -1,39 +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 ClockedObject import ClockedObject - -class MemoryControl(ClockedObject): - abstract = True - type = 'MemoryControl' - cxx_class = 'MemoryControl' - cxx_header = "mem/ruby/structures/MemoryControl.hh" - version = Param.Int(""); - ruby_system = Param.RubySystem("") diff --git a/src/mem/ruby/structures/MemoryNode.cc b/src/mem/ruby/structures/MemoryNode.cc index 2a5cbb189..1e68cc459 100644 --- a/src/mem/ruby/structures/MemoryNode.cc +++ b/src/mem/ruby/structures/MemoryNode.cc @@ -36,6 +36,6 @@ MemoryNode::print(ostream& out) const out << "["; out << m_time << ", "; out << m_msg_counter << ", "; - out << m_msgptr << "; "; + out << pkt << "; "; out << "]"; } diff --git a/src/mem/ruby/structures/MemoryNode.hh b/src/mem/ruby/structures/MemoryNode.hh index 3f40e3648..b48f64704 100644 --- a/src/mem/ruby/structures/MemoryNode.hh +++ b/src/mem/ruby/structures/MemoryNode.hh @@ -47,25 +47,23 @@ class MemoryNode { public: // old constructor - MemoryNode(const Cycles& time, int counter, const MsgPtr& msgptr, + MemoryNode(const Cycles& time, int counter, const PacketPtr p, const physical_address_t addr, const bool is_mem_read) - : m_time(time) + : m_time(time), pkt(p) { m_msg_counter = counter; - m_msgptr = msgptr; m_addr = addr; m_is_mem_read = is_mem_read; m_is_dirty_wb = !is_mem_read; } // new constructor - MemoryNode(const Cycles& time, const MsgPtr& msgptr, + MemoryNode(const Cycles& time, const PacketPtr p, const physical_address_t addr, const bool is_mem_read, const bool is_dirty_wb) - : m_time(time) + : m_time(time), pkt(p) { m_msg_counter = 0; - m_msgptr = msgptr; m_addr = addr; m_is_mem_read = is_mem_read; m_is_dirty_wb = is_dirty_wb; @@ -75,7 +73,7 @@ class MemoryNode Cycles m_time; int m_msg_counter; - MsgPtr m_msgptr; + PacketPtr pkt; physical_address_t m_addr; bool m_is_mem_read; bool m_is_dirty_wb; diff --git a/src/mem/ruby/structures/MemoryVector.hh b/src/mem/ruby/structures/MemoryVector.hh deleted file mode 100644 index 384c68ad6..000000000 --- a/src/mem/ruby/structures/MemoryVector.hh +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright (c) 2009 Mark D. Hill and David A. Wood - * 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. - */ - -#ifndef __MEM_RUBY_STRUCTURES_MEMORYVECTOR_HH__ -#define __MEM_RUBY_STRUCTURES_MEMORYVECTOR_HH__ - -#include "base/trace.hh" -#include "debug/RubyCacheTrace.hh" -#include "mem/ruby/common/Address.hh" - -class DirectoryMemory; - -/** - * MemoryVector holds memory data (DRAM only) - */ -class MemoryVector -{ - public: - MemoryVector(); - MemoryVector(uint64 size); - ~MemoryVector(); - friend class DirectoryMemory; - - void resize(uint64 size); // destructive - - void write(const Address & paddr, uint8_t *data, int len); - uint8_t *read(const Address & paddr, uint8_t *data, int len); - uint32_t collatePages(uint8_t *&raw_data); - void populatePages(uint8_t *raw_data); - - private: - uint8_t *getBlockPtr(const PhysAddress & addr); - - uint64 m_size; - uint8_t **m_pages; - uint32_t m_num_pages; - const uint32_t m_page_offset_mask; - static const uint32_t PAGE_SIZE = 4096; -}; - -inline -MemoryVector::MemoryVector() - : m_page_offset_mask(4095) -{ - m_size = 0; - m_num_pages = 0; - m_pages = NULL; -} - -inline -MemoryVector::MemoryVector(uint64 size) - : m_page_offset_mask(4095) -{ - resize(size); -} - -inline -MemoryVector::~MemoryVector() -{ - for (int i = 0; i < m_num_pages; i++) { - if (m_pages[i] != 0) { - delete [] m_pages[i]; - } - } - delete [] m_pages; -} - -inline void -MemoryVector::resize(uint64 size) -{ - if (m_pages != NULL){ - for (int i = 0; i < m_num_pages; i++) { - if (m_pages[i] != 0) { - delete [] m_pages[i]; - } - } - delete [] m_pages; - } - m_size = size; - assert(size%PAGE_SIZE == 0); - m_num_pages = size >> 12; - m_pages = new uint8_t*[m_num_pages]; - memset(m_pages, 0, m_num_pages * sizeof(uint8_t*)); -} - -inline void -MemoryVector::write(const Address & paddr, uint8_t *data, int len) -{ - assert(paddr.getAddress() + len <= m_size); - uint32_t page_num = paddr.getAddress() >> 12; - if (m_pages[page_num] == 0) { - bool all_zeros = true; - for (int i = 0; i < len;i++) { - if (data[i] != 0) { - all_zeros = false; - break; - } - } - if (all_zeros) - return; - m_pages[page_num] = new uint8_t[PAGE_SIZE]; - memset(m_pages[page_num], 0, PAGE_SIZE); - uint32_t offset = paddr.getAddress() & m_page_offset_mask; - memcpy(&m_pages[page_num][offset], data, len); - } else { - memcpy(&m_pages[page_num][paddr.getAddress()&m_page_offset_mask], - data, len); - } -} - -inline uint8_t* -MemoryVector::read(const Address & paddr, uint8_t *data, int len) -{ - assert(paddr.getAddress() + len <= m_size); - uint32_t page_num = paddr.getAddress() >> 12; - if (m_pages[page_num] == 0) { - memset(data, 0, len); - } else { - memcpy(data, &m_pages[page_num][paddr.getAddress()&m_page_offset_mask], - len); - } - return data; -} - -inline uint8_t* -MemoryVector::getBlockPtr(const PhysAddress & paddr) -{ - uint32_t page_num = paddr.getAddress() >> 12; - if (m_pages[page_num] == 0) { - m_pages[page_num] = new uint8_t[PAGE_SIZE]; - memset(m_pages[page_num], 0, PAGE_SIZE); - } - return &m_pages[page_num][paddr.getAddress()&m_page_offset_mask]; -} - -/*! - * Function for collating all the pages of the physical memory together. - * In case a pointer for a page is NULL, this page needs only a single byte - * to represent that the pointer is NULL. Otherwise, it needs 1 + PAGE_SIZE - * bytes. The first represents that the page pointer is not NULL, and rest of - * the bytes represent the data on the page. - */ - -inline uint32_t -MemoryVector::collatePages(uint8_t *&raw_data) -{ - uint32_t num_zero_pages = 0; - uint32_t data_size = 0; - - for (uint32_t i = 0;i < m_num_pages; ++i) - { - if (m_pages[i] == 0) num_zero_pages++; - } - - raw_data = new uint8_t[sizeof(uint32_t) /* number of pages*/ + - m_num_pages /* whether the page is all zeros */ + - PAGE_SIZE * (m_num_pages - num_zero_pages)]; - - /* Write the number of pages to be stored. */ - memcpy(raw_data, &m_num_pages, sizeof(uint32_t)); - data_size = sizeof(uint32_t); - - DPRINTF(RubyCacheTrace, "collating %d pages\n", m_num_pages); - - for (uint32_t i = 0;i < m_num_pages; ++i) - { - if (m_pages[i] == 0) { - raw_data[data_size] = 0; - } else { - raw_data[data_size] = 1; - memcpy(raw_data + data_size + 1, m_pages[i], PAGE_SIZE); - data_size += PAGE_SIZE; - } - data_size += 1; - } - - return data_size; -} - -/*! - * Function for populating the pages of the memory using the available raw - * data. Each page has a byte associate with it, which represents whether the - * page was NULL or not, when all the pages were collated. The function assumes - * that the number of pages in the memory are same as those that were recorded - * in the checkpoint. - */ -inline void -MemoryVector::populatePages(uint8_t *raw_data) -{ - uint32_t data_size = 0; - uint32_t num_pages = 0; - - /* Read the number of pages that were stored. */ - memcpy(&num_pages, raw_data, sizeof(uint32_t)); - data_size = sizeof(uint32_t); - assert(num_pages == m_num_pages); - - DPRINTF(RubyCacheTrace, "Populating %d pages\n", num_pages); - - for (uint32_t i = 0;i < m_num_pages; ++i) - { - assert(m_pages[i] == 0); - if (raw_data[data_size] != 0) { - m_pages[i] = new uint8_t[PAGE_SIZE]; - memcpy(m_pages[i], raw_data + data_size + 1, PAGE_SIZE); - data_size += PAGE_SIZE; - } - data_size += 1; - } -} - -#endif // __MEM_RUBY_STRUCTURES_MEMORYVECTOR_HH__ diff --git a/src/mem/ruby/structures/RubyMemoryControl.cc b/src/mem/ruby/structures/RubyMemoryControl.cc index 2e71c0c2f..a7a815adb 100644 --- a/src/mem/ruby/structures/RubyMemoryControl.cc +++ b/src/mem/ruby/structures/RubyMemoryControl.cc @@ -145,7 +145,8 @@ operator<<(ostream& out, const RubyMemoryControl& obj) // CONSTRUCTOR RubyMemoryControl::RubyMemoryControl(const Params *p) - : MemoryControl(p) + : AbstractMemory(p), Consumer(this), port(name() + ".port", *this), + m_event(this) { m_banks_per_rank = p->banks_per_rank; m_ranks_per_dimm = p->ranks_per_dimm; @@ -173,9 +174,7 @@ RubyMemoryControl::RubyMemoryControl(const Params *p) void RubyMemoryControl::init() { - m_ram = g_system_ptr->getMemoryVector(); m_msg_counter = 0; - assert(m_tFaw <= 62); // must fit in a uint64 shift register m_total_banks = m_banks_per_rank * m_ranks_per_dimm * m_dimms_per_channel; @@ -221,6 +220,16 @@ RubyMemoryControl::init() } } +BaseSlavePort& +RubyMemoryControl::getSlavePort(const string &if_name, PortID idx) +{ + if (if_name != "port") { + return MemObject::getSlavePort(if_name, idx); + } else { + return port; + } +} + void RubyMemoryControl::reset() { @@ -275,30 +284,18 @@ RubyMemoryControl::~RubyMemoryControl() } // enqueue new request from directory -void -RubyMemoryControl::enqueue(const MsgPtr& message, Cycles latency) +bool +RubyMemoryControl::recvTimingReq(PacketPtr pkt) { - Cycles arrival_time = curCycle() + latency; - const MemoryMsg* memMess = safe_cast(message.get()); - physical_address_t addr = memMess->getAddr().getAddress(); - MemoryRequestType type = memMess->getType(); - bool is_mem_read = (type == MemoryRequestType_MEMORY_READ); + Cycles arrival_time = curCycle(); + physical_address_t addr = pkt->getAddr(); + bool is_mem_read = pkt->isRead(); - if (is_mem_read) { - m_ram->read(memMess->getAddr(), const_cast( - memMess->getDataBlk().getData(0, - RubySystem::getBlockSizeBytes())), - RubySystem::getBlockSizeBytes()); - } else { - m_ram->write(memMess->getAddr(), const_cast( - memMess->getDataBlk().getData(0, - RubySystem::getBlockSizeBytes())), - RubySystem::getBlockSizeBytes()); - } - - MemoryNode *thisReq = new MemoryNode(arrival_time, message, addr, + access(pkt); + MemoryNode *thisReq = new MemoryNode(arrival_time, pkt, addr, is_mem_read, !is_mem_read); enqueueMemRef(thisReq); + return true; } // Alternate entry point used when we already have a MemoryNode @@ -325,51 +322,6 @@ RubyMemoryControl::enqueueMemRef(MemoryNode *memRef) } } -// dequeue, peek, and isReady are used to transfer completed requests -// back to the directory -void -RubyMemoryControl::dequeue() -{ - assert(isReady()); - MemoryNode *req = m_response_queue.front(); - m_response_queue.pop_front(); - delete req; -} - -const Message* -RubyMemoryControl::peek() -{ - MemoryNode *node = peekNode(); - Message* msg_ptr = node->m_msgptr.get(); - assert(msg_ptr != NULL); - return msg_ptr; -} - -MemoryNode * -RubyMemoryControl::peekNode() -{ - assert(isReady()); - MemoryNode *req = m_response_queue.front(); - DPRINTF(RubyMemory, "Peek: memory request%7d: %#08x %c sched %c\n", - req->m_msg_counter, req->m_addr, req->m_is_mem_read ? 'R':'W', - m_event.scheduled() ? 'Y':'N'); - - return req; -} - -bool -RubyMemoryControl::isReady() -{ - return ((!m_response_queue.empty()) && - (m_response_queue.front()->m_time <= g_system_ptr->curCycle())); -} - -void -RubyMemoryControl::setConsumer(Consumer* consumer_ptr) -{ - m_consumer_ptr = consumer_ptr; -} - void RubyMemoryControl::print(ostream& out) const { @@ -380,15 +332,17 @@ void RubyMemoryControl::enqueueToDirectory(MemoryNode *req, Cycles latency) { Tick arrival_time = clockEdge(latency); - Cycles ruby_arrival_time = g_system_ptr->ticksToCycles(arrival_time); - req->m_time = ruby_arrival_time; - m_response_queue.push_back(req); + PacketPtr pkt = req->pkt; + + // access already turned the packet into a response + assert(pkt->isResponse()); + + // queue the packet in the response queue to be sent out after + // the static latency has passed + port.schedTimingResp(pkt, arrival_time); DPRINTF(RubyMemory, "Enqueueing msg %#08x %c back to directory at %15d\n", req->m_addr, req->m_is_mem_read ? 'R':'W', arrival_time); - - // schedule the wake up - m_consumer_ptr->scheduleEventAbsolute(arrival_time); } // getBank returns an integer that is unique for each @@ -560,9 +514,8 @@ RubyMemoryControl::issueRequest(int bank) req->m_is_mem_read? 'R':'W', bank, m_event.scheduled() ? 'Y':'N'); - if (req->m_msgptr) { // don't enqueue L3 writebacks - enqueueToDirectory(req, Cycles(m_mem_ctl_latency + m_mem_fixed_delay)); - } + enqueueToDirectory(req, Cycles(m_mem_ctl_latency + m_mem_fixed_delay)); + m_oldRequest[bank] = 0; markTfaw(rank); m_bankBusyCounter[bank] = m_bank_busy_time; @@ -724,16 +677,16 @@ RubyMemoryControl::functionalRead(Packet *pkt) { for (std::list::iterator it = m_input_queue.begin(); it != m_input_queue.end(); ++it) { - Message* msg_ptr = (*it)->m_msgptr.get(); - if (msg_ptr->functionalRead(pkt)) { + PacketPtr msg = (*it)->pkt; + if (pkt->checkFunctional(msg)) { return true; } } for (std::list::iterator it = m_response_queue.begin(); it != m_response_queue.end(); ++it) { - Message* msg_ptr = (*it)->m_msgptr.get(); - if (msg_ptr->functionalRead(pkt)) { + PacketPtr msg = (*it)->pkt; + if (pkt->checkFunctional(msg)) { return true; } } @@ -741,16 +694,14 @@ RubyMemoryControl::functionalRead(Packet *pkt) for (uint32_t bank = 0; bank < m_total_banks; ++bank) { for (std::list::iterator it = m_bankQueues[bank].begin(); it != m_bankQueues[bank].end(); ++it) { - Message* msg_ptr = (*it)->m_msgptr.get(); - if (msg_ptr->functionalRead(pkt)) { + PacketPtr msg = (*it)->pkt; + if (pkt->checkFunctional(msg)) { return true; } } } - m_ram->read(Address(pkt->getAddr()), pkt->getPtr(true), - pkt->getSize()); - + functionalAccess(pkt); return true; } @@ -769,16 +720,16 @@ RubyMemoryControl::functionalWrite(Packet *pkt) for (std::list::iterator it = m_input_queue.begin(); it != m_input_queue.end(); ++it) { - Message* msg_ptr = (*it)->m_msgptr.get(); - if (msg_ptr->functionalWrite(pkt)) { + PacketPtr msg = (*it)->pkt; + if (pkt->checkFunctional(msg)) { num_functional_writes++; } } for (std::list::iterator it = m_response_queue.begin(); it != m_response_queue.end(); ++it) { - Message* msg_ptr = (*it)->m_msgptr.get(); - if (msg_ptr->functionalWrite(pkt)) { + PacketPtr msg = (*it)->pkt; + if (pkt->checkFunctional(msg)) { num_functional_writes++; } } @@ -786,17 +737,15 @@ RubyMemoryControl::functionalWrite(Packet *pkt) for (uint32_t bank = 0; bank < m_total_banks; ++bank) { for (std::list::iterator it = m_bankQueues[bank].begin(); it != m_bankQueues[bank].end(); ++it) { - Message* msg_ptr = (*it)->m_msgptr.get(); - if (msg_ptr->functionalWrite(pkt)) { + PacketPtr msg = (*it)->pkt; + if (pkt->checkFunctional(msg)) { num_functional_writes++; } } } - m_ram->write(Address(pkt->getAddr()), pkt->getPtr(true), - pkt->getSize()); + functionalAccess(pkt); num_functional_writes++; - return num_functional_writes; } @@ -804,6 +753,7 @@ void RubyMemoryControl::regStats() { m_profiler_ptr->regStats(); + AbstractMemory::regStats(); } RubyMemoryControl * @@ -811,3 +761,45 @@ RubyMemoryControlParams::create() { return new RubyMemoryControl(this); } + +RubyMemoryControl::MemoryPort::MemoryPort(const std::string& name, + RubyMemoryControl& _memory) + : QueuedSlavePort(name, &_memory, queue), queue(_memory, *this), + memory(_memory) +{ } + +AddrRangeList +RubyMemoryControl::MemoryPort::getAddrRanges() const +{ + AddrRangeList ranges; + ranges.push_back(memory.getAddrRange()); + return ranges; +} + +void +RubyMemoryControl::MemoryPort::recvFunctional(PacketPtr pkt) +{ + pkt->pushLabel(memory.name()); + + if (!queue.checkFunctional(pkt)) { + // Default implementation of SimpleTimingPort::recvFunctional() + // calls recvAtomic() and throws away the latency; we can save a + // little here by just not calculating the latency. + memory.functionalWrite(pkt); + } + + pkt->popLabel(); +} + +Tick +RubyMemoryControl::MemoryPort::recvAtomic(PacketPtr pkt) +{ + panic("This controller does not support recv atomic!\n"); +} + +bool +RubyMemoryControl::MemoryPort::recvTimingReq(PacketPtr pkt) +{ + // pass it to the memory controller + return memory.recvTimingReq(pkt); +} diff --git a/src/mem/ruby/structures/RubyMemoryControl.hh b/src/mem/ruby/structures/RubyMemoryControl.hh index dde6143c4..6b1ec1702 100644 --- a/src/mem/ruby/structures/RubyMemoryControl.hh +++ b/src/mem/ruby/structures/RubyMemoryControl.hh @@ -34,12 +34,12 @@ #include #include +#include "mem/abstract_mem.hh" #include "mem/protocol/MemoryMsg.hh" #include "mem/ruby/common/Address.hh" #include "mem/ruby/common/Global.hh" #include "mem/ruby/profiler/MemCntrlProfiler.hh" -#include "mem/ruby/structures/MemoryControl.hh" -#include "mem/ruby/structures/MemoryVector.hh" +#include "mem/ruby/structures/MemoryNode.hh" #include "mem/ruby/system/System.hh" #include "params/RubyMemoryControl.hh" @@ -49,7 +49,7 @@ ////////////////////////////////////////////////////////////////////////////// -class RubyMemoryControl : public MemoryControl +class RubyMemoryControl : public AbstractMemory, public Consumer { public: typedef RubyMemoryControlParams Params; @@ -59,22 +59,18 @@ class RubyMemoryControl : public MemoryControl ~RubyMemoryControl(); + virtual BaseSlavePort& getSlavePort(const std::string& if_name, + PortID idx = InvalidPortID); unsigned int drain(DrainManager *dm); - void wakeup(); - void setConsumer(Consumer* consumer_ptr); - Consumer* getConsumer() { return m_consumer_ptr; }; void setDescription(const std::string& name) { m_description = name; }; std::string getDescription() { return m_description; }; // Called from the directory: - void enqueue(const MsgPtr& message, Cycles latency); + bool recvTimingReq(PacketPtr pkt); + void recvFunctional(PacketPtr pkt); void enqueueMemRef(MemoryNode *memRef); - void dequeue(); - const Message* peek(); - MemoryNode *peekNode(); - bool isReady(); bool areNSlotsAvailable(int n) { return true; }; // infinite queue length void print(std::ostream& out) const; @@ -108,8 +104,34 @@ class RubyMemoryControl : public MemoryControl RubyMemoryControl (const RubyMemoryControl& obj); RubyMemoryControl& operator=(const RubyMemoryControl& obj); + private: + // For now, make use of a queued slave port to avoid dealing with + // flow control for the responses being sent back + class MemoryPort : public QueuedSlavePort + { + SlavePacketQueue queue; + RubyMemoryControl& memory; + + public: + MemoryPort(const std::string& name, RubyMemoryControl& _memory); + + protected: + Tick recvAtomic(PacketPtr pkt); + + void recvFunctional(PacketPtr pkt); + + bool recvTimingReq(PacketPtr); + + virtual AddrRangeList getAddrRanges() const; + }; + + /** + * Our incoming port, for a multi-ported controller add a crossbar + * in front of it + */ + MemoryPort port; + // data members - Consumer* m_consumer_ptr; // Consumer to signal a wakeup() std::string m_description; int m_msg_counter; @@ -163,8 +185,20 @@ class RubyMemoryControl : public MemoryControl MemCntrlProfiler* m_profiler_ptr; - // Actual physical memory. - MemoryVector* m_ram; + class MemCntrlEvent : public Event + { + public: + MemCntrlEvent(RubyMemoryControl* _mem_cntrl) + { + mem_cntrl = _mem_cntrl; + } + private: + void process() { mem_cntrl->wakeup(); } + + RubyMemoryControl* mem_cntrl; + }; + + MemCntrlEvent m_event; }; std::ostream& operator<<(std::ostream& out, const RubyMemoryControl& obj); diff --git a/src/mem/ruby/structures/RubyMemoryControl.py b/src/mem/ruby/structures/RubyMemoryControl.py index f0828fb19..78f2d8dcb 100644 --- a/src/mem/ruby/structures/RubyMemoryControl.py +++ b/src/mem/ruby/structures/RubyMemoryControl.py @@ -28,14 +28,12 @@ # Brad Beckmann from m5.params import * -from m5.SimObject import SimObject -from MemoryControl import MemoryControl +from AbstractMemory import AbstractMemory -class RubyMemoryControl(MemoryControl): +class RubyMemoryControl(AbstractMemory): type = 'RubyMemoryControl' cxx_class = 'RubyMemoryControl' cxx_header = "mem/ruby/structures/RubyMemoryControl.hh" - version = Param.Int(""); banks_per_rank = Param.Int(8, ""); ranks_per_dimm = Param.Int(2, ""); @@ -53,3 +51,7 @@ class RubyMemoryControl(MemoryControl): tFaw = Param.Int(0, ""); mem_random_arbitrate = Param.Int(0, ""); mem_fixed_delay = Param.Cycles(0, ""); + + # single-ported on the system interface side, instantiate with a + # crossbar in front of the controller for multiple ports + port = SlavePort("Slave port") diff --git a/src/mem/ruby/structures/SConscript b/src/mem/ruby/structures/SConscript index dee5769d3..ed00d7382 100644 --- a/src/mem/ruby/structures/SConscript +++ b/src/mem/ruby/structures/SConscript @@ -35,14 +35,12 @@ if env['PROTOCOL'] == 'None': SimObject('Cache.py') SimObject('DirectoryMemory.py') -SimObject('MemoryControl.py') SimObject('RubyMemoryControl.py') SimObject('RubyPrefetcher.py') SimObject('WireBuffer.py') Source('DirectoryMemory.cc') Source('CacheMemory.cc') -Source('MemoryControl.cc') Source('WireBuffer.cc') Source('RubyMemoryControl.cc') Source('MemoryNode.cc') diff --git a/src/mem/ruby/system/RubySystem.py b/src/mem/ruby/system/RubySystem.py index 0943fb3f6..77bd9448d 100644 --- a/src/mem/ruby/system/RubySystem.py +++ b/src/mem/ruby/system/RubySystem.py @@ -38,8 +38,8 @@ class RubySystem(ClockedObject): "insert random delays on message enqueue times"); block_size_bytes = Param.UInt32(64, "default cache block size; must be a power of two"); - mem_size = Param.MemorySize("total memory size of the system"); - no_mem_vec = Param.Bool(False, "do not allocate Ruby's mem vector"); + memory_size_bits = Param.UInt32(64, + "number of bits that a memory address requires"); # Profiler related configuration variables hot_lines = Param.Bool(False, "") diff --git a/src/mem/ruby/system/Sequencer.py b/src/mem/ruby/system/Sequencer.py index 6f64207dc..b54924ba7 100644 --- a/src/mem/ruby/system/Sequencer.py +++ b/src/mem/ruby/system/Sequencer.py @@ -55,7 +55,7 @@ class RubyPort(MemObject): class RubyPortProxy(RubyPort): type = 'RubyPortProxy' cxx_header = "mem/ruby/system/RubyPortProxy.hh" - access_phys_mem = True + access_phys_mem = False class RubySequencer(RubyPort): type = 'RubySequencer' diff --git a/src/mem/ruby/system/System.cc b/src/mem/ruby/system/System.cc index 8bcc87474..066cfae87 100644 --- a/src/mem/ruby/system/System.cc +++ b/src/mem/ruby/system/System.cc @@ -47,7 +47,6 @@ int RubySystem::m_random_seed; bool RubySystem::m_randomization; uint32_t RubySystem::m_block_size_bytes; uint32_t RubySystem::m_block_size_bits; -uint64_t RubySystem::m_memory_size_bytes; uint32_t RubySystem::m_memory_size_bits; RubySystem::RubySystem(const Params *p) @@ -63,20 +62,7 @@ RubySystem::RubySystem(const Params *p) m_block_size_bytes = p->block_size_bytes; assert(isPowerOf2(m_block_size_bytes)); m_block_size_bits = floorLog2(m_block_size_bytes); - - m_memory_size_bytes = p->mem_size; - if (m_memory_size_bytes == 0) { - m_memory_size_bits = 0; - } else { - m_memory_size_bits = ceilLog2(m_memory_size_bytes); - } - - if (p->no_mem_vec) { - m_mem_vec = NULL; - } else { - m_mem_vec = new MemoryVector; - m_mem_vec->resize(m_memory_size_bytes); - } + m_memory_size_bits = p->memory_size_bits; m_warmup_enabled = false; m_cooldown_enabled = false; @@ -108,17 +94,10 @@ RubySystem::registerAbstractController(AbstractController* cntrl) g_abs_controls[id.getType()][id.getNum()] = cntrl; } -void -RubySystem::registerMemController(MemoryControl *mc) { - m_memory_controller_vec.push_back(mc); -} - RubySystem::~RubySystem() { delete m_network; delete m_profiler; - if (m_mem_vec) - delete m_mem_vec; } void @@ -206,19 +185,8 @@ RubySystem::serialize(std::ostream &os) // Restore curTick setCurTick(curtick_original); - uint8_t *raw_data = NULL; - uint64 memory_trace_size = m_mem_vec->collatePages(raw_data); - - string memory_trace_file = name() + ".memory.gz"; - writeCompressedTrace(raw_data, memory_trace_file, - memory_trace_size); - - SERIALIZE_SCALAR(memory_trace_file); - SERIALIZE_SCALAR(memory_trace_size); - - // Aggergate the trace entries together into a single array - raw_data = new uint8_t[4096]; + uint8_t *raw_data = new uint8_t[4096]; uint64 cache_trace_size = m_cache_recorder->aggregateRecords(&raw_data, 4096); string cache_trace_file = name() + ".cache.gz"; @@ -272,22 +240,6 @@ RubySystem::unserialize(Checkpoint *cp, const string §ion) uint64 block_size_bytes = getBlockSizeBytes(); UNSERIALIZE_OPT_SCALAR(block_size_bytes); - if (m_mem_vec != NULL) { - string memory_trace_file; - uint64 memory_trace_size = 0; - - UNSERIALIZE_SCALAR(memory_trace_file); - UNSERIALIZE_SCALAR(memory_trace_size); - memory_trace_file = cp->cptDir + "/" + memory_trace_file; - - readCompressedTrace(memory_trace_file, uncompressed_trace, - memory_trace_size); - m_mem_vec->populatePages(uncompressed_trace); - - delete [] uncompressed_trace; - uncompressed_trace = NULL; - } - string cache_trace_file; uint64 cache_trace_size = 0; @@ -355,12 +307,6 @@ RubySystem::startup() m_cache_recorder = NULL; m_warmup_enabled = false; - // reset DRAM so that it's not waiting for events on the old event - // queue - for (int i = 0; i < m_memory_controller_vec.size(); ++i) { - m_memory_controller_vec[i]->reset(); - } - // Restore eventq head eventq_head = eventq->replaceHead(eventq_head); // Restore curTick and Ruby System's clock diff --git a/src/mem/ruby/system/System.hh b/src/mem/ruby/system/System.hh index 8193764dc..81c6029c6 100644 --- a/src/mem/ruby/system/System.hh +++ b/src/mem/ruby/system/System.hh @@ -39,8 +39,6 @@ #include "base/output.hh" #include "mem/ruby/profiler/Profiler.hh" #include "mem/ruby/slicc_interface/AbstractController.hh" -#include "mem/ruby/structures/MemoryControl.hh" -#include "mem/ruby/structures/MemoryVector.hh" #include "mem/ruby/system/CacheRecorder.hh" #include "mem/packet.hh" #include "params/RubySystem.hh" @@ -75,7 +73,6 @@ class RubySystem : public ClockedObject static int getRandomization() { return m_randomization; } static uint32_t getBlockSizeBytes() { return m_block_size_bytes; } static uint32_t getBlockSizeBits() { return m_block_size_bits; } - static uint64_t getMemorySizeBytes() { return m_memory_size_bytes; } static uint32_t getMemorySizeBits() { return m_memory_size_bits; } // Public Methods @@ -86,13 +83,6 @@ class RubySystem : public ClockedObject return m_profiler; } - MemoryVector* - getMemoryVector() - { - assert(m_mem_vec != NULL); - return m_mem_vec; - } - void regStats() { m_profiler->regStats(name()); } void collateStats() { m_profiler->collateStats(); } void resetStats(); @@ -106,7 +96,6 @@ class RubySystem : public ClockedObject void registerNetwork(Network*); void registerAbstractController(AbstractController*); - void registerMemController(MemoryControl *mc); bool eventQueueEmpty() { return eventq->empty(); } void enqueueRubyEvent(Tick tick) @@ -132,16 +121,13 @@ class RubySystem : public ClockedObject static bool m_randomization; static uint32_t m_block_size_bytes; static uint32_t m_block_size_bits; - static uint64_t m_memory_size_bytes; static uint32_t m_memory_size_bits; Network* m_network; - std::vector m_memory_controller_vec; std::vector m_abs_cntrl_vec; public: Profiler* m_profiler; - MemoryVector* m_mem_vec; bool m_warmup_enabled; bool m_cooldown_enabled; CacheRecorder* m_cache_recorder; diff --git a/src/mem/slicc/symbols/StateMachine.py b/src/mem/slicc/symbols/StateMachine.py index 009680941..8b7a63f6a 100644 --- a/src/mem/slicc/symbols/StateMachine.py +++ b/src/mem/slicc/symbols/StateMachine.py @@ -285,7 +285,7 @@ class $c_ident : public AbstractController void recordCacheTrace(int cntrl, CacheRecorder* tr); Sequencer* getSequencer() const; - uint32_t functionalWriteBuffers(PacketPtr&); + int functionalWriteBuffers(PacketPtr&); void countTransition(${ident}_State state, ${ident}_Event event); void possibleTransition(${ident}_State state, ${ident}_Event event); @@ -989,10 +989,10 @@ $c_ident::${{action.ident}}(const Address& addr) # Function for functional writes to messages buffered in the controller code(''' -uint32_t +int $c_ident::functionalWriteBuffers(PacketPtr& pkt) { - uint32_t num_functional_writes = 0; + int num_functional_writes = 0; ''') for var in self.objects: vtype = var.type diff --git a/src/python/swig/pyobject.cc b/src/python/swig/pyobject.cc index fed60ba46..08b9ee69f 100644 --- a/src/python/swig/pyobject.cc +++ b/src/python/swig/pyobject.cc @@ -106,7 +106,7 @@ connectPorts(SimObject *o1, const std::string &name1, int i1, ac1 = dynamic_cast(o1); ac2 = dynamic_cast(o2); - if (ac1 || ac2) { + if ((ac1 || ac2) && name1 != "memory" && name2 != "memory") { MessageBuffer *b = new MessageBuffer(); // set the message buffer associated with the provided names diff --git a/tests/configs/memtest-ruby.py b/tests/configs/memtest-ruby.py index badd64e63..f71370c5e 100644 --- a/tests/configs/memtest-ruby.py +++ b/tests/configs/memtest-ruby.py @@ -80,7 +80,6 @@ options.num_cpus = nb_cores # system simulated system = System(cpu = cpus, funcmem = SimpleMemory(in_addr_map = False), - physmem = SimpleMemory(null = True), funcbus = NoncoherentXBar()) # Dummy voltage domain for all our clock domains system.voltage_domain = VoltageDomain() diff --git a/tests/configs/pc-simple-timing-ruby.py b/tests/configs/pc-simple-timing-ruby.py index 633a19e2f..782cda60d 100644 --- a/tests/configs/pc-simple-timing-ruby.py +++ b/tests/configs/pc-simple-timing-ruby.py @@ -91,8 +91,5 @@ for (i, cpu) in enumerate(system.cpu): cpu.interrupts.int_master = system.ruby._cpu_ports[i].slave cpu.interrupts.int_slave = system.ruby._cpu_ports[i].master -system.physmem = [SimpleMemory(range = r, null = True) - for r in system.mem_ranges] - root = Root(full_system = True, system = system) m5.ticks.setGlobalFrequency('1THz') diff --git a/tests/configs/rubytest-ruby.py b/tests/configs/rubytest-ruby.py index cbb578938..22334efb4 100644 --- a/tests/configs/rubytest-ruby.py +++ b/tests/configs/rubytest-ruby.py @@ -80,7 +80,7 @@ tester = RubyTester(check_flush = check_flush, checks_to_complete = 100, # We set the testers as cpu for ruby to find the correct clock domains # for the L1 Objects. -system = System(cpu = tester, physmem = SimpleMemory(null = True)) +system = System(cpu = tester) # Dummy voltage domain for all our clock domains system.voltage_domain = VoltageDomain(voltage = options.sys_voltage) diff --git a/tests/configs/simple-timing-mp-ruby.py b/tests/configs/simple-timing-mp-ruby.py index da7733acb..263b330fb 100644 --- a/tests/configs/simple-timing-mp-ruby.py +++ b/tests/configs/simple-timing-mp-ruby.py @@ -71,8 +71,7 @@ cpus = [ TimingSimpleCPU(cpu_id=i) for i in xrange(nb_cores) ] options.num_cpus = nb_cores # system simulated -system = System(cpu = cpus, physmem = SimpleMemory(), - clk_domain = SrcClockDomain(clock = '1GHz')) +system = System(cpu = cpus, clk_domain = SrcClockDomain(clock = '1GHz')) # Create a seperate clock domain for components that should run at # CPUs frequency diff --git a/tests/configs/simple-timing-ruby.py b/tests/configs/simple-timing-ruby.py index 3ce6266c1..b9fb650e5 100644 --- a/tests/configs/simple-timing-ruby.py +++ b/tests/configs/simple-timing-ruby.py @@ -65,9 +65,9 @@ options.l3_assoc=2 # this is a uniprocessor only test options.num_cpus = 1 - cpu = TimingSimpleCPU(cpu_id=0) -system = System(cpu = cpu, physmem = SimpleMemory(null = True)) +system = System(cpu = cpu) + # Dummy voltage domain for all our clock domains system.voltage_domain = VoltageDomain(voltage = options.sys_voltage) system.clk_domain = SrcClockDomain(clock = '1GHz',