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