summaryrefslogtreecommitdiff
path: root/src/mem/dram_ctrl.cc
diff options
context:
space:
mode:
authorWendy Elsasser <wendy.elsasser@arm.com>2014-09-20 17:18:21 -0400
committerWendy Elsasser <wendy.elsasser@arm.com>2014-09-20 17:18:21 -0400
commitbf238470726b4cc5c0b34fcb349d767726fe53bc (patch)
treef04c382caae938fe688affbafdbbfdb803a307fd /src/mem/dram_ctrl.cc
parentb6ecfe918364ce4b7df0f95590b483100bbfcba9 (diff)
downloadgem5-bf238470726b4cc5c0b34fcb349d767726fe53bc.tar.xz
mem: Add DDR4 bank group timing
Added the following parameter to the DRAMCtrl class: - bank_groups_per_rank This defaults to 1. For the DDR4 case, the default is overridden to indicate bank group architecture, with multiple bank groups per rank. Added the following delays to the DRAMCtrl class: - tCCD_L : CAS-to-CAS, same bank group delay - tRRD_L : RAS-to-RAS, same bank group delay These parameters are only applied when bank group timing is enabled. Bank group timing is currently enabled only for DDR4 memories. For all other memories, these delays will default to '0 ns' In the DRAM controller model, applied the bank group timing to the per bank parameters actAllowedAt and colAllowedAt. The actAllowedAt will be updated based on bank group when an ACT is issued. The colAllowedAt will be updated based on bank group when a RD/WR burst is issued. At the moment no modifications are made to the scheduling.
Diffstat (limited to 'src/mem/dram_ctrl.cc')
-rw-r--r--src/mem/dram_ctrl.cc127
1 files changed, 101 insertions, 26 deletions
diff --git a/src/mem/dram_ctrl.cc b/src/mem/dram_ctrl.cc
index ca562f4f7..38c240fcf 100644
--- a/src/mem/dram_ctrl.cc
+++ b/src/mem/dram_ctrl.cc
@@ -69,6 +69,8 @@ DRAMCtrl::DRAMCtrl(const DRAMCtrlParams* p) :
columnsPerRowBuffer(rowBufferSize / burstSize),
columnsPerStripe(range.granularity() / burstSize),
ranksPerChannel(p->ranks_per_channel),
+ bankGroupsPerRank(p->bank_groups_per_rank),
+ bankGroupArch(p->bank_groups_per_rank > 0),
banksPerRank(p->banks_per_rank), channels(p->channels), rowsPerBank(0),
readBufferSize(p->read_buffer_size),
writeBufferSize(p->write_buffer_size),
@@ -77,9 +79,9 @@ DRAMCtrl::DRAMCtrl(const DRAMCtrlParams* p) :
minWritesPerSwitch(p->min_writes_per_switch),
writesThisTime(0), readsThisTime(0),
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),
+ tCCD_L(p->tCCD_L), 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),
+ tRRD_L(p->tRRD_L), tXAW(p->tXAW), activationLimit(p->activation_limit),
memSchedPolicy(p->mem_sched_policy), addrMapping(p->addr_mapping),
pageMgmt(p->page_policy),
maxAccessesPerRow(p->max_accesses_per_row),
@@ -104,6 +106,19 @@ DRAMCtrl::DRAMCtrl(const DRAMCtrlParams* p) :
for (int b = 0; b < banksPerRank; b++) {
banks[r][b].rank = r;
banks[r][b].bank = b;
+ if (bankGroupArch) {
+ // Simply assign lower bits to bank group in order to
+ // rotate across bank groups as banks are incremented
+ // e.g. with 4 banks per bank group and 16 banks total:
+ // banks 0,4,8,12 are in bank group 0
+ // 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;
+ } else {
+ // No bank groups; simply assign to bank number
+ banks[r][b].bankgr = b;
+ }
}
}
@@ -168,6 +183,35 @@ DRAMCtrl::DRAMCtrl(const DRAMCtrlParams* p) :
fatal("tREFI (%d) must be larger than tRP (%d) and tRFC (%d)\n",
tREFI, tRP, tRFC);
}
+
+ // basic bank group architecture checks ->
+ if (bankGroupArch) {
+ // must have at least one bank per bank group
+ if (bankGroupsPerRank > banksPerRank) {
+ fatal("banks per rank (%d) must be equal to or larger than "
+ "banks groups per rank (%d)\n",
+ banksPerRank, bankGroupsPerRank);
+ }
+ // must have same number of banks in each bank group
+ if ((banksPerRank % bankGroupsPerRank) != 0) {
+ fatal("Banks per rank (%d) must be evenly divisible by bank groups "
+ "per rank (%d) for equal banks per bank group\n",
+ banksPerRank, bankGroupsPerRank);
+ }
+ // tCCD_L should be greater than minimal, back-to-back burst delay
+ if (tCCD_L <= tBURST) {
+ fatal("tCCD_L (%d) should be larger than tBURST (%d) when "
+ "bank groups per rank (%d) is greater than 1\n",
+ tCCD_L, tBURST, bankGroupsPerRank);
+ }
+ // tRRD_L is greater than minimal, same bank group ACT-to-ACT delay
+ if (tRRD_L <= tRRD) {
+ fatal("tRRD_L (%d) should be larger than tRRD (%d) when "
+ "bank groups per rank (%d) is greater than 1\n",
+ tRRD_L, tRRD, bankGroupsPerRank);
+ }
+ }
+
}
void
@@ -824,14 +868,25 @@ DRAMCtrl::activateBank(Bank& bank, Tick act_tick, uint32_t row)
bank.preAllowedAt = act_tick + tRAS;
// Respect the row-to-column command delay
- bank.colAllowedAt = act_tick + tRCD;
+ bank.colAllowedAt = std::max(act_tick + tRCD, bank.colAllowedAt);
// start by enforcing tRRD
for(int i = 0; i < banksPerRank; i++) {
// next activate to any bank in this rank must not happen
// before tRRD
- banks[rank][i].actAllowedAt = std::max(act_tick + tRRD,
- banks[rank][i].actAllowedAt);
+ if (bankGroupArch && (bank.bankgr == banks[rank][i].bankgr)) {
+ // bank group architecture requires longer delays between
+ // ACT commands within the same bank group. Use tRRD_L
+ // in this case
+ banks[rank][i].actAllowedAt = std::max(act_tick + tRRD_L,
+ banks[rank][i].actAllowedAt);
+ } else {
+ // use shorter tRRD value when either
+ // 1) bank group architecture is not supportted
+ // 2) bank is in a different bank group
+ banks[rank][i].actAllowedAt = std::max(act_tick + tRRD,
+ banks[rank][i].actAllowedAt);
+ }
}
// next, we deal with tXAW, if the activation limit is disabled
@@ -986,9 +1041,38 @@ DRAMCtrl::doDRAMAccess(DRAMPacket* dram_pkt)
// only one burst can use the bus at any one point in time
assert(dram_pkt->readyTime - busBusyUntil >= tBURST);
- // not strictly necessary, but update the time for the next
- // read/write (add a max with tCCD here)
- bank.colAllowedAt = cmd_at + tBURST;
+ // update the time for the next read/write burst for each
+ // bank (add a max with tCCD/tCCD_L here)
+ Tick cmd_dly;
+ for(int j = 0; j < ranksPerChannel; j++) {
+ for(int i = 0; i < banksPerRank; i++) {
+ // next burst to same bank group in this rank must not happen
+ // before tCCD_L. Different bank group timing requirement is
+ // tBURST; Add tCS for different ranks
+ if (dram_pkt->rank == j) {
+ if (bankGroupArch && (bank.bankgr == banks[j][i].bankgr)) {
+ // bank group architecture requires longer delays between
+ // RD/WR burst commands to the same bank group.
+ // Use tCCD_L in this case
+ cmd_dly = tCCD_L;
+ } else {
+ // use tBURST (equivalent to tCCD_S), the shorter
+ // cas-to-cas delay value, when either:
+ // 1) bank group architecture is not supportted
+ // 2) bank is in a different bank group
+ cmd_dly = tBURST;
+ }
+ } else {
+ // different rank is by default in a different bank group
+ // use tBURST (equivalent to tCCD_S), which is the shorter
+ // cas-to-cas delay in this case
+ // Add tCS to account for rank-to-rank bus delay requirements
+ cmd_dly = tBURST + tCS;
+ }
+ banks[j][i].colAllowedAt = std::max(cmd_at + cmd_dly,
+ banks[j][i].colAllowedAt);
+ }
+ }
// Save rank of current access
activeRank = dram_pkt->rank;
@@ -1184,15 +1268,8 @@ DRAMCtrl::processNextReqEvent()
// 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;
+ if (switched_cmd_type && dram_pkt->rank == activeRank) {
+ busBusyUntil += tWTR + tCL;
}
doDRAMAccess(dram_pkt);
@@ -1235,14 +1312,12 @@ DRAMCtrl::processNextReqEvent()
// 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
- busBusyUntil += (dram_pkt->rank == activeRank) ? tRTW : 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;
+ // add a bubble to the data bus, as defined by the
+ // tRTW when access is to the same rank as previous burst
+ // Different rank timing is handled with tCS, which is
+ // applied to colAllowedAt
+ if (switched_cmd_type && dram_pkt->rank == activeRank) {
+ busBusyUntil += tRTW;
}
doDRAMAccess(dram_pkt);