https://github.com/akkartik/mu/blob/master/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   // Found effective_address(addr)
 60   return addr;
 61 }
 62 
 63 string rname(uint8_t r) {
 64   switch (r) {
 65   case 0: return "EAX";
 66   case 1: return "ECX";
 67   case 2: return "EDX";
 68   case 3: return "EBX";
 69   case 4: return "ESP";
 70   case 5: return "EBP";
 71   case 6: return "ESI";
 72   case 7: return "EDI";
 73   default: raise << "invalid register " << r << '\n' << end();  return "";
 74   }
 75 }
 76 
 77 //:: subtract
 78 
 79 :(before "End Initialize Op Names")
 80 put_new(Name, "29", "subtract r32 from rm32 (sub)");
 81 
 82 :(scenario subtract_r32_from_r32)
 83 % Reg[EAX].i = 10;
 84 % Reg[EBX].i = 1;
 85 == 0x1
 86 # op  ModR/M  SIB   displacement  immediate
 87   29  d8                                      # subtract EBX from EAX
 88 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
 89 +run: subtract EBX from r/m32
 90 +run: r/m32 is EAX
 91 +run: storing 0x00000009
 92 
 93 :(before "End Single-Byte Opcodes")
 94 case 0x29: {  // subtract r32 from r/m32
 95   const uint8_t modrm = next();
 96   const uint8_t arg2 = (modrm>>3)&0x7;
 97   trace(90, "run") << "subtract " << rname(arg2) << " from r/m32" << end();
 98   int32_t* arg1 = effective_address(modrm);
 99   BINARY_ARITHMETIC_OP(-, *arg1, Reg[arg2].i);
100   break;
101 }
102 
103 //:: multiply
104 
105 :(before "End Initialize Op Names")
106 put_new(Name, "f7", "negate/multiply rm32 (with EAX if necessary) depending on subop (neg/mul)");
107 
108 :(scenario multiply_eax_by_r32)
109 % Reg[EAX].i = 4;
110 % Reg[ECX].i = 3;
111 == 0x1
112 # op      ModR/M  SIB   displacement  immediate
113   f7      e1                                      # multiply EAX by ECX
114 # ModR/M in binary: 11 (direct mode) 100 (subop mul) 001 (src ECX)
115 +run: operate on r/m32
116 +run: r/m32 is ECX
117 +run: subop: multiply EAX by r/m32
118 +run: storing 0x0000000c
119 
120 :(before "End Single-Byte Opcodes")
121 case 0xf7: {
122   const uint8_t modrm = next();
123   trace(90, "run") << "operate on r/m32" << end();
124   int32_t* arg1 = effective_address(modrm);
125   const uint8_t subop = (modrm>>3)&0x7;  // middle 3 'reg opcode' bits
126   switch (subop) {
127   case 4: {  // mul unsigned EAX by r/m32
128     trace(90, "run") << "subop: multiply EAX by r/m32" << end();
129     const uint64_t result = Reg[EAX].u * static_cast<uint32_t>(*arg1);
130     Reg[EAX].u = result & 0xffffffff;
131     Reg[EDX].u = result >> 32;
132     OF = (Reg[EDX].u != 0);
133     trace(90, "run") << "storing 0x" << HEXWORD << Reg[EAX].u << end();
134     break;
135   }
136   // End Op f7 Subops
137   default:
138     cerr << "unrecognized subop for opcode f7: " << NUM(subop) << '\n';
139     exit(1);
140   }
141   break;
142 }
143 
144 //:
145 
146 :(before "End Initialize Op Names")
147 put_new(Name_0f, "af", "multiply rm32 into r32 (imul)");
148 
149 :(scenario multiply_r32_into_r32)
150 % Reg[EAX].i = 4;
151 % Reg[EBX].i = 2;
152 == 0x1
153 # op      ModR/M  SIB   displacement  immediate
154   0f af   d8                                      # subtract EBX into EAX
155 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
156 +run: multiply r/m32 into EBX
157 +run: r/m32 is EAX
158 +run: storing 0x00000008
159 
160 :(before "End Two-Byte Opcodes Starting With 0f")
161 case 0xaf: {  // multiply r32 into r/m32
162   const uint8_t modrm = next();
163   const uint8_t arg2 = (modrm>>3)&0x7;
164   trace(90, "run") << "multiply r/m32 into " << rname(arg2) << end();
165   const int32_t* arg1 = effective_address(modrm);
166   BINARY_ARITHMETIC_OP(*, Reg[arg2].i, *arg1);
167   break;
168 }
169 
170 //:: negate
171 
172 :(scenario negate_r32)
173 % Reg[EBX].i = 1;
174 == 0x1
175 # op  ModR/M  SIB   displacement  immediate
176   f7  db                                      # negate EBX
177 # ModR/M in binary: 11 (direct mode) 011 (subop negate) 011 (dest EBX)
178 +run: operate on r/m32
179 +run: r/m32 is EBX
180 +run: subop: negate
181 +run: storing 0xffffffff
182 
183 :(before "End Op f7 Subops")
184 case 3: {  // negate r/m32
185   trace(90, "run") << "subop: negate" << end();
186   // one case that can overflow
187   if (static_cast<uint32_t>(*arg1) == 0x80000000) {
188     trace(90, "run") << "overflow" << end();
189     SF = true;
190     ZF = false;
191     OF = true;
192     break;
193   }
194   *arg1 = -(*arg1);
195   trace(90, "run") << "storing 0x" << HEXWORD << *arg1 << end();
196   SF = (*arg1 >> 31);
197   ZF = (*arg1 == 0);
198   OF = false;
199   break;
200 }
201 
202 :(scenario negate_can_overflow)  // in exactly one situation
203 % Reg[EBX].i = 0x80000000;  // INT_MIN
204 == 0x1
205 # op  ModR/M  SIB   displacement  immediate
206   f7  db                                      # negate EBX
207 # ModR/M in binary: 11 (direct mode) 011 (subop negate) 011 (dest EBX)
208 +run: operate on r/m32
209 +run: r/m32 is EBX
210 +run: subop: negate
211 +run: overflow
212 
213 //:: shift left
214 
215 :(before "End Initialize Op Names")
216 put_new(Name, "d3", "shift rm32 by CL bits depending on subop (sal/sar/shl/shr)");
217 
218 :(scenario shift_left_r32_with_cl)
219 % Reg[EBX].i = 13;
220 % Reg[ECX].i = 1;
221 == 0x1
222 # op  ModR/M  SIB   displacement  immediate
223   d3  e3                                      # negate EBX
224 # ModR/M in binary: 11 (direct mode) 100 (subop shift left) 011 (dest EBX)
225 +run: operate on r/m32
226 +run: r/m32 is EBX
227 +run: subop: shift left by CL bits
228 +run: storing 0x0000001a
229 
230 :(before "End Single-Byte Opcodes")
231 case 0xd3: {
232   const uint8_t modrm = next();
233   trace(90, "run") << "operate on r/m32" << end();
234   int32_t* arg1 = effective_address(modrm);
235   const uint8_t subop = (modrm>>3)&0x7;  // middle 3 'reg opcode' bits
236   switch (subop) {
237   case 4: {  // shift left r/m32 by CL
238     trace(90, "run") << "subop: shift left by CL bits" << end();
239     uint8_t count = Reg[ECX].u & 0x1f;
240     // OF is only defined if count is 1
241     if (count == 1) {
242       bool msb = (*arg1 & 0x80000000) >> 1;
243       bool pnsb = (*arg1 & 0x40000000);
244       OF = (msb != pnsb);
245     }
246     *arg1 = (*arg1 << count);
247     ZF = (*arg1 == 0);
248     SF = (*arg1 < 0);
249     trace(90, "run") << "storing 0x" << HEXWORD << *arg1 << end();
250     break;
251   }
252   // End Op d3 Subops
253   default:
254     cerr << "unrecognized subop for opcode d3: " << NUM(subop) << '\n';
255     exit(1);
256   }
257   break;
258 }
259 
260 //:: shift right arithmetic
261 
262 :(scenario shift_right_arithmetic_r32_with_cl)
263 % Reg[EBX].i = 26;
264 % Reg[ECX].i = 1;
265 == 0x1
266 # op  ModR/M  SIB   displacement  immediate
267   d3  fb                                      # negate EBX
268 # ModR/M in binary: 11 (direct mode) 111 (subop shift right arithmetic) 011 (dest EBX)
269 +run: operate on r/m32
270 +run: r/m32 is EBX
271 +run: subop: shift right by CL bits, while preserving sign
272 +run: storing 0x0000000d
273 
274 :(before "End Op d3 Subops")
275 case 7: {  // shift right r/m32 by CL, preserving sign
276   trace(90, "run") << "subop: shift right by CL bits, while preserving sign" << end();
277   uint8_t count = Reg[ECX].u & 0x1f;
278   *arg1 = (*arg1 >> count);
279   ZF = (*arg1 == 0);
280   SF = (*arg1 < 0);
281   // OF is only defined if count is 1
282   if (count == 1) OF = false;
283   trace(90, "run") << "storing 0x" << HEXWORD << *arg1 << end();
284   break;
285 }
286 
287 :(scenario shift_right_arithmetic_odd_r32_with_cl)
288 % Reg[EBX].i = 27;
289 % Reg[ECX].i = 1;
290 == 0x1
291 # op  ModR/M  SIB   displacement  immediate
292   d3  fb                                      # negate EBX
293 # ModR/M in binary: 11 (direct mode) 111 (subop shift right arithmetic) 011 (dest EBX)
294 +run: operate on r/m32
295 +run: r/m32 is EBX
296 +run: subop: shift right by CL bits, while preserving sign
297 # result: 13
298 +run: storing 0x0000000d
299 
300 :(scenario shift_right_arithmetic_negative_r32_with_cl)
301 % Reg[EBX].i = 0xfffffffd;  // -3
302 % Reg[ECX].i = 1;
303 == 0x1
304 # op  ModR/M  SIB   displacement  immediate
305   d3  fb                                      # negate EBX
306 # ModR/M in binary: 11 (direct mode) 111 (subop shift right arithmetic) 011 (dest EBX)
307 +run: operate on r/m32
308 +run: r/m32 is EBX
309 +run: subop: shift right by CL bits, while preserving sign
310 # result: -2
311 +run: storing 0xfffffffe
312 
313 //:: shift right logical
314 
315 :(scenario shift_right_logical_r32_with_cl)
316 % Reg[EBX].i = 26;
317 % Reg[ECX].i = 1;
318 == 0x1
319 # op  ModR/M  SIB   displacement  immediate
320   d3  eb                                      # negate EBX
321 # ModR/M in binary: 11 (direct mode) 101 (subop shift right logical) 011 (dest EBX)
322 +run: operate on r/m32
323 +run: r/m32 is EBX
324 +run: subop: shift right by CL bits, while padding zeroes
325 +run: storing 0x0000000d
326 
327 :(before "End Op d3 Subops")
328 case 5: {  // shift right r/m32 by CL, preserving sign
329   trace(90, "run") << "subop: shift right by CL bits, while padding zeroes" << end();
330   uint8_t count = Reg[ECX].u & 0x1f;
331   // OF is only defined if count is 1
332   if (count == 1) {
333     bool msb = (*arg1 & 0x80000000) >> 1;
334     bool pnsb = (*arg1 & 0x40000000);
335     OF = (msb != pnsb);
336   }
337   uint32_t* uarg1 = reinterpret_cast<uint32_t*>(arg1);
338   *uarg1 = (*uarg1 >> count);
339   ZF = (*uarg1 == 0);
340   // result is always positive by definition
341   SF = false;
342   trace(90, "run") << "storing 0x" << HEXWORD << *arg1 << end();
343   break;
344 }
345 
346 :(scenario shift_right_logical_odd_r32_with_cl)
347 % Reg[EBX].i = 27;
348 % Reg[ECX].i = 1;
349 == 0x1
350 # op  ModR/M  SIB   displacement  immediate
351   d3  eb                                      # negate EBX
352 # ModR/M in binary: 11 (direct mode) 101 (subop shift right logical) 011 (dest EBX)
353 +run: operate on r/m32
354 +run: r/m32 is EBX
355 +run: subop: shift right by CL bits, while padding zeroes
356 # result: 13
357 +run: storing 0x0000000d
358 
359 :(scenario shift_right_logical_negative_r32_with_cl)
360 % Reg[EBX].i = 0xfffffffd;
361 % Reg[ECX].i = 1;
362 == 0x1
363 # op  ModR/M  SIB   displacement  immediate
364   d3  eb                                      # negate EBX
365 # ModR/M in binary: 11 (direct mode) 101 (subop shift right logical) 011 (dest EBX)
366 +run: operate on r/m32
367 +run: r/m32 is EBX
368 +run: subop: shift right by CL bits, while padding zeroes
369 +run: storing 0x7ffffffe
370 
371 //:: and
372 
373 :(before "End Initialize Op Names")
374 put_new(Name, "21", "rm32 = bitwise AND of r32 with rm32 (and)");
375 
376 :(scenario and_r32_with_r32)
377 % Reg[EAX].i = 0x0a0b0c0d;
378 % Reg[EBX].i = 0x000000ff;
379 == 0x1
380 # op  ModR/M  SIB   displacement  immediate
381   21  d8                                      # and EBX with destination EAX
382 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
383 +run: and EBX with r/m32
384 +run: r/m32 is EAX
385 +run: storing 0x0000000d
386 
387 :(before "End Single-Byte Opcodes")
388 case 0x21: {  // and r32 with r/m32
389   const uint8_t modrm = next();
390   const uint8_t arg2 = (modrm>>3)&0x7;
391   trace(90, "run") << "and " << rname(arg2) << " with r/m32" << end();
392   int32_t* arg1 = effective_address(modrm);
393   BINARY_BITWISE_OP(&, *arg1, Reg[arg2].u);
394   break;
395 }
396 
397 //:: or
398 
399 :(before "End Initialize Op Names")
400 put_new(Name, "09", "rm32 = bitwise OR of r32 with rm32 (or)");
401 
402 :(scenario or_r32_with_r32)
403 % Reg[EAX].i = 0x0a0b0c0d;
404 % Reg[EBX].i = 0xa0b0c0d0;
405 == 0x1
406 # op  ModR/M  SIB   displacement  immediate
407   09  d8                                      # or EBX with destination EAX
408 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
409 +run: or EBX with r/m32
410 +run: r/m32 is EAX
411 +run: storing 0xaabbccdd
412 
413 :(before "End Single-Byte Opcodes")
414 case 0x09: {  // or r32 with r/m32
415   const uint8_t modrm = next();
416   const uint8_t arg2 = (modrm>>3)&0x7;
417   trace(90, "run") << "or " << rname(arg2) << " with r/m32" << end();
418   int32_t* arg1 = effective_address(modrm);
419   BINARY_BITWISE_OP(|, *arg1, Reg[arg2].u);
420   break;
421 }
422 
423 //:: xor
424 
425 :(before "End Initialize Op Names")
426 put_new(Name, "31", "rm32 = bitwise XOR of r32 with rm32 (xor)");
427 
428 :(scenario xor_r32_with_r32)
429 % Reg[EAX].i = 0x0a0b0c0d;
430 % Reg[EBX].i = 0xaabbc0d0;
431 == 0x1
432 # op  ModR/M  SIB   displacement  immediate
433   31  d8                                      # xor EBX with destination EAX
434 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
435 +run: xor EBX with r/m32
436 +run: r/m32 is EAX
437 +run: storing 0xa0b0ccdd
438 
439 :(before "End Single-Byte Opcodes")
440 case 0x31: {  // xor r32 with r/m32
441   const uint8_t modrm = next();
442   const uint8_t arg2 = (modrm>>3)&0x7;
443   trace(90, "run") << "xor " << rname(arg2) << " with r/m32" << end();
444   int32_t* arg1 = effective_address(modrm);
445   BINARY_BITWISE_OP(^, *arg1, Reg[arg2].u);
446   break;
447 }
448 
449 //:: not
450 
451 :(scenario not_r32)
452 % Reg[EBX].i = 0x0f0f00ff;
453 == 0x1
454 # op  ModR/M  SIB   displacement  immediate
455   f7  d3                                      # not EBX
456 # ModR/M in binary: 11 (direct mode) 010 (subop not) 011 (dest EBX)
457 +run: operate on r/m32
458 +run: r/m32 is EBX
459 +run: subop: not
460 +run: storing 0xf0f0ff00
461 
462 :(before "End Op f7 Subops")
463 case 2: {  // not r/m32
464   trace(90, "run") << "subop: not" << end();
465   *arg1 = ~(*arg1);
466   trace(90, "run") << "storing 0x" << HEXWORD << *arg1 << end();
467   SF = (*arg1 >> 31);
468   ZF = (*arg1 == 0);
469   OF = false;
470   break;
471 }
472 
473 //:: compare (cmp)
474 
475 :(before "End Initialize Op Names")
476 put_new(Name, "39", "compare: set SF if rm32 < r32 (cmp)");
477 
478 :(scenario compare_r32_with_r32_greater)
479 % Reg[EAX].i = 0x0a0b0c0d;
480 % Reg[EBX].i = 0x0a0b0c07;
481 == 0x1
482 # op  ModR/M  SIB   displacement  immediate
483   39  d8                                      # compare EBX with EAX
484 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
485 +run: compare EBX with r/m32
486 +run: r/m32 is EAX
487 +run: SF=0; ZF=0; OF=0
488 
489 :(before "End Single-Byte Opcodes")
490 case 0x39: {  // set SF if r/m32 < r32
491   const uint8_t modrm = next();
492   const uint8_t reg2 = (modrm>>3)&0x7;
493   trace(90, "run") << "compare " << rname(reg2) << " with r/m32" << end();
494   const int32_t* arg1 = effective_address(modrm);
495   const int32_t arg2 = Reg[reg2].i;
496   const int32_t tmp1 = *arg1 - arg2;
497   SF = (tmp1 < 0);
498   ZF = (tmp1 == 0);
499   const int64_t tmp2 = *arg1 - arg2;
500   OF = (tmp1 != tmp2);
501   trace(90, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end();
502   break;
503 }
504 
505 :(scenario compare_r32_with_r32_lesser)
506 % Reg[EAX].i = 0x0a0b0c07;
507 % Reg[EBX].i = 0x0a0b0c0d;
508 == 0x1
509 # op  ModR/M  SIB   displacement  immediate
510   39  d8                                      # compare EBX with EAX
511 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
512 +run: compare EBX with r/m32
513 +run: r/m32 is EAX
514 +run: SF=1; ZF=0; OF=0
515 
516 :(scenario compare_r32_with_r32_equal)
517 % Reg[EAX].i = 0x0a0b0c0d;
518 % Reg[EBX].i = 0x0a0b0c0d;
519 == 0x1
520 # op  ModR/M  SIB   displacement  immediate
521   39  d8                                      # compare EBX with EAX
522 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
523 +run: compare EBX with r/m32
524 +run: r/m32 is EAX
525 +run: SF=0; ZF=1; OF=0
526 
527 //:: copy (mov)
528 
529 :(before "End Initialize Op Names")
530 put_new(Name, "89", "copy r32 to rm32 (mov)");
531 
532 :(scenario copy_r32_to_r32)
533 % Reg[EBX].i = 0xaf;
534 == 0x1
535 # op  ModR/M  SIB   displacement  immediate
536   89  d8                                      # copy EBX to EAX
537 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
538 +run: copy EBX to r/m32
539 +run: r/m32 is EAX
540 +run: storing 0x000000af
541 
542 :(before "End Single-Byte Opcodes")
543 case 0x89: {  // copy r32 to r/m32
544   const uint8_t modrm = next();
545   const uint8_t rsrc = (modrm>>3)&0x7;
546   trace(90, "run") << "copy " << rname(rsrc) << " to r/m32" << end();
547   int32_t* dest = effective_address(modrm);
548   *dest = Reg[rsrc].i;
549   trace(90, "run") << "storing 0x" << HEXWORD << *dest << end();
550   break;
551 }
552 
553 //:: xchg
554 
555 :(before "End Initialize Op Names")
556 put_new(Name, "87", "swap the contents of r32 and rm32 (xchg)");
557 
558 :(scenario xchg_r32_with_r32)
559 % Reg[EBX].i = 0xaf;
560 % Reg[EAX].i = 0x2e;
561 == 0x1
562 # op  ModR/M  SIB   displacement  immediate
563   87  d8                                      # exchange EBX with EAX
564 # ModR/M in binary: 11 (direct mode) 011 (src EBX) 000 (dest EAX)
565 +run: exchange EBX with r/m32
566 +run: r/m32 is EAX
567 +run: storing 0x000000af in r/m32
568 +run: storing 0x0000002e in EBX
569 
570 :(before "End Single-Byte Opcodes")
571 case 0x87: {  // exchange r32 with r/m32
572   const uint8_t modrm = next();
573   const uint8_t reg2 = (modrm>>3)&0x7;
574   trace(90, "run") << "exchange " << rname(reg2) << " with r/m32" << end();
575   int32_t* arg1 = effective_address(modrm);
576   const int32_t tmp = *arg1;
577   *arg1 = Reg[reg2].i;
578   Reg[reg2].i = tmp;
579   trace(90, "run") << "storing 0x" << HEXWORD << *arg1 << " in r/m32" << end();
580   trace(90, "run") << "storing 0x" << HEXWORD << Reg[reg2].i << " in " << rname(reg2) << end();
581   break;
582 }
583 
584 //:: increment
585 
586 :(before "End Initialize Op Names")
587 put_new(Name, "40", "increment EAX (inc)");
588 put_new(Name, "41", "increment ECX (inc)");
589 put_new(Name, "42", "increment EDX (inc)");
590 put_new(Name, "43", "increment EBX (inc)");
591 put_new(Name, "44", "increment ESP (inc)");
592 put_new(Name, "45", "increment EBP (inc)");
593 put_new(Name, "46", "increment ESI (inc)");
594 put_new(Name, "47", "increment EDI (inc)");
595 
596 :(scenario increment_r32)
597 % Reg[ECX].u = 0x1f;
598 == 0x1  # code segment
599 # op  ModR/M  SIB   displacement  immediate
600   41                                          # increment ECX
601 +run: increment ECX
602 +run: storing value 0x00000020
603 
604 :(before "End Single-Byte Opcodes")
605 case 0x40:
606 case 0x41:
607 case 0x42:
608 case 0x43:
609 case 0x44:
610 case 0x45:
611 case 0x46:
612 case 0x47: {  // increment r32
613   const uint8_t reg = op & 0x7;
614   trace(90, "run") << "increment " << rname(reg) << end();
615   ++Reg[reg].u;
616   trace(90, "run") << "storing value 0x" << HEXWORD << Reg[reg].u << end();
617   break;
618 }
619 
620 :(before "End Initialize Op Names")
621 put_new(Name, "ff", "increment/decrement/jump/push/call rm32 based on subop (inc/dec/jmp/push/call)");
622 
623 :(scenario increment_rm32)
624 % Reg[EAX].u = 0x20;
625 == 0x1  # code segment
626 # op  ModR/M  SIB   displacement  immediate
627   ff  c0                                      # increment EAX
628 # ModR/M in binary: 11 (direct mode) 000 (subop inc) 000 (EAX)
629 +run: increment r/m32
630 +run: r/m32 is EAX
631 +run: storing value 0x00000021
632 
633 :(before "End Single-Byte Opcodes")
634 case 0xff: {
635   const uint8_t modrm = next();
636   const uint8_t subop = (modrm>>3)&0x7;  // middle 3 'reg opcode' bits
637   switch (subop) {
638     case 0: {  // increment r/m32
639       trace(90, "run") << "increment r/m32" << end();
640       int32_t* arg = effective_address(modrm);
641       ++*arg;
642       trace(90, "run") << "storing value 0x" << HEXWORD << *arg << end();
643       break;
644     }
645     default:
646       cerr << "unrecognized subop for ff: " << HEXBYTE << NUM(subop) << '\n';
647       DUMP("");
648       exit(1);
649     // End Op ff Subops
650   }
651   break;
652 }
653 
654 //:: decrement
655 
656 :(before "End Initialize Op Names")
657 put_new(Name, "48", "decrement EAX (dec)");
658 put_new(Name, "49", "decrement ECX (dec)");
659 put_new(Name, "4a", "decrement EDX (dec)");
660 put_new(Name, "4b", "decrement EBX (dec)");
661 put_new(Name, "4c", "decrement ESP (dec)");
662 put_new(Name, "4d", "decrement EBP (dec)");
663 put_new(Name, "4e", "decrement ESI (dec)");
664 put_new(Name, "4f", "decrement EDI (dec)");
665 
666 :(scenario decrement_r32)
667 % Reg[ECX].u = 0x1f;
668 == 0x1  # code segment
669 # op  ModR/M  SIB   displacement  immediate
670   49                                          # decrement ECX
671 +run: decrement ECX
672 +run: storing value 0x0000001e
673 
674 :(before "End Single-Byte Opcodes")
675 case 0x48:
676 case 0x49:
677 case 0x4a:
678 case 0x4b:
679 case 0x4c:
680 case 0x4d:
681 case 0x4e:
682 case 0x4f: {  // decrement r32
683   const uint8_t reg = op & 0x7;
684   trace(90, "run") << "decrement " << rname(reg) << end();
685   --Reg[reg].u;
686   trace(90, "run") << "storing value 0x" << HEXWORD << Reg[reg].u << end();
687   break;
688 }
689 
690 :(scenario decrement_rm32)
691 % Reg[EAX].u = 0x20;
692 == 0x1  # code segment
693 # op  ModR/M  SIB   displacement  immediate
694   ff  c8                                      # decrement EAX
695 # ModR/M in binary: 11 (direct mode) 001 (subop inc) 000 (EAX)
696 +run: decrement r/m32
697 +run: r/m32 is EAX
698 +run: storing value 0x0000001f
699 
700 :(before "End Op ff Subops")
701 case 1: {  // decrement r/m32
702   trace(90, "run") << "decrement r/m32" << end();
703   int32_t* arg = effective_address(modrm);
704   --*arg;
705   trace(90, "run") << "storing value 0x" << HEXWORD << *arg << end();
706   break;
707 }
708 
709 //:: push
710 
711 :(before "End Initialize Op Names")
712 put_new(Name, "50", "push EAX to stack (push)");
713 put_new(Name, "51", "push ECX to stack (push)");
714 put_new(Name, "52", "push EDX to stack (push)");
715 put_new(Name, "53", "push EBX to stack (push)");
716 put_new(Name, "54", "push ESP to stack (push)");
717 put_new(Name, "55", "push EBP to stack (push)");
718 put_new(Name, "56", "push ESI to stack (push)");
719 put_new(Name, "57", "push EDI to stack (push)");
720 
721 :(scenario push_r32)
722 % Reg[ESP].u = 0x64;
723 % Reg[EBX].i = 0x0000000a;
724 == 0x1
725 # op  ModR/M  SIB   displacement  immediate
726   53                                          # push EBX to stack
727 +run: push EBX
728 +run: decrementing ESP to 0x00000060
729 +run: pushing value 0x0000000a
730 
731 :(before "End Single-Byte Opcodes")
732 case 0x50:
733 case 0x51:
734 case 0x52:
735 case 0x53:
736 case 0x54:
737 case 0x55:
738 case 0x56:
739 case 0x57: {  // push r32 to stack
740   uint8_t reg = op & 0x7;
741   trace(90, "run") << "push " << rname(reg) << end();
742 //?   cerr << "push: " << NUM(reg) << ": " << Reg[reg].u << " => " << Reg[ESP].u << '\n';
743   push(Reg[reg].u);
744   break;
745 }
746 
747 //:: pop
748 
749 :(before "End Initialize Op Names")
750 put_new(Name, "58", "pop top of stack to EAX (pop)");
751 put_new(Name, "59", "pop top of stack to ECX (pop)");
752 put_new(Name, "5a", "pop top of stack to EDX (pop)");
753 put_new(Name, "5b", "pop top of stack to EBX (pop)");
754 put_new(Name, "5c", "pop top of stack to ESP (pop)");
755 put_new(Name, "5d", "pop top of stack to EBP (pop)");
756 put_new(Name, "5e", "pop top of stack to ESI (pop)");
757 put_new(Name, "5f", "pop top of stack to EDI (pop)");
758 
759 :(scenario pop_r32)
760 % Reg[ESP].u = 0x02000000;
761 % Mem.push_back(vma(0x02000000));  // manually allocate memory
762 % write_mem_i32(0x02000000, 0x0000000a);  // ..before this write
763 == 0x1  # code segment
764 # op  ModR/M  SIB   displacement  immediate
765   5b                                          # pop stack to EBX
766 == 0x2000  # data segment
767 0a 00 00 00  # 0x0a
768 +run: pop into EBX
769 +run: popping value 0x0000000a
770 +run: incrementing ESP to 0x02000004
771 
772 :(before "End Single-Byte Opcodes")
773 case 0x58:
774 case 0x59:
775 case 0x5a:
776 case 0x5b:
777 case 0x5c:
778 case 0x5d:
779 case 0x5e:
780 case 0x5f: {  // pop stack into r32
781   const uint8_t reg = op & 0x7;
782   trace(90, "run") << "pop into " << rname(reg) << end();
783 //?   cerr << "pop from " << Reg[ESP].u << '\n';
784   Reg[reg].u = pop();
785 //?   cerr << "=> " << NUM(reg) << ": " << Reg[reg].u << '\n';
786   break;
787 }
788 :(code)
789 uint32_t pop() {
790   const uint32_t result = read_mem_u32(Reg[ESP].u);
791   trace(90, "run") << "popping value 0x" << HEXWORD << result << end();
792   Reg[ESP].u += 4;
793   trace(90, "run") << "incrementing ESP to 0x" << HEXWORD << Reg[ESP].u << end();
794   return result;
795 }