1 #include <string.h>
2 #include <stdio.h>
3 #include <stddef.h>
4 #include "COP_SCU.h"
5 #include "MIPS.h"
6 #include "Jitter.h"
7 #include "offsetof_def.h"
8
9 // clang-format off
10 const char* CCOP_SCU::m_sRegName[] =
11 {
12 "Index",
13 "Random",
14 "EntryLo0",
15 "EntryLo1",
16 "Context",
17 "PageMask",
18 "Wired",
19 "*RESERVED*",
20 "BadVAddr",
21 "Count",
22 "EntryHi",
23 "Compare",
24 "Status",
25 "Cause",
26 "EPC",
27 "PrevID",
28 "Config",
29 "LLAddr",
30 "WatchLo",
31 "WatchHi",
32 "XContext",
33 "CPCOND0",
34 "*RESERVED*",
35 "*RESERVED*",
36 "*RESERVED*",
37 "*RESERVED*",
38 "PErr",
39 "CacheErr",
40 "TagLo",
41 "TagHi",
42 "ErrorEPC",
43 "*RESERVED*"
44 };
45 // clang-format on
46
CCOP_SCU(MIPS_REGSIZE nRegSize)47 CCOP_SCU::CCOP_SCU(MIPS_REGSIZE nRegSize)
48 : CMIPSCoprocessor(nRegSize)
49 , m_nRT(0)
50 , m_nRD(0)
51 {
52 SetupReflectionTables();
53 }
54
CompileInstruction(uint32 nAddress,CMipsJitter * codeGen,CMIPS * pCtx)55 void CCOP_SCU::CompileInstruction(uint32 nAddress, CMipsJitter* codeGen, CMIPS* pCtx)
56 {
57 SetupQuickVariables(nAddress, codeGen, pCtx);
58
59 m_nRT = (uint8)((m_nOpcode >> 16) & 0x1F);
60 m_nRD = (uint8)((m_nOpcode >> 11) & 0x1F);
61
62 ((this)->*(m_pOpGeneral[(m_nOpcode >> 21) & 0x1F]))();
63 }
64
HandleTLBRead(CMIPS * context)65 void CCOP_SCU::HandleTLBRead(CMIPS* context)
66 {
67 uint32 index = context->m_State.nCOP0[CCOP_SCU::INDEX];
68 assert(index < MIPSSTATE::TLB_ENTRY_MAX);
69 index &= (MIPSSTATE::TLB_ENTRY_MAX - 1);
70
71 const auto& entry = context->m_State.tlbEntries[index];
72 context->m_State.nCOP0[CCOP_SCU::ENTRYLO0] = entry.entryLo0;
73 context->m_State.nCOP0[CCOP_SCU::ENTRYLO1] = entry.entryLo1;
74 context->m_State.nCOP0[CCOP_SCU::ENTRYHI] = entry.entryHi;
75 context->m_State.nCOP0[CCOP_SCU::PAGEMASK] = entry.pageMask;
76 }
77
HandleTLBWrite(CMIPS * context)78 void CCOP_SCU::HandleTLBWrite(CMIPS* context)
79 {
80 uint32 index = context->m_State.nCOP0[CCOP_SCU::INDEX];
81 assert(index < MIPSSTATE::TLB_ENTRY_MAX);
82 index &= (MIPSSTATE::TLB_ENTRY_MAX - 1);
83
84 auto& entry = context->m_State.tlbEntries[index];
85 entry.entryLo0 = context->m_State.nCOP0[CCOP_SCU::ENTRYLO0];
86 entry.entryLo1 = context->m_State.nCOP0[CCOP_SCU::ENTRYLO1];
87 entry.entryHi = context->m_State.nCOP0[CCOP_SCU::ENTRYHI];
88 entry.pageMask = context->m_State.nCOP0[CCOP_SCU::PAGEMASK];
89 }
90
91 //////////////////////////////////////////////////
92 //General Opcodes
93 //////////////////////////////////////////////////
94
95 //00
MFC0()96 void CCOP_SCU::MFC0()
97 {
98 switch(m_nRD)
99 {
100 case 25:
101 switch(m_nOpcode & 1)
102 {
103 case 0:
104 //MFPS
105 m_codeGen->PushRel(offsetof(CMIPS, m_State.cop0_pccr));
106 break;
107 case 1:
108 //MFPC
109 {
110 uint32 reg = (m_nOpcode >> 1) & 1;
111 m_codeGen->PushRel(offsetof(CMIPS, m_State.cop0_pcr[reg]));
112 }
113 break;
114 default:
115 assert(false);
116 break;
117 }
118 break;
119 default:
120 m_codeGen->PushRel(offsetof(CMIPS, m_State.nCOP0[m_nRD]));
121 break;
122 }
123
124 if(m_regSize == MIPS_REGSIZE_64)
125 {
126 m_codeGen->PushTop();
127 m_codeGen->SignExt();
128 m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1]));
129 }
130 m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
131 }
132
133 //04
MTC0()134 void CCOP_SCU::MTC0()
135 {
136 m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
137
138 if(m_nRD == CCOP_SCU::STATUS)
139 {
140 //Keep the EXL bit
141 //This is needed for Valkyrie Profile 2 which resets the EXL bit
142 m_codeGen->PushRel(offsetof(CMIPS, m_State.nCOP0[m_nRD]));
143 m_codeGen->PushCst(CMIPS::STATUS_EXL);
144 m_codeGen->And();
145 m_codeGen->Or();
146 }
147
148 switch(m_nRD)
149 {
150 case 25:
151 switch(m_nOpcode & 1)
152 {
153 case 0:
154 //MTPS
155 {
156 uint32 reg = (m_nOpcode >> 1) & 0x1F;
157 if(reg == 0)
158 {
159 //Mask out bits that stay 0
160 m_codeGen->PushCst(0x800FFBFE);
161 m_codeGen->And();
162 m_codeGen->PullRel(offsetof(CMIPS, m_State.cop0_pccr));
163 }
164 else
165 {
166 //No-op when reg is not 0
167 m_codeGen->PullTop();
168 }
169 }
170 break;
171 case 1:
172 //MTPC
173 {
174 uint32 reg = (m_nOpcode >> 1) & 1;
175 m_codeGen->PullRel(offsetof(CMIPS, m_State.cop0_pcr[reg]));
176 }
177 break;
178 }
179 break;
180 default:
181 m_codeGen->PullRel(offsetof(CMIPS, m_State.nCOP0[m_nRD]));
182 break;
183 }
184 }
185
186 //08
BC0()187 void CCOP_SCU::BC0()
188 {
189 ((this)->*(m_pOpBC0[m_nRT]))();
190 }
191
192 //10
C0()193 void CCOP_SCU::C0()
194 {
195 ((this)->*(m_pOpC0[(m_nOpcode & 0x3F)]))();
196 }
197
198 //////////////////////////////////////////////////
199 //Branches
200 //////////////////////////////////////////////////
201
202 //00
BC0F()203 void CCOP_SCU::BC0F()
204 {
205 m_codeGen->PushRel(offsetof(CMIPS, m_State.nCOP0[CPCOND0]));
206 m_codeGen->PushCst(0);
207 Branch(Jitter::CONDITION_EQ);
208 }
209
210 //01
BC0T()211 void CCOP_SCU::BC0T()
212 {
213 m_codeGen->PushRel(offsetof(CMIPS, m_State.nCOP0[CPCOND0]));
214 m_codeGen->PushCst(0);
215 Branch(Jitter::CONDITION_NE);
216 }
217
218 //02
BC0FL()219 void CCOP_SCU::BC0FL()
220 {
221 m_codeGen->PushRel(offsetof(CMIPS, m_State.nCOP0[CPCOND0]));
222 m_codeGen->PushCst(0);
223 BranchLikely(Jitter::CONDITION_EQ);
224 }
225
226 //////////////////////////////////////////////////
227 //Coprocessor Specific Opcodes
228 //////////////////////////////////////////////////
229
230 //01
TLBR()231 void CCOP_SCU::TLBR()
232 {
233 m_codeGen->PushCtx();
234 m_codeGen->Call(reinterpret_cast<void*>(&CCOP_SCU::HandleTLBRead), 1, Jitter::CJitter::RETURN_VALUE_NONE);
235 }
236
237 //02
TLBWI()238 void CCOP_SCU::TLBWI()
239 {
240 m_codeGen->PushCtx();
241 m_codeGen->Call(reinterpret_cast<void*>(&CCOP_SCU::HandleTLBWrite), 1, Jitter::CJitter::RETURN_VALUE_NONE);
242 }
243
244 //18
ERET()245 void CCOP_SCU::ERET()
246 {
247 m_codeGen->PushRel(offsetof(CMIPS, m_State.nCOP0[STATUS]));
248 m_codeGen->PushCst(CMIPS::STATUS_ERL);
249 m_codeGen->And();
250
251 m_codeGen->PushCst(0);
252 m_codeGen->BeginIf(Jitter::CONDITION_NE);
253 {
254 //ERL bit was set
255 m_codeGen->PushRel(offsetof(CMIPS, m_State.nCOP0[ERROREPC]));
256 m_codeGen->PullRel(offsetof(CMIPS, m_State.nDelayedJumpAddr));
257
258 //Clear ERL bit
259 m_codeGen->PushRel(offsetof(CMIPS, m_State.nCOP0[STATUS]));
260 m_codeGen->PushCst(~CMIPS::STATUS_ERL);
261 m_codeGen->And();
262 m_codeGen->PullRel(offsetof(CMIPS, m_State.nCOP0[STATUS]));
263 }
264 m_codeGen->Else();
265 {
266 //EXL bit was set
267 m_codeGen->PushRel(offsetof(CMIPS, m_State.nCOP0[EPC]));
268 m_codeGen->PullRel(offsetof(CMIPS, m_State.nDelayedJumpAddr));
269
270 //Clear EXL bit
271 m_codeGen->PushRel(offsetof(CMIPS, m_State.nCOP0[STATUS]));
272 m_codeGen->PushCst(~CMIPS::STATUS_EXL);
273 m_codeGen->And();
274 m_codeGen->PullRel(offsetof(CMIPS, m_State.nCOP0[STATUS]));
275 }
276 m_codeGen->EndIf();
277
278 //Force the main loop to do special processing
279 m_codeGen->PushCst(MIPS_EXCEPTION_RETURNFROMEXCEPTION);
280 m_codeGen->PullRel(offsetof(CMIPS, m_State.nHasException));
281 }
282
283 //38
EI()284 void CCOP_SCU::EI()
285 {
286 m_codeGen->PushRel(offsetof(CMIPS, m_State.nCOP0[STATUS]));
287 m_codeGen->PushCst(CMIPS::STATUS_EIE);
288 m_codeGen->Or();
289 m_codeGen->PullRel(offsetof(CMIPS, m_State.nCOP0[STATUS]));
290
291 //Force the main loop to check for pending interrupts
292 m_codeGen->PushCst(MIPS_EXCEPTION_CHECKPENDINGINT);
293 m_codeGen->PullRel(offsetof(CMIPS, m_State.nHasException));
294 }
295
296 //39
DI()297 void CCOP_SCU::DI()
298 {
299 m_codeGen->PushRel(offsetof(CMIPS, m_State.nCOP0[STATUS]));
300 m_codeGen->PushCst(~CMIPS::STATUS_EIE);
301 m_codeGen->And();
302 m_codeGen->PullRel(offsetof(CMIPS, m_State.nCOP0[STATUS]));
303 }
304
305 //////////////////////////////////////////////////
306 //Opcode Tables
307 //////////////////////////////////////////////////
308
309 // clang-format off
310 CCOP_SCU::InstructionFuncConstant CCOP_SCU::m_pOpGeneral[0x20] =
311 {
312 //0x00
313 &CCOP_SCU::MFC0, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::MTC0, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
314 //0x08
315 &CCOP_SCU::BC0, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
316 //0x10
317 &CCOP_SCU::C0, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
318 //0x18
319 &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
320 };
321
322 CCOP_SCU::InstructionFuncConstant CCOP_SCU::m_pOpBC0[0x20] =
323 {
324 //0x00
325 &CCOP_SCU::BC0F, &CCOP_SCU::BC0T, &CCOP_SCU::BC0FL, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
326 //0x08
327 &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
328 //0x10
329 &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
330 //0x18
331 &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
332 };
333
334 CCOP_SCU::InstructionFuncConstant CCOP_SCU::m_pOpC0[0x40] =
335 {
336 //0x00
337 &CCOP_SCU::Illegal, &CCOP_SCU::TLBR, &CCOP_SCU::TLBWI, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
338 //0x08
339 &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
340 //0x10
341 &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
342 //0x18
343 &CCOP_SCU::ERET, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
344 //0x20
345 &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
346 //0x28
347 &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
348 //0x30
349 &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
350 //0x38
351 &CCOP_SCU::EI, &CCOP_SCU::DI, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
352 };
353 // clang-format on
354