mem-ruby: Add a CHI-TLM CacheController

This commit is extending the previously defined CHIGenericController
to implement a CacheController which acts as a bridge between the
AMBA TLM 2.0 implementation of CHI [1][2] with the gem5 (ruby) one.

In other words it translates AMBA CHI transactions into ruby
messages (which are then forwarded to the MessageQueues)
and viceversa.

ARM::CHI::Payload,         CHIRequestMsg
                     <-->  CHIDataMsg
ARM::CHI::Phase            CHIResponseMsg
                           CHIDataMsg

[1]: https://developer.arm.com/documentation/101459/latest
[2]: https://developer.arm.com/Architectures/AMBA#Downloads

Change-Id: I6f35e7b4ade4d0de1b5e5d2dbf73ce796a9f9fb6
Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
This commit is contained in:
Giacomo Travaglini
2024-08-06 10:32:03 +01:00
committed by Bobby R. Bruce
parent 76541929c9
commit b795d28ee8
7 changed files with 1357 additions and 0 deletions

View File

@@ -0,0 +1,75 @@
# -*- mode:python -*-
# Copyright (c) 2024 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("*")
def get_tlm_paths():
tlm_dir = Dir(env["CONF"]["TLM_PATH"])
assert tlm_dir is not None and tlm_dir != "."
include_dir = tlm_dir.Dir("include")
lib_dir = tlm_dir.Dir("lib")
model_lib = "libarmtlmchi.so"
if not lib_dir.File(model_lib).exists():
print(f"Error: Can't find {model_lib} in AMBA TLM directory.")
print(f"TLM path: {tlm_dir}")
Exit(1)
return include_dir, lib_dir, "armtlmchi"
if env["CONF"]["BUILD_TLM"]:
include_path, lib_path, tlm_lib = get_tlm_paths()
env.Append(CPPPATH=include_path)
env.Append(LIBPATH=lib_path)
env.Append(LIBS=[tlm_lib])
SimObject(
"TlmController.py", sim_objects=["TlmController"], tags="arm isa"
)
Source("utils.cc", tags="arm isa")
Source("controller.cc", tags="arm isa")
DebugFlag("TLM", tags="arm isa")
print(
"BUILD_TLM set: "
f"Building TLM integration with libarmtlmchi.so from '{lib_path}'\n"
)
elif not GetOption("silent"):
print("BUILD_TLM not set, not building CHI-TLM integration\n")

View File

@@ -0,0 +1,58 @@
# -*- 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('*')
import os
tlm_vars = Variables()
tlm_vars.AddVariables(
PathVariable('TLM_PATH', "CHI TLM library path", '.', PathVariable.PathIsDir),
)
tlm_vars.Update(main)
main["CONF"]["BUILD_TLM"] = False
tlm_path_ev = os.environ.get("TLM_PATH", None)
if tlm_path_ev is not None and tlm_path_ev != ".":
print(f"Setting TLM_PATH from os.environ: {tlm_path_ev}")
main["CONF"]["TLM_PATH"] = tlm_path_ev
main["CONF"]["BUILD_TLM"] = True
if "TLM_PATH" in main and main["TLM_PATH"] != ".":
print(f"Setting TLM_PATH to SCons command line: {main['TLM_PATH']}")
main["CONF"]["TLM_PATH"] = str(main["TLM_PATH"])
main["CONF"]["BUILD_TLM"] = True

View File

@@ -0,0 +1,43 @@
# 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.CHIGeneric import CHIGenericController
from m5.params import *
class TlmController(CHIGenericController):
type = "TlmController"
cxx_header = "mem/ruby/protocol/chi/tlm/controller.hh"
cxx_class = "gem5::tlm::chi::CacheController"

View File

