# Copyright (c) 2016-2017, 2022-2023 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 argparse import os import shlex import m5 from m5.objects import * from m5.util import addToPath m5.util.addToPath("../..") import devices from common import ObjectList def get_processes(cmd): """Interprets commands to run and returns a list of processes""" cwd = os.getcwd() multiprocesses = [] for idx, c in enumerate(cmd): argv = shlex.split(c) process = Process(pid=100 + idx, cwd=cwd, cmd=argv, executable=argv[0]) process.gid = os.getgid() print("info: %d. command and arguments: %s" % (idx + 1, process.cmd)) multiprocesses.append(process) return multiprocesses def create(args): """Create and configure the system object.""" system = devices.SimpleSeSystem( mem_mode="timing", ) # Add CPUs to the system. A cluster of CPUs typically have # private L1 caches and a shared L2 cache. system.cpu_cluster = devices.ArmCpuCluster( system, args.num_cores, args.cpu_freq, "1.2V", ObjectList.cpu_list.get("O3_ARM_v7a_3_Etrace"), devices.L1I, devices.L1D, devices.L2, ) # Attach the elastic trace probe listener to every CPU in the cluster for cpu in system.cpu_cluster: cpu.attach_probe_listener(args.inst_trace_file, args.data_trace_file) # As elastic trace generation is enabled, make sure the memory system is # minimal so that compute delays do not include memory access latencies. # Configure the compulsory L1 caches for the O3CPU, do not configure # any more caches. system.addCaches(True, last_cache_level=1) # For elastic trace, over-riding Simple Memory latency to 1ns." system.memory = SimpleMemory( range=AddrRange(start=0, size=args.mem_size), latency="1ns", port=system.membus.mem_side_ports, ) # Parse the command line and get a list of Processes instances # that we can pass to gem5. processes = get_processes(args.commands_to_run) if len(processes) != args.num_cores: print( "Error: Cannot map %d command(s) onto %d CPU(s)" % (len(processes), args.num_cores) ) sys.exit(1) system.workload = SEWorkload.init_compatible(processes[0].executable) # Assign one workload to each CPU for cpu, workload in zip(system.cpu_cluster.cpus, processes): cpu.workload = workload return system def main(): parser = argparse.ArgumentParser(epilog=__doc__) parser.add_argument( "commands_to_run", metavar="command(s)", nargs="+", help="Command(s) to run", ) parser.add_argument( "--inst-trace-file", action="store", type=str, help="""Instruction fetch trace file input to Elastic Trace probe in a capture simulation and Trace CPU in a replay simulation""", default="fetchtrace.proto.gz", ) parser.add_argument( "--data-trace-file", action="store", type=str, help="""Data dependency trace file input to Elastic Trace probe in a capture simulation and Trace CPU in a replay simulation""", default="deptrace.proto.gz", ) parser.add_argument("--cpu-freq", type=str, default="4GHz") parser.add_argument( "--num-cores", type=int, default=1, help="Number of CPU cores" ) parser.add_argument( "--mem-size", action="store", type=str, default="2GiB", help="Specify the physical memory size", ) args = parser.parse_args() # Create a single root node for gem5's object hierarchy. There can # only exist one root node in the simulator at any given # time. Tell gem5 that we want to use syscall emulation mode # instead of full system mode. root = Root(full_system=False) # Populate the root node with a system. A system corresponds to a # single node with shared memory. root.system = create(args) # Instantiate the C++ object hierarchy. After this point, # SimObjects can't be instantiated anymore. m5.instantiate() # Start the simulator. This gives control to the C++ world and # starts the simulator. The returned event tells the simulation # script why the simulator exited. event = m5.simulate() # Print the reason for the simulation exit. Some exit codes are # requests for service (e.g., checkpoints) from the simulation # script. We'll just ignore them here and exit. print(f"{event.getCause()} ({event.getCode()}) @ {m5.curTick()}") if __name__ == "__m5_main__": main()