summaryrefslogblamecommitdiffstats
path: root/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
blob: 7b861670287c48a405faede1b753467e236a0051 (plain) (tree)
1
2
3
4
5
6
7
8
9
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389


                                                           



                            
                 
                                
                               
                                
                                             
                                           
                                                   
                                           
                                             
                                             
                                            
                                           
                                           
                                 

                         
 

                                
 

                                              
                                                         
                                                        
                                                    
                                                  
 
                                                                   



                                        

                   




















                                   
                                  
                           
                                  
                           
                                               
                           
                                              


                                            
     

                 

 
                                                                             


                                                                            
                        





                                                          
                                                                            





                                                
                                                                                               












                                                         
                                                                                              


















                                                              
                                                                                                












                                                        
                                                                                               


















                                                             
                                                                                                   



                                                
                             
                                
            
                                         
                                             






                                                            
                                                                                                  


















                                                                 
                                                                                          












                                                         
                                                                                         













                                                              

 


                                                                                                    
 


                                   
 




                                   
 
                                                                                                    

                                         

              
                                                        
        
                                                        
 
                     

 
                                                                                                   




                                                   

              
                       
        
                       
 
                     

 

                                                                              

                                                     
 
              
                                  
        
                                  

                     

 

                                                                             

                                         

              
                                                        
        
                                                        

                     
 
                                            
                            

 
                                                                                                    

                                         
                                       


                                                   
              
                       
        
                       

                     
 
                                            
                            

 

                                                                            




                                                   

              
                       
        
                       
 
                     
 


                                              
 
 

                                                                                  



                                               
                           
                      














                                                   







                                                      

              




                                                   

              

              
                          
        
                          
 
                     
 

                                            

 

                                                                                   



                                               
                           
                                                     
                                                   
 











                                    







                                                      

              




                                                   

              
 
                     
 





                                              

 

                                                                             
                                         
                                       
                                                   
 
                                             







                                              

 
                                                                                                 

                                            
                                         


                                                   

              
                                                       
        
                                                       
 
                     

 
                                                                                                

                                         
                                       

                                                   

              
                       
        
                       
 
                     

 




                                                                          



                                                   
              
                             
        


                             
 
                                            
                            

 




                                                                           
                                                   
 
                   


                                                       
                  
                           
            
                           
 

                          
 
 

                                                                          
                                         
                                       
                                                   
 
                                             

                                              
                  
                               
            
                               
     

 
                                                                                                   


                                         

               

                    

                   
 
                                                         
 
                                                             
                                  

 
                                                                                                   

                                         
                  

               

                    


                   
                                                 
 
                                                             
                                  

 
                                                                                                  

                                         
                  
 


                    

                   
 
                                             
 
                                                             
                                  

 
                                                                                                  


                                         


                    



                                                   
 




                                                               

 

                                                                              



                                               
                           
                      

                                                   
 











                                    

                                        


                                   
                



                                                      




                                                   

              
 





                          

 
                                            























                                                    
                                                  

















                                                                                         

                                                                                         
                                     

                                                                                         
                                    

                                                                                         
                                         

                                                                                         
                                        

                                                                                         
                                          

                                                                                         










                                            

 














                                                                                                 
                                      
 

                                                                                                  
                             
                                                                                       
                                           
                       
                                                     
                                                     
 
                                          

                
                                                                                 




























                                                                                       
                                               



                  
 
 
                                     
 

                                                                            

                                                                                                


                                                               

                                                                                              

                     

                                                                                       










                                                                               



                                                                                               







                                                                                 
                                      
 




                                                  
                                                
                                                    
                                   
 

                                
 
                                             
                                                                                            
 
               
 


                                       
                                                      


                            


                                                


                      
                                                                                  


                                      
                                   





                                                               

                                                    






                                                
                                
          

                    
          















                         

                      

 

                                                                            
                                                
                                       
 
                                               
 


































                                                                                                    

     


                                                                                                   





                                                                                                    
     































































































































































































































































































































































































































                                                                                                    


      


















                                                                                                    
                                         













































































































































































































                                            
      
                        
                      
                                
 
            

               



                                  
         
     
 















                                                                                  
 




                                                                                                  
 






























                                                                                   
     







                                                                                   
 
                                                              
 


                                                                         
 




                                                           
             




                                   
         


                                     
         
     







                                                                                   
 

                                  
 

                                                 
 
                       
 




                                                           
             



                                   
         

                                     

                          












                                                                                     


                                 









                                                                                     
         






                                                                
             






                                     

                          


































                                                                                                


                                 



                                              
 








                                                                                       
 

                                                                                   
 
                         
 

                                                     
 

                                            


                                
 

































































































                                                                                   
         


                                                                    
         













                                                                                   
         












                                                                                   
         






                                                                
             







                                     
         
     
















                                                                                   
 





                                                          
                 
             






                                                              
             
















                                                                               
                     
 
                                      
                              
                 




                                                          
                              
                 

             



                                                           
             






                                                   
         
     







                                                                                   
 




                                                                            
         





























                                                                   
                                                          
 
                                                     
                                                         
 






                                                                       



















                                                                                     
 












                                                                                   
     








                                                                                   
 

                                                              
 


                                                
 
                                     
     










                                                                                              
 



                                                                                   
 
                                                                 
     




                              
 



                                                                                   
 


                                                  
     








                                                                                   
 
                                                  
 
                                         
     








                                                                                   
 
                                                  
 
                                          
     








                                                                                   
 
                                                  
 











                                                                                   
 













                                                                                   
         
                                                         
     








                                                                                   
 


                                                     
         
                                                         
     








                                                                                   
 
















                                                                                   
 





                                                                         
         











                                                                                   
 


                                                                                                   

     




                                              
 


                                                                                   
 







                                                           
         















                                                                                   
             



                                   
         


                                     
         
     







                                                                                   
 

                                                                                       
 





                                                                             
         





                                              
 








                                                                                                   

     




                                              
 


                                                                                   
 


































                                                                                          
                    
                                            
             








                                                                             
             
         

































                                                                                   
             







                                     
         
     







                                                                                   
 

                                  
 

                                                 
 
                       
 




                                                                
             







                                     
         
     











                                              
 



                                                                                   
     




                                              
 










                                                                                   
 

                                                                    
 




                                              
 








                                                                                     
 
                       
 


                                     
 







                                                               
 


                                                               
             



                                   
 



                                                          
 
                                  
 


                                                               
             
         


                                   
 


                                                         
             





                                                               
             
         
 


























































                                                                                     

         
                                                                 

     




                                              
 


              
 

                                                                                   
 

                                       
 















                                                                                                
     
 




                                              
 


                                                                   
 

                                                         
 

                                                  
 


                              
 


                                                                                   
 


                                                    
 








                                                                          
             
































                                                                                   
             




                                   
         

































                                                                                     
             













                                            
             
 
                                                                     
 






                                        
 























                                                                                      

             

                                                                                         
 



                                        
 



                                        
 



                                        
 



                                        
         

     








                                                                                   
 


                                                    
 


                                                                                   
 




                                                                
             








                                     
         
     




                                              
 


                                                                                     
 


                                   
 




                                 
 



                                        
 



                                        
 



                                        
 
                    

     




                                              
 



                                                                       
 



                               
 
                                                                            
 




                                              
 



                                                                                   

     




                                              
 







                                                                                     
 


                                       
 


                                                                       
 


















                                                                                                   
             
 



                                                                       
 



                                                                                         
 

                                                                                           
             



                                                                                         
 


                                                                                           
 

                                                                                        
         
     
 













                                                                                          
 















                                                                                          
 






                                                                                   
 

                                                    
 

                                                                  
 



                                                    
 

                                             
 


                                               
 

                                                   
 
                                                                                      

                                           
 
                        
 





                                                       
 




                                                                                      
             
 

                        

     












                                                                                   
         











                                                   
         
     




                                              
 



























                                                                                   
 


                                                                                   
 



                                                    
 

                                                                                            
 
                                  
 

                                      
     
 




                                              
 



                                                                                   
 




                                                     
 

                                                                  
 


                                                                                             
 






                                                                                     

         

                                             
     
 




                                              
 




                                                                                   
 


                                                   
 

                                                         
 

                                                        
 




                                                      

         



                                           
     
 




                                              
 


























                                                                                          
         





                                       
 


                                                  
         
     




                                              
 


                                                                                   
 
                                                                              
 

                                            
     




                                              
 


                                                                   
 

                                                         
 

                                                    
 




                                              
 


                                                                                   
 


                                               
 


                                                   
 



                                                   
 

                                                                           
 

                                   
 
                    

     




                                              
 



                                                                                   
 

                          
 

                                                                       
 


                                   
 


























                                                                                   
                              
                 
























                                                              
                        
                                                              

                              
                 
             
 


                                                           

             
     







                                                                                   
 




                                                                            
         
                      
     








                                                                                   
 

                                                          
 

                                                   
 
                                        
     

















                                                                                   
 























                                                                                   
 

                                                                          
 



































                                                                                   
         

















                                                                                   
         
     








                                                                                   
 

                                                       
 


                                                         
 




























                                                                                   
         
     








                                                                                   
 











                                                                                   
 

                                                            
 


                                                   
 


                                                
     







                                                                                   
 
                                                              
 














                                                                          
         


                                     
         
     









                                                                                   
 







                                                                                   
 


                                                     
 
                   
     




















                                                                                   
 
                                                                                   
 


                                                                          
     




                                              
 



                                                                                   
 


                                                   
 

                                                                          
 










                                                                                  
         
     
 




                                              
 


                                                                                   
 









                                                                                     
 


                                                                                   
 

                                  
 

                                                 
 
                               
 











                                                                                   
 

                                  
 

                                                 
 
                               
 








                                              
 


























                                                                                     
             
 





                                         
             
         











                                                                      
 


















                                                                      
             
 



















                                                                              
 





                                                

             










                                                                         
 



                                        
 



                                        
 






                                                             
         










                                                                          
 



                                        
 



                                        
 



                                        
 


                                                               
 

                                                                 
 






















                                                                                     
                              

                                                                               
             
                    
                                   

                                                                       
             
                    
                                   

                                                                       
             
                      
                                   

                                                                               
             
















                                                                         
             
                     
                  



                                                                         

             






                                                                               
         






                                              
 



















































                                                                                   
     












                                                                   
 



                                                          
 




























                                                                 
 

















































                                                                                                    
 

                                                
 




                                              
 







                                                                                   
 














                                                                                           

     




                                              
 


                                                                                   
 


                                               
 


                                                   
 



                                                   
 

                                                                             
 

                                   
 
                    

     




                                              
 



                                                                                   
 

                          
 

                                                                         
 

                                   

     




                                              
 



                                                                                   
 



                                                                                    
 








                                                                      
 

                                                            

     




                                              
 



                                                                                   

     




                                              
 



                                                                                   

     




                                              
 



                                                                                   

     








                                                  
 








                                
 
// Copyright 2012 Michael Kang, 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.

#define CITRA_IGNORE_EXIT(x)

#include <algorithm>
#include <cstdio>
#include "common/common_types.h"
#include "common/logging/log.h"
#include "common/microprofile.h"
#include "core/arm/disassembler/arm_disasm.h"
#include "core/arm/dyncom/arm_dyncom_dec.h"
#include "core/arm/dyncom/arm_dyncom_interpreter.h"
#include "core/arm/dyncom/arm_dyncom_run.h"
#include "core/arm/dyncom/arm_dyncom_thumb.h"
#include "core/arm/dyncom/arm_dyncom_trans.h"
#include "core/arm/skyeye_common/armstate.h"
#include "core/arm/skyeye_common/armsupp.h"
#include "core/arm/skyeye_common/vfp/vfp.h"
#include "core/gdbstub/gdbstub.h"
#include "core/hle/svc.h"
#include "core/memory.h"

#define RM BITS(sht_oper, 0, 3)
#define RS BITS(sht_oper, 8, 11)

#define glue(x, y) x##y
#define DPO(s) glue(DataProcessingOperands, s)
#define ROTATE_RIGHT(n, i, l) ((n << (l - i)) | (n >> i))
#define ROTATE_LEFT(n, i, l) ((n >> (l - i)) | (n << i))
#define ROTATE_RIGHT_32(n, i) ROTATE_RIGHT(n, i, 32)
#define ROTATE_LEFT_32(n, i) ROTATE_LEFT(n, i, 32)

static bool CondPassed(const ARMul_State* cpu, unsigned int cond) {
    const bool n_flag = cpu->NFlag != 0;
    const bool z_flag = cpu->ZFlag != 0;
    const bool c_flag = cpu->CFlag != 0;
    const bool v_flag = cpu->VFlag != 0;

    switch (cond) {
    case ConditionCode::EQ:
        return z_flag;
    case ConditionCode::NE:
        return !z_flag;
    case ConditionCode::CS:
        return c_flag;
    case ConditionCode::CC:
        return !c_flag;
    case ConditionCode::MI:
        return n_flag;
    case ConditionCode::PL:
        return !n_flag;
    case ConditionCode::VS:
        return v_flag;
    case ConditionCode::VC:
        return !v_flag;
    case ConditionCode::HI:
        return (c_flag && !z_flag);
    case ConditionCode::LS:
        return (!c_flag || z_flag);
    case ConditionCode::GE:
        return (n_flag == v_flag);
    case ConditionCode::LT:
        return (n_flag != v_flag);
    case ConditionCode::GT:
        return (!z_flag && (n_flag == v_flag));
    case ConditionCode::LE:
        return (z_flag || (n_flag != v_flag));
    case ConditionCode::AL:
    case ConditionCode::NV: // Unconditional
        return true;
    }

    return false;
}

static unsigned int DPO(Immediate)(ARMul_State* cpu, unsigned int sht_oper) {
    unsigned int immed_8 = BITS(sht_oper, 0, 7);
    unsigned int rotate_imm = BITS(sht_oper, 8, 11);
    unsigned int shifter_operand = ROTATE_RIGHT_32(immed_8, rotate_imm * 2);
    if (rotate_imm == 0)
        cpu->shifter_carry_out = cpu->CFlag;
    else
        cpu->shifter_carry_out = BIT(shifter_operand, 31);
    return shifter_operand;
}

static unsigned int DPO(Register)(ARMul_State* cpu, unsigned int sht_oper) {
    unsigned int rm = CHECK_READ_REG15(cpu, RM);
    unsigned int shifter_operand = rm;
    cpu->shifter_carry_out = cpu->CFlag;
    return shifter_operand;
}

static unsigned int DPO(LogicalShiftLeftByImmediate)(ARMul_State* cpu, unsigned int sht_oper) {
    int shift_imm = BITS(sht_oper, 7, 11);
    unsigned int rm = CHECK_READ_REG15(cpu, RM);
    unsigned int shifter_operand;
    if (shift_imm == 0) {
        shifter_operand = rm;
        cpu->shifter_carry_out = cpu->CFlag;
    } else {
        shifter_operand = rm << shift_imm;
        cpu->shifter_carry_out = BIT(rm, 32 - shift_imm);
    }
    return shifter_operand;
}

static unsigned int DPO(LogicalShiftLeftByRegister)(ARMul_State* cpu, unsigned int sht_oper) {
    int shifter_operand;
    unsigned int rm = CHECK_READ_REG15(cpu, RM);
    unsigned int rs = CHECK_READ_REG15(cpu, RS);
    if (BITS(rs, 0, 7) == 0) {
        shifter_operand = rm;
        cpu->shifter_carry_out = cpu->CFlag;
    } else if (BITS(rs, 0, 7) < 32) {
        shifter_operand = rm << BITS(rs, 0, 7);
        cpu->shifter_carry_out = BIT(rm, 32 - BITS(rs, 0, 7));
    } else if (BITS(rs, 0, 7) == 32) {
        shifter_operand = 0;
        cpu->shifter_carry_out = BIT(rm, 0);
    } else {
        shifter_operand = 0;
        cpu->shifter_carry_out = 0;
    }
    return shifter_operand;
}

static unsigned int DPO(LogicalShiftRightByImmediate)(ARMul_State* cpu, unsigned int sht_oper) {
    unsigned int rm = CHECK_READ_REG15(cpu, RM);
    unsigned int shifter_operand;
    int shift_imm = BITS(sht_oper, 7, 11);
    if (shift_imm == 0) {
        shifter_operand = 0;
        cpu->shifter_carry_out = BIT(rm, 31);
    } else {
        shifter_operand = rm >> shift_imm;
        cpu->shifter_carry_out = BIT(rm, shift_imm - 1);
    }
    return shifter_operand;
}

static unsigned int DPO(LogicalShiftRightByRegister)(ARMul_State* cpu, unsigned int sht_oper) {
    unsigned int rs = CHECK_READ_REG15(cpu, RS);
    unsigned int rm = CHECK_READ_REG15(cpu, RM);
    unsigned int shifter_operand;
    if (BITS(rs, 0, 7) == 0) {
        shifter_operand = rm;
        cpu->shifter_carry_out = cpu->CFlag;
    } else if (BITS(rs, 0, 7) < 32) {
        shifter_operand = rm >> BITS(rs, 0, 7);
        cpu->shifter_carry_out = BIT(rm, BITS(rs, 0, 7) - 1);
    } else if (BITS(rs, 0, 7) == 32) {
        shifter_operand = 0;
        cpu->shifter_carry_out = BIT(rm, 31);
    } else {
        shifter_operand = 0;
        cpu->shifter_carry_out = 0;
    }
    return shifter_operand;
}

static unsigned int DPO(ArithmeticShiftRightByImmediate)(ARMul_State* cpu, unsigned int sht_oper) {
    unsigned int rm = CHECK_READ_REG15(cpu, RM);
    unsigned int shifter_operand;
    int shift_imm = BITS(sht_oper, 7, 11);
    if (shift_imm == 0) {
        if (BIT(rm, 31) == 0)
            shifter_operand = 0;
        else
            shifter_operand = 0xFFFFFFFF;
        cpu->shifter_carry_out = BIT(rm, 31);
    } else {
        shifter_operand = static_cast<int>(rm) >> shift_imm;
        cpu->shifter_carry_out = BIT(rm, shift_imm - 1);
    }
    return shifter_operand;
}

static unsigned int DPO(ArithmeticShiftRightByRegister)(ARMul_State* cpu, unsigned int sht_oper) {
    unsigned int rs = CHECK_READ_REG15(cpu, RS);
    unsigned int rm = CHECK_READ_REG15(cpu, RM);
    unsigned int shifter_operand;
    if (BITS(rs, 0, 7) == 0) {
        shifter_operand = rm;
        cpu->shifter_carry_out = cpu->CFlag;
    } else if (BITS(rs, 0, 7) < 32) {
        shifter_operand = static_cast<int>(rm) >> BITS(rs, 0, 7);
        cpu->shifter_carry_out = BIT(rm, BITS(rs, 0, 7) - 1);
    } else {
        if (BIT(rm, 31) == 0)
            shifter_operand = 0;
        else
            shifter_operand = 0xffffffff;
        cpu->shifter_carry_out = BIT(rm, 31);
    }
    return shifter_operand;
}

