mem: Add tRAS parameter to the DRAM controller model
authorAni Udipi <ani.udipi@arm.com>
Fri, 1 Nov 2013 15:56:16 +0000 (11:56 -0400)
committerAni Udipi <ani.udipi@arm.com>
Fri, 1 Nov 2013 15:56:16 +0000 (11:56 -0400)
This patch adds an explicit tRAS parameter to the DRAM controller
model. Previously tRAS was, rather conservatively, assumed to be tRCD
+ tCL + tRP. The default values for tRAS are chosen to match the
previous behaviour and will be updated later.

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

index 0ce94ba3e38ae9e8c685d584761fe1a121e03389..f75860dce7ac17dd7dbf44500cb1b6fedd92de33 100644 (file)
@@ -114,6 +114,9 @@ class SimpleDRAM(AbstractMemory):
     # minimum time between a precharge and subsequent activate
     tRP = Param.Latency("Row precharge time")
 
+    # minimum time between an activate and a precharge to the same row
+    tRAS = Param.Latency("ACT to PRE delay")
+
     # time to complete a burst transfer, typically the burst length
     # divided by two due to the DDR bus, but by making it a parameter
     # it is easier to also evaluate SDR memories like WideIO.
@@ -140,11 +143,7 @@ class SimpleDRAM(AbstractMemory):
     # Currently rolled into other params
     ######################################################################
 
-    # the minimum amount of time between a row being activated, and
-    # precharged (de-activated)
-    # tRAS - assumed to be 3 * tRP
-
-    # tRC  - assumed to be 4 * tRP
+    # tRC  - assumed to be tRAS + tRP
 
 # A single DDR3 x64 interface (one command and address bus), with
 # default timings based on DDR3-1600 4 Gbit parts in an 8x8
@@ -173,6 +172,7 @@ class DDR3_1600_x64(SimpleDRAM):
     tRCD = '13.75ns'
     tCL = '13.75ns'
     tRP = '13.75ns'
+    tRAS = '41.25ns'
 
     # 8 beats across an x64 interface translates to 4 clocks @ 800 MHz.
     # Note this is a BL8 DDR device.
@@ -224,6 +224,8 @@ class LPDDR2_S4_1066_x32(SimpleDRAM):
     # Pre-charge one bank 15 ns (all banks 18 ns)
     tRP = '15ns'
 
+    tRAS = '45ns'
+
     # 8 beats across an x32 DDR interface translates to 4 clocks @ 533 MHz.
     # Note this is a BL8 DDR device.
     # Requests larger than 32 bytes are broken down into multiple requests
@@ -267,6 +269,7 @@ class WideIO_200_x128(SimpleDRAM):
     tRCD = '18ns'
     tCL = '18ns'
     tRP = '18ns'
+    tRAS = '54ns'
 
     # 4 beats across an x128 SDR interface translates to 4 clocks @ 200 MHz.
     # Note this is a BL4 SDR device.
@@ -314,6 +317,8 @@ class LPDDR3_1600_x32(SimpleDRAM):
     # 12 CK read latency, 6 CK write latency @ 800 MHz, 1.25 ns cycle time
     tCL = '15ns'
 
+    tRAS = '45ns'
+
     # Pre-charge one bank 15 ns (all banks 18 ns)
     tRP = '15ns'
 
index 0deaedcf9c18524f9e525954a35d9dd08689a9e7..c537006a1c2d9530af3df457f74074f2086558a2 100644 (file)
@@ -68,7 +68,7 @@ SimpleDRAM::SimpleDRAM(const SimpleDRAMParams* p) :
     writeBufferSize(p->write_buffer_size),
     writeThresholdPerc(p->write_thresh_perc),
     tWTR(p->tWTR), tBURST(p->tBURST),
