stdlib: Removing SingleChannelMemory

This change removes the code base for SingleChannelMemory and
replaces it with MultiChannelMemory. muli_channel defines all
the classes that were defined by single_channel. Basically any
SingleChannelMemory could be thought of as a MultiChannelMemory
with 1 channel.

Change-Id: If96079d5f77be5a3ba26d2c2ddb98f5c60375cd8
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/53304
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/arm-hello.py b/configs/example/gem5_library/arm-hello.py
index 540a96b..5a2f46c 100644
--- a/configs/example/gem5_library/arm-hello.py
+++ b/configs/example/gem5_library/arm-hello.py
@@ -47,11 +47,11 @@
 from gem5.isas import ISA
 from gem5.utils.requires import requires
 from gem5.resources.resource import Resource
+from gem5.components.memory import SingleChannelDDR3_1600
+from gem5.components.processors.cpu_types import CPUTypes
 from gem5.components.boards.simple_board import SimpleBoard
 from gem5.components.cachehierarchies.classic.no_cache import NoCache
-from gem5.components.memory.single_channel import SingleChannelDDR3_1600
 from gem5.components.processors.simple_processor import SimpleProcessor
-from gem5.components.processors.cpu_types import CPUTypes
 
 # This check ensures the gem5 binary is compiled to the ARM ISA target. If not,
 # an exception will be thrown.
diff --git a/configs/example/gem5_library/riscv-fs.py b/configs/example/gem5_library/riscv-fs.py
index f46a345..4d0a2c8 100644
--- a/configs/example/gem5_library/riscv-fs.py
+++ b/configs/example/gem5_library/riscv-fs.py
@@ -43,7 +43,7 @@
 from m5.objects import Root
 
 from gem5.components.boards.riscv_board import RiscvBoard
