BaseCPU.py revision 12563
11689SN/A# Copyright (c) 2012-2013, 2015-2017 ARM Limited 210715SRekai.GonzalezAlberquilla@arm.com# All rights reserved. 39913Ssteve.reinhardt@amd.com# 47854SAli.Saidi@ARM.com# The license below extends only to copyright in the software and shall 57854SAli.Saidi@ARM.com# not be construed as granting a license to any other intellectual 67854SAli.Saidi@ARM.com# property including but not limited to intellectual property relating 77854SAli.Saidi@ARM.com# to a hardware implementation of the functionality of the software 87854SAli.Saidi@ARM.com# licensed hereunder. You may use the software subject to the license 97854SAli.Saidi@ARM.com# terms below provided that you ensure that this notice is replicated 107854SAli.Saidi@ARM.com# unmodified and in its entirety in all distributions of the software, 117854SAli.Saidi@ARM.com# modified or unmodified, in source code or in binary form. 127854SAli.Saidi@ARM.com# 137854SAli.Saidi@ARM.com# Copyright (c) 2005-2008 The Regents of The University of Michigan 147854SAli.Saidi@ARM.com# Copyright (c) 2011 Regents of the University of California 152329SN/A# All rights reserved. 161689SN/A# 171689SN/A# Redistribution and use in source and binary forms, with or without 181689SN/A# modification, are permitted provided that the following conditions are 191689SN/A# met: redistributions of source code must retain the above copyright 201689SN/A# notice, this list of conditions and the following disclaimer; 211689SN/A# redistributions in binary form must reproduce the above copyright 221689SN/A# notice, this list of conditions and the following disclaimer in the 231689SN/A# documentation and/or other materials provided with the distribution; 241689SN/A# neither the name of the copyright holders nor the names of its 251689SN/A# contributors may be used to endorse or promote products derived from 261689SN/A# this software without specific prior written permission. 271689SN/A# 281689SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 291689SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 301689SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 311689SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 321689SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 331689SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 341689SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 351689SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 361689SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 371689SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 381689SN/A# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 391689SN/A# 402665Ssaidi@eecs.umich.edu# Authors: Nathan Binkert 412665Ssaidi@eecs.umich.edu# Rick Strong 422935Sksewell@umich.edu# Andreas Hansson 431689SN/A# Glenn Bergmans 441689SN/A 459944Smatt.horsnell@ARM.comfrom __future__ import print_function 469944Smatt.horsnell@ARM.com 479944Smatt.horsnell@ARM.comimport sys 481060SN/A 491060SN/Afrom m5.SimObject import * 503773Sgblack@eecs.umich.edufrom m5.defines import buildEnv 516329Sgblack@eecs.umich.edufrom m5.params import * 526658Snate@binkert.orgfrom m5.proxy import * 531717SN/Afrom m5.util.fdthelper import * 549913Ssteve.reinhardt@amd.com 558232Snate@binkert.orgfrom XBar import L2XBar 568232Snate@binkert.orgfrom InstTracer import InstTracer 579527SMatt.Horsnell@arm.comfrom CPUTracers import ExeTracer 585529Snate@binkert.orgfrom MemObject import MemObject 591060SN/Afrom SubSystem import SubSystem 606221Snate@binkert.orgfrom ClockDomain import * 616221Snate@binkert.orgfrom Platform import Platform 621061SN/A 635529Snate@binkert.orgdefault_tracer = ExeTracer() 644329Sktlim@umich.edu 654329Sktlim@umich.eduif buildEnv['TARGET_ISA'] == 'alpha': 662292SN/A from AlphaTLB import AlphaDTB as ArchDTB, AlphaITB as ArchITB 672292SN/A from AlphaInterrupts import AlphaInterrupts 682292SN/A from AlphaISA import AlphaISA 692292SN/A default_isa_class = AlphaISA 705529Snate@binkert.orgelif buildEnv['TARGET_ISA'] == 'sparc': 719920Syasuko.eckert@amd.com from SparcTLB import SparcTLB as ArchDTB, SparcTLB as ArchITB 729920Syasuko.eckert@amd.com from SparcInterrupts import SparcInterrupts 731060SN/A from SparcISA import SparcISA 7410172Sdam.sunwoo@arm.com default_isa_class = SparcISA 7510172Sdam.sunwoo@arm.comelif buildEnv['TARGET_ISA'] == 'x86': 7610172Sdam.sunwoo@arm.com from X86TLB import X86TLB as ArchDTB, X86TLB as ArchITB 7710172Sdam.sunwoo@arm.com from X86LocalApic import X86LocalApic 7810172Sdam.sunwoo@arm.com from X86ISA import X86ISA 792292SN/A default_isa_class = X86ISA 8010328Smitch.hayenga@arm.comelif buildEnv['TARGET_ISA'] == 'mips': 812292SN/A from MipsTLB import MipsTLB as ArchDTB, MipsTLB as ArchITB 822292SN/A from MipsInterrupts import MipsInterrupts 832292SN/A from MipsISA import MipsISA 842292SN/A default_isa_class = MipsISA 852292SN/Aelif buildEnv['TARGET_ISA'] == 'arm': 862292SN/A from ArmTLB import ArmTLB as ArchDTB, ArmTLB as ArchITB 872292SN/A from ArmTLB import ArmStage2IMMU, ArmStage2DMMU 881060SN/A from ArmInterrupts import ArmInterrupts 891060SN/A from ArmISA import ArmISA 901061SN/A default_isa_class = ArmISA 911060SN/Aelif buildEnv['TARGET_ISA'] == 'power': 922292SN/A from PowerTLB import PowerTLB as ArchDTB, PowerTLB as ArchITB 931062SN/A from PowerInterrupts import PowerInterrupts 941062SN/A from PowerISA import PowerISA 958240Snate@binkert.org default_isa_class = PowerISA 961062SN/Aelif buildEnv['TARGET_ISA'] == 'riscv': 971062SN/A from RiscvTLB import RiscvTLB as ArchDTB, RiscvTLB as ArchITB 981062SN/A from RiscvInterrupts import RiscvInterrupts 998240Snate@binkert.org from RiscvISA import RiscvISA 1001062SN/A default_isa_class = RiscvISA 1011062SN/A 1021062SN/Aclass BaseCPU(MemObject): 1038240Snate@binkert.org type = 'BaseCPU' 1041062SN/A abstract = True 1051062SN/A cxx_header = "cpu/base.hh" 1062301SN/A 1078240Snate@binkert.org cxx_exports = [ 1082301SN/A PyBindMethod("switchOut"), 1092301SN/A PyBindMethod("takeOverFrom"), 1102292SN/A PyBindMethod("switchedOut"), 1118240Snate@binkert.org PyBindMethod("flushTLBs"), 1122292SN/A PyBindMethod("totalInsts"), 1132292SN/A PyBindMethod("scheduleInstStop"), 1141062SN/A PyBindMethod("scheduleLoadStop"), 1158240Snate@binkert.org PyBindMethod("getCurrentInstCount"), 1161062SN/A ] 1171062SN/A 1181062SN/A @classmethod 1198240Snate@binkert.org def memory_mode(cls): 1201062SN/A """Which memory mode does this CPU require?""" 1211062SN/A return 'invalid' 1221062SN/A 1238240Snate@binkert.org @classmethod 1241062SN/A def require_caches(cls): 1251062SN/A """Does the CPU model require caches? 1261062SN/A 1278240Snate@binkert.org Some CPU models might make assumptions that require them to 1282292SN/A have caches. 1291062SN/A """ 1301062SN/A return False 1318240Snate@binkert.org 1322292SN/A @classmethod 1331062SN/A def support_take_over(cls): 13410239Sbinhpham@cs.rutgers.edu """Does the CPU model support CPU takeOverFrom?""" 13510239Sbinhpham@cs.rutgers.edu return False 13610239Sbinhpham@cs.rutgers.edu 13710239Sbinhpham@cs.rutgers.edu def takeOverFrom(self, old_cpu): 13810239Sbinhpham@cs.rutgers.edu self._ccObject.takeOverFrom(old_cpu._ccObject) 13910239Sbinhpham@cs.rutgers.edu 14010239Sbinhpham@cs.rutgers.edu 14110239Sbinhpham@cs.rutgers.edu system = Param.System(Parent.any, "system object") 1421062SN/A cpu_id = Param.Int(-1, "CPU identifier") 1438240Snate@binkert.org socket_id = Param.Unsigned(0, "Physical Socket identifier") 1441062SN/A numThreads = Param.Unsigned(1, "number of HW thread contexts") 1451062SN/A pwr_gating_latency = Param.Cycles(300, 1461062SN/A "Latency to enter power gating state when all contexts are suspended") 1478240Snate@binkert.org 1481062SN/A power_gating_on_idle = Param.Bool(False, "Control whether the core goes "\ 1491062SN/A "to the OFF power state after all thread are disabled for "\ 1501062SN/A "pwr_gating_latency cycles") 1518240Snate@binkert.org 1521062SN/A function_trace = Param.Bool(False, "Enable function trace") 1531062SN/A function_trace_start = Param.Tick(0, "Tick to start function trace") 1541062SN/A 1558240Snate@binkert.org checker = Param.BaseCPU(NULL, "checker CPU") 1561062SN/A 1571062SN/A syscallRetryLatency = Param.Cycles(10000, "Cycles to wait until retry") 1581062SN/A 1598240Snate@binkert.org do_checkpoint_insts = Param.Bool(True, 1601062SN/A "enable checkpoint pseudo instructions") 1611062SN/A do_statistics_insts = Param.Bool(True, 1622301SN/A "enable statistics pseudo instructions") 1638240Snate@binkert.org 1642301SN/A profile = Param.Latency('0ns', "trace the kernel stack") 1652301SN/A do_quiesce = Param.Bool(True, "enable quiesce instructions") 1662301SN/A 1672301SN/A wait_for_remote_gdb = Param.Bool(False, 1688240Snate@binkert.org "Wait for a remote GDB connection"); 1692301SN/A 1702301SN/A workload = VectorParam.Process([], "processes to run") 1712301SN/A 1722307SN/A dtb = Param.BaseTLB(ArchDTB(), "Data TLB") 1738240Snate@binkert.org itb = Param.BaseTLB(ArchITB(), "Instruction TLB") 1742307SN/A if buildEnv['TARGET_ISA'] == 'sparc': 1752307SN/A interrupts = VectorParam.SparcInterrupts( 1762307SN/A [], "Interrupt Controller") 1777897Shestness@cs.utexas.edu isa = VectorParam.SparcISA([], "ISA instance") 1788240Snate@binkert.org elif buildEnv['TARGET_ISA'] == 'alpha': 1797897Shestness@cs.utexas.edu interrupts = VectorParam.AlphaInterrupts( 1807897Shestness@cs.utexas.edu [], "Interrupt Controller") 1817897Shestness@cs.utexas.edu isa = VectorParam.AlphaISA([], "ISA instance") 1828240Snate@binkert.org elif buildEnv['TARGET_ISA'] == 'x86': 1837897Shestness@cs.utexas.edu interrupts = VectorParam.X86LocalApic([], "Interrupt Controller") 1847897Shestness@cs.utexas.edu isa = VectorParam.X86ISA([], "ISA instance") 1851062SN/A elif buildEnv['TARGET_ISA'] == 'mips': 1861062SN/A interrupts = VectorParam.MipsInterrupts( 1871062SN/A [], "Interrupt Controller") 1881062SN/A isa = VectorParam.MipsISA([], "ISA instance") 1892292SN/A elif buildEnv['TARGET_ISA'] == 'arm': 1901060SN/A istage2_mmu = Param.ArmStage2MMU(ArmStage2IMMU(), "Stage 2 trans") 1911060SN/A dstage2_mmu = Param.ArmStage2MMU(ArmStage2DMMU(), "Stage 2 trans") 1921060SN/A interrupts = VectorParam.ArmInterrupts( 1931060SN/A [], "Interrupt Controller") 1941060SN/A isa = VectorParam.ArmISA([], "ISA instance") 1951060SN/A elif buildEnv['TARGET_ISA'] == 'power': 1961060SN/A UnifiedTLB = Param.Bool(True, "Is this a Unified TLB?") 1971060SN/A interrupts = VectorParam.PowerInterrupts( 1981060SN/A [], "Interrupt Controller") 1991060SN/A isa = VectorParam.PowerISA([], "ISA instance") 2001060SN/A elif buildEnv['TARGET_ISA'] == 'riscv': 2011060SN/A interrupts = VectorParam.RiscvInterrupts( 2021060SN/A [], "Interrupt Controller") 2031061SN/A isa = VectorParam.RiscvISA([], "ISA instance") 2041060SN/A else: 2052292SN/A print("Don't know what TLB to use for ISA %s" % 2061060SN/A buildEnv['TARGET_ISA']) 2071060SN/A sys.exit(1) 2081060SN/A 2091060SN/A max_insts_all_threads = Param.Counter(0, 2101060SN/A "terminate when all threads have reached this inst count") 2111060SN/A max_insts_any_thread = Param.Counter(0, 2121060SN/A "terminate when any thread reaches this inst count") 2131061SN/A simpoint_start_insts = VectorParam.Counter([], 2141060SN/A "starting instruction counts of simpoints") 2152292SN/A max_loads_all_threads = Param.Counter(0, 2161060SN/A "terminate when all threads have reached this load count") 2171060SN/A max_loads_any_thread = Param.Counter(0, 2181060SN/A "terminate when any thread reaches this load count") 2191060SN/A progress_interval = Param.Frequency('0Hz', 2201060SN/A "frequency to print out the progress message") 2211060SN/A 2221060SN/A switched_out = Param.Bool(False, 2231061SN/A "Leave the CPU switched out after startup (used when switching " \ 2241060SN/A "between CPU models)") 2259427SAndreas.Sandberg@ARM.com 2261060SN/A tracer = Param.InstTracer(default_tracer, "Instruction tracer") 2279444SAndreas.Sandberg@ARM.com 2289444SAndreas.Sandberg@ARM.com icache_port = MasterPort("Instruction Port") 2299444SAndreas.Sandberg@ARM.com dcache_port = MasterPort("Data Port") 2309444SAndreas.Sandberg@ARM.com _cached_ports = ['icache_port', 'dcache_port'] 2319444SAndreas.Sandberg@ARM.com 2329444SAndreas.Sandberg@ARM.com if buildEnv['TARGET_ISA'] in ['x86', 'arm']: 2339444SAndreas.Sandberg@ARM.com _cached_ports += ["itb.walker.port", "dtb.walker.port"] 2349444SAndreas.Sandberg@ARM.com 2359444SAndreas.Sandberg@ARM.com _uncached_slave_ports = [] 2369444SAndreas.Sandberg@ARM.com _uncached_master_ports = [] 2379444SAndreas.Sandberg@ARM.com if buildEnv['TARGET_ISA'] == 'x86': 2389444SAndreas.Sandberg@ARM.com _uncached_slave_ports += ["interrupts[0].pio", 2392329SN/A "interrupts[0].int_slave"] 2406221Snate@binkert.org _uncached_master_ports += ["interrupts[0].int_master"] 2419444SAndreas.Sandberg@ARM.com 2429444SAndreas.Sandberg@ARM.com def createInterruptController(self): 2432292SN/A if buildEnv['TARGET_ISA'] == 'sparc': 24410239Sbinhpham@cs.rutgers.edu self.interrupts = [SparcInterrupts() for i in xrange(self.numThreads)] 24510239Sbinhpham@cs.rutgers.edu elif buildEnv['TARGET_ISA'] == 'alpha': 2462292SN/A self.interrupts = [AlphaInterrupts() for i in xrange(self.numThreads)] 2472292SN/A elif buildEnv['TARGET_ISA'] == 'x86': 2489444SAndreas.Sandberg@ARM.com self.apic_clk_domain = DerivedClockDomain(clk_domain = 2499444SAndreas.Sandberg@ARM.com Parent.clk_domain, 2509444SAndreas.Sandberg@ARM.com clk_divider = 16) 2519444SAndreas.Sandberg@ARM.com self.interrupts = [X86LocalApic(clk_domain = self.apic_clk_domain, 2529444SAndreas.Sandberg@ARM.com pio_addr=0x2000000000000000) 25310239Sbinhpham@cs.rutgers.edu for i in xrange(self.numThreads)] 25410239Sbinhpham@cs.rutgers.edu _localApic = self.interrupts 2559444SAndreas.Sandberg@ARM.com elif buildEnv['TARGET_ISA'] == 'mips': 2569444SAndreas.Sandberg@ARM.com self.interrupts = [MipsInterrupts() for i in xrange(self.numThreads)] 2572292SN/A elif buildEnv['TARGET_ISA'] == 'arm': 2581060SN/A self.interrupts = [ArmInterrupts() for i in xrange(self.numThreads)] 2591060SN/A elif buildEnv['TARGET_ISA'] == 'power': 2602292SN/A self.interrupts = [PowerInterrupts() for i in xrange(self.numThreads)] 2612292SN/A elif buildEnv['TARGET_ISA'] == 'riscv': 2626221Snate@binkert.org self.interrupts = \ 2632292SN/A [RiscvInterrupts() for i in xrange(self.numThreads)] 2642292SN/A else: 2652292SN/A print("Don't know what Interrupt Controller to use for ISA %s" % 2662292SN/A buildEnv['TARGET_ISA']) 2672292SN/A sys.exit(1) 2681061SN/A 2691060SN/A def connectCachedPorts(self, bus): 2702292SN/A for p in self._cached_ports: 2711060SN/A exec('self.%s = bus.slave' % p) 2726221Snate@binkert.org 2736221Snate@binkert.org def connectUncachedPorts(self, bus): 2741060SN/A for p in self._uncached_slave_ports: 2751060SN/A exec('self.%s = bus.master' % p) 2761061SN/A for p in self._uncached_master_ports: 2771060SN/A exec('self.%s = bus.slave' % p) 2782292SN/A 2791060SN/A def connectAllPorts(self, cached_bus, uncached_bus = None): 2802292SN/A self.connectCachedPorts(cached_bus) 2812292SN/A if not uncached_bus: 2821060SN/A uncached_bus = cached_bus 2832292SN/A self.connectUncachedPorts(uncached_bus) 2842292SN/A 2852292SN/A def addPrivateSplitL1Caches(self, ic, dc, iwc = None, dwc = None): 2862292SN/A self.icache = ic 2872292SN/A self.dcache = dc 2881060SN/A self.icache_port = ic.cpu_side 2891060SN/A self.dcache_port = dc.cpu_side 2901061SN/A self._cached_ports = ['icache.mem_side', 'dcache.mem_side'] 2912863Sktlim@umich.edu if buildEnv['TARGET_ISA'] in ['x86', 'arm']: 2929444SAndreas.Sandberg@ARM.com if iwc and dwc: 2931060SN/A self.itb_walker_cache = iwc 2949444SAndreas.Sandberg@ARM.com self.dtb_walker_cache = dwc 2959444SAndreas.Sandberg@ARM.com self.itb.walker.port = iwc.cpu_side 2969444SAndreas.Sandberg@ARM.com self.dtb.walker.port = dwc.cpu_side 2979444SAndreas.Sandberg@ARM.com self._cached_ports += ["itb_walker_cache.mem_side", \ 2989444SAndreas.Sandberg@ARM.com "dtb_walker_cache.mem_side"] 2999444SAndreas.Sandberg@ARM.com else: 3009444SAndreas.Sandberg@ARM.com self._cached_ports += ["itb.walker.port", "dtb.walker.port"] 3012863Sktlim@umich.edu 3022316SN/A # Checker doesn't need its own tlb caches because it does 3031060SN/A # functional accesses only 3042316SN/A if self.checker != NULL: 3052316SN/A self._cached_ports += ["checker.itb.walker.port", \ 3062307SN/A "checker.dtb.walker.port"] 3071060SN/A 3089444SAndreas.Sandberg@ARM.com def addTwoLevelCacheHierarchy(self, ic, dc, l2c, iwc=None, dwc=None, 3099444SAndreas.Sandberg@ARM.com xbar=None): 3101060SN/A self.addPrivateSplitL1Caches(ic, dc, iwc, dwc) 3119444SAndreas.Sandberg@ARM.com self.toL2Bus = xbar if xbar else L2XBar() 3129444SAndreas.Sandberg@ARM.com self.connectCachedPorts(self.toL2Bus) 3139444SAndreas.Sandberg@ARM.com self.l2cache = l2c 3149444SAndreas.Sandberg@ARM.com self.toL2Bus.master = self.l2cache.cpu_side 3156221Snate@binkert.org self._cached_ports = ['l2cache.mem_side'] 3169444SAndreas.Sandberg@ARM.com 3179444SAndreas.Sandberg@ARM.com def createThreads(self): 3189444SAndreas.Sandberg@ARM.com # If no ISAs have been created, assume that the user wants the 3199444SAndreas.Sandberg@ARM.com # default ISA. 3202307SN/A if len(self.isa) == 0: 3212307SN/A self.isa = [ default_isa_class() for i in xrange(self.numThreads) ] 3222307SN/A else: 3232307SN/A if len(self.isa) != int(self.numThreads): 3242307SN/A raise RuntimeError("Number of ISA instances doesn't " 3256221Snate@binkert.org "match thread count") 3261858SN/A if self.checker != NULL: 3272292SN/A self.checker.createThreads() 3281858SN/A 3292292SN/A def addCheckerCpu(self): 3302292SN/A pass 3312292SN/A 3322292SN/A def createPhandleKey(self, thread): 3333788Sgblack@eecs.umich.edu # This method creates a unique key for this cpu as a function of a 3342292SN/A # certain thread 3352698Sktlim@umich.edu return 'CPU-%d-%d-%d' % (self.socket_id, self.cpu_id, thread) 3363788Sgblack@eecs.umich.edu 3372301SN/A #Generate simple CPU Device Tree structure 3383788Sgblack@eecs.umich.edu def generateDeviceTree(self, state): 3393788Sgblack@eecs.umich.edu """Generate cpu nodes for each thread and the corresponding part of the 3403788Sgblack@eecs.umich.edu cpu-map node. Note that this implementation does not support clusters 3413788Sgblack@eecs.umich.edu of clusters. Note that GEM5 is not compatible with the official way of 3423788Sgblack@eecs.umich.edu numbering cores as defined in the Device Tree documentation. Where the 3433788Sgblack@eecs.umich.edu cpu_id needs to reset to 0 for each cluster by specification, GEM5 3443788Sgblack@eecs.umich.edu expects the cpu_id to be globally unique and incremental. This 3453788Sgblack@eecs.umich.edu generated node adheres the GEM5 way of doing things.""" 3463788Sgblack@eecs.umich.edu if bool(self.switched_out): 3473788Sgblack@eecs.umich.edu return 3483788Sgblack@eecs.umich.edu 3492292SN/A cpus_node = FdtNode('cpus') 3502292SN/A cpus_node.append(state.CPUCellsProperty()) 3512292SN/A #Special size override of 0 3522292SN/A cpus_node.append(FdtPropertyWords('#size-cells', [0])) 3532292SN/A 3542329SN/A # Generate cpu nodes 3552292SN/A for i in range(int(self.numThreads)): 3562935Sksewell@umich.edu reg = (int(self.socket_id)<<8) + int(self.cpu_id) + i 3572935Sksewell@umich.edu node = FdtNode("cpu@%x" % reg) 3582731Sktlim@umich.edu node.append(FdtPropertyStrings("device_type", "cpu")) 3592292SN/A node.appendCompatible(["gem5,arm-cpu"]) 3602292SN/A node.append(FdtPropertyWords("reg", state.CPUAddrCells(reg))) 3612935Sksewell@umich.edu platform, found = self.system.unproxy(self).find_any(Platform) 3622292SN/A if found: 3632292SN/A platform.annotateCpuDeviceNode(node, state) 3642935Sksewell@umich.edu else: 3654632Sgblack@eecs.umich.edu warn("Platform not found for device tree generation; " \ 3663093Sksewell@umich.edu "system or multiple CPUs may not start") 3672292SN/A 3682292SN/A freq = round(self.clk_domain.unproxy(self).clock[0].frequency) 3693093Sksewell@umich.edu node.append(FdtPropertyWords("clock-frequency", freq)) 3704632Sgblack@eecs.umich.edu 3712935Sksewell@umich.edu # Unique key for this CPU 3722292SN/A phandle_key = self.createPhandleKey(i) 3732292SN/A node.appendPhandle(phandle_key) 3742292SN/A cpus_node.append(node) 3752292SN/A 3762292SN/A yield cpus_node 3772292SN/A