stdlib,mem-ruby: CHI support in components

This changeset adds CHI support in the components library. Currently,
only a very simple one level protocol is implemented, but hopefully this
design will be able to scale to other more complex hierarchies.

I've tested this with RISC-V with 1 and 4 cores and with x86 with 1
core. Since we don't have an Arm-compatible board, I haven't tested with
ARM. Note that x86 with more than 1 core boots most of the way, but it
hangs during systemd (the kernel comes up completely).

Change-Id: I56953238c6b0ca5ac754b103a1b6ec05a85a0af5
Signed-off-by: Jason Lowe-Power <jason@lowepower.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/52463
Reviewed-by: Tiago Mück <tiago.muck@arm.com>
Reviewed-by: Bobby R. Bruce <bbruce@ucdavis.edu>
Maintainer: Jason Lowe-Power <power.jg@gmail.com>
Maintainer: Bobby R. Bruce <bbruce@ucdavis.edu>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Jason Lowe-Power
2021-10-21 23:24:57 +00:00
committed by Jason Lowe-Power
parent 549431390f
commit e2b95722af
9 changed files with 734 additions and 0 deletions

View File

@@ -50,6 +50,22 @@ PySource('gem5.components.cachehierarchies',
'gem5/components/cachehierarchies/abstract_cache_hierarchy.py')
PySource('gem5.components.cachehierarchies',
'gem5/components/cachehierarchies/abstract_two_level_cache_hierarchy.py')
PySource('gem5.components.cachehierarchies.chi',
'gem5/components/cachehierarchies/chi/__init__.py')
PySource('gem5.components.cachehierarchies.chi',
'gem5/components/cachehierarchies/chi/private_l1_cache_hierarchy.py')
PySource('gem5.components.cachehierarchies.chi.nodes',
'gem5/components/cachehierarchies/chi/nodes/__init__.py')
PySource('gem5.components.cachehierarchies.chi.nodes',
'gem5/components/cachehierarchies/chi/nodes/abstract_node.py')
PySource('gem5.components.cachehierarchies.chi.nodes',
'gem5/components/cachehierarchies/chi/nodes/directory.py')
PySource('gem5.components.cachehierarchies.chi.nodes',
'gem5/components/cachehierarchies/chi/nodes/dma_requestor.py')
PySource('gem5.components.cachehierarchies.chi.nodes',
'gem5/components/cachehierarchies/chi/nodes/private_l1_moesi_cache.py')
PySource('gem5.components.cachehierarchies.chi.nodes',
'gem5/components/cachehierarchies/chi/nodes/memory_controller.py')
PySource('gem5.components.cachehierarchies.classic',
'gem5/components/cachehierarchies/classic/__init__.py')
PySource('gem5.components.cachehierarchies.classic',

View File

@@ -0,0 +1,132 @@
# Copyright (c) 2021 The Regents of the University of California
# All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from abc import abstractmethod
from gem5.isas import ISA
from gem5.components.processors.cpu_types import CPUTypes
from gem5.components.processors.abstract_core import AbstractCore
from m5.objects import Cache_Controller, MessageBuffer, RubyNetwork
import math
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 AbstractNode(Cache_Controller):
"""A node is the abstract unit for caches in the CHI protocol.
You can extend the AbstractNode to create caches (private or shared) and
directories with or without data caches.
"""
_version = 0
@classmethod
def versionCount(cls):
cls._version += 1 # Use count for this particular type
return cls._version - 1
# TODO: I don't love that we have to pass in the cache line size.
# However, we need some way to set the index bits
def __init__(self, network: RubyNetwork, cache_line_size: int):
super(AbstractNode, self).__init__()
# Note: Need to call versionCount method on *this* class, not the
# potentially derived class
self.version = AbstractNode.versionCount()
self._cache_line_size = cache_line_size
# 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
# Use 32-byte channels (two flits per message)
self.data_channel_size = 32
self.connectQueues(network)
def getBlockSizeBits(self):
bits = int(math.log(self._cache_line_size, 2))
if 2 ** bits != self._cache_line_size.value:
raise Exception("Cache line size not a power of 2!")
return bits
def sendEvicts(self, core: AbstractCore, target_isa: ISA):
"""True if the CPU model or ISA requires sending evictions from caches
to the CPU. Scenarios warrant forwarding evictions to the CPU:
1. The O3 model must keep the LSQ coherent with the caches
2. The x86 mwait instruction is built on top of coherence
3. The local exclusive monitor in ARM systems
"""
if core.get_type() is CPUTypes.O3 or target_isa in (ISA.X86, ISA.ARM):
return True
return False
def connectQueues(self, network: RubyNetwork):
"""Connect all of the queues for this controller.
This may be extended in subclasses.
"""
self.mandatoryQueue = MessageBuffer()
self.prefetchQueue = MessageBuffer()
self.triggerQueue = TriggerMessageBuffer()
self.retryTriggerQueue = OrderedTriggerMessageBuffer()
self.replTriggerQueue = OrderedTriggerMessageBuffer()
self.reqRdy = TriggerMessageBuffer()
self.snpRdy = TriggerMessageBuffer()
self.reqOut = MessageBuffer()
self.rspOut = MessageBuffer()
self.snpOut = MessageBuffer()
self.datOut = MessageBuffer()
self.reqIn = MessageBuffer()
self.rspIn = MessageBuffer()
self.snpIn = MessageBuffer()
self.datIn = MessageBuffer()
self.reqOut.out_port = network.in_port
self.rspOut.out_port = network.in_port
self.snpOut.out_port = network.in_port
self.datOut.out_port = network.in_port
self.reqIn.in_port = network.out_port
self.rspIn.in_port = network.out_port
self.snpIn.in_port = network.out_port
self.datIn.in_port = network.out_port

View File

@@ -0,0 +1,90 @@
# Copyright (c) 2021 The Regents of the University of California
# All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from .abstract_node import AbstractNode
from m5.objects import (
ClockDomain,
NULL,
RubyCache,
RubyNetwork,
)
class SimpleDirectory(AbstractNode):
"""A directory or home node (HNF)
This simple directory has no cache. It forwards all requests as directly
as possible.
"""
def __init__(
self,
network: RubyNetwork,
cache_line_size: int,
clk_domain: ClockDomain,
):
super().__init__(network, cache_line_size)
# Dummy cache
self.cache = RubyCache(
dataAccessLatency = 0,
tagAccessLatency = 1,
size = "128",
assoc = 1
)
self.clk_domain = clk_domain
# Only used for L1 controllers
self.send_evictions = False
self.sequencer = NULL
self.use_prefetcher = False
# Set up home node that allows three hop protocols
self.is_HN = True
self.enable_DMT = True
self.enable_DCT = True
# "Owned state"
self.allow_SD = True
# No cache
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
# Some reasonable default TBE params
self.number_of_TBEs = 32
self.number_of_repl_TBEs = 32
self.number_of_snoop_TBEs = 1
self.unify_repl_TBEs = False

View File

@@ -0,0 +1,80 @@
# Copyright (c) 2021 The Regents of the University of California
# All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from gem5.components.processors.abstract_core import AbstractCore
from gem5.isas import ISA
from .abstract_node import AbstractNode
from m5.objects import (
ClockDomain,
RubyCache,
)
class DMARequestor(AbstractNode):
def __init__(
self,
network,
cache_line_size,
clk_domain: ClockDomain,
):
super().__init__(network, cache_line_size)
# Dummy cache
self.cache = RubyCache(
dataAccessLatency = 0,
tagAccessLatency = 1,
size = "128",
assoc = 1
)
self.clk_domain = clk_domain
# Only applies to home nodes
self.is_HN = False
self.enable_DMT = False
self.enable_DCT = False
# No cache
self.allow_SD = 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 = True
self.dealloc_backinv_shared = True
self.send_evictions = False
self.use_prefetcher = False
# Some reasonable default TBE params
self.number_of_TBEs = 16
self.number_of_repl_TBEs = 1
self.number_of_snoop_TBEs = 1 # Should never receive snoops
self.unify_repl_TBEs = False

View File

@@ -0,0 +1,86 @@
# Copyright (c) 2021 The Regents of the University of California
# All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from typing import List
from m5.objects import (
AddrRange,
Memory_Controller,
MessageBuffer,
Port,
RubyNetwork,
)
from .abstract_node import TriggerMessageBuffer
class MemoryController(Memory_Controller):
"""A controller that connects to memory
"""
_version = 0
@classmethod
def versionCount(cls):
cls._version += 1 # Use count for this particular type
return cls._version - 1
def __init__(
self,
network: RubyNetwork,
ranges: List[AddrRange],
port: Port
):
super().__init__()
self.version = self.versionCount()
self.addr_ranges = ranges
self.memory_out_port = port
self.data_channel_size = 32
self.connectQueues(network)
def connectQueues(self, network):
self.triggerQueue = TriggerMessageBuffer()
self.responseFromMemory = MessageBuffer()
self.requestToMemory = MessageBuffer(ordered = True)
self.reqRdy = TriggerMessageBuffer()
self.reqOut = MessageBuffer()
self.rspOut = MessageBuffer()
self.snpOut = MessageBuffer()
self.datOut = MessageBuffer()
self.reqIn = MessageBuffer()
self.rspIn = MessageBuffer()
self.snpIn = MessageBuffer()
self.datIn = MessageBuffer()
self.reqOut.out_port = network.in_port
self.rspOut.out_port = network.in_port
self.snpOut.out_port = network.in_port
self.datOut.out_port = network.in_port
self.reqIn.in_port = network.out_port
self.rspIn.in_port = network.out_port
self.snpIn.in_port = network.out_port
self.datIn.in_port = network.out_port

View File

@@ -0,0 +1,81 @@
# Copyright (c) 2021 The Regents of the University of California
# All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from gem5.components.processors.abstract_core import AbstractCore
from gem5.isas import ISA
from .abstract_node import AbstractNode
from m5.objects import (
ClockDomain,
RubyCache,
RubyNetwork,
)
class PrivateL1MOESICache(AbstractNode):
def __init__(
self,
size: str,
assoc: int,
network: RubyNetwork,
core: AbstractCore,
cache_line_size,
target_isa: ISA,
clk_domain: ClockDomain,
):
super().__init__(network, cache_line_size)
self.cache = RubyCache(
size=size, assoc=assoc, start_index_bit=self.getBlockSizeBits()
)
self.clk_domain = clk_domain
self.send_evictions = self.sendEvicts(core=core, target_isa=target_isa)
self.use_prefetcher = False
# Only applies to home nodes
self.is_HN = False
self.enable_DMT = False
self.enable_DCT = False
# MOESI states for a 1 level cache
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 = False # Should never happen in an L1
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

View File

@@ -0,0 +1,249 @@
# Copyright (c) 2021 The Regents of the University of California
# All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from itertools import chain
from typing import List
from m5.objects.SubSystem import SubSystem
from gem5.components.cachehierarchies.ruby.abstract_ruby_cache_hierarchy \
import AbstractRubyCacheHierarchy
from gem5.components.cachehierarchies.abstract_cache_hierarchy import (
AbstractCacheHierarchy,
)
from gem5.coherence_protocol import CoherenceProtocol
from gem5.isas import ISA
from gem5.runtime import get_runtime_isa
from gem5.utils.requires import requires
from gem5.utils.override import overrides
from gem5.components.boards.abstract_board import AbstractBoard
from gem5.components.processors.abstract_core import AbstractCore
from gem5.components.cachehierarchies.ruby.topologies.simple_pt2pt import (
SimplePt2Pt,
)
from .nodes.private_l1_moesi_cache import PrivateL1MOESICache
from .nodes.dma_requestor import DMARequestor
from .nodes.directory import SimpleDirectory
from .nodes.memory_controller import MemoryController
from m5.objects import (
NULL,
RubySystem,
RubySequencer,
RubyPortProxy,
)
class PrivateL1CacheHierarchy(AbstractRubyCacheHierarchy):
"""A single level cache based on CHI for RISC-V
This hierarchy has a split I/D L1 caches per CPU, a single directory (HNF),
and as many memory controllers (SNF) as memory channels. The directory does
not have an associated cache.
The network is a simple point-to-point between all of the controllers.
"""
def __init__(self, size: str, assoc: int) -> None:
"""
:param size: The size of the priavte I/D caches in the hierarchy.
:param assoc: The associativity of each cache.
"""
super().__init__()
self._size = size
self._assoc = assoc
@overrides(AbstractCacheHierarchy)
def incorporate_cache(self, board: AbstractBoard) -> None:
requires(coherence_protocol_required=CoherenceProtocol.CHI)
self.ruby_system = RubySystem()
# Ruby's global network.
self.ruby_system.network = SimplePt2Pt(self.ruby_system)
# Network configurations
# virtual networks: 0=request, 1=snoop, 2=response, 3=data
self.ruby_system.number_of_virtual_networks = 4
self.ruby_system.network.number_of_virtual_networks = 4
# Create a single centralized directory
self.directory = SimpleDirectory(
self.ruby_system.network,
cache_line_size=board.get_cache_line_size(),
clk_domain=board.get_clock_domain(),
)
self.directory.ruby_system = self.ruby_system
# Create one core cluster with a split I/D cache for each core
self.core_clusters = [
self._create_core_cluster(core, i, board)
for i, core in enumerate(board.get_processor().get_cores())
]
# Create the coherent side of the memory controllers
self.memory_controllers = self._create_memory_controllers(board)
self.directory.downstream_destinations = self.memory_controllers
# Create the DMA Controllers, if required.
if board.has_dma_ports():
self.dma_controllers = self._create_dma_controllers(board)
self.ruby_system.num_of_sequencers = len(self.core_clusters) * 2 \
+ len(self.dma_controllers)
else:
self.ruby_system.num_of_sequencers = len(self.core_clusters) * 2
self.ruby_system.network.connectControllers(
list(
chain.from_iterable( # Grab the controllers from each cluster
[
(cluster.dcache, cluster.icache)
for cluster in self.core_clusters
]
)
)
+ self.memory_controllers
+ [self.directory]
+ (self.dma_controllers if board.has_dma_ports() else [])
)
self.ruby_system.network.setup_buffers()
# Set up a proxy port for the system_port. Used for load binaries and
# other functional-only things.
self.ruby_system.sys_port_proxy = RubyPortProxy()
board.connect_system_port(self.ruby_system.sys_port_proxy.in_ports)
def _create_core_cluster(self,
core: AbstractCore,
core_num: int,
board: AbstractBoard
) -> SubSystem:
"""Given the core and the core number this function creates a cluster
for the core with a split I/D cache
"""
cluster = SubSystem()
cluster.dcache = PrivateL1MOESICache(
size=self._size,
assoc=self._assoc,
network=self.ruby_system.network,
core=core,
cache_line_size=board.get_cache_line_size(),
target_isa=get_runtime_isa(),
clk_domain=board.get_clock_domain(),
)
cluster.icache = PrivateL1MOESICache(
size=self._size,
assoc=self._assoc,
network=self.ruby_system.network,
core=core,
cache_line_size=board.get_cache_line_size(),
target_isa=get_runtime_isa(),
clk_domain=board.get_clock_domain(),
)
cluster.icache.sequencer = RubySequencer(
version=core_num,
dcache=NULL,
clk_domain=cluster.icache.clk_domain,
)
cluster.dcache.sequencer = RubySequencer(
version=core_num,
dcache=cluster.dcache.cache,
clk_domain=cluster.dcache.clk_domain,
)
if board.has_io_bus():
cluster.dcache.sequencer.connectIOPorts(board.get_io_bus())
cluster.dcache.ruby_system = self.ruby_system
cluster.icache.ruby_system = self.ruby_system
core.connect_icache(cluster.icache.sequencer.in_ports)
core.connect_dcache(cluster.dcache.sequencer.in_ports)
core.connect_walker_ports(
cluster.dcache.sequencer.in_ports,
cluster.icache.sequencer.in_ports,
)
# Connect the interrupt ports
if get_runtime_isa() == ISA.X86:
int_req_port = cluster.dcache.sequencer.interrupt_out_port
int_resp_port = cluster.dcache.sequencer.in_ports
core.connect_interrupt(int_req_port, int_resp_port)
else:
core.connect_interrupt()
cluster.dcache.downstream_destinations = [self.directory]
cluster.icache.downstream_destinations = [self.directory]
return cluster
def _create_memory_controllers(
self,
board: AbstractBoard
) -> List[MemoryController]:
memory_controllers = []
for rng, port in board.get_memory().get_mem_ports():
mc = MemoryController(
self.ruby_system.network,
rng,
port,
)
mc.ruby_system = self.ruby_system
memory_controllers.append(mc)
return memory_controllers
def _create_dma_controllers(
self,
board: AbstractBoard
) -> List[DMARequestor]:
dma_controllers = []
for i, port in enumerate(board.get_dma_ports()):
ctrl = DMARequestor(
self.ruby_system.network,
board.get_cache_line_size(),
board.get_clock_domain(),
)
version = len(board.get_processor().get_cores()) + i
ctrl.sequencer = RubySequencer(
version=version,
in_ports=port
)
ctrl.sequencer.dcache = NULL
ctrl.ruby_system = self.ruby_system
ctrl.sequencer.ruby_system = self.ruby_system
ctrl.downstream_destinations = [self.directory]
dma_controllers.append(ctrl)
return dma_controllers