1 //: instructions that (immediately) contain an argument to act with
  2 
  3 :(scenario add_imm32_to_r32)
  4 % Reg[3].i = 1;
  5 # op  ModRM   SIB   displacement  immediate
  6   81  c3                          0a 0b 0c 0d  # add 0x0d0c0b0a to EBX (reg 3)
  7 +run: combine imm32 0x0d0c0b0a with effective address
  8 +run: effective address is reg 3
  9 +run: subop add
 10 +run: storing 0x0d0c0b0b
 11 
 12 :(before "End Single-Byte Opcodes")
 13 case 0x81: {  // combine imm32 with r/m32
 14   uint8_t modrm = next();
 15   int32_t arg2 = imm32();
 16   trace(2, "run") << "combine imm32 0x" << HEXWORD << arg2 << " with effective address" << end();
 17   int32_t* arg1 = effective_address(modrm);
 18   uint8_t subop = (modrm>>3)&0x7;  // middle 3 'reg opcode' bits
 19   switch (subop) {
 20   case 0:
 21   ¦ trace(2, "run") << "subop add" << end();
 22   ¦ BINARY_ARITHMETIC_OP(+, *arg1, arg2);
 23   ¦ break;
 24   // End Op 81 Subops
 25   default:
 26   ¦ cerr << "unrecognized sub-opcode after 81: " << NUM(subop) << '\n';
 27   ¦ exit(1);
 28   }
 29   break;
 30 }
 31 
 32 //:
 33 
 34 :(scenario add_imm32_to_mem_at_r32)
 35 % Reg[3].i = 0x60;
 36 % SET_WORD_IN_MEM(0x60, 1);
 37 # op  ModR/M  SIB   displacement  immediate
 38   81  03                          0a 0b 0c 0d  # add 0x0d0c0b0a to *EBX (reg 3)
 39 +run: combine imm32 0x0d0c0b0a with effective address
 40 +run: effective address is mem at address 0x60 (reg 3)
 41 +run: subop add
 42 +run: storing 0x0d0c0b0b
 43 
 44 //:: subtract
 45 
 46 :(scenario subtract_imm32_from_eax)
 47 % Reg[EAX].i = 0x0d0c0baa;
 48 # op  ModR/M  SIB   displacement  immediate
 49   2d                              0a 0b 0c 0d  # subtract 0x0d0c0b0a from EAX (reg 0)
 50 +run: subtract imm32 0x0d0c0b0a from reg EAX
 51 +run: storing 0x000000a0
 52 
 53 :(before "End Single-Byte Opcodes")
 54 case 0x2d: {  // subtract imm32 from EAX
 55   int32_t arg2 = imm32();
 56   trace(2, "run") << "subtract imm32 0x" << HEXWORD << arg2 << " from reg EAX" << end();
 57   BINARY_ARITHMETIC_OP(-, Reg[EAX].i, arg2);
 58   break;
 59 }
 60 
 61 //:
 62 
 63 :(scenario subtract_imm32_from_mem_at_r32)
 64 % Reg[3].i = 0x60;
 65 % SET_WORD_IN_MEM(0x60, 10);
 66 # op  ModRM   SIB   displacement  immediate
 67   81  2b                          01 00 00 00  # subtract 1 from *EBX (reg 3)
 68 +run: combine imm32 0x00000001 with effective address
 69 +run: effective address is mem at address 0x60 (reg 3)
 70 +run: subop subtract
 71 +run: storing 0x00000009
 72 
 73 //:
 74 
 75 :(scenario subtract_imm32_from_r32)
 76 % Reg[3].i = 10;
 77 # op  ModRM   SIB   displacement  immediate
 78   81  eb                          01 00 00 00  # subtract 1 from EBX (reg 3)
 79 +run: combine imm32 0x00000001 with effective address
 80 +run: effective address is reg 3
 81 +run: subop subtract
 82 +run: storing 0x00000009
 83 
 84 :(before "End Op 81 Subops")
 85 case 5: {
 86   trace(2, "run") << "subop subtract" << end();
 87   BINARY_ARITHMETIC_OP(-, *arg1, arg2);
 88   break;
 89 }
 90 
 91 //:: and
 92 
 93 :(scenario and_imm32_with_eax)
 94 % Reg[EAX].i = 0xff;
 95 # op  ModR/M  SIB   displacement  immediate
 96   25                              0a 0b 0c 0d  # and 0x0d0c0b0a with EAX (reg 0)
 97 +run: and imm32 0x0d0c0b0a with reg EAX
 98 +run: storing 0x0000000a
 99 
