MemConfig.py revision 13774:a1be2a0c55f2
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            if opt_elastic_trace_en:
228                mem_ctrl.latency = '1ns'
229                print("For elastic trace, over-riding Simple Memory "
230                    "latency to 1ns.")
231
232            mem_ctrls.append(mem_ctrl)
233
234    subsystem.mem_ctrls = mem_ctrls
235
236    # Connect the controllers to the membus
237    for i in range(len(subsystem.mem_ctrls)):
238        if opt_mem_type == "HMC_2500_1x32":
239            subsystem.mem_ctrls[i].port = xbar[i/4].master
240            # Set memory device size. There is an independent controller for
241            # each vault. All vaults are same size.
242            subsystem.mem_ctrls[i].device_size = options.hmc_dev_vault_size
243        else:
244            subsystem.mem_ctrls[i].port = xbar.master
245