1 # Copyright (c) 2012-2013, 2015-2017 ARM Limited
2 # Copyright (c) 2020 Barkhausen Institut
5 # The license below extends only to copyright in the software and shall
6 # not be construed as granting a license to any other intellectual
7 # property including but not limited to intellectual property relating
8 # to a hardware implementation of the functionality of the software
9 # licensed hereunder. You may use the software subject to the license
10 # terms below provided that you ensure that this notice is replicated
11 # unmodified and in its entirety in all distributions of the software,
12 # modified or unmodified, in source code or in binary form.
14 # Copyright (c) 2005-2008 The Regents of The University of Michigan
15 # Copyright (c) 2011 Regents of the University of California
16 # All rights reserved.
18 # Redistribution and use in source and binary forms, with or without
19 # modification, are permitted provided that the following conditions are
20 # met: redistributions of source code must retain the above copyright
21 # notice, this list of conditions and the following disclaimer;
22 # redistributions in binary form must reproduce the above copyright
23 # notice, this list of conditions and the following disclaimer in the
24 # documentation and/or other materials provided with the distribution;
25 # neither the name of the copyright holders nor the names of its
26 # contributors may be used to endorse or promote products derived from
27 # this software without specific prior written permission.
29 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 from __future__
import print_function
45 from m5
.SimObject
import *
46 from m5
.defines
import buildEnv
47 from m5
.params
import *
48 from m5
.proxy
import *
49 from m5
.util
.fdthelper
import *
51 from m5
.objects
.ClockedObject
import ClockedObject
52 from m5
.objects
.XBar
import L2XBar
53 from m5
.objects
.InstTracer
import InstTracer
54 from m5
.objects
.CPUTracers
import ExeTracer
55 from m5
.objects
.SubSystem
import SubSystem
56 from m5
.objects
.ClockDomain
import *
57 from m5
.objects
.Platform
import Platform
59 default_tracer
= ExeTracer()
61 if buildEnv
['TARGET_ISA'] == 'sparc':
62 from m5
.objects
.SparcTLB
import SparcTLB
as ArchDTB
, SparcTLB
as ArchITB
63 from m5
.objects
.SparcInterrupts
import SparcInterrupts
as ArchInterrupts
64 from m5
.objects
.SparcISA
import SparcISA
as ArchISA
65 elif buildEnv
['TARGET_ISA'] == 'x86':
66 from m5
.objects
.X86TLB
import X86TLB
as ArchDTB
, X86TLB
as ArchITB
67 from m5
.objects
.X86LocalApic
import X86LocalApic
as ArchInterrupts
68 from m5
.objects
.X86ISA
import X86ISA
as ArchISA
69 elif buildEnv
['TARGET_ISA'] == 'mips':
70 from m5
.objects
.MipsTLB
import MipsTLB
as ArchDTB
, MipsTLB
as ArchITB
71 from m5
.objects
.MipsInterrupts
import MipsInterrupts
as ArchInterrupts
72 from m5
.objects
.MipsISA
import MipsISA
as ArchISA
73 elif buildEnv
['TARGET_ISA'] == 'arm':
74 from m5
.objects
.ArmTLB
import ArmDTB
as ArchDTB
, ArmITB
as ArchITB
75 from m5
.objects
.ArmInterrupts
import ArmInterrupts
as ArchInterrupts
76 from m5
.objects
.ArmISA
import ArmISA
as ArchISA
77 elif buildEnv
['TARGET_ISA'] == 'power':
78 from m5
.objects
.PowerTLB
import PowerTLB
as ArchDTB
, PowerTLB
as ArchITB
79 from m5
.objects
.PowerInterrupts
import PowerInterrupts
as ArchInterrupts
80 from m5
.objects
.PowerISA
import PowerISA
as ArchISA
81 elif buildEnv
['TARGET_ISA'] == 'riscv':
82 from m5
.objects
.RiscvTLB
import RiscvTLB
as ArchDTB
, RiscvTLB
as ArchITB
83 from m5
.objects
.RiscvInterrupts
import RiscvInterrupts
as ArchInterrupts
84 from m5
.objects
.RiscvISA
import RiscvISA
as ArchISA
86 print("Don't know what object types to use for ISA %s" %
87 buildEnv
['TARGET_ISA'])
90 class BaseCPU(ClockedObject
):
93 cxx_header
= "cpu/base.hh"
96 PyBindMethod("switchOut"),
97 PyBindMethod("takeOverFrom"),
98 PyBindMethod("switchedOut"),
99 PyBindMethod("flushTLBs"),
100 PyBindMethod("totalInsts"),
101 PyBindMethod("scheduleInstStop"),
102 PyBindMethod("getCurrentInstCount"),
106 def memory_mode(cls
):
107 """Which memory mode does this CPU require?"""
111 def require_caches(cls
):
112 """Does the CPU model require caches?
114 Some CPU models might make assumptions that require them to
120 def support_take_over(cls
):
121 """Does the CPU model support CPU takeOverFrom?"""
124 def takeOverFrom(self
, old_cpu
):
125 self
._ccObject
.takeOverFrom(old_cpu
._ccObject
)
128 system
= Param
.System(Parent
.any
, "system object")
129 cpu_id
= Param
.Int(-1, "CPU identifier")
130 socket_id
= Param
.Unsigned(0, "Physical Socket identifier")
131 numThreads
= Param
.Unsigned(1, "number of HW thread contexts")
132 pwr_gating_latency
= Param
.Cycles(300,
133 "Latency to enter power gating state when all contexts are suspended")
135 power_gating_on_idle
= Param
.Bool(False, "Control whether the core goes "\
136 "to the OFF power state after all thread are disabled for "\
137 "pwr_gating_latency cycles")
139 function_trace
= Param
.Bool(False, "Enable function trace")
140 function_trace_start
= Param
.Tick(0, "Tick to start function trace")
142 checker
= Param
.BaseCPU(NULL
, "checker CPU")
144 syscallRetryLatency
= Param
.Cycles(10000, "Cycles to wait until retry")
146 do_checkpoint_insts
= Param
.Bool(True,
147 "enable checkpoint pseudo instructions")
148 do_statistics_insts
= Param
.Bool(True,
149 "enable statistics pseudo instructions")
151 wait_for_remote_gdb
= Param
.Bool(False,
152 "Wait for a remote GDB connection");
154 workload
= VectorParam
.Process([], "processes to run")
156 dtb
= Param
.BaseTLB(ArchDTB(), "Data TLB")
157 itb
= Param
.BaseTLB(ArchITB(), "Instruction TLB")
158 if buildEnv
['TARGET_ISA'] == 'power':
159 UnifiedTLB
= Param
.Bool(True, "Is this a Unified TLB?")
160 interrupts
= VectorParam
.BaseInterrupts([], "Interrupt Controller")
161 isa
= VectorParam
.BaseISA([], "ISA instance")
163 max_insts_all_threads
= Param
.Counter(0,
164 "terminate when all threads have reached this inst count")
165 max_insts_any_thread
= Param
.Counter(0,
166 "terminate when any thread reaches this inst count")
167 simpoint_start_insts
= VectorParam
.Counter([],
168 "starting instruction counts of simpoints")
169 progress_interval
= Param
.Frequency('0Hz',
170 "frequency to print out the progress message")
172 switched_out
= Param
.Bool(False,
173 "Leave the CPU switched out after startup (used when switching " \
174 "between CPU models)")
176 tracer
= Param
.InstTracer(default_tracer
, "Instruction tracer")
178 icache_port
= RequestPort("Instruction Port")
179 dcache_port
= RequestPort("Data Port")
180 _cached_ports
= ['icache_port', 'dcache_port']
182 if buildEnv
['TARGET_ISA'] in ['x86', 'arm', 'riscv']:
183 _cached_ports
+= ["itb.walker.port", "dtb.walker.port"]
185 _uncached_slave_ports
= []
186 _uncached_master_ports
= []
187 if buildEnv
['TARGET_ISA'] == 'x86':
188 _uncached_slave_ports
+= ["interrupts[0].pio",
189 "interrupts[0].int_slave"]
190 _uncached_master_ports
+= ["interrupts[0].int_master"]
192 def createInterruptController(self
):
193 self
.interrupts
= [ArchInterrupts() for i
in range(self
.numThreads
)]
195 def connectCachedPorts(self
, bus
):
196 for p
in self
._cached
_ports
:
197 exec('self.%s = bus.slave' % p
)
199 def connectUncachedPorts(self
, bus
):
200 for p
in self
._uncached
_slave
_ports
:
201 exec('self.%s = bus.master' % p
)
202 for p
in self
._uncached
_master
_ports
:
203 exec('self.%s = bus.slave' % p
)
205 def connectAllPorts(self
, cached_bus
, uncached_bus
= None):
206 self
.connectCachedPorts(cached_bus
)
208 uncached_bus
= cached_bus
209 self
.connectUncachedPorts(uncached_bus
)
211 def addPrivateSplitL1Caches(self
, ic
, dc
, iwc
= None, dwc
= None):
214 self
.icache_port
= ic
.cpu_side
215 self
.dcache_port
= dc
.cpu_side
216 self
._cached
_ports
= ['icache.mem_side', 'dcache.mem_side']
217 if buildEnv
['TARGET_ISA'] in ['x86', 'arm', 'riscv']:
219 self
.itb_walker_cache
= iwc
220 self
.dtb_walker_cache
= dwc
221 self
.itb
.walker
.port
= iwc
.cpu_side
222 self
.dtb
.walker
.port
= dwc
.cpu_side
223 self
._cached
_ports
+= ["itb_walker_cache.mem_side", \
224 "dtb_walker_cache.mem_side"]
226 self
._cached
_ports
+= ["itb.walker.port", "dtb.walker.port"]
228 # Checker doesn't need its own tlb caches because it does
229 # functional accesses only
230 if self
.checker
!= NULL
:
231 self
._cached
_ports
+= ["checker.itb.walker.port", \
232 "checker.dtb.walker.port"]
234 def addTwoLevelCacheHierarchy(self
, ic
, dc
, l2c
, iwc
=None, dwc
=None,
236 self
.addPrivateSplitL1Caches(ic
, dc
, iwc
, dwc
)
237 self
.toL2Bus
= xbar
if xbar
else L2XBar()
238 self
.connectCachedPorts(self
.toL2Bus
)
240 self
.toL2Bus
.master
= self
.l2cache
.cpu_side
241 self
._cached
_ports
= ['l2cache.mem_side']
243 def createThreads(self
):
244 # If no ISAs have been created, assume that the user wants the
246 if len(self
.isa
) == 0:
247 self
.isa
= [ ArchISA() for i
in range(self
.numThreads
) ]
249 if len(self
.isa
) != int(self
.numThreads
):
250 raise RuntimeError("Number of ISA instances doesn't "
251 "match thread count")
252 if self
.checker
!= NULL
:
253 self
.checker
.createThreads()
255 def addCheckerCpu(self
):
258 def createPhandleKey(self
, thread
):
259 # This method creates a unique key for this cpu as a function of a
261 return 'CPU-%d-%d-%d' % (self
.socket_id
, self
.cpu_id
, thread
)
263 #Generate simple CPU Device Tree structure
264 def generateDeviceTree(self
, state
):
265 """Generate cpu nodes for each thread and the corresponding part of the
266 cpu-map node. Note that this implementation does not support clusters
267 of clusters. Note that GEM5 is not compatible with the official way of
268 numbering cores as defined in the Device Tree documentation. Where the
269 cpu_id needs to reset to 0 for each cluster by specification, GEM5
270 expects the cpu_id to be globally unique and incremental. This
271 generated node adheres the GEM5 way of doing things."""
272 if bool(self
.switched_out
):
275 cpus_node
= FdtNode('cpus')
276 cpus_node
.append(state
.CPUCellsProperty())
277 #Special size override of 0
278 cpus_node
.append(FdtPropertyWords('#size-cells', [0]))
281 for i
in range(int(self
.numThreads
)):
282 reg
= (int(self
.socket_id
)<<8) + int(self
.cpu_id
) + i
283 node
= FdtNode("cpu@%x" % reg
)
284 node
.append(FdtPropertyStrings("device_type", "cpu"))
285 node
.appendCompatible(["gem5,arm-cpu"])
286 node
.append(FdtPropertyWords("reg", state
.CPUAddrCells(reg
)))
287 platform
, found
= self
.system
.unproxy(self
).find_any(Platform
)
289 platform
.annotateCpuDeviceNode(node
, state
)
291 warn("Platform not found for device tree generation; " \
292 "system or multiple CPUs may not start")
294 freq
= int(self
.clk_domain
.unproxy(self
).clock
[0].frequency
)
295 node
.append(FdtPropertyWords("clock-frequency", freq
))
297 # Unique key for this CPU
298 phandle_key
= self
.createPhandleKey(i
)
299 node
.appendPhandle(phandle_key
)
300 cpus_node
.append(node
)
304 def __init__(self
, **kwargs
):
305 super(BaseCPU
, self
).__init
__(**kwargs
)
306 self
.power_state
.possible_states
=['ON', 'CLK_GATED', 'OFF']