BaseCPU.py revision 13709:dd6b7ac5801f
1# Copyright (c) 2012-2013, 2015-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# Copyright (c) 2005-2008 The Regents of The University of Michigan
14# Copyright (c) 2011 Regents of the University of California
15# All rights reserved.
16#
17# Redistribution and use in source and binary forms, with or without
18# modification, are permitted provided that the following conditions are
19# met: redistributions of source code must retain the above copyright
20# notice, this list of conditions and the following disclaimer;
21# redistributions in binary form must reproduce the above copyright
22# notice, this list of conditions and the following disclaimer in the
23# documentation and/or other materials provided with the distribution;
24# neither the name of the copyright holders nor the names of its
25# contributors may be used to endorse or promote products derived from
26# this software without specific prior written permission.
27#
28# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39#
40# Authors: Nathan Binkert
41#          Rick Strong
42#          Andreas Hansson
43#          Glenn Bergmans
44
45from __future__ import print_function
46
47import sys
48
49from m5.SimObject import *
50from m5.defines import buildEnv
51from m5.params import *
52from m5.proxy import *
53from m5.util.fdthelper import *
54
55from m5.objects.XBar import L2XBar
56from m5.objects.InstTracer import InstTracer
57from m5.objects.CPUTracers import ExeTracer
58from m5.objects.MemObject import MemObject
59from m5.objects.SubSystem import SubSystem
60from m5.objects.ClockDomain import *
61from m5.objects.Platform import Platform
62
63default_tracer = ExeTracer()
64
65if buildEnv['TARGET_ISA'] == 'alpha':
66    from m5.objects.AlphaTLB import AlphaDTB as ArchDTB, AlphaITB as ArchITB
67    from m5.objects.AlphaInterrupts import AlphaInterrupts
68    from m5.objects.AlphaISA import AlphaISA
69    default_isa_class = AlphaISA
70elif buildEnv['TARGET_ISA'] == 'sparc':
71    from m5.objects.SparcTLB import SparcTLB as ArchDTB, SparcTLB as ArchITB
72    from m5.objects.SparcInterrupts import SparcInterrupts
73    from m5.objects.SparcISA import SparcISA
74    default_isa_class = SparcISA
75elif buildEnv['TARGET_ISA'] == 'x86':
76    from m5.objects.X86TLB import X86TLB as ArchDTB, X86TLB as ArchITB
77    from m5.objects.X86LocalApic import X86LocalApic
78    from m5.objects.X86ISA import X86ISA
79    default_isa_class = X86ISA
80elif buildEnv['TARGET_ISA'] == 'mips':
81    from m5.objects.MipsTLB import MipsTLB as ArchDTB, MipsTLB as ArchITB
82    from m5.objects.MipsInterrupts import MipsInterrupts
83    from m5.objects.MipsISA import MipsISA
84    default_isa_class = MipsISA
85elif buildEnv['TARGET_ISA'] == 'arm':
86    from m5.objects.ArmTLB import ArmTLB as ArchDTB, ArmTLB as ArchITB
87    from m5.objects.ArmTLB import ArmStage2IMMU, ArmStage2DMMU
88    from m5.objects.ArmInterrupts import ArmInterrupts
89    from m5.objects.ArmISA import ArmISA
90    default_isa_class = ArmISA
91elif buildEnv['TARGET_ISA'] == 'power':
92    from m5.objects.PowerTLB import PowerTLB as ArchDTB, PowerTLB as ArchITB
93    from m5.objects.PowerInterrupts import PowerInterrupts
94    from m5.objects.PowerISA import PowerISA
95    default_isa_class = PowerISA
96elif buildEnv['TARGET_ISA'] == 'riscv':
97    from m5.objects.RiscvTLB import RiscvTLB as ArchDTB, RiscvTLB as ArchITB
98    from m5.objects.RiscvInterrupts import RiscvInterrupts
99    from m5.objects.RiscvISA import RiscvISA
100    default_isa_class = RiscvISA
101
102class BaseCPU(MemObject):
103    type = 'BaseCPU'
104    abstract = True
105    cxx_header = "cpu/base.hh"
106
107    cxx_exports = [
108        PyBindMethod("switchOut"),
109        PyBindMethod("takeOverFrom"),
110        PyBindMethod("switchedOut"),
111        PyBindMethod("flushTLBs"),
112        PyBindMethod("totalInsts"),
113        PyBindMethod("scheduleInstStop"),
114        PyBindMethod("scheduleLoadStop"),
115        PyBindMethod("getCurrentInstCount"),
116    ]
117
118    @classmethod
119    def memory_mode(cls):
120        """Which memory mode does this CPU require?"""
121        return 'invalid'
122
123    @classmethod
124    def require_caches(cls):
125        """Does the CPU model require caches?
126
127        Some CPU models might make assumptions that require them to
128        have caches.
129        """
130        return False
131
132    @classmethod
133    def support_take_over(cls):
134        """Does the CPU model support CPU takeOverFrom?"""
135        return False
136
137    def takeOverFrom(self, old_cpu):
138        self._ccObject.takeOverFrom(old_cpu._ccObject)
139
140
141    system = Param.System(Parent.any, "system object")
142    cpu_id = Param.Int(-1, "CPU identifier")
143    socket_id = Param.Unsigned(0, "Physical Socket identifier")
144    numThreads = Param.Unsigned(1, "number of HW thread contexts")
145    pwr_gating_latency = Param.Cycles(300,
146        "Latency to enter power gating state when all contexts are suspended")
147
148    power_gating_on_idle = Param.Bool(False, "Control whether the core goes "\
149        "to the OFF power state after all thread are disabled for "\
150        "pwr_gating_latency cycles")
151
152    function_trace = Param.Bool(False, "Enable function trace")
153    function_trace_start = Param.Tick(0, "Tick to start function trace")
154
155    checker = Param.BaseCPU(NULL, "checker CPU")
156
157    syscallRetryLatency = Param.Cycles(10000, "Cycles to wait until retry")
158
159    do_checkpoint_insts = Param.Bool(True,
160        "enable checkpoint pseudo instructions")
161    do_statistics_insts = Param.Bool(True,
162        "enable statistics pseudo instructions")
163
164    profile = Param.Latency('0ns', "trace the kernel stack")
165    do_quiesce = Param.Bool(True, "enable quiesce instructions")
166
167    wait_for_remote_gdb = Param.Bool(False,
168        "Wait for a remote GDB connection");
169
170    workload = VectorParam.Process([], "processes to run")
171
172    dtb = Param.BaseTLB(ArchDTB(), "Data TLB")
173    itb = Param.BaseTLB(ArchITB(), "Instruction TLB")
174    if buildEnv['TARGET_ISA'] == 'sparc':
175        interrupts = VectorParam.SparcInterrupts(
176                [], "Interrupt Controller")
177        isa = VectorParam.SparcISA([], "ISA instance")
178    elif buildEnv['TARGET_ISA'] == 'alpha':
179        interrupts = VectorParam.AlphaInterrupts(
180                [], "Interrupt Controller")
181        isa = VectorParam.AlphaISA([], "ISA instance")
182    elif buildEnv['TARGET_ISA'] == 'x86':
183        interrupts = VectorParam.X86LocalApic([], "Interrupt Controller")
184        isa = VectorParam.X86ISA([], "ISA instance")
185    elif buildEnv['TARGET_ISA'] == 'mips':
186        interrupts = VectorParam.MipsInterrupts(
187                [], "Interrupt Controller")
188        isa = VectorParam.MipsISA([], "ISA instance")
189    elif buildEnv['TARGET_ISA'] == 'arm':
190        istage2_mmu = Param.ArmStage2MMU(ArmStage2IMMU(), "Stage 2 trans")
191        dstage2_mmu = Param.ArmStage2MMU(ArmStage2DMMU(), "Stage 2 trans")
192        interrupts = VectorParam.ArmInterrupts(
193                [], "Interrupt Controller")
194        isa = VectorParam.ArmISA([], "ISA instance")
195    elif buildEnv['TARGET_ISA'] == 'power':
196        UnifiedTLB = Param.Bool(True, "Is this a Unified TLB?")
197        interrupts = VectorParam.PowerInterrupts(
198                [], "Interrupt Controller")
199        isa = VectorParam.PowerISA([], "ISA instance")
200    elif buildEnv['TARGET_ISA'] == 'riscv':
201        interrupts = VectorParam.RiscvInterrupts(
202                [], "Interrupt Controller")
203        isa = VectorParam.RiscvISA([], "ISA instance")
204    else:
205        print("Don't know what TLB to use for ISA %s" %
206              buildEnv['TARGET_ISA'])
207        sys.exit(1)
208
209    max_insts_all_threads = Param.Counter(0,
210        "terminate when all threads have reached this inst count")
211    max_insts_any_thread = Param.Counter(0,
212        "terminate when any thread reaches this inst count")
213    simpoint_start_insts = VectorParam.Counter([],
214        "starting instruction counts of simpoints")
215    max_loads_all_threads = Param.Counter(0,
216        "terminate when all threads have reached this load count")
217    max_loads_any_thread = Param.Counter(0,
218        "terminate when any thread reaches this load count")
219    progress_interval = Param.Frequency('0Hz',
220        "frequency to print out the progress message")
221
222    switched_out = Param.Bool(False,
223        "Leave the CPU switched out after startup (used when switching " \
224        "between CPU models)")
225
226    tracer = Param.InstTracer(default_tracer, "Instruction tracer")
227
228    icache_port = MasterPort("Instruction Port")
229    dcache_port = MasterPort("Data Port")
230    _cached_ports = ['icache_port', 'dcache_port']
231
232    if buildEnv['TARGET_ISA'] in ['x86', 'arm']:
233        _cached_ports += ["itb.walker.port", "dtb.walker.port"]
234
235    _uncached_slave_ports = []
236    _uncached_master_ports = []
237    if buildEnv['TARGET_ISA'] == 'x86':
238        _uncached_slave_ports += ["interrupts[0].pio",
239                                  "interrupts[0].int_slave"]
240        _uncached_master_ports += ["interrupts[0].int_master"]
241
242    def createInterruptController(self):
243        if buildEnv['TARGET_ISA'] == 'sparc':
244            self.interrupts = [SparcInterrupts() for i in range(self.numThreads)]
245        elif buildEnv['TARGET_ISA'] == 'alpha':
246            self.interrupts = [AlphaInterrupts() for i in range(self.numThreads)]
247        elif buildEnv['TARGET_ISA'] == 'x86':
248            self.apic_clk_domain = DerivedClockDomain(clk_domain =
249                                                      Parent.clk_domain,
250                                                      clk_divider = 16)
251            self.interrupts = [X86LocalApic(clk_domain = self.apic_clk_domain,
252                                           pio_addr=0x2000000000000000)
253                               for i in range(self.numThreads)]
254            _localApic = self.interrupts
255        elif buildEnv['TARGET_ISA'] == 'mips':
256            self.interrupts = [MipsInterrupts() for i in range(self.numThreads)]
257        elif buildEnv['TARGET_ISA'] == 'arm':
258            self.interrupts = [ArmInterrupts() for i in range(self.numThreads)]
259        elif buildEnv['TARGET_ISA'] == 'power':
260            self.interrupts = [PowerInterrupts() for i in range(self.numThreads)]
261        elif buildEnv['TARGET_ISA'] == 'riscv':
262            self.interrupts = \
263                [RiscvInterrupts() for i in range(self.numThreads)]
264        else:
265            print("Don't know what Interrupt Controller to use for ISA %s" %
266                  buildEnv['TARGET_ISA'])
267            sys.exit(1)
268
269    def connectCachedPorts(self, bus):
270        for p in self._cached_ports:
271            exec('self.%s = bus.slave' % p)
272
273    def connectUncachedPorts(self, bus):
274        for p in self._uncached_slave_ports:
275            exec('self.%s = bus.master' % p)
276        for p in self._uncached_master_ports:
277            exec('self.%s = bus.slave' % p)
278
279    def connectAllPorts(self, cached_bus, uncached_bus = None):
280        self.connectCachedPorts(cached_bus)
281        if not uncached_bus:
282            uncached_bus = cached_bus
283        self.connectUncachedPorts(uncached_bus)
284
285    def addPrivateSplitL1Caches(self, ic, dc, iwc = None, dwc = None):
286        self.icache = ic
287        self.dcache = dc
288        self.icache_port = ic.cpu_side
289        self.dcache_port = dc.cpu_side
290        self._cached_ports = ['icache.mem_side', 'dcache.mem_side']
291        if buildEnv['TARGET_ISA'] in ['x86', 'arm']:
292            if iwc and dwc:
293                self.itb_walker_cache = iwc
294                self.dtb_walker_cache = dwc
295                self.itb.walker.port = iwc.cpu_side
296                self.dtb.walker.port = dwc.cpu_side
297                self._cached_ports += ["itb_walker_cache.mem_side", \
298                                       "dtb_walker_cache.mem_side"]
299            else:
300                self._cached_ports += ["itb.walker.port", "dtb.walker.port"]
301
302            # Checker doesn't need its own tlb caches because it does
303            # functional accesses only
304            if self.checker != NULL:
305                self._cached_ports += ["checker.itb.walker.port", \
306                                       "checker.dtb.walker.port"]
307
308    def addTwoLevelCacheHierarchy(self, ic, dc, l2c, iwc=None, dwc=None,
309                                  xbar=None):
310        self.addPrivateSplitL1Caches(ic, dc, iwc, dwc)
311        self.toL2Bus = xbar if xbar else L2XBar()
312        self.connectCachedPorts(self.toL2Bus)
313        self.l2cache = l2c
314        self.toL2Bus.master = self.l2cache.cpu_side
315        self._cached_ports = ['l2cache.mem_side']
316
317    def createThreads(self):
318        # If no ISAs have been created, assume that the user wants the
319        # default ISA.
320        if len(self.isa) == 0:
321            self.isa = [ default_isa_class() for i in range(self.numThreads) ]
322        else:
323            if len(self.isa) != int(self.numThreads):
324                raise RuntimeError("Number of ISA instances doesn't "
325                                   "match thread count")
326        if self.checker != NULL:
327            self.checker.createThreads()
328
329    def addCheckerCpu(self):
330        pass
331
332    def createPhandleKey(self, thread):
333        # This method creates a unique key for this cpu as a function of a
334        # certain thread
335        return 'CPU-%d-%d-%d' % (self.socket_id, self.cpu_id, thread)
336
337    #Generate simple CPU Device Tree structure
338    def generateDeviceTree(self, state):
339        """Generate cpu nodes for each thread and the corresponding part of the
340        cpu-map node. Note that this implementation does not support clusters
341        of clusters. Note that GEM5 is not compatible with the official way of
342        numbering cores as defined in the Device Tree documentation. Where the
343        cpu_id needs to reset to 0 for each cluster by specification, GEM5
344        expects the cpu_id to be globally unique and incremental. This
345        generated node adheres the GEM5 way of doing things."""
346        if bool(self.switched_out):
347            return
348
349        cpus_node = FdtNode('cpus')
350        cpus_node.append(state.CPUCellsProperty())
351        #Special size override of 0
352        cpus_node.append(FdtPropertyWords('#size-cells', [0]))
353
354        # Generate cpu nodes
355        for i in range(int(self.numThreads)):
356            reg = (int(self.socket_id)<<8) + int(self.cpu_id) + i
357            node = FdtNode("cpu@%x" % reg)
358            node.append(FdtPropertyStrings("device_type", "cpu"))
359            node.appendCompatible(["gem5,arm-cpu"])
360            node.append(FdtPropertyWords("reg", state.CPUAddrCells(reg)))
361            platform, found = self.system.unproxy(self).find_any(Platform)
362            if found:
363                platform.annotateCpuDeviceNode(node, state)
364            else:
365                warn("Platform not found for device tree generation; " \
366                     "system or multiple CPUs may not start")
367
368            freq = round(self.clk_domain.unproxy(self).clock[0].frequency)
369            node.append(FdtPropertyWords("clock-frequency", freq))
370
371            # Unique key for this CPU
372            phandle_key = self.createPhandleKey(i)
373            node.appendPhandle(phandle_key)
374            cpus_node.append(node)
375
376        yield cpus_node
377