mem: create port_wrapper classes

The port_wrapper classes convert the Request/ResponsePort from
inherit-base to callback registrations. This help 'composition over
inheritance' that most design pattern follows, which help reducing
code length and increase reusability.

Change-Id: Ia13cc62507ac8425bd7cf143a2e080d041c173f9
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/67232
Maintainer: Jason Lowe-Power <power.jg@gmail.com>
Reviewed-by: Jason Lowe-Power <power.jg@gmail.com>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Earl Ou
2023-01-04 19:48:18 -08:00
parent a2658f08e5
commit 4954167fe5
3 changed files with 329 additions and 0 deletions

View File

@@ -88,6 +88,7 @@ Source('packet.cc')
Source('port.cc')
Source('packet_queue.cc')
Source('port_proxy.cc')
Source('port_wrapper.cc')
Source('physical.cc')
Source('shared_memory_server.cc')
Source('simple_mem.cc')

169
src/mem/port_wrapper.cc Normal file
View File

@@ -0,0 +1,169 @@
/*
* Copyright 2023 Google, LLC.
*
* 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/port_wrapper.hh"
namespace gem5
{
RequestPortWrapper::RequestPortWrapper(const std::string& name,
SimObject* _owner, PortID id)
: RequestPort(name, _owner, id)
{
}
void
RequestPortWrapper::recvRangeChange()
{
if (!recvRangeChangeCb) {
RequestPort::recvRangeChange();
return;
}
recvRangeChangeCb();
}
bool
RequestPortWrapper::recvTimingResp(PacketPtr packet)
{
panic_if(!recvTimingRespCb, "RecvTimingRespCallback is empty.");
return recvTimingRespCb(packet);
}
void
RequestPortWrapper::recvReqRetry()
{
panic_if(!recvReqRetryCb, "RecvReqRetryCallback is empty.");
recvReqRetryCb();
}
void
RequestPortWrapper::setRangeChangeCallback(RecvReqRetryCallback cb)
{
recvRangeChangeCb = std::move(cb);
}
void
RequestPortWrapper::setTimingCallbacks(RecvTimingRespCallback resp_cb,
RecvReqRetryCallback retry_cb)
{
recvTimingRespCb = std::move(resp_cb);
recvReqRetryCb = std::move(retry_cb);
}
ResponsePortWrapper::ResponsePortWrapper(const std::string& name,
SimObject* _owner, PortID id)
: ResponsePort(name, _owner, id)
{
}
AddrRangeList
ResponsePortWrapper::getAddrRanges() const
{
panic_if(!getAddrRangesCb, "GetAddrRangesCallback is empty.");
return getAddrRangesCb();
}
bool
ResponsePortWrapper::recvTimingReq(PacketPtr packet)
{
panic_if(!recvTimingReqCb, "RecvTimingReqCallback is empty.");
return recvTimingReqCb(packet);
}
void
ResponsePortWrapper::recvRespRetry()
{
panic_if(!recvRespRetryCb, "RecvRespRetryCallback is empty.");
recvRespRetryCb();
}
Tick
ResponsePortWrapper::recvAtomic(PacketPtr packet)
{
panic_if(!recvAtomicCb, "RecvAtomicCallback is empty.");
return recvAtomicCb(packet);
}
Tick
ResponsePortWrapper::recvAtomicBackdoor(PacketPtr packet,
MemBackdoorPtr& backdoor)
{
if (!recvAtomicBackdoorCb) {
return ResponsePort::recvAtomicBackdoor(packet, backdoor);
}
return recvAtomicBackdoorCb(packet, backdoor);
}
void
ResponsePortWrapper::recvFunctional(PacketPtr packet)
{
panic_if(!recvFunctionalCb, "RecvFunctionalCallback is empty.");
recvTimingReqCb(packet);
}
void
ResponsePortWrapper::recvMemBackdoorReq(const MemBackdoorReq& req,
MemBackdoorPtr& backdoor)
{
if (!recvMemBackdoorReqCb) {
ResponsePort::recvMemBackdoorReq(req, backdoor);
return;
}
recvMemBackdoorReqCb(req, backdoor);
}
void
ResponsePortWrapper::setGetAddrRangesCallback(GetAddrRangesCallback cb)
{
getAddrRangesCb = std::move(cb);
}
void
ResponsePortWrapper::setTimingCallbacks(RecvTimingReqCallback timing_cb,
RecvRespRetryCallback retry_cb)
{
recvTimingReqCb = std::move(timing_cb);
recvRespRetryCb = std::move(retry_cb);
}
void
ResponsePortWrapper::setAtomicCallbacks(RecvAtomicCallback atomic_cb,
RecvAtomicBackdoorCallback backdoor_cb)
{
recvAtomicCb = std::move(atomic_cb);
recvAtomicBackdoorCb = std::move(backdoor_cb);
}
void
ResponsePortWrapper::setFunctionalCallbacks(
RecvFunctionalCallback func_cb, RecvMemBackdoorReqCallback backdoor_cb)
{
recvFunctionalCb = std::move(func_cb);
recvMemBackdoorReqCb = std::move(backdoor_cb);
}
} // namespace gem5

159
src/mem/port_wrapper.hh Normal file
View File

@@ -0,0 +1,159 @@
/*
* Copyright 2023 Google, LLC.
*
* 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.
*/
/**
* @file
* PortWrapper Object Declaration.
*
* The RequestPortWrapper and ResponsePortWrapper converts inherit-based
* RequestPort and ResponsePort into callback-based. This help reducing
* redundant code and increase code reusability in most cases, allowing
* composition over inheritance pattern.
*
* Example usage:
*
* class MySimObject : public SimObject
* {
* public:
* ResponsePortWrapper inPort;
*
* MySimObject(...) : inPort("in_port", this)... {
* inPort.setGetAddrRangesCallback([this]() {
* return getRange();
* });
*
* inPort.setAtomicCallbacks([this](PacketPtr packet) {
* // process the packet
* ...
* return Tick();
* });
* }
*
* private:
* AddrRangeList getRange() const {...}
* };
*/
#ifndef __MEM_PORT_WRAPPER_HH__
#define __MEM_PORT_WRAPPER_HH__
#include <functional>
#include "mem/port.hh"
namespace gem5
{
/**
* The RequestPortWrapper converts inherit-based RequestPort into
* callback-based.
*/
class RequestPortWrapper : public RequestPort
{
public:
using RecvRangeChangeCallback = std::function<void()>;
// Timing Protocol
using RecvTimingRespCallback = std::function<bool(PacketPtr)>;
using RecvReqRetryCallback = std::function<void()>;
RequestPortWrapper(const std::string& name, SimObject* _owner,
PortID id = InvalidPortID);
void recvRangeChange() override;
// TimingRequestProtocol
bool recvTimingResp(PacketPtr) override;
void recvReqRetry() override;
void setRangeChangeCallback(RecvReqRetryCallback);
void setTimingCallbacks(RecvTimingRespCallback, RecvReqRetryCallback);
private:
RecvRangeChangeCallback recvRangeChangeCb = nullptr;
RecvTimingRespCallback recvTimingRespCb = nullptr;
RecvReqRetryCallback recvReqRetryCb = nullptr;
};
/**
* The ResponsePortWrapper converts inherit-based ResponsePort into
* callback-based.
*/
class ResponsePortWrapper : public ResponsePort
{
public:
using GetAddrRangesCallback = std::function<AddrRangeList()>;
// Timing Protocol
using RecvTimingReqCallback = std::function<bool(PacketPtr)>;
// Atomic Protocol
using RecvAtomicCallback = std::function<Tick(PacketPtr)>;
using RecvAtomicBackdoorCallback =
std::function<Tick(PacketPtr, MemBackdoorPtr&)>;
// Functional Protocol
using RecvFunctionalCallback = std::function<void(PacketPtr)>;
using RecvMemBackdoorReqCallback =
std::function<void(const MemBackdoorReq&, MemBackdoorPtr&)>;
using RecvRespRetryCallback = std::function<void()>;
ResponsePortWrapper(const std::string& name, SimObject* _owner,
PortID id = InvalidPortID);
AddrRangeList getAddrRanges() const override;
// TimingResponseProtocol
bool recvTimingReq(PacketPtr) override;
void recvRespRetry() override;
// AtomicResponseProtocol
Tick recvAtomic(PacketPtr) override;
Tick recvAtomicBackdoor(PacketPtr, MemBackdoorPtr&) override;
// FunctionalResponseProtocol
void recvFunctional(PacketPtr) override;
void recvMemBackdoorReq(const MemBackdoorReq&, MemBackdoorPtr&) override;
void setGetAddrRangesCallback(GetAddrRangesCallback);
void setTimingCallbacks(RecvTimingReqCallback, RecvRespRetryCallback);
void setAtomicCallbacks(RecvAtomicCallback,
RecvAtomicBackdoorCallback = nullptr);
void setFunctionalCallbacks(RecvFunctionalCallback,
RecvMemBackdoorReqCallback = nullptr);
private:
GetAddrRangesCallback getAddrRangesCb = nullptr;
RecvTimingReqCallback recvTimingReqCb = nullptr;
RecvRespRetryCallback recvRespRetryCb = nullptr;
RecvAtomicCallback recvAtomicCb = nullptr;
RecvAtomicBackdoorCallback recvAtomicBackdoorCb = nullptr;
RecvFunctionalCallback recvFunctionalCb = nullptr;
RecvMemBackdoorReqCallback recvMemBackdoorReqCb = nullptr;
};
} // namespace gem5
#endif //__MEM_PORT_WRAPPER_HH__