cpu,stats: Update stats style for base.hh and base.cc
[gem5.git] / src / cpu / BaseCPU.py
1 # Copyright (c) 2012-2013, 2015-2017 ARM Limited
2 # Copyright (c) 2020 Barkhausen Institut
3 # All rights reserved.
4 #
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.
13 #
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.
17 #
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.
28 #
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.
40
41 from __future__ import print_function
42
43 import sys
44
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 *
50
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
58
59 default_tracer = ExeTracer()
60
61 if buildEnv['TARGET_ISA'] == 'sparc':
62 from m5.objects.SparcMMU import SparcMMU as ArchMMU
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.X86MMU import X86MMU as ArchMMU
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.MipsMMU import MipsMMU as ArchMMU
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.ArmMMU import ArmMMU as ArchMMU
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.PowerMMU import PowerMMU as ArchMMU
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.RiscvMMU import RiscvMMU as ArchMMU
83 from m5.objects.RiscvInterrupts import RiscvInterrupts as ArchInterrupts
84 from m5.objects.RiscvISA import RiscvISA as ArchISA
85 else:
86 print("Don't know what object types to use for ISA %s" %
87 buildEnv['TARGET_ISA'])
88 sys.exit(1)
89
90 class BaseCPU(ClockedObject):
91 type = 'BaseCPU'
92 abstract = True
93 cxx_header = "cpu/base.hh"
94
95 cxx_exports = [
96 PyBindMethod("switchOut"),
97 PyBindMethod("takeOverFrom"),
98 PyBindMethod("switchedOut"),
99 PyBindMethod("flushTLBs"),
100 PyBindMethod("totalInsts"),
101 PyBindMethod("scheduleInstStop"),
102 PyBindMethod("getCurrentInstCount"),
103 ]
104
105 @classmethod
106 def memory_mode(cls):
107 """Which memory mode does this CPU require?"""
108 return 'invalid'
109
110 @classmethod
111 def require_caches(cls):
112 """Does the CPU model require caches?
113
114 Some CPU models might make assumptions that require them to
115 have caches.
116 """
117 return False
118
119 @classmethod
120 def support_take_over(cls):
121 """Does the CPU model support CPU takeOverFrom?"""
122 return False
123
124 def takeOverFrom(self, old_cpu):
125 self._ccObject.takeOverFrom(old_cpu._ccObject)
126
127
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")
134
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")
138
139 function_trace = Param.Bool(False, "Enable function trace")
140 function_trace_start = Param.Tick(0, "Tick to start function trace")
141
142 checker = Param.BaseCPU(NULL, "checker CPU")
143
144 syscallRetryLatency = Param.Cycles(10000, "Cycles to wait until retry")
145
146 do_checkpoint_insts = Param.Bool(True,
147 "enable checkpoint pseudo instructions")
148 do_statistics_insts = Param.Bool(True,
149 "enable statistics pseudo instructions")
150
151 wait_for_remote_gdb = Param.Bool(False,
152 "Wait for a remote GDB connection");
153
154 workload = VectorParam.Process([], "processes to run")
155
156 mmu = Param.BaseMMU(ArchMMU(), "CPU memory management unit")
157 if buildEnv['TARGET_ISA'] == 'power':
158 UnifiedTLB = Param.Bool(True, "Is this a Unified TLB?")
159 interrupts = VectorParam.BaseInterrupts([], "Interrupt Controller")
160 isa = VectorParam.BaseISA([], "ISA instance")
161
162 max_insts_all_threads = Param.Counter(0,
163 "terminate when all threads have reached this inst count")
164 max_insts_any_thread = Param.Counter(0,
165 "terminate when any thread reaches this inst count")
166 simpoint_start_insts = VectorParam.Counter([],
167 "starting instruction counts of simpoints")
168 progress_interval = Param.Frequency('0Hz',
169 "frequency to print out the progress message")
170
171 switched_out = Param.Bool(False,
172 "Leave the CPU switched out after startup (used when switching " \
173 "between CPU models)")
174
175 tracer = Param.InstTracer(default_tracer, "Instruction tracer")
176
177 icache_port = RequestPort("Instruction Port")
178 dcache_port = RequestPort("Data Port")
179 _cached_ports = ['icache_port', 'dcache_port']
180
181 _cached_ports += ArchMMU.walkerPorts()
182
183 _uncached_interrupt_response_ports = []
184 _uncached_interrupt_request_ports = []
185 if buildEnv['TARGET_ISA'] == 'x86':
186 _uncached_interrupt_response_ports += ["interrupts[0].pio",
187 "interrupts[0].int_responder"]
188 _uncached_interrupt_request_ports += ["interrupts[0].int_requestor"]
189
190 def createInterruptController(self):
191 self.interrupts = [ArchInterrupts() for i in range(self.numThreads)]
192
193 def connectCachedPorts(self, bus):
194 for p in self._cached_ports:
195 exec('self.%s = bus.slave' % p)
196
197 def connectUncachedPorts(self, bus):
198 for p in self._uncached_interrupt_response_ports:
199 exec('self.%s = bus.master' % p)
200 for p in self._uncached_interrupt_request_ports:
201 exec('self.%s = bus.slave' % p)
202
203 def connectAllPorts(self, cached_bus, uncached_bus = None):
204 self.connectCachedPorts(cached_bus)
205 if not uncached_bus:
206 uncached_bus = cached_bus
207 self.connectUncachedPorts(uncached_bus)
208
209 def addPrivateSplitL1Caches(self, ic, dc, iwc = None, dwc = None):
210 self.icache = ic
211 self.dcache = dc
212 self.icache_port = ic.cpu_side
213 self.dcache_port = dc.cpu_side
214 self._cached_ports = ['icache.mem_side', 'dcache.mem_side']
215 if buildEnv['TARGET_ISA'] in ['x86', 'arm', 'riscv']:
216 if iwc and dwc:
217 self.itb_walker_cache = iwc
218 self.dtb_walker_cache = dwc
219 self.mmu.connectWalkerPorts(
220 iwc.cpu_side, dwc.cpu_side)
221 self._cached_ports += ["itb_walker_cache.mem_side", \
222 "dtb_walker_cache.mem_side"]
223 else:
224 self._cached_ports += ArchMMU.walkerPorts()
225
226 # Checker doesn't need its own tlb caches because it does
227 # functional accesses only
228 if self.checker != NULL:
229 self._cached_ports += [ ".".join("checker", port) \
230 for port in ArchMMU.walkerPorts() ]
231
232 def addTwoLevelCacheHierarchy(self, ic, dc, l2c, iwc=None, dwc=None,
233 xbar=None):
234 self.addPrivateSplitL1Caches(ic, dc, iwc, dwc)
235 self.toL2Bus = xbar if xbar else L2XBar()
236 self.connectCachedPorts(self.toL2Bus)
237 self.l2cache = l2c
238 self.toL2Bus.mem_side_ports = self.l2cache.cpu_side
239 self._cached_ports = ['l2cache.mem_side']
240
241 def createThreads(self):
242 # If no ISAs have been created, assume that the user wants the
243 # default ISA.
244 if len(self.isa) == 0:
245 self.isa = [ ArchISA() for i in range(self.numThreads) ]
246 else:
247 if len(self.isa) != int(self.numThreads):
248 raise RuntimeError("Number of ISA instances doesn't "
249 "match thread count")
250 if self.checker != NULL:
251 self.checker.createThreads()
252
253 def addCheckerCpu(self):
254 pass
255
256 def createPhandleKey(self, thread):
257 # This method creates a unique key for this cpu as a function of a
258 # certain thread
259 return 'CPU-%d-%d-%d' % (self.socket_id, self.cpu_id, thread)
260
261 #Generate simple CPU Device Tree structure
262 def generateDeviceTree(self, state):
263 """Generate cpu nodes for each thread and the corresponding part of the
264 cpu-map node. Note that this implementation does not support clusters
265 of clusters. Note that GEM5 is not compatible with the official way of
266 numbering cores as defined in the Device Tree documentation. Where the
267 cpu_id needs to reset to 0 for each cluster by specification, GEM5
268 expects the cpu_id to be globally unique and incremental. This
269 generated node adheres the GEM5 way of doing things."""
270 if bool(self.switched_out):
271 return
272
273 cpus_node = FdtNode('cpus')
274 cpus_node.append(state.CPUCellsProperty())
275 #Special size override of 0
276 cpus_node.append(FdtPropertyWords('#size-cells', [0]))
277
278 # Generate cpu nodes
279 for i in range(int(self.numThreads)):
280 reg = (int(self.socket_id)<<8) + int(self.cpu_id) + i
281 node = FdtNode("cpu@%x" % reg)
282 node.append(FdtPropertyStrings("device_type", "cpu"))
283 node.appendCompatible(["gem5,arm-cpu"])
284 node.append(FdtPropertyWords("reg", state.CPUAddrCells(reg)))
285 platform, found = self.system.unproxy(self).find_any(Platform)
286 if found:
287 platform.annotateCpuDeviceNode(node, state)
288 else:
289 warn("Platform not found for device tree generation; " \
290 "system or multiple CPUs may not start")
291
292 freq = int(self.clk_domain.unproxy(self).clock[0].frequency)
293 node.append(FdtPropertyWords("clock-frequency", freq))
294
295 # Unique key for this CPU
296 phandle_key = self.createPhandleKey(i)
297 node.appendPhandle(phandle_key)
298 cpus_node.append(node)
299
300 yield cpus_node
301
302 # Generate nodes from the BaseCPU children (hence under the root node,
303 # and don't add them as subnode). Please note: this is mainly needed
304 # for the ISA class, to generate the PMU entry in the DTB.
305 for child_node in self.recurseDeviceTree(state):
306 yield child_node
307
308 def __init__(self, **kwargs):
309 super(BaseCPU, self).__init__(**kwargs)
310 self.power_state.possible_states=['ON', 'CLK_GATED', 'OFF']