MemConfig.py revision 14038:8ba13d8b7810
1# Copyright (c) 2013, 2017 ARM Limited 2# All rights reserved. 3# 4# The license below extends only to copyright in the software and shall 5# not be construed as granting a license to any other intellectual 6# property including but not limited to intellectual property relating 7# to a hardware implementation of the functionality of the software 8# licensed hereunder. You may use the software subject to the license 9# terms below provided that you ensure that this notice is replicated 10# unmodified and in its entirety in all distributions of the software, 11# modified or unmodified, in source code or in binary form. 12# 13# Redistribution and use in source and binary forms, with or without 14# modification, are permitted provided that the following conditions are 15# met: redistributions of source code must retain the above copyright 16# notice, this list of conditions and the following disclaimer; 17# redistributions in binary form must reproduce the above copyright 18# notice, this list of conditions and the following disclaimer in the 19# documentation and/or other materials provided with the distribution; 20# neither the name of the copyright holders nor the names of its 21# contributors may be used to endorse or promote products derived from 22# this software without specific prior written permission. 23# 24# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 27# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 28# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 29# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 30# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35# 36# Authors: Andreas Sandberg 37# Andreas Hansson 38 39from __future__ import print_function 40from __future__ import absolute_import 41 42import m5.objects 43import inspect 44import sys 45from textwrap import TextWrapper 46from . import HMC 47 48# Dictionary of mapping names of real memory controller models to 49# classes. 50_mem_classes = {} 51 52def is_mem_class(cls): 53 """Determine if a class is a memory controller that can be instantiated""" 54 55 # We can't use the normal inspect.isclass because the ParamFactory 56 # and ProxyFactory classes have a tendency to confuse it. 57 try: 58 return issubclass(cls, m5.objects.AbstractMemory) and \ 59 not cls.abstract 60 except TypeError: 61 return False 62 63def get(name): 64 """Get a memory class from a user provided class name.""" 65 66 try: 67 mem_class = _mem_classes[name] 68 return mem_class 69 except KeyError: 70 print("%s is not a valid memory controller." % (name,)) 71 sys.exit(1) 72 73def print_mem_list(): 74 """Print a list of available memory classes.""" 75 76 print("Available memory classes:") 77 doc_wrapper = TextWrapper(initial_indent="\t\t", subsequent_indent="\t\t") 78 for name, cls in _mem_classes.items(): 79 print("\t%s" % name) 80 81 # Try to extract the class documentation from the class help 82 # string. 83 doc = inspect.getdoc(cls) 84 if doc: 85 for line in doc_wrapper.wrap(doc): 86 print(line) 87 88def mem_names(): 89 """Return a list of valid memory names.""" 90 return list(_mem_classes.keys()) 91 92# Add all memory controllers in the object hierarchy. 93for name, cls in inspect.getmembers(m5.objects, is_mem_class): 94 _mem_classes[name] = cls 95 96def create_mem_ctrl(cls, r, i, nbr_mem_ctrls, intlv_bits, intlv_size): 97 """ 98 Helper function for creating a single memoy controller from the given 99 options. This function is invoked multiple times in config_mem function 100 to create an array of controllers. 101 """ 102 103 import math 104 intlv_low_bit = int(math.log(intlv_size, 2)) 105 106 # Use basic hashing for the channel selection, and preferably use 107 # the lower tag bits from the last level cache. As we do not know 108 # the details of the caches here, make an educated guess. 4 MByte 109 # 4-way associative with 64 byte cache lines is 6 offset bits and 110 # 14 index bits. 111 xor_low_bit = 20 112 113 # Create an instance so we can figure out the address 114 # mapping and row-buffer size 115 ctrl = cls() 116 117 # Only do this for DRAMs 118 if issubclass(cls, m5.objects.DRAMCtrl): 119 # Inform each controller how many channels to account 120 # for 121 ctrl.channels = nbr_mem_ctrls 122 123 # If the channel bits are appearing after the column 124 # bits, we need to add the appropriate number of bits 125 # for the row buffer size 126 if ctrl.addr_mapping.value == 'RoRaBaChCo': 127 # This computation only really needs to happen 128 # once, but as we rely on having an instance we 129 # end up having to repeat it for each and every 130 # one 131 rowbuffer_size = ctrl.device_rowbuffer_size.value * \ 132 ctrl.devices_per_rank.value 133 134 intlv_low_bit = int(math.log(rowbuffer_size, 2)) 135 136 # We got all we need to configure the appropriate address 137 # range 138 ctrl.range = m5.objects.AddrRange(r.start, size = r.size(), 139 intlvHighBit = \ 140 intlv_low_bit + intlv_bits - 1, 141 xorHighBit = \ 142 xor_low_bit + intlv_bits - 1, 143 intlvBits = intlv_bits, 144 intlvMatch = i) 145 return ctrl 146 147def config_mem(options, system): 148 """ 149 Create the memory controllers based on the options and attach them. 150 151 If requested, we make a multi-channel configuration of the 152 selected memory controller class by creating multiple instances of 153 the specific class. The individual controllers have their 154 parameters set such that the address range is interleaved between 155 them. 156 """ 157 158 # Mandatory options 159 opt_mem_type = options.mem_type 160 opt_mem_channels = options.mem_channels 161 162 # Optional options 163 opt_tlm_memory = getattr(options, "tlm_memory", None) 164 opt_external_memory_system = getattr(options, "external_memory_system", 165 None) 166 opt_elastic_trace_en = getattr(options, "elastic_trace_en", False) 167 opt_mem_ranks = getattr(options, "mem_ranks", None) 168 169 if opt_mem_type == "HMC_2500_1x32": 170 HMChost = HMC.config_hmc_host_ctrl(options, system) 171 HMC.config_hmc_dev(options, system, HMChost.hmc_host) 172 subsystem = system.hmc_dev 173 xbar = system.hmc_dev.xbar 174 else: 175 subsystem = system 176 xbar = system.membus 177 178 if opt_tlm_memory: 179 system.external_memory = m5.objects.ExternalSlave( 180 port_type="tlm_slave", 181 port_data=opt_tlm_memory, 182 port=system.membus.master, 183 addr_ranges=system.mem_ranges) 184 system.kernel_addr_check = False 185 return 186 187 if opt_external_memory_system: 188 subsystem.external_memory = m5.objects.ExternalSlave( 189 port_type=opt_external_memory_system, 190 port_data="init_mem0", port=xbar.master, 191 addr_ranges=system.mem_ranges) 192 subsystem.kernel_addr_check = False 193 return 194 195 nbr_mem_ctrls = opt_mem_channels 196 import math 197 from m5.util import fatal 198 intlv_bits = int(math.log(nbr_mem_ctrls, 2)) 199 if 2 ** intlv_bits != nbr_mem_ctrls: 200 fatal("Number of memory channels must be a power of 2") 201 202 cls = get(opt_mem_type) 203 mem_ctrls = [] 204 205 if opt_elastic_trace_en and not issubclass(cls, m5.objects.SimpleMemory): 206 fatal("When elastic trace is enabled, configure mem-type as " 207 "simple-mem.") 208 209 # The default behaviour is to interleave memory channels on 128 210 # byte granularity, or cache line granularity if larger than 128 211 # byte. This value is based on the locality seen across a large 212 # range of workloads. 213 intlv_size = max(128, system.cache_line_size.value) 214 215 # For every range (most systems will only have one), create an 216 # array of controllers and set their parameters to match their 217 # address mapping in the case of a DRAM 218 for r in system.mem_ranges: 219 for i in range(nbr_mem_ctrls): 220 mem_ctrl = create_mem_ctrl(cls, r, i, nbr_mem_ctrls, intlv_bits, 221 intlv_size) 222 # Set the number of ranks based on the command-line 223 # options if it was explicitly set 224 if issubclass(cls, m5.objects.DRAMCtrl) and opt_mem_ranks: 225 mem_ctrl.ranks_per_channel = opt_mem_ranks 226 227 # Enable low-power DRAM states if option is set 228 if issubclass(cls, m5.objects.DRAMCtrl): 229 mem_ctrl.enable_dram_powerdown = \ 230 options.enable_dram_powerdown 231 232 if opt_elastic_trace_en: 233 mem_ctrl.latency = '1ns' 234 print("For elastic trace, over-riding Simple Memory " 235 "latency to 1ns.") 236 237 mem_ctrls.append(mem_ctrl) 238 239 subsystem.mem_ctrls = mem_ctrls 240 241 # Connect the controllers to the membus 242 for i in range(len(subsystem.mem_ctrls)): 243 if opt_mem_type == "HMC_2500_1x32": 244 subsystem.mem_ctrls[i].port = xbar[i/4].master 245 # Set memory device size. There is an independent controller for 246 # each vault. All vaults are same size. 247 subsystem.mem_ctrls[i].device_size = options.hmc_dev_vault_size 248 else: 249 subsystem.mem_ctrls[i].port = xbar.master 250