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
This commit is contained in:
Tiago Mück
2023-05-17 19:06:15 -05:00
committed by Bobby R. Bruce
parent 488c6fc246
commit 390c2b67e4
4 changed files with 596 additions and 0 deletions

View File

@@ -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("")

View File

@@ -0,0 +1,290 @@
/*
* 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 <sys/types.h>
#include <unistd.h>
#include <cassert>
#include <sstream>
#include <string>
#include <typeinfo>
#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::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(p.ruby_system->getBlockSizeBytes()),
cacheLineBits(floorLog2(cacheLineSize)),
dataChannelSize(p.data_channel_size),
dataMsgsPerLine(cacheLineSize / p.data_channel_size)
{
m_machineID.type = MachineType_Cache;
m_machineID.num = m_version;
p.ruby_system->registerAbstractController(this);
p.ruby_system->m_num_controllers[m_machineID.type]++;
m_ruby_system = p.ruby_system;
}
void
CHIGenericController::initNetQueues()
{
int base = m_ruby_system->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<CHIResponseMsg>(rspIn,
[this](const CHIResponseMsg* msg){ return recvResponseMsg(msg); });
DPRINTF(RubyCHIGeneric, "wakeup: checking incoming dat messages\n");
pending = pending || receiveAllRdyMessages<CHIDataMsg>(datIn,
[this](const CHIDataMsg* msg){ return recvDataMsg(msg); });
DPRINTF(RubyCHIGeneric, "wakeup: checking incoming snp messages\n");
pending = pending || receiveAllRdyMessages<CHIRequestMsg>(snpIn,
[this](const CHIRequestMsg* msg){ return recvSnoopMsg(msg); });
DPRINTF(RubyCHIGeneric, "wakeup: checking incoming req messages\n");
pending = pending || receiveAllRdyMessages<CHIRequestMsg>(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

View File

@@ -0,0 +1,202 @@
/*
* 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 <iostream>
#include <sstream>
#include <string>
#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);
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<RubyPort*> sequencers;
public:
const int cacheLineSize;
const int cacheLineBits;
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<CHIRequestMsg> CHIRequestMsgPtr;
typedef std::shared_ptr<CHIResponseMsg> CHIResponseMsgPtr;
typedef std::shared_ptr<CHIDataMsg> 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<typename MsgType>
bool receiveAllRdyMessages(MessageBuffer *buffer,
const std::function<bool(const MsgType*)> &callback)
{
bool pending = false;
Tick cur_tick = curTick();
while (buffer->isReady(cur_tick)) {
const MsgType *msg =
dynamic_cast<const MsgType*>(buffer->peek());
assert(msg);
if (callback(msg))
buffer->dequeue(cur_tick);
else {
pending = true;
break;
}
}
return pending;
}
template<typename MessageType>
bool sendMessage(MessageType &msg, MessageBuffer *buffer)
{
Tick cur_tick = curTick();
if (buffer->areNSlotsAvailable(1, cur_tick)) {
buffer->enqueue(msg, curTick(), cyclesToTicks(Cycles(1)),
m_ruby_system->getRandomization(),
m_ruby_system->getWarmupEnabled());
return true;
} else {
return false;
}
}
};
} // namespace ruby
} // namespace gem5
#endif // __CHIGenericController_H__

View File

@@ -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')