configs: changed CHI --noc-config format
Changed format from yaml to plain python. The new py configuration
file, when provided, must specialize the CHI node types defined in
configs/ruby/CHI_config.py (moved from configs/ruby/CHI.py). This
is required in order to setup the node->router bindings when the
CustomMesh topology is used.
See configs/example/noc_config/2x4.py (replaces
configs/example/noc_config/2x4.yaml) for an example.
--noc-config was also renamed to --chi-config, since the CHI node types
can be fully specialized in the configuration file.
Change-Id: Ic0c5407dba3d2483d5c30634c115b5410a5228fd
Signed-off-by: Tiago Mück <tiago.muck@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/43123
Reviewed-by: Jason Lowe-Power <power.jg@gmail.com>
Maintainer: Jason Lowe-Power <power.jg@gmail.com>
Tested-by: kokoro <noreply+kokoro@google.com>
diff --git a/configs/example/noc_config/2x4.yaml b/configs/example/noc_config/2x4.py
similarity index 63%
rename from configs/example/noc_config/2x4.yaml
rename to configs/example/noc_config/2x4.py
index 84ec476..fe2522b 100644
--- a/configs/example/noc_config/2x4.yaml
+++ b/configs/example/noc_config/2x4.py
@@ -33,38 +33,45 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-# 2x4 mesh definition
+from ruby import CHI_config
+
+# CustomMesh parameters for a 2x4 mesh. Routers will have the following layout:
#
# 0 --- 1 --- 2 --- 3
# | | | |
# 4 --- 5 --- 6 --- 7
#
-mesh:
- num_rows : 2
- num_cols : 4
- router_latency : 1
- link_latency : 1
+# Default parameter are configs/ruby/CHI_config.py
+#
+class NoC_Params(CHI_config.NoC_Params):
+ num_rows = 2
+ num_cols = 4
-# Bindings for each CHI node type.
+# Specialization of nodes to define bindings for each CHI node type
+# needed by CustomMesh.
+# The default types are defined in CHI_Node and their derivatives in
+# configs/ruby/CHI_config.py
-CHI_RNF:
- # Uncomment to map num_nodes_per_router RNFs in each provided router,
- # assuming num. created CHI_RNFs == len(router_list)*num_nodes_per_router
- # num_nodes_per_router: 1
- router_list: [1, 2, 5, 6]
+class CHI_RNF(CHI_config.CHI_RNF):
+ class NoC_Params(CHI_config.CHI_RNF.NoC_Params):
+ router_list = [1, 2, 5, 6]
-CHI_HNF:
- # num_nodes_per_router: 1
- router_list: [1, 2, 5, 6]
+class CHI_HNF(CHI_config.CHI_HNF):
+ class NoC_Params(CHI_config.CHI_HNF.NoC_Params):
+ router_list = [1, 2, 5, 6]
-CHI_SNF_MainMem:
- # num_nodes_per_router: 1
- router_list: [0, 4]
+class CHI_SNF_MainMem(CHI_config.CHI_SNF_MainMem):
+ class NoC_Params(CHI_config.CHI_SNF_MainMem.NoC_Params):
+ router_list = [0, 4]
-# Applies to CHI_SNF_BootMem and possibly other non-main memories
-CHI_SNF_IO:
- router_list: [3]
+class CHI_SNF_BootMem(CHI_config.CHI_SNF_BootMem):
+ class NoC_Params(CHI_config.CHI_SNF_BootMem.NoC_Params):
+ router_list = [3]
-# Applies to CHI_RNI_DMA and CHI_RNI_IO
-CHI_RNI_IO:
- router_list: [7]
+class CHI_RNI_DMA(CHI_config.CHI_RNI_DMA):
+ class NoC_Params(CHI_config.CHI_RNI_DMA.NoC_Params):
+ router_list = [7]
+
+class CHI_RNI_IO(CHI_config.CHI_RNI_IO):
+ class NoC_Params(CHI_config.CHI_RNI_IO.NoC_Params):
+ router_list = [7]
diff --git a/configs/ruby/CHI.py b/configs/ruby/CHI.py
index 0a49371..61f0e18 100644
--- a/configs/ruby/CHI.py
+++ b/configs/ruby/CHI.py
@@ -33,617 +33,25 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-import math
-import yaml
import m5
from m5.objects import *
from m5.defines import buildEnv
-from .Ruby import create_topology, setup_memory_controllers
+from .Ruby import create_topology
def define_options(parser):
- parser.add_option("--noc-config", action="store", type="string",
+ parser.add_option("--chi-config", action="store", type="string",
default=None,
- help="YAML NoC config. parameters and bindings. "
- "required for CustomMesh topology")
+ help="NoC config. parameters and bindings. "
+ "Required for CustomMesh topology")
-class Versions:
- '''
- Helper class to obtain unique ids for a given controller class.
- These are passed as the 'version' parameter when creating the controller.
- '''
- _seqs = 0
- @classmethod
- def getSeqId(cls):
- val = cls._seqs
- cls._seqs += 1
- return val
-
- _version = {}
- @classmethod
- def getVersion(cls, tp):
- if tp not in cls._version:
- cls._version[tp] = 0
- val = cls._version[tp]
- cls._version[tp] = val + 1
- return val
-
-
-class CHI_Node(SubSystem):
- '''
- Base class with common functions for setting up Cache or Memory
- controllers that are part of a CHI RNF, RNFI, HNF, or SNF nodes.
- Notice getNetworkSideControllers and getAllControllers must be implemented
- in the derived classes.
- '''
-
- def __init__(self, ruby_system):
- super(CHI_Node, self).__init__()
- self._ruby_system = ruby_system
- self._network = ruby_system.network
-
- def getNetworkSideControllers(self):
- '''
- Returns all ruby controllers that need to be connected to the
- network
- '''
- raise NotImplementedError()
-
- def getAllControllers(self):
- '''
- Returns all ruby controllers associated with this node
- '''
- raise NotImplementedError()
-
- def setDownstream(self, cntrls):
- '''
- Sets cntrls as the downstream list of all controllers in this node
- '''
- for c in self.getNetworkSideControllers():
- c.downstream_destinations = cntrls
-
- def connectController(self, cntrl):
- '''
- Creates and configures the messages buffers for the CHI input/output
- ports that connect to the network
- '''
- cntrl.reqOut = MessageBuffer()
- cntrl.rspOut = MessageBuffer()
- cntrl.snpOut = MessageBuffer()
- cntrl.datOut = MessageBuffer()
- cntrl.reqIn = MessageBuffer()
- cntrl.rspIn = MessageBuffer()
- cntrl.snpIn = MessageBuffer()
- cntrl.datIn = MessageBuffer()
-
- # All CHI ports are always connected to the network.
- # Controllers that are not part of the getNetworkSideControllers list
- # still communicate using internal routers, thus we need to wire-up the
- # ports
- cntrl.reqOut.out_port = self._network.in_port
- cntrl.rspOut.out_port = self._network.in_port
- cntrl.snpOut.out_port = self._network.in_port
- cntrl.datOut.out_port = self._network.in_port
- cntrl.reqIn.in_port = self._network.out_port
- cntrl.rspIn.in_port = self._network.out_port
- cntrl.snpIn.in_port = self._network.out_port
- cntrl.datIn.in_port = self._network.out_port
-
-class TriggerMessageBuffer(MessageBuffer):
- '''
- MessageBuffer for triggering internal controller events.
- These buffers should not be affected by the Ruby tester randomization
- and allow poping messages enqueued in the same cycle.
- '''
- randomization = 'disabled'
- allow_zero_latency = True
-
-class OrderedTriggerMessageBuffer(TriggerMessageBuffer):
- ordered = True
-
-class CHI_Cache_Controller(Cache_Controller):
- '''
- Default parameters for a Cache controller
- The Cache_Controller can also be used as a DMA requester or as
- a pure directory if all cache allocation policies are disabled.
- '''
-
- def __init__(self, ruby_system):
- super(CHI_Cache_Controller, self).__init__(
- version = Versions.getVersion(Cache_Controller),
- ruby_system = ruby_system,
- mandatoryQueue = MessageBuffer(),
- prefetchQueue = MessageBuffer(),
- triggerQueue = TriggerMessageBuffer(),
- retryTriggerQueue = OrderedTriggerMessageBuffer(),
- replTriggerQueue = OrderedTriggerMessageBuffer(),
- reqRdy = TriggerMessageBuffer(),
- snpRdy = TriggerMessageBuffer())
- # Set somewhat large number since we really a lot on internal
- # triggers. To limit the controller performance, tweak other
- # params such as: input port buffer size, cache banks, and output
- # port latency
- self.transitions_per_cycle = 128
- # This should be set to true in the data cache controller to enable
- # timeouts on unique lines when a store conditional fails
- self.sc_lock_enabled = False
-
-class CHI_L1Controller(CHI_Cache_Controller):
- '''
- Default parameters for a L1 Cache controller
- '''
-
- def __init__(self, ruby_system, sequencer, cache, prefetcher):
- super(CHI_L1Controller, self).__init__(ruby_system)
- self.sequencer = sequencer
- self.cache = cache
- self.use_prefetcher = False
- self.send_evictions = True
- self.is_HN = False
- self.enable_DMT = False
- self.enable_DCT = False
- # Strict inclusive MOESI
- self.allow_SD = True
- self.alloc_on_seq_acc = True
- self.alloc_on_seq_line_write = False
- self.alloc_on_readshared = True
- self.alloc_on_readunique = True
- self.alloc_on_readonce = True
- self.alloc_on_writeback = True
- self.dealloc_on_unique = False
- self.dealloc_on_shared = False
- self.dealloc_backinv_unique = True
- self.dealloc_backinv_shared = True
- # Some reasonable default TBE params
- self.number_of_TBEs = 16
- self.number_of_repl_TBEs = 16
- self.number_of_snoop_TBEs = 4
- self.unify_repl_TBEs = False
-
-class CHI_L2Controller(CHI_Cache_Controller):
- '''
- Default parameters for a L2 Cache controller
- '''
-
- def __init__(self, ruby_system, cache, prefetcher):
- super(CHI_L2Controller, self).__init__(ruby_system)
- self.sequencer = NULL
- self.cache = cache
- self.use_prefetcher = False
- self.allow_SD = True
- self.is_HN = False
- self.enable_DMT = False
- self.enable_DCT = False
- self.send_evictions = False
- # Strict inclusive MOESI
- self.alloc_on_seq_acc = False
- self.alloc_on_seq_line_write = False
- self.alloc_on_readshared = True
- self.alloc_on_readunique = True
- self.alloc_on_readonce = True
- self.alloc_on_writeback = True
- self.dealloc_on_unique = False
- self.dealloc_on_shared = False
- self.dealloc_backinv_unique = True
- self.dealloc_backinv_shared = True
- # Some reasonable default TBE params
- self.number_of_TBEs = 32
- self.number_of_repl_TBEs = 32
- self.number_of_snoop_TBEs = 16
- self.unify_repl_TBEs = False
-
-class CHI_HNFController(CHI_Cache_Controller):
- '''
- Default parameters for a coherent home node (HNF) cache controller
- '''
-
- def __init__(self, ruby_system, cache, prefetcher, addr_ranges):
- super(CHI_HNFController, self).__init__(ruby_system)
- self.sequencer = NULL
- self.cache = cache
- self.use_prefetcher = False
- self.addr_ranges = addr_ranges
- self.allow_SD = True
- self.is_HN = True
- self.enable_DMT = True
- self.enable_DCT = True
- self.send_evictions = False
- # MOESI / Mostly inclusive for shared / Exclusive for unique
- self.alloc_on_seq_acc = False
- self.alloc_on_seq_line_write = False
- self.alloc_on_readshared = True
- self.alloc_on_readunique = False
- self.alloc_on_readonce = True
- self.alloc_on_writeback = True
- self.dealloc_on_unique = True
- self.dealloc_on_shared = False
- self.dealloc_backinv_unique = False
- self.dealloc_backinv_shared = False
- # Some reasonable default TBE params
- self.number_of_TBEs = 32
- self.number_of_repl_TBEs = 32
- self.number_of_snoop_TBEs = 1 # should not receive any snoop
- self.unify_repl_TBEs = False
-
-class CHI_DMAController(CHI_Cache_Controller):
- '''
- Default parameters for a DMA controller
- '''
-
- def __init__(self, ruby_system, sequencer):
- super(CHI_DMAController, self).__init__(ruby_system)
- self.sequencer = sequencer
- class DummyCache(RubyCache):
- dataAccessLatency = 0
- tagAccessLatency = 1
- size = "128"
- assoc = 1
- self.use_prefetcher = False
- self.cache = DummyCache()
- self.sequencer.dcache = NULL
- # All allocations are false
- # Deallocations are true (don't really matter)
- self.allow_SD = False
- self.is_HN = False
- self.enable_DMT = False
- self.enable_DCT = False
- self.alloc_on_seq_acc = False
- self.alloc_on_seq_line_write = False
- self.alloc_on_readshared = False
- self.alloc_on_readunique = False
- self.alloc_on_readonce = False
- self.alloc_on_writeback = False
- self.dealloc_on_unique = False
- self.dealloc_on_shared = False
- self.dealloc_backinv_unique = False
- self.dealloc_backinv_shared = False
- self.send_evictions = False
- self.number_of_TBEs = 16
- self.number_of_repl_TBEs = 1
- self.number_of_snoop_TBEs = 1 # should not receive any snoop
- self.unify_repl_TBEs = False
-
-class CPUSequencerWrapper:
- '''
- Other generic configuration scripts assume a matching number of sequencers
- and cpus. This wraps the instruction and data sequencer so they are
- compatible with the other scripts. This assumes all scripts are using
- connectCpuPorts/connectIOPorts to bind ports
- '''
-
- def __init__(self, iseq, dseq):
- # use this style due to __setattr__ override below
- self.__dict__['inst_seq'] = iseq
- self.__dict__['data_seq'] = dseq
- self.__dict__['support_data_reqs'] = True
- self.__dict__['support_inst_reqs'] = True
- # Compatibility with certain scripts that wire up ports
- # without connectCpuPorts
- self.__dict__['slave'] = dseq.in_ports
- self.__dict__['in_ports'] = dseq.in_ports
-
- def connectCpuPorts(self, cpu):
- assert(isinstance(cpu, BaseCPU))
- cpu.icache_port = self.inst_seq.in_ports
- for p in cpu._cached_ports:
- if str(p) != 'icache_port':
- exec('cpu.%s = self.data_seq.in_ports' % p)
- cpu.connectUncachedPorts(self.data_seq)
-
- def connectIOPorts(self, piobus):
- self.data_seq.connectIOPorts(piobus)
-
- def __setattr__(self, name, value):
- setattr(self.inst_seq, name, value)
- setattr(self.data_seq, name, value)
-
-class CHI_RNF(CHI_Node):
- '''
- Defines a CHI request node.
- Notice all contollers and sequencers are set as children of the cpus, so
- this object acts more like a proxy for seting things up and has no topology
- significance unless the cpus are set as its children at the top level
- '''
- def __init__(self, cpus, ruby_system,
- l1Icache_type, l1Dcache_type,
- cache_line_size,
- l1Iprefetcher_type=None, l1Dprefetcher_type=None):
- super(CHI_RNF, self).__init__(ruby_system)
-
- self._block_size_bits = int(math.log(cache_line_size, 2))
-
- # All sequencers and controllers
- self._seqs = []
- self._cntrls = []
-
- # Last level controllers in this node, i.e., the ones that will send
- # requests to the home nodes
- self._ll_cntrls = []
-
- self._cpus = cpus
-
- # First creates L1 caches and sequencers
- for cpu in self._cpus:
- cpu.inst_sequencer = RubySequencer(version = Versions.getSeqId(),
- ruby_system = ruby_system)
- cpu.data_sequencer = RubySequencer(version = Versions.getSeqId(),
- ruby_system = ruby_system)
-
- self._seqs.append(CPUSequencerWrapper(cpu.inst_sequencer,
- cpu.data_sequencer))
-
- # caches
- l1i_cache = l1Icache_type(start_index_bit = self._block_size_bits,
- is_icache = True)
-
- l1d_cache = l1Dcache_type(start_index_bit = self._block_size_bits,
- is_icache = False)
-
- # Placeholders for future prefetcher support
- if l1Iprefetcher_type != None or l1Dprefetcher_type != None:
- m5.fatal('Prefetching not supported yet')
- l1i_pf = NULL
- l1d_pf = NULL
-
- # cache controllers
- cpu.l1i = CHI_L1Controller(ruby_system, cpu.inst_sequencer,
- l1i_cache, l1i_pf)
-
- cpu.l1d = CHI_L1Controller(ruby_system, cpu.data_sequencer,
- l1d_cache, l1d_pf)
-
- cpu.inst_sequencer.dcache = NULL
- cpu.data_sequencer.dcache = cpu.l1d.cache
-
- cpu.l1d.sc_lock_enabled = True
-
- cpu._ll_cntrls = [cpu.l1i, cpu.l1d]
- for c in cpu._ll_cntrls:
- self._cntrls.append(c)
- self.connectController(c)
- self._ll_cntrls.append(c)
-
- def getSequencers(self):
- return self._seqs
-
- def getAllControllers(self):
- return self._cntrls
-
- def getNetworkSideControllers(self):
- return self._cntrls
-
- def setDownstream(self, cntrls):
- for c in self._ll_cntrls:
- c.downstream_destinations = cntrls
-
- def getCpus(self):
- return self._cpus
-
- # Adds a private L2 for each cpu
- def addPrivL2Cache(self, cache_type, pf_type=None):
- self._ll_cntrls = []
- for cpu in self._cpus:
- l2_cache = cache_type(start_index_bit = self._block_size_bits,
- is_icache = False)
- if pf_type != None:
- m5.fatal('Prefetching not supported yet')
- l2_pf = NULL
-
- cpu.l2 = CHI_L2Controller(self._ruby_system, l2_cache, l2_pf)
-
- self._cntrls.append(cpu.l2)
- self.connectController(cpu.l2)
-
- self._ll_cntrls.append(cpu.l2)
-
- for c in cpu._ll_cntrls:
- c.downstream_destinations = [cpu.l2]
- cpu._ll_cntrls = [cpu.l2]
-
-
-class CHI_HNF(CHI_Node):
- '''
- Encapsulates an HNF cache/directory controller.
- Before the first controller is created, the class method
- CHI_HNF.createAddrRanges must be called before creating any CHI_HNF object
- to set-up the interleaved address ranges used by the HNFs
- '''
-
- _addr_ranges = []
- @classmethod
- def createAddrRanges(cls, sys_mem_ranges, cache_line_size, num_hnfs):
- # Create the HNFs interleaved addr ranges
- block_size_bits = int(math.log(cache_line_size, 2))
- cls._addr_ranges = []
- llc_bits = int(math.log(num_hnfs, 2))
- numa_bit = block_size_bits + llc_bits - 1
- for i in range(num_hnfs):
- ranges = []
- for r in sys_mem_ranges:
- addr_range = AddrRange(r.start, size = r.size(),
- intlvHighBit = numa_bit,
- intlvBits = llc_bits,
- intlvMatch = i)
- ranges.append(addr_range)
- cls._addr_ranges.append((ranges, numa_bit, i))
-
- @classmethod
- def getAddrRanges(cls, hnf_idx):
- assert(len(cls._addr_ranges) != 0)
- return cls._addr_ranges[hnf_idx]
-
- # The CHI controller can be a child of this object or another if
- # 'parent' if specified
- def __init__(self, hnf_idx, ruby_system, llcache_type, parent):
- super(CHI_HNF, self).__init__(ruby_system)
-
- addr_ranges,intlvHighBit,intlvMatch = CHI_HNF.getAddrRanges(hnf_idx)
- # All ranges should have the same interleaving
- assert(len(addr_ranges) >= 1)
- assert(intlvMatch == hnf_idx)
-
- ll_cache = llcache_type(start_index_bit = intlvHighBit + 1)
- self._cntrl = CHI_HNFController(ruby_system, ll_cache, NULL,
- addr_ranges)
-
- if parent == None:
- self.cntrl = self._cntrl
- else:
- parent.cntrl = self._cntrl
-
- self.connectController(self._cntrl)
-
- def getAllControllers(self):
- return [self._cntrl]
-
- def getNetworkSideControllers(self):
- return [self._cntrl]
-
-
-class CHI_SNF_Base(CHI_Node):
- '''
- Creates CHI node controllers for the memory controllers
- '''
-
- # The CHI controller can be a child of this object or another if
- # 'parent' if specified
- def __init__(self, ruby_system, parent):
- super(CHI_SNF_Base, self).__init__(ruby_system)
-
- self._cntrl = Memory_Controller(
- version = Versions.getVersion(Memory_Controller),
- ruby_system = ruby_system,
- triggerQueue = TriggerMessageBuffer(),
- responseFromMemory = MessageBuffer(),
- requestToMemory = MessageBuffer(ordered = True),
- reqRdy = TriggerMessageBuffer())
-
- self.connectController(self._cntrl)
-
- if parent:
- parent.cntrl = self._cntrl
- else:
- self.cntrl = self._cntrl
-
- def getAllControllers(self):
- return [self._cntrl]
-
- def getNetworkSideControllers(self):
- return [self._cntrl]
-
- def getMemRange(self, mem_ctrl):
- # TODO need some kind of transparent API for
- # MemCtrl+DRAM vs SimpleMemory
- if hasattr(mem_ctrl, 'range'):
- return mem_ctrl.range
- else:
- return mem_ctrl.dram.range
-
-class CHI_SNF_BootMem(CHI_SNF_Base):
- '''
- Create the SNF for the boot memory
- '''
- def __init__(self, ruby_system, parent, bootmem):
- super(CHI_SNF_BootMem, self).__init__(ruby_system, parent)
- self._cntrl.memory_out_port = bootmem.port
- self._cntrl.addr_ranges = self.getMemRange(bootmem)
-
-class CHI_SNF_MainMem(CHI_SNF_Base):
- '''
- Create the SNF for a list main memory controllers
- '''
- def __init__(self, ruby_system, parent, mem_ctrl = None):
- super(CHI_SNF_MainMem, self).__init__(ruby_system, parent)
- if mem_ctrl:
- self._cntrl.memory_out_port = mem_ctrl.port
- self._cntrl.addr_ranges = self.getMemRange(mem_ctrl)
- # else bind ports and range later
-
-class CHI_RNI_Base(CHI_Node):
- '''
- Request node without cache / DMA
- '''
-
- # The CHI controller can be a child of this object or another if
- # 'parent' if specified
- def __init__(self, ruby_system, parent):
- super(CHI_RNI_Base, self).__init__(ruby_system)
-
- self._sequencer = RubySequencer(version = Versions.getSeqId(),
- ruby_system = ruby_system,
- clk_domain = ruby_system.clk_domain)
- self._cntrl = CHI_DMAController(ruby_system, self._sequencer)
-
- if parent:
- parent.cntrl = self._cntrl
- else:
- self.cntrl = self._cntrl
-
- self.connectController(self._cntrl)
-
- def getAllControllers(self):
- return [self._cntrl]
-
- def getNetworkSideControllers(self):
- return [self._cntrl]
-
-class CHI_RNI_DMA(CHI_RNI_Base):
- '''
- DMA controller wiredup to a given dma port
- '''
- def __init__(self, ruby_system, dma_port, parent):
- super(CHI_RNI_DMA, self).__init__(ruby_system, parent)
- assert(dma_port != None)
- self._sequencer.in_ports = dma_port
-
-class CHI_RNI_IO(CHI_RNI_Base):
- '''
- DMA controller wiredup to ruby_system IO port
- '''
- def __init__(self, ruby_system, parent):
- super(CHI_RNI_IO, self).__init__(ruby_system, parent)
- ruby_system._io_port = self._sequencer
-
-def noc_params_from_config(config, noc_params):
- # mesh options
- noc_params.num_rows = config['mesh']['num_rows']
- noc_params.num_cols = config['mesh']['num_cols']
- if 'router_latency' in config['mesh']:
- noc_params.router_latency = config['mesh']['router_latency']
- if 'link_latency' in config['mesh']:
- noc_params.router_link_latency = config['mesh']['link_latency']
- noc_params.node_link_latency = config['mesh']['link_latency']
- if 'router_link_latency' in config['mesh']:
- noc_params.router_link_latency = config['mesh']['router_link_latency']
- if 'node_link_latency' in config['mesh']:
- noc_params.node_link_latency = config['mesh']['node_link_latency']
- if 'cross_links' in config['mesh']:
- noc_params.cross_link_latency = \
- config['mesh']['cross_link_latency']
- noc_params.cross_links = []
- for x, y in config['mesh']['cross_links']:
- noc_params.cross_links.append((x, y))
- noc_params.cross_links.append((y, x))
- else:
- noc_params.cross_links = []
- noc_params.cross_link_latency = 0
-
- # CHI_RNF options
- noc_params.CHI_RNF = config['CHI_RNF']
-
- # CHI_RNI_IO
- noc_params.CHI_RNI_IO = config['CHI_RNI_IO']
-
- # CHI_HNF options
- noc_params.CHI_HNF = config['CHI_HNF']
- if 'pairing' in config['CHI_HNF']:
- noc_params.pairing = config['CHI_HNF']['pairing']
-
- # CHI_SNF_MainMem
- noc_params.CHI_SNF_MainMem = config['CHI_SNF_MainMem']
-
- # CHI_SNF_IO (applies to CHI_SNF_Bootmem)
- noc_params.CHI_SNF_IO = config['CHI_SNF_IO']
-
+def read_config_file(file):
+ ''' Read file as a module and return it '''
+ import types
+ import importlib.machinery
+ loader = importlib.machinery.SourceFileLoader('chi_configs', file)
+ chi_configs = types.ModuleType(loader.name)
+ loader.exec_module(chi_configs)
+ return chi_configs
def create_system(options, full_system, system, dma_ports, bootmem,
ruby_system):
@@ -657,25 +65,25 @@
if options.num_l3caches < 1:
m5.fatal('--num-l3caches must be at least 1')
- # Default parameters for the network
- class NoC_Params(object):
- def __init__(self):
- self.topology = options.topology
- self.network = options.network
- self.router_link_latency = 1
- self.node_link_latency = 1
- self.router_latency = 1
- self.router_buffer_size = 4
- self.cntrl_msg_size = 8
- self.data_width = 32
- params = NoC_Params()
-
- # read additional configurations from yaml file if provided
- if options.noc_config:
- with open(options.noc_config, 'r') as file:
- noc_params_from_config(yaml.load(file), params)
- elif params.topology == 'CustomMesh':
+ # read specialized classes from config file if provided
+ if options.chi_config:
+ chi_defs = read_config_file(options.chi_config)
+ elif options.topology == 'CustomMesh':
m5.fatal('--noc-config must be provided if topology is CustomMesh')
+ else:
+ # Use the defaults from CHI_config
+ from . import CHI_config as chi_defs
+
+ # NoC params
+ params = chi_defs.NoC_Params
+ # Node types
+ CHI_RNF = chi_defs.CHI_RNF
+ CHI_HNF = chi_defs.CHI_HNF
+ CHI_SNF_MainMem = chi_defs.CHI_SNF_MainMem
+ CHI_SNF_BootMem = chi_defs.CHI_SNF_BootMem
+ CHI_RNI_DMA = chi_defs.CHI_RNI_DMA
+ CHI_RNI_IO = chi_defs.CHI_RNI_IO
+
# Declare caches and controller types used by the protocol
# Notice tag and data accesses are not concurrent, so the a cache hit
@@ -824,17 +232,17 @@
ruby_system.network.data_msg_size = params.data_width
ruby_system.network.buffer_size = params.router_buffer_size
- if params.topology == 'CustomMesh':
- topology = create_topology(network_nodes, params)
- elif params.topology in ['Crossbar', 'Pt2Pt']:
- topology = create_topology(network_cntrls, params)
- else:
- m5.fatal("%s not supported!" % params.topology)
-
# Incorporate the params into options so it's propagated to
- # makeTopology by the parent script
+ # makeTopology and create_topology the parent scripts
for k in dir(params):
if not k.startswith('__'):
setattr(options, k, getattr(params, k))
+ if options.topology == 'CustomMesh':
+ topology = create_topology(network_nodes, options)
+ elif options.topology in ['Crossbar', 'Pt2Pt']:
+ topology = create_topology(network_cntrls, options)
+ else:
+ m5.fatal("%s not supported!" % options.topology)
+
return (cpu_sequencers, mem_cntrls, topology)
diff --git a/configs/ruby/CHI_config.py b/configs/ruby/CHI_config.py
new file mode 100644
index 0000000..0ca3c5f
--- /dev/null
+++ b/configs/ruby/CHI_config.py
@@ -0,0 +1,646 @@
+# Copyright (c) 2021 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.
+
+'''
+Definitions for CHI nodes and controller types. These are used by
+create_system in configs/ruby/CHI.py or may be used in custom configuration
+scripts. When used with create_system, the user may provide an additional
+configuration file as the --chi-config parameter to specialize the classes
+defined here.
+
+When using the CustomMesh topology, --chi-config must be provided with
+specialization of the NoC_Param classes defining the NoC dimensions and
+node to router binding. See configs/example/noc_config/2x4.py for an example.
+'''
+
+import math
+import m5
+from m5.objects import *
+
+class Versions:
+ '''
+ Helper class to obtain unique ids for a given controller class.
+ These are passed as the 'version' parameter when creating the controller.
+ '''
+ _seqs = 0
+ @classmethod
+ def getSeqId(cls):
+ val = cls._seqs
+ cls._seqs += 1
+ return val
+
+ _version = {}
+ @classmethod
+ def getVersion(cls, tp):
+ if tp not in cls._version:
+ cls._version[tp] = 0
+ val = cls._version[tp]
+ cls._version[tp] = val + 1
+ return val
+
+
+class NoC_Params:
+ '''
+ Default parameters for the interconnect. The value of data_width is
+ also used to set the data_channel_size for all CHI controllers.
+ (see configs/ruby/CHI.py)
+ '''
+ router_link_latency = 1
+ node_link_latency = 1
+ router_latency = 1
+ router_buffer_size = 4
+ cntrl_msg_size = 8
+ data_width = 32
+ cross_links = []
+ cross_link_latency = 0
+
+class CHI_Node(SubSystem):
+ '''
+ Base class with common functions for setting up Cache or Memory
+ controllers that are part of a CHI RNF, RNFI, HNF, or SNF nodes.
+ Notice getNetworkSideControllers and getAllControllers must be implemented
+ in the derived classes.
+ '''
+
+ class NoC_Params:
+ '''
+ NoC config. parameters and bindings required for CustomMesh topology.
+
+ Maps 'num_nodes_per_router' CHI nodes to each router provided in
+ 'router_list'. This assumes len(router_list)*num_nodes_per_router
+ equals the number of nodes
+ If 'num_nodes_per_router' is left undefined, we circulate around
+ 'router_list' until all nodes are mapped.
+ See 'distributeNodes' in configs/topologies/CustomMesh.py
+ '''
+ num_nodes_per_router = None
+ router_list = None
+
+ def __init__(self, ruby_system):
+ super(CHI_Node, self).__init__()
+ self._ruby_system = ruby_system
+ self._network = ruby_system.network
+
+ def getNetworkSideControllers(self):
+ '''
+ Returns all ruby controllers that need to be connected to the
+ network
+ '''
+ raise NotImplementedError()
+
+ def getAllControllers(self):
+ '''
+ Returns all ruby controllers associated with this node
+ '''
+ raise NotImplementedError()
+
+ def setDownstream(self, cntrls):
+ '''
+ Sets cntrls as the downstream list of all controllers in this node
+ '''
+ for c in self.getNetworkSideControllers():
+ c.downstream_destinations = cntrls
+
+ def connectController(self, cntrl):
+ '''
+ Creates and configures the messages buffers for the CHI input/output
+ ports that connect to the network
+ '''
+ cntrl.reqOut = MessageBuffer()
+ cntrl.rspOut = MessageBuffer()
+ cntrl.snpOut = MessageBuffer()
+ cntrl.datOut = MessageBuffer()
+ cntrl.reqIn = MessageBuffer()
+ cntrl.rspIn = MessageBuffer()
+ cntrl.snpIn = MessageBuffer()
+ cntrl.datIn = MessageBuffer()
+
+ # All CHI ports are always connected to the network.
+ # Controllers that are not part of the getNetworkSideControllers list
+ # still communicate using internal routers, thus we need to wire-up the
+ # ports
+ cntrl.reqOut.out_port = self._network.in_port
+ cntrl.rspOut.out_port = self._network.in_port
+ cntrl.snpOut.out_port = self._network.in_port
+ cntrl.datOut.out_port = self._network.in_port
+ cntrl.reqIn.in_port = self._network.out_port
+ cntrl.rspIn.in_port = self._network.out_port
+ cntrl.snpIn.in_port = self._network.out_port
+ cntrl.datIn.in_port = self._network.out_port
+
+
+class TriggerMessageBuffer(MessageBuffer):
+ '''
+ MessageBuffer for triggering internal controller events.
+ These buffers should not be affected by the Ruby tester randomization
+ and allow poping messages enqueued in the same cycle.
+ '''
+ randomization = 'disabled'
+ allow_zero_latency = True
+
+class OrderedTriggerMessageBuffer(TriggerMessageBuffer):
+ ordered = True
+
+class CHI_Cache_Controller(Cache_Controller):
+ '''
+ Default parameters for a Cache controller
+ The Cache_Controller can also be used as a DMA requester or as
+ a pure directory if all cache allocation policies are disabled.
+ '''
+
+ def __init__(self, ruby_system):
+ super(CHI_Cache_Controller, self).__init__(
+ version = Versions.getVersion(Cache_Controller),
+ ruby_system = ruby_system,
+ mandatoryQueue = MessageBuffer(),
+ prefetchQueue = MessageBuffer(),
+ triggerQueue = TriggerMessageBuffer(),
+ retryTriggerQueue = OrderedTriggerMessageBuffer(),
+ replTriggerQueue = OrderedTriggerMessageBuffer(),
+ reqRdy = TriggerMessageBuffer(),
+ snpRdy = TriggerMessageBuffer())
+ # Set somewhat large number since we really a lot on internal
+ # triggers. To limit the controller performance, tweak other
+ # params such as: input port buffer size, cache banks, and output
+ # port latency
+ self.transitions_per_cycle = 128
+ # This should be set to true in the data cache controller to enable
+ # timeouts on unique lines when a store conditional fails
+ self.sc_lock_enabled = False
+
+class CHI_L1Controller(CHI_Cache_Controller):
+ '''
+ Default parameters for a L1 Cache controller
+ '''
+
+ def __init__(self, ruby_system, sequencer, cache, prefetcher):
+ super(CHI_L1Controller, self).__init__(ruby_system)
+ self.sequencer = sequencer
+ self.cache = cache
+ self.use_prefetcher = False
+ self.send_evictions = True
+ self.is_HN = False
+ self.enable_DMT = False
+ self.enable_DCT = False
+ # Strict inclusive MOESI
+ self.allow_SD = True
+ self.alloc_on_seq_acc = True
+ self.alloc_on_seq_line_write = False
+ self.alloc_on_readshared = True
+ self.alloc_on_readunique = True
+ self.alloc_on_readonce = True
+ self.alloc_on_writeback = True
+ self.dealloc_on_unique = False
+ self.dealloc_on_shared = False
+ self.dealloc_backinv_unique = True
+ self.dealloc_backinv_shared = True
+ # Some reasonable default TBE params
+ self.number_of_TBEs = 16
+ self.number_of_repl_TBEs = 16
+ self.number_of_snoop_TBEs = 4
+ self.unify_repl_TBEs = False
+
+class CHI_L2Controller(CHI_Cache_Controller):
+ '''
+ Default parameters for a L2 Cache controller
+ '''
+
+ def __init__(self, ruby_system, cache, prefetcher):
+ super(CHI_L2Controller, self).__init__(ruby_system)
+ self.sequencer = NULL
+ self.cache = cache
+ self.use_prefetcher = False
+ self.allow_SD = True
+ self.is_HN = False
+ self.enable_DMT = False
+ self.enable_DCT = False
+ self.send_evictions = False
+ # Strict inclusive MOESI
+ self.alloc_on_seq_acc = False
+ self.alloc_on_seq_line_write = False
+ self.alloc_on_readshared = True
+ self.alloc_on_readunique = True
+ self.alloc_on_readonce = True
+ self.alloc_on_writeback = True
+ self.dealloc_on_unique = False
+ self.dealloc_on_shared = False
+ self.dealloc_backinv_unique = True
+ self.dealloc_backinv_shared = True
+ # Some reasonable default TBE params
+ self.number_of_TBEs = 32
+ self.number_of_repl_TBEs = 32
+ self.number_of_snoop_TBEs = 16
+ self.unify_repl_TBEs = False
+
+class CHI_HNFController(CHI_Cache_Controller):
+ '''
+ Default parameters for a coherent home node (HNF) cache controller
+ '''
+
+ def __init__(self, ruby_system, cache, prefetcher, addr_ranges):
+ super(CHI_HNFController, self).__init__(ruby_system)
+ self.sequencer = NULL
+ self.cache = cache
+ self.use_prefetcher = False
+ self.addr_ranges = addr_ranges
+ self.allow_SD = True
+ self.is_HN = True
+ self.enable_DMT = True
+ self.enable_DCT = True
+ self.send_evictions = False
+ # MOESI / Mostly inclusive for shared / Exclusive for unique
+ self.alloc_on_seq_acc = False
+ self.alloc_on_seq_line_write = False
+ self.alloc_on_readshared = True
+ self.alloc_on_readunique = False
+ self.alloc_on_readonce = True
+ self.alloc_on_writeback = True
+ self.dealloc_on_unique = True
+ self.dealloc_on_shared = False
+ self.dealloc_backinv_unique = False
+ self.dealloc_backinv_shared = False
+ # Some reasonable default TBE params
+ self.number_of_TBEs = 32
+ self.number_of_repl_TBEs = 32
+ self.number_of_snoop_TBEs = 1 # should not receive any snoop
+ self.unify_repl_TBEs = False
+
+class CHI_DMAController(CHI_Cache_Controller):
+ '''
+ Default parameters for a DMA controller
+ '''
+
+ def __init__(self, ruby_system, sequencer):
+ super(CHI_DMAController, self).__init__(ruby_system)
+ self.sequencer = sequencer
+ class DummyCache(RubyCache):
+ dataAccessLatency = 0
+ tagAccessLatency = 1
+ size = "128"
+ assoc = 1
+ self.use_prefetcher = False
+ self.cache = DummyCache()
+ self.sequencer.dcache = NULL
+ # All allocations are false
+ # Deallocations are true (don't really matter)
+ self.allow_SD = False
+ self.is_HN = False
+ self.enable_DMT = False
+ self.enable_DCT = False
+ self.alloc_on_seq_acc = False
+ self.alloc_on_seq_line_write = False
+ self.alloc_on_readshared = False
+ self.alloc_on_readunique = False
+ self.alloc_on_readonce = False
+ self.alloc_on_writeback = False
+ self.dealloc_on_unique = False
+ self.dealloc_on_shared = False
+ self.dealloc_backinv_unique = False
+ self.dealloc_backinv_shared = False
+ self.send_evictions = False
+ self.number_of_TBEs = 16
+ self.number_of_repl_TBEs = 1
+ self.number_of_snoop_TBEs = 1 # should not receive any snoop
+ self.unify_repl_TBEs = False
+
+class CPUSequencerWrapper:
+ '''
+ Other generic configuration scripts assume a matching number of sequencers
+ and cpus. This wraps the instruction and data sequencer so they are
+ compatible with the other scripts. This assumes all scripts are using
+ connectCpuPorts/connectIOPorts to bind ports
+ '''
+
+ def __init__(self, iseq, dseq):
+ # use this style due to __setattr__ override below
+ self.__dict__['inst_seq'] = iseq
+ self.__dict__['data_seq'] = dseq
+ self.__dict__['support_data_reqs'] = True
+ self.__dict__['support_inst_reqs'] = True
+ # Compatibility with certain scripts that wire up ports
+ # without connectCpuPorts
+ self.__dict__['slave'] = dseq.in_ports
+ self.__dict__['in_ports'] = dseq.in_ports
+
+ def connectCpuPorts(self, cpu):
+ assert(isinstance(cpu, BaseCPU))
+ cpu.icache_port = self.inst_seq.in_ports
+ for p in cpu._cached_ports:
+ if str(p) != 'icache_port':
+ exec('cpu.%s = self.data_seq.in_ports' % p)
+ cpu.connectUncachedPorts(self.data_seq)
+
+ def connectIOPorts(self, piobus):
+ self.data_seq.connectIOPorts(piobus)
+
+ def __setattr__(self, name, value):
+ setattr(self.inst_seq, name, value)
+ setattr(self.data_seq, name, value)
+
+class CHI_RNF(CHI_Node):
+ '''
+ Defines a CHI request node.
+ Notice all contollers and sequencers are set as children of the cpus, so
+ this object acts more like a proxy for seting things up and has no topology
+ significance unless the cpus are set as its children at the top level
+ '''
+
+ def __init__(self, cpus, ruby_system,
+ l1Icache_type, l1Dcache_type,
+ cache_line_size,
+ l1Iprefetcher_type=None, l1Dprefetcher_type=None):
+ super(CHI_RNF, self).__init__(ruby_system)
+
+ self._block_size_bits = int(math.log(cache_line_size, 2))
+
+ # All sequencers and controllers
+ self._seqs = []
+ self._cntrls = []
+
+ # Last level controllers in this node, i.e., the ones that will send
+ # requests to the home nodes
+ self._ll_cntrls = []
+
+ self._cpus = cpus
+
+ # First creates L1 caches and sequencers
+ for cpu in self._cpus:
+ cpu.inst_sequencer = RubySequencer(version = Versions.getSeqId(),
+ ruby_system = ruby_system)
+ cpu.data_sequencer = RubySequencer(version = Versions.getSeqId(),
+ ruby_system = ruby_system)
+
+ self._seqs.append(CPUSequencerWrapper(cpu.inst_sequencer,
+ cpu.data_sequencer))
+
+ # caches
+ l1i_cache = l1Icache_type(start_index_bit = self._block_size_bits,
+ is_icache = True)
+
+ l1d_cache = l1Dcache_type(start_index_bit = self._block_size_bits,
+ is_icache = False)
+
+ # Placeholders for future prefetcher support
+ if l1Iprefetcher_type != None or l1Dprefetcher_type != None:
+ m5.fatal('Prefetching not supported yet')
+ l1i_pf = NULL
+ l1d_pf = NULL
+
+ # cache controllers
+ cpu.l1i = CHI_L1Controller(ruby_system, cpu.inst_sequencer,
+ l1i_cache, l1i_pf)
+
+ cpu.l1d = CHI_L1Controller(ruby_system, cpu.data_sequencer,
+ l1d_cache, l1d_pf)
+
+ cpu.inst_sequencer.dcache = NULL
+ cpu.data_sequencer.dcache = cpu.l1d.cache
+
+ cpu.l1d.sc_lock_enabled = True
+
+ cpu._ll_cntrls = [cpu.l1i, cpu.l1d]
+ for c in cpu._ll_cntrls:
+ self._cntrls.append(c)
+ self.connectController(c)
+ self._ll_cntrls.append(c)
+
+ def getSequencers(self):
+ return self._seqs
+
+ def getAllControllers(self):
+ return self._cntrls
+
+ def getNetworkSideControllers(self):
+ return self._cntrls
+
+ def setDownstream(self, cntrls):
+ for c in self._ll_cntrls:
+ c.downstream_destinations = cntrls
+
+ def getCpus(self):
+ return self._cpus
+
+ # Adds a private L2 for each cpu
+ def addPrivL2Cache(self, cache_type, pf_type=None):
+ self._ll_cntrls = []
+ for cpu in self._cpus:
+ l2_cache = cache_type(start_index_bit = self._block_size_bits,
+ is_icache = False)
+ if pf_type != None:
+ m5.fatal('Prefetching not supported yet')
+ l2_pf = NULL
+
+ cpu.l2 = CHI_L2Controller(self._ruby_system, l2_cache, l2_pf)
+
+ self._cntrls.append(cpu.l2)
+ self.connectController(cpu.l2)
+
+ self._ll_cntrls.append(cpu.l2)
+
+ for c in cpu._ll_cntrls:
+ c.downstream_destinations = [cpu.l2]
+ cpu._ll_cntrls = [cpu.l2]
+
+
+class CHI_HNF(CHI_Node):
+ '''
+ Encapsulates an HNF cache/directory controller.
+ Before the first controller is created, the class method
+ CHI_HNF.createAddrRanges must be called before creating any CHI_HNF object
+ to set-up the interleaved address ranges used by the HNFs
+ '''
+
+ class NoC_Params(CHI_Node.NoC_Params):
+ '''HNFs may also define the 'pairing' parameter to allow pairing'''
+ pairing = None
+
+ _addr_ranges = []
+ @classmethod
+ def createAddrRanges(cls, sys_mem_ranges, cache_line_size, num_hnfs):
+ # Create the HNFs interleaved addr ranges
+ block_size_bits = int(math.log(cache_line_size, 2))
+ cls._addr_ranges = []
+ llc_bits = int(math.log(num_hnfs, 2))
+ numa_bit = block_size_bits + llc_bits - 1
+ for i in range(num_hnfs):
+ ranges = []
+ for r in sys_mem_ranges:
+ addr_range = AddrRange(r.start, size = r.size(),
+ intlvHighBit = numa_bit,
+ intlvBits = llc_bits,
+ intlvMatch = i)
+ ranges.append(addr_range)
+ cls._addr_ranges.append((ranges, numa_bit, i))
+
+ @classmethod
+ def getAddrRanges(cls, hnf_idx):
+ assert(len(cls._addr_ranges) != 0)
+ return cls._addr_ranges[hnf_idx]
+
+ # The CHI controller can be a child of this object or another if
+ # 'parent' if specified
+ def __init__(self, hnf_idx, ruby_system, llcache_type, parent):
+ super(CHI_HNF, self).__init__(ruby_system)
+
+ addr_ranges,intlvHighBit,intlvMatch = self.getAddrRanges(hnf_idx)
+ # All ranges should have the same interleaving
+ assert(len(addr_ranges) >= 1)
+ assert(intlvMatch == hnf_idx)
+
+ ll_cache = llcache_type(start_index_bit = intlvHighBit + 1)
+ self._cntrl = CHI_HNFController(ruby_system, ll_cache, NULL,
+ addr_ranges)
+
+ if parent == None:
+ self.cntrl = self._cntrl
+ else:
+ parent.cntrl = self._cntrl
+
+ self.connectController(self._cntrl)
+
+ def getAllControllers(self):
+ return [self._cntrl]
+
+ def getNetworkSideControllers(self):
+ return [self._cntrl]
+
+
+class CHI_SNF_Base(CHI_Node):
+ '''
+ Creates CHI node controllers for the memory controllers
+ '''
+
+ # The CHI controller can be a child of this object or another if
+ # 'parent' if specified
+ def __init__(self, ruby_system, parent):
+ super(CHI_SNF_Base, self).__init__(ruby_system)
+
+ self._cntrl = Memory_Controller(
+ version = Versions.getVersion(Memory_Controller),
+ ruby_system = ruby_system,
+ triggerQueue = TriggerMessageBuffer(),
+ responseFromMemory = MessageBuffer(),
+ requestToMemory = MessageBuffer(ordered = True),
+ reqRdy = TriggerMessageBuffer())
+
+ self.connectController(self._cntrl)
+
+ if parent:
+ parent.cntrl = self._cntrl
+ else:
+ self.cntrl = self._cntrl
+
+ def getAllControllers(self):
+ return [self._cntrl]
+
+ def getNetworkSideControllers(self):
+ return [self._cntrl]
+
+ def getMemRange(self, mem_ctrl):
+ # TODO need some kind of transparent API for
+ # MemCtrl+DRAM vs SimpleMemory
+ if hasattr(mem_ctrl, 'range'):
+ return mem_ctrl.range
+ else:
+ return mem_ctrl.dram.range
+
+class CHI_SNF_BootMem(CHI_SNF_Base):
+ '''
+ Create the SNF for the boot memory
+ '''
+
+ def __init__(self, ruby_system, parent, bootmem):
+ super(CHI_SNF_BootMem, self).__init__(ruby_system, parent)
+ self._cntrl.memory_out_port = bootmem.port
+ self._cntrl.addr_ranges = self.getMemRange(bootmem)
+
+class CHI_SNF_MainMem(CHI_SNF_Base):
+ '''
+ Create the SNF for a list main memory controllers
+ '''
+
+ def __init__(self, ruby_system, parent, mem_ctrl = None):
+ super(CHI_SNF_MainMem, self).__init__(ruby_system, parent)
+ if mem_ctrl:
+ self._cntrl.memory_out_port = mem_ctrl.port
+ self._cntrl.addr_ranges = self.getMemRange(mem_ctrl)
+ # else bind ports and range later
+
+class CHI_RNI_Base(CHI_Node):
+ '''
+ Request node without cache / DMA
+ '''
+
+ # The CHI controller can be a child of this object or another if
+ # 'parent' if specified
+ def __init__(self, ruby_system, parent):
+ super(CHI_RNI_Base, self).__init__(ruby_system)
+
+ self._sequencer = RubySequencer(version = Versions.getSeqId(),
+ ruby_system = ruby_system,
+ clk_domain = ruby_system.clk_domain)
+ self._cntrl = CHI_DMAController(ruby_system, self._sequencer)
+
+ if parent:
+ parent.cntrl = self._cntrl
+ else:
+ self.cntrl = self._cntrl
+
+ self.connectController(self._cntrl)
+
+ def getAllControllers(self):
+ return [self._cntrl]
+
+ def getNetworkSideControllers(self):
+ return [self._cntrl]
+
+class CHI_RNI_DMA(CHI_RNI_Base):
+ '''
+ DMA controller wiredup to a given dma port
+ '''
+
+ def __init__(self, ruby_system, dma_port, parent):
+ super(CHI_RNI_DMA, self).__init__(ruby_system, parent)
+ assert(dma_port != None)
+ self._sequencer.in_ports = dma_port
+
+class CHI_RNI_IO(CHI_RNI_Base):
+ '''
+ DMA controller wiredup to ruby_system IO port
+ '''
+
+ def __init__(self, ruby_system, parent):
+ super(CHI_RNI_IO, self).__init__(ruby_system, parent)
+ ruby_system._io_port = self._sequencer
diff --git a/configs/topologies/CustomMesh.py b/configs/topologies/CustomMesh.py
index 73793e4..70bf55d 100644
--- a/configs/topologies/CustomMesh.py
+++ b/configs/topologies/CustomMesh.py
@@ -42,7 +42,7 @@
from m5.defines import buildEnv
if buildEnv['PROTOCOL'] == 'CHI':
- import ruby.CHI as CHI
+ import ruby.CHI_config as CHI
from topologies.BaseTopology import SimpleTopology
@@ -163,8 +163,12 @@
return node_router
- def distributeNodes(self, num_nodes_per_router, router_idx_list,
- node_list):
+ def distributeNodes(self, node_placement_config, node_list):
+ if len(node_list) == 0:
+ return
+
+ num_nodes_per_router = node_placement_config.num_nodes_per_router
+ router_idx_list = node_placement_config.router_list
if num_nodes_per_router:
# evenly distribute nodes to all listed routers
@@ -233,25 +237,45 @@
self._node_link_latency = options.link_latency
# classify nodes into different types
- rnf_list = []
- hnf_list = []
- mem_ctrls = []
- io_mem_ctrls = []
- io_rni_ctrls = []
+ rnf_nodes = []
+ hnf_nodes = []
+ mem_nodes = []
+ io_mem_nodes = []
+ rni_dma_nodes = []
+ rni_io_nodes = []
+
+ # Notice below that all the type must be the same for all nodes with
+ # the same base type.
+ rnf_params = None
+ hnf_params = None
+ mem_params = None
+ io_mem_params = None
+ rni_dma_params = None
+ rni_io_params = None
+
+ def check_same(val, curr):
+ assert(curr == None or curr == val)
+ return val
for n in self.nodes:
if isinstance(n, CHI.CHI_RNF):
- rnf_list.append(n)
+ rnf_nodes.append(n)
+ rnf_params = check_same(type(n).NoC_Params, rnf_params)
elif isinstance(n, CHI.CHI_HNF):
- hnf_list.append(n)
+ hnf_nodes.append(n)
+ hnf_params = check_same(type(n).NoC_Params, hnf_params)
elif isinstance(n, CHI.CHI_SNF_MainMem):
- mem_ctrls.append(n)
+ mem_nodes.append(n)
+ mem_params = check_same(type(n).NoC_Params, mem_params)
elif isinstance(n, CHI.CHI_SNF_BootMem):
- io_mem_ctrls.append(n)
+ io_mem_nodes.append(n)
+ io_mem_params = check_same(type(n).NoC_Params, io_mem_params)
elif isinstance(n, CHI.CHI_RNI_DMA):
- io_rni_ctrls.append(n)
+ rni_dma_nodes.append(n)
+ rni_dma_params = check_same(type(n).NoC_Params, rni_dma_params)
elif isinstance(n, CHI.CHI_RNI_IO):
- io_rni_ctrls.append(n)
+ rni_io_nodes.append(n)
+ rni_io_params = check_same(type(n).NoC_Params, rni_io_params)
else:
fatal('topologies.CustomMesh: {} not supported'
.format(n.__class__.__name__))
@@ -269,39 +293,20 @@
options.cross_links, options.cross_link_latency)
# Place CHI_RNF on the mesh
- num_nodes_per_router = options.CHI_RNF['num_nodes_per_router'] \
- if 'num_nodes_per_router' in options.CHI_RNF else None
- self.distributeNodes(num_nodes_per_router,
- options.CHI_RNF['router_list'],
- rnf_list)
+ self.distributeNodes(rnf_params, rnf_nodes)
# Place CHI_HNF on the mesh
- num_nodes_per_router = options.CHI_HNF['num_nodes_per_router'] \
- if 'num_nodes_per_router' in options.CHI_HNF else None
- self.distributeNodes(num_nodes_per_router,
- options.CHI_HNF['router_list'],
- hnf_list)
+ self.distributeNodes(hnf_params, hnf_nodes)
# Place CHI_SNF_MainMem on the mesh
- num_nodes_per_router = options.CHI_SNF_MainMem['num_nodes_per_router']\
- if 'num_nodes_per_router' in options.CHI_SNF_MainMem else None
- self.distributeNodes(num_nodes_per_router,
- options.CHI_SNF_MainMem['router_list'],
- mem_ctrls)
+ self.distributeNodes(mem_params, mem_nodes)
# Place all IO mem nodes on the mesh
- num_nodes_per_router = options.CHI_SNF_IO['num_nodes_per_router'] \
- if 'num_nodes_per_router' in options.CHI_SNF_IO else None
- self.distributeNodes(num_nodes_per_router,
- options.CHI_SNF_IO['router_list'],
- io_mem_ctrls)
+ self.distributeNodes(io_mem_params, io_mem_nodes)
# Place all IO request nodes on the mesh
- num_nodes_per_router = options.CHI_RNI_IO['num_nodes_per_router'] \
- if 'num_nodes_per_router' in options.CHI_RNI_IO else None
- self.distributeNodes(num_nodes_per_router,
- options.CHI_RNI_IO['router_list'],
- io_rni_ctrls)
+ self.distributeNodes(rni_dma_params, rni_dma_nodes)
+ self.distributeNodes(rni_io_params, rni_io_nodes)
# Set up
network.int_links = self._int_links