mem: Use the same timing calculation for DRAM read and write
authorAni Udipi <ani.udipi@arm.com>
Fri, 1 Nov 2013 15:56:19 +0000 (11:56 -0400)
committerAni Udipi <ani.udipi@arm.com>
Fri, 1 Nov 2013 15:56:19 +0000 (11:56 -0400)
This patch simplifies the DRAM model by re-using the function that
computes the busy and access time for both reads and writes.

src/mem/SConscript
src/mem/simple_dram.cc
src/mem/simple_dram.hh

index 02d0aee739af436e3ff3b6b657f1554ca7ebf22c..90b49067e8aa424d404e26f427bae9f39b19d482 100644 (file)
@@ -76,7 +76,6 @@ CompoundFlag('Bus', ['BaseBus', 'BusAddrRanges', 'CoherentBus',
 DebugFlag('Bridge')
 DebugFlag('CommMonitor')
 DebugFlag('DRAM')
-DebugFlag('DRAMWR')
 DebugFlag('LLSC')
 DebugFlag('MMU')
 DebugFlag('MemoryAccess')
index 39f320dc5f9adb03bb8ad457528b90ff8e6559d9..62f825395c7d622539db5355351b86576ebf672b 100644 (file)
@@ -44,7 +44,6 @@
 #include "base/trace.hh"
 #include "debug/Drain.hh"
 #include "debug/DRAM.hh"
-#include "debug/DRAMWR.hh"
 #include "mem/simple_dram.hh"
 #include "sim/system.hh"
 
@@ -186,7 +185,7 @@ SimpleDRAM::writeQueueFull(unsigned int neededEntries) const
 }
 
 SimpleDRAM::DRAMPacket*
-SimpleDRAM::decodeAddr(PacketPtr pkt, Addr dramPktAddr, unsigned size)
+SimpleDRAM::decodeAddr(PacketPtr pkt, Addr dramPktAddr, unsigned size, bool isRead)
 {
     // decode the address based on the address mapping scheme, with
     // Ra, Co, Ba and Ch denoting rank, column, bank and channel,
@@ -279,7 +278,7 @@ SimpleDRAM::decodeAddr(PacketPtr pkt, Addr dramPktAddr, unsigned size)
     // create the corresponding DRAM packet with the entry time and
     // ready time set to the current tick, the latter will be updated
     // later
-    return new DRAMPacket(pkt, rank, bank, row, dramPktAddr, size,
+    return new DRAMPacket(pkt, isRead, rank, bank, row, dramPktAddr, size,
                           banks[rank][bank]);
 }
 
@@ -337,7 +336,7 @@ SimpleDRAM::addToReadQueue(PacketPtr pkt, unsigned int pktCount)
                 burst_helper = new BurstHelper(pktCount);
             }
 
-            DRAMPacket* dram_pkt = decodeAddr(pkt, addr, size);
+            DRAMPacket* dram_pkt = decodeAddr(pkt, addr, size, true);
             dram_pkt->burstHelper = burst_helper;
 
             assert(!readQueueFull(1));
@@ -382,92 +381,30 @@ SimpleDRAM::processWriteEvent()
 {
     assert(!writeQueue.empty());
     uint32_t numWritesThisTime = 0;
-    Tick actTick;
 
-    DPRINTF(DRAMWR, "Beginning DRAM Writes\n");
+    DPRINTF(DRAM, "Beginning DRAM Writes\n");
     Tick temp1 M5_VAR_USED = std::max(curTick(), busBusyUntil);
     Tick temp2 M5_VAR_USED = std::max(curTick(), maxBankFreeAt());
 
     // @todo: are there any dangers with the untimed while loop?
     while (!writeQueue.empty()) {
-        if (numWritesThisTime > writeThreshold) {
-            DPRINTF(DRAMWR, "Hit write threshold %d\n", writeThreshold);
+        if (numWritesThisTime >= writeThreshold) {
+            DPRINTF(DRAM, "Hit write threshold %d\n", writeThreshold);
             break;
         }
 
         chooseNextWrite();
         DRAMPacket* dram_pkt = writeQueue.front();
-
         // sanity check
         assert(dram_pkt->size <= burstSize);
-
-        // What's the earliest the request can be put on the bus
-        Tick schedTime = std::max(curTick(), busBusyUntil);
-
-        DPRINTF(DRAMWR, "Asking for latency estimate at %lld\n",
-                schedTime + tBURST);
-
-        pair<Tick, Tick> lat = estimateLatency(dram_pkt, schedTime + tBURST);
-        Tick accessLat = lat.second;
-
-        // look at the rowHitFlag set by estimateLatency
-        if (rowHitFlag)
-            writeRowHits++;
-
-        Bank& bank = dram_pkt->bank_ref;
-
-        if (pageMgmt == Enums::open) {
-            bank.openRow = dram_pkt->row;
-            bank.freeAt = schedTime + tBURST + std::max(accessLat, tCL);
-            busBusyUntil = bank.freeAt - tCL;
-            bank.bytesAccessed += burstSize;
-
-            if (!rowHitFlag) {
-                actTick = bank.freeAt - tCL - tRCD;//new row opened
-                bank.tRASDoneAt = actTick + tRAS;
-                recordActivate(actTick);
-                busBusyUntil = actTick;
-
-                // sample the number of bytes accessed and reset it as
-                // we are now closing this row
-                bytesPerActivate.sample(bank.bytesAccessed);
-                bank.bytesAccessed = 0;
-            }
-        } else if (pageMgmt == Enums::close) {
-            // All ticks waiting for a bank (if required) are included
-            // in accessLat
-            actTick = schedTime + tBURST + accessLat - tCL - tRCD;
-            recordActivate(actTick);
-
-            // If the DRAM has a very quick tRAS, bank can be made free
-            // after consecutive tCL,tRCD,tRP times. In general, however,
-            // an additional wait is required to respect tRAS.
-            bank.freeAt = std::max(actTick + tRAS + tRP,
-                                   actTick + tCL + tRCD + tRP);
-
-            //assuming that DRAM first gets write data, then activates
-            busBusyUntil = actTick;
-            DPRINTF(DRAMWR, "processWriteEvent::bank.freeAt for "
-                    "banks_id %d is %lld\n",
-                    dram_pkt->rank * banksPerRank + dram_pkt->bank,
-                    bank.freeAt);
-            bytesPerActivate.sample(burstSize);
-        } else
-            panic("Unknown page management policy chosen\n");
-
-        DPRINTF(DRAMWR, "Done writing to address %lld\n", dram_pkt->addr);
-
-        DPRINTF(DRAMWR, "schedtime is %lld, tBURST is %lld, "
-                "busbusyuntil is %lld\n",
-                schedTime, tBURST, busBusyUntil);
+        doDRAMAccess(dram_pkt);
 
         writeQueue.pop_front();
         delete dram_pkt;
-
         numWritesThisTime++;
     }
 
-    DPRINTF(DRAMWR, "Completed %d writes, bus busy for %lld ticks,"\
+    DPRINTF(DRAM, "Completed %d writes, bus busy for %lld ticks,"\
             "banks busy for %lld ticks\n", numWritesThisTime,
             busBusyUntil - temp1, maxBankFreeAt() - temp2);
 
@@ -498,6 +435,7 @@ SimpleDRAM::processWriteEvent()
         schedule(nextReqEvent, busBusyUntil);
 }
 
+
 void
 SimpleDRAM::triggerWrites()
 {
@@ -592,7 +530,7 @@ SimpleDRAM::addToWriteQueue(PacketPtr pkt, unsigned int pktCount)
         // if the item was not merged we need to create a new write
         // and enqueue it
         if (!merged) {
-            DRAMPacket* dram_pkt = decodeAddr(pkt, addr, size);
+            DRAMPacket* dram_pkt = decodeAddr(pkt, addr, size, false);
 
             assert(writeQueue.size() < writeBufferSize);
             wrQLenPdf[writeQueue.size()]++;
@@ -836,7 +774,7 @@ SimpleDRAM::chooseNextWrite()
     assert(!writeQueue.empty());
 
     if (writeQueue.size() == 1) {
-        DPRINTF(DRAMWR, "Single write request, nothing to do\n");
+        DPRINTF(DRAM, "Single write request, nothing to do\n");
         return;
     }
 
@@ -849,7 +787,7 @@ SimpleDRAM::chooseNextWrite()
             DRAMPacket* dram_pkt = *i;
             const Bank& bank = dram_pkt->bank_ref;
             if (bank.openRow == dram_pkt->row) { //FR part
-                DPRINTF(DRAMWR, "Write row buffer hit\n");
+                DPRINTF(DRAM, "Write row buffer hit\n");
                 writeQueue.erase(i);
                 writeQueue.push_front(dram_pkt);
                 foundRowHit = true;
@@ -861,7 +799,7 @@ SimpleDRAM::chooseNextWrite()
     } else
         panic("No scheduling policy chosen\n");
 
-    DPRINTF(DRAMWR, "Selected next write request\n");
+    DPRINTF(DRAM, "Selected next write request\n");
 }
 
 bool
@@ -965,7 +903,7 @@ SimpleDRAM::estimateLatency(DRAMPacket* dram_pkt, Tick inTime)
             // penalty beyond waiting for the existing read to complete.
             if (bank.freeAt > inTime) {
                 accLat += bank.freeAt - inTime;
-                bankLat += tBURST;
+                bankLat += 0;
             } else {
                // CAS latency only
                accLat += tCL;
@@ -1124,14 +1062,29 @@ SimpleDRAM::doDRAMAccess(DRAMPacket* dram_pkt)
     DPRINTF(DRAM,"Access time is %lld\n",
             dram_pkt->readyTime - dram_pkt->entryTime);
 
+    if (rowHitFlag) {
+        if(dram_pkt->isRead)
+            readRowHits++;
+         else
+            writeRowHits++;
+    }
+
+    // At this point, commonality between reads and writes ends.
+    // For writes, we are done since we long ago responded to the
+    // requestor. We also don't care about stats for writes. For
+    // reads, we still need to figure out respoding to the requestor,
+    // and capture stats.
+
+    if (!dram_pkt->isRead) {
+        return;
+    }
+
     // Update stats
     totMemAccLat += dram_pkt->readyTime - dram_pkt->entryTime;
     totBankLat += bankLat;
     totBusLat += tBURST;
     totQLat += dram_pkt->readyTime - dram_pkt->entryTime - bankLat - tBURST;
 
-    if (rowHitFlag)
-        readRowHits++;
 
     // At this point we're done dealing with the request
     // It will be moved to a separate response queue with a
index a340a427d3639fe24a0fb5394f062a3a642136e3..edba587747ecf025e62b48b9b7605584d4462dd5 100644 (file)
@@ -198,6 +198,8 @@ class SimpleDRAM : public AbstractMemory
         /** This comes from the outside world */
         const PacketPtr pkt;
 
+        const bool isRead;
+
         /** Will be populated by address decoder */
         const uint8_t rank;
         const uint16_t bank;
@@ -224,12 +226,12 @@ class SimpleDRAM : public AbstractMemory
         BurstHelper* burstHelper;
         Bank& bank_ref;
 
-        DRAMPacket(PacketPtr _pkt, uint8_t _rank, uint16_t _bank,
+        DRAMPacket(PacketPtr _pkt, bool _isRead, uint8_t _rank, uint16_t _bank,
                    uint16_t _row, Addr _addr, unsigned int _size,
                    Bank& _bank_ref)
             : entryTime(curTick()), readyTime(curTick()),
-              pkt(_pkt), rank(_rank), bank(_bank), row(_row), addr(_addr),
-              size(_size), burstHelper(NULL), bank_ref(_bank_ref)
+              pkt(_pkt), isRead(_isRead), rank(_rank), bank(_bank), row(_row),
+              addr(_addr), size(_size), burstHelper(NULL), bank_ref(_bank_ref)
         { }
 
     };
@@ -336,9 +338,10 @@ class SimpleDRAM : public AbstractMemory
      * @param pkt The packet from the outside world
      * @param dramPktAddr The starting address of the DRAM packet
      * @param size The size of the DRAM packet in bytes
+     * @param isRead Is the request for a read or a write to DRAM
      * @return A DRAMPacket pointer with the decoded information
      */
-    DRAMPacket* decodeAddr(PacketPtr pkt, Addr dramPktAddr, unsigned int size);
+    DRAMPacket* decodeAddr(PacketPtr pkt, Addr dramPktAddr, unsigned int size, bool isRead);
 
     /**
      * The memory schduler/arbiter - picks which read request needs to