cpu: Limit TrafficGen outstanding reqs
[gem5.git] / configs / common / MemConfig.py
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
39 from __future__ import print_function
40 from __future__ import absolute_import
41
42 import m5.objects
43 import inspect
44 import sys
45 from textwrap import TextWrapper
46 from . import HMC
47
48 # Dictionary of mapping names of real memory controller models to
49 # classes.
50 _mem_classes = {}
51
52 def 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
63 def 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
73 def 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
88 def 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.
93 for name, cls in inspect.getmembers(m5.objects, is_mem_class):
94 _mem_classes[name] = cls
95
96 def 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
147 def 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