# Mu - subx/013direct_addressing.cc

      1 //: operating directly on a register
      2
      3 :(before "End Initialize Op Names")
      4 put_new(Name, "01", "add r32 to rm32 (add)");
      5
      6 :(scenario add_r32_to_r32)
      7 % Reg[EAX].i = 0x10;
      8 % Reg[EBX].i = 1;
      9 == 0x1
     10 # op  ModR/M  SIB   displacement  immediate
     11   01  d8                                      # add EBX to EAX
     12 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
     13 +run: add EBX to r/m32
     14 +run: r/m32 is EAX
     15 +run: storing 0x00000011
     16
     17 :(before "End Single-Byte Opcodes")
     18 case 0x01: {  // add r32 to r/m32
     19   uint8_t modrm = next();
     20   uint8_t arg2 = (modrm>>3)&0x7;
     21   trace(90, "run") << "add " << rname(arg2) << " to r/m32" << end();
     22   int32_t* arg1 = effective_address(modrm);
     23   BINARY_ARITHMETIC_OP(+, *arg1, Reg[arg2].i);
     24   break;
     25 }
     26
     27 :(code)
     28 // Implement tables 2-2 and 2-3 in the Intel manual, Volume 2.
     29 // We return a pointer so that instructions can write to multiple bytes in
     30 // 'Mem' at once.
     31 int32_t* effective_address(uint8_t modrm) {
     32   const uint8_t mod = (modrm>>6);
     33   // ignore middle 3 'reg opcode' bits
     34   const uint8_t rm = modrm & 0x7;
     35   if (mod == 3) {
     36     // mod 3 is just register direct addressing
     37     trace(90, "run") << "r/m32 is " << rname(rm) << end();
     38     return &Reg[rm].i;
     39   }
     40   return mem_addr_i32(effective_address_number(modrm));
     41 }
     42
     43 uint32_t effective_address_number(uint8_t modrm) {
     44   const uint8_t mod = (modrm>>6);
     45   // ignore middle 3 'reg opcode' bits
     46   const uint8_t rm = modrm & 0x7;
     47   uint32_t addr = 0;
     48   switch (mod) {
     49   case 3:
     50     // mod 3 is just register direct addressing
     51     raise << "unexpected direct addressing mode\n" << end();
     52     return 0;
     53   // End Mod Special-cases(addr)
     54   default:
     55     cerr << "unrecognized mod bits: " << NUM(mod) << '\n';
     56     exit(1);
     57   }
     58   //: other mods are indirect, and they'll set addr appropriately
     59   return addr;
     60 }
     61
     62 string rname(uint8_t r) {
     63   switch (r) {
     64   case 0: return "EAX";
     65   case 1: return "ECX";
     66   case 2: return "EDX";
     67   case 3: return "EBX";
     68   case 4: return "ESP";
     69   case 5: return "EBP";
     70   case 6: return "ESI";
     71   case 7: return "EDI";
     72   default: raise << "invalid register " << r << '\n' << end();  return "";
     73   }
     74 }
     75
     76 //:: subtract
     77
     78 :(before "End Initialize Op Names")
     79 put_new(Name, "29", "subtract r32 from rm32 (sub)");
     80
     81 :(scenario subtract_r32_from_r32)
     82 % Reg[EAX].i = 10;
     83 % Reg[EBX].i = 1;
     84 == 0x1
     85 # op  ModR/M  SIB   displacement  immediate
     86   29  d8                                      # subtract EBX from EAX
     87 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
     88 +run: subtract EBX from r/m32
     89 +run: r/m32 is EAX
     90 +run: storing 0x00000009
     91
     92 :(before "End Single-Byte Opcodes")
     93 case 0x29: {  // subtract r32 from r/m32
     94   const uint8_t modrm = next();
     95   const uint8_t arg2 = (modrm>>3)&0x7;
     96   trace(90, "run") << "subtract " << rname(arg2) << " from r/m32" << end();
     97   int32_t* arg1 = effective_address(modrm);
     98   BINARY_ARITHMETIC_OP(-, *arg1, Reg[arg2].i);
     99   break;
    100 }
    101
    102 //:: multiply
    103
    104 :(before "End Initialize Op Names")
    105 put_new(Name, "f7", "negate/multiply rm32 (with EAX if necessary) depending on subop (neg/mul)");
    106
    107 :(scenario multiply_eax_by_r32)
    108 % Reg[EAX].i = 4;
    109 % Reg[ECX].i = 3;
    110 == 0x1
    111 # op      ModR/M  SIB   displacement  immediate
    112   f7      e1                                      # multiply EAX by ECX
    113 # ModR/M in binary: 11 (direct mode) 100 (subop mul) 001 (src ECX)
    114 +run: operate on r/m32
    115 +run: r/m32 is ECX
    116 +run: subop: multiply EAX by r/m32
    117 +run: storing 0x0000000c
    118
    119 :(before "End Single-Byte Opcodes")
    120 case 0xf7: {  // xor r32 with r/m32
    121   const uint8_t modrm = next();
    122   trace(90, "run") << "operate on r/m32" << end();
    123   int32_t* arg1 = effective_address(modrm);
    124   const uint8_t subop = (modrm>>3)&0x7;  // middle 3 'reg opcode' bits
    125   switch (subop) {
    126   case 4: {  // mul unsigned EAX by r/m32
    127     trace(90, "run") << "subop: multiply EAX by r/m32" << end();
    128     const uint64_t result = Reg[EAX].u * static_cast<uint32_t>(*arg1);
    129     Reg[EAX].u = result & 0xffffffff;
    130     Reg[EDX].u = result >> 32;
    131     OF = (Reg[EDX].u != 0);
    132     trace(90, "run") << "storing 0x" << HEXWORD << Reg[EAX].u << end();
    133     break;
    134   }
    135   // End Op f7 Subops
    136   default:
    137     cerr << "unrecognized sub-opcode after f7: " << NUM(subop) << '\n';
    138     exit(1);
    139   }
    140   break;
    141 }
    142
    143 //:
    144
    145 :(before "End Initialize Op Names")
    146 put_new(Name_0f, "af", "multiply rm32 into r32 (imul)");
    147
    148 :(scenario multiply_r32_into_r32)
    149 % Reg[EAX].i = 4;
    150 % Reg[EBX].i = 2;
    151 == 0x1
    152 # op      ModR/M  SIB   displacement  immediate
    153   0f af   d8                                      # subtract EBX into EAX
    154 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
    155 +run: multiply r/m32 into EBX
    156 +run: r/m32 is EAX
    157 +run: storing 0x00000008
    158
    159 :(before "End Two-Byte Opcodes Starting With 0f")
    160 case 0xaf: {  // multiply r32 into r/m32
    161   const uint8_t modrm = next();
    162   const uint8_t arg2 = (modrm>>3)&0x7;
    163   trace(90, "run") << "multiply r/m32 into " << rname(arg2) << end();
    164   const int32_t* arg1 = effective_address(modrm);
    165   BINARY_ARITHMETIC_OP(*, Reg[arg2].i, *arg1);
    166   break;
    167 }
    168
    169 //:: negate
    170
    171 :(scenario negate_r32)
    172 % Reg[EBX].i = 1;
    173 == 0x1
    174 # op  ModR/M  SIB   displacement  immediate
    175   f7  db                                      # negate EBX
    176 # ModR/M in binary: 11 (direct mode) 011 (subop negate) 011 (dest EBX)
    177 +run: operate on r/m32
    178 +run: r/m32 is EBX
    179 +run: subop: negate
    180 +run: storing 0xffffffff
    181
    182 :(before "End Op f7 Subops")
    183 case 3: {  // negate r/m32
    184   trace(90, "run") << "subop: negate" << end();
    185   // one case that can overflow
    186   if (static_cast<uint32_t>(*arg1) == 0x80000000) {
    187     trace(90, "run") << "overflow" << end();
    188     SF = true;
    189     ZF = false;
    190     OF = true;
    191     break;
    192   }
    193   *arg1 = -(*arg1);
    194   trace(90, "run") << "storing 0x" << HEXWORD << *arg1 << end();
    195   SF = (*arg1 >> 31);
    196   ZF = (*arg1 == 0);
    197   OF = false;
    198   break;
    199 }
    200
    201 :(scenario negate_can_overflow)  // in exactly one situation
    202 % Reg[EBX].i = 0x80000000;  // INT_MIN
    203 == 0x1
    204 # op  ModR/M  SIB   displacement  immediate
    205   f7  db                                      # negate EBX
    206 # ModR/M in binary: 11 (direct mode) 011 (subop negate) 011 (dest EBX)
    207 +run: operate on r/m32
    208 +run: r/m32 is EBX
    209 +run: subop: negate
    210 +run: overflow
    211
    212 //:: and
    213
    214 :(before "End Initialize Op Names")
    215 put_new(Name, "21", "rm32 = bitwise AND of r32 with rm32 (and)");
    216
    217 :(scenario and_r32_with_r32)
    218 % Reg[EAX].i = 0x0a0b0c0d;
    219 % Reg[EBX].i = 0x000000ff;
    220 == 0x1
    221 # op  ModR/M  SIB   displacement  immediate
    222   21  d8                                      # and EBX with destination EAX
    223 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
    224 +run: and EBX with r/m32
    225 +run: r/m32 is EAX
    226 +run: storing 0x0000000d
    227
    228 :(before "End Single-Byte Opcodes")
    229 case 0x21: {  // and r32 with r/m32
    230   const uint8_t modrm = next();
    231   const uint8_t arg2 = (modrm>>3)&0x7;
    232   trace(90, "run") << "and " << rname(arg2) << " with r/m32" << end();
    233   int32_t* arg1 = effective_address(modrm);
    234   BINARY_BITWISE_OP(&, *arg1, Reg[arg2].u);
    235   break;
    236 }
    237
    238 //:: or
    239
    240 :(before "End Initialize Op Names")
    241 put_new(Name, "09", "rm32 = bitwise OR of r32 with rm32 (or)");
    242
    243 :(scenario or_r32_with_r32)
    244 % Reg[EAX].i = 0x0a0b0c0d;
    245 % Reg[EBX].i = 0xa0b0c0d0;
    246 == 0x1
    247 # op  ModR/M  SIB   displacement  immediate
    248   09  d8                                      # or EBX with destination EAX
    249 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
    250 +run: or EBX with r/m32
    251 +run: r/m32 is EAX
    252 +run: storing 0xaabbccdd
    253
    254 :(before "End Single-Byte Opcodes")
    255 case 0x09: {  // or r32 with r/m32
    256   const uint8_t modrm = next();
    257   const uint8_t arg2 = (modrm>>3)&0x7;
    258   trace(90, "run") << "or " << rname(arg2) << " with r/m32" << end();
    259   int32_t* arg1 = effective_address(modrm);
    260   BINARY_BITWISE_OP(|, *arg1, Reg[arg2].u);
    261   break;
    262 }
    263
    264 //:: xor
    265
    266 :(before "End Initialize Op Names")
    267 put_new(Name, "31", "rm32 = bitwise XOR of r32 with rm32 (xor)");
    268
    269 :(scenario xor_r32_with_r32)
    270 % Reg[EAX].i = 0x0a0b0c0d;
    271 % Reg[EBX].i = 0xaabbc0d0;
    272 == 0x1
    273 # op  ModR/M  SIB   displacement  immediate
    274   31  d8                                      # xor EBX with destination EAX
    275 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
    276 +run: xor EBX with r/m32
    277 +run: r/m32 is EAX
    278 +run: storing 0xa0b0ccdd
    279
    280 :(before "End Single-Byte Opcodes")
    281 case 0x31: {  // xor r32 with r/m32
    282   const uint8_t modrm = next();
    283   const uint8_t arg2 = (modrm>>3)&0x7;
    284   trace(90, "run") << "xor " << rname(arg2) << " with r/m32" << end();
    285   int32_t* arg1 = effective_address(modrm);
    286   BINARY_BITWISE_OP(^, *arg1, Reg[arg2].u);
    287   break;
    288 }
    289
    290 //:: not
    291
    292 :(scenario not_r32)
    293 % Reg[EBX].i = 0x0f0f00ff;
    294 == 0x1
    295 # op  ModR/M  SIB   displacement  immediate
    296   f7  d3                                      # not EBX
    297 # ModR/M in binary: 11 (direct mode) 010 (subop not) 011 (dest EBX)
    298 +run: operate on r/m32
    299 +run: r/m32 is EBX
    300 +run: subop: not
    301 +run: storing 0xf0f0ff00
    302
    303 :(before "End Op f7 Subops")
    304 case 2: {  // not r/m32
    305   trace(90, "run") << "subop: not" << end();
    306   *arg1 = ~(*arg1);
    307   trace(90, "run") << "storing 0x" << HEXWORD << *arg1 << end();
    308   SF = (*arg1 >> 31);
    309   ZF = (*arg1 == 0);
    310   OF = false;
    311   break;
    312 }
    313
    314 //:: compare (cmp)
    315
    316 :(before "End Initialize Op Names")
    317 put_new(Name, "39", "compare: set SF if rm32 < r32 (cmp)");
    318
    319 :(scenario compare_r32_with_r32_greater)
    320 % Reg[EAX].i = 0x0a0b0c0d;
    321 % Reg[EBX].i = 0x0a0b0c07;
    322 == 0x1
    323 # op  ModR/M  SIB   displacement  immediate
    324   39  d8                                      # compare EBX with EAX
    325 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
    326 +run: compare EBX with r/m32
    327 +run: r/m32 is EAX
    328 +run: SF=0; ZF=0; OF=0
    329
    330 :(before "End Single-Byte Opcodes")
    331 case 0x39: {  // set SF if r/m32 < r32
    332   const uint8_t modrm = next();
    333   const uint8_t reg2 = (modrm>>3)&0x7;
    334   trace(90, "run") << "compare " << rname(reg2) << " with r/m32" << end();
    335   const int32_t* arg1 = effective_address(modrm);
    336   const int32_t arg2 = Reg[reg2].i;
    337   const int32_t tmp1 = *arg1 - arg2;
    338   SF = (tmp1 < 0);
    339   ZF = (tmp1 == 0);
    340   const int64_t tmp2 = *arg1 - arg2;
    341   OF = (tmp1 != tmp2);
    342   trace(90, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end();
    343   break;
    344 }
    345
    346 :(scenario compare_r32_with_r32_lesser)
    347 % Reg[EAX].i = 0x0a0b0c07;
    348 % Reg[EBX].i = 0x0a0b0c0d;
    349 == 0x1
    350 # op  ModR/M  SIB   displacement  immediate
    351   39  d8                                      # compare EBX with EAX
    352 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
    353 +run: compare EBX with r/m32
    354 +run: r/m32 is EAX
    355 +run: SF=1; ZF=0; OF=0
    356
    357 :(scenario compare_r32_with_r32_equal)
    358 % Reg[EAX].i = 0x0a0b0c0d;
    359 % Reg[EBX].i = 0x0a0b0c0d;
    360 == 0x1
    361 # op  ModR/M  SIB   displacement  immediate
    362   39  d8                                      # compare EBX with EAX
    363 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
    364 +run: compare EBX with r/m32
    365 +run: r/m32 is EAX
    366 +run: SF=0; ZF=1; OF=0
    367
    368 //:: copy (mov)
    369
    370 :(before "End Initialize Op Names")
    371 put_new(Name, "89", "copy r32 to rm32 (mov)");
    372
    373 :(scenario copy_r32_to_r32)
    374 % Reg[EBX].i = 0xaf;
    375 == 0x1
    376 # op  ModR/M  SIB   displacement  immediate
    377   89  d8                                      # copy EBX to EAX
    378 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
    379 +run: copy EBX to r/m32
    380 +run: r/m32 is EAX
    381 +run: storing 0x000000af
    382
    383 :(before "End Single-Byte Opcodes")
    384 case 0x89: {  // copy r32 to r/m32
    385   const uint8_t modrm = next();
    386   const uint8_t rsrc = (modrm>>3)&0x7;
    387   trace(90, "run") << "copy " << rname(rsrc) << " to r/m32" << end();
    388   int32_t* dest = effective_address(modrm);
    389   *dest = Reg[rsrc].i;
    390   trace(90, "run") << "storing 0x" << HEXWORD << *dest << end();
    391   break;
    392 }
    393
    394 //:: xchg
    395
    396 :(before "End Initialize Op Names")
    397 put_new(Name, "87", "swap the contents of r32 and rm32 (xchg)");
    398
    399 :(scenario xchg_r32_with_r32)
    400 % Reg[EBX].i = 0xaf;
    401 % Reg[EAX].i = 0x2e;
    402 == 0x1
    403 # op  ModR/M  SIB   displacement  immediate
    404   87  d8                                      # exchange EBX with EAX
    405 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
    406 +run: exchange EBX with r/m32
    407 +run: r/m32 is EAX
    408 +run: storing 0x000000af in r/m32
    409 +run: storing 0x0000002e in EBX
    410
    411 :(before "End Single-Byte Opcodes")
    412 case 0x87: {  // exchange r32 with r/m32
    413   const uint8_t modrm = next();
    414   const uint8_t reg2 = (modrm>>3)&0x7;
    415   trace(90, "run") << "exchange " << rname(reg2) << " with r/m32" << end();
    416   int32_t* arg1 = effective_address(modrm);
    417   const int32_t tmp = *arg1;
    418   *arg1 = Reg[reg2].i;
    419   Reg[reg2].i = tmp;
    420   trace(90, "run") << "storing 0x" << HEXWORD << *arg1 << " in r/m32" << end();
    421   trace(90, "run") << "storing 0x" << HEXWORD << Reg[reg2].i << " in " << rname(reg2) << end();
    422   break;
    423 }
    424
    425 //:: increment
    426
    427 :(before "End Initialize Op Names")
    428 put_new(Name, "40", "increment EAX (inc)");
    429 put_new(Name, "41", "increment ECX (inc)");
    430 put_new(Name, "42", "increment EDX (inc)");
    431 put_new(Name, "43", "increment EBX (inc)");
    432 put_new(Name, "44", "increment ESP (inc)");
    433 put_new(Name, "45", "increment EBP (inc)");
    434 put_new(Name, "46", "increment ESI (inc)");
    435 put_new(Name, "47", "increment EDI (inc)");
    436
    437 :(scenario increment_r32)
    438 % Reg[ECX].u = 0x1f;
    439 == 0x1  # code segment
    440 # op  ModR/M  SIB   displacement  immediate
    441   41                                          # increment ECX
    442 +run: increment ECX
    443 +run: storing value 0x00000020
    444
    445 :(before "End Single-Byte Opcodes")
    446 case 0x40:
    447 case 0x41:
    448 case 0x42:
    449 case 0x43:
    450 case 0x44:
    451 case 0x45:
    452 case 0x46:
    453 case 0x47: {  // increment r32
    454   const uint8_t reg = op & 0x7;
    455   trace(90, "run") << "increment " << rname(reg) << end();
    456   ++Reg[reg].u;
    457   trace(90, "run") << "storing value 0x" << HEXWORD << Reg[reg].u << end();
    458   break;
    459 }
    460
    461 :(before "End Initialize Op Names")
    462 put_new(Name, "ff", "increment/decrement/jump/push/call rm32 based on subop (inc/dec/jmp/push/call)");
    463
    464 :(scenario increment_rm32)
    465 % Reg[EAX].u = 0x20;
    466 == 0x1  # code segment
    467 # op  ModR/M  SIB   displacement  immediate
    468   ff  c0                                      # increment EAX
    469 # ModR/M in binary: 11 (direct mode) 000 (subop inc) 000 (EAX)
    470 +run: increment r/m32
    471 +run: r/m32 is EAX
    472 +run: storing value 0x00000021
    473
    474 :(before "End Single-Byte Opcodes")
    475 case 0xff: {
    476   const uint8_t modrm = next();
    477   const uint8_t subop = (modrm>>3)&0x7;  // middle 3 'reg opcode' bits
    478   switch (subop) {
    479     case 0: {  // increment r/m32
    480       trace(90, "run") << "increment r/m32" << end();
    481       int32_t* arg = effective_address(modrm);
    482       ++*arg;
    483       trace(90, "run") << "storing value 0x" << HEXWORD << *arg << end();
    484       break;
    485     }
    486     default:
    487       cerr << "unrecognized subop for ff: " << HEXBYTE << NUM(subop) << '\n';
    488       DUMP("");
    489       exit(1);
    490     // End Op ff Subops
    491   }
    492   break;
    493 }
    494
    495 //:: decrement
    496
    497 :(before "End Initialize Op Names")
    498 put_new(Name, "48", "decrement EAX (dec)");
    499 put_new(Name, "49", "decrement ECX (dec)");
    500 put_new(Name, "4a", "decrement EDX (dec)");
    501 put_new(Name, "4b", "decrement EBX (dec)");
    502 put_new(Name, "4c", "decrement ESP (dec)");
    503 put_new(Name, "4d", "decrement EBP (dec)");
    504 put_new(Name, "4e", "decrement ESI (dec)");
    505 put_new(Name, "4f", "decrement EDI (dec)");
    506
    507 :(scenario decrement_r32)
    508 % Reg[ECX].u = 0x1f;
    509 == 0x1  # code segment
    510 # op  ModR/M  SIB   displacement  immediate
    511   49                                          # decrement ECX
    512 +run: decrement ECX
    513 +run: storing value 0x0000001e
    514
    515 :(before "End Single-Byte Opcodes")
    516 case 0x48:
    517 case 0x49:
    518 case 0x4a:
    519 case 0x4b:
    520 case 0x4c:
    521 case 0x4d:
    522 case 0x4e:
    523 case 0x4f: {  // decrement r32
    524   const uint8_t reg = op & 0x7;
    525   trace(90, "run") << "decrement " << rname(reg) << end();
    526   --Reg[reg].u;
    527   trace(90, "run") << "storing value 0x" << HEXWORD << Reg[reg].u << end();
    528   break;
    529 }
    530
    531 :(scenario decrement_rm32)
    532 % Reg[EAX].u = 0x20;
    533 == 0x1  # code segment
    534 # op  ModR/M  SIB   displacement  immediate
    535   ff  c8                                      # decrement EAX
    536 # ModR/M in binary: 11 (direct mode) 001 (subop inc) 000 (EAX)
    537 +run: decrement r/m32
    538 +run: r/m32 is EAX
    539 +run: storing value 0x0000001f
    540
    541 :(before "End Op ff Subops")
    542 case 1: {  // decrement r/m32
    543   trace(90, "run") << "decrement r/m32" << end();
    544   int32_t* arg = effective_address(modrm);
    545   --*arg;
    546   trace(90, "run") << "storing value 0x" << HEXWORD << *arg << end();
    547   break;
    548 }
    549
    550 //:: push
    551
    552 :(before "End Initialize Op Names")
    553 put_new(Name, "50", "push EAX to stack (push)");
    554 put_new(Name, "51", "push ECX to stack (push)");
    555 put_new(Name, "52", "push EDX to stack (push)");
    556 put_new(Name, "53", "push EBX to stack (push)");
    557 put_new(Name, "54", "push ESP to stack (push)");
    558 put_new(Name, "55", "push EBP to stack (push)");
    559 put_new(Name, "56", "push ESI to stack (push)");
    560 put_new(Name, "57", "push EDI to stack (push)");
    561
    562 :(scenario push_r32)
    563 % Reg[ESP].u = 0x64;
    564 % Reg[EBX].i = 0x0000000a;
    565 == 0x1
    566 # op  ModR/M  SIB   displacement  immediate
    567   53                                          # push EBX to stack
    568 +run: push EBX
    569 +run: decrementing ESP to 0x00000060
    570 +run: pushing value 0x0000000a
    571
    572 :(before "End Single-Byte Opcodes")
    573 case 0x50:
    574 case 0x51:
    575 case 0x52:
    576 case 0x53:
    577 case 0x54:
    578 case 0x55:
    579 case 0x56:
    580 case 0x57: {  // push r32 to stack
    581   uint8_t reg = op & 0x7;
    582   trace(90, "run") << "push " << rname(reg) << end();
    583 //?   cerr << "push: " << NUM(reg) << ": " << Reg[reg].u << " => " << Reg[ESP].u << '\n';
    584   push(Reg[reg].u);
    585   break;
    586 }
    587
    588 //:: pop
    589
    590 :(before "End Initialize Op Names")
    591 put_new(Name, "58", "pop top of stack to EAX (pop)");
    592 put_new(Name, "59", "pop top of stack to ECX (pop)");
    593 put_new(Name, "5a", "pop top of stack to EDX (pop)");
    594 put_new(Name, "5b", "pop top of stack to EBX (pop)");
    595 put_new(Name, "5c", "pop top of stack to ESP (pop)");
    596 put_new(Name, "5d", "pop top of stack to EBP (pop)");
    597 put_new(Name, "5e", "pop top of stack to ESI (pop)");
    598 put_new(Name, "5f", "pop top of stack to EDI (pop)");
    599
    600 :(scenario pop_r32)
    601 % Reg[ESP].u = 0x2000;
    602 % Mem.push_back(vma(0x2000));  // manually allocate memory
    603 % write_mem_i32(0x2000, 0x0000000a);  // ..before this write
    604 == 0x1  # code segment
    605 # op  ModR/M  SIB   displacement  immediate
    606   5b                                          # pop stack to EBX
    607 == 0x2000  # data segment
    608 0a 00 00 00  # 0x0a
    609 +run: pop into EBX
    610 +run: popping value 0x0000000a
    611 +run: incrementing ESP to 0x00002004
    612
    613 :(before "End Single-Byte Opcodes")
    614 case 0x58:
    615 case 0x59:
    616 case 0x5a:
    617 case 0x5b:
    618 case 0x5c:
    619 case 0x5d:
    620 case 0x5e:
    621 case 0x5f: {  // pop stack into r32
    622   const uint8_t reg = op & 0x7;
    623   trace(90, "run") << "pop into " << rname(reg) << end();
    624 //?   cerr << "pop from " << Reg[ESP].u << '\n';
    625   Reg[reg].u = pop();
    626 //?   cerr << "=> " << NUM(reg) << ": " << Reg[reg].u << '\n';
    627   break;
    628 }
    629 :(code)
    630 uint32_t pop() {
    631   const uint32_t result = read_mem_u32(Reg[ESP].u);
    632   trace(90, "run") << "popping value 0x" << HEXWORD << result << end();
    633   Reg[ESP].u += 4;
    634   trace(90, "run") << "incrementing ESP to 0x" << HEXWORD << Reg[ESP].u << end();
    635   return result;
    636 }