def _setup_memory_ranges(self): memory = self.get_memory() if memory.get_size() > toMemorySize("3GB"): raise Exception("X86Board currently only supports memory sizes up " "to 3GB because of the I/O hole.") data_range = AddrRange(memory.get_size()) memory.set_memory_range([data_range]) # Add the address range for the IO self.mem_ranges = [ data_range, # All data AddrRange(0xC0000000, size=0x100000), # For I/0 ]
def config_hybrid_mem(options, system): """ Assign proper address ranges for DRAM and NVM controllers. Create memory controllers and add their shared bus to the system. """ system.thnvm_bus = VirtualXBar() mem_ctrls = [] # The default behaviour is to interleave memory channels on 128 # byte granularity, or cache line granularity if larger than 128 # byte. This value is based on the locality seen across a large # range of workloads. intlv_size = max(128, system.cache_line_size.value) total_size = Addr(options.mem_size) dram_size = pow(2, options.page_bits) * options.ptt_length if dram_size < total_size.value: nvm_cls = MemConfig.get(options.nvm_type) nvm_range = AddrRange(0, total_size - dram_size - 1) nvm_ctrl = MemConfig.create_mem_ctrl(nvm_cls, nvm_range, 0, 1, 0, intlv_size) # Set the number of ranks based on the command-line # options if it was explicitly set if issubclass(nvm_cls, DRAMCtrl) and options.mem_ranks: nvm_ctrl.ranks_per_channel = options.mem_ranks mem_ctrls.append(nvm_ctrl) if dram_size > 0: dram_cls = MemConfig.get(options.dram_type) dram_range = AddrRange(total_size - dram_size, total_size - 1) dram_ctrl = MemConfig.create_mem_ctrl(dram_cls, dram_range, 0, 1, 0, intlv_size) # Set the number of ranks based on the command-line # options if it was explicitly set if issubclass(dram_cls, DRAMCtrl) and options.mem_ranks: dram_ctrl.ranks_per_channel = options.mem_ranks mem_ctrls.append(dram_ctrl) system.mem_ctrls = mem_ctrls # Connect the controllers to the THNVM bus for i in xrange(len(system.mem_ctrls)): system.mem_ctrls[i].port = system.thnvm_bus.master system.thnvm_bus.slave = system.membus.master
def _interleave_addresses(self): if self._addr_mapping == "RoRaBaChCo": rowbuffer_size = ( self._dram_class.device_rowbuffer_size.value * self._dram_class.devices_per_rank.value ) intlv_low_bit = log(rowbuffer_size, 2) elif self._addr_mapping in ["RoRaBaCoCh", "RoCoRaBaCh"]: intlv_low_bit = log(self._intlv_size, 2) else: raise ValueError( "Only these address mappings are supported: " "RoRaBaChCo, RoRaBaCoCh, RoCoRaBaCh" ) intlv_bits = log(self._num_channels, 2) for i, ctrl in enumerate(self.mem_ctrl): ctrl.dram.range = AddrRange( start=self._mem_range.start, size=self._mem_range.size(), intlvHighBit=intlv_low_bit + intlv_bits - 1, xorHighBit=0, intlvBits=intlv_bits, intlvMatch=i, )
def _setup_memory_ranges(self) -> None: memory = self.get_memory() # The simple board just has one memory range that is the size of the # memory. self.mem_ranges = [AddrRange(memory.get_size())] memory.set_memory_range(self.mem_ranges)
def _setup_pma(self) -> None: """Set the PMA devices on each core""" uncacheable_range = [ AddrRange(dev.pio_addr, size=dev.pio_size) for dev in self._on_chip_devices + self._off_chip_devices ] # TODO: Not sure if this should be done per-core like in the example for cpu in self.get_processor().get_cores(): cpu.get_mmu().pma_checker = PMAChecker( uncacheable=uncacheable_range)
def __init__(self, mem_type: str, size: Optional[str]): """ :param mem_name: The name of the type of memory to be configured. :param num_chnls: The number of channels. """ super(SingleChannel, self).__init__() self.mem_ctrl = DRAMSim3MemCtrl(mem_type, 1) if size: self.mem_ctrl.range = AddrRange(size) else: raise NotImplementedError( "DRAMSim3 memory controller requires a size parameter.")
def create_home_agent(phys_ranges): from m5.util import convert from m5.objects import AddrRange, HomeAgent mem_ranges = [] next_base = convert.toMemorySize('0') assert (valid_size_of(phys_ranges) > 0) for rg in phys_ranges: mem_ranges.append(AddrRange(next_base, size=rg.size())) next_base = next_base + rg.size() assert (valid_size_of(phys_ranges) == valid_size_of(mem_ranges)) return HomeAgent(phys_ranges=phys_ranges, mem_ranges=mem_ranges)
def create_addr_alignment_mapper(addr_base, original_ranges): from m5.util import convert from m5.objects import AddrRange, CowardAddrMapper remapped_ranges = [] next_base = addr_base assert (valid_size_of(original_ranges) > 0) for rg in original_ranges: remapped_ranges.append(AddrRange(next_base, size=rg.size())) next_base = next_base + rg.size() assert (valid_size_of(original_ranges) == valid_size_of(remapped_ranges)) return CowardAddrMapper(original_ranges = original_ranges, \ remapped_ranges = remapped_ranges)
def config_mem(options, system): """ Create the memory controllers based on the options and attach them. If requested, we make a multi-channel configuration of the selected memory controller class by creating multiple instances of the specific class. The individual controllers have their parameters set such that the address range is interleaved between them. """ nbr_mem_ctrls = options.mem_channels import math from m5.util import fatal intlv_bits = int(math.log(nbr_mem_ctrls, 2)) if 2**intlv_bits != nbr_mem_ctrls: fatal("Number of memory channels must be a power of 2") cls = get(options.mem_type) mem_ctrls = [] #### For every range (most systems will only have one), create an #### array of controllers and set their parameters to match their #### address mapping in the case of a DRAM ###for r in system.mem_ranges: ### for i in xrange(nbr_mem_ctrls): ### mem_ctrls.append(create_mem_ctrl(cls, r, i, nbr_mem_ctrls, ### intlv_bits, ### system.cache_line_size.value)) ### ###system.mem_ctrls = mem_ctrls #### Connect the controllers to the membus ###for i in xrange(len(system.mem_ctrls)): ### system.mem_ctrls[i].port = system.membus.memory_port from m5.objects import AddrRange from m5.util import convert mem_size = convert.toMemorySize( options.mem_size) + convert.toMemorySize('1GB') mem_ctrls.append( create_mem_ctrl(cls, AddrRange(0, size=mem_size), 0, 1, intlv_bits, system.cache_line_size.value)) #system.mem_ctrls = mem_ctrls #system.mem_ctrls[0].port = system.membus.memory_port from m5.objects import PARDMemoryCtrl system.mem_ctrl = PARDMemoryCtrl(memories=mem_ctrls[0]) system.mem_ctrl.port = system.membus.memory_port system.mem_ctrl.attachDRAM()
def _setup_io_devices(self) -> None: """Connect the I/O devices to the I/O bus""" for device in self._off_chip_devices: device.pio = self.iobus.mem_side_ports self.lupio_blk.dma = self.iobus.cpu_side_ports for device in self._on_chip_devices: device.pio = self.get_cache_hierarchy().get_mem_side_port() self.bridge = Bridge(delay="10ns") self.bridge.mem_side_port = self.iobus.cpu_side_ports self.bridge.cpu_side_port = ( self.get_cache_hierarchy().get_mem_side_port()) self.bridge.ranges = [ AddrRange(dev.pio_addr, size=dev.pio_size) for dev in self._off_chip_devices ]
def __init__( self, dram_interface_class: Type[DRAMInterface], size: Optional[str] = None, ): """ :param dram_interface_class: The DRAM interface type to create with this memory controller :param size: Optionally specify the size of the DRAM controller's address space. By default, it starts at 0 and ends at the size of the DRAM device specified """ super().__init__() self._dram = dram_interface_class() if size: self._dram.range = size else: self._dram.range = AddrRange(self.get_size(self._dram)) self.mem_ctrl = MemCtrl(dram=self._dram)
def create_mem_subsystem(options, system, intlv_size, disable_kvm_map): import math from m5.util import fatal, convert from m5.objects import Addr, AddrRange from m5.objects import FlexMem, HybridMem, PortForwarder, SimpleMemory if options.mem_type != "MemSubsystem": fatal("options.mem_type != 'MemSubsystem'") if getattr(options, "tlm_memory", None): fatal("tlm_memory") if getattr(options, "external_memory_system", None): fatal("external_memory_system") if getattr(options, "elastic_trace_en", False): fatal("elastic_trace_en") if options.mem_channels != 1: fatal("options.mem_channels != 1") if options.num_dirs != 1: fatal("options.num_dirs != 1") if getattr(options, "mem_ranks", None): fatal("mem_ranks") split_char = ';' channel_forwarder = PortForwarder() channel_ranges = [] channel_sizes = options.channel_sizes.split(split_char) channel_types = options.channel_types.split(split_char) to_channel_addr = [] mem_ctrls = [] phys_data = [] mem_space_size = convert.toMemorySize('0') assert (valid_size_of(channel_sizes) > 0) for sz in [convert.toMemorySize(x) for x in channel_sizes]: channel_ranges.append(AddrRange(mem_space_size, size=sz)) mem_space_size = mem_space_size + sz assert (mem_space_size >= (sum(rg.size() for rg in system.mem_ranges))) assert (valid_size_of(channel_types) > 0) for tp in channel_types: assert (issubclass(get(tp), m5.objects.DRAMCtrl)) assert (tp != "HMC_2500_1x32") assert (valid_size_of(channel_types) == valid_size_of(channel_ranges)) assert (valid_size_of(channel_ranges) > 0) for idx in range(len(channel_ranges)): mapper = create_addr_alignment_mapper( \ convert.toMemorySize('0'), [channel_ranges[idx]]) assert (valid_size_of(mapper.remapped_ranges) == 1) mem_ctrl = create_mem_ctrl(get(channel_types[idx]), \ mapper.remapped_ranges[0], 0, 1, 0, intlv_size) mem_ctrl.in_addr_map = False mem_ctrl.kvm_map = False channel_forwarder.master = mapper.slave mapper.master = mem_ctrl.port to_channel_addr.append(mapper) mem_ctrls.append(mem_ctrl) assert (valid_size_of(system.mem_ranges) > 0) for rg in system.mem_ranges: data = SimpleMemory(range=rg) if disable_kvm_map: data.kvm_map = False phys_data.append(data) home_agent = create_home_agent(system.mem_ranges) if convert.toMemorySize(options.channel_intlv_size) == 0: hybrid_mem = HybridMem(phys_ranges = home_agent.phys_ranges, \ mem_ranges = home_agent.mem_ranges, \ channel_ranges = channel_ranges) home_agent.master = hybrid_mem.slave hybrid_mem.master = channel_forwarder.slave system.hybrid_mem = hybrid_mem elif convert.toMemorySize(options.channel_intlv_size) > 0: flex_mem = FlexMem(mem_ranges = home_agent.mem_ranges, \ channel_ranges = channel_ranges, \ intlv_size = options.channel_intlv_size) home_agent.master = flex_mem.slave flex_mem.master = channel_forwarder.slave system.flex_mem = flex_mem else: fatal("impossible") system.mem_subsystem = home_agent system.channel_forwarder = channel_forwarder system.to_channel_addr = to_channel_addr system.mem_ctrls = mem_ctrls system.phys_data = phys_data system.mmap_using_noreserve = True return system.mem_subsystem
def _setup_io_devices(self): """ Sets up the x86 IO devices. Note: This is mostly copy-paste from prior X86 FS setups. Some of it may not be documented and there may be bugs. """ # Constants similar to x86_traits.hh IO_address_space_base = 0x8000000000000000 pci_config_address_space_base = 0xC000000000000000 interrupts_address_space_base = 0xA000000000000000 APIC_range_size = 1 << 12 # Setup memory system specific settings. if self.get_cache_hierarchy().is_ruby(): self.pc.attachIO(self.get_io_bus(), [self.pc.south_bridge.ide.dma]) else: self.bridge = Bridge(delay="50ns") self.bridge.mem_side_port = self.get_io_bus().cpu_side_ports self.bridge.cpu_side_port = ( self.get_cache_hierarchy().get_mem_side_port()) # # Constants similar to x86_traits.hh IO_address_space_base = 0x8000000000000000 pci_config_address_space_base = 0xC000000000000000 interrupts_address_space_base = 0xA000000000000000 APIC_range_size = 1 << 12 self.bridge.ranges = [ AddrRange(0xC0000000, 0xFFFF0000), AddrRange(IO_address_space_base, interrupts_address_space_base - 1), AddrRange(pci_config_address_space_base, Addr.max), ] self.apicbridge = Bridge(delay="50ns") self.apicbridge.cpu_side_port = self.get_io_bus().mem_side_ports self.apicbridge.mem_side_port = ( self.get_cache_hierarchy().get_cpu_side_port()) self.apicbridge.ranges = [ AddrRange( interrupts_address_space_base, interrupts_address_space_base + self.get_processor().get_num_cores() * APIC_range_size - 1, ) ] self.pc.attachIO(self.get_io_bus()) # Add in a Bios information structure. self.workload.smbios_table.structures = [X86SMBiosBiosInformation()] # Set up the Intel MP table base_entries = [] ext_entries = [] for i in range(self.get_processor().get_num_cores()): bp = X86IntelMPProcessor( local_apic_id=i, local_apic_version=0x14, enable=True, bootstrap=(i == 0), ) base_entries.append(bp) io_apic = X86IntelMPIOAPIC( id=self.get_processor().get_num_cores(), version=0x11, enable=True, address=0xFEC00000, ) self.pc.south_bridge.io_apic.apic_id = io_apic.id base_entries.append(io_apic) pci_bus = X86IntelMPBus(bus_id=0, bus_type="PCI ") base_entries.append(pci_bus) isa_bus = X86IntelMPBus(bus_id=1, bus_type="ISA ") base_entries.append(isa_bus) connect_busses = X86IntelMPBusHierarchy(bus_id=1, subtractive_decode=True, parent_bus=0) ext_entries.append(connect_busses) pci_dev4_inta = X86IntelMPIOIntAssignment( interrupt_type="INT", polarity="ConformPolarity", trigger="ConformTrigger", source_bus_id=0, source_bus_irq=0 + (4 << 2), dest_io_apic_id=io_apic.id, dest_io_apic_intin=16, ) base_entries.append(pci_dev4_inta) def assignISAInt(irq, apicPin): assign_8259_to_apic = X86IntelMPIOIntAssignment( interrupt_type="ExtInt", polarity="ConformPolarity", trigger="ConformTrigger", source_bus_id=1, source_bus_irq=irq, dest_io_apic_id=io_apic.id, dest_io_apic_intin=0, ) base_entries.append(assign_8259_to_apic) assign_to_apic = X86IntelMPIOIntAssignment( interrupt_type="INT", polarity="ConformPolarity", trigger="ConformTrigger", source_bus_id=1, source_bus_irq=irq, dest_io_apic_id=io_apic.id, dest_io_apic_intin=apicPin, ) base_entries.append(assign_to_apic) assignISAInt(0, 2) assignISAInt(1, 1) for i in range(3, 15): assignISAInt(i, i) self.workload.intel_mp_table.base_entries = base_entries self.workload.intel_mp_table.ext_entries = ext_entries 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=f"{self.mem_ranges[0].size() - 0x100000:d}B", range_type=1, ), ] # Reserve the last 16kB of the 32-bit address space for m5ops entries.append(X86E820Entry(addr=0xFFFF0000, size="64kB", range_type=2)) self.workload.e820_table.entries = entries
def setMemoryMode(self, mode): self.mem_mode = 'timing' self.mem_ranges = [AddrRange('512MB')]
def _setup_memory_ranges(self): memory = self.get_memory() mem_size = memory.get_size() self.mem_ranges = [AddrRange(start=0x80000000, size=mem_size)] memory.set_memory_range(self.mem_ranges)
def __init__( self, clk_freq: str, processor: AbstractProcessor, memory: AbstractMemorySystem, cache_hierarchy: AbstractCacheHierarchy, exit_on_work_items: bool = False, ) -> None: super(X86Board, self).__init__( clk_freq=clk_freq, processor=processor, memory=memory, cache_hierarchy=cache_hierarchy, exit_on_work_items=exit_on_work_items, ) if get_runtime_isa() != ISA.X86: raise EnvironmentError( "X86Motherboard will only work with the X86 ISA." ) # Add the address range for the IO # TODO: This should definitely NOT be hardcoded to 3GB self.mem_ranges = [ AddrRange(Addr("3GB")), # All data AddrRange(0xC0000000, size=0x100000), # For I/0 ] self.pc = Pc() self.workload = X86FsLinux() # Constants similar to x86_traits.hh IO_address_space_base = 0x8000000000000000 pci_config_address_space_base = 0xC000000000000000 interrupts_address_space_base = 0xA000000000000000 APIC_range_size = 1 << 12 # North Bridge self.iobus = IOXBar() # Setup memory system specific settings. if self.get_cache_hierarchy().is_ruby(): self.pc.attachIO(self.get_io_bus(), [self.pc.south_bridge.ide.dma]) else: self.bridge = Bridge(delay="50ns") self.bridge.mem_side_port = self.get_io_bus().cpu_side_ports self.bridge.cpu_side_port = ( self.get_cache_hierarchy().get_mem_side_port() ) # # Constants similar to x86_traits.hh IO_address_space_base = 0x8000000000000000 pci_config_address_space_base = 0xC000000000000000 interrupts_address_space_base = 0xA000000000000000 APIC_range_size = 1 << 12 self.bridge.ranges = [ AddrRange(0xC0000000, 0xFFFF0000), AddrRange( IO_address_space_base, interrupts_address_space_base - 1 ), AddrRange(pci_config_address_space_base, Addr.max), ] self.apicbridge = Bridge(delay="50ns") self.apicbridge.cpu_side_port = self.get_io_bus().mem_side_ports self.apicbridge.mem_side_port = ( self.get_cache_hierarchy().get_cpu_side_port() ) self.apicbridge.ranges = [ AddrRange( interrupts_address_space_base, interrupts_address_space_base + self.get_processor().get_num_cores() * APIC_range_size - 1, ) ] self.pc.attachIO(self.get_io_bus()) self.iocache = Cache( assoc=8, tag_latency=50, data_latency=50, response_latency=50, mshrs=20, size="1kB", tgts_per_mshr=12, addr_ranges=self.mem_ranges, ) self.iocache.cpu_side = self.get_io_bus().mem_side_ports self.iocache.mem_side = ( self.get_cache_hierarchy().get_cpu_side_port() ) # Add in a Bios information structure. self.workload.smbios_table.structures = [X86SMBiosBiosInformation()] # Set up the Intel MP table base_entries = [] ext_entries = [] for i in range(self.get_processor().get_num_cores()): bp = X86IntelMPProcessor( local_apic_id=i, local_apic_version=0x14, enable=True, bootstrap=(i == 0), ) base_entries.append(bp) io_apic = X86IntelMPIOAPIC( id=self.get_processor().get_num_cores(), version=0x11, enable=True, address=0xFEC00000, ) self.pc.south_bridge.io_apic.apic_id = io_apic.id base_entries.append(io_apic) pci_bus = X86IntelMPBus(bus_id=0, bus_type="PCI ") base_entries.append(pci_bus) isa_bus = X86IntelMPBus(bus_id=1, bus_type="ISA ") base_entries.append(isa_bus) connect_busses = X86IntelMPBusHierarchy( bus_id=1, subtractive_decode=True, parent_bus=0 ) ext_entries.append(connect_busses) pci_dev4_inta = X86IntelMPIOIntAssignment( interrupt_type="INT", polarity="ConformPolarity", trigger="ConformTrigger", source_bus_id=0, source_bus_irq=0 + (4 << 2), dest_io_apic_id=io_apic.id, dest_io_apic_intin=16, ) base_entries.append(pci_dev4_inta) def assignISAInt(irq, apicPin): assign_8259_to_apic = X86IntelMPIOIntAssignment( interrupt_type="ExtInt", polarity="ConformPolarity", trigger="ConformTrigger", source_bus_id=1, source_bus_irq=irq, dest_io_apic_id=io_apic.id, dest_io_apic_intin=0, ) base_entries.append(assign_8259_to_apic) assign_to_apic = X86IntelMPIOIntAssignment( interrupt_type="INT", polarity="ConformPolarity", trigger="ConformTrigger", source_bus_id=1, source_bus_irq=irq, dest_io_apic_id=io_apic.id, dest_io_apic_intin=apicPin, ) base_entries.append(assign_to_apic) assignISAInt(0, 2) assignISAInt(1, 1) for i in range(3, 15): assignISAInt(i, i) self.workload.intel_mp_table.base_entries = base_entries self.workload.intel_mp_table.ext_entries = ext_entries 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=f"{self.mem_ranges[0].size() - 0x100000:d}B", range_type=1, ), ] # Reserve the last 16kB of the 32-bit address space for m5ops entries.append( X86E820Entry(addr=0xFFFF0000, size="64kB", range_type=2) ) self.workload.e820_table.entries = entries
def config_mem(options, system): """ Create the memory controllers based on the options and attach them. If requested, we make a multi-channel configuration of the selected memory controller class by creating multiple instances of the specific class. The individual controllers have their parameters set such that the address range is interleaved between them. """ nbr_mem_ctrls = options.mem_channels import math from m5.util import fatal intlv_bits = int(math.log(nbr_mem_ctrls, 2)) if 2**intlv_bits != nbr_mem_ctrls: fatal("Number of memory channels must be a power of 2") cls = get(options.mem_type) mem_ctrls = [] # The default behaviour is to interleave on cache line granularity cache_line_bit = int(math.log(system.cache_line_size.value, 2)) - 1 intlv_low_bit = cache_line_bit # For every range (most systems will only have one), create an # array of controllers and set their parameters to match their # address mapping in the case of a DRAM for r in system.mem_ranges: for i in xrange(nbr_mem_ctrls): # Create an instance so we can figure out the address # mapping and row-buffer size ctrl = cls() # Only do this for DRAMs if issubclass(cls, m5.objects.DRAMCtrl): # Inform each controller how many channels to account # for ctrl.channels = nbr_mem_ctrls # If the channel bits are appearing after the column # bits, we need to add the appropriate number of bits # for the row buffer size if ctrl.addr_mapping.value == 'RoRaBaChCo': # This computation only really needs to happen # once, but as we rely on having an instance we # end up having to repeat it for each and every # one rowbuffer_size = ctrl.device_rowbuffer_size.value * \ ctrl.devices_per_rank.value intlv_low_bit = int(math.log(rowbuffer_size, 2)) - 1 # We got all we need to configure the appropriate address # range ctrl.range = m5.objects.AddrRange(r.start, size = r.size(), intlvHighBit = \ intlv_low_bit + intlv_bits, intlvBits = intlv_bits, intlvMatch = i) mem_ctrls.append(ctrl) system.mem_ctrls = mem_ctrls ### Connect the controllers to the membus ##for i in xrange(len(system.mem_ctrls)): ## system.mem_ctrls[i].port = system.membus.master from m5.objects import NoncoherentBus, Bridge, AddrRange system.dram_internal_bus = NoncoherentBus() system.dram_internal_bridge = Bridge(ranges=[AddrRange('2GB')]) system.membus.master = system.dram_internal_bridge.slave system.dram_internal_bridge.master = system.dram_internal_bus.slave # Connect the controllers to the membus for i in xrange(len(system.mem_ctrls)): system.mem_ctrls[i].port = system.dram_internal_bus.master