@@ -77,7 +77,7 @@ auto CPU::Recompiler::emit(u64 vaddr, u32 address, JITContext ctx) -> Block* {
77
77
mov32 (reg (2 ), imm (instruction));
78
78
call (&CPU::instructionPrologue);
79
79
}
80
- bool branched = emitEXECUTE (instruction);
80
+ bool branched = emitEXECUTE (instruction, ctx );
81
81
if (unlikely (instruction == branchToSelf || instruction == jumpToSelf)) {
82
82
// accelerate idle loops
83
83
mov32 (reg (1 ), imm (64 * 2 ));
@@ -134,12 +134,31 @@ auto CPU::Recompiler::emitZeroClear(u32 n) -> void {
134
134
if (n == 0 ) mov64 (mem (IpuReg (r[0 ])), imm (0 ));
135
135
}
136
136
137
- auto CPU::Recompiler::emitEXECUTE (u32 instruction) -> bool {
137
+ auto CPU::Recompiler::emitOverflowCheck (reg temp) -> sljit_jump* {
138
+ // If overflow flag set: throw an exception, skip the instruction via the 'end' label.
139
+ mov32_f (temp, flag_o);
140
+ auto didntOverflow = cmp32_jump (temp, imm (0 ), flag_eq);
141
+ call (&CPU::Exception::arithmeticOverflow, &cpu.exception );
142
+ auto end = jump ();
143
+ setLabel (didntOverflow);
144
+ return end;
145
+ }
146
+
147
+ auto CPU::Recompiler::checkDualAllowed (const JITContext& ctx) -> bool {
148
+ if (ctx.mode != Context::Mode::Kernel && !ctx.is64bit ) {
149
+ call (&CPU::Exception::reservedInstruction, &self.exception );
150
+ return false ;
151
+ }
152
+
153
+ return true ;
154
+ }
155
+
156
+ auto CPU::Recompiler::emitEXECUTE (u32 instruction, JITContext ctx) -> bool {
138
157
switch (instruction >> 26 ) {
139
158
140
159
// SPECIAL
141
160
case 0x00 : {
142
- return emitSPECIAL (instruction);
161
+ return emitSPECIAL (instruction, ctx );
143
162
}
144
163
145
164
// REGIMM
@@ -315,21 +334,19 @@ auto CPU::Recompiler::emitEXECUTE(u32 instruction) -> bool {
315
334
316
335
// DADDI Rt,Rs,i16
317
336
case 0x18 : {
318
- lea ( reg ( 1 ), Rt) ;
319
- lea (reg (2 ), Rs );
320
- mov32 (reg (3 ), imm (i16 ));
321
- call (&CPU::DADDI );
322
- emitZeroClear (Rtn );
337
+ if (! checkDualAllowed (ctx)) return 1 ;
338
+ add64 (reg (0 ), mem (Rs), imm (i16), set_o );
339
+ auto skip = emitOverflowCheck (reg (2 ));
340
+ if (Rtn > 0 ) mov64 ( mem (Rt), reg ( 0 ) );
341
+ setLabel (skip );
323
342
return 0 ;
324
343
}
325
344
326
345
// DADDIU Rt,Rs,i16
327
346
case 0x19 : {
328
- lea (reg (1 ), Rt);
329
- lea (reg (2 ), Rs);
330
- mov32 (reg (3 ), imm (i16));
331
- call (&CPU::DADDIU);
332
- emitZeroClear (Rtn);
347
+ if (!checkDualAllowed (ctx)) return 1 ;
348
+ add64 (reg (0 ), mem (Rs), imm (i16), set_o);
349
+ if (Rtn > 0 ) mov64 (mem (Rt), reg (0 ));
333
350
return 0 ;
334
351
}
335
352
@@ -647,7 +664,7 @@ auto CPU::Recompiler::emitEXECUTE(u32 instruction) -> bool {
647
664
return 0 ;
648
665
}
649
666
650
- auto CPU::Recompiler::emitSPECIAL (u32 instruction) -> bool {
667
+ auto CPU::Recompiler::emitSPECIAL (u32 instruction, JITContext ctx ) -> bool {
651
668
switch (instruction & 0x3f ) {
652
669
653
670
// SLL Rd,Rt,Sa
@@ -791,11 +808,10 @@ auto CPU::Recompiler::emitSPECIAL(u32 instruction) -> bool {
791
808
792
809
// DSLLV Rd,Rt,Rs
793
810
case 0x14 : {
794
- lea (reg (1 ), Rd);
795
- lea (reg (2 ), Rt);
796
- lea (reg (3 ), Rs);
797
- call (&CPU::DSLLV);
798
- emitZeroClear (Rdn);
811
+ if (!checkDualAllowed (ctx)) return 1 ;
812
+ if (Rdn == 0 ) return 0 ;
813
+ and64 (reg (0 ), mem (Rs32), imm (63 ));
814
+ shl64 (mem (Rd), mem (Rt), reg (0 ));
799
815
return 0 ;
800
816
}
801
817
@@ -807,21 +823,19 @@ auto CPU::Recompiler::emitSPECIAL(u32 instruction) -> bool {
807
823
808
824
// DSRLV Rd,Rt,Rs
809
825
case 0x16 : {
810
- lea (reg (1 ), Rd);
811
- lea (reg (2 ), Rt);
812
- lea (reg (3 ), Rs);
813
- call (&CPU::DSRLV);
814
- emitZeroClear (Rdn);
826
+ if (!checkDualAllowed (ctx)) return 1 ;
827
+ if (Rdn == 0 ) return 0 ;
828
+ and64 (reg (0 ), mem (Rs32), imm (63 ));
829
+ lshr64 (mem (Rd), mem (Rt), reg (0 ));
815
830
return 0 ;
816
831
}
817
832
818
833
// DSRAV Rd,Rt,Rs
819
834
case 0x17 : {
820
- lea (reg (1 ), Rd);
821
- lea (reg (2 ), Rt);
822
- lea (reg (3 ), Rs);
823
- call (&CPU::DSRAV);
824
- emitZeroClear (Rdn);
835
+ if (!checkDualAllowed (ctx)) return 1 ;
836
+ if (Rdn == 0 ) return 0 ;
837
+ and64 (reg (0 ), mem (Rs32), imm (63 ));
838
+ ashr64 (mem (Rd), mem (Rt), reg (0 ));
825
839
return 0 ;
826
840
}
827
841
@@ -981,41 +995,42 @@ auto CPU::Recompiler::emitSPECIAL(u32 instruction) -> bool {
981
995
982
996
// DADD Rd,Rs,Rt
983
997
case 0x2c : {
984
- lea ( reg ( 1 ), Rd) ;
985
- lea (reg (2 ), Rs );
986
- lea (reg (3 ), Rt );
987
- call (&CPU::DADD );
988
- emitZeroClear (Rdn );
998
+ if (! checkDualAllowed (ctx)) return 1 ;
999
+ add64 (reg (0 ), mem (Rs), mem (Rt), set_o );
1000
+ auto skip = emitOverflowCheck (reg (2 ) );
1001
+ if (Rdn > 0 ) mov64 ( mem (Rd), reg ( 0 ) );
1002
+ setLabel (skip );
989
1003
return 0 ;
990
1004
}
991
1005
992
1006
// DADDU Rd,Rs,Rt
993
1007
case 0x2d : {
994
- lea (reg (1 ), Rd);
995
- lea (reg (2 ), Rs);
996
- lea (reg (3 ), Rt);
997
- call (&CPU::DADDU);
998
- emitZeroClear (Rdn);
1008
+ if (!checkDualAllowed (ctx)) {
1009
+ return 1 ;
1010
+ }
1011
+
1012
+ if (Rdn == 0 ) return 0 ;
1013
+
1014
+ add64 (reg (0 ), mem (Rs), mem (Rt));
1015
+ mov64 (mem (Rd), reg (0 ));
999
1016
return 0 ;
1000
1017
}
1001
1018
1002
1019
// DSUB Rd,Rs,Rt
1003
1020
case 0x2e : {
1004
- lea ( reg ( 1 ), Rd) ;
1005
- lea (reg (2 ), Rs );
1006
- lea (reg (3 ), Rt );
1007
- call (&CPU::DSUB );
1008
- emitZeroClear (Rdn );
1021
+ if (! checkDualAllowed (ctx)) return 1 ;
1022
+ sub64 (reg (0 ), mem (Rs), mem (Rt), set_o );
1023
+ auto skip = emitOverflowCheck (reg (2 ) );
1024
+ if (Rdn > 0 ) mov64 ( mem (Rd), reg ( 0 ) );
1025
+ setLabel (skip );
1009
1026
return 0 ;
1010
1027
}
1011
1028
1012
1029
// DSUBU Rd,Rs,Rt
1013
1030
case 0x2f : {
1014
- lea (reg (1 ), Rd);
1015
- lea (reg (2 ), Rs);
1016
- lea (reg (3 ), Rt);
1017
- call (&CPU::DSUBU);
1018
- emitZeroClear (Rdn);
1031
+ if (!checkDualAllowed (ctx)) return 1 ;
1032
+ sub64 (reg (0 ), mem (Rs), mem (Rt), set_o);
1033
+ if (Rdn > 0 ) mov64 (mem (Rd), reg (0 ));
1019
1034
return 0 ;
1020
1035
}
1021
1036
@@ -1081,11 +1096,9 @@ auto CPU::Recompiler::emitSPECIAL(u32 instruction) -> bool {
1081
1096
1082
1097
// DSLL Rd,Rt,Sa
1083
1098
case 0x38 : {
1084
- lea (reg (1 ), Rd);
1085
- lea (reg (2 ), Rt);
1086
- mov32 (reg (3 ), imm (Sa));
1087
- call (&CPU::DSLL);
1088
- emitZeroClear (Rdn);
1099
+ if (!checkDualAllowed (ctx)) return 1 ;
1100
+ if (Rdn == 0 ) return 0 ;
1101
+ shl64 (mem (Rd), mem (Rt), imm (Sa));
1089
1102
return 0 ;
1090
1103
}
1091
1104
@@ -1107,21 +1120,17 @@ auto CPU::Recompiler::emitSPECIAL(u32 instruction) -> bool {
1107
1120
1108
1121
// DSRA Rd,Rt,Sa
1109
1122
case 0x3b : {
1110
- lea (reg (1 ), Rd);
1111
- lea (reg (2 ), Rt);
1112
- mov32 (reg (3 ), imm (Sa));
1113
- call (&CPU::DSRA);
1114
- emitZeroClear (Rdn);
1123
+ if (!checkDualAllowed (ctx)) return 1 ;
1124
+ if (Rdn == 0 ) return 0 ;
1125
+ ashr64 (mem (Rd), mem (Rt), imm (Sa));
1115
1126
return 0 ;
1116
1127
}
1117
1128
1118
1129
// DSLL32 Rd,Rt,Sa
1119
1130
case 0x3c : {
1120
- lea (reg (1 ), Rd);
1121
- lea (reg (2 ), Rt);
1122
- mov32 (reg (3 ), imm (Sa+32 ));
1123
- call (&CPU::DSLL);
1124
- emitZeroClear (Rdn);
1131
+ if (!checkDualAllowed (ctx)) return 1 ;
1132
+ if (Rdn == 0 ) return 0 ;
1133
+ shl64 (mem (Rd), mem (Rt), imm (Sa+32 ));
1125
1134
return 0 ;
1126
1135
}
1127
1136
0 commit comments