# Copyright (c) 2021, 2024 Arm Limited # All rights reserved. # # The license below extends only to copyright in the software and shall # not be construed as granting a license to any other intellectual # property including but not limited to intellectual property relating # to a hardware implementation of the functionality of the software # licensed hereunder. You may use the software subject to the license # terms below provided that you ensure that this notice is replicated # unmodified and in its entirety in all distributions of the software, # modified or unmodified, in source code or in binary form. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer; # redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution; # neither the name of the copyright holders nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import m5 from m5.defines import buildEnv from m5.objects import * from .Ruby import create_topology def define_options(parser): parser.add_argument( "--chi-config", action="store", type=str, default=None, help="NoC config. parameters and bindings. " "Required for CustomMesh topology", ) parser.add_argument("--enable-dvm", default=False, action="store_true") def read_config_file(file): """Read file as a module and return it""" import importlib.machinery import types loader = importlib.machinery.SourceFileLoader("chi_configs", file) chi_configs = types.ModuleType(loader.name) loader.exec_module(chi_configs) return chi_configs def create_system( options, full_system, system, dma_ports, bootmem, ruby_system, cpus ): if buildEnv["PROTOCOL"] != "CHI": m5.panic("This script requires the CHI build") if options.num_dirs < 1: m5.fatal("--num-dirs must be at least 1") if options.num_l3caches < 1: m5.fatal("--num-l3caches must be at least 1") if full_system and options.enable_dvm: if len(cpus) <= 1: m5.fatal("--enable-dvm can't be used with a single CPU") for cpu in cpus: for decoder in cpu.decoder: decoder.dvm_enabled = True # read specialized classes from config file if provided if options.chi_config: chi_defs = read_config_file(options.chi_config) elif options.topology == "CustomMesh": m5.fatal("--noc-config must be provided if topology is CustomMesh") else: # Use the defaults from CHI_config from . import CHI_config as chi_defs # NoC params params = chi_defs.NoC_Params # Node types CHI_RNF = chi_defs.CHI_RNF CHI_HNF = chi_defs.CHI_HNF CHI_MN = chi_defs.CHI_MN CHI_SNF_MainMem = chi_defs.CHI_SNF_MainMem CHI_SNF_BootMem = chi_defs.CHI_SNF_BootMem CHI_RNI_DMA = chi_defs.CHI_RNI_DMA CHI_RNI_IO = chi_defs.CHI_RNI_IO class HNFCache(RubyCache): dataAccessLatency = 10 tagAccessLatency = 2 size = options.l3_size assoc = options.l3_assoc # other functions use system.cache_line_size assuming it has been set assert system.cache_line_size.value == options.cacheline_size cpu_sequencers = [] mem_cntrls = [] mem_dests = [] network_nodes = [] network_cntrls = [] hnf_dests = [] all_cntrls = [] # Creates on RNF per cpu with priv l2 caches assert len(cpus) == options.num_cpus rnf_cb = getattr(system, "_rnf_gen", CHI_RNF.generate) # Generate the Request Nodes ruby_system.rnf = rnf_cb(options, ruby_system, cpus) for rnf in ruby_system.rnf: cpu_sequencers.extend(rnf.getSequencers()) all_cntrls.extend(rnf.getAllControllers()) network_nodes.append(rnf) network_cntrls.extend(rnf.getNetworkSideControllers()) mn_cb = getattr(system, "_mn_gen", CHI_MN.generate) # Generate the Misc Nodes ruby_system.mn = mn_cb(options, ruby_system, cpus) for mn in ruby_system.mn: all_cntrls.extend(mn.getAllControllers()) network_nodes.append(mn) network_cntrls.extend(mn.getNetworkSideControllers()) assert mn.getAllControllers() == mn.getNetworkSideControllers() # Look for other memories other_memories = [] if bootmem: other_memories.append(bootmem) if getattr(system, "sram", None): other_memories.append(getattr(system, "sram", None)) on_chip_mem_ports = getattr(system, "_on_chip_mem_ports", None) if on_chip_mem_ports: other_memories.extend([p.simobj for p in on_chip_mem_ports]) # Create the LLCs cntrls sysranges = [] + system.mem_ranges for m in other_memories: sysranges.append(m.range) hnf_list = [i for i in range(options.num_l3caches)] CHI_HNF.createAddrRanges(sysranges, system.cache_line_size.value, hnf_list) ruby_system.hnf = [ CHI_HNF(i, ruby_system, HNFCache, None) for i in range(options.num_l3caches) ] for hnf in ruby_system.hnf: network_nodes.append(hnf) network_cntrls.extend(hnf.getNetworkSideControllers()) assert hnf.getAllControllers() == hnf.getNetworkSideControllers() all_cntrls.extend(hnf.getAllControllers()) hnf_dests.extend(hnf.getAllControllers()) # Create the memory controllers # Notice we don't define a Directory_Controller type so we don't use # create_directories shared by other protocols. ruby_system.snf = [ CHI_SNF_MainMem(ruby_system, None, None) for i in range(options.num_dirs) ] for snf in ruby_system.snf: network_nodes.append(snf) network_cntrls.extend(snf.getNetworkSideControllers()) assert snf.getAllControllers() == snf.getNetworkSideControllers() mem_cntrls.extend(snf.getAllControllers()) all_cntrls.extend(snf.getAllControllers()) mem_dests.extend(snf.getAllControllers()) if len(other_memories) > 0: ruby_system.rom_snf = [ CHI_SNF_BootMem(ruby_system, None, m) for m in other_memories ] for snf in ruby_system.rom_snf: network_nodes.append(snf) network_cntrls.extend(snf.getNetworkSideControllers()) all_cntrls.extend(snf.getAllControllers()) mem_dests.extend(snf.getAllControllers()) # Creates the controller for dma ports and io if len(dma_ports) > 0: ruby_system.dma_rni = [ CHI_RNI_DMA(ruby_system, dma_port, None) for dma_port in dma_ports ] for rni in ruby_system.dma_rni: network_nodes.append(rni) network_cntrls.extend(rni.getNetworkSideControllers()) all_cntrls.extend(rni.getAllControllers()) if full_system: ruby_system.io_rni = CHI_RNI_IO(ruby_system, None) network_nodes.append(ruby_system.io_rni) network_cntrls.extend(ruby_system.io_rni.getNetworkSideControllers()) all_cntrls.extend(ruby_system.io_rni.getAllControllers()) # Assign downstream destinations for rnf in ruby_system.rnf: rnf.setDownstream(hnf_dests) if len(dma_ports) > 0: for rni in ruby_system.dma_rni: rni.setDownstream(hnf_dests) if full_system: ruby_system.io_rni.setDownstream(hnf_dests) for hnf in ruby_system.hnf: hnf.setDownstream(mem_dests) # Setup data message size for all controllers for cntrl in all_cntrls: cntrl.data_channel_size = params.data_width # Network configurations # virtual networks: 0=request, 1=snoop, 2=response, 3=data ruby_system.network.number_of_virtual_networks = 4 ruby_system.network.control_msg_size = params.cntrl_msg_size ruby_system.network.data_msg_size = params.data_width if options.network == "simple": ruby_system.network.buffer_size = params.router_buffer_size # Incorporate the params into options so it's propagated to # makeTopology and create_topology the parent scripts for k in dir(params): if not k.startswith("__"): setattr(options, k, getattr(params, k)) if options.topology == "CustomMesh": topology = create_topology(network_nodes, options) elif options.topology in ["Crossbar", "Pt2Pt"]: topology = create_topology(network_cntrls, options) else: m5.fatal(f"{options.topology} not supported!") return (cpu_sequencers, mem_cntrls, topology)