diff --git a/configs/ruby/CHI.py b/configs/ruby/CHI.py index cb8fe646646..236f13dc889 100644 --- a/configs/ruby/CHI.py +++ b/configs/ruby/CHI.py @@ -1,4 +1,4 @@ -# Copyright (c) 2021 ARM Limited +# Copyright (c) 2021, 2024 Arm Limited # All rights reserved. # # The license below extends only to copyright in the software and shall @@ -102,32 +102,6 @@ def create_system( CHI_RNI_DMA = chi_defs.CHI_RNI_DMA CHI_RNI_IO = chi_defs.CHI_RNI_IO - # Declare caches and controller types used by the protocol - # Notice tag and data accesses are not concurrent, so the a cache hit - # latency = tag + data + response latencies. - # Default response latencies are 1 cy for all controllers. - # For L1 controllers the mandatoryQueue enqueue latency is always 1 cy and - # this is deducted from the initial tag read latency for sequencer requests - # dataAccessLatency may be set to 0 if one wants to consider parallel - # data and tag lookups - class L1ICache(RubyCache): - dataAccessLatency = 1 - tagAccessLatency = 1 - size = options.l1i_size - assoc = options.l1i_assoc - - class L1DCache(RubyCache): - dataAccessLatency = 2 - tagAccessLatency = 1 - size = options.l1d_size - assoc = options.l1d_assoc - - class L2Cache(RubyCache): - dataAccessLatency = 6 - tagAccessLatency = 2 - size = options.l2_size - assoc = options.l2_assoc - class HNFCache(RubyCache): dataAccessLatency = 10 tagAccessLatency = 2 @@ -147,25 +121,23 @@ class HNFCache(RubyCache): # Creates on RNF per cpu with priv l2 caches assert len(cpus) == options.num_cpus - ruby_system.rnf = [ - CHI_RNF( - [cpu], - ruby_system, - L1ICache, - L1DCache, - system.cache_line_size.value, - ) - for cpu in cpus - ] + + rnf_cb = getattr(system, "_rnf_gen", CHI_RNF.generate) + + # Generate the Request Nodes + ruby_system.rnf = rnf_cb(options, ruby_system, cpus) + for rnf in ruby_system.rnf: - rnf.addPrivL2Cache(L2Cache) cpu_sequencers.extend(rnf.getSequencers()) all_cntrls.extend(rnf.getAllControllers()) network_nodes.append(rnf) network_cntrls.extend(rnf.getNetworkSideControllers()) - # Creates one Misc Node - ruby_system.mn = [CHI_MN(ruby_system, [cpu.l1d for cpu in cpus])] + mn_cb = getattr(system, "_mn_gen", CHI_MN.generate) + + # Generate the Misc Nodes + ruby_system.mn = mn_cb(options, ruby_system, cpus) + for mn in ruby_system.mn: all_cntrls.extend(mn.getAllControllers()) network_nodes.append(mn) diff --git a/configs/ruby/CHI_config.py b/configs/ruby/CHI_config.py index 80ca38ad5ae..bac9d3c4d84 100644 --- a/configs/ruby/CHI_config.py +++ b/configs/ruby/CHI_config.py @@ -1,4 +1,4 @@ -# Copyright (c) 2021-2023 ARM Limited +# Copyright (c) 2021-2024 Arm Limited # All rights reserved. # # The license below extends only to copyright in the software and shall @@ -51,6 +51,29 @@ from m5.objects import * +# Declare caches and controller types used by the protocol +# Notice tag and data accesses are not concurrent, so the a cache hit +# latency = tag + data + response latencies. +# Default response latencies are 1 cy for all controllers. +# For L1 controllers the mandatoryQueue enqueue latency is always 1 cy and +# this is deducted from the initial tag read latency for sequencer requests +# dataAccessLatency may be set to 0 if one wants to consider parallel +# data and tag lookups +class L1ICache(RubyCache): + dataAccessLatency = 1 + tagAccessLatency = 1 + + +class L1DCache(RubyCache): + dataAccessLatency = 2 + tagAccessLatency = 1 + + +class L2Cache(RubyCache): + dataAccessLatency = 6 + tagAccessLatency = 2 + + class Versions: """ Helper class to obtain unique ids for a given controller class. @@ -575,6 +598,24 @@ def addPrivL2Cache(self, cache_type, pf_type=None): c.downstream_destinations = [cpu.l2] cpu._ll_cntrls = [cpu.l2] + @classmethod + def generate(cls, options, ruby_system, cpus): + rnfs = [ + CHI_RNF( + [cpu], + ruby_system, + L1ICache(size=options.l1i_size, assoc=options.l1i_assoc), + L1DCache(size=options.l1d_size, assoc=options.l1d_assoc), + options.cacheline_size, + ) + for cpu in cpus + ] + for rnf in rnfs: + rnf.addPrivL2Cache( + L2Cache(size=options.l2_size, assoc=options.l2_assoc) + ) + return rnfs + class CHI_HNF(CHI_Node): """ @@ -678,6 +719,13 @@ def getAllControllers(self): def getNetworkSideControllers(self): return [self._cntrl] + @classmethod + def generate(cls, options, ruby_system, cpus): + """ + Creates one Misc Node + """ + return [CHI_MN(ruby_system, [cpu.l1d for cpu in cpus])] + class CHI_SNF_Base(CHI_Node): """ diff --git a/src/mem/ruby/protocol/chi/CHI-cache-actions.sm b/src/mem/ruby/protocol/chi/CHI-cache-actions.sm index 4f7c03bde4c..6a0c7f9d05c 100644 --- a/src/mem/ruby/protocol/chi/CHI-cache-actions.sm +++ b/src/mem/ruby/protocol/chi/CHI-cache-actions.sm @@ -1950,6 +1950,7 @@ action(Send_SnpSharedFwd_ToOwner, desc="") { if (retToSrc) { tbe.expected_snp_resp.addExpectedDataType(CHIDataType:SnpRespData_SC_Fwded_SC); tbe.expected_snp_resp.addExpectedDataType(CHIDataType:SnpRespData_SC_Fwded_SD_PD); + tbe.expected_snp_resp.addExpectedDataType(CHIDataType:SnpRespData_SD_Fwded_SC); tbe.expected_snp_resp.addExpectedDataType(CHIDataType:SnpRespData_I_Fwded_SC); tbe.expected_snp_resp.addExpectedDataType(CHIDataType:SnpRespData_I_Fwded_SD_PD); } else { @@ -1964,6 +1965,7 @@ action(Send_SnpSharedFwd_ToOwner, desc="") { tbe.expected_snp_resp.addExpectedRespType(CHIResponseType:SnpResp_SC_Fwded_SC); } tbe.expected_snp_resp.addExpectedDataType(CHIDataType:SnpRespData_SC_PD_Fwded_SC); + tbe.expected_snp_resp.addExpectedDataType(CHIDataType:SnpRespData_SD_Fwded_SC); tbe.expected_snp_resp.addExpectedDataType(CHIDataType:SnpRespData_I_PD_Fwded_SC); } tbe.expected_snp_resp.addExpectedCount(1); @@ -1994,6 +1996,7 @@ action(Send_SnpSharedFwd_ToSharer, desc="") { bool retToSrc := tbe.doCacheFill; if (retToSrc) { tbe.expected_snp_resp.addExpectedDataType(CHIDataType:SnpRespData_SC_Fwded_SC); + tbe.expected_snp_resp.addExpectedDataType(CHIDataType:SnpRespData_I_Fwded_SC); } else { tbe.expected_snp_resp.addExpectedRespType(CHIResponseType:SnpResp_SC_Fwded_SC); } @@ -2304,7 +2307,8 @@ action(UpdateDirState_FromSnpDataResp, desc="") { (in_msg.type == CHIDataType:SnpRespData_SC) || (in_msg.type == CHIDataType:SnpRespData_SC_Fwded_SC) || (in_msg.type == CHIDataType:SnpRespData_SC_Fwded_SD_PD) || - (in_msg.type == CHIDataType:SnpRespData_SC_PD_Fwded_SC)) { + (in_msg.type == CHIDataType:SnpRespData_SC_PD_Fwded_SC) || + (in_msg.type == CHIDataType:SnpRespData_SD_Fwded_SC)) { // the owner must have been the responder, if there was one assert((tbe.dir_ownerExists == false) || (tbe.dir_ownerExists && (tbe.dir_owner == in_msg.responder))); @@ -2313,12 +2317,16 @@ action(UpdateDirState_FromSnpDataResp, desc="") { tbe.dir_ownerIsExcl := false; if ((in_msg.type == CHIDataType:SnpRespData_SC_Fwded_SC) || (in_msg.type == CHIDataType:SnpRespData_SC_PD_Fwded_SC) || - (in_msg.type == CHIDataType:SnpRespData_SC_Fwded_SD_PD)) { + (in_msg.type == CHIDataType:SnpRespData_SC_Fwded_SD_PD) || + (in_msg.type == CHIDataType:SnpRespData_SD_Fwded_SC)) { tbe.dir_sharers.add(tbe.requestor); } if (in_msg.type == CHIDataType:SnpRespData_SC_Fwded_SD_PD) { tbe.dir_ownerExists := true; tbe.dir_owner := tbe.requestor; + } else if (in_msg.type == CHIDataType:SnpRespData_SD_Fwded_SC) { + tbe.dir_ownerExists := true; + tbe.dir_owner := in_msg.responder; } } else if ((in_msg.type == CHIDataType:SnpRespData_I_Fwded_SD_PD) || @@ -2507,7 +2515,8 @@ action(UpdateDataState_FromSnpDataResp, desc="") { } else if ((in_msg.type == CHIDataType:SnpRespData_SD) || (in_msg.type == CHIDataType:SnpRespData_SC_Fwded_SD_PD) || - (in_msg.type == CHIDataType:SnpRespData_I_Fwded_SD_PD)) { + (in_msg.type == CHIDataType:SnpRespData_I_Fwded_SD_PD) || + (in_msg.type == CHIDataType:SnpRespData_SD_Fwded_SC)) { tbe.dataDirty := true; tbe.dataValid := true; tbe.dataMaybeDirtyUpstream := true; diff --git a/src/mem/ruby/protocol/chi/CHI-cache-funcs.sm b/src/mem/ruby/protocol/chi/CHI-cache-funcs.sm index a717ede4e97..c9edfe3eecc 100644 --- a/src/mem/ruby/protocol/chi/CHI-cache-funcs.sm +++ b/src/mem/ruby/protocol/chi/CHI-cache-funcs.sm @@ -228,6 +228,7 @@ void functionalRead(Addr addr, Packet *pkt, WriteMask &mask) { tbe.expected_snp_resp.receivedDataType(CHIDataType:SnpRespData_UD) || tbe.expected_snp_resp.receivedDataType(CHIDataType:SnpRespData_SC_Fwded_SD_PD) || tbe.expected_snp_resp.receivedDataType(CHIDataType:SnpRespData_SC_PD_Fwded_SC) || + tbe.expected_snp_resp.receivedDataType(CHIDataType:SnpRespData_SD_Fwded_SC) || tbe.expected_snp_resp.receivedDataType(CHIDataType:SnpRespData_I_Fwded_SD_PD) || tbe.expected_snp_resp.receivedDataType(CHIDataType:SnpRespData_I_PD_Fwded_SC); } @@ -1419,6 +1420,8 @@ Event dataToEvent (CHIDataType type) { return Event:SnpRespData_SC_Fwded_SC; } else if (type == CHIDataType:SnpRespData_SC_Fwded_SD_PD) { return Event:SnpRespData_SC_Fwded_SD_PD; + } else if (type == CHIDataType:SnpRespData_SD_Fwded_SC) { + return Event:SnpRespData_SD_Fwded_SC; } else if (type == CHIDataType:SnpRespData_SC_PD_Fwded_SC) { return Event:SnpRespData_SC_PD_Fwded_SC; } else if (type == CHIDataType:SnpRespData_I_Fwded_SD_PD) { diff --git a/src/mem/ruby/protocol/chi/CHI-cache-transitions.sm b/src/mem/ruby/protocol/chi/CHI-cache-transitions.sm index 2e19245d364..89adc928ddd 100644 --- a/src/mem/ruby/protocol/chi/CHI-cache-transitions.sm +++ b/src/mem/ruby/protocol/chi/CHI-cache-transitions.sm @@ -1426,6 +1426,7 @@ transition(BUSY_BLKD, {SnpRespData_I_PD,SnpRespData_I,SnpRespData_SC_PD, SnpRespData_SC,SnpRespData_SD,SnpRespData_UC,SnpRespData_UD, SnpRespData_SC_Fwded_SC,SnpRespData_SC_Fwded_SD_PD, + SnpRespData_SD_Fwded_SC, SnpRespData_SC_PD_Fwded_SC,SnpRespData_I_Fwded_SD_PD, SnpRespData_I_PD_Fwded_SC,SnpRespData_I_Fwded_SC}) { Receive_SnpDataResp; diff --git a/src/mem/ruby/protocol/chi/CHI-cache.sm b/src/mem/ruby/protocol/chi/CHI-cache.sm index dcd142ea472..45043f6bdfb 100644 --- a/src/mem/ruby/protocol/chi/CHI-cache.sm +++ b/src/mem/ruby/protocol/chi/CHI-cache.sm @@ -406,6 +406,7 @@ machine(MachineType:Cache, "Cache coherency protocol") : SnpRespData_UD, desc=""; SnpRespData_SC_Fwded_SC, desc=""; SnpRespData_SC_Fwded_SD_PD, desc=""; + SnpRespData_SD_Fwded_SC, desc=""; SnpRespData_SC_PD_Fwded_SC, desc=""; SnpRespData_I_Fwded_SD_PD, desc=""; SnpRespData_I_PD_Fwded_SC, desc=""; diff --git a/src/mem/ruby/protocol/chi/CHI-msg.sm b/src/mem/ruby/protocol/chi/CHI-msg.sm index 0c2d542d77b..05e1b768c64 100644 --- a/src/mem/ruby/protocol/chi/CHI-msg.sm +++ b/src/mem/ruby/protocol/chi/CHI-msg.sm @@ -205,6 +205,7 @@ enumeration(CHIDataType, desc="...") { SnpRespData_SC_Fwded_SC; SnpRespData_SC_Fwded_SD_PD; SnpRespData_SC_PD_Fwded_SC; + SnpRespData_SD_Fwded_SC; SnpRespData_I_Fwded_SD_PD; SnpRespData_I_PD_Fwded_SC; SnpRespData_I_Fwded_SC; @@ -243,6 +244,7 @@ structure(CHIDataMsg, desc="", interface="Message") { (type == CHIDataType:SnpRespData_SD) || (type == CHIDataType:SnpRespData_UD) || (type == CHIDataType:SnpRespData_SC_Fwded_SD_PD) || + (type == CHIDataType:SnpRespData_SD_Fwded_SC) || (type == CHIDataType:SnpRespData_SC_PD_Fwded_SC) || (type == CHIDataType:SnpRespData_I_Fwded_SD_PD) || (type == CHIDataType:SnpRespData_I_PD_Fwded_SC); diff --git a/src/mem/ruby/protocol/chi/generic/CHIGeneric.py b/src/mem/ruby/protocol/chi/generic/CHIGeneric.py new file mode 100644 index 00000000000..09260dc5a43 --- /dev/null +++ b/src/mem/ruby/protocol/chi/generic/CHIGeneric.py @@ -0,0 +1,55 @@ +# Copyright (c) 2023 ARM Limited +# All rights reserved. +# +# The license below extends only to copyright in the software and shall +# not be construed as granting a license to any other intellectual +# property including but not limited to intellectual property relating +# to a hardware implementation of the functionality of the software +# licensed hereunder. You may use the software subject to the license +# terms below provided that you ensure that this notice is replicated +# unmodified and in its entirety in all distributions of the software, +# modified or unmodified, in source code or in binary form. +# +# 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 m5.objects.Controller import RubyController +from m5.params import * + + +class CHIGenericController(RubyController): + type = "CHIGenericController" + cxx_header = "mem/ruby/protocol/chi/generic/CHIGenericController.hh" + cxx_class = "gem5::ruby::CHIGenericController" + abstract = True + + data_channel_size = Param.Int("") + + reqOut = Param.MessageBuffer("") + snpOut = Param.MessageBuffer("") + rspOut = Param.MessageBuffer("") + datOut = Param.MessageBuffer("") + reqIn = Param.MessageBuffer("") + snpIn = Param.MessageBuffer("") + rspIn = Param.MessageBuffer("") + datIn = Param.MessageBuffer("") diff --git a/src/mem/ruby/protocol/chi/generic/CHIGenericController.cc b/src/mem/ruby/protocol/chi/generic/CHIGenericController.cc new file mode 100644 index 00000000000..86dffed8adc --- /dev/null +++ b/src/mem/ruby/protocol/chi/generic/CHIGenericController.cc @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2023 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * 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. + */ + +#include "mem/ruby/protocol/chi/generic/CHIGenericController.hh" + +#include +#include + +#include +#include +#include +#include + +#include "debug/RubyCHIGeneric.hh" +#include "mem/ruby/network/Network.hh" +#include "mem/ruby/protocol/MemoryMsg.hh" +#include "mem/ruby/system/RubySystem.hh" +#include "mem/ruby/system/Sequencer.hh" + +namespace gem5 +{ + +namespace ruby +{ + +// CHIGenericController appears as a Cache_Controller to the rest of CHI +// TODO should this be configurable ? +int +CHIGenericController::getNumControllers() +{ + return Cache_Controller::getNumControllers(); +} + +void +CHIGenericController::incNumControllers() +{ + Cache_Controller::incNumControllers(); +} + +CHIGenericController::CHIGenericController(const Params &p) + : AbstractController(p), + reqOut(p.reqOut), snpOut(p.snpOut), + rspOut(p.rspOut), datOut(p.datOut), + reqIn(p.reqIn), snpIn(p.snpIn), + rspIn(p.rspIn), datIn(p.datIn), + cacheLineSize(RubySystem::getBlockSizeBytes()), + dataChannelSize(p.data_channel_size), + dataMsgsPerLine(RubySystem::getBlockSizeBytes() / p.data_channel_size) +{ + m_machineID.type = MachineType_Cache; + m_machineID.num = m_version; + incNumControllers(); + p.ruby_system->registerAbstractController(this); +} + +void +CHIGenericController::initNetQueues() +{ + int base = MachineType_base_number(m_machineID.type); + + assert(m_net_ptr != nullptr); + + m_net_ptr->setToNetQueue(m_version + base, reqOut->getOrdered(), + CHI_REQ, "none", reqOut); + m_net_ptr->setToNetQueue(m_version + base, snpOut->getOrdered(), + CHI_SNP, "none", snpOut); + m_net_ptr->setToNetQueue(m_version + base, rspOut->getOrdered(), + CHI_RSP, "none", rspOut); + m_net_ptr->setToNetQueue(m_version + base, datOut->getOrdered(), + CHI_DAT, "response", datOut); + + m_net_ptr->setFromNetQueue(m_version + base, reqIn->getOrdered(), + CHI_REQ, "none", reqIn); + m_net_ptr->setFromNetQueue(m_version + base, snpIn->getOrdered(), + CHI_SNP, "none", snpIn); + m_net_ptr->setFromNetQueue(m_version + base, rspIn->getOrdered(), + CHI_RSP, "none", rspIn); + m_net_ptr->setFromNetQueue(m_version + base, datIn->getOrdered(), + CHI_DAT, "response", datIn); +} + +void +CHIGenericController::init() +{ + AbstractController::init(); + + rspIn->setConsumer(this); + datIn->setConsumer(this); + snpIn->setConsumer(this); + reqIn->setConsumer(this); + + resetStats(); +} + +void +CHIGenericController::addSequencer(RubyPort *seq) +{ + assert(seq != nullptr); + sequencers.emplace_back(seq); +} + +void +CHIGenericController::print(std::ostream& out) const +{ + out << "[CHIGenericController " << m_version << "]"; +} + +Sequencer* +CHIGenericController::getCPUSequencer() const +{ + // CHIGenericController doesn't have a CPUSequencer + return nullptr; +} + +DMASequencer* +CHIGenericController::getDMASequencer() const +{ + // CHIGenericController doesn't have a DMASequencer + return nullptr; +} + +GPUCoalescer* +CHIGenericController::getGPUCoalescer() const +{ + // CHIGenericController doesn't have a GPUCoalescer + return nullptr; +} + +MessageBuffer* +CHIGenericController::getMandatoryQueue() const +{ + // CHIGenericController doesn't have a MandatoryQueue + return nullptr; +} + +MessageBuffer* +CHIGenericController::getMemReqQueue() const +{ + // CHIGenericController doesn't have a MemReqQueue + return nullptr; +} + +MessageBuffer* +CHIGenericController::getMemRespQueue() const +{ + // CHIGenericController doesn't have a MemRespQueue + return nullptr; +} + +void +CHIGenericController::regStats() +{ + AbstractController::regStats(); +} + +void +CHIGenericController::collateStats() +{ + +} + +void +CHIGenericController::resetStats() +{ + AbstractController::resetStats(); +} + + +void +CHIGenericController::wakeup() +{ + bool pending = false; + + DPRINTF(RubyCHIGeneric, "wakeup: checking incoming rsp messages\n"); + pending = pending || receiveAllRdyMessages(rspIn, + [this](const CHIResponseMsg* msg){ return recvResponseMsg(msg); }); + + DPRINTF(RubyCHIGeneric, "wakeup: checking incoming dat messages\n"); + pending = pending || receiveAllRdyMessages(datIn, + [this](const CHIDataMsg* msg){ return recvDataMsg(msg); }); + + DPRINTF(RubyCHIGeneric, "wakeup: checking incoming snp messages\n"); + pending = pending || receiveAllRdyMessages(snpIn, + [this](const CHIRequestMsg* msg){ return recvSnoopMsg(msg); }); + + DPRINTF(RubyCHIGeneric, "wakeup: checking incoming req messages\n"); + pending = pending || receiveAllRdyMessages(reqIn, + [this](const CHIRequestMsg* msg){ return recvRequestMsg(msg); }); + + if (pending) { + DPRINTF(RubyCHIGeneric, "wakeup: messages pending\n"); + scheduleEvent(Cycles(1)); + } +} + +void +CHIGenericController::recordCacheTrace(int cntrl, CacheRecorder* tr) +{ + panic("CHIGenericController doesn't implement recordCacheTrace"); +} + +AccessPermission +CHIGenericController::getAccessPermission(const Addr& param_addr) +{ + return AccessPermission_NotPresent; +} + +void +CHIGenericController::functionalRead( + const Addr& param_addr, Packet* param_pkt, WriteMask& param_mask) +{ + panic("CHIGenericController doesn't expect functionalRead"); +} + +int +CHIGenericController::functionalWrite( + const Addr& param_addr, Packet* param_pkt) +{ + panic("CHIGenericController doesn't expect functionalRead"); + return 0; +} + +int +CHIGenericController::functionalWriteBuffers(PacketPtr& pkt) +{ + int num_functional_writes = 0; + num_functional_writes += reqOut->functionalWrite(pkt); + num_functional_writes += snpOut->functionalWrite(pkt); + num_functional_writes += rspOut->functionalWrite(pkt); + num_functional_writes += datOut->functionalWrite(pkt); + num_functional_writes += reqIn->functionalWrite(pkt); + num_functional_writes += snpIn->functionalWrite(pkt); + num_functional_writes += rspIn->functionalWrite(pkt); + num_functional_writes += datIn->functionalWrite(pkt); + return num_functional_writes; +} + +bool +CHIGenericController::functionalReadBuffers(PacketPtr& pkt) +{ + if (reqOut->functionalRead(pkt)) return true; + if (snpOut->functionalRead(pkt)) return true; + if (rspOut->functionalRead(pkt)) return true; + if (datOut->functionalRead(pkt)) return true; + if (reqIn->functionalRead(pkt)) return true; + if (snpIn->functionalRead(pkt)) return true; + if (rspIn->functionalRead(pkt)) return true; + if (datIn->functionalRead(pkt)) return true; + return false; +} + +bool +CHIGenericController::functionalReadBuffers(PacketPtr& pkt, WriteMask &mask) +{ + bool read = false; + if (reqOut->functionalRead(pkt, mask)) read = true; + if (snpOut->functionalRead(pkt, mask)) read = true; + if (rspOut->functionalRead(pkt, mask)) read = true; + if (datOut->functionalRead(pkt, mask)) read = true; + if (reqIn->functionalRead(pkt, mask)) read = true; + if (snpIn->functionalRead(pkt, mask)) read = true; + if (rspIn->functionalRead(pkt, mask)) read = true; + if (datIn->functionalRead(pkt, mask)) read = true; + return read; +} + +} // namespace ruby +} // namespace gem5 diff --git a/src/mem/ruby/protocol/chi/generic/CHIGenericController.hh b/src/mem/ruby/protocol/chi/generic/CHIGenericController.hh new file mode 100644 index 00000000000..5ddc1fd704e --- /dev/null +++ b/src/mem/ruby/protocol/chi/generic/CHIGenericController.hh @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2023 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * 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. + */ + +#ifndef __MEM_RUBY_PROTOCOL_CHI_CHIGenericController_HH__ +#define __MEM_RUBY_PROTOCOL_CHI_CHIGenericController_HH__ + +#include +#include +#include + +#include "mem/ruby/common/Consumer.hh" +#include "mem/ruby/network/MessageBuffer.hh" +#include "mem/ruby/protocol/AccessPermission.hh" +#include "mem/ruby/slicc_interface/AbstractController.hh" +#include "mem/ruby/system/CacheRecorder.hh" +#include "params/CHIGenericController.hh" + +// Generated from SLICC +#include "mem/ruby/protocol/CHIDataMsg.hh" +#include "mem/ruby/protocol/CHIRequestMsg.hh" +#include "mem/ruby/protocol/CHIResponseMsg.hh" +#include "mem/ruby/protocol/Cache_Controller.hh" + +namespace gem5 +{ + +namespace ruby +{ + +class CHIGenericController : public AbstractController +{ + public: + PARAMS(CHIGenericController); + CHIGenericController(const Params &p); + static int getNumControllers(); + static void incNumControllers(); + + void init() override; + + MessageBuffer *getMandatoryQueue() const override; + MessageBuffer *getMemReqQueue() const override; + MessageBuffer *getMemRespQueue() const override; + void initNetQueues() override; + + void print(std::ostream& out) const override; + void wakeup() override; + void resetStats() override; + void regStats() override; + void collateStats() override; + + void recordCacheTrace(int cntrl, CacheRecorder* tr) override; + Sequencer* getCPUSequencer() const override; + DMASequencer* getDMASequencer() const override; + GPUCoalescer* getGPUCoalescer() const override; + + void addSequencer(RubyPort* seq); + + bool functionalReadBuffers(PacketPtr&) override; + bool functionalReadBuffers(PacketPtr&, WriteMask&) override; + int functionalWriteBuffers(PacketPtr&) override; + + AccessPermission getAccessPermission(const Addr& param_addr) override; + + void functionalRead(const Addr& param_addr, Packet* param_pkt, + WriteMask& param_mask) override; + int functionalWrite(const Addr& param_addr, Packet* param_pkt) override; + + protected: + MessageBuffer* const reqOut; + MessageBuffer* const snpOut; + MessageBuffer* const rspOut; + MessageBuffer* const datOut; + MessageBuffer* const reqIn; + MessageBuffer* const snpIn; + MessageBuffer* const rspIn; + MessageBuffer* const datIn; + + std::vector sequencers; + + public: + const int cacheLineSize; + const int dataChannelSize; + const int dataMsgsPerLine; + + // interface to generic requesters and responders + + enum CHIChannel + { + CHI_REQ = 0, + CHI_SNP = 1, + CHI_RSP = 2, + CHI_DAT = 3 + }; + + typedef std::shared_ptr CHIRequestMsgPtr; + typedef std::shared_ptr CHIResponseMsgPtr; + typedef std::shared_ptr CHIDataMsgPtr; + + bool + sendRequestMsg(CHIRequestMsgPtr msg) + { + return sendMessage(msg, reqOut); + } + + bool + sendSnoopMsg(CHIRequestMsgPtr msg) + { + return sendMessage(msg, snpOut); + } + + bool + sendResponseMsg(CHIResponseMsgPtr msg) + { + return sendMessage(msg, rspOut); + } + + bool + sendDataMsg(CHIDataMsgPtr msg) + { + return sendMessage(msg, datOut); + } + + protected: + virtual bool recvRequestMsg(const CHIRequestMsg *msg) = 0; + virtual bool recvSnoopMsg(const CHIRequestMsg *msg) = 0; + virtual bool recvResponseMsg(const CHIResponseMsg *msg) = 0; + virtual bool recvDataMsg(const CHIDataMsg *msg) = 0; + + private: + template + bool receiveAllRdyMessages(MessageBuffer *buffer, + const std::function &callback) + { + bool pending = false; + Tick cur_tick = curTick(); + while (buffer->isReady(cur_tick)) { + const MsgType *msg = + dynamic_cast(buffer->peek()); + assert(msg); + if (callback(msg)) + buffer->dequeue(cur_tick); + else { + pending = true; + break; + } + } + return pending; + } + + template + bool sendMessage(MessageType &msg, MessageBuffer *buffer) + { + Tick cur_tick = curTick(); + if (buffer->areNSlotsAvailable(1, cur_tick)) { + buffer->enqueue(msg, curTick(), cyclesToTicks(Cycles(1))); + return true; + } else { + return false; + } + } + +}; + +} // namespace ruby +} // namespace gem5 + +#endif // __CHIGenericController_H__ diff --git a/src/mem/ruby/protocol/chi/generic/SConscript b/src/mem/ruby/protocol/chi/generic/SConscript new file mode 100644 index 00000000000..135c988b8ea --- /dev/null +++ b/src/mem/ruby/protocol/chi/generic/SConscript @@ -0,0 +1,49 @@ +# -*- mode:python -*- + +# Copyright (c) 2023 ARM Limited +# All rights reserved. +# +# The license below extends only to copyright in the software and shall +# not be construed as granting a license to any other intellectual +# property including but not limited to intellectual property relating +# to a hardware implementation of the functionality of the software +# licensed hereunder. You may use the software subject to the license +# terms below provided that you ensure that this notice is replicated +# unmodified and in its entirety in all distributions of the software, +# modified or unmodified, in source code or in binary form. +# +# 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. + +Import('*') + +if env['CONF']['PROTOCOL'] != 'CHI': + Return() + +SimObject('CHIGeneric.py', + sim_objects=['CHIGenericController']) + +DebugFlag('RubyCHIGeneric') +DebugFlag('RubyCHIGenericVerbose') + +Source('CHIGenericController.cc') diff --git a/src/mem/ruby/system/Sequencer.cc b/src/mem/ruby/system/Sequencer.cc index 4fef7090b68..0a7c742aa82 100644 --- a/src/mem/ruby/system/Sequencer.cc +++ b/src/mem/ruby/system/Sequencer.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 ARM Limited + * Copyright (c) 2019-2021,2023 ARM Limited * All rights reserved. * * The license below extends only to copyright in the software and shall @@ -1013,7 +1013,8 @@ Sequencer::makeRequest(PacketPtr pkt) m_cache_inv_pkt = pkt; invL1(); } else { - panic("Unsupported ruby packet type\n"); + panic("Cannot convert packet [%s] to ruby request\n", + pkt->print()); } } diff --git a/src/mem/slicc/symbols/StateMachine.py b/src/mem/slicc/symbols/StateMachine.py index b5235225013..038eb2942de 100644 --- a/src/mem/slicc/symbols/StateMachine.py +++ b/src/mem/slicc/symbols/StateMachine.py @@ -353,6 +353,7 @@ class $c_ident : public AbstractController typedef ${c_ident}Params Params; $c_ident(const Params &p); static int getNumControllers(); + static void incNumControllers(); void init(); MessageBuffer *getMandatoryQueue() const; @@ -644,7 +645,7 @@ def printControllerCC(self, path, includes): { m_machineID.type = MachineType_${ident}; m_machineID.num = m_version; - m_num_controllers++; + incNumControllers(); p.ruby_system->registerAbstractController(this); m_in_ports = $num_in_ports; @@ -1131,6 +1132,12 @@ def printControllerCC(self, path, includes): return m_num_controllers; } +void +$c_ident::incNumControllers() +{ + ++m_num_controllers; +} + MessageBuffer* $c_ident::getMandatoryQueue() const {