diff --git a/src/mem/SConscript b/src/mem/SConscript index 3bcfc0d9c5..ca164c1e27 100644 --- a/src/mem/SConscript +++ b/src/mem/SConscript @@ -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') diff --git a/src/mem/port_wrapper.cc b/src/mem/port_wrapper.cc new file mode 100644 index 0000000000..fd5ebbd614 --- /dev/null +++ b/src/mem/port_wrapper.cc @@ -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 diff --git a/src/mem/port_wrapper.hh b/src/mem/port_wrapper.hh new file mode 100644 index 0000000000..5dcdd5dc9b --- /dev/null +++ b/src/mem/port_wrapper.hh @@ -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 + +#include "mem/port.hh" + +namespace gem5 +{ + +/** + * The RequestPortWrapper converts inherit-based RequestPort into + * callback-based. + */ +class RequestPortWrapper : public RequestPort +{ + public: + using RecvRangeChangeCallback = std::function; + // Timing Protocol + using RecvTimingRespCallback = std::function; + using RecvReqRetryCallback = std::function; + + 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; + // Timing Protocol + using RecvTimingReqCallback = std::function; + // Atomic Protocol + using RecvAtomicCallback = std::function; + using RecvAtomicBackdoorCallback = + std::function; + + // Functional Protocol + using RecvFunctionalCallback = std::function; + using RecvMemBackdoorReqCallback = + std::function; + + using RecvRespRetryCallback = std::function; + + 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__