stdlib: Create the AbstractSystemBoard

In the prior design the AbstractBoard inherited from System. This was
fine for the X86Board and RISCVBoard, but was causing problems for the
design of the ARMBoard which must inherit from ArmSystem (which itself
inherits from System).

This new design removes the System inheritance from AbstractBoard, and
creates a new "AbstractSystemBoard" class which inherits from both
AbstractBoard and System. This allows for the creation of an ArmBoard
which inherits from both AbstractBoard and Arm System.

Change-Id: I3831f2ebe61e4adfb9dc10b7790b39403a99beaa
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/58909
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Bobby Bruce <bbruce@ucdavis.edu>
Reviewed-by: Jason Lowe-Power <power.jg@gmail.com>
Maintainer: Bobby Bruce <bbruce@ucdavis.edu>
diff --git a/src/python/SConscript b/src/python/SConscript
index 63cc406..47e577a 100644
--- a/src/python/SConscript
+++ b/src/python/SConscript
@@ -39,6 +39,8 @@
 PySource('gem5.components', 'gem5/components/__init__.py')
 PySource('gem5.components.boards', 'gem5/components/boards/__init__.py')
 PySource('gem5.components.boards', 'gem5/components/boards/abstract_board.py')
+PySource('gem5.components.boards',
+    'gem5/components/boards/abstract_system_board.py')
 PySource('gem5.components.boards', 'gem5/components/boards/mem_mode.py')
 PySource('gem5.components.boards', 'gem5/components/boards/riscv_board.py')
 PySource('gem5.components.boards.experimental',
diff --git a/src/python/gem5/components/boards/abstract_board.py b/src/python/gem5/components/boards/abstract_board.py
index 9ab6780..3067f7d 100644
--- a/src/python/gem5/components/boards/abstract_board.py
+++ b/src/python/gem5/components/boards/abstract_board.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2021 The Regents of the University of California
+# Copyright (c) 2022 The Regents of the University of California
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -40,7 +40,7 @@
 from typing import List
 
 
-class AbstractBoard(System):
+class AbstractBoard:
     """The abstract board interface.
 
     Boards are used as the object which can connect together all other
@@ -65,10 +65,9 @@
         self,
         clk_freq: str,
         processor: "AbstractProcessor",
-        memory: "AbstractMemory",
+        memory: "AbstractMemorySystem",
         cache_hierarchy: "AbstractCacheHierarchy",
     ) -> None:
-        super().__init__()
         """
         :param clk_freq: The clock frequency for this board.
         :param processor: The processor for this board.
@@ -76,6 +75,9 @@
         :param cache_hierarchy: The Cachie Hierarchy for this board.
         """
 
+        if not isinstance(self, System):
+            raise Exception("A gem5 stdlib board must inherit from System.")
+
         # Set up the clock domain and the voltage domain.
         self.clk_domain = SrcClockDomain()
         self.clk_domain.clock = clk_freq
diff --git a/src/python/gem5/components/boards/abstract_system_board.py b/src/python/gem5/components/boards/abstract_system_board.py
new file mode 100644
index 0000000..463a5b6
--- /dev/null
+++ b/src/python/gem5/components/boards/abstract_system_board.py
@@ -0,0 +1,54 @@
+# 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 abc import ABCMeta
+
+from .abstract_board import AbstractBoard
+
+from m5.objects import System
+
+class AbstractSystemBoard(System, AbstractBoard):
+
+    """
+    An abstract board for cases where boards should inherit from System.
+    """
+
+    __metaclass__ = ABCMeta
+    def __init__(
+        self,
+        clk_freq: str,
+        processor: "AbstractProcessor",
+        memory: "AbstractMemorySystem",
+        cache_hierarchy: "AbstractCacheHierarchy",
+    ):
+        System.__init__(self)
+        AbstractBoard.__init__(
+            self,
+            clk_freq=clk_freq,
+            processor=processor,
+            memory=memory,
+            cache_hierarchy=cache_hierarchy,
+        )
\ No newline at end of file
diff --git a/src/python/gem5/components/boards/riscv_board.py b/src/python/gem5/components/boards/riscv_board.py
index f72b31d..15cf84c 100644
--- a/src/python/gem5/components/boards/riscv_board.py
+++ b/src/python/gem5/components/boards/riscv_board.py
@@ -29,7 +29,7 @@
 from typing import List
 
 from ...utils.override import overrides
-from .abstract_board import AbstractBoard
+from .abstract_system_board import AbstractSystemBoard
 from .kernel_disk_workload import KernelDiskWorkload
 from ..processors.abstract_processor import AbstractProcessor
 from ..memory.abstract_memory_system import AbstractMemorySystem
@@ -68,7 +68,7 @@
 )
 
 
-class RiscvBoard(AbstractBoard, KernelDiskWorkload):
+class RiscvBoard(AbstractSystemBoard, KernelDiskWorkload):
     """
     A board capable of full system simulation for RISC-V
 
@@ -94,7 +94,7 @@
                 "RISCV ISA. Current processor ISA: "
                 f"'{processor.get_isa().name}'.")
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def _setup_board(self) -> None:
         self.workload = RiscvLinux()
 
