stdlib: Add a component for HBM2 stack
This change adds a component for HBM2 stack in the gem5 stdlib. For HBM2 stack, the atom size is used to interleave across pseudo channels in a single physical channel or HBMCtrl and the bits beyond that will be used to interleave across channels/controllers. Change-Id: I95a279504981a5c000f38c9a6ad0e03484eb258e Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/61489 Reviewed-by: Jason Lowe-Power <power.jg@gmail.com> Tested-by: kokoro <noreply+kokoro@google.com> Maintainer: Jason Lowe-Power <power.jg@gmail.com>
This commit is contained in:
@@ -148,6 +148,7 @@ 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', 'gem5/components/memory/hbm.py')
|
||||
PySource('gem5.components.memory.dram_interfaces',
|
||||
'gem5/components/memory/dram_interfaces/__init__.py')
|
||||
PySource('gem5.components.memory.dram_interfaces',
|
||||
|
||||
@@ -70,6 +70,9 @@ class NoCache(AbstractClassicCacheHierarchy):
|
||||
membus = SystemXBar(width=64)
|
||||
membus.badaddr_responder = BadAddr()
|
||||
membus.default = membus.badaddr_responder.pio
|
||||
# the max. routing table size needs to be set
|
||||
# to a higher value for HBM2 stack
|
||||
membus.max_routing_table_size = 2048
|
||||
return membus
|
||||
|
||||
def __init__(
|
||||
|
||||
@@ -32,5 +32,5 @@ 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
|
||||
from .hbm import HBM2Stack
|
||||
|
||||
@@ -194,3 +194,85 @@ class HBM_1000_4H_1x64(HBM_1000_4H_1x128):
|
||||
|
||||
# self refresh exit time
|
||||
tXS = "65ns"
|
||||
|
||||
|
||||
# A single HBM2 x64 interface (tested with HBMCtrl in gem5)
|
||||
# to be used as a single pseudo channel. The timings are based
|
||||
# on HBM gen2 specifications. 4H stack, 8Gb per die and total capacity
|
||||
# of 4GiB.
|
||||
class HBM_2000_4H_1x64(DRAMInterface):
|
||||
|
||||
# 64-bit interface for a single pseudo channel
|
||||
device_bus_width = 64
|
||||
|
||||
# HBM2 supports BL4
|
||||
burst_length = 4
|
||||
|
||||
# size of channel in bytes, 4H stack of 8Gb dies is 4GiB per stack;
|
||||
# with 16 pseudo channels, 256MiB per pseudo channel
|
||||
device_size = "256MiB"
|
||||
|
||||
device_rowbuffer_size = "1KiB"
|
||||
|
||||
# 1x128 configuration
|
||||
devices_per_rank = 1
|
||||
|
||||
ranks_per_channel = 1
|
||||
|
||||
banks_per_rank = 16
|
||||
bank_groups_per_rank = 4
|
||||
|
||||
# 1000 MHz for 2Gbps DDR data rate
|
||||
tCK = "1ns"
|
||||
|
||||
tRP = "14ns"
|
||||
|
||||
tCCD_L = "3ns"
|
||||
|
||||
tRCD = "12ns"
|
||||
tRCD_WR = "6ns"
|
||||
tCL = "18ns"
|
||||
tCWL = "7ns"
|
||||
tRAS = "28ns"
|
||||
|
||||
# BL4 in pseudo channel mode
|
||||
# DDR @ 1000 MHz means 4 * 1ns / 2 = 2ns
|
||||
tBURST = "2ns"
|
||||
|
||||
# value for 2Gb device from JEDEC spec
|
||||
tRFC = "220ns"
|
||||
|
||||
# value for 2Gb device from JEDEC spec
|
||||
tREFI = "3.9us"
|
||||
|
||||
tWR = "14ns"
|
||||
tRTP = "5ns"
|
||||
tWTR = "4ns"
|
||||
tWTR_L = "9ns"
|
||||
tRTW = "18ns"
|
||||
|
||||
# tAAD from RBus
|
||||
tAAD = "1ns"
|
||||
|
||||
# single rank device, set to 0
|
||||
tCS = "0ns"
|
||||
|
||||
tRRD = "4ns"
|
||||
tRRD_L = "6ns"
|
||||
|
||||
# for a single pseudo channel
|
||||
tXAW = "16ns"
|
||||
activation_limit = 4
|
||||
|
||||
# 4tCK
|
||||
tXP = "8ns"
|
||||
|
||||
# start with tRFC + tXP -> 160ns + 8ns = 168ns
|
||||
tXS = "216ns"
|
||||
|
||||
page_policy = "close_adaptive"
|
||||
|
||||
read_buffer_size = 64
|
||||
write_buffer_size = 64
|
||||
|
||||
two_cycle_activate = True
|
||||
|
||||
143
src/python/gem5/components/memory/hbm.py
Normal file
143
src/python/gem5/components/memory/hbm.py
Normal file
@@ -0,0 +1,143 @@
|
||||
# Copyright (c) 2022 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.
|
||||
|
||||
""" HBM2 memory system using HBMCtrl
|
||||
"""
|
||||
|
||||
from .memory import ChanneledMemory
|
||||
from .abstract_memory_system import AbstractMemorySystem
|
||||
from math import log
|
||||
from ...utils.override import overrides
|
||||
from m5.objects import AddrRange, DRAMInterface, HBMCtrl, Port
|
||||
from typing import Type, Optional, Union
|
||||
from .memory import _try_convert
|
||||
from .dram_interfaces.hbm import HBM_2000_4H_1x64
|
||||
|
||||
|
||||
class HighBandwidthMemory(ChanneledMemory):
|
||||
"""
|
||||
This class extends ChanneledMemory and can be used to create HBM based
|
||||
memory system where a single physical channel contains two pseudo channels.
|
||||
This is supposed to be used with the HBMCtrl and two dram (HBM2) interfaces
|
||||
per channel.
|
||||
"""
|
||||
|
||||
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.
|
||||
"""
|
||||
super().__init__(
|
||||
dram_interface_class,
|
||||
num_channels,
|
||||
interleaving_size,
|
||||
size,
|
||||
addr_mapping,
|
||||
)
|
||||
|
||||
_num_channels = _try_convert(num_channels, int)
|
||||
|
||||
@overrides(ChanneledMemory)
|
||||
def _create_mem_interfaces_controller(self):
|
||||
self._dram = [
|
||||
self._dram_class(addr_mapping=self._addr_mapping)
|
||||
for _ in range(self._num_channels)
|
||||
]
|
||||
self._dram_2 = [
|
||||
self._dram_class(addr_mapping=self._addr_mapping)
|
||||
for _ in range(self._num_channels)
|
||||
]
|
||||
|
||||
self.mem_ctrl = [
|
||||
HBMCtrl(
|
||||
dram=self._dram[i],
|
||||
dram_2=self._dram_2[i],
|
||||
disable_sanity_check=True,
|
||||
)
|
||||
for i in range(self._num_channels)
|
||||
]
|
||||
|
||||
@overrides(ChanneledMemory)
|
||||
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)
|
||||
mask_list = []
|
||||
|
||||
for ib in range(int(intlv_bits)):
|
||||
mask_list.append(1 << int(ib + intlv_low_bit))
|
||||
|
||||
# for interleaving across pseudo channels (at 64B currently)
|
||||
mask_list.insert(0, 1 << 6)
|
||||
for i, ctrl in enumerate(self.mem_ctrl):
|
||||
ctrl.partitioned_q = False
|
||||
ctrl.dram.range = AddrRange(
|
||||
start=self._mem_range.start,
|
||||
size=self._mem_range.size(),
|
||||
masks=mask_list,
|
||||
intlvMatch=(i << 1) | 0,
|
||||
)
|
||||
ctrl.dram_2.range = AddrRange(
|
||||
start=self._mem_range.start,
|
||||
size=self._mem_range.size(),
|
||||
masks=mask_list,
|
||||
intlvMatch=(i << 1) | 1,
|
||||
)
|
||||
|
||||
|
||||
def HBM2Stack(
|
||||
size: Optional[str] = "4GiB",
|
||||
) -> AbstractMemorySystem:
|
||||
return HighBandwidthMemory(HBM_2000_4H_1x64, 8, 128, size=size)
|
||||
@@ -107,12 +107,16 @@ class ChanneledMemory(AbstractMemorySystem):
|
||||
else:
|
||||
self._size = self._get_dram_size(num_channels, self._dram_class)
|
||||
|
||||
self._create_mem_interfaces_controller()
|
||||
|
||||
def _create_mem_interfaces_controller(self):
|
||||
self._dram = [
|
||||
self._dram_class(addr_mapping=self._addr_mapping)
|
||||
for _ in range(num_channels)
|
||||
for _ in range(self._num_channels)
|
||||
]
|
||||
|
||||
self.mem_ctrl = [
|
||||
MemCtrl(dram=self._dram[i]) for i in range(num_channels)
|
||||
MemCtrl(dram=self._dram[i]) for i in range(self._num_channels)
|
||||
]
|
||||
|
||||
def _get_dram_size(self, num_channels: int, dram: DRAMInterface) -> int:
|
||||
|
||||
@@ -65,11 +65,3 @@ def DualChannelLPDDR3_1600(
|
||||
size: Optional[str] = None,
|
||||
) -> AbstractMemorySystem:
|
||||
return ChanneledMemory(LPDDR3_1600_1x32, 2, 64, size=size)
|
||||
|
||||
|
||||
def HBM2Stack(
|
||||
size: Optional[str] = None,
|
||||
) -> AbstractMemorySystem:
|
||||
if not size:
|
||||
size = "4GiB"
|
||||
return ChanneledMemory(HBM_1000_4H_1x64, 16, 64, size=size)
|
||||
|
||||
Reference in New Issue
Block a user