#include <memory>
-#include "debug/Config.hh"
-#include "debug/Drain.hh"
#include "debug/RubyDma.hh"
#include "debug/RubyStats.hh"
#include "mem/protocol/SequencerMsg.hh"
+#include "mem/protocol/SequencerRequestType.hh"
#include "mem/ruby/system/DMASequencer.hh"
#include "mem/ruby/system/RubySystem.hh"
-#include "sim/system.hh"
DMASequencer::DMASequencer(const Params *p)
- : MemObject(p), m_ruby_system(p->ruby_system), m_version(p->version),
- m_controller(NULL), m_mandatory_q_ptr(NULL),
- m_usingRubyTester(p->using_ruby_tester),
- slave_port(csprintf("%s.slave", name()), this, 0, p->ruby_system,
- p->ruby_system->getAccessBackingStore()),
- system(p->system), retry(false)
+ : RubyPort(p)
{
- assert(m_version != -1);
}
void
DMASequencer::init()
{
- MemObject::init();
- assert(m_controller != NULL);
- m_mandatory_q_ptr = m_controller->getMandatoryQueue();
+ RubyPort::init();
m_is_busy = false;
m_data_block_mask = ~ (~0 << RubySystem::getBlockSizeBits());
-
- slave_port.sendRangeChange();
-}
-
-BaseSlavePort &
-DMASequencer::getSlavePort(const std::string &if_name, PortID idx)
-{
- // used by the CPUs to connect the caches to the interconnect, and
- // for the x86 case also the interrupt master
- if (if_name != "slave") {
- // pass it along to our super class
- return MemObject::getSlavePort(if_name, idx);
- } else {
- return slave_port;
- }
-}
-
-DMASequencer::MemSlavePort::MemSlavePort(const std::string &_name,
- DMASequencer *_port, PortID id, RubySystem* _ruby_system,
- bool _access_backing_store)
- : QueuedSlavePort(_name, _port, queue, id), queue(*_port, *this),
- m_ruby_system(_ruby_system), access_backing_store(_access_backing_store)
-{
- DPRINTF(RubyDma, "Created slave memport on ruby sequencer %s\n", _name);
-}
-
-bool
-DMASequencer::MemSlavePort::recvTimingReq(PacketPtr pkt)
-{
- DPRINTF(RubyDma, "Timing request for address %#x on port %d\n",
- pkt->getAddr(), id);
- DMASequencer *seq = static_cast<DMASequencer *>(&owner);
-
- if (pkt->cacheResponding())
- panic("DMASequencer should never see a request with the "
- "cacheResponding flag set\n");
-
- assert(isPhysMemAddress(pkt->getAddr()));
- assert(getOffset(pkt->getAddr()) + pkt->getSize() <=
- RubySystem::getBlockSizeBytes());
-
- // Submit the ruby request
- RequestStatus requestStatus = seq->makeRequest(pkt);
-
- // If the request successfully issued then we should return true.
- // Otherwise, we need to tell the port to retry at a later point
- // and return false.
- if (requestStatus == RequestStatus_Issued) {
- DPRINTF(RubyDma, "Request %s 0x%x issued\n", pkt->cmdString(),
- pkt->getAddr());
- return true;
- }
-
- // Unless one is using the ruby tester, record the stalled M5 port for
- // later retry when the sequencer becomes free.
- if (!seq->m_usingRubyTester) {
- seq->retry = true;
- }
-
- DPRINTF(RubyDma, "Request for address %#x did not issued because %s\n",
- pkt->getAddr(), RequestStatus_to_string(requestStatus));
-
- return false;
-}
-
-void
-DMASequencer::ruby_hit_callback(PacketPtr pkt)
-{
- DPRINTF(RubyDma, "Hit callback for %s 0x%x\n", pkt->cmdString(),
- pkt->getAddr());
-
- // The packet was destined for memory and has not yet been turned
- // into a response
- assert(system->isMemAddr(pkt->getAddr()));
- assert(pkt->isRequest());
- slave_port.hitCallback(pkt);
-
- // If we had to stall the slave ports, wake it up because
- // the sequencer likely has free resources now.
- if (retry) {
- retry = false;
- DPRINTF(RubyDma,"Sequencer may now be free. SendRetry to port %s\n",
- slave_port.name());
- slave_port.sendRetryReq();
- }
-
- testDrainComplete();
-}
-
-void
-DMASequencer::testDrainComplete()
-{
- //If we weren't able to drain before, we might be able to now.
- if (drainState() == DrainState::Draining) {
- unsigned int drainCount = outstandingCount();
- DPRINTF(Drain, "Drain count: %u\n", drainCount);
- if (drainCount == 0) {
- DPRINTF(Drain, "DMASequencer done draining, signaling drain done\n");
- signalDrainDone();
- }
- }
-}
-
-DrainState
-DMASequencer::drain()
-{
- if (isDeadlockEventScheduled()) {
- descheduleDeadlockEvent();
- }
-
- // If the DMASequencer is not empty, then it needs to clear all outstanding
- // requests before it should call signalDrainDone()
- DPRINTF(Config, "outstanding count %d\n", outstandingCount());
-
- // Set status
- if (outstandingCount() > 0) {
- DPRINTF(Drain, "DMASequencer not drained\n");
- return DrainState::Draining;
- } else {
- return DrainState::Drained;
- }
-}
-
-void
-DMASequencer::MemSlavePort::hitCallback(PacketPtr pkt)
-{
- bool needsResponse = pkt->needsResponse();
- assert(!pkt->isLLSC());
- assert(!pkt->isFlush());
-
- DPRINTF(RubyDma, "Hit callback needs response %d\n", needsResponse);
-
- // turn packet around to go back to requester if response expected
-
- if (access_backing_store) {
- m_ruby_system->getPhysMem()->access(pkt);
- } else if (needsResponse) {
- pkt->makeResponse();
- }
-
- if (needsResponse) {
- DPRINTF(RubyDma, "Sending packet back over port\n");
- // send next cycle
- DMASequencer *seq = static_cast<DMASequencer *>(&owner);
- RubySystem *rs = seq->m_ruby_system;
- schedTimingResp(pkt, curTick() + rs->clockPeriod());
- } else {
- delete pkt;
- }
-
- DPRINTF(RubyDma, "Hit callback done!\n");
-}
-
-bool
-DMASequencer::MemSlavePort::isPhysMemAddress(Addr addr) const
-{
- DMASequencer *seq = static_cast<DMASequencer *>(&owner);
- return seq->system->isMemAddr(addr);
}
RequestStatus
#include <memory>
#include <ostream>
-#include "mem/mem_object.hh"
#include "mem/protocol/DMASequencerRequestType.hh"
-#include "mem/protocol/RequestStatus.hh"
#include "mem/ruby/common/DataBlock.hh"
-#include "mem/ruby/network/MessageBuffer.hh"
-#include "mem/ruby/system/RubySystem.hh"
-#include "mem/simple_mem.hh"
-#include "mem/tport.hh"
+#include "mem/ruby/system/RubyPort.hh"
#include "params/DMASequencer.hh"
-class AbstractController;
-
struct DMARequest
{
uint64_t start_paddr;
PacketPtr pkt;
};
-class DMASequencer : public MemObject
+class DMASequencer : public RubyPort
{
public:
typedef DMASequencerParams Params;
DMASequencer(const Params *);
void init() override;
- RubySystem *m_ruby_system;
-
- public:
- class MemSlavePort : public QueuedSlavePort
- {
- private:
- RespPacketQueue queue;
- RubySystem* m_ruby_system;
- bool access_backing_store;
-
- public:
- MemSlavePort(const std::string &_name, DMASequencer *_port,
- PortID id, RubySystem *_ruby_system,
- bool _access_backing_store);
- void hitCallback(PacketPtr pkt);
- void evictionCallback(Addr address);
-
- protected:
- bool recvTimingReq(PacketPtr pkt);
-
- Tick recvAtomic(PacketPtr pkt)
- { panic("DMASequencer::MemSlavePort::recvAtomic() not implemented!\n"); }
-
- void recvFunctional(PacketPtr pkt)
- { panic("DMASequencer::MemSlavePort::recvFunctional() not implemented!\n"); }
-
- AddrRangeList getAddrRanges() const
- { AddrRangeList ranges; return ranges; }
-
- private:
- bool isPhysMemAddress(Addr addr) const;
- };
-
- BaseSlavePort &getSlavePort(const std::string &if_name,
- PortID idx = InvalidPortID) override;
/* external interface */
RequestStatus makeRequest(PacketPtr pkt);
bool isDeadlockEventScheduled() const { return false; }
void descheduleDeadlockEvent() {}
- // Called by the controller to give the sequencer a pointer.
- // A pointer to the controller is needed for atomic support.
- void setController(AbstractController* _cntrl) { m_controller = _cntrl; }
- uint32_t getId() { return m_version; }
- DrainState drain() override;
-
/* SLICC callback */
void dataCallback(const DataBlock & dblk);
void ackCallback();
private:
void issueNext();
- void ruby_hit_callback(PacketPtr pkt);
- void testDrainComplete();
-
- /**
- * Called by the PIO port when receiving a timing response.
- *
- * @param pkt Response packet
- * @param master_port_id Port id of the PIO port
- *
- * @return Whether successfully sent
- */
- bool recvTimingResp(PacketPtr pkt, PortID master_port_id);
- unsigned int getChildDrainCount();
-
- private:
- uint32_t m_version;
- AbstractController* m_controller;
- MessageBuffer* m_mandatory_q_ptr;
- bool m_usingRubyTester;
-
- MemSlavePort slave_port;
-
- System* system;
- bool retry;
bool m_is_busy;
uint64_t m_data_block_mask;
DMARequest active_request;