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:
committed by
Jason Lowe-Power
parent
549431390f
commit
e2b95722af
@@ -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',
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user