-    tRCD(p->tRCD), tCL(p->tCL), tRP(p->tRP),
+    tRCD(p->tRCD), tCL(p->tCL), tRP(p->tRP), tRAS(p->tRAS),
     tRFC(p->tRFC), tREFI(p->tREFI),
     tXAW(p->tXAW), activationLimit(p->activation_limit),
     memSchedPolicy(p->mem_sched_policy), addrMapping(p->addr_mapping),
@@ -382,6 +382,7 @@ SimpleDRAM::processWriteEvent()
 {
     assert(!writeQueue.empty());
     uint32_t numWritesThisTime = 0;
+    Tick actTick;
 
     DPRINTF(DRAMWR, "Beginning DRAM Writes\n");
     Tick temp1 M5_VAR_USED = std::max(curTick(), busBusyUntil);
@@ -422,9 +423,10 @@ SimpleDRAM::processWriteEvent()
             bank.bytesAccessed += burstSize;
 
             if (!rowHitFlag) {
-                bank.tRASDoneAt = bank.freeAt + tRP;
-                recordActivate(bank.freeAt - tCL - tRCD);
-                busBusyUntil = bank.freeAt - tCL - tRCD;
+                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
@@ -432,10 +434,19 @@ SimpleDRAM::processWriteEvent()
                 bank.bytesAccessed = 0;
             }
         } else if (pageMgmt == Enums::close) {
-            bank.freeAt = schedTime + tBURST + accessLat + tRP + tRP;
-            // Work backwards from bank.freeAt to determine activate time
-            recordActivate(bank.freeAt - tRP - tRP - tCL - tRCD);
-            busBusyUntil = bank.freeAt - tRP - tRP - tCL - tRCD;
+            // 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,
@@ -1043,6 +1054,7 @@ SimpleDRAM::doDRAMAccess(DRAMPacket* dram_pkt)
     pair<Tick, Tick> lat = estimateLatency(dram_pkt, curTick());
     Tick bankLat = lat.first;
     Tick accessLat = lat.second;
+    Tick actTick;
 
     // This request was woken up at this time based on a prior call
     // to estimateLatency(). However, between then and now, both the
@@ -1061,22 +1073,28 @@ SimpleDRAM::doDRAMAccess(DRAMPacket* dram_pkt)
         bank.bytesAccessed += burstSize;
 
         // If you activated a new row do to this access, the next access
-        // will have to respect tRAS for this bank. Assume tRAS ~= 3 * tRP.
-        // Also need to account for t_XAW
+        // will have to respect tRAS for this bank.
         if (!rowHitFlag) {
-            bank.tRASDoneAt = bank.freeAt + tRP;
-            recordActivate(bank.freeAt - tCL - tRCD); //since this is open page,
-                                                      //no tRP by default
+            // any waiting for banks account for in freeAt
+            actTick = bank.freeAt - tCL - tRCD;
+            bank.tRASDoneAt = actTick + tRAS;
+            recordActivate(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) { // accounting for tRAS also
-        // assuming that tRAS ~= 3 * tRP, and tRC ~= 4 * tRP, as is common
-        // (refer Jacob/Ng/Wang and Micron datasheets)
-        bank.freeAt = curTick() + addDelay + accessLat + tRP + tRP;
-        recordActivate(bank.freeAt - tRP - tRP - tCL - tRCD); //essentially (freeAt - tRC)
+    } else if (pageMgmt == Enums::close) {
+        actTick = curTick() + addDelay + accessLat - tRCD - tCL;
+        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 + tRCD + tCL + tRP);
+
         DPRINTF(DRAM,"doDRAMAccess::bank.freeAt is %lld\n",bank.freeAt);
         bytesPerActivate.sample(burstSize);
     } else
index abc64c3cd3794ea5ba82e94acbd4878512dd1753..a340a427d3639fe24a0fb5394f062a3a642136e3 100644 (file)
@@ -462,6 +462,7 @@ class SimpleDRAM : public AbstractMemory
     const Tick tRCD;
     const Tick tCL;
     const Tick tRP;
+    const Tick tRAS;
     const Tick tRFC;
     const Tick tREFI;
     const Tick tXAW;