changeset 0fafa62b6c01 in /z/repo/gem5
details: http://repo.gem5.org/gem5?cmd=changeset;node=0fafa62b6c01
description:
        mem: Add memory rank-to-rank delay

        Add the following delay to the DRAM controller:
         - tCS : Different rank bus turnaround delay

        This will be applied for
         1) read-to-read,
         2) write-to-write,
         3) write-to-read, and
         4) read-to-write
        command sequences, where the new command accesses a different rank
        than the previous burst.

        The delay defaults to 2*tCK for each defined memory class. Note that
        this does not correspond to one particular timing constraint, but is a
        way of modelling all the associated constraints.

        The DRAM controller has some minor changes to prioritize commands to
        the same rank. This prioritization will only occur when the command
        stream is not switching from a read to write or vice versa (in the
        case of switching we have a gap in any case).

        To prioritize commands to the same rank, the model will determine if 
there are
        any commands queued (same type) to the same rank as the previous 
command.
        This check will ensure that the 'same rank' command will be able to 
execute
        without adding bubbles to the command flow, e.g. any ACT delay 
requirements
        can be done under the hoods, allowing the burst to issue seamlessly.

diffstat:

 src/mem/DRAMCtrl.py  |   44 +++++++++--
 src/mem/dram_ctrl.cc |  178 +++++++++++++++++++++++++++++++++++---------------
 src/mem/dram_ctrl.hh |   25 ++++++-
 3 files changed, 179 insertions(+), 68 deletions(-)

diffs (truncated from 485 to 300 lines):

diff -r 0100f00a229e -r 0fafa62b6c01 src/mem/DRAMCtrl.py
--- a/src/mem/DRAMCtrl.py       Sat Sep 20 17:17:55 2014 -0400
+++ b/src/mem/DRAMCtrl.py       Sat Sep 20 17:17:57 2014 -0400
@@ -156,11 +156,17 @@
     # to be sent. It is 7.8 us for a 64ms refresh requirement
     tREFI = Param.Latency("Refresh command interval")
 
-    # write-to-read turn around penalty
-    tWTR = Param.Latency("Write to read switching time")
+    # write-to-read, same rank turnaround penalty
+    tWTR = Param.Latency("Write to read, same rank switching time")
 
-    # read-to-write turn around penalty, bus turnaround delay
-    tRTW = Param.Latency("Read to write switching time")
+    # read-to-write, same rank turnaround penalty
+    tRTW = Param.Latency("Read to write, same rank switching time")
+
+    # rank-to-rank bus delay penalty
+    # this does not correlate to a memory timing parameter and encompasses:
+    # 1) RD-to-RD, 2) WR-to-WR, 3) RD-to-WR, and 4) WR-to-RD
+    # different rank bus delay
+    tCS = Param.Latency("Rank to rank switching time")
 
     # minimum row activate to row activate delay time
     tRRD = Param.Latency("ACT to ACT delay")
@@ -221,9 +227,12 @@
     # Greater of 4 CK or 7.5 ns
     tRTP = '7.5ns'
 
-    # Default read-to-write bus around to 2 CK, @800 MHz = 2.5 ns
+    # Default same rank rd-to-wr bus turnaround to 2 CK, @800 MHz = 2.5 ns
     tRTW = '2.5ns'
 
+    # Default different rank bus delay to 2 CK, @800 MHz = 2.5 ns
+    tCS = '2.5ns'
+
     # <=85C, half for >85C
     tREFI = '7.8us'
 
@@ -296,9 +305,12 @@
     # Greater of 4 CK or 7.5 ns
     tRTP = '7.5ns'
 
-    # Default read-to-write bus around to 2 CK, @1200 MHz = 1.666 ns
+    # Default same rank rd-to-wr bus turnaround to 2 CK, @1200 MHz = 1.666 ns
     tRTW = '1.666ns'
 
+    # Default different rank bus delay to 2 CK, @1200 MHz = 1.666 ns
+    tCS = '1.666ns'
+
     # <=85C, half for >85C
     tREFI = '7.8us'
 
@@ -353,9 +365,12 @@
     # Greater of 4 CK or 7.5 ns, 4 CK @ 666.66 MHz = 6 ns
     tWTR = '7.5ns'
 
-    # Default read-to-write bus around to 2 CK, @666.66 MHz = 3 ns
+    # Default same rank rd-to-wr bus turnaround to 2 CK, @666.66 MHz = 3 ns
     tRTW = '3ns'
 
+    # Default different rank bus delay to 2 CK, @666.66 MHz = 3 ns
+    tCS = '3ns'
+
     tRRD = '6.0ns'
 
     tXAW = '30ns'
@@ -416,9 +431,12 @@
     # Irrespective of speed grade, tWTR is 7.5 ns
     tWTR = '7.5ns'
 
-    # Default read-to-write bus around to 2 CK, @533 MHz = 3.75 ns
+    # Default same rank rd-to-wr bus turnaround to 2 CK, @533 MHz = 3.75 ns
     tRTW = '3.75ns'
 