@@ -173,34 +173,34 @@
                 uncacheable=uncacheable_range
             )
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def has_dma_ports(self) -> bool:
         return False
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def get_dma_ports(self) -> List[Port]:
         raise NotImplementedError(
             "RISCVBoard does not have DMA Ports. "
             "Use `has_dma_ports()` to check this."
         )
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def has_io_bus(self) -> bool:
         return True
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def get_io_bus(self) -> IOXBar:
         return self.iobus
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def has_coherent_io(self) -> bool:
         return True
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def get_mem_side_coherent_io_port(self) -> Port:
         return self.iobus.mem_side_ports
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def _setup_memory_ranges(self):
         memory = self.get_memory()
         mem_size = memory.get_size()
diff --git a/src/python/gem5/components/boards/simple_board.py b/src/python/gem5/components/boards/simple_board.py
index d0f4f2a..532475d 100644
--- a/src/python/gem5/components/boards/simple_board.py
+++ b/src/python/gem5/components/boards/simple_board.py
@@ -30,7 +30,7 @@
     Port,
 )
 
-from .abstract_board import AbstractBoard
+from .abstract_system_board import AbstractSystemBoard
 from .se_binary_workload import SEBinaryWorkload
 from ..processors.abstract_processor import AbstractProcessor
 from ..memory.abstract_memory_system import AbstractMemorySystem
@@ -40,7 +40,7 @@
 from typing import List
 
 
-class SimpleBoard(AbstractBoard, SEBinaryWorkload):
+class SimpleBoard(AbstractSystemBoard, SEBinaryWorkload):
     """
     This is an incredibly simple system. It contains no I/O, and will work only
     with a classic cache hierarchy setup.
@@ -65,44 +65,44 @@
             cache_hierarchy=cache_hierarchy,
         )
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def _setup_board(self) -> None:
         pass
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def has_io_bus(self) -> bool:
         return False
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def get_io_bus(self) -> IOXBar:
         raise NotImplementedError(
             "SimpleBoard does not have an IO Bus. "
             "Use `has_io_bus()` to check this."
         )
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def has_dma_ports(self) -> bool:
         return False
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def get_dma_ports(self) -> List[Port]:
         raise NotImplementedError(
             "SimpleBoard does not have DMA Ports. "
             "Use `has_dma_ports()` to check this."
         )
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def has_coherent_io(self) -> bool:
         return False
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def get_mem_side_coherent_io_port(self) -> Port:
         raise NotImplementedError(
             "SimpleBoard does not have any I/O ports. Use has_coherent_io to "
             "check this."
         )
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def _setup_memory_ranges(self) -> None:
         memory = self.get_memory()
 
diff --git a/src/python/gem5/components/boards/test_board.py b/src/python/gem5/components/boards/test_board.py
index d39e25d..7031e0e 100644
--- a/src/python/gem5/components/boards/test_board.py
+++ b/src/python/gem5/components/boards/test_board.py
@@ -32,7 +32,7 @@
 
 from .mem_mode import MemMode, mem_mode_to_string
 from ...utils.override import overrides
-from .abstract_board import AbstractBoard
+from .abstract_system_board import AbstractSystemBoard
 from ..processors.abstract_processor import AbstractProcessor
 from ..memory.abstract_memory_system import AbstractMemorySystem
 from ..cachehierarchies.abstract_cache_hierarchy import AbstractCacheHierarchy
@@ -41,7 +41,7 @@
 from typing import List
 
 
-class TestBoard(AbstractBoard):
+class TestBoard(AbstractSystemBoard):
 
     """This is a Testing Board used to run traffic generators on a simple
     architecture.
