78c78
< tRCD(p->tRCD), tCL(p->tCL), tRP(p->tRP), tRAS(p->tRAS),
---
> tRCD(p->tRCD), tCL(p->tCL), tRP(p->tRP), tRAS(p->tRAS), tWR(p->tWR),
561a562
> "tWR %d ticks\n" \
564c565
< tRTW, activationLimit, tXAW);
---
> tRTW, tWR, activationLimit, tXAW);
810d810
< Tick potentialActTick;
835,838c835,838
< // Row-buffer miss, need to close existing row
< // once tRAS has expired, then open the new one,
< // then add cas latency.
< Tick freeTime = std::max(bank.tRASDoneAt, bank.freeAt);
---
> // Row-buffer miss, need to potentially close an existing row,
> // then open the new one, then add CAS latency
> Tick free_at = bank.freeAt;
> Tick precharge_delay = 0;
840,841c840,844
< if (freeTime > inTime)
< accLat += freeTime - inTime;
---
> // Check if we first need to precharge
> if (bank.openRow != Bank::NO_ROW) {
> free_at = std::max(bank.preAllowedAt, free_at);
> precharge_delay = tRP;
> }
843,845c846,849
< // If the there is no open row, then there is no precharge
< // delay, otherwise go with tRP
< Tick precharge_delay = bank.openRow == Bank::NO_ROW ? 0 : tRP;
---
> // If the earliest time to issue the command is in the future,
> // add it to the access latency
> if (free_at > inTime)
> accLat += free_at - inTime;
847,850c851,855
< //The bank is free, and you may be able to activate
< potentialActTick = inTime + accLat + precharge_delay;
< if (potentialActTick < bank.actAllowedAt)
< accLat += bank.actAllowedAt - potentialActTick;
---
> // We also need to account for the earliest activation time,
> // and potentially add that as well to the access latency
> Tick act_at = inTime + accLat + precharge_delay;
> if (act_at < bank.actAllowedAt)
> accLat += bank.actAllowedAt - act_at;
863,864c868,869
< DRAMCtrl::recordActivate(Tick act_tick, uint8_t rank, uint8_t bank,
< uint16_t row)
---
> DRAMCtrl::activateBank(Tick act_tick, uint8_t rank, uint8_t bank,
> uint16_t row, Bank& bank_ref)
872,873c877,878
< assert(banks[rank][bank].openRow == Bank::NO_ROW);
< banks[rank][bank].openRow = row;
---
> assert(bank_ref.openRow == Bank::NO_ROW);
> bank_ref.openRow = row;
878,879c883,884
< banks[rank][bank].bytesAccessed = 0;
< banks[rank][bank].rowAccesses = 0;
---
> bank_ref.bytesAccessed = 0;
> bank_ref.rowAccesses = 0;
889,890c894,897
< // next activate must not happen before tRRD
< banks[rank][i].actAllowedAt = act_tick + tRRD;
---
> // 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);
893,897d899
< // tRC should be added to activation tick of the bank currently accessed,
< // where tRC = tRAS + tRP, this is just for a check as actAllowedAt for same
< // bank is already captured by bank.freeAt and bank.tRASDoneAt
< banks[rank][bank].actAllowedAt = act_tick + tRAS + tRP;
<
905,908c907,909
< // @todo For now, stick with a warning
< warn("Got %d activates in window %d (%d - %d) which is smaller "
< "than %d\n", activationLimit, act_tick - actTicks[rank].back(),
< act_tick, actTicks[rank].back(), tXAW);
---
> panic("Got %d activates in window %d (%llu - %llu) which is smaller "
> "than %llu\n", activationLimit, act_tick - actTicks[rank].back(),
> act_tick, actTicks[rank].back(), tXAW);
923c924
< "than %d\n", activationLimit, actTicks[rank].back() + tXAW);
---
> "than %llu\n", activationLimit, actTicks[rank].back() + tXAW);
926c927,929
< banks[rank][j].actAllowedAt = actTicks[rank].back() + tXAW;
---
> banks[rank][j].actAllowedAt =
> std::max(actTicks[rank].back() + tXAW,
> banks[rank][j].actAllowedAt);
1009d1011
<
1012a1015,1025
> // Update request parameters
> dram_pkt->readyTime = curTick() + addDelay + accessLat + tBURST;
>
> DPRINTF(DRAM, "Req %lld: curtick is %lld accessLat is %d " \
> "readytime is %lld busbusyuntil is %lld. " \
> "Scheduling at readyTime\n", dram_pkt->addr,
> curTick(), accessLat, dram_pkt->readyTime, busBusyUntil);
>
> // Make sure requests are not overlapping on the databus
> assert(dram_pkt->readyTime - busBusyUntil >= tBURST);
>
1022c1035
< bank.tRASDoneAt),
---
> bank.preAllowedAt),
1033,1035c1046,1047
< // If you activated a new row do to this access, the next access
< // will have to respect tRAS for this bank
< bank.tRASDoneAt = actTick + tRAS;
---
> // The next access has to respect tRAS for this bank
> bank.preAllowedAt = actTick + tRAS;
1037,1038c1049,1053
< recordActivate(actTick, dram_pkt->rank, dram_pkt->bank,
< dram_pkt->row);
---
> // Record the activation and deal with all the global timing
> // constraints caused be a new activation (tRRD and tXAW)
> activateBank(actTick, dram_pkt->rank, dram_pkt->bank,
> dram_pkt->row, bank);
>
1040a1056,1069
> // If this is a write, we also need to respect the write
> // recovery time before a precharge
> if (!dram_pkt->isRead) {
> bank.preAllowedAt = std::max(bank.preAllowedAt,
> dram_pkt->readyTime + tWR);
> }
>
> // We also have to respect tRP, and any constraints on when we may
> // precharge the bank, in the case of reads this is really only
> // going to cause any change if we did not have a row hit and are
> // now forced to respect tRAS
> bank.actAllowedAt = std::max(bank.actAllowedAt,
> bank.preAllowedAt + tRP);
>
1097c1126
< prechargeBank(bank, std::max(bank.freeAt, bank.tRASDoneAt) + tRP);
---
> prechargeBank(bank, std::max(bank.freeAt, bank.preAllowedAt) + tRP);
1104,1114d1132
< // Update request parameters
< dram_pkt->readyTime = curTick() + addDelay + accessLat + tBURST;
<
< DPRINTF(DRAM, "Req %lld: curtick is %lld accessLat is %d " \
< "readytime is %lld busbusyuntil is %lld. " \
< "Scheduling at readyTime\n", dram_pkt->addr,
< curTick(), accessLat, dram_pkt->readyTime, busBusyUntil);
<
< // Make sure requests are not overlapping on the databus
< assert(dram_pkt->readyTime - busBusyUntil >= tBURST);
<
1415c1433
< banks[i][j].tRASDoneAt),
---
> banks[i][j].preAllowedAt),