100 :(before "End Single-Byte Opcodes")
101 case 0x25: {  // and imm32 with EAX
102   int32_t arg2 = imm32();
103   trace(2, "run") << "and imm32 0x" << HEXWORD << arg2 << " with reg EAX" << end();
104   BINARY_BITWISE_OP(&, Reg[EAX].i, arg2);
105   break;
106 }
107 
108 //:
109 
110 :(scenario and_imm32_with_mem_at_r32)
111 % Reg[3].i = 0x60;
112 % SET_WORD_IN_MEM(0x60, 0x000000ff);
113 # op  ModRM   SIB   displacement  immediate
114   81  23                          0a 0b 0c 0d  # and 0x0d0c0b0a with *EBX (reg 3)
115 +run: combine imm32 0x0d0c0b0a with effective address
116 +run: effective address is mem at address 0x60 (reg 3)
117 +run: subop and
118 +run: storing 0x0000000a
119 
120 //:
121 
122 :(scenario and_imm32_with_r32)
123 % Reg[3].i = 0xff;
124 # op  ModRM   SIB   displacement  immediate
125   81  e3                          0a 0b 0c 0d  # and 0x0d0c0b0a with EBX (reg 3)
126 +run: combine imm32 0x0d0c0b0a with effective address
127 +run: effective address is reg 3
128 +run: subop and
129 +run: storing 0x0000000a
130 
131 :(before "End Op 81 Subops")
132 case 4: {
133   trace(2, "run") << "subop and" << end();
134   BINARY_BITWISE_OP(&, *arg1, arg2);
135   break;
136 }
137 
138 //:: or
139 
140 :(scenario or_imm32_with_eax)
141 % Reg[EAX].i = 0xd0c0b0a0;
142 # op  ModR/M  SIB   displacement  immediate
143   0d                              0a 0b 0c 0d  # or 0x0d0c0b0a with EAX (reg 0)
144 +run: or imm32 0x0d0c0b0a with reg EAX
145 +run: storing 0xddccbbaa
146 
147 :(before "End Single-Byte Opcodes")
148 case 0x0d: {  // or imm32 with EAX
149   int32_t arg2 = imm32();
150   trace(2, "run") << "or imm32 0x" << HEXWORD << arg2 << " with reg EAX" << end();
151   BINARY_BITWISE_OP(|, Reg[EAX].i, arg2);
152   break;
153 }
154 
155 //:
156 
157 :(scenario or_imm32_with_mem_at_r32)
158 % Reg[3].i = 0x60;
159 % SET_WORD_IN_MEM(0x60, 0xd0c0b0a0);
160 # op  ModRM   SIB   displacement  immediate
161   81  0b                          0a 0b 0c 0d  # or 0x0d0c0b0a with *EBX (reg 3)
162 +run: combine imm32 0x0d0c0b0a with effective address
163 +run: effective address is mem at address 0x60 (reg 3)
164 +run: subop or
165 +run: storing 0xddccbbaa
166 
167 //:
168 
169 :(scenario or_imm32_with_r32)
170 % Reg[3].i = 0xd0c0b0a0;
171 # op  ModRM   SIB   displacement  immediate
172   81  cb                          0a 0b 0c 0d  # or 0x0d0c0b0a with EBX (reg 3)
173 +run: combine imm32 0x0d0c0b0a with effective address
174 +run: effective address is reg 3
175 +run: subop or
176 +run: storing 0xddccbbaa
177 
178 :(before "End Op 81 Subops")
179 case 1: {
180   trace(2, "run") << "subop or" << end();
181   BINARY_BITWISE_OP(|, *arg1, arg2);
182   break;
183 }
184 
185 //:: xor
186 
187 :(scenario xor_imm32_with_eax)
188 % Reg[EAX].i = 0xddccb0a0;
189 # op  ModR/M  SIB   displacement  immediate
190   35                              0a 0b 0c 0d  # xor 0x0d0c0b0a with EAX (reg 0)
191 +run: xor imm32 0x0d0c0b0a with reg EAX
192 +run: storing 0xd0c0bbaa
193 
194 :(before "End Single-Byte Opcodes")
195 case 0x35: {  // xor imm32 with EAX
196   int32_t arg2 = imm32();
197   trace(2, "run") << "xor imm32 0x" << HEXWORD << arg2 << " with reg EAX" << end();
198   BINARY_BITWISE_OP(^, Reg[EAX].i, arg2);
199   break;
200 }
201 
202 //:
203 
204 :(scenario xor_imm32_with_mem_at_r32)
205 % Reg[3].i = 0x60;
206 % SET_WORD_IN_MEM(0x60, 0xd0c0b0a0);
207 # op  ModRM   SIB   displacement  immediate
208   81  33                          0a 0b 0c 0d  # xor 0x0d0c0b0a with *EBX (reg 3)
209 +run: combine imm32 0x0d0c0b0a with effective address
210 +run: effective address is mem at address 0x60 (reg 3)
211 +run: subop xor
212 +run: storing 0xddccbbaa
213 
214 //:
215 
216 :(scenario xor_imm32_with_r32)
217 % Reg[3].i = 0xd0c0b0a0;
218 # op  ModRM   SIB   displacement  immediate
219   81  f3                          0a 0b 0c 0d  # xor 0x0d0c0b0a with EBX (reg 3)
220 +run: combine imm32 0x0d0c0b0a with effective address
221 +run: effective address is reg 3
222 +run: subop xor
223 +run: storing 0xddccbbaa
224 
225 :(before "End Op 81 Subops")
226 case 6: {
227   trace(2, "run") << "subop xor" << end();
228   BINARY_BITWISE_OP(^, *arg1, arg2);
229   break;
230 }
231 
232 //:: compare (cmp)
233 
234 :(scenario compare_imm32_with_eax_greater)
235 % Reg[0].i = 0x0d0c0b0a;
236 # op  ModRM   SIB   displacement  immediate
237   3d                              07 0b 0c 0d  # compare 0x0d0c0b07 with EAX (reg 0)
238 +run: compare reg EAX and imm32 0x0d0c0b07
239 +run: SF=0; ZF=0; OF=0
240 
241 :(before "End Single-Byte Opcodes")
242 case 0x3d: {  // subtract imm32 from EAX
243   int32_t arg1 = Reg[EAX].i;
244   int32_t arg2 = imm32();
245   trace(2, "run") << "compare reg EAX and imm32 0x" << HEXWORD << arg2 << end();
246   int32_t tmp1 = arg1 - arg2;
247   SF = (tmp1 < 0);
248   ZF = (tmp1 == 0);
249   int64_t tmp2 = arg1 - arg2;
250   OF = (tmp1 != tmp2);
251   trace(2, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end();
252   break;
253 }
254 
255 :(scenario compare_imm32_with_eax_lesser)
256 % Reg[0].i = 0x0d0c0b07;
257 # op  ModRM   SIB   displacement  immediate
258   3d                              0a 0b 0c 0d  # compare 0x0d0c0b0a with EAX (reg 0)
259 +run: compare reg EAX and imm32 0x0d0c0b0a
260 +run: SF=1; ZF=0; OF=0
261 
262 :(scenario compare_imm32_with_eax_equal)
263 % Reg[0].i = 0x0d0c0b0a;
264 # op  ModRM   SIB   displacement  immediate
265   3d                              0a 0b 0c 0d  # compare 0x0d0c0b0a with EAX (reg 0)
266 +run: compare reg EAX and imm32 0x0d0c0b0a
267 +run: SF=0; ZF=1; OF=0
268 
269 //:
270 
271 :(scenario compare_imm32_with_r32_greater)
272 % Reg[3].i = 0x0d0c0b0a;
273 # op  ModRM   SIB   displacement  immediate
274   81  fb                          07 0b 0c 0d  # compare 0x0d0c0b07 with EBX (reg 3)
275 +run: combine imm32 0x0d0c0b07 with effective address
276 +run: effective address is reg 3
277 +run: SF=0; ZF=0; OF=0
278 
279 :(before "End Op 81 Subops")
280 case 7: {
281   trace(2, "run") << "subop compare" << end();
282   int32_t tmp1 = *arg1 - arg2;
283   SF = (tmp1 < 0);
284   ZF = (tmp1 == 0);
285   int64_t tmp2 = *arg1 - arg2;
286   OF = (tmp1 != tmp2);
287   trace(2, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end();
288   break;
289 }
290 
291 :(scenario compare_imm32_with_r32_lesser)
292 % Reg[3].i = 0x0d0c0b07;
293 # op  ModRM   SIB   displacement  immediate
294   81  fb                          0a 0b 0c 0d  # compare 0x0d0c0b0a with EBX (reg 3)
295 +run: combine imm32 0x0d0c0b0a with effective address
296 +run: effective address is reg 3
297 +run: SF=1; ZF=0; OF=0
298 
299 :(scenario compare_imm32_with_r32_equal)
300 % Reg[3].i = 0x0d0c0b0a;
301 # op  ModRM   SIB   displacement  immediate
302   81  fb                          0a 0b 0c 0d  # compare 0x0d0c0b0a with EBX (reg 3)
303 +run: combine imm32 0x0d0c0b0a with effective address
304 +run: effective address is reg 3
305 +run: SF=0; ZF=1; OF=0
306 
307 :(scenario compare_imm32_with_mem_at_r32_greater)
308 % Reg[3].i = 0x60;
309 % SET_WORD_IN_MEM(0x60, 0x0d0c0b0a);
310 # op  ModRM   SIB   displacement  immediate
311   81  3b                          07 0b 0c 0d  # compare 0x0d0c0b07 with *EBX (reg 3)
312 +run: combine imm32 0x0d0c0b07 with effective address
313 +run: effective address is mem at address 0x60 (reg 3)
314 +run: SF=0; ZF=0; OF=0
315 
316 :(scenario compare_imm32_with_mem_at_r32_lesser)
317 % Reg[3].i = 0x60;
318 % SET_WORD_IN_MEM(0x60, 0x0d0c0b07);
319 # op  ModRM   SIB   displacement  immediate
320   81  3b                          0a 0b 0c 0d  # compare 0x0d0c0b0a with *EBX (reg 3)
321 +run: combine imm32 0x0d0c0b0a with effective address
322 +run: effective address is mem at address 0x60 (reg 3)
323 +run: SF=1; ZF=0; OF=0
324 
325 :(scenario compare_imm32_with_mem_at_r32_equal)
326 % Reg[3].i = 0x0d0c0b0a;
327 % Reg[3].i = 0x60;
328 % SET_WORD_IN_MEM(0x60, 0x0d0c0b0a);
329 # op  ModRM   SIB   displacement  immediate
330   81  3b                          0a 0b 0c 0d  # compare 0x0d0c0b0a with *EBX (reg 3)
331 +run: combine imm32 0x0d0c0b0a with effective address
332 +run: effective address is mem at address 0x60 (reg 3)
333 +run: SF=0; ZF=1; OF=0
334 
335 //:: copy (mov)
336 
337 :(scenario copy_imm32_to_r32)
338 # op  ModRM   SIB   displacement  immediate
339   b8  03                          0a 0b 0c 0d  # copy 0x0d0c0b0a to EBX (reg 3)
340 +run: copy imm32 0x0d0c0b0a to reg 3
341 
342 :(before "End Single-Byte Opcodes")
343 case 0xb8: {  // copy imm32 to r32
344   uint8_t modrm = next();
345   int32_t arg2 = imm32();
346   uint8_t reg1 = modrm&0x7;  // ignore mod bits
347   trace(2, "run") << "copy imm32 0x" << HEXWORD << arg2 << " to reg " << NUM(reg1) << end();
348   Reg[reg1].i = arg2;
349   break;
350 }
351 
352 //:
353 :(scenario copy_imm32_to_mem_at_r32)
354 % Reg[3].i = 0x60;
355 # op  ModRM   SIB   displacement  immediate
356   c7  03                          0a 0b 0c 0d  # copy 0x0d0c0b0a to *EBX (reg 3)
357 +run: copy imm32 0x0d0c0b0a to effective address
358 +run: effective address is mem at address 0x60 (reg 3)
359 
360 :(before "End Single-Byte Opcodes")
361 case 0xc7: {  // copy imm32 to r32
362   uint8_t modrm = next();
363   int32_t arg2 = imm32();
364   trace(2, "run") << "copy imm32 0x" << HEXWORD << arg2 << " to effective address" << end();
365   int32_t* arg1 = effective_address(modrm);
366   *arg1 = arg2;
367   break;
368 }
369 
370 //:: jump
371 
372 :(scenario jump_rel8)
373 # op  ModRM   SIB   displacement  immediate
374   eb                05                        # skip 1 instruction
375   05                              00 00 00 01
376   05                              00 00 00 02
377 +run: inst: 0x00000001
378 +run: jump 5
379 +run: inst: 0x00000008
380 -run: inst: 0x00000003
381 
382 :(before "End Single-Byte Opcodes")
383 case 0xeb: {  // jump rel8
384   int8_t offset = static_cast<int>(next());
385   trace(2, "run") << "jump " << NUM(offset) << end();
386   EIP += offset;
387   break;
388 }
389 
390 //:
391 
392 :(scenario jump_rel16)
393 # op  ModRM   SIB   displacement  immediate
394   e9                05 00                     # skip 1 instruction
395   05                              00 00 00 01
396   05                              00 00 00 02
397 +run: inst: 0x00000001
398 +run: jump 5
399 +run: inst: 0x00000009
400 -run: inst: 0x00000003
401 
402 :(before "End Single-Byte Opcodes")
403 case 0xe9: {  // jump rel8
404   int16_t offset = imm16();
405   trace(2, "run") << "jump " << offset << end();
406   EIP += offset;
407   break;
408 }
409 :(code)
410 int16_t imm16() {
411   int16_t result = next();
412   result |= (next()<<8);
413   return result;
414 }