From 6e1eeeebfb453fa7c871869c19375ce60fbd7413 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Sat, 27 Jul 2019 16:01:55 -0700 Subject: 5485 - promote SubX to top-level --- html/015immediate_addressing.cc.html | 1337 ++++++++++++++++++++++++++++++++++ 1 file changed, 1337 insertions(+) create mode 100644 html/015immediate_addressing.cc.html (limited to 'html/015immediate_addressing.cc.html') diff --git a/html/015immediate_addressing.cc.html b/html/015immediate_addressing.cc.html new file mode 100644 index 00000000..cbc5d8cc --- /dev/null +++ b/html/015immediate_addressing.cc.html @@ -0,0 +1,1337 @@ + + + + +Mu - subx/015immediate_addressing.cc + + + + + + + + + + +https://github.com/akkartik/mu/blob/master/subx/015immediate_addressing.cc +
+   1 //: instructions that (immediately) contain an argument to act with
+   2 
+   3 :(before "End Initialize Op Names")
+   4 put_new(Name, "05", "add imm32 to EAX (add)");
+   5 
+   6 :(before "End Single-Byte Opcodes")
+   7 case 0x05: {  // add imm32 to EAX
+   8   int32_t signed_arg2 = next32();
+   9   trace(Callstack_depth+1, "run") << "add imm32 0x" << HEXWORD << signed_arg2 << " to EAX" << end();
+  10   int32_t signed_result = Reg[EAX].i + signed_arg2;
+  11   SF = (signed_result < 0);
+  12   ZF = (signed_result == 0);
+  13   int64_t signed_full_result = static_cast<int64_t>(Reg[EAX].i) + signed_arg2;
+  14   OF = (signed_result != signed_full_result);
+  15   // set CF
+  16   uint32_t unsigned_arg2 = static_cast<uint32_t>(signed_arg2);
+  17   uint32_t unsigned_result = Reg[EAX].u + unsigned_arg2;
+  18   uint64_t unsigned_full_result = static_cast<uint64_t>(Reg[EAX].u) + unsigned_arg2;
+  19   CF = (unsigned_result != unsigned_full_result);
+  20   trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
+  21   Reg[EAX].i = signed_result;
+  22   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[EAX].i << end();
+  23   break;
+  24 }
+  25 
+  26 :(code)
+  27 void test_add_imm32_to_EAX_signed_overflow() {
+  28   Reg[EAX].i = 0x7fffffff;  // largest positive signed integer
+  29   run(
+  30       "== code 0x1\n"
+  31       // op     ModR/M  SIB   displacement  immediate
+  32       "  05                                 01 00 00 00 \n" // add 1 to EAX
+  33   );
+  34   CHECK_TRACE_CONTENTS(
+  35       "run: add imm32 0x00000001 to EAX\n"
+  36       "run: SF=1; ZF=0; CF=0; OF=1\n"
+  37       "run: storing 0x80000000\n"
+  38   );
+  39 }
+  40 
+  41 void test_add_imm32_to_EAX_unsigned_overflow() {
+  42   Reg[EAX].u = 0xffffffff;  // largest unsigned number
+  43   Reg[EBX].u = 1;
+  44   run(
+  45       "== code 0x1\n"
+  46       // op     ModR/M  SIB   displacement  immediate
+  47       "  05                                 01 00 00 00 \n" // add 1 to EAX
+  48   );
+  49   CHECK_TRACE_CONTENTS(
+  50       "run: add imm32 0x00000001 to EAX\n"
+  51       "run: SF=0; ZF=1; CF=1; OF=0\n"
+  52       "run: storing 0x00000000\n"
+  53   );
+  54 }
+  55 
+  56 void test_add_imm32_to_EAX_unsigned_and_signed_overflow() {
+  57   Reg[EAX].u = 0x80000000;  // smallest negative signed integer
+  58   run(
+  59       "== code 0x1\n"
+  60       // op     ModR/M  SIB   displacement  immediate
+  61       "  05                                 00 00 00 80 \n" // add 0x80000000 to EAX
+  62   );
+  63   CHECK_TRACE_CONTENTS(
+  64       "run: add imm32 0x80000000 to EAX\n"
+  65       "run: SF=0; ZF=1; CF=1; OF=1\n"
+  66       "run: storing 0x00000000\n"
+  67   );
+  68 }
+  69 
+  70 //:
+  71 
+  72 :(before "End Initialize Op Names")
+  73 put_new(Name, "81", "combine rm32 with imm32 based on subop (add/sub/and/or/xor/cmp)");
+  74 
+  75 :(code)
+  76 void test_add_imm32_to_r32() {
+  77   Reg[EBX].i = 1;
+  78   run(
+  79       "== code 0x1\n"
+  80       // op     ModR/M  SIB   displacement  immediate
+  81       "  81     c3                          0a 0b 0c 0d\n"  // add 0x0d0c0b0a to EBX
+  82       // ModR/M in binary: 11 (direct mode) 000 (subop add) 011 (dest EBX)
+  83   );
+  84   CHECK_TRACE_CONTENTS(
+  85       "run: combine r/m32 with imm32\n"
+  86       "run: r/m32 is EBX\n"
+  87       "run: imm32 is 0x0d0c0b0a\n"
+  88       "run: subop add\n"
+  89       "run: storing 0x0d0c0b0b\n"
+  90   );
+  91 }
+  92 
+  93 :(before "End Single-Byte Opcodes")
+  94 case 0x81: {  // combine r/m32 with imm32
+  95   trace(Callstack_depth+1, "run") << "combine r/m32 with imm32" << end();
+  96   const uint8_t modrm = next();
+  97   int32_t* signed_arg1 = effective_address(modrm);
+  98   const int32_t signed_arg2 = next32();
+  99   trace(Callstack_depth+1, "run") << "imm32 is 0x" << HEXWORD << signed_arg2 << end();
+ 100   const uint8_t subop = (modrm>>3)&0x7;  // middle 3 'reg opcode' bits
+ 101   switch (subop) {
+ 102   case 0: {
+ 103     trace(Callstack_depth+1, "run") << "subop add" << end();
+ 104     int32_t signed_result = *signed_arg1 + signed_arg2;
+ 105     SF = (signed_result < 0);
+ 106     ZF = (signed_result == 0);
+ 107     int64_t signed_full_result = static_cast<int64_t>(*signed_arg1) + signed_arg2;
+ 108     OF = (signed_result != signed_full_result);
+ 109     // set CF
+ 110     uint32_t unsigned_arg1 = static_cast<uint32_t>(*signed_arg1);
+ 111     uint32_t unsigned_arg2 = static_cast<uint32_t>(signed_arg2);
+ 112     uint32_t unsigned_result = unsigned_arg1 + unsigned_arg2;
+ 113     uint64_t unsigned_full_result = static_cast<uint64_t>(unsigned_arg1) + unsigned_arg2;
+ 114     CF = (unsigned_result != unsigned_full_result);
+ 115     trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
+ 116     *signed_arg1 = signed_result;
+ 117     trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end();
+ 118     break;
+ 119   }
+ 120   // End Op 81 Subops
+ 121   default:
+ 122     cerr << "unrecognized subop for opcode 81: " << NUM(subop) << '\n';
+ 123     exit(1);
+ 124   }
+ 125   break;
+ 126 }
+ 127 
+ 128 :(code)
+ 129 void test_add_imm32_to_r32_signed_overflow() {
+ 130   Reg[EBX].i = 0x7fffffff;  // largest positive signed integer
+ 131   run(
+ 132       "== code 0x1\n"
+ 133       // op     ModR/M  SIB   displacement  immediate
+ 134       "  81     c3                          01 00 00 00\n"  // add 1 to EBX
+ 135       // ModR/M in binary: 11 (direct mode) 000 (subop add) 011 (dest EBX)
+ 136   );
+ 137   CHECK_TRACE_CONTENTS(
+ 138       "run: combine r/m32 with imm32\n"
+ 139       "run: r/m32 is EBX\n"
+ 140       "run: imm32 is 0x00000001\n"
+ 141       "run: subop add\n"
+ 142       "run: SF=1; ZF=0; CF=0; OF=1\n"
+ 143       "run: storing 0x80000000\n"
+ 144   );
+ 145 }
+ 146 
+ 147 void test_add_imm32_to_r32_unsigned_overflow() {
+ 148   Reg[EBX].u = 0xffffffff;  // largest unsigned number
+ 149   run(
+ 150       "== code 0x1\n"
+ 151       // op     ModR/M  SIB   displacement  immediate
+ 152       "  81     c3                          01 00 00 00\n"  // add 1 to EBX
+ 153       // ModR/M in binary: 11 (direct mode) 011 (subop add) 011 (dest EBX)
+ 154   );
+ 155   CHECK_TRACE_CONTENTS(
+ 156       "run: combine r/m32 with imm32\n"
+ 157       "run: r/m32 is EBX\n"
+ 158       "run: imm32 is 0x00000001\n"
+ 159       "run: subop add\n"
+ 160       "run: SF=0; ZF=1; CF=1; OF=0\n"
+ 161       "run: storing 0x00000000\n"
+ 162   );
+ 163 }
+ 164 
+ 165 void test_add_imm32_to_r32_unsigned_and_signed_overflow() {
+ 166   Reg[EBX].u = 0x80000000;  // smallest negative signed integer
+ 167   run(
+ 168       "== code 0x1\n"
+ 169       // op     ModR/M  SIB   displacement  immediate
+ 170       "  81     c3                          00 00 00 80\n"  // add 0x80000000 to EBX
+ 171       // ModR/M in binary: 11 (direct mode) 011 (subop add) 011 (dest EBX)
+ 172   );
+ 173   CHECK_TRACE_CONTENTS(
+ 174       "run: combine r/m32 with imm32\n"
+ 175       "run: r/m32 is EBX\n"
+ 176       "run: imm32 is 0x80000000\n"
+ 177       "run: subop add\n"
+ 178       "run: SF=0; ZF=1; CF=1; OF=1\n"
+ 179       "run: storing 0x00000000\n"
+ 180   );
+ 181 }
+ 182 
+ 183 //:
+ 184 
+ 185 :(code)
+ 186 void test_add_imm32_to_mem_at_r32() {
+ 187   Reg[EBX].i = 0x2000;
+ 188   run(
+ 189       "== code 0x1\n"
+ 190       // op     ModR/M  SIB   displacement  immediate
+ 191       "  81     03                          0a 0b 0c 0d \n"  // add 0x0d0c0b0a to *EBX
+ 192       // ModR/M in binary: 00 (indirect mode) 000 (subop add) 011 (dest EBX)
+ 193       "== data 0x2000\n"
+ 194       "01 00 00 00\n"  // 0x00000001
+ 195   );
+ 196   CHECK_TRACE_CONTENTS(
+ 197       "run: combine r/m32 with imm32\n"
+ 198       "run: effective address is 0x00002000 (EBX)\n"
+ 199       "run: imm32 is 0x0d0c0b0a\n"
+ 200       "run: subop add\n"
+ 201       "run: storing 0x0d0c0b0b\n"
+ 202   );
+ 203 }
+ 204 
+ 205 //:: subtract
+ 206 
+ 207 :(before "End Initialize Op Names")
+ 208 put_new(Name, "2d", "subtract imm32 from EAX (sub)");
+ 209 
+ 210 :(code)
+ 211 void test_subtract_imm32_from_EAX() {
+ 212   Reg[EAX].i = 0x0d0c0baa;
+ 213   run(
+ 214       "== code 0x1\n"
+ 215       // op     ModR/M  SIB   displacement  immediate
+ 216       "  2d                                 0a 0b 0c 0d \n"  // subtract 0x0d0c0b0a from EAX
+ 217   );
+ 218   CHECK_TRACE_CONTENTS(
+ 219       "run: subtract imm32 0x0d0c0b0a from EAX\n"
+ 220       "run: storing 0x000000a0\n"
+ 221   );
+ 222 }
+ 223 
+ 224 :(before "End Single-Byte Opcodes")
+ 225 case 0x2d: {  // subtract imm32 from EAX
+ 226   const int32_t signed_arg2 = next32();
+ 227   trace(Callstack_depth+1, "run") << "subtract imm32 0x" << HEXWORD << signed_arg2 << " from EAX" << end();
+ 228   int32_t signed_result = Reg[EAX].i - signed_arg2;
+ 229   SF = (signed_result < 0);
+ 230   ZF = (signed_result == 0);
+ 231   int64_t signed_full_result = static_cast<int64_t>(Reg[EAX].i) - signed_arg2;
+ 232   OF = (signed_result != signed_full_result);
+ 233   // set CF
+ 234   uint32_t unsigned_arg2 = static_cast<uint32_t>(signed_arg2);
+ 235   uint32_t unsigned_result = Reg[EAX].u - unsigned_arg2;
+ 236   uint64_t unsigned_full_result = static_cast<uint64_t>(Reg[EAX].u) - unsigned_arg2;
+ 237   CF = (unsigned_result != unsigned_full_result);
+ 238   trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
+ 239   Reg[EAX].i = signed_result;
+ 240   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[EAX].i << end();
+ 241   break;
+ 242 }
+ 243 
+ 244 :(code)
+ 245 void test_subtract_imm32_from_EAX_signed_overflow() {
+ 246   Reg[EAX].i = 0x80000000;  // smallest negative signed integer
+ 247   run(
+ 248       "== code 0x1\n"
+ 249       // op     ModR/M  SIB   displacement  immediate
+ 250       "  2d                                 ff ff ff 7f \n"  // subtract largest positive signed integer from EAX
+ 251   );
+ 252   CHECK_TRACE_CONTENTS(
+ 253       "run: subtract imm32 0x7fffffff from EAX\n"
+ 254       "run: SF=0; ZF=0; CF=0; OF=1\n"
+ 255       "run: storing 0x00000001\n"
+ 256   );
+ 257 }
+ 258 
+ 259 void test_subtract_imm32_from_EAX_unsigned_overflow() {
+ 260   Reg[EAX].i = 0;
+ 261   run(
+ 262       "== code 0x1\n"
+ 263       // op     ModR/M  SIB   displacement  immediate
+ 264       "  2d                                 01 00 00 00 \n"  // subtract 1 from EAX
+ 265   );
+ 266   CHECK_TRACE_CONTENTS(
+ 267       "run: subtract imm32 0x00000001 from EAX\n"
+ 268       "run: SF=1; ZF=0; CF=1; OF=0\n"
+ 269       "run: storing 0xffffffff\n"
+ 270   );
+ 271 }
+ 272 
+ 273 void test_subtract_imm32_from_EAX_signed_and_unsigned_overflow() {
+ 274   Reg[EAX].i = 0;
+ 275   run(
+ 276       "== code 0x1\n"
+ 277       // op     ModR/M  SIB   displacement  immediate
+ 278       "  2d                                 00 00 00 80 \n"  // subtract smallest negative signed integer from EAX
+ 279   );
+ 280   CHECK_TRACE_CONTENTS(
+ 281       "run: subtract imm32 0x80000000 from EAX\n"
+ 282       "run: SF=1; ZF=0; CF=1; OF=1\n"
+ 283       "run: storing 0x80000000\n"
+ 284   );
+ 285 }
+ 286 
+ 287 //:
+ 288 
+ 289 void test_subtract_imm32_from_mem_at_r32() {
+ 290   Reg[EBX].i = 0x2000;
+ 291   run(
+ 292       "== code 0x1\n"
+ 293       // op     ModR/M  SIB   displacement  immediate
+ 294       "  81     2b                          01 00 00 00 \n"  // subtract 1 from *EBX
+ 295       // ModR/M in binary: 00 (indirect mode) 101 (subop subtract) 011 (dest EBX)
+ 296       "== data 0x2000\n"
+ 297       "0a 00 00 00\n"  // 0x0000000a
+ 298   );
+ 299   CHECK_TRACE_CONTENTS(
+ 300       "run: combine r/m32 with imm32\n"
+ 301       "run: effective address is 0x00002000 (EBX)\n"
+ 302       "run: imm32 is 0x00000001\n"
+ 303       "run: subop subtract\n"
+ 304       "run: storing 0x00000009\n"
+ 305   );
+ 306 }
+ 307 
+ 308 :(before "End Op 81 Subops")
+ 309 case 5: {
+ 310   trace(Callstack_depth+1, "run") << "subop subtract" << end();
+ 311   int32_t signed_result = *signed_arg1 - signed_arg2;
+ 312   SF = (signed_result < 0);
+ 313   ZF = (signed_result == 0);
+ 314   int64_t signed_full_result = static_cast<int64_t>(*signed_arg1) - signed_arg2;
+ 315   OF = (signed_result != signed_full_result);
+ 316   // set CF
+ 317   uint32_t unsigned_arg1 = static_cast<uint32_t>(*signed_arg1);
+ 318   uint32_t unsigned_arg2 = static_cast<uint32_t>(signed_arg2);
+ 319   uint32_t unsigned_result = unsigned_arg1 - unsigned_arg2;
+ 320   uint64_t unsigned_full_result = static_cast<uint64_t>(unsigned_arg1) - unsigned_arg2;
+ 321   CF = (unsigned_result != unsigned_full_result);
+ 322   trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
+ 323   *signed_arg1 = signed_result;
+ 324   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end();
+ 325   break;
+ 326 }
+ 327 
+ 328 :(code)
+ 329 void test_subtract_imm32_from_mem_at_r32_signed_overflow() {
+ 330   Reg[EBX].i = 0x2000;
+ 331   run(
+ 332       "== code 0x1\n"
+ 333       // op     ModR/M  SIB   displacement  immediate
+ 334       "  81     2b                          ff ff ff 7f \n"  // subtract largest positive signed integer from *EBX
+ 335       // ModR/M in binary: 00 (indirect mode) 101 (subop subtract) 011 (dest EBX)
+ 336       "== data 0x2000\n"
+ 337       "00 00 00 80\n"  // smallest negative signed integer
+ 338   );
+ 339   CHECK_TRACE_CONTENTS(
+ 340       "run: combine r/m32 with imm32\n"
+ 341       "run: effective address is 0x00002000 (EBX)\n"
+ 342       "run: effective address contains 80000000\n"
+ 343       "run: imm32 is 0x7fffffff\n"
+ 344       "run: subop subtract\n"
+ 345       "run: SF=0; ZF=0; CF=0; OF=1\n"
+ 346       "run: storing 0x00000001\n"
+ 347   );
+ 348 }
+ 349 
+ 350 void test_subtract_imm32_from_mem_at_r32_unsigned_overflow() {
+ 351   Reg[EBX].i = 0x2000;
+ 352   run(
+ 353       "== code 0x1\n"
+ 354       // op     ModR/M  SIB   displacement  immediate
+ 355       "  81     2b                          01 00 00 00 \n"  // subtract 1 from *EBX
+ 356       // ModR/M in binary: 00 (indirect mode) 101 (subop subtract) 011 (dest EBX)
+ 357       "== data 0x2000\n"
+ 358       "00 00 00 00\n"  // 0
+ 359   );
+ 360   CHECK_TRACE_CONTENTS(
+ 361       "run: combine r/m32 with imm32\n"
+ 362       "run: effective address is 0x00002000 (EBX)\n"
+ 363       "run: effective address contains 0\n"
+ 364       "run: imm32 is 0x00000001\n"
+ 365       "run: subop subtract\n"
+ 366       "run: SF=1; ZF=0; CF=1; OF=0\n"
+ 367       "run: storing 0xffffffff\n"
+ 368   );
+ 369 }
+ 370 
+ 371 void test_subtract_imm32_from_mem_at_r32_signed_and_unsigned_overflow() {
+ 372   Reg[EBX].i = 0x2000;
+ 373   run(
+ 374       "== code 0x1\n"
+ 375       // op     ModR/M  SIB   displacement  immediate
+ 376       "  81     2b                          00 00 00 80 \n"  // subtract smallest negative signed integer from *EBX
+ 377       // ModR/M in binary: 00 (indirect mode) 101 (subop subtract) 011 (dest EBX)
+ 378       "== data 0x2000\n"
+ 379       "00 00 00 00\n"  // 0
+ 380   );
+ 381   CHECK_TRACE_CONTENTS(
+ 382       "run: combine r/m32 with imm32\n"
+ 383       "run: effective address is 0x00002000 (EBX)\n"
+ 384       "run: effective address contains 0\n"
+ 385       "run: imm32 is 0x80000000\n"
+ 386       "run: subop subtract\n"
+ 387       "run: SF=1; ZF=0; CF=1; OF=1\n"
+ 388       "run: storing 0x80000000\n"
+ 389   );
+ 390 }
+ 391 
+ 392 //:
+ 393 
+ 394 void test_subtract_imm32_from_r32() {
+ 395   Reg[EBX].i = 10;
+ 396   run(
+ 397       "== code 0x1\n"
+ 398       // op     ModR/M  SIB   displacement  immediate
+ 399       "  81     eb                          01 00 00 00 \n"  // subtract 1 from EBX
+ 400       // ModR/M in binary: 11 (direct mode) 101 (subop subtract) 011 (dest EBX)
+ 401   );
+ 402   CHECK_TRACE_CONTENTS(
+ 403       "run: combine r/m32 with imm32\n"
+ 404       "run: r/m32 is EBX\n"
+ 405       "run: imm32 is 0x00000001\n"
+ 406       "run: subop subtract\n"
+ 407       "run: storing 0x00000009\n"
+ 408   );
+ 409 }
+ 410 
+ 411 //:: shift left
+ 412 
+ 413 :(before "End Initialize Op Names")
+ 414 put_new(Name, "c1", "shift rm32 by imm8 bits depending on subop (sal/sar/shl/shr)");
+ 415 
+ 416 :(code)
+ 417 void test_shift_left_r32_with_imm8() {
+ 418   Reg[EBX].i = 13;
+ 419   run(
+ 420       "== code 0x1\n"
+ 421       // op     ModR/M  SIB   displacement  immediate
+ 422       "  c1     e3                          01          \n"  // shift EBX left by 1 bit
+ 423       // ModR/M in binary: 11 (direct mode) 100 (subop shift left) 011 (dest EBX)
+ 424   );
+ 425   CHECK_TRACE_CONTENTS(
+ 426       "run: operate on r/m32\n"
+ 427       "run: r/m32 is EBX\n"
+ 428       "run: subop: shift left by CL bits\n"
+ 429       "run: storing 0x0000001a\n"
+ 430   );
+ 431 }
+ 432 
+ 433 :(before "End Single-Byte Opcodes")
+ 434 case 0xc1: {
+ 435   const uint8_t modrm = next();
+ 436   trace(Callstack_depth+1, "run") << "operate on r/m32" << end();
+ 437   int32_t* arg1 = effective_address(modrm);
+ 438   const uint8_t subop = (modrm>>3)&0x7;  // middle 3 'reg opcode' bits
+ 439   switch (subop) {
+ 440   case 4: {  // shift left r/m32 by CL
+ 441     trace(Callstack_depth+1, "run") << "subop: shift left by CL bits" << end();
+ 442     uint8_t count = next() & 0x1f;
+ 443     // OF is only defined if count is 1
+ 444     if (count == 1) {
+ 445       bool msb = (*arg1 & 0x80000000) >> 1;
+ 446       bool pnsb = (*arg1 & 0x40000000);
+ 447       OF = (msb != pnsb);
+ 448     }
+ 449     *arg1 = (*arg1 << count);
+ 450     ZF = (*arg1 == 0);
+ 451     SF = (*arg1 < 0);
+ 452     // CF undefined
+ 453     trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
+ 454     trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *arg1 << end();
+ 455     break;
+ 456   }
+ 457   // End Op c1 Subops
+ 458   default:
+ 459     cerr << "unrecognized subop for opcode c1: " << NUM(subop) << '\n';
+ 460     exit(1);
+ 461   }
+ 462   break;
+ 463 }
+ 464 
+ 465 //:: shift right arithmetic
+ 466 
+ 467 :(code)
+ 468 void test_shift_right_arithmetic_r32_with_imm8() {
+ 469   Reg[EBX].i = 26;
+ 470   run(
+ 471       "== code 0x1\n"
+ 472       // op     ModR/M  SIB   displacement  immediate
+ 473       "  c1     fb                          01          \n"  // shift EBX right by 1 bit
+ 474       // ModR/M in binary: 11 (direct mode) 111 (subop shift right arithmetic) 011 (dest EBX)
+ 475   );
+ 476   CHECK_TRACE_CONTENTS(
+ 477       "run: operate on r/m32\n"
+ 478       "run: r/m32 is EBX\n"
+ 479       "run: subop: shift right by CL bits, while preserving sign\n"
+ 480       "run: storing 0x0000000d\n"
+ 481   );
+ 482 }
+ 483 
+ 484 :(before "End Op c1 Subops")
+ 485 case 7: {  // shift right r/m32 by CL, preserving sign
+ 486   trace(Callstack_depth+1, "run") << "subop: shift right by CL bits, while preserving sign" << end();
+ 487   uint8_t count = next() & 0x1f;
+ 488   int32_t result = (*arg1 >> count);
+ 489   ZF = (*arg1 == 0);
+ 490   SF = (*arg1 < 0);
+ 491   // OF is only defined if count is 1
+ 492   if (count == 1) OF = false;
+ 493   // CF
+ 494   CF = ((*arg1 >> (count-1)) & 0x1);
+ 495   trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
+ 496   *arg1 = result;
+ 497   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *arg1 << end();
+ 498   break;
+ 499 }
+ 500 
+ 501 :(code)
+ 502 void test_shift_right_arithmetic_odd_r32_with_imm8() {
+ 503   Reg[EBX].i = 27;
+ 504   run(
+ 505       "== code 0x1\n"
+ 506       // op     ModR/M  SIB   displacement  immediate
+ 507       "  c1     fb                          01          \n"  // shift EBX right by 1 bit
+ 508       // ModR/M in binary: 11 (direct mode) 111 (subop shift right arithmetic) 011 (dest EBX)
+ 509   );
+ 510   CHECK_TRACE_CONTENTS(
+ 511       "run: operate on r/m32\n"
+ 512       "run: r/m32 is EBX\n"
+ 513       "run: subop: shift right by CL bits, while preserving sign\n"
+ 514       // result: 13
+ 515       "run: storing 0x0000000d\n"
+ 516   );
+ 517 }
+ 518 
+ 519 :(code)
+ 520 void test_shift_right_arithmetic_negative_r32_with_imm8() {
+ 521   Reg[EBX].i = 0xfffffffd;  // -3
+ 522   run(
+ 523       "== code 0x1\n"
+ 524       // op     ModR/M  SIB   displacement  immediate
+ 525       "  c1     fb                          01          \n"  // shift EBX right by 1 bit, while preserving sign
+ 526       // ModR/M in binary: 11 (direct mode) 111 (subop shift right arithmetic) 011 (dest EBX)
+ 527   );
+ 528   CHECK_TRACE_CONTENTS(
+ 529       "run: operate on r/m32\n"
+ 530       "run: r/m32 is EBX\n"
+ 531       "run: subop: shift right by CL bits, while preserving sign\n"
+ 532       // result: -2
+ 533       "run: storing 0xfffffffe\n"
+ 534   );
+ 535 }
+ 536 
+ 537 //:: shift right logical
+ 538 
+ 539 :(code)
+ 540 void test_shift_right_logical_r32_with_imm8() {
+ 541   Reg[EBX].i = 26;
+ 542   run(
+ 543       "== code 0x1\n"
+ 544       // op     ModR/M  SIB   displacement  immediate
+ 545       "  c1     eb                          01          \n"  // shift EBX right by 1 bit, while padding zeroes
+ 546       // ModR/M in binary: 11 (direct mode) 101 (subop shift right logical) 011 (dest EBX)
+ 547   );
+ 548   CHECK_TRACE_CONTENTS(
+ 549       "run: operate on r/m32\n"
+ 550       "run: r/m32 is EBX\n"
+ 551       "run: subop: shift right by CL bits, while padding zeroes\n"
+ 552       "run: storing 0x0000000d\n"
+ 553   );
+ 554 }
+ 555 
+ 556 :(before "End Op c1 Subops")
+ 557 case 5: {  // shift right r/m32 by CL, preserving sign
+ 558   trace(Callstack_depth+1, "run") << "subop: shift right by CL bits, while padding zeroes" << end();
+ 559   uint8_t count = next() & 0x1f;
+ 560   // OF is only defined if count is 1
+ 561   if (count == 1) {
+ 562     bool msb = (*arg1 & 0x80000000) >> 1;
+ 563     bool pnsb = (*arg1 & 0x40000000);
+ 564     OF = (msb != pnsb);
+ 565   }
+ 566   uint32_t* uarg1 = reinterpret_cast<uint32_t*>(arg1);
+ 567   *uarg1 = (*uarg1 >> count);
+ 568   ZF = (*uarg1 == 0);
+ 569   // result is always positive by definition
+ 570   SF = false;
+ 571   // CF undefined
+ 572   trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
+ 573   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *arg1 << end();
+ 574   break;
+ 575 }
+ 576 
+ 577 :(code)
+ 578 void test_shift_right_logical_odd_r32_with_imm8() {
+ 579   Reg[EBX].i = 27;
+ 580   run(
+ 581       "== code 0x1\n"
+ 582       // op     ModR/M  SIB   displacement  immediate
+ 583       "  c1     eb                          01          \n"  // shift EBX right by 1 bit, while padding zeroes
+ 584   );
+ 585   CHECK_TRACE_CONTENTS(
+ 586       "run: operate on r/m32\n"
+ 587       "run: r/m32 is EBX\n"
+ 588       "run: subop: shift right by CL bits, while padding zeroes\n"
+ 589       // result: 13
+ 590       "run: storing 0x0000000d\n"
+ 591   );
+ 592 }
+ 593 
+ 594 :(code)
+ 595 void test_shift_right_logical_negative_r32_with_imm8() {
+ 596   Reg[EBX].i = 0xfffffffd;
+ 597   run(
+ 598       "== code 0x1\n"
+ 599       // op     ModR/M  SIB   displacement  immediate
+ 600       "  c1     eb                          01          \n"  // shift EBX right by 1 bit, while padding zeroes
+ 601       // ModR/M in binary: 11 (direct mode) 101 (subop shift right logical) 011 (dest EBX)
+ 602   );
+ 603   CHECK_TRACE_CONTENTS(
+ 604       "run: operate on r/m32\n"
+ 605       "run: r/m32 is EBX\n"
+ 606       "run: subop: shift right by CL bits, while padding zeroes\n"
+ 607       "run: storing 0x7ffffffe\n"
+ 608   );
+ 609 }
+ 610 
+ 611 //:: and
+ 612 
+ 613 :(before "End Initialize Op Names")
+ 614 put_new(Name, "25", "EAX = bitwise AND of imm32 with EAX (and)");
+ 615 
+ 616 :(code)
+ 617 void test_and_EAX_with_imm32() {
+ 618   Reg[EAX].i = 0xff;
+ 619   run(
+ 620       "== code 0x1\n"
+ 621       // op     ModR/M  SIB   displacement  immediate
+ 622       "  25                                 0a 0b 0c 0d \n"  // and 0x0d0c0b0a with EAX
+ 623   );
+ 624   CHECK_TRACE_CONTENTS(
+ 625       "run: and imm32 0x0d0c0b0a with EAX\n"
+ 626       "run: storing 0x0000000a\n"
+ 627   );
+ 628 }
+ 629 
+ 630 :(before "End Single-Byte Opcodes")
+ 631 case 0x25: {  // and imm32 with EAX
+ 632   // bitwise ops technically operate on unsigned numbers, but it makes no
+ 633   // difference
+ 634   const int32_t signed_arg2 = next32();
+ 635   trace(Callstack_depth+1, "run") << "and imm32 0x" << HEXWORD << signed_arg2 << " with EAX" << end();
+ 636   Reg[EAX].i &= signed_arg2;
+ 637   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[EAX].i << end();
+ 638   SF = (Reg[EAX].i >> 31);
+ 639   ZF = (Reg[EAX].i == 0);
+ 640   CF = false;
+ 641   OF = false;
+ 642   trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
+ 643   break;
+ 644 }
+ 645 
+ 646 //:
+ 647 
+ 648 :(code)
+ 649 void test_and_imm32_with_mem_at_r32() {
+ 650   Reg[EBX].i = 0x2000;
+ 651   run(
+ 652       "== code 0x1\n"
+ 653       // op     ModR/M  SIB   displacement  immediate
+ 654       "  81     23                          0a 0b 0c 0d \n"  // and 0x0d0c0b0a with *EBX
+ 655       // ModR/M in binary: 00 (indirect mode) 100 (subop and) 011 (dest EBX)
+ 656       "== data 0x2000\n"
+ 657       "ff 00 00 00\n"  // 0x000000ff
+ 658   );
+ 659   CHECK_TRACE_CONTENTS(
+ 660       "run: combine r/m32 with imm32\n"
+ 661       "run: effective address is 0x00002000 (EBX)\n"
+ 662       "run: imm32 is 0x0d0c0b0a\n"
+ 663       "run: subop and\n"
+ 664       "run: storing 0x0000000a\n"
+ 665   );
+ 666 }
+ 667 
+ 668 :(before "End Op 81 Subops")
+ 669 case 4: {
+ 670   trace(Callstack_depth+1, "run") << "subop and" << end();
+ 671   // bitwise ops technically operate on unsigned numbers, but it makes no
+ 672   // difference
+ 673   *signed_arg1 &= signed_arg2;
+ 674   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end();
+ 675   SF = (*signed_arg1 >> 31);
+ 676   ZF = (*signed_arg1 == 0);
+ 677   CF = false;
+ 678   OF = false;
+ 679   trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
+ 680   break;
+ 681 }
+ 682 
+ 683 //:
+ 684 
+ 685 :(code)
+ 686 void test_and_imm32_with_r32() {
+ 687   Reg[EBX].i = 0xff;
+ 688   run(
+ 689       "== code 0x1\n"
+ 690       // op     ModR/M  SIB   displacement  immediate
+ 691       "  81     e3                          0a 0b 0c 0d \n"  // and 0x0d0c0b0a with EBX
+ 692       // ModR/M in binary: 11 (direct mode) 100 (subop and) 011 (dest EBX)
+ 693   );
+ 694   CHECK_TRACE_CONTENTS(
+ 695       "run: combine r/m32 with imm32\n"
+ 696       "run: r/m32 is EBX\n"
+ 697       "run: imm32 is 0x0d0c0b0a\n"
+ 698       "run: subop and\n"
+ 699       "run: storing 0x0000000a\n"
+ 700   );
+ 701 }
+ 702 
+ 703 //:: or
+ 704 
+ 705 :(before "End Initialize Op Names")
+ 706 put_new(Name, "0d", "EAX = bitwise OR of imm32 with EAX (or)");
+ 707 
+ 708 :(code)
+ 709 void test_or_EAX_with_imm32() {
+ 710   Reg[EAX].i = 0xd0c0b0a0;
+ 711   run(
+ 712       "== code 0x1\n"
+ 713       // op     ModR/M  SIB   displacement  immediate
+ 714       "  0d                                 0a 0b 0c 0d \n"  // or 0x0d0c0b0a with EAX
+ 715   );
+ 716   CHECK_TRACE_CONTENTS(
+ 717       "run: or imm32 0x0d0c0b0a with EAX\n"
+ 718       "run: storing 0xddccbbaa\n"
+ 719   );
+ 720 }
+ 721 
+ 722 :(before "End Single-Byte Opcodes")
+ 723 case 0x0d: {  // or imm32 with EAX
+ 724   // bitwise ops technically operate on unsigned numbers, but it makes no
+ 725   // difference
+ 726   const int32_t signed_arg2 = next32();
+ 727   trace(Callstack_depth+1, "run") << "or imm32 0x" << HEXWORD << signed_arg2 << " with EAX" << end();
+ 728   Reg[EAX].i |= signed_arg2;
+ 729   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[EAX].i << end();
+ 730   SF = (Reg[EAX].i >> 31);
+ 731   ZF = (Reg[EAX].i == 0);
+ 732   CF = false;
+ 733   OF = false;
+ 734   trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
+ 735   break;
+ 736 }
+ 737 
+ 738 //:
+ 739 
+ 740 :(code)
+ 741 void test_or_imm32_with_mem_at_r32() {
+ 742   Reg[EBX].i = 0x2000;
+ 743   run(
+ 744       "== code 0x1\n"
+ 745       // op     ModR/M  SIB   displacement  immediate
+ 746       "  81     0b                          0a 0b 0c 0d \n"  // or 0x0d0c0b0a with *EBX
+ 747       // ModR/M in binary: 00 (indirect mode) 001 (subop or) 011 (dest EBX)
+ 748       "== data 0x2000\n"
+ 749       "a0 b0 c0 d0\n"  // 0xd0c0b0a0
+ 750   );
+ 751   CHECK_TRACE_CONTENTS(
+ 752       "run: combine r/m32 with imm32\n"
+ 753       "run: effective address is 0x00002000 (EBX)\n"
+ 754       "run: imm32 is 0x0d0c0b0a\n"
+ 755       "run: subop or\n"
+ 756       "run: storing 0xddccbbaa\n"
+ 757   );
+ 758 }
+ 759 
+ 760 :(before "End Op 81 Subops")
+ 761 case 1: {
+ 762   trace(Callstack_depth+1, "run") << "subop or" << end();
+ 763   // bitwise ops technically operate on unsigned numbers, but it makes no
+ 764   // difference
+ 765   *signed_arg1 |= signed_arg2;
+ 766   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end();
+ 767   SF = (*signed_arg1 >> 31);
+ 768   ZF = (*signed_arg1 == 0);
+ 769   CF = false;
+ 770   OF = false;
+ 771   trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
+ 772   break;
+ 773 }
+ 774 
+ 775 :(code)
+ 776 void test_or_imm32_with_r32() {
+ 777   Reg[EBX].i = 0xd0c0b0a0;
+ 778   run(
+ 779       "== code 0x1\n"
+ 780       // op     ModR/M  SIB   displacement  immediate
+ 781       "  81     cb                          0a 0b 0c 0d \n"  // or 0x0d0c0b0a with EBX
+ 782       // ModR/M in binary: 11 (direct mode) 001 (subop or) 011 (dest EBX)
+ 783   );
+ 784   CHECK_TRACE_CONTENTS(
+ 785       "run: combine r/m32 with imm32\n"
+ 786       "run: r/m32 is EBX\n"
+ 787       "run: imm32 is 0x0d0c0b0a\n"
+ 788       "run: subop or\n"
+ 789       "run: storing 0xddccbbaa\n"
+ 790   );
+ 791 }
+ 792 
+ 793 //:: xor
+ 794 
+ 795 :(before "End Initialize Op Names")
+ 796 put_new(Name, "35", "EAX = bitwise XOR of imm32 with EAX (xor)");
+ 797 
+ 798 :(code)
+ 799 void test_xor_EAX_with_imm32() {
+ 800   Reg[EAX].i = 0xddccb0a0;
+ 801   run(
+ 802       "== code 0x1\n"
+ 803       // op     ModR/M  SIB   displacement  immediate
+ 804       "  35                                 0a 0b 0c 0d \n"  // xor 0x0d0c0b0a with EAX
+ 805   );
+ 806   CHECK_TRACE_CONTENTS(
+ 807       "run: xor imm32 0x0d0c0b0a with EAX\n"
+ 808       "run: storing 0xd0c0bbaa\n"
+ 809   );
+ 810 }
+ 811 
+ 812 :(before "End Single-Byte Opcodes")
+ 813 case 0x35: {  // xor imm32 with EAX
+ 814   // bitwise ops technically operate on unsigned numbers, but it makes no
+ 815   // difference
+ 816   const int32_t signed_arg2 = next32();
+ 817   trace(Callstack_depth+1, "run") << "xor imm32 0x" << HEXWORD << signed_arg2 << " with EAX" << end();
+ 818   Reg[EAX].i ^= signed_arg2;
+ 819   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[EAX].i << end();
+ 820   SF = (Reg[EAX].i >> 31);
+ 821   ZF = (Reg[EAX].i == 0);
+ 822   CF = false;
+ 823   OF = false;
+ 824   trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
+ 825   break;
+ 826 }
+ 827 
+ 828 //:
+ 829 
+ 830 :(code)
+ 831 void test_xor_imm32_with_mem_at_r32() {
+ 832   Reg[EBX].i = 0x2000;
+ 833   run(
+ 834       "== code 0x1\n"
+ 835       // op     ModR/M  SIB   displacement  immediate
+ 836       "  81     33                          0a 0b 0c 0d \n"  // xor 0x0d0c0b0a with *EBX
+ 837       // ModR/M in binary: 00 (indirect mode) 110 (subop xor) 011 (dest EBX)
+ 838       "== data 0x2000\n"
+ 839       "a0 b0 c0 d0\n"  // 0xd0c0b0a0
+ 840   );
+ 841   CHECK_TRACE_CONTENTS(
+ 842       "run: combine r/m32 with imm32\n"
+ 843       "run: effective address is 0x00002000 (EBX)\n"
+ 844       "run: imm32 is 0x0d0c0b0a\n"
+ 845       "run: subop xor\n"
+ 846       "run: storing 0xddccbbaa\n"
+ 847   );
+ 848 }
+ 849 
+ 850 :(before "End Op 81 Subops")
+ 851 case 6: {
+ 852   trace(Callstack_depth+1, "run") << "subop xor" << end();
+ 853   // bitwise ops technically operate on unsigned numbers, but it makes no
+ 854   // difference
+ 855   *signed_arg1 ^= signed_arg2;
+ 856   trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end();
+ 857   SF = (*signed_arg1 >> 31);
+ 858   ZF = (*signed_arg1 == 0);
+ 859   CF = false;
+ 860   OF = false;
+ 861   trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
+ 862   break;
+ 863 }
+ 864 
+ 865 :(code)
+ 866 void test_xor_imm32_with_r32() {
+ 867   Reg[EBX].i = 0xd0c0b0a0;
+ 868   run(
+ 869       "== code 0x1\n"
+ 870       // op     ModR/M  SIB   displacement  immediate
+ 871       "  81     f3                          0a 0b 0c 0d \n"  // xor 0x0d0c0b0a with EBX
+ 872       // ModR/M in binary: 11 (direct mode) 110 (subop xor) 011 (dest EBX)
+ 873   );
+ 874   CHECK_TRACE_CONTENTS(
+ 875       "run: combine r/m32 with imm32\n"
+ 876       "run: r/m32 is EBX\n"
+ 877       "run: imm32 is 0x0d0c0b0a\n"
+ 878       "run: subop xor\n"
+ 879       "run: storing 0xddccbbaa\n"
+ 880   );
+ 881 }
+ 882 
+ 883 //:: compare (cmp)
+ 884 
+ 885 :(before "End Initialize Op Names")
+ 886 put_new(Name, "3d", "compare: set SF if EAX < imm32 (cmp)");
+ 887 
+ 888 :(code)
+ 889 void test_compare_EAX_with_imm32_greater() {
+ 890   Reg[EAX].i = 0x0d0c0b0a;
+ 891   run(
+ 892       "== code 0x1\n"
+ 893       // op     ModR/M  SIB   displacement  immediate
+ 894       "  3d                                 07 0b 0c 0d \n"  // compare EAX with 0x0d0c0b07
+ 895   );
+ 896   CHECK_TRACE_CONTENTS(
+ 897       "run: compare EAX with imm32 0x0d0c0b07\n"
+ 898       "run: SF=0; ZF=0; CF=0; OF=0\n"
+ 899   );
+ 900 }
+ 901 
+ 902 :(before "End Single-Byte Opcodes")
+ 903 case 0x3d: {  // compare EAX with imm32
+ 904   const int32_t signed_arg1 = Reg[EAX].i;
+ 905   const int32_t signed_arg2 = next32();
+ 906   trace(Callstack_depth+1, "run") << "compare EAX with imm32 0x" << HEXWORD << signed_arg2 << end();
+ 907   const int32_t signed_difference = signed_arg1 - signed_arg2;
+ 908   SF = (signed_difference < 0);
+ 909   ZF = (signed_difference == 0);
+ 910   const int64_t full_signed_difference = static_cast<int64_t>(signed_arg1) - signed_arg2;
+ 911   OF = (signed_difference != full_signed_difference);
+ 912   const uint32_t unsigned_arg1 = static_cast<uint32_t>(signed_arg1);
+ 913   const uint32_t unsigned_arg2 = static_cast<uint32_t>(signed_arg2);
+ 914   const uint32_t unsigned_difference = unsigned_arg1 - unsigned_arg2;
+ 915   const uint64_t full_unsigned_difference = static_cast<uint64_t>(unsigned_arg1) - unsigned_arg2;
+ 916   CF = (unsigned_difference != full_unsigned_difference);
+ 917   trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
+ 918   break;
+ 919 }
+ 920 
+ 921 :(code)
+ 922 void test_compare_EAX_with_imm32_lesser_unsigned_and_signed() {
+ 923   Reg[EAX].i = 0x0a0b0c07;
+ 924   run(
+ 925       "== code 0x1\n"
+ 926       // op     ModR/M  SIB   displacement  immediate
+ 927       "  3d                                 0d 0c 0b 0a \n"  // compare EAX with imm32
+ 928   );
+ 929   CHECK_TRACE_CONTENTS(
+ 930       "run: compare EAX with imm32 0x0a0b0c0d\n"
+ 931       "run: SF=1; ZF=0; CF=1; OF=0\n"
+ 932   );
+ 933 }
+ 934 
+ 935 void test_compare_EAX_with_imm32_lesser_unsigned_and_signed_due_to_overflow() {
+ 936   Reg[EAX].i = 0x7fffffff;  // largest positive signed integer
+ 937   run(
+ 938       "== code 0x1\n"
+ 939       // op     ModR/M  SIB   displacement  immediate
+ 940       "  3d                                 00 00 00 80\n"  // compare EAX with smallest negative signed integer
+ 941   );
+ 942   CHECK_TRACE_CONTENTS(
+ 943       "run: compare EAX with imm32 0x80000000\n"
+ 944       "run: SF=1; ZF=0; CF=1; OF=1\n"
+ 945   );
+ 946 }
+ 947 
+ 948 void test_compare_EAX_with_imm32_lesser_signed() {
+ 949   Reg[EAX].i = 0xffffffff;  // -1
+ 950   run(
+ 951       "== code 0x1\n"
+ 952       // op     ModR/M  SIB   displacement  immediate
+ 953       "  3d                                 01 00 00 00\n"  // compare EAX with 1
+ 954   );
+ 955   CHECK_TRACE_CONTENTS(
+ 956       "run: compare EAX with imm32 0x00000001\n"
+ 957       "run: SF=1; ZF=0; CF=0; OF=0\n"
+ 958   );
+ 959 }
+ 960 
+ 961 void test_compare_EAX_with_imm32_lesser_unsigned() {
+ 962   Reg[EAX].i = 0x00000001;  // 1
+ 963   run(
+ 964       "== code 0x1\n"
+ 965       // op     ModR/M  SIB   displacement  immediate
+ 966       "  3d                                 ff ff ff ff\n"  // compare EAX with -1
+ 967   );
+ 968   CHECK_TRACE_CONTENTS(
+ 969       "run: compare EAX with imm32 0xffffffff\n"
+ 970       "run: SF=0; ZF=0; CF=1; OF=0\n"
+ 971   );
+ 972 }
+ 973 
+ 974 void test_compare_EAX_with_imm32_equal() {
+ 975   Reg[EAX].i = 0x0d0c0b0a;
+ 976   run(
+ 977       "== code 0x1\n"
+ 978       // op     ModR/M  SIB   displacement  immediate
+ 979       "  3d                                 0a 0b 0c 0d \n"  // compare 0x0d0c0b0a with EAX
+ 980   );
+ 981   CHECK_TRACE_CONTENTS(
+ 982       "run: compare EAX with imm32 0x0d0c0b0a\n"
+ 983       "run: SF=0; ZF=1; CF=0; OF=0\n"
+ 984   );
+ 985 }
+ 986 
+ 987 //:
+ 988 
+ 989 void test_compare_imm32_with_r32_greater() {
+ 990   Reg[EBX].i = 0x0d0c0b0a;
+ 991   run(
+ 992       "== code 0x1\n"
+ 993       // op     ModR/M  SIB   displacement  immediate
+ 994       "  81     fb                          07 0b 0c 0d \n"  // compare 0x0d0c0b07 with EBX
+ 995       // ModR/M in binary: 11 (direct mode) 111 (subop compare) 011 (dest EBX)
+ 996   );
+ 997   CHECK_TRACE_CONTENTS(
+ 998       "run: combine r/m32 with imm32\n"
+ 999       "run: r/m32 is EBX\n"
+1000       "run: imm32 is 0x0d0c0b07\n"
+1001       "run: SF=0; ZF=0; CF=0; OF=0\n"
+1002   );
+1003 }
+1004 
+1005 :(before "End Op 81 Subops")
+1006 case 7: {
+1007   trace(Callstack_depth+1, "run") << "subop compare" << end();
+1008   const int32_t tmp1 = *signed_arg1 - signed_arg2;
+1009   SF = (tmp1 < 0);
+1010   ZF = (tmp1 == 0);
+1011   const int64_t tmp2 = static_cast<int64_t>(*signed_arg1) - signed_arg2;
+1012   OF = (tmp1 != tmp2);
+1013   const uint32_t unsigned_arg1 = static_cast<uint32_t>(*signed_arg1);
+1014   const uint32_t unsigned_arg2 = static_cast<uint32_t>(signed_arg2);
+1015   const uint32_t tmp3 = unsigned_arg1 - unsigned_arg2;
+1016   const uint64_t tmp4 = static_cast<uint64_t>(unsigned_arg1) - unsigned_arg2;
+1017   CF = (tmp3 != tmp4);
+1018   trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end();
+1019   break;
+1020 }
+1021 
+1022 :(code)
+1023 void test_compare_rm32_with_imm32_lesser_unsigned_and_signed() {
+1024   Reg[EAX].i = 0x0a0b0c07;
+1025   run(
+1026       "== code 0x1\n"
+1027       // op     ModR/M  SIB   displacement  immediate
+1028       "  81     f8                          0d 0c 0b 0a \n"  // compare EAX with imm32
+1029       // ModR/M in binary: 11 (direct mode) 111 (subop compare) 000 (dest EAX)
+1030   );
+1031   CHECK_TRACE_CONTENTS(
+1032       "run: combine r/m32 with imm32\n"
+1033       "run: r/m32 is EAX\n"
+1034       "run: imm32 is 0x0a0b0c0d\n"
+1035       "run: subop compare\n"
+1036       "run: SF=1; ZF=0; CF=1; OF=0\n"
+1037   );
+1038 }
+1039 
+1040 void test_compare_rm32_with_imm32_lesser_unsigned_and_signed_due_to_overflow() {
+1041   Reg[EAX].i = 0x7fffffff;  // largest positive signed integer
+1042   run(
+1043       "== code 0x1\n"
+1044       // op     ModR/M  SIB   displacement  immediate
+1045       "  81     f8                          00 00 00 80\n"  // compare EAX with smallest negative signed integer
+1046       // ModR/M in binary: 11 (direct mode) 111 (subop compare) 000 (dest EAX)
+1047   );
+1048   CHECK_TRACE_CONTENTS(
+1049       "run: combine r/m32 with imm32\n"
+1050       "run: r/m32 is EAX\n"
+1051       "run: imm32 is 0x80000000\n"
+1052       "run: subop compare\n"
+1053       "run: SF=1; ZF=0; CF=1; OF=1\n"
+1054   );
+1055 }
+1056 
+1057 void test_compare_rm32_with_imm32_lesser_signed() {
+1058   Reg[EAX].i = 0xffffffff;  // -1
+1059   run(
+1060       "== code 0x1\n"
+1061       // op     ModR/M  SIB   displacement  immediate
+1062       "  81     f8                          01 00 00 00\n"  // compare EAX with 1
+1063       // ModR/M in binary: 11 (direct mode) 111 (subop compare) 000 (dest EAX)
+1064   );
+1065   CHECK_TRACE_CONTENTS(
+1066       "run: combine r/m32 with imm32\n"
+1067       "run: r/m32 is EAX\n"
+1068       "run: imm32 is 0x00000001\n"
+1069       "run: subop compare\n"
+1070       "run: SF=1; ZF=0; CF=0; OF=0\n"
+1071   );
+1072 }
+1073 
+1074 void test_compare_rm32_with_imm32_lesser_unsigned() {
+1075   Reg[EAX].i = 0x00000001;  // 1
+1076   run(
+1077       "== code 0x1\n"
+1078       // op     ModR/M  SIB   displacement  immediate
+1079       "  81     f8                          ff ff ff ff\n"  // compare EAX with -1
+1080       // ModR/M in binary: 11 (direct mode) 111 (subop compare) 000 (dest EAX)
+1081   );
+1082   CHECK_TRACE_CONTENTS(
+1083       "run: combine r/m32 with imm32\n"
+1084       "run: r/m32 is EAX\n"
+1085       "run: imm32 is 0xffffffff\n"
+1086       "run: subop compare\n"
+1087       "run: SF=0; ZF=0; CF=1; OF=0\n"
+1088   );
+1089 }
+1090 
+1091 :(code)
+1092 void test_compare_imm32_with_r32_equal() {
+1093   Reg[EBX].i = 0x0d0c0b0a;
+1094   run(
+1095       "== code 0x1\n"
+1096       // op     ModR/M  SIB   displacement  immediate
+1097       "  81     fb                          0a 0b 0c 0d \n"  // compare 0x0d0c0b0a with EBX
+1098       // ModR/M in binary: 11 (direct mode) 111 (subop compare) 011 (dest EBX)
+1099   );
+1100   CHECK_TRACE_CONTENTS(
+1101       "run: combine r/m32 with imm32\n"
+1102       "run: r/m32 is EBX\n"
+1103       "run: imm32 is 0x0d0c0b0a\n"
+1104       "run: SF=0; ZF=1; CF=0; OF=0\n"
+1105   );
+1106 }
+1107 
+1108 :(code)
+1109 void test_compare_imm32_with_mem_at_r32_greater() {
+1110   Reg[EBX].i = 0x2000;
+1111   run(
+1112       "== code 0x1\n"
+1113       // op     ModR/M  SIB   displacement  immediate
+1114       "  81     3b                          07 0b 0c 0d \n"  // compare 0x0d0c0b07 with *EBX
+1115       // ModR/M in binary: 00 (indirect mode) 111 (subop compare) 011 (dest EBX)
+1116       "== data 0x2000\n"
+1117       "0a 0b 0c 0d\n"  // 0x0d0c0b0a
+1118   );
+1119   CHECK_TRACE_CONTENTS(
+1120       "run: combine r/m32 with imm32\n"
+1121       "run: effective address is 0x00002000 (EBX)\n"
+1122       "run: imm32 is 0x0d0c0b07\n"
+1123       "run: SF=0; ZF=0; CF=0; OF=0\n"
+1124   );
+1125 }
+1126 
+1127 :(code)
+1128 void test_compare_imm32_with_mem_at_r32_lesser() {
+1129   Reg[EAX].i = 0x2000;
+1130   run(
+1131       "== code 0x1\n"
+1132       // op     ModR/M  SIB   displacement  immediate
+1133       "  81     38                          0a 0b 0c 0d \n"  // compare 0x0d0c0b0a with *EAX
+1134       // ModR/M in binary: 00 (indirect mode) 111 (subop compare) 000 (dest EAX)
+1135       "== data 0x2000\n"
+1136       "07 0b 0c 0d\n"  // 0x0d0c0b07
+1137   );
+1138   CHECK_TRACE_CONTENTS(
+1139       "run: combine r/m32 with imm32\n"
+1140       "run: effective address is 0x00002000 (EAX)\n"
+1141       "run: imm32 is 0x0d0c0b0a\n"
+1142       "run: SF=1; ZF=0; CF=1; OF=0\n"
+1143   );
+1144 }
+1145 
+1146 :(code)
+1147 void test_compare_imm32_with_mem_at_r32_equal() {
+1148   Reg[EBX].i = 0x0d0c0b0a;
+1149   Reg[EBX].i = 0x2000;
+1150   run(
+1151       "== code 0x1\n"
+1152       // op     ModR/M  SIB   displacement  immediate
+1153       "  81     3b                          0a 0b 0c 0d \n"  // compare 0x0d0c0b0a with *EBX
+1154       // ModR/M in binary: 00 (indirect mode) 111 (subop compare) 011 (dest EBX)
+1155       "== data 0x2000\n"
+1156       "0a 0b 0c 0d\n"  // 0x0d0c0b0a
+1157   );
+1158   CHECK_TRACE_CONTENTS(
+1159       "run: combine r/m32 with imm32\n"
+1160       "run: effective address is 0x00002000 (EBX)\n"
+1161       "run: imm32 is 0x0d0c0b0a\n"
+1162       "run: SF=0; ZF=1; CF=0; OF=0\n"
+1163   );
+1164 }
+1165 
+1166 //:: copy (mov)
+1167 
+1168 :(before "End Initialize Op Names")
+1169 // b8 defined earlier to copy imm32 to EAX
+1170 put_new(Name, "b9", "copy imm32 to ECX (mov)");
+1171 put_new(Name, "ba", "copy imm32 to EDX (mov)");
+1172 put_new(Name, "bb", "copy imm32 to EBX (mov)");
+1173 put_new(Name, "bc", "copy imm32 to ESP (mov)");
+1174 put_new(Name, "bd", "copy imm32 to EBP (mov)");
+1175 put_new(Name, "be", "copy imm32 to ESI (mov)");
+1176 put_new(Name, "bf", "copy imm32 to EDI (mov)");
+1177 
+1178 :(code)
+1179 void test_copy_imm32_to_r32() {
+1180   run(
+1181       "== code 0x1\n"
+1182       // op     ModR/M  SIB   displacement  immediate
+1183       "  bb                                 0a 0b 0c 0d \n"  // copy 0x0d0c0b0a to EBX
+1184   );
+1185   CHECK_TRACE_CONTENTS(
+1186       "run: copy imm32 0x0d0c0b0a to EBX\n"
+1187   );
+1188 }
+1189 
+1190 :(before "End Single-Byte Opcodes")
+1191 case 0xb9:
+1192 case 0xba:
+1193 case 0xbb:
+1194 case 0xbc:
+1195 case 0xbd:
+1196 case 0xbe:
+1197 case 0xbf: {  // copy imm32 to r32
+1198   const uint8_t rdest = op & 0x7;
+1199   const int32_t src = next32();
+1200   trace(Callstack_depth+1, "run") << "copy imm32 0x" << HEXWORD << src << " to " << rname(rdest) << end();
+1201   Reg[rdest].i = src;
+1202   break;
+1203 }
+1204 
+1205 //:
+1206 
+1207 :(before "End Initialize Op Names")
+1208 put_new(Name, "c7", "copy imm32 to rm32 (mov)");
+1209 
+1210 :(code)
+1211 void test_copy_imm32_to_mem_at_r32() {
+1212   Reg[EBX].i = 0x60;
+1213   run(
+1214       "== code 0x1\n"
+1215       // op     ModR/M  SIB   displacement  immediate
+1216       "  c7     03                          0a 0b 0c 0d \n"  // copy 0x0d0c0b0a to *EBX
+1217       // ModR/M in binary: 00 (indirect mode) 000 (unused) 011 (dest EBX)
+1218   );
+1219   CHECK_TRACE_CONTENTS(
+1220       "run: copy imm32 to r/m32\n"
+1221       "run: effective address is 0x00000060 (EBX)\n"
+1222       "run: imm32 is 0x0d0c0b0a\n"
+1223   );
+1224 }
+1225 
+1226 :(before "End Single-Byte Opcodes")
+1227 case 0xc7: {  // copy imm32 to r32
+1228   const uint8_t modrm = next();
+1229   trace(Callstack_depth+1, "run") << "copy imm32 to r/m32" << end();
+1230   const uint8_t subop = (modrm>>3)&0x7;  // middle 3 'reg opcode' bits
+1231   if (subop != 0) {
+1232     cerr << "unrecognized subop for opcode c7: " << NUM(subop) << " (only 0/copy currently implemented)\n";
+1233     exit(1);
+1234   }
+1235   int32_t* dest = effective_address(modrm);
+1236   const int32_t src = next32();
+1237   trace(Callstack_depth+1, "run") << "imm32 is 0x" << HEXWORD << src << end();
+1238   *dest = src;
+1239   break;
+1240 }
+1241 
+1242 //:: push
+1243 
+1244 :(before "End Initialize Op Names")
+1245 put_new(Name, "68", "push imm32 to stack (push)");
+1246 
+1247 :(code)
+1248 void test_push_imm32() {
+1249   Mem.push_back(vma(0xbd000000));  // manually allocate memory
+1250   Reg[ESP].u = 0xbd000014;
+1251   run(
+1252       "== code 0x1\n"
+1253       // op     ModR/M  SIB   displacement  immediate
+1254       "  68                                 af 00 00 00 \n"  // push *EAX to stack
+1255   );
+1256   CHECK_TRACE_CONTENTS(
+1257       "run: push imm32 0x000000af\n"
+1258       "run: ESP is now 0xbd000010\n"
+1259       "run: contents at ESP: 0x000000af\n"
+1260   );
+1261 }
+1262 
+1263 :(before "End Single-Byte Opcodes")
+1264 case 0x68: {
+1265   const uint32_t val = static_cast<uint32_t>(next32());
+1266   trace(Callstack_depth+1, "run") << "push imm32 0x" << HEXWORD << val << end();
+1267 //?   cerr << "push: " << val << " => " << Reg[ESP].u << '\n';
+1268   push(val);
+1269   trace(Callstack_depth+1, "run") << "ESP is now 0x" << HEXWORD << Reg[ESP].u << end();
+1270   trace(Callstack_depth+1, "run") << "contents at ESP: 0x" << HEXWORD << read_mem_u32(Reg[ESP].u) << end();
+1271   break;
+1272 }
+
+ + + -- cgit 1.4.1-2-gfad0