📄 mipssimulator.cpp
字号:
// MIPSSimulator.cpp : implementation file
//
#include "stdafx.h"
#include "pipeline.h"
#include "MIPSSimulator.h"
#include "Error.h"
#include <malloc.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
CString MIPSStage[] =
{
"IF", "ID", "EX", "MEM", "WB", "STALL", "IDLE", "COMPLETE"
};
/////////////////////////////////////////////////////////
// Global
CMIPSSimulator simulator;
/////////////////////////////////////////////////////////
// CLASS CMIPSSIMULATOR
/////////////////////////////////////////////////////////
// Construction
CMIPSSimulator::CMIPSSimulator()
{
m_pInsts = NULL;
m_pExecInsts = new CExecInst(1);
data = NULL;
/****************************************
* Configurations
****************************************/
m_bForwardingEnable = TRUE;
m_nBranchMethod = kFreeze;
// delays
m_nAddDelay = 1;
m_nMulDelay = 5;
m_nDivDelay = 19;
// ALU numbers
m_nAddNum = 1;
m_nMulNum = 1;
m_nDivNum = 1;
// is ALU pipelined
m_bAddPipelined = TRUE;
m_bMulPipelined = TRUE;
m_bDivPipelined = FALSE;
// memory
m_nMemSize = 0x1000;
m_nDataSize = 0x100;
m_bBigEnding = FALSE;
Reset();
}
CMIPSSimulator::~CMIPSSimulator()
{
if( m_pExecInsts ) delete m_pExecInsts;
if( m_pInsts ) delete m_pInsts;
if( data ) free( data );
if( data_bak ) free( data_bak );
if( m_TraceFile.m_hFile != CFile::hFileNull )
m_TraceFile.Close();
}
void CMIPSSimulator::ResetProgram()
{
m_bTrace = FALSE;
m_bNewStep = FALSE;
m_nState = kNone;
// Program Counter
PC = m_nDataSize;
if( m_pExecInsts->next ) {
delete m_pExecInsts->next;
m_pExecInsts->next = NULL;
}
if( m_pInsts ) { delete m_pInsts; m_pInsts = NULL; }
memset( &STAT, 0, sizeof(STAT) );
}
void CMIPSSimulator::Reset()
{
m_bTrace = FALSE;
m_bNewStep = FALSE;
m_nState = kNone;
// Program Counter
PC = m_nDataSize;
if( m_pExecInsts->next ) {
delete m_pExecInsts->next;
m_pExecInsts->next = NULL;
}
if( m_pInsts ) { delete m_pInsts; m_pInsts = NULL; }
if( data ) memset( data, 0, m_nDataSize );
memset( reg, 0, sizeof(reg) );
memset( &STAT, 0, sizeof(STAT) );
ClearIFIDReg();
ClearIDEXReg();
ClearEXMEMReg();
ClearMUL_EXMEMReg();
ClearDIV_EXMEMReg();
ClearMEMWBReg();
ClearMUL_MEMWBReg();
ClearDIV_MEMWBReg();
}
void CMIPSSimulator::CreateDataMem()
{
if( data == NULL ) {
data = (int*)malloc( m_nDataSize );
memset( data, 0, m_nDataSize );
} else {
UINT len = _msize( data );
if( m_nDataSize != len )
data = (int*)realloc( data, m_nDataSize );
if( len < m_nDataSize )
memset( &data[len/4], 0, m_nDataSize - len );
}
if( m_pInsts ) {
PC = m_nDataSize;
// asign addresses
AsignAddress();
// Resolve labels in J-TYPE instructions
ResolveLabels();
}
}
void CMIPSSimulator::ClearDataMem()
{
memset( data, 0, _msize(data) );
}
void CMIPSSimulator::FreeDataMem()
{
free( data ); data = NULL;
}
void CMIPSSimulator::BackupMem()
{
data_bak = (int*)realloc(data_bak, _msize(data));
memcpy( data_bak, data, _msize(data) );
}
void CMIPSSimulator::RollBackMem()
{
ASSERT( _msize(data) == _msize(data_bak) );
memcpy( data, data_bak, _msize(data) );
}
void CMIPSSimulator::BackupReg()
{
for( int i = 0; i < 32; i++ )
reg_bak[i] = reg[i].content;
}
void CMIPSSimulator::RollBackReg()
{
CSlot slot;
for( int i = 0; i < 32; i++ ) {
slot.content = reg_bak[i];
reg[i] = slot;
}
}
BOOL CMIPSSimulator::IsReadyForExec()
{
if( data && m_pInsts && m_pInsts->m_instList.GetCount() )
return TRUE;
return FALSE;
}
BOOL CMIPSSimulator::LoadInstFromFile( LPCTSTR pathname )
{
CFile cfile;
// open the file
try {
cfile.Open( pathname, CFile::modeRead );
} catch( CFileException& ) {
CString temp;
temp.Format( "failed to open\n%s", pathname );
AfxMessageBox( temp );
return FALSE;
}
// read the whole content
CString strBuf;
char buf[ 4100 ];
int len = 0;
try {
while( (len = cfile.Read(buf, 4096)) > 0 ) {
buf[len] = '\0';
strBuf += (CString)buf;
}
strBuf += "\r\n";
} catch( CFileException& ) {
CString temp;
temp.Format( "error occurs while reading\n%s", pathname );
AfxMessageBox( temp );
cfile.Close();
return FALSE;
}
cfile.Close();// close the file
try {
// construct the Instructions object
m_pInsts = new CInstructions( strBuf );
if( m_pInsts->m_instList.IsEmpty() ) {
delete m_pInsts; m_pInsts = NULL;
return FALSE;
}
// asign addresses
AsignAddress();
// Resolve labels in J-TYPE instructions
ResolveLabels();
} catch( Error& e ) {
AfxMessageBox( e.GetStrError() );
return FALSE;
}
strBuf.Empty();
return TRUE;
}
BOOL CMIPSSimulator::Trace( LPCTSTR pathname )
{
// close the file if necessary
if( m_TraceFile.m_hFile != CFile::hFileNull )
m_TraceFile.Close();
// create the output file
CFileException e;
if( !m_TraceFile.Open( pathname, CFile::modeCreate |
CFile::modeWrite, &e ) ) {
CString temp;
temp.Format( "failed to open %s\n%s", pathname, e.m_cause );
AfxMessageBox( temp );
return FALSE;
}
m_bTrace = TRUE;
return TRUE;
}
void CMIPSSimulator::StopTrace()
{
if( m_TraceFile.m_hFile != CFile::hFileNull )
m_TraceFile.Close();
}
/////////////////////////////////////////////////////////
// Asign memory addresses and Resolve labels
void CMIPSSimulator::AsignAddress()
{
UINT address = m_nDataSize;
POSITION pos = m_pInsts->m_instList.GetHeadPosition();
while( pos ) {
CAsmInstruction* pInst = m_pInsts->m_instList.GetNext( pos );
pInst->m_nAddress = address;
address += 4;
}
}
int CMIPSSimulator::FindTargetAddress( CString& target )
{
POSITION pos = m_pInsts->m_instList.GetHeadPosition();
while( pos ) {
CAsmInstruction* pInst = m_pInsts->m_instList.GetNext( pos );
if( pInst->m_strLabel == target )
return pInst->m_nAddress;
}
return -1;
}
void CMIPSSimulator::ResolveLabels()
{
POSITION pos = m_pInsts->m_instList.GetHeadPosition();
while( pos ) {
CAsmInstruction* pInst = m_pInsts->m_instList.GetNext( pos );
if( pInst->m_key == J || pInst->m_key == BEQZ || pInst->m_key == BNEZ ) {
int address = FindTargetAddress( pInst->m_inst.target );
if( address < 0 )
throw Error( ERROR_ASM_TARGET, 0, pInst->m_inst.target );
if( pInst->m_key == J )
pInst->m_inst.inst.j.offset = address>>2;
else {
int offset = address - pInst->m_nAddress - 4;
pInst->m_inst.inst.i.imm = offset;
}
}
}
}
int CMIPSSimulator::FindIndexFromAddress( UINT address )
{
int index = 0;
POSITION pos = m_pInsts->m_instList.GetHeadPosition();
while( pos ) {
CAsmInstruction* pInst;
pInst = m_pInsts->m_instList.GetNext( pos );
if( pInst->m_nAddress == address )
return index;
index++;
}
return -1;
}
//
/////////////////////////////////////////////////////////
// Clear MIPS CPU Registers
void CMIPSSimulator::ClearIFIDReg()
{
IFID.NPC = 0;
IFID.IR = NULL;
}
void CMIPSSimulator::ClearIDEXReg()
{
IDEX.A = 0;
IDEX.B = 0;
IDEX.Imm = 0;
IDEX.IR = NULL;
}
void CMIPSSimulator::ClearEXMEMReg()
{
EXMEM.ALUOutput = 0;
EXMEM.B = 0;
EXMEM.IR = NULL;
}
void CMIPSSimulator::ClearMUL_EXMEMReg()
{
MUL_EXMEM.ALUOutput = 0;
MUL_EXMEM.B = 0;
MUL_EXMEM.IR = NULL;
}
void CMIPSSimulator::ClearDIV_EXMEMReg()
{
DIV_EXMEM.ALUOutput = 0;
DIV_EXMEM.B = 0;
DIV_EXMEM.IR = NULL;
}
void CMIPSSimulator::ClearMEMWBReg()
{
MEMWB.ALUOutput = 0;
MEMWB.LMD = 0;
MEMWB.IR = NULL;
}
void CMIPSSimulator::ClearMUL_MEMWBReg()
{
MUL_MEMWB.ALUOutput = 0;
MUL_MEMWB.LMD = 0;
MUL_MEMWB.IR = NULL;
}
void CMIPSSimulator::ClearDIV_MEMWBReg()
{
DIV_MEMWB.ALUOutput = 0;
DIV_MEMWB.LMD = 0;
DIV_MEMWB.IR = NULL;
}
//
// Set Program Counter
BOOL CMIPSSimulator::SetPC(UINT address)
{
POSITION pos = m_pInsts->m_instList.GetHeadPosition();
while( pos ) {
CAsmInstruction* pInst = m_pInsts->m_instList.GetNext( pos );
if( pInst->m_nAddress == address ) {
PC = address;
return TRUE;
}
}
return FALSE;
}
// fetch instruction pointed by PC;
CAsmInstruction* CMIPSSimulator::FetchInst()
{
CAsmInstruction* pInst = NULL;
POSITION pos = m_pInsts->m_instList.GetHeadPosition();
while( pos ) {
pInst = m_pInsts->m_instList.GetNext( pos );
if( pInst->m_nAddress == PC ) {
CalcStat( pInst );
m_bNewStep = TRUE;
/*
* trace instructions
*/
if( m_bTrace ) {
CString temp;
temp.Format( "STEP:%3d CYCLE:%3d %s\r\n", GetCurStep(),
GetCurCycle() + 1, (LPCTSTR)pInst->InstWithLabelAddress() );
try {
m_TraceFile.Write( (LPCTSTR)temp, temp.GetLength() );
m_TraceFile.Flush();
} catch( CFileException* e ) {
temp.Format( "%s", e->m_cause );
AfxMessageBox( temp );
}
}
return pInst;
}
}
return NULL;
}
void CMIPSSimulator::CalcStat(CAsmInstruction* pInst)
{
STAT.steps++;
// increase instruction count
int* p = (int*)&STAT;
p[(int)pInst->m_key]++;
}
/////////////////////////////////////////////////////////
// Execution
void CMIPSSimulator::Start()
{
ASSERT( m_pExecInsts->next == NULL );
ASSERT( data != NULL );
// trace
if( m_bTrace ) {
CString temp = _T("Program start:\r\n");
m_TraceFile.Write( (LPCTSTR)temp, temp.GetLength() );
m_TraceFile.Flush();
}
m_nState = kRun;
BackupMem();
BackupReg();
m_nStartPC = PC;
m_pExecInsts->m_nCurCycle = 1;
m_pExecInsts->FetchInst();
STAT.cycles = 0;
}
void CMIPSSimulator::NextCycle()
{
if( m_nState == kComplete ) return;
if( IsExecComplete() ) m_nState = kComplete;
m_bNewStep = FALSE;
m_nLastPC = PC;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -