configs: Update component API for memory size

This change updates the API in the component library for setting the
size of memory. Now, you can set the size of the memory system as an
argument to the memory object. Then, the board is responsible for
figuring out what the overall memory ranges should be which it
communicates back to the memory system.

This should make multi-channel memories easier to implement and it fixes
some confusion around things like the HiFive platform starting at
0x8000000.

Change-Id: Ibef5aafbbb1177a992950cdc2bd2634dcfb81eec
Signed-off-by: Jason Lowe-Power <jason@lowepower.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/49348
Maintainer: Bobby R. Bruce <bbruce@ucdavis.edu>
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Bobby R. Bruce <bbruce@ucdavis.edu>
This commit is contained in:
Jason Lowe-Power
2021-08-13 17:22:39 -07:00
committed by Jason Lowe-Power
parent 31c7d8cf46
commit 3a4e366042
7 changed files with 143 additions and 26 deletions

View File

@@ -25,6 +25,7 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from abc import ABCMeta, abstractmethod
from .mem_mode import MemMode
from m5.objects import System, Port, IOXBar, ClockDomain
@@ -164,6 +165,22 @@ class AbstractBoard(System):
"""
raise NotImplementedError
@abstractmethod
def setup_memory_ranges(self) -> None:
"""
Set the memory ranges for this board.
This is called by `connect_things`. It can query the board's memory
to determine the size and the set the memory ranges on the memory if
it needs to move the memory devices.
The simplest implementation just sets the board's memory range to be
the size of memory and memory's memory range to be the same as the
board. Full system implementations will likely need something more
complicated.
"""
raise NotImplementedError
@abstractmethod
def connect_things(self) -> None:
"""Connects all the components to the board.

View File

