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()))