static unsigned int DPO(RotateRightByImmediate)(ARMul_State* cpu, unsigned int sht_oper) {
    unsigned int shifter_operand;
    unsigned int rm = CHECK_READ_REG15(cpu, RM);
    int shift_imm = BITS(sht_oper, 7, 11);
    if (shift_imm == 0) {
        shifter_operand = (cpu->CFlag << 31) | (rm >> 1);
        cpu->shifter_carry_out = BIT(rm, 0);
    } else {
        shifter_operand = ROTATE_RIGHT_32(rm, shift_imm);
        cpu->shifter_carry_out = BIT(rm, shift_imm - 1);
    }
    return shifter_operand;
}

static unsigned int DPO(RotateRightByRegister)(ARMul_State* cpu, unsigned int sht_oper) {
    unsigned int rm = CHECK_READ_REG15(cpu, RM);
    unsigned int rs = CHECK_READ_REG15(cpu, RS);
    unsigned int shifter_operand;
    if (BITS(rs, 0, 7) == 0) {
        shifter_operand = rm;
        cpu->shifter_carry_out = cpu->CFlag;
    } else if (BITS(rs, 0, 4) == 0) {
        shifter_operand = rm;
        cpu->shifter_carry_out = BIT(rm, 31);
    } else {
        shifter_operand = ROTATE_RIGHT_32(rm, BITS(rs, 0, 4));
        cpu->shifter_carry_out = BIT(rm, BITS(rs, 0, 4) - 1);
    }
    return shifter_operand;
}

#define DEBUG_MSG                                                                                  \
    LOG_DEBUG(Core_ARM11, "inst is %x", inst);                                                     \
    CITRA_IGNORE_EXIT(0)

#define LnSWoUB(s) glue(LnSWoUB, s)
#define MLnS(s) glue(MLnS, s)
#define LdnStM(s) glue(LdnStM, s)

#define W_BIT BIT(inst, 21)
#define U_BIT BIT(inst, 23)
#define I_BIT BIT(inst, 25)
#define P_BIT BIT(inst, 24)
#define OFFSET_12 BITS(inst, 0, 11)

static void LnSWoUB(ImmediateOffset)(ARMul_State* cpu, unsigned int inst, unsigned int& virt_addr) {
    unsigned int Rn = BITS(inst, 16, 19);
    unsigned int addr;

    if (U_BIT)
        addr = CHECK_READ_REG15_WA(cpu, Rn) + OFFSET_12;
    else
        addr = CHECK_READ_REG15_WA(cpu, Rn) - OFFSET_12;

    virt_addr = addr;
}

static void LnSWoUB(RegisterOffset)(ARMul_State* cpu, unsigned int inst, unsigned int& virt_addr) {
    unsigned int Rn = BITS(inst, 16, 19);
    unsigned int Rm = BITS(inst, 0, 3);
    unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
    unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
    unsigned int addr;

    if (U_BIT)
        addr = rn + rm;
    else
        addr = rn - rm;

    virt_addr = addr;
}

static void LnSWoUB(ImmediatePostIndexed)(ARMul_State* cpu, unsigned int inst,
                                          unsigned int& virt_addr) {
    unsigned int Rn = BITS(inst, 16, 19);
    unsigned int addr = CHECK_READ_REG15_WA(cpu, Rn);

    if (U_BIT)
        cpu->Reg[Rn] += OFFSET_12;
    else
        cpu->Reg[Rn] -= OFFSET_12;

    virt_addr = addr;
}

static void LnSWoUB(ImmediatePreIndexed)(ARMul_State* cpu, unsigned int inst,
                                         unsigned int& virt_addr) {
    unsigned int Rn = BITS(inst, 16, 19);
    unsigned int addr;

    if (U_BIT)
        addr = CHECK_READ_REG15_WA(cpu, Rn) + OFFSET_12;
    else
        addr = CHECK_READ_REG15_WA(cpu, Rn) - OFFSET_12;

    virt_addr = addr;

    if (CondPassed(cpu, BITS(inst, 28, 31)))
        cpu->Reg[Rn] = addr;
}

static void MLnS(RegisterPreIndexed)(ARMul_State* cpu, unsigned int inst, unsigned int& virt_addr) {
    unsigned int addr;
    unsigned int Rn = BITS(inst, 16, 19);
    unsigned int Rm = BITS(inst, 0, 3);
    unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
    unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);

    if (U_BIT)
        addr = rn + rm;
    else
        addr = rn - rm;

    virt_addr = addr;

    if (CondPassed(cpu, BITS(inst, 28, 31)))
        cpu->Reg[Rn] = addr;
}

static void LnSWoUB(RegisterPreIndexed)(ARMul_State* cpu, unsigned int inst,
                                        unsigned int& virt_addr) {
    unsigned int Rn = BITS(inst, 16, 19);
    unsigned int Rm = BITS(inst, 0, 3);
    unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
    unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
    unsigned int addr;

    if (U_BIT)
        addr = rn + rm;
    else
        addr = rn - rm;

    virt_addr = addr;

    if (CondPassed(cpu, BITS(inst, 28, 31))) {
        cpu->Reg[Rn] = addr;
    }
}

static void LnSWoUB(ScaledRegisterPreIndexed)(ARMul_State* cpu, unsigned int inst,
                                              unsigned int& virt_addr) {
    unsigned int shift = BITS(inst, 5, 6);
    unsigned int shift_imm = BITS(inst, 7, 11);
    unsigned int Rn = BITS(inst, 16, 19);
    unsigned int Rm = BITS(inst, 0, 3);
    unsigned int index = 0;
    unsigned int addr;
    unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
    unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);

    switch (shift) {
    case 0:
        index = rm << shift_imm;
        break;
    case 1:
        if (shift_imm == 0) {
            index = 0;
        } else {
            index = rm >> shift_imm;
        }
        break;
    case 2:
        if (shift_imm == 0) { // ASR #32
            if (BIT(rm, 31) == 1)
                index = 0xFFFFFFFF;
            else
                index = 0;
        } else {
            index = static_cast<int>(rm) >> shift_imm;
        }
        break;
    case 3:
        if (shift_imm == 0) {
            index = (cpu->CFlag << 31) | (rm >> 1);
        } else {
            index = ROTATE_RIGHT_32(rm, shift_imm);
        }
        break;
    }

    if (U_BIT)
        addr = rn + index;
    else
        addr = rn - index;

    virt_addr = addr;

    if (CondPassed(cpu, BITS(inst, 28, 31)))
        cpu->Reg[Rn] = addr;
}

static void LnSWoUB(ScaledRegisterPostIndexed)(ARMul_State* cpu, unsigned int inst,
                                               unsigned int& virt_addr) {
    unsigned int shift = BITS(inst, 5, 6);
    unsigned int shift_imm = BITS(inst, 7, 11);
    unsigned int Rn = BITS(inst, 16, 19);
    unsigned int Rm = BITS(inst, 0, 3);
    unsigned int index = 0;
    unsigned int addr = CHECK_READ_REG15_WA(cpu, Rn);
    unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);

    switch (shift) {
    case 0:
        index = rm << shift_imm;
        break;
    case 1:
        if (shift_imm == 0) {
            index = 0;
        } else {
            index = rm >> shift_imm;
        }
        break;
    case 2:
        if (shift_imm == 0) { // ASR #32
            if (BIT(rm, 31) == 1)
                index = 0xFFFFFFFF;
            else
                index = 0;
        } else {
            index = static_cast<int>(rm) >> shift_imm;
        }
        break;
    case 3:
        if (shift_imm == 0) {
            index = (cpu->CFlag << 31) | (rm >> 1);
        } else {
            index = ROTATE_RIGHT_32(rm, shift_imm);
        }
        break;
    }

    virt_addr = addr;

    if (CondPassed(cpu, BITS(inst, 28, 31))) {
        if (U_BIT)
            cpu->Reg[Rn] += index;
        else
            cpu->Reg[Rn] -= index;
    }
}

static void LnSWoUB(RegisterPostIndexed)(ARMul_State* cpu, unsigned int inst,
                                         unsigned int& virt_addr) {
    unsigned int Rn = BITS(inst, 16, 19);
    unsigned int Rm = BITS(inst, 0, 3);
    unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);

    virt_addr = CHECK_READ_REG15_WA(cpu, Rn);

    if (CondPassed(cpu, BITS(inst, 28, 31))) {
        if (U_BIT) {
            cpu->Reg[Rn] += rm;
        } else {
            cpu->Reg[Rn] -= rm;
        }
    }
}

static void MLnS(ImmediateOffset)(ARMul_State* cpu, unsigned int inst, unsigned int& virt_addr) {
    unsigned int immedL = BITS(inst, 0, 3);
    unsigned int immedH = BITS(inst, 8, 11);
    unsigned int Rn = BITS(inst, 16, 19);
    unsigned int addr;

    unsigned int offset_8 = (immedH << 4) | immedL;

    if (U_BIT)
        addr = CHECK_READ_REG15_WA(cpu, Rn) + offset_8;
    else
        addr = CHECK_READ_REG15_WA(cpu, Rn) - offset_8;

    virt_addr = addr;
}

static void MLnS(RegisterOffset)(ARMul_State* cpu, unsigned int inst, unsigned int& virt_addr) {
    unsigned int addr;
    unsigned int Rn = BITS(inst, 16, 19);
    unsigned int Rm = BITS(inst, 0, 3);
    unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
    unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);

    if (U_BIT)
        addr = rn + rm;
    else
        addr = rn - rm;

    virt_addr = addr;
}

static void MLnS(ImmediatePreIndexed)(ARMul_State* cpu, unsigned int inst,
                                      unsigned int& virt_addr) {
    unsigned int Rn = BITS(inst, 16, 19);
    unsigned int immedH = BITS(inst, 8, 11);
    unsigned int immedL = BITS(inst, 0, 3);
    unsigned int addr;
    unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
    unsigned int offset_8 = (immedH << 4) | immedL;

    if (U_BIT)
        addr = rn + offset_8;
    else
        addr = rn - offset_8;

    virt_addr = addr;

    if (CondPassed(cpu, BITS(inst, 28, 31)))
        cpu->Reg[Rn] = addr;
}

static void MLnS(ImmediatePostIndexed)(ARMul_State* cpu, unsigned int inst,
                                       unsigned int& virt_addr) {
    unsigned int Rn = BITS(inst, 16, 19);
    unsigned int immedH = BITS(inst, 8, 11);
    unsigned int immedL = BITS(inst, 0, 3);
    unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);

    virt_addr = rn;

    if (CondPassed(cpu, BITS(inst, 28, 31))) {
        unsigned int offset_8 = (immedH << 4) | immedL;
        if (U_BIT)
            rn += offset_8;
        else
            rn -= offset_8;

        cpu->Reg[Rn] = rn;
    }
}

static void MLnS(RegisterPostIndexed)(ARMul_State* cpu, unsigned int inst,
                                      unsigned int& virt_addr) {
    unsigned int Rn = BITS(inst, 16, 19);
    unsigned int Rm = BITS(inst, 0, 3);
    unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);

    virt_addr = CHECK_READ_REG15_WA(cpu, Rn);

    if (CondPassed(cpu, BITS(inst, 28, 31))) {
        if (U_BIT)
            cpu->Reg[Rn] += rm;
        else
            cpu->Reg[Rn] -= rm;
    }
}

static void LdnStM(DecrementBefore)(ARMul_State* cpu, unsigned int inst, unsigned int& virt_addr) {
    unsigned int Rn = BITS(inst, 16, 19);
    unsigned int i = BITS(inst, 0, 15);
    int count = 0;

    while (i) {
        if (i & 1)
            count++;
        i = i >> 1;
    }

    virt_addr = CHECK_READ_REG15_WA(cpu, Rn) - count * 4;

    if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21))
        cpu->Reg[Rn] -= count * 4;
}

static void LdnStM(IncrementBefore)(ARMul_State* cpu, unsigned int inst, unsigned int& virt_addr) {
    unsigned int Rn = BITS(inst, 16, 19);
    unsigned int i = BITS(inst, 0, 15);
    int count = 0;

    while (i) {
        if (i & 1)
            count++;
        i = i >> 1;
    }

    virt_addr = CHECK_READ_REG15_WA(cpu, Rn) + 4;

    if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21))
        cpu->Reg[Rn] += count * 4;
}

static void LdnStM(IncrementAfter)(ARMul_State* cpu, unsigned int inst, unsigned int& virt_addr) {
    unsigned int Rn = BITS(inst, 16, 19);
    unsigned int i = BITS(inst, 0, 15);
    int count = 0;

    while (i) {
        if (i & 1)
            count++;
        i = i >> 1;
    }

    virt_addr = CHECK_READ_REG15_WA(cpu, Rn);

    if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21))
        cpu->Reg[Rn] += count * 4;
}

static void LdnStM(DecrementAfter)(ARMul_State* cpu, unsigned int inst, unsigned int& virt_addr) {
    unsigned int Rn = BITS(inst, 16, 19);
    unsigned int i = BITS(inst, 0, 15);
    int count = 0;
    while (i) {
        if (i & 1)
            count++;
        i = i >> 1;
    }
    unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
    unsigned int start_addr = rn - count * 4 + 4;

    virt_addr = start_addr;

    if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21)) {
        cpu->Reg[Rn] -= count * 4;
    }
}

static void LnSWoUB(ScaledRegisterOffset)(ARMul_State* cpu, unsigned int inst,
                                          unsigned int& virt_addr) {
    unsigned int shift = BITS(inst, 5, 6);
    unsigned int shift_imm = BITS(inst, 7, 11);
    unsigned int Rn = BITS(inst, 16, 19);
    unsigned int Rm = BITS(inst, 0, 3);
    unsigned int index = 0;
    unsigned int addr;
    unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
    unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);

    switch (shift) {
    case 0:
        index = rm << shift_imm;
        break;
    case 1:
        if (shift_imm == 0) {
            index = 0;
        } else {
            index = rm >> shift_imm;
        }
        break;
    case 2:
        if (shift_imm == 0) { // ASR #32
            if (BIT(rm, 31) == 1)
                index = 0xFFFFFFFF;
            else
                index = 0;
        } else {
            index = static_cast<int>(rm) >> shift_imm;
        }
        break;
    case 3:
        if (shift_imm == 0) {
            index = (cpu->CFlag << 31) | (rm >> 1);
        } else {
            index = ROTATE_RIGHT_32(rm, shift_imm);
        }
        break;
    }

    if (U_BIT) {
        addr = rn + index;
    } else
        addr = rn - index;

    virt_addr = addr;
}

shtop_fp_t GetShifterOp(unsigned int inst) {
    if (BIT(inst, 25)) {
        return DPO(Immediate);
    } else if (BITS(inst, 4, 11) == 0) {
        return DPO(Register);
    } else if (BITS(inst, 4, 6) == 0) {
        return DPO(LogicalShiftLeftByImmediate);
    } else if (BITS(inst, 4, 7) == 1) {
        return DPO(LogicalShiftLeftByRegister);
    } else if (BITS(inst, 4, 6) == 2) {
        return DPO(LogicalShiftRightByImmediate);
    } else if (BITS(inst, 4, 7) == 3) {
        return DPO(LogicalShiftRightByRegister);
    } else if (BITS(inst, 4, 6) == 4) {
        return DPO(ArithmeticShiftRightByImmediate);
    } else if (BITS(inst, 4, 7) == 5) {
        return DPO(ArithmeticShiftRightByRegister);
    } else if (BITS(inst, 4, 6) == 6) {
        return DPO(RotateRightByImmediate);
    } else if (BITS(inst, 4, 7) == 7) {
        return DPO(RotateRightByRegister);
    }
    return nullptr;
}

get_addr_fp_t GetAddressingOp(unsigned int inst) {
    if (BITS(inst, 24, 27) == 5 && BIT(inst, 21) == 0) {
        return LnSWoUB(ImmediateOffset);
    } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 0 && BITS(inst, 4, 11) == 0) {
        return LnSWoUB(RegisterOffset);
    } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 0 && BIT(inst, 4) == 0) {
        return LnSWoUB(ScaledRegisterOffset);
    } else if (BITS(inst, 24, 27) == 5 && BIT(inst, 21) == 1) {
        return LnSWoUB(ImmediatePreIndexed);
    } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 1 && BITS(inst, 4, 11) == 0) {
        return LnSWoUB(RegisterPreIndexed);
    } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 1 && BIT(inst, 4) == 0) {
        return LnSWoUB(ScaledRegisterPreIndexed);
    } else if (BITS(inst, 24, 27) == 4 && BIT(inst, 21) == 0) {
        return LnSWoUB(ImmediatePostIndexed);
    } else if (BITS(inst, 24, 27) == 6 && BIT(inst, 21) == 0 && BITS(inst, 4, 11) == 0) {
        return LnSWoUB(RegisterPostIndexed);
    } else if (BITS(inst, 24, 27) == 6 && BIT(inst, 21) == 0 && BIT(inst, 4) == 0) {
        return LnSWoUB(ScaledRegisterPostIndexed);
    } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 2 && BIT(inst, 7) == 1 &&
               BIT(inst, 4) == 1) {
        return MLnS(ImmediateOffset);
    } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 0 && BIT(inst, 7) == 1 &&
               BIT(inst, 4) == 1) {
        return MLnS(RegisterOffset);
    } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 3 && BIT(inst, 7) == 1 &&
               BIT(inst, 4) == 1) {
        return MLnS(ImmediatePreIndexed);
    } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 1 && BIT(inst, 7) == 1 &&
               BIT(inst, 4) == 1) {
        return MLnS(RegisterPreIndexed);
    } else if (BITS(inst, 24, 27) == 0 && BITS(inst, 21, 22) == 2 && BIT(inst, 7) == 1 &&
               BIT(inst, 4) == 1) {
        return MLnS(ImmediatePostIndexed);
    } else if (BITS(inst, 24, 27) == 0 && BITS(inst, 21, 22) == 0 && BIT(inst, 7) == 1 &&
               BIT(inst, 4) == 1) {
        return MLnS(RegisterPostIndexed);
    } else if (BITS(inst, 23, 27) == 0x11) {
        return LdnStM(IncrementAfter);
    } else if (BITS(inst, 23, 27) == 0x13) {
        return LdnStM(IncrementBefore);
    } else if (BITS(inst, 23, 27) == 0x10) {
        return LdnStM(DecrementAfter);
    } else if (BITS(inst, 23, 27) == 0x12) {
        return LdnStM(DecrementBefore);
    }
    return nullptr;
}

// Specialized for LDRT, LDRBT, STRT, and STRBT, which have specific addressing mode requirements
get_addr_fp_t GetAddressingOpLoadStoreT(unsigned int inst) {
    if (BITS(inst, 25, 27) == 2) {
        return LnSWoUB(ImmediatePostIndexed);
    } else if (BITS(inst, 25, 27) == 3) {
        return LnSWoUB(ScaledRegisterPostIndexed);
    }
    // Reaching this would indicate the thumb version
    // of this instruction, however the 3DS CPU doesn't
    // support this variant (the 3DS CPU is only ARMv6K,
    // while this variant is added in ARMv6T2).
    // So it's sufficient for citra to not implement this.
    return nullptr;
}

enum { FETCH_SUCCESS, FETCH_FAILURE };

