changeset bb665366cc00 in /z/repo/gem5
details: http://repo.gem5.org/gem5?cmd=changeset;node=bb665366cc00
description:
        mem: Add rank-wise refresh to the DRAM controller

        This patch adds rank-wise refresh to the controller, as opposed to the
        channel-wide refresh currently in place. In essence each rank can be
        refreshed independently, and for this to be possible the controller
        is extended with a state machine per rank.

        Without this patch the data bus is always idle during a refresh, as
        all the ranks are refreshing at the same time. With the rank-wise
        refresh it is possible to use one rank while another one is
        refreshing, and thus the data bus can be kept busy.

        The patch introduces a Rank class to encapsulate the state per rank,
        and also shifts all the relevant banks, activation tracking etc to the
        rank. The arbitration is also updated to consider the state of the rank.

diffstat:

 src/mem/dram_ctrl.cc |  717 ++++++++++++++++++++++++++++----------------------
 src/mem/dram_ctrl.hh |  360 ++++++++++++++++---------
 2 files changed, 637 insertions(+), 440 deletions(-)

diffs (truncated from 1621 to 300 lines):

diff -r 471d390943f0 -r bb665366cc00 src/mem/dram_ctrl.cc
--- a/src/mem/dram_ctrl.cc      Tue Dec 23 09:31:18 2014 -0500
+++ b/src/mem/dram_ctrl.cc      Tue Dec 23 09:31:18 2014 -0500
@@ -40,6 +40,7 @@
  * Authors: Andreas Hansson
  *          Ani Udipi
  *          Neha Agarwal
+ *          Omar Naji
  */
 
 #include "base/bitfield.hh"
@@ -59,8 +60,7 @@
     port(name() + ".port", *this),
     retryRdReq(false), retryWrReq(false),
     busState(READ),
-    nextReqEvent(this), respondEvent(this), activateEvent(this),
-    prechargeEvent(this), refreshEvent(this), powerEvent(this),
+    nextReqEvent(this), respondEvent(this),
     drainManager(NULL),
     deviceSize(p->device_size),
     deviceBusWidth(p->device_bus_width), burstLength(p->burst_length),
@@ -89,32 +89,19 @@
     maxAccessesPerRow(p->max_accesses_per_row),
     frontendLatency(p->static_frontend_latency),
     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),
-    activeRank(0), timeStampOffset(0)
+    busBusyUntil(0), prevArrival(0),
+    nextReqTime(0), activeRank(0), timeStampOffset(0)
 {
-    // create the bank states based on the dimensions of the ranks and
-    // banks
-    banks.resize(ranksPerChannel);
+    for (int i = 0; i < ranksPerChannel; i++) {
+        Rank* rank = new Rank(*this, p);
+        ranks.push_back(rank);
 
-    //create list of drampower objects. For each rank 1 drampower instance.
-    for (int i = 0; i < ranksPerChannel; i++) {
-        DRAMPower drampower = DRAMPower(p, false);
-        rankPower.emplace_back(drampower);
-    }
+        rank->actTicks.resize(activationLimit, 0);
+        rank->banks.resize(banksPerRank);
+        rank->rank = i;
 
-    actTicks.resize(ranksPerChannel);
-    for (size_t c = 0; c < ranksPerChannel; ++c) {
-        banks[c].resize(banksPerRank);
-        actTicks[c].resize(activationLimit, 0);
-    }
-
-    // set the bank indices
-    for (int r = 0; r < ranksPerChannel; r++) {
         for (int b = 0; b < banksPerRank; b++) {
-            banks[r][b].rank = r;
-            banks[r][b].bank = b;
+            rank->banks[b].bank = b;
             // GDDR addressing of banks to BG is linear.
             // Here we assume that all DRAM generations address bank groups as
             // follows:
@@ -126,10 +113,10 @@
                 //    banks 1,5,9,13  are in bank group 1
                 //    banks 2,6,10,14 are in bank group 2
                 //    banks 3,7,11,15 are in bank group 3
-                banks[r][b].bankgr = b % bankGroupsPerRank;
+                rank->banks[b].bankgr = b % bankGroupsPerRank;
             } else {
                 // No bank groups; simply assign to bank number
-                banks[r][b].bankgr = b;
+                rank->banks[b].bankgr = b;
             }
         }
     }
@@ -254,19 +241,18 @@
 {
     // timestamp offset should be in clock cycles for DRAMPower
     timeStampOffset = divCeil(curTick(), tCK);
+
     // update the start tick for the precharge accounting to the
     // current tick
-    pwrStateTick = curTick();
+    for (auto r : ranks) {
+        r->startup(curTick() + tREFI - tRP);
+    }
 
     // shift the bus busy time sufficiently far ahead that we never
     // have to worry about negative values when computing the time for
     // the next request, this will add an insignificant bubble at the
     // start of simulation
     busBusyUntil = curTick() + tRP + tRCD + tCL;
-
-    // kick off the refresh, and give ourselves enough time to
-    // precharge
-    schedule(refreshEvent, curTick() + tREFI - tRP);
 }
 
 Tick
@@ -411,7 +397,7 @@
     // later
     uint16_t bank_id = banksPerRank * rank + bank;
     return new DRAMPacket(pkt, isRead, rank, bank, row, bank_id, dramPktAddr,
-                          size, banks[rank][bank]);
+                          size, ranks[rank]->banks[bank], *ranks[rank]);
 }
 
 void
