MemConfig.py revision 14062:21848204c189
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 opt_dram_powerdown = getattr(options, "enable_dram_powerdown", None) 169 170 if opt_mem_type == "HMC_2500_1x32": 171 HMChost = HMC.config_hmc_host_ctrl(options, system) 172 HMC.config_hmc_dev(options, system, HMChost.hmc_host) 173 subsystem = system.hmc_dev 174 xbar = system.hmc_dev.xbar 175 else: 176 subsystem = system 177 xbar = system.membus 178 179 if opt_tlm_memory: 180 system.external_memory = m5.objects.ExternalSlave( 181 port_type="tlm_slave", 182 port_data=opt_tlm_memory, 183 port=system.membus.master, 184 addr_ranges=system.mem_ranges) 185 system.kernel_addr_check = False 186 return 187 188 if opt_external_memory_system: 189 subsystem.external_memory = m5.objects.ExternalSlave( 190 port_type=opt_external_memory_system, 191 port_data="init_mem0", port=xbar.master, 192 addr_ranges=system.mem_ranges) 193 subsystem.kernel_addr_check = False 194 return 195 196 nbr_mem_ctrls = opt_mem_channels 197 import math 198 from m5.util import fatal 199 intlv_bits = int(math.log(nbr_mem_ctrls, 2)) 200 if 2 ** intlv_bits != nbr_mem_ctrls: 201 fatal("Number of memory channels must be a power of 2") 202 203 cls = get(opt_mem_type) 204 mem_ctrls = [] 205 206 if opt_elastic_trace_en and not issubclass(cls, m5.objects.SimpleMemory): 207 fatal("When elastic trace is enabled, configure mem-type as " 208 "simple-mem.") 209 210 # The default behaviour is to interleave memory channels on 128 211 # byte granularity, or cache line granularity if larger than 128 212 # byte. This value is based on the locality seen across a large 213 # range of workloads. 214 intlv_size = max(128, system.cache_line_size.value) 215 216 # For every range (most systems will only have one), create an 217 # array of controllers and set their parameters to match their 218 # address mapping in the case of a DRAM 219 for r in system.mem_ranges: 220 for i in range(nbr_mem_ctrls): 221 mem_ctrl = create_mem_ctrl(cls, r, i, nbr_mem_ctrls, intlv_bits, 222 intlv_size) 223 # Set the number of ranks based on the command-line 224 # options if it was explicitly set 225 if issubclass(cls, m5.objects.DRAMCtrl) and opt_mem_ranks: 226 mem_ctrl.ranks_per_channel = opt_mem_ranks 227 228 # Enable low-power DRAM states if option is set 229 if issubclass(cls, m5.objects.DRAMCtrl): 230 mem_ctrl.enable_dram_powerdown = opt_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