# 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 .caches.mi_example.l1_cache import L1Cache from .caches.mi_example.dma_controller import DMAController from .caches.mi_example.directory import Directory from .topologies.simple_pt2pt import SimplePt2Pt from .abstract_ruby_cache_hierarhcy import AbstractRubyCacheHierarchy from ..abstract_cache_hierarchy import AbstractCacheHierarchy from ...boards.abstract_board import AbstractBoard from ...coherence_protocol import CoherenceProtocol from ...isas import ISA from ...utils.override import overrides from ...runtime import get_runtime_isa from components_library.utils.requires import requires from m5.objects import ( RubySystem, RubySequencer, DMASequencer, RubyPortProxy, ) class MIExampleCacheHierarchy(AbstractRubyCacheHierarchy): """ The MI_Example cache hierarchy creates a Ruby cache for each code in a simple point-to-point topology. """ def __init__( self, size: str, assoc: str, ): """ :param size: The size of each cache in the heirarchy. :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.MI_EXAMPLE) self.ruby_system = RubySystem() # Ruby's global network. self.ruby_system.network = SimplePt2Pt(self.ruby_system) # MI Example users 5 virtual networks. self.ruby_system.number_of_virtual_networks = 5 self.ruby_system.network.number_of_virtual_networks = 5 # There is a single global list of all of the controllers to make it # easier to connect everything to the global network. This can be # customized depending on the topology/network requirements. # Create one controller for each L1 cache (and the cache mem obj.) # Create a single directory controller (Really the memory cntrl). self._controllers = [] for i, core in enumerate(board.get_processor().get_cores()): cache = L1Cache( 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(), ) if board.has_io_bus(): cache.sequencer = RubySequencer( version=i, dcache=cache.cacheMemory, 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) else: core.connect_interrupt() cache.ruby_system = self.ruby_system self._controllers.append(cache) # Create the directory controllers self._directory_controllers = [] for range, port in board.get_memory().get_mem_ports(): dir = Directory( self.ruby_system.network, board.get_cache_line_size(), range, port, ) dir.ruby_system = self.ruby_system self._directory_controllers.append(dir) # Create the DMA Controllers, if required. self._dma_controllers = [] if board.has_dma_ports(): dma_ports = board.get_dma_ports() for i, port in enumerate(dma_ports): ctrl = DMAController( self.ruby_system.network, board.get_cache_line_size() ) ctrl.dma_sequencer = DMASequencer(version=i, in_ports=port) ctrl.ruby_system = self.ruby_system ctrl.dma_sequencer.ruby_system = self.ruby_system self._dma_controllers.append(ctrl) self.ruby_system.num_of_sequencers = len(self._controllers) + len( self._dma_controllers ) # Connect the controllers. self.ruby_system.controllers = self._controllers self.ruby_system.directory_controllers = self._directory_controllers if len(self._dma_controllers) != 0: self.ruby_system.dma_controllers = self._dma_controllers self.ruby_system.network.connectControllers( self._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)