dram_ctrl.cc (12084:5a3769ff3d55) | dram_ctrl.cc (12266:63b8da9eeca4) |
---|---|
1/* 2 * Copyright (c) 2010-2017 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software --- 28 unchanged lines hidden (view full) --- 37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 * 40 * Authors: Andreas Hansson 41 * Ani Udipi 42 * Neha Agarwal 43 * Omar Naji 44 * Wendy Elsasser | 1/* 2 * Copyright (c) 2010-2017 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software --- 28 unchanged lines hidden (view full) --- 37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 * 40 * Authors: Andreas Hansson 41 * Ani Udipi 42 * Neha Agarwal 43 * Omar Naji 44 * Wendy Elsasser |
45 * Radhika Jagtap |
|
45 */ 46 47#include "mem/dram_ctrl.hh" 48 49#include "base/bitfield.hh" 50#include "base/trace.hh" 51#include "debug/DRAM.hh" 52#include "debug/DRAMPower.hh" --- 36 unchanged lines hidden (view full) --- 89 tRRD_L(p->tRRD_L), tXAW(p->tXAW), tXP(p->tXP), tXS(p->tXS), 90 activationLimit(p->activation_limit), 91 memSchedPolicy(p->mem_sched_policy), addrMapping(p->addr_mapping), 92 pageMgmt(p->page_policy), 93 maxAccessesPerRow(p->max_accesses_per_row), 94 frontendLatency(p->static_frontend_latency), 95 backendLatency(p->static_backend_latency), 96 busBusyUntil(0), prevArrival(0), | 46 */ 47 48#include "mem/dram_ctrl.hh" 49 50#include "base/bitfield.hh" 51#include "base/trace.hh" 52#include "debug/DRAM.hh" 53#include "debug/DRAMPower.hh" --- 36 unchanged lines hidden (view full) --- 90 tRRD_L(p->tRRD_L), tXAW(p->tXAW), tXP(p->tXP), tXS(p->tXS), 91 activationLimit(p->activation_limit), 92 memSchedPolicy(p->mem_sched_policy), addrMapping(p->addr_mapping), 93 pageMgmt(p->page_policy), 94 maxAccessesPerRow(p->max_accesses_per_row), 95 frontendLatency(p->static_frontend_latency), 96 backendLatency(p->static_backend_latency), 97 busBusyUntil(0), prevArrival(0), |
97 nextReqTime(0), activeRank(0), timeStampOffset(0) | 98 nextReqTime(0), activeRank(0), timeStampOffset(0), 99 lastStatsResetTick(0) |
98{ 99 // sanity check the ranks since we rely on bit slicing for the 100 // address decoding 101 fatal_if(!isPowerOf2(ranksPerChannel), "DRAM rank count of %d is not " 102 "allowed, must be a power of two\n", ranksPerChannel); 103 104 fatal_if(!isPowerOf2(burstSize), "DRAM burst size %d is not allowed, " 105 "must be a power of two\n", burstSize); --- 631 unchanged lines hidden (view full) --- 737 // FCFS, this method does nothing 738 assert(!queue.empty()); 739 740 // bool to indicate if a packet to an available rank is found 741 bool found_packet = false; 742 if (queue.size() == 1) { 743 DRAMPacket* dram_pkt = queue.front(); 744 // available rank corresponds to state refresh idle | 100{ 101 // sanity check the ranks since we rely on bit slicing for the 102 // address decoding 103 fatal_if(!isPowerOf2(ranksPerChannel), "DRAM rank count of %d is not " 104 "allowed, must be a power of two\n", ranksPerChannel); 105 106 fatal_if(!isPowerOf2(burstSize), "DRAM burst size %d is not allowed, " 107 "must be a power of two\n", burstSize); --- 631 unchanged lines hidden (view full) --- 739 // FCFS, this method does nothing 740 assert(!queue.empty()); 741 742 // bool to indicate if a packet to an available rank is found 743 bool found_packet = false; 744 if (queue.size() == 1) { 745 DRAMPacket* dram_pkt = queue.front(); 746 // available rank corresponds to state refresh idle |
745 if (ranks[dram_pkt->rank]->isAvailable()) { | 747 if (ranks[dram_pkt->rank]->inRefIdleState()) { |
746 found_packet = true; 747 DPRINTF(DRAM, "Single request, going to a free rank\n"); 748 } else { 749 DPRINTF(DRAM, "Single request, going to a busy rank\n"); 750 } 751 return found_packet; 752 } 753 754 if (memSchedPolicy == Enums::fcfs) { 755 // check if there is a packet going to a free rank 756 for (auto i = queue.begin(); i != queue.end() ; ++i) { 757 DRAMPacket* dram_pkt = *i; | 748 found_packet = true; 749 DPRINTF(DRAM, "Single request, going to a free rank\n"); 750 } else { 751 DPRINTF(DRAM, "Single request, going to a busy rank\n"); 752 } 753 return found_packet; 754 } 755 756 if (memSchedPolicy == Enums::fcfs) { 757 // check if there is a packet going to a free rank 758 for (auto i = queue.begin(); i != queue.end() ; ++i) { 759 DRAMPacket* dram_pkt = *i; |
758 if (ranks[dram_pkt->rank]->isAvailable()) { | 760 if (ranks[dram_pkt->rank]->inRefIdleState()) { |
759 queue.erase(i); 760 queue.push_front(dram_pkt); 761 found_packet = true; 762 break; 763 } 764 } 765 } else if (memSchedPolicy == Enums::frfcfs) { 766 found_packet = reorderQueue(queue, extra_col_delay); --- 29 unchanged lines hidden (view full) --- 796 // time we need to issue a column command to be seamless 797 const Tick min_col_at = std::max(busBusyUntil - tCL + extra_col_delay, 798 curTick()); 799 800 for (auto i = queue.begin(); i != queue.end() ; ++i) { 801 DRAMPacket* dram_pkt = *i; 802 const Bank& bank = dram_pkt->bankRef; 803 | 761 queue.erase(i); 762 queue.push_front(dram_pkt); 763 found_packet = true; 764 break; 765 } 766 } 767 } else if (memSchedPolicy == Enums::frfcfs) { 768 found_packet = reorderQueue(queue, extra_col_delay); --- 29 unchanged lines hidden (view full) --- 798 // time we need to issue a column command to be seamless 799 const Tick min_col_at = std::max(busBusyUntil - tCL + extra_col_delay, 800 curTick()); 801 802 for (auto i = queue.begin(); i != queue.end() ; ++i) { 803 DRAMPacket* dram_pkt = *i; 804 const Bank& bank = dram_pkt->bankRef; 805 |
804 // check if rank is available, if not, jump to the next packet 805 if (dram_pkt->rankRef.isAvailable()) { | 806 // check if rank is not doing a refresh and thus is available, if not, 807 // jump to the next packet 808 if (dram_pkt->rankRef.inRefIdleState()) { |
806 // check if it is a row hit 807 if (bank.openRow == dram_pkt->row) { 808 // no additional rank-to-rank or same bank-group 809 // delays, or we switched read/write and might as well 810 // go for the row hit 811 if (bank.colAllowedAt <= min_col_at) { 812 // FCFS within the hits, giving priority to 813 // commands that can issue seamlessly, without --- 449 unchanged lines hidden (view full) --- 1263 } 1264} 1265 1266void 1267DRAMCtrl::processNextReqEvent() 1268{ 1269 int busyRanks = 0; 1270 for (auto r : ranks) { | 809 // check if it is a row hit 810 if (bank.openRow == dram_pkt->row) { 811 // no additional rank-to-rank or same bank-group 812 // delays, or we switched read/write and might as well 813 // go for the row hit 814 if (bank.colAllowedAt <= min_col_at) { 815 // FCFS within the hits, giving priority to 816 // commands that can issue seamlessly, without --- 449 unchanged lines hidden (view full) --- 1266 } 1267} 1268 1269void 1270DRAMCtrl::processNextReqEvent() 1271{ 1272 int busyRanks = 0; 1273 for (auto r : ranks) { |
1271 if (!r->isAvailable()) { | 1274 if (!r->inRefIdleState()) { |
1272 if (r->pwrState != PWR_SREF) { 1273 // rank is busy refreshing 1274 DPRINTF(DRAMState, "Rank %d is not available\n", r->rank); 1275 busyRanks++; 1276 1277 // let the rank know that if it was waiting to drain, it 1278 // is now done and ready to proceed 1279 r->checkDrainDone(); --- 100 unchanged lines hidden (view full) --- 1380 // at this point. There could be writes to the available ranks 1381 // which are above the required threshold. However, to 1382 // avoid adding more complexity to the code, return and wait 1383 // for a refresh event to kick things into action again. 1384 if (!found_read) 1385 return; 1386 1387 DRAMPacket* dram_pkt = readQueue.front(); | 1275 if (r->pwrState != PWR_SREF) { 1276 // rank is busy refreshing 1277 DPRINTF(DRAMState, "Rank %d is not available\n", r->rank); 1278 busyRanks++; 1279 1280 // let the rank know that if it was waiting to drain, it 1281 // is now done and ready to proceed 1282 r->checkDrainDone(); --- 100 unchanged lines hidden (view full) --- 1383 // at this point. There could be writes to the available ranks 1384 // which are above the required threshold. However, to 1385 // avoid adding more complexity to the code, return and wait 1386 // for a refresh event to kick things into action again. 1387 if (!found_read) 1388 return; 1389 1390 DRAMPacket* dram_pkt = readQueue.front(); |
1388 assert(dram_pkt->rankRef.isAvailable()); | 1391 assert(dram_pkt->rankRef.inRefIdleState()); |
1389 1390 // here we get a bit creative and shift the bus busy time not 1391 // just the tWTR, but also a CAS latency to capture the fact 1392 // that we are allowed to prepare a new bank, but not issue a 1393 // read command until after tWTR, in essence we capture a 1394 // bubble on the data bus that is tWTR + tCL 1395 if (switched_cmd_type && dram_pkt->rank == activeRank) { 1396 busBusyUntil += tWTR + tCL; --- 40 unchanged lines hidden (view full) --- 1437 // bool to check if write to free rank is found 1438 bool found_write = false; 1439 1440 // If we are changing command type, incorporate the minimum 1441 // bus turnaround delay 1442 found_write = chooseNext(writeQueue, 1443 switched_cmd_type ? std::min(tRTW, tCS) : 0); 1444 | 1392 1393 // here we get a bit creative and shift the bus busy time not 1394 // just the tWTR, but also a CAS latency to capture the fact 1395 // that we are allowed to prepare a new bank, but not issue a 1396 // read command until after tWTR, in essence we capture a 1397 // bubble on the data bus that is tWTR + tCL 1398 if (switched_cmd_type && dram_pkt->rank == activeRank) { 1399 busBusyUntil += tWTR + tCL; --- 40 unchanged lines hidden (view full) --- 1440 // bool to check if write to free rank is found 1441 bool found_write = false; 1442 1443 // If we are changing command type, incorporate the minimum 1444 // bus turnaround delay 1445 found_write = chooseNext(writeQueue, 1446 switched_cmd_type ? std::min(tRTW, tCS) : 0); 1447 |
1445 // if no writes to an available rank are found then return. 1446 // There could be reads to the available ranks. However, to avoid 1447 // adding more complexity to the code, return at this point and wait 1448 // for a refresh event to kick things into action again. | 1448 // if there are no writes to a rank that is available to service 1449 // requests (i.e. rank is in refresh idle state) are found then 1450 // return. There could be reads to the available ranks. However, to 1451 // avoid adding more complexity to the code, return at this point and 1452 // wait for a refresh event to kick things into action again. |
1449 if (!found_write) 1450 return; 1451 1452 DRAMPacket* dram_pkt = writeQueue.front(); | 1453 if (!found_write) 1454 return; 1455 1456 DRAMPacket* dram_pkt = writeQueue.front(); |
1453 assert(dram_pkt->rankRef.isAvailable()); | 1457 assert(dram_pkt->rankRef.inRefIdleState()); |
1454 // sanity check 1455 assert(dram_pkt->size <= burstSize); 1456 1457 // add a bubble to the data bus, as defined by the 1458 // tRTW when access is to the same rank as previous burst 1459 // Different rank timing is handled with tCS, which is 1460 // applied to colAllowedAt 1461 if (switched_cmd_type && dram_pkt->rank == activeRank) { --- 75 unchanged lines hidden (view full) --- 1537 // Flag condition when bank can be opened without incurring additional 1538 // delay on the data bus 1539 bool hidden_bank_prep = false; 1540 1541 // determine if we have queued transactions targetting the 1542 // bank in question 1543 vector<bool> got_waiting(ranksPerChannel * banksPerRank, false); 1544 for (const auto& p : queue) { | 1458 // sanity check 1459 assert(dram_pkt->size <= burstSize); 1460 1461 // add a bubble to the data bus, as defined by the 1462 // tRTW when access is to the same rank as previous burst 1463 // Different rank timing is handled with tCS, which is 1464 // applied to colAllowedAt 1465 if (switched_cmd_type && dram_pkt->rank == activeRank) { --- 75 unchanged lines hidden (view full) --- 1541 // Flag condition when bank can be opened without incurring additional 1542 // delay on the data bus 1543 bool hidden_bank_prep = false; 1544 1545 // determine if we have queued transactions targetting the 1546 // bank in question 1547 vector<bool> got_waiting(ranksPerChannel * banksPerRank, false); 1548 for (const auto& p : queue) { |
1545 if (p->rankRef.isAvailable()) | 1549 if (p->rankRef.inRefIdleState()) |
1546 got_waiting[p->bankId] = true; 1547 } 1548 1549 // Find command with optimal bank timing 1550 // Will prioritize commands that can issue seamlessly. 1551 for (int i = 0; i < ranksPerChannel; i++) { 1552 for (int j = 0; j < banksPerRank; j++) { 1553 uint16_t bank_id = i * banksPerRank + j; 1554 1555 // if we have waiting requests for the bank, and it is 1556 // amongst the first available, update the mask 1557 if (got_waiting[bank_id]) { 1558 // make sure this rank is not currently refreshing. | 1550 got_waiting[p->bankId] = true; 1551 } 1552 1553 // Find command with optimal bank timing 1554 // Will prioritize commands that can issue seamlessly. 1555 for (int i = 0; i < ranksPerChannel; i++) { 1556 for (int j = 0; j < banksPerRank; j++) { 1557 uint16_t bank_id = i * banksPerRank + j; 1558 1559 // if we have waiting requests for the bank, and it is 1560 // amongst the first available, update the mask 1561 if (got_waiting[bank_id]) { 1562 // make sure this rank is not currently refreshing. |
1559 assert(ranks[i]->isAvailable()); | 1563 assert(ranks[i]->inRefIdleState()); |
1560 // simplistic approximation of when the bank can issue 1561 // an activate, ignoring any rank-to-rank switching 1562 // cost in this calculation 1563 Tick act_at = ranks[i]->banks[j].openRow == Bank::NO_ROW ? 1564 std::max(ranks[i]->banks[j].actAllowedAt, curTick()) : 1565 std::max(ranks[i]->banks[j].preAllowedAt, curTick()) + tRP; 1566 1567 // When is the earliest the R/W burst can issue? --- 605 unchanged lines hidden (view full) --- 2173 2174 // go back to REF event and close banks 2175 refreshState = REF_PRE; 2176 schedule(refreshEvent, curTick()); 2177 } 2178 } else if (pwrState == PWR_IDLE) { 2179 DPRINTF(DRAMState, "All banks precharged\n"); 2180 if (prev_state == PWR_SREF) { | 1564 // simplistic approximation of when the bank can issue 1565 // an activate, ignoring any rank-to-rank switching 1566 // cost in this calculation 1567 Tick act_at = ranks[i]->banks[j].openRow == Bank::NO_ROW ? 1568 std::max(ranks[i]->banks[j].actAllowedAt, curTick()) : 1569 std::max(ranks[i]->banks[j].preAllowedAt, curTick()) + tRP; 1570 1571 // When is the earliest the R/W burst can issue? --- 605 unchanged lines hidden (view full) --- 2177 2178 // go back to REF event and close banks 2179 refreshState = REF_PRE; 2180 schedule(refreshEvent, curTick()); 2181 } 2182 } else if (pwrState == PWR_IDLE) { 2183 DPRINTF(DRAMState, "All banks precharged\n"); 2184 if (prev_state == PWR_SREF) { |
2181 // set refresh state to REF_SREF_EXIT, ensuring isAvailable | 2185 // set refresh state to REF_SREF_EXIT, ensuring inRefIdleState |
2182 // continues to return false during tXS after SREF exit 2183 // Schedule a refresh which kicks things back into action 2184 // when it finishes 2185 refreshState = REF_SREF_EXIT; 2186 schedule(refreshEvent, curTick() + memory.tXS); 2187 } else { 2188 // if we have a pending refresh, and are now moving to 2189 // the idle state, directly transition to a refresh --- 40 unchanged lines hidden (view full) --- 2230 2231void 2232DRAMCtrl::Rank::updatePowerStats() 2233{ 2234 // All commands up to refresh have completed 2235 // flush cmdList to DRAMPower 2236 flushCmdList(); 2237 | 2186 // continues to return false during tXS after SREF exit 2187 // Schedule a refresh which kicks things back into action 2188 // when it finishes 2189 refreshState = REF_SREF_EXIT; 2190 schedule(refreshEvent, curTick() + memory.tXS); 2191 } else { 2192 // if we have a pending refresh, and are now moving to 2193 // the idle state, directly transition to a refresh --- 40 unchanged lines hidden (view full) --- 2234 2235void 2236DRAMCtrl::Rank::updatePowerStats() 2237{ 2238 // All commands up to refresh have completed 2239 // flush cmdList to DRAMPower 2240 flushCmdList(); 2241 |
2238 // update the counters for DRAMPower, passing false to 2239 // indicate that this is not the last command in the 2240 // list. DRAMPower requires this information for the 2241 // correct calculation of the background energy at the end 2242 // of the simulation. Ideally we would want to call this 2243 // function with true once at the end of the 2244 // simulation. However, the discarded energy is extremly 2245 // small and does not effect the final results. 2246 power.powerlib.updateCounters(false); | 2242 // Call the function that calculates window energy at intermediate update 2243 // events like at refresh, stats dump as well as at simulation exit. 2244 // Window starts at the last time the calcWindowEnergy function was called 2245 // and is upto current time. 2246 power.powerlib.calcWindowEnergy(divCeil(curTick(), memory.tCK) - 2247 memory.timeStampOffset); |
2247 | 2248 |
2248 // call the energy function 2249 power.powerlib.calcEnergy(); | 2249 // Get the energy from DRAMPower 2250 Data::MemoryPowerModel::Energy energy = power.powerlib.getEnergy(); |
2250 | 2251 |
2251 // Get the energy and power from DRAMPower 2252 Data::MemoryPowerModel::Energy energy = 2253 power.powerlib.getEnergy(); 2254 Data::MemoryPowerModel::Power rank_power = 2255 power.powerlib.getPower(); | 2252 // The energy components inside the power lib are calculated over 2253 // the window so accumulate into the corresponding gem5 stat 2254 actEnergy += energy.act_energy * memory.devicesPerRank; 2255 preEnergy += energy.pre_energy * memory.devicesPerRank; 2256 readEnergy += energy.read_energy * memory.devicesPerRank; 2257 writeEnergy += energy.write_energy * memory.devicesPerRank; 2258 refreshEnergy += energy.ref_energy * memory.devicesPerRank; 2259 actBackEnergy += energy.act_stdby_energy * memory.devicesPerRank; 2260 preBackEnergy += energy.pre_stdby_energy * memory.devicesPerRank; 2261 actPowerDownEnergy += energy.f_act_pd_energy * memory.devicesPerRank; 2262 prePowerDownEnergy += energy.f_pre_pd_energy * memory.devicesPerRank; 2263 selfRefreshEnergy += energy.sref_energy * memory.devicesPerRank; |
2256 | 2264 |
2257 actEnergy = energy.act_energy * memory.devicesPerRank; 2258 preEnergy = energy.pre_energy * memory.devicesPerRank; 2259 readEnergy = energy.read_energy * memory.devicesPerRank; 2260 writeEnergy = energy.write_energy * memory.devicesPerRank; 2261 refreshEnergy = energy.ref_energy * memory.devicesPerRank; 2262 actBackEnergy = energy.act_stdby_energy * memory.devicesPerRank; 2263 preBackEnergy = energy.pre_stdby_energy * memory.devicesPerRank; 2264 actPowerDownEnergy = energy.f_act_pd_energy * memory.devicesPerRank; 2265 prePowerDownEnergy = energy.f_pre_pd_energy * memory.devicesPerRank; 2266 selfRefreshEnergy = energy.sref_energy * memory.devicesPerRank; 2267 totalEnergy = energy.total_energy * memory.devicesPerRank; 2268 averagePower = rank_power.average_power * memory.devicesPerRank; | 2265 // Accumulate window energy into the total energy. 2266 totalEnergy += energy.window_energy * memory.devicesPerRank; 2267 // Average power must not be accumulated but calculated over the time 2268 // since last stats reset. SimClock::Frequency is tick period not tick 2269 // frequency. 2270 // energy (pJ) 1e-9 2271 // power (mW) = ----------- * ---------- 2272 // time (tick) tick_frequency 2273 averagePower = (totalEnergy.value() / 2274 (curTick() - memory.lastStatsResetTick)) * 2275 (SimClock::Frequency / 1000000000.0); |
2269} 2270 2271void 2272DRAMCtrl::Rank::computeStats() 2273{ | 2276} 2277 2278void 2279DRAMCtrl::Rank::computeStats() 2280{ |
2274 DPRINTF(DRAM,"Computing final stats\n"); | 2281 DPRINTF(DRAM,"Computing stats due to a dump callback\n"); |
2275 | 2282 |
2276 // Force DRAM power to update counters based on time spent in 2277 // current state up to curTick() 2278 cmdList.push_back(Command(MemCommand::NOP, 0, curTick())); 2279 | |
2280 // Update the stats 2281 updatePowerStats(); 2282 2283 // final update of power state times 2284 pwrStateTime[pwrState] += (curTick() - pwrStateTick); 2285 pwrStateTick = curTick(); 2286 2287} 2288 2289void | 2283 // Update the stats 2284 updatePowerStats(); 2285 2286 // final update of power state times 2287 pwrStateTime[pwrState] += (curTick() - pwrStateTick); 2288 pwrStateTick = curTick(); 2289 2290} 2291 2292void |
2293DRAMCtrl::Rank::resetStats() { 2294 // The only way to clear the counters in DRAMPower is to call 2295 // calcWindowEnergy function as that then calls clearCounters. The 2296 // clearCounters method itself is private. 2297 power.powerlib.calcWindowEnergy(divCeil(curTick(), memory.tCK) - 2298 memory.timeStampOffset); 2299 2300} 2301 2302void |
|
2290DRAMCtrl::Rank::regStats() 2291{ 2292 using namespace Stats; 2293 2294 pwrStateTime 2295 .init(6) 2296 .name(name() + ".memoryStateTime") 2297 .desc("Time in different power states"); --- 52 unchanged lines hidden (view full) --- 2350 .name(name() + ".averagePower") 2351 .desc("Core power per rank (mW)"); 2352 2353 totalIdleTime 2354 .name(name() + ".totalIdleTime") 2355 .desc("Total Idle time Per DRAM Rank"); 2356 2357 registerDumpCallback(new RankDumpCallback(this)); | 2303DRAMCtrl::Rank::regStats() 2304{ 2305 using namespace Stats; 2306 2307 pwrStateTime 2308 .init(6) 2309 .name(name() + ".memoryStateTime") 2310 .desc("Time in different power states"); --- 52 unchanged lines hidden (view full) --- 2363 .name(name() + ".averagePower") 2364 .desc("Core power per rank (mW)"); 2365 2366 totalIdleTime 2367 .name(name() + ".totalIdleTime") 2368 .desc("Total Idle time Per DRAM Rank"); 2369 2370 registerDumpCallback(new RankDumpCallback(this)); |
2371 registerResetCallback(new RankResetCallback(this)); |
|
2358} 2359void 2360DRAMCtrl::regStats() 2361{ 2362 using namespace Stats; 2363 2364 AbstractMemory::regStats(); 2365 2366 for (auto r : ranks) { 2367 r->regStats(); 2368 } 2369 | 2372} 2373void 2374DRAMCtrl::regStats() 2375{ 2376 using namespace Stats; 2377 2378 AbstractMemory::regStats(); 2379 2380 for (auto r : ranks) { 2381 r->regStats(); 2382 } 2383 |
2384 registerResetCallback(new MemResetCallback(this)); 2385 |
|
2370 readReqs 2371 .name(name() + ".readReqs") 2372 .desc("Number of read requests accepted"); 2373 2374 writeReqs 2375 .name(name() + ".writeReqs") 2376 .desc("Number of write requests accepted"); 2377 --- 289 unchanged lines hidden (view full) --- 2667} 2668 2669bool 2670DRAMCtrl::allRanksDrained() const 2671{ 2672 // true until proven false 2673 bool all_ranks_drained = true; 2674 for (auto r : ranks) { | 2386 readReqs 2387 .name(name() + ".readReqs") 2388 .desc("Number of read requests accepted"); 2389 2390 writeReqs 2391 .name(name() + ".writeReqs") 2392 .desc("Number of write requests accepted"); 2393 --- 289 unchanged lines hidden (view full) --- 2683} 2684 2685bool 2686DRAMCtrl::allRanksDrained() const 2687{ 2688 // true until proven false 2689 bool all_ranks_drained = true; 2690 for (auto r : ranks) { |
2675 // then verify that the power state is IDLE 2676 // ensuring all banks are closed and rank is not in a low power state 2677 all_ranks_drained = r->inPwrIdleState() && all_ranks_drained; | 2691 // then verify that the power state is IDLE ensuring all banks are 2692 // closed and rank is not in a low power state. Also verify that rank 2693 // is idle from a refresh point of view. 2694 all_ranks_drained = r->inPwrIdleState() && r->inRefIdleState() && 2695 all_ranks_drained; |
2678 } 2679 return all_ranks_drained; 2680} 2681 2682void 2683DRAMCtrl::drainResume() 2684{ 2685 if (!isTimingMode && system()->isTimingMode()) { --- 61 unchanged lines hidden --- | 2696 } 2697 return all_ranks_drained; 2698} 2699 2700void 2701DRAMCtrl::drainResume() 2702{ 2703 if (!isTimingMode && system()->isTimingMode()) { --- 61 unchanged lines hidden --- |