revision 361:be3de4ecd954
summary |
tree |
shortlog |
changelog |
graph |
changeset |
raw | bz2 | zip | gz changeset | 361:be3de4ecd954 |
parent | 360:dff4a3bbac0c |
child | 362:dc40e2064dc4 |
author | nkeynes |
date | Tue Aug 28 08:46:14 2007 +0000 (16 years ago) |
Translator WIP: fill out and correct another batch of instructions
src/sh4/sh4x86.c | view | annotate | diff | log | ||
src/sh4/sh4x86.in | view | annotate | diff | log | ||
src/sh4/x86op.h | view | annotate | diff | log |
1.1 --- a/src/sh4/sh4x86.c Thu Aug 23 12:34:43 2007 +00001.2 +++ b/src/sh4/sh4x86.c Tue Aug 28 08:46:14 2007 +00001.3 @@ -1,5 +1,5 @@1.4 /**1.5 - * $Id: sh4x86.c,v 1.1 2007-08-23 12:33:27 nkeynes Exp $1.6 + * $Id: sh4x86.c,v 1.2 2007-08-28 08:46:14 nkeynes Exp $1.7 *1.8 * SH4 => x86 translation. This version does no real optimization, it just1.9 * outputs straight-line x86 code - it mainly exists to provide a baseline1.10 @@ -28,27 +28,19 @@1.11 static inline void load_reg( int x86reg, int sh4reg )1.12 {1.13 /* mov [bp+n], reg */1.14 - OP(0x89);1.15 - OP(0x45 + x86reg<<3);1.16 + OP(0x8B);1.17 + OP(0x45 + (x86reg<<3));1.18 OP(REG_OFFSET(r[sh4reg]));1.19 }1.21 static inline void load_spreg( int x86reg, int regoffset )1.22 {1.23 /* mov [bp+n], reg */1.24 - OP(0x89);1.25 - OP(0x45 + x86reg<<3);1.26 + OP(0x8B);1.27 + OP(0x45 + (x86reg<<3));1.28 OP(regoffset);1.29 }1.31 -#define UNDEF()1.32 -#define MEM_READ_BYTE( addr_reg, value_reg )1.33 -#define MEM_READ_WORD( addr_reg, value_reg )1.34 -#define MEM_READ_LONG( addr_reg, value_reg )1.35 -#define MEM_WRITE_BYTE( addr_reg, value_reg )1.36 -#define MEM_WRITE_WORD( addr_reg, value_reg )1.37 -#define MEM_WRITE_LONG( addr_reg, value_reg )1.38 -1.39 /**1.40 * Emit an instruction to load an immediate value into a register1.41 */1.42 @@ -63,17 +55,52 @@1.43 */1.44 void static inline store_reg( int x86reg, int sh4reg ) {1.45 /* mov reg, [bp+n] */1.46 - OP(0x8B);1.47 - OP(0x45 + x86reg<<3);1.48 + OP(0x89);1.49 + OP(0x45 + (x86reg<<3));1.50 OP(REG_OFFSET(r[sh4reg]));1.51 }1.52 void static inline store_spreg( int x86reg, int regoffset ) {1.53 /* mov reg, [bp+n] */1.54 - OP(0x8B);1.55 - OP(0x45 + x86reg<<3);1.56 + OP(0x89);1.57 + OP(0x45 + (x86reg<<3));1.58 OP(regoffset);1.59 }1.61 +/**1.62 + * Note: clobbers EAX to make the indirect call - this isn't usually1.63 + * a problem since the callee will usually clobber it anyway.1.64 + */1.65 +static inline void call_func0( void *ptr )1.66 +{1.67 + load_imm32(R_EAX, (uint32_t)ptr);1.68 + OP(0xFF);1.69 + MODRM_rm32_r32(R_EAX, 2);1.70 +}1.71 +1.72 +static inline void call_func1( void *ptr, int arg1 )1.73 +{1.74 + PUSH_r32(arg1);1.75 + call_func0(ptr);1.76 + ADD_imm8s_r32( -4, R_ESP );1.77 +}1.78 +1.79 +static inline void call_func2( void *ptr, int arg1, int arg2 )1.80 +{1.81 + PUSH_r32(arg2);1.82 + PUSH_r32(arg1);1.83 + call_func0(ptr);1.84 + ADD_imm8s_r32( -4, R_ESP );1.85 +}1.86 +1.87 +#define UNDEF()1.88 +#define MEM_RESULT(value_reg) if(value_reg != R_EAX) { MOV_r32_r32(R_EAX,value_reg); }1.89 +#define MEM_READ_BYTE( addr_reg, value_reg ) call_func1(sh4_read_byte, addr_reg ); MEM_RESULT(value_reg)1.90 +#define MEM_READ_WORD( addr_reg, value_reg ) call_func1(sh4_read_word, addr_reg ); MEM_RESULT(value_reg)1.91 +#define MEM_READ_LONG( addr_reg, value_reg ) call_func1(sh4_read_long, addr_reg ); MEM_RESULT(value_reg)1.92 +#define MEM_WRITE_BYTE( addr_reg, value_reg ) call_func2(sh4_write_byte, addr_reg, value_reg)1.93 +#define MEM_WRITE_WORD( addr_reg, value_reg ) call_func2(sh4_write_word, addr_reg, value_reg)1.94 +#define MEM_WRITE_LONG( addr_reg, value_reg ) call_func2(sh4_write_long, addr_reg, value_reg)1.95 +1.97 /**1.98 * Emit the 'start of block' assembly. Sets up the stack frame and save1.99 @@ -110,7 +137,7 @@1.100 */1.101 uint32_t sh4_x86_translate_instruction( uint32_t pc )1.102 {1.103 - uint16_t ir = 0;1.104 + uint16_t ir = sh4_read_word( pc );1.106 switch( (ir&0xF000) >> 12 ) {1.107 case 0x0:1.108 @@ -201,6 +228,9 @@1.109 case 0xC:1.110 { /* MOVCA.L R0, @Rn */1.111 uint32_t Rn = ((ir>>8)&0xF);1.112 + load_reg( R_EAX, 0 );1.113 + load_reg( R_ECX, Rn );1.114 + MEM_WRITE_LONG( R_ECX, R_EAX );1.115 }1.116 break;1.117 default:1.118 @@ -221,16 +251,30 @@1.119 case 0x5:1.120 { /* MOV.W Rm, @(R0, Rn) */1.121 uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF);1.122 + load_reg( R_EAX, 0 );1.123 + load_reg( R_ECX, Rn );1.124 + ADD_r32_r32( R_EAX, R_ECX );1.125 + load_reg( R_EAX, Rm );1.126 + MEM_WRITE_WORD( R_ECX, R_EAX );1.127 }1.128 break;1.129 case 0x6:1.130 { /* MOV.L Rm, @(R0, Rn) */1.131 uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF);1.132 + load_reg( R_EAX, 0 );1.133 + load_reg( R_ECX, Rn );1.134 + ADD_r32_r32( R_EAX, R_ECX );1.135 + load_reg( R_EAX, Rm );1.136 + MEM_WRITE_LONG( R_ECX, R_EAX );1.137 }1.138 break;1.139 case 0x7:1.140 { /* MUL.L Rm, Rn */1.141 uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF);1.142 + load_reg( R_EAX, Rm );1.143 + load_reg( R_ECX, Rn );1.144 + MUL_r32( R_ECX );1.145 + store_spreg( R_EAX, R_MACL );1.146 }1.147 break;1.148 case 0x8:1.149 @@ -273,6 +317,10 @@1.150 break;1.151 case 0x1:1.152 { /* DIV0U */1.153 + XOR_r32_r32( R_EAX, R_EAX );1.154 + store_spreg( R_EAX, R_Q );1.155 + store_spreg( R_EAX, R_M );1.156 + store_spreg( R_EAX, R_T );1.157 }1.158 break;1.159 case 0x2:1.160 @@ -375,11 +423,21 @@1.161 case 0xD:1.162 { /* MOV.W @(R0, Rm), Rn */1.163 uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF);1.164 + load_reg( R_EAX, 0 );1.165 + load_reg( R_ECX, Rm );1.166 + ADD_r32_r32( R_EAX, R_ECX );1.167 + MEM_READ_WORD( R_ECX, R_EAX );1.168 + store_reg( R_EAX, Rn );1.169 }1.170 break;1.171 case 0xE:1.172 { /* MOV.L @(R0, Rm), Rn */1.173 uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF);1.174 + load_reg( R_EAX, 0 );1.175 + load_reg( R_ECX, Rm );1.176 + ADD_r32_r32( R_EAX, R_ECX );1.177 + MEM_READ_LONG( R_ECX, R_EAX );1.178 + store_reg( R_EAX, Rn );1.179 }1.180 break;1.181 case 0xF:1.182 @@ -395,6 +453,10 @@1.183 case 0x1:1.184 { /* MOV.L Rm, @(disp, Rn) */1.185 uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); uint32_t disp = (ir&0xF)<<2;1.186 + load_reg( R_ECX, Rn );1.187 + load_reg( R_EAX, Rm );1.188 + ADD_imm32_r32( disp, R_ECX );1.189 + MEM_WRITE_LONG( R_ECX, R_EAX );1.190 }1.191 break;1.192 case 0x2:1.193 @@ -410,11 +472,17 @@1.194 case 0x1:1.195 { /* MOV.W Rm, @Rn */1.196 uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF);1.197 + load_reg( R_ECX, Rn );1.198 + MEM_READ_WORD( R_ECX, R_EAX );1.199 + store_reg( R_EAX, Rn );1.200 }1.201 break;1.202 case 0x2:1.203 { /* MOV.L Rm, @Rn */1.204 uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF);1.205 + load_reg( R_EAX, Rm );1.206 + load_reg( R_ECX, Rn );1.207 + MEM_WRITE_LONG( R_ECX, R_EAX );1.208 }1.209 break;1.210 case 0x4:1.211 @@ -430,21 +498,42 @@1.212 case 0x5:1.213 { /* MOV.W Rm, @-Rn */1.214 uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF);1.215 + load_reg( R_ECX, Rn );1.216 + load_reg( R_EAX, Rm );1.217 + ADD_imm8s_r32( -2, R_ECX );1.218 + MEM_WRITE_WORD( R_ECX, R_EAX );1.219 }1.220 break;1.221 case 0x6:1.222 { /* MOV.L Rm, @-Rn */1.223 uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF);1.224 + load_reg( R_EAX, Rm );1.225 + load_reg( R_ECX, Rn );1.226 + ADD_imm8s_r32( -4, R_ECX );1.227 + store_reg( R_ECX, Rn );1.228 + MEM_WRITE_LONG( R_ECX, R_EAX );1.229 }1.230 break;1.231 case 0x7:1.232 { /* DIV0S Rm, Rn */1.233 uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF);1.234 + load_reg( R_EAX, Rm );1.235 + load_reg( R_ECX, Rm );1.236 + SHR_imm8_r32( 31, R_EAX );1.237 + SHR_imm8_r32( 31, R_ECX );1.238 + store_spreg( R_EAX, R_M );1.239 + store_spreg( R_ECX, R_Q );1.240 + CMP_r32_r32( R_EAX, R_ECX );1.241 + SETE_t();1.242 }1.243 break;1.244 case 0x8:1.245 { /* TST Rm, Rn */1.246 uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF);1.247 + load_reg( R_EAX, Rm );1.248 + load_reg( R_ECX, Rn );1.249 + TEST_r32_r32( R_EAX, R_ECX );1.250 + SETE_t();1.251 }1.252 break;1.253 case 0x9:1.254 @@ -482,6 +571,12 @@1.255 case 0xD:1.256 { /* XTRCT Rm, Rn */1.257 uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF);1.258 + load_reg( R_EAX, Rm );1.259 + MOV_r32_r32( R_EAX, R_ECX );1.260 + SHR_imm8_r32( 16, R_EAX );1.261 + SHL_imm8_r32( 16, R_ECX );1.262 + OR_r32_r32( R_EAX, R_ECX );1.263 + store_reg( R_ECX, Rn );1.264 }1.265 break;1.266 case 0xE:1.267 @@ -536,6 +631,11 @@1.268 case 0x5:1.269 { /* DMULU.L Rm, Rn */1.270 uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF);1.271 + load_reg( R_EAX, Rm );1.272 + load_reg( R_ECX, Rn );1.273 + MUL_r32(R_ECX);1.274 + store_spreg( R_EDX, R_MACH );1.275 + store_spreg( R_EAX, R_MACL );1.276 }1.277 break;1.278 case 0x6:1.279 @@ -597,6 +697,11 @@1.280 case 0xD:1.281 { /* DMULS.L Rm, Rn */1.282 uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF);1.283 + load_reg( R_EAX, Rm );1.284 + load_reg( R_ECX, Rn );1.285 + IMUL_r32(R_ECX);1.286 + store_spreg( R_EDX, R_MACH );1.287 + store_spreg( R_EAX, R_MACL );1.288 }1.289 break;1.290 case 0xE:1.291 @@ -1166,6 +1271,12 @@1.292 case 0x1:1.293 { /* TAS.B @Rn */1.294 uint32_t Rn = ((ir>>8)&0xF);1.295 + load_reg( R_ECX, Rn );1.296 + MEM_READ_BYTE( R_ECX, R_EAX );1.297 + TEST_r8_r8( R_AL, R_AL );1.298 + SETE_t();1.299 + OR_imm8_r8( 0x80, R_AL );1.300 + MEM_WRITE_BYTE( R_ECX, R_EAX );1.301 }1.302 break;1.303 case 0x2:1.304 @@ -1182,6 +1293,20 @@1.305 { /* SHAD Rm, Rn */1.306 uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF);1.307 /* Annoyingly enough, not directly convertible */1.308 + load_reg( R_EAX, Rn );1.309 + load_reg( R_ECX, Rm );1.310 + CMP_imm32_r32( 0, R_ECX );1.311 + JAE_rel8(9);1.312 +1.313 + NEG_r32( R_ECX ); // 21.314 + AND_imm8_r8( 0x1F, R_CL ); // 31.315 + SAR_r32_CL( R_EAX ); // 21.316 + JMP_rel8(5); // 21.317 +1.318 + AND_imm8_r8( 0x1F, R_CL ); // 31.319 + SHL_r32_CL( R_EAX ); // 21.320 +1.321 + store_reg( R_EAX, Rn );1.322 }1.323 break;1.324 case 0xD:1.325 @@ -1249,6 +1374,10 @@1.326 case 0x5:1.327 { /* MOV.L @(disp, Rm), Rn */1.328 uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); uint32_t disp = (ir&0xF)<<2;1.329 + load_reg( R_ECX, Rm );1.330 + ADD_imm8s_r32( disp, R_ECX );1.331 + MEM_READ_LONG( R_ECX, R_EAX );1.332 + store_reg( R_EAX, Rn );1.333 }1.334 break;1.335 case 0x6:1.336 @@ -1264,11 +1393,17 @@1.337 case 0x1:1.338 { /* MOV.W @Rm, Rn */1.339 uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF);1.340 + load_reg( R_ECX, Rm );1.341 + MEM_READ_WORD( R_ECX, R_EAX );1.342 + store_reg( R_EAX, Rn );1.343 }1.344 break;1.345 case 0x2:1.346 { /* MOV.L @Rm, Rn */1.347 uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF);1.348 + load_reg( R_ECX, Rm );1.349 + MEM_READ_LONG( R_ECX, R_EAX );1.350 + store_reg( R_EAX, Rn );1.351 }1.352 break;1.353 case 0x3:1.354 @@ -1292,11 +1427,23 @@1.355 case 0x5:1.356 { /* MOV.W @Rm+, Rn */1.357 uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF);1.358 + load_reg( R_EAX, Rm );1.359 + MOV_r32_r32( R_EAX, R_ECX );1.360 + ADD_imm8s_r32( 2, R_EAX );1.361 + store_reg( R_EAX, Rm );1.362 + MEM_READ_WORD( R_ECX, R_EAX );1.363 + store_reg( R_EAX, Rn );1.364 }1.365 break;1.366 case 0x6:1.367 { /* MOV.L @Rm+, Rn */1.368 uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF);1.369 + load_reg( R_EAX, Rm );1.370 + MOV_r32_r32( R_EAX, R_ECX );1.371 + ADD_imm8s_r32( 4, R_EAX );1.372 + store_reg( R_EAX, Rm );1.373 + MEM_READ_LONG( R_ECX, R_EAX );1.374 + store_reg( R_EAX, Rn );1.375 }1.376 break;1.377 case 0x7:1.378 @@ -1348,11 +1495,17 @@1.379 case 0xC:1.380 { /* EXTU.B Rm, Rn */1.381 uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF);1.382 + load_reg( R_EAX, Rm );1.383 + MOVZX_r8_r32( R_EAX, R_EAX );1.384 + store_reg( R_EAX, Rn );1.385 }1.386 break;1.387 case 0xD:1.388 { /* EXTU.W Rm, Rn */1.389 uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF);1.390 + load_reg( R_EAX, Rm );1.391 + MOVZX_r16_r32( R_EAX, R_EAX );1.392 + store_reg( R_EAX, Rn );1.393 }1.394 break;1.395 case 0xE:1.396 @@ -1366,6 +1519,9 @@1.397 case 0xF:1.398 { /* EXTS.W Rm, Rn */1.399 uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF);1.400 + load_reg( R_EAX, Rm );1.401 + MOVSX_r16_r32( R_EAX, R_EAX );1.402 + store_reg( R_EAX, Rn );1.403 }1.404 break;1.405 }1.406 @@ -1392,6 +1548,10 @@1.407 case 0x1:1.408 { /* MOV.W R0, @(disp, Rn) */1.409 uint32_t Rn = ((ir>>4)&0xF); uint32_t disp = (ir&0xF)<<1;1.410 + load_reg( R_ECX, Rn );1.411 + load_reg( R_EAX, 0 );1.412 + ADD_imm32_r32( disp, R_ECX );1.413 + MEM_WRITE_WORD( R_ECX, R_EAX );1.414 }1.415 break;1.416 case 0x4:1.417 @@ -1406,6 +1566,10 @@1.418 case 0x5:1.419 { /* MOV.W @(disp, Rm), R0 */1.420 uint32_t Rm = ((ir>>4)&0xF); uint32_t disp = (ir&0xF)<<1;1.421 + load_reg( R_ECX, Rm );1.422 + ADD_imm32_r32( disp, R_ECX );1.423 + MEM_READ_WORD( R_ECX, R_EAX );1.424 + store_reg( R_EAX, 0 );1.425 }1.426 break;1.427 case 0x8:1.428 @@ -1447,6 +1611,9 @@1.429 case 0x9:1.430 { /* MOV.W @(disp, PC), Rn */1.431 uint32_t Rn = ((ir>>8)&0xF); uint32_t disp = (ir&0xFF)<<1;1.432 + load_imm32( R_ECX, pc + disp + 4 );1.433 + MEM_READ_WORD( R_ECX, R_EAX );1.434 + store_reg( R_EAX, Rn );1.435 }1.436 break;1.437 case 0xA:1.438 @@ -1473,11 +1640,19 @@1.439 case 0x1:1.440 { /* MOV.W R0, @(disp, GBR) */1.441 uint32_t disp = (ir&0xFF)<<1;1.442 + load_spreg( R_ECX, R_GBR );1.443 + load_reg( R_EAX, 0 );1.444 + ADD_imm32_r32( disp, R_ECX );1.445 + MEM_WRITE_WORD( R_ECX, R_EAX );1.446 }1.447 break;1.448 case 0x2:1.449 { /* MOV.L R0, @(disp, GBR) */1.450 uint32_t disp = (ir&0xFF)<<2;1.451 + load_spreg( R_ECX, R_GBR );1.452 + load_reg( R_EAX, 0 );1.453 + ADD_imm32_r32( disp, R_ECX );1.454 + MEM_WRITE_LONG( R_ECX, R_EAX );1.455 }1.456 break;1.457 case 0x3:1.458 @@ -1497,16 +1672,26 @@1.459 case 0x5:1.460 { /* MOV.W @(disp, GBR), R0 */1.461 uint32_t disp = (ir&0xFF)<<1;1.462 + load_spreg( R_ECX, R_GBR );1.463 + ADD_imm32_r32( disp, R_ECX );1.464 + MEM_READ_WORD( R_ECX, R_EAX );1.465 + store_reg( R_EAX, 0 );1.466 }1.467 break;1.468 case 0x6:1.469 { /* MOV.L @(disp, GBR), R0 */1.470 uint32_t disp = (ir&0xFF)<<2;1.471 + load_spreg( R_ECX, R_GBR );1.472 + ADD_imm32_r32( disp, R_ECX );1.473 + MEM_READ_LONG( R_ECX, R_EAX );1.474 + store_reg( R_EAX, 0 );1.475 }1.476 break;1.477 case 0x7:1.478 { /* MOVA @(disp, PC), R0 */1.479 uint32_t disp = (ir&0xFF)<<2;1.480 + load_imm32( R_ECX, (pc & 0xFFFFFFFC) + disp + 4 );1.481 + store_reg( R_ECX, 0 );1.482 }1.483 break;1.484 case 0x8:1.485 @@ -1517,8 +1702,6 @@1.486 case 0x9:1.487 { /* AND #imm, R0 */1.488 uint32_t imm = (ir&0xFF);1.489 - // Note: x86 AND imm8 sign-extends, SH4 version zero-extends. So1.490 - // need to use the imm32 version1.491 load_reg( R_EAX, 0 );1.492 AND_imm32_r32(imm, R_EAX);1.493 store_reg( R_EAX, 0 );1.494 @@ -1577,6 +1760,9 @@1.495 case 0xD:1.496 { /* MOV.L @(disp, PC), Rn */1.497 uint32_t Rn = ((ir>>8)&0xF); uint32_t disp = (ir&0xFF)<<2;1.498 + load_imm32( R_ECX, (pc & 0xFFFFFFFC) + disp + 4 );1.499 + MEM_READ_LONG( R_ECX, R_EAX );1.500 + store_reg( R_EAX, 0 );1.501 }1.502 break;1.503 case 0xE:
2.1 --- a/src/sh4/sh4x86.in Thu Aug 23 12:34:43 2007 +00002.2 +++ b/src/sh4/sh4x86.in Tue Aug 28 08:46:14 2007 +00002.3 @@ -1,5 +1,5 @@2.4 /**2.5 - * $Id: sh4x86.in,v 1.1 2007-08-23 12:33:27 nkeynes Exp $2.6 + * $Id: sh4x86.in,v 1.2 2007-08-28 08:46:14 nkeynes Exp $2.7 *2.8 * SH4 => x86 translation. This version does no real optimization, it just2.9 * outputs straight-line x86 code - it mainly exists to provide a baseline2.10 @@ -28,27 +28,19 @@2.11 static inline void load_reg( int x86reg, int sh4reg )2.12 {2.13 /* mov [bp+n], reg */2.14 - OP(0x89);2.15 - OP(0x45 + x86reg<<3);2.16 + OP(0x8B);2.17 + OP(0x45 + (x86reg<<3));2.18 OP(REG_OFFSET(r[sh4reg]));2.19 }2.21 static inline void load_spreg( int x86reg, int regoffset )2.22 {2.23 /* mov [bp+n], reg */2.24 - OP(0x89);2.25 - OP(0x45 + x86reg<<3);2.26 + OP(0x8B);2.27 + OP(0x45 + (x86reg<<3));2.28 OP(regoffset);2.29 }2.31 -#define UNDEF()2.32 -#define MEM_READ_BYTE( addr_reg, value_reg )2.33 -#define MEM_READ_WORD( addr_reg, value_reg )2.34 -#define MEM_READ_LONG( addr_reg, value_reg )2.35 -#define MEM_WRITE_BYTE( addr_reg, value_reg )2.36 -#define MEM_WRITE_WORD( addr_reg, value_reg )2.37 -#define MEM_WRITE_LONG( addr_reg, value_reg )2.38 -2.39 /**2.40 * Emit an instruction to load an immediate value into a register2.41 */2.42 @@ -63,17 +55,52 @@2.43 */2.44 void static inline store_reg( int x86reg, int sh4reg ) {2.45 /* mov reg, [bp+n] */2.46 - OP(0x8B);2.47 - OP(0x45 + x86reg<<3);2.48 + OP(0x89);2.49 + OP(0x45 + (x86reg<<3));2.50 OP(REG_OFFSET(r[sh4reg]));2.51 }2.52 void static inline store_spreg( int x86reg, int regoffset ) {2.53 /* mov reg, [bp+n] */2.54 - OP(0x8B);2.55 - OP(0x45 + x86reg<<3);2.56 + OP(0x89);2.57 + OP(0x45 + (x86reg<<3));2.58 OP(regoffset);2.59 }2.61 +/**2.62 + * Note: clobbers EAX to make the indirect call - this isn't usually2.63 + * a problem since the callee will usually clobber it anyway.2.64 + */2.65 +static inline void call_func0( void *ptr )2.66 +{2.67 + load_imm32(R_EAX, (uint32_t)ptr);2.68 + OP(0xFF);2.69 + MODRM_rm32_r32(R_EAX, 2);2.70 +}2.71 +2.72 +static inline void call_func1( void *ptr, int arg1 )2.73 +{2.74 + PUSH_r32(arg1);2.75 + call_func0(ptr);2.76 + ADD_imm8s_r32( -4, R_ESP );2.77 +}2.78 +2.79 +static inline void call_func2( void *ptr, int arg1, int arg2 )2.80 +{2.81 + PUSH_r32(arg2);2.82 + PUSH_r32(arg1);2.83 + call_func0(ptr);2.84 + ADD_imm8s_r32( -4, R_ESP );2.85 +}2.86 +2.87 +#define UNDEF()2.88 +#define MEM_RESULT(value_reg) if(value_reg != R_EAX) { MOV_r32_r32(R_EAX,value_reg); }2.89 +#define MEM_READ_BYTE( addr_reg, value_reg ) call_func1(sh4_read_byte, addr_reg ); MEM_RESULT(value_reg)2.90 +#define MEM_READ_WORD( addr_reg, value_reg ) call_func1(sh4_read_word, addr_reg ); MEM_RESULT(value_reg)2.91 +#define MEM_READ_LONG( addr_reg, value_reg ) call_func1(sh4_read_long, addr_reg ); MEM_RESULT(value_reg)2.92 +#define MEM_WRITE_BYTE( addr_reg, value_reg ) call_func2(sh4_write_byte, addr_reg, value_reg)2.93 +#define MEM_WRITE_WORD( addr_reg, value_reg ) call_func2(sh4_write_word, addr_reg, value_reg)2.94 +#define MEM_WRITE_LONG( addr_reg, value_reg ) call_func2(sh4_write_long, addr_reg, value_reg)2.95 +2.97 /**2.98 * Emit the 'start of block' assembly. Sets up the stack frame and save2.99 @@ -110,7 +137,7 @@2.100 */2.101 uint32_t sh4_x86_translate_instruction( uint32_t pc )2.102 {2.103 - uint16_t ir = 0;2.104 + uint16_t ir = sh4_read_word( pc );2.106 %%2.107 /* ALU operations */2.108 @@ -147,8 +174,6 @@2.109 store_reg( R_ECX, Rn );2.110 :}2.111 AND #imm, R0 {:2.112 - // Note: x86 AND imm8 sign-extends, SH4 version zero-extends. So2.113 - // need to use the imm32 version2.114 load_reg( R_EAX, 0 );2.115 AND_imm32_r32(imm, R_EAX);2.116 store_reg( R_EAX, 0 );2.117 @@ -206,12 +231,39 @@2.118 CMP_imm8s_r32( 0, R_EAX );2.119 SETGE_t();2.120 :}2.121 -CMP/STR Rm, Rn {: :}2.122 -DIV0S Rm, Rn {: :}2.123 -DIV0U {: :}2.124 +CMP/STR Rm, Rn {:2.125 +:}2.126 +DIV0S Rm, Rn {:2.127 + load_reg( R_EAX, Rm );2.128 + load_reg( R_ECX, Rm );2.129 + SHR_imm8_r32( 31, R_EAX );2.130 + SHR_imm8_r32( 31, R_ECX );2.131 + store_spreg( R_EAX, R_M );2.132 + store_spreg( R_ECX, R_Q );2.133 + CMP_r32_r32( R_EAX, R_ECX );2.134 + SETE_t();2.135 +:}2.136 +DIV0U {:2.137 + XOR_r32_r32( R_EAX, R_EAX );2.138 + store_spreg( R_EAX, R_Q );2.139 + store_spreg( R_EAX, R_M );2.140 + store_spreg( R_EAX, R_T );2.141 +:}2.142 DIV1 Rm, Rn {: :}2.143 -DMULS.L Rm, Rn {: :}2.144 -DMULU.L Rm, Rn {: :}2.145 +DMULS.L Rm, Rn {:2.146 + load_reg( R_EAX, Rm );2.147 + load_reg( R_ECX, Rn );2.148 + IMUL_r32(R_ECX);2.149 + store_spreg( R_EDX, R_MACH );2.150 + store_spreg( R_EAX, R_MACL );2.151 +:}2.152 +DMULU.L Rm, Rn {:2.153 + load_reg( R_EAX, Rm );2.154 + load_reg( R_ECX, Rn );2.155 + MUL_r32(R_ECX);2.156 + store_spreg( R_EDX, R_MACH );2.157 + store_spreg( R_EAX, R_MACL );2.158 +:}2.159 DT Rn {:2.160 load_reg( R_EAX, Rn );2.161 ADD_imm8s_r32( -1, Rn );2.162 @@ -223,17 +275,35 @@2.163 MOVSX_r8_r32( R_EAX, R_EAX );2.164 store_reg( R_EAX, Rn );2.165 :}2.166 -EXTS.W Rm, Rn {: :}2.167 -EXTU.B Rm, Rn {: :}2.168 -EXTU.W Rm, Rn {: :}2.169 +EXTS.W Rm, Rn {:2.170 + load_reg( R_EAX, Rm );2.171 + MOVSX_r16_r32( R_EAX, R_EAX );2.172 + store_reg( R_EAX, Rn );2.173 +:}2.174 +EXTU.B Rm, Rn {:2.175 + load_reg( R_EAX, Rm );2.176 + MOVZX_r8_r32( R_EAX, R_EAX );2.177 + store_reg( R_EAX, Rn );2.178 +:}2.179 +EXTU.W Rm, Rn {:2.180 + load_reg( R_EAX, Rm );2.181 + MOVZX_r16_r32( R_EAX, R_EAX );2.182 + store_reg( R_EAX, Rn );2.183 +:}2.184 MAC.L @Rm+, @Rn+ {: :}2.185 MAC.W @Rm+, @Rn+ {: :}2.186 MOVT Rn {:2.187 load_spreg( R_EAX, R_T );2.188 store_reg( R_EAX, Rn );2.189 :}2.190 -MUL.L Rm, Rn {: :}2.191 -MULS.W Rm, Rn {: :}2.192 +MUL.L Rm, Rn {:2.193 + load_reg( R_EAX, Rm );2.194 + load_reg( R_ECX, Rn );2.195 + MUL_r32( R_ECX );2.196 + store_spreg( R_EAX, R_MACL );2.197 +:}2.198 +MULS.W Rm, Rn {:2.199 +:}2.200 MULU.W Rm, Rn {: :}2.201 NEG Rm, Rn {:2.202 load_reg( R_EAX, Rm );2.203 @@ -293,6 +363,20 @@2.204 :}2.205 SHAD Rm, Rn {:2.206 /* Annoyingly enough, not directly convertible */2.207 + load_reg( R_EAX, Rn );2.208 + load_reg( R_ECX, Rm );2.209 + CMP_imm32_r32( 0, R_ECX );2.210 + JAE_rel8(9);2.211 +2.212 + NEG_r32( R_ECX ); // 22.213 + AND_imm8_r8( 0x1F, R_CL ); // 32.214 + SAR_r32_CL( R_EAX ); // 22.215 + JMP_rel8(5); // 22.216 +2.217 + AND_imm8_r8( 0x1F, R_CL ); // 32.218 + SHL_r32_CL( R_EAX ); // 22.219 +2.220 + store_reg( R_EAX, Rn );2.221 :}2.222 SHLD Rm, Rn {:2.223 :}2.224 @@ -379,8 +463,20 @@2.225 OR_r32_r32( R_EAX, R_ECX );2.226 store_reg( R_ECX, Rn );2.227 :}2.228 -TAS.B @Rn {: :}2.229 -TST Rm, Rn {: :}2.230 +TAS.B @Rn {:2.231 + load_reg( R_ECX, Rn );2.232 + MEM_READ_BYTE( R_ECX, R_EAX );2.233 + TEST_r8_r8( R_AL, R_AL );2.234 + SETE_t();2.235 + OR_imm8_r8( 0x80, R_AL );2.236 + MEM_WRITE_BYTE( R_ECX, R_EAX );2.237 +:}2.238 +TST Rm, Rn {:2.239 + load_reg( R_EAX, Rm );2.240 + load_reg( R_ECX, Rn );2.241 + TEST_r32_r32( R_EAX, R_ECX );2.242 + SETE_t();2.243 +:}2.244 TST #imm, R0 {: :}2.245 TST.B #imm, @(R0, GBR) {: :}2.246 XOR Rm, Rn {:2.247 @@ -402,7 +498,13 @@2.248 XOR_imm32_r32( imm, R_EAX );2.249 MEM_WRITE_BYTE( R_ECX, R_EAX );2.250 :}2.251 -XTRCT Rm, Rn {:2.252 +XTRCT Rm, Rn {:2.253 + load_reg( R_EAX, Rm );2.254 + MOV_r32_r32( R_EAX, R_ECX );2.255 + SHR_imm8_r32( 16, R_EAX );2.256 + SHL_imm8_r32( 16, R_ECX );2.257 + OR_r32_r32( R_EAX, R_ECX );2.258 + store_reg( R_ECX, Rn );2.259 :}2.261 /* Data move instructions */2.262 @@ -477,30 +579,150 @@2.263 MEM_READ_BYTE( R_ECX, R_EAX );2.264 store_reg( R_EAX, 0 );2.265 :}2.266 -MOV.L Rm, @Rn {: :}2.267 -MOV.L Rm, @-Rn {: :}2.268 -MOV.L Rm, @(R0, Rn) {: :}2.269 -MOV.L R0, @(disp, GBR) {: :}2.270 -MOV.L Rm, @(disp, Rn) {: :}2.271 -MOV.L @Rm, Rn {: :}2.272 -MOV.L @Rm+, Rn {: :}2.273 -MOV.L @(R0, Rm), Rn {: :}2.274 -MOV.L @(disp, GBR), R0 {: :}2.275 -MOV.L @(disp, PC), Rn {: :}2.276 -MOV.L @(disp, Rm), Rn {: :}2.277 -MOV.W Rm, @Rn {: :}2.278 -MOV.W Rm, @-Rn {: :}2.279 -MOV.W Rm, @(R0, Rn) {: :}2.280 -MOV.W R0, @(disp, GBR) {: :}2.281 -MOV.W R0, @(disp, Rn) {: :}2.282 -MOV.W @Rm, Rn {: :}2.283 -MOV.W @Rm+, Rn {: :}2.284 -MOV.W @(R0, Rm), Rn {: :}2.285 -MOV.W @(disp, GBR), R0 {: :}2.286 -MOV.W @(disp, PC), Rn {: :}2.287 -MOV.W @(disp, Rm), R0 {: :}2.288 -MOVA @(disp, PC), R0 {: :}2.289 -MOVCA.L R0, @Rn {: :}2.290 +MOV.L Rm, @Rn {:2.291 + load_reg( R_EAX, Rm );2.292 + load_reg( R_ECX, Rn );2.293 + MEM_WRITE_LONG( R_ECX, R_EAX );2.294 +:}2.295 +MOV.L Rm, @-Rn {:2.296 + load_reg( R_EAX, Rm );2.297 + load_reg( R_ECX, Rn );2.298 + ADD_imm8s_r32( -4, R_ECX );2.299 + store_reg( R_ECX, Rn );2.300 + MEM_WRITE_LONG( R_ECX, R_EAX );2.301 +:}2.302 +MOV.L Rm, @(R0, Rn) {:2.303 + load_reg( R_EAX, 0 );2.304 + load_reg( R_ECX, Rn );2.305 + ADD_r32_r32( R_EAX, R_ECX );2.306 + load_reg( R_EAX, Rm );2.307 + MEM_WRITE_LONG( R_ECX, R_EAX );2.308 +:}2.309 +MOV.L R0, @(disp, GBR) {:2.310 + load_spreg( R_ECX, R_GBR );2.311 + load_reg( R_EAX, 0 );2.312 + ADD_imm32_r32( disp, R_ECX );2.313 + MEM_WRITE_LONG( R_ECX, R_EAX );2.314 +:}2.315 +MOV.L Rm, @(disp, Rn) {:2.316 + load_reg( R_ECX, Rn );2.317 + load_reg( R_EAX, Rm );2.318 + ADD_imm32_r32( disp, R_ECX );2.319 + MEM_WRITE_LONG( R_ECX, R_EAX );2.320 +:}2.321 +MOV.L @Rm, Rn {:2.322 + load_reg( R_ECX, Rm );2.323 + MEM_READ_LONG( R_ECX, R_EAX );2.324 + store_reg( R_EAX, Rn );2.325 +:}2.326 +MOV.L @Rm+, Rn {:2.327 + load_reg( R_EAX, Rm );2.328 + MOV_r32_r32( R_EAX, R_ECX );2.329 + ADD_imm8s_r32( 4, R_EAX );2.330 + store_reg( R_EAX, Rm );2.331 + MEM_READ_LONG( R_ECX, R_EAX );2.332 + store_reg( R_EAX, Rn );2.333 +:}2.334 +MOV.L @(R0, Rm), Rn {:2.335 + load_reg( R_EAX, 0 );2.336 + load_reg( R_ECX, Rm );2.337 + ADD_r32_r32( R_EAX, R_ECX );2.338 + MEM_READ_LONG( R_ECX, R_EAX );2.339 + store_reg( R_EAX, Rn );2.340 +:}2.341 +MOV.L @(disp, GBR), R0 {:2.342 + load_spreg( R_ECX, R_GBR );2.343 + ADD_imm32_r32( disp, R_ECX );2.344 + MEM_READ_LONG( R_ECX, R_EAX );2.345 + store_reg( R_EAX, 0 );2.346 +:}2.347 +MOV.L @(disp, PC), Rn {:2.348 + load_imm32( R_ECX, (pc & 0xFFFFFFFC) + disp + 4 );2.349 + MEM_READ_LONG( R_ECX, R_EAX );2.350 + store_reg( R_EAX, 0 );2.351 +:}2.352 +MOV.L @(disp, Rm), Rn {:2.353 + load_reg( R_ECX, Rm );2.354 + ADD_imm8s_r32( disp, R_ECX );2.355 + MEM_READ_LONG( R_ECX, R_EAX );2.356 + store_reg( R_EAX, Rn );2.357 +:}2.358 +MOV.W Rm, @Rn {:2.359 + load_reg( R_ECX, Rn );2.360 + MEM_READ_WORD( R_ECX, R_EAX );2.361 + store_reg( R_EAX, Rn );2.362 +:}2.363 +MOV.W Rm, @-Rn {:2.364 + load_reg( R_ECX, Rn );2.365 + load_reg( R_EAX, Rm );2.366 + ADD_imm8s_r32( -2, R_ECX );2.367 + MEM_WRITE_WORD( R_ECX, R_EAX );2.368 +:}2.369 +MOV.W Rm, @(R0, Rn) {:2.370 + load_reg( R_EAX, 0 );2.371 + load_reg( R_ECX, Rn );2.372 + ADD_r32_r32( R_EAX, R_ECX );2.373 + load_reg( R_EAX, Rm );2.374 + MEM_WRITE_WORD( R_ECX, R_EAX );2.375 +:}2.376 +MOV.W R0, @(disp, GBR) {:2.377 + load_spreg( R_ECX, R_GBR );2.378 + load_reg( R_EAX, 0 );2.379 + ADD_imm32_r32( disp, R_ECX );2.380 + MEM_WRITE_WORD( R_ECX, R_EAX );2.381 +:}2.382 +MOV.W R0, @(disp, Rn) {:2.383 + load_reg( R_ECX, Rn );2.384 + load_reg( R_EAX, 0 );2.385 + ADD_imm32_r32( disp, R_ECX );2.386 + MEM_WRITE_WORD( R_ECX, R_EAX );2.387 +:}2.388 +MOV.W @Rm, Rn {:2.389 + load_reg( R_ECX, Rm );2.390 + MEM_READ_WORD( R_ECX, R_EAX );2.391 + store_reg( R_EAX, Rn );2.392 +:}2.393 +MOV.W @Rm+, Rn {:2.394 + load_reg( R_EAX, Rm );2.395 + MOV_r32_r32( R_EAX, R_ECX );2.396 + ADD_imm8s_r32( 2, R_EAX );2.397 + store_reg( R_EAX, Rm );2.398 + MEM_READ_WORD( R_ECX, R_EAX );2.399 + store_reg( R_EAX, Rn );2.400 +:}2.401 +MOV.W @(R0, Rm), Rn {:2.402 + load_reg( R_EAX, 0 );2.403 + load_reg( R_ECX, Rm );2.404 + ADD_r32_r32( R_EAX, R_ECX );2.405 + MEM_READ_WORD( R_ECX, R_EAX );2.406 + store_reg( R_EAX, Rn );2.407 +:}2.408 +MOV.W @(disp, GBR), R0 {:2.409 + load_spreg( R_ECX, R_GBR );2.410 + ADD_imm32_r32( disp, R_ECX );2.411 + MEM_READ_WORD( R_ECX, R_EAX );2.412 + store_reg( R_EAX, 0 );2.413 +:}2.414 +MOV.W @(disp, PC), Rn {:2.415 + load_imm32( R_ECX, pc + disp + 4 );2.416 + MEM_READ_WORD( R_ECX, R_EAX );2.417 + store_reg( R_EAX, Rn );2.418 +:}2.419 +MOV.W @(disp, Rm), R0 {:2.420 + load_reg( R_ECX, Rm );2.421 + ADD_imm32_r32( disp, R_ECX );2.422 + MEM_READ_WORD( R_ECX, R_EAX );2.423 + store_reg( R_EAX, 0 );2.424 +:}2.425 +MOVA @(disp, PC), R0 {:2.426 + load_imm32( R_ECX, (pc & 0xFFFFFFFC) + disp + 4 );2.427 + store_reg( R_ECX, 0 );2.428 +:}2.429 +MOVCA.L R0, @Rn {:2.430 + load_reg( R_EAX, 0 );2.431 + load_reg( R_ECX, Rn );2.432 + MEM_WRITE_LONG( R_ECX, R_EAX );2.433 +:}2.435 /* Control transfer instructions */2.436 BF disp {: :}
3.1 --- a/src/sh4/x86op.h Thu Aug 23 12:34:43 2007 +00003.2 +++ b/src/sh4/x86op.h Tue Aug 28 08:46:14 2007 +00003.3 @@ -1,5 +1,5 @@3.4 /**3.5 - * $Id: x86op.h,v 1.1 2007-08-23 12:33:27 nkeynes Exp $3.6 + * $Id: x86op.h,v 1.2 2007-08-28 08:46:14 nkeynes Exp $3.7 *3.8 * Definitions of x86 opcodes for use by the translator.3.9 *3.10 @@ -39,13 +39,16 @@3.11 #define R_BH 73.14 -#define OP(x) *xlat_output++ = x3.15 -#define OP32(x) *((uint32_t *)xlat_output) = x; xlat_output+=23.16 +#define OP(x) *xlat_output++ = (x)3.17 +#define OP32(x) *((uint32_t *)xlat_output) = (x); xlat_output+=43.19 /* Offset of a reg relative to the sh4r structure */3.20 #define REG_OFFSET(reg) (((char *)&sh4r.reg) - ((char *)&sh4r))3.22 #define R_T REG_OFFSET(t)3.23 +#define R_Q REG_OFFSET(q)3.24 +#define R_S REG_OFFSET(s)3.25 +#define R_M REG_OFFSET(m)3.26 #define R_GBR REG_OFFSET(gbr)3.27 #define R_SSR REG_OFFSET(ssr)3.28 #define R_SPC REG_OFFSET(spc)3.29 @@ -82,6 +85,7 @@3.30 #define CMC() OP(0xF5)3.31 #define CMP_r32_r32(r1,r2) OP(0x3B); MODRM_rm32_r32(r1,r2)3.32 #define CMP_imm8s_r32(imm,r1) OP(0x83); MODRM_rm32_r32(r1,7); OP(imm)3.33 +#define JMP_rel8(rel) OP(0xEB); OP(rel)3.34 #define MOV_r32_ebp8(r1,disp) OP(0x89); MODRM_r32_ebp8(r1,disp)3.35 #define MOV_r32_ebp32(r1,disp) OP(0x89); MODRM_r32_ebp32(r1,disp)3.36 #define MOV_ebp8_r32(r1,disp) OP(0x8B); MODRM_r32_ebp8(r1,disp)3.37 @@ -94,6 +98,7 @@3.38 #define NOT_r32(r1) OP(0xF7); MODRM_rm32_r32(r1,2)3.39 #define OR_r32_r32(r1,r2) OP(0x0B); MODRM_rm32_r32(r1,r2)3.40 #define OR_imm32_r32(imm,r1) OP(0x81); MODRM_rm32_r32(r1,1); OP32(imm)3.41 +#define PUSH_r32(r1) OP(0x50 + r1)3.42 #define RCL1_r32(r1) OP(0xD1); MODRM_rm32_r32(r1,2)3.43 #define RCR1_r32(r1) OP(0xD1); MODRM_rm32_r32(r1,3)3.44 #define RET() OP(0xC3)3.45 @@ -112,9 +117,18 @@3.46 #define XOR_r32_r32(r1,r2) OP(0x33); MODRM_rm32_r32(r1,r2)3.47 #define XOR_imm32_r32(imm,r1) OP(0x81); MODRM_rm32_r32(r1,6); OP32(imm)3.49 -#define ADD_imm32_r32(imm32,r1)3.50 -#define MOV_r32_r32(r1,r2)3.51 -#define XCHG_r8_r8(r1,r2)3.52 +#define ADD_imm32_r32(imm32,r1) OP(0x81); MODRM_rm32_r32(r1,0); OP32(imm32)3.53 +#define AND_imm8_r8(imm8, r1) OP(0x80); MODRM_rm32_r32(r1,4); OP(imm8)3.54 +#define CMP_imm32_r32(imm32, r1) OP(0x81); MODRM_rm32_r32(r1,7); OP32(imm32)3.55 +#define MOV_r32_r32(r1,r2) OP(0x89); MODRM_r32_rm32(r1,r2)3.56 +#define MUL_r32(r1) OP(0xF7); MODRM_rm32_r32(r1,4)3.57 +#define IMUL_r32(r1) OP(0xF7); MODRM_rm32_r32(r1,5)3.58 +#define OR_imm8_r8(imm,r1) OP(0x80); MODRM_rm32_r32(r1,1)3.59 +#define TEST_r8_r8(r1,r2) OP(0x84); MODRM_r32_rm32(r1,r2)3.60 +#define SAR_r32_CL(r1) OP(0xD3); MODRM_rm32_r32(r1,7)3.61 +#define SHR_r32_CL(r1) OP(0xD3); MODRM_rm32_r32(r1,5)3.62 +#define SHL_r32_CL(r1) OP(0xD3); MODRM_rm32_r32(r1,4)3.63 +#define XCHG_r8_r8(r1,r2) OP(0x86); MODRM_rm32_r32(r1,r2)3.65 /* Conditional branches */3.66 #define JE_rel8(rel) OP(0x74); OP(rel)
.