-from gem5.components.memory.single_channel import SingleChannelDDR3_1600
+from gem5.components.memory import SingleChannelDDR3_1600
 from gem5.components.processors.simple_processor import SimpleProcessor
 from gem5.components.cachehierarchies.classic.\
     private_l1_private_l2_cache_hierarchy import (
diff --git a/configs/example/gem5_library/x86-ubuntu-run.py b/configs/example/gem5_library/x86-ubuntu-run.py
index 9979c14..622f4f3 100644
--- a/configs/example/gem5_library/x86-ubuntu-run.py
+++ b/configs/example/gem5_library/x86-ubuntu-run.py
@@ -47,8 +47,8 @@
 import m5
 from m5.objects import Root
 
-from gem5.prebuilt.demo.x86_demo_board import X86DemoBoard
 from gem5.resources.resource import Resource
+from gem5.prebuilt.demo.x86_demo_board import X86DemoBoard
 
 # Here we setup the board. The prebuilt X86DemoBoard allows for Full-System X86
 # simulation.
@@ -64,4 +64,4 @@
 
 root = Root(full_system=True, system=board)
 m5.instantiate()
-m5.simulate()
\ No newline at end of file
+m5.simulate()
diff --git a/src/python/SConscript b/src/python/SConscript
index 4487bdd..3d91ccb 100644
--- a/src/python/SConscript
+++ b/src/python/SConscript
@@ -133,8 +133,9 @@
 PySource('gem5.components.memory', 'gem5/components/memory/__init__.py')
 PySource('gem5.components.memory', 'gem5/components/memory/abstract_memory_system.py')
 PySource('gem5.components.memory', 'gem5/components/memory/dramsim_3.py')
-PySource('gem5.components.memory', 'gem5/components/memory/single_channel.py')
 PySource('gem5.components.memory', 'gem5/components/memory/simple.py')
+PySource('gem5.components.memory', 'gem5/components/memory/memory.py')
+PySource('gem5.components.memory', 'gem5/components/memory/single_channel.py')
 PySource('gem5.components.memory', 'gem5/components/memory/multi_channel.py')
 PySource('gem5.components.memory.dram_interfaces',
     'gem5/components/memory/dram_interfaces/__init__.py')
diff --git a/src/python/gem5/components/memory/__init__.py b/src/python/gem5/components/memory/__init__.py
index e69de29..5e16865 100644
--- a/src/python/gem5/components/memory/__init__.py
+++ b/src/python/gem5/components/memory/__init__.py
@@ -0,0 +1,36 @@
+# 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 .single_channel import SingleChannelDDR3_1600
+from .single_channel import SingleChannelDDR3_2133
+from .single_channel import SingleChannelDDR4_2400
+from .single_channel import SingleChannelHBM
+from .single_channel import SingleChannelLPDDR3_1600
+from .multi_channel import DualChannelDDR3_1600
+from .multi_channel import DualChannelDDR3_2133
+from .multi_channel import DualChannelDDR4_2400
+from .multi_channel import HBM2Stack
+from .multi_channel import DualChannelLPDDR3_1600
diff --git a/src/python/gem5/components/memory/memory.py b/src/python/gem5/components/memory/memory.py
new file mode 100644
index 0000000..929a6ae
--- /dev/null
+++ b/src/python/gem5/components/memory/memory.py
@@ -0,0 +1,185 @@
+# 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.
+
+""" Channeled "generic" DDR memory controllers
+"""
+
+from math import log
+from ...utils.override import overrides
+from m5.util.convert import toMemorySize
+from ..boards.abstract_board import AbstractBoard
+from .abstract_memory_system import AbstractMemorySystem
+from m5.objects import AddrRange, DRAMInterface, MemCtrl, Port
+from typing import Type, Sequence, Tuple, List, Optional, Union
+
+
+def _try_convert(val, cls):
+    try:
+        return cls(val)
+    except:
+        raise Exception(f"Could not convert {val} to {cls}")
+
+def _isPow2(num):
+    log_num = int(log(num, 2))
+    if 2 ** log_num != num:
+        return False
+    else:
+        return True
+
+class ChanneledMemory(AbstractMemorySystem):
+    """A class to implement multi-channel memory system
+
+    This class can take a DRAM Interface as a parameter to model a multi
+    channel DDR DRAM memory system.
+    """
+    def __init__(
+        self,
+        dram_interface_class: Type[DRAMInterface],
+        num_channels: Union[int, str],
+        interleaving_size: Union[int, str],
+        size: Optional[str] = None,
+        addr_mapping: Optional[str] = None,
+    ) -> None:
+        """
+        :param dram_interface_class: The DRAM interface type to create with
+            this memory controller
+        :param num_channels: The number of channels that needs to be
+        simulated
+        :param size: Optionally specify the size of the DRAM controller's
+            address space. By default, it starts at 0 and ends at the size of
+            the DRAM device specified
+        :param addr_mapping: Defines the address mapping scheme to be used.
+            If None, it is defaulted to addr_mapping from dram_interface_class.
+        :param interleaving_size: Defines the interleaving size of the multi-
+            channel memory system. By default, it is equivalent to the atom
+            size, i.e., 64.
+        """
+        num_channels = _try_convert(num_channels, int)
+        interleaving_size = _try_convert(interleaving_size, int)
+
+        if size:
+            size = _try_convert(size, str)
+
+        if addr_mapping:
+            addr_mapping = _try_convert(addr_mapping, str)
+
+        super().__init__()
+        self._dram_class = dram_interface_class
+        self._num_channels = num_channels
+
+        if not _isPow2(interleaving_size):
+            raise ValueError("Memory interleaving size should be a power of 2")
+        self._intlv_size = interleaving_size
+
+        if addr_mapping:
+            self._addr_mapping = addr_mapping
+        else:
+            self._addr_mapping = self._dram_class.addr_mapping.value
+
+        if size:
+            self._size = toMemorySize(size)
+        else:
+            self._size = self._get_dram_size(num_channels, self._dram_class)
+
+        self._dram = [
+            self._dram_class(addr_mapping=self._addr_mapping)
+            for _ in range(num_channels)
+        ]
+        self.mem_ctrl = [
+            MemCtrl(dram=self._dram[i]) for i in range(num_channels)
+        ]
+
+    def _get_dram_size(self, num_channels: int, dram: DRAMInterface) -> int:
+        return num_channels * (
+            dram.device_size.value
+            * dram.devices_per_rank.value
+            * dram.ranks_per_channel.value
+        )
+
+    def _interleave_addresses(self):
+        if self._addr_mapping == "RoRaBaChCo":
+            rowbuffer_size = (
+                self._dram_class.device_rowbuffer_size.value
+                * self._dram_class.devices_per_rank.value
+            )
+            intlv_low_bit = log(rowbuffer_size, 2)
+        elif self._addr_mapping in ["RoRaBaCoCh", "RoCoRaBaCh"]:
+            intlv_low_bit = log(self._intlv_size, 2)
+        else:
+            raise ValueError(
+                "Only these address mappings are supported: "
+                "RoRaBaChCo, RoRaBaCoCh, RoCoRaBaCh"
+            )
+
+        intlv_bits = log(self._num_channels, 2)
+        for i, ctrl in enumerate(self.mem_ctrl):
+            ctrl.dram.range = AddrRange(
+                start=self._mem_range.start,
+                size=self._mem_range.size(),
+                intlvHighBit=intlv_low_bit + intlv_bits - 1,
+                xorHighBit=0,
+                intlvBits=intlv_bits,
+                intlvMatch=i,
+            )
+
+    @overrides(AbstractMemorySystem)
+    def incorporate_memory(self, board: AbstractBoard) -> None:
+        if self._intlv_size < int(board.get_cache_line_size()):
+            raise ValueError(
+                "Memory interleaving size can not be smaller than"
+                " board's cache line size.\nBoard's cache line size: "
+                f"{board.get_cache_line_size()}\n, This memory's interleaving "
+                f"size: {self._intlv_size}"
+            )
+
+    @overrides(AbstractMemorySystem)
+    def get_mem_ports(self) -> Sequence[Tuple[AddrRange, Port]]:
+        return [(ctrl.dram.range, ctrl.port) for ctrl in self.mem_ctrl]
+
+    @overrides(AbstractMemorySystem)
+    def get_memory_controllers(self) -> List[MemCtrl]:
+        return [ctrl for ctrl in self.mem_ctrl]
+
+    @overrides(AbstractMemorySystem)
+    def get_size(self) -> int:
+        return self._size
+
+    @overrides(AbstractMemorySystem)
+    def set_memory_range(self, ranges: List[AddrRange]) -> None:
+        """Need to add support for non-contiguous non overlapping ranges in
+        the future.
+        """
+        if len(ranges) != 1 or ranges[0].size() != self._size:
+            raise Exception(
+                "Multi channel memory controller requires a single range "
+                "which matches the memory's size.\n"
+                f"The range size: {range[0].size()}\n"
+                f"This memory's size: {self._size}"
+            )
+        self._mem_range = ranges[0]
+        self._interleave_addresses()
+
+
diff --git a/src/python/gem5/components/memory/multi_channel.py b/src/python/gem5/components/memory/multi_channel.py
index 8736f02..d54347a 100644
--- a/src/python/gem5/components/memory/multi_channel.py
+++ b/src/python/gem5/components/memory/multi_channel.py
@@ -24,182 +24,15 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-"""Multi channel "generic" DDR memory controllers
-"""
-
-from math import log
-from ...utils.override import overrides
-from m5.util.convert import toMemorySize
-from ..boards.abstract_board import AbstractBoard
+from .memory import ChanneledMemory
 from .abstract_memory_system import AbstractMemorySystem
-from m5.objects import AddrRange, DRAMInterface, MemCtrl, Port
-from typing import Type, Sequence, Tuple, List, Optional, Union
 
-
-def _try_convert(val, cls):
-    try:
-        return cls(val)
-    except:
-        raise Exception(f"Could not convert {val} to {cls}")
-
-def _isPow2(num):
-    log_num = int(log(num, 2))
-    if 2 ** log_num != num:
-        return False
-    else:
-        return True
-
-class MultiChannelMemory(AbstractMemorySystem):
-    """A class to implement multi-channel memory system
-
-    This class can take a DRAM Interface as a parameter to model a multi
-    channel DDR DRAM memory system.
-    """
-    def __init__(
-        self,
-        dram_interface_class: Type[DRAMInterface],
-        num_channels: Union[int, str],
-        interleaving_size: Union[int, str],
-        size: Optional[str] = None,
-        addr_mapping: Optional[str] = None,
-    ) -> None:
-        """
-        :param dram_interface_class: The DRAM interface type to create with
-            this memory controller
-        :param num_channels: The number of channels that needs to be
-        simulated
-        :param size: Optionally specify the size of the DRAM controller's
-            address space. By default, it starts at 0 and ends at the size of
-            the DRAM device specified
-        :param addr_mapping: Defines the address mapping scheme to be used.
-            If None, it is defaulted to addr_mapping from dram_interface_class.
-        :param interleaving_size: Defines the interleaving size of the multi-
-            channel memory system. By default, it is equivalent to the atom
-            size, i.e., 64.
-        """
-        num_channels = _try_convert(num_channels, int)
-        interleaving_size = _try_convert(interleaving_size, int)
-
-        if size:
-            size = _try_convert(size, str)
-
-        if addr_mapping:
-            addr_mapping = _try_convert(addr_mapping, str)
-
-        super().__init__()
-        self._dram_class = dram_interface_class
-        self._num_channels = num_channels
-
-        if not _isPow2(interleaving_size):
-            raise ValueError("Memory interleaving size should be a power of 2")
-        self._intlv_size = interleaving_size
-
-        if addr_mapping:
-            self._addr_mapping = addr_mapping
-        else:
-            self._addr_mapping = self._dram_class.addr_mapping.value
-
-        if size:
-            self._size = toMemorySize(size)
-        else:
-            self._size = self._get_dram_size(num_channels, self._dram_class)
-
-        self._dram = [
-            self._dram_class(addr_mapping=self._addr_mapping)
-            for _ in range(num_channels)
-        ]
-        self.mem_ctrl = [
-            MemCtrl(dram=self._dram[i]) for i in range(num_channels)
-        ]
-
-    def _get_dram_size(self, num_channels: int, dram: DRAMInterface) -> int:
-        return num_channels * (
-            dram.device_size.value
-            * dram.devices_per_rank.value
-            * dram.ranks_per_channel.value
-        )
-
-    def _interleave_addresses(self):
-        if self._addr_mapping == "RoRaBaChCo":
-            rowbuffer_size = (
-                self._dram_class.device_rowbuffer_size.value
-                * self._dram_class.devices_per_rank.value
-            )
-            intlv_low_bit = log(rowbuffer_size, 2)
-        elif self._addr_mapping in ["RoRaBaCoCh", "RoCoRaBaCh"]:
-            intlv_low_bit = log(self._intlv_size, 2)
-        else:
-            raise ValueError(
-                "Only these address mappings are supported: "
-                "RoRaBaChCo, RoRaBaCoCh, RoCoRaBaCh"
-            )
-
-        intlv_bits = log(self._num_channels, 2)
-        for i, ctrl in enumerate(self.mem_ctrl):
-            ctrl.dram.range = AddrRange(
-                start=self._mem_range.start,
-                size=self._mem_range.size(),
-                intlvHighBit=intlv_low_bit + intlv_bits - 1,
-                xorHighBit=0,
-                intlvBits=intlv_bits,
-                intlvMatch=i,
-            )
-
-    @overrides(AbstractMemorySystem)
-    def incorporate_memory(self, board: AbstractBoard) -> None:
-        if self._intlv_size < int(board.get_cache_line_size()):
-            raise ValueError(
-                "Memory interleaving size can not be smaller than"
-                " board's cache line size.\nBoard's cache line size: "
-                f"{board.get_cache_line_size()}\n, This memory's interleaving "
-                f"size: {self._intlv_size}"
-            )
-
-    @overrides(AbstractMemorySystem)
-    def get_mem_ports(self) -> Sequence[Tuple[AddrRange, Port]]:
-        return [(ctrl.dram.range, ctrl.port) for ctrl in self.mem_ctrl]
-
-    @overrides(AbstractMemorySystem)
-    def get_memory_controllers(self) -> List[MemCtrl]:
-        return [ctrl for ctrl in self.mem_ctrl]
-
-    @overrides(AbstractMemorySystem)
-    def get_size(self) -> int:
-        return self._size
-
-    @overrides(AbstractMemorySystem)
-    def set_memory_range(self, ranges: List[AddrRange]) -> None:
-        """Need to add support for non-contiguous non overlapping ranges in
-        the future.
-        """
-        if len(ranges) != 1 or ranges[0].size() != self._size:
-            raise Exception(
-                "Multi channel memory controller requires a single range "
-                "which matches the memory's size.\n"
-                f"The range size: {range[0].size()}\n"
-                f"This memory's size: {self._size}"
-            )
-        self._mem_range = ranges[0]
-        self._interleave_addresses()
-
-
+from typing import Optional
 from .dram_interfaces.ddr3 import DDR3_1600_8x8, DDR3_2133_8x8
 from .dram_interfaces.ddr4 import DDR4_2400_8x8
 from .dram_interfaces.lpddr3 import LPDDR3_1600_1x32
-from .dram_interfaces.hbm import HBM_1000_4H_1x64, HBM_1000_4H_1x128
+from .dram_interfaces.hbm import HBM_1000_4H_1x64
 
-def SingleChannelDDR3_1600(
-    size: Optional[str] = None,
-) -> AbstractMemorySystem:
-    """
-    A single channel memory system using DDR3_1600_8x8 based DIMM
-    """
-    return MultiChannelMemory(
-        DDR3_1600_8x8,
-        1,
-        64,
-        size=size,
-    )
 
 def DualChannelDDR3_1600(
     size: Optional[str] = None,
@@ -207,103 +40,55 @@
     """
     A dual channel memory system using DDR3_1600_8x8 based DIMM
     """
-    return MultiChannelMemory(
+    return ChanneledMemory(
         DDR3_1600_8x8,
         2,
         64,
         size=size,
     )
 
-def SingleChannelDDR3_2133(
-    size: Optional[str] = None,
-) -> AbstractMemorySystem:
-    """
-    A single channel memory system using DDR3_2133_8x8 based DIMM
-    """
-    return MultiChannelMemory(
-        DDR3_2133_8x8,
-        1,
-        64,
-        size=size,
-    )
-
 def DualChannelDDR3_2133(
     size: Optional[str] = None,
 ) -> AbstractMemorySystem:
     """
     A dual channel memory system using DDR3_2133_8x8 based DIMM
     """
-    return MultiChannelMemory(
+    return ChanneledMemory(
         DDR3_2133_8x8,
         2,
         64,
         size=size,
     )
 
-def SingleChannelDDR4_2400(
-    size: Optional[str] = None,
-) -> AbstractMemorySystem:
-    """
-    A single channel memory system using DDR4_2400_8x8 based DIMM
-    """
-    return MultiChannelMemory(
-        DDR4_2400_8x8,
-        1,
-        64,
-        size=size,
-    )
-
 def DualChannelDDR4_2400(
     size: Optional[str] = None,
 ) -> AbstractMemorySystem:
     """
     A dual channel memory system using DDR4_2400_8x8 based DIMM
     """
-    return MultiChannelMemory(
+    return ChanneledMemory(
         DDR4_2400_8x8,
         2,
         64,
         size=size,
     )
 
-def SingleChannelLPDDR3_1600(
-    size: Optional[str] = None,
-) -> AbstractMemorySystem:
-    return MultiChannelMemory(
-        LPDDR3_1600_1x32,
-        1,
-        64,
-        size=size,
-    )
-
 def DualChannelLPDDR3_1600(
     size: Optional[str] = None,
 ) -> AbstractMemorySystem:
-    return MultiChannelMemory(
+    return ChanneledMemory(
         LPDDR3_1600_1x32,
         2,
         64,
         size=size,
     )
 
-def SingleChannelHBM(
-    size: Optional[str] = None,
-) -> AbstractMemorySystem:
-    if not size:
-        size = "256MiB"
-    return MultiChannelMemory(
-        HBM_1000_4H_1x128,
-        1,
-        64,
-        size=size
-    )
-
 def HBM2Stack(
     size: Optional[str] = None,
 ) -> AbstractMemorySystem:
     if not size:
         size = "4GiB"
-    return MultiChannelMemory(
+    return ChanneledMemory(
         HBM_1000_4H_1x64,
         16,
         64,
diff --git a/src/python/gem5/components/memory/single_channel.py b/src/python/gem5/components/memory/single_channel.py
index 11a0b15..57ce232 100644
--- a/src/python/gem5/components/memory/single_channel.py
+++ b/src/python/gem5/components/memory/single_channel.py
@@ -24,113 +24,74 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-"""Single channel "generic" DDR memory controllers
-"""
-
-from ..boards.abstract_board import AbstractBoard
+from .memory import ChanneledMemory
 from .abstract_memory_system import AbstractMemorySystem
-from ...utils.override import overrides
 
-from m5.objects import AddrRange, DRAMInterface, MemCtrl, Port
-from m5.util.convert import toMemorySize
+from typing import Optional
 
-from typing import List, Sequence, Tuple, Type, Optional
-
-
-class SingleChannelMemory(AbstractMemorySystem):
-    """A simple implementation of a single channel memory system
-
-    This class can take a DRAM Interface as a parameter to model many different
-    DDR memory systems.
-    """
-
-    def __init__(
-        self,
-        dram_interface_class: Type[DRAMInterface],
-        size: Optional[str] = None,
-    ):
-        """
-        :param dram_interface_class: The DRAM interface type to create with
-            this memory controller
-        :param size: Optionally specify the size of the DRAM controller's
-            address space. By default, it starts at 0 and ends at the size of
-            the DRAM device specified
-        """
-        super().__init__()
-
-        self._dram = dram_interface_class()
-        if size:
-            self._size = toMemorySize(size)
-        else:
-            self._size = self._get_dram_size(self._dram)
-        self.mem_ctrl = MemCtrl(dram=self._dram)
-
-    def _get_dram_size(self, dram: DRAMInterface) -> int:
-        return (
-            dram.device_size.value
-            * dram.devices_per_rank.value
-            * dram.ranks_per_channel.value
-        )
-
-    @overrides(AbstractMemorySystem)
-    def incorporate_memory(self, board: AbstractBoard) -> None:
-        pass
-
-    @overrides(AbstractMemorySystem)
-    def get_mem_ports(self) -> Tuple[Sequence[AddrRange], Port]:
-        return [(self._dram.range, self.mem_ctrl.port)]
-
-    @overrides(AbstractMemorySystem)
-    def get_memory_controllers(self) -> List[MemCtrl]:
-        return [self.mem_ctrl]
-
-    @overrides(AbstractMemorySystem)
-    def get_size(self) -> int:
-        return self._size
-
-    @overrides(AbstractMemorySystem)
-    def set_memory_range(self, ranges: List[AddrRange]) -> None:
-        if len(ranges) != 1 or ranges[0].size() != self._size:
-            print(ranges[0].size())
-            raise Exception(
-                "Single channel memory controller requires a single range "
-                "which matches the memory's size."
-            )
-        self.mem_ctrl.dram.range = ranges[0]
-
-
-from .dram_interfaces.ddr3 import DDR3_1600_8x8, DDR3_2133_8x8
 from .dram_interfaces.ddr4 import DDR4_2400_8x8
-from .dram_interfaces.lpddr3 import LPDDR3_1600_1x32
 from .dram_interfaces.hbm import HBM_1000_4H_1x128
-
-# Enumerate all of the different DDR memory systems we support
-def SingleChannelDDR3_1600(size: Optional[str] = None) -> AbstractMemorySystem:
-    """
-    A single channel memory system using a single DDR3_1600_8x8 based DIMM
-    """
-    return SingleChannelMemory(DDR3_1600_8x8, size)
+from .dram_interfaces.lpddr3 import LPDDR3_1600_1x32
+from .dram_interfaces.ddr3 import DDR3_1600_8x8, DDR3_2133_8x8
 
 
-def SingleChannelDDR3_2133(size: Optional[str] = None) -> AbstractMemorySystem:
+def SingleChannelDDR3_1600(
+    size: Optional[str] = None,
+) -> AbstractMemorySystem:
     """
-    A single channel memory system using a single DDR3_2133_8x8 based DIMM
+    A single channel memory system using DDR3_1600_8x8 based DIMM
     """
-    return SingleChannelMemory(DDR3_2133_8x8, size)
+    return ChanneledMemory(
+        DDR3_1600_8x8,
+        1,
+        64,
+        size=size,
+    )
 
-
-def SingleChannelDDR4_2400(size: Optional[str] = None) -> AbstractMemorySystem:
+def SingleChannelDDR3_2133(
+    size: Optional[str] = None,
+) -> AbstractMemorySystem:
     """
-    A single channel memory system using a single DDR4_2400_8x8 based DIMM
+    A single channel memory system using DDR3_2133_8x8 based DIMM
     """
-    return SingleChannelMemory(DDR4_2400_8x8, size)
+    return ChanneledMemory(
+        DDR3_2133_8x8,
+        1,
+        64,
+        size=size,
+    )
 
+def SingleChannelDDR4_2400(
+    size: Optional[str] = None,
+) -> AbstractMemorySystem:
+    """
+    A single channel memory system using DDR4_2400_8x8 based DIMM
+    """
+    return ChanneledMemory(
+        DDR4_2400_8x8,
+        1,
+        64,
+        size=size,
+    )
 
 def SingleChannelLPDDR3_1600(
     size: Optional[str] = None,
 ) -> AbstractMemorySystem:
-    return SingleChannelMemory(LPDDR3_1600_1x32, size)
+    return ChanneledMemory(
+        LPDDR3_1600_1x32,
+        1,
+        64,
+        size=size,
+    )
 
-
-def SingleChannelHBM(size: Optional[str] = None) -> AbstractMemorySystem:
-    return SingleChannelMemory(HBM_1000_4H_1x128, size)
+def SingleChannelHBM(
+    size: Optional[str] = None,
+) -> AbstractMemorySystem:
+    if not size:
+        size = "256MiB"
+    return ChanneledMemory(
+        HBM_1000_4H_1x128,
+        1,
+        64,
+        size=size
+    )
diff --git a/tests/gem5/configs/boot_kvm_fork_run.py b/tests/gem5/configs/boot_kvm_fork_run.py
index 14d6a4b..2cd180a 100644
--- a/tests/gem5/configs/boot_kvm_fork_run.py
+++ b/tests/gem5/configs/boot_kvm_fork_run.py
@@ -46,7 +46,7 @@
 from gem5.components.boards.x86_board import X86Board
 from gem5.coherence_protocol import CoherenceProtocol
 from gem5.isas import ISA
-from gem5.components.memory.single_channel import SingleChannelDDR3_1600
+from gem5.components.memory import SingleChannelDDR3_1600
 from gem5.components.processors.cpu_types import CPUTypes
 from gem5.components.processors.simple_switchable_processor import (
     SimpleSwitchableProcessor,
diff --git a/tests/gem5/configs/boot_kvm_switch_exit.py b/tests/gem5/configs/boot_kvm_switch_exit.py
index 68651eb..5aa19f5 100644
--- a/tests/gem5/configs/boot_kvm_switch_exit.py
+++ b/tests/gem5/configs/boot_kvm_switch_exit.py
@@ -33,10 +33,10 @@
 import m5
 from m5.objects import Root
 
+from gem5.isas import ISA
 from gem5.components.boards.x86_board import X86Board
 from gem5.coherence_protocol import CoherenceProtocol
-from gem5.isas import ISA
-from gem5.components.memory.single_channel import SingleChannelDDR3_1600
+from gem5.components.memory import SingleChannelDDR3_1600
 from gem5.components.processors.cpu_types import CPUTypes
 from gem5.components.processors.simple_switchable_processor import (
     SimpleSwitchableProcessor,
diff --git a/tests/gem5/configs/parsec_disk_run.py b/tests/gem5/configs/parsec_disk_run.py
index c65be10..1315c58 100644
--- a/tests/gem5/configs/parsec_disk_run.py
+++ b/tests/gem5/configs/parsec_disk_run.py
@@ -42,7 +42,7 @@
 
 from gem5.resources.resource import Resource
 from gem5.components.boards.x86_board import X86Board
-from gem5.components.memory.single_channel import SingleChannelDDR3_1600
+from gem5.components.memory import SingleChannelDDR3_1600
 from gem5.components.processors.simple_switchable_processor import (
     SimpleSwitchableProcessor,
 )
diff --git a/tests/gem5/configs/riscv_boot_exit_run.py b/tests/gem5/configs/riscv_boot_exit_run.py
index 45ce62c..38f57d8 100644
--- a/tests/gem5/configs/riscv_boot_exit_run.py
+++ b/tests/gem5/configs/riscv_boot_exit_run.py
@@ -125,7 +125,7 @@
     )
 
 # Setup the system memory.
-python_module = "gem5.components.memory.multi_channel"
+python_module = "gem5.components.memory"
 memory_class = getattr(
     importlib.import_module(python_module), args.dram_class
 )
diff --git a/tests/gem5/configs/simple_binary_run.py b/tests/gem5/configs/simple_binary_run.py
index b41f26d..fa4faa0 100644
--- a/tests/gem5/configs/simple_binary_run.py
+++ b/tests/gem5/configs/simple_binary_run.py
@@ -34,11 +34,11 @@
 from m5.objects import Root
 
 from gem5.resources.resource import Resource
+from gem5.components.processors.cpu_types import CPUTypes
+from gem5.components.memory import SingleChannelDDR3_1600
 from gem5.components.boards.simple_board import SimpleBoard
 from gem5.components.cachehierarchies.classic.no_cache import NoCache
-from gem5.components.memory.single_channel import SingleChannelDDR3_1600
 from gem5.components.processors.simple_processor import SimpleProcessor
-from gem5.components.processors.cpu_types import CPUTypes
 
 import argparse
 
diff --git a/tests/gem5/configs/x86_boot_exit_run.py b/tests/gem5/configs/x86_boot_exit_run.py
index 58e7713..96d1dad 100644
--- a/tests/gem5/configs/x86_boot_exit_run.py
+++ b/tests/gem5/configs/x86_boot_exit_run.py
@@ -161,7 +161,7 @@
 # Setup the system memory.
 # Warning: This must be kept at 3GB for now. X86Motherboard does not support
 # anything else right now!
-python_module = "gem5.components.memory.multi_channel"
+python_module = "gem5.components.memory"
 memory_class = getattr(
     importlib.import_module(python_module), args.dram_class
 )
diff --git a/tests/gem5/traffic_gen/test_memory_traffic_gen.py b/tests/gem5/traffic_gen/test_memory_traffic_gen.py
index 13b4638..5910f96 100644
--- a/tests/gem5/traffic_gen/test_memory_traffic_gen.py
+++ b/tests/gem5/traffic_gen/test_memory_traffic_gen.py
@@ -89,14 +89,12 @@
 
 
 cache_classes = ["NoCache", "PrivateL1", "PrivateL1PrivateL2", "MESITwoLevel"]
-common_memory_classes = [
+memory_classes = [
     "SingleChannelDDR3_1600",
     "SingleChannelDDR3_2133",
     "SingleChannelDDR4_2400",
     "SingleChannelLPDDR3_1600",
     "SingleChannelHBM",
-]
-multi_memory_classes = [
     "DualChannelDDR3_1600",
     "DualChannelDDR3_2133",
     "DualChannelDDR4_2400",
@@ -135,19 +133,10 @@
                 )
 
 create_single_core_tests(
-    "gem5.components.memory.single_channel",
-    common_memory_classes,
+    "gem5.components.memory",
+    memory_classes,
 )
 create_dual_core_tests(
-    "gem5.components.memory.single_channel",
-    common_memory_classes,
-)
-
-create_single_core_tests(
-    "gem5.components.memory.multi_channel",
-    common_memory_classes + multi_memory_classes,
-)
-create_dual_core_tests(
-    "gem5.components.memory.multi_channel",
-    common_memory_classes + multi_memory_classes,
+    "gem5.components.memory",
+    memory_classes,
 )