diff -r b8e18fb0dd30 -r 069084e2706e configs/example/fs.py --- a/configs/example/fs.py Tue Sep 30 15:03:16 2014 -0500 +++ b/configs/example/fs.py Tue Sep 30 15:05:30 2014 -0500 @@ -136,8 +136,6 @@ sys.exit(1) Ruby.create_system(options, 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 -r b8e18fb0dd30 -r 069084e2706e configs/example/ruby_mem_test.py --- a/configs/example/ruby_mem_test.py Tue Sep 30 15:03:16 2014 -0500 +++ b/configs/example/ruby_mem_test.py Tue Sep 30 15:05:30 2014 -0500 @@ -107,7 +107,6 @@ 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 -r b8e18fb0dd30 -r 069084e2706e configs/example/ruby_random_test.py --- a/configs/example/ruby_random_test.py Tue Sep 30 15:03:16 2014 -0500 +++ b/configs/example/ruby_random_test.py Tue Sep 30 15:05:30 2014 -0500 @@ -97,8 +97,7 @@ # 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 -r b8e18fb0dd30 -r 069084e2706e configs/example/se.py --- a/configs/example/se.py Tue Sep 30 15:03:16 2014 -0500 +++ b/configs/example/se.py Tue Sep 30 15:05:30 2014 -0500 @@ -225,11 +225,6 @@ 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, system) assert(options.num_cpus == len(system.ruby._cpu_ports)) diff -r b8e18fb0dd30 -r 069084e2706e configs/ruby/MESI_Three_Level.py --- a/configs/ruby/MESI_Three_Level.py Tue Sep 30 15:03:16 2014 -0500 +++ b/configs/ruby/MESI_Three_Level.py Tue Sep 30 15:05:30 2014 -0500 @@ -182,22 +182,12 @@ # # 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 -r b8e18fb0dd30 -r 069084e2706e configs/ruby/MESI_Two_Level.py --- a/configs/ruby/MESI_Two_Level.py Tue Sep 30 15:03:16 2014 -0500 +++ b/configs/ruby/MESI_Two_Level.py Tue Sep 30 15:05:30 2014 -0500 @@ -162,25 +162,12 @@ 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 -r b8e18fb0dd30 -r 069084e2706e configs/ruby/MI_example.py --- a/configs/ruby/MI_example.py Tue Sep 30 15:03:16 2014 -0500 +++ b/configs/ruby/MI_example.py Tue Sep 30 15:05:30 2014 -0500 @@ -117,27 +117,11 @@ 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 -r b8e18fb0dd30 -r 069084e2706e configs/ruby/MOESI_CMP_directory.py --- a/configs/ruby/MOESI_CMP_directory.py Tue Sep 30 15:03:16 2014 -0500 +++ b/configs/ruby/MOESI_CMP_directory.py Tue Sep 30 15:05:30 2014 -0500 @@ -156,24 +156,12 @@ 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 -r b8e18fb0dd30 -r 069084e2706e configs/ruby/MOESI_CMP_token.py --- a/configs/ruby/MOESI_CMP_token.py Tue Sep 30 15:03:16 2014 -0500 +++ b/configs/ruby/MOESI_CMP_token.py Tue Sep 30 15:05:30 2014 -0500 @@ -180,24 +180,12 @@ 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 -r b8e18fb0dd30 -r 069084e2706e configs/ruby/MOESI_hammer.py --- a/configs/ruby/MOESI_hammer.py Tue Sep 30 15:03:16 2014 -0500 +++ b/configs/ruby/MOESI_hammer.py Tue Sep 30 15:05:30 2014 -0500 @@ -170,15 +170,6 @@ 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 @@ 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 -r b8e18fb0dd30 -r 069084e2706e configs/ruby/Ruby.py --- a/configs/ruby/Ruby.py Tue Sep 30 15:03:16 2014 -0500 +++ b/configs/ruby/Ruby.py Tue Sep 30 15:05:30 2014 -0500 @@ -45,6 +45,7 @@ from m5.defines import buildEnv from m5.util import addToPath, fatal +import MemConfig addToPath('../topologies') def define_options(parser): @@ -75,22 +76,67 @@ 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_system(options, 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 @@ -168,33 +214,7 @@ 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 -r b8e18fb0dd30 -r 069084e2706e src/mem/protocol/MESI_Two_Level-dir.sm --- a/src/mem/protocol/MESI_Two_Level-dir.sm Tue Sep 30 15:03:16 2014 -0500 +++ b/src/mem/protocol/MESI_Two_Level-dir.sm Tue Sep 30 15:05:30 2014 -0500 @@ -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 @@ 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 @@ // ** OUT_PORTS ** out_port(responseNetwork_out, ResponseMsg, responseFromDir); - out_port(memQueue_out, MemoryMsg, memBuffer); // ** IN_PORTS ** @@ -223,7 +225,7 @@ } // 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 @@ 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 @@ } } - 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 @@ } } - 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 -r b8e18fb0dd30 -r 069084e2706e src/mem/protocol/MI_example-dir.sm --- a/src/mem/protocol/MI_example-dir.sm Tue Sep 30 15:03:16 2014 -0500 +++ b/src/mem/protocol/MI_example-dir.sm Tue Sep 30 15:05:30 2014 -0500 @@ -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 @@ 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 @@ 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 @@ //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 @@ 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 -r b8e18fb0dd30 -r 069084e2706e src/mem/protocol/MOESI_CMP_directory-dir.sm --- a/src/mem/protocol/MOESI_CMP_directory-dir.sm Tue Sep 30 15:03:16 2014 -0500 +++ b/src/mem/protocol/MOESI_CMP_directory-dir.sm Tue Sep 30 15:05:30 2014 -0500 @@ -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 @@ } 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 @@ // ** 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 @@ } // 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 @@ 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 @@ 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 -r b8e18fb0dd30 -r 069084e2706e src/mem/protocol/MOESI_CMP_token-dir.sm --- a/src/mem/protocol/MOESI_CMP_token-dir.sm Tue Sep 30 15:03:16 2014 -0500 +++ b/src/mem/protocol/MOESI_CMP_token-dir.sm Tue Sep 30 15:05:30 2014 -0500 @@ -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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 -r b8e18fb0dd30 -r 069084e2706e src/mem/protocol/MOESI_hammer-dir.sm --- a/src/mem/protocol/MOESI_hammer-dir.sm Tue Sep 30 15:03:16 2014 -0500 +++ b/src/mem/protocol/MOESI_hammer-dir.sm Tue Sep 30 15:05:30 2014 -0500 @@ -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 @@ 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 @@ 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 @@ } // 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } } 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 @@ 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 @@ } } } 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 @@ 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 @@ 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 @@ } } } 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 @@ // 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 @@ 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 @@ } } 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 @@ 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 @@ } } 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 @@ 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 @@ 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 @@ 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 -r b8e18fb0dd30 -r 069084e2706e src/mem/protocol/RubySlicc_Defines.sm --- a/src/mem/protocol/RubySlicc_Defines.sm Tue Sep 30 15:03:16 2014 -0500 +++ b/src/mem/protocol/RubySlicc_Defines.sm Tue Sep 30 15:05:30 2014 -0500 @@ -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 -r b8e18fb0dd30 -r 069084e2706e src/mem/protocol/RubySlicc_Types.sm --- a/src/mem/protocol/RubySlicc_Types.sm Tue Sep 30 15:03:16 2014 -0500 +++ b/src/mem/protocol/RubySlicc_Types.sm Tue Sep 30 15:05:30 2014 -0500 @@ -161,12 +161,6 @@ } -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 -r b8e18fb0dd30 -r 069084e2706e src/mem/ruby/SConscript --- a/src/mem/ruby/SConscript Tue Sep 30 15:03:16 2014 -0500 +++ b/src/mem/ruby/SConscript Tue Sep 30 15:05:30 2014 -0500 @@ -126,7 +126,6 @@ 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 -r b8e18fb0dd30 -r 069084e2706e src/mem/ruby/network/MessageBuffer.cc --- a/src/mem/ruby/network/MessageBuffer.cc Tue Sep 30 15:03:16 2014 -0500 +++ b/src/mem/ruby/network/MessageBuffer.cc Tue Sep 30 15:05:30 2014 -0500 @@ -144,17 +144,17 @@ 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_msg_counter++; m_msgs_this_cycle++; - assert(m_ordering_set); - // Calculate the arrival time of the message, that is, the first // cycle the message can be dequeued. assert(delta > 0); diff -r b8e18fb0dd30 -r 069084e2706e src/mem/ruby/slicc_interface/AbstractController.hh --- a/src/mem/ruby/slicc_interface/AbstractController.hh Tue Sep 30 15:03:16 2014 -0500 +++ b/src/mem/ruby/slicc_interface/AbstractController.hh Tue Sep 30 15:05:30 2014 -0500 @@ -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 @@ //! 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 @@ //! 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 @@ 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 @@ 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 -r b8e18fb0dd30 -r 069084e2706e src/mem/ruby/slicc_interface/AbstractController.cc --- a/src/mem/ruby/slicc_interface/AbstractController.cc Tue Sep 30 15:03:16 2014 -0500 +++ b/src/mem/ruby/slicc_interface/AbstractController.cc Tue Sep 30 15:05:30 2014 -0500 @@ -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,131 @@ 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; + num_functional_writes += m_responseFromMemory_ptr->functionalWrite(pkt); + memoryPort.sendFunctional(pkt); + return num_functional_writes + 1; +} + +void +AbstractController::recvTimingResp(PacketPtr pkt) +{ + assert(pkt->isResponse()); + + MemoryMsg *msg = new MemoryMsg(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 -r b8e18fb0dd30 -r 069084e2706e src/mem/ruby/slicc_interface/Controller.py --- a/src/mem/ruby/slicc_interface/Controller.py Tue Sep 30 15:03:16 2014 -0500 +++ b/src/mem/ruby/slicc_interface/Controller.py Tue Sep 30 15:05:30 2014 -0500 @@ -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 @@ 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 -r b8e18fb0dd30 -r 069084e2706e src/mem/ruby/structures/Cache.py --- a/src/mem/ruby/structures/Cache.py Tue Sep 30 15:03:16 2014 -0500 +++ b/src/mem/ruby/structures/Cache.py Tue Sep 30 15:05:30 2014 -0500 @@ -29,7 +29,6 @@ from m5.params import * from m5.SimObject import SimObject -from Controller import RubyController class RubyCache(SimObject): type = 'RubyCache' diff -r b8e18fb0dd30 -r 069084e2706e src/mem/ruby/structures/DirectoryMemory.py --- a/src/mem/ruby/structures/DirectoryMemory.py Tue Sep 30 15:03:16 2014 -0500 +++ b/src/mem/ruby/structures/DirectoryMemory.py Tue Sep 30 15:05:30 2014 -0500 @@ -37,8 +37,6 @@ 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 -r b8e18fb0dd30 -r 069084e2706e src/mem/ruby/structures/MemoryControl.hh --- a/src/mem/ruby/structures/MemoryControl.hh Tue Sep 30 15:03:16 2014 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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 -r b8e18fb0dd30 -r 069084e2706e src/mem/ruby/structures/MemoryControl.cc --- a/src/mem/ruby/structures/MemoryControl.cc Tue Sep 30 15:03:16 2014 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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 -r b8e18fb0dd30 -r 069084e2706e src/mem/ruby/structures/MemoryControl.py --- a/src/mem/ruby/structures/MemoryControl.py Tue Sep 30 15:03:16 2014 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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 -r b8e18fb0dd30 -r 069084e2706e src/mem/ruby/structures/MemoryVector.hh --- a/src/mem/ruby/structures/MemoryVector.hh Tue Sep 30 15:03:16 2014 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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 -r b8e18fb0dd30 -r 069084e2706e src/mem/ruby/structures/RubyMemoryControl.hh --- a/src/mem/ruby/structures/RubyMemoryControl.hh Tue Sep 30 15:03:16 2014 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,172 +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_MEMORY_CONTROL_HH__ -#define __MEM_RUBY_STRUCTURES_MEMORY_CONTROL_HH__ - -#include -#include -#include - -#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/system/System.hh" -#include "params/RubyMemoryControl.hh" - -// This constant is part of the definition of tFAW; see -// the comments in header to RubyMemoryControl.cc -#define ACTIVATE_PER_TFAW 4 - -////////////////////////////////////////////////////////////////////////////// - -class RubyMemoryControl : public MemoryControl -{ - public: - typedef RubyMemoryControlParams Params; - RubyMemoryControl(const Params *p); - void init(); - void reset(); - - ~RubyMemoryControl(); - - 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); - 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; - void regStats(); - - const int getBank(const physical_address_t addr) const; - const int getRank(const physical_address_t addr) const; - - // not used in Ruby memory controller - const int getChannel(const physical_address_t addr) const; - const int getRow(const physical_address_t addr) const; - - //added by SS - int getBanksPerRank() { return m_banks_per_rank; }; - int getRanksPerDimm() { return m_ranks_per_dimm; }; - int getDimmsPerChannel() { return m_dimms_per_channel; } - - bool functionalRead(Packet *pkt); - uint32_t functionalWrite(Packet *pkt); - - private: - void enqueueToDirectory(MemoryNode *req, Cycles latency); - const int getRank(int bank) const; - bool queueReady(int bank); - void issueRequest(int bank); - bool issueRefresh(int bank); - void markTfaw(int rank); - void executeCycle(); - - // Private copy constructor and assignment operator - RubyMemoryControl (const RubyMemoryControl& obj); - RubyMemoryControl& operator=(const RubyMemoryControl& obj); - - // data members - Consumer* m_consumer_ptr; // Consumer to signal a wakeup() - std::string m_description; - int m_msg_counter; - - int m_banks_per_rank; - int m_ranks_per_dimm; - int m_dimms_per_channel; - int m_bank_bit_0; - int m_rank_bit_0; - int m_dimm_bit_0; - unsigned int m_bank_queue_size; - int m_bank_busy_time; - int m_rank_rank_delay; - int m_read_write_delay; - int m_basic_bus_busy_time; - Cycles m_mem_ctl_latency; - int m_refresh_period; - int m_mem_random_arbitrate; - int m_tFaw; - Cycles m_mem_fixed_delay; - - int m_total_banks; - int m_total_ranks; - int m_refresh_period_system; - - // queues where memory requests live - std::list m_response_queue; - std::list m_input_queue; - std::list* m_bankQueues; - - // Each entry indicates number of address-bus cycles until bank - // is reschedulable: - int* m_bankBusyCounter; - int* m_oldRequest; - - uint64* m_tfaw_shift; - int* m_tfaw_count; - - // Each of these indicates number of address-bus cycles until - // we can issue a new request of the corresponding type: - int m_busBusyCounter_Write; - int m_busBusyCounter_ReadNewRank; - int m_busBusyCounter_Basic; - - int m_busBusy_WhichRank; // which rank last granted - int m_roundRobin; // which bank queue was last granted - int m_refresh_count; // cycles until next refresh - int m_need_refresh; // set whenever m_refresh_count goes to zero - int m_refresh_bank; // which bank to refresh next - int m_ageCounter; // age of old requests; to detect starvation - int m_idleCount; // watchdog timer for shutting down - - MemCntrlProfiler* m_profiler_ptr; - - // Actual physical memory. - MemoryVector* m_ram; -}; - -std::ostream& operator<<(std::ostream& out, const RubyMemoryControl& obj); - -#endif // __MEM_RUBY_STRUCTURES_MEMORY_CONTROL_HH__ diff -r b8e18fb0dd30 -r 069084e2706e src/mem/ruby/structures/RubyMemoryControl.cc --- a/src/mem/ruby/structures/RubyMemoryControl.cc Tue Sep 30 15:03:16 2014 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,813 +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. - */ - -/* - * Description: This module simulates a basic DDR-style memory controller - * (and can easily be extended to do FB-DIMM as well). - * - * This module models a single channel, connected to any number of - * DIMMs with any number of ranks of DRAMs each. If you want multiple - * address/data channels, you need to instantiate multiple copies of - * this module. - * - * Each memory request is placed in a queue associated with a specific - * memory bank. This queue is of finite size; if the queue is full - * the request will back up in an (infinite) common queue and will - * effectively throttle the whole system. This sort of behavior is - * intended to be closer to real system behavior than if we had an - * infinite queue on each bank. If you want the latter, just make - * the bank queues unreasonably large. - * - * The head item on a bank queue is issued when all of the - * following are true: - * the bank is available - * the address path to the DIMM is available - * the data path to or from the DIMM is available - * - * Note that we are not concerned about fixed offsets in time. The bank - * will not be used at the same moment as the address path, but since - * there is no queue in the DIMM or the DRAM it will be used at a constant - * number of cycles later, so it is treated as if it is used at the same - * time. - * - * We are assuming closed bank policy; that is, we automatically close - * each bank after a single read or write. Adding an option for open - * bank policy is for future work. - * - * We are assuming "posted CAS"; that is, we send the READ or WRITE - * immediately after the ACTIVATE. This makes scheduling the address - * bus trivial; we always schedule a fixed set of cycles. For DDR-400, - * this is a set of two cycles; for some configurations such as - * DDR-800 the parameter tRRD forces this to be set to three cycles. - * - * We assume a four-bit-time transfer on the data wires. This is - * the minimum burst length for DDR-2. This would correspond - * to (for example) a memory where each DIMM is 72 bits wide - * and DIMMs are ganged in pairs to deliver 64 bytes at a shot. - * This gives us the same occupancy on the data wires as on the - * address wires (for the two-address-cycle case). - * - * The only non-trivial scheduling problem is the data wires. - * A write will use the wires earlier in the operation than a read - * will; typically one cycle earlier as seen at the DRAM, but earlier - * by a worst-case round-trip wire delay when seen at the memory controller. - * So, while reads from one rank can be scheduled back-to-back - * every two cycles, and writes (to any rank) scheduled every two cycles, - * when a read is followed by a write we need to insert a bubble. - * Furthermore, consecutive reads from two different ranks may need - * to insert a bubble due to skew between when one DRAM stops driving the - * wires and when the other one starts. (These bubbles are parameters.) - * - * This means that when some number of reads and writes are at the - * heads of their queues, reads could starve writes, and/or reads - * to the same rank could starve out other requests, since the others - * would never see the data bus ready. - * For this reason, we have implemented an anti-starvation feature. - * A group of requests is marked "old", and a counter is incremented - * each cycle as long as any request from that batch has not issued. - * if the counter reaches twice the bank busy time, we hold off any - * newer requests until all of the "old" requests have issued. - * - * We also model tFAW. This is an obscure DRAM parameter that says - * that no more than four activate requests can happen within a window - * of a certain size. For most configurations this does not come into play, - * or has very little effect, but it could be used to throttle the power - * consumption of the DRAM. In this implementation (unlike in a DRAM - * data sheet) TFAW is measured in memory bus cycles; i.e. if TFAW = 16 - * then no more than four activates may happen within any 16 cycle window. - * Refreshes are included in the activates. - * - */ - -#include "base/cast.hh" -#include "base/cprintf.hh" -#include "base/random.hh" -#include "debug/RubyMemory.hh" -#include "mem/ruby/common/Address.hh" -#include "mem/ruby/common/Global.hh" -#include "mem/ruby/profiler/Profiler.hh" -#include "mem/ruby/slicc_interface/NetworkMessage.hh" -#include "mem/ruby/slicc_interface/RubySlicc_ComponentMapping.hh" -#include "mem/ruby/structures/RubyMemoryControl.hh" -#include "mem/ruby/system/System.hh" - -using namespace std; - -// Value to reset watchdog timer to. -// If we're idle for this many memory control cycles, -// shut down our clock (our rescheduling of ourselves). -// Refresh shuts down as well. -// When we restart, we'll be in a different phase -// with respect to ruby cycles, so this introduces -// a slight inaccuracy. But it is necessary or the -// ruby tester never terminates because the event -// queue is never empty. -#define IDLECOUNT_MAX_VALUE 1000 - -// Output operator definition - -ostream& -operator<<(ostream& out, const RubyMemoryControl& obj) -{ - obj.print(out); - out << flush; - return out; -} - - -// **************************************************************** - -// CONSTRUCTOR -RubyMemoryControl::RubyMemoryControl(const Params *p) - : MemoryControl(p) -{ - m_banks_per_rank = p->banks_per_rank; - m_ranks_per_dimm = p->ranks_per_dimm; - m_dimms_per_channel = p->dimms_per_channel; - m_bank_bit_0 = p->bank_bit_0; - m_rank_bit_0 = p->rank_bit_0; - m_dimm_bit_0 = p->dimm_bit_0; - m_bank_queue_size = p->bank_queue_size; - m_bank_busy_time = p->bank_busy_time; - m_rank_rank_delay = p->rank_rank_delay; - m_read_write_delay = p->read_write_delay; - m_basic_bus_busy_time = p->basic_bus_busy_time; - m_mem_ctl_latency = p->mem_ctl_latency; - m_refresh_period = p->refresh_period; - m_tFaw = p->tFaw; - m_mem_random_arbitrate = p->mem_random_arbitrate; - m_mem_fixed_delay = p->mem_fixed_delay; - - m_profiler_ptr = new MemCntrlProfiler(name(), - m_banks_per_rank, - m_ranks_per_dimm, - m_dimms_per_channel); -} - -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; - m_total_ranks = m_ranks_per_dimm * m_dimms_per_channel; - m_refresh_period_system = m_refresh_period / m_total_banks; - - m_bankQueues = new list [m_total_banks]; - assert(m_bankQueues); - - m_bankBusyCounter = new int [m_total_banks]; - assert(m_bankBusyCounter); - - m_oldRequest = new int [m_total_banks]; - assert(m_oldRequest); - - for (int i = 0; i < m_total_banks; i++) { - m_bankBusyCounter[i] = 0; - m_oldRequest[i] = 0; - } - - m_busBusyCounter_Basic = 0; - m_busBusyCounter_Write = 0; - m_busBusyCounter_ReadNewRank = 0; - m_busBusy_WhichRank = 0; - - m_roundRobin = 0; - m_refresh_count = 1; - m_need_refresh = 0; - m_refresh_bank = 0; - m_idleCount = 0; - m_ageCounter = 0; - - // Each tfaw shift register keeps a moving bit pattern - // which shows when recent activates have occurred. - // m_tfaw_count keeps track of how many 1 bits are set - // in each shift register. When m_tfaw_count is >= 4, - // new activates are not allowed. - m_tfaw_shift = new uint64[m_total_ranks]; - m_tfaw_count = new int[m_total_ranks]; - for (int i = 0; i < m_total_ranks; i++) { - m_tfaw_shift[i] = 0; - m_tfaw_count[i] = 0; - } -} - -void -RubyMemoryControl::reset() -{ - 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; - m_total_ranks = m_ranks_per_dimm * m_dimms_per_channel; - m_refresh_period_system = m_refresh_period / m_total_banks; - - assert(m_bankQueues); - - assert(m_bankBusyCounter); - - assert(m_oldRequest); - - for (int i = 0; i < m_total_banks; i++) { - m_bankBusyCounter[i] = 0; - m_oldRequest[i] = 0; - } - - m_busBusyCounter_Basic = 0; - m_busBusyCounter_Write = 0; - m_busBusyCounter_ReadNewRank = 0; - m_busBusy_WhichRank = 0; - - m_roundRobin = 0; - m_refresh_count = 1; - m_need_refresh = 0; - m_refresh_bank = 0; - m_idleCount = 0; - m_ageCounter = 0; - - // Each tfaw shift register keeps a moving bit pattern - // which shows when recent activates have occurred. - // m_tfaw_count keeps track of how many 1 bits are set - // in each shift register. When m_tfaw_count is >= 4, - // new activates are not allowed. - for (int i = 0; i < m_total_ranks; i++) { - m_tfaw_shift[i] = 0; - m_tfaw_count[i] = 0; - } -} - -RubyMemoryControl::~RubyMemoryControl() -{ - delete [] m_bankQueues; - delete [] m_bankBusyCounter; - delete [] m_oldRequest; - delete m_profiler_ptr; -} - -// enqueue new request from directory -void -RubyMemoryControl::enqueue(const MsgPtr& message, Cycles latency) -{ - 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); - - 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, - is_mem_read, !is_mem_read); - enqueueMemRef(thisReq); -} - -// Alternate entry point used when we already have a MemoryNode -// structure built. -void -RubyMemoryControl::enqueueMemRef(MemoryNode *memRef) -{ - m_msg_counter++; - memRef->m_msg_counter = m_msg_counter; - physical_address_t addr = memRef->m_addr; - int bank = getBank(addr); - - DPRINTF(RubyMemory, - "New memory request%7d: %#08x %c arrived at %10d bank = %3x sched %c\n", - m_msg_counter, addr, memRef->m_is_mem_read ? 'R':'W', - memRef->m_time * g_system_ptr->clockPeriod(), - bank, m_event.scheduled() ? 'Y':'N'); - - m_profiler_ptr->profileMemReq(bank); - m_input_queue.push_back(memRef); - - if (!m_event.scheduled()) { - schedule(m_event, clockEdge()); - } -} - -// 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 -{ -} - -// Queue up a completed request to send back to directory -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); - - 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 -// bank across this memory controller. -const int -RubyMemoryControl::getBank(const physical_address_t addr) const -{ - int dimm = (addr >> m_dimm_bit_0) & (m_dimms_per_channel - 1); - int rank = (addr >> m_rank_bit_0) & (m_ranks_per_dimm - 1); - int bank = (addr >> m_bank_bit_0) & (m_banks_per_rank - 1); - return (dimm * m_ranks_per_dimm * m_banks_per_rank) - + (rank * m_banks_per_rank) - + bank; -} - -const int -RubyMemoryControl::getRank(const physical_address_t addr) const -{ - int bank = getBank(addr); - int rank = (bank / m_banks_per_rank); - assert (rank < (m_ranks_per_dimm * m_dimms_per_channel)); - return rank; -} - -// getRank returns an integer that is unique for each rank -// and independent of individual bank. -const int -RubyMemoryControl::getRank(int bank) const -{ - int rank = (bank / m_banks_per_rank); - assert (rank < (m_ranks_per_dimm * m_dimms_per_channel)); - return rank; -} - -// Not used! -const int -RubyMemoryControl::getChannel(const physical_address_t addr) const -{ - assert(false); - return -1; -} - -// Not used! -const int -RubyMemoryControl::getRow(const physical_address_t addr) const -{ - assert(false); - return -1; -} - -// queueReady determines if the head item in a bank queue -// can be issued this cycle -bool -RubyMemoryControl::queueReady(int bank) -{ - if ((m_bankBusyCounter[bank] > 0) && !m_mem_fixed_delay) { - m_profiler_ptr->profileMemBankBusy(); - - DPRINTF(RubyMemory, "bank %x busy %d\n", bank, m_bankBusyCounter[bank]); - return false; - } - - if (m_mem_random_arbitrate >= 2) { - if (random_mt.random(0, 100) < m_mem_random_arbitrate) { - m_profiler_ptr->profileMemRandBusy(); - return false; - } - } - - if (m_mem_fixed_delay) - return true; - - if ((m_ageCounter > (2 * m_bank_busy_time)) && !m_oldRequest[bank]) { - m_profiler_ptr->profileMemNotOld(); - return false; - } - - if (m_busBusyCounter_Basic == m_basic_bus_busy_time) { - // Another bank must have issued this same cycle. For - // profiling, we count this as an arb wait rather than a bus - // wait. This is a little inaccurate since it MIGHT have also - // been blocked waiting for a read-write or a read-read - // instead, but it's pretty close. - m_profiler_ptr->profileMemArbWait(1); - return false; - } - - if (m_busBusyCounter_Basic > 0) { - m_profiler_ptr->profileMemBusBusy(); - return false; - } - - int rank = getRank(bank); - if (m_tfaw_count[rank] >= ACTIVATE_PER_TFAW) { - m_profiler_ptr->profileMemTfawBusy(); - return false; - } - - bool write = !m_bankQueues[bank].front()->m_is_mem_read; - if (write && (m_busBusyCounter_Write > 0)) { - m_profiler_ptr->profileMemReadWriteBusy(); - return false; - } - - if (!write && (rank != m_busBusy_WhichRank) - && (m_busBusyCounter_ReadNewRank > 0)) { - m_profiler_ptr->profileMemDataBusBusy(); - return false; - } - - return true; -} - -// issueRefresh checks to see if this bank has a refresh scheduled -// and, if so, does the refresh and returns true -bool -RubyMemoryControl::issueRefresh(int bank) -{ - if (!m_need_refresh || (m_refresh_bank != bank)) - return false; - if (m_bankBusyCounter[bank] > 0) - return false; - // Note that m_busBusyCounter will prevent multiple issues during - // the same cycle, as well as on different but close cycles: - if (m_busBusyCounter_Basic > 0) - return false; - int rank = getRank(bank); - if (m_tfaw_count[rank] >= ACTIVATE_PER_TFAW) - return false; - - // Issue it: - DPRINTF(RubyMemory, "Refresh bank %3x\n", bank); - - m_profiler_ptr->profileMemRefresh(); - m_need_refresh--; - m_refresh_bank++; - if (m_refresh_bank >= m_total_banks) - m_refresh_bank = 0; - m_bankBusyCounter[bank] = m_bank_busy_time; - m_busBusyCounter_Basic = m_basic_bus_busy_time; - m_busBusyCounter_Write = m_basic_bus_busy_time; - m_busBusyCounter_ReadNewRank = m_basic_bus_busy_time; - markTfaw(rank); - return true; -} - -// Mark the activate in the tFaw shift register -void -RubyMemoryControl::markTfaw(int rank) -{ - if (m_tFaw) { - m_tfaw_shift[rank] |= (1 << (m_tFaw-1)); - m_tfaw_count[rank]++; - } -} - -// Issue a memory request: Activate the bank, reserve the address and -// data buses, and queue the request for return to the requesting -// processor after a fixed latency. -void -RubyMemoryControl::issueRequest(int bank) -{ - int rank = getRank(bank); - MemoryNode *req = m_bankQueues[bank].front(); - m_bankQueues[bank].pop_front(); - - DPRINTF(RubyMemory, "Mem issue request%7d: %#08x %c " - "bank=%3x sched %c\n", req->m_msg_counter, req->m_addr, - 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)); - } - m_oldRequest[bank] = 0; - markTfaw(rank); - m_bankBusyCounter[bank] = m_bank_busy_time; - m_busBusy_WhichRank = rank; - if (req->m_is_mem_read) { - m_profiler_ptr->profileMemRead(); - m_busBusyCounter_Basic = m_basic_bus_busy_time; - m_busBusyCounter_Write = m_basic_bus_busy_time + m_read_write_delay; - m_busBusyCounter_ReadNewRank = - m_basic_bus_busy_time + m_rank_rank_delay; - } else { - m_profiler_ptr->profileMemWrite(); - m_busBusyCounter_Basic = m_basic_bus_busy_time; - m_busBusyCounter_Write = m_basic_bus_busy_time; - m_busBusyCounter_ReadNewRank = m_basic_bus_busy_time; - } -} - -// executeCycle: This function is called once per memory clock cycle -// to simulate all the periodic hardware. -void -RubyMemoryControl::executeCycle() -{ - // Keep track of time by counting down the busy counters: - for (int bank=0; bank < m_total_banks; bank++) { - if (m_bankBusyCounter[bank] > 0) m_bankBusyCounter[bank]--; - } - if (m_busBusyCounter_Write > 0) - m_busBusyCounter_Write--; - if (m_busBusyCounter_ReadNewRank > 0) - m_busBusyCounter_ReadNewRank--; - if (m_busBusyCounter_Basic > 0) - m_busBusyCounter_Basic--; - - // Count down the tFAW shift registers: - for (int rank=0; rank < m_total_ranks; rank++) { - if (m_tfaw_shift[rank] & 1) m_tfaw_count[rank]--; - m_tfaw_shift[rank] >>= 1; - } - - // After time period expires, latch an indication that we need a refresh. - // Disable refresh if in mem_fixed_delay mode. - if (!m_mem_fixed_delay) m_refresh_count--; - if (m_refresh_count == 0) { - m_refresh_count = m_refresh_period_system; - - // Are we overrunning our ability to refresh? - assert(m_need_refresh < 10); - m_need_refresh++; - } - - // If this batch of requests is all done, make a new batch: - m_ageCounter++; - int anyOld = 0; - for (int bank=0; bank < m_total_banks; bank++) { - anyOld |= m_oldRequest[bank]; - } - if (!anyOld) { - for (int bank=0; bank < m_total_banks; bank++) { - if (!m_bankQueues[bank].empty()) m_oldRequest[bank] = 1; - } - m_ageCounter = 0; - } - - // If randomness desired, re-randomize round-robin position each cycle - if (m_mem_random_arbitrate) { - m_roundRobin = random_mt.random(0, m_total_banks - 1); - } - - // For each channel, scan round-robin, and pick an old, ready - // request and issue it. Treat a refresh request as if it were at - // the head of its bank queue. After we issue something, keep - // scanning the queues just to gather statistics about how many - // are waiting. If in mem_fixed_delay mode, we can issue more - // than one request per cycle. - int queueHeads = 0; - int banksIssued = 0; - for (int i = 0; i < m_total_banks; i++) { - m_roundRobin++; - if (m_roundRobin >= m_total_banks) m_roundRobin = 0; - issueRefresh(m_roundRobin); - int qs = m_bankQueues[m_roundRobin].size(); - if (qs > 1) { - m_profiler_ptr->profileMemBankQ(qs-1); - } - if (qs > 0) { - // we're not idle if anything is queued - m_idleCount = IDLECOUNT_MAX_VALUE; - queueHeads++; - if (queueReady(m_roundRobin)) { - issueRequest(m_roundRobin); - banksIssued++; - if (m_mem_fixed_delay) { - m_profiler_ptr->profileMemWaitCycles(m_mem_fixed_delay); - } - } - } - } - - // memWaitCycles is a redundant catch-all for the specific - // counters in queueReady - m_profiler_ptr->profileMemWaitCycles(queueHeads - banksIssued); - - // Check input queue and move anything to bank queues if not full. - // Since this is done here at the end of the cycle, there will - // always be at least one cycle of latency in the bank queue. We - // deliberately move at most one request per cycle (to simulate - // typical hardware). Note that if one bank queue fills up, other - // requests can get stuck behind it here. - if (!m_input_queue.empty()) { - // we're not idle if anything is pending - m_idleCount = IDLECOUNT_MAX_VALUE; - MemoryNode *req = m_input_queue.front(); - int bank = getBank(req->m_addr); - if (m_bankQueues[bank].size() < m_bank_queue_size) { - m_input_queue.pop_front(); - m_bankQueues[bank].push_back(req); - } - m_profiler_ptr->profileMemInputQ(m_input_queue.size()); - } -} - -unsigned int -RubyMemoryControl::drain(DrainManager *dm) -{ - DPRINTF(RubyMemory, "MemoryController drain\n"); - if(m_event.scheduled()) { - deschedule(m_event); - } - return 0; -} - -// wakeup: This function is called once per memory controller clock cycle. -void -RubyMemoryControl::wakeup() -{ - DPRINTF(RubyMemory, "MemoryController wakeup\n"); - // execute everything - executeCycle(); - - m_idleCount--; - if (m_idleCount > 0) { - assert(!m_event.scheduled()); - schedule(m_event, clockEdge(Cycles(1))); - } -} - -/** - * This function reads the different buffers that exist in the Ruby Memory - * Controller, and figures out if any of the buffers hold a message that - * contains the data for the address provided in the packet. True is returned - * if any of the messages was read, otherwise false is returned. - * - * I think we should move these buffers to being message buffers, instead of - * being lists. - */ -bool -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)) { - 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)) { - return true; - } - } - - 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)) { - return true; - } - } - } - - m_ram->read(Address(pkt->getAddr()), pkt->getPtr(true), - pkt->getSize()); - - return true; -} - -/** - * This function reads the different buffers that exist in the Ruby Memory - * Controller, and figures out if any of the buffers hold a message that - * needs to functionally written with the data in the packet. - * - * The number of messages written is returned at the end. This is required - * for debugging purposes. - */ -uint32_t -RubyMemoryControl::functionalWrite(Packet *pkt) -{ - uint32_t num_functional_writes = 0; - - 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)) { - 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)) { - num_functional_writes++; - } - } - - 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)) { - num_functional_writes++; - } - } - } - - m_ram->write(Address(pkt->getAddr()), pkt->getPtr(true), - pkt->getSize()); - num_functional_writes++; - - return num_functional_writes; -} - -void -RubyMemoryControl::regStats() -{ - m_profiler_ptr->regStats(); -} - -RubyMemoryControl * -RubyMemoryControlParams::create() -{ - return new RubyMemoryControl(this); -} diff -r b8e18fb0dd30 -r 069084e2706e src/mem/ruby/structures/RubyMemoryControl.py --- a/src/mem/ruby/structures/RubyMemoryControl.py Tue Sep 30 15:03:16 2014 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -# Copyright (c) 2009 Advanced Micro Devices, Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Authors: Steve Reinhardt -# Brad Beckmann - -from m5.params import * -from m5.SimObject import SimObject -from MemoryControl import MemoryControl - -class RubyMemoryControl(MemoryControl): - 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, ""); - dimms_per_channel = Param.Int(2, ""); - bank_bit_0 = Param.Int(8, ""); - rank_bit_0 = Param.Int(11, ""); - dimm_bit_0 = Param.Int(12, ""); - bank_queue_size = Param.Int(12, ""); - bank_busy_time = Param.Int(11, ""); - rank_rank_delay = Param.Int(1, ""); - read_write_delay = Param.Int(2, ""); - basic_bus_busy_time = Param.Int(2, ""); - mem_ctl_latency = Param.Cycles(12, ""); - refresh_period = Param.Cycles(1560, ""); - tFaw = Param.Int(0, ""); - mem_random_arbitrate = Param.Int(0, ""); - mem_fixed_delay = Param.Cycles(0, ""); diff -r b8e18fb0dd30 -r 069084e2706e src/mem/ruby/structures/SConscript --- a/src/mem/ruby/structures/SConscript Tue Sep 30 15:03:16 2014 -0500 +++ b/src/mem/ruby/structures/SConscript Tue Sep 30 15:05:30 2014 -0500 @@ -35,16 +35,12 @@ 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') Source('PersistentTable.cc') Source('Prefetcher.cc') diff -r b8e18fb0dd30 -r 069084e2706e src/mem/ruby/system/RubySystem.py --- a/src/mem/ruby/system/RubySystem.py Tue Sep 30 15:03:16 2014 -0500 +++ b/src/mem/ruby/system/RubySystem.py Tue Sep 30 15:05:30 2014 -0500 @@ -38,8 +38,8 @@ "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 -r b8e18fb0dd30 -r 069084e2706e src/mem/ruby/system/System.hh --- a/src/mem/ruby/system/System.hh Tue Sep 30 15:03:16 2014 -0500 +++ b/src/mem/ruby/system/System.hh Tue Sep 30 15:05:30 2014 -0500 @@ -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 @@ 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 @@ 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 @@ void registerNetwork(Network*); void registerAbstractController(AbstractController*); - void registerMemController(MemoryControl *mc); bool eventQueueEmpty() { return eventq->empty(); } void enqueueRubyEvent(Tick tick) @@ -132,16 +121,13 @@ 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 -r b8e18fb0dd30 -r 069084e2706e src/mem/ruby/system/System.cc --- a/src/mem/ruby/system/System.cc Tue Sep 30 15:03:16 2014 -0500 +++ b/src/mem/ruby/system/System.cc Tue Sep 30 15:05:30 2014 -0500 @@ -47,7 +47,6 @@ 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 @@ 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 @@ 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 @@ // 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 @@ 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 @@ 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 -r b8e18fb0dd30 -r 069084e2706e src/mem/slicc/symbols/StateMachine.py --- a/src/mem/slicc/symbols/StateMachine.py Tue Sep 30 15:03:16 2014 -0500 +++ b/src/mem/slicc/symbols/StateMachine.py Tue Sep 30 15:05:30 2014 -0500 @@ -285,7 +285,7 @@ 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 @@ # 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 -r b8e18fb0dd30 -r 069084e2706e src/python/swig/pyobject.cc --- a/src/python/swig/pyobject.cc Tue Sep 30 15:03:16 2014 -0500 +++ b/src/python/swig/pyobject.cc Tue Sep 30 15:05:30 2014 -0500 @@ -106,7 +106,7 @@ 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 -r b8e18fb0dd30 -r 069084e2706e tests/configs/pc-simple-timing-ruby.py --- a/tests/configs/pc-simple-timing-ruby.py Tue Sep 30 15:03:16 2014 -0500 +++ b/tests/configs/pc-simple-timing-ruby.py Tue Sep 30 15:05:30 2014 -0500 @@ -91,8 +91,5 @@ 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')