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