-
-
Notifications
You must be signed in to change notification settings - Fork 270
/
Copy pathMIPS.cpp
162 lines (138 loc) · 3.36 KB
/
MIPS.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#include <stdio.h>
#include <string.h>
#include "MIPS.h"
#include "COP_SCU.h"
// clang-format off
const char* CMIPS::m_sGPRName[] =
{
"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
CMIPS::CMIPS(MEMORYMAP_ENDIANNESS endianness, bool usePageTable)
{
m_analysis = new CMIPSAnalysis(this);
switch(endianness)
{
case MEMORYMAP_ENDIAN_LSBF:
m_pMemoryMap = new CMemoryMap_LSBF;
break;
case MEMORYMAP_ENDIAN_MSBF:
//
break;
}
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;
}
}
m_pCOP[0] = nullptr;
m_pCOP[1] = nullptr;
m_pCOP[2] = nullptr;
m_pCOP[3] = nullptr;
Reset();
}
CMIPS::~CMIPS()
{
delete m_pMemoryMap;
delete m_analysis;
delete[] m_pageLookup;
}
void CMIPS::Reset()
{
memset(&m_State, 0, sizeof(MIPSSTATE));
m_State.nDelayedJumpAddr = MIPS_INVALID_PC;
//Reset FCSR
m_State.nFCSR = 0x01000001;
//Set VF0[w] to 1.0
m_State.nCOP2[0].nV3 = 0x3F800000;
}
void CMIPS::ToggleBreakpoint(uint32 address)
{
if(m_breakpoints.find(address) != m_breakpoints.end())
{
m_breakpoints.erase(address);
}
else
{
m_breakpoints.insert(address);
}
m_executor->ClearActiveBlocksInRange(address, address 4, false);
}
bool CMIPS::HasBreakpointInRange(uint32 begin, uint32 end) const
{
for(auto breakpointAddress : m_breakpoints)
{
if((breakpointAddress >= begin) && (breakpointAddress <= end)) return true;
}
return false;
}
int32 CMIPS::GetBranch(uint16 nData)
{
if(nData & 0x8000)
{
return -((0x10000 - nData) * 4);
}
else
{
return ((nData & 0x7FFF) * 4);
}
}
bool CMIPS::IsBranch(uint32 nAddress)
{
uint32 nOpcode = m_pMemoryMap->GetInstruction(nAddress);
return m_pArch->IsInstructionBranch(this, nAddress, nOpcode) == MIPS_BRANCH_NORMAL;
}
uint32 CMIPS::TranslateAddress64(CMIPS* pC, uint32 nVAddrLO)
{
//Proper address translation?
return nVAddrLO & 0x1FFFFFFF;
}
bool CMIPS::CanGenerateInterrupt() const
{
//Check if interrupts are enabled
if(!(m_State.nCOP0[CCOP_SCU::STATUS] & STATUS_IE)) return false;
//Check if we're in exception mode (interrupts are disabled in exception mode)
if(m_State.nCOP0[CCOP_SCU::STATUS] & STATUS_EXL) return false;
return true;
}
bool CMIPS::GenerateInterrupt(uint32 nAddress)
{
if(!CanGenerateInterrupt()) return false;
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
m_State.nCOP0[CCOP_SCU::STATUS] |= STATUS_EXL;
return true;
}
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);
}
}