blob: 96537e558a3a13aae91d9491cde03ae95c99c3fe [file] [log] [blame]
# Copyright (c) 2021 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.objects import *
from m5.defines import buildEnv
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 types
import importlib.machinery
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
# Declare caches and controller types used by the protocol
# Notice tag and data accesses are not concurrent, so the a cache hit
# latency = tag + data + response latencies.
# Default response latencies are 1 cy for all controllers.
# For L1 controllers the mandatoryQueue enqueue latency is always 1 cy and
# this is deducted from the initial tag read latency for sequencer requests
# dataAccessLatency may be set to 0 if one wants to consider parallel
# data and tag lookups
class L1ICache(RubyCache):
dataAccessLatency = 1
tagAccessLatency = 1
size = options.l1i_size
assoc = options.l1i_assoc
class L1DCache(RubyCache):
dataAccessLatency = 2
tagAccessLatency = 1
size = options.l1d_size
assoc = options.l1d_assoc
class L2Cache(RubyCache):
dataAccessLatency = 6
tagAccessLatency = 2
size = options.l2_size
assoc = options.l2_assoc
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
ruby_system.rnf = [
CHI_RNF(
[cpu],
ruby_system,
L1ICache,
L1DCache,
system.cache_line_size.value,
)
for cpu in cpus
]
for rnf in ruby_system.rnf:
rnf.addPrivL2Cache(L2Cache)
cpu_sequencers.extend(rnf.getSequencers())
all_cntrls.extend(rnf.getAllControllers())
network_nodes.append(rnf)
network_cntrls.extend(rnf.getNetworkSideControllers())
# Creates one Misc Node
ruby_system.mn = [CHI_MN(ruby_system, [cpu.l1d for cpu in 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)