1 |
/* |
2 |
* PearPC |
3 |
* ppc_opc.cc |
4 |
* |
5 |
* Copyright (C) 2003 Sebastian Biallas (sb@biallas.net) |
6 |
* Copyright (C) 2004 Dainel Foesch (dfoesch@cs.nmsu.edu) |
7 |
* |
8 |
* This program is free software; you can redistribute it and/or modify |
9 |
* it under the terms of the GNU General Public License version 2 as |
10 |
* published by the Free Software Foundation. |
11 |
* |
12 |
* This program is distributed in the hope that it will be useful, |
13 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 |
* GNU General Public License for more details. |
16 |
* |
17 |
* You should have received a copy of the GNU General Public License |
18 |
* along with this program; if not, write to the Free Software |
19 |
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
20 |
*/ |
21 |
|
22 |
#include "debug/tracers.h" |
23 |
#include "cpu/debug.h" |
24 |
#include "io/pic/pic.h" |
25 |
#include "info.h" |
26 |
#include "ppc_cpu.h" |
27 |
#include "ppc_exc.h" |
28 |
#include "ppc_mmu.h" |
29 |
#include "ppc_opc.h" |
30 |
#include "ppc_dec.h" |
31 |
|
32 |
|
33 |
void ppc_set_msr(uint32 newmsr) |
34 |
{ |
35 |
/* if ((newmsr & MSR_EE) && !(gCPU.msr & MSR_EE)) { |
36 |
if (pic_check_interrupt()) { |
37 |
gCPU.exception_pending = true; |
38 |
gCPU.ext_exception = true; |
39 |
} |
40 |
}*/ |
41 |
ppc_mmu_tlb_invalidate(); |
42 |
#ifndef PPC_CPU_ENABLE_SINGLESTEP |
43 |
if (newmsr & MSR_SE) { |
44 |
SINGLESTEP(""); |
45 |
PPC_CPU_WARN("MSR[SE] (singlestep enable) set, but compiled w/o SE support.\n"); |
46 |
} |
47 |
#else |
48 |
gCPU.singlestep_ignore = true; |
49 |
#endif |
50 |
if (newmsr & PPC_CPU_UNSUPPORTED_MSR_BITS) { |
51 |
PPC_CPU_ERR("unsupported bits in MSR set: %08x @%08x\n", newmsr & PPC_CPU_UNSUPPORTED_MSR_BITS, gCPU.pc); |
52 |
} |
53 |
if (newmsr & MSR_POW) { |
54 |
// doze(); |
55 |
newmsr &= ~MSR_POW; |
56 |
} |
57 |
gCPU.msr = newmsr; |
58 |
|
59 |
} |
60 |
|
61 |
/* |
62 |
* bx Branch |
63 |
* .435 |
64 |
*/ |
65 |
void ppc_opc_bx() |
66 |
{ |
67 |
uint32 li; |
68 |
PPC_OPC_TEMPL_I(gCPU.current_opc, li); |
69 |
if (!(gCPU.current_opc & PPC_OPC_AA)) { |
70 |
li += gCPU.pc; |
71 |
} |
72 |
if (gCPU.current_opc & PPC_OPC_LK) { |
73 |
gCPU.lr = gCPU.pc + 4; |
74 |
} |
75 |
gCPU.npc = li; |
76 |
} |
77 |
|
78 |
/* |
79 |
* bcx Branch Conditional |
80 |
* .436 |
81 |
*/ |
82 |
void ppc_opc_bcx() |
83 |
{ |
84 |
uint32 BO, BI, BD; |
85 |
PPC_OPC_TEMPL_B(gCPU.current_opc, BO, BI, BD); |
86 |
if (!(BO & 4)) { |
87 |
gCPU.ctr--; |
88 |
} |
89 |
bool bo2 = (BO & 2); |
90 |
bool bo8 = (BO & 8); // branch condition true |
91 |
bool cr = (gCPU.cr & (1<<(31-BI))); |
92 |
if (((BO & 4) || ((gCPU.ctr!=0) ^ bo2)) |
93 |
&& ((BO & 16) || (!(cr ^ bo8)))) { |
94 |
if (!(gCPU.current_opc & PPC_OPC_AA)) { |
95 |
BD += gCPU.pc; |
96 |
} |
97 |
if (gCPU.current_opc & PPC_OPC_LK) { |
98 |
gCPU.lr = gCPU.pc + 4; |
99 |
} |
100 |
gCPU.npc = BD; |
101 |
} |
102 |
} |
103 |
|
104 |
/* |
105 |
* bcctrx Branch Conditional to Count Register |
106 |
* .438 |
107 |
*/ |
108 |
void ppc_opc_bcctrx() |
109 |
{ |
110 |
uint32 BO, BI, BD; |
111 |
PPC_OPC_TEMPL_XL(gCPU.current_opc, BO, BI, BD); |
112 |
PPC_OPC_ASSERT(BD==0); |
113 |
PPC_OPC_ASSERT(!(BO & 2)); |
114 |
bool bo8 = (BO & 8); |
115 |
bool cr = (gCPU.cr & (1<<(31-BI))); |
116 |
if ((BO & 16) || (!(cr ^ bo8))) { |
117 |
if (gCPU.current_opc & PPC_OPC_LK) { |
118 |
gCPU.lr = gCPU.pc + 4; |
119 |
} |
120 |
gCPU.npc = gCPU.ctr & 0xfffffffc; |
121 |
} |
122 |
} |
123 |
/* |
124 |
* bclrx Branch Conditional to Link Register |
125 |
* .440 |
126 |
*/ |
127 |
void ppc_opc_bclrx() |
128 |
{ |
129 |
uint32 BO, BI, BD; |
130 |
PPC_OPC_TEMPL_XL(gCPU.current_opc, BO, BI, BD); |
131 |
PPC_OPC_ASSERT(BD==0); |
132 |
if (!(BO & 4)) { |
133 |
gCPU.ctr--; |
134 |
} |
135 |
bool bo2 = (BO & 2); |
136 |
bool bo8 = (BO & 8); |
137 |
bool cr = (gCPU.cr & (1<<(31-BI))); |
138 |
if (((BO & 4) || ((gCPU.ctr!=0) ^ bo2)) |
139 |
&& ((BO & 16) || (!(cr ^ bo8)))) { |
140 |
BD = gCPU.lr & 0xfffffffc; |
141 |
if (gCPU.current_opc & PPC_OPC_LK) { |
142 |
gCPU.lr = gCPU.pc + 4; |
143 |
} |
144 |
gCPU.npc = BD; |
145 |
} |
146 |
} |
147 |
|
148 |
/* |
149 |
* dcbf Data Cache Block Flush |
150 |
* .458 |
151 |
*/ |
152 |
void ppc_opc_dcbf() |
153 |
{ |
154 |
// NO-OP |
155 |
} |
156 |
/* |
157 |
* dcbi Data Cache Block Invalidate |
158 |
* .460 |
159 |
*/ |
160 |
void ppc_opc_dcbi() |
161 |
{ |
162 |
if (gCPU.msr & MSR_PR) { |
163 |
ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_PRIV); |
164 |
return; |
165 |
} |
166 |
// FIXME: check addr |
167 |
} |
168 |
/* |
169 |
* dcbst Data Cache Block Store |
170 |
* .461 |
171 |
*/ |
172 |
void ppc_opc_dcbst() |
173 |
{ |
174 |
// NO-OP |
175 |
} |
176 |
/* |
177 |
* dcbt Data Cache Block Touch |
178 |
* .462 |
179 |
*/ |
180 |
void ppc_opc_dcbt() |
181 |
{ |
182 |
// NO-OP |
183 |
} |
184 |
/* |
185 |
* dcbtst Data Cache Block Touch for Store |
186 |
* .463 |
187 |
*/ |
188 |
void ppc_opc_dcbtst() |
189 |
{ |
190 |
// NO-OP |
191 |
} |
192 |
/* |
193 |
* eciwx External Control In Word Indexed |
194 |
* .474 |
195 |
*/ |
196 |
void ppc_opc_eciwx() |
197 |
{ |
198 |
PPC_OPC_ERR("eciwx unimplemented.\n"); |
199 |
} |
200 |
/* |
201 |
* ecowx External Control Out Word Indexed |
202 |
* .476 |
203 |
*/ |
204 |
void ppc_opc_ecowx() |
205 |
{ |
206 |
PPC_OPC_ERR("ecowx unimplemented.\n"); |
207 |
} |
208 |
/* |
209 |
* eieio Enforce In-Order Execution of I/O |
210 |
* .478 |
211 |
*/ |
212 |
void ppc_opc_eieio() |
213 |
{ |
214 |
// NO-OP |
215 |
} |
216 |
|
217 |
/* |
218 |
* icbi Instruction Cache Block Invalidate |
219 |
* .519 |
220 |
*/ |
221 |
void ppc_opc_icbi() |
222 |
{ |
223 |
// NO-OP |
224 |
} |
225 |
|
226 |
/* |
227 |
* isync Instruction Synchronize |
228 |
* .520 |
229 |
*/ |
230 |
void ppc_opc_isync() |
231 |
{ |
232 |
// NO-OP |
233 |
} |
234 |
|
235 |
static uint32 ppc_cmp_and_mask[8] = { |
236 |
0xfffffff0, |
237 |
0xffffff0f, |
238 |
0xfffff0ff, |
239 |
0xffff0fff, |
240 |
0xfff0ffff, |
241 |
0xff0fffff, |
242 |
0xf0ffffff, |
243 |
0x0fffffff, |
244 |
}; |
245 |
/* |
246 |
* mcrf Move Condition Register Field |
247 |
* .561 |
248 |
*/ |
249 |
void ppc_opc_mcrf() |
250 |
{ |
251 |
uint32 crD, crS, bla; |
252 |
PPC_OPC_TEMPL_X(gCPU.current_opc, crD, crS, bla); |
253 |
// FIXME: bla == 0 |
254 |
crD>>=2; |
255 |
crS>>=2; |
256 |
crD = 7-crD; |
257 |
crS = 7-crS; |
258 |
uint32 c = (gCPU.cr>>(crS*4)) & 0xf; |
259 |
gCPU.cr &= ppc_cmp_and_mask[crD]; |
260 |
gCPU.cr |= c<<(crD*4); |
261 |
} |
262 |
/* |
263 |
* mcrfs Move to Condition Register from FPSCR |
264 |
* .562 |
265 |
*/ |
266 |
void ppc_opc_mcrfs() |
267 |
{ |
268 |
PPC_OPC_ERR("mcrfs unimplemented.\n"); |
269 |
} |
270 |
/* |
271 |
* mcrxr Move to Condition Register from XER |
272 |
* .563 |
273 |
*/ |
274 |
void ppc_opc_mcrxr() |
275 |
{ |
276 |
PPC_OPC_ERR("mcrxr unimplemented.\n"); |
277 |
} |
278 |
/* |
279 |
* mfcr Move from Condition Register |
280 |
* .564 |
281 |
*/ |
282 |
void ppc_opc_mfcr() |
283 |
{ |
284 |
int rD, rA, rB; |
285 |
PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB); |
286 |
PPC_OPC_ASSERT(rA==0 && rB==0); |
287 |
gCPU.gpr[rD] = gCPU.cr; |
288 |
} |
289 |
/* |
290 |
* mffs Move from FPSCR |
291 |
* .565 |
292 |
*/ |
293 |
void ppc_opc_mffsx() |
294 |
{ |
295 |
int frD, rA, rB; |
296 |
PPC_OPC_TEMPL_X(gCPU.current_opc, frD, rA, rB); |
297 |
PPC_OPC_ASSERT(rA==0 && rB==0); |
298 |
gCPU.fpr[frD] = gCPU.fpscr; |
299 |
if (gCPU.current_opc & PPC_OPC_Rc) { |
300 |
// update cr1 flags |
301 |
PPC_OPC_ERR("mffs. unimplemented.\n"); |
302 |
} |
303 |
} |
304 |
/* |
305 |
* mfmsr Move from Machine State Register |
306 |
* .566 |
307 |
*/ |
308 |
void ppc_opc_mfmsr() |
309 |
{ |
310 |
if (gCPU.msr & MSR_PR) { |
311 |
ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_PRIV); |
312 |
return; |
313 |
} |
314 |
int rD, rA, rB; |
315 |
PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB); |
316 |
PPC_OPC_ASSERT((rA == 0) && (rB == 0)); |
317 |
gCPU.gpr[rD] = gCPU.msr; |
318 |
} |
319 |
/* |
320 |
* mfspr Move from Special-Purpose Register |
321 |
* .567 |
322 |
*/ |
323 |
void ppc_opc_mfspr() |
324 |
{ |
325 |
int rD, spr1, spr2; |
326 |
PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, spr1, spr2); |
327 |
switch (spr2) { |
328 |
case 0: |
329 |
switch (spr1) { |
330 |
case 1: gCPU.gpr[rD] = gCPU.xer; return; |
331 |
case 8: gCPU.gpr[rD] = gCPU.lr; return; |
332 |
case 9: gCPU.gpr[rD] = gCPU.ctr; return; |
333 |
} |
334 |
case 8: // altivec made this spr unpriviledged |
335 |
if (spr1 == 0) { |
336 |
gCPU.gpr[rD] = gCPU.vrsave; |
337 |
return; |
338 |
} |
339 |
} |
340 |
if (gCPU.msr & MSR_PR) { |
341 |
ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_PRIV); |
342 |
return; |
343 |
} |
344 |
switch (spr2) { |
345 |
case 0: |
346 |
switch (spr1) { |
347 |
case 18: gCPU.gpr[rD] = gCPU.dsisr; return; |
348 |
case 19: gCPU.gpr[rD] = gCPU.dar; return; |
349 |
case 22: { |
350 |
gCPU.dec = gCPU.pdec / TB_TO_PTB_FACTOR; |
351 |
gCPU.gpr[rD] = gCPU.dec; |
352 |
return; |
353 |
} |
354 |
case 25: gCPU.gpr[rD] = gCPU.sdr1; return; |
355 |
case 26: gCPU.gpr[rD] = gCPU.srr[0]; return; |
356 |
case 27: gCPU.gpr[rD] = gCPU.srr[1]; return; |
357 |
} |
358 |
break; |
359 |
case 8: |
360 |
switch (spr1) { |
361 |
case 12: { |
362 |
gCPU.tb = gCPU.ptb / TB_TO_PTB_FACTOR; |
363 |
gCPU.gpr[rD] = gCPU.tb; |
364 |
return; |
365 |
} |
366 |
case 13: { |
367 |
gCPU.tb = gCPU.ptb / TB_TO_PTB_FACTOR; |
368 |
gCPU.gpr[rD] = gCPU.tb >> 32; |
369 |
return; |
370 |
} |
371 |
case 16: gCPU.gpr[rD] = gCPU.sprg[0]; return; |
372 |
case 17: gCPU.gpr[rD] = gCPU.sprg[1]; return; |
373 |
case 18: gCPU.gpr[rD] = gCPU.sprg[2]; return; |
374 |
case 19: gCPU.gpr[rD] = gCPU.sprg[3]; return; |
375 |
case 26: gCPU.gpr[rD] = gCPU.ear; return; |
376 |
case 31: gCPU.gpr[rD] = gCPU.pvr; return; |
377 |
} |
378 |
break; |
379 |
case 16: |
380 |
switch (spr1) { |
381 |
case 16: gCPU.gpr[rD] = gCPU.ibatu[0]; return; |
382 |
case 17: gCPU.gpr[rD] = gCPU.ibatl[0]; return; |
383 |
case 18: gCPU.gpr[rD] = gCPU.ibatu[1]; return; |
384 |
case 19: gCPU.gpr[rD] = gCPU.ibatl[1]; return; |
385 |
case 20: gCPU.gpr[rD] = gCPU.ibatu[2]; return; |
386 |
case 21: gCPU.gpr[rD] = gCPU.ibatl[2]; return; |
387 |
case 22: gCPU.gpr[rD] = gCPU.ibatu[3]; return; |
388 |
case 23: gCPU.gpr[rD] = gCPU.ibatl[3]; return; |
389 |
case 24: gCPU.gpr[rD] = gCPU.dbatu[0]; return; |
390 |
case 25: gCPU.gpr[rD] = gCPU.dbatl[0]; return; |
391 |
case 26: gCPU.gpr[rD] = gCPU.dbatu[1]; return; |
392 |
case 27: gCPU.gpr[rD] = gCPU.dbatl[1]; return; |
393 |
case 28: gCPU.gpr[rD] = gCPU.dbatu[2]; return; |
394 |
case 29: gCPU.gpr[rD] = gCPU.dbatl[2]; return; |
395 |
case 30: gCPU.gpr[rD] = gCPU.dbatu[3]; return; |
396 |
case 31: gCPU.gpr[rD] = gCPU.dbatl[3]; return; |
397 |
} |
398 |
break; |
399 |
case 29: |
400 |
switch (spr1) { |
401 |
case 16: |
402 |
gCPU.gpr[rD] = 0; |
403 |
return; |
404 |
case 17: |
405 |
gCPU.gpr[rD] = 0; |
406 |
return; |
407 |
case 18: |
408 |
gCPU.gpr[rD] = 0; |
409 |
return; |
410 |
case 24: |
411 |
gCPU.gpr[rD] = 0; |
412 |
return; |
413 |
case 25: |
414 |
gCPU.gpr[rD] = 0; |
415 |
return; |
416 |
case 26: |
417 |
gCPU.gpr[rD] = 0; |
418 |
return; |
419 |
case 28: |
420 |
gCPU.gpr[rD] = 0; |
421 |
return; |
422 |
case 29: |
423 |
gCPU.gpr[rD] = 0; |
424 |
return; |
425 |
case 30: |
426 |
gCPU.gpr[rD] = 0; |
427 |
return; |
428 |
} |
429 |
case 31: |
430 |
switch (spr1) { |
431 |
case 16: |
432 |
// PPC_OPC_WARN("read from spr %d:%d (HID0) not supported!\n", spr1, spr2); |
433 |
gCPU.gpr[rD] = gCPU.hid[0]; |
434 |
return; |
435 |
case 17: |
436 |
PPC_OPC_WARN("read from spr %d:%d (HID1) not supported!\n", spr1, spr2); |
437 |
gCPU.gpr[rD] = gCPU.hid[1]; |
438 |
return; |
439 |
case 18: |
440 |
gCPU.gpr[rD] = 0; |
441 |
return; |
442 |
case 21: |
443 |
gCPU.gpr[rD] = 0; |
444 |
return; |
445 |
case 22: |
446 |
gCPU.gpr[rD] = 0; |
447 |
return; |
448 |
case 23: |
449 |
gCPU.gpr[rD] = 0; |
450 |
return; |
451 |
case 25: |
452 |
PPC_OPC_WARN("read from spr %d:%d (L2CR) not supported! (from %08x)\n", spr1, spr2, gCPU.pc); |
453 |
gCPU.gpr[rD] = 0; |
454 |
return; |
455 |
case 27: |
456 |
PPC_OPC_WARN("read from spr %d:%d (ICTC) not supported!\n", spr1, spr2); |
457 |
gCPU.gpr[rD] = 0; |
458 |
return; |
459 |
case 28: |
460 |
// PPC_OPC_WARN("read from spr %d:%d (THRM1) not supported!\n", spr1, spr2); |
461 |
gCPU.gpr[rD] = 0; |
462 |
return; |
463 |
case 29: |
464 |
// PPC_OPC_WARN("read from spr %d:%d (THRM2) not supported!\n", spr1, spr2); |
465 |
gCPU.gpr[rD] = 0; |
466 |
return; |
467 |
case 30: |
468 |
// PPC_OPC_WARN("read from spr %d:%d (THRM3) not supported!\n", spr1, spr2); |
469 |
gCPU.gpr[rD] = 0; |
470 |
return; |
471 |
case 31: |
472 |
// PPC_OPC_WARN("read from spr %d:%d (???) not supported!\n", spr1, spr2); |
473 |
gCPU.gpr[rD] = 0; |
474 |
return; |
475 |
} |
476 |
} |
477 |
fprintf(stderr, "unknown mfspr: %i:%i\n", spr1, spr2); |
478 |
SINGLESTEP("invalid mfspr\n"); |
479 |
} |
480 |
/* |
481 |
* mfsr Move from Segment Register |
482 |
* .570 |
483 |
*/ |
484 |
void ppc_opc_mfsr() |
485 |
{ |
486 |
if (gCPU.msr & MSR_PR) { |
487 |
ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_PRIV); |
488 |
return; |
489 |
} |
490 |
int rD, SR, rB; |
491 |
PPC_OPC_TEMPL_X(gCPU.current_opc, rD, SR, rB); |
492 |
// FIXME: check insn |
493 |
gCPU.gpr[rD] = gCPU.sr[SR & 0xf]; |
494 |
} |
495 |
/* |
496 |
* mfsrin Move from Segment Register Indirect |
497 |
* .572 |
498 |
*/ |
499 |
void ppc_opc_mfsrin() |
500 |
{ |
501 |
if (gCPU.msr & MSR_PR) { |
502 |
ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_PRIV); |
503 |
return; |
504 |
} |
505 |
int rD, rA, rB; |
506 |
PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB); |
507 |
// FIXME: check insn |
508 |
gCPU.gpr[rD] = gCPU.sr[gCPU.gpr[rB] >> 28]; |
509 |
} |
510 |
/* |
511 |
* mftb Move from Time Base |
512 |
* .574 |
513 |
*/ |
514 |
void ppc_opc_mftb() |
515 |
{ |
516 |
int rD, spr1, spr2; |
517 |
PPC_OPC_TEMPL_X(gCPU.current_opc, rD, spr1, spr2); |
518 |
switch (spr2) { |
519 |
case 8: |
520 |
switch (spr1) { |
521 |
case 12: { |
522 |
gCPU.tb = gCPU.ptb / TB_TO_PTB_FACTOR; |
523 |
gCPU.gpr[rD] = gCPU.tb; |
524 |
return; |
525 |
} |
526 |
case 13: { |
527 |
gCPU.tb = gCPU.ptb / TB_TO_PTB_FACTOR; |
528 |
gCPU.gpr[rD] = gCPU.tb >> 32; |
529 |
return; |
530 |
} |
531 |
} |
532 |
break; |
533 |
} |
534 |
SINGLESTEP("unknown mftb\n"); |
535 |
} |
536 |
/* |
537 |
* mtcrf Move to Condition Register Fields |
538 |
* .576 |
539 |
*/ |
540 |
void ppc_opc_mtcrf() |
541 |
{ |
542 |
|
543 |
int rS; |
544 |
uint32 crm; |
545 |
uint32 CRM; |
546 |
PPC_OPC_TEMPL_XFX(gCPU.current_opc, rS, crm); |
547 |
CRM = ((crm&0x80)?0xf0000000:0)|((crm&0x40)?0x0f000000:0)|((crm&0x20)?0x00f00000:0)|((crm&0x10)?0x000f0000:0)| |
548 |
((crm&0x08)?0x0000f000:0)|((crm&0x04)?0x00000f00:0)|((crm&0x02)?0x000000f0:0)|((crm&0x01)?0x0000000f:0); |
549 |
gCPU.cr = (gCPU.gpr[rS] & CRM) | (gCPU.cr & ~CRM); |
550 |
} |
551 |
/* |
552 |
* mtfsb0x Move to FPSCR Bit 0 |
553 |
* .577 |
554 |
*/ |
555 |
void ppc_opc_mtfsb0x() |
556 |
{ |
557 |
int crbD, n1, n2; |
558 |
PPC_OPC_TEMPL_X(gCPU.current_opc, crbD, n1, n2); |
559 |
if (crbD != 1 && crbD != 2) { |
560 |
gCPU.fpscr &= ~(1<<(31-crbD)); |
561 |
} |
562 |
if (gCPU.current_opc & PPC_OPC_Rc) { |
563 |
// update cr1 flags |
564 |
PPC_OPC_ERR("mtfsb0. unimplemented.\n"); |
565 |
} |
566 |
} |
567 |
/* |
568 |
* mtfsb1x Move to FPSCR Bit 1 |
569 |
* .578 |
570 |
*/ |
571 |
void ppc_opc_mtfsb1x() |
572 |
{ |
573 |
int crbD, n1, n2; |
574 |
PPC_OPC_TEMPL_X(gCPU.current_opc, crbD, n1, n2); |
575 |
if (crbD != 1 && crbD != 2) { |
576 |
gCPU.fpscr |= 1<<(31-crbD); |
577 |
} |
578 |
if (gCPU.current_opc & PPC_OPC_Rc) { |
579 |
// update cr1 flags |
580 |
PPC_OPC_ERR("mtfsb1. unimplemented.\n"); |
581 |
} |
582 |
} |
583 |
/* |
584 |
* mtfsfx Move to FPSCR Fields |
585 |
* .579 |
586 |
*/ |
587 |
void ppc_opc_mtfsfx() |
588 |
{ |
589 |
int frB; |
590 |
uint32 fm, FM; |
591 |
PPC_OPC_TEMPL_XFL(gCPU.current_opc, frB, fm); |
592 |
FM = ((fm&0x80)?0xf0000000:0)|((fm&0x40)?0x0f000000:0)|((fm&0x20)?0x00f00000:0)|((fm&0x10)?0x000f0000:0)| |
593 |
((fm&0x08)?0x0000f000:0)|((fm&0x04)?0x00000f00:0)|((fm&0x02)?0x000000f0:0)|((fm&0x01)?0x0000000f:0); |
594 |
gCPU.fpscr = (gCPU.fpr[frB] & FM) | (gCPU.fpscr & ~FM); |
595 |
if (gCPU.current_opc & PPC_OPC_Rc) { |
596 |
// update cr1 flags |
597 |
PPC_OPC_ERR("mtfsf. unimplemented.\n"); |
598 |
} |
599 |
} |
600 |
/* |
601 |
* mtfsfix Move to FPSCR Field Immediate |
602 |
* .580 |
603 |
*/ |
604 |
void ppc_opc_mtfsfix() |
605 |
{ |
606 |
int crfD, n1; |
607 |
uint32 imm; |
608 |
PPC_OPC_TEMPL_X(gCPU.current_opc, crfD, n1, imm); |
609 |
crfD >>= 2; |
610 |
imm >>= 1; |
611 |
crfD = 7-crfD; |
612 |
gCPU.fpscr &= ppc_cmp_and_mask[crfD]; |
613 |
gCPU.fpscr |= imm<<(crfD*4); |
614 |
if (gCPU.current_opc & PPC_OPC_Rc) { |
615 |
// update cr1 flags |
616 |
PPC_OPC_ERR("mtfsfi. unimplemented.\n"); |
617 |
} |
618 |
} |
619 |
/* |
620 |
* mtmsr Move to Machine State Register |
621 |
* .581 |
622 |
*/ |
623 |
void ppc_opc_mtmsr() |
624 |
{ |
625 |
if (gCPU.msr & MSR_PR) { |
626 |
ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_PRIV); |
627 |
return; |
628 |
} |
629 |
int rS, rA, rB; |
630 |
PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB); |
631 |
PPC_OPC_ASSERT((rA == 0) && (rB == 0)); |
632 |
ppc_set_msr(gCPU.gpr[rS]); |
633 |
} |
634 |
/* |
635 |
* mtspr Move to Special-Purpose Register |
636 |
* .584 |
637 |
*/ |
638 |
void ppc_opc_mtspr() |
639 |
{ |
640 |
int rS, spr1, spr2; |
641 |
PPC_OPC_TEMPL_X(gCPU.current_opc, rS, spr1, spr2); |
642 |
switch (spr2) { |
643 |
case 0: |
644 |
switch (spr1) { |
645 |
case 1: gCPU.xer = gCPU.gpr[rS]; return; |
646 |
case 8: gCPU.lr = gCPU.gpr[rS]; return; |
647 |
case 9: gCPU.ctr = gCPU.gpr[rS]; return; |
648 |
} |
649 |
case 8: //altivec makes this register unpriviledged |
650 |
if (spr1 == 0) { |
651 |
gCPU.vrsave = gCPU.gpr[rS]; |
652 |
return; |
653 |
} |
654 |
} |
655 |
if (gCPU.msr & MSR_PR) { |
656 |
ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_PRIV); |
657 |
return; |
658 |
} |
659 |
switch (spr2) { |
660 |
case 0: |
661 |
switch (spr1) { |
662 |
/* case 18: gCPU.gpr[rD] = gCPU.dsisr; return; |
663 |
case 19: gCPU.gpr[rD] = gCPU.dar; return;*/ |
664 |
case 22: { |
665 |
gCPU.dec = gCPU.gpr[rS]; |
666 |
gCPU.pdec = gCPU.dec; |
667 |
gCPU.pdec *= TB_TO_PTB_FACTOR; |
668 |
return; |
669 |
} |
670 |
case 25: |
671 |
if (!ppc_mmu_set_sdr1(gCPU.gpr[rS], true)) { |
672 |
PPC_OPC_ERR("cannot set sdr1\n"); |
673 |
} |
674 |
return; |
675 |
case 26: gCPU.srr[0] = gCPU.gpr[rS]; return; |
676 |
case 27: gCPU.srr[1] = gCPU.gpr[rS]; return; |
677 |
} |
678 |
break; |
679 |
case 8: |
680 |
switch (spr1) { |
681 |
case 16: gCPU.sprg[0] = gCPU.gpr[rS]; return; |
682 |
case 17: gCPU.sprg[1] = gCPU.gpr[rS]; return; |
683 |
case 18: gCPU.sprg[2] = gCPU.gpr[rS]; return; |
684 |
case 19: gCPU.sprg[3] = gCPU.gpr[rS]; return; |
685 |
/* case 26: gCPU.gpr[rD] = gCPU.ear; return; |
686 |
case 31: gCPU.gpr[rD] = gCPU.pvr; return;*/ |
687 |
} |
688 |
break; |
689 |
case 16: |
690 |
switch (spr1) { |
691 |
case 16: |
692 |
gCPU.ibatu[0] = gCPU.gpr[rS]; |
693 |
gCPU.ibat_bl17[0] = ~(BATU_BL(gCPU.ibatu[0])<<17); |
694 |
return; |
695 |
case 17: |
696 |
gCPU.ibatl[0] = gCPU.gpr[rS]; |
697 |
return; |
698 |
case 18: |
699 |
gCPU.ibatu[1] = gCPU.gpr[rS]; |
700 |
gCPU.ibat_bl17[1] = ~(BATU_BL(gCPU.ibatu[1])<<17); |
701 |
return; |
702 |
case 19: |
703 |
gCPU.ibatl[1] = gCPU.gpr[rS]; |
704 |
return; |
705 |
case 20: |
706 |
gCPU.ibatu[2] = gCPU.gpr[rS]; |
707 |
gCPU.ibat_bl17[2] = ~(BATU_BL(gCPU.ibatu[2])<<17); |
708 |
return; |
709 |
case 21: |
710 |
gCPU.ibatl[2] = gCPU.gpr[rS]; |
711 |
return; |
712 |
case 22: |
713 |
gCPU.ibatu[3] = gCPU.gpr[rS]; |
714 |
gCPU.ibat_bl17[3] = ~(BATU_BL(gCPU.ibatu[3])<<17); |
715 |
return; |
716 |
case 23: |
717 |
gCPU.ibatl[3] = gCPU.gpr[rS]; |
718 |
return; |
719 |
case 24: |
720 |
gCPU.dbatu[0] = gCPU.gpr[rS]; |
721 |
gCPU.dbat_bl17[0] = ~(BATU_BL(gCPU.dbatu[0])<<17); |
722 |
return; |
723 |
case 25: |
724 |
gCPU.dbatl[0] = gCPU.gpr[rS]; |
725 |
return; |
726 |
case 26: |
727 |
gCPU.dbatu[1] = gCPU.gpr[rS]; |
728 |
gCPU.dbat_bl17[1] = ~(BATU_BL(gCPU.dbatu[1])<<17); |
729 |
return; |
730 |
case 27: |
731 |
gCPU.dbatl[1] = gCPU.gpr[rS]; |
732 |
return; |
733 |
case 28: |
734 |
gCPU.dbatu[2] = gCPU.gpr[rS]; |
735 |
gCPU.dbat_bl17[2] = ~(BATU_BL(gCPU.dbatu[2])<<17); |
736 |
return; |
737 |
case 29: |
738 |
gCPU.dbatl[2] = gCPU.gpr[rS]; |
739 |
return; |
740 |
case 30: |
741 |
gCPU.dbatu[3] = gCPU.gpr[rS]; |
742 |
gCPU.dbat_bl17[3] = ~(BATU_BL(gCPU.dbatu[3])<<17); |
743 |
return; |
744 |
case 31: |
745 |
gCPU.dbatl[3] = gCPU.gpr[rS]; |
746 |
return; |
747 |
} |
748 |
break; |
749 |
case 29: |
750 |
switch(spr1) { |
751 |
case 17: return; |
752 |
case 24: return; |
753 |
case 25: return; |
754 |
case 26: return; |
755 |
} |
756 |
case 31: |
757 |
switch (spr1) { |
758 |
case 16: |
759 |
// PPC_OPC_WARN("write(%08x) to spr %d:%d (HID0) not supported! @%08x\n", gCPU.gpr[rS], spr1, spr2, gCPU.pc); |
760 |
gCPU.hid[0] = gCPU.gpr[rS]; |
761 |
return; |
762 |
case 17: return; |
763 |
case 18: |
764 |
PPC_OPC_ERR("write(%08x) to spr %d:%d (IABR) not supported!\n", gCPU.gpr[rS], spr1, spr2); |
765 |
return; |
766 |
case 21: |
767 |
PPC_OPC_ERR("write(%08x) to spr %d:%d (DABR) not supported!\n", gCPU.gpr[rS], spr1, spr2); |
768 |
return; |
769 |
case 24: |
770 |
PPC_OPC_WARN("write(%08x) to spr %d:%d (?) not supported!\n", gCPU.gpr[rS], spr1, spr2); |
771 |
return; |
772 |
case 27: |
773 |
PPC_OPC_WARN("write(%08x) to spr %d:%d (ICTC) not supported!\n", gCPU.gpr[rS], spr1, spr2); |
774 |
return; |
775 |
case 28: |
776 |
// PPC_OPC_WARN("write(%08x) to spr %d:%d (THRM1) not supported!\n", gCPU.gpr[rS], spr1, spr2); |
777 |
return; |
778 |
case 29: |
779 |
// PPC_OPC_WARN("write(%08x) to spr %d:%d (THRM2) not supported!\n", gCPU.gpr[rS], spr1, spr2); |
780 |
return; |
781 |
case 30: |
782 |
// PPC_OPC_WARN("write(%08x) to spr %d:%d (THRM3) not supported!\n", gCPU.gpr[rS], spr1, spr2); |
783 |
return; |
784 |
case 31: return; |
785 |
} |
786 |
} |
787 |
fprintf(stderr, "unknown mtspr: %i:%i\n", spr1, spr2); |
788 |
SINGLESTEP("unknown mtspr\n"); |
789 |
} |
790 |
/* |
791 |
* mtsr Move to Segment Register |
792 |
* .587 |
793 |
*/ |
794 |
void ppc_opc_mtsr() |
795 |
{ |
796 |
if (gCPU.msr & MSR_PR) { |
797 |
ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_PRIV); |
798 |
return; |
799 |
} |
800 |
int rS, SR, rB; |
801 |
PPC_OPC_TEMPL_X(gCPU.current_opc, rS, SR, rB); |
802 |
// FIXME: check insn |
803 |
gCPU.sr[SR & 0xf] = gCPU.gpr[rS]; |
804 |
} |
805 |
/* |
806 |
* mtsrin Move to Segment Register Indirect |
807 |
* .591 |
808 |
*/ |
809 |
void ppc_opc_mtsrin() |
810 |
{ |
811 |
if (gCPU.msr & MSR_PR) { |
812 |
ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_PRIV); |
813 |
return; |
814 |
} |
815 |
int rS, rA, rB; |
816 |
PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB); |
817 |
// FIXME: check insn |
818 |
gCPU.sr[gCPU.gpr[rB] >> 28] = gCPU.gpr[rS]; |
819 |
} |
820 |
|
821 |
/* |
822 |
* rfi Return from Interrupt |
823 |
* .607 |
824 |
*/ |
825 |
void ppc_opc_rfi() |
826 |
{ |
827 |
if (gCPU.msr & MSR_PR) { |
828 |
ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_PRIV); |
829 |
return; |
830 |
} |
831 |
ppc_set_msr(gCPU.srr[1] & MSR_RFI_SAVE_MASK); |
832 |
gCPU.npc = gCPU.srr[0] & 0xfffffffc; |
833 |
} |
834 |
|
835 |
/* |
836 |
* sc System Call |
837 |
* .621 |
838 |
*/ |
839 |
#include "io/graphic/gcard.h" |
840 |
void ppc_opc_sc() |
841 |
{ |
842 |
if (gCPU.gpr[3] == 0x113724fa && gCPU.gpr[4] == 0x77810f9b) { |
843 |
gcard_osi(0); |
844 |
return; |
845 |
} |
846 |
ppc_exception(PPC_EXC_SC); |
847 |
} |
848 |
|
849 |
/* |
850 |
* sync Synchronize |
851 |
* .672 |
852 |
*/ |
853 |
void ppc_opc_sync() |
854 |
{ |
855 |
// NO-OP |
856 |
} |
857 |
|
858 |
/* |
859 |
* tlbie Translation Lookaside Buffer Invalidate Entry |
860 |
* .676 |
861 |
*/ |
862 |
void ppc_opc_tlbia() |
863 |
{ |
864 |
if (gCPU.msr & MSR_PR) { |
865 |
ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_PRIV); |
866 |
return; |
867 |
} |
868 |
int rS, rA, rB; |
869 |
PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB); |
870 |
// FIXME: check rS.. for 0 |
871 |
ppc_mmu_tlb_invalidate(); |
872 |
} |
873 |
|
874 |
/* |
875 |
* tlbie Translation Lookaside Buffer Invalidate All |
876 |
* .676 |
877 |
*/ |
878 |
void ppc_opc_tlbie() |
879 |
{ |
880 |
if (gCPU.msr & MSR_PR) { |
881 |
ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_PRIV); |
882 |
return; |
883 |
} |
884 |
int rS, rA, rB; |
885 |
PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB); |
886 |
// FIXME: check rS.. for 0 |
887 |
ppc_mmu_tlb_invalidate(); |
888 |
} |
889 |
|
890 |
/* |
891 |
* tlbsync Translation Lookaside Buffer Syncronize |
892 |
* .677 |
893 |
*/ |
894 |
void ppc_opc_tlbsync() |
895 |
{ |
896 |
if (gCPU.msr & MSR_PR) { |
897 |
ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_PRIV); |
898 |
return; |
899 |
} |
900 |
int rS, rA, rB; |
901 |
PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB); |
902 |
// FIXME: check rS.. for 0 |
903 |
ppc_mmu_tlb_invalidate(); |
904 |
} |
905 |
|
906 |
/* |
907 |
* tw Trap Word |
908 |
* .678 |
909 |
*/ |
910 |
void ppc_opc_tw() |
911 |
{ |
912 |
int TO, rA, rB; |
913 |
PPC_OPC_TEMPL_X(gCPU.current_opc, TO, rA, rB); |
914 |
uint32 a = gCPU.gpr[rA]; |
915 |
uint32 b = gCPU.gpr[rB]; |
916 |
if (((TO & 16) && ((sint32)a < (sint32)b)) |
917 |
|| ((TO & 8) && ((sint32)a > (sint32)b)) |
918 |
|| ((TO & 4) && (a == b)) |
919 |
|| ((TO & 2) && (a < b)) |
920 |
|| ((TO & 1) && (a > b))) { |
921 |
ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_TRAP); |
922 |
} |
923 |
} |
924 |
|
925 |
/* |
926 |
* twi Trap Word Immediate |
927 |
* .679 |
928 |
*/ |
929 |
void ppc_opc_twi() |
930 |
{ |
931 |
int TO, rA; |
932 |
uint32 imm; |
933 |
PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, TO, rA, imm); |
934 |
uint32 a = gCPU.gpr[rA]; |
935 |
if (((TO & 16) && ((sint32)a < (sint32)imm)) |
936 |
|| ((TO & 8) && ((sint32)a > (sint32)imm)) |
937 |
|| ((TO & 4) && (a == imm)) |
938 |
|| ((TO & 2) && (a < imm)) |
939 |
|| ((TO & 1) && (a > imm))) { |
940 |
ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_TRAP); |
941 |
} |
942 |
} |
943 |
|
944 |
/* dcba Data Cache Block Allocate |
945 |
* .??? |
946 |
*/ |
947 |
void ppc_opc_dcba() |
948 |
{ |
949 |
/* NO-OP */ |
950 |
} |