using namespace std;
-SimpleMemory::SimpleMemory(const Params* p) :
+SimpleMemory::SimpleMemory(const SimpleMemoryParams* p) :
AbstractMemory(p),
- lat(p->latency), lat_var(p->latency_var)
+ port(name() + ".port", *this), lat(p->latency),
+ lat_var(p->latency_var), bandwidth(p->bandwidth),
+ isBusy(false), retryReq(false), releaseEvent(this)
{
- for (size_t i = 0; i < p->port_port_connection_count; ++i) {
- ports.push_back(new MemoryPort(csprintf("%s-port-%d", name(), i),
- *this));
- }
}
void
SimpleMemory::init()
{
- for (vector<MemoryPort*>::iterator p = ports.begin(); p != ports.end();
- ++p) {
- if (!(*p)->isConnected()) {
- fatal("SimpleMemory port %s is unconnected!\n", (*p)->name());
- } else {
- (*p)->sendRangeChange();
- }
+ // allow unconnected memories as this is used in several ruby
+ // systems at the moment
+ if (port.isConnected()) {
+ port.sendRangeChange();
}
}
functionalAccess(pkt);
}
-SlavePort &
-SimpleMemory::getSlavePort(const std::string &if_name, int idx)
+bool
+SimpleMemory::recvTimingReq(PacketPtr pkt)
+{
+ /// @todo temporary hack to deal with memory corruption issues until
+ /// 4-phase transactions are complete
+ for (int x = 0; x < pendingDelete.size(); x++)
+ delete pendingDelete[x];
+ pendingDelete.clear();
+
+ if (pkt->memInhibitAsserted()) {
+ // snooper will supply based on copy of packet
+ // still target's responsibility to delete packet
+ pendingDelete.push_back(pkt);
+ return true;
+ }
+
+ // we should never get a new request after committing to retry the
+ // current one, the bus violates the rule as it simply sends a
+ // retry to the next one waiting on the retry list, so simply
+ // ignore it
+ if (retryReq)
+ return false;
+
+ // if we are busy with a read or write, remember that we have to
+ // retry
+ if (isBusy) {
+ retryReq = true;
+ return false;
+ }
+
+ // update the release time according to the bandwidth limit, and
+ // do so with respect to the time it takes to finish this request
+ // rather than long term as it is the short term data rate that is
+ // limited for any real memory
+
+ // only look at reads and writes when determining if we are busy,
+ // and for how long, as it is not clear what to regulate for the
+ // other types of commands
+ if (pkt->isRead() || pkt->isWrite()) {
+ // calculate an appropriate tick to release to not exceed
+ // the bandwidth limit
+ Tick duration = pkt->getSize() * bandwidth;
+
+ // only consider ourselves busy if there is any need to wait
+ // to avoid extra events being scheduled for (infinitely) fast
+ // memories
+ if (duration != 0) {
+ schedule(releaseEvent, curTick() + duration);
+ isBusy = true;
+ }
+ }
+
+ // go ahead and deal with the packet and put the response in the
+ // queue if there is one
+ bool needsResponse = pkt->needsResponse();
+ Tick latency = doAtomicAccess(pkt);
+ // turn packet around to go back to requester if response expected
+ if (needsResponse) {
+ // doAtomicAccess() should already have turned packet into
+ // atomic response
+ assert(pkt->isResponse());
+ port.schedTimingResp(pkt, curTick() + latency);
+ } else {
+ pendingDelete.push_back(pkt);
+ }
+
+ return true;
+}
+
+void
+SimpleMemory::release()
+{
+ assert(isBusy);
+ isBusy = false;
+ if (retryReq) {
+ retryReq = false;
+ port.sendRetry();
+ }
+}
+
+BaseSlavePort &
+SimpleMemory::getSlavePort(const std::string &if_name, PortID idx)
{
if (if_name != "port") {
return MemObject::getSlavePort(if_name, idx);
} else {
- if (idx >= static_cast<int>(ports.size())) {
- fatal("SimpleMemory::getSlavePort: unknown index %d\n", idx);
- }
-
- return *ports[idx];
+ return port;
}
}
unsigned int
-SimpleMemory::drain(Event *de)
+SimpleMemory::drain(DrainManager *dm)
{
- int count = 0;
- for (vector<MemoryPort*>::iterator p = ports.begin(); p != ports.end();
- ++p) {
- count += (*p)->drain(de);
- }
+ int count = port.drain(dm);
if (count)
- changeState(Draining);
+ setDrainState(Drainable::Draining);
else
- changeState(Drained);
+ setDrainState(Drainable::Drained);
return count;
}
SimpleMemory::MemoryPort::MemoryPort(const std::string& _name,
SimpleMemory& _memory)
- : SimpleTimingPort(_name, &_memory), memory(_memory)
+ : QueuedSlavePort(_name, &_memory, queueImpl),
+ queueImpl(_memory, *this), memory(_memory)
{ }
AddrRangeList
pkt->popLabel();
}
+bool
+SimpleMemory::MemoryPort::recvTimingReq(PacketPtr pkt)
+{
+ return memory.recvTimingReq(pkt);
+}
+
SimpleMemory*
SimpleMemoryParams::create()
{