website: update learning gem5 part 1 scripts
Signed-off-by: Hoa Nguyen <hoanguyen@ucdavis.edu>
Change-Id: I88d775f783d19c55eee0ad0db8609d0cf79a3f20
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5-website/+/46359
Reviewed-by: Bobby R. Bruce <bbruce@ucdavis.edu>
Maintainer: Bobby R. Bruce <bbruce@ucdavis.edu>
Tested-by: Bobby R. Bruce <bbruce@ucdavis.edu>
diff --git a/_pages/documentation/learning_gem5/part1/part1_2_simple_config.md b/_pages/documentation/learning_gem5/part1/part1_2_simple_config.md
index 67cdce2..a8b495d 100644
--- a/_pages/documentation/learning_gem5/part1/part1_2_simple_config.md
+++ b/_pages/documentation/learning_gem5/part1/part1_2_simple_config.md
@@ -176,7 +176,7 @@
> 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 gem5 Python
+> 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:
>
diff --git a/_pages/documentation/learning_gem5/part1/part1_3_cache_config.md b/_pages/documentation/learning_gem5/part1/part1_3_cache_config.md
index ecf55bb..f53ca8e 100644
--- a/_pages/documentation/learning_gem5/part1/part1_3_cache_config.md
+++ b/_pages/documentation/learning_gem5/part1/part1_3_cache_config.md
@@ -272,14 +272,19 @@
caches, let's add some options.
```
-from optparse import OptionParser
+import argparse
-parser = OptionParser()
-parser.add_option('--l1i_size', help="L1 instruction cache size")
-parser.add_option('--l1d_size', help="L1 data cache size")
-parser.add_option('--l2_size', help="Unified L2 cache size")
+parser = argparse.ArgumentParser(description='A simple system with 2-level cache.')
+parser.add\_argument("binary", default="", nargs="?", type=str,
+ help="Path to the binary to execute.")
+parser.add\_argument("--l1i_size",
+ help=f"L1 instruction cache size. Default: 16kB.")
+parser.add\_argument("--l1d_size",
+ help="L1 data cache size. Default: Default: 64kB.")
+parser.add\_argument("--l2_size",
+ help="L2 cache size. Default: 256kB.")
-(options, args) = parser.parse_args()
+options = parser.parse\_args()
```
Now, you can run
@@ -287,7 +292,7 @@
will display the options you just added.
Next, we need to pass these options onto the caches that we create in
-the configuration script. To do this, we'll simply change two\_level.py
+the configuration script. To do this, we'll simply change two\_level\_opts.py
to pass the options into the caches as a parameter to their constructor
and add an appropriate constructor, next.
diff --git a/_pages/static/scripts/part1/caches.py b/_pages/static/scripts/part1/caches.py
index 5733e39..755f6b2 100644
--- a/_pages/static/scripts/part1/caches.py
+++ b/_pages/static/scripts/part1/caches.py
@@ -24,25 +24,23 @@
# 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.
-#
-# Authors: Jason Power
-""" Simple caches with default values
+""" Caches with options for a simple gem5 configuration script
This file contains L1 I/D and L2 caches to be used in the simple
-gem5 configuration script.
-
+gem5 configuration script. It uses the SimpleOpts wrapper to set up command
+line options from each individual class.
"""
+import m5
from m5.objects import Cache
# Some specific options for caches
-# For all options see src/mem/cache/Cache.py
+# For all options see src/mem/cache/BaseCache.py
class L1Cache(Cache):
"""Simple L1 Cache with default values"""
- # Default parameters for both L1 I and D caches
assoc = 2
tag_latency = 2
data_latency = 2
@@ -50,21 +48,31 @@
mshrs = 4
tgts_per_mshr = 20
- def connectCPU(self, cpu):
- """Connect this cache's port to a CPU-side port
- This must be defined in a subclass"""
- raise NotImplementedError
+ def __init__(self, options=None):
+ super(L1Cache, self).__init__()
+ pass
def connectBus(self, bus):
"""Connect this cache to a memory-side bus"""
self.mem_side = bus.slave
+ def connectCPU(self, cpu):
+ """Connect this cache's port to a CPU-side port
+ This must be defined in a subclass"""
+ raise NotImplementedError
+
class L1ICache(L1Cache):
"""Simple L1 instruction cache with default values"""
# Set the default size
size = '16kB'
+ def __init__(self, opts=None):
+ super(L1ICache, self).__init__(opts)
+ if not opts or not opts.l1i_size:
+ return
+ self.size = opts.l1i_size
+
def connectCPU(self, cpu):
"""Connect this cache's port to a CPU icache port"""
self.cpu_side = cpu.icache_port
@@ -75,6 +83,12 @@
# Set the default size
size = '64kB'
+ def __init__(self, opts=None):
+ super(L1DCache, self).__init__(opts)
+ if not opts or not opts.l1d_size:
+ return
+ self.size = opts.l1d_size
+
def connectCPU(self, cpu):
"""Connect this cache's port to a CPU dcache port"""
self.cpu_side = cpu.dcache_port
@@ -91,10 +105,14 @@
mshrs = 20
tgts_per_mshr = 12
+ def __init__(self, opts=None):
+ super(L2Cache, self).__init__()
+ if not opts or not opts.l2_size:
+ return
+ self.size = opts.l2_size
+
def connectCPUSideBus(self, bus):
- """"Connect this cache to a cpu-side bus"""
- self.cpu_side = bus.master
+ self.cpu_side = bus.mem_side_ports
def connectMemSideBus(self, bus):
- """"Connect this cache to a memory-side bus"""
- self.mem_side = bus.slave
+ self.mem_side = bus.cpu_side_ports
diff --git a/_pages/static/scripts/part1/caches_opts.py b/_pages/static/scripts/part1/caches_opts.py
index 670d718..9a05aa0 100644
--- a/_pages/static/scripts/part1/caches_opts.py
+++ b/_pages/static/scripts/part1/caches_opts.py
@@ -24,26 +24,23 @@
# 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.
-#
-# Authors: Jason Power
""" Caches with options for a simple gem5 configuration script
This file contains L1 I/D and L2 caches to be used in the simple
-gem5 configuration script. These caches take options as a parameter to their
-constructors to initialize some of their parameters.
-
+gem5 configuration script. It uses the SimpleOpts wrapper to set up command
+line options from each individual class.
"""
+import m5
from m5.objects import Cache
# Some specific options for caches
-# For all options see src/mem/cache/Cache.py
+# For all options see src/mem/cache/BaseCache.py
class L1Cache(Cache):
"""Simple L1 Cache with default values"""
- # Default parameters for both L1 I and D caches
assoc = 2
tag_latency = 2
data_latency = 2
@@ -55,26 +52,26 @@
super(L1Cache, self).__init__()
pass
+ def connectBus(self, bus):
+ """Connect this cache to a memory-side bus"""
+ self.mem_side = bus.cpu_side_ports
+
def connectCPU(self, cpu):
"""Connect this cache's port to a CPU-side port
This must be defined in a subclass"""
raise NotImplementedError
- def connectBus(self, bus):
- """Connect this cache to a memory-side bus"""
- self.mem_side = bus.slave
-
class L1ICache(L1Cache):
"""Simple L1 instruction cache with default values"""
# Set the default size
size = '16kB'
- def __init__(self, options=None):
- super(L1ICache, self).__init__(options)
- if not options or not options.l1i_size:
+ def __init__(self, opts=None):
+ super(L1ICache, self).__init__(opts)
+ if not opts or not opts.l1i_size:
return
- self.size = options.l1i_size
+ self.size = opts.l1i_size
def connectCPU(self, cpu):
"""Connect this cache's port to a CPU icache port"""
@@ -86,11 +83,11 @@
# Set the default size
size = '64kB'
- def __init__(self, options=None):
- super(L1DCache, self).__init__(options)
- if not options or not options.l1d_size:
+ def __init__(self, opts=None):
+ super(L1DCache, self).__init__(opts)
+ if not opts or not opts.l1d_size:
return
- self.size = options.l1d_size
+ self.size = opts.l1d_size
def connectCPU(self, cpu):
"""Connect this cache's port to a CPU dcache port"""
@@ -108,16 +105,14 @@
mshrs = 20
tgts_per_mshr = 12
- def __init__(self, options=None):
+ def __init__(self, opts=None):
super(L2Cache, self).__init__()
- if not options or not options.l2_size:
+ if not opts or not opts.l2_size:
return
- self.size = options.l2_size
+ self.size = opts.l2_size
def connectCPUSideBus(self, bus):
- """"Connect this cache to a cpu-side bus"""
- self.cpu_side = bus.master
+ self.cpu_side = bus.mem_side_ports
def connectMemSideBus(self, bus):
- """"Connect this cache to a memory-side bus"""
- self.mem_side = bus.slave
+ self.mem_side = bus.cpu_side_ports
diff --git a/_pages/static/scripts/part1/simple.py b/_pages/static/scripts/part1/simple.py
index 1bf3eae..69521fe 100644
--- a/_pages/static/scripts/part1/simple.py
+++ b/_pages/static/scripts/part1/simple.py
@@ -24,14 +24,14 @@
# 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.
-#
-# Authors: Jason Power
""" This file creates a barebones system and executes 'hello', a simple Hello
World application.
+See Part 1, Chapter 2: Creating a simple configuration script in the
+learning_gem5 book for more information about this script.
-This config file assumes that the x86 ISA was built.
-See gem5/configs/learning_gem5/part1/simple.py for a general script.
+IMPORTANT: If you modify this file, it's likely that the Learning gem5 book
+ also needs to be updated. For now, email Jason <power.jg@gmail.com>
"""
@@ -55,7 +55,7 @@
# Create a simple CPU
system.cpu = TimingSimpleCPU()
-# Create a memory bus, a coherent crossbar, in this case
+# Create a memory bus, a system crossbar, in this case
system.membus = SystemXBar()
# Hook the CPU ports up to the membus
@@ -64,23 +64,39 @@
# create the interrupt controller for the CPU and connect to the membus
system.cpu.createInterruptController()
-system.cpu.interrupts[0].pio = system.membus.master
-system.cpu.interrupts[0].int_master = system.membus.slave
-system.cpu.interrupts[0].int_slave = system.membus.master
+
+# For x86 only, make sure the interrupts are connected to the memory
+# Note: these are directly connected to the memory bus and are not cached
+if m5.defines.buildEnv['TARGET_ISA'] == "x86":
+ system.cpu.interrupts[0].pio = system.membus.master
+ system.cpu.interrupts[0].int_master = system.membus.slave
+ system.cpu.interrupts[0].int_slave = system.membus.master
# Create a DDR3 memory controller and connect it to the membus
-system.mem_ctrl = DDR3_1600_8x8()
-system.mem_ctrl.range = system.mem_ranges[0]
+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.master
# Connect the system up to the membus
system.system_port = system.membus.slave
+# get ISA for the binary to run.
+isa = str(m5.defines.buildEnv['TARGET_ISA']).lower()
+
+# 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__))
+binary = os.path.join(thispath, '../../../',
+ 'tests/test-progs/hello/bin/', isa, 'linux/hello')
+
+system.workload = SEWorkload.init_compatible(binary)
+
# Create a process for a simple "Hello World" application
process = Process()
# Set the command
# cmd is a list which begins with the executable (like argv)
-process.cmd = ['tests/test-progs/hello/bin/x86/linux/hello']
+process.cmd = [binary]
# Set the cpu to use the process as its workload and create thread contexts
system.cpu.workload = process
system.cpu.createThreads()
@@ -90,6 +106,6 @@
# instantiate all of the objects we've created above
m5.instantiate()
-print "Beginning simulation!"
+print("Beginning simulation!")
exit_event = m5.simulate()
-print 'Exiting @ tick %i because %s' % (m5.curTick(), exit_event.getCause())
+print('Exiting @ tick %i because %s' % (m5.curTick(), exit_event.getCause()))
diff --git a/_pages/static/scripts/part1/two_level.py b/_pages/static/scripts/part1/two_level.py
index 23c519b..64ee33c 100644
--- a/_pages/static/scripts/part1/two_level.py
+++ b/_pages/static/scripts/part1/two_level.py
@@ -24,13 +24,17 @@
# 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.
-#
-# Authors: Jason Power
-""" This file creates a simple system with a single CPU and a 2-level cache
-and executes 'hello', a simple Hello World application.
+""" This file creates a single CPU and a two-level cache system.
+This script takes a single parameter which specifies a binary to execute.
+If none is provided it executes 'hello' by default (mostly used for testing)
-This config file assumes that the x86 ISA was built.
+See Part 1, Chapter 3: Adding cache to the configuration script in the
+learning_gem5 book for more information about this script.
+This file exports options for the L1 I/D and L2 cache sizes.
+
+IMPORTANT: If you modify this file, it's likely that the Learning gem5 book
+ also needs to be updated. For now, email Jason <power.jg@gmail.com>
"""
@@ -42,6 +46,15 @@
# import the caches which we made
from caches import *
+# get ISA for the default binary to run. This is mostly for simple testing
+isa = str(m5.defines.buildEnv['TARGET_ISA']).lower()
+
+# 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__))
+binary = os.path.join(thispath, '../../../',
+ 'tests/test-progs/hello/bin/', isa, 'linux/hello')
+
# create the system we are going to simulate
system = System()
@@ -82,26 +95,32 @@
# Connect the L2 cache to the membus
system.l2cache.connectMemSideBus(system.membus)
-# create the interrupt controller for the CPU and connect to the membus
-# Note: these are directly connected to the memory bus and are not cached
+# create the interrupt controller for the CPU
system.cpu.createInterruptController()
-system.cpu.interrupts[0].pio = system.membus.master
-system.cpu.interrupts[0].int_master = system.membus.slave
-system.cpu.interrupts[0].int_slave = system.membus.master
+
+# For x86 only, make sure the interrupts are connected to the memory
+# Note: these are directly connected to the memory bus and are not cached
+if m5.defines.buildEnv['TARGET_ISA'] == "x86":
+ system.cpu.interrupts[0].pio = system.membus.mem_side_ports
+ system.cpu.interrupts[0].int_requestor = system.membus.cpu_side_ports
+ system.cpu.interrupts[0].int_responder = system.membus.mem_side_ports
# Connect the system up to the membus
-system.system_port = system.membus.slave
+system.system_port = system.membus.cpu_side_ports
# Create a DDR3 memory controller
-system.mem_ctrl = DDR3_1600_8x8()
-system.mem_ctrl.range = system.mem_ranges[0]
-system.mem_ctrl.port = system.membus.master
+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
+
+system.workload = SEWorkload.init_compatible(binary)
# Create a process for a simple "Hello World" application
process = Process()
# Set the command
# cmd is a list which begins with the executable (like argv)
-process.cmd = ['tests/test-progs/hello/bin/x86/linux/hello']
+process.cmd = [binary]
# Set the cpu to use the process as its workload and create thread contexts
system.cpu.workload = process
system.cpu.createThreads()
@@ -111,6 +130,6 @@
# instantiate all of the objects we've created above
m5.instantiate()
-print "Beginning simulation!"
+print("Beginning simulation!")
exit_event = m5.simulate()
-print 'Exiting @ tick %i because %s' % (m5.curTick(), exit_event.getCause())
+print('Exiting @ tick %i because %s' % (m5.curTick(), exit_event.getCause()))
diff --git a/_pages/static/scripts/part1/two_level_opts.py b/_pages/static/scripts/part1/two_level_opts.py
index b176b6d..ce0dd47 100644
--- a/_pages/static/scripts/part1/two_level_opts.py
+++ b/_pages/static/scripts/part1/two_level_opts.py
@@ -24,14 +24,17 @@
# 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.
-#
-# Authors: Jason Power
-""" This file creates a simple system with a single CPU and a 2-level cache
-and executes 'hello', a simple Hello World application.
+""" This file creates a single CPU and a two-level cache system.
+This script takes a single parameter which specifies a binary to execute.
+If none is provided it executes 'hello' by default (mostly used for testing)
-This config file assumes that the x86 ISA was built.
-See gem5/configs/learning_gem5/part1/two_level.py for a general script.
+See Part 1, Chapter 3: Adding cache to the configuration script in the
+learning_gem5 book for more information about this script.
+This file exports options for the L1 I/D and L2 cache sizes.
+
+IMPORTANT: If you modify this file, it's likely that the Learning gem5 book
+ also needs to be updated. For now, email Jason <power.jg@gmail.com>
"""
@@ -43,16 +46,34 @@
# import the caches which we made
from caches_opts import *
-# import the options parser
-from optparse import OptionParser
+# import the argparse module
+import argparse
-# add the options we want to be able to control from the command line
-parser = OptionParser()
-parser.add_option('--l1i_size', help="L1 instruction cache size")
-parser.add_option('--l1d_size', help="L1 data cache size")
-parser.add_option('--l2_size', help="Unified L2 cache size")
+# Set the usage message to display
+parser = argparse.ArgumentParser(description='A simple system with 2-level cache.')
+parser.add_argument("binary", default="", nargs="?", type=str,
+ help="Path to the binary to execute.")
+parser.add_argument("--l1i_size",
+ help=f"L1 instruction cache size. Default: 16kB.")
+parser.add_argument("--l1d_size",
+ help="L1 data cache size. Default: Default: 64kB.")
+parser.add_argument("--l2_size",
+ help="L2 cache size. Default: 256kB.")
+# Finalize the arguments and grab the opts so we can pass it on to our objects
+options = parser.parse_args()
-(options, args) = parser.parse_args()
+# get ISA for the default binary to run. This is mostly for simple testing
+isa = str(m5.defines.buildEnv['TARGET_ISA']).lower()
+
+# 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__))
+binary = os.path.join(thispath, '../../../',
+ 'tests/test-progs/hello/bin/', isa, 'linux/hello')
+
+# If the executable is specified by user, run the hello program
+if hasattr(parser, "binary"):
+ binary = parser.binary
# create the system we are going to simulate
system = System()
@@ -94,26 +115,32 @@
# Connect the L2 cache to the membus
system.l2cache.connectMemSideBus(system.membus)
-# create the interrupt controller for the CPU and connect to the membus
-# Note: these are directly connected to the memory bus and are not cached
+# create the interrupt controller for the CPU
system.cpu.createInterruptController()
-system.cpu.interrupts[0].pio = system.membus.master
-system.cpu.interrupts[0].int_master = system.membus.slave
-system.cpu.interrupts[0].int_slave = system.membus.master
+
+# For x86 only, make sure the interrupts are connected to the memory
+# Note: these are directly connected to the memory bus and are not cached
+if m5.defines.buildEnv['TARGET_ISA'] == "x86":
+ system.cpu.interrupts[0].pio = system.membus.mem_side_ports
+ system.cpu.interrupts[0].int_requestor = system.membus.cpu_side_ports
+ system.cpu.interrupts[0].int_responder = system.membus.mem_side_ports
# Connect the system up to the membus
-system.system_port = system.membus.slave
+system.system_port = system.membus.cpu_side_ports
# Create a DDR3 memory controller
-system.mem_ctrl = DDR3_1600_8x8()
-system.mem_ctrl.range = system.mem_ranges[0]
-system.mem_ctrl.port = system.membus.master
+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
+
+system.workload = SEWorkload.init_compatible(binary)
# Create a process for a simple "Hello World" application
process = Process()
# Set the command
# cmd is a list which begins with the executable (like argv)
-process.cmd = ['tests/test-progs/hello/bin/x86/linux/hello']
+process.cmd = [binary]
# Set the cpu to use the process as its workload and create thread contexts
system.cpu.workload = process
system.cpu.createThreads()
@@ -123,6 +150,6 @@
# instantiate all of the objects we've created above
m5.instantiate()
-print "Beginning simulation!"
+print("Beginning simulation!")
exit_event = m5.simulate()
-print 'Exiting @ tick %i because %s' % (m5.curTick(), exit_event.getCause())
+print('Exiting @ tick %i because %s' % (m5.curTick(), exit_event.getCause()))