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