tests: Write unit-tests for ruby using the CHI-TLM library

This commit is adding two python files:

* ruby_mem_test.py is the canonical gem5 configuration script,
and it is an adaptation of the existing ruby_mem_test.py [1].
The main difference is the use of the TlmController as a
cache controller, and the use of TlmGenerator instead of
the MemTest memory tester. The config is minimally setting up
the system. The extent of the testing is specified in the second
python file:

* read_shared_unit.py: "unit-test" for the CHI ReadShared request
The file should be passed to the ruby_mem_test.py as cmdline
argument:

build/ARM/gem5.opt <>/ruby_mem_test.py <>/read_shared_unit.py

This is a simple testing file. We should ideally generate separate
test files for separate transactions/scenarios.
The test file can have whatever for inside, it only needs to comply
to the minimal interface required by the ruby_mem_test.py, which is
to define the following function:

def test_all(generator):

[1]: https://github.com/gem5/gem5/blob/stable/\
    configs/example/ruby_mem_test.py

Change-Id: I767ede9b8572f3eafe677c84da45fd904d77e319
Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
This commit is contained in:
Giacomo Travaglini
2024-08-06 13:09:55 +01:00
committed by Bobby R. Bruce
parent 706cb4195f
commit 44b8f5f422
2 changed files with 335 additions and 0 deletions

View File

@@ -0,0 +1,232 @@
# Copyright (c) 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.
#
# Copyright (c) 2006-2007 The Regents of The University of Michigan
# Copyright (c) 2009 Advanced Micro Devices, Inc.
# All rights reserved.
#
# 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 argparse
import importlib
import os
import sys
import m5
from m5.defines import buildEnv
from m5.objects import *
from m5.tlm_chi import *
from m5.util import addToPath
m5.util.addToPath(os.path.join(m5.util.repoPath(), "configs"))
from common import Options
from ruby import (
CHI,
Ruby,
)
from ruby.CHI_config import (
CHI_MN,
CHI_Node,
Versions,
)
class TLM_RNF(CHI_Node):
# The CHI controller can be a child of this object or another if
# 'parent' is specified
def __init__(self, ruby_system, parent):
super().__init__(ruby_system)
self._cntrl = TlmController(
version=Versions.getVersion(Cache_Controller),
ruby_system=ruby_system,
)
parent.chi_controller = self._cntrl
self.connectController(self._cntrl)
def getSequencers(self):
return []
def getAllControllers(self):
return [self._cntrl]
def getNetworkSideControllers(self):
return [self._cntrl]
def rnf_gen(options, ruby_system, cpus):
return [TLM_RNF(ruby_system, cpu) for cpu in system.cpu]
def mn_gen(options, ruby_system, cpus):
all_rnf_cntrls = []
for rnf in ruby_system.rnf:
all_rnf_cntrls.extend(rnf.getAllControllers())
return [CHI_MN(ruby_system, all_rnf_cntrls)]
def suite_importer(file_path):
"""
Used to import the suite file.
:param file_path: Path of the file to import
"""
module_name = os.path.basename(file_path)
spec = importlib.util.spec_from_file_location(module_name, file_path)
module = importlib.util.module_from_spec(spec)
sys.modules[module_name] = module
spec.loader.exec_module(module)
return module
def create_system(options, system):
system.ruby = RubySystem()
# Instantiate the network object
# so that the controllers can connect to it.
system.ruby.network = SimpleNetwork(
ruby_system=system.ruby,
topology=options.topology,
routers=[],
ext_links=[],
int_links=[],
netifs=[],
)
bootmem = None
dma_ports = []
(cpu_sequencers, dir_cntrls, topology) = CHI.create_system(
options, False, system, dma_ports, bootmem, system.ruby, system.cpu
)
# Create the network topology
topology.makeTopology(
options, system.ruby.network, SimpleIntLink, SimpleExtLink, Switch
)
system.ruby.network.setup_buffers()
# Create a port proxy for connecting the system port. This is
# independent of the protocol and kept in the protocol-agnostic
# part (i.e. here).
# Give the system port proxy a SimObject parent without creating a
# full-fledged controller
system.sys_port_proxy = RubyPortProxy(ruby_system=system.ruby)
# Connect the system port for loading of binaries etc
system.system_port = system.sys_port_proxy.in_ports
Ruby.setup_memory_controllers(system, system.ruby, dir_cntrls, options)
system.ruby.number_of_virtual_networks = (
system.ruby.network.number_of_virtual_networks
)
system.ruby._cpu_ports = cpu_sequencers
system.ruby.num_of_sequencers = len(cpu_sequencers)
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument(
"suite",
type=str,
help="Path to the suite file",
)
Options.addNoISAOptions(parser)
#
# Add the ruby specific and protocol specific options
#
Ruby.define_options(parser)
args = parser.parse_args()
#
# Configuring 4GiBs of SimpleMemory
#
args.mem_type = "SimpleMemory"
args.mem_size = "4GiB"
#
# Currently ruby does not support atomic or uncacheable accesses
#
cpus = [TlmGenerator(cpu_id=i) for i in range(args.num_cpus)]
for cpu in cpus:
suite = suite_importer(args.suite)
suite.test_all(cpu)
system = System(
cpu=cpus,
clk_domain=SrcClockDomain(clock=args.sys_clock),
mem_ranges=[AddrRange(args.mem_size)],
)
m5.util.addToPath("../common")
# Hooking up the RN-F generation callback
system._rnf_gen = rnf_gen
system._mn_gen = mn_gen
create_system(args, system)
# Create a top-level voltage domain and clock domain
system.voltage_domain = VoltageDomain(voltage=args.sys_voltage)
system.clk_domain = SrcClockDomain(
clock=args.sys_clock, voltage_domain=system.voltage_domain
)
# Create a seperate clock domain for Ruby
system.ruby.clk_domain = SrcClockDomain(
clock=args.ruby_clock, voltage_domain=system.voltage_domain
)
# To make unit-tests reproducible, we disable randomization
system.ruby.randomization = False
# -----------------------
# run simulation
# -----------------------
root = Root(full_system=False, system=system)
root.system.mem_mode = "timing"
# Not much point in this being higher than the L1 latency
m5.ticks.setGlobalFrequency("1ns")
# instantiate configuration
m5.instantiate()
# simulate until program terminates
exit_event = m5.simulate(args.abs_max_tick)
print("Exiting @ tick", m5.curTick(), "because", exit_event.getCause())

