Skip to main content

Process Creation

Now that we have a fully functional processor, we can set up the binary that we want to run.

First, lets just grab the hello_world binary gem5 provides in their tests directory.

default_binary = os.path.join(
os.environ['GEM_TESTS'],
"test-progs/hello/bin/riscv/linux/hello",
)

Initializing the Binary

gem5 uses a process abstraction to run processes on your cpu, so we can initialize the process as required.

process = Process()
process.cmd = [binary]
system.cpu.workload = process
system.cpu.createThreads() # you _could_ multithread things

Enter the Matrix

Morpheus from the Matrix

Now we can start our simulation by instantiating the gem5 system.

# Instantiate the system with gem5
root = Root(full_system = False, system = system)
m5.instantiate()

Finally, we can hit play.

print("Beginning simulation!")
exit_event = m5.simulate()

# And once simulation finishes, we can inspect the state of the system.
print('Exiting @ tick {} because {}'
.format(m5.curTick(), exit_event.getCause()))

Congrats, you now have a working processor.

The Completed Code

#### IMPORTS ####
# import the m5 (gem5) library created when gem5 is built
import m5
import os
import sys

# import all of the SimObjects
from m5.objects import *
from m5.util import fatal

#### CONSTANTS ####
try:
os.environ['GEM_TESTS']
os.environ['GEM_PATH']
os.environ['GEM_CONFIGS']
except e:
fatal("This script requires the GEM_TESTS, GEM_PATH and GEM_CONFIGS environment variables")

# Add the common scripts to our path
# m5.util.addToPath(os.environ['GEM_CONFIGS'])
sys.path.append(os.environ['GEM_CONFIGS'])

# import the SimpleOpts module
from common import SimpleOpts
from common import Options

# Default to running 'hello', use the compiled ISA to find the binary
# grab the specific path to the binary
thispath = os.path.dirname(os.path.realpath(__file__))
default_binary = os.path.join(
os.environ['GEM_TESTS'],
"test-progs/hello/bin/riscv/linux/hello",
)

# Creaing a simple system
system = System() # YAAAAAAAAAAAY

# We can now reference the system and change some parameters
system.clk_domain = SrcClockDomain()
system.clk_domain.clock = '1GHz'
system.clk_domain.voltage_domain = VoltageDomain()

# now we set the memory
system.mem_mode = 'timing'
system.mem_ranges = [AddrRange('512MB')]

# The type of CPU
system.cpu = RiscvTimingSimpleCPU()

# System membus
system.membus = SystemXBar()

# Cache ports!
system.cpu.icache_port = system.membus.cpu_side_ports
system.cpu.dcache_port = system.membus.cpu_side_ports

# Setup an interrupt controller
system.cpu.createInterruptController()
system.system_port = system.membus.cpu_side_ports
# NOTE: RISCV does not require the PIO setup they have in the tutorial

# MEMORYYYYY
system.mem_ctrl = MemCtrl()
system.mem_ctrl.dram = DDR3_1600_8x8()
system.mem_ctrl.dram.range = system.mem_ranges[0]
system.mem_ctrl.port = system.membus.mem_side_ports

# Set up our binary
binary = default_binary

# for gem5 V21 and beyond
system.workload = SEWorkload.init_compatible(binary)

process = Process()
process.cmd = [binary]
system.cpu.workload = process
system.cpu.createThreads()

# Instantiate the system with gem5
root = Root(full_system = False, system = system)
m5.instantiate()

print("Beginning simulation!")
exit_event = m5.simulate()

# And once simulation finishes, we can inspect the state of the system.
print('Exiting @ tick {} because {}'
.format(m5.curTick(), exit_event.getCause()))

This tutorial is heavily based on learning gem5 with some modifications for the University of Alberta CMPUT 429 course made by Ayrton Chilibeck in Summer 2024.