@@ -755,7 +741,7 @@
     }
 }
 
-void
+bool
 DRAMCtrl::chooseNext(std::deque<DRAMPacket*>& queue, bool switched_cmd_type)
 {
     // This method does the arbitration between requests. The chosen
@@ -764,20 +750,39 @@
     // FCFS, this method does nothing
     assert(!queue.empty());
 
+    // bool to indicate if a packet to an available rank is found
+    bool found_packet = false;
     if (queue.size() == 1) {
-        DPRINTF(DRAM, "Single request, nothing to do\n");
-        return;
+        DRAMPacket* dram_pkt = queue.front();
+        // available rank corresponds to state refresh idle
+        if (ranks[dram_pkt->rank]->isAvailable()) {
+            found_packet = true;
+            DPRINTF(DRAM, "Single request, going to a free rank\n");
+        } else {
+            DPRINTF(DRAM, "Single request, going to a busy rank\n");
+        }
+        return found_packet;
     }
 
     if (memSchedPolicy == Enums::fcfs) {
-        // Do nothing, since the correct request is already head
+        // check if there is a packet going to a free rank
+        for(auto i = queue.begin(); i != queue.end() ; ++i) {
+            DRAMPacket* dram_pkt = *i;
+            if (ranks[dram_pkt->rank]->isAvailable()) {
+                queue.erase(i);
+                queue.push_front(dram_pkt);
+                found_packet = true;
+                break;
+            }
+        }
     } else if (memSchedPolicy == Enums::frfcfs) {
-        reorderQueue(queue, switched_cmd_type);
+        found_packet = reorderQueue(queue, switched_cmd_type);
     } else
         panic("No scheduling policy chosen\n");
+    return found_packet;
 }
 
-void
+bool
 DRAMCtrl::reorderQueue(std::deque<DRAMPacket*>& queue, bool switched_cmd_type)
 {
     // Only determine this when needed
@@ -785,50 +790,66 @@
 
     // Search for row hits first, if no row hit is found then schedule the
     // packet to one of the earliest banks available
+    bool found_packet = false;
     bool found_earliest_pkt = false;
     bool found_prepped_diff_rank_pkt = false;
-    auto selected_pkt_it = queue.begin();
+    auto selected_pkt_it = queue.end();
 
     for (auto i = queue.begin(); i != queue.end() ; ++i) {
         DRAMPacket* dram_pkt = *i;
         const Bank& bank = dram_pkt->bankRef;
+        // check if rank is busy. If this is the case jump to the next packet
         // Check if it is a row hit
-        if (bank.openRow == dram_pkt->row) {
-            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)
-                // 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);
+        if (dram_pkt->rankRef.isAvailable()) {
+            if (bank.openRow == dram_pkt->row) {
+                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) {
+                // packet going to a rank which is currently not waiting for a
+                // refresh, No row hit and
+                // haven't found an entry with a row hit to a new rank
+                if (earliest_banks == 0)
+                    // 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);
 
-            // 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;
-                found_earliest_pkt = true;
+                // 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;
+                    //if the packet found is going to a rank that is currently
+                    //not busy then update the found_packet to true
+                    found_earliest_pkt = true;
+                }
             }
         }
     }
 
-    DRAMPacket* selected_pkt = *selected_pkt_it;
-    queue.erase(selected_pkt_it);
-    queue.push_front(selected_pkt);
+    if (selected_pkt_it != queue.end()) {
+        DRAMPacket* selected_pkt = *selected_pkt_it;
+        queue.erase(selected_pkt_it);
+        queue.push_front(selected_pkt);
+        found_packet = true;
+    }
+    return found_packet;
 }
 
 void
@@ -864,119 +885,108 @@
 }
 
 void
-DRAMCtrl::activateBank(Bank& bank, Tick act_tick, uint32_t row)
+DRAMCtrl::activateBank(Rank& rank_ref, Bank& bank_ref,
+                       Tick act_tick, uint32_t row)
 {
-    // get the rank index from the bank
-    uint8_t rank = bank.rank;
-
-    assert(actTicks[rank].size() == activationLimit);
+    assert(rank_ref.actTicks.size() == activationLimit);
 
     DPRINTF(DRAM, "Activate at tick %d\n", act_tick);
 
     // update the open row
-    assert(bank.openRow == Bank::NO_ROW);
-    bank.openRow = row;
+    assert(bank_ref.openRow == Bank::NO_ROW);
+    bank_ref.openRow = row;
 
     // start counting anew, this covers both the case when we
     // auto-precharged, and when this access is forced to
     // precharge
-    bank.bytesAccessed = 0;
-    bank.rowAccesses = 0;
+    bank_ref.bytesAccessed = 0;
+    bank_ref.rowAccesses = 0;
 
-    ++numBanksActive;
-    assert(numBanksActive <= banksPerRank * ranksPerChannel);
+    ++rank_ref.numBanksActive;
+    assert(rank_ref.numBanksActive <= banksPerRank);
 
     DPRINTF(DRAM, "Activate bank %d, rank %d at tick %lld, now got %d 
active\n",
-            bank.bank, bank.rank, act_tick, numBanksActive);
+            bank_ref.bank, rank_ref.rank, act_tick,
_______________________________________________
gem5-dev mailing list
gem5-dev@gem5.org
http://m5sim.org/mailman/listinfo/gem5-dev

Reply via email to