static ThumbDecodeStatus DecodeThumbInstruction(u32 inst, u32 addr, u32* arm_inst, u32* inst_size,
                                                ARM_INST_PTR* ptr_inst_base) {
    // Check if in Thumb mode
    ThumbDecodeStatus ret = TranslateThumbInstruction(addr, inst, arm_inst, inst_size);
    if (ret == ThumbDecodeStatus::BRANCH) {
        int inst_index;
        int table_length = arm_instruction_trans_len;
        u32 tinstr = GetThumbInstruction(inst, addr);

        switch ((tinstr & 0xF800) >> 11) {
        case 26:
        case 27:
            if (((tinstr & 0x0F00) != 0x0E00) && ((tinstr & 0x0F00) != 0x0F00)) {
                inst_index = table_length - 4;
                *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index);
            } else {
                LOG_ERROR(Core_ARM11, "thumb decoder error");
            }
            break;
        case 28:
            // Branch 2, unconditional branch
            inst_index = table_length - 5;
            *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index);
            break;

        case 8:
        case 29:
            // For BLX 1 thumb instruction
            inst_index = table_length - 1;
            *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index);
            break;
        case 30:
            // For BL 1 thumb instruction
            inst_index = table_length - 3;
            *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index);
            break;
        case 31:
            // For BL 2 thumb instruction
            inst_index = table_length - 2;
            *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index);
            break;
        default:
            ret = ThumbDecodeStatus::UNDEFINED;
            break;
        }
    }
    return ret;
}

enum { KEEP_GOING, FETCH_EXCEPTION };

MICROPROFILE_DEFINE(DynCom_Decode, "DynCom", "Decode", MP_RGB(255, 64, 64));

static unsigned int InterpreterTranslateInstruction(const ARMul_State* cpu, const u32 phys_addr,
                                                    ARM_INST_PTR& inst_base) {
    unsigned int inst_size = 4;
    unsigned int inst = Memory::Read32(phys_addr & 0xFFFFFFFC);

    // If we are in Thumb mode, we'll translate one Thumb instruction to the corresponding ARM
    // instruction
    if (cpu->TFlag) {
        u32 arm_inst;
        ThumbDecodeStatus state =
            DecodeThumbInstruction(inst, phys_addr, &arm_inst, &inst_size, &inst_base);

        // We have translated the Thumb branch instruction in the Thumb decoder
        if (state == ThumbDecodeStatus::BRANCH) {
            return inst_size;
        }
        inst = arm_inst;
    }

    int idx;
    if (DecodeARMInstruction(inst, &idx) == ARMDecodeStatus::FAILURE) {
        std::string disasm = ARM_Disasm::Disassemble(phys_addr, inst);
        LOG_ERROR(Core_ARM11, "Decode failure.\tPC : [0x%x]\tInstruction : %s [%x]", phys_addr,
                  disasm.c_str(), inst);
        LOG_ERROR(Core_ARM11, "cpsr=0x%x, cpu->TFlag=%d, r15=0x%x", cpu->Cpsr, cpu->TFlag,
                  cpu->Reg[15]);
        CITRA_IGNORE_EXIT(-1);
    }
    inst_base = arm_instruction_trans[idx](inst, idx);

    return inst_size;
}

static int InterpreterTranslateBlock(ARMul_State* cpu, int& bb_start, u32 addr) {
    MICROPROFILE_SCOPE(DynCom_Decode);

    // Decode instruction, get index
    // Allocate memory and init InsCream
    // Go on next, until terminal instruction
    // Save start addr of basicblock in CreamCache
    ARM_INST_PTR inst_base = nullptr;
    TransExtData ret = TransExtData::NON_BRANCH;
    int size = 0; // instruction size of basic block
    bb_start = trans_cache_buf_top;

    u32 phys_addr = addr;
    u32 pc_start = cpu->Reg[15];

    while (ret == TransExtData::NON_BRANCH) {
        unsigned int inst_size = InterpreterTranslateInstruction(cpu, phys_addr, inst_base);

        size++;

        phys_addr += inst_size;

        if ((phys_addr & 0xfff) == 0) {
            inst_base->br = TransExtData::END_OF_PAGE;
        }
        ret = inst_base->br;
    };

    cpu->instruction_cache[pc_start] = bb_start;

    return KEEP_GOING;
}

static int InterpreterTranslateSingle(ARMul_State* cpu, int& bb_start, u32 addr) {
    MICROPROFILE_SCOPE(DynCom_Decode);

    ARM_INST_PTR inst_base = nullptr;
    bb_start = trans_cache_buf_top;

    u32 phys_addr = addr;
    u32 pc_start = cpu->Reg[15];

    InterpreterTranslateInstruction(cpu, phys_addr, inst_base);

    if (inst_base->br == TransExtData::NON_BRANCH) {
        inst_base->br = TransExtData::SINGLE_STEP;
    }

    cpu->instruction_cache[pc_start] = bb_start;

    return KEEP_GOING;
}

static int clz(unsigned int x) {
    int n;
    if (x == 0)
        return (32);
    n = 1;
    if ((x >> 16) == 0) {
        n = n + 16;
        x = x << 16;
    }
    if ((x >> 24) == 0) {
        n = n + 8;
        x = x << 8;
    }
    if ((x >> 28) == 0) {
        n = n + 4;
        x = x << 4;
    }
    if ((x >> 30) == 0) {
        n = n + 2;
        x = x << 2;
    }
    n = n - (x >> 31);
    return n;
}

MICROPROFILE_DEFINE(DynCom_Execute, "DynCom", "Execute", MP_RGB(255, 0, 0));