@@ -63,44 +63,44 @@
             cache_hierarchy=cache_hierarchy,
         )
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def _setup_board(self) -> None:
         pass
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def has_io_bus(self) -> bool:
         return False
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def get_io_bus(self) -> IOXBar:
         raise NotImplementedError(
             "The TestBoard does not have an IO Bus. "
             "Use `has_io_bus()` to check this."
         )
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def get_dma_ports(self) -> List[Port]:
         return False
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def get_dma_ports(self) -> List[Port]:
         raise NotImplementedError(
             "The TestBoard does not have DMA Ports. "
             "Use `has_dma_ports()` to check this."
         )
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def has_coherent_io(self) -> bool:
         return False
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def get_mem_side_coherent_io_port(self):
         raise NotImplementedError(
             "SimpleBoard does not have any I/O ports. Use has_coherent_io to "
             "check this."
         )
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def _setup_memory_ranges(self) -> None:
         memory = self.get_memory()
 
@@ -109,6 +109,6 @@
         self.mem_ranges = [AddrRange(memory.get_size())]
         memory.set_memory_range(self.mem_ranges)
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def has_dma_ports(self) -> bool:
         return False
diff --git a/src/python/gem5/components/boards/x86_board.py b/src/python/gem5/components/boards/x86_board.py
index 1ffc86c..6761bdb 100644
--- a/src/python/gem5/components/boards/x86_board.py
+++ b/src/python/gem5/components/boards/x86_board.py
@@ -28,7 +28,7 @@
 from .kernel_disk_workload import KernelDiskWorkload
 from ...resources.resource import AbstractResource
 from ...utils.override import overrides
-from .abstract_board import AbstractBoard
+from .abstract_system_board import AbstractSystemBoard
 from ...isas import ISA
 
 from m5.objects import (
@@ -61,7 +61,7 @@
 from typing import List, Sequence
 
 
-class X86Board(AbstractBoard, KernelDiskWorkload):
+class X86Board(AbstractSystemBoard, KernelDiskWorkload):
     """
     A board capable of full system simulation for X86.
 
@@ -88,7 +88,7 @@
             raise Exception("The X86Board requires a processor using the X86 "
                 f"ISA. Current processor ISA: '{processor.get_isa().name}'.")
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def _setup_board(self) -> None:
         self.pc = Pc()
 
@@ -251,31 +251,31 @@
 
         self.workload.e820_table.entries = entries
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def has_io_bus(self) -> bool:
         return True
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def get_io_bus(self) -> BaseXBar:
         return self.iobus
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def has_dma_ports(self) -> bool:
         return True
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def get_dma_ports(self) -> Sequence[Port]:
         return [self.pc.south_bridge.ide.dma, self.iobus.mem_side_ports]
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def has_coherent_io(self) -> bool:
         return True
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def get_mem_side_coherent_io_port(self) -> Port:
         return self.iobus.mem_side_ports
 
-    @overrides(AbstractBoard)
+    @overrides(AbstractSystemBoard)
     def _setup_memory_ranges(self):
         memory = self.get_memory()