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