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