SimObject initialization is controlled by the instantiate method in src/python/m5/simulate.py. There are slightly different initialization paths when starting the simulation afresh and when loading from a checkpoint. After instantiation and connecting ports, simulate.py initializes the object using the following call sequence:
SimObject::init()
SimObject::regStats()
SimObject::initState() if starting afresh.
SimObject::loadState() if restoring from a checkpoint.
SimObject::resetStats()
SimObject::startup()
Drainable::drainResume() if resuming from a checkpoint.
# Physical memory # On the PC platform, the memory region 0xC0000000-0xFFFFFFFF is reserved # for various devices. Hence, if the physical memory size is greater than # 3GB, we need to split it into two parts. excess_mem_size = \ convert.toMemorySize(mdesc.mem()) - convert.toMemorySize('3GB') if excess_mem_size <= 0: self.mem_ranges = [AddrRange(mdesc.mem())] else: warn("Physical memory size specified is %s which is greater than " \ "3GB. Twice the number of memory controllers would be " \ "created." % (mdesc.mem()))
# North Bridge x86_sys.iobus = IOXBar() x86_sys.bridge = Bridge(delay='50ns') x86_sys.bridge.mem_side_port = x86_sys.iobus.cpu_side_ports x86_sys.bridge.cpu_side_port = x86_sys.membus.mem_side_ports # Allow the bridge to pass through: # 1) kernel configured PCI device memory map address: address range # [0xC0000000, 0xFFFF0000). (The upper 64kB are reserved for m5ops.) # 2) the bridge to pass through the IO APIC (two pages, already contained in 1), # 3) everything in the IO address range up to the local APIC, and # 4) then the entire PCI address space and beyond. x86_sys.bridge.ranges = \ [ AddrRange(0xC0000000, 0xFFFF0000), AddrRange(IO_address_space_base, interrupts_address_space_base - 1), AddrRange(pci_config_address_space_base, Addr.max) ]
# Create a bridge from the IO bus to the memory bus to allow access to # the local APIC (two pages) x86_sys.apicbridge = Bridge(delay='50ns') x86_sys.apicbridge.cpu_side_port = x86_sys.iobus.mem_side_ports x86_sys.apicbridge.mem_side_port = x86_sys.membus.cpu_side_ports x86_sys.apicbridge.ranges = [AddrRange(interrupts_address_space_base, interrupts_address_space_base + numCPUs * APIC_range_size - 1)]
# connect the io bus x86_sys.pc.attachIO(x86_sys.iobus)
defmakeLinuxX86System(mem_mode, numCPUs=1, mdesc=None, Ruby=False, cmdline=None): # Build up the x86 system and then specialize it for Linux self = makeX86System(mem_mode, numCPUs, mdesc, X86FsLinux(), Ruby)
# We assume below that there's at least 1MB of memory. We'll require 2 # just to avoid corner cases. phys_mem_size = sum([r.size() for r in self.mem_ranges]) assert(phys_mem_size >= 0x200000) assert(len(self.mem_ranges) <= 2)
entries = \ [ # Mark the first megabyte of memory as reserved X86E820Entry(addr = 0, size = '639kB', range_type = 1), X86E820Entry(addr = 0x9fc00, size = '385kB', range_type = 2), # Mark the rest of physical memory as available X86E820Entry(addr = 0x100000, size = '%dB' % (self.mem_ranges[0].size() - 0x100000), range_type = 1), ]
# Mark [mem_size, 3GB) as reserved if memory less than 3GB, which force # IO devices to be mapped to [0xC0000000, 0xFFFF0000). Requests to this # specific range can pass though bridge to iobus. iflen(self.mem_ranges) == 1: entries.append(X86E820Entry(addr = self.mem_ranges[0].size(), size='%dB' % (0xC0000000 - self.mem_ranges[0].size()), range_type=2))
# Reserve the last 16kB of the 32-bit address space for the m5op interface entries.append(X86E820Entry(addr=0xFFFF0000, size='64kB', range_type=2))
# In case the physical memory is greater than 3GB, we split it into two # parts and add a separate e820 entry for the second part. This entry # starts at 0x100000000, which is the first address after the space # reserved for devices. iflen(self.mem_ranges) == 2: entries.append(X86E820Entry(addr = 0x100000000, size = '%dB' % (self.mem_ranges[1].size()), range_type = 1))
# Set the cache line size for the entire system test_sys.cache_line_size = options.cacheline_size
# Create a top-level voltage domain test_sys.voltage_domain = VoltageDomain(voltage = options.sys_voltage)
# Create a source clock for the system and set the clock period test_sys.clk_domain = SrcClockDomain(clock = options.sys_clock, voltage_domain = test_sys.voltage_domain)
# Create a CPU voltage domain test_sys.cpu_voltage_domain = VoltageDomain()
# Create a source clock for the CPUs and set the clock period test_sys.cpu_clk_domain = SrcClockDomain(clock = options.cpu_clock, voltage_domain = test_sys.cpu_voltage_domain)
# Create a seperate clock domain for Ruby test_sys.ruby.clk_domain = SrcClockDomain(clock = options.ruby_clock, voltage_domain = test_sys.voltage_domain)
# Connect the ruby io port to the PIO bus, # assuming that there is just one such port. test_sys.iobus.master = test_sys.ruby._io_port.slave
for (i, cpu) inenumerate(test_sys.cpu): # # Tie the cpu ports to the correct ruby system ports # cpu.clk_domain = test_sys.cpu_clk_domain cpu.createThreads() cpu.createInterruptController()
else: if options.caches or options.l2cache: # By default the IOCache runs at the system clock test_sys.iocache = IOCache(addr_ranges = test_sys.mem_ranges) test_sys.iocache.cpu_side = test_sys.iobus.master test_sys.iocache.mem_side = test_sys.membus.slave elifnot options.external_memory_system: test_sys.iobridge = Bridge(delay='50ns', ranges = test_sys.mem_ranges) test_sys.iobridge.slave = test_sys.iobus.master test_sys.iobridge.master = test_sys.membus.slave
# Sanity check if options.simpoint_profile: ifnot ObjectList.is_noncaching_cpu(TestCPUClass): fatal("SimPoint generation should be done with atomic cpu") if np > 1: fatal("SimPoint generation not supported with more than one CPUs")
for i inrange(np): if options.simpoint_profile: test_sys.cpu[i].addSimPointProbe(options.simpoint_interval) if options.checker: test_sys.cpu[i].addCheckerCpu() ifnot ObjectList.is_kvm_cpu(TestCPUClass): if options.bp_type: bpClass = ObjectList.bp_list.get(options.bp_type) test_sys.cpu[i].branchPred = bpClass() if options.indirect_bp_type: IndirectBPClass = ObjectList.indirect_bp_list.get( options.indirect_bp_type) test_sys.cpu[i].branchPred.indirectBranchPred = \ IndirectBPClass() test_sys.cpu[i].createThreads()
# If elastic tracing is enabled when not restoring from checkpoint and # when not fast forwarding using the atomic cpu, then check that the # TestCPUClass is DerivO3CPU or inherits from DerivO3CPU. If the check # passes then attach the elastic trace probe. # If restoring from checkpoint or fast forwarding, the code that does this for # FutureCPUClass is in the Simulation module. If the check passes then the # elastic trace probe is attached to the switch CPUs. if options.elastic_trace_en and options.checkpoint_restore == Noneand \ not options.fast_forward: CpuConfig.config_etrace(TestCPUClass, test_sys.cpu, options)
# "Non-existant" ports used for timing purposes by the linux kernel i_dont_exist1 = IsaFake(pio_addr=x86IOAddress(0x80), pio_size=1) i_dont_exist2 = IsaFake(pio_addr=x86IOAddress(0xed), pio_size=1)
# Ports behind the pci config and data regsiters. These don't do anything, # but the linux kernel fiddles with them anway. behind_pci = IsaFake(pio_addr=x86IOAddress(0xcf8), pio_size=8)
# Serial port and terminal com_1 = Uart8250() com_1.pio_addr = x86IOAddress(0x3f8) com_1.device = Terminal()
# Devices to catch access to non-existant serial ports. fake_com_2 = IsaFake(pio_addr=x86IOAddress(0x2f8), pio_size=8) fake_com_3 = IsaFake(pio_addr=x86IOAddress(0x3e8), pio_size=8) fake_com_4 = IsaFake(pio_addr=x86IOAddress(0x2e8), pio_size=8)
# A device to catch accesses to the non-existant floppy controller. fake_floppy = IsaFake(pio_addr=x86IOAddress(0x3f2), pio_size=2)
cpu_side_ports = VectorResponsePort("Vector port for connecting " "mem side ports") slave = DeprecatedParam(cpu_side_ports, '`slave` is now called `cpu_side_ports`') mem_side_ports = VectorRequestPort("Vector port for connecting " "cpu side ports") master = DeprecatedParam(mem_side_ports, '`master` is now called `mem_side_ports`') ... # The default port can be left unconnected, or be used to connect # a default response port default = RequestPort("Port for connecting an optional default responder")
gem5的HMC部分
hmc位于src/mem部分。
HMC.py构建了一个完整的HMC设备,包含了valut controllers, serial links, main internal crossbar和一个external hmc controller。