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