# Copyright (c) 2021 Advanced Micro Devices, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # # 2. 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. # # 3. Neither the name of the copyright holder 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 HOLDER 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 m5.defines import buildEnv from m5.objects import * from m5.util import fatal from example.gpufs.DisjointNetwork import * from ruby.GPU_VIPER import * from ruby import Ruby class DummySystem: def __init__(self, mem_ranges): self.mem_ctrls = [] self.mem_ranges = mem_ranges class Disjoint_VIPER(RubySystem): def __init__(self): if buildEnv["PROTOCOL"] != "GPU_VIPER": fatal("This ruby config only supports the GPU_VIPER protocol") super(Disjoint_VIPER, self).__init__() def create(self, options, system, piobus, dma_devices): # Disjoint network topology if "garnet" in options.network: self.network_cpu = DisjointGarnet(self) self.network_gpu = DisjointGarnet(self) else: self.network_cpu = DisjointSimple(self) self.network_gpu = DisjointSimple(self) # Construct CPU controllers cpu_dir_nodes = construct_dirs(options, system, self, self.network_cpu) (cp_sequencers, cp_cntrl_nodes) = construct_corepairs( options, system, self, self.network_cpu ) # Construct GPU controllers (tcp_sequencers, tcp_cntrl_nodes) = construct_tcps( options, system, self, self.network_gpu ) (sqc_sequencers, sqc_cntrl_nodes) = construct_sqcs( options, system, self, self.network_gpu ) (scalar_sequencers, scalar_cntrl_nodes) = construct_scalars( options, system, self, self.network_gpu ) tcc_cntrl_nodes = construct_tccs( options, system, self, self.network_gpu ) # Construct CPU memories Ruby.setup_memory_controllers(system, self, cpu_dir_nodes, options) # Construct GPU memories (gpu_dir_nodes, gpu_mem_ctrls) = construct_gpudirs( options, system, self, self.network_gpu ) # Configure the directories based on which network they are in for cpu_dir_node in cpu_dir_nodes: cpu_dir_node.CPUonly = True cpu_dir_node.GPUonly = False for gpu_dir_node in gpu_dir_nodes: gpu_dir_node.CPUonly = False gpu_dir_node.GPUonly = True # Set access backing store if specified if options.access_backing_store: self.access_backing_store = True # Assign the memory controllers to the system cpu_abstract_mems = [] for mem_ctrl in system.mem_ctrls: cpu_abstract_mems.append(mem_ctrl.dram) system.memories = cpu_abstract_mems gpu_abstract_mems = [] for mem_ctrl in gpu_mem_ctrls: gpu_abstract_mems.append(mem_ctrl.dram) system.pc.south_bridge.gpu.memories = gpu_abstract_mems # Setup DMA controllers gpu_dma_types = ["VegaPagetableWalker", "AMDGPUMemoryManager"] cpu_dma_ctrls = [] gpu_dma_ctrls = [] dma_cntrls = [] for i, dma_device in enumerate(dma_devices): dma_seq = DMASequencer(version=i, ruby_system=self) dma_cntrl = DMA_Controller( version=i, dma_sequencer=dma_seq, ruby_system=self ) # Handle inconsistently named ports on various DMA devices: if not hasattr(dma_device, "type"): # IDE doesn't have a .type but seems like everything else does. dma_seq.in_ports = dma_device elif dma_device.type in gpu_dma_types: dma_seq.in_ports = dma_device.port else: dma_seq.in_ports = dma_device.dma if ( hasattr(dma_device, "type") and dma_device.type in gpu_dma_types ): dma_cntrl.requestToDir = MessageBuffer(buffer_size=0) dma_cntrl.requestToDir.out_port = self.network_gpu.in_port dma_cntrl.responseFromDir = MessageBuffer(buffer_size=0) dma_cntrl.responseFromDir.in_port = self.network_gpu.out_port dma_cntrl.mandatoryQueue = MessageBuffer(buffer_size=0) gpu_dma_ctrls.append(dma_cntrl) else: dma_cntrl.requestToDir = MessageBuffer(buffer_size=0) dma_cntrl.requestToDir.out_port = self.network_cpu.in_port dma_cntrl.responseFromDir = MessageBuffer(buffer_size=0) dma_cntrl.responseFromDir.in_port = self.network_cpu.out_port dma_cntrl.mandatoryQueue = MessageBuffer(buffer_size=0) cpu_dma_ctrls.append(dma_cntrl) dma_cntrls.append(dma_cntrl) system.dma_cntrls = dma_cntrls # Collect CPU and GPU controllers into seperate lists cpu_cntrls = cpu_dir_nodes + cp_cntrl_nodes + cpu_dma_ctrls gpu_cntrls = ( tcp_cntrl_nodes + sqc_cntrl_nodes + scalar_cntrl_nodes + tcc_cntrl_nodes + gpu_dma_ctrls + gpu_dir_nodes ) # Setup number of vnets self.number_of_virtual_networks = 11 self.network_cpu.number_of_virtual_networks = 11 self.network_gpu.number_of_virtual_networks = 11 # Set up the disjoint topology self.network_cpu.connectCPU(options, cpu_cntrls) self.network_gpu.connectGPU(options, gpu_cntrls) # Create port proxy for connecting system port. System port is used # for loading from outside guest, e.g., binaries like vmlinux. system.sys_port_proxy = RubyPortProxy(ruby_system=self) system.sys_port_proxy.pio_request_port = piobus.cpu_side_ports system.system_port = system.sys_port_proxy.in_ports # Only CPU sequencers connect to PIO bus. This acts as the "default" # destination for unknown address ranges. PCIe requests fall under # this category. for i in range(len(cp_sequencers)): cp_sequencers[i].pio_request_port = piobus.cpu_side_ports cp_sequencers[i].mem_request_port = piobus.cpu_side_ports # The CorePairs in MOESI_AMD_Base round up when constructing # sequencers, but if the CPU does not exit there would be no # sequencer to send a range change, leading to assert. if i < options.num_cpus: cp_sequencers[i].pio_response_port = piobus.mem_side_ports # Setup ruby port. Both CPU and GPU are actually connected here. all_sequencers = ( cp_sequencers + tcp_sequencers + sqc_sequencers + scalar_sequencers ) self._cpu_ports = all_sequencers self.num_of_sequencers = len(all_sequencers)