787 lines
27 KiB
Plaintext
787 lines
27 KiB
Plaintext
package dram;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import config.SystemConfig;
|
|
import config.MainMemoryConfig;
|
|
import config.MainMemoryConfig.QueuingStructure;
|
|
import config.MainMemoryConfig.RowBufferPolicy;
|
|
import config.MainMemoryConfig.SchedulingPolicy;
|
|
import dram.BankState.CurrentBankState;
|
|
import dram.MainMemoryBusPacket.BusPacketType;
|
|
import generic.Core;
|
|
import generic.Event;
|
|
import generic.EventQueue;
|
|
import generic.GlobalClock;
|
|
import generic.RequestType;
|
|
import main.ArchitecturalComponent;
|
|
import main.Main;
|
|
import memorysystem.AddressCarryingEvent;
|
|
import memorysystem.Cache;
|
|
import memorysystem.MainMemoryController;
|
|
import misc.Error;
|
|
|
|
public class MainMemoryDRAMControllerTest extends MainMemoryController{
|
|
|
|
private int numTransactions;
|
|
|
|
|
|
MainMemoryConfig mainMemoryConfig;
|
|
|
|
//TODO: need a way to store the actual requesting element
|
|
//dirty workaround for now
|
|
|
|
Cache parentCache;
|
|
int refreshRank;
|
|
Test parentTest;
|
|
|
|
ArrayList<MainMemoryBusPacket> pendingTransQueue;
|
|
//MainMemoryBusPacket pendingTransQueue[]; //to keep track of packets that could not be added to command queue
|
|
BankState bankStates[][];
|
|
CommandQueue commandQueue;
|
|
Rank ranks[];
|
|
int refreshCount[];
|
|
|
|
public MainMemoryDRAMControllerTest(MainMemoryConfig mainMemoryConfig, Test parentTest) {
|
|
super();
|
|
|
|
this.parentTest = parentTest;
|
|
this.mainMemoryConfig = mainMemoryConfig;
|
|
|
|
numTransactions = 0;
|
|
refreshRank=0;
|
|
ranks = new Rank[mainMemoryConfig.numRanks];
|
|
bankStates = new BankState[mainMemoryConfig.numRanks][mainMemoryConfig.numBanks];
|
|
|
|
//TODO is there a more elegant way :P
|
|
for(int i=0; i < mainMemoryConfig.numRanks;i++)
|
|
{
|
|
for(int j=0; j < mainMemoryConfig.numBanks; j++)
|
|
{
|
|
bankStates[i][j] = new BankState();
|
|
}
|
|
ranks[i] = new Rank(mainMemoryConfig,i,this);
|
|
}
|
|
|
|
pendingTransQueue=new ArrayList<MainMemoryBusPacket>();
|
|
|
|
commandQueue = new CommandQueue(mainMemoryConfig,bankStates);
|
|
|
|
//TODO: allocate and initialize arrays
|
|
refreshCount=new int[mainMemoryConfig.numRanks];
|
|
|
|
for(int i=0;i<mainMemoryConfig.numRanks;i++){
|
|
refreshCount[i]=(int)((mainMemoryConfig.RefreshPeriod/mainMemoryConfig.tCK)/mainMemoryConfig.numRanks)*(i+1);
|
|
}
|
|
|
|
}
|
|
|
|
@Override
|
|
public void handleEvent(EventQueue eventQ, Event e)
|
|
{
|
|
|
|
|
|
long currentTime = GlobalClock.getCurrentTime();
|
|
|
|
//System.out.println("Hi!! handling a dram event of type " + e.getRequestType());
|
|
Test.debugPrinter.print("\nHi!! handling a dram event of type " + e.getRequestType()+ "\n");
|
|
|
|
|
|
//check if state update event
|
|
|
|
if(e.getRequestType() == RequestType.Mem_Cntrlr_State_Update) {
|
|
|
|
StateUpdateEvent event = (StateUpdateEvent) e;
|
|
|
|
int rank = event.getRank();
|
|
int bank = event.getBank();
|
|
long eventTime = event.getEventTime(); //IMP: the reference for timing should be the time previous event was generated
|
|
//and not the current clock cycle as these 2 may differ sometimes!
|
|
BankState bankState = bankStates[rank][bank];
|
|
|
|
Test.debugPrinter.print("\nHi!! Updating state for bank " + bank + " with last command " + bankState.lastCommand
|
|
+ " and current Bank State " + bankState.currentBankState +"\n\n");
|
|
|
|
//FSM for commands with implicit state change
|
|
switch(bankState.lastCommand) {
|
|
|
|
case WRITE_P:
|
|
case READ_P:
|
|
bankState.currentBankState = CurrentBankState.PRECHARGING;
|
|
bankState.lastCommand = BusPacketType.PRECHARGE;
|
|
//create new FSM event and add to original queue
|
|
StateUpdateEvent FSMevent = new StateUpdateEvent(eventQ, (eventTime+mainMemoryConfig.tRP-1), e.getRequestingElement(),
|
|
e.getProcessingElement(), RequestType.Mem_Cntrlr_State_Update, rank, bank);
|
|
eventQ.addEvent(FSMevent);
|
|
break;
|
|
|
|
case REFRESH:
|
|
//if last command was refresh, all banks were refreshed in that rank. set all as idle
|
|
for(int i=0; i < mainMemoryConfig.numBanks; i++)
|
|
{
|
|
bankStates[rank][i].currentBankState = CurrentBankState.IDLE;
|
|
}
|
|
break;
|
|
case PRECHARGE:
|
|
bankState.currentBankState = CurrentBankState.IDLE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
else if(e.getRequestType() == RequestType.Cache_Read || e.getRequestType() == RequestType.Cache_Write) {
|
|
|
|
//got a read or write event -> perform address mapping and add it to command queue
|
|
|
|
if(true)
|
|
{
|
|
|
|
//System.out.println("Hi handling a Cache Read!!");
|
|
|
|
|
|
//TODO: very dirty workaround
|
|
this.parentCache = (Cache) e.getRequestingElement();
|
|
|
|
|
|
AddressCarryingEvent event = (AddressCarryingEvent) e;
|
|
|
|
//maintain number of transactions waiting to be serviced
|
|
numTransactions++;
|
|
|
|
|
|
MainMemoryBusPacket b = AddressMapping(event.getAddress());
|
|
b.setBusPacketType(requestTypeToBusPacketType(event.getRequestType()));
|
|
|
|
//for TIMING
|
|
b.timeCreated = GlobalClock.getCurrentTime();
|
|
|
|
//pendingTransQueue.add(x);
|
|
|
|
//MainMemoryBusPacket b=pendingTransQueue.get(0);
|
|
|
|
|
|
Test.debugPrinter.print("Of bus packet type:");
|
|
b.printPacketToFile();
|
|
|
|
|
|
if(commandQueue.hasRoomFor(2,b.rank, b.bank))
|
|
{
|
|
numTransactions--; //the transaction is no longer waiting in the controller
|
|
//pendingTransQueue.remove(0);
|
|
//create new ACTIVATE bus packet with the address we just decoded
|
|
MainMemoryBusPacket ACTcommand = b.Clone(); //check cloning is ok
|
|
ACTcommand.setBusPacketType(BusPacketType.ACTIVATE);
|
|
|
|
//create read or write command and enqueue it
|
|
MainMemoryBusPacket RWcommand = b.Clone();
|
|
//RWcommand.setBusPacketType(requestTypeToBusPacketType(event.getRequestType()));
|
|
|
|
//System.out.println("Enqueuing commands for address " + event.getAddress());
|
|
//System.out.println("ACTcommand busPacketType "+ACTcommand.busPacketType);
|
|
//System.out.println("RWcommand busPacketType "+RWcommand.busPacketType);
|
|
|
|
commandQueue.enqueue(ACTcommand);
|
|
commandQueue.enqueue(RWcommand);
|
|
|
|
Test.debugPrinter.print("Enqueued ACT command bus packet to queue as follows:");
|
|
ACTcommand.printPacketToFile();
|
|
Test.debugPrinter.print("Enqueued RW command bus packet to queue as follows:");
|
|
RWcommand.printPacketToFile();
|
|
|
|
//TODO: do we need to keep transactions yet to receive data in a pending queue?
|
|
|
|
}
|
|
|
|
//TODO: add power calculations. here?
|
|
|
|
else
|
|
{
|
|
//TODO: need to postpone this event, but by how much time??
|
|
Test.debugPrinter.print("No room in command queue!! For rank " + b.rank +"\n");
|
|
Test.debugPrinter.print("Adding to pending queue!");
|
|
pendingTransQueue.add(b);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
//TODO: see how to handle this
|
|
//actually there is no need to handle this if the transq size is not limited
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
//finally send the data to cpu
|
|
|
|
else if (e.getRequestType() == RequestType.Rank_Response)
|
|
{
|
|
|
|
//System.out.println("Received rank response! Sending event");
|
|
|
|
//for TEST
|
|
if(mainMemoryConfig.DEBUG_BUS)
|
|
{
|
|
Test.outputLog.print(" -- MC Receiving From Data Bus on Clock Cycle "+ GlobalClock.getCurrentTime() +" : ");
|
|
//((RamBusAddressCarryingEvent) e).getBusPacket().printTest();
|
|
}
|
|
|
|
//for TEST
|
|
if (mainMemoryConfig.DEBUG_BUS)
|
|
{
|
|
Test.outputLog.print(" -- MC Issuing to CPU bus at Clock Cycle " + GlobalClock.getCurrentTime() +" : ");
|
|
Test.outputLog.print("T [Data] [0x"+ String.format("%07X",((AddressCarryingEvent)e).getAddress()).toLowerCase() + "] [0]\n");
|
|
}
|
|
|
|
//for TIMING TEST
|
|
|
|
/*Test.timingLog.print("Id: " + ((RamBusAddressCarryingEvent) e).getBusPacket().testid);
|
|
Test.timingLog.print(" Address : " + String.format("%08X",((RamBusAddressCarryingEvent) e).getBusPacket().physicalAddress));
|
|
Test.timingLog.print(" Created at : " + ((RamBusAddressCarryingEvent) e).getBusPacket().timeCreated);
|
|
Test.timingLog.print(" Completed at : " + GlobalClock.getCurrentTime() + "\n");
|
|
*/
|
|
|
|
Test.timingLog.print(Long.toString(((RamBusAddressCarryingEvent) e).getBusPacket().timeCreated));
|
|
Test.timingLog.print(" " + GlobalClock.getCurrentTime() + "\n");
|
|
|
|
|
|
|
|
AddressCarryingEvent event = new AddressCarryingEvent(eventQ, 0,
|
|
this, this.parentCache, RequestType.Mem_Response,
|
|
((AddressCarryingEvent)e).getAddress());
|
|
//IMP
|
|
//TODO: how to make processing element as cache????
|
|
//very dirty workaround right now
|
|
|
|
//understand what this does
|
|
//getComInterface().sendMessage(event);
|
|
|
|
|
|
|
|
//TODO: what to do for a write?
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
public void oneCycleOperation(){
|
|
Test.debugPrinter.print("\nhi! In one cycle operation for time " + GlobalClock.getCurrentTime() + "\n");
|
|
//MainMemoryBusPacket b = commandQueue.pop();
|
|
long currentTime = GlobalClock.getCurrentTime();
|
|
//Core parentTest = ArchitecturalComponent.getCores()[0]; //using core 0 queue similar to as in cache
|
|
|
|
if (refreshCount[refreshRank]==0)
|
|
{
|
|
commandQueue.needRefresh(refreshRank);
|
|
ranks[refreshRank].refreshWaiting = true;
|
|
refreshCount[refreshRank] = (int)(mainMemoryConfig.RefreshPeriod/mainMemoryConfig.tCK);
|
|
refreshRank++;
|
|
if (refreshRank == mainMemoryConfig.numRanks)
|
|
{
|
|
refreshRank = 0;
|
|
}
|
|
}
|
|
|
|
//TODO:need to implement power portion of refresh
|
|
MainMemoryBusPacket b = null;
|
|
b = commandQueue.pop(currentTime);
|
|
//if(commandQueue.canPop())
|
|
|
|
|
|
if(b!=null)
|
|
{
|
|
|
|
//TODO: is there a more elegant way to do this?
|
|
//MainMemoryBusPacket b = commandQueue.pop(currentTime);
|
|
|
|
|
|
Test.debugPrinter.print("\n\nHi!! Popped a bus packet from queue successfully! Packet is \n");
|
|
b.printPacketToFile();
|
|
Test.debugPrinter.print("\n\n");
|
|
|
|
|
|
//added by harveenk
|
|
//Popped a memory packet so let's add pending packets if we have space for 2 and if it is the correct queue
|
|
//First check if we have any pending packets
|
|
if(pendingTransQueue.size()>0 && commandQueue.hasRoomFor(2, b.rank, b.bank))
|
|
{
|
|
|
|
int foundPacketIndex = -1;
|
|
MainMemoryBusPacket pendingPacket = null;
|
|
|
|
//find the first packet from the pending list that belongs to this particular queue
|
|
for(int i = 0; i < pendingTransQueue.size(); i++)
|
|
{
|
|
pendingPacket = pendingTransQueue.get(i);
|
|
if(pendingPacket.rank == b.rank &&
|
|
!( mainMemoryConfig.queuingStructure == QueuingStructure.PerRankPerBank && pendingPacket.bank != b.bank))
|
|
{
|
|
foundPacketIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*if(mainMemoryConfig.DEBUG_CMDQ && currentTime >= 34193)
|
|
{
|
|
Test.outputLog.print("Trying to enqueue pending packet\n");
|
|
pendingPacket.printTest();
|
|
Test.outputLog.print("\n");
|
|
}*/
|
|
|
|
if(foundPacketIndex != -1) //found a packet for this queue, so add!
|
|
{
|
|
numTransactions--; //the transaction is no longer waiting in the controller
|
|
pendingTransQueue.remove(foundPacketIndex);
|
|
//create new ACTIVATE bus packet with the address we just decoded
|
|
MainMemoryBusPacket ACTcommand = pendingPacket.Clone(); //check cloning is ok
|
|
ACTcommand.setBusPacketType(BusPacketType.ACTIVATE);
|
|
|
|
//create read or write command and enqueue it
|
|
MainMemoryBusPacket RWcommand = pendingPacket.Clone();
|
|
//RWcommand.setBusPacketType(requestTypeToBusPacketType(event.getRequestType()));
|
|
|
|
Test.debugPrinter.print("\nGot room in queue! Adding a pending bus packet!!\n\n");
|
|
|
|
//System.out.println("Enqueuing commands for address " + pendingPacket.physicalAddress);
|
|
//System.out.println("ACTcommand busPacketType "+ACTcommand.busPacketType);
|
|
//System.out.println("RWcommand busPacketType "+RWcommand.busPacketType);
|
|
|
|
commandQueue.enqueue(ACTcommand);
|
|
commandQueue.enqueue(RWcommand);
|
|
|
|
Test.debugPrinter.print("Enqueued ACT command bus packet to queue as follows:");
|
|
ACTcommand.printPacketToFile();
|
|
Test.debugPrinter.print("Enqueued RW command bus packet to queue as follows:");
|
|
RWcommand.printPacketToFile();
|
|
|
|
//TODO: do we need to keep transactions yet to receive data in a pending queue?
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int rank = b.rank;
|
|
int bank = b.bank;
|
|
|
|
if (b.busPacketType == BusPacketType.WRITE || b.busPacketType == BusPacketType.WRITE_P)
|
|
{
|
|
//if write, schedule the data packet
|
|
|
|
MainMemoryBusPacket dataPacketToSend = b.Clone();
|
|
dataPacketToSend.setBusPacketType(BusPacketType.DATA);
|
|
|
|
Test.debugPrinter.print("\n\n Received a write, scheduling event for data packet for address " + dataPacketToSend.physicalAddress + "\n\n");
|
|
|
|
RamBusAddressCarryingEvent event = new RamBusAddressCarryingEvent( parentTest.getEventQueue() , (currentTime + mainMemoryConfig.tWL), this,
|
|
ranks[rank], RequestType.Main_Mem_Access, dataPacketToSend.physicalAddress, dataPacketToSend);
|
|
event.getEventQ().addEvent(event);
|
|
|
|
}
|
|
|
|
//update state according to the popped bus packet
|
|
|
|
switch(b.busPacketType)
|
|
{
|
|
case READ_P:
|
|
case READ:
|
|
if(b.busPacketType == BusPacketType.READ_P)
|
|
{
|
|
bankStates[rank][bank].nextActivate = Math.max(currentTime + mainMemoryConfig.ReadAutopreDelay,
|
|
bankStates[rank][bank].nextActivate);
|
|
bankStates[rank][bank].lastCommand = BusPacketType.READ_P;
|
|
|
|
|
|
//create and send event state update event
|
|
//sending to core 0 event queue currently
|
|
//keeping requesting and processing element same
|
|
StateUpdateEvent StUpdtEvent = new StateUpdateEvent(parentTest.getEventQueue(), (currentTime+mainMemoryConfig.ReadToPreDelay), this,
|
|
this, RequestType.Mem_Cntrlr_State_Update, rank, bank);
|
|
StUpdtEvent.getEventQ().addEvent(StUpdtEvent);
|
|
|
|
}
|
|
else if (b.busPacketType == BusPacketType.READ)
|
|
{
|
|
bankStates[rank][bank].nextPrecharge = Math.max(currentTime + mainMemoryConfig.ReadToPreDelay,
|
|
bankStates[rank][bank].nextPrecharge);
|
|
bankStates[rank][bank].lastCommand = BusPacketType.READ;
|
|
|
|
}
|
|
|
|
for (int i=0;i< mainMemoryConfig.numRanks;i++)
|
|
{
|
|
for (int j=0;j<mainMemoryConfig.numBanks;j++)
|
|
{
|
|
if (i!= rank)
|
|
{
|
|
|
|
if (bankStates[i][j].currentBankState == CurrentBankState.ROW_ACTIVE)
|
|
{
|
|
bankStates[i][j].nextRead = Math.max(currentTime + mainMemoryConfig.tBL/2 + mainMemoryConfig.tRTRS, bankStates[i][j].nextRead);
|
|
bankStates[i][j].nextWrite = Math.max(currentTime + mainMemoryConfig.ReadToWriteDelay,
|
|
bankStates[i][j].nextWrite);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bankStates[i][j].nextRead = Math.max(currentTime + Math.max(mainMemoryConfig.tCCD, mainMemoryConfig.tBL/2),
|
|
bankStates[i][j].nextRead);
|
|
bankStates[i][j].nextWrite = Math.max(currentTime + mainMemoryConfig.ReadToWriteDelay,
|
|
bankStates[i][j].nextWrite);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (b.busPacketType == BusPacketType.READ_P)
|
|
{
|
|
//set read and write to nextActivate so the state table will prevent a read or write
|
|
// being issued (in cq.isIssuable())before the bank state has been changed because of the
|
|
// auto-precharge associated with this command
|
|
bankStates[rank][bank].nextRead = bankStates[rank][bank].nextActivate;
|
|
bankStates[rank][bank].nextWrite = bankStates[rank][bank].nextActivate;
|
|
}
|
|
|
|
break;
|
|
case WRITE_P:
|
|
case WRITE:
|
|
if (b.busPacketType == BusPacketType.WRITE_P)
|
|
{
|
|
bankStates[rank][bank].nextActivate = Math.max(currentTime + mainMemoryConfig.WriteAutopreDelay,
|
|
bankStates[rank][bank].nextActivate);
|
|
bankStates[rank][bank].lastCommand = BusPacketType.WRITE_P;
|
|
|
|
//create and send event state update event
|
|
//sending to core 0 event queue currently
|
|
//keeping requesting and processing element same
|
|
StateUpdateEvent StUpdtEvent = new StateUpdateEvent(parentTest.getEventQueue(), (currentTime+mainMemoryConfig.WriteToPreDelay), this,
|
|
this, RequestType.Mem_Cntrlr_State_Update, rank, bank);
|
|
StUpdtEvent.getEventQ().addEvent(StUpdtEvent);
|
|
Test.debugPrinter.print("\nAdded State update event to trigger at "+ (currentTime+mainMemoryConfig.WriteToPreDelay) + " for WRITE_P for bus packet ");
|
|
b.printPacketToFile();
|
|
|
|
}
|
|
else if (b.busPacketType == BusPacketType.WRITE)
|
|
{
|
|
bankStates[rank][bank].nextPrecharge = Math.max(currentTime + mainMemoryConfig.WriteToPreDelay,
|
|
bankStates[rank][bank].nextPrecharge);
|
|
bankStates[rank][bank].lastCommand = BusPacketType.WRITE;
|
|
}
|
|
|
|
|
|
|
|
for (int i=0;i< mainMemoryConfig.numRanks;i++)
|
|
{
|
|
for (int j=0;j<mainMemoryConfig.numBanks;j++)
|
|
{
|
|
if (i!=rank)
|
|
{
|
|
if (bankStates[i][j].currentBankState == CurrentBankState.ROW_ACTIVE)
|
|
{
|
|
bankStates[i][j].nextWrite = Math.max(currentTime + mainMemoryConfig.tBL/2 + mainMemoryConfig.tRTRS, bankStates[i][j].nextWrite);
|
|
bankStates[i][j].nextRead = Math.max(currentTime + mainMemoryConfig.WriteToReadDelayR,
|
|
bankStates[i][j].nextRead);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bankStates[i][j].nextWrite = Math.max(currentTime + Math.max(mainMemoryConfig.tBL/2, mainMemoryConfig.tCCD), bankStates[i][j].nextWrite);
|
|
bankStates[i][j].nextRead = Math.max(currentTime + mainMemoryConfig.WriteToReadDelayB,
|
|
bankStates[i][j].nextRead);
|
|
}
|
|
}
|
|
}
|
|
|
|
//set read and write to nextActivate so the state table will prevent a read or write
|
|
// being issued (in cq.isIssuable())before the bank state has been changed because of the
|
|
// auto-precharge associated with this command
|
|
if (b.busPacketType == BusPacketType.WRITE_P)
|
|
{
|
|
bankStates[rank][bank].nextRead = bankStates[rank][bank].nextActivate;
|
|
bankStates[rank][bank].nextWrite = bankStates[rank][bank].nextActivate;
|
|
}
|
|
|
|
break;
|
|
|
|
case ACTIVATE:
|
|
|
|
bankStates[rank][bank].currentBankState = CurrentBankState.ROW_ACTIVE;
|
|
bankStates[rank][bank].lastCommand = BusPacketType.ACTIVATE;
|
|
bankStates[rank][bank].openRowAddress = b.row;
|
|
bankStates[rank][bank].nextActivate = Math.max(currentTime + mainMemoryConfig.tRC, bankStates[rank][bank].nextActivate);
|
|
bankStates[rank][bank].nextPrecharge = Math.max(currentTime + mainMemoryConfig.tRAS, bankStates[rank][bank].nextPrecharge);
|
|
|
|
//if we are using posted-CAS, the next column access can be sooner than normal operation
|
|
|
|
bankStates[rank][bank].nextRead = Math.max(currentTime + (mainMemoryConfig.tRCD-mainMemoryConfig.tAL), bankStates[rank][bank].nextRead);
|
|
bankStates[rank][bank].nextWrite = Math.max(currentTime + (mainMemoryConfig.tRCD-mainMemoryConfig.tAL), bankStates[rank][bank].nextWrite);
|
|
|
|
for (int i=0;i<mainMemoryConfig.numBanks;i++)
|
|
{
|
|
if (i!=bank)
|
|
{
|
|
bankStates[rank][i].nextActivate = Math.max(currentTime + mainMemoryConfig.tRRD, bankStates[rank][i].nextActivate);
|
|
}
|
|
}
|
|
|
|
break;
|
|
case PRECHARGE:
|
|
{
|
|
bankStates[rank][bank].currentBankState = CurrentBankState.PRECHARGING;
|
|
bankStates[rank][bank].lastCommand = BusPacketType.PRECHARGE;
|
|
bankStates[rank][bank].nextActivate = Math.max(currentTime + mainMemoryConfig.tRP, bankStates[rank][bank].nextActivate);
|
|
|
|
//create and send event state update event
|
|
//sending to core 0 event queue currently
|
|
//keeping requesting and processing element same
|
|
StateUpdateEvent StUpdtEvent = new StateUpdateEvent(parentTest.getEventQueue(), (currentTime+mainMemoryConfig.tRP - 1), this,
|
|
this, RequestType.Mem_Cntrlr_State_Update, rank, bank);
|
|
StUpdtEvent.getEventQ().addEvent(StUpdtEvent);
|
|
}
|
|
break;
|
|
case REFRESH:
|
|
{
|
|
for (int i=0; i< mainMemoryConfig.numBanks ;i++)
|
|
{
|
|
bankStates[rank][i].nextActivate = currentTime + mainMemoryConfig.tRFC;
|
|
bankStates[rank][i].currentBankState = CurrentBankState.REFRESHING;
|
|
bankStates[rank][i].lastCommand = BusPacketType.REFRESH;
|
|
}
|
|
|
|
//create and send event state update event
|
|
//sending to core 0 event queue currently
|
|
//keeping requesting and processing element same
|
|
|
|
//Sending only 1 event, need to refresh all banks in the rank for this - do this in handle event
|
|
StateUpdateEvent StUpdtEvent = new StateUpdateEvent(parentTest.getEventQueue(), (currentTime+mainMemoryConfig.tRFC - 1), this,
|
|
this, RequestType.Mem_Cntrlr_State_Update, rank, bank);
|
|
StUpdtEvent.getEventQ().addEvent(StUpdtEvent);
|
|
}
|
|
break;
|
|
default:
|
|
Error.showErrorAndExit("== Error - Popped a command we shouldn't have of type : " + b.busPacketType);
|
|
}
|
|
|
|
//IMP!!!
|
|
//TODO: check for collision on bus
|
|
|
|
//after state update
|
|
//schedule command packet as event to rank
|
|
RamBusAddressCarryingEvent event = new RamBusAddressCarryingEvent( parentTest.getEventQueue() , (currentTime + mainMemoryConfig.tCMD), this,
|
|
ranks[rank], RequestType.Main_Mem_Access, b.physicalAddress, b);
|
|
|
|
//TODO why is sendEvent not working?
|
|
//sendEvent(event); //using send event
|
|
|
|
event.getEventQ().addEvent(event);
|
|
|
|
|
|
|
|
|
|
//for TEST
|
|
if(mainMemoryConfig.DEBUG_BUS)
|
|
{
|
|
Test.outputLog.print(" -- MC Issuing On Command Bus at Clock Cycle "+ GlobalClock.getCurrentTime() +" : ");
|
|
//b.printTest();
|
|
}
|
|
|
|
|
|
}
|
|
|
|
else{
|
|
Test.debugPrinter.print("Nothing to pop at this time\n");
|
|
//nothing to do this cycle as nothing popped
|
|
}
|
|
|
|
|
|
// if(mainMemoryConfig.DEBUG_CMDQ){
|
|
// commandQueue.printTest();
|
|
// }
|
|
|
|
for (int i=0;i<mainMemoryConfig.numRanks;i++)
|
|
{
|
|
refreshCount[i]--;
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
public boolean WillAcceptTransaction()
|
|
{
|
|
return (this.numTransactions < mainMemoryConfig.TRANSQUEUE_DEPTH);
|
|
}
|
|
|
|
public MainMemoryBusPacket AddressMapping(long physicalAddress)
|
|
{
|
|
//TODO: implement other schemes
|
|
|
|
|
|
long address = physicalAddress; //this will be returned
|
|
|
|
//always remember - physical Address is the Byte address!
|
|
|
|
long tempA, tempB;
|
|
int decodedRank, decodedBank, decodedRow, decodedCol, decodedChan;
|
|
|
|
int transactionMask = mainMemoryConfig.TRANSACTION_SIZE - 1; //this is the mask in binary. for eg: 0x3f for 64 bytes
|
|
|
|
int channelBits = log2(mainMemoryConfig.numChans);
|
|
int rankBits = log2(mainMemoryConfig.numRanks);
|
|
int bankBits = log2(mainMemoryConfig.numBanks);
|
|
int rowBits = log2(mainMemoryConfig.numRows);
|
|
int colBits = log2(mainMemoryConfig.numCols);
|
|
int colEffectiveBits;
|
|
|
|
int DataBusBytesOffest = log2(mainMemoryConfig.DATA_BUS_BYTES); //for 64 bit bus -> 8 bytes -> lower 3 bits of address irrelevant
|
|
|
|
int ColBytesOffset = log2(mainMemoryConfig.tBL);
|
|
//these are the bits we need to throw away because of "bursts". The column address is incremented internally on bursts
|
|
//So for a burst length of 4, 8 bytes of data are transferred on each burst
|
|
//Each consecutive 8 byte chunk comes for the "next" column
|
|
//So we traverse 4 columns in 1 request. Thus the lower log2(4) bits become irrelevant for us. Throw them away
|
|
//Finally we get 8 bytes * 4 = 32 bytes of data for a 64 bit data bus and BL = 4.
|
|
//This is equal to a cache line
|
|
|
|
//For clarity
|
|
//Throw away bits to account for data bus size in bytes
|
|
//and for burst length
|
|
physicalAddress >>>= (DataBusBytesOffest + ColBytesOffset); //using >>> for unsigned right shift
|
|
//System.out.println("Shifted address by " + (DataBusBytesOffest + ColBytesOffset) + " bits");
|
|
|
|
|
|
//By the same logic, need to remove the burst-related column bits from the column bit width to be decoded
|
|
colEffectiveBits = colBits - ColBytesOffset;
|
|
|
|
|
|
//implementing 1 scheme --- "scheme 2"
|
|
//chan:row:col:bank:rank
|
|
|
|
tempA = physicalAddress;
|
|
physicalAddress = physicalAddress >>> rankBits; //always unsigned shifting
|
|
tempB = physicalAddress << rankBits;
|
|
//System.out.println("Shifted address by " + rankBits + " bits");
|
|
decodedRank = (int) (tempA ^ tempB);
|
|
//System.out.println("decoded rank: " + Integer.toBinaryString(decodedRank));
|
|
|
|
tempA = physicalAddress;
|
|
physicalAddress = physicalAddress >>> bankBits;
|
|
tempB = physicalAddress << bankBits;
|
|
//System.out.println("Shifted address by " + bankBits + " bits");
|
|
decodedBank = (int) (tempA ^ tempB);
|
|
//System.out.println("decoded bank: " + Integer.toBinaryString(decodedBank));
|
|
|
|
tempA = physicalAddress;
|
|
physicalAddress = physicalAddress >>> colEffectiveBits;
|
|
tempB = physicalAddress << colEffectiveBits;
|
|
//System.out.println("Shifted address by " + colEffectiveBits + " bits");
|
|
decodedCol = (int) (tempA ^ tempB);
|
|
//System.out.println("decoded col: " + Integer.toBinaryString(decodedCol));
|
|
|
|
tempA = physicalAddress;
|
|
physicalAddress = physicalAddress >>> rowBits;
|
|
tempB = physicalAddress << rowBits;
|
|
decodedRow = (int) (tempA ^ tempB);
|
|
|
|
tempA = physicalAddress;
|
|
physicalAddress = physicalAddress >>> channelBits;
|
|
tempB = physicalAddress << channelBits;
|
|
decodedChan = (int) (tempA ^ tempB);
|
|
|
|
//TODO: channel not being taken into acount right now!!
|
|
|
|
//if num ranks = 1, decoded rank will always be "0"
|
|
|
|
MainMemoryBusPacket b = new MainMemoryBusPacket(decodedRow, decodedCol, decodedBank, decodedRank, address, null);
|
|
return b;
|
|
}
|
|
|
|
public static int log2(int a)
|
|
{
|
|
return (int) (Math.log(a)/Math.log(2));
|
|
}
|
|
|
|
|
|
public BusPacketType requestTypeToBusPacketType(RequestType requestType)
|
|
{
|
|
switch(requestType)
|
|
{
|
|
case Cache_Read:
|
|
if(mainMemoryConfig.getRowBufferPolicy()==RowBufferPolicy.ClosePage)
|
|
{
|
|
return BusPacketType.READ_P;
|
|
}
|
|
else if(mainMemoryConfig.getRowBufferPolicy()==RowBufferPolicy.OpenPage)
|
|
{
|
|
return BusPacketType.READ;
|
|
}
|
|
else
|
|
{
|
|
Error.showErrorAndExit("Unkown row buffer policy");
|
|
return null; //needed to avoid compile error
|
|
}
|
|
//break; //not required because "unreachable" code
|
|
case Cache_Write:
|
|
if(mainMemoryConfig.getRowBufferPolicy()==RowBufferPolicy.ClosePage)
|
|
{
|
|
return BusPacketType.WRITE_P;
|
|
}
|
|
else if(mainMemoryConfig.getRowBufferPolicy()==RowBufferPolicy.OpenPage)
|
|
{
|
|
return BusPacketType.WRITE;
|
|
}
|
|
else
|
|
{
|
|
Error.showErrorAndExit("Unkown row buffer policy");
|
|
return null; //needed to avoid compile error
|
|
}
|
|
//break;
|
|
default:
|
|
Error.showErrorAndExit("Request type "+ requestType + "does not have a corresponding bus packet type");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
|
|
void printBankStateTest()
|
|
{
|
|
Test.outputLog.print("== Printing bank states (According to MC) at Clock Cycle " + GlobalClock.getCurrentTime() + "\n");
|
|
for (int i=0; i < mainMemoryConfig.numRanks; i++)
|
|
{
|
|
for (int j=0; j < mainMemoryConfig.numBanks; j++)
|
|
{
|
|
if (bankStates[i][j].currentBankState == CurrentBankState.ROW_ACTIVE)
|
|
{
|
|
Test.outputLog.print("[" + bankStates[i][j].openRowAddress + "] ");
|
|
}
|
|
else if (bankStates[i][j].currentBankState == CurrentBankState.IDLE)
|
|
{
|
|
Test.outputLog.print("[idle] ");
|
|
}
|
|
else if (bankStates[i][j].currentBankState == CurrentBankState.PRECHARGING)
|
|
{
|
|
Test.outputLog.print("[pre] ");
|
|
}
|
|
else if (bankStates[i][j].currentBankState == CurrentBankState.REFRESHING)
|
|
{
|
|
Test.outputLog.print("[ref] ");
|
|
}
|
|
else if (bankStates[i][j].currentBankState == CurrentBankState.POWER_DOWN)
|
|
{
|
|
Test.outputLog.print("[lowp] ");
|
|
}
|
|
}
|
|
Test.outputLog.print("\n");
|
|
}
|
|
}
|
|
|
|
}
|