View File

@@ -0,0 +1,103 @@
# -*- mode:python -*-
# Copyright (c) 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.
from m5.tlm_chi import *
def payload_gen():
# Populating payload
payload = TlmPayload()
payload.address = 0x80000000
payload.ns = True
payload.size = Size.SIZE_64
return payload
def phase_gen():
# Populating phase
phase = TlmPhase()
phase.opcode = ReqOpcode.READ_SHARED
phase.src_id = 0
phase.tgt_id = 0
phase.exp_comp_ack = True
return phase
def channel_check(transaction):
return expect_equal(transaction.phase.channel, Channel.DAT)
def opcode_check(transaction):
return expect_equal(transaction.phase.opcode, DatOpcode.COMP_DATA)
def cacheline_check(transaction):
return expect_equal(transaction.phase.resp, Resp.RESP_UC)
def data_id_check_gen(exp):
def data_id_check(transaction):
return expect_equal(transaction.phase.data_id, exp)
return data_id_check
def wait_data(transaction):
return True
def do_comp_ack(transaction):
transaction.phase.channel = Channel.RSP
transaction.phase.opcode = RspOpcode.COMP_ACK
transaction.inject()
return False
def test_all(generator):
payload = payload_gen()
phase = phase_gen()
tran = generator.injectAt(10, payload, phase)
tran.EXPECT(channel_check)
tran.EXPECT(opcode_check)
tran.EXPECT(cacheline_check)
tran.EXPECT(data_id_check_gen(0))
tran.DO_WAIT(wait_data)
tran.EXPECT(channel_check)
tran.EXPECT(opcode_check)
tran.EXPECT(cacheline_check)
tran.EXPECT(data_id_check_gen(2))
tran.DO(do_comp_ack)