📄 mipssimulator.cpp
字号:
if( m_pExecInsts->next )
m_pExecInsts->next->NextCycle();
STAT.cycles++;
}
void CMIPSSimulator::PrevCycle()
{
CycleTo( STAT.cycles - 1 );
}
void CMIPSSimulator::RollBackToStartState()
{
m_nState = kRun;
PC = m_nStartPC;
RollBackMem();
RollBackReg();
memset( &STAT, 0, sizeof(STAT) );
if( m_pExecInsts->next ) {
delete m_pExecInsts->next; m_pExecInsts->next = NULL;
}
// trace
if( m_bTrace ) {
CString temp = _T("Program restart:\r\n");
m_TraceFile.Write( (LPCTSTR)temp, temp.GetLength() );
m_TraceFile.Flush();
}
m_pExecInsts->m_nCurCycle = 1;
m_pExecInsts->FetchInst();
STAT.cycles = 0;
}
void CMIPSSimulator::CycleTo( int cycle )
{
RollBackToStartState();
while( STAT.cycles < cycle )
NextCycle();
}
int CMIPSSimulator::GetCurCycle()
{
return STAT.cycles;
}
int CMIPSSimulator::GetCurStep()
{
return STAT.steps;
}
// The space pExecInst pointed is deallocated after this function
BOOL CMIPSSimulator::GetStageArray( CExecInst* pExecInst,
UINT_ARRAY& outStageArray )
{
BOOL found = FALSE;
CExecInst* next = m_pExecInsts->next;
while( next ) {
if( next == pExecInst ) {
found = TRUE; break;
}
next = next->next;
}
if( !found ) {
#ifdef _DEBUG
AfxMessageBox( "CMIPSSimulator::GetStageArray(..) error." );
#endif //_DEBUG
return FALSE;// It should not occur.
}
// close trace
BOOL bTrace = m_bTrace; m_bTrace = FALSE;
UINT nCurCycle = pExecInst->m_nCurCycle;
outStageArray.Add( pExecInst->m_nLastStage );
while( pExecInst->m_nCurStage != COMPLETE ) {
NextCycle();
outStageArray.Add( pExecInst->m_nLastStage );
}
// Roll back
CycleTo( nCurCycle );
//
m_bTrace = bTrace;
return TRUE;
}
BOOL CMIPSSimulator::HasNewStep()
{
return m_bNewStep;
}
CExecInst* CMIPSSimulator::GetNewExecInst()
{
CExecInst* next = m_pExecInsts->next;
while( next && next->next ) {
next = next->next;
}
return next;
}
BOOL CMIPSSimulator::HasInstComplete(UINT_ARRAY& outCompleteArray)
{
outCompleteArray.RemoveAll();
CExecInst* next = m_pExecInsts->next;
while( next ) {
if( next->m_nCurStage == COMPLETE && next->pInst->m_key != IDLE_INST )
outCompleteArray.Add( next->pInst->m_nAddress );
next = next->next;
}
if( outCompleteArray.GetSize() > 0 ) return TRUE;
return FALSE;
}
BOOL CMIPSSimulator::HasIdleInstComplete()
{
CExecInst* next = m_pExecInsts->next;
while( next ) {
if( next->m_nCurStage == COMPLETE && next->pInst->m_key == IDLE_INST )
return TRUE;
next = next->next;
}
return FALSE;
}
BOOL CMIPSSimulator::IsExecComplete()
{
if( m_pExecInsts->next == NULL )
return TRUE;
return FALSE;
}
/////////////////////////////////////////////////////////
// CLASS CEXECINST
/////////////////////////////////////////////////////////
// Construction
CExecInst::CExecInst( int cycle, CAsmInstruction* inst,
CExecInst* prev, CExecInst* next )
{
m_nStartCycle = cycle;
m_nCurCycle = cycle - 1;
m_nCurMulCycle = 0;
m_nCurDivCycle = 0;
m_nCurStage = IF;
m_nLastStage = IF;
m_bBranchTaken = TRUE;
m_bStall = FALSE;
m_bIdle = FALSE;
m_nA = 0;
m_nB = 0;
m_nImm = 0;
pInst = inst;
// link the previous and next node
this->prev = prev;
this->next = next;
if( prev ) prev->next = this;
if( next ) next->prev = this;
// prevent data hazards
m_bForward = FALSE;
m_bForwardReady = FALSE;
m_bReadFromForward = FALSE;
}
CExecInst::~CExecInst()
{
if( pInst && pInst->m_key == IDLE_INST )// create by Freeze()
delete pInst;
if( prev ) prev->next = NULL;
if( next ) {
next->prev = NULL;
delete next;
}
}
// MIPS CPU: DO ONE CYCLE
void CExecInst::NextCycle()
{
m_nCurCycle++;
// for stageComplete() delete itself
CExecInst* pNextExecInst = next;
switch( m_nCurStage ) {
case IF:
stageIF(); break;
case ID:
stageID();
pNextExecInst = next;// this stage load the next instruction
break;
case EX:
stageEX(); break;
case MEM:
stageMEM(); break;
case WB:
stageWB(); break;
case COMPLETE:
stageComplete();
}
// Recursive call
if( pNextExecInst ) pNextExecInst->NextCycle();
}
// stall call
void CExecInst::Stall()
{
m_bStall = TRUE;
if( next ) next->Stall();
}
// idle call, clear next stage registers
void CExecInst::Idle()
{
m_bIdle = TRUE;
}
// Fetch the next instruction...
COLORREF ColorArray[] =
{
RGB(255,0,0), RGB(128,0,0), RGB(0,0,255),
RGB(0,128,0), RGB(0,0,160), RGB(255,0,255),
RGB(128,128,0), RGB(0,64,128), RGB(0,128,128),
RGB(255,128,0)
};
void CExecInst::FetchInst()
{
CAsmInstruction* pInst = simulator.FetchInst();
if( pInst ) {
CExecInst* pExecInst = new CExecInst( m_nCurCycle,
pInst, this, this->next );
pExecInst->color = ColorArray[m_nCurCycle % 10];
}
}
// Freeze the pipeline, deleting any instructions after the branch
void CExecInst::Freeze()
{
simulator.m_bNewStep = TRUE;
CAsmInstruction* pInst = CAsmInstruction::IdleInst();
CExecInst* pExecInst = new CExecInst( m_nCurCycle, pInst, this, this->next );
pExecInst->Idle();
pExecInst->color = ColorArray[m_nCurCycle % 10];
}
/////////////////////////////////////////////////////////
// MIPS CPU Registers Access
int CExecInst::GetRegContent(UINT reg)
{
if( reg < 32 )
return simulator.reg[reg].content;
throw Error(ERROR_MIPS_REG_OUTRANGE, reg);
}
int CExecInst::GetRegForward(UINT reg)
{
if( reg < 32 )
return simulator.reg[reg].forward;
throw Error(ERROR_MIPS_REG_OUTRANGE, reg);
}
int CExecInst::GetRegStatus(UINT reg)
{
if( reg < 32 )
return simulator.reg[reg].status;
throw Error(ERROR_MIPS_REG_OUTRANGE, reg);
}
int CExecInst::GetRegData(UINT reg)
{
if( reg < 32 ) {
if( m_bReadFromForward ) {
m_bReadFromForward = FALSE;
return simulator.reg[reg].forward;
} else
return simulator.reg[reg].content;
}
throw Error(ERROR_MIPS_REG_OUTRANGE, reg);
}
void CExecInst::SetRegContent(UINT reg, int content)
{
if( reg < 32 ) {
if( reg > 0 ) {// R0 is always be 0
simulator.reg[reg].content = content;
if( simulator.reg[reg].write_count > 0 )
simulator.reg[reg].write_count--;
if( simulator.reg[reg].write_count == 0 )
simulator.reg[reg].status = kReady;
else
simulator.reg[reg].status = kWrite;
}
} else
throw Error(ERROR_MIPS_REG_OUTRANGE, reg);
}
void CExecInst::SetRegForward(UINT reg, int forward)
{
if( reg < 31 ) {
// R0 is always be 0
if( reg > 0 && simulator.m_bForwardingEnable ) {
simulator.reg[reg].forward = forward;
m_bForward = TRUE;
}
} else
throw Error(ERROR_MIPS_REG_OUTRANGE, reg);
}
void CExecInst::SetRegStatus(UINT reg, int status)
{
if( reg < 31 ) {
if( reg > 0 ) {// R0 is always be 0
simulator.reg[reg].status = status;
if( status == kWrite )
simulator.reg[reg].write_count++;
}
} else
throw Error(ERROR_MIPS_REG_OUTRANGE, reg);
}
int CExecInst::GetImm()
{
if( pInst->m_inst.type == TYPE_I )
return (int)pInst->m_inst.inst.i.imm;
return 0;
}
//
/////////////////////////////////////////////////////////
int CExecInst::ReadMem(UINT address)
{
if( address < simulator.m_nDataSize )
return simulator.data[address/4];
throw Error(ERROR_MIPS_MEM_OUTRANGE, address);
}
void CExecInst::WriteMem(UINT address, int content)
{
if( address < simulator.m_nDataSize )
simulator.data[address/4] = content;
else
throw Error(ERROR_MIPS_MEM_OUTRANGE, address);
}
/////////////////////////////////////////////////////////
// Stage Operations
// IF
void CExecInst::stageIF()
{
if( m_bStall ) {
// stall this cycle, remain in stage IF
m_nLastStage = STALL;
m_bStall = FALSE;
} else if( m_bIdle ) {
// clear cpu registers and go to next stage
m_nLastStage = IDLE;
m_nCurStage = ID;
simulator.ClearIFIDReg();
} else {
// put results into IF/ID registers and
// go to next stage
m_nLastStage = IF;
m_nCurStage = ID;// Go to next cycle
simulator.PC += 4;
simulator.IFID.IR = pInst;
simulator.IFID.NPC = simulator.PC;
}
}
// ID
void CExecInst::stageID()
{
if( m_bStall ) {
// stall this cycle, remain in stage ID
m_nLastStage = STALL;
m_bStall = FALSE;
} else if( m_bIdle ) {
// Read in the next instruction.
// clear cpu registers and go to next stage
FetchInst();
m_nLastStage = IDLE;
m_nCurStage = EX;
simulator.ClearIDEXReg();
} else {
// Read in the next instruction, decode
// Put results into ID/EX registers and go to next stage.
m_nLastStage = ID;
m_nCurStage = EX;// Go to next cycle
switch( pInst->m_inst.type ) {
case TYPE_R:
// fetch next instruction
if( next == NULL ) FetchInst();
SetRegStatus(pInst->m_inst.inst.r.rd, kWrite);
simulator.IDEX.A = GetRegContent(pInst->m_inst.inst.r.rs);
simulator.IDEX.B = GetRegContent(pInst->m_inst.inst.r.rt);
simulator.IDEX.Imm = 0;
simulator.IDEX.IR = pInst;
// If forwarding is disable, check data hazards
if( !simulator.m_bForwardingEnable &&
(GetRegStatus(pInst->m_inst.inst.r.rs) == kWrite ||
GetRegStatus(pInst->m_inst.inst.r.rt) == kWrite) ) {
m_nLastStage = STALL;
m_nCurStage = ID;
if( next ) next->Stall();
return;
}
break;
case TYPE_I:
// set register status
if( pInst->m_key != SW && pInst->m_key != BEQZ &&
pInst->m_key != BNEZ && pInst->m_key != JR )
SetRegStatus(pInst->m_inst.inst.i.rt, kWrite);
simulator.IDEX.A = GetRegContent(pInst->m_inst.inst.i.rs);
simulator.IDEX.B = GetRegContent(pInst->m_inst.inst.i.rt);
simulator.IDEX.Imm = GetImm();
simulator.IDEX.IR = pInst;
// If forwarding is disable, check data hazards
if( !simulator.m_bForwardingEnable &&
(GetRegStatus(pInst->m_inst.inst.r.rs) == kWrite ||
(pInst->m_key == SW)?(GetRegStatus(pInst->m_inst.inst.r.rt) == kWrite):FALSE) ) {
m_nLastStage = STALL;
m_nCurStage = ID;
if( next ) next->Stall();
return;
}
// For BEQZ and BNEZ, use different Branch strategies
if( pInst->m_key == BEQZ || pInst->m_key == BNEZ || pInst->m_key == JR ) {
// Methods
if( simulator.m_nBranchMethod == CMIPSSimulator::kFreeze ||
simulator.m_nBranchMethod == CMIPSSimulator::kPredictedTaken ) {
// Freeze and Branch-Taken methods,
// they are the same in 5-stage integer pipeline
// read in the next instruction, NOP
if( !next ) Freeze();
} else {
// Predicted-Not-Taken and Delayed slot,
// fetch the next instruction
// read in the next instruction, NORMAL
if( !next ) FetchInst();
}
if( HasDataHazards(pInst->m_inst.inst.i.rs) ) {
// Data hazzard, stall
m_nLastStage = STALL;
m_nCurStage = ID;
if( next ) next->Stall();
return;
}
// for conditional branch BEQZ and BNEZ
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -