dram_ctrl.cc (10889:c4c13fced000) | dram_ctrl.cc (10890:bac38d2a4acb) |
---|---|
1/* 2 * Copyright (c) 2010-2015 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 --- 697 unchanged lines hidden (view full) --- 706 // so if there is a read that was forced to wait, retry now 707 if (retryRdReq) { 708 retryRdReq = false; 709 port.sendRetryReq(); 710 } 711} 712 713bool | 1/* 2 * Copyright (c) 2010-2015 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 --- 697 unchanged lines hidden (view full) --- 706 // so if there is a read that was forced to wait, retry now 707 if (retryRdReq) { 708 retryRdReq = false; 709 port.sendRetryReq(); 710 } 711} 712 713bool |
714DRAMCtrl::chooseNext(std::deque<DRAMPacket*>& queue, bool switched_cmd_type) | 714DRAMCtrl::chooseNext(std::deque<DRAMPacket*>& queue, Tick extra_col_delay) |
715{ 716 // This method does the arbitration between requests. The chosen 717 // packet is simply moved to the head of the queue. The other 718 // methods know that this is the place to look. For example, with 719 // FCFS, this method does nothing 720 assert(!queue.empty()); 721 722 // bool to indicate if a packet to an available rank is found --- 17 unchanged lines hidden (view full) --- 740 if (ranks[dram_pkt->rank]->isAvailable()) { 741 queue.erase(i); 742 queue.push_front(dram_pkt); 743 found_packet = true; 744 break; 745 } 746 } 747 } else if (memSchedPolicy == Enums::frfcfs) { | 715{ 716 // This method does the arbitration between requests. The chosen 717 // packet is simply moved to the head of the queue. The other 718 // methods know that this is the place to look. For example, with 719 // FCFS, this method does nothing 720 assert(!queue.empty()); 721 722 // bool to indicate if a packet to an available rank is found --- 17 unchanged lines hidden (view full) --- 740 if (ranks[dram_pkt->rank]->isAvailable()) { 741 queue.erase(i); 742 queue.push_front(dram_pkt); 743 found_packet = true; 744 break; 745 } 746 } 747 } else if (memSchedPolicy == Enums::frfcfs) { |
748 found_packet = reorderQueue(queue, switched_cmd_type); | 748 found_packet = reorderQueue(queue, extra_col_delay); |
749 } else 750 panic("No scheduling policy chosen\n"); 751 return found_packet; 752} 753 754bool | 749 } else 750 panic("No scheduling policy chosen\n"); 751 return found_packet; 752} 753 754bool |
755DRAMCtrl::reorderQueue(std::deque<DRAMPacket*>& queue, bool switched_cmd_type) | 755DRAMCtrl::reorderQueue(std::deque<DRAMPacket*>& queue, Tick extra_col_delay) |
756{ | 756{ |
757 // Only determine this when needed | 757 // Only determine this if needed |
758 uint64_t earliest_banks = 0; | 758 uint64_t earliest_banks = 0; |
759 bool hidden_bank_prep = false; |
|
759 | 760 |
760 // Search for row hits first, if no row hit is found then schedule the 761 // packet to one of the earliest banks available 762 bool found_packet = false; | 761 // search for seamless row hits first, if no seamless row hit is 762 // found then determine if there are other packets that can be issued 763 // without incurring additional bus delay due to bank timing 764 // Will select closed rows first to enable more open row possibilies 765 // in future selections 766 bool found_hidden_bank = false; 767 768 // remember if we found a row hit, not seamless, but bank prepped 769 // and ready 770 bool found_prepped_pkt = false; 771 772 // if we have no row hit, prepped or not, and no seamless packet, 773 // just go for the earliest possible |
763 bool found_earliest_pkt = false; | 774 bool found_earliest_pkt = false; |
764 bool found_prepped_diff_rank_pkt = false; | 775 |
765 auto selected_pkt_it = queue.end(); 766 | 776 auto selected_pkt_it = queue.end(); 777 |
778 // time we need to issue a column command to be seamless 779 const Tick min_col_at = std::max(busBusyUntil - tCL + extra_col_delay, 780 curTick()); 781 |
|
767 for (auto i = queue.begin(); i != queue.end() ; ++i) { 768 DRAMPacket* dram_pkt = *i; 769 const Bank& bank = dram_pkt->bankRef; | 782 for (auto i = queue.begin(); i != queue.end() ; ++i) { 783 DRAMPacket* dram_pkt = *i; 784 const Bank& bank = dram_pkt->bankRef; |
770 // check if rank is busy. If this is the case jump to the next packet 771 // Check if it is a row hit | 785 786 // check if rank is available, if not, jump to the next packet |
772 if (dram_pkt->rankRef.isAvailable()) { | 787 if (dram_pkt->rankRef.isAvailable()) { |
788 // check if it is a row hit |
|
773 if (bank.openRow == dram_pkt->row) { | 789 if (bank.openRow == dram_pkt->row) { |
774 if (dram_pkt->rank == activeRank || switched_cmd_type) { 775 // FCFS within the hits, giving priority to commands 776 // that access the same rank as the previous burst 777 // to minimize bus turnaround delays 778 // Only give rank prioity when command type is 779 // not changing 780 DPRINTF(DRAM, "Row buffer hit\n"); | 790 // no additional rank-to-rank or same bank-group 791 // delays, or we switched read/write and might as well 792 // go for the row hit 793 if (bank.colAllowedAt <= min_col_at) { 794 // FCFS within the hits, giving priority to 795 // commands that can issue seamlessly, without 796 // additional delay, such as same rank accesses 797 // and/or different bank-group accesses 798 DPRINTF(DRAM, "Seamless row buffer hit\n"); |
781 selected_pkt_it = i; | 799 selected_pkt_it = i; |
800 // no need to look through the remaining queue entries |
|
782 break; | 801 break; |
783 } else if (!found_prepped_diff_rank_pkt) { 784 // found row hit for command on different rank 785 // than prev burst | 802 } else if (!found_hidden_bank && !found_prepped_pkt) { 803 // if we did not find a packet to a closed row that can 804 // issue the bank commands without incurring delay, and 805 // did not yet find a packet to a prepped row, remember 806 // the current one |
786 selected_pkt_it = i; | 807 selected_pkt_it = i; |
787 found_prepped_diff_rank_pkt = true; | 808 found_prepped_pkt = true; 809 DPRINTF(DRAM, "Prepped row buffer hit\n"); |
788 } | 810 } |
789 } else if (!found_earliest_pkt & !found_prepped_diff_rank_pkt) { 790 // packet going to a rank which is currently not waiting for a 791 // refresh, No row hit and 792 // haven't found an entry with a row hit to a new rank 793 if (earliest_banks == 0) 794 // Determine entries with earliest bank prep delay 795 // Function will give priority to commands that access the 796 // same rank as previous burst and can prep 797 // the bank seamlessly 798 earliest_banks = minBankPrep(queue, switched_cmd_type); | 811 } else if (!found_earliest_pkt) { 812 // if we have not initialised the bank status, do it 813 // now, and only once per scheduling decisions 814 if (earliest_banks == 0) { 815 // determine entries with earliest bank delay 816 pair<uint64_t, bool> bankStatus = 817 minBankPrep(queue, min_col_at); 818 earliest_banks = bankStatus.first; 819 hidden_bank_prep = bankStatus.second; 820 } |
799 | 821 |
800 // FCFS - Bank is first available bank 801 if (bits(earliest_banks, dram_pkt->bankId, 802 dram_pkt->bankId)) { 803 // Remember the packet to be scheduled to one of 804 // the earliest banks available, FCFS amongst the 805 // earliest banks 806 selected_pkt_it = i; 807 //if the packet found is going to a rank that is currently 808 //not busy then update the found_packet to true | 822 // bank is amongst first available banks 823 // minBankPrep will give priority to packets that can 824 // issue seamlessly 825 if (bits(earliest_banks, dram_pkt->bankId, dram_pkt->bankId)) { |
809 found_earliest_pkt = true; | 826 found_earliest_pkt = true; |
827 found_hidden_bank = hidden_bank_prep; 828 829 // give priority to packets that can issue 830 // bank commands 'behind the scenes' 831 // any additional delay if any will be due to 832 // col-to-col command requirements 833 if (hidden_bank_prep || !found_prepped_pkt) 834 selected_pkt_it = i; |
|
810 } 811 } 812 } 813 } 814 815 if (selected_pkt_it != queue.end()) { 816 DRAMPacket* selected_pkt = *selected_pkt_it; 817 queue.erase(selected_pkt_it); 818 queue.push_front(selected_pkt); | 835 } 836 } 837 } 838 } 839 840 if (selected_pkt_it != queue.end()) { 841 DRAMPacket* selected_pkt = *selected_pkt_it; 842 queue.erase(selected_pkt_it); 843 queue.push_front(selected_pkt); |
819 found_packet = true; | 844 return true; |
820 } | 845 } |
821 return found_packet; | 846 847 return false; |
822} 823 824void 825DRAMCtrl::accessAndRespond(PacketPtr pkt, Tick static_latency) 826{ 827 DPRINTF(DRAM, "Responding to Address %lld.. ",pkt->getAddr()); 828 829 bool needsResponse = pkt->needsResponse(); --- 456 unchanged lines hidden (view full) --- 1286 return; 1287 } 1288 } else { 1289 // bool to check if there is a read to a free rank 1290 bool found_read = false; 1291 1292 // Figure out which read request goes next, and move it to the 1293 // front of the read queue | 848} 849 850void 851DRAMCtrl::accessAndRespond(PacketPtr pkt, Tick static_latency) 852{ 853 DPRINTF(DRAM, "Responding to Address %lld.. ",pkt->getAddr()); 854 855 bool needsResponse = pkt->needsResponse(); --- 456 unchanged lines hidden (view full) --- 1312 return; 1313 } 1314 } else { 1315 // bool to check if there is a read to a free rank 1316 bool found_read = false; 1317 1318 // Figure out which read request goes next, and move it to the 1319 // front of the read queue |
1294 found_read = chooseNext(readQueue, switched_cmd_type); | 1320 // If we are changing command type, incorporate the minimum 1321 // bus turnaround delay which will be tCS (different rank) case 1322 found_read = chooseNext(readQueue, 1323 switched_cmd_type ? tCS : 0); |
1295 1296 // if no read to an available rank is found then return 1297 // at this point. There could be writes to the available ranks 1298 // which are above the required threshold. However, to 1299 // avoid adding more complexity to the code, return and wait 1300 // for a refresh event to kick things into action again. 1301 if (!found_read) 1302 return; --- 42 unchanged lines hidden (view full) --- 1345 if (switch_to_writes) { 1346 // transition to writing 1347 busState = READ_TO_WRITE; 1348 } 1349 } else { 1350 // bool to check if write to free rank is found 1351 bool found_write = false; 1352 | 1324 1325 // if no read to an available rank is found then return 1326 // at this point. There could be writes to the available ranks 1327 // which are above the required threshold. However, to 1328 // avoid adding more complexity to the code, return and wait 1329 // for a refresh event to kick things into action again. 1330 if (!found_read) 1331 return; --- 42 unchanged lines hidden (view full) --- 1374 if (switch_to_writes) { 1375 // transition to writing 1376 busState = READ_TO_WRITE; 1377 } 1378 } else { 1379 // bool to check if write to free rank is found 1380 bool found_write = false; 1381 |
1353 found_write = chooseNext(writeQueue, switched_cmd_type); | 1382 // If we are changing command type, incorporate the minimum 1383 // bus turnaround delay 1384 found_write = chooseNext(writeQueue, 1385 switched_cmd_type ? std::min(tRTW, tCS) : 0); |
1354 1355 // if no writes to an available rank are found then return. 1356 // There could be reads to the available ranks. However, to avoid 1357 // adding more complexity to the code, return at this point and wait 1358 // for a refresh event to kick things into action again. 1359 if (!found_write) 1360 return; 1361 --- 43 unchanged lines hidden (view full) --- 1405 // cause a nextReqEvent to be scheduled before we do so as part of 1406 // the next request processing 1407 if (retryWrReq && writeQueue.size() < writeBufferSize) { 1408 retryWrReq = false; 1409 port.sendRetryReq(); 1410 } 1411} 1412 | 1386 1387 // if no writes to an available rank are found then return. 1388 // There could be reads to the available ranks. However, to avoid 1389 // adding more complexity to the code, return at this point and wait 1390 // for a refresh event to kick things into action again. 1391 if (!found_write) 1392 return; 1393 --- 43 unchanged lines hidden (view full) --- 1437 // cause a nextReqEvent to be scheduled before we do so as part of 1438 // the next request processing 1439 if (retryWrReq && writeQueue.size() < writeBufferSize) { 1440 retryWrReq = false; 1441 port.sendRetryReq(); 1442 } 1443} 1444 |
1413uint64_t | 1445pair<uint64_t, bool> |
1414DRAMCtrl::minBankPrep(const deque<DRAMPacket*>& queue, | 1446DRAMCtrl::minBankPrep(const deque<DRAMPacket*>& queue, |
1415 bool switched_cmd_type) const | 1447 Tick min_col_at) const |
1416{ 1417 uint64_t bank_mask = 0; 1418 Tick min_act_at = MaxTick; 1419 | 1448{ 1449 uint64_t bank_mask = 0; 1450 Tick min_act_at = MaxTick; 1451 |
1420 uint64_t bank_mask_same_rank = 0; 1421 Tick min_act_at_same_rank = MaxTick; | 1452 // latest Tick for which ACT can occur without incurring additoinal 1453 // delay on the data bus 1454 const Tick hidden_act_max = std::max(min_col_at - tRCD, curTick()); |
1422 | 1455 |
1423 // Give precedence to commands that access same rank as previous command 1424 bool same_rank_match = false; | 1456 // Flag condition when burst can issue back-to-back with previous burst 1457 bool found_seamless_bank = false; |
1425 | 1458 |
1459 // Flag condition when bank can be opened without incurring additional 1460 // delay on the data bus 1461 bool hidden_bank_prep = false; 1462 |
|
1426 // determine if we have queued transactions targetting the 1427 // bank in question 1428 vector<bool> got_waiting(ranksPerChannel * banksPerRank, false); 1429 for (const auto& p : queue) { 1430 if(p->rankRef.isAvailable()) 1431 got_waiting[p->bankId] = true; 1432 } 1433 | 1463 // determine if we have queued transactions targetting the 1464 // bank in question 1465 vector<bool> got_waiting(ranksPerChannel * banksPerRank, false); 1466 for (const auto& p : queue) { 1467 if(p->rankRef.isAvailable()) 1468 got_waiting[p->bankId] = true; 1469 } 1470 |
1471 // Find command with optimal bank timing 1472 // Will prioritize commands that can issue seamlessly. |
|
1434 for (int i = 0; i < ranksPerChannel; i++) { 1435 for (int j = 0; j < banksPerRank; j++) { 1436 uint16_t bank_id = i * banksPerRank + j; 1437 1438 // if we have waiting requests for the bank, and it is 1439 // amongst the first available, update the mask 1440 if (got_waiting[bank_id]) { 1441 // make sure this rank is not currently refreshing. 1442 assert(ranks[i]->isAvailable()); 1443 // simplistic approximation of when the bank can issue 1444 // an activate, ignoring any rank-to-rank switching 1445 // cost in this calculation 1446 Tick act_at = ranks[i]->banks[j].openRow == Bank::NO_ROW ? | 1473 for (int i = 0; i < ranksPerChannel; i++) { 1474 for (int j = 0; j < banksPerRank; j++) { 1475 uint16_t bank_id = i * banksPerRank + j; 1476 1477 // if we have waiting requests for the bank, and it is 1478 // amongst the first available, update the mask 1479 if (got_waiting[bank_id]) { 1480 // make sure this rank is not currently refreshing. 1481 assert(ranks[i]->isAvailable()); 1482 // simplistic approximation of when the bank can issue 1483 // an activate, ignoring any rank-to-rank switching 1484 // cost in this calculation 1485 Tick act_at = ranks[i]->banks[j].openRow == Bank::NO_ROW ? |
1447 ranks[i]->banks[j].actAllowedAt : | 1486 std::max(ranks[i]->banks[j].actAllowedAt, curTick()) : |
1448 std::max(ranks[i]->banks[j].preAllowedAt, curTick()) + tRP; 1449 | 1487 std::max(ranks[i]->banks[j].preAllowedAt, curTick()) + tRP; 1488 |
1450 // prioritize commands that access the 1451 // same rank as previous burst 1452 // Calculate bank mask separately for the case and 1453 // evaluate after loop iterations complete 1454 if (i == activeRank && ranksPerChannel > 1) { 1455 if (act_at <= min_act_at_same_rank) { 1456 // reset same rank bank mask if new minimum is found 1457 // and previous minimum could not immediately send ACT 1458 if (act_at < min_act_at_same_rank && 1459 min_act_at_same_rank > curTick()) 1460 bank_mask_same_rank = 0; | 1489 // When is the earliest the R/W burst can issue? 1490 Tick col_at = std::max(ranks[i]->banks[j].colAllowedAt, 1491 act_at + tRCD); |
1461 | 1492 |
1462 // Set flag indicating that a same rank 1463 // opportunity was found 1464 same_rank_match = true; | 1493 // bank can issue burst back-to-back (seamlessly) with 1494 // previous burst 1495 bool new_seamless_bank = col_at <= min_col_at; |
1465 | 1496 |
1466 // set the bit corresponding to the available bank 1467 replaceBits(bank_mask_same_rank, bank_id, bank_id, 1); 1468 min_act_at_same_rank = act_at; | 1497 // if we found a new seamless bank or we have no 1498 // seamless banks, and got a bank with an earlier 1499 // activate time, it should be added to the bit mask 1500 if (new_seamless_bank || 1501 (!found_seamless_bank && act_at <= min_act_at)) { 1502 // if we did not have a seamless bank before, and 1503 // we do now, reset the bank mask, also reset it 1504 // if we have not yet found a seamless bank and 1505 // the activate time is smaller than what we have 1506 // seen so far 1507 if (!found_seamless_bank && 1508 (new_seamless_bank || act_at < min_act_at)) { 1509 bank_mask = 0; |
1469 } | 1510 } |
1470 } else { 1471 if (act_at <= min_act_at) { 1472 // reset bank mask if new minimum is found 1473 // and either previous minimum could not immediately send ACT 1474 if (act_at < min_act_at && min_act_at > curTick()) 1475 bank_mask = 0; 1476 // set the bit corresponding to the available bank 1477 replaceBits(bank_mask, bank_id, bank_id, 1); 1478 min_act_at = act_at; 1479 } | 1511 1512 found_seamless_bank |= new_seamless_bank; 1513 1514 // ACT can occur 'behind the scenes' 1515 hidden_bank_prep = act_at <= hidden_act_max; 1516 1517 // set the bit corresponding to the available bank 1518 replaceBits(bank_mask, bank_id, bank_id, 1); 1519 min_act_at = act_at; |
1480 } 1481 } 1482 } 1483 } 1484 | 1520 } 1521 } 1522 } 1523 } 1524 |
1485 // Determine the earliest time when the next burst can issue based 1486 // on the current busBusyUntil delay. 1487 // Offset by tRCD to correlate with ACT timing variables 1488 Tick min_cmd_at = busBusyUntil - tCL - tRCD; 1489 1490 // if we have multiple ranks and all 1491 // waiting packets are accessing a rank which was previously active 1492 // then bank_mask_same_rank will be set to a value while bank_mask will 1493 // remain 0. In this case, the function should return the value of 1494 // bank_mask_same_rank. 1495 // else if waiting packets access a rank which was previously active and 1496 // other ranks, prioritize same rank accesses that can issue B2B 1497 // Only optimize for same ranks when the command type 1498 // does not change; do not want to unnecessarily incur tWTR 1499 // 1500 // Resulting FCFS prioritization Order is: 1501 // 1) Commands that access the same rank as previous burst 1502 // and can prep the bank seamlessly. 1503 // 2) Commands (any rank) with earliest bank prep 1504 if ((bank_mask == 0) || (!switched_cmd_type && same_rank_match && 1505 min_act_at_same_rank <= min_cmd_at)) { 1506 bank_mask = bank_mask_same_rank; 1507 } 1508 1509 return bank_mask; | 1525 return make_pair(bank_mask, hidden_bank_prep); |
1510} 1511 1512DRAMCtrl::Rank::Rank(DRAMCtrl& _memory, const DRAMCtrlParams* _p) 1513 : EventManager(&_memory), memory(_memory), 1514 pwrStateTrans(PWR_IDLE), pwrState(PWR_IDLE), pwrStateTick(0), 1515 refreshState(REF_IDLE), refreshDueAt(0), 1516 power(_p, false), numBanksActive(0), 1517 activateEvent(*this), prechargeEvent(*this), --- 729 unchanged lines hidden --- | 1526} 1527 1528DRAMCtrl::Rank::Rank(DRAMCtrl& _memory, const DRAMCtrlParams* _p) 1529 : EventManager(&_memory), memory(_memory), 1530 pwrStateTrans(PWR_IDLE), pwrState(PWR_IDLE), pwrStateTick(0), 1531 refreshState(REF_IDLE), refreshDueAt(0), 1532 power(_p, false), numBanksActive(0), 1533 activateEvent(*this), prechargeEvent(*this), --- 729 unchanged lines hidden --- |