base_config.py revision 12070
1# Copyright (c) 2012-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 abc import ABCMeta, abstractmethod
40import optparse
41import m5
42from m5.objects import *
43from m5.proxy import *
44m5.util.addToPath('../configs/')
45from common import FSConfig
46from common import Options
47from common.Caches import *
48from ruby import Ruby
49
50_have_kvm_support = 'BaseKvmCPU' in globals()
51
52class BaseSystem(object):
53    """Base system builder.
54
55    This class provides some basic functionality for creating an ARM
56    system with the usual peripherals (caches, GIC, etc.). It allows
57    customization by defining separate methods for different parts of
58    the initialization process.
59    """
60
61    __metaclass__ = ABCMeta
62
63    def __init__(self, mem_mode='timing', mem_class=SimpleMemory,
64                 cpu_class=TimingSimpleCPU, num_cpus=1, num_threads=1,
65                 checker=False, mem_size=None, use_ruby=False):
66        """Initialize a simple base system.
67
68        Keyword Arguments:
69          mem_mode -- String describing the memory mode (timing or atomic)
70          mem_class -- Memory controller class to use
71          cpu_class -- CPU class to use
72          num_cpus -- Number of CPUs to instantiate
73          checker -- Set to True to add checker CPUs
74          mem_size -- Override the default memory size
75          use_ruby -- Set to True to use ruby memory
76        """
77        self.mem_mode = mem_mode
78        self.mem_class = mem_class
79        self.cpu_class = cpu_class
80        self.num_cpus = num_cpus
81        self.num_threads = num_threads
82        self.checker = checker
83        self.use_ruby = use_ruby
84
85    def create_cpus(self, cpu_clk_domain):
86        """Return a list of CPU objects to add to a system."""
87        cpus = [ self.cpu_class(clk_domain=cpu_clk_domain,
88                                numThreads=self.num_threads,
89                                cpu_id=i)
90                 for i in range(self.num_cpus) ]
91        if self.checker:
92            for c in cpus:
93                c.addCheckerCpu()
94        return cpus
95
96    def create_caches_private(self, cpu):
97        """Add private caches to a CPU.
98
99        Arguments:
100          cpu -- CPU instance to work on.
101        """
102        cpu.addPrivateSplitL1Caches(L1_ICache(size='32kB', assoc=1),
103                                    L1_DCache(size='32kB', assoc=4))
104
105    def create_caches_shared(self, system):
106        """Add shared caches to a system.
107
108        Arguments:
109          system -- System to work on.
110
111        Returns:
112          A bus that CPUs should use to connect to the shared cache.
113        """
114        system.toL2Bus = L2XBar(clk_domain=system.cpu_clk_domain)
115        system.l2c = L2Cache(clk_domain=system.cpu_clk_domain,
116                             size='4MB', assoc=8)
117        system.l2c.cpu_side = system.toL2Bus.master
118        system.l2c.mem_side = system.membus.slave
119        return system.toL2Bus
120
121    def init_cpu(self, system, cpu, sha_bus):
122        """Initialize a CPU.
123
124        Arguments:
125          system -- System to work on.
126          cpu -- CPU to initialize.
127        """
128        if not cpu.switched_out:
129            self.create_caches_private(cpu)
130            cpu.createInterruptController()
131            cpu.connectAllPorts(sha_bus if sha_bus != None else system.membus,
132                                system.membus)
133
134    def init_kvm(self, system):
135        """Do KVM-specific system initialization.
136
137        Arguments:
138          system -- System to work on.
139        """
140        system.vm = KvmVM()
141
142    def init_system(self, system):
143        """Initialize a system.
144
145        Arguments:
146          system -- System to initialize.
147        """
148        self.create_clk_src(system)
149        system.cpu = self.create_cpus(system.cpu_clk_domain)
150
151        if _have_kvm_support and \
152                any([isinstance(c, BaseKvmCPU) for c in system.cpu]):
153            self.init_kvm(system)
154
155        if self.use_ruby:
156            # Add the ruby specific and protocol specific options
157            parser = optparse.OptionParser()
158            Options.addCommonOptions(parser)
159            Ruby.define_options(parser)
160            (options, args) = parser.parse_args()
161
162            # Set the default cache size and associativity to be very
163            # small to encourage races between requests and writebacks.
164            options.l1d_size="32kB"
165            options.l1i_size="32kB"
166            options.l2_size="4MB"
167            options.l1d_assoc=4
168            options.l1i_assoc=2
169            options.l2_assoc=8
170            options.num_cpus = self.num_cpus
171            options.num_dirs = 2
172
173            Ruby.create_system(options, True, system, system.iobus,
174                               system._dma_ports)
175
176            # Create a seperate clock domain for Ruby
177            system.ruby.clk_domain = SrcClockDomain(
178                clock = options.ruby_clock,
179                voltage_domain = system.voltage_domain)
180            for i, cpu in enumerate(system.cpu):
181                if not cpu.switched_out:
182                    cpu.createInterruptController()
183                    cpu.connectCachedPorts(system.ruby._cpu_ports[i])
184        else:
185            sha_bus = self.create_caches_shared(system)
186            for cpu in system.cpu:
187                self.init_cpu(system, cpu, sha_bus)
188
189
190    def create_clk_src(self,system):
191        # Create system clock domain. This provides clock value to every
192        # clocked object that lies beneath it unless explicitly overwritten
193        # by a different clock domain.
194        system.voltage_domain = VoltageDomain()
195        system.clk_domain = SrcClockDomain(clock = '1GHz',
196                                           voltage_domain =
197                                           system.voltage_domain)
198
199        # Create a seperate clock domain for components that should
200        # run at CPUs frequency
201        system.cpu_clk_domain = SrcClockDomain(clock = '2GHz',
202                                               voltage_domain =
203                                               system.voltage_domain)
204
205    @abstractmethod
206    def create_system(self):
207        """Create an return an initialized system."""
208        pass
209
210    @abstractmethod
211    def create_root(self):
212        """Create and return a simulation root using the system
213        defined by this class."""
214        pass
215
216class BaseSESystem(BaseSystem):
217    """Basic syscall-emulation builder."""
218
219    def __init__(self, **kwargs):
220        BaseSystem.__init__(self, **kwargs)
221
222    def init_system(self, system):
223        BaseSystem.init_system(self, system)
224
225    def create_system(self):
226        system = System(physmem = self.mem_class(),
227                        membus = SystemXBar(),
228                        mem_mode = self.mem_mode,
229                        multi_thread = (self.num_threads > 1))
230        if not self.use_ruby:
231            system.system_port = system.membus.slave
232        system.physmem.port = system.membus.master
233        self.init_system(system)
234        return system
235
236    def create_root(self):
237        system = self.create_system()
238        m5.ticks.setGlobalFrequency('1THz')
239        return Root(full_system=False, system=system)
240
241class BaseSESystemUniprocessor(BaseSESystem):
242    """Basic syscall-emulation builder for uniprocessor systems.
243
244    Note: This class is only really needed to provide backwards
245    compatibility in existing test cases.
246    """
247
248    def __init__(self, **kwargs):
249        BaseSESystem.__init__(self, **kwargs)
250
251    def create_caches_private(self, cpu):
252        # The atomic SE configurations do not use caches
253        if self.mem_mode == "timing":
254            # @todo We might want to revisit these rather enthusiastic L1 sizes
255            cpu.addTwoLevelCacheHierarchy(L1_ICache(size='128kB'),
256                                          L1_DCache(size='256kB'),
257                                          L2Cache(size='2MB'))
258
259    def create_caches_shared(self, system):
260        return None
261
262class BaseFSSystem(BaseSystem):
263    """Basic full system builder."""
264
265    def __init__(self, **kwargs):
266        BaseSystem.__init__(self, **kwargs)
267
268    def init_system(self, system):
269        BaseSystem.init_system(self, system)
270
271        if self.use_ruby:
272            # Connect the ruby io port to the PIO bus,
273            # assuming that there is just one such port.
274            system.iobus.master = system.ruby._io_port.slave
275        else:
276            # create the memory controllers and connect them, stick with
277            # the physmem name to avoid bumping all the reference stats
278            system.physmem = [self.mem_class(range = r)
279                              for r in system.mem_ranges]
280            for i in xrange(len(system.physmem)):
281                system.physmem[i].port = system.membus.master
282
283            # create the iocache, which by default runs at the system clock
284            system.iocache = IOCache(addr_ranges=system.mem_ranges)
285            system.iocache.cpu_side = system.iobus.master
286            system.iocache.mem_side = system.membus.slave
287
288    def create_root(self):
289        system = self.create_system()
290        m5.ticks.setGlobalFrequency('1THz')
291        return Root(full_system=True, system=system)
292
293class BaseFSSystemUniprocessor(BaseFSSystem):
294    """Basic full system builder for uniprocessor systems.
295
296    Note: This class is only really needed to provide backwards
297    compatibility in existing test cases.
298    """
299
300    def __init__(self, **kwargs):
301        BaseFSSystem.__init__(self, **kwargs)
302
303    def create_caches_private(self, cpu):
304        cpu.addTwoLevelCacheHierarchy(L1_ICache(size='32kB', assoc=1),
305                                      L1_DCache(size='32kB', assoc=4),
306                                      L2Cache(size='4MB', assoc=8))
307
308    def create_caches_shared(self, system):
309        return None
310
311class BaseFSSwitcheroo(BaseFSSystem):
312    """Uniprocessor system prepared for CPU switching"""
313
314    def __init__(self, cpu_classes, **kwargs):
315        BaseFSSystem.__init__(self, **kwargs)
316        self.cpu_classes = tuple(cpu_classes)
317
318    def create_cpus(self, cpu_clk_domain):
319        cpus = [ cclass(clk_domain = cpu_clk_domain,
320                        cpu_id=0,
321                        switched_out=True)
322                 for cclass in self.cpu_classes ]
323        cpus[0].switched_out = False
324        return cpus
325