mem: Add NVM interface

Add NVM interface to memory controller.

This can be used with or instead of the existing
DRAM interface. Therefore, a single controller can interface
to either DRAM or NVM, or both.

Specifically, a memory channel can be configured as:
- Memory controller interfacing to DRAM only
- Memory controller interfacing to NVM only
- Memory controller interfacing to both DRAM and NVM

How data is placed or migrated between media types is outside
of the scope of this change.

The NVM interface incorporates new static delay parameters
for read and write completion. The interface defines a 2
stage read to manage non-deterministic read delays while
enabling deterministic data transfer, similar to NVDIMM-P.
The NVM interface also includes parameters to define
read and write buffers on the media side (on-DIMM). These are
utilized to quickly offload commands and write data, mitigating
the effects of lower latency and bandwidth media characteristics.

Change-Id: I6b22ddb495877f88d161f0bd74ade32cc8fdcbcc
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/29027
Reviewed-by: Jason Lowe-Power <power.jg@gmail.com>
Reviewed-by: Wendy Elsasser <wendy.elsasser@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
Maintainer: Jason Lowe-Power <power.jg@gmail.com>
This commit is contained in:
Wendy Elsasser
2020-04-01 12:39:42 -05:00
committed by Jason Lowe-Power
parent 4acc419b6f
commit dab7c78eca
20 changed files with 3522 additions and 521 deletions

View File