+    # Default different rank bus delay to 2 CK, @533 MHz = 3.75 ns
+    tCS = '3.75ns'
+
     # Activate to activate irrespective of density and speed grade
     tRRD = '10.0ns'
 
@@ -473,9 +491,12 @@
     # Greater of 2 CK or 15 ns, 2 CK @ 200 MHz = 10 ns
     tWTR = '15ns'
 
-    # Default read-to-write bus around to 2 CK, @200 MHz = 10 ns
+    # Default same rank rd-to-wr bus turnaround to 2 CK, @200 MHz = 10 ns
     tRTW = '10ns'
 
+    # Default different rank bus delay to 2 CK, @200 MHz = 10 ns
+    tCS = '10ns'
+
     # Activate to activate irrespective of density and speed grade
     tRRD = '10.0ns'
 
@@ -536,9 +557,12 @@
     # Irrespective of speed grade, tWTR is 7.5 ns
     tWTR = '7.5ns'
 
-    # Default read-to-write bus around to 2 CK, @800 MHz = 2.5 ns
+    # Default same rank rd-to-wr bus turnaround to 2 CK, @800 MHz = 2.5 ns
     tRTW = '2.5ns'
 
+    # Default different rank bus delay to 2 CK, @800 MHz = 2.5 ns
+    tCS = '2.5ns'
+
     # Activate to activate irrespective of density and speed grade
     tRRD = '10.0ns'
 
diff -r 0100f00a229e -r 0fafa62b6c01 src/mem/dram_ctrl.cc
--- a/src/mem/dram_ctrl.cc      Sat Sep 20 17:17:55 2014 -0400
+++ b/src/mem/dram_ctrl.cc      Sat Sep 20 17:17:57 2014 -0400
@@ -76,7 +76,7 @@
     writeLowThreshold(writeBufferSize * p->write_low_thresh_perc / 100.0),
     minWritesPerSwitch(p->min_writes_per_switch),
     writesThisTime(0), readsThisTime(0),
-    tCK(p->tCK), tWTR(p->tWTR), tRTW(p->tRTW), tBURST(p->tBURST),
+    tCK(p->tCK), tWTR(p->tWTR), tRTW(p->tRTW), tCS(p->tCS), tBURST(p->tBURST),
     tRCD(p->tRCD), tCL(p->tCL), tRP(p->tRP), tRAS(p->tRAS), tWR(p->tWR),
     tRTP(p->tRTP), tRFC(p->tRFC), tREFI(p->tREFI), tRRD(p->tRRD),
     tXAW(p->tXAW), activationLimit(p->activation_limit),
@@ -87,7 +87,8 @@
     backendLatency(p->static_backend_latency),
     busBusyUntil(0), refreshDueAt(0), refreshState(REF_IDLE),
     pwrStateTrans(PWR_IDLE), pwrState(PWR_IDLE), prevArrival(0),
-    nextReqTime(0), pwrStateTick(0), numBanksActive(0)
+    nextReqTime(0), pwrStateTick(0), numBanksActive(0),
+    activeRank(0)
 {
     // create the bank states based on the dimensions of the ranks and
     // banks
@@ -683,7 +684,7 @@
 }
 
 void
-DRAMCtrl::chooseNext(std::deque<DRAMPacket*>& queue)
+DRAMCtrl::chooseNext(std::deque<DRAMPacket*>& queue, bool switched_cmd_type)
 {
     // This method does the arbitration between requests. The chosen
     // packet is simply moved to the head of the queue. The other
@@ -699,13 +700,13 @@
     if (memSchedPolicy == Enums::fcfs) {
         // Do nothing, since the correct request is already head
     } else if (memSchedPolicy == Enums::frfcfs) {
-        reorderQueue(queue);
+        reorderQueue(queue, switched_cmd_type);
     } else
         panic("No scheduling policy chosen\n");
 }
 
 void
