Creating a simple configuration script
This chapter of the tutorial will walk you through how to set up a
simple simulation script for gem5 and to run gem5 for the first time.
It’s assumed that you’ve followed the instructions for Lab G1 and
have downloaded a successfully built gem5 with an executable
build/ARM/gem5.opt
(which is what the ‘setup_vm’ script did).
Our configuration script is going to model a very simple system. We’ll have just one simple CPU core. This CPU core will be connected to a system-wide memory bus. And we’ll have a single DDR3 memory channel, also connected to the memory bus.
gem5 configuration scripts
The gem5 binary takes, as a parameter, a Python script which sets up and executes the simulation. In this script, you create a system to simulate, create all of the components of the system, and specify all of the parameters for the system components. Then, from the script, you can begin the simulation.
There are a number of example configuration scripts that ship with gem5
in configs/examples
.
The scripts most relevant to a beginner to gem5 are located in configs/examples/gem5-library
.
These are scripts that are intended to be used with the gem5 standard library,
which provides components that can be connected together to form a complete system.
An aside on SimObjects
gem5’s modular design is built around the SimObject type. Most of the components in the simulated system are SimObjects: CPUs, caches, memory controllers, buses, etc. gem5 exports all of these objects from their
C++
implementation to python. Thus, from the python configuration script you can create any SimObject, set its parameters, and specify the interactions between SimObjects.See SimObject details for more information.
What is the gem5 standard library?
The gem5 standard library provides a set of predefined components that can be used to define a system in a configuration script. Without the standard library, you would have to define every part of your simulation, potentially resulting in scripts with hundreds of lines of code even for the most basic of simulations.
Main Idea
Due to its modular, object-oriented design, gem5 can be thought of as a set of components that can be plugged together to form a simulation. The types of components are boards, processors, memory systems, and cache hierarchies:
- Board: The “backbone” of the system. You plug components into the board. The board also contains the system-level things like devices, workload, etc. It’s the boards job to negotiate the connections between other components.
- Processor: Processors connect to boards and have one or more cores.
- Cache hierarchy: A cache hierarchy is a set of caches that can be connected to a processor and memory system.
- Memory system: A memory system is a set of memory controllers and memory devices that can be connected to the cache hierarchy.
Relationship to gem5 models
The C++ code in gem5 specifies parameterized models (typically referred to “SimObjects” in most gem5 literature). These models are then instantiated in the pre-made Python scripts in the gem5 standard library.
The standard library is a way to wrap these models in a standard API into, what we call, components.
The gem5 models are fine grained concepts, while components are coarser grained and typically contain many models instantiated with sensible parameters. For example, a gem5 model could be a core, and a component could be a processor with multiple cores that also specifies bus connections and sets parameters to sensible vlaues.
If you want to create a new component you are encouraged to extend (i.e., subclass) the components in the standard library or create new components. This allows you to choose the models within the component and the value of their parameters.
Setting up a configuration script for gem5 v25.1
Let’s start by creating a new config file and opening it:
mkdir configs/tutorial/
mkdir configs/tutorial/part1/
touch configs/tutorial/part1/simple.py
This is just a normal python file that will be executed by the embedded python in the gem5 executable. Therefore, you can use any features and libraries available in python.
Open simple.py in your favorite Linux text editor. To set up a basic configuration script, we can start by adding our imports:
from gem5.components.boards.simple_board import SimpleBoard
from gem5.components.processors.cpu_types import CPUTypes
from gem5.components.processors.simple_processor import SimpleProcessor
from gem5.isas import ISA
from gem5.components.cachehierarchies.classic.private_l1_shared_l2_cache_hierarchy import (
PrivateL1SharedL2CacheHierarchy,
)
from gem5.components.memory import DualChannelDDR4_2400
from gem5.resources.resource import obtain_resource
from gem5.simulate.simulator import Simulator
from gem5.utils.requires import requires
Next, we add a check to ensure that the binary being executed uses the Arm ISA, since we are running an Arm CPU:
requires(isa_required=ISA.ARM)
We now have to define the basic parameters of our CPU. We want it to have the following properties:
- A 2 core processor using gem5’s
TIMING
model - A private L1, shared L2 cache hierarchy with 64 KiB data and instruction caches and a 8MiB L2 cache.
- 4GiB DualChannelDDR4_2400 memory
Let’s start by adding the CPU cores:
processor = SimpleProcessor(cpu_type=CPUTypes.TIMING, isa=ISA.ARM, num_cores=2)
The SimpleProcessor
is a component that allows you to customize the model for the underlying cores.
The cpu_type
parameter specifies the type of CPU model to use.
Moving onto adding our caches:
cache_hierarchy = PrivateL1SharedL2CacheHierarchy(l1d_size="64KiB", l1i_size="64KiB", l2_size="8MiB")
See here for more information about caches in gem5.
Finally, let’s add our DRAM:
memory = DualChannelDDR4_2400(size="4GiB")
This component represents a single-channel DDR4 memory system.
There is a size parameter that can be used to specify the size of the memory system of the simulated system. You can reduce the size to save simulation time, or use the default for the memory type (e.g., one channel of DDR3 defaults to 8 GiB). There are also multi channel memories available. You can see these gem5 2024 bootcamp slides for more information.
In gem5, we assemble these components together into a board. There are several different types of boards available, but we’ll use the SimpleBoard, which lets us run simple simulations such as the one we’re doing now:
board = SimpleBoard(
clk_freq="3GHz",
processor=processor,
memory=memory,
cache_hierarchy=cache_hierarchy,
)
The SimpleBoard can run any ISA in Syscall Emulation (SE) mode.
It is “Simple” due the relative simplicity of SE mode.
Most boards are tied to a specific ISA and require more complex designs to run Full System (FS) simulation.
You can find the boards in the gem5 standard library at src/python/gem5/components/boards
. The demo boards are located in src/python/gem5/prebuilt/demo
.
Next, let’s set a workload to run on the board:
board.set_se_binary_workload(
obtain_resource("arm-hello64-static")
)
The function obtain_resource
downloads workloads and resources.
For the arm-hello64-static
, it downloads a small Hello World binary, and sets default parameters.
Finally, for the last lines of the configuration, we need to add Python code that tells the simulator to run the binary on the board and print out a message when it completes:
simulator = Simulator(board=board)
simulator.run()
print(
"Exiting @ tick {} because {}.".format(
simulator.get_current_tick(), simulator.get_last_exit_event_cause()
)
)
To run the simulation after setting up the configuration script, use the following command:
./build/ARM/gem5.opt configs/tutorial/part1/simple.py
The output should look something like this:
gem5 Simulator System. https://www.gem5.org
gem5 is copyrighted software; use the --copyright option for details.
gem5 version 25.0.0.1
gem5 compiled Sep 13 2025 13:46:50
gem5 started Sep 14 2025 06:18:55
gem5 executing on fa25-cs433-xxx.cs.illinois.edu, pid 401364
command line: ./build/ARM/gem5.opt configs/tutorial/part1/simple.py
info: Using default config
warn: Resource arm-hello64-static is not compatible with gem5 version 25.0.0.1.
warn: Resource arm-hello64-static is not compatible with gem5 version 25.0.0.1.
warn: Resource arm-hello64-static is not compatible with gem5 version 25.0.0.1.
Global frequency set at 1000000000000 ticks per second
src/mem/dram_interface.cc:690: warn: DRAM device capacity (16384 Mbytes) does not match the address range assigned (2048 Mbytes)
src/mem/dram_interface.cc:690: warn: DRAM device capacity (16384 Mbytes) does not match the address range assigned (2048 Mbytes)
src/base/statistics.hh:279: warn: One of the stats is a legacy stat. Legacy stat is a stat that does not belong to any statistics::Group. Legacy stat is deprecated.
board.remote_gdb: Listening for connections on port 7000
src/sim/mem_state.cc:443: info: Increasing stack size by one page.
src/sim/syscall_emul.hh:1121: warn: readlink() called on '/proc/self/exe' may yield unexpected results in various settings.
Returning '/home/ghose/.cache/gem5/arm-hello64-static'
Hello world!
Exiting @ tick 23779197 because exiting with last active thread context.
An aside on gem5 ports
To connect memory system components together, gem5 uses a port abstraction. Each memory object can have two kinds of ports, request ports and response ports. Requests are sent from a request port to a response port, and responses are sent from a response port to a request port. When connecting ports, you must connect a request port to a response port.
Connecting ports together is easy to do from the python configuration files. You can simply set the request port
=
to the response port and they will be connected. For instance:system.cpu.icache_port = system.l1_cache.cpu_side
In this example, the cpu’s
icache_port
is a request port, and the cache’scpu_side
is a response port. The request port and the response port can be on either side of the=
and the same connection will be made. After making the connection, the requestor can send requests to the responder. There is a lot of magic going on behind the scenes to set up the connection, the details of which are unimportant to most users.Another notable kind of magic of the
=
of two ports in a gem5 Python configuration is that, it is allowed to have one port on one side, and an array of ports on the other side. For example:system.cpu.icache_port = system.membus.cpu_side_ports
In this example, the cpu’s
icache_port
is a request port, and the membus’scpu_side_ports
is an array of response ports. In this case, a new response port is spawned on thecpu_side_ports
, and this newly created port will be connected to the request port.We will discuss ports and MemObject in more detail in the MemObject chapter.
Next, we will add caches to our configuration file to model a more complex system.