@@ -80,6 +80,21 @@ def create_mem_intf(intf, r, i, nbr_mem_ctrls, intlv_bits, intlv_size,
intlv_low_bit = int(math.log(rowbuffer_size, 2))
# Also adjust interleaving bits for NVM attached as memory
# Will have separate range defined with unique interleaving
if issubclass(intf, m5.objects.NVMInterface):
# If the channel bits are appearing after the low order
# address bits (buffer bits), we need to add the appropriate
# number of bits for the buffer size
if interface.addr_mapping.value == 'RoRaBaChCo':
# This computation only really needs to happen
# once, but as we rely on having an instance we
# end up having to repeat it for each and every
# one
buffer_size = interface.per_bank_buffer_size.value
intlv_low_bit = int(math.log(buffer_size, 2))
# We got all we need to configure the appropriate address
# range
interface.range = m5.objects.AddrRange(r.start, size = r.size(),
@@ -102,15 +117,23 @@ def config_mem(options, system):
"""
# Mandatory options
opt_mem_type = options.mem_type
opt_mem_channels = options.mem_channels
# Semi-optional options
# Must have either mem_type or nvm_type or both
opt_mem_type = getattr(options, "mem_type", None)
opt_nvm_type = getattr(options, "nvm_type", None)
if not opt_mem_type and not opt_nvm_type:
fatal("Must have option for either mem-type or nvm-type, or both")
# Optional options
opt_tlm_memory = getattr(options, "tlm_memory", None)
opt_external_memory_system = getattr(options, "external_memory_system",
None)
opt_elastic_trace_en = getattr(options, "elastic_trace_en", False)
opt_mem_ranks = getattr(options, "mem_ranks", None)
opt_nvm_ranks = getattr(options, "nvm_ranks", None)
opt_hybrid_channel = getattr(options, "hybrid_channel", False)
opt_dram_powerdown = getattr(options, "enable_dram_powerdown", None)
opt_mem_channels_intlv = getattr(options, "mem_channels_intlv", 128)
opt_xor_low_bit = getattr(options, "xor_low_bit", 0)
@@ -142,13 +165,19 @@ def config_mem(options, system):
return
nbr_mem_ctrls = opt_mem_channels
import math
from m5.util import fatal
intlv_bits = int(math.log(nbr_mem_ctrls, 2))
if 2 ** intlv_bits != nbr_mem_ctrls:
fatal("Number of memory channels must be a power of 2")
intf = ObjectList.mem_list.get(opt_mem_type)
if opt_mem_type:
intf = ObjectList.mem_list.get(opt_mem_type)
if opt_nvm_type:
n_intf = ObjectList.mem_list.get(opt_nvm_type)
nvm_intfs = []
mem_ctrls = []
if opt_elastic_trace_en and not issubclass(intf, m5.objects.SimpleMemory):
@@ -164,51 +193,80 @@ def config_mem(options, system):
# For every range (most systems will only have one), create an
# array of memory interfaces and set their parameters to match
# their address mapping in the case of a DRAM
range_iter = 0
for r in system.mem_ranges:
# As the loops iterates across ranges, assign them alternatively
# to DRAM and NVM if both configured, starting with DRAM
range_iter += 1
for i in range(nbr_mem_ctrls):
# Create the DRAM interface
dram_intf = create_mem_intf(intf, r, i, nbr_mem_ctrls, intlv_bits,
intlv_size, opt_xor_low_bit)
if opt_mem_type and (not opt_nvm_type or range_iter % 2 != 0):
# Create the DRAM interface
dram_intf = create_mem_intf(intf, r, i, nbr_mem_ctrls,
intlv_bits, intlv_size, opt_xor_low_bit)
# Set the number of ranks based on the command-line
# options if it was explicitly set
if issubclass(intf, m5.objects.DRAMInterface) and opt_mem_ranks:
dram_intf.ranks_per_channel = opt_mem_ranks
# Set the number of ranks based on the command-line
# options if it was explicitly set
if issubclass(intf, m5.objects.DRAMInterface) and \
opt_mem_ranks:
dram_intf.ranks_per_channel = opt_mem_ranks
# Enable low-power DRAM states if option is set
if issubclass(intf, m5.objects.DRAMInterface):
dram_intf.enable_dram_powerdown = opt_dram_powerdown
# Enable low-power DRAM states if option is set
if issubclass(intf, m5.objects.DRAMInterface):
dram_intf.enable_dram_powerdown = opt_dram_powerdown
if opt_elastic_trace_en:
dram_intf.latency = '1ns'
print("For elastic trace, over-riding Simple Memory "
"latency to 1ns.")
if opt_elastic_trace_en:
dram_intf.latency = '1ns'
print("For elastic trace, over-riding Simple Memory "
"latency to 1ns.")
# Create the controller that will drive the interface
if opt_mem_type == "HMC_2500_1x32":
# The static latency of the vault controllers is estimated
# to be smaller than a full DRAM channel controller
mem_ctrl = m5.objects.DRAMCtrl(min_writes_per_switch = 8,
static_backend_latency = '4ns',
static_frontend_latency = '4ns')
else:
mem_ctrl = m5.objects.DRAMCtrl()
# Create the controller that will drive the interface
if opt_mem_type == "HMC_2500_1x32":
# The static latency of the vault controllers is estimated
# to be smaller than a full DRAM channel controller
mem_ctrl = m5.objects.DRAMCtrl(min_writes_per_switch = 8,
static_backend_latency = '4ns',
static_frontend_latency = '4ns')
else:
mem_ctrl = m5.objects.DRAMCtrl()
# Hookup the controller to the interface and add to the list
mem_ctrl.dram = dram_intf
mem_ctrls.append(mem_ctrl)
# Hookup the controller to the interface and add to the list
mem_ctrl.dram = dram_intf
mem_ctrls.append(mem_ctrl)
# Create a controller and connect the interfaces to a controller
elif opt_nvm_type and (not opt_mem_type or range_iter % 2 == 0):
nvm_intf = create_mem_intf(n_intf, r, i, nbr_mem_ctrls,
intlv_bits, intlv_size)
# Set the number of ranks based on the command-line
# options if it was explicitly set
if issubclass(n_intf, m5.objects.NVMInterface) and \
opt_nvm_ranks:
nvm_intf.ranks_per_channel = opt_nvm_ranks
# Create a controller if not sharing a channel with DRAM
# in which case the controller has already been created
if not opt_hybrid_channel:
mem_ctrl = m5.objects.DRAMCtrl()
mem_ctrl.nvm = nvm_intf
mem_ctrls.append(mem_ctrl)
else:
nvm_intfs.append(nvm_intf)
# hook up NVM interface when channel is shared with DRAM + NVM
for i in range(len(nvm_intfs)):
mem_ctrls[i].nvm = nvm_intfs[i];
# Connect the controller to the xbar port
for i in range(len(mem_ctrls)):
if opt_mem_type == "HMC_2500_1x32":
# Connect the controllers to the membus
mem_ctrls[i].port = xbar[i/4].master
# Set memory device size. There is an independent controller for
# each vault. All vaults are same size.
# Set memory device size. There is an independent controller
# for each vault. All vaults are same size.
mem_ctrls[i].dram.device_size = options.hmc_dev_vault_size
else:
# Connect the controllers to the membus
mem_ctrls[i].port = xbar.master
subsystem.mem_ctrls = mem_ctrls

199
configs/nvm/sweep.py Normal file
View File

@@ -0,0 +1,199 @@
# Copyright (c) 2020 ARM Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# 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.
#
# Authors: Andreas Hansson
from __future__ import print_function
from __future__ import absolute_import
import math
import optparse
import m5
from m5.objects import *
from m5.util import addToPath
from m5.stats import periodicStatDump
addToPath('../')
from common import ObjectList
from common import MemConfig
# this script is helpful to sweep the efficiency of a specific memory
# controller configuration, by varying the number of banks accessed,
# and the sequential stride size (how many bytes per activate), and
# observe what bus utilisation (bandwidth) is achieved
parser = optparse.OptionParser()
nvm_generators = {
"NVM" : lambda x: x.createNvm,
}
# Use a single-channel DDR3-1600 x64 (8x8 topology) by default
parser.add_option("--nvm-type", type="choice", default="NVM_2400_1x64",
choices=ObjectList.mem_list.get_names(),
help = "type of memory to use")
parser.add_option("--nvm-ranks", "-r", type="int", default=1,
help = "Number of ranks to iterate across")
parser.add_option("--rd_perc", type="int", default=100,
help = "Percentage of read commands")
parser.add_option("--mode", type="choice", default="NVM",
choices=nvm_generators.keys(),
help = "NVM: Random traffic")
parser.add_option("--addr-map", type="choice",
choices=ObjectList.dram_addr_map_list.get_names(),
default="RoRaBaCoCh", help = "NVM address map policy")
(options, args) = parser.parse_args()
if args:
print("Error: script doesn't take any positional arguments")
sys.exit(1)
# at the moment we stay with the default open-adaptive page policy,
# and address mapping
# start with the system itself, using a multi-layer 2.0 GHz
# crossbar, delivering 64 bytes / 3 cycles (one header cycle)
# which amounts to 42.7 GByte/s per layer and thus per port
system = System(membus = IOXBar(width = 32))
system.clk_domain = SrcClockDomain(clock = '2.0GHz',
voltage_domain =
VoltageDomain(voltage = '1V'))
# we are fine with 256 MB memory for now
mem_range = AddrRange('512MB')
system.mem_ranges = [mem_range]
# do not worry about reserving space for the backing store
system.mmap_using_noreserve = True
# force a single channel to match the assumptions in the DRAM traffic
# generator
options.mem_channels = 1
options.external_memory_system = 0
MemConfig.config_mem(options, system)
# the following assumes that we are using the native memory
# controller with an NVM interface, check to be sure
if not isinstance(system.mem_ctrls[0], m5.objects.DRAMCtrl):
fatal("This script assumes the controller is a DRAMCtrl subclass")
if not isinstance(system.mem_ctrls[0].nvm, m5.objects.NVMInterface):
fatal("This script assumes the memory is a NVMInterface class")
# there is no point slowing things down by saving any data
system.mem_ctrls[0].nvm.null = True
# Set the address mapping based on input argument
system.mem_ctrls[0].nvm.addr_mapping = options.addr_map
# stay in each state for 0.25 ms, long enough to warm things up, and
# short enough to avoid hitting a refresh
period = 250000000
# stay in each state as long as the dump/reset period, use the entire
# range, issue transactions of the right DRAM burst size, and match
# the DRAM maximum bandwidth to ensure that it is saturated
# get the number of regions
nbr_banks = system.mem_ctrls[0].nvm.banks_per_rank.value
# determine the burst length in bytes
burst_size = int((system.mem_ctrls[0].nvm.devices_per_rank.value *
system.mem_ctrls[0].nvm.device_bus_width.value *
system.mem_ctrls[0].nvm.burst_length.value) / 8)
# next, get the page size in bytes
buffer_size = system.mem_ctrls[0].nvm.devices_per_rank.value * \
system.mem_ctrls[0].nvm.device_rowbuffer_size.value
# match the maximum bandwidth of the memory, the parameter is in seconds
# and we need it in ticks (ps)
itt = system.mem_ctrls[0].nvm.tBURST.value * 1000000000000
# assume we start at 0
max_addr = mem_range.end
# use min of the page size and 512 bytes as that should be more than
# enough
max_stride = min(256, buffer_size)
# create a traffic generator, and point it to the file we just created
system.tgen = PyTrafficGen()
# add a communication monitor
system.monitor = CommMonitor()
# connect the traffic generator to the bus via a communication monitor
system.tgen.port = system.monitor.slave
system.monitor.master = system.membus.slave
# connect the system port even if it is not used in this example
system.system_port = system.membus.slave
# every period, dump and reset all stats
periodicStatDump(period)
# run Forrest, run!
root = Root(full_system = False, system = system)
root.system.mem_mode = 'timing'
m5.instantiate()
def trace():
addr_map = ObjectList.dram_addr_map_list.get(options.addr_map)
generator = nvm_generators[options.mode](system.tgen)
for stride_size in range(burst_size, max_stride + 1, burst_size):
for bank in range(1, nbr_banks + 1):
num_seq_pkts = int(math.ceil(float(stride_size) / burst_size))
yield generator(period,
0, max_addr, burst_size, int(itt), int(itt),
options.rd_perc, 0,
num_seq_pkts, buffer_size, nbr_banks, bank,
addr_map, options.nvm_ranks)
yield system.tgen.createExit(0)
system.tgen.start(trace())
m5.simulate()
print("NVM sweep with burst: %d, banks: %d, max stride: %d" %
(burst_size, nbr_banks, max_stride))

242
configs/nvm/sweep_hybrid.py Normal file
View File

@@ -0,0 +1,242 @@
# Copyright (c) 2020 ARM Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# 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.
#
# Authors: Andreas Hansson
from __future__ import print_function
from __future__ import absolute_import
import math
import optparse
import m5
from m5.objects import *
from m5.util import addToPath
from m5.stats import periodicStatDump
addToPath('../')
from common import ObjectList
from common import MemConfig
# this script is helpful to sweep the efficiency of a specific memory
# controller configuration, by varying the number of banks accessed,
# and the sequential stride size (how many bytes per activate), and
# observe what bus utilisation (bandwidth) is achieved
parser = optparse.OptionParser()
hybrid_generators = {
"HYBRID" : lambda x: x.createHybrid,
}
# Use a single-channel DDR3-1600 x64 (8x8 topology) by default
parser.add_option("--nvm-type", type="choice", default="NVM_2400_1x64",
choices=ObjectList.mem_list.get_names(),
help = "type of memory to use")
parser.add_option("--mem-type", type="choice", default="DDR4_2400_16x4",
choices=ObjectList.mem_list.get_names(),
help = "type of memory to use")
parser.add_option("--nvm-ranks", "-n", type="int", default=1,
help = "Number of ranks to iterate across")
parser.add_option("--mem-ranks", "-r", type="int", default=2,
help = "Number of ranks to iterate across")
parser.add_option("--rd-perc", type="int", default=100,
help = "Percentage of read commands")
parser.add_option("--nvm-perc", type="int", default=100,
help = "Percentage of NVM commands")
parser.add_option("--mode", type="choice", default="HYBRID",
choices=hybrid_generators.keys(),
help = "Hybrid: Random DRAM + NVM traffic")
parser.add_option("--addr-map", type="choice",
choices=ObjectList.dram_addr_map_list.get_names(),
default="RoRaBaCoCh", help = "NVM address map policy")
(options, args) = parser.parse_args()
if args:
print("Error: script doesn't take any positional arguments")
sys.exit(1)
# at the moment we stay with the default open-adaptive page policy,
# and address mapping
# start with the system itself, using a multi-layer 2.0 GHz
# crossbar, delivering 64 bytes / 3 cycles (one header cycle)
# which amounts to 42.7 GByte/s per layer and thus per port
system = System(membus = IOXBar(width = 32))
system.clk_domain = SrcClockDomain(clock = '2.0GHz',
voltage_domain =
VoltageDomain(voltage = '1V'))
# set 2 ranges, the first, smaller range for DDR
# the second, larger (1024) range for NVM
# the NVM range starts directly after the DRAM range
system.mem_ranges = [AddrRange('128MB'),
AddrRange(Addr('128MB'), size ='1024MB')]
# do not worry about reserving space for the backing store
system.mmap_using_noreserve = True
# force a single channel to match the assumptions in the DRAM traffic
# generator
options.mem_channels = 1
options.external_memory_system = 0
options.hybrid_channel = True
MemConfig.config_mem(options, system)
# the following assumes that we are using the native controller
# with NVM and DRAM interfaces, check to be sure
if not isinstance(system.mem_ctrls[0], m5.objects.DRAMCtrl):
fatal("This script assumes the controller is a DRAMCtrl subclass")
if not isinstance(system.mem_ctrls[0].dram, m5.objects.DRAMInterface):
fatal("This script assumes the first memory is a DRAMInterface subclass")
if not isinstance(system.mem_ctrls[0].nvm, m5.objects.NVMInterface):
fatal("This script assumes the second memory is a NVMInterface subclass")
# there is no point slowing things down by saving any data
system.mem_ctrls[0].dram.null = True
system.mem_ctrls[0].nvm.null = True
# Set the address mapping based on input argument
system.mem_ctrls[0].dram.addr_mapping = options.addr_map
system.mem_ctrls[0].nvm.addr_mapping = options.addr_map
# stay in each state for 0.25 ms, long enough to warm things up, and
# short enough to avoid hitting a refresh
period = 250000000
# stay in each state as long as the dump/reset period, use the entire
# range, issue transactions of the right burst size, and match
# the maximum bandwidth to ensure that it is saturated
# get the number of banks
nbr_banks_dram = system.mem_ctrls[0].dram.banks_per_rank.value
# determine the burst length in bytes
burst_size_dram = int((system.mem_ctrls[0].dram.devices_per_rank.value *
system.mem_ctrls[0].dram.device_bus_width.value *
system.mem_ctrls[0].dram.burst_length.value) / 8)
# next, get the page size in bytes
page_size_dram = system.mem_ctrls[0].dram.devices_per_rank.value * \
system.mem_ctrls[0].dram.device_rowbuffer_size.value
# get the number of regions
nbr_banks_nvm = system.mem_ctrls[0].nvm.banks_per_rank.value
# determine the burst length in bytes
burst_size_nvm = int((system.mem_ctrls[0].nvm.devices_per_rank.value *
system.mem_ctrls[0].nvm.device_bus_width.value *
system.mem_ctrls[0].nvm.burst_length.value) / 8)
burst_size = max(burst_size_dram, burst_size_nvm)
# next, get the page size in bytes
buffer_size_nvm = system.mem_ctrls[0].nvm.devices_per_rank.value * \
system.mem_ctrls[0].nvm.device_rowbuffer_size.value
# match the maximum bandwidth of the memory, the parameter is in seconds
# and we need it in ticks (ps)
itt = min(system.mem_ctrls[0].dram.tBURST.value,
system.mem_ctrls[0].nvm.tBURST.value) * 1000000000000
# assume we start at 0 for DRAM
max_addr_dram = system.mem_ranges[0].end
min_addr_nvm = system.mem_ranges[1].start
max_addr_nvm = system.mem_ranges[1].end
# use min of the page size and 512 bytes as that should be more than
# enough
max_stride = min(256, buffer_size_nvm, page_size_dram)
# create a traffic generator, and point it to the file we just created
system.tgen = PyTrafficGen()
# add a communication monitor
system.monitor = CommMonitor()
# connect the traffic generator to the bus via a communication monitor
system.tgen.port = system.monitor.slave
system.monitor.master = system.membus.slave
# connect the system port even if it is not used in this example
system.system_port = system.membus.slave
# every period, dump and reset all stats
periodicStatDump(period)
# run Forrest, run!
root = Root(full_system = False, system = system)
root.system.mem_mode = 'timing'
m5.instantiate()
def trace():
addr_map = ObjectList.dram_addr_map_list.get(options.addr_map)
generator = hybrid_generators[options.mode](system.tgen)
for stride_size in range(burst_size, max_stride + 1, burst_size):
num_seq_pkts_dram = int(math.ceil(float(stride_size) /
burst_size_dram))
num_seq_pkts_nvm = int(math.ceil(float(stride_size) / burst_size_nvm))
yield generator(period,
0, max_addr_dram, burst_size_dram,
min_addr_nvm, max_addr_nvm, burst_size_nvm,
int(itt), int(itt),
options.rd_perc, 0,
num_seq_pkts_dram, page_size_dram,
nbr_banks_dram, nbr_banks_dram,
num_seq_pkts_nvm, buffer_size_nvm,
nbr_banks_nvm, nbr_banks_nvm,
addr_map, options.mem_ranks,
options.nvm_ranks, options.nvm_perc)
yield system.tgen.createExit(0)
system.tgen.start(trace())
m5.simulate()
print("Hybrid DRAM + NVM sweep with max_stride: %d" % (max_stride))
print("NVM burst: %d, NVM banks: %d" % (burst_size_nvm, nbr_banks_nvm))
print("DRAM burst: %d, DRAM banks: %d" % (burst_size_dram, nbr_banks_dram))

View File

@@ -147,8 +147,8 @@ def setup_memory_controllers(system, ruby, dir_cntrls, options):
mem_ctrl.port = dir_cntrl.memory
# Enable low-power DRAM states if option is set
if issubclass(mem_type, DRAMCtrl):
mem_ctrl.enable_dram_powerdown = \
if issubclass(mem_type, DRAMInterface):
mem_ctrl.dram.enable_dram_powerdown = \
options.enable_dram_powerdown
index += 1

View File

@@ -1,4 +1,4 @@
# Copyright (c) 2018 ARM Limited
# Copyright (c) 2018-2020 ARM Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
@@ -58,6 +58,8 @@ class PyTrafficGen(BaseTrafficGen):
PyBindMethod("createRandom"),
PyBindMethod("createDram"),
PyBindMethod("createDramRot"),
PyBindMethod("createHybrid"),
PyBindMethod("createNvm"),
]
@cxxMethod(override=True)

View File

@@ -1,6 +1,6 @@
# -*- mode:python -*-
# Copyright (c) 2012, 2017-2018 ARM Limited
# Copyright (c) 2012, 2017-2020 ARM Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
@@ -43,8 +43,10 @@ Source('base_gen.cc')
Source('dram_gen.cc')
Source('dram_rot_gen.cc')
Source('exit_gen.cc')
Source('hybrid_gen.cc')
Source('idle_gen.cc')
Source('linear_gen.cc')
Source('nvm_gen.cc')
Source('random_gen.cc')
Source('stream_gen.cc')

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2013, 2016-2019 ARM Limited
* Copyright (c) 2012-2013, 2016-2020 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
@@ -45,8 +45,10 @@
#include "cpu/testers/traffic_gen/dram_gen.hh"
#include "cpu/testers/traffic_gen/dram_rot_gen.hh"
#include "cpu/testers/traffic_gen/exit_gen.hh"
#include "cpu/testers/traffic_gen/hybrid_gen.hh"
#include "cpu/testers/traffic_gen/idle_gen.hh"
#include "cpu/testers/traffic_gen/linear_gen.hh"
#include "cpu/testers/traffic_gen/nvm_gen.hh"
#include "cpu/testers/traffic_gen/random_gen.hh"
#include "cpu/testers/traffic_gen/stream_gen.hh"
#include "debug/Checkpoint.hh"
@@ -399,7 +401,7 @@ BaseTrafficGen::createDram(Tick duration,
Tick min_period, Tick max_period,
uint8_t read_percent, Addr data_limit,
unsigned int num_seq_pkts, unsigned int page_size,
unsigned int nbr_of_banks_DRAM,
unsigned int nbr_of_banks,
unsigned int nbr_of_banks_util,
Enums::AddrMap addr_mapping,
unsigned int nbr_of_ranks)
@@ -411,7 +413,7 @@ BaseTrafficGen::createDram(Tick duration,
min_period, max_period,
read_percent, data_limit,
num_seq_pkts, page_size,
nbr_of_banks_DRAM,
nbr_of_banks,
nbr_of_banks_util,
addr_mapping,
nbr_of_ranks));
@@ -424,7 +426,7 @@ BaseTrafficGen::createDramRot(Tick duration,
uint8_t read_percent, Addr data_limit,
unsigned int num_seq_pkts,
unsigned int page_size,
unsigned int nbr_of_banks_DRAM,
unsigned int nbr_of_banks,
unsigned int nbr_of_banks_util,
Enums::AddrMap addr_mapping,
unsigned int nbr_of_ranks,
@@ -437,13 +439,80 @@ BaseTrafficGen::createDramRot(Tick duration,
min_period, max_period,
read_percent, data_limit,
num_seq_pkts, page_size,
nbr_of_banks_DRAM,
nbr_of_banks,
nbr_of_banks_util,
addr_mapping,
nbr_of_ranks,
max_seq_count_per_rank));
}
std::shared_ptr<BaseGen>
BaseTrafficGen::createHybrid(Tick duration,
Addr start_addr_dram, Addr end_addr_dram,
Addr blocksize_dram,
Addr start_addr_nvm, Addr end_addr_nvm,
Addr blocksize_nvm,
Tick min_period, Tick max_period,
uint8_t read_percent, Addr data_limit,
unsigned int num_seq_pkts_dram,
unsigned int page_size_dram,
unsigned int nbr_of_banks_dram,
unsigned int nbr_of_banks_util_dram,
unsigned int num_seq_pkts_nvm,
unsigned int buffer_size_nvm,
unsigned int nbr_of_banks_nvm,
unsigned int nbr_of_banks_util_nvm,
Enums::AddrMap addr_mapping,
unsigned int nbr_of_ranks_dram,
unsigned int nbr_of_ranks_nvm,
uint8_t nvm_percent)
{
return std::shared_ptr<BaseGen>(new HybridGen(*this, masterID,
duration, start_addr_dram,
end_addr_dram, blocksize_dram,
start_addr_nvm,
end_addr_nvm, blocksize_nvm,
system->cacheLineSize(),
min_period, max_period,
read_percent, data_limit,
num_seq_pkts_dram,
page_size_dram,
nbr_of_banks_dram,
nbr_of_banks_util_dram,
num_seq_pkts_nvm,
buffer_size_nvm,
nbr_of_banks_nvm,
nbr_of_banks_util_nvm,
addr_mapping,
nbr_of_ranks_dram,
nbr_of_ranks_nvm,
nvm_percent));
}
std::shared_ptr<BaseGen>
BaseTrafficGen::createNvm(Tick duration,
Addr start_addr, Addr end_addr, Addr blocksize,
Tick min_period, Tick max_period,
uint8_t read_percent, Addr data_limit,
unsigned int num_seq_pkts, unsigned int buffer_size,
unsigned int nbr_of_banks,
unsigned int nbr_of_banks_util,
Enums::AddrMap addr_mapping,
unsigned int nbr_of_ranks)
{
return std::shared_ptr<BaseGen>(new NvmGen(*this, masterID,
duration, start_addr,
end_addr, blocksize,
system->cacheLineSize(),
min_period, max_period,
read_percent, data_limit,
num_seq_pkts, buffer_size,
nbr_of_banks,
nbr_of_banks_util,
addr_mapping,
nbr_of_ranks));
}
std::shared_ptr<BaseGen>
BaseTrafficGen::createTrace(Tick duration,
const std::string& trace_file, Addr addr_offset)

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2013, 2016-2019 ARM Limited
* Copyright (c) 2012-2013, 2016-2020 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
@@ -274,7 +274,7 @@ class BaseTrafficGen : public ClockedObject
Tick min_period, Tick max_period,
uint8_t read_percent, Addr data_limit,
unsigned int num_seq_pkts, unsigned int page_size,
unsigned int nbr_of_banks_DRAM, unsigned int nbr_of_banks_util,
unsigned int nbr_of_banks, unsigned int nbr_of_banks_util,
Enums::AddrMap addr_mapping,
unsigned int nbr_of_ranks);
@@ -284,11 +284,36 @@ class BaseTrafficGen : public ClockedObject
Tick min_period, Tick max_period,
uint8_t read_percent, Addr data_limit,
unsigned int num_seq_pkts, unsigned int page_size,
unsigned int nbr_of_banks_DRAM, unsigned int nbr_of_banks_util,
unsigned int nbr_of_banks, unsigned int nbr_of_banks_util,
Enums::AddrMap addr_mapping,
unsigned int nbr_of_ranks,
unsigned int max_seq_count_per_rank);
std::shared_ptr<BaseGen> createHybrid(
Tick duration,
Addr start_addr_dram, Addr end_addr_dram, Addr blocksize_dram,
Addr start_addr_nvm, Addr end_addr_nvm, Addr blocksize_nvm,
Tick min_period, Tick max_period,
uint8_t read_percent, Addr data_limit,
unsigned int num_seq_pkts_dram, unsigned int page_size_dram,
unsigned int nbr_of_banks_dram, unsigned int nbr_of_banks_util_dram,
unsigned int num_seq_pkts_nvm, unsigned int buffer_size_nvm,
unsigned int nbr_of_banks_nvm, unsigned int nbr_of_banks_util_nvm,
Enums::AddrMap addr_mapping,
unsigned int nbr_of_ranks_dram,
unsigned int nbr_of_ranks_nvm,
uint8_t nvm_percent);
std::shared_ptr<BaseGen> createNvm(
Tick duration,
Addr start_addr, Addr end_addr, Addr blocksize,
Tick min_period, Tick max_period,
uint8_t read_percent, Addr data_limit,
unsigned int num_seq_pkts, unsigned int buffer_size,
unsigned int nbr_of_banks, unsigned int nbr_of_banks_util,
Enums::AddrMap addr_mapping,
unsigned int nbr_of_ranks);
std::shared_ptr<BaseGen> createTrace(
Tick duration,
const std::string& trace_file, Addr addr_offset);

View File

@@ -0,0 +1,314 @@
/*
* Copyright (c) 2020 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed here under. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* 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.
*
* Authors: Wendy Elsasser
*/
#include "cpu/testers/traffic_gen/hybrid_gen.hh"
#include <algorithm>
#include "base/random.hh"
#include "base/trace.hh"
#include "debug/TrafficGen.hh"
#include "enums/AddrMap.hh"
using namespace std;
HybridGen::HybridGen(SimObject &obj,
MasterID master_id, Tick _duration,
Addr start_addr_dram, Addr end_addr_dram,
Addr blocksize_dram,
Addr start_addr_nvm, Addr end_addr_nvm,
Addr blocksize_nvm,
Addr cacheline_size,
Tick min_period, Tick max_period,
uint8_t read_percent, Addr data_limit,
unsigned int num_seq_pkts_dram, unsigned int page_size_dram,
unsigned int nbr_of_banks_dram,
unsigned int nbr_of_banks_util_dram,
unsigned int num_seq_pkts_nvm, unsigned int buffer_size_nvm,
unsigned int nbr_of_banks_nvm,
unsigned int nbr_of_banks_util_nvm,
Enums::AddrMap addr_mapping,
unsigned int nbr_of_ranks_dram,
unsigned int nbr_of_ranks_nvm,
uint8_t nvm_percent)
: BaseGen(obj, master_id, _duration),
startAddrDram(start_addr_dram),
endAddrDram(end_addr_dram),
blocksizeDram(blocksize_dram),
startAddrNvm(start_addr_nvm),
endAddrNvm(end_addr_nvm),
blocksizeNvm(blocksize_nvm),
cacheLineSize(cacheline_size),
minPeriod(min_period), maxPeriod(max_period),
readPercent(read_percent), dataLimit(data_limit),
numSeqPktsDram(num_seq_pkts_dram),
numSeqPktsNvm(num_seq_pkts_nvm),
countNumSeqPkts(0), addr(0),
pageSizeDram(page_size_dram),
pageBitsDram(floorLog2(pageSizeDram / blocksizeDram)),
bankBitsDram(floorLog2(nbr_of_banks_dram)),
blockBitsDram(floorLog2(blocksizeDram)),
nbrOfBanksDram(nbr_of_banks_dram),
nbrOfBanksUtilDram(nbr_of_banks_util_dram),
bufferSizeNvm(buffer_size_nvm),
pageBitsNvm(floorLog2(bufferSizeNvm / blocksizeNvm)),
bankBitsNvm(floorLog2(nbr_of_banks_nvm)),
blockBitsNvm(floorLog2(blocksizeNvm)),
nbrOfBanksNvm(nbr_of_banks_nvm),
nbrOfBanksUtilNvm(nbr_of_banks_util_nvm),
addrMapping(addr_mapping),
nbrOfRanksDram(nbr_of_ranks_dram),
rankBitsDram(floorLog2(nbrOfRanksDram)),
nbrOfRanksNvm(nbr_of_ranks_nvm),
rankBitsNvm(floorLog2(nbrOfRanksNvm)),
nvmPercent(nvm_percent),
isRead(true),
isNvm(false),
dataManipulated(0)
{
if (blocksizeDram > cacheLineSize)
fatal("TrafficGen %s Dram block size (%d) is larger than "
"cache line size (%d)\n", name(),
blocksizeDram, cacheLineSize);
if (blocksizeNvm > cacheLineSize)
fatal("TrafficGen %s Nvm block size (%d) is larger than "
"cache line size (%d)\n", name(),
blocksizeNvm, cacheLineSize);
if (readPercent > 100)
fatal("%s cannot have more than 100% reads", name());
if (minPeriod > maxPeriod)
fatal("%s cannot have min_period > max_period", name());
if (nbrOfBanksUtilDram > nbrOfBanksDram)
fatal("Attempting to use more Dram banks (%d) than "
"what is available (%d)\n",
nbrOfBanksUtilDram, nbrOfBanksDram);
if (nbrOfBanksUtilNvm > nbrOfBanksNvm)
fatal("Attempting to use more Nvm banks (%d) than "
"what is available (%d)\n",
nbrOfBanksUtilNvm, nbrOfBanksNvm);
}
void
HybridGen::enter()
{
// reset the counter to zero
dataManipulated = 0;
}
PacketPtr
HybridGen::getNextPacket()
{
// if this is the first of the packets in series to be generated,
// start counting again
if (countNumSeqPkts == 0) {
isNvm = nvmPercent != 0 &&
(nvmPercent == 100 || random_mt.random(0, 100) < nvmPercent);
// choose if we generate a read or a write here
isRead = readPercent != 0 &&
(readPercent == 100 || random_mt.random(0, 100) < readPercent);
assert((readPercent == 0 && !isRead) ||
(readPercent == 100 && isRead) ||
readPercent != 100);
if (isNvm) {
// Select the appropriate parameters for this interface
numSeqPkts = numSeqPktsNvm;
startAddr = startAddrNvm;
endAddr = endAddrNvm;
blocksize = blocksizeNvm;
pageSize = bufferSizeNvm;
pageBits = pageBitsNvm;
bankBits = bankBitsNvm;
blockBits = blockBitsNvm;
nbrOfBanks = nbrOfBanksNvm;
nbrOfBanksUtil = nbrOfBanksUtilNvm;
nbrOfRanks = nbrOfRanksNvm;
rankBits = rankBitsNvm;
} else {
// Select the appropriate parameters for this interface
numSeqPkts = numSeqPktsDram;
startAddr = startAddrDram;
endAddr = endAddrDram;
blocksize = blocksizeDram;
pageSize = pageSizeDram;
pageBits = pageBitsDram;
bankBits = bankBitsDram;
blockBits = blockBitsDram;
nbrOfBanks = nbrOfBanksDram;
nbrOfBanksUtil = nbrOfBanksUtilDram;
nbrOfRanks = nbrOfRanksDram;
rankBits = rankBitsDram;
}
countNumSeqPkts = numSeqPkts;
// pick a random bank
unsigned int new_bank =
random_mt.random<unsigned int>(0, nbrOfBanksUtil - 1);
// pick a random rank
unsigned int new_rank =
random_mt.random<unsigned int>(0, nbrOfRanks - 1);
// Generate the start address of the command series
// routine will update addr variable with bank, rank, and col
// bits updated for random traffic mode
genStartAddr(new_bank, new_rank);
} else {
// increment the column by one
if (addrMapping == Enums::RoRaBaCoCh ||
addrMapping == Enums::RoRaBaChCo)
// Simply increment addr by blocksize to increment
// the column by one
addr += blocksize;
else if (addrMapping == Enums::RoCoRaBaCh) {
// Explicity increment the column bits
unsigned int new_col = ((addr / blocksize /
nbrOfBanks / nbrOfRanks) %
(pageSize / blocksize)) + 1;
replaceBits(addr, blockBits + bankBits + rankBits + pageBits - 1,
blockBits + bankBits + rankBits, new_col);
}
}
DPRINTF(TrafficGen, "HybridGen::getNextPacket: %c to addr %x, "
"size %d, countNumSeqPkts: %d, numSeqPkts: %d\n",
isRead ? 'r' : 'w', addr, blocksize, countNumSeqPkts, numSeqPkts);
// create a new request packet
PacketPtr pkt = getPacket(addr, blocksize,
isRead ? MemCmd::ReadReq : MemCmd::WriteReq);
// add the amount of data manipulated to the total
dataManipulated += blocksize;
// subtract the number of packets remained to be generated
--countNumSeqPkts;
// return the generated packet
return pkt;
}
void
HybridGen::genStartAddr(unsigned int new_bank, unsigned int new_rank)
{
// start by picking a random address in the range
addr = random_mt.random<Addr>(startAddr, endAddr - 1);
// round down to start address of a block, i.e. a DRAM burst
addr -= addr % blocksize;
// insert the bank bits at the right spot, and align the
// address to achieve the required hit length, this involves
// finding the appropriate start address such that all
// sequential packets target successive columns in the same
// page
// for example, if we have a stride size of 192B, which means
// for LPDDR3 where burstsize = 32B we have numSeqPkts = 6,
// the address generated previously can be such that these
// 192B cross the page boundary, hence it needs to be aligned
// so that they all belong to the same page for page hit
unsigned int burst_per_page = pageSize / blocksize;
// pick a random column, but ensure that there is room for
// numSeqPkts sequential columns in the same page
unsigned int new_col =
random_mt.random<unsigned int>(0, burst_per_page - numSeqPkts);
if (addrMapping == Enums::RoRaBaCoCh ||
addrMapping == Enums::RoRaBaChCo) {
// Block bits, then page bits, then bank bits, then rank bits
replaceBits(addr, blockBits + pageBits + bankBits - 1,
blockBits + pageBits, new_bank);
replaceBits(addr, blockBits + pageBits - 1, blockBits, new_col);
if (rankBits != 0) {
replaceBits(addr, blockBits + pageBits + bankBits +rankBits - 1,
blockBits + pageBits + bankBits, new_rank);
}
} else if (addrMapping == Enums::RoCoRaBaCh) {
// Block bits, then bank bits, then rank bits, then page bits
replaceBits(addr, blockBits + bankBits - 1, blockBits, new_bank);
replaceBits(addr, blockBits + bankBits + rankBits + pageBits - 1,
blockBits + bankBits + rankBits, new_col);
if (rankBits != 0) {
replaceBits(addr, blockBits + bankBits + rankBits - 1,
blockBits + bankBits, new_rank);
}
}
}
Tick
HybridGen::nextPacketTick(bool elastic, Tick delay) const
{
// Check to see if we have reached the data limit. If dataLimit is
// zero we do not have a data limit and therefore we will keep
// generating requests for the entire residency in this state.
if (dataLimit && dataManipulated >= dataLimit)
{
DPRINTF(TrafficGen, "Data limit for RandomGen reached.\n");
// No more requests. Return MaxTick.
return MaxTick;
} else {
// return the time when the next request should take place
Tick wait = random_mt.random(minPeriod, maxPeriod);
// compensate for the delay experienced to not be elastic, by
// default the value we generate is from the time we are
// asked, so the elasticity happens automatically
if (!elastic) {
if (wait < delay)
wait = 0;
else
wait -= delay;
}
return curTick() + wait;
}
}

View File

@@ -0,0 +1,277 @@
/*
* Copyright (c) 2020 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed here under. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* 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.
*
* Authors: Wendy Elsasser
*/
/**
* @file
* Declaration of the NVM generator for issuing variable buffer
* hit length requests and bank utilisation.
*/
#ifndef __CPU_TRAFFIC_GEN_HYBRID_GEN_HH__
#define __CPU_TRAFFIC_GEN_HYBRID_GEN_HH__
#include "base/bitfield.hh"
#include "base/intmath.hh"
#include "base_gen.hh"
#include "enums/AddrMap.hh"
#include "mem/packet.hh"
/**
* Hybrid NVM + DRAM specific generator is for issuing request with variable
* buffer hit length and bank utilization. Currently assumes a single
* channel configuration.
*/
class HybridGen : public BaseGen
{
public:
/**
* Create a hybrid DRAM + NVM address sequence generator.
*
* @param obj SimObject owning this sequence generator
* @param master_id MasterID related to the memory requests
* @param _duration duration of this state before transitioning
* @param start_addr_dram Start address for DRAM range
* @param end_addr_dram End address for DRAM range
* @param _blocksize_dram Size used for transactions injected
* @param start_addr_nvm Start address for NVM range
* @param end_addr_nvm End address for NVM range
* @param _blocksize_nvm Size used for transactions injected
* @param cacheline_size cache line size in the system
* @param min_period Lower limit of random inter-transaction time
* @param max_period Upper limit of random inter-transaction time
* @param read_percent Percent of transactions that are reads
* @param data_limit Upper limit on how much data to read/write
* @param num_seq_pkts_dram Number of packets per stride, each _blocksize
* @param page_size_dram Buffer size (bytes) used in the NVM
* @param nbr_of_banks_dram Total number of parallel banks in NVM
* @param nbr_of_banks_util_dram Number of banks to utilized,
* for N banks, we will use banks: 0->(N-1)
* @param num_seq_pkts_nvm Number of packets per stride, each _blocksize
* @param buffer_size_nvm Buffer size (bytes) used in the NVM
* @param nbr_of_banks_nvm Total number of parallel banks in NVM
* @param nbr_of_banks_util_nvm Number of banks to utilized,
* for N banks, we will use banks: 0->(N-1)
* @param addr_mapping Address mapping to be used,
* assumes single channel system
* @param nbr_of_ranks_dram Number of DRAM ranks
* @param nbr_of_ranks_nvm Number of NVM ranks
* @param nvm_percent Percentage of traffic going to NVM
*/
HybridGen(SimObject &obj,
MasterID master_id, Tick _duration,
Addr start_addr_dram, Addr end_addr_dram,
Addr blocksize_dram,
Addr start_addr_nvm, Addr end_addr_nvm,
Addr blocksize_nvm,
Addr cacheline_size,
Tick min_period, Tick max_period,
uint8_t read_percent, Addr data_limit,
unsigned int num_seq_pkts_dram, unsigned int page_size_dram,
unsigned int nbr_of_banks_dram, unsigned int nbr_of_banks_util_dram,
unsigned int num_seq_pkts_nvm, unsigned int buffer_size_nvm,
unsigned int nbr_of_banks_nvm, unsigned int nbr_of_banks_util_nvm,
Enums::AddrMap addr_mapping,
unsigned int nbr_of_ranks_dram,
unsigned int nbr_of_ranks_nvm,
uint8_t nvm_percent);
void enter();
PacketPtr getNextPacket();
/** Insert bank, rank, and column bits into packed
* address to create address for 1st command in a
* series
* @param new_bank Bank number of next packet series
* @param new_rank Rank value of next packet series
*/
void genStartAddr(unsigned int new_bank , unsigned int new_rank);
Tick nextPacketTick(bool elastic, Tick delay) const;
protected:
/** Start of DRAM address range */
const Addr startAddrDram;
/** End of DRAM address range */
const Addr endAddrDram;
/** Blocksize and address increment for DRAM */
const Addr blocksizeDram;
/** Start of DRAM address range */
const Addr startAddrNvm;
/** End of DRAM address range */
const Addr endAddrNvm;
/** Blocksize and address increment for DRAM */
const Addr blocksizeNvm;
/** Cache line size in the simulated system */
const Addr cacheLineSize;
/** Request generation period */
const Tick minPeriod;
const Tick maxPeriod;
/** Percent of generated transactions that should be reads */
const uint8_t readPercent;
/** Maximum amount of data to manipulate */
const Addr dataLimit;
/** Number of sequential packets to be generated per cpu request */
const unsigned int numSeqPktsDram;
const unsigned int numSeqPktsNvm;
/** Track number of sequential packets generated for a request */
unsigned int countNumSeqPkts;
/** Address of request */
Addr addr;
/** Page size of DRAM */
const unsigned int pageSizeDram;
/** Number of page bits in DRAM address */
const unsigned int pageBitsDram;
/** Number of bank bits in DRAM address*/
const unsigned int bankBitsDram;
/** Number of block bits in DRAM address */
const unsigned int blockBitsDram;
/** Number of banks in DRAM */
const unsigned int nbrOfBanksDram;
/** Number of banks to be utilized for a given configuration */
const unsigned int nbrOfBanksUtilDram;
/** Buffer size of NVM */
const unsigned int bufferSizeNvm;
/** Number of buffer bits in NVM address */
const unsigned int pageBitsNvm;
/** Number of bank bits in NVM address*/
const unsigned int bankBitsNvm;
/** Number of block bits in NVM address */
const unsigned int blockBitsNvm;
/** Number of banks in NVM */
const unsigned int nbrOfBanksNvm;
/** Number of banks to be utilized for a given configuration */
const unsigned int nbrOfBanksUtilNvm;
/** Address mapping to be used */
Enums::AddrMap addrMapping;
/** Number of ranks to be utilized for a given configuration */
const unsigned int nbrOfRanksDram;
/** Number of rank bits in DRAM address*/
const unsigned int rankBitsDram;
/** Number of ranks to be utilized for a given configuration */
const unsigned int nbrOfRanksNvm;
/** Number of rank bits in DRAM address*/
const unsigned int rankBitsNvm;
/** Percent of generated transactions that should go to NVM */
const uint8_t nvmPercent;
/** Remember type of requests to be generated in series */
bool isRead;
/** Remember the interface to be generated in series */
bool isNvm;
/**
* Counter to determine the amount of data
* manipulated. Used to determine if we should continue
* generating requests.
*/
Addr dataManipulated;
/** Number of sequential DRAM packets to be generated per cpu request */
unsigned int numSeqPkts;
/** Start of address range */
Addr startAddr;
/** End of address range */
Addr endAddr;
/** Blocksize and address increment */
Addr blocksize;
/** Page size of DRAM */
unsigned int pageSize;
/** Number of page bits in DRAM address */
unsigned int pageBits;
/** Number of bank bits in DRAM address*/
unsigned int bankBits;
/** Number of block bits in DRAM address */
unsigned int blockBits;
/** Number of banks in DRAM */
unsigned int nbrOfBanks;
/** Number of banks to be utilized for a given configuration */
unsigned int nbrOfBanksUtil;
/** Number of ranks to be utilized for a given configuration */
unsigned int nbrOfRanks;
/** Number of rank bits in DRAM address*/
unsigned int rankBits;
};
#endif

View File

@@ -0,0 +1,187 @@
/*
* Copyright (c) 2020 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed here under. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* 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.
*
* Authors: Wendy Elsasser
*/
#include "cpu/testers/traffic_gen/nvm_gen.hh"
#include <algorithm>
#include "base/random.hh"
#include "base/trace.hh"
#include "debug/TrafficGen.hh"
#include "enums/AddrMap.hh"
NvmGen::NvmGen(SimObject &obj,
MasterID master_id, Tick _duration,
Addr start_addr, Addr end_addr,
Addr _blocksize, Addr cacheline_size,
Tick min_period, Tick max_period,
uint8_t read_percent, Addr data_limit,
unsigned int num_seq_pkts, unsigned int buffer_size,
unsigned int nbr_of_banks,
unsigned int nbr_of_banks_util,
Enums::AddrMap addr_mapping,
unsigned int nbr_of_ranks)
: RandomGen(obj, master_id, _duration, start_addr, end_addr,
_blocksize, cacheline_size, min_period, max_period,
read_percent, data_limit),
numSeqPkts(num_seq_pkts), countNumSeqPkts(0), addr(0),
isRead(true), bufferSize(buffer_size),
bufferBits(floorLog2(buffer_size / _blocksize)),
bankBits(floorLog2(nbr_of_banks)),
blockBits(floorLog2(_blocksize)),
nbrOfBanksNVM(nbr_of_banks),
nbrOfBanksUtil(nbr_of_banks_util), addrMapping(addr_mapping),
rankBits(floorLog2(nbr_of_ranks)),
nbrOfRanks(nbr_of_ranks)
{
if (nbr_of_banks_util > nbr_of_banks)
fatal("Attempting to use more banks (%d) than "
"what is available (%d)\n",
nbr_of_banks_util, nbr_of_banks);
}
PacketPtr
NvmGen::getNextPacket()
{
// if this is the first of the packets in series to be generated,
// start counting again
if (countNumSeqPkts == 0) {
countNumSeqPkts = numSeqPkts;
// choose if we generate a read or a write here
isRead = readPercent != 0 &&
(readPercent == 100 || random_mt.random(0, 100) < readPercent);
assert((readPercent == 0 && !isRead) ||
(readPercent == 100 && isRead) ||
readPercent != 100);
// pick a random bank
unsigned int new_bank =
random_mt.random<unsigned int>(0, nbrOfBanksUtil - 1);
// pick a random rank
unsigned int new_rank =
random_mt.random<unsigned int>(0, nbrOfRanks - 1);
// Generate the start address of the command series
// routine will update addr variable with bank, rank, and col
// bits updated for random traffic mode
genStartAddr(new_bank, new_rank);
} else {
// increment the column by one
if (addrMapping == Enums::RoRaBaCoCh ||
addrMapping == Enums::RoRaBaChCo)
// Simply increment addr by blocksize to increment
// the column by one
addr += blocksize;
else if (addrMapping == Enums::RoCoRaBaCh) {
// Explicity increment the column bits
unsigned int new_col = ((addr / blocksize /
nbrOfBanksNVM / nbrOfRanks) %
(bufferSize / blocksize)) + 1;
replaceBits(addr, blockBits + bankBits + rankBits +
bufferBits - 1,
blockBits + bankBits + rankBits, new_col);
}
}
DPRINTF(TrafficGen, "NvmGen::getNextPacket: %c to addr %x, "
"size %d, countNumSeqPkts: %d, numSeqPkts: %d\n",
isRead ? 'r' : 'w', addr, blocksize, countNumSeqPkts, numSeqPkts);
// create a new request packet
PacketPtr pkt = getPacket(addr, blocksize,
isRead ? MemCmd::ReadReq : MemCmd::WriteReq);
// add the amount of data manipulated to the total
dataManipulated += blocksize;
// subtract the number of packets remained to be generated
--countNumSeqPkts;
// return the generated packet
return pkt;
}
void
NvmGen::genStartAddr(unsigned int new_bank, unsigned int new_rank)
{
// start by picking a random address in the range
addr = random_mt.random<Addr>(startAddr, endAddr - 1);
// round down to start address of a block, i.e. a NVM burst
addr -= addr % blocksize;
// insert the bank bits at the right spot, and align the
// address to achieve the required hit length, this involves
// finding the appropriate start address such that all
// sequential packets target successive bursts in the same
// buffer
unsigned int burst_per_buffer = bufferSize / blocksize;
// pick a random burst address, but ensure that there is room for
// numSeqPkts sequential bursts in the same buffer
unsigned int new_col =
random_mt.random<unsigned int>(0, burst_per_buffer - numSeqPkts);
if (addrMapping == Enums::RoRaBaCoCh ||
addrMapping == Enums::RoRaBaChCo) {
// Block bits, then buffer bits, then bank bits, then rank bits
replaceBits(addr, blockBits + bufferBits + bankBits - 1,
blockBits + bufferBits, new_bank);
replaceBits(addr, blockBits + bufferBits - 1, blockBits, new_col);
if (rankBits != 0) {
replaceBits(addr, blockBits + bufferBits + bankBits +
rankBits - 1, blockBits + bufferBits + bankBits,
new_rank);
}
} else if (addrMapping == Enums::RoCoRaBaCh) {
// Block bits, then bank bits, then rank bits, then buffer bits
replaceBits(addr, blockBits + bankBits - 1, blockBits, new_bank);
replaceBits(addr, blockBits + bankBits + rankBits + bufferBits - 1,
blockBits + bankBits + rankBits, new_col);
if (rankBits != 0) {
replaceBits(addr, blockBits + bankBits + rankBits - 1,
blockBits + bankBits, new_rank);
}
}
}

View File

@@ -0,0 +1,151 @@
/*
* Copyright (c) 2020 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed here under. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* 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.
*
* Authors: Wendy Elsasser
*/
/**
* @file
* Declaration of the NVM generator for issuing variable buffer
* hit length requests and bank utilisation.
*/
#ifndef __CPU_TRAFFIC_GEN_NVM_GEN_HH__
#define __CPU_TRAFFIC_GEN_NVM_GEN_HH__
#include "base/bitfield.hh"
#include "base/intmath.hh"
#include "enums/AddrMap.hh"
#include "mem/packet.hh"
#include "random_gen.hh"
/**
* NVM specific generator is for issuing request with variable buffer
* hit length and bank utilization. Currently assumes a single
* channel configuration.
*/
class NvmGen : public RandomGen
{
public:
/**
* Create a NVM address sequence generator.
*
* @param obj SimObject owning this sequence generator
* @param master_id MasterID related to the memory requests
* @param _duration duration of this state before transitioning
* @param start_addr Start address
* @param end_addr End address
* @param _blocksize Size used for transactions injected
* @param cacheline_size cache line size in the system
* @param min_period Lower limit of random inter-transaction time
* @param max_period Upper limit of random inter-transaction time
* @param read_percent Percent of transactions that are reads
* @param data_limit Upper limit on how much data to read/write
* @param num_seq_pkts Number of packets per stride, each of _blocksize
* @param page_size Buffer size (bytes) used in the NVM
* @param nbr_of_banks Total number of parallel banks in NVM
* @param nbr_of_banks_util Number of banks to utilized,
* for N banks, we will use banks: 0->(N-1)
* @param addr_mapping Address mapping to be used,
* assumes single channel system
*/
NvmGen(SimObject &obj,
MasterID master_id, Tick _duration,
Addr start_addr, Addr end_addr,
Addr _blocksize, Addr cacheline_size,
Tick min_period, Tick max_period,
uint8_t read_percent, Addr data_limit,
unsigned int num_seq_pkts, unsigned int buffer_size,
unsigned int nbr_of_banks, unsigned int nbr_of_banks_util,
Enums::AddrMap addr_mapping,
unsigned int nbr_of_ranks);
PacketPtr getNextPacket();
/** Insert bank, rank, and column bits into packed
* address to create address for 1st command in a
* series
* @param new_bank Bank number of next packet series
* @param new_rank Rank value of next packet series
*/
void genStartAddr(unsigned int new_bank, unsigned int new_rank);
protected:
/** Number of sequential NVM packets to be generated per cpu request */
const unsigned int numSeqPkts;
/** Track number of sequential packets generated for a request */
unsigned int countNumSeqPkts;
/** Address of request */
Addr addr;
/** Remember type of requests to be generated in series */
bool isRead;
/** Buffer size of NVM */
const unsigned int bufferSize;
/** Number of buffer bits in NVM address */
const unsigned int bufferBits;
/** Number of bank bits in NVM address*/
const unsigned int bankBits;
/** Number of block bits in NVM address */
const unsigned int blockBits;
/** Number of banks in NVM */
const unsigned int nbrOfBanksNVM;
/** Number of banks to be utilized for a given configuration */
const unsigned int nbrOfBanksUtil;
/** Address mapping to be used */
Enums::AddrMap addrMapping;
/** Number of rank bits in NVM address*/
const unsigned int rankBits;
/** Number of ranks to be utilized for a given configuration */
const unsigned int nbrOfRanks;
};
#endif

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2013, 2016-2019 ARM Limited
* Copyright (c) 2012-2013, 2016-2020 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
@@ -182,7 +182,8 @@ TrafficGen::parseConfig()
states[id] = createExit(duration);
DPRINTF(TrafficGen, "State: %d ExitGen\n", id);
} else if (mode == "LINEAR" || mode == "RANDOM" ||
mode == "DRAM" || mode == "DRAM_ROTATE") {
mode == "DRAM" || mode == "DRAM_ROTATE" ||
mode == "NVM") {
uint32_t read_percent;
Addr start_addr;
Addr end_addr;
@@ -212,25 +213,26 @@ TrafficGen::parseConfig()
min_period, max_period,
read_percent, data_limit);
DPRINTF(TrafficGen, "State: %d RandomGen\n", id);
} else if (mode == "DRAM" || mode == "DRAM_ROTATE") {
} else if (mode == "DRAM" || mode == "DRAM_ROTATE" ||
mode == "NVM") {
// stride size (bytes) of the request for achieving
// required hit length
unsigned int stride_size;
unsigned int page_size;
unsigned int nbr_of_banks_DRAM;
unsigned int nbr_of_banks;
unsigned int nbr_of_banks_util;
unsigned _addr_mapping;
unsigned int nbr_of_ranks;
is >> stride_size >> page_size >> nbr_of_banks_DRAM >>
is >> stride_size >> page_size >> nbr_of_banks >>
nbr_of_banks_util >> _addr_mapping >>
nbr_of_ranks;
Enums::AddrMap addr_mapping =
static_cast<Enums::AddrMap>(_addr_mapping);
if (stride_size > page_size)
warn("DRAM generator stride size (%d) is greater "
"than page size (%d) of the memory\n",
warn("Memory generator stride size (%d) is greater"
" than page size (%d) of the memory\n",
blocksize, page_size);
// count the number of sequential packets to
@@ -250,12 +252,12 @@ TrafficGen::parseConfig()
min_period, max_period,
read_percent, data_limit,
num_seq_pkts, page_size,
nbr_of_banks_DRAM,
nbr_of_banks,
nbr_of_banks_util,
addr_mapping,
nbr_of_ranks);
DPRINTF(TrafficGen, "State: %d DramGen\n", id);
} else {
} else if (mode == "DRAM_ROTATE") {
// Will rotate to the next rank after rotating
// through all banks, for each command type.
// In the 50% read case, series will be issued
@@ -270,12 +272,23 @@ TrafficGen::parseConfig()
read_percent,
data_limit,
num_seq_pkts, page_size,
nbr_of_banks_DRAM,
nbr_of_banks,
nbr_of_banks_util,
addr_mapping,
nbr_of_ranks,
max_seq_count_per_rank);
DPRINTF(TrafficGen, "State: %d DramRotGen\n", id);
} else {
states[id] = createNvm(duration, start_addr,
end_addr, blocksize,
min_period, max_period,
read_percent, data_limit,
num_seq_pkts, page_size,
nbr_of_banks,
nbr_of_banks_util,
addr_mapping,
nbr_of_ranks);
DPRINTF(TrafficGen, "State: %d NvmGen\n", id);
}
}
} else {

View File

@@ -59,7 +59,10 @@ class DRAMCtrl(QoSMemCtrl):
port = SlavePort("Slave port")
# Interface to volatile, DRAM media
dram = Param.DRAMInterface("DRAM interface")
dram = Param.DRAMInterface(NULL, "DRAM interface")
# Interface to non-volatile media
nvm = Param.NVMInterface(NULL, "NVM interface")
# read and write buffer depths are set in the interface
# the controller will read these values when instantiated
@@ -85,3 +88,5 @@ class DRAMCtrl(QoSMemCtrl):
# serviced by the memory seeing the sum of the two
static_frontend_latency = Param.Latency("10ns", "Static frontend latency")
static_backend_latency = Param.Latency("10ns", "Static backend latency")
command_window = Param.Latency("10ns", "Static backend latency")

View File

@@ -38,59 +38,28 @@
# (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.params import *
from m5.proxy import *
from m5.objects.AbstractMemory import AbstractMemory
# Enum for the address mapping. With Ch, Ra, Ba, Ro and Co denoting
# channel, rank, bank, row and column, respectively, and going from
# MSB to LSB. Available are RoRaBaChCo and RoRaBaCoCh, that are
# suitable for an open-page policy, optimising for sequential accesses
# hitting in the open row. For a closed-page policy, RoCoRaBaCh
# maximises parallelism.
class AddrMap(Enum): vals = ['RoRaBaChCo', 'RoRaBaCoCh', 'RoCoRaBaCh']
from m5.objects.MemInterface import *
# Enum for the page policy, either open, open_adaptive, close, or
# close_adaptive.
class PageManage(Enum): vals = ['open', 'open_adaptive', 'close',
'close_adaptive']
class DRAMInterface(AbstractMemory):
class DRAMInterface(MemInterface):
type = 'DRAMInterface'
cxx_header = "mem/dram_ctrl.hh"
# Allow the interface to set required controller buffer sizes
# each entry corresponds to a burst for the specific DRAM
# configuration (e.g. x32 with burst length 8 is 32 bytes) and not
# the cacheline size or request/packet size
write_buffer_size = Param.Unsigned(64, "Number of write queue entries")
read_buffer_size = Param.Unsigned(32, "Number of read queue entries")
# scheduler, address map and page policy
addr_mapping = Param.AddrMap('RoRaBaCoCh', "Address mapping policy")
# scheduler page policy
page_policy = Param.PageManage('open_adaptive', "Page management policy")
# enforce a limit on the number of accesses per row
max_accesses_per_row = Param.Unsigned(16, "Max accesses per row before "
"closing");
# size of DRAM Chip in Bytes
device_size = Param.MemorySize("Size of DRAM chip")
# the physical organisation of the DRAM
device_bus_width = Param.Unsigned("data bus width in bits for each DRAM "\
"device/chip")
burst_length = Param.Unsigned("Burst lenght (BL) in beats")
device_rowbuffer_size = Param.MemorySize("Page (row buffer) size per "\
"device/chip")
devices_per_rank = Param.Unsigned("Number of devices/chips per rank")
ranks_per_channel = Param.Unsigned("Number of ranks per channel")
# default to 0 bank groups per rank, indicating bank group architecture
# is not used
# update per memory class when bank group architecture is supported
bank_groups_per_rank = Param.Unsigned(0, "Number of bank groups per rank")
banks_per_rank = Param.Unsigned("Number of banks per rank")
# Enable DRAM powerdown states if True. This is False by default due to
# performance being lower when enabled
@@ -107,9 +76,6 @@ class DRAMInterface(AbstractMemory):
# timing behaviour and constraints - all in nanoseconds
# the base clock period of the DRAM
tCK = Param.Latency("Clock period")
# the amount of time in nanoseconds from issuing an activate command
# to the data being available in the row buffer for a read/write
tRCD = Param.Latency("RAS to CAS delay")
@@ -129,18 +95,6 @@ class DRAMInterface(AbstractMemory):
# minimum time between a read and precharge command
tRTP = Param.Latency("Read to precharge")
# time to complete a burst transfer, typically the burst length
# divided by two due to the DDR bus, but by making it a parameter
# it is easier to also evaluate SDR memories like WideIO.
# This parameter has to account for burst length.
# Read/Write requests with data size larger than one full burst are broken
# down into multiple requests in the controller
# tBURST is equivalent to the CAS-to-CAS delay (tCCD)
# With bank group architectures, tBURST represents the CAS-to-CAS
# delay for bursts to different bank groups (tCCD_S)
tBURST = Param.Latency("Burst duration "
"(typically burst length / 2 cycles)")
# tBURST_MAX is the column array cycle delay required before next access,
# which could be greater than tBURST when the memory access time is greater
# than tBURST
@@ -170,22 +124,10 @@ class DRAMInterface(AbstractMemory):
# to be sent. It is 7.8 us for a 64ms refresh requirement
tREFI = Param.Latency("Refresh command interval")
# write-to-read, same rank turnaround penalty
tWTR = Param.Latency("Write to read, same rank switching time")
# write-to-read, same rank turnaround penalty for same bank group
tWTR_L = Param.Latency(Self.tWTR, "Write to read, same rank switching "
"time, same bank group")
# read-to-write, same rank turnaround penalty
tRTW = Param.Latency("Read to write, same rank switching time")
# rank-to-rank bus delay penalty
# this does not correlate to a memory timing parameter and encompasses:
# 1) RD-to-RD, 2) WR-to-WR, 3) RD-to-WR, and 4) WR-to-RD
# different rank bus delay
tCS = Param.Latency("Rank to rank switching time")
# minimum precharge to precharge delay time
tPPD = Param.Latency("0ns", "PRE to PRE delay")
@@ -221,6 +163,7 @@ class DRAMInterface(AbstractMemory):
tXSDLL = Param.Latency("0ns", "Self-refresh exit latency DLL")
# number of data beats per clock. with DDR, default is 2, one per edge
# used in drampower.cc
beats_per_clock = Param.Unsigned(2, "Data beats per clock")
data_clock_sync = Param.Bool(False, "Synchronization commands required")

106
src/mem/MemInterface.py Normal file
View File

@@ -0,0 +1,106 @@
# Copyright (c) 2012-2020 ARM Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# Copyright (c) 2013 Amin Farmahini-Farahani
# Copyright (c) 2015 University of Kaiserslautern
# Copyright (c) 2015 The University of Bologna
# 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 m5.params import *
from m5.proxy import *
from m5.objects.AbstractMemory import AbstractMemory
# Enum for the address mapping. With Ch, Ra, Ba, Ro and Co denoting
# channel, rank, bank, row and column, respectively, and going from
# MSB to LSB. Available are RoRaBaChCo and RoRaBaCoCh, that are
# suitable for an open-page policy, optimising for sequential accesses
# hitting in the open row. For a closed-page policy, RoCoRaBaCh
# maximises parallelism.
class AddrMap(Enum): vals = ['RoRaBaChCo', 'RoRaBaCoCh', 'RoCoRaBaCh']
class MemInterface(AbstractMemory):
type = 'MemInterface'
abstract = True
cxx_header = "mem/dram_ctrl.hh"
# Allow the interface to set required controller buffer sizes
# each entry corresponds to a burst for the specific memory channel
# configuration (e.g. x32 with burst length 8 is 32 bytes) and not
# the cacheline size or request/packet size
write_buffer_size = Param.Unsigned(64, "Number of write queue entries")
read_buffer_size = Param.Unsigned(32, "Number of read queue entries")
# scheduler, address map
addr_mapping = Param.AddrMap('RoRaBaCoCh', "Address mapping policy")
# size of memory device in Bytes
device_size = Param.MemorySize("Size of memory device")
# the physical organisation of the memory
device_bus_width = Param.Unsigned("data bus width in bits for each "\
"memory device/chip")
burst_length = Param.Unsigned("Burst lenght (BL) in beats")
device_rowbuffer_size = Param.MemorySize("Page (row buffer) size per "\
"device/chip")
devices_per_rank = Param.Unsigned("Number of devices/chips per rank")
ranks_per_channel = Param.Unsigned("Number of ranks per channel")
banks_per_rank = Param.Unsigned("Number of banks per rank")
# timing behaviour and constraints - all in nanoseconds
# the base clock period of the memory
tCK = Param.Latency("Clock period")
# time to complete a burst transfer, typically the burst length
# divided by two due to the DDR bus, but by making it a parameter
# it is easier to also evaluate SDR memories like WideIO and new
# interfaces, emerging technologies.
# This parameter has to account for burst length.
# Read/Write requests with data size larger than one full burst are broken
# down into multiple requests in the controller
tBURST = Param.Latency("Burst duration "
"(typically burst length / 2 cycles)")
# write-to-read, same rank turnaround penalty
tWTR = Param.Latency("Write to read, same rank switching time")
# read-to-write, same rank turnaround penalty
tRTW = Param.Latency("Read to write, same rank switching time")
# rank-to-rank bus delay penalty
# this does not correlate to a memory timing parameter and encompasses:
# 1) RD-to-RD, 2) WR-to-WR, 3) RD-to-WR, and 4) WR-to-RD
# different rank bus delay
tCS = Param.Latency("Rank to rank switching time")

103
src/mem/NVMInterface.py Normal file
View File

@@ -0,0 +1,103 @@
# Copyright (c) 2020 ARM Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# 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 m5.params import *
from m5.proxy import *
from m5.objects.MemInterface import MemInterface
from m5.objects.DRAMInterface import AddrMap
# The following interface aims to model byte-addressable NVM
# The most important system-level performance effects of a NVM
# are modeled without getting into too much detail of the media itself.
class NVMInterface(MemInterface):
type = 'NVMInterface'
cxx_header = "mem/dram_ctrl.hh"
# NVM DIMM could have write buffer to offload writes
# define buffer depth, which will limit the number of pending writes
max_pending_writes = Param.Unsigned("1", "Max pending write commands")
# NVM DIMM could have buffer to offload read commands
# define buffer depth, which will limit the number of pending reads
max_pending_reads = Param.Unsigned("1", "Max pending read commands")
# timing behaviour and constraints - all in nanoseconds
# define average latency for NVM media. Latency defined uniquely
# for read and writes as the media is typically not symmetric
tREAD = Param.Latency("100ns", "Average NVM read latency")
tWRITE = Param.Latency("200ns", "Average NVM write latency")
tSEND = Param.Latency("15ns", "Access latency")
two_cycle_rdwr = Param.Bool(False,
"Two cycles required to send read and write commands")
# NVM delays and device architecture defined to mimic PCM like memory.
# Can be configured with DDR4_2400 sharing the channel
class NVM_2400_1x64(NVMInterface):
write_buffer_size = 128
read_buffer_size = 64
max_pending_writes = 128
max_pending_reads = 64
device_rowbuffer_size = '256B'
# 8X capacity compared to DDR4 x4 DIMM with 8Gb devices
device_size = '512GB'
# Mimic 64-bit media agnostic DIMM interface
device_bus_width = 64
devices_per_rank = 1
ranks_per_channel = 1
banks_per_rank = 16
burst_length = 8
two_cycle_rdwr = True
# 1200 MHz
tCK = '0.833ns'
tREAD = '150ns'
tWRITE = '500ns';
tSEND = '14.16ns';
tBURST = '3.332ns';
# Default all bus turnaround and rank bus delay to 2 cycles
# With DDR data bus, clock = 1200 MHz = 1.666 ns
tWTR = '1.666ns';
tRTW = '1.666ns';
tCS = '1.666ns'

View File

@@ -47,7 +47,9 @@ SimObject('AbstractMemory.py')
SimObject('AddrMapper.py')
SimObject('Bridge.py')
SimObject('DRAMCtrl.py')
SimObject('MemInterface.py')
SimObject('DRAMInterface.py')
SimObject('NVMInterface.py')
SimObject('ExternalMaster.py')
SimObject('ExternalSlave.py')
SimObject('MemObject.py')
@@ -114,6 +116,7 @@ DebugFlag('CommMonitor')
DebugFlag('DRAM')
DebugFlag('DRAMPower')
DebugFlag('DRAMState')
DebugFlag('NVM')
DebugFlag('ExternalPort')
DebugFlag('HtmMem', 'Hardware Transactional Memory (Mem side)')
DebugFlag('LLSC')

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff