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