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:
committed by
Jason Lowe-Power
parent
4acc419b6f
commit
dab7c78eca
@@ -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
199
configs/nvm/sweep.py
Normal 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
242
configs/nvm/sweep_hybrid.py
Normal 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))
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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')
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
314
src/cpu/testers/traffic_gen/hybrid_gen.cc
Normal file
314
src/cpu/testers/traffic_gen/hybrid_gen.cc
Normal 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;
|
||||
}
|
||||
}
|
||||
277
src/cpu/testers/traffic_gen/hybrid_gen.hh
Normal file
277
src/cpu/testers/traffic_gen/hybrid_gen.hh
Normal 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
|
||||
187
src/cpu/testers/traffic_gen/nvm_gen.cc
Normal file
187
src/cpu/testers/traffic_gen/nvm_gen.cc
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
151
src/cpu/testers/traffic_gen/nvm_gen.hh
Normal file
151
src/cpu/testers/traffic_gen/nvm_gen.hh
Normal 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
|
||||
@@ -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 {
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
106
src/mem/MemInterface.py
Normal 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
103
src/mem/NVMInterface.py
Normal 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'
|
||||
|
||||
@@ -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')
|
||||
|
||||
1270
src/mem/dram_ctrl.cc
1270
src/mem/dram_ctrl.cc
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user