@@ -0,0 +1,424 @@
/*
* 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/tlm/controller.hh"
#include "debug/TLM.hh"
#include "mem/ruby/protocol/CHIDataMsg.hh"
#include "mem/ruby/protocol/CHIRequestMsg.hh"
#include "mem/ruby/protocol/CHIResponseMsg.hh"
#include "mem/ruby/protocol/chi/tlm/utils.hh"
namespace gem5 {
namespace tlm::chi {
using namespace ruby;
CacheController::CacheController(const Params &p)
: CHIGenericController(p)
{
}
bool
CacheController::recvRequestMsg(const CHIRequestMsg *msg)
{
panic("recvRequestMsg");
return true;
}
bool
CacheController::recvSnoopMsg(const CHIRequestMsg *msg)
{
ARM::CHI::Phase phase;
ARM::CHI::Payload *payload = ARM::CHI::Payload::new_payload();
payload->address = msg->m_addr;
payload->ns = msg->m_ns;
phase.channel = ARM::CHI::CHANNEL_SNP;
phase.snp_opcode = ruby_to_tlm::snpOpcode(msg->m_type);
phase.txn_id = msg->m_txnId % 1024;
bw(payload, &phase);
// payload->unref(); ??
return true;
}
void
CacheController::pCreditGrant(const CHIResponseMsg *msg)
{
ARM::CHI::Phase phase;
ARM::CHI::Payload *payload = ARM::CHI::Payload::new_payload();
phase.channel = ARM::CHI::CHANNEL_RSP;
phase.rsp_opcode = ARM::CHI::RSP_OPCODE_PCRD_GRANT;
phase.pcrd_type = 0; // TODO: set this one depending on allow retry
bw(payload, &phase);
payload->unref(); // TODO: check this
}
bool
CacheController::recvResponseMsg(const CHIResponseMsg *msg)
{
if (msg->m_type == ruby::CHIResponseType_PCrdGrant) {
// P-credit grant does not refer to a specific transaction id
pCreditGrant(msg);
return true;
}
auto txn_id = msg->m_txnId;
if (auto it = pendingTransactions.find(txn_id);
it != pendingTransactions.end()) {
auto& transaction = it->second;
if (transaction->handle(msg))
pendingTransactions.erase(it);
} else {
panic("recvResponseMsg");
}
return true;
}
bool
CacheController::recvDataMsg(const CHIDataMsg *msg)
{
auto txn_id = msg->m_txnId;
if (auto it = pendingTransactions.find(txn_id);
it != pendingTransactions.end()) {
auto& transaction = it->second;
if (transaction->handle(msg))
pendingTransactions.erase(it);
} else {
panic("Not able to find transaction");
}
return true;
}
bool
CacheController::Transaction::handle(const CHIResponseMsg *msg)
{
const auto opcode = ruby_to_tlm::rspOpcode(msg->m_type);
phase.channel = ARM::CHI::CHANNEL_RSP;
phase.rsp_opcode = opcode;
phase.resp = ruby_to_tlm::rspResp(msg->m_type);
phase.txn_id = msg->m_txnId % 1024;
controller->bw(payload, &phase);
return opcode != ARM::CHI::RSP_OPCODE_RETRY_ACK;
}
bool
CacheController::ReadTransaction::handle(const CHIDataMsg *msg)
{
dataMsgCnt++;
for (auto byte = 0; byte < controller->cacheLineSize; byte++) {
if (msg->m_bitMask.test(byte))
payload->data[byte] = msg->m_dataBlk.getByte(byte);
}
// ARM::CHI::Phase phase;
phase.channel = ARM::CHI::CHANNEL_DAT;
phase.dat_opcode = ruby_to_tlm::datOpcode(msg->m_type);
phase.resp = ruby_to_tlm::datResp(msg->m_type);
phase.txn_id = msg->m_txnId % 1024;
phase.data_id = dataId(msg->m_addr + msg->m_bitMask.firstBitSet(true));
// This is a hack, we should fix it on the ruby side
if (forward(msg)) {
controller->bw(payload, &phase);
}
if (dataMsgCnt == controller->dataMsgsPerLine) {
if (phase.exp_comp_ack == false) {
// The client is not sending a CompAck but ruby is
// expecting it so we send it anyway
controller->sendCompAck(*payload, phase);
}
return true;
} else {
return false;
}
}
bool
CacheController::ReadTransaction::handle(const CHIResponseMsg *msg)
{
/// TODO: remove this, DBID is not sent
phase.dbid = msg->m_dbid % 1024;
return Transaction::handle(msg);
}
bool
CacheController::ReadTransaction::forward(const CHIDataMsg *msg)
{
if (payload->size == 6) {
return true;
} else {
if (msg->m_bitMask.test(payload->address - msg->m_addr)) {
return true;
} else {
// This is not the packet holding the original address
// Do not forward it back (just drop it)
return false;
}
}
}
bool
CacheController::DatalessTransaction::handle(const CHIResponseMsg *msg)
{
const auto opcode = ruby_to_tlm::rspOpcode(msg->m_type);
assert(opcode == ARM::CHI::RSP_OPCODE_COMP ||
opcode == ARM::CHI::RSP_OPCODE_RETRY_ACK);
return Transaction::handle(msg);
}
bool
CacheController::WriteTransaction::handle(const CHIResponseMsg *msg)
{
const auto opcode = ruby_to_tlm::rspOpcode(msg->m_type);
if (opcode == ARM::CHI::RSP_OPCODE_COMP_DBID_RESP) {
recvComp = true;
recvDBID = true;
}
if (opcode == ARM::CHI::RSP_OPCODE_COMP) {
recvComp = true;
}
if (opcode == ARM::CHI::RSP_OPCODE_DBID_RESP) {
recvDBID = true;
}
phase.dbid = msg->m_dbid % 1024;
Transaction::handle(msg);
return recvComp && recvDBID;
}
void
CacheController::sendCompAck(ARM::CHI::Payload &payload,
ARM::CHI::Phase &phase)
{
auto res_msg = std::make_shared<CHIResponseMsg>(
curTick(), cacheLineSize, m_ruby_system);
res_msg->m_addr = ruby::makeLineAddress(payload.address, cacheLineBits);
res_msg->m_type = CHIResponseType_CompAck;
res_msg->m_Destination.add(mapAddressToDownstreamMachine(payload.address));
res_msg->m_responder = getMachineID();
res_msg->m_txnId = phase.txn_id;
sendResponseMsg(res_msg);
}
void
CacheController::sendMsg(ARM::CHI::Payload &payload, ARM::CHI::Phase &phase)
{
switch (phase.channel) {
case ARM::CHI::CHANNEL_REQ:
sendRequestMsg(payload, phase);
break;
case ARM::CHI::CHANNEL_DAT:
sendDataMsg(payload, phase);
break;
case ARM::CHI::CHANNEL_RSP:
sendResponseMsg(payload, phase);
break;
default:
panic("Unimplemented channel: %d", phase.channel);
}
}
Addr
CacheController::reqAddr(ARM::CHI::Payload &payload,
ARM::CHI::Phase &phase) const
{
switch (phase.req_opcode) {
case ARM::CHI::REQ_OPCODE_WRITE_NO_SNP_PTL:
return ruby::makeLineAddress(payload.address, cacheLineBits) +
ctz64(payload.byte_enable);
default:
return payload.address;
}
}
Addr
CacheController::reqSize(ARM::CHI::Payload &payload,
ARM::CHI::Phase &phase) const
{
switch (phase.req_opcode) {
case ARM::CHI::REQ_OPCODE_WRITE_NO_SNP_PTL:
assert(transactionSize(payload.size) >= popCount(payload.byte_enable));
return popCount(payload.byte_enable);
default:
return transactionSize(payload.size);
}
}
void
CacheController::sendRequestMsg(ARM::CHI::Payload &payload,
ARM::CHI::Phase &phase)
{
auto req_msg = std::make_shared<CHIRequestMsg>(
curTick(), cacheLineSize, m_ruby_system);
req_msg->m_addr = ruby::makeLineAddress(payload.address, cacheLineBits);
req_msg->m_accAddr = reqAddr(payload, phase);
req_msg->m_accSize = reqSize(payload, phase);
req_msg->m_requestor = getMachineID();
req_msg->m_fwdRequestor = getMachineID();
req_msg->m_dataToFwdRequestor = false;
req_msg->m_type = tlm_to_ruby::reqOpcode(phase.req_opcode);
req_msg->m_isSeqReqValid = false;
req_msg->m_is_local_pf = false;
req_msg->m_is_remote_pf = false;
req_msg->m_allowRetry = phase.allow_retry;
req_msg->m_Destination.add(mapAddressToDownstreamMachine(payload.address));
req_msg->m_txnId = phase.txn_id + (payload.lpid * 1024);
req_msg->m_ns = payload.ns;
sendRequestMsg(req_msg);
pendingTransactions[req_msg->m_txnId] = Transaction::gen(
this, payload, phase);
}
void
CacheController::sendDataMsg(ARM::CHI::Payload &payload,
ARM::CHI::Phase &phase)
{
auto data_msg = std::make_shared<CHIDataMsg>(
curTick(), cacheLineSize, m_ruby_system);
data_msg->m_addr = ruby::makeLineAddress(payload.address, cacheLineBits);
data_msg->m_responder = getMachineID();
data_msg->m_type = tlm_to_ruby::datOpcode(phase.dat_opcode, phase.resp);
data_msg->m_Destination.add(
mapAddressToDownstreamMachine(payload.address));
data_msg->m_txnId = phase.txn_id + (payload.lpid * 1024);
data_msg->m_dataBlk.setData(payload.data, 0, cacheLineSize);
std::vector<bool> byte_enabled(cacheLineSize, false);
const Addr data_id_offset = phase.data_id * 16;
for (int bit = data_id_offset; bit < data_id_offset + 32; bit++) {
if (bits(payload.byte_enable, bit)) {
byte_enabled[bit] = true;
}
}
data_msg->m_bitMask = WriteMask(byte_enabled.size(), byte_enabled);
sendDataMsg(data_msg);
}
void
CacheController::sendResponseMsg(ARM::CHI::Payload &payload,
ARM::CHI::Phase &phase)
{
auto res_msg = std::make_shared<CHIResponseMsg>(
curTick(), cacheLineSize, m_ruby_system);
res_msg->m_addr = ruby::makeLineAddress(payload.address, cacheLineBits);
res_msg->m_responder = getMachineID();
res_msg->m_type = tlm_to_ruby::rspOpcode(phase.rsp_opcode, phase.resp);
res_msg->m_Destination.add(mapAddressToDownstreamMachine(payload.address));
res_msg->m_txnId = phase.txn_id + (payload.lpid * 1024);
sendResponseMsg(res_msg);
}
CacheController::Transaction::Transaction(CacheController *_controller,
ARM::CHI::Payload &_payload,
ARM::CHI::Phase &_phase)
: controller(_controller), payload(&_payload), phase(_phase)
{
payload->ref();
}
CacheController::Transaction::~Transaction()
{
payload->unref();
}
std::unique_ptr<CacheController::Transaction>
CacheController::Transaction::gen(CacheController *controller,
ARM::CHI::Payload &payload,
ARM::CHI::Phase &phase)
{
switch (phase.req_opcode) {
case ARM::CHI::REQ_OPCODE_READ_SHARED:
case ARM::CHI::REQ_OPCODE_READ_CLEAN:
case ARM::CHI::REQ_OPCODE_READ_ONCE:
case ARM::CHI::REQ_OPCODE_READ_NO_SNP:
case ARM::CHI::REQ_OPCODE_READ_UNIQUE:
case ARM::CHI::REQ_OPCODE_READ_NOT_SHARED_DIRTY:
case ARM::CHI::REQ_OPCODE_READ_PREFER_UNIQUE:
case ARM::CHI::REQ_OPCODE_MAKE_READ_UNIQUE:
return std::make_unique<ReadTransaction>(controller, payload, phase);
case ARM::CHI::REQ_OPCODE_WRITE_NO_SNP_PTL:
case ARM::CHI::REQ_OPCODE_WRITE_NO_SNP_FULL:
case ARM::CHI::REQ_OPCODE_WRITE_UNIQUE_ZERO:
case ARM::CHI::REQ_OPCODE_WRITE_UNIQUE_FULL:
case ARM::CHI::REQ_OPCODE_WRITE_BACK_FULL:
// This is a write transaction for now. Will
// this still be the case once WriteEvictOrEvict will also be supported
// in ruby
case ARM::CHI::REQ_OPCODE_WRITE_EVICT_OR_EVICT:
return std::make_unique<WriteTransaction>(
controller, payload, phase);
case ARM::CHI::REQ_OPCODE_CLEAN_UNIQUE:
case ARM::CHI::REQ_OPCODE_MAKE_UNIQUE:
case ARM::CHI::REQ_OPCODE_EVICT:
case ARM::CHI::REQ_OPCODE_STASH_ONCE_SEP_SHARED:
case ARM::CHI::REQ_OPCODE_STASH_ONCE_SEP_UNIQUE:
return std::make_unique<DatalessTransaction>(
controller, payload, phase);
default:
panic("Impossible to generate transaction object");
}
}
} // namespace tlm::chi
} // namespace gem5

View File

@@ -0,0 +1,177 @@
/*
* 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_TLM_CONTROLLER_HH__
#define __MEM_RUBY_PROTOCOL_CHI_TLM_CONTROLLER_HH__
#include <ARM/TLM/arm_chi.h>
#include "mem/ruby/protocol/chi/generic/CHIGenericController.hh"
#include "mem/ruby/protocol/CHIDataType.hh"
#include "mem/ruby/protocol/CHIRequestType.hh"
#include "mem/ruby/protocol/CHIResponseType.hh"
#include "mem/ruby/protocol/RequestStatus.hh"
#include "mem/ruby/protocol/WriteMask.hh"
#include "params/TlmController.hh"
namespace gem5 {
namespace ruby {
class CHIRequestMsg;
class CHIResponseMsg;
class CHIDataMsg;
}
namespace tlm::chi {
/**
* The tlm::chi::CacheController is a ruby CacheController which acts as
* a bridge between the AMBA TLM 2.0 implementation of CHI [1][2] with
* the gem5 (ruby) one.
*
* In other words it translates AMBA CHI transactions into ruby
* messages (which are then forwarded to the MessageQueues)
* and viceversa.
*
* ARM::CHI::Payload, CHIRequestMsg
* <--> CHIDataMsg
* ARM::CHI::Phase CHIResponseMsg
* CHIDataMsg
*
* To connect the tlm::chi::CacheController in python is relatively
* straightforward. The upstream initiator/RNF needs to have a pointer
* to the controller, and this can be done for example with
* SimObject params.
* Example:
*
* class MyRNF():
* chi_controller = Param.TlmController("TLM-to-Ruby CacheController")
*
* The RNF C++ code would then have to set the
* tlm::chi::CacheController::bw callback to implement the backward path
* to send data from downstream to upstream.
*
* [1]: https://developer.arm.com/documentation/101459/latest
* [2]: https://developer.arm.com/Architectures/AMBA#Downloads
*/
class CacheController : public ruby::CHIGenericController
{
public:
PARAMS(TlmController);
CacheController(const Params &p);
/** Set this to send data upstream */
std::function<void(ARM::CHI::Payload* payload, ARM::CHI::Phase* phase)> bw;
bool recvRequestMsg(const ruby::CHIRequestMsg *msg) override;
bool recvSnoopMsg(const ruby::CHIRequestMsg *msg) override;
bool recvResponseMsg(const ruby::CHIResponseMsg *msg) override;
bool recvDataMsg(const ruby::CHIDataMsg *msg) override;
void sendMsg(ARM::CHI::Payload &payload, ARM::CHI::Phase &phase);
using CHIGenericController::sendRequestMsg;
void sendRequestMsg(ARM::CHI::Payload &payload, ARM::CHI::Phase &phase);
using CHIGenericController::sendResponseMsg;
void sendResponseMsg(ARM::CHI::Payload &payload, ARM::CHI::Phase &phase);
void sendCompAck(ARM::CHI::Payload &payload, ARM::CHI::Phase &phase);
using CHIGenericController::sendDataMsg;
void sendDataMsg(ARM::CHI::Payload &payload, ARM::CHI::Phase &phase);
Addr reqAddr(ARM::CHI::Payload &payload, ARM::CHI::Phase &phase) const;
Addr reqSize(ARM::CHI::Payload &payload, ARM::CHI::Phase &phase) const;
void pCreditGrant(const ruby::CHIResponseMsg *msg);
struct Transaction
{
enum class Type
{
READ,
WRITE,
DATALESS
};
Transaction(CacheController *parent,
ARM::CHI::Payload &_payload,
ARM::CHI::Phase &_phase);
~Transaction();
static std::unique_ptr<Transaction> gen(CacheController *parent,
ARM::CHI::Payload &_payload,
ARM::CHI::Phase &_phase);
virtual bool
handle(const ruby::CHIDataMsg *msg)
{
panic("Unimplemented");
}
virtual bool handle(const ruby::CHIResponseMsg *msg);
CacheController *controller;
ARM::CHI::Payload *payload;
ARM::CHI::Phase phase;
};
struct ReadTransaction : public Transaction
{
using Transaction::Transaction;
bool handle(const ruby::CHIDataMsg *msg) override;
bool handle(const ruby::CHIResponseMsg *msg) override;
bool forward(const ruby::CHIDataMsg *msg);
uint8_t dataMsgCnt = 0;
};
struct DatalessTransaction : public Transaction
{
using Transaction::Transaction;
bool handle(const ruby::CHIResponseMsg *msg) override;
};
struct WriteTransaction : public Transaction
{
using Transaction::Transaction;
bool handle(const ruby::CHIResponseMsg *msg) override;
bool recvComp = false;
bool recvDBID = false;
};
std::unordered_map<uint16_t, std::unique_ptr<Transaction>> pendingTransactions;
};
} // namespace tlm::chi
} // namespace gem5
#endif // __MEM_RUBY_PROTOCOL_CHI_TLM_CONTROLLER_HH__

