mem: Add static latency to the DRAM controller
authorAndreas Hansson <andreas.hansson@arm.com>
Thu, 30 May 2013 16:54:12 +0000 (12:54 -0400)
committerAndreas Hansson <andreas.hansson@arm.com>
Thu, 30 May 2013 16:54:12 +0000 (12:54 -0400)
This patch adds a frontend and backend static latency to the DRAM
controller by delaying the responses. Two parameters expressing the
frontend and backend contributions in absolute time are added to the
controller, and the appropriate latency is added to the responses when
adding them to the (infinite) queued port for sending.

For writes and reads that hit in the write buffer, only the frontend
latency is added. For reads that are serviced by the DRAM, the static
latency is the sum of the pipeline latencies of the entire frontend,
backend and PHY. The default values are chosen based on having roughly
10 pipeline stages in total at 500 MHz.

In the future, it would be sensible to make the controller use its
clock and convert these latencies (and a few of the DRAM timings) to
cycles.

src/mem/SimpleDRAM.py
src/mem/simple_dram.cc
src/mem/simple_dram.hh

index 9101de10118cfc15fd4aac215e7ca6abe94571bb..75c5b077b1c0b1062f6a45879ea16a128375e1c1 100644 (file)
@@ -110,6 +110,13 @@ class SimpleDRAM(AbstractMemory):
     addr_mapping = Param.AddrMap('RaBaChCo', "Address mapping policy")
     page_policy = Param.PageManage('open', "Page closure management policy")
 
+    # pipeline latency of the controller and PHY, split into a
+    # frontend part and a backend part, with reads and writes serviced
+    # by the queues only seeing the frontend contribution, and reads
+    # serviced by the memory seeing the sum of the two
+    static_frontend_latency = Param.Latency("10ns", "Static frontend latency")
+    static_backend_latency = Param.Latency("10ns", "Static backend latency")
+
     # the physical organisation of the DRAM
     lines_per_rowbuffer = Param.Unsigned("Row buffer size in cache lines")
     ranks_per_channel = Param.Unsigned("Number of ranks per channel")
index 310530a692625ed3a5290fb4f8dcfa61ed970d28..c549474384108ce6eeaf3b75bf054ddb6ab9c6b2 100644 (file)
@@ -66,6 +66,8 @@ SimpleDRAM::SimpleDRAM(const SimpleDRAMParams* p) :
     tXAW(p->tXAW), activationLimit(p->activation_limit),
     memSchedPolicy(p->mem_sched_policy), addrMapping(p->addr_mapping),
     pageMgmt(p->page_policy),
+    frontendLatency(p->static_frontend_latency),
+    backendLatency(p->static_backend_latency),
     busBusyUntil(0), writeStartTime(0),
     prevArrival(0), numReqs(0)
 {
@@ -294,7 +296,7 @@ SimpleDRAM::addToReadQueue(PacketPtr pkt)
             DPRINTF(DRAM, "Read to %lld serviced by write queue\n", addr);
             bytesRead += bytesPerCacheLine;
             bytesConsumedRd += pkt->getSize();
-            accessAndRespond(pkt);
+            accessAndRespond(pkt, frontendLatency);
             return;
         }
     }
@@ -467,7 +469,7 @@ SimpleDRAM::addToWriteQueue(PacketPtr pkt)
 
     bytesConsumedWr += pkt->getSize();
     bytesWritten += bytesPerCacheLine;
-    accessAndRespond(pkt);
+    accessAndRespond(pkt, frontendLatency);
 
     // If your write buffer is starting to fill up, drain it!
     if (writeQueue.size() > writeThreshold && !stopReads){
@@ -609,7 +611,7 @@ SimpleDRAM::recvTimingReq(PacketPtr pkt)
     } else {
         DPRINTF(DRAM,"Neither read nor write, ignore timing\n");
         neitherReadNorWrite++;
-        accessAndRespond(pkt);
+        accessAndRespond(pkt, 1);
     }
 
     retryRdReq = false;
@@ -628,7 +630,7 @@ SimpleDRAM::processRespondEvent()
      // Actually responds to the requestor
      bytesConsumedRd += pkt->getSize();
      bytesRead += bytesPerCacheLine;
-     accessAndRespond(pkt);
+     accessAndRespond(pkt, frontendLatency + backendLatency);
 
      delete respQueue.front();
      respQueue.pop_front();
@@ -737,7 +739,7 @@ SimpleDRAM::chooseNextRead()
 }
 
 void
-SimpleDRAM::accessAndRespond(PacketPtr pkt)
+SimpleDRAM::accessAndRespond(PacketPtr pkt, Tick static_latency)
 {
     DPRINTF(DRAM, "Responding to Address %lld.. ",pkt->getAddr());
 
@@ -754,9 +756,9 @@ SimpleDRAM::accessAndRespond(PacketPtr pkt)
         // @todo someone should pay for this
         pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
 
-        // queue the packet in the response queue to be sent out the
-        // next tick
-        port.schedTimingResp(pkt, curTick() + 1);
+        // queue the packet in the response queue to be sent out after
+        // the static latency has passed
+        port.schedTimingResp(pkt, curTick() + static_latency);
     } else {
         // @todo the packet is going to be deleted, and the DRAMPacket
         // is still having a pointer to it
index 6521c67682bc6d66b20182be97f9824d8b66a501..920dcf33a0a2763e4d7c86c62b45645bcda71d74 100644 (file)
@@ -265,8 +265,9 @@ class SimpleDRAM : public AbstractMemory
      * world requestor.
      *
      * @param pkt The packet from the outside world
+     * @param static_latency Static latency to add before sending the packet
      */
-    void accessAndRespond(PacketPtr pkt);
+    void accessAndRespond(PacketPtr pkt, Tick static_latency);
 
     /**
      * Address decoder to figure out physical mapping onto ranks,
@@ -409,6 +410,20 @@ class SimpleDRAM : public AbstractMemory
     Enums::AddrMap addrMapping;
     Enums::PageManage pageMgmt;
 
+    /**
+     * Pipeline latency of the controller frontend. The frontend
+     * contribution is added to writes (that complete when they are in
+     * the write buffer) and reads that are serviced the write buffer.
+     */
+    const Tick frontendLatency;
+
+    /**
+     * Pipeline latency of the backend and PHY. Along with the
+     * frontend contribution, this latency is added to reads serviced
+     * by the DRAM.
+     */
+    const Tick backendLatency;
+
     /**
      * Till when has the main data bus been spoken for already?
      */