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:
committed by
Bobby R. Bruce
parent
706cb4195f
commit
44b8f5f422
232
tests/gem5/chi_tlm_tests/configs/ruby_mem_test.py
Normal file
232
tests/gem5/chi_tlm_tests/configs/ruby_mem_test.py
Normal 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())
|
||||
103
tests/gem5/chi_tlm_tests/configs/suites/read_shared_unit.py
Normal file
103
tests/gem5/chi_tlm_tests/configs/suites/read_shared_unit.py
Normal 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)
|
||||
Reference in New Issue
Block a user