1 Star 0 Fork 0

chisuhua/DRAMSim2

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
CommandQueue.cpp 20.67 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763
/*********************************************************************************
* Copyright (c) 2010-2011, Elliott Cooper-Balis
* Paul Rosenfeld
* Bruce Jacob
* University of Maryland
* dramninjas [at] gmail [dot] com
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*********************************************************************************/
//CommandQueue.cpp
//
//Class file for command queue object
//
#include "CommandQueue.h"
#include "MemoryController.h"
#include <assert.h>
using namespace DRAMSim;
CommandQueue::CommandQueue(vector< vector<BankState> > &states, ostream &dramsim_log_) :
dramsim_log(dramsim_log_),
bankStates(states),
nextBank(0),
nextRank(0),
nextBankPRE(0),
nextRankPRE(0),
refreshRank(0),
refreshWaiting(false),
sendAct(true)
{
//set here to avoid compile errors
currentClockCycle = 0;
//use numBankQueus below to create queue structure
size_t numBankQueues;
if (queuingStructure==PerRank)
{
numBankQueues = 1;
}
else if (queuingStructure==PerRankPerBank)
{
numBankQueues = NUM_BANKS;
}
else
{
ERROR("== Error - Unknown queuing structure");
exit(0);
}
//vector of counters used to ensure rows don't stay open too long
rowAccessCounters = vector< vector<unsigned> >(NUM_RANKS, vector<unsigned>(NUM_BANKS,0));
//create queue based on the structure we want
BusPacket1D actualQueue;
BusPacket2D perBankQueue = BusPacket2D();
queues = BusPacket3D();
for (size_t rank=0; rank<NUM_RANKS; rank++)
{
//this loop will run only once for per-rank and NUM_BANKS times for per-rank-per-bank
for (size_t bank=0; bank<numBankQueues; bank++)
{
actualQueue = BusPacket1D();
perBankQueue.push_back(actualQueue);
}
queues.push_back(perBankQueue);
}
//FOUR-bank activation window
// this will count the number of activations within a given window
// (decrementing counter)
//
//countdown vector will have decrementing counters starting at tFAW
// when the 0th element reaches 0, remove it
tFAWCountdown.reserve(NUM_RANKS);
for (size_t i=0;i<NUM_RANKS;i++)
{
//init the empty vectors here so we don't seg fault later
tFAWCountdown.push_back(vector<unsigned>());
}
}
CommandQueue::~CommandQueue()
{
//ERROR("COMMAND QUEUE destructor");
size_t bankMax = NUM_RANKS;
if (queuingStructure == PerRank) {
bankMax = 1;
}
for (size_t r=0; r< NUM_RANKS; r++)
{
for (size_t b=0; b<bankMax; b++)
{
for (size_t i=0; i<queues[r][b].size(); i++)
{
delete(queues[r][b][i]);
}
queues[r][b].clear();
}
}
}
//Adds a command to appropriate queue
void CommandQueue::enqueue(BusPacket *newBusPacket)
{
unsigned rank = newBusPacket->rank;
unsigned bank = newBusPacket->bank;
if (queuingStructure==PerRank)
{
queues[rank][0].push_back(newBusPacket);
if (queues[rank][0].size()>CMD_QUEUE_DEPTH)
{
ERROR("== Error - Enqueued more than allowed in command queue");
ERROR(" Need to call .hasRoomFor(int numberToEnqueue, unsigned rank, unsigned bank) first");
exit(0);
}
}
else if (queuingStructure==PerRankPerBank)
{
queues[rank][bank].push_back(newBusPacket);
if (queues[rank][bank].size()>CMD_QUEUE_DEPTH)
{
ERROR("== Error - Enqueued more than allowed in command queue");
ERROR(" Need to call .hasRoomFor(int numberToEnqueue, unsigned rank, unsigned bank) first");
exit(0);
}
}
else
{
ERROR("== Error - Unknown queuing structure");
exit(0);
}
}
//Removes the next item from the command queue based on the system's
//command scheduling policy
bool CommandQueue::pop(BusPacket **busPacket)
{
//this can be done here because pop() is called every clock cycle by the parent MemoryController
// figures out the sliding window requirement for tFAW
//
//deal with tFAW book-keeping
// each rank has it's own counter since the restriction is on a device level
for (size_t i=0;i<NUM_RANKS;i++)
{
//decrement all the counters we have going
for (size_t j=0;j<tFAWCountdown[i].size();j++)
{
tFAWCountdown[i][j]--;
}
//the head will always be the smallest counter, so check if it has reached 0
if (tFAWCountdown[i].size()>0 && tFAWCountdown[i][0]==0)
{
tFAWCountdown[i].erase(tFAWCountdown[i].begin());
}
}
/* Now we need to find a packet to issue. When the code picks a packet, it will set
*busPacket = [some eligible packet]
First the code looks if any refreshes need to go
Then it looks for data packets
Otherwise, it starts looking for rows to close (in open page)
*/
if (rowBufferPolicy==ClosePage)
{
bool sendingREF = false;
//if the memory controller set the flags signaling that we need to issue a refresh
if (refreshWaiting)
{
bool foundActiveOrTooEarly = false;
//look for an open bank
for (size_t b=0;b<NUM_BANKS;b++)
{
vector<BusPacket *> &queue = getCommandQueue(refreshRank,b);
//checks to make sure that all banks are idle
if (bankStates[refreshRank][b].currentBankState == RowActive)
{
foundActiveOrTooEarly = true;
//if the bank is open, make sure there is nothing else
// going there before we close it
for (size_t j=0;j<queue.size();j++)
{
BusPacket *packet = queue[j];
if (packet->row == bankStates[refreshRank][b].openRowAddress &&
packet->bank == b)
{
if (packet->busPacketType != ACTIVATE && isIssuable(packet))
{
*busPacket = packet;
queue.erase(queue.begin() + j);
sendingREF = true;
}
break;
}
}
break;
}
// NOTE: checks nextActivate time for each bank to make sure tRP is being
// satisfied. the next ACT and next REF can be issued at the same
// point in the future, so just use nextActivate field instead of
// creating a nextRefresh field
else if (bankStates[refreshRank][b].nextActivate > currentClockCycle)
{
foundActiveOrTooEarly = true;
break;
}
}
//if there are no open banks and timing has been met, send out the refresh
// reset flags and rank pointer
if (!foundActiveOrTooEarly && bankStates[refreshRank][0].currentBankState != PowerDown)
{
*busPacket = new BusPacket(REFRESH, 0, 0, 0, refreshRank, 0, 0, dramsim_log);
refreshRank = -1;
refreshWaiting = false;
sendingREF = true;
}
} // refreshWaiting
//if we're not sending a REF, proceed as normal
if (!sendingREF)
{
bool foundIssuable = false;
unsigned startingRank = nextRank;
unsigned startingBank = nextBank;
do
{
vector<BusPacket *> &queue = getCommandQueue(nextRank, nextBank);
//make sure there is something in this queue first
// also make sure a rank isn't waiting for a refresh
// if a rank is waiting for a refesh, don't issue anything to it until the
// refresh logic above has sent one out (ie, letting banks close)
if (!queue.empty() && !((nextRank == refreshRank) && refreshWaiting))
{
if (queuingStructure == PerRank)
{
//search from beginning to find first issuable bus packet
for (size_t i=0;i<queue.size();i++)
{
if (isIssuable(queue[i]))
{
//check to make sure we aren't removing a read/write that is paired with an activate
if (i>0 && queue[i-1]->busPacketType==ACTIVATE &&
queue[i-1]->physicalAddress == queue[i]->physicalAddress)
continue;
*busPacket = queue[i];
queue.erase(queue.begin()+i);
foundIssuable = true;
break;
}
}
}
else
{
if (isIssuable(queue[0]))
{
//no need to search because if the front can't be sent,
// then no chance something behind it can go instead
*busPacket = queue[0];
queue.erase(queue.begin());
foundIssuable = true;
}
}
}
//if we found something, break out of do-while
if (foundIssuable) break;
//rank round robin
if (queuingStructure == PerRank)
{
nextRank = (nextRank + 1) % NUM_RANKS;
if (startingRank == nextRank)
{
break;
}
}
else
{
nextRankAndBank(nextRank, nextBank);
if (startingRank == nextRank && startingBank == nextBank)
{
break;
}
}
}
while (true);
//if we couldn't find anything to send, return false
if (!foundIssuable) return false;
}
}
else if (rowBufferPolicy==OpenPage)
{
bool sendingREForPRE = false;
if (refreshWaiting)
{
bool sendREF = true;
//make sure all banks idle and timing met for a REF
for (size_t b=0;b<NUM_BANKS;b++)
{
//if a bank is active we can't send a REF yet
if (bankStates[refreshRank][b].currentBankState == RowActive)
{
sendREF = false;
bool closeRow = true;
//search for commands going to an open row
vector <BusPacket *> &refreshQueue = getCommandQueue(refreshRank,b);
for (size_t j=0;j<refreshQueue.size();j++)
{
BusPacket *packet = refreshQueue[j];
//if a command in the queue is going to the same row . . .
if (bankStates[refreshRank][b].openRowAddress == packet->row &&
b == packet->bank)
{
// . . . and is not an activate . . .
if (packet->busPacketType != ACTIVATE)
{
closeRow = false;
// . . . and can be issued . . .
if (isIssuable(packet))
{
//send it out
*busPacket = packet;
refreshQueue.erase(refreshQueue.begin()+j);
sendingREForPRE = true;
}
break;
}
else //command is an activate
{
//if we've encountered another act, no other command will be of interest
break;
}
}
}
//if the bank is open and we are allowed to close it, then send a PRE
if (closeRow && currentClockCycle >= bankStates[refreshRank][b].nextPrecharge)
{
rowAccessCounters[refreshRank][b]=0;
*busPacket = new BusPacket(PRECHARGE, 0, 0, 0, refreshRank, b, 0, dramsim_log);
sendingREForPRE = true;
}
break;
}
// NOTE: the next ACT and next REF can be issued at the same
// point in the future, so just use nextActivate field instead of
// creating a nextRefresh field
else if (bankStates[refreshRank][b].nextActivate > currentClockCycle) //and this bank doesn't have an open row
{
sendREF = false;
break;
}
}
//if there are no open banks and timing has been met, send out the refresh
// reset flags and rank pointer
if (sendREF && bankStates[refreshRank][0].currentBankState != PowerDown)
{
*busPacket = new BusPacket(REFRESH, 0, 0, 0, refreshRank, 0, 0, dramsim_log);
refreshRank = -1;
refreshWaiting = false;
sendingREForPRE = true;
}
}
if (!sendingREForPRE)
{
unsigned startingRank = nextRank;
unsigned startingBank = nextBank;
bool foundIssuable = false;
do // round robin over queues
{
vector<BusPacket *> &queue = getCommandQueue(nextRank,nextBank);
//make sure there is something there first
if (!queue.empty() && !((nextRank == refreshRank) && refreshWaiting))
{
//search from the beginning to find first issuable bus packet
for (size_t i=0;i<queue.size();i++)
{
BusPacket *packet = queue[i];
if (isIssuable(packet))
{
//check for dependencies
bool dependencyFound = false;
for (size_t j=0;j<i;j++)
{
BusPacket *prevPacket = queue[j];
if (prevPacket->busPacketType != ACTIVATE &&
prevPacket->bank == packet->bank &&
prevPacket->row == packet->row)
{
dependencyFound = true;
break;
}
}
if (dependencyFound) continue;
*busPacket = packet;
//if the bus packet before is an activate, that is the act that was
// paired with the column access we are removing, so we have to remove
// that activate as well (check i>0 because if i==0 then theres nothing before it)
if (i>0 && queue[i-1]->busPacketType == ACTIVATE)
{
rowAccessCounters[(*busPacket)->rank][(*busPacket)->bank]++;
// i is being returned, but i-1 is being thrown away, so must delete it here
delete (queue[i-1]);
// remove both i-1 (the activate) and i (we've saved the pointer in *busPacket)
queue.erase(queue.begin()+i-1,queue.begin()+i+1);
}
else // there's no activate before this packet
{
//or just remove the one bus packet
queue.erase(queue.begin()+i);
}
foundIssuable = true;
break;
}
}
}
//if we found something, break out of do-while
if (foundIssuable) break;
//rank round robin
if (queuingStructure == PerRank)
{
nextRank = (nextRank + 1) % NUM_RANKS;
if (startingRank == nextRank)
{
break;
}
}
else
{
nextRankAndBank(nextRank, nextBank);
if (startingRank == nextRank && startingBank == nextBank)
{
break;
}
}
}
while (true);
//if nothing was issuable, see if we can issue a PRE to an open bank
// that has no other commands waiting
if (!foundIssuable)
{
//search for banks to close
bool sendingPRE = false;
unsigned startingRank = nextRankPRE;
unsigned startingBank = nextBankPRE;
do // round robin over all ranks and banks
{
vector <BusPacket *> &queue = getCommandQueue(nextRankPRE, nextBankPRE);
bool found = false;
//check if bank is open
if (bankStates[nextRankPRE][nextBankPRE].currentBankState == RowActive)
{
for (size_t i=0;i<queue.size();i++)
{
//if there is something going to that bank and row, then we don't want to send a PRE
if (queue[i]->bank == nextBankPRE &&
queue[i]->row == bankStates[nextRankPRE][nextBankPRE].openRowAddress)
{
found = true;
break;
}
}
//if nothing found going to that bank and row or too many accesses have happend, close it
if (!found || rowAccessCounters[nextRankPRE][nextBankPRE]==TOTAL_ROW_ACCESSES)
{
if (currentClockCycle >= bankStates[nextRankPRE][nextBankPRE].nextPrecharge)
{
sendingPRE = true;
rowAccessCounters[nextRankPRE][nextBankPRE] = 0;
*busPacket = new BusPacket(PRECHARGE, 0, 0, 0, nextRankPRE, nextBankPRE, 0, dramsim_log);
break;
}
}
}
nextRankAndBank(nextRankPRE, nextBankPRE);
}
while (!(startingRank == nextRankPRE && startingBank == nextBankPRE));
//if no PREs could be sent, just return false
if (!sendingPRE) return false;
}
}
}
//sendAct is flag used for posted-cas
// posted-cas is enabled when AL>0
// when sendAct is true, when don't want to increment our indexes
// so we send the column access that is paid with this act
if (AL>0 && sendAct)
{
sendAct = false;
}
else
{
sendAct = true;
nextRankAndBank(nextRank, nextBank);
}
//if its an activate, add a tfaw counter
if ((*busPacket)->busPacketType==ACTIVATE)
{
tFAWCountdown[(*busPacket)->rank].push_back(tFAW);
}
return true;
}
//check if a rank/bank queue has room for a certain number of bus packets
bool CommandQueue::hasRoomFor(unsigned numberToEnqueue, unsigned rank, unsigned bank)
{
vector<BusPacket *> &queue = getCommandQueue(rank, bank);
return (CMD_QUEUE_DEPTH - queue.size() >= numberToEnqueue);
}
//prints the contents of the command queue
void CommandQueue::print()
{
if (queuingStructure==PerRank)
{
PRINT(endl << "== Printing Per Rank Queue" );
for (size_t i=0;i<NUM_RANKS;i++)
{
PRINT(" = Rank " << i << " size : " << queues[i][0].size() );
for (size_t j=0;j<queues[i][0].size();j++)
{
PRINTN(" "<< j << "]");
queues[i][0][j]->print();
}
}
}
else if (queuingStructure==PerRankPerBank)
{
PRINT("\n== Printing Per Rank, Per Bank Queue" );
for (size_t i=0;i<NUM_RANKS;i++)
{
PRINT(" = Rank " << i );
for (size_t j=0;j<NUM_BANKS;j++)
{
PRINT(" Bank "<< j << " size : " << queues[i][j].size() );
for (size_t k=0;k<queues[i][j].size();k++)
{
PRINTN(" " << k << "]");
queues[i][j][k]->print();
}
}
}
}
}
/**
* return a reference to the queue for a given rank, bank. Since we
* don't always have a per bank queuing structure, sometimes the bank
* argument is ignored (and the 0th index is returned
*/
vector<BusPacket *> &CommandQueue::getCommandQueue(unsigned rank, unsigned bank)
{
if (queuingStructure == PerRankPerBank)
{
return queues[rank][bank];
}
else if (queuingStructure == PerRank)
{
return queues[rank][0];
}
else
{
ERROR("Unknown queue structure");
abort();
}
}
//checks if busPacket is allowed to be issued
bool CommandQueue::isIssuable(BusPacket *busPacket)
{
switch (busPacket->busPacketType)
{
case REFRESH:
break;
case ACTIVATE:
if ((bankStates[busPacket->rank][busPacket->bank].currentBankState == Idle ||
bankStates[busPacket->rank][busPacket->bank].currentBankState == Refreshing) &&
currentClockCycle >= bankStates[busPacket->rank][busPacket->bank].nextActivate &&
tFAWCountdown[busPacket->rank].size() < 4)
{
return true;
}
else
{
return false;
}
break;
case WRITE:
case WRITE_P:
if (bankStates[busPacket->rank][busPacket->bank].currentBankState == RowActive &&
currentClockCycle >= bankStates[busPacket->rank][busPacket->bank].nextWrite &&
busPacket->row == bankStates[busPacket->rank][busPacket->bank].openRowAddress &&
rowAccessCounters[busPacket->rank][busPacket->bank] < TOTAL_ROW_ACCESSES)
{
return true;
}
else
{
return false;
}
break;
case READ_P:
case READ:
if (bankStates[busPacket->rank][busPacket->bank].currentBankState == RowActive &&
currentClockCycle >= bankStates[busPacket->rank][busPacket->bank].nextRead &&
busPacket->row == bankStates[busPacket->rank][busPacket->bank].openRowAddress &&
rowAccessCounters[busPacket->rank][busPacket->bank] < TOTAL_ROW_ACCESSES)
{
return true;
}
else
{
return false;
}
break;
case PRECHARGE:
if (bankStates[busPacket->rank][busPacket->bank].currentBankState == RowActive &&
currentClockCycle >= bankStates[busPacket->rank][busPacket->bank].nextPrecharge)
{
return true;
}
else
{
return false;
}
break;
default:
ERROR("== Error - Trying to issue a crazy bus packet type : ");
busPacket->print();
exit(0);
}
return false;
}
//figures out if a rank's queue is empty
bool CommandQueue::isEmpty(unsigned rank)
{
if (queuingStructure == PerRank)
{
return queues[rank][0].empty();
}
else if (queuingStructure == PerRankPerBank)
{
for (size_t i=0;i<NUM_BANKS;i++)
{
if (!queues[rank][i].empty()) return false;
}
return true;
}
else
{
DEBUG("Invalid Queueing Stucture");
abort();
}
}
//tells the command queue that a particular rank is in need of a refresh
void CommandQueue::needRefresh(unsigned rank)
{
refreshWaiting = true;
refreshRank = rank;
}
void CommandQueue::nextRankAndBank(unsigned &rank, unsigned &bank)
{
if (schedulingPolicy == RankThenBankRoundRobin)
{
rank++;
if (rank == NUM_RANKS)
{
rank = 0;
bank++;
if (bank == NUM_BANKS)
{
bank = 0;
}
}
}
//bank-then-rank round robin
else if (schedulingPolicy == BankThenRankRoundRobin)
{
bank++;
if (bank == NUM_BANKS)
{
bank = 0;
rank++;
if (rank == NUM_RANKS)
{
rank = 0;
}
}
}
else
{
ERROR("== Error - Unknown scheduling policy");
exit(0);
}
}
void CommandQueue::update()
{
//do nothing since pop() is effectively update(),
//needed for SimulatorObject
//TODO: make CommandQueue not a SimulatorObject
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/chisuhua/DRAMSim2.git
[email protected]:chisuhua/DRAMSim2.git
chisuhua
DRAMSim2
DRAMSim2
master

搜索帮助