@@ -25,6 +25,7 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from m5.objects import (
AddrRange,
SrcClockDomain,
VoltageDomain,
Process,
@@ -74,8 +75,6 @@ class SimpleBoard(AbstractBoard):
self.clk_domain.clock = clk_freq
self.clk_domain.voltage_domain = VoltageDomain()
self.mem_ranges = memory.get_memory_ranges()
self.exit_on_work_items = exit_on_work_items
@overrides(AbstractBoard)
@@ -92,6 +91,9 @@ class SimpleBoard(AbstractBoard):
@overrides(AbstractBoard)
def connect_things(self) -> None:
# Before incorporating the memory, set up the memory ranges
self.setup_memory_ranges()
# Incorporate the cache hierarchy for the motherboard.
self.get_cache_hierarchy().incorporate_cache(self)
@@ -123,6 +125,15 @@ class SimpleBoard(AbstractBoard):
"Use `has_dma_ports()` to check this."
)
@overrides(AbstractBoard)
def setup_memory_ranges(self) -> None:
memory = self.get_memory()
# The simple board just has one memory range that is the size of the
# memory.
self.mem_ranges = [AddrRange(memory.get_size())]
memory.set_memory_range(self.mem_ranges)
def set_workload(self, binary: str) -> None:
"""Set up the system to run a specific binary.

View File

@@ -24,7 +24,14 @@
# (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.objects import SrcClockDomain, ClockDomain, VoltageDomain, Port, IOXBar
from m5.objects import (
SrcClockDomain,
ClockDomain,
VoltageDomain,
Port,
IOXBar,
AddrRange,
)
from .mem_mode import MemMode, mem_mode_to_string
from ..utils.override import overrides
@@ -61,12 +68,12 @@ class TestBoard(AbstractBoard):
clock=clk_freq, voltage_domain=VoltageDomain()
)
self.mem_ranges = memory.get_memory_ranges()
def connect_system_port(self, port: Port) -> None:
self.system_port = port
def connect_things(self) -> None:
self.set_memory_ranges()
self.get_cache_hierarchy().incorporate_cache(self)
self.get_processor().incorporate_processor(self)
@@ -101,3 +108,12 @@ class TestBoard(AbstractBoard):
@overrides(AbstractBoard)
def set_mem_mode(self, mem_mode: MemMode) -> None:
self.mem_mode = mem_mode_to_string(mem_mode=mem_mode)
@overrides(AbstractBoard)
def setup_memory_ranges(self) -> None:
memory = self.get_memory()
# The simple board just has one memory range that is the size of the
# memory.
self.mem_ranges = [AddrRange(memory.get_size())]
memory.set_memory_range(self.mem_ranges)

View File

@@ -49,9 +49,10 @@ from m5.objects import (
CowDiskImage,
RawDiskImage,
BaseXBar,
Port,
)
from m5.params import Port
from m5.util.convert import toMemorySize
from .simple_board import SimpleBoard
@@ -94,17 +95,17 @@ class X86Board(SimpleBoard):
"X86Motherboard will only work with the X86 ISA."
)
# Add the address range for the IO
# TODO: This should definitely NOT be hardcoded to 3GB
self.mem_ranges = [
AddrRange(Addr("3GB")), # All data
AddrRange(0xC0000000, size=0x100000), # For I/0
]
self.pc = Pc()
self.workload = X86FsLinux()
def _setup_io_devices(self):
""" Sets up the x86 IO devices.
Note: This is mostly copy-paste from prior X86 FS setups. Some of it
may not be documented and there may be bugs.
"""
# Constants similar to x86_traits.hh
IO_address_space_base = 0x8000000000000000
pci_config_address_space_base = 0xC000000000000000
@@ -267,7 +268,25 @@ class X86Board(SimpleBoard):
self.workload.e820_table.entries = entries
def connect_things(self) -> None:
super().connect_things()
# This board is a bit particular about the order that things are
# connected together.
# Before incorporating the memory or creating the I/O devices figure
# out the memory ranges.
self.setup_memory_ranges()
# Set up all of the I/O before we incorporate anything else.
self._setup_io_devices()
# Incorporate the cache hierarchy for the motherboard.
self.get_cache_hierarchy().incorporate_cache(self)
# Incorporate the processor into the motherboard.
self.get_processor().incorporate_processor(self)
# Incorporate the memory into the motherboard.
self.get_memory().incorporate_memory(self)
def set_workload(
self, kernel: str, disk_image: str, command: Optional[str] = None
@@ -340,3 +359,21 @@ class X86Board(SimpleBoard):
@overrides(AbstractBoard)
def get_dma_ports(self) -> Sequence[Port]:
return [self.pc.south_bridge.ide.dma, self.iobus.mem_side_ports]
@overrides(AbstractBoard)
def setup_memory_ranges(self):
memory = self.get_memory()
if memory.get_size() > toMemorySize("3GB"):
raise Exception(
"X86Board currently only supports memory sizes up "
"to 3GB because of the I/O hole."
)
data_range = AddrRange(memory.get_size())
memory.set_memory_range([data_range])
# Add the address range for the IO
self.mem_ranges = [
data_range, # All data
AddrRange(0xC0000000, size=0x100000), # For I/0
]

View File

@@ -41,17 +41,33 @@ class AbstractMemorySystem(SubSystem):
@abstractmethod
def incorporate_memory(self, board: AbstractBoard) -> None:
"""This function completes all of the necessary steps to add this
memory system to the board."""
raise NotImplementedError
@abstractmethod
def get_mem_ports(self) -> Sequence[Tuple[AddrRange, Port]]:
"""Get the ports to connect this memory system to the cache"""
raise NotImplementedError
@abstractmethod
def get_memory_controllers(self) -> List[MemCtrl]:
"""Get all of the memory controllers in this memory system"""
raise NotImplementedError
@abstractmethod
def get_memory_ranges(self) -> List[AddrRange]:
"""All of the memory ranges that this memory system responds to."""
def get_size(self) -> int:
"""Returns the total size of the memory system"""
raise NotImplementedError
@abstractmethod
def set_memory_range(self, ranges: List[AddrRange]) -> None:
"""Set the total range for this memory system
May pass multiple non-overlapping ranges. The total size of the ranges
should match the size of the memory.
If this memory system is incompatible with the ranges, an exception
will be raised.
"""
raise NotImplementedError

View File

@@ -3,6 +3,7 @@ import os
import configparser
from m5.objects import DRAMsim3, AddrRange, Port, MemCtrl
from m5.util.convert import toMemorySize
from ..utils.override import overrides
from ..boards.abstract_board import AbstractBoard
@@ -95,9 +96,8 @@ class SingleChannel(AbstractMemorySystem):
"""
super(SingleChannel, self).__init__()
self.mem_ctrl = DRAMSim3MemCtrl(mem_type, 1)
if size:
self.mem_ctrl.range = AddrRange(size)
else:
self._size = toMemorySize(size)
if not size:
raise NotImplementedError(
"DRAMSim3 memory controller requires a size parameter."
)
@@ -115,8 +115,17 @@ class SingleChannel(AbstractMemorySystem):
return [self.mem_ctrl]
@overrides(AbstractMemorySystem)
def get_memory_ranges(self):
return [self.mem_ctrl.range]
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:
raise Exception(
"Single channel DRAMSim memory controller requires a single "
"range which matches the memory's size."
)
self.mem_ctrl.range = ranges[0]
def SingleChannelDDR3_1600(

View File

@@ -32,6 +32,7 @@ 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 List, Sequence, Tuple, Type, Optional
@@ -59,12 +60,12 @@ class SingleChannelMemory(AbstractMemorySystem):
self._dram = dram_interface_class()
if size:
self._dram.range = size
self._size = toMemorySize(size)
else:
self._dram.range = AddrRange(self.get_size(self._dram))
self._size = self._get_dram_size(self._dram)
self.mem_ctrl = MemCtrl(dram=self._dram)
def get_size(self, dram: DRAMInterface) -> int:
def _get_dram_size(self, dram: DRAMInterface) -> int:
return (
dram.device_size.value
* dram.devices_per_rank.value
@@ -84,8 +85,18 @@ class SingleChannelMemory(AbstractMemorySystem):
return [self.mem_ctrl]
@overrides(AbstractMemorySystem)
def get_memory_ranges(self):
return [self._dram.range]
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