From 7540548abbee3f3394eb4552d644c595ac14b0bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tiago=20M=C3=BCck?= Date: Wed, 17 May 2023 19:02:09 -0500 Subject: [PATCH 1/6] mem-ruby: expose controller count increment Allow the number of controllers of an specific type to incremented externally. This enables a custom implementation of AbstractController to pose as an specific SLICC-generated machine. See subsequent patches for examples. Change-Id: I0b9a3fc82439c18156e377363cebc0385b47f1cd --- src/mem/slicc/symbols/StateMachine.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) 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 { From 8c23b70d571bd37aa0c84a6ab73d6d5c680c3025 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tiago=20M=C3=BCck?= Date: Wed, 5 Oct 2022 18:00:21 -0500 Subject: [PATCH 2/6] mem-ruby: sequencer prints panic pkts Change-Id: I9cd780597c4680513d9cbeb8dda2e13f2a1faf56 --- src/mem/ruby/system/Sequencer.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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()); } } From 473dde3862ed77ca240f3eb4af654bb86cd8bdb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tiago=20M=C3=BCck?= Date: Thu, 1 Jun 2023 18:38:50 -0500 Subject: [PATCH 3/6] mem-ruby: add CHI SnpRespData_SD_Fwded_SC message This snoop reponse is not generated internally by the SLICC implementation, but is required for compatibility with classic caches which may remain in SD state while returning SC data upon receiving a converted SnpShared. Change-Id: I5270b29c8863c7afd8abc39b3c7978b95330c183 --- src/mem/ruby/protocol/chi/CHI-cache-actions.sm | 14 +++++++++++--- src/mem/ruby/protocol/chi/CHI-cache-funcs.sm | 3 +++ src/mem/ruby/protocol/chi/CHI-cache-transitions.sm | 1 + src/mem/ruby/protocol/chi/CHI-cache.sm | 1 + src/mem/ruby/protocol/chi/CHI-msg.sm | 2 ++ 5 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/mem/ruby/protocol/chi/CHI-cache-actions.sm b/src/mem/ruby/protocol/chi/CHI-cache-actions.sm index 3db54934c6b..94e05d81c7c 100644 --- a/src/mem/ruby/protocol/chi/CHI-cache-actions.sm +++ b/src/mem/ruby/protocol/chi/CHI-cache-actions.sm @@ -1884,6 +1884,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 { @@ -1898,6 +1899,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); @@ -2234,7 +2236,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))); @@ -2243,12 +2246,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) || @@ -2437,7 +2444,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 9fda5ba0522..e1589dc93e3 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); } @@ -1412,6 +1413,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 012e5f4ce5d..df1880c2d4d 100644 --- a/src/mem/ruby/protocol/chi/CHI-cache-transitions.sm +++ b/src/mem/ruby/protocol/chi/CHI-cache-transitions.sm @@ -1389,6 +1389,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 6a74045c23b..78782bfedc9 100644 --- a/src/mem/ruby/protocol/chi/CHI-cache.sm +++ b/src/mem/ruby/protocol/chi/CHI-cache.sm @@ -405,6 +405,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 eacd29a4b3b..2a02933566f 100644 --- a/src/mem/ruby/protocol/chi/CHI-msg.sm +++ b/src/mem/ruby/protocol/chi/CHI-msg.sm @@ -202,6 +202,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; @@ -240,6 +241,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); From 886b329bf23761d34861d591606b727ddec0430e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tiago=20M=C3=BCck?= Date: Mon, 5 Jun 2023 18:08:08 -0500 Subject: [PATCH 4/6] mem-ruby: add CHI missing valid SnpRespData type Change-Id: I49c24e8b99932f8ae88511bb7a08a94f59ce7d29 --- src/mem/ruby/protocol/chi/CHI-cache-actions.sm | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mem/ruby/protocol/chi/CHI-cache-actions.sm b/src/mem/ruby/protocol/chi/CHI-cache-actions.sm index 94e05d81c7c..b35895d31e6 100644 --- a/src/mem/ruby/protocol/chi/CHI-cache-actions.sm +++ b/src/mem/ruby/protocol/chi/CHI-cache-actions.sm @@ -1929,6 +1929,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); } From a51b7da73c45772d1912c326c8ecd88744e280be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tiago=20M=C3=BCck?= Date: Wed, 17 May 2023 19:06:15 -0500 Subject: [PATCH 5/6] mem-ruby: Implement a CHI generic controller Component implementing a generic controller that allow classic caches interaction with Ruby/CHI. The CHIGenericController provides an interface to send/receive CHI messages to/from the interconnect. This is implement in C++ rather then SLICC. This controller is seen as a MachineType:Cache by the CHI implementation in SLICC. Change-Id: I3afc4363f4290095c2f7428c8487bccd932e0300 --- .../ruby/protocol/chi/generic/CHIGeneric.py | 55 ++++ .../chi/generic/CHIGenericController.cc | 302 ++++++++++++++++++ .../chi/generic/CHIGenericController.hh | 201 ++++++++++++ src/mem/ruby/protocol/chi/generic/SConscript | 49 +++ 4 files changed, 607 insertions(+) create mode 100644 src/mem/ruby/protocol/chi/generic/CHIGeneric.py create mode 100644 src/mem/ruby/protocol/chi/generic/CHIGenericController.cc create mode 100644 src/mem/ruby/protocol/chi/generic/CHIGenericController.hh create mode 100644 src/mem/ruby/protocol/chi/generic/SConscript 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') From 9c7d1b4d0748b9d68f9d63f826454bdbee21daec Mon Sep 17 00:00:00 2001 From: Giacomo Travaglini Date: Wed, 5 Jul 2023 14:50:18 +0100 Subject: [PATCH 6/6] configs: Instantiate RNFs and MN via callbacks This commit allows top level configs making use of the Ruby module to define node generation callbacks. The config_ruby function will check the system object for two factory methods 1) _rnf_gen, if defined, will be called to generate RNFs 2) _mn_gen, if defined, will be called to generate MNs Change-Id: I9daeece646e7cdb2d3bfefa761a9650562f8eb4b Signed-off-by: Giacomo Travaglini --- configs/ruby/CHI.py | 52 +++++++++----------------------------- configs/ruby/CHI_config.py | 50 +++++++++++++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 41 deletions(-) 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): """