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