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:
committed by
Jason Lowe-Power
parent
31c7d8cf46
commit
3a4e366042
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user