2007-12-22 05:25:57 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "MIPS.h"
|
|
|
|
#include "COP_SCU.h"
|
|
|
|
|
2019-04-17 13:10:01 -04:00
|
|
|
// clang-format off
|
2007-12-22 05:25:57 +00:00
|
|
|
const char* CMIPS::m_sGPRName[] =
|
2019-04-17 13:10:01 -04:00
|
|
|
{
|
|
|
|
"R0", "AT", "V0", "V1", "A0", "A1", "A2", "A3",
|
|
|
|
"T0", "T1", "T2", "T3", "T4", "T5", "T6", "T7",
|
|
|
|
"S0", "S1", "S2", "S3", "S4", "S5", "S6", "S7",
|
|
|
|
"T8", "T9", "K0", "K1", "GP", "SP", "FP", "RA"
|
|
|
|
};
|
|
|
|
// clang-format on
|
2007-12-22 05:25:57 +00:00
|
|
|
|
2019-04-17 13:11:35 -04:00
|
|
|
CMIPS::CMIPS(MEMORYMAP_ENDIANESS endianess, bool usePageTable)
|
2007-12-22 05:25:57 +00:00
|
|
|
{
|
2014-08-16 21:42:19 -04:00
|
|
|
m_analysis = new CMIPSAnalysis(this);
|
2019-04-17 13:11:35 -04:00
|
|
|
switch(endianess)
|
2007-12-22 05:25:57 +00:00
|
|
|
{
|
|
|
|
case MEMORYMAP_ENDIAN_LSBF:
|
|
|
|
m_pMemoryMap = new CMemoryMap_LSBF;
|
|
|
|
break;
|
|
|
|
case MEMORYMAP_ENDIAN_MSBF:
|
|
|
|
//
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-04-17 13:11:35 -04:00
|
|
|
if(usePageTable)
|
|
|
|
{
|
|
|
|
const uint32 pageCount = 0x100000000ULL / MIPS_PAGE_SIZE;
|
|
|
|
m_pageLookup = new void*[pageCount];
|
|
|
|
for(uint32 i = 0; i < pageCount; i++)
|
|
|
|
{
|
|
|
|
m_pageLookup[i] = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-08 15:59:24 -04:00
|
|
|
m_pCOP[0] = nullptr;
|
|
|
|
m_pCOP[1] = nullptr;
|
|
|
|
m_pCOP[2] = nullptr;
|
|
|
|
m_pCOP[3] = nullptr;
|
2007-12-22 05:25:57 +00:00
|
|
|
|
2008-05-02 15:00:27 +00:00
|
|
|
Reset();
|
2007-12-22 05:25:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CMIPS::~CMIPS()
|
|
|
|
{
|
2014-08-16 21:42:19 -04:00
|
|
|
delete m_pMemoryMap;
|
|
|
|
delete m_analysis;
|
2019-04-17 20:05:27 -04:00
|
|
|
delete[] m_pageLookup;
|
2007-12-22 05:25:57 +00:00
|
|
|
}
|
|
|
|
|
2008-05-02 15:00:27 +00:00
|
|
|
void CMIPS::Reset()
|
|
|
|
{
|
|
|
|
memset(&m_State, 0, sizeof(MIPSSTATE));
|
|
|
|
m_State.nDelayedJumpAddr = MIPS_INVALID_PC;
|
|
|
|
|
2017-01-04 15:08:16 -05:00
|
|
|
//Reset FCSR
|
|
|
|
m_State.nFCSR = 0x01000001;
|
|
|
|
|
2008-05-02 15:00:27 +00:00
|
|
|
//Set VF0[w] to 1.0
|
|
|
|
m_State.nCOP2[0].nV3 = 0x3F800000;
|
|
|
|
}
|
|
|
|
|
2007-12-22 05:25:57 +00:00
|
|
|
void CMIPS::ToggleBreakpoint(uint32 address)
|
|
|
|
{
|
2012-03-13 06:16:33 +00:00
|
|
|
if(m_breakpoints.find(address) != m_breakpoints.end())
|
2007-12-22 05:25:57 +00:00
|
|
|
{
|
2012-03-13 06:16:33 +00:00
|
|
|
m_breakpoints.erase(address);
|
2007-12-22 05:25:57 +00:00
|
|
|
}
|
2018-07-21 20:49:58 -04:00
|
|
|
else
|
|
|
|
{
|
|
|
|
m_breakpoints.insert(address);
|
|
|
|
}
|
|
|
|
m_executor->ClearActiveBlocksInRange(address, address + 4, false);
|
2007-12-22 05:25:57 +00:00
|
|
|
}
|
|
|
|
|
2020-02-06 07:44:19 -05:00
|
|
|
bool CMIPS::HasBreakpointInRange(uint32 begin, uint32 end) const
|
|
|
|
{
|
|
|
|
for(auto breakpointAddress : m_breakpoints)
|
|
|
|
{
|
|
|
|
if((breakpointAddress >= begin) && (breakpointAddress <= end)) return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-03-04 19:03:37 -08:00
|
|
|
int32 CMIPS::GetBranch(uint16 nData)
|
2007-12-22 05:25:57 +00:00
|
|
|
{
|
|
|
|
if(nData & 0x8000)
|
|
|
|
{
|
|
|
|
return -((0x10000 - nData) * 4);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return ((nData & 0x7FFF) * 4);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CMIPS::IsBranch(uint32 nAddress)
|
|
|
|
{
|
2011-12-10 20:49:50 +00:00
|
|
|
uint32 nOpcode = m_pMemoryMap->GetInstruction(nAddress);
|
|
|
|
return m_pArch->IsInstructionBranch(this, nAddress, nOpcode) == MIPS_BRANCH_NORMAL;
|
2007-12-22 05:25:57 +00:00
|
|
|
}
|
|
|
|
|
2012-04-16 02:34:36 +00:00
|
|
|
uint32 CMIPS::TranslateAddress64(CMIPS* pC, uint32 nVAddrLO)
|
2007-12-22 05:25:57 +00:00
|
|
|
{
|
|
|
|
//Proper address translation?
|
|
|
|
return nVAddrLO & 0x1FFFFFFF;
|
|
|
|
}
|
|
|
|
|
2017-06-15 10:43:42 -04:00
|
|
|
bool CMIPS::CanGenerateInterrupt() const
|
2007-12-22 05:25:57 +00:00
|
|
|
{
|
|
|
|
//Check if interrupts are enabled
|
2015-04-13 00:24:35 -04:00
|
|
|
if(!(m_State.nCOP0[CCOP_SCU::STATUS] & STATUS_IE)) return false;
|
2007-12-22 05:25:57 +00:00
|
|
|
|
|
|
|
//Check if we're in exception mode (interrupts are disabled in exception mode)
|
2008-05-13 21:43:29 +00:00
|
|
|
if(m_State.nCOP0[CCOP_SCU::STATUS] & STATUS_EXL) return false;
|
2007-12-22 05:25:57 +00:00
|
|
|
|
2017-06-15 10:43:42 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CMIPS::GenerateInterrupt(uint32 nAddress)
|
|
|
|
{
|
|
|
|
if(!CanGenerateInterrupt()) return false;
|
2007-12-22 05:25:57 +00:00
|
|
|
return CMIPS::GenerateException(nAddress);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CMIPS::GenerateException(uint32 nAddress)
|
|
|
|
{
|
|
|
|
//Save exception PC
|
|
|
|
if(m_State.nDelayedJumpAddr != MIPS_INVALID_PC)
|
|
|
|
{
|
|
|
|
m_State.nCOP0[CCOP_SCU::EPC] = m_State.nPC - 4;
|
|
|
|
//m_State.nCOP0[CCOP_SCU::EPC] = m_State.nDelayedJumpAddr;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_State.nCOP0[CCOP_SCU::EPC] = m_State.nPC;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_State.nDelayedJumpAddr = MIPS_INVALID_PC;
|
|
|
|
|
|
|
|
m_State.nPC = nAddress;
|
|
|
|
|
|
|
|
//Set in exception mode
|
2011-10-23 20:19:51 +00:00
|
|
|
m_State.nCOP0[CCOP_SCU::STATUS] |= STATUS_EXL;
|
2007-12-22 05:25:57 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2019-04-17 13:11:35 -04:00
|
|
|
|
|
|
|
void CMIPS::MapPages(uint32 vAddress, uint32 size, uint8* memory)
|
|
|
|
{
|
|
|
|
assert(m_pageLookup);
|
|
|
|
assert((vAddress % MIPS_PAGE_SIZE) == 0);
|
|
|
|
assert((size % MIPS_PAGE_SIZE) == 0);
|
|
|
|
uint32 pageBase = vAddress / MIPS_PAGE_SIZE;
|
|
|
|
for(uint32 pageIndex = 0; pageIndex < (size / MIPS_PAGE_SIZE); pageIndex++)
|
|
|
|
{
|
|
|
|
m_pageLookup[pageBase + pageIndex] = memory + (MIPS_PAGE_SIZE * pageIndex);
|
|
|
|
}
|
|
|
|
}
|