Files
gem5/configs/ruby/CHI.py
Giacomo Travaglini 76541929c9 configs: Instantiate RNFs and MN via callbacks
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>
2024-12-02 08:33:11 -08:00

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)