base_config.py revision 12598
112863Sgabeblack@google.com# Copyright (c) 2012-2013, 2017 ARM Limited
212863Sgabeblack@google.com# All rights reserved.
312863Sgabeblack@google.com#
412863Sgabeblack@google.com# The license below extends only to copyright in the software and shall
512863Sgabeblack@google.com# not be construed as granting a license to any other intellectual
612863Sgabeblack@google.com# property including but not limited to intellectual property relating
712863Sgabeblack@google.com# to a hardware implementation of the functionality of the software
812863Sgabeblack@google.com# licensed hereunder.  You may use the software subject to the license
912863Sgabeblack@google.com# terms below provided that you ensure that this notice is replicated
1012863Sgabeblack@google.com# unmodified and in its entirety in all distributions of the software,
1112863Sgabeblack@google.com# modified or unmodified, in source code or in binary form.
1212863Sgabeblack@google.com#
1312863Sgabeblack@google.com# Redistribution and use in source and binary forms, with or without
1412863Sgabeblack@google.com# modification, are permitted provided that the following conditions are
1512863Sgabeblack@google.com# met: redistributions of source code must retain the above copyright
1612863Sgabeblack@google.com# notice, this list of conditions and the following disclaimer;
1712863Sgabeblack@google.com# redistributions in binary form must reproduce the above copyright
1812863Sgabeblack@google.com# notice, this list of conditions and the following disclaimer in the
1912863Sgabeblack@google.com# documentation and/or other materials provided with the distribution;
2012863Sgabeblack@google.com# neither the name of the copyright holders nor the names of its
2112863Sgabeblack@google.com# contributors may be used to endorse or promote products derived from
2212863Sgabeblack@google.com# this software without specific prior written permission.
2312863Sgabeblack@google.com#
2412863Sgabeblack@google.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2512863Sgabeblack@google.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2612863Sgabeblack@google.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2712863Sgabeblack@google.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2812863Sgabeblack@google.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2912863Sgabeblack@google.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3012863Sgabeblack@google.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3112863Sgabeblack@google.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3212863Sgabeblack@google.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3312950Sgabeblack@google.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3412982Sgabeblack@google.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3512950Sgabeblack@google.com#
3612950Sgabeblack@google.com# Authors: Andreas Sandberg
3712950Sgabeblack@google.com#          Andreas Hansson
3812950Sgabeblack@google.com
3912950Sgabeblack@google.comfrom abc import ABCMeta, abstractmethod
4012863Sgabeblack@google.comimport optparse
4112863Sgabeblack@google.comimport m5
4212863Sgabeblack@google.comfrom m5.objects import *
4312863Sgabeblack@google.comfrom m5.proxy import *
4412863Sgabeblack@google.comm5.util.addToPath('../configs/')
4512863Sgabeblack@google.comfrom common import FSConfig
4612950Sgabeblack@google.comfrom common import Options
4712950Sgabeblack@google.comfrom common.Caches import *
4812863Sgabeblack@google.comfrom ruby import Ruby
4912863Sgabeblack@google.com
5012863Sgabeblack@google.com_have_kvm_support = 'BaseKvmCPU' in globals()
5112950Sgabeblack@google.com
5212982Sgabeblack@google.comclass BaseSystem(object):
5312982Sgabeblack@google.com    """Base system builder.
5412950Sgabeblack@google.com
5512863Sgabeblack@google.com    This class provides some basic functionality for creating an ARM
5612950Sgabeblack@google.com    system with the usual peripherals (caches, GIC, etc.). It allows
5712950Sgabeblack@google.com    customization by defining separate methods for different parts of
5812950Sgabeblack@google.com    the initialization process.
5912950Sgabeblack@google.com    """
6012950Sgabeblack@google.com
6112950Sgabeblack@google.com    __metaclass__ = ABCMeta
6212950Sgabeblack@google.com
6312950Sgabeblack@google.com    def __init__(self, mem_mode='timing', mem_class=SimpleMemory,
6412950Sgabeblack@google.com                 cpu_class=TimingSimpleCPU, num_cpus=1, num_threads=1,
6512950Sgabeblack@google.com                 checker=False, mem_size=None, use_ruby=False):
6612950Sgabeblack@google.com        """Initialize a simple base system.
6712950Sgabeblack@google.com
6812950Sgabeblack@google.com        Keyword Arguments:
6912950Sgabeblack@google.com          mem_mode -- String describing the memory mode (timing or atomic)
7012950Sgabeblack@google.com          mem_class -- Memory controller class to use
7112950Sgabeblack@google.com          cpu_class -- CPU class to use
7212950Sgabeblack@google.com          num_cpus -- Number of CPUs to instantiate
7312950Sgabeblack@google.com          checker -- Set to True to add checker CPUs
7412950Sgabeblack@google.com          mem_size -- Override the default memory size
7512950Sgabeblack@google.com          use_ruby -- Set to True to use ruby memory
7612950Sgabeblack@google.com        """
7712950Sgabeblack@google.com        self.mem_mode = mem_mode
7812950Sgabeblack@google.com        self.mem_class = mem_class
7912863Sgabeblack@google.com        self.cpu_class = cpu_class
8012863Sgabeblack@google.com        self.num_cpus = num_cpus
8112863Sgabeblack@google.com        self.num_threads = num_threads
8212950Sgabeblack@google.com        self.checker = checker
8312950Sgabeblack@google.com        self.use_ruby = use_ruby
8412863Sgabeblack@google.com
8512982Sgabeblack@google.com    def create_cpus(self, cpu_clk_domain):
8612982Sgabeblack@google.com        """Return a list of CPU objects to add to a system."""
8712863Sgabeblack@google.com        cpus = [ self.cpu_class(clk_domain=cpu_clk_domain,
8812863Sgabeblack@google.com                                numThreads=self.num_threads,
8912863Sgabeblack@google.com                                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            bootmem = getattr(system, 'bootmem', None)
174            Ruby.create_system(options, True, system, system.iobus,
175                               system._dma_ports, bootmem)
176
177            # Create a seperate clock domain for Ruby
178            system.ruby.clk_domain = SrcClockDomain(
179                clock = options.ruby_clock,
180                voltage_domain = system.voltage_domain)
181            for i, cpu in enumerate(system.cpu):
182                if not cpu.switched_out:
183                    cpu.createInterruptController()
184                    cpu.connectCachedPorts(system.ruby._cpu_ports[i])
185        else:
186            sha_bus = self.create_caches_shared(system)
187            for cpu in system.cpu:
188                self.init_cpu(system, cpu, sha_bus)
189
190
191    def create_clk_src(self,system):
192        # Create system clock domain. This provides clock value to every
193        # clocked object that lies beneath it unless explicitly overwritten
194        # by a different clock domain.
195        system.voltage_domain = VoltageDomain()
196        system.clk_domain = SrcClockDomain(clock = '1GHz',
197                                           voltage_domain =
198                                           system.voltage_domain)
199
200        # Create a seperate clock domain for components that should
201        # run at CPUs frequency
202        system.cpu_clk_domain = SrcClockDomain(clock = '2GHz',
203                                               voltage_domain =
204                                               system.voltage_domain)
205
206    @abstractmethod
207    def create_system(self):
208        """Create an return an initialized system."""
209        pass
210
211    @abstractmethod
212    def create_root(self):
213        """Create and return a simulation root using the system
214        defined by this class."""
215        pass
216
217class BaseSESystem(BaseSystem):
218    """Basic syscall-emulation builder."""
219
220    def __init__(self, **kwargs):
221        BaseSystem.__init__(self, **kwargs)
222
223    def init_system(self, system):
224        BaseSystem.init_system(self, system)
225
226    def create_system(self):
227        system = System(physmem = self.mem_class(),
228                        membus = SystemXBar(),
229                        mem_mode = self.mem_mode,
230                        multi_thread = (self.num_threads > 1))
231        if not self.use_ruby:
232            system.system_port = system.membus.slave
233        system.physmem.port = system.membus.master
234        self.init_system(system)
235        return system
236
237    def create_root(self):
238        system = self.create_system()
239        m5.ticks.setGlobalFrequency('1THz')
240        return Root(full_system=False, system=system)
241
242class BaseSESystemUniprocessor(BaseSESystem):
243    """Basic syscall-emulation builder for uniprocessor systems.
244
245    Note: This class is only really needed to provide backwards
246    compatibility in existing test cases.
247    """
248
249    def __init__(self, **kwargs):
250        BaseSESystem.__init__(self, **kwargs)
251
252    def create_caches_private(self, cpu):
253        # The atomic SE configurations do not use caches
254        if self.mem_mode == "timing":
255            # @todo We might want to revisit these rather enthusiastic L1 sizes
256            cpu.addTwoLevelCacheHierarchy(L1_ICache(size='128kB'),
257                                          L1_DCache(size='256kB'),
258                                          L2Cache(size='2MB'))
259
260    def create_caches_shared(self, system):
261        return None
262
263class BaseFSSystem(BaseSystem):
264    """Basic full system builder."""
265
266    def __init__(self, **kwargs):
267        BaseSystem.__init__(self, **kwargs)
268
269    def init_system(self, system):
270        BaseSystem.init_system(self, system)
271
272        if self.use_ruby:
273            # Connect the ruby io port to the PIO bus,
274            # assuming that there is just one such port.
275            system.iobus.master = system.ruby._io_port.slave
276        else:
277            # create the memory controllers and connect them, stick with
278            # the physmem name to avoid bumping all the reference stats
279            system.physmem = [self.mem_class(range = r)
280                              for r in system.mem_ranges]
281            for i in xrange(len(system.physmem)):
282                system.physmem[i].port = system.membus.master
283
284            # create the iocache, which by default runs at the system clock
285            system.iocache = IOCache(addr_ranges=system.mem_ranges)
286            system.iocache.cpu_side = system.iobus.master
287            system.iocache.mem_side = system.membus.slave
288
289    def create_root(self):
290        system = self.create_system()
291        m5.ticks.setGlobalFrequency('1THz')
292        return Root(full_system=True, system=system)
293
294class BaseFSSystemUniprocessor(BaseFSSystem):
295    """Basic full system builder for uniprocessor systems.
296
297    Note: This class is only really needed to provide backwards
298    compatibility in existing test cases.
299    """
300
301    def __init__(self, **kwargs):
302        BaseFSSystem.__init__(self, **kwargs)
303
304    def create_caches_private(self, cpu):
305        cpu.addTwoLevelCacheHierarchy(L1_ICache(size='32kB', assoc=1),
306                                      L1_DCache(size='32kB', assoc=4),
307                                      L2Cache(size='4MB', assoc=8))
308
309    def create_caches_shared(self, system):
310        return None
311
312class BaseFSSwitcheroo(BaseFSSystem):
313    """Uniprocessor system prepared for CPU switching"""
314
315    def __init__(self, cpu_classes, **kwargs):
316        BaseFSSystem.__init__(self, **kwargs)
317        self.cpu_classes = tuple(cpu_classes)
318
319    def create_cpus(self, cpu_clk_domain):
320        cpus = [ cclass(clk_domain = cpu_clk_domain,
321                        cpu_id=0,
322                        switched_out=True)
323                 for cclass in self.cpu_classes ]
324        cpus[0].switched_out = False
325        return cpus
326