-DRAMCtrl::reorderQueue(std::deque<DRAMPacket*>& queue)
+DRAMCtrl::reorderQueue(std::deque<DRAMPacket*>& queue, bool switched_cmd_type)
 {
     // Only determine this when needed
     uint64_t earliest_banks = 0;
@@ -713,6 +714,7 @@
     // Search for row hits first, if no row hit is found then schedule the
     // packet to one of the earliest banks available
     bool found_earliest_pkt = false;
+    bool found_prepped_diff_rank_pkt = false;
     auto selected_pkt_it = queue.begin();
 
     for (auto i = queue.begin(); i != queue.end() ; ++i) {
@@ -720,25 +722,30 @@
         const Bank& bank = dram_pkt->bankRef;
         // Check if it is a row hit
         if (bank.openRow == dram_pkt->row) {
-            // FCFS within the hits
-            DPRINTF(DRAM, "Row buffer hit\n");
-            selected_pkt_it = i;
-            break;
-        } else if (!found_earliest_pkt) {
-            // No row hit, go for first ready
+            if (dram_pkt->rank == activeRank || switched_cmd_type) {
+                // FCFS within the hits, giving priority to commands
+                // that access the same rank as the previous burst
+                // to minimize bus turnaround delays
+                // Only give rank prioity when command type is not changing
+                DPRINTF(DRAM, "Row buffer hit\n");
+                selected_pkt_it = i;
+                break;
+            } else if (!found_prepped_diff_rank_pkt) {
+                // found row hit for command on different rank than prev burst
+                selected_pkt_it = i;
+                found_prepped_diff_rank_pkt = true;
+            }
+        } else if (!found_earliest_pkt & !found_prepped_diff_rank_pkt) {
+            // No row hit and
+            // haven't found an entry with a row hit to a new rank
             if (earliest_banks == 0)
-                earliest_banks = minBankActAt(queue);
+                // Determine entries with earliest bank prep delay
+                // Function will give priority to commands that access the
+                // same rank as previous burst and can prep the bank seamlessly
+                earliest_banks = minBankPrep(queue, switched_cmd_type);
 
-            // simplistic approximation of when the bank can issue an
-            // activate, this is calculated in minBankActAt and could
-            // be cached
-            Tick act_at = bank.openRow == Bank::NO_ROW ?
-                bank.actAllowedAt :
-                std::max(bank.preAllowedAt, curTick()) + tRP;
-
-            // Bank is ready or is the first available bank
-            if (act_at <= curTick() ||
-                bits(earliest_banks, dram_pkt->bankId, dram_pkt->bankId)) {
+            // FCFS - Bank is first available bank
+            if (bits(earliest_banks, dram_pkt->bankId, dram_pkt->bankId)) {
                 // Remember the packet to be scheduled to one of the earliest
                 // banks available, FCFS amongst the earliest banks
                 selected_pkt_it = i;
@@ -983,6 +990,9 @@
     // read/write (add a max with tCCD here)
     bank.colAllowedAt = cmd_at + tBURST;
 
+    // Save rank of current access
+    activeRank = dram_pkt->rank;
+
     // If this is a write, we also need to respect the write recovery
     // time before a precharge, in the case of a read, respect the
     // read to precharge constraint
@@ -1095,6 +1105,9 @@
 void
 DRAMCtrl::processNextReqEvent()
 {
+    // pre-emptively set to false.  Overwrite if in READ_TO_WRITE
+    // or WRITE_TO_READ state
+    bool switched_cmd_type = false;
     if (busState == READ_TO_WRITE) {
         DPRINTF(DRAM, "Switching to writes after %d reads with %d reads "
                 "waiting\n", readsThisTime, readQueue.size());
@@ -1106,6 +1119,7 @@
 
         // now proceed to do the actual writes
         busState = WRITE;
+        switched_cmd_type = true;
     } else if (busState == WRITE_TO_READ) {
         DPRINTF(DRAM, "Switching to reads after %d writes with %d writes "
                 "waiting\n", writesThisTime, writeQueue.size());
@@ -1114,6 +1128,7 @@
         writesThisTime = 0;
 
         busState = READ;
+        switched_cmd_type = true;
     }
 
     if (refreshState != REF_IDLE) {
@@ -1160,10 +1175,26 @@
         } else {
             // Figure out which read request goes next, and move it to the
             // front of the read queue
-            chooseNext(readQueue);
+            chooseNext(readQueue, switched_cmd_type);
 
             DRAMPacket* dram_pkt = readQueue.front();
 
+            // here we get a bit creative and shift the bus busy time not
+            // just the tWTR, but also a CAS latency to capture the fact
+            // that we are allowed to prepare a new bank, but not issue a
+            // read command until after tWTR, in essence we capture a
+            // bubble on the data bus that is tWTR + tCL
+            if (switched_cmd_type) {
+                // add a bubble to the data bus for write-to-read turn around
+                // or tCS (different rank bus delay).
+                busBusyUntil += (dram_pkt->rank == activeRank) ? tWTR + tCL :
+                                                                 tCS;
+            } else if (dram_pkt->rank != activeRank) {
+                // add a bubble to the data bus, as defined by the
+                // tCS parameter for rank-to-rank delay
+                busBusyUntil += tCS;
+            }
+
             doDRAMAccess(dram_pkt);
 
             // At this point we're done dealing with the request
@@ -1197,21 +1228,23 @@
         if (switch_to_writes) {
             // transition to writing
             busState = READ_TO_WRITE;
-
-            // add a bubble to the data bus, as defined by the
-            // tRTW parameter
-            busBusyUntil += tRTW;
-
-            // update the minimum timing between the requests,
-            // this shifts us back in time far enough to do any
-            // bank preparation
-            nextReqTime = busBusyUntil - (tRP + tRCD + tCL);
         }
     } else {
-        chooseNext(writeQueue);
+        chooseNext(writeQueue, switched_cmd_type);
         DRAMPacket* dram_pkt = writeQueue.front();
         // sanity check
         assert(dram_pkt->size <= burstSize);
+
+        if (switched_cmd_type) {
+            // add a bubble to the data bus, as defined by the
+            // tRTW or tCS parameter, depending on whether changing ranks
_______________________________________________
gem5-dev mailing list
[email protected]
http://m5sim.org/mailman/listinfo/gem5-dev

Reply via email to