blob: cc643e5b7e255ca9f6d40637ff678d1388e5fee1 [file] [log] [blame]
# 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_ruby_cache_hierarhcy import AbstractRubyCacheHierarchy
from ..abstract_two_level_cache_hierarchy import AbstractTwoLevelCacheHierarchy
from ...coherence_protocol import CoherenceProtocol
from ...isas import ISA
from ...boards.abstract_board import AbstractBoard
from ...runtime import get_runtime_coherence_protocol, get_runtime_isa
from .topologies.simple_pt2pt import SimplePt2Pt
from .caches.mesi_two_level.l1_cache import L1Cache
from .caches.mesi_two_level.l2_cache import L2Cache
from .caches.mesi_two_level.directory import Directory
from .caches.mesi_two_level.dma_controller import DMAController
from m5.objects import (
RubySystem,
RubySequencer,
DMASequencer,
RubyPortProxy,
)
class MESITwoLevelCacheHierarchy(
AbstractRubyCacheHierarchy, AbstractTwoLevelCacheHierarchy
):
"""A two level private L1 shared L2 MESI hierarchy.
In addition to the normal two level parameters, you can also change the
number of L2 banks in this protocol.
The on-chip network is a point-to-point all-to-all simple network.
"""
def __init__(
self,
l1i_size: str,
l1i_assoc: str,
l1d_size: str,
l1d_assoc: str,
l2_size: str,
l2_assoc: str,
num_l2_banks: int,
):
AbstractRubyCacheHierarchy.__init__(self=self)
AbstractTwoLevelCacheHierarchy.__init__(
self,
l1i_size=l1i_size,
l1i_assoc=l1i_assoc,
l1d_size=l1d_size,
l1d_assoc=l1d_assoc,
l2_size=l2_size,
l2_assoc=l2_assoc,
)
self._num_l2_banks = num_l2_banks
def incorporate_cache(self, board: AbstractBoard) -> None:
if (
get_runtime_coherence_protocol()
!= CoherenceProtocol.MESI_TWO_LEVEL
):
raise EnvironmentError(
"The MESITwoLevelCacheHierarchy must be used with with the "
"MESI_Two_Level coherence protocol."
)
cache_line_size = board.get_cache_line_size()
self.ruby_system = RubySystem()
# MESI_Two_Level needs 5 virtual networks
self.ruby_system.number_of_virtual_networks = 5
self.ruby_system.network = SimplePt2Pt(self.ruby_system)
self.ruby_system.network.number_of_virtual_networks = 5
self._l1_controllers = []
for i, core in enumerate(board.get_processor().get_cores()):
cache = L1Cache(
self._l1i_size,
self._l1i_assoc,
self._l1d_size,
self._l1d_assoc,
self.ruby_system.network,
core,
self._num_l2_banks,
cache_line_size,
get_runtime_isa(),
board.get_clock_domain(),
)
if board.has_io_bus():
cache.sequencer = RubySequencer(
version=i,
dcache=cache.L1Dcache,
clk_domain=cache.clk_domain,
pio_request_port=board.get_io_bus().cpu_side_ports,
mem_request_port=board.get_io_bus().cpu_side_ports,
pio_response_port=board.get_io_bus().mem_side_ports,
)
else:
cache.sequencer = RubySequencer(
version=i,
dcache=cache.L1Dcache,
clk_domain=cache.clk_domain,
)
cache.ruby_system = self.ruby_system
core.connect_icache(cache.sequencer.in_ports)
core.connect_dcache(cache.sequencer.in_ports)
core.connect_walker_ports(
cache.sequencer.in_ports, cache.sequencer.in_ports
)
# Connect the interrupt ports
if get_runtime_isa() == ISA.X86:
int_req_port = cache.sequencer.interrupt_out_port
int_resp_port = cache.sequencer.in_ports
core.connect_interrupt(int_req_port, int_resp_port)
self._l1_controllers.append(cache)
self._l2_controllers = [
L2Cache(
self._l2_size,
self._l2_assoc,
self.ruby_system.network,
self._num_l2_banks,
cache_line_size,
)
for _ in range(self._num_l2_banks)
]
# TODO: Make this prettier: The problem is not being able to proxy
# the ruby system correctly
for cache in self._l2_controllers:
cache.ruby_system = self.ruby_system
self._directory_controllers = [
Directory(self.ruby_system.network, cache_line_size, range, port)
for range, port in board.get_memory().get_mem_ports()
]
# TODO: Make this prettier: The problem is not being able to proxy
# the ruby system correctly
for dir in self._directory_controllers:
dir.ruby_system = self.ruby_system
dma_ports = board.get_dma_ports()
self._dma_controllers = []
for i, port in enumerate(dma_ports):
ctrl = DMAController(self.ruby_system.network, cache_line_size)
ctrl.dma_sequencer = DMASequencer(version=i, in_ports=port)
self._dma_controllers.append(ctrl)
ctrl.ruby_system = self.ruby_system
self.ruby_system.num_of_sequencers = len(self._l1_controllers) + len(
self._dma_controllers
)
self.ruby_system.l1_controllers = self._l1_controllers
self.ruby_system.l2_controllers = self._l2_controllers
self.ruby_system.directory_controllers = self._directory_controllers
if len(self._dma_controllers) != 0:
self.ruby_system.dma_controllers = self._dma_controllers
# Create the network and connect the controllers.
self.ruby_system.network.connectControllers(
self._l1_controllers
+ self._l2_controllers
+ self._directory_controllers
+ self._dma_controllers
)
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)