1 #include <stdio.h>
2 #include <string.h>
3 #include "MIPS.h"
4 #include "COP_SCU.h"
5 
6 // clang-format off
7 const char* CMIPS::m_sGPRName[] =
8 {
9     "R0", "AT", "V0", "V1", "A0", "A1", "A2", "A3",
10     "T0", "T1", "T2", "T3", "T4", "T5", "T6", "T7",
11     "S0", "S1", "S2", "S3", "S4", "S5", "S6", "S7",
12     "T8", "T9", "K0", "K1", "GP", "SP", "FP", "RA"
13 };
14 // clang-format on
15 
CMIPS(MEMORYMAP_ENDIANESS endianess,bool usePageTable)16 CMIPS::CMIPS(MEMORYMAP_ENDIANESS endianess, bool usePageTable)
17 {
18 	m_analysis = new CMIPSAnalysis(this);
19 	switch(endianess)
20 	{
21 	case MEMORYMAP_ENDIAN_LSBF:
22 		m_pMemoryMap = new CMemoryMap_LSBF;
23 		break;
24 	case MEMORYMAP_ENDIAN_MSBF:
25 		//
26 		break;
27 	}
28 
29 	if(usePageTable)
30 	{
31 		const uint32 pageCount = 0x100000000ULL / MIPS_PAGE_SIZE;
32 		m_pageLookup = new void*[pageCount];
33 		for(uint32 i = 0; i < pageCount; i++)
34 		{
35 			m_pageLookup[i] = nullptr;
36 		}
37 	}
38 
39 	m_pCOP[0] = nullptr;
40 	m_pCOP[1] = nullptr;
41 	m_pCOP[2] = nullptr;
42 	m_pCOP[3] = nullptr;
43 
44 	Reset();
45 }
46 
~CMIPS()47 CMIPS::~CMIPS()
48 {
49 	delete m_pMemoryMap;
50 	delete m_analysis;
51 	delete[] m_pageLookup;
52 }
53 
Reset()54 void CMIPS::Reset()
55 {
56 	memset(&m_State, 0, sizeof(MIPSSTATE));
57 	m_State.nDelayedJumpAddr = MIPS_INVALID_PC;
58 
59 	//Reset FCSR
60 	m_State.nFCSR = 0x01000001;
61 
62 	//Set VF0[w] to 1.0
63 	m_State.nCOP2[0].nV3 = 0x3F800000;
64 }
65 
ToggleBreakpoint(uint32 address)66 void CMIPS::ToggleBreakpoint(uint32 address)
67 {
68 	if(m_breakpoints.find(address) != m_breakpoints.end())
69 	{
70 		m_breakpoints.erase(address);
71 	}
72 	else
73 	{
74 		m_breakpoints.insert(address);
75 	}
76 	m_executor->ClearActiveBlocksInRange(address, address + 4, false);
77 }
78 
HasBreakpointInRange(uint32 begin,uint32 end) const79 bool CMIPS::HasBreakpointInRange(uint32 begin, uint32 end) const
80 {
81 	for(auto breakpointAddress : m_breakpoints)
82 	{
83 		if((breakpointAddress >= begin) && (breakpointAddress <= end)) return true;
84 	}
85 	return false;
86 }
87 
GetBranch(uint16 nData)88 int32 CMIPS::GetBranch(uint16 nData)
89 {
90 	if(nData & 0x8000)
91 	{
92 		return -((0x10000 - nData) * 4);
93 	}
94 	else
95 	{
96 		return ((nData & 0x7FFF) * 4);
97 	}
98 }
99 
IsBranch(uint32 nAddress)100 bool CMIPS::IsBranch(uint32 nAddress)
101 {
102 	uint32 nOpcode = m_pMemoryMap->GetInstruction(nAddress);
103 	return m_pArch->IsInstructionBranch(this, nAddress, nOpcode) == MIPS_BRANCH_NORMAL;
104 }
105 
TranslateAddress64(CMIPS * pC,uint32 nVAddrLO)106 uint32 CMIPS::TranslateAddress64(CMIPS* pC, uint32 nVAddrLO)
107 {
108 	//Proper address translation?
109 	return nVAddrLO & 0x1FFFFFFF;
110 }
111 
CanGenerateInterrupt() const112 bool CMIPS::CanGenerateInterrupt() const
113 {
114 	//Check if interrupts are enabled
115 	if(!(m_State.nCOP0[CCOP_SCU::STATUS] & STATUS_IE)) return false;
116 
117 	//Check if we're in exception mode (interrupts are disabled in exception mode)
118 	if(m_State.nCOP0[CCOP_SCU::STATUS] & STATUS_EXL) return false;
119 
120 	return true;
121 }
122 
GenerateInterrupt(uint32 nAddress)123 bool CMIPS::GenerateInterrupt(uint32 nAddress)
124 {
125 	if(!CanGenerateInterrupt()) return false;
126 	return CMIPS::GenerateException(nAddress);
127 }
128 
GenerateException(uint32 nAddress)129 bool CMIPS::GenerateException(uint32 nAddress)
130 {
131 	//Save exception PC
132 	if(m_State.nDelayedJumpAddr != MIPS_INVALID_PC)
133 	{
134 		m_State.nCOP0[CCOP_SCU::EPC] = m_State.nPC - 4;
135 		//m_State.nCOP0[CCOP_SCU::EPC] = m_State.nDelayedJumpAddr;
136 	}
137 	else
138 	{
139 		m_State.nCOP0[CCOP_SCU::EPC] = m_State.nPC;
140 	}
141 
142 	m_State.nDelayedJumpAddr = MIPS_INVALID_PC;
143 
144 	m_State.nPC = nAddress;
145 
146 	//Set in exception mode
147 	m_State.nCOP0[CCOP_SCU::STATUS] |= STATUS_EXL;
148 
149 	return true;
150 }
151 
MapPages(uint32 vAddress,uint32 size,uint8 * memory)152 void CMIPS::MapPages(uint32 vAddress, uint32 size, uint8* memory)
153 {
154 	assert(m_pageLookup);
155 	assert((vAddress % MIPS_PAGE_SIZE) == 0);
156 	assert((size % MIPS_PAGE_SIZE) == 0);
157 	uint32 pageBase = vAddress / MIPS_PAGE_SIZE;
158 	for(uint32 pageIndex = 0; pageIndex < (size / MIPS_PAGE_SIZE); pageIndex++)
159 	{
160 		m_pageLookup[pageBase + pageIndex] = memory + (MIPS_PAGE_SIZE * pageIndex);
161 	}
162 }
163