Tejas/src/simulator/dram/MainMemoryDRAMControllerTes...

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");
}
}
}