This commit allows top level configs making use of the Ruby module to define node generation callbacks. The config_ruby function will check the system object for two factory methods 1) _rnf_gen, if defined, will be called to generate RNFs 2) _mn_gen, if defined, will be called to generate MNs Change-Id: I9daeece646e7cdb2d3bfefa761a9650562f8eb4b Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
258 lines
9.4 KiB
Python
258 lines
9.4 KiB
Python
# 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)
|