1 // Copyright 2008 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4
5 #include "Common/Assert.h"
6 #include "Common/CommonTypes.h"
7 #include "Common/Logging/Log.h"
8 #include "Common/MsgHandler.h"
9 #include "Common/Swap.h"
10
11 #include "Core/ConfigManager.h"
12 #include "Core/PowerPC/Interpreter/ExceptionUtils.h"
13 #include "Core/PowerPC/Interpreter/Interpreter.h"
14 #include "Core/PowerPC/Interpreter/Interpreter_FPUtils.h"
15 #include "Core/PowerPC/JitInterface.h"
16 #include "Core/PowerPC/MMU.h"
17 #include "Core/PowerPC/PowerPC.h"
18
19 bool Interpreter::m_reserve;
20 u32 Interpreter::m_reserve_address;
21
Helper_Get_EA(const PowerPC::PowerPCState & ppcs,const UGeckoInstruction inst)22 static u32 Helper_Get_EA(const PowerPC::PowerPCState& ppcs, const UGeckoInstruction inst)
23 {
24 return inst.RA ? (ppcs.gpr[inst.RA] + inst.SIMM_16) : (u32)inst.SIMM_16;
25 }
26
Helper_Get_EA_U(const PowerPC::PowerPCState & ppcs,const UGeckoInstruction inst)27 static u32 Helper_Get_EA_U(const PowerPC::PowerPCState& ppcs, const UGeckoInstruction inst)
28 {
29 return (ppcs.gpr[inst.RA] + inst.SIMM_16);
30 }
31
Helper_Get_EA_X(const PowerPC::PowerPCState & ppcs,const UGeckoInstruction inst)32 static u32 Helper_Get_EA_X(const PowerPC::PowerPCState& ppcs, const UGeckoInstruction inst)
33 {
34 return inst.RA ? (ppcs.gpr[inst.RA] + ppcs.gpr[inst.RB]) : ppcs.gpr[inst.RB];
35 }
36
Helper_Get_EA_UX(const PowerPC::PowerPCState & ppcs,const UGeckoInstruction inst)37 static u32 Helper_Get_EA_UX(const PowerPC::PowerPCState& ppcs, const UGeckoInstruction inst)
38 {
39 return (ppcs.gpr[inst.RA] + ppcs.gpr[inst.RB]);
40 }
41
lbz(UGeckoInstruction inst)42 void Interpreter::lbz(UGeckoInstruction inst)
43 {
44 const u32 temp = PowerPC::Read_U8(Helper_Get_EA(PowerPC::ppcState, inst));
45
46 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
47 rGPR[inst.RD] = temp;
48 }
49
lbzu(UGeckoInstruction inst)50 void Interpreter::lbzu(UGeckoInstruction inst)
51 {
52 const u32 address = Helper_Get_EA_U(PowerPC::ppcState, inst);
53 const u32 temp = PowerPC::Read_U8(address);
54
55 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
56 {
57 rGPR[inst.RD] = temp;
58 rGPR[inst.RA] = address;
59 }
60 }
61
lfd(UGeckoInstruction inst)62 void Interpreter::lfd(UGeckoInstruction inst)
63 {
64 const u32 address = Helper_Get_EA(PowerPC::ppcState, inst);
65
66 if ((address & 0b11) != 0)
67 {
68 GenerateAlignmentException(address);
69 return;
70 }
71
72 const u64 temp = PowerPC::Read_U64(address);
73
74 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
75 rPS(inst.FD).SetPS0(temp);
76 }
77
lfdu(UGeckoInstruction inst)78 void Interpreter::lfdu(UGeckoInstruction inst)
79 {
80 const u32 address = Helper_Get_EA_U(PowerPC::ppcState, inst);
81
82 if ((address & 0b11) != 0)
83 {
84 GenerateAlignmentException(address);
85 return;
86 }
87
88 const u64 temp = PowerPC::Read_U64(address);
89
90 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
91 {
92 rPS(inst.FD).SetPS0(temp);
93 rGPR[inst.RA] = address;
94 }
95 }
96
lfdux(UGeckoInstruction inst)97 void Interpreter::lfdux(UGeckoInstruction inst)
98 {
99 const u32 address = Helper_Get_EA_UX(PowerPC::ppcState, inst);
100
101 if ((address & 0b11) != 0)
102 {
103 GenerateAlignmentException(address);
104 return;
105 }
106
107 const u64 temp = PowerPC::Read_U64(address);
108
109 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
110 {
111 rPS(inst.FD).SetPS0(temp);
112 rGPR[inst.RA] = address;
113 }
114 }
115
lfdx(UGeckoInstruction inst)116 void Interpreter::lfdx(UGeckoInstruction inst)
117 {
118 const u32 address = Helper_Get_EA_X(PowerPC::ppcState, inst);
119
120 if ((address & 0b11) != 0)
121 {
122 GenerateAlignmentException(address);
123 return;
124 }
125
126 const u64 temp = PowerPC::Read_U64(address);
127
128 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
129 rPS(inst.FD).SetPS0(temp);
130 }
131
lfs(UGeckoInstruction inst)132 void Interpreter::lfs(UGeckoInstruction inst)
133 {
134 const u32 address = Helper_Get_EA(PowerPC::ppcState, inst);
135
136 if ((address & 0b11) != 0)
137 {
138 GenerateAlignmentException(address);
139 return;
140 }
141
142 const u32 temp = PowerPC::Read_U32(address);
143
144 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
145 {
146 const u64 value = ConvertToDouble(temp);
147 rPS(inst.FD).Fill(value);
148 }
149 }
150
lfsu(UGeckoInstruction inst)151 void Interpreter::lfsu(UGeckoInstruction inst)
152 {
153 const u32 address = Helper_Get_EA_U(PowerPC::ppcState, inst);
154
155 if ((address & 0b11) != 0)
156 {
157 GenerateAlignmentException(address);
158 return;
159 }
160
161 const u32 temp = PowerPC::Read_U32(address);
162
163 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
164 {
165 const u64 value = ConvertToDouble(temp);
166 rPS(inst.FD).Fill(value);
167 rGPR[inst.RA] = address;
168 }
169 }
170
lfsux(UGeckoInstruction inst)171 void Interpreter::lfsux(UGeckoInstruction inst)
172 {
173 const u32 address = Helper_Get_EA_UX(PowerPC::ppcState, inst);
174
175 if ((address & 0b11) != 0)
176 {
177 GenerateAlignmentException(address);
178 return;
179 }
180
181 const u32 temp = PowerPC::Read_U32(address);
182
183 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
184 {
185 const u64 value = ConvertToDouble(temp);
186 rPS(inst.FD).Fill(value);
187 rGPR[inst.RA] = address;
188 }
189 }
190
lfsx(UGeckoInstruction inst)191 void Interpreter::lfsx(UGeckoInstruction inst)
192 {
193 const u32 address = Helper_Get_EA_X(PowerPC::ppcState, inst);
194
195 if ((address & 0b11) != 0)
196 {
197 GenerateAlignmentException(address);
198 return;
199 }
200
201 const u32 temp = PowerPC::Read_U32(address);
202
203 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
204 {
205 const u64 value = ConvertToDouble(temp);
206 rPS(inst.FD).Fill(value);
207 }
208 }
209
lha(UGeckoInstruction inst)210 void Interpreter::lha(UGeckoInstruction inst)
211 {
212 const u32 temp = (u32)(s32)(s16)PowerPC::Read_U16(Helper_Get_EA(PowerPC::ppcState, inst));
213
214 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
215 {
216 rGPR[inst.RD] = temp;
217 }
218 }
219
lhau(UGeckoInstruction inst)220 void Interpreter::lhau(UGeckoInstruction inst)
221 {
222 const u32 address = Helper_Get_EA_U(PowerPC::ppcState, inst);
223 const u32 temp = (u32)(s32)(s16)PowerPC::Read_U16(address);
224
225 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
226 {
227 rGPR[inst.RD] = temp;
228 rGPR[inst.RA] = address;
229 }
230 }
231
lhz(UGeckoInstruction inst)232 void Interpreter::lhz(UGeckoInstruction inst)
233 {
234 const u32 temp = PowerPC::Read_U16(Helper_Get_EA(PowerPC::ppcState, inst));
235
236 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
237 {
238 rGPR[inst.RD] = temp;
239 }
240 }
241
lhzu(UGeckoInstruction inst)242 void Interpreter::lhzu(UGeckoInstruction inst)
243 {
244 const u32 address = Helper_Get_EA_U(PowerPC::ppcState, inst);
245 const u32 temp = PowerPC::Read_U16(address);
246
247 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
248 {
249 rGPR[inst.RD] = temp;
250 rGPR[inst.RA] = address;
251 }
252 }
253
254 // FIXME: lmw should do a total rollback if a DSI occurs
lmw(UGeckoInstruction inst)255 void Interpreter::lmw(UGeckoInstruction inst)
256 {
257 u32 address = Helper_Get_EA(PowerPC::ppcState, inst);
258
259 if ((address & 0b11) != 0 || MSR.LE)
260 {
261 GenerateAlignmentException(address);
262 return;
263 }
264
265 for (int i = inst.RD; i <= 31; i++, address += 4)
266 {
267 const u32 temp_reg = PowerPC::Read_U32(address);
268
269 if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
270 {
271 PanicAlert("DSI exception in lmw");
272 NOTICE_LOG(POWERPC, "DSI exception in lmw");
273 return;
274 }
275 else
276 {
277 rGPR[i] = temp_reg;
278 }
279 }
280 }
281
282 // FIXME: stmw should do a total rollback if a DSI occurs
stmw(UGeckoInstruction inst)283 void Interpreter::stmw(UGeckoInstruction inst)
284 {
285 u32 address = Helper_Get_EA(PowerPC::ppcState, inst);
286
287 if ((address & 0b11) != 0 || MSR.LE)
288 {
289 GenerateAlignmentException(address);
290 return;
291 }
292
293 for (int i = inst.RS; i <= 31; i++, address += 4)
294 {
295 PowerPC::Write_U32(rGPR[i], address);
296 if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
297 {
298 PanicAlert("DSI exception in stmw");
299 NOTICE_LOG(POWERPC, "DSI exception in stmw");
300 return;
301 }
302 }
303 }
304
lwz(UGeckoInstruction inst)305 void Interpreter::lwz(UGeckoInstruction inst)
306 {
307 const u32 address = Helper_Get_EA(PowerPC::ppcState, inst);
308 const u32 temp = PowerPC::Read_U32(address);
309
310 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
311 {
312 rGPR[inst.RD] = temp;
313 }
314 }
315
lwzu(UGeckoInstruction inst)316 void Interpreter::lwzu(UGeckoInstruction inst)
317 {
318 const u32 address = Helper_Get_EA_U(PowerPC::ppcState, inst);
319 const u32 temp = PowerPC::Read_U32(address);
320
321 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
322 {
323 rGPR[inst.RD] = temp;
324 rGPR[inst.RA] = address;
325 }
326 }
327
stb(UGeckoInstruction inst)328 void Interpreter::stb(UGeckoInstruction inst)
329 {
330 PowerPC::Write_U8((u8)rGPR[inst.RS], Helper_Get_EA(PowerPC::ppcState, inst));
331 }
332
stbu(UGeckoInstruction inst)333 void Interpreter::stbu(UGeckoInstruction inst)
334 {
335 const u32 address = Helper_Get_EA_U(PowerPC::ppcState, inst);
336
337 PowerPC::Write_U8((u8)rGPR[inst.RS], address);
338 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
339 {
340 rGPR[inst.RA] = address;
341 }
342 }
343
stfd(UGeckoInstruction inst)344 void Interpreter::stfd(UGeckoInstruction inst)
345 {
346 const u32 address = Helper_Get_EA(PowerPC::ppcState, inst);
347
348 if ((address & 0b11) != 0)
349 {
350 GenerateAlignmentException(address);
351 return;
352 }
353
354 PowerPC::Write_U64(rPS(inst.FS).PS0AsU64(), address);
355 }
356
stfdu(UGeckoInstruction inst)357 void Interpreter::stfdu(UGeckoInstruction inst)
358 {
359 const u32 address = Helper_Get_EA_U(PowerPC::ppcState, inst);
360
361 if ((address & 0b11) != 0)
362 {
363 GenerateAlignmentException(address);
364 return;
365 }
366
367 PowerPC::Write_U64(rPS(inst.FS).PS0AsU64(), address);
368 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
369 {
370 rGPR[inst.RA] = address;
371 }
372 }
373
stfs(UGeckoInstruction inst)374 void Interpreter::stfs(UGeckoInstruction inst)
375 {
376 const u32 address = Helper_Get_EA(PowerPC::ppcState, inst);
377
378 if ((address & 0b11) != 0)
379 {
380 GenerateAlignmentException(address);
381 return;
382 }
383
384 PowerPC::Write_U32(ConvertToSingle(rPS(inst.FS).PS0AsU64()), address);
385 }
386
stfsu(UGeckoInstruction inst)387 void Interpreter::stfsu(UGeckoInstruction inst)
388 {
389 const u32 address = Helper_Get_EA_U(PowerPC::ppcState, inst);
390
391 if ((address & 0b11) != 0)
392 {
393 GenerateAlignmentException(address);
394 return;
395 }
396
397 PowerPC::Write_U32(ConvertToSingle(rPS(inst.FS).PS0AsU64()), address);
398 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
399 {
400 rGPR[inst.RA] = address;
401 }
402 }
403
sth(UGeckoInstruction inst)404 void Interpreter::sth(UGeckoInstruction inst)
405 {
406 PowerPC::Write_U16((u16)rGPR[inst.RS], Helper_Get_EA(PowerPC::ppcState, inst));
407 }
408
sthu(UGeckoInstruction inst)409 void Interpreter::sthu(UGeckoInstruction inst)
410 {
411 const u32 address = Helper_Get_EA_U(PowerPC::ppcState, inst);
412
413 PowerPC::Write_U16((u16)rGPR[inst.RS], address);
414 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
415 {
416 rGPR[inst.RA] = address;
417 }
418 }
419
stw(UGeckoInstruction inst)420 void Interpreter::stw(UGeckoInstruction inst)
421 {
422 PowerPC::Write_U32(rGPR[inst.RS], Helper_Get_EA(PowerPC::ppcState, inst));
423 }
424
stwu(UGeckoInstruction inst)425 void Interpreter::stwu(UGeckoInstruction inst)
426 {
427 const u32 address = Helper_Get_EA_U(PowerPC::ppcState, inst);
428
429 PowerPC::Write_U32(rGPR[inst.RS], address);
430 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
431 {
432 rGPR[inst.RA] = address;
433 }
434 }
435
dcba(UGeckoInstruction inst)436 void Interpreter::dcba(UGeckoInstruction inst)
437 {
438 ASSERT_MSG(POWERPC, 0, "dcba - Not implemented - not a Gekko instruction");
439 }
440
dcbf(UGeckoInstruction inst)441 void Interpreter::dcbf(UGeckoInstruction inst)
442 {
443 // TODO: Implement some sort of L2 emulation.
444 // TODO: Raise DSI if translation fails (except for direct-store segments).
445
446 // Invalidate the JIT cache here as a heuristic to compensate for
447 // the lack of precise L1 icache emulation in the JIT. (Portable software
448 // should use icbi consistently, but games aren't portable.)
449 const u32 address = Helper_Get_EA_X(PowerPC::ppcState, inst);
450 JitInterface::InvalidateICache(address & ~0x1f, 32, false);
451 }
452
dcbi(UGeckoInstruction inst)453 void Interpreter::dcbi(UGeckoInstruction inst)
454 {
455 if (MSR.PR)
456 {
457 GenerateProgramException();
458 return;
459 }
460
461 // TODO: Implement some sort of L2 emulation.
462 // TODO: Raise DSI if translation fails (except for direct-store segments).
463
464 // Invalidate the JIT cache here as a heuristic to compensate for
465 // the lack of precise L1 icache emulation in the JIT. (Portable software
466 // should use icbi consistently, but games aren't portable.)
467 const u32 address = Helper_Get_EA_X(PowerPC::ppcState, inst);
468 JitInterface::InvalidateICache(address & ~0x1f, 32, false);
469 }
470
dcbst(UGeckoInstruction inst)471 void Interpreter::dcbst(UGeckoInstruction inst)
472 {
473 // TODO: Implement some sort of L2 emulation.
474 // TODO: Raise DSI if translation fails (except for direct-store segments).
475
476 // Invalidate the JIT cache here as a heuristic to compensate for
477 // the lack of precise L1 icache emulation in the JIT. (Portable software
478 // should use icbi consistently, but games aren't portable.)
479 const u32 address = Helper_Get_EA_X(PowerPC::ppcState, inst);
480 JitInterface::InvalidateICache(address & ~0x1f, 32, false);
481 }
482
dcbt(UGeckoInstruction inst)483 void Interpreter::dcbt(UGeckoInstruction inst)
484 {
485 if (HID0.NOOPTI)
486 return;
487
488 // TODO: Implement some sort of L2 emulation.
489 }
490
dcbtst(UGeckoInstruction inst)491 void Interpreter::dcbtst(UGeckoInstruction inst)
492 {
493 if (HID0.NOOPTI)
494 return;
495
496 // TODO: Implement some sort of L2 emulation.
497 }
498
dcbz(UGeckoInstruction inst)499 void Interpreter::dcbz(UGeckoInstruction inst)
500 {
501 const u32 dcbz_addr = Helper_Get_EA_X(PowerPC::ppcState, inst);
502
503 if (!HID0.DCE)
504 {
505 GenerateAlignmentException(dcbz_addr);
506 return;
507 }
508
509 // Hack to stop dcbz/dcbi over low MEM1 trashing memory.
510 if (SConfig::GetInstance().bLowDCBZHack && (dcbz_addr < 0x80008000) && (dcbz_addr >= 0x80000000))
511 return;
512
513 // TODO: Implement some sort of L2 emulation.
514 PowerPC::ClearCacheLine(dcbz_addr & (~31));
515 }
516
dcbz_l(UGeckoInstruction inst)517 void Interpreter::dcbz_l(UGeckoInstruction inst)
518 {
519 if (!HID2.LCE)
520 {
521 GenerateProgramException();
522 return;
523 }
524
525 const u32 address = Helper_Get_EA_X(PowerPC::ppcState, inst);
526
527 if (!HID0.DCE)
528 {
529 GenerateAlignmentException(address);
530 return;
531 }
532
533 // FAKE: clear memory instead of clearing the cache block
534 PowerPC::ClearCacheLine(address & (~31));
535 }
536
537 // eciwx/ecowx technically should access the specified device
538 // We just do it instantly from ppc...and hey, it works! :D
eciwx(UGeckoInstruction inst)539 void Interpreter::eciwx(UGeckoInstruction inst)
540 {
541 const u32 EA = Helper_Get_EA_X(PowerPC::ppcState, inst);
542
543 if (!(PowerPC::ppcState.spr[SPR_EAR] & 0x80000000))
544 {
545 GenerateDSIException(EA);
546 return;
547 }
548
549 if (EA & 3)
550 {
551 GenerateAlignmentException(EA);
552 return;
553 }
554
555 rGPR[inst.RD] = PowerPC::Read_U32(EA);
556 }
557
ecowx(UGeckoInstruction inst)558 void Interpreter::ecowx(UGeckoInstruction inst)
559 {
560 const u32 EA = Helper_Get_EA_X(PowerPC::ppcState, inst);
561
562 if (!(PowerPC::ppcState.spr[SPR_EAR] & 0x80000000))
563 {
564 GenerateDSIException(EA);
565 return;
566 }
567
568 if (EA & 3)
569 {
570 GenerateAlignmentException(EA);
571 return;
572 }
573
574 PowerPC::Write_U32(rGPR[inst.RS], EA);
575 }
576
eieio(UGeckoInstruction inst)577 void Interpreter::eieio(UGeckoInstruction inst)
578 {
579 // Basically ensures that loads/stores before this instruction
580 // have completed (in order) before executing the next op.
581 // Prevents real ppc from "smartly" reordering loads/stores
582 // But (at least in interpreter) we do everything realtime anyways.
583 }
584
icbi(UGeckoInstruction inst)585 void Interpreter::icbi(UGeckoInstruction inst)
586 {
587 // TODO: Raise DSI if translation fails (except for direct-store segments).
588 const u32 address = Helper_Get_EA_X(PowerPC::ppcState, inst);
589 PowerPC::ppcState.iCache.Invalidate(address);
590 }
591
lbzux(UGeckoInstruction inst)592 void Interpreter::lbzux(UGeckoInstruction inst)
593 {
594 const u32 address = Helper_Get_EA_UX(PowerPC::ppcState, inst);
595 const u32 temp = PowerPC::Read_U8(address);
596
597 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
598 {
599 rGPR[inst.RD] = temp;
600 rGPR[inst.RA] = address;
601 }
602 }
603
lbzx(UGeckoInstruction inst)604 void Interpreter::lbzx(UGeckoInstruction inst)
605 {
606 const u32 temp = PowerPC::Read_U8(Helper_Get_EA_X(PowerPC::ppcState, inst));
607
608 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
609 {
610 rGPR[inst.RD] = temp;
611 }
612 }
613
lhaux(UGeckoInstruction inst)614 void Interpreter::lhaux(UGeckoInstruction inst)
615 {
616 const u32 address = Helper_Get_EA_UX(PowerPC::ppcState, inst);
617 const s32 temp = (s32)(s16)PowerPC::Read_U16(address);
618
619 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
620 {
621 rGPR[inst.RD] = temp;
622 rGPR[inst.RA] = address;
623 }
624 }
625
lhax(UGeckoInstruction inst)626 void Interpreter::lhax(UGeckoInstruction inst)
627 {
628 const s32 temp = (s32)(s16)PowerPC::Read_U16(Helper_Get_EA_X(PowerPC::ppcState, inst));
629
630 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
631 {
632 rGPR[inst.RD] = temp;
633 }
634 }
635
lhbrx(UGeckoInstruction inst)636 void Interpreter::lhbrx(UGeckoInstruction inst)
637 {
638 const u32 temp = Common::swap16(PowerPC::Read_U16(Helper_Get_EA_X(PowerPC::ppcState, inst)));
639
640 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
641 {
642 rGPR[inst.RD] = temp;
643 }
644 }
645
lhzux(UGeckoInstruction inst)646 void Interpreter::lhzux(UGeckoInstruction inst)
647 {
648 const u32 address = Helper_Get_EA_UX(PowerPC::ppcState, inst);
649 const u32 temp = PowerPC::Read_U16(address);
650
651 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
652 {
653 rGPR[inst.RD] = temp;
654 rGPR[inst.RA] = address;
655 }
656 }
657
lhzx(UGeckoInstruction inst)658 void Interpreter::lhzx(UGeckoInstruction inst)
659 {
660 const u32 temp = PowerPC::Read_U16(Helper_Get_EA_X(PowerPC::ppcState, inst));
661
662 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
663 {
664 rGPR[inst.RD] = temp;
665 }
666 }
667
668 // FIXME: Should rollback if a DSI occurs
lswx(UGeckoInstruction inst)669 void Interpreter::lswx(UGeckoInstruction inst)
670 {
671 u32 EA = Helper_Get_EA_X(PowerPC::ppcState, inst);
672
673 if (MSR.LE)
674 {
675 GenerateAlignmentException(EA);
676 return;
677 }
678
679 // Confirmed by hardware test that the zero case doesn't zero rGPR[r]
680 for (u32 n = 0; n < static_cast<u8>(PowerPC::ppcState.xer_stringctrl); n++)
681 {
682 const int reg = (inst.RD + (n >> 2)) & 0x1f;
683 const int offset = (n & 3) << 3;
684
685 if ((n & 3) == 0)
686 rGPR[reg] = 0;
687
688 const u32 temp_value = PowerPC::Read_U8(EA) << (24 - offset);
689 // Not64 (Homebrew N64 Emulator for Wii) triggers the following case.
690 if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
691 {
692 NOTICE_LOG(POWERPC, "DSI exception in lswx");
693 return;
694 }
695 rGPR[reg] |= temp_value;
696
697 EA++;
698 }
699 }
700
lwbrx(UGeckoInstruction inst)701 void Interpreter::lwbrx(UGeckoInstruction inst)
702 {
703 const u32 temp = Common::swap32(PowerPC::Read_U32(Helper_Get_EA_X(PowerPC::ppcState, inst)));
704
705 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
706 {
707 rGPR[inst.RD] = temp;
708 }
709 }
710
lwzux(UGeckoInstruction inst)711 void Interpreter::lwzux(UGeckoInstruction inst)
712 {
713 const u32 address = Helper_Get_EA_UX(PowerPC::ppcState, inst);
714 const u32 temp = PowerPC::Read_U32(address);
715
716 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
717 {
718 rGPR[inst.RD] = temp;
719 rGPR[inst.RA] = address;
720 }
721 }
722
lwzx(UGeckoInstruction inst)723 void Interpreter::lwzx(UGeckoInstruction inst)
724 {
725 const u32 address = Helper_Get_EA_X(PowerPC::ppcState, inst);
726 const u32 temp = PowerPC::Read_U32(address);
727
728 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
729 {
730 rGPR[inst.RD] = temp;
731 }
732 }
733
stbux(UGeckoInstruction inst)734 void Interpreter::stbux(UGeckoInstruction inst)
735 {
736 const u32 address = Helper_Get_EA_UX(PowerPC::ppcState, inst);
737
738 PowerPC::Write_U8((u8)rGPR[inst.RS], address);
739 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
740 {
741 rGPR[inst.RA] = address;
742 }
743 }
744
stbx(UGeckoInstruction inst)745 void Interpreter::stbx(UGeckoInstruction inst)
746 {
747 PowerPC::Write_U8((u8)rGPR[inst.RS], Helper_Get_EA_X(PowerPC::ppcState, inst));
748 }
749
stfdux(UGeckoInstruction inst)750 void Interpreter::stfdux(UGeckoInstruction inst)
751 {
752 const u32 address = Helper_Get_EA_UX(PowerPC::ppcState, inst);
753
754 if ((address & 0b11) != 0)
755 {
756 GenerateAlignmentException(address);
757 return;
758 }
759
760 PowerPC::Write_U64(rPS(inst.FS).PS0AsU64(), address);
761 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
762 {
763 rGPR[inst.RA] = address;
764 }
765 }
766
stfdx(UGeckoInstruction inst)767 void Interpreter::stfdx(UGeckoInstruction inst)
768 {
769 const u32 address = Helper_Get_EA_X(PowerPC::ppcState, inst);
770
771 if ((address & 0b11) != 0)
772 {
773 GenerateAlignmentException(address);
774 return;
775 }
776
777 PowerPC::Write_U64(rPS(inst.FS).PS0AsU64(), address);
778 }
779
780 // Stores Floating points into Integers indeXed
stfiwx(UGeckoInstruction inst)781 void Interpreter::stfiwx(UGeckoInstruction inst)
782 {
783 const u32 address = Helper_Get_EA_X(PowerPC::ppcState, inst);
784
785 if ((address & 0b11) != 0)
786 {
787 GenerateAlignmentException(address);
788 return;
789 }
790
791 PowerPC::Write_U32(rPS(inst.FS).PS0AsU32(), address);
792 }
793
stfsux(UGeckoInstruction inst)794 void Interpreter::stfsux(UGeckoInstruction inst)
795 {
796 const u32 address = Helper_Get_EA_UX(PowerPC::ppcState, inst);
797
798 if ((address & 0b11) != 0)
799 {
800 GenerateAlignmentException(address);
801 return;
802 }
803
804 PowerPC::Write_U32(ConvertToSingle(rPS(inst.FS).PS0AsU64()), address);
805 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
806 {
807 rGPR[inst.RA] = address;
808 }
809 }
810
stfsx(UGeckoInstruction inst)811 void Interpreter::stfsx(UGeckoInstruction inst)
812 {
813 const u32 address = Helper_Get_EA_X(PowerPC::ppcState, inst);
814
815 if ((address & 0b11) != 0)
816 {
817 GenerateAlignmentException(address);
818 return;
819 }
820
821 PowerPC::Write_U32(ConvertToSingle(rPS(inst.FS).PS0AsU64()), address);
822 }
823
sthbrx(UGeckoInstruction inst)824 void Interpreter::sthbrx(UGeckoInstruction inst)
825 {
826 PowerPC::Write_U16(Common::swap16((u16)rGPR[inst.RS]), Helper_Get_EA_X(PowerPC::ppcState, inst));
827 }
828
sthux(UGeckoInstruction inst)829 void Interpreter::sthux(UGeckoInstruction inst)
830 {
831 const u32 address = Helper_Get_EA_UX(PowerPC::ppcState, inst);
832
833 PowerPC::Write_U16((u16)rGPR[inst.RS], address);
834 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
835 {
836 rGPR[inst.RA] = address;
837 }
838 }
839
sthx(UGeckoInstruction inst)840 void Interpreter::sthx(UGeckoInstruction inst)
841 {
842 PowerPC::Write_U16((u16)rGPR[inst.RS], Helper_Get_EA_X(PowerPC::ppcState, inst));
843 }
844
845 // lswi - bizarro string instruction
846 // FIXME: Should rollback if a DSI occurs
lswi(UGeckoInstruction inst)847 void Interpreter::lswi(UGeckoInstruction inst)
848 {
849 u32 EA;
850 if (inst.RA == 0)
851 EA = 0;
852 else
853 EA = rGPR[inst.RA];
854
855 if (MSR.LE)
856 {
857 GenerateAlignmentException(EA);
858 return;
859 }
860
861 u32 n;
862 if (inst.NB == 0)
863 n = 32;
864 else
865 n = inst.NB;
866
867 int r = inst.RD - 1;
868 int i = 0;
869 while (n > 0)
870 {
871 if (i == 0)
872 {
873 r++;
874 r &= 31;
875 rGPR[r] = 0;
876 }
877
878 const u32 temp_value = PowerPC::Read_U8(EA) << (24 - i);
879 if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
880 {
881 PanicAlert("DSI exception in lsw.");
882 return;
883 }
884
885 rGPR[r] |= temp_value;
886
887 i += 8;
888 if (i == 32)
889 i = 0;
890 EA++;
891 n--;
892 }
893 }
894
895 // todo : optimize ?
896 // stswi - bizarro string instruction
897 // FIXME: Should rollback if a DSI occurs
stswi(UGeckoInstruction inst)898 void Interpreter::stswi(UGeckoInstruction inst)
899 {
900 u32 EA;
901 if (inst.RA == 0)
902 EA = 0;
903 else
904 EA = rGPR[inst.RA];
905
906 if (MSR.LE)
907 {
908 GenerateAlignmentException(EA);
909 return;
910 }
911
912 u32 n;
913 if (inst.NB == 0)
914 n = 32;
915 else
916 n = inst.NB;
917
918 int r = inst.RS - 1;
919 int i = 0;
920 while (n > 0)
921 {
922 if (i == 0)
923 {
924 r++;
925 r &= 31;
926 }
927 PowerPC::Write_U8((rGPR[r] >> (24 - i)) & 0xFF, EA);
928 if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
929 {
930 return;
931 }
932
933 i += 8;
934 if (i == 32)
935 i = 0;
936 EA++;
937 n--;
938 }
939 }
940
941 // TODO: is this right? is it DSI interruptible?
stswx(UGeckoInstruction inst)942 void Interpreter::stswx(UGeckoInstruction inst)
943 {
944 u32 EA = Helper_Get_EA_X(PowerPC::ppcState, inst);
945
946 if (MSR.LE)
947 {
948 GenerateAlignmentException(EA);
949 return;
950 }
951
952 u32 n = (u8)PowerPC::ppcState.xer_stringctrl;
953 int r = inst.RS;
954 int i = 0;
955
956 while (n > 0)
957 {
958 PowerPC::Write_U8((rGPR[r] >> (24 - i)) & 0xFF, EA);
959
960 EA++;
961 n--;
962 i += 8;
963 if (i == 32)
964 {
965 i = 0;
966 r = (r + 1) & 0x1f; // wrap
967 }
968 }
969 }
970
stwbrx(UGeckoInstruction inst)971 void Interpreter::stwbrx(UGeckoInstruction inst)
972 {
973 const u32 address = Helper_Get_EA_X(PowerPC::ppcState, inst);
974
975 PowerPC::Write_U32(Common::swap32(rGPR[inst.RS]), address);
976 }
977
978 // The following two instructions are for SMP communications. On a single
979 // CPU, they cannot fail unless an interrupt happens in between.
980
lwarx(UGeckoInstruction inst)981 void Interpreter::lwarx(UGeckoInstruction inst)
982 {
983 const u32 address = Helper_Get_EA_X(PowerPC::ppcState, inst);
984
985 if ((address & 0b11) != 0)
986 {
987 GenerateAlignmentException(address);
988 return;
989 }
990
991 const u32 temp = PowerPC::Read_U32(address);
992
993 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
994 {
995 rGPR[inst.RD] = temp;
996 m_reserve = true;
997 m_reserve_address = address;
998 }
999 }
1000
1001 // Stores Word Conditional indeXed
stwcxd(UGeckoInstruction inst)1002 void Interpreter::stwcxd(UGeckoInstruction inst)
1003 {
1004 const u32 address = Helper_Get_EA_X(PowerPC::ppcState, inst);
1005
1006 if ((address & 0b11) != 0)
1007 {
1008 GenerateAlignmentException(address);
1009 return;
1010 }
1011
1012 if (m_reserve)
1013 {
1014 if (address == m_reserve_address)
1015 {
1016 PowerPC::Write_U32(rGPR[inst.RS], address);
1017 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
1018 {
1019 m_reserve = false;
1020 PowerPC::ppcState.cr.SetField(0, 2 | PowerPC::GetXER_SO());
1021 return;
1022 }
1023 }
1024 }
1025
1026 PowerPC::ppcState.cr.SetField(0, PowerPC::GetXER_SO());
1027 }
1028
stwux(UGeckoInstruction inst)1029 void Interpreter::stwux(UGeckoInstruction inst)
1030 {
1031 const u32 address = Helper_Get_EA_UX(PowerPC::ppcState, inst);
1032
1033 PowerPC::Write_U32(rGPR[inst.RS], address);
1034 if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
1035 {
1036 rGPR[inst.RA] = address;
1037 }
1038 }
1039
stwx(UGeckoInstruction inst)1040 void Interpreter::stwx(UGeckoInstruction inst)
1041 {
1042 const u32 address = Helper_Get_EA_X(PowerPC::ppcState, inst);
1043
1044 PowerPC::Write_U32(rGPR[inst.RS], address);
1045 }
1046
sync(UGeckoInstruction inst)1047 void Interpreter::sync(UGeckoInstruction inst)
1048 {
1049 // ignored
1050 }
1051
tlbie(UGeckoInstruction inst)1052 void Interpreter::tlbie(UGeckoInstruction inst)
1053 {
1054 if (MSR.PR)
1055 {
1056 GenerateProgramException();
1057 return;
1058 }
1059
1060 // Invalidate TLB entry
1061 const u32 address = rGPR[inst.RB];
1062
1063 PowerPC::InvalidateTLBEntry(address);
1064 }
1065
tlbsync(UGeckoInstruction inst)1066 void Interpreter::tlbsync(UGeckoInstruction inst)
1067 {
1068 if (MSR.PR)
1069 {
1070 GenerateProgramException();
1071 }
1072
1073 // Ignored
1074 }
1075