stdlib: Add X86DemoBoard

Change-Id: I5aae95d2d8fe37374c393b337243526eb1c90aa1
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/53004
Reviewed-by: Bobby Bruce <bbruce@ucdavis.edu>
Maintainer: Bobby Bruce <bbruce@ucdavis.edu>
Tested-by: kokoro <noreply+kokoro@google.com>
diff --git a/configs/example/gem5_library/x86-ubuntu-run-with-kvm.py b/configs/example/gem5_library/x86-ubuntu-run-with-kvm.py
new file mode 100644
index 0000000..630cb09
--- /dev/null
+++ b/configs/example/gem5_library/x86-ubuntu-run-with-kvm.py
@@ -0,0 +1,144 @@
+# Copyright (c) 2021 The Regents of the University of California
+# All rights reserved.
+#
+# 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.
+
+"""
+
+This script shows an example of running a full system Ubuntu boot simulation
+using the gem5 library. This simulation boots Ubuntu 18.04 using 2 KVM CPU
+cores. The simulation then switches to 2 Timing CPU cores before running an
+echo statement.
+
+Usage
+-----
+
+```
+scons build/X86_MESI_Two_Level/gem5.opt
+./build/X86/gem5.opt configs/example/gem5_library/x86-ubuntu-run-with-kvm.py
+```
+"""
+
+import m5
+from m5.objects import Root
+
+from gem5.utils.requires import requires
+from gem5.components.boards.x86_board import X86Board
+from gem5.components.memory.single_channel import SingleChannelDDR3_1600
+from gem5.components.processors.simple_switchable_processor import (
+    SimpleSwitchableProcessor,
+)
+from gem5.components.processors.cpu_types import CPUTypes
+from gem5.isas import ISA
+from gem5.coherence_protocol import CoherenceProtocol
+from gem5.resources.resource import Resource
+
+# This runs a check to ensure the gem5 binary is compiled to X86 and to the
+# MESI Two Level coherence protocol.
+requires(
+    isa_required=ISA.X86,
+    coherence_protocol_required=CoherenceProtocol.MESI_TWO_LEVEL,
+    kvm_required=True,
+)
+
+from gem5.components.cachehierarchies.ruby.\
+    mesi_two_level_cache_hierarchy import (
+    MESITwoLevelCacheHierarchy,
+)
+
+# Here we setup a MESI Two Level Cache Hierarchy.
+cache_hierarchy = MESITwoLevelCacheHierarchy(
+    l1d_size="16kB",
+    l1d_assoc=8,
+    l1i_size="16kB",
+    l1i_assoc=8,
+    l2_size="256kB",
+    l2_assoc=16,
+    num_l2_banks=1,
+)
+
+# Setup the system memory.
+memory = SingleChannelDDR3_1600(size="3GB")
+
+# Here we setup the processor. This is a special switchable processor in which
+# a starting core type and a switch core type must be specified. Once a
+# configuration is instantiated a user may call `processor.switch()` to switch
+# from the starting core types to the switch core types. In this simulation
+# we start with KVM cores to simulate the OS boot, then switch to the Timing
+# cores for the command we wish to run after boot.
+processor = SimpleSwitchableProcessor(
+    starting_core_type=CPUTypes.KVM,
+    switch_core_type=CPUTypes.TIMING,
+    num_cores=2,
+)
+
+# Here we setup the board. The X86Board allows for Full-System X86 simulations.
+board = X86Board(
+    clk_freq="3GHz",
+    processor=processor,
+    memory=memory,
+    cache_hierarchy=cache_hierarchy,
+)
+
+# Here we set the Full System workload.
+# The `set_kernel_disk_workload` function for the X86Board takes a kernel, a
+# disk image, and, optionally, a command to run.
+
+# This is the command to run after the system has booted. The first `m5 exit`
+# will stop the simulation so we can switch the CPU cores from KVM to timing
+# and continue the simulation to run the echo command, sleep for a second,
+# then, again, call `m5 exit` to terminate the simulation. After simulation
+# has ended you may inspect `m5out/system.pc.com_1.device` to see the echo
+# output.
+command = "m5 exit;" \
+        + "echo 'This is running on Timing CPU cores.';" \
+        + "sleep 1;" \
+        + "m5 exit;"
+
+board.set_kernel_disk_workload(
+    # The x86 linux kernel will be automatically downloaded to the if not
+    # already present.
+    kernel=Resource("x86-linux-kernel-5.4.49"),
+    # The x86 ubuntu image will be automatically downloaded to the if not
+    # already present.
+    disk_image=Resource("x86-ubuntu-img"),
+    readfile_contents=command,
+)
+
+
+root = Root(full_system=True, system=board)
+root.sim_quantum = int(1e9)  # sim_quantum must be st if KVM cores are used.
+
+m5.instantiate()
+
+# This first stretch of the simulation runs using the KVM cores. In this setup
+# this will terminate until Ubuntu boot is complete.
+m5.simulate()
+
+# This will switch from the KVM cores to the Timing cores.
+processor.switch()
+
+# This final stretch of the simulation will be run using the Timing cores. In
+# this setup an echo statement will be executed prior to exiting.
+m5.simulate()
diff --git a/configs/example/gem5_library/x86-ubuntu-run.py b/configs/example/gem5_library/x86-ubuntu-run.py
index 3ee566b..9979c14 100644
--- a/configs/example/gem5_library/x86-ubuntu-run.py
+++ b/configs/example/gem5_library/x86-ubuntu-run.py
@@ -25,11 +25,15 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 """
+This script utilizes the X86DemoBoard to run a simple Ubunutu boot. The script
+will boot the the OS to login before exiting the simulation.
 
-This script shows an example of running a full system Ubuntu boot simulation
-using the gem5 library. This simulation boots Ubuntu 18.04 using 2 KVM CPU
-cores. The simulation then switches to 2 Timing CPU cores before running an
-echo statement.
+A detailed terminal output can be found in `m5out/system.pc.com_1.device`.
+
+**Warning:** The X86DemoBoard uses the Timing CPU. The boot may take
+considerable time to complete execution.
+`configs/example/gem5_library/x86-ubuntu-run-with-kvm.py` can be referenced as
+an example of booting Ubuntu with a KVM CPU.
 
 Usage
 -----
@@ -43,102 +47,21 @@
 import m5
 from m5.objects import Root
 
-from gem5.utils.requires import requires
-from gem5.components.boards.x86_board import X86Board
-from gem5.components.memory.single_channel import SingleChannelDDR3_1600
-from gem5.components.processors.simple_switchable_processor import (
-    SimpleSwitchableProcessor,
-)
-from gem5.components.processors.cpu_types import CPUTypes
-from gem5.isas import ISA
-from gem5.coherence_protocol import CoherenceProtocol
+from gem5.prebuilt.demo.x86_demo_board import X86DemoBoard
 from gem5.resources.resource import Resource
 
-# This runs a check to ensure the gem5 binary is compiled to X86 and to the
-# MESI Two Level coherence protocol.
-requires(
-    isa_required=ISA.X86,
-    coherence_protocol_required=CoherenceProtocol.MESI_TWO_LEVEL,
-    kvm_required=True,
-)
+# Here we setup the board. The prebuilt X86DemoBoard allows for Full-System X86
+# simulation.
+board = X86DemoBoard()
 
-from gem5.components.cachehierarchies.ruby.\
-    mesi_two_level_cache_hierarchy import (
-    MESITwoLevelCacheHierarchy,
-)
-
-# Here we setup a MESI Two Level Cache Hierarchy.
-cache_hierarchy = MESITwoLevelCacheHierarchy(
-    l1d_size="16kB",
-    l1d_assoc=8,
-    l1i_size="16kB",
-    l1i_assoc=8,
-    l2_size="256kB",
-    l2_assoc=16,
-    num_l2_banks=1,
-)
-
-# Setup the system memory.
-memory = SingleChannelDDR3_1600(size="3GB")
-
-# Here we setup the processor. This is a special switchable processor in which
-# a starting core type and a switch core type must be specified. Once a
-# configuration is instantiated a user may call `processor.switch()` to switch
-# from the starting core types to the switch core types. In this simulation
-# we start with KVM cores to simulate the OS boot, then switch to the Timing
-# cores for the command we wish to run after boot.
-processor = SimpleSwitchableProcessor(
-    starting_core_type=CPUTypes.KVM,
-    switch_core_type=CPUTypes.TIMING,
-    num_cores=2,
-)
-
-# Here we setup the board. The X86Board allows for Full-System X86 simulations.
-board = X86Board(
-    clk_freq="3GHz",
-    processor=processor,
-    memory=memory,
-    cache_hierarchy=cache_hierarchy,
-)
-
-# Here we set the Full System workload.
-# The `set_kernel_disk_workload` function for the X86Board takes a kernel, a
-# disk image, and, optionally, a command to run.
-
-# This is the command to run after the system has booted. The first `m5 exit`
-# will stop the simulation so we can switch the CPU cores from KVM to timing
-# and continue the simulation to run the echo command, sleep for a second,
-# then, again, call `m5 exit` to terminate the simulation. After simulation
-# has ended you may inspect `m5out/system.pc.com_1.device` to see the echo
-# output.
-command = "m5 exit;" \
-        + "echo 'This is running on Timing CPU cores.';" \
-        + "sleep 1;" \
-        + "m5 exit;"
-
+# We then set the workload. Here we use the 5.4.49 Linux kernel with an X86
+# Ubuntu OS. If these cannot be found locally they will be automatically
+# downloaded.
 board.set_kernel_disk_workload(
-    # The x86 linux kernel will be automatically downloaded to the if not
-    # already present.
     kernel=Resource("x86-linux-kernel-5.4.49"),
-    # The x86 ubuntu image will be automatically downloaded to the if not
-    # already present.
     disk_image=Resource("x86-ubuntu-img"),
-    readfile_contents=command,
 )
 
-
 root = Root(full_system=True, system=board)
-root.sim_quantum = int(1e9)  # sim_quantum must be st if KVM cores are used.
-
 m5.instantiate()
-
-# This first stretch of the simulation runs using the KVM cores. In this setup
-# this will terminate until Ubuntu boot is complete.
-m5.simulate()
-
-# This will switch from the KVM cores to the Timing cores.
-processor.switch()
-
-# This final stretch of the simulation will be run using the Timing cores. In
-# this setup an echo statement will be executed prior to exiting.
-m5.simulate()
+m5.simulate()
\ No newline at end of file
diff --git a/src/python/SConscript b/src/python/SConscript
index f9b74c0..4487bdd 100644
--- a/src/python/SConscript
+++ b/src/python/SConscript
@@ -194,6 +194,9 @@
     'gem5/components/processors/simple_switchable_processor.py')
 PySource('gem5.components.processors',
     'gem5/components/processors/switchable_processor.py')
+PySource('gem5.prebuilt', 'gem5/prebuilt/__init__.py')
+PySource('gem5.prebuilt.demo', 'gem5/prebuilt/demo/__init__.py')
+PySource('gem5.prebuilt.demo', 'gem5/prebuilt/demo/x86_demo_board.py')
 PySource('gem5.resources', 'gem5/resources/__init__.py')
 PySource('gem5.resources', 'gem5/resources/downloader.py')
 PySource('gem5.resources', 'gem5/resources/resource.py')
diff --git a/src/python/gem5/prebuilt/__init__.py b/src/python/gem5/prebuilt/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/python/gem5/prebuilt/__init__.py
diff --git a/src/python/gem5/prebuilt/demo/__init__.py b/src/python/gem5/prebuilt/demo/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/python/gem5/prebuilt/demo/__init__.py
diff --git a/src/python/gem5/prebuilt/demo/x86_demo_board.py b/src/python/gem5/prebuilt/demo/x86_demo_board.py
new file mode 100644
index 0000000..7583849
--- /dev/null
+++ b/src/python/gem5/prebuilt/demo/x86_demo_board.py
@@ -0,0 +1,94 @@
+# Copyright (c) 2021 The Regents of the University of California
+# All rights reserved.
+#
+# 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.
+
+from m5.util import warn
+
+from ...components.processors.cpu_types import CPUTypes
+from ...components.boards.x86_board import X86Board
+from ...components.memory.single_channel import SingleChannelDDR3_1600
+from ...components.processors.simple_processor import SimpleProcessor
+from ...components.cachehierarchies.ruby.mesi_two_level_cache_hierarchy \
+    import MESITwoLevelCacheHierarchy
+from ...coherence_protocol import CoherenceProtocol
+from ...isas import ISA
+from ...utils.requires import requires
+
+
+class X86DemoBoard(X86Board):
+    """
+    This prebuilt X86 board is used for demonstration purposes. It simulates
+    an X86 3GHz quad-core system with a 2GB DDR3_1600 memory system. A
+    MESI_Two_Level cache hierarchy is set with an l1 data and instruction
+    cache, each 32kB with an associativity of 8, and a single bank l2 cache of
+    1MB with an associativity of 16.
+
+    **DISCLAIMER**: This board is solely for demonstration purposes. This board
+    is not known to be representative of any real-world system or produce
+    reliable statistical results.
+
+    Example
+    -------
+
+    An example of using the X86DemoBoard can be found in
+    `configs/example/gem5_library/x86-ubuntu-run.py`.
+
+    To run:
+
+    ```
+    scons build/X86/gem5.opt -j`nproc`
+    ./build/X86/gem5.opt configs/example/gem5_library/x86-ubuntu-run.py
+    ```
+
+    """
+
+    def __init__(self):
+        requires(
+            isa_required=ISA.X86,
+            coherence_protocol_required=CoherenceProtocol.MESI_TWO_LEVEL,
+        )
+
+        warn("The X86DemoBoard is solely for demonstration purposes. "
+             "This board is not known to be be representative of any "
+             "real-world system. Use with caution.")
+
+        memory = SingleChannelDDR3_1600(size="2GB")
+        processor = SimpleProcessor(cpu_type=CPUTypes.TIMING, num_cores=4)
+        cache_hierarchy = MESITwoLevelCacheHierarchy(
+            l1d_size="32kB",
+            l1d_assoc=8,
+            l1i_size="32kB",
+            l1i_assoc=8,
+            l2_size="1MB",
+            l2_assoc=16,
+            num_l2_banks=1,
+        )
+
+        super().__init__(
+            clk_freq="3GHz",
+            processor=processor,
+            memory=memory,
+            cache_hierarchy=cache_hierarchy,
+        )
diff --git a/tests/gem5/gem5_library_example_tests/test_gem5_library_examples.py b/tests/gem5/gem5_library_example_tests/test_gem5_library_examples.py
index cd59423..a2bbf28 100644
--- a/tests/gem5/gem5_library_example_tests/test_gem5_library_examples.py
+++ b/tests/gem5/gem5_library_example_tests/test_gem5_library_examples.py
@@ -56,7 +56,7 @@
     # The x86-ubuntu-run uses KVM cores, this test will therefore only be run
     # on systems that support KVM.
     gem5_verify_config(
-        name="test-gem5-library-example-x86-ubuntu-run",
+        name="test-gem5-library-example-x86-ubuntu-run-with-kvm",
         fixtures=(),
         verifiers=(),
         config=joinpath(
@@ -64,10 +64,27 @@
             "configs",
             "example",
             "gem5_library",
-            "x86-ubuntu-run.py",
+            "x86-ubuntu-run-with-kvm.py",
         ),
         config_args=[],
         valid_isas=(constants.x86_tag,),
         valid_hosts=constants.supported_hosts,
         length=constants.long_tag,
     )
+
+gem5_verify_config(
+    name="test-gem5-library-example-x86-ubuntu-run",
+    fixtures=(),
+    verifiers=(),
+    config=joinpath(
+        config.base_dir,
+        "configs",
+        "example",
+        "gem5_library",
+        "x86-ubuntu-run.py",
+    ),
+    config_args=[],
+    valid_isas=(constants.x86_tag,),
+    valid_hosts=constants.supported_hosts,
+    length=constants.long_tag,
+)