View File

@@ -0,0 +1,498 @@
/*
* 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/tlm/utils.hh"
#include "base/bitfield.hh"
#include "base/logging.hh"
namespace gem5 {
namespace tlm::chi {
namespace {
using namespace ARM::CHI;
std::string
reqOpcodeToName(ReqOpcode req_opcode)
{
switch (req_opcode) {
case REQ_OPCODE_REQ_LCRD_RETURN: return "ReqLCrdReturn";
case REQ_OPCODE_READ_SHARED: return "ReadShared";
case REQ_OPCODE_READ_CLEAN: return "ReadClean";
case REQ_OPCODE_READ_ONCE: return "ReadOnce";
case REQ_OPCODE_READ_NO_SNP: return "ReadNoSnp";
case REQ_OPCODE_PCRD_RETURN: return "PCrdReturn";
case REQ_OPCODE_READ_UNIQUE: return "ReadUnique";
case REQ_OPCODE_CLEAN_SHARED: return "CleanShared";
case REQ_OPCODE_CLEAN_INVALID: return "CleanInvalid";
case REQ_OPCODE_MAKE_INVALID: return "MakeInvalid";
case REQ_OPCODE_CLEAN_UNIQUE: return "CleanUnique";
case REQ_OPCODE_MAKE_UNIQUE: return "MakeUnique";
case REQ_OPCODE_EVICT: return "Evict";
case REQ_OPCODE_EO_BARRIER: return "EoBarrier";
case REQ_OPCODE_EC_BARRIER: return "EcBarrier";
case REQ_OPCODE_READ_NO_SNP_SEP: return "ReadNoSnpSep";
case REQ_OPCODE_CLEAN_SHARED_PERSIST_SEP: return "CleanSharedPersistSep";
case REQ_OPCODE_DVM_OP: return "DvmOp";
case REQ_OPCODE_WRITE_EVICT_FULL: return "WriteEvictFull";
case REQ_OPCODE_WRITE_CLEAN_PTL: return "WriteCleanPtl";
case REQ_OPCODE_WRITE_CLEAN_FULL: return "WriteCleanFull";
case REQ_OPCODE_WRITE_UNIQUE_PTL: return "WriteUniquePtl";
case REQ_OPCODE_WRITE_UNIQUE_FULL: return "WriteUniqueFull";
case REQ_OPCODE_WRITE_BACK_PTL: return "WriteBackPtl";
case REQ_OPCODE_WRITE_BACK_FULL: return "WriteBackFull";
case REQ_OPCODE_WRITE_NO_SNP_PTL: return "WriteNoSnpPtl";
case REQ_OPCODE_WRITE_NO_SNP_FULL: return "WriteNoSnpFull";
case REQ_OPCODE_WRITE_UNIQUE_FULL_STASH: return "WriteUniqueFullStash";
case REQ_OPCODE_WRITE_UNIQUE_PTL_STASH: return "WriteUniquePtlStash";
case REQ_OPCODE_STASH_ONCE_SHARED: return "StashOnceShared";
case REQ_OPCODE_STASH_ONCE_UNIQUE: return "StashOnceUnique";
case REQ_OPCODE_READ_ONCE_CLEAN_INVALID: return "ReadOnceCleanInvalid";
case REQ_OPCODE_READ_ONCE_MAKE_INVALID: return "ReadOnceMakeInvalid";
case REQ_OPCODE_READ_NOT_SHARED_DIRTY: return "ReadNotSharedDirty";
case REQ_OPCODE_CLEAN_SHARED_PERSIST: return "CleanSharedPersist";
case REQ_OPCODE_ATOMIC_STORE_ADD: return "AtomicStoreAdd";
case REQ_OPCODE_ATOMIC_STORE_CLR: return "AtomicStoreClr";
case REQ_OPCODE_ATOMIC_STORE_EOR: return "AtomicStoreEor";
case REQ_OPCODE_ATOMIC_STORE_SET: return "AtomicStoreSet";
case REQ_OPCODE_ATOMIC_STORE_SMAX: return "AtomicStoreSmax";
case REQ_OPCODE_ATOMIC_STORE_SMIN: return "AtomicStoreSmin";
case REQ_OPCODE_ATOMIC_STORE_UMAX: return "AtomicStoreUmax";
case REQ_OPCODE_ATOMIC_STORE_UMIN: return "AtomicStoreUmin";
case REQ_OPCODE_ATOMIC_LOAD_ADD: return "AtomicLoadAdd";
case REQ_OPCODE_ATOMIC_LOAD_CLR: return "AtomicLoadClr";
case REQ_OPCODE_ATOMIC_LOAD_EOR: return "AtomicLoadEor";
case REQ_OPCODE_ATOMIC_LOAD_SET: return "AtomicLoadSet";
case REQ_OPCODE_ATOMIC_LOAD_SMAX: return "AtomicLoadSmax";
case REQ_OPCODE_ATOMIC_LOAD_SMIN: return "AtomicLoadSmin";
case REQ_OPCODE_ATOMIC_LOAD_UMAX: return "AtomicLoadUmax";
case REQ_OPCODE_ATOMIC_LOAD_UMIN: return "AtomicLoadUmin";
case REQ_OPCODE_ATOMIC_SWAP: return "AtomicSwap";
case REQ_OPCODE_ATOMIC_COMPARE: return "AtomicCompare";
case REQ_OPCODE_PREFETCH_TGT: return "PrefetchTgt";
case REQ_OPCODE_MAKE_READ_UNIQUE: return "MakeReadUnique";
case REQ_OPCODE_WRITE_EVICT_OR_EVICT: return "WriteEvictOrEvict";
case REQ_OPCODE_WRITE_UNIQUE_ZERO: return "WriteUniqueZero";
case REQ_OPCODE_WRITE_NO_SNP_ZERO: return "WriteNoSnpZero";
case REQ_OPCODE_STASH_ONCE_SEP_SHARED: return "StashOnceSepShared";
case REQ_OPCODE_STASH_ONCE_SEP_UNIQUE: return "StashOnceSepUnique";
case REQ_OPCODE_READ_PREFER_UNIQUE: return "ReadPreferUnique";
case REQ_OPCODE_WRITE_NO_SNP_FULL_CLEAN_SH: return "WriteNoSnpFullCleanSh";
default: return std::string{};
}
}
std::string
snpOpcodeToName(SnpOpcode snp_opcode)
{
switch (snp_opcode) {
case SNP_OPCODE_SNP_LCRD_RETURN: return "SnpLcrdReturn";
case SNP_OPCODE_SNP_SHARED: return "SnpShared";
case SNP_OPCODE_SNP_CLEAN: return "SnpClean";
case SNP_OPCODE_SNP_ONCE: return "SnpOnce";
case SNP_OPCODE_SNP_NOT_SHARED_DIRTY: return "SnpNotSharedDirty";
case SNP_OPCODE_SNP_UNIQUE_STASH: return "SnpUniqueStash";
case SNP_OPCODE_SNP_MAKE_INVALID_STASH: return "SnpMakeInvalidStash";
case SNP_OPCODE_SNP_UNIQUE: return "SnpUnique";
case SNP_OPCODE_SNP_CLEAN_SHARED: return "SnpCleanShared";
case SNP_OPCODE_SNP_CLEAN_INVALID: return "SnpCleanInvalid";
case SNP_OPCODE_SNP_MAKE_INVALID: return "SnpMakeInvalid";
case SNP_OPCODE_SNP_STASH_UNIQUE: return "SnpStashUnique";
case SNP_OPCODE_SNP_STASH_SHARED: return "SnpStashShared";
case SNP_OPCODE_SNP_DVM_OP: return "SnpDvmOp";
case SNP_OPCODE_SNP_QUERY: return "SnpQuery";
case SNP_OPCODE_SNP_SHARED_FWD: return "SnpSharedFwd";
case SNP_OPCODE_SNP_CLEAN_FWD: return "SnpCleanFwd";
case SNP_OPCODE_SNP_ONCE_FWD: return "SnpOnceFwd";
case SNP_OPCODE_SNP_NOT_SHARED_DIRTY_FWD: return "SnpNotSharedDirtyFwd";
case SNP_OPCODE_SNP_PREFER_UNIQUE: return "SnpPreferUnique";
case SNP_OPCODE_SNP_PREFER_UNIQUE_FWD: return "SnpPreferUniqueFwd";
case SNP_OPCODE_SNP_UNIQUE_FWD: return "SnpUniqueFwd";
default: return std::string{};
}
}
std::string
datOpcodeToName(DatOpcode dat_opcode)
{
switch (dat_opcode) {
case DAT_OPCODE_DAT_LCRD_RETURN: return "DatLcrdReturn";
case DAT_OPCODE_SNP_RESP_DATA: return "SnpRespData";
case DAT_OPCODE_COPY_BACK_WR_DATA: return "CopyBackWrData";
case DAT_OPCODE_NON_COPY_BACK_WR_DATA: return "NonCopyBackWrData";
case DAT_OPCODE_COMP_DATA: return "CompData";
case DAT_OPCODE_SNP_RESP_DATA_PTL: return "SnpRespDataPtl";
case DAT_OPCODE_SNP_RESP_DATA_FWDED: return "SnpRespDataFwded";
case DAT_OPCODE_WRITE_DATA_CANCEL: return "WriteDataCancel";
case DAT_OPCODE_DATA_SEP_RESP: return "DataSepResp";
case DAT_OPCODE_NCB_WR_DATA_COMP_ACK: return "NcbWrDataCompAck";
default: return std::string{};
}
}
std::string
rspOpcodeToName(RspOpcode rsp_opcode)
{
switch (rsp_opcode) {
case RSP_OPCODE_RSP_LCRD_RETURN: return "RspLcrdReturn";
case RSP_OPCODE_SNP_RESP: return "SnpResp";
case RSP_OPCODE_COMP_ACK: return "CompAck";
case RSP_OPCODE_RETRY_ACK: return "RetryAck";
case RSP_OPCODE_COMP: return "OpcodeComp";
case RSP_OPCODE_COMP_DBID_RESP: return "CompDbidResp";
case RSP_OPCODE_DBID_RESP: return "DbidResp";
case RSP_OPCODE_PCRD_GRANT: return "PcrdGrant";
case RSP_OPCODE_READ_RECEIPT: return "ReadReceipt";
case RSP_OPCODE_SNP_RESP_FWDED: return "SnpRespFwded";
case RSP_OPCODE_TAG_MATCH: return "TagMatch";
case RSP_OPCODE_RESP_SEP_DATA: return "RespSepData";
case RSP_OPCODE_PERSIST: return "Persist";
case RSP_OPCODE_COMP_PERSIST: return "CompPersist";
case RSP_OPCODE_DBID_RESP_ORD: return "DbidRespOrd";
case RSP_OPCODE_STASH_DONE: return "StashDone";
case RSP_OPCODE_COMP_STASH_DONE: return "CompStashDone";
case RSP_OPCODE_COMP_CMO: return "CompCMO";
default: return std::string{};
}
}
std::string
phaseToOpcodeName(const Phase &phase)
{
switch (phase.channel) {
case CHANNEL_REQ:
return reqOpcodeToName(phase.req_opcode);
case CHANNEL_SNP:
return snpOpcodeToName(phase.snp_opcode);
case CHANNEL_DAT:
return datOpcodeToName(phase.dat_opcode);
case CHANNEL_RSP:
return rspOpcodeToName(phase.rsp_opcode);
default:
break;
}
return std::string{};
}
std::string
phaseToChannelName(const Phase &phase)
{
switch (phase.channel) {
case CHANNEL_REQ:
return "REQ";
case CHANNEL_SNP:
return "SNP";
case CHANNEL_DAT:
return "DAT";
case CHANNEL_RSP:
return "RSP";
default:
return std::string{};
}
}
} // namespace
std::string
transactionToString(const Payload &payload,
const Phase &phase)
{
return csprintf("%s %s addr=0x%08lx ns=%d size=%d attrs=0x%x",
phaseToChannelName(phase),
phaseToOpcodeName(phase).c_str(),
payload.address, payload.ns,
(int)payload.size, (int)payload.mem_attr);
}
namespace tlm_to_ruby {
ruby::CHIRequestType
reqOpcode(ReqOpcode req)
{
static std::unordered_map<uint8_t, ruby::CHIRequestType> translation_map = {
{ REQ_OPCODE_READ_SHARED, ruby::CHIRequestType_ReadShared },
{ REQ_OPCODE_READ_CLEAN, ruby::CHIRequestType_ReadOnce }, // TODO
{ REQ_OPCODE_READ_ONCE, ruby::CHIRequestType_ReadOnce },
{ REQ_OPCODE_READ_NO_SNP, ruby::CHIRequestType_ReadNoSnp }, // TODO
{ REQ_OPCODE_READ_UNIQUE, ruby::CHIRequestType_ReadUnique },
{ REQ_OPCODE_READ_NOT_SHARED_DIRTY, ruby::CHIRequestType_ReadNotSharedDirty },
{ REQ_OPCODE_READ_PREFER_UNIQUE, ruby::CHIRequestType_ReadUnique }, // TODO
{ REQ_OPCODE_MAKE_READ_UNIQUE, ruby::CHIRequestType_MakeReadUnique }, // TODO
{ REQ_OPCODE_CLEAN_UNIQUE, ruby::CHIRequestType_CleanUnique },
{ REQ_OPCODE_MAKE_UNIQUE, ruby::CHIRequestType_CleanUnique }, // TODO
{ REQ_OPCODE_EVICT, ruby::CHIRequestType_Evict },
{ REQ_OPCODE_STASH_ONCE_SEP_SHARED, ruby::CHIRequestType_StashOnceShared }, // TODO
{ REQ_OPCODE_STASH_ONCE_SEP_UNIQUE, ruby::CHIRequestType_StashOnceUnique },
{ REQ_OPCODE_WRITE_NO_SNP_PTL, ruby::CHIRequestType_WriteUniquePtl },
{ REQ_OPCODE_WRITE_NO_SNP_FULL, ruby::CHIRequestType_WriteUniqueFull },
{ REQ_OPCODE_WRITE_UNIQUE_FULL, ruby::CHIRequestType_WriteUniqueFull },
{ REQ_OPCODE_WRITE_UNIQUE_ZERO, ruby::CHIRequestType_WriteUniqueZero },
{ REQ_OPCODE_WRITE_BACK_FULL, ruby::CHIRequestType_WriteBackFull },
{ REQ_OPCODE_WRITE_EVICT_OR_EVICT, ruby::CHIRequestType_WriteEvictFull }, // TODO
};
auto it = translation_map.find(req);
if (it != translation_map.end()) {
return it->second;
} else {
panic("Unsupported Translation: %s\n", reqOpcodeToName(req));
}
}
#define RESP_CASE(opc) \
switch (resp) { \
case RESP_I: return opc ## _ ## I; \
case RESP_SC: return opc ## _ ## SC; \
case RESP_UC: return opc ## _ ## UC; \
case RESP_SD: return opc ## _ ## SD; \
case RESP_I_PD: return opc ## _ ## I_PD; \
case RESP_SC_PD: return opc ## _ ## SC_PD; \
case RESP_UC_PD: return opc ## _ ## UC; \
case RESP_SD_PD: return opc ## _ ## SD; \
default: panic(""); \
}
ruby::CHIDataType
datOpcode(DatOpcode dat, Resp resp)
{
switch (dat) {
case DAT_OPCODE_NON_COPY_BACK_WR_DATA:
return ruby::CHIDataType_NCBWrData;
case DAT_OPCODE_COPY_BACK_WR_DATA:
switch (resp) {
case RESP_I: return ruby::CHIDataType_CBWrData_I;
case RESP_UC: return ruby::CHIDataType_CBWrData_UC;
case RESP_SC: return ruby::CHIDataType_CBWrData_SC;
case RESP_UD_PD: return ruby::CHIDataType_CBWrData_UD_PD;
default: panic("");
}
case DAT_OPCODE_SNP_RESP_DATA:
RESP_CASE(ruby::CHIDataType_SnpRespData)
default:
panic("Unsupported Translation: %s\n", datOpcodeToName(dat));
}
}
ruby::CHIResponseType
rspOpcode(RspOpcode opc, Resp resp)
{
switch(opc) {
case RSP_OPCODE_COMP_ACK: return ruby::CHIResponseType_CompAck;
case RSP_OPCODE_SNP_RESP:
switch (resp) {
case RESP_I: return ruby::CHIResponseType_SnpResp_I;
default: panic("Invalid resp %d for %d\n", resp, opc);
}
default:
panic("Unsupported Translation: %s\n", rspOpcodeToName(opc));
};
}
}
namespace ruby_to_tlm {
uint8_t
datOpcode(ruby::CHIDataType dat)
{
switch (dat) {
case ruby::CHIDataType_CompData_I:
case ruby::CHIDataType_CompData_UC:
case ruby::CHIDataType_CompData_SC:
case ruby::CHIDataType_CompData_UD_PD:
case ruby::CHIDataType_CompData_SD_PD:
return 0x4;
case ruby::CHIDataType_DataSepResp_UC:
return 0xb;
case ruby::CHIDataType_CBWrData_UC:
case ruby::CHIDataType_CBWrData_SC:
case ruby::CHIDataType_CBWrData_UD_PD:
case ruby::CHIDataType_CBWrData_SD_PD:
case ruby::CHIDataType_CBWrData_I:
return 0x2;
case ruby::CHIDataType_NCBWrData:
return 0x3;
case ruby::CHIDataType_SnpRespData_I:
case ruby::CHIDataType_SnpRespData_I_PD:
case ruby::CHIDataType_SnpRespData_SC:
case ruby::CHIDataType_SnpRespData_SC_PD:
case ruby::CHIDataType_SnpRespData_SD:
case ruby::CHIDataType_SnpRespData_UC:
case ruby::CHIDataType_SnpRespData_UD:
return 0x1;
case ruby::CHIDataType_SnpRespData_SC_Fwded_SC:
case ruby::CHIDataType_SnpRespData_SC_Fwded_SD_PD:
case ruby::CHIDataType_SnpRespData_SC_PD_Fwded_SC:
case ruby::CHIDataType_SnpRespData_SD_Fwded_SC:
case ruby::CHIDataType_SnpRespData_I_Fwded_SD_PD:
case ruby::CHIDataType_SnpRespData_I_PD_Fwded_SC:
case ruby::CHIDataType_SnpRespData_I_Fwded_SC:
return 0x6;
default:
panic("Unrecognised data opcode: %d\n", dat);
}
}
uint8_t
rspOpcode(ruby::CHIResponseType rsp)
{
switch (rsp) {
case ruby::CHIResponseType_Comp_UD_PD:
case ruby::CHIResponseType_Comp_UC:
case ruby::CHIResponseType_Comp_I:
return RSP_OPCODE_COMP;
case ruby::CHIResponseType_CompDBIDResp:
return RSP_OPCODE_COMP_DBID_RESP;
case ruby::CHIResponseType_RetryAck:
return RSP_OPCODE_RETRY_ACK;
default:
panic("Unrecognised rsp opcode: %d\n", rsp);
}
}
uint8_t
snpOpcode(ruby::CHIRequestType snp)
{
switch (snp) {
case ruby::CHIRequestType_SnpOnceFwd:
return SNP_OPCODE_SNP_ONCE_FWD;
case ruby::CHIRequestType_SnpOnce:
return SNP_OPCODE_SNP_ONCE;
case ruby::CHIRequestType_SnpShared:
return SNP_OPCODE_SNP_SHARED;
case ruby::CHIRequestType_SnpCleanInvalid:
return SNP_OPCODE_SNP_CLEAN_INVALID;
case ruby::CHIRequestType_SnpUnique:
return SNP_OPCODE_SNP_UNIQUE;
default:
panic("Unrecognised snp opcode: %d\n", snp);
}
}
Resp
datResp(ruby::CHIDataType dat)
{
switch (dat) {
case ruby::CHIDataType_SnpRespData_I:
case ruby::CHIDataType_CompData_I:
case ruby::CHIDataType_CBWrData_I:
return RESP_I;
case ruby::CHIDataType_SnpRespData_SC:
case ruby::CHIDataType_CompData_SC:
case ruby::CHIDataType_CBWrData_SC:
return RESP_SC;
case ruby::CHIDataType_SnpRespData_UC:
case ruby::CHIDataType_CompData_UC:
case ruby::CHIDataType_CBWrData_UC:
case ruby::CHIDataType_DataSepResp_UC:
return RESP_UC;
case ruby::CHIDataType_SnpRespData_UD:
return RESP_UD;
case ruby::CHIDataType_SnpRespData_SD:
return RESP_SD;
case ruby::CHIDataType_SnpRespData_I_PD:
return RESP_I_PD;
case ruby::CHIDataType_SnpRespData_SC_PD:
return RESP_SC_PD;
case ruby::CHIDataType_CompData_UD_PD:
case ruby::CHIDataType_CBWrData_UD_PD:
return RESP_UD_PD;
case ruby::CHIDataType_CompData_SD_PD:
case ruby::CHIDataType_CBWrData_SD_PD:
return RESP_SD_PD;
// TODO
case ruby::CHIDataType_SnpRespData_SC_Fwded_SC:
case ruby::CHIDataType_SnpRespData_SC_Fwded_SD_PD:
case ruby::CHIDataType_SnpRespData_SC_PD_Fwded_SC:
case ruby::CHIDataType_SnpRespData_SD_Fwded_SC:
case ruby::CHIDataType_SnpRespData_I_Fwded_SD_PD:
case ruby::CHIDataType_SnpRespData_I_PD_Fwded_SC:
case ruby::CHIDataType_SnpRespData_I_Fwded_SC:
default:
panic("Unrecognised data opcode: %d\n", dat);
}
}
Resp
rspResp(ruby::CHIResponseType rsp)
{
switch (rsp) {
case ruby::CHIResponseType_Comp_I:
return RESP_I;
case ruby::CHIResponseType_Comp_UC:
return RESP_UC;
case ruby::CHIResponseType_Comp_UD_PD:
return RESP_UD_PD;
case ruby::CHIResponseType_CompDBIDResp:
return RESP_I;
case ruby::CHIResponseType_RetryAck:
// Just setup to zero
return RESP_I;
default:
panic("Unrecognised rsp opcode: %d\n", rsp);
}
}
}
Addr
transactionSize(Size sz)
{
return 1 << sz;
}
uint8_t
dataId(Addr address)
{
uint64_t bus_width = 256;
switch (bus_width) {
case 128:
return bits(address, 5, 4);
case 256:
return bits(address, 5, 4) & 0b10;
case 512:
default:
return 0b00;
}
}
} // namespace tlm::chi
} // namespace gem5

View File

@@ -0,0 +1,82 @@
/*
* 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_TLM_UTILS_HH__
#define __MEM_RUBY_PROTOCOL_CHI_TLM_UTILS_HH__
#include <ARM/TLM/arm_chi.h>
#include "base/types.hh"
#include "mem/ruby/protocol/CHIDataType.hh"
#include "mem/ruby/protocol/CHIRequestType.hh"
#include "mem/ruby/protocol/CHIResponseType.hh"
namespace gem5 {
namespace tlm::chi {
std::string transactionToString(const ARM::CHI::Payload &payload,
const ARM::CHI::Phase &phase);
namespace tlm_to_ruby {
ruby::CHIRequestType reqOpcode(ARM::CHI::ReqOpcode req);
ruby::CHIDataType datOpcode(ARM::CHI::DatOpcode dat, ARM::CHI::Resp resp);
ruby::CHIResponseType rspOpcode(ARM::CHI::RspOpcode res, ARM::CHI::Resp resp);
}
namespace ruby_to_tlm {
uint8_t datOpcode(ruby::CHIDataType dat);
uint8_t rspOpcode(ruby::CHIResponseType res);
uint8_t snpOpcode(ruby::CHIRequestType snp);
ARM::CHI::Resp datResp(ruby::CHIDataType dat);
ARM::CHI::Resp rspResp(ruby::CHIResponseType rsp);
}
Addr transactionSize(ARM::CHI::Size sz);
uint8_t dataId(Addr address);
} // namespace tlm::chi
} // namespace gem5
#endif // __MEM_RUBY_PROTOCOL_CHI_TLM_UTILS_HH__