unsigned InterpreterMainLoop(ARMul_State* cpu) {
    MICROPROFILE_SCOPE(DynCom_Execute);

    GDBStub::BreakpointAddress breakpoint_data;

#undef RM
#undef RS

#define CRn inst_cream->crn
#define OPCODE_1 inst_cream->opcode_1
#define OPCODE_2 inst_cream->opcode_2
#define CRm inst_cream->crm
#define RD cpu->Reg[inst_cream->Rd]
#define RD2 cpu->Reg[inst_cream->Rd + 1]
#define RN cpu->Reg[inst_cream->Rn]
#define RM cpu->Reg[inst_cream->Rm]
#define RS cpu->Reg[inst_cream->Rs]
#define RDHI cpu->Reg[inst_cream->RdHi]
#define RDLO cpu->Reg[inst_cream->RdLo]
#define LINK_RTN_ADDR (cpu->Reg[14] = cpu->Reg[15] + 4)
#define SET_PC (cpu->Reg[15] = cpu->Reg[15] + 8 + inst_cream->signed_immed_24)
#define SHIFTER_OPERAND inst_cream->shtop_func(cpu, inst_cream->shifter_operand)

#define FETCH_INST                                                                                 \
    if (inst_base->br != TransExtData::NON_BRANCH)                                                 \
        goto DISPATCH;                                                                             \
    inst_base = (arm_inst*)&trans_cache_buf[ptr]

#define INC_PC(l) ptr += sizeof(arm_inst) + l
#define INC_PC_STUB ptr += sizeof(arm_inst)

#define GDB_BP_CHECK                                                                               \
    cpu->Cpsr &= ~(1 << 5);                                                                        \
    cpu->Cpsr |= cpu->TFlag << 5;                                                                  \
    if (GDBStub::g_server_enabled) {                                                               \
        if (GDBStub::IsMemoryBreak() || (breakpoint_data.type != GDBStub::BreakpointType::None &&  \
                                         PC == breakpoint_data.address)) {                         \
            GDBStub::Break();                                                                      \
            goto END;                                                                              \
        }                                                                                          \
    }

// GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback to a
// clunky switch statement.
#if defined __GNUC__ || defined __clang__
#define GOTO_NEXT_INST                                                                             \
    GDB_BP_CHECK;                                                                                  \
    if (num_instrs >= cpu->NumInstrsToExecute)                                                     \
        goto END;                                                                                  \
    num_instrs++;                                                                                  \
    goto* InstLabel[inst_base->idx]
#else
#define GOTO_NEXT_INST                                                                             \
    GDB_BP_CHECK;                                                                                  \
    if (num_instrs >= cpu->NumInstrsToExecute)                                                     \
        goto END;                                                                                  \
    num_instrs++;                                                                                  \
    switch (inst_base->idx) {                                                                      \
    case 0:                                                                                        \
        goto VMLA_INST;                                                                            \
    case 1:                                                                                        \
        goto VMLS_INST;                                                                            \
    case 2:                                                                                        \
        goto VNMLA_INST;                                                                           \
    case 3:                                                                                        \
        goto VNMLS_INST;                                                                           \
    case 4:                                                                                        \
        goto VNMUL_INST;                                                                           \
    case 5:                                                                                        \
        goto VMUL_INST;                                                                            \
    case 6:                                                                                        \
        goto VADD_INST;                                                                            \
    case 7:                                                                                        \
        goto VSUB_INST;                                                                            \
    case 8:                                                                                        \
        goto VDIV_INST;                                                                            \
    case 9:                                                                                        \
        goto VMOVI_INST;                                                                           \
    case 10:                                                                                       \
        goto VMOVR_INST;                                                                           \
    case 11:                                                                                       \
        goto VABS_INST;                                                                            \
    case 12:                                                                                       \
        goto VNEG_INST;                                                                            \
    case 13:                                                                                       \
        goto VSQRT_INST;                                                                           \
    case 14:                                                                                       \
        goto VCMP_INST;                                                                            \
    case 15:                                                                                       \
        goto VCMP2_INST;                                                                           \
    case 16:                                                                                       \
        goto VCVTBDS_INST;                                                                         \
    case 17:                                                                                       \
        goto VCVTBFF_INST;                                                                         \
    case 18:                                                                                       \
        goto VCVTBFI_INST;                                                                         \
    case 19:                                                                                       \
        goto VMOVBRS_INST;                                                                         \
    case 20:                                                                                       \
        goto VMSR_INST;                                                                            \
    case 21:                                                                                       \
        goto VMOVBRC_INST;                                                                         \
    case 22:                                                                                       \
        goto VMRS_INST;                                                                            \
    case 23:                                                                                       \
        goto VMOVBCR_INST;                                                                         \
    case 24:                                                                                       \
        goto VMOVBRRSS_INST;                                                                       \
    case 25:                                                                                       \
        goto VMOVBRRD_INST;                                                                        \
    case 26:                                                                                       \
        goto VSTR_INST;                                                                            \
    case 27:                                                                                       \
        goto VPUSH_INST;                                                                           \
    case 28:                                                                                       \
        goto VSTM_INST;                                                                            \
    case 29:                                                                                       \
        goto VPOP_INST;                                                                            \
    case 30:                                                                                       \
        goto VLDR_INST;                                                                            \
    case 31:                                                                                       \
        goto VLDM_INST;                                                                            \
    case 32:                                                                                       \
        goto SRS_INST;                                                                             \
    case 33:                                                                                       \
        goto RFE_INST;                                                                             \
    case 34:                                                                                       \
        goto BKPT_INST;                                                                            \
    case 35:                                                                                       \
        goto BLX_INST;                                                                             \
    case 36:                                                                                       \
        goto CPS_INST;                                                                             \
    case 37:                                                                                       \
        goto PLD_INST;                                                                             \
    case 38:                                                                                       \
        goto SETEND_INST;                                                                          \
    case 39:                                                                                       \
        goto CLREX_INST;                                                                           \
    case 40:                                                                                       \
        goto REV16_INST;                                                                           \
    case 41:                                                                                       \
        goto USAD8_INST;                                                                           \
    case 42:                                                                                       \
        goto SXTB_INST;                                                                            \
    case 43:                                                                                       \
        goto UXTB_INST;                                                                            \
    case 44:                                                                                       \
        goto SXTH_INST;                                                                            \
    case 45:                                                                                       \
        goto SXTB16_INST;                                                                          \
    case 46:                                                                                       \
        goto UXTH_INST;                                                                            \
    case 47:                                                                                       \
        goto UXTB16_INST;                                                                          \
    case 48:                                                                                       \
        goto CPY_INST;                                                                             \
    case 49:                                                                                       \
        goto UXTAB_INST;                                                                           \
    case 50:                                                                                       \
        goto SSUB8_INST;                                                                           \
    case 51:                                                                                       \
        goto SHSUB8_INST;                                                                          \
    case 52:                                                                                       \
        goto SSUBADDX_INST;                                                                        \
    case 53:                                                                                       \
        goto STREX_INST;                                                                           \
    case 54:                                                                                       \
        goto STREXB_INST;                                                                          \
    case 55:                                                                                       \
        goto SWP_INST;                                                                             \
    case 56:                                                                                       \
        goto SWPB_INST;                                                                            \
    case 57:                                                                                       \
        goto SSUB16_INST;                                                                          \
    case 58:                                                                                       \
        goto SSAT16_INST;                                                                          \
    case 59:                                                                                       \
        goto SHSUBADDX_INST;                                                                       \
    case 60:                                                                                       \
        goto QSUBADDX_INST;                                                                        \
    case 61:                                                                                       \
        goto SHADDSUBX_INST;                                                                       \
    case 62:                                                                                       \
        goto SHADD8_INST;                                                                          \
    case 63:                                                                                       \
        goto SHADD16_INST;                                                                         \
    case 64:                                                                                       \
        goto SEL_INST;                                                                             \
    case 65:                                                                                       \
        goto SADDSUBX_INST;                                                                        \
    case 66:                                                                                       \
        goto SADD8_INST;                                                                           \
    case 67:                                                                                       \
        goto SADD16_INST;                                                                          \
    case 68:                                                                                       \
        goto SHSUB16_INST;                                                                         \
    case 69:                                                                                       \
        goto UMAAL_INST;                                                                           \
    case 70:                                                                                       \
        goto UXTAB16_INST;                                                                         \
    case 71:                                                                                       \
        goto USUBADDX_INST;                                                                        \
    case 72:                                                                                       \
        goto USUB8_INST;                                                                           \
    case 73:                                                                                       \
        goto USUB16_INST;                                                                          \
    case 74:                                                                                       \
        goto USAT16_INST;                                                                          \
    case 75:                                                                                       \
        goto USADA8_INST;                                                                          \
    case 76:                                                                                       \
        goto UQSUBADDX_INST;                                                                       \
    case 77:                                                                                       \
        goto UQSUB8_INST;                                                                          \
    case 78:                                                                                       \
        goto UQSUB16_INST;                                                                         \
    case 79:                                                                                       \
        goto UQADDSUBX_INST;                                                                       \
    case 80:                                                                                       \
        goto UQADD8_INST;                                                                          \
    case 81:                                                                                       \
        goto UQADD16_INST;                                                                         \
    case 82:                                                                                       \
        goto SXTAB_INST;                                                                           \
    case 83:                                                                                       \
        goto UHSUBADDX_INST;                                                                       \
    case 84:                                                                                       \
        goto UHSUB8_INST;                                                                          \
    case 85:                                                                                       \
        goto UHSUB16_INST;                                                                         \
    case 86:                                                                                       \
        goto UHADDSUBX_INST;                                                                       \
    case 87:                                                                                       \
        goto UHADD8_INST;                                                                          \
    case 88:                                                                                       \
        goto UHADD16_INST;                                                                         \
    case 89:                                                                                       \
        goto UADDSUBX_INST;                                                                        \
    case 90:                                                                                       \
        goto UADD8_INST;                                                                           \
    case 91:                                                                                       \
        goto UADD16_INST;                                                                          \
    case 92:                                                                                       \
        goto SXTAH_INST;                                                                           \
    case 93:                                                                                       \
        goto SXTAB16_INST;                                                                         \
    case 94:                                                                                       \
        goto QADD8_INST;                                                                           \
    case 95:                                                                                       \
        goto BXJ_INST;                                                                             \
    case 96:                                                                                       \
        goto CLZ_INST;                                                                             \
    case 97:                                                                                       \
        goto UXTAH_INST;                                                                           \
    case 98:                                                                                       \
        goto BX_INST;                                                                              \
    case 99:                                                                                       \
        goto REV_INST;                                                                             \
    case 100:                                                                                      \
        goto BLX_INST;                                                                             \
    case 101:                                                                                      \
        goto REVSH_INST;                                                                           \
    case 102:                                                                                      \
        goto QADD_INST;                                                                            \
    case 103:                                                                                      \
        goto QADD16_INST;                                                                          \
    case 104:                                                                                      \
        goto QADDSUBX_INST;                                                                        \
    case 105:                                                                                      \
        goto LDREX_INST;                                                                           \
    case 106:                                                                                      \
        goto QDADD_INST;                                                                           \
    case 107:                                                                                      \
        goto QDSUB_INST;                                                                           \
    case 108:                                                                                      \
        goto QSUB_INST;                                                                            \
    case 109:                                                                                      \
        goto LDREXB_INST;                                                                          \
    case 110:                                                                                      \
        goto QSUB8_INST;                                                                           \
    case 111:                                                                                      \
        goto QSUB16_INST;                                                                          \
    case 112:                                                                                      \
        goto SMUAD_INST;                                                                           \
    case 113:                                                                                      \
        goto SMMUL_INST;                                                                           \
    case 114:                                                                                      \
        goto SMUSD_INST;                                                                           \
    case 115:                                                                                      \
        goto SMLSD_INST;                                                                           \
    case 116:                                                                                      \
        goto SMLSLD_INST;                                                                          \
    case 117:                                                                                      \
        goto SMMLA_INST;                                                                           \
    case 118:                                                                                      \
        goto SMMLS_INST;                                                                           \
    case 119:                                                                                      \
        goto SMLALD_INST;                                                                          \
    case 120:                                                                                      \
        goto SMLAD_INST;                                                                           \
    case 121:                                                                                      \
        goto SMLAW_INST;                                                                           \
    case 122:                                                                                      \
        goto SMULW_INST;                                                                           \
    case 123:                                                                                      \
        goto PKHTB_INST;                                                                           \
    case 124:                                                                                      \
        goto PKHBT_INST;                                                                           \
    case 125:                                                                                      \
        goto SMUL_INST;                                                                            \
    case 126:                                                                                      \
        goto SMLALXY_INST;                                                                         \
    case 127:                                                                                      \
        goto SMLA_INST;                                                                            \
    case 128:                                                                                      \
        goto MCRR_INST;                                                                            \
    case 129:                                                                                      \
        goto MRRC_INST;                                                                            \
    case 130:                                                                                      \
        goto CMP_INST;                                                                             \
    case 131:                                                                                      \
        goto TST_INST;                                                                             \
    case 132:                                                                                      \
        goto TEQ_INST;                                                                             \
    case 133:                                                                                      \
        goto CMN_INST;                                                                             \
    case 134:                                                                                      \
        goto SMULL_INST;                                                                           \
    case 135:                                                                                      \
        goto UMULL_INST;                                                                           \
    case 136:                                                                                      \
        goto UMLAL_INST;                                                                           \
    case 137:                                                                                      \
        goto SMLAL_INST;                                                                           \
    case 138:                                                                                      \
        goto MUL_INST;                                                                             \
    case 139:                                                                                      \
        goto MLA_INST;                                                                             \
    case 140:                                                                                      \
        goto SSAT_INST;                                                                            \
    case 141:                                                                                      \
        goto USAT_INST;                                                                            \
    case 142:                                                                                      \
        goto MRS_INST;                                                                             \
    case 143:                                                                                      \
        goto MSR_INST;                                                                             \
    case 144:                                                                                      \
        goto AND_INST;                                                                             \
    case 145:                                                                                      \
        goto BIC_INST;                                                                             \
    case 146:                                                                                      \
        goto LDM_INST;                                                                             \
    case 147:                                                                                      \
        goto EOR_INST;                                                                             \
    case 148:                                                                                      \
        goto ADD_INST;                                                                             \
    case 149:                                                                                      \
        goto RSB_INST;                                                                             \
    case 150:                                                                                      \
        goto RSC_INST;                                                                             \
    case 151:                                                                                      \
        goto SBC_INST;                                                                             \
    case 152:                                                                                      \
        goto ADC_INST;                                                                             \
    case 153:                                                                                      \
        goto SUB_INST;                                                                             \
    case 154:                                                                                      \
        goto ORR_INST;                                                                             \
    case 155:                                                                                      \
        goto MVN_INST;                                                                             \
    case 156:                                                                                      \
        goto MOV_INST;                                                                             \
    case 157:                                                                                      \
        goto STM_INST;                                                                             \
    case 158:                                                                                      \
        goto LDM_INST;                                                                             \
    case 159:                                                                                      \
        goto LDRSH_INST;                                                                           \
    case 160:                                                                                      \
        goto STM_INST;                                                                             \
    case 161:                                                                                      \
        goto LDM_INST;                                                                             \
    case 162:                                                                                      \
        goto LDRSB_INST;                                                                           \
    case 163:                                                                                      \
        goto STRD_INST;                                                                            \
    case 164:                                                                                      \
        goto LDRH_INST;                                                                            \
    case 165:                                                                                      \
        goto STRH_INST;                                                                            \
    case 166:                                                                                      \
        goto LDRD_INST;                                                                            \
    case 167:                                                                                      \
        goto STRT_INST;                                                                            \
    case 168:                                                                                      \
        goto STRBT_INST;                                                                           \
    case 169:                                                                                      \
        goto LDRBT_INST;                                                                           \
    case 170:                                                                                      \
        goto LDRT_INST;                                                                            \
    case 171:                                                                                      \
        goto MRC_INST;                                                                             \
    case 172:                                                                                      \
        goto MCR_INST;                                                                             \
    case 173:                                                                                      \
        goto MSR_INST;                                                                             \
    case 174:                                                                                      \
        goto MSR_INST;                                                                             \
    case 175:                                                                                      \
        goto MSR_INST;                                                                             \
    case 176:                                                                                      \
        goto MSR_INST;                                                                             \
    case 177:                                                                                      \
        goto MSR_INST;                                                                             \
    case 178:                                                                                      \
        goto LDRB_INST;                                                                            \
    case 179:                                                                                      \
        goto STRB_INST;                                                                            \
    case 180:                                                                                      \
        goto LDR_INST;                                                                             \
    case 181:                                                                                      \
        goto LDRCOND_INST;                                                                         \
    case 182:                                                                                      \
        goto STR_INST;                                                                             \
    case 183:                                                                                      \
        goto CDP_INST;                                                                             \
    case 184:                                                                                      \
        goto STC_INST;                                                                             \
    case 185:                                                                                      \
        goto LDC_INST;                                                                             \
    case 186:                                                                                      \
        goto LDREXD_INST;                                                                          \
    case 187:                                                                                      \
        goto STREXD_INST;                                                                          \
    case 188:                                                                                      \
        goto LDREXH_INST;                                                                          \
    case 189:                                                                                      \
        goto STREXH_INST;                                                                          \
    case 190:                                                                                      \
        goto NOP_INST;                                                                             \
    case 191:                                                                                      \
        goto YIELD_INST;                                                                           \
    case 192:                                                                                      \
        goto WFE_INST;                                                                             \
    case 193:                                                                                      \
        goto WFI_INST;                                                                             \
    case 194:                                                                                      \
        goto SEV_INST;                                                                             \
    case 195:                                                                                      \
        goto SWI_INST;                                                                             \
    case 196:                                                                                      \
        goto BBL_INST;                                                                             \
    case 197:                                                                                      \
        goto B_2_THUMB;                                                                            \
    case 198:                                                                                      \
        goto B_COND_THUMB;                                                                         \
    case 199:                                                                                      \
        goto BL_1_THUMB;                                                                           \
    case 200:                                                                                      \
        goto BL_2_THUMB;                                                                           \
    case 201:                                                                                      \
        goto BLX_1_THUMB;                                                                          \
    case 202:                                                                                      \
        goto DISPATCH;                                                                             \
    case 203:                                                                                      \
        goto INIT_INST_LENGTH;                                                                     \
    case 204:                                                                                      \
        goto END;                                                                                  \
    }
#endif

#define UPDATE_NFLAG(dst) (cpu->NFlag = BIT(dst, 31) ? 1 : 0)
#define UPDATE_ZFLAG(dst) (cpu->ZFlag = dst ? 0 : 1)
#define UPDATE_CFLAG_WITH_SC (cpu->CFlag = cpu->shifter_carry_out)

#define SAVE_NZCVT                                                                                 \
    cpu->Cpsr = (cpu->Cpsr & 0x0fffffdf) | (cpu->NFlag << 31) | (cpu->ZFlag << 30) |               \
                (cpu->CFlag << 29) | (cpu->VFlag << 28) | (cpu->TFlag << 5)
#define LOAD_NZCVT                                                                                 \
    cpu->NFlag = (cpu->Cpsr >> 31);                                                                \
    cpu->ZFlag = (cpu->Cpsr >> 30) & 1;                                                            \
    cpu->CFlag = (cpu->Cpsr >> 29) & 1;                                                            \
    cpu->VFlag = (cpu->Cpsr >> 28) & 1;                                                            \
    cpu->TFlag = (cpu->Cpsr >> 5) & 1;

#define CurrentModeHasSPSR (cpu->Mode != SYSTEM32MODE) && (cpu->Mode != USER32MODE)
#define PC (cpu->Reg[15])

// GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback
// to a clunky switch statement.
#if defined __GNUC__ || defined __clang__
    void* InstLabel[] = {&&VMLA_INST,
                         &&VMLS_INST,
                         &&VNMLA_INST,
                         &&VNMLS_INST,
                         &&VNMUL_INST,
                         &&VMUL_INST,
                         &&VADD_INST,
                         &&VSUB_INST,
                         &&VDIV_INST,
                         &&VMOVI_INST,
                         &&VMOVR_INST,
                         &&VABS_INST,
                         &&VNEG_INST,
                         &&VSQRT_INST,
                         &&VCMP_INST,
                         &&VCMP2_INST,
                         &&VCVTBDS_INST,
                         &&VCVTBFF_INST,
                         &&VCVTBFI_INST,
                         &&VMOVBRS_INST,
                         &&VMSR_INST,
                         &&VMOVBRC_INST,
                         &&VMRS_INST,
                         &&VMOVBCR_INST,
                         &&VMOVBRRSS_INST,
                         &&VMOVBRRD_INST,
                         &&VSTR_INST,
                         &&VPUSH_INST,
                         &&VSTM_INST,
                         &&VPOP_INST,
                         &&VLDR_INST,
                         &&VLDM_INST,

                         &&SRS_INST,
                         &&RFE_INST,
                         &&BKPT_INST,
                         &&BLX_INST,
                         &&CPS_INST,
                         &&PLD_INST,
                         &&SETEND_INST,
                         &&CLREX_INST,
                         &&REV16_INST,
                         &&USAD8_INST,
                         &&SXTB_INST,
                         &&UXTB_INST,
                         &&SXTH_INST,
                         &&SXTB16_INST,
                         &&UXTH_INST,
                         &&UXTB16_INST,
                         &&CPY_INST,
                         &&UXTAB_INST,
                         &&SSUB8_INST,
                         &&SHSUB8_INST,
                         &&SSUBADDX_INST,
                         &&STREX_INST,
                         &&STREXB_INST,
                         &&SWP_INST,
                         &&SWPB_INST,
                         &&SSUB16_INST,
                         &&SSAT16_INST,
                         &&SHSUBADDX_INST,
                         &&QSUBADDX_INST,
                         &&SHADDSUBX_INST,
                         &&SHADD8_INST,
                         &&SHADD16_INST,
                         &&SEL_INST,
                         &&SADDSUBX_INST,
                         &&SADD8_INST,
                         &&SADD16_INST,
                         &&SHSUB16_INST,
                         &&UMAAL_INST,
                         &&UXTAB16_INST,
                         &&USUBADDX_INST,
                         &&USUB8_INST,
                         &&USUB16_INST,
                         &&USAT16_INST,
                         &&USADA8_INST,
                         &&UQSUBADDX_INST,
                         &&UQSUB8_INST,
                         &&UQSUB16_INST,
                         &&UQADDSUBX_INST,
                         &&UQADD8_INST,
                         &&UQADD16_INST,
                         &&SXTAB_INST,
                         &&UHSUBADDX_INST,
                         &&UHSUB8_INST,
                         &&UHSUB16_INST,
                         &&UHADDSUBX_INST,
                         &&UHADD8_INST,
                         &&UHADD16_INST,
                         &&UADDSUBX_INST,
                         &&UADD8_INST,
                         &&UADD16_INST,
                         &&SXTAH_INST,
                         &&SXTAB16_INST,
                         &&QADD8_INST,
                         &&BXJ_INST,
                         &&CLZ_INST,
                         &&UXTAH_INST,
                         &&BX_INST,
                         &&REV_INST,
                         &&BLX_INST,
                         &&REVSH_INST,
                         &&QADD_INST,
                         &&QADD16_INST,
                         &&QADDSUBX_INST,
                         &&LDREX_INST,
                         &&QDADD_INST,
                         &&QDSUB_INST,
                         &&QSUB_INST,
                         &&LDREXB_INST,
                         &&QSUB8_INST,
                         &&QSUB16_INST,
                         &&SMUAD_INST,
                         &&SMMUL_INST,
                         &&SMUSD_INST,
                         &&SMLSD_INST,
                         &&SMLSLD_INST,
                         &&SMMLA_INST,
                         &&SMMLS_INST,
                         &&SMLALD_INST,
                         &&SMLAD_INST,
                         &&SMLAW_INST,
                         &&SMULW_INST,
                         &&PKHTB_INST,
                         &&PKHBT_INST,
                         &&SMUL_INST,
                         &&SMLALXY_INST,
                         &&SMLA_INST,
                         &&MCRR_INST,
                         &&MRRC_INST,
                         &&CMP_INST,
                         &&TST_INST,
                         &&TEQ_INST,
                         &&CMN_INST,
                         &&SMULL_INST,
                         &&UMULL_INST,
                         &&UMLAL_INST,
                         &&SMLAL_INST,
                         &&MUL_INST,
                         &&MLA_INST,
                         &&SSAT_INST,
                         &&USAT_INST,
                         &&MRS_INST,
                         &&MSR_INST,
                         &&AND_INST,
                         &&BIC_INST,
                         &&LDM_INST,
                         &&EOR_INST,
                         &&ADD_INST,
                         &&RSB_INST,
                         &&RSC_INST,
                         &&SBC_INST,
                         &&ADC_INST,
                         &&SUB_INST,
                         &&ORR_INST,
                         &&MVN_INST,
                         &&MOV_INST,
                         &&STM_INST,
                         &&LDM_INST,
                         &&LDRSH_INST,
                         &&STM_INST,
                         &&LDM_INST,
                         &&LDRSB_INST,
                         &&STRD_INST,
                         &&LDRH_INST,
                         &&STRH_INST,
                         &&LDRD_INST,
                         &&STRT_INST,
                         &&STRBT_INST,
                         &&LDRBT_INST,
                         &&LDRT_INST,
                         &&MRC_INST,
                         &&MCR_INST,
                         &&MSR_INST,
                         &&MSR_INST,
                         &&MSR_INST,
                         &&MSR_INST,
                         &&MSR_INST,
                         &&LDRB_INST,
                         &&STRB_INST,
                         &&LDR_INST,
                         &&LDRCOND_INST,
                         &&STR_INST,
                         &&CDP_INST,
                         &&STC_INST,
                         &&LDC_INST,
                         &&LDREXD_INST,
                         &&STREXD_INST,
                         &&LDREXH_INST,
                         &&STREXH_INST,
                         &&NOP_INST,
                         &&YIELD_INST,
                         &&WFE_INST,
                         &&WFI_INST,
                         &&SEV_INST,
                         &&SWI_INST,
                         &&BBL_INST,
                         &&B_2_THUMB,
                         &&B_COND_THUMB,
                         &&BL_1_THUMB,
                         &&BL_2_THUMB,
                         &&BLX_1_THUMB,
                         &&DISPATCH,
                         &&INIT_INST_LENGTH,
                         &&END};
#endif
    arm_inst* inst_base;
    unsigned int addr;
    unsigned int num_instrs = 0;

    int ptr;

    LOAD_NZCVT;
DISPATCH : {
    if (!cpu->NirqSig) {
        if (!(cpu->Cpsr & 0x80)) {
            goto END;
        }
    }

    if (cpu->TFlag)
        cpu->Reg[15] &= 0xfffffffe;
    else
        cpu->Reg[15] &= 0xfffffffc;

    // Find the cached instruction cream, otherwise translate it...
    auto itr = cpu->instruction_cache.find(cpu->Reg[15]);
    if (itr != cpu->instruction_cache.end()) {
        ptr = itr->second;
    } else if (cpu->NumInstrsToExecute != 1) {
        if (InterpreterTranslateBlock(cpu, ptr, cpu->Reg[15]) == FETCH_EXCEPTION)
            goto END;
    } else {
        if (InterpreterTranslateSingle(cpu, ptr, cpu->Reg[15]) == FETCH_EXCEPTION)
            goto END;
    }

    // Find breakpoint if one exists within the block
    if (GDBStub::g_server_enabled && GDBStub::IsConnected()) {
        breakpoint_data =
            GDBStub::GetNextBreakpointFromAddress(cpu->Reg[15], GDBStub::BreakpointType::Execute);
    }

    inst_base = (arm_inst*)&trans_cache_buf[ptr];
    GOTO_NEXT_INST;
}
ADC_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        adc_inst* const inst_cream = (adc_inst*)inst_base->component;

        u32 rn_val = RN;
        if (inst_cream->Rn == 15)
            rn_val += 2 * cpu->GetInstructionSize();

        bool carry;
        bool overflow;
        RD = AddWithCarry(rn_val, SHIFTER_OPERAND, cpu->CFlag, &carry, &overflow);

        if (inst_cream->S && (inst_cream->Rd == 15)) {
            if (CurrentModeHasSPSR) {
                cpu->Cpsr = cpu->Spsr_copy;
                cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
                LOAD_NZCVT;
            }
        } else if (inst_cream->S) {
            UPDATE_NFLAG(RD);
            UPDATE_ZFLAG(RD);
            cpu->CFlag = carry;
            cpu->VFlag = overflow;
        }
        if (inst_cream->Rd == 15) {
            INC_PC(sizeof(adc_inst));
            goto DISPATCH;
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(adc_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
ADD_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        add_inst* const inst_cream = (add_inst*)inst_base->component;

        u32 rn_val = CHECK_READ_REG15_WA(cpu, inst_cream->Rn);

        bool carry;
        bool overflow;
        RD = AddWithCarry(rn_val, SHIFTER_OPERAND, 0, &carry, &overflow);

        if (inst_cream->S && (inst_cream->Rd == 15)) {
            if (CurrentModeHasSPSR) {
                cpu->Cpsr = cpu->Spsr_copy;
                cpu->ChangePrivilegeMode(cpu->Cpsr & 0x1F);
                LOAD_NZCVT;
            }
        } else if (inst_cream->S) {
            UPDATE_NFLAG(RD);
            UPDATE_ZFLAG(RD);
            cpu->CFlag = carry;
            cpu->VFlag = overflow;
        }
        if (inst_cream->Rd == 15) {
            INC_PC(sizeof(add_inst));
            goto DISPATCH;
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(add_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
AND_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        and_inst* const inst_cream = (and_inst*)inst_base->component;

        u32 lop = RN;
        u32 rop = SHIFTER_OPERAND;

        if (inst_cream->Rn == 15)
            lop += 2 * cpu->GetInstructionSize();

        RD = lop & rop;

        if (inst_cream->S && (inst_cream->Rd == 15)) {
            if (CurrentModeHasSPSR) {
                cpu->Cpsr = cpu->Spsr_copy;
                cpu->ChangePrivilegeMode(cpu->Cpsr & 0x1F);
                LOAD_NZCVT;
            }
        } else if (inst_cream->S) {
            UPDATE_NFLAG(RD);
            UPDATE_ZFLAG(RD);
            UPDATE_CFLAG_WITH_SC;
        }
        if (inst_cream->Rd == 15) {
            INC_PC(sizeof(and_inst));
            goto DISPATCH;
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(and_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
BBL_INST : {
    if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) {
        bbl_inst* inst_cream = (bbl_inst*)inst_base->component;
        if (inst_cream->L) {
            LINK_RTN_ADDR;
        }
        SET_PC;
        INC_PC(sizeof(bbl_inst));
        goto DISPATCH;
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(bbl_inst));
    goto DISPATCH;
}
BIC_INST : {
    bic_inst* inst_cream = (bic_inst*)inst_base->component;
    if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) {
        u32 lop = RN;
        if (inst_cream->Rn == 15) {
            lop += 2 * cpu->GetInstructionSize();
        }
        u32 rop = SHIFTER_OPERAND;
        RD = lop & (~rop);
        if ((inst_cream->S) && (inst_cream->Rd == 15)) {
            if (CurrentModeHasSPSR) {
                cpu->Cpsr = cpu->Spsr_copy;
                cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
                LOAD_NZCVT;
            }
        } else if (inst_cream->S) {
            UPDATE_NFLAG(RD);
            UPDATE_ZFLAG(RD);
            UPDATE_CFLAG_WITH_SC;
        }
        if (inst_cream->Rd == 15) {
            INC_PC(sizeof(bic_inst));
            goto DISPATCH;
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(bic_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
BKPT_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        bkpt_inst* const inst_cream = (bkpt_inst*)inst_base->component;
        LOG_DEBUG(Core_ARM11, "Breakpoint instruction hit. Immediate: 0x%08X", inst_cream->imm);
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(bkpt_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
BLX_INST : {
    blx_inst* inst_cream = (blx_inst*)inst_base->component;
    if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) {
        unsigned int inst = inst_cream->inst;
        if (BITS(inst, 20, 27) == 0x12 && BITS(inst, 4, 7) == 0x3) {
            const u32 jump_address = cpu->Reg[inst_cream->val.Rm];
            cpu->Reg[14] = (cpu->Reg[15] + cpu->GetInstructionSize());
            if (cpu->TFlag)
                cpu->Reg[14] |= 0x1;
            cpu->Reg[15] = jump_address & 0xfffffffe;
            cpu->TFlag = jump_address & 0x1;
        } else {
            cpu->Reg[14] = (cpu->Reg[15] + cpu->GetInstructionSize());
            cpu->TFlag = 0x1;
            int signed_int = inst_cream->val.signed_immed_24;
            signed_int = (signed_int & 0x800000) ? (0x3F000000 | signed_int) : signed_int;
            signed_int = signed_int << 2;
            cpu->Reg[15] = cpu->Reg[15] + 8 + signed_int + (BIT(inst, 24) << 1);
        }
        INC_PC(sizeof(blx_inst));
        goto DISPATCH;
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(blx_inst));
    goto DISPATCH;
}

BX_INST:
BXJ_INST : {
    // Note that only the 'fail' case of BXJ is emulated. This is because
    // the facilities for Jazelle emulation are not implemented.
    //
    // According to the ARM documentation on BXJ, if setting the J bit in the APSR
    // fails, then BXJ functions identically like a regular BX instruction.
    //
    // This is sufficient for citra, as the CPU for the 3DS does not implement Jazelle.

    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        bx_inst* const inst_cream = (bx_inst*)inst_base->component;

        u32 address = RM;

        if (inst_cream->Rm == 15)
            address += 2 * cpu->GetInstructionSize();

        cpu->TFlag = address & 1;
        cpu->Reg[15] = address & 0xfffffffe;
        INC_PC(sizeof(bx_inst));
        goto DISPATCH;
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(bx_inst));
    goto DISPATCH;
}

CDP_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        // Undefined instruction here
        cpu->NumInstrsToExecute = 0;
        return num_instrs;
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(cdp_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

CLREX_INST : {
    cpu->UnsetExclusiveMemoryAddress();
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(clrex_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
CLZ_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        clz_inst* inst_cream = (clz_inst*)inst_base->component;
        RD = clz(RM);
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(clz_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
CMN_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        cmn_inst* const inst_cream = (cmn_inst*)inst_base->component;

        u32 rn_val = RN;
        if (inst_cream->Rn == 15)
            rn_val += 2 * cpu->GetInstructionSize();

        bool carry;
        bool overflow;
        u32 result = AddWithCarry(rn_val, SHIFTER_OPERAND, 0, &carry, &overflow);

        UPDATE_NFLAG(result);
        UPDATE_ZFLAG(result);
        cpu->CFlag = carry;
        cpu->VFlag = overflow;
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(cmn_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
CMP_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        cmp_inst* const inst_cream = (cmp_inst*)inst_base->component;

        u32 rn_val = RN;
        if (inst_cream->Rn == 15)
            rn_val += 2 * cpu->GetInstructionSize();

        bool carry;
        bool overflow;
        u32 result = AddWithCarry(rn_val, ~SHIFTER_OPERAND, 1, &carry, &overflow);

        UPDATE_NFLAG(result);
        UPDATE_ZFLAG(result);
        cpu->CFlag = carry;
        cpu->VFlag = overflow;
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(cmp_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
CPS_INST : {
    cps_inst* inst_cream = (cps_inst*)inst_base->component;
    u32 aif_val = 0;
    u32 aif_mask = 0;
    if (cpu->InAPrivilegedMode()) {
        if (inst_cream->imod1) {
            if (inst_cream->A) {
                aif_val |= (inst_cream->imod0 << 8);
                aif_mask |= 1 << 8;
            }
            if (inst_cream->I) {
                aif_val |= (inst_cream->imod0 << 7);
                aif_mask |= 1 << 7;
            }
            if (inst_cream->F) {
                aif_val |= (inst_cream->imod0 << 6);
                aif_mask |= 1 << 6;
            }
            aif_mask = ~aif_mask;
            cpu->Cpsr = (cpu->Cpsr & aif_mask) | aif_val;
        }
        if (inst_cream->mmod) {
            cpu->Cpsr = (cpu->Cpsr & 0xffffffe0) | inst_cream->mode;
            cpu->ChangePrivilegeMode(inst_cream->mode);
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(cps_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
CPY_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        mov_inst* inst_cream = (mov_inst*)inst_base->component;

        RD = SHIFTER_OPERAND;
        if (inst_cream->Rd == 15) {
            INC_PC(sizeof(mov_inst));
            goto DISPATCH;
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(mov_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
EOR_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        eor_inst* inst_cream = (eor_inst*)inst_base->component;

        u32 lop = RN;
        if (inst_cream->Rn == 15) {
            lop += 2 * cpu->GetInstructionSize();
        }
        u32 rop = SHIFTER_OPERAND;
        RD = lop ^ rop;
        if (inst_cream->S && (inst_cream->Rd == 15)) {
            if (CurrentModeHasSPSR) {
                cpu->Cpsr = cpu->Spsr_copy;
                cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
                LOAD_NZCVT;
            }
        } else if (inst_cream->S) {
            UPDATE_NFLAG(RD);
            UPDATE_ZFLAG(RD);
            UPDATE_CFLAG_WITH_SC;
        }
        if (inst_cream->Rd == 15) {
            INC_PC(sizeof(eor_inst));
            goto DISPATCH;
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(eor_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
LDC_INST : {
    // Instruction not implemented
    // LOG_CRITICAL(Core_ARM11, "unimplemented instruction");
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(ldc_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
LDM_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
        inst_cream->get_addr(cpu, inst_cream->inst, addr);

        unsigned int inst = inst_cream->inst;
        if (BIT(inst, 22) && !BIT(inst, 15)) {
            for (int i = 0; i < 13; i++) {
                if (BIT(inst, i)) {
                    cpu->Reg[i] = cpu->ReadMemory32(addr);
                    addr += 4;
                }
            }
            if (BIT(inst, 13)) {
                if (cpu->Mode == USER32MODE)
                    cpu->Reg[13] = cpu->ReadMemory32(addr);
                else
                    cpu->Reg_usr[0] = cpu->ReadMemory32(addr);

                addr += 4;
            }
            if (BIT(inst, 14)) {
                if (cpu->Mode == USER32MODE)
                    cpu->Reg[14] = cpu->ReadMemory32(addr);
                else
                    cpu->Reg_usr[1] = cpu->ReadMemory32(addr);

                addr += 4;
            }
        } else if (!BIT(inst, 22)) {
            for (int i = 0; i < 16; i++) {
                if (BIT(inst, i)) {
                    unsigned int ret = cpu->ReadMemory32(addr);

                    // For armv5t, should enter thumb when bits[0] is non-zero.
                    if (i == 15) {
                        cpu->TFlag = ret & 0x1;
                        ret &= 0xFFFFFFFE;
                    }

                    cpu->Reg[i] = ret;
                    addr += 4;
                }
            }
        } else if (BIT(inst, 22) && BIT(inst, 15)) {
            for (int i = 0; i < 15; i++) {
                if (BIT(inst, i)) {
                    cpu->Reg[i] = cpu->ReadMemory32(addr);
                    addr += 4;
                }
            }

            if (CurrentModeHasSPSR) {
                cpu->Cpsr = cpu->Spsr_copy;
                cpu->ChangePrivilegeMode(cpu->Cpsr & 0x1F);
                LOAD_NZCVT;
            }

            cpu->Reg[15] = cpu->ReadMemory32(addr);
        }

        if (BIT(inst, 15)) {
            INC_PC(sizeof(ldst_inst));
            goto DISPATCH;
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(ldst_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
SXTH_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        sxth_inst* inst_cream = (sxth_inst*)inst_base->component;

        unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate);
        if (BIT(operand2, 15)) {
            operand2 |= 0xffff0000;
        } else {
            operand2 &= 0xffff;
        }
        RD = operand2;
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(sxth_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
LDR_INST : {
    ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
    inst_cream->get_addr(cpu, inst_cream->inst, addr);

    unsigned int value = cpu->ReadMemory32(addr);
    cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;

    if (BITS(inst_cream->inst, 12, 15) == 15) {
        // For armv5t, should enter thumb when bits[0] is non-zero.
        cpu->TFlag = value & 0x1;
        cpu->Reg[15] &= 0xFFFFFFFE;
        INC_PC(sizeof(ldst_inst));
        goto DISPATCH;
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(ldst_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
LDRCOND_INST : {
    if (CondPassed(cpu, inst_base->cond)) {
        ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
        inst_cream->get_addr(cpu, inst_cream->inst, addr);

        unsigned int value = cpu->ReadMemory32(addr);
        cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;

        if (BITS(inst_cream->inst, 12, 15) == 15) {
            // For armv5t, should enter thumb when bits[0] is non-zero.
            cpu->TFlag = value & 0x1;
            cpu->Reg[15] &= 0xFFFFFFFE;
            INC_PC(sizeof(ldst_inst));
            goto DISPATCH;
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(ldst_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
UXTH_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        uxth_inst* inst_cream = (uxth_inst*)inst_base->component;
        RD = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xffff;
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(uxth_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
UXTAH_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        uxtah_inst* inst_cream = (uxtah_inst*)inst_base->component;
        unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xffff;

        RD = RN + operand2;
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(uxtah_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
LDRB_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
        inst_cream->get_addr(cpu, inst_cream->inst, addr);

        cpu->Reg[BITS(inst_cream->inst, 12, 15)] = cpu->ReadMemory8(addr);
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(ldst_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
LDRBT_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
        inst_cream->get_addr(cpu, inst_cream->inst, addr);

        const u32 dest_index = BITS(inst_cream->inst, 12, 15);
        const u32 previous_mode = cpu->Mode;

        cpu->ChangePrivilegeMode(USER32MODE);
        const u8 value = cpu->ReadMemory8(addr);
        cpu->ChangePrivilegeMode(previous_mode);

        cpu->Reg[dest_index] = value;
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(ldst_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
LDRD_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
        // Should check if RD is even-numbered, Rd != 14, addr[0:1] == 0, (CP15_reg1_U == 1 ||
        // addr[2] == 0)
        inst_cream->get_addr(cpu, inst_cream->inst, addr);

        // The 3DS doesn't have LPAE (Large Physical Access Extension), so it
        // wouldn't do this as a single read.
        cpu->Reg[BITS(inst_cream->inst, 12, 15) + 0] = cpu->ReadMemory32(addr);
        cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1] = cpu->ReadMemory32(addr + 4);

        // No dispatch since this operation should not modify R15
    }
    cpu->Reg[15] += 4;
    INC_PC(sizeof(ldst_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

LDREX_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
        unsigned int read_addr = RN;

        cpu->SetExclusiveMemoryAddress(read_addr);

        RD = cpu->ReadMemory32(read_addr);
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(generic_arm_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
LDREXB_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
        unsigned int read_addr = RN;

        cpu->SetExclusiveMemoryAddress(read_addr);

        RD = cpu->ReadMemory8(read_addr);
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(generic_arm_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
LDREXH_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
        unsigned int read_addr = RN;

        cpu->SetExclusiveMemoryAddress(read_addr);

        RD = cpu->ReadMemory16(read_addr);
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(generic_arm_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
LDREXD_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
        unsigned int read_addr = RN;

        cpu->SetExclusiveMemoryAddress(read_addr);

        RD = cpu->ReadMemory32(read_addr);
        RD2 = cpu->ReadMemory32(read_addr + 4);
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(generic_arm_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
LDRH_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
        inst_cream->get_addr(cpu, inst_cream->inst, addr);

        cpu->Reg[BITS(inst_cream->inst, 12, 15)] = cpu->ReadMemory16(addr);
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(ldst_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
LDRSB_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
        inst_cream->get_addr(cpu, inst_cream->inst, addr);
        unsigned int value = cpu->ReadMemory8(addr);
        if (BIT(value, 7)) {
            value |= 0xffffff00;
        }
        cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(ldst_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
LDRSH_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
        inst_cream->get_addr(cpu, inst_cream->inst, addr);

        unsigned int value = cpu->ReadMemory16(addr);
        if (BIT(value, 15)) {
            value |= 0xffff0000;
        }
        cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(ldst_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
LDRT_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
        inst_cream->get_addr(cpu, inst_cream->inst, addr);

        const u32 dest_index = BITS(inst_cream->inst, 12, 15);
        const u32 previous_mode = cpu->Mode;

        cpu->ChangePrivilegeMode(USER32MODE);
        const u32 value = cpu->ReadMemory32(addr);
        cpu->ChangePrivilegeMode(previous_mode);

        cpu->Reg[dest_index] = value;
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(ldst_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
MCR_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        mcr_inst* inst_cream = (mcr_inst*)inst_base->component;

        unsigned int inst = inst_cream->inst;
        if (inst_cream->Rd == 15) {
            DEBUG_MSG;
        } else {
            if (inst_cream->cp_num == 15)
                cpu->WriteCP15Register(RD, CRn, OPCODE_1, CRm, OPCODE_2);
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(mcr_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

MCRR_INST : {
    // Stubbed, as the MPCore doesn't have any registers that are accessible
    // through this instruction.
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        mcrr_inst* const inst_cream = (mcrr_inst*)inst_base->component;

        LOG_ERROR(Core_ARM11, "MCRR executed | Coprocessor: %u, CRm %u, opc1: %u, Rt: %u, Rt2: %u",
                  inst_cream->cp_num, inst_cream->crm, inst_cream->opcode_1, inst_cream->rt,
                  inst_cream->rt2);
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(mcrr_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

MLA_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        mla_inst* inst_cream = (mla_inst*)inst_base->component;

        u64 rm = RM;
        u64 rs = RS;
        u64 rn = RN;

        RD = static_cast<u32>((rm * rs + rn) & 0xffffffff);
        if (inst_cream->S) {
            UPDATE_NFLAG(RD);
            UPDATE_ZFLAG(RD);
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(mla_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
MOV_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        mov_inst* inst_cream = (mov_inst*)inst_base->component;

        RD = SHIFTER_OPERAND;
        if (inst_cream->S && (inst_cream->Rd == 15)) {
            if (CurrentModeHasSPSR) {
                cpu->Cpsr = cpu->Spsr_copy;
                cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
                LOAD_NZCVT;
            }
        } else if (inst_cream->S) {
            UPDATE_NFLAG(RD);
            UPDATE_ZFLAG(RD);
            UPDATE_CFLAG_WITH_SC;
        }
        if (inst_cream->Rd == 15) {
            INC_PC(sizeof(mov_inst));
            goto DISPATCH;
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(mov_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
MRC_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        mrc_inst* inst_cream = (mrc_inst*)inst_base->component;

        if (inst_cream->cp_num == 15) {
            const uint32_t value = cpu->ReadCP15Register(CRn, OPCODE_1, CRm, OPCODE_2);

            if (inst_cream->Rd == 15) {
                cpu->Cpsr = (cpu->Cpsr & ~0xF0000000) | (value & 0xF0000000);
                LOAD_NZCVT;
            } else {
                RD = value;
            }
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(mrc_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

MRRC_INST : {
    // Stubbed, as the MPCore doesn't have any registers that are accessible
    // through this instruction.
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        mcrr_inst* const inst_cream = (mcrr_inst*)inst_base->component;

        LOG_ERROR(Core_ARM11, "MRRC executed | Coprocessor: %u, CRm %u, opc1: %u, Rt: %u, Rt2: %u",
                  inst_cream->cp_num, inst_cream->crm, inst_cream->opcode_1, inst_cream->rt,
                  inst_cream->rt2);
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(mcrr_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

MRS_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        mrs_inst* inst_cream = (mrs_inst*)inst_base->component;

        if (inst_cream->R) {
            RD = cpu->Spsr_copy;
        } else {
            SAVE_NZCVT;
            RD = cpu->Cpsr;
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(mrs_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
MSR_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        msr_inst* inst_cream = (msr_inst*)inst_base->component;
        const u32 UserMask = 0xf80f0200, PrivMask = 0x000001df, StateMask = 0x01000020;
        unsigned int inst = inst_cream->inst;
        unsigned int operand;

        if (BIT(inst, 25)) {
            int rot_imm = BITS(inst, 8, 11) * 2;
            operand = ROTATE_RIGHT_32(BITS(inst, 0, 7), rot_imm);
        } else {
            operand = cpu->Reg[BITS(inst, 0, 3)];
        }
        u32 byte_mask = (BIT(inst, 16) ? 0xff : 0) | (BIT(inst, 17) ? 0xff00 : 0) |
                        (BIT(inst, 18) ? 0xff0000 : 0) | (BIT(inst, 19) ? 0xff000000 : 0);
        u32 mask = 0;
        if (!inst_cream->R) {
            if (cpu->InAPrivilegedMode()) {
                if ((operand & StateMask) != 0) {
                    /// UNPREDICTABLE
                    DEBUG_MSG;
                } else
                    mask = byte_mask & (UserMask | PrivMask);
            } else {
                mask = byte_mask & UserMask;
            }
            SAVE_NZCVT;

            cpu->Cpsr = (cpu->Cpsr & ~mask) | (operand & mask);
            cpu->ChangePrivilegeMode(cpu->Cpsr & 0x1F);
            LOAD_NZCVT;
        } else {
            if (CurrentModeHasSPSR) {
                mask = byte_mask & (UserMask | PrivMask | StateMask);
                cpu->Spsr_copy = (cpu->Spsr_copy & ~mask) | (operand & mask);
            }
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(msr_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
MUL_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        mul_inst* inst_cream = (mul_inst*)inst_base->component;

        u64 rm = RM;
        u64 rs = RS;
        RD = static_cast<u32>((rm * rs) & 0xffffffff);
        if (inst_cream->S) {
            UPDATE_NFLAG(RD);
            UPDATE_ZFLAG(RD);
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(mul_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
MVN_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        mvn_inst* const inst_cream = (mvn_inst*)inst_base->component;

        RD = ~SHIFTER_OPERAND;

        if (inst_cream->S && (inst_cream->Rd == 15)) {
            if (CurrentModeHasSPSR) {
                cpu->Cpsr = cpu->Spsr_copy;
                cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
                LOAD_NZCVT;
            }
        } else if (inst_cream->S) {
            UPDATE_NFLAG(RD);
            UPDATE_ZFLAG(RD);
            UPDATE_CFLAG_WITH_SC;
        }
        if (inst_cream->Rd == 15) {
            INC_PC(sizeof(mvn_inst));
            goto DISPATCH;
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(mvn_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
ORR_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        orr_inst* const inst_cream = (orr_inst*)inst_base->component;

        u32 lop = RN;
        u32 rop = SHIFTER_OPERAND;

        if (inst_cream->Rn == 15)
            lop += 2 * cpu->GetInstructionSize();

        RD = lop | rop;

        if (inst_cream->S && (inst_cream->Rd == 15)) {
            if (CurrentModeHasSPSR) {
                cpu->Cpsr = cpu->Spsr_copy;
                cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
                LOAD_NZCVT;
            }
        } else if (inst_cream->S) {
            UPDATE_NFLAG(RD);
            UPDATE_ZFLAG(RD);
            UPDATE_CFLAG_WITH_SC;
        }
        if (inst_cream->Rd == 15) {
            INC_PC(sizeof(orr_inst));
            goto DISPATCH;
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(orr_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

NOP_INST : {
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC_STUB;
    FETCH_INST;
    GOTO_NEXT_INST;
}

PKHBT_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        pkh_inst* inst_cream = (pkh_inst*)inst_base->component;
        RD = (RN & 0xFFFF) | ((RM << inst_cream->imm) & 0xFFFF0000);
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(pkh_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

PKHTB_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        pkh_inst* inst_cream = (pkh_inst*)inst_base->component;
        int shift_imm = inst_cream->imm ? inst_cream->imm : 31;
        RD = ((static_cast<s32>(RM) >> shift_imm) & 0xFFFF) | (RN & 0xFFFF0000);
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(pkh_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

PLD_INST : {
    // Not implemented. PLD is a hint instruction, so it's optional.

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(pld_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

QADD_INST:
QDADD_INST:
QDSUB_INST:
QSUB_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
        const u8 op1 = inst_cream->op1;
        const u32 rm_val = RM;
        const u32 rn_val = RN;

        u32 result = 0;

        // QADD
        if (op1 == 0x00) {
            result = rm_val + rn_val;

            if (AddOverflow(rm_val, rn_val, result)) {
                result = POS(result) ? 0x80000000 : 0x7FFFFFFF;
                cpu->Cpsr |= (1 << 27);
            }
        }
        // QSUB
        else if (op1 == 0x01) {
            result = rm_val - rn_val;

            if (SubOverflow(rm_val, rn_val, result)) {
                result = POS(result) ? 0x80000000 : 0x7FFFFFFF;
                cpu->Cpsr |= (1 << 27);
            }
        }
        // QDADD
        else if (op1 == 0x02) {
            u32 mul = (rn_val * 2);

            if (AddOverflow(rn_val, rn_val, rn_val * 2)) {
                mul = POS(mul) ? 0x80000000 : 0x7FFFFFFF;
                cpu->Cpsr |= (1 << 27);
            }

            result = mul + rm_val;

            if (AddOverflow(rm_val, mul, result)) {
                result = POS(result) ? 0x80000000 : 0x7FFFFFFF;
                cpu->Cpsr |= (1 << 27);
            }
        }
        // QDSUB
        else if (op1 == 0x03) {
            u32 mul = (rn_val * 2);

            if (AddOverflow(rn_val, rn_val, mul)) {
                mul = POS(mul) ? 0x80000000 : 0x7FFFFFFF;
                cpu->Cpsr |= (1 << 27);
            }

            result = rm_val - mul;

            if (SubOverflow(rm_val, mul, result)) {
                result = POS(result) ? 0x80000000 : 0x7FFFFFFF;
                cpu->Cpsr |= (1 << 27);
            }
        }

        RD = result;
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(generic_arm_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

QADD8_INST:
QADD16_INST:
QADDSUBX_INST:
QSUB8_INST:
QSUB16_INST:
QSUBADDX_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
        const u16 rm_lo = (RM & 0xFFFF);
        const u16 rm_hi = ((RM >> 16) & 0xFFFF);
        const u16 rn_lo = (RN & 0xFFFF);
        const u16 rn_hi = ((RN >> 16) & 0xFFFF);
        const u8 op2 = inst_cream->op2;

        u16 lo_result = 0;
        u16 hi_result = 0;

        // QADD16
        if (op2 == 0x00) {
            lo_result = ARMul_SignedSaturatedAdd16(rn_lo, rm_lo);
            hi_result = ARMul_SignedSaturatedAdd16(rn_hi, rm_hi);
        }
        // QASX
        else if (op2 == 0x01) {
            lo_result = ARMul_SignedSaturatedSub16(rn_lo, rm_hi);
            hi_result = ARMul_SignedSaturatedAdd16(rn_hi, rm_lo);
        }
        // QSAX
        else if (op2 == 0x02) {
            lo_result = ARMul_SignedSaturatedAdd16(rn_lo, rm_hi);
            hi_result = ARMul_SignedSaturatedSub16(rn_hi, rm_lo);
        }
        // QSUB16
        else if (op2 == 0x03) {
            lo_result = ARMul_SignedSaturatedSub16(rn_lo, rm_lo);
            hi_result = ARMul_SignedSaturatedSub16(rn_hi, rm_hi);
        }
        // QADD8
        else if (op2 == 0x04) {
            lo_result = ARMul_SignedSaturatedAdd8(rn_lo & 0xFF, rm_lo & 0xFF) |
                        ARMul_SignedSaturatedAdd8(rn_lo >> 8, rm_lo >> 8) << 8;
            hi_result = ARMul_SignedSaturatedAdd8(rn_hi & 0xFF, rm_hi & 0xFF) |
                        ARMul_SignedSaturatedAdd8(rn_hi >> 8, rm_hi >> 8) << 8;
        }
        // QSUB8
        else if (op2 == 0x07) {
            lo_result = ARMul_SignedSaturatedSub8(rn_lo & 0xFF, rm_lo & 0xFF) |
                        ARMul_SignedSaturatedSub8(rn_lo >> 8, rm_lo >> 8) << 8;
            hi_result = ARMul_SignedSaturatedSub8(rn_hi & 0xFF, rm_hi & 0xFF) |
                        ARMul_SignedSaturatedSub8(rn_hi >> 8, rm_hi >> 8) << 8;
        }

        RD = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16);
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(generic_arm_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

REV_INST:
REV16_INST:
REVSH_INST : {

    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        rev_inst* const inst_cream = (rev_inst*)inst_base->component;

        const u8 op1 = inst_cream->op1;
        const u8 op2 = inst_cream->op2;

        // REV
        if (op1 == 0x03 && op2 == 0x01) {
            RD = ((RM & 0xFF) << 24) | (((RM >> 8) & 0xFF) << 16) | (((RM >> 16) & 0xFF) << 8) |
                 ((RM >> 24) & 0xFF);
        }
        // REV16
        else if (op1 == 0x03 && op2 == 0x05) {
            RD = ((RM & 0xFF) << 8) | ((RM & 0xFF00) >> 8) | ((RM & 0xFF0000) << 8) |
                 ((RM & 0xFF000000) >> 8);
        }
        // REVSH
        else if (op1 == 0x07 && op2 == 0x05) {
            RD = ((RM & 0xFF) << 8) | ((RM & 0xFF00) >> 8);
            if (RD & 0x8000)
                RD |= 0xffff0000;
        }
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(rev_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

RFE_INST : {
    // RFE is unconditional
    ldst_inst* const inst_cream = (ldst_inst*)inst_base->component;

    u32 address = 0;
    inst_cream->get_addr(cpu, inst_cream->inst, address);

    cpu->Cpsr = cpu->ReadMemory32(address);
    cpu->Reg[15] = cpu->ReadMemory32(address + 4);

    INC_PC(sizeof(ldst_inst));
    goto DISPATCH;
}

RSB_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        rsb_inst* const inst_cream = (rsb_inst*)inst_base->component;

        u32 rn_val = RN;
        if (inst_cream->Rn == 15)
            rn_val += 2 * cpu->GetInstructionSize();

        bool carry;
        bool overflow;
        RD = AddWithCarry(~rn_val, SHIFTER_OPERAND, 1, &carry, &overflow);

        if (inst_cream->S && (inst_cream->Rd == 15)) {
            if (CurrentModeHasSPSR) {
                cpu->Cpsr = cpu->Spsr_copy;
                cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
                LOAD_NZCVT;
            }
        } else if (inst_cream->S) {
            UPDATE_NFLAG(RD);
            UPDATE_ZFLAG(RD);
            cpu->CFlag = carry;
            cpu->VFlag = overflow;
        }
        if (inst_cream->Rd == 15) {
            INC_PC(sizeof(rsb_inst));
            goto DISPATCH;
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(rsb_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
RSC_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        rsc_inst* const inst_cream = (rsc_inst*)inst_base->component;

        u32 rn_val = RN;
        if (inst_cream->Rn == 15)
            rn_val += 2 * cpu->GetInstructionSize();

        bool carry;
        bool overflow;
        RD = AddWithCarry(~rn_val, SHIFTER_OPERAND, cpu->CFlag, &carry, &overflow);

        if (inst_cream->S && (inst_cream->Rd == 15)) {
            if (CurrentModeHasSPSR) {
                cpu->Cpsr = cpu->Spsr_copy;
                cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
                LOAD_NZCVT;
            }
        } else if (inst_cream->S) {
            UPDATE_NFLAG(RD);
            UPDATE_ZFLAG(RD);
            cpu->CFlag = carry;
            cpu->VFlag = overflow;
        }
        if (inst_cream->Rd == 15) {
            INC_PC(sizeof(rsc_inst));
            goto DISPATCH;
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(rsc_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

SADD8_INST:
SSUB8_INST:
SADD16_INST:
SADDSUBX_INST:
SSUBADDX_INST:
SSUB16_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
        const u8 op2 = inst_cream->op2;

        if (op2 == 0x00 || op2 == 0x01 || op2 == 0x02 || op2 == 0x03) {
            const s16 rn_lo = (RN & 0xFFFF);
            const s16 rn_hi = ((RN >> 16) & 0xFFFF);
            const s16 rm_lo = (RM & 0xFFFF);
            const s16 rm_hi = ((RM >> 16) & 0xFFFF);

            s32 lo_result = 0;
            s32 hi_result = 0;

            // SADD16
            if (inst_cream->op2 == 0x00) {
                lo_result = (rn_lo + rm_lo);
                hi_result = (rn_hi + rm_hi);
            }
            // SASX
            else if (op2 == 0x01) {
                lo_result = (rn_lo - rm_hi);
                hi_result = (rn_hi + rm_lo);
            }
            // SSAX
            else if (op2 == 0x02) {
                lo_result = (rn_lo + rm_hi);
                hi_result = (rn_hi - rm_lo);
            }
            // SSUB16
            else if (op2 == 0x03) {
                lo_result = (rn_lo - rm_lo);
                hi_result = (rn_hi - rm_hi);
            }

            RD = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16);

            if (lo_result >= 0) {
                cpu->Cpsr |= (1 << 16);
                cpu->Cpsr |= (1 << 17);
            } else {
                cpu->Cpsr &= ~(1 << 16);
                cpu->Cpsr &= ~(1 << 17);
            }

            if (hi_result >= 0) {
                cpu->Cpsr |= (1 << 18);
                cpu->Cpsr |= (1 << 19);
            } else {
                cpu->Cpsr &= ~(1 << 18);
                cpu->Cpsr &= ~(1 << 19);
            }
        } else if (op2 == 0x04 || op2 == 0x07) {
            s32 lo_val1, lo_val2;
            s32 hi_val1, hi_val2;

            // SADD8
            if (op2 == 0x04) {
                lo_val1 = (s32)(s8)(RN & 0xFF) + (s32)(s8)(RM & 0xFF);
                lo_val2 = (s32)(s8)((RN >> 8) & 0xFF) + (s32)(s8)((RM >> 8) & 0xFF);
                hi_val1 = (s32)(s8)((RN >> 16) & 0xFF) + (s32)(s8)((RM >> 16) & 0xFF);
                hi_val2 = (s32)(s8)((RN >> 24) & 0xFF) + (s32)(s8)((RM >> 24) & 0xFF);
            }
            // SSUB8
            else {
                lo_val1 = (s32)(s8)(RN & 0xFF) - (s32)(s8)(RM & 0xFF);
                lo_val2 = (s32)(s8)((RN >> 8) & 0xFF) - (s32)(s8)((RM >> 8) & 0xFF);
                hi_val1 = (s32)(s8)((RN >> 16) & 0xFF) - (s32)(s8)((RM >> 16) & 0xFF);
                hi_val2 = (s32)(s8)((RN >> 24) & 0xFF) - (s32)(s8)((RM >> 24) & 0xFF);
            }

            RD = ((lo_val1 & 0xFF) | ((lo_val2 & 0xFF) << 8) | ((hi_val1 & 0xFF) << 16) |
                  ((hi_val2 & 0xFF) << 24));

            if (lo_val1 >= 0)
                cpu->Cpsr |= (1 << 16);
            else
                cpu->Cpsr &= ~(1 << 16);

            if (lo_val2 >= 0)
                cpu->Cpsr |= (1 << 17);
            else
                cpu->Cpsr &= ~(1 << 17);

            if (hi_val1 >= 0)
                cpu->Cpsr |= (1 << 18);
            else
                cpu->Cpsr &= ~(1 << 18);

            if (hi_val2 >= 0)
                cpu->Cpsr |= (1 << 19);
            else
                cpu->Cpsr &= ~(1 << 19);
        }
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(generic_arm_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

SBC_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        sbc_inst* const inst_cream = (sbc_inst*)inst_base->component;

        u32 rn_val = RN;
        if (inst_cream->Rn == 15)
            rn_val += 2 * cpu->GetInstructionSize();

        bool carry;
        bool overflow;
        RD = AddWithCarry(rn_val, ~SHIFTER_OPERAND, cpu->CFlag, &carry, &overflow);

        if (inst_cream->S && (inst_cream->Rd == 15)) {
            if (CurrentModeHasSPSR) {
                cpu->Cpsr = cpu->Spsr_copy;
                cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
                LOAD_NZCVT;
            }
        } else if (inst_cream->S) {
            UPDATE_NFLAG(RD);
            UPDATE_ZFLAG(RD);
            cpu->CFlag = carry;
            cpu->VFlag = overflow;
        }
        if (inst_cream->Rd == 15) {
            INC_PC(sizeof(sbc_inst));
            goto DISPATCH;
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(sbc_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

SEL_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;

        const u32 to = RM;
        const u32 from = RN;
        const u32 cpsr = cpu->Cpsr;

        u32 result;
        if (cpsr & (1 << 16))
            result = from & 0xff;
        else
            result = to & 0xff;

        if (cpsr & (1 << 17))
            result |= from & 0x0000ff00;
        else
            result |= to & 0x0000ff00;

        if (cpsr & (1 << 18))
            result |= from & 0x00ff0000;
        else
            result |= to & 0x00ff0000;

        if (cpsr & (1 << 19))
            result |= from & 0xff000000;
        else
            result |= to & 0xff000000;

        RD = result;
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(generic_arm_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

SETEND_INST : {
    // SETEND is unconditional
    setend_inst* const inst_cream = (setend_inst*)inst_base->component;
    const bool big_endian = (inst_cream->set_bigend == 1);

    if (big_endian)
        cpu->Cpsr |= (1 << 9);
    else
        cpu->Cpsr &= ~(1 << 9);

    LOG_WARNING(Core_ARM11, "SETEND %s executed", big_endian ? "BE" : "LE");

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(setend_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

SEV_INST : {
    // Stubbed, as SEV is a hint instruction.
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        LOG_TRACE(Core_ARM11, "SEV executed.");
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC_STUB;
    FETCH_INST;
    GOTO_NEXT_INST;
}

SHADD8_INST:
SHADD16_INST:
SHADDSUBX_INST:
SHSUB8_INST:
SHSUB16_INST:
SHSUBADDX_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;

        const u8 op2 = inst_cream->op2;
        const u32 rm_val = RM;
        const u32 rn_val = RN;

        if (op2 == 0x00 || op2 == 0x01 || op2 == 0x02 || op2 == 0x03) {
            s32 lo_result = 0;
            s32 hi_result = 0;

            // SHADD16
            if (op2 == 0x00) {
                lo_result = ((s16)(rn_val & 0xFFFF) + (s16)(rm_val & 0xFFFF)) >> 1;
                hi_result = ((s16)((rn_val >> 16) & 0xFFFF) + (s16)((rm_val >> 16) & 0xFFFF)) >> 1;
            }
            // SHASX
            else if (op2 == 0x01) {
                lo_result = ((s16)(rn_val & 0xFFFF) - (s16)((rm_val >> 16) & 0xFFFF)) >> 1;
                hi_result = ((s16)((rn_val >> 16) & 0xFFFF) + (s16)(rm_val & 0xFFFF)) >> 1;
            }
            // SHSAX
            else if (op2 == 0x02) {
                lo_result = ((s16)(rn_val & 0xFFFF) + (s16)((rm_val >> 16) & 0xFFFF)) >> 1;
                hi_result = ((s16)((rn_val >> 16) & 0xFFFF) - (s16)(rm_val & 0xFFFF)) >> 1;
            }
            // SHSUB16
            else if (op2 == 0x03) {
                lo_result = ((s16)(rn_val & 0xFFFF) - (s16)(rm_val & 0xFFFF)) >> 1;
                hi_result = ((s16)((rn_val >> 16) & 0xFFFF) - (s16)((rm_val >> 16) & 0xFFFF)) >> 1;
            }

            RD = ((lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16));
        } else if (op2 == 0x04 || op2 == 0x07) {
            s16 lo_val1, lo_val2;
            s16 hi_val1, hi_val2;

            // SHADD8
            if (op2 == 0x04) {
                lo_val1 = ((s8)(rn_val & 0xFF) + (s8)(rm_val & 0xFF)) >> 1;
                lo_val2 = ((s8)((rn_val >> 8) & 0xFF) + (s8)((rm_val >> 8) & 0xFF)) >> 1;

                hi_val1 = ((s8)((rn_val >> 16) & 0xFF) + (s8)((rm_val >> 16) & 0xFF)) >> 1;
                hi_val2 = ((s8)((rn_val >> 24) & 0xFF) + (s8)((rm_val >> 24) & 0xFF)) >> 1;
            }
            // SHSUB8
            else {
                lo_val1 = ((s8)(rn_val & 0xFF) - (s8)(rm_val & 0xFF)) >> 1;
                lo_val2 = ((s8)((rn_val >> 8) & 0xFF) - (s8)((rm_val >> 8) & 0xFF)) >> 1;

                hi_val1 = ((s8)((rn_val >> 16) & 0xFF) - (s8)((rm_val >> 16) & 0xFF)) >> 1;
                hi_val2 = ((s8)((rn_val >> 24) & 0xFF) - (s8)((rm_val >> 24) & 0xFF)) >> 1;
            }

            RD = (lo_val1 & 0xFF) | ((lo_val2 & 0xFF) << 8) | ((hi_val1 & 0xFF) << 16) |
                 ((hi_val2 & 0xFF) << 24);
        }
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(generic_arm_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

SMLA_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        smla_inst* inst_cream = (smla_inst*)inst_base->component;
        s32 operand1, operand2;
        if (inst_cream->x == 0)
            operand1 = (BIT(RM, 15)) ? (BITS(RM, 0, 15) | 0xffff0000) : BITS(RM, 0, 15);
        else
            operand1 = (BIT(RM, 31)) ? (BITS(RM, 16, 31) | 0xffff0000) : BITS(RM, 16, 31);

        if (inst_cream->y == 0)
            operand2 = (BIT(RS, 15)) ? (BITS(RS, 0, 15) | 0xffff0000) : BITS(RS, 0, 15);
        else
            operand2 = (BIT(RS, 31)) ? (BITS(RS, 16, 31) | 0xffff0000) : BITS(RS, 16, 31);

        u32 product = operand1 * operand2;
        u32 result = product + RN;
        if (AddOverflow(product, RN, result))
            cpu->Cpsr |= (1 << 27);
        RD = result;
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(smla_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

SMLAD_INST:
SMLSD_INST:
SMUAD_INST:
SMUSD_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        smlad_inst* const inst_cream = (smlad_inst*)inst_base->component;
        const u8 op2 = inst_cream->op2;

        u32 rm_val = cpu->Reg[inst_cream->Rm];
        const u32 rn_val = cpu->Reg[inst_cream->Rn];

        if (inst_cream->m)
            rm_val = (((rm_val & 0xFFFF) << 16) | (rm_val >> 16));

        const s16 rm_lo = (rm_val & 0xFFFF);
        const s16 rm_hi = ((rm_val >> 16) & 0xFFFF);
        const s16 rn_lo = (rn_val & 0xFFFF);
        const s16 rn_hi = ((rn_val >> 16) & 0xFFFF);

        const u32 product1 = (rn_lo * rm_lo);
        const u32 product2 = (rn_hi * rm_hi);

        // SMUAD and SMLAD
        if (BIT(op2, 1) == 0) {
            u32 rd_val = (product1 + product2);

            if (inst_cream->Ra != 15) {
                rd_val += cpu->Reg[inst_cream->Ra];

                if (ARMul_AddOverflowQ(product1 + product2, cpu->Reg[inst_cream->Ra]))
                    cpu->Cpsr |= (1 << 27);
            }

            RD = rd_val;

            if (ARMul_AddOverflowQ(product1, product2))
                cpu->Cpsr |= (1 << 27);
        }
        // SMUSD and SMLSD
        else {
            u32 rd_val = (product1 - product2);

            if (inst_cream->Ra != 15) {
                rd_val += cpu->Reg[inst_cream->Ra];

                if (ARMul_AddOverflowQ(product1 - product2, cpu->Reg[inst_cream->Ra]))
                    cpu->Cpsr |= (1 << 27);
            }

            RD = rd_val;
        }
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(smlad_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

SMLAL_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        umlal_inst* inst_cream = (umlal_inst*)inst_base->component;
        long long int rm = RM;
        long long int rs = RS;
        if (BIT(rm, 31)) {
            rm |= 0xffffffff00000000LL;
        }
        if (BIT(rs, 31)) {
            rs |= 0xffffffff00000000LL;
        }
        long long int rst = rm * rs;
        long long int rdhi32 = RDHI;
        long long int hilo = (rdhi32 << 32) + RDLO;
        rst += hilo;
        RDLO = BITS(rst, 0, 31);
        RDHI = BITS(rst, 32, 63);
        if (inst_cream->S) {
            cpu->NFlag = BIT(RDHI, 31);
            cpu->ZFlag = (RDHI == 0 && RDLO == 0);
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(umlal_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

SMLALXY_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        smlalxy_inst* const inst_cream = (smlalxy_inst*)inst_base->component;

        u64 operand1 = RN;
        u64 operand2 = RM;

        if (inst_cream->x != 0)
            operand1 >>= 16;
        if (inst_cream->y != 0)
            operand2 >>= 16;
        operand1 &= 0xFFFF;
        if (operand1 & 0x8000)
            operand1 -= 65536;
        operand2 &= 0xFFFF;
        if (operand2 & 0x8000)
            operand2 -= 65536;

        u64 dest = ((u64)RDHI << 32 | RDLO) + (operand1 * operand2);
        RDLO = (dest & 0xFFFFFFFF);
        RDHI = ((dest >> 32) & 0xFFFFFFFF);
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(smlalxy_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

SMLAW_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        smlad_inst* const inst_cream = (smlad_inst*)inst_base->component;

        const u32 rm_val = RM;
        const u32 rn_val = RN;
        const u32 ra_val = cpu->Reg[inst_cream->Ra];
        const bool high = (inst_cream->m == 1);

        const s16 operand2 = (high) ? ((rm_val >> 16) & 0xFFFF) : (rm_val & 0xFFFF);
        const s64 result = (s64)(s32)rn_val * (s64)(s32)operand2 + ((s64)(s32)ra_val << 16);

        RD = BITS(result, 16, 47);

        if ((result >> 16) != (s32)RD)
            cpu->Cpsr |= (1 << 27);
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(smlad_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

SMLALD_INST:
SMLSLD_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        smlald_inst* const inst_cream = (smlald_inst*)inst_base->component;

        const bool do_swap = (inst_cream->swap == 1);
        const u32 rdlo_val = RDLO;
        const u32 rdhi_val = RDHI;
        const u32 rn_val = RN;
        u32 rm_val = RM;

        if (do_swap)
            rm_val = (((rm_val & 0xFFFF) << 16) | (rm_val >> 16));

        const s32 product1 = (s16)(rn_val & 0xFFFF) * (s16)(rm_val & 0xFFFF);
        const s32 product2 = (s16)((rn_val >> 16) & 0xFFFF) * (s16)((rm_val >> 16) & 0xFFFF);
        s64 result;

        // SMLALD
        if (BIT(inst_cream->op2, 1) == 0) {
            result = (product1 + product2) + (s64)(rdlo_val | ((s64)rdhi_val << 32));
        }
        // SMLSLD
        else {
            result = (product1 - product2) + (s64)(rdlo_val | ((s64)rdhi_val << 32));
        }

        RDLO = (result & 0xFFFFFFFF);
        RDHI = ((result >> 32) & 0xFFFFFFFF);
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(smlald_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

SMMLA_INST:
SMMLS_INST:
SMMUL_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        smlad_inst* const inst_cream = (smlad_inst*)inst_base->component;

        const u32 rm_val = RM;
        const u32 rn_val = RN;
        const bool do_round = (inst_cream->m == 1);

        // Assume SMMUL by default.
        s64 result = (s64)(s32)rn_val * (s64)(s32)rm_val;

        if (inst_cream->Ra != 15) {
            const u32 ra_val = cpu->Reg[inst_cream->Ra];

            // SMMLA, otherwise SMMLS
            if (BIT(inst_cream->op2, 1) == 0)
                result += ((s64)ra_val << 32);
            else
                result = ((s64)ra_val << 32) - result;
        }

        if (do_round)
            result += 0x80000000;

        RD = ((result >> 32) & 0xFFFFFFFF);
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(smlad_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

SMUL_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        smul_inst* inst_cream = (smul_inst*)inst_base->component;
        u32 operand1, operand2;
        if (inst_cream->x == 0)
            operand1 = (BIT(RM, 15)) ? (BITS(RM, 0, 15) | 0xffff0000) : BITS(RM, 0, 15);
        else
            operand1 = (BIT(RM, 31)) ? (BITS(RM, 16, 31) | 0xffff0000) : BITS(RM, 16, 31);

        if (inst_cream->y == 0)
            operand2 = (BIT(RS, 15)) ? (BITS(RS, 0, 15) | 0xffff0000) : BITS(RS, 0, 15);
        else
            operand2 = (BIT(RS, 31)) ? (BITS(RS, 16, 31) | 0xffff0000) : BITS(RS, 16, 31);
        RD = operand1 * operand2;
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(smul_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
SMULL_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        umull_inst* inst_cream = (umull_inst*)inst_base->component;
        s64 rm = RM;
        s64 rs = RS;
        if (BIT(rm, 31)) {
            rm |= 0xffffffff00000000LL;
        }
        if (BIT(rs, 31)) {
            rs |= 0xffffffff00000000LL;
        }
        s64 rst = rm * rs;
        RDHI = BITS(rst, 32, 63);
        RDLO = BITS(rst, 0, 31);

        if (inst_cream->S) {
            cpu->NFlag = BIT(RDHI, 31);
            cpu->ZFlag = (RDHI == 0 && RDLO == 0);
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(umull_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

SMULW_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        smlad_inst* const inst_cream = (smlad_inst*)inst_base->component;

        s16 rm = (inst_cream->m == 1) ? ((RM >> 16) & 0xFFFF) : (RM & 0xFFFF);

        s64 result = (s64)rm * (s64)(s32)RN;
        RD = BITS(result, 16, 47);
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(smlad_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

SRS_INST : {
    // SRS is unconditional
    ldst_inst* const inst_cream = (ldst_inst*)inst_base->component;

    u32 address = 0;
    inst_cream->get_addr(cpu, inst_cream->inst, address);

    cpu->WriteMemory32(address + 0, cpu->Reg[14]);
    cpu->WriteMemory32(address + 4, cpu->Spsr_copy);

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(ldst_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

SSAT_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        ssat_inst* const inst_cream = (ssat_inst*)inst_base->component;

        u8 shift_type = inst_cream->shift_type;
        u8 shift_amount = inst_cream->imm5;
        u32 rn_val = RN;

        // 32-bit ASR is encoded as an amount of 0.
        if (shift_type == 1 && shift_amount == 0)
            shift_amount = 31;

        if (shift_type == 0)
            rn_val <<= shift_amount;
        else if (shift_type == 1)
            rn_val = ((s32)rn_val >> shift_amount);

        bool saturated = false;
        rn_val = ARMul_SignedSatQ(rn_val, inst_cream->sat_imm, &saturated);

        if (saturated)
            cpu->Cpsr |= (1 << 27);

        RD = rn_val;
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(ssat_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

SSAT16_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        ssat_inst* const inst_cream = (ssat_inst*)inst_base->component;
        const u8 saturate_to = inst_cream->sat_imm;

        bool sat1 = false;
        bool sat2 = false;

        RD = (ARMul_SignedSatQ((s16)RN, saturate_to, &sat1) & 0xFFFF) |
             ARMul_SignedSatQ((s32)RN >> 16, saturate_to, &sat2) << 16;

        if (sat1 || sat2)
            cpu->Cpsr |= (1 << 27);
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(ssat_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

STC_INST : {
    // Instruction not implemented
    // LOG_CRITICAL(Core_ARM11, "unimplemented instruction");
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(stc_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
STM_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
        unsigned int inst = inst_cream->inst;

        unsigned int Rn = BITS(inst, 16, 19);
        unsigned int old_RN = cpu->Reg[Rn];

        inst_cream->get_addr(cpu, inst_cream->inst, addr);
        if (BIT(inst_cream->inst, 22) == 1) {
            for (int i = 0; i < 13; i++) {
                if (BIT(inst_cream->inst, i)) {
                    cpu->WriteMemory32(addr, cpu->Reg[i]);
                    addr += 4;
                }
            }
            if (BIT(inst_cream->inst, 13)) {
                if (cpu->Mode == USER32MODE)
                    cpu->WriteMemory32(addr, cpu->Reg[13]);
                else
                    cpu->WriteMemory32(addr, cpu->Reg_usr[0]);

                addr += 4;
            }
            if (BIT(inst_cream->inst, 14)) {
                if (cpu->Mode == USER32MODE)
                    cpu->WriteMemory32(addr, cpu->Reg[14]);
                else
                    cpu->WriteMemory32(addr, cpu->Reg_usr[1]);

                addr += 4;
            }
            if (BIT(inst_cream->inst, 15)) {
                cpu->WriteMemory32(addr, cpu->Reg[15] + 8);
            }
        } else {
            for (int i = 0; i < 15; i++) {
                if (BIT(inst_cream->inst, i)) {
                    if (i == Rn)
                        cpu->WriteMemory32(addr, old_RN);
                    else
                        cpu->WriteMemory32(addr, cpu->Reg[i]);

                    addr += 4;
                }
            }

            // Check PC reg
            if (BIT(inst_cream->inst, 15)) {
                cpu->WriteMemory32(addr, cpu->Reg[15] + 8);
            }
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(ldst_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
SXTB_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        sxtb_inst* inst_cream = (sxtb_inst*)inst_base->component;

        unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate);
        if (BIT(operand2, 7)) {
            operand2 |= 0xffffff00;
        } else {
            operand2 &= 0xff;
        }
        RD = operand2;
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(sxtb_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
STR_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
        inst_cream->get_addr(cpu, inst_cream->inst, addr);

        unsigned int reg = BITS(inst_cream->inst, 12, 15);
        unsigned int value = cpu->Reg[reg];

        if (reg == 15)
            value += 2 * cpu->GetInstructionSize();

        cpu->WriteMemory32(addr, value);
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(ldst_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
UXTB_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        uxtb_inst* inst_cream = (uxtb_inst*)inst_base->component;
        RD = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xff;
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(uxtb_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
UXTAB_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        uxtab_inst* inst_cream = (uxtab_inst*)inst_base->component;

        unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xff;
        RD = RN + operand2;
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(uxtab_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
STRB_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
        inst_cream->get_addr(cpu, inst_cream->inst, addr);
        unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff;
        cpu->WriteMemory8(addr, value);
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(ldst_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
STRBT_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
        inst_cream->get_addr(cpu, inst_cream->inst, addr);

        const u32 previous_mode = cpu->Mode;
        const u32 value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff;

        cpu->ChangePrivilegeMode(USER32MODE);
        cpu->WriteMemory8(addr, value);
        cpu->ChangePrivilegeMode(previous_mode);
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(ldst_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
STRD_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
        inst_cream->get_addr(cpu, inst_cream->inst, addr);

        // The 3DS doesn't have the Large Physical Access Extension (LPAE)
        // so STRD wouldn't store these as a single write.
        cpu->WriteMemory32(addr + 0, cpu->Reg[BITS(inst_cream->inst, 12, 15)]);
        cpu->WriteMemory32(addr + 4, cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1]);
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(ldst_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
STREX_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
        unsigned int write_addr = cpu->Reg[inst_cream->Rn];

        if (cpu->IsExclusiveMemoryAccess(write_addr)) {
            cpu->UnsetExclusiveMemoryAddress();
            cpu->WriteMemory32(write_addr, RM);
            RD = 0;
        } else {
            // Failed to write due to mutex access
            RD = 1;
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(generic_arm_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
STREXB_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
        unsigned int write_addr = cpu->Reg[inst_cream->Rn];

        if (cpu->IsExclusiveMemoryAccess(write_addr)) {
            cpu->UnsetExclusiveMemoryAddress();
            cpu->WriteMemory8(write_addr, cpu->Reg[inst_cream->Rm]);
            RD = 0;
        } else {
            // Failed to write due to mutex access
            RD = 1;
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(generic_arm_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
STREXD_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
        unsigned int write_addr = cpu->Reg[inst_cream->Rn];

        if (cpu->IsExclusiveMemoryAccess(write_addr)) {
            cpu->UnsetExclusiveMemoryAddress();

            const u32 rt = cpu->Reg[inst_cream->Rm + 0];
            const u32 rt2 = cpu->Reg[inst_cream->Rm + 1];
            u64 value;

            if (cpu->InBigEndianMode())
                value = (((u64)rt << 32) | rt2);
            else
                value = (((u64)rt2 << 32) | rt);

            cpu->WriteMemory64(write_addr, value);
            RD = 0;
        } else {
            // Failed to write due to mutex access
            RD = 1;
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(generic_arm_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
STREXH_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
        unsigned int write_addr = cpu->Reg[inst_cream->Rn];

        if (cpu->IsExclusiveMemoryAccess(write_addr)) {
            cpu->UnsetExclusiveMemoryAddress();
            cpu->WriteMemory16(write_addr, RM);
            RD = 0;
        } else {
            // Failed to write due to mutex access
            RD = 1;
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(generic_arm_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
STRH_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
        inst_cream->get_addr(cpu, inst_cream->inst, addr);

        unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xffff;
        cpu->WriteMemory16(addr, value);
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(ldst_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
STRT_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
        inst_cream->get_addr(cpu, inst_cream->inst, addr);

        const u32 previous_mode = cpu->Mode;
        const u32 rt_index = BITS(inst_cream->inst, 12, 15);

        u32 value = cpu->Reg[rt_index];
        if (rt_index == 15)
            value += 2 * cpu->GetInstructionSize();

        cpu->ChangePrivilegeMode(USER32MODE);
        cpu->WriteMemory32(addr, value);
        cpu->ChangePrivilegeMode(previous_mode);
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(ldst_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
SUB_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        sub_inst* const inst_cream = (sub_inst*)inst_base->component;

        u32 rn_val = CHECK_READ_REG15_WA(cpu, inst_cream->Rn);

        bool carry;
        bool overflow;
        RD = AddWithCarry(rn_val, ~SHIFTER_OPERAND, 1, &carry, &overflow);

        if (inst_cream->S && (inst_cream->Rd == 15)) {
            if (CurrentModeHasSPSR) {
                cpu->Cpsr = cpu->Spsr_copy;
                cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
                LOAD_NZCVT;
            }
        } else if (inst_cream->S) {
            UPDATE_NFLAG(RD);
            UPDATE_ZFLAG(RD);
            cpu->CFlag = carry;
            cpu->VFlag = overflow;
        }
        if (inst_cream->Rd == 15) {
            INC_PC(sizeof(sub_inst));
            goto DISPATCH;
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(sub_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
SWI_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        swi_inst* const inst_cream = (swi_inst*)inst_base->component;
        SVC::CallSVC(inst_cream->num & 0xFFFF);
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(swi_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
SWP_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        swp_inst* inst_cream = (swp_inst*)inst_base->component;

        addr = RN;
        unsigned int value = cpu->ReadMemory32(addr);
        cpu->WriteMemory32(addr, RM);

        RD = value;
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(swp_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
SWPB_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        swp_inst* inst_cream = (swp_inst*)inst_base->component;
        addr = RN;
        unsigned int value = cpu->ReadMemory8(addr);
        cpu->WriteMemory8(addr, (RM & 0xFF));
        RD = value;
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(swp_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
SXTAB_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        sxtab_inst* inst_cream = (sxtab_inst*)inst_base->component;

        unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xff;

        // Sign extend for byte
        operand2 = (0x80 & operand2) ? (0xFFFFFF00 | operand2) : operand2;
        RD = RN + operand2;
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(uxtab_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

SXTAB16_INST:
SXTB16_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        sxtab_inst* const inst_cream = (sxtab_inst*)inst_base->component;

        const u8 rotation = inst_cream->rotate * 8;
        u32 rm_val = RM;
        u32 rn_val = RN;

        if (rotation)
            rm_val = ((rm_val << (32 - rotation)) | (rm_val >> rotation));

        // SXTB16
        if (inst_cream->Rn == 15) {
            u32 lo = (u32)(s8)rm_val;
            u32 hi = (u32)(s8)(rm_val >> 16);
            RD = (lo | (hi << 16));
        }
        // SXTAB16
        else {
            u32 lo = (rn_val & 0xFFFF) + (u32)(s8)(rm_val & 0xFF);
            u32 hi = ((rn_val >> 16) & 0xFFFF) + (u32)(s8)((rm_val >> 16) & 0xFF);
            RD = (lo | (hi << 16));
        }
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(sxtab_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

SXTAH_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        sxtah_inst* inst_cream = (sxtah_inst*)inst_base->component;

        unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xffff;
        // Sign extend for half
        operand2 = (0x8000 & operand2) ? (0xFFFF0000 | operand2) : operand2;
        RD = RN + operand2;
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(sxtah_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

TEQ_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        teq_inst* const inst_cream = (teq_inst*)inst_base->component;

        u32 lop = RN;
        u32 rop = SHIFTER_OPERAND;

        if (inst_cream->Rn == 15)
            lop += cpu->GetInstructionSize() * 2;

        u32 result = lop ^ rop;

        UPDATE_NFLAG(result);
        UPDATE_ZFLAG(result);
        UPDATE_CFLAG_WITH_SC;
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(teq_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
TST_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        tst_inst* const inst_cream = (tst_inst*)inst_base->component;

        u32 lop = RN;
        u32 rop = SHIFTER_OPERAND;

        if (inst_cream->Rn == 15)
            lop += cpu->GetInstructionSize() * 2;

        u32 result = lop & rop;

        UPDATE_NFLAG(result);
        UPDATE_ZFLAG(result);
        UPDATE_CFLAG_WITH_SC;
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(tst_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

UADD8_INST:
UADD16_INST:
UADDSUBX_INST:
USUB8_INST:
USUB16_INST:
USUBADDX_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;

        const u8 op2 = inst_cream->op2;
        const u32 rm_val = RM;
        const u32 rn_val = RN;

        s32 lo_result = 0;
        s32 hi_result = 0;

        // UADD16
        if (op2 == 0x00) {
            lo_result = (rn_val & 0xFFFF) + (rm_val & 0xFFFF);
            hi_result = ((rn_val >> 16) & 0xFFFF) + ((rm_val >> 16) & 0xFFFF);

            if (lo_result & 0xFFFF0000) {
                cpu->Cpsr |= (1 << 16);
                cpu->Cpsr |= (1 << 17);
            } else {
                cpu->Cpsr &= ~(1 << 16);
                cpu->Cpsr &= ~(1 << 17);
            }

            if (hi_result & 0xFFFF0000) {
                cpu->Cpsr |= (1 << 18);
                cpu->Cpsr |= (1 << 19);
            } else {
                cpu->Cpsr &= ~(1 << 18);
                cpu->Cpsr &= ~(1 << 19);
            }
        }
        // UASX
        else if (op2 == 0x01) {
            lo_result = (rn_val & 0xFFFF) - ((rm_val >> 16) & 0xFFFF);
            hi_result = ((rn_val >> 16) & 0xFFFF) + (rm_val & 0xFFFF);

            if (lo_result >= 0) {
                cpu->Cpsr |= (1 << 16);
                cpu->Cpsr |= (1 << 17);
            } else {
                cpu->Cpsr &= ~(1 << 16);
                cpu->Cpsr &= ~(1 << 17);
            }

            if (hi_result >= 0x10000) {
                cpu->Cpsr |= (1 << 18);
                cpu->Cpsr |= (1 << 19);
            } else {
                cpu->Cpsr &= ~(1 << 18);
                cpu->Cpsr &= ~(1 << 19);
            }
        }
        // USAX
        else if (op2 == 0x02) {
            lo_result = (rn_val & 0xFFFF) + ((rm_val >> 16) & 0xFFFF);
            hi_result = ((rn_val >> 16) & 0xFFFF) - (rm_val & 0xFFFF);

            if (lo_result >= 0x10000) {
                cpu->Cpsr |= (1 << 16);
                cpu->Cpsr |= (1 << 17);
            } else {
                cpu->Cpsr &= ~(1 << 16);
                cpu->Cpsr &= ~(1 << 17);
            }

            if (hi_result >= 0) {
                cpu->Cpsr |= (1 << 18);
                cpu->Cpsr |= (1 << 19);
            } else {
                cpu->Cpsr &= ~(1 << 18);
                cpu->Cpsr &= ~(1 << 19);
            }
        }
        // USUB16
        else if (op2 == 0x03) {
            lo_result = (rn_val & 0xFFFF) - (rm_val & 0xFFFF);
            hi_result = ((rn_val >> 16) & 0xFFFF) - ((rm_val >> 16) & 0xFFFF);

            if ((lo_result & 0xFFFF0000) == 0) {
                cpu->Cpsr |= (1 << 16);
                cpu->Cpsr |= (1 << 17);
            } else {
                cpu->Cpsr &= ~(1 << 16);
                cpu->Cpsr &= ~(1 << 17);
            }

            if ((hi_result & 0xFFFF0000) == 0) {
                cpu->Cpsr |= (1 << 18);
                cpu->Cpsr |= (1 << 19);
            } else {
                cpu->Cpsr &= ~(1 << 18);
                cpu->Cpsr &= ~(1 << 19);
            }
        }
        // UADD8
        else if (op2 == 0x04) {
            s16 sum1 = (rn_val & 0xFF) + (rm_val & 0xFF);
            s16 sum2 = ((rn_val >> 8) & 0xFF) + ((rm_val >> 8) & 0xFF);
            s16 sum3 = ((rn_val >> 16) & 0xFF) + ((rm_val >> 16) & 0xFF);
            s16 sum4 = ((rn_val >> 24) & 0xFF) + ((rm_val >> 24) & 0xFF);

            if (sum1 >= 0x100)
                cpu->Cpsr |= (1 << 16);
            else
                cpu->Cpsr &= ~(1 << 16);

            if (sum2 >= 0x100)
                cpu->Cpsr |= (1 << 17);
            else
                cpu->Cpsr &= ~(1 << 17);

            if (sum3 >= 0x100)
                cpu->Cpsr |= (1 << 18);
            else
                cpu->Cpsr &= ~(1 << 18);

            if (sum4 >= 0x100)
                cpu->Cpsr |= (1 << 19);
            else
                cpu->Cpsr &= ~(1 << 19);

            lo_result = ((sum1 & 0xFF) | (sum2 & 0xFF) << 8);
            hi_result = ((sum3 & 0xFF) | (sum4 & 0xFF) << 8);
        }
        // USUB8
        else if (op2 == 0x07) {
            s16 diff1 = (rn_val & 0xFF) - (rm_val & 0xFF);
            s16 diff2 = ((rn_val >> 8) & 0xFF) - ((rm_val >> 8) & 0xFF);
            s16 diff3 = ((rn_val >> 16) & 0xFF) - ((rm_val >> 16) & 0xFF);
            s16 diff4 = ((rn_val >> 24) & 0xFF) - ((rm_val >> 24) & 0xFF);

            if (diff1 >= 0)
                cpu->Cpsr |= (1 << 16);
            else
                cpu->Cpsr &= ~(1 << 16);

            if (diff2 >= 0)
                cpu->Cpsr |= (1 << 17);
            else
                cpu->Cpsr &= ~(1 << 17);

            if (diff3 >= 0)
                cpu->Cpsr |= (1 << 18);
            else
                cpu->Cpsr &= ~(1 << 18);

            if (diff4 >= 0)
                cpu->Cpsr |= (1 << 19);
            else
                cpu->Cpsr &= ~(1 << 19);

            lo_result = (diff1 & 0xFF) | ((diff2 & 0xFF) << 8);
            hi_result = (diff3 & 0xFF) | ((diff4 & 0xFF) << 8);
        }

        RD = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16);
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(generic_arm_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

UHADD8_INST:
UHADD16_INST:
UHADDSUBX_INST:
UHSUBADDX_INST:
UHSUB8_INST:
UHSUB16_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
        const u32 rm_val = RM;
        const u32 rn_val = RN;
        const u8 op2 = inst_cream->op2;

        if (op2 == 0x00 || op2 == 0x01 || op2 == 0x02 || op2 == 0x03) {
            u32 lo_val = 0;
            u32 hi_val = 0;

            // UHADD16
            if (op2 == 0x00) {
                lo_val = (rn_val & 0xFFFF) + (rm_val & 0xFFFF);
                hi_val = ((rn_val >> 16) & 0xFFFF) + ((rm_val >> 16) & 0xFFFF);
            }
            // UHASX
            else if (op2 == 0x01) {
                lo_val = (rn_val & 0xFFFF) - ((rm_val >> 16) & 0xFFFF);
                hi_val = ((rn_val >> 16) & 0xFFFF) + (rm_val & 0xFFFF);
            }
            // UHSAX
            else if (op2 == 0x02) {
                lo_val = (rn_val & 0xFFFF) + ((rm_val >> 16) & 0xFFFF);
                hi_val = ((rn_val >> 16) & 0xFFFF) - (rm_val & 0xFFFF);
            }
            // UHSUB16
            else if (op2 == 0x03) {
                lo_val = (rn_val & 0xFFFF) - (rm_val & 0xFFFF);
                hi_val = ((rn_val >> 16) & 0xFFFF) - ((rm_val >> 16) & 0xFFFF);
            }

            lo_val >>= 1;
            hi_val >>= 1;

            RD = (lo_val & 0xFFFF) | ((hi_val & 0xFFFF) << 16);
        } else if (op2 == 0x04 || op2 == 0x07) {
            u32 sum1;
            u32 sum2;
            u32 sum3;
            u32 sum4;

            // UHADD8
            if (op2 == 0x04) {
                sum1 = (rn_val & 0xFF) + (rm_val & 0xFF);
                sum2 = ((rn_val >> 8) & 0xFF) + ((rm_val >> 8) & 0xFF);
                sum3 = ((rn_val >> 16) & 0xFF) + ((rm_val >> 16) & 0xFF);
                sum4 = ((rn_val >> 24) & 0xFF) + ((rm_val >> 24) & 0xFF);
            }
            // UHSUB8
            else {
                sum1 = (rn_val & 0xFF) - (rm_val & 0xFF);
                sum2 = ((rn_val >> 8) & 0xFF) - ((rm_val >> 8) & 0xFF);
                sum3 = ((rn_val >> 16) & 0xFF) - ((rm_val >> 16) & 0xFF);
                sum4 = ((rn_val >> 24) & 0xFF) - ((rm_val >> 24) & 0xFF);
            }

            sum1 >>= 1;
            sum2 >>= 1;
            sum3 >>= 1;
            sum4 >>= 1;

            RD = (sum1 & 0xFF) | ((sum2 & 0xFF) << 8) | ((sum3 & 0xFF) << 16) |
                 ((sum4 & 0xFF) << 24);
        }
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(generic_arm_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

UMAAL_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        umaal_inst* const inst_cream = (umaal_inst*)inst_base->component;
        const u64 rm = RM;
        const u64 rn = RN;
        const u64 rd_lo = RDLO;
        const u64 rd_hi = RDHI;
        const u64 result = (rm * rn) + rd_lo + rd_hi;

        RDLO = (result & 0xFFFFFFFF);
        RDHI = ((result >> 32) & 0xFFFFFFFF);
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(umaal_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
UMLAL_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        umlal_inst* inst_cream = (umlal_inst*)inst_base->component;
        unsigned long long int rm = RM;
        unsigned long long int rs = RS;
        unsigned long long int rst = rm * rs;
        unsigned long long int add = ((unsigned long long)RDHI) << 32;
        add += RDLO;
        rst += add;
        RDLO = BITS(rst, 0, 31);
        RDHI = BITS(rst, 32, 63);

        if (inst_cream->S) {
            cpu->NFlag = BIT(RDHI, 31);
            cpu->ZFlag = (RDHI == 0 && RDLO == 0);
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(umlal_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
UMULL_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        umull_inst* inst_cream = (umull_inst*)inst_base->component;
        unsigned long long int rm = RM;
        unsigned long long int rs = RS;
        unsigned long long int rst = rm * rs;
        RDHI = BITS(rst, 32, 63);
        RDLO = BITS(rst, 0, 31);

        if (inst_cream->S) {
            cpu->NFlag = BIT(RDHI, 31);
            cpu->ZFlag = (RDHI == 0 && RDLO == 0);
        }
    }
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(umull_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}
B_2_THUMB : {
    b_2_thumb* inst_cream = (b_2_thumb*)inst_base->component;
    cpu->Reg[15] = cpu->Reg[15] + 4 + inst_cream->imm;
    INC_PC(sizeof(b_2_thumb));
    goto DISPATCH;
}
B_COND_THUMB : {
    b_cond_thumb* inst_cream = (b_cond_thumb*)inst_base->component;

    if (CondPassed(cpu, inst_cream->cond))
        cpu->Reg[15] = cpu->Reg[15] + 4 + inst_cream->imm;
    else
        cpu->Reg[15] += 2;

    INC_PC(sizeof(b_cond_thumb));
    goto DISPATCH;
}
BL_1_THUMB : {
    bl_1_thumb* inst_cream = (bl_1_thumb*)inst_base->component;
    cpu->Reg[14] = cpu->Reg[15] + 4 + inst_cream->imm;
    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(bl_1_thumb));
    FETCH_INST;
    GOTO_NEXT_INST;
}
BL_2_THUMB : {
    bl_2_thumb* inst_cream = (bl_2_thumb*)inst_base->component;
    int tmp = ((cpu->Reg[15] + 2) | 1);
    cpu->Reg[15] = (cpu->Reg[14] + inst_cream->imm);
    cpu->Reg[14] = tmp;
    INC_PC(sizeof(bl_2_thumb));
    goto DISPATCH;
}
BLX_1_THUMB : {
    // BLX 1 for armv5t and above
    u32 tmp = cpu->Reg[15];
    blx_1_thumb* inst_cream = (blx_1_thumb*)inst_base->component;
    cpu->Reg[15] = (cpu->Reg[14] + inst_cream->imm) & 0xFFFFFFFC;
    cpu->Reg[14] = ((tmp + 2) | 1);
    cpu->TFlag = 0;
    INC_PC(sizeof(blx_1_thumb));
    goto DISPATCH;
}

UQADD8_INST:
UQADD16_INST:
UQADDSUBX_INST:
UQSUB8_INST:
UQSUB16_INST:
UQSUBADDX_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;

        const u8 op2 = inst_cream->op2;
        const u32 rm_val = RM;
        const u32 rn_val = RN;

        u16 lo_val = 0;
        u16 hi_val = 0;

        // UQADD16
        if (op2 == 0x00) {
            lo_val = ARMul_UnsignedSaturatedAdd16(rn_val & 0xFFFF, rm_val & 0xFFFF);
            hi_val = ARMul_UnsignedSaturatedAdd16((rn_val >> 16) & 0xFFFF, (rm_val >> 16) & 0xFFFF);
        }
        // UQASX
        else if (op2 == 0x01) {
            lo_val = ARMul_UnsignedSaturatedSub16(rn_val & 0xFFFF, (rm_val >> 16) & 0xFFFF);
            hi_val = ARMul_UnsignedSaturatedAdd16((rn_val >> 16) & 0xFFFF, rm_val & 0xFFFF);
        }
        // UQSAX
        else if (op2 == 0x02) {
            lo_val = ARMul_UnsignedSaturatedAdd16(rn_val & 0xFFFF, (rm_val >> 16) & 0xFFFF);
            hi_val = ARMul_UnsignedSaturatedSub16((rn_val >> 16) & 0xFFFF, rm_val & 0xFFFF);
        }
        // UQSUB16
        else if (op2 == 0x03) {
            lo_val = ARMul_UnsignedSaturatedSub16(rn_val & 0xFFFF, rm_val & 0xFFFF);
            hi_val = ARMul_UnsignedSaturatedSub16((rn_val >> 16) & 0xFFFF, (rm_val >> 16) & 0xFFFF);
        }
        // UQADD8
        else if (op2 == 0x04) {
            lo_val = ARMul_UnsignedSaturatedAdd8(rn_val, rm_val) |
                     ARMul_UnsignedSaturatedAdd8(rn_val >> 8, rm_val >> 8) << 8;
            hi_val = ARMul_UnsignedSaturatedAdd8(rn_val >> 16, rm_val >> 16) |
                     ARMul_UnsignedSaturatedAdd8(rn_val >> 24, rm_val >> 24) << 8;
        }
        // UQSUB8
        else {
            lo_val = ARMul_UnsignedSaturatedSub8(rn_val, rm_val) |
                     ARMul_UnsignedSaturatedSub8(rn_val >> 8, rm_val >> 8) << 8;
            hi_val = ARMul_UnsignedSaturatedSub8(rn_val >> 16, rm_val >> 16) |
                     ARMul_UnsignedSaturatedSub8(rn_val >> 24, rm_val >> 24) << 8;
        }

        RD = ((lo_val & 0xFFFF) | hi_val << 16);
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(generic_arm_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

USAD8_INST:
USADA8_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;

        const u8 ra_idx = inst_cream->Ra;
        const u32 rm_val = RM;
        const u32 rn_val = RN;

        const u8 diff1 = ARMul_UnsignedAbsoluteDifference(rn_val & 0xFF, rm_val & 0xFF);
        const u8 diff2 =
            ARMul_UnsignedAbsoluteDifference((rn_val >> 8) & 0xFF, (rm_val >> 8) & 0xFF);
        const u8 diff3 =
            ARMul_UnsignedAbsoluteDifference((rn_val >> 16) & 0xFF, (rm_val >> 16) & 0xFF);
        const u8 diff4 =
            ARMul_UnsignedAbsoluteDifference((rn_val >> 24) & 0xFF, (rm_val >> 24) & 0xFF);

        u32 finalDif = (diff1 + diff2 + diff3 + diff4);

        // Op is USADA8 if true.
        if (ra_idx != 15)
            finalDif += cpu->Reg[ra_idx];

        RD = finalDif;
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(generic_arm_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

USAT_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        ssat_inst* const inst_cream = (ssat_inst*)inst_base->component;

        u8 shift_type = inst_cream->shift_type;
        u8 shift_amount = inst_cream->imm5;
        u32 rn_val = RN;

        // 32-bit ASR is encoded as an amount of 0.
        if (shift_type == 1 && shift_amount == 0)
            shift_amount = 31;

        if (shift_type == 0)
            rn_val <<= shift_amount;
        else if (shift_type == 1)
            rn_val = ((s32)rn_val >> shift_amount);

        bool saturated = false;
        rn_val = ARMul_UnsignedSatQ(rn_val, inst_cream->sat_imm, &saturated);

        if (saturated)
            cpu->Cpsr |= (1 << 27);

        RD = rn_val;
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(ssat_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

USAT16_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        ssat_inst* const inst_cream = (ssat_inst*)inst_base->component;
        const u8 saturate_to = inst_cream->sat_imm;

        bool sat1 = false;
        bool sat2 = false;

        RD = (ARMul_UnsignedSatQ((s16)RN, saturate_to, &sat1) & 0xFFFF) |
             ARMul_UnsignedSatQ((s32)RN >> 16, saturate_to, &sat2) << 16;

        if (sat1 || sat2)
            cpu->Cpsr |= (1 << 27);
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(ssat_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

UXTAB16_INST:
UXTB16_INST : {
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        uxtab_inst* const inst_cream = (uxtab_inst*)inst_base->component;

        const u8 rn_idx = inst_cream->Rn;
        const u32 rm_val = RM;
        const u32 rotation = inst_cream->rotate * 8;
        const u32 rotated_rm = ((rm_val << (32 - rotation)) | (rm_val >> rotation));

        // UXTB16, otherwise UXTAB16
        if (rn_idx == 15) {
            RD = rotated_rm & 0x00FF00FF;
        } else {
            const u32 rn_val = RN;
            const u8 lo_rotated = (rotated_rm & 0xFF);
            const u16 lo_result = (rn_val & 0xFFFF) + (u16)lo_rotated;
            const u8 hi_rotated = (rotated_rm >> 16) & 0xFF;
            const u16 hi_result = (rn_val >> 16) + (u16)hi_rotated;

            RD = ((hi_result << 16) | (lo_result & 0xFFFF));
        }
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC(sizeof(uxtab_inst));
    FETCH_INST;
    GOTO_NEXT_INST;
}

WFE_INST : {
    // Stubbed, as WFE is a hint instruction.
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        LOG_TRACE(Core_ARM11, "WFE executed.");
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC_STUB;
    FETCH_INST;
    GOTO_NEXT_INST;
}

WFI_INST : {
    // Stubbed, as WFI is a hint instruction.
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        LOG_TRACE(Core_ARM11, "WFI executed.");
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC_STUB;
    FETCH_INST;
    GOTO_NEXT_INST;
}

YIELD_INST : {
    // Stubbed, as YIELD is a hint instruction.
    if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
        LOG_TRACE(Core_ARM11, "YIELD executed.");
    }

    cpu->Reg[15] += cpu->GetInstructionSize();
    INC_PC_STUB;
    FETCH_INST;
    GOTO_NEXT_INST;
}

#define VFP_INTERPRETER_IMPL
#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
#undef VFP_INTERPRETER_IMPL

END : {
    SAVE_NZCVT;
    cpu->NumInstrsToExecute = 0;
    return num_instrs;
}
INIT_INST_LENGTH : {
    cpu->NumInstrsToExecute = 0;
    return num_instrs;
}
}