From d4cf009b95d34b75408363bc085c2e9e9de458d9 Mon Sep 17 00:00:00 2001
From: Ani Udipi <ani.udipi@arm.com>
Date: Fri, 1 Nov 2013 11:56:16 -0400
Subject: [PATCH] mem: Add tRAS parameter to the DRAM controller model

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  | 15 ++++++++----
 src/mem/simple_dram.cc | 54 ++++++++++++++++++++++++++++--------------
 src/mem/simple_dram.hh |  1 +
 3 files changed, 47 insertions(+), 23 deletions(-)

diff --git a/src/mem/SimpleDRAM.py b/src/mem/SimpleDRAM.py
index 0ce94ba3e..f75860dce 100644
--- a/src/mem/SimpleDRAM.py
+++ b/src/mem/SimpleDRAM.py
@@ -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'
 
diff --git a/src/mem/simple_dram.cc b/src/mem/simple_dram.cc
index 0deaedcf9..c537006a1 100644
--- a/src/mem/simple_dram.cc
+++ b/src/mem/simple_dram.cc
@@ -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
diff --git a/src/mem/simple_dram.hh b/src/mem/simple_dram.hh
index abc64c3cd..a340a427d 100644
--- a/src/mem/simple_dram.hh
+++ b/src/mem/simple_dram.hh
@@ -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;
-- 
2.30.2