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