1 //: operating directly on a register
  2 
  3 :(scenario add_r32_to_r32)
  4 % Reg[0].i = 0x10;
  5 % Reg[3].i = 1;
  6 # op  ModR/M  SIB   displacement  immediate
  7   01  d8                                      # add EBX (reg 3) to EAX (reg 0)
  8 +run: add reg 3 to effective address
  9 +run: effective address is reg 0
 10 +run: storing 0x00000011
 11 
 12 :(before "End Single-Byte Opcodes")
 13 case 0x01: {  // add r32 to r/m32
 14   uint8_t modrm = next();
 15   uint8_t arg2 = (modrm>>3)&0x7;
 16   trace(2, "run") << "add reg " << NUM(arg2) << " to effective address" << end();
 17   int32_t* arg1 = effective_address(modrm);
 18   BINARY_ARITHMETIC_OP(+, *arg1, Reg[arg2].i);
 19   break;
 20 }
 21 
 22 :(code)
 23 // Implement tables 2-2 and 2-3 in the Intel manual, Volume 2.
 24 // We return a pointer so that instructions can write to multiple bytes in
 25 // 'Mem' at once.
 26 int32_t* effective_address(uint8_t modrm) {
 27   uint8_t mod = (modrm>>6);
 28   // ignore middle 3 'reg opcode' bits
 29   uint8_t rm = modrm & 0x7;
 30   int32_t* result = 0;
 31   switch (mod) {
 32   case 3:
 33   ¦ // mod 3 is just register direct addressing
 34   ¦ trace(2, "run") << "effective address is reg " << NUM(rm) << end();
 35   ¦ result = &Reg[rm].i;
 36   ¦ break;
 37   // End Mod Special-cases
 38   default:
 39   ¦ cerr << "unrecognized mod bits: " << NUM(mod) << '\n';
 40   ¦ exit(1);
 41   }
 42   return result;
 43 }
 44 
 45 //:: subtract
 46 
 47 :(scenario subtract_r32_from_r32)
 48 % Reg[0].i = 10;
 49 % Reg[3].i = 1;
 50 # op  ModR/M  SIB   displacement  immediate
 51   29  d8                                      # subtract EBX (reg 3) from EAX (reg 0)
 52 +run: subtract reg 3 from effective address
 53 +run: effective address is reg 0
 54 +run: storing 0x00000009
 55 
 56 :(before "End Single-Byte Opcodes")
 57 case 0x29: {  // subtract r32 from r/m32
 58   uint8_t modrm = next();
 59   uint8_t arg2 = (modrm>>3)&0x7;
 60   trace(2, "run") << "subtract reg " << NUM(arg2) << " from effective address" << end();
 61   int32_t* arg1 = effective_address(modrm);
 62   BINARY_ARITHMETIC_OP(-, *arg1, Reg[arg2].i);
 63   break;
 64 }
 65 
 66 //:: and
 67 
 68 :(scenario and_r32_with_r32)
 69 % Reg[0].i = 0x0a0b0c0d;
 70 % Reg[3].i = 0x000000ff;
 71 # op  ModR/M  SIB   displacement  immediate
 72   21  d8                                      # and EBX (reg 3) with destination EAX (reg 0)
 73 +run: and reg 3 with effective address
 74 +run: effective address is reg 0
 75 +run: storing 0x0000000d
 76 
 77 :(before "End Single-Byte Opcodes")
 78 case 0x21: {  // and r32 with r/m32
 79   uint8_t modrm = next();
 80   uint8_t arg2 = (modrm>>3)&0x7;
 81   trace(2, "run") << "and reg " << NUM(arg2) << " with effective address" << end();
 82   int32_t* arg1 = effective_address(modrm);
 83   BINARY_BITWISE_OP(&, *arg1, Reg[arg2].u);
 84   break;
 85 }
 86 
 87 //:: or
 88 
 89 :(scenario or_r32_with_r32)
 90 % Reg[0].i = 0x0a0b0c0d;
 91 % Reg[3].i = 0xa0b0c0d0;
 92 # op  ModR/M  SIB   displacement  immediate
 93   09  d8                                      # or EBX (reg 3) with destination EAX (reg 0)
 94 +run: or reg 3 with effective address
 95 +run: effective address is reg 0
 96 +run: storing 0xaabbccdd
 97 
 98 :(before "End Single-Byte Opcodes")
 99 case 0x09: {  // or r32 with r/m32
100   uint8_t modrm = next();
101   uint8_t arg2 = (modrm>>3)&0x7;
102   trace(2, "run") << "or reg " << NUM(arg2) << " with effective address" << end();
103   int32_t* arg1 = effective_address(modrm);
104   BINARY_BITWISE_OP(|, *arg1, Reg[arg2].u);
105   break;
106 }
107 
108 //:: xor
109 
110 :(scenario xor_r32_with_r32)
111 % Reg[0].i = 0x0a0b0c0d;
112 % Reg[3].i = 0xaabbc0d0;
113 # op  ModR/M  SIB   displacement  immediate
114   31  d8                                      # xor EBX (reg 3) with destination EAX (reg 0)
115 +run: xor reg 3 with effective address
116 +run: effective address is reg 0
117 +run: storing 0xa0b0ccdd
118 
119 :(before "End Single-Byte Opcodes")
120 case 0x31: {  // xor r32 with r/m32
121   uint8_t modrm = next();
122   uint8_t arg2 = (modrm>>3)&0x7;
123   trace(2, "run") << "xor reg " << NUM(arg2) << " with effective address" << end();
124   int32_t* arg1 = effective_address(modrm);
125   BINARY_BITWISE_OP(^, *arg1, Reg[arg2].u);
126   break;
127 }
128 
129 //:: not
130 
131 :(scenario not_r32)
132 % Reg[3].i = 0x0f0f00ff;
133 # op  ModR/M  SIB   displacement  immediate
134   f7  c3                                      # not EBX (reg 3)
135 +run: 'not' of effective address
136 +run: effective address is reg 3
137 +run: storing 0xf0f0ff00
138 
139 :(before "End Single-Byte Opcodes")
140 case 0xf7: {  // xor r32 with r/m32
141   uint8_t modrm = next();
142   trace(2, "run") << "'not' of effective address" << end();
143   int32_t* arg1 = effective_address(modrm);
144   *arg1 = ~(*arg1);
145   trace(2, "run") << "storing 0x" << HEXWORD << *arg1 << end();
146   SF = (*arg1 >> 31);
147   ZF = (*arg1 == 0);
148   OF = false;
149   break;
150 }
151 
152 //:: compare (cmp)
153 
154 :(scenario compare_r32_with_r32_greater)
155 % Reg[0].i = 0x0a0b0c0d;
156 % Reg[3].i = 0x0a0b0c07;
157 # op  ModRM   SIB   displacement  immediate
158   39  d8                                      # compare EBX (reg 3) with EAX (reg 0)
159 +run: compare reg 3 with effective address
160 +run: effective address is reg 0
161 +run: SF=0; ZF=0; OF=0
162 
163 :(before "End Single-Byte Opcodes")
164 case 0x39: {  // set SF if r/m32 < r32
165   uint8_t modrm = next();
166   uint8_t reg2 = (modrm>>3)&0x7;
167   trace(2, "run") << "compare reg " << NUM(reg2) << " with effective address" << end();
168   int32_t* arg1 = effective_address(modrm);
169   int32_t arg2 = Reg[reg2].i;
170   int32_t tmp1 = *arg1 - arg2;
171   SF = (tmp1 < 0);
172   ZF = (tmp1 == 0);
173   int64_t tmp2 = *arg1 - arg2;
174   OF = (tmp1 != tmp2);
175   trace(2, "run") << "SF=" << SF << "; ZF=" << ZF << "; OF=" << OF << end();
176   break;
177 }
178 
179 :(scenario compare_r32_with_r32_lesser)
180 % Reg[0].i = 0x0a0b0c07;
181 % Reg[3].i = 0x0a0b0c0d;
182 # op  ModRM   SIB   displacement  immediate
183   39  d8                                      # compare EBX (reg 3) with EAX (reg 0)
184 +run: compare reg 3 with effective address
185 +run: effective address is reg 0
186 +run: SF=1; ZF=0; OF=0
187 
188 :(scenario compare_r32_with_r32_equal)
189 % Reg[0].i = 0x0a0b0c0d;
190 % Reg[3].i = 0x0a0b0c0d;
191 # op  ModRM   SIB   displacement  immediate
192   39  d8                                      # compare EBX (reg 3) with EAX (reg 0)
193 +run: compare reg 3 with effective address
194 +run: effective address is reg 0
195 +run: SF=0; ZF=1; OF=0
196 
197 //:: copy (mov)
198 
199 :(scenario copy_r32_to_r32)
200 % Reg[3].i = 0xaf;
201 # op  ModRM   SIB   displacement  immediate
202   89  d8                                      # copy EBX (reg 3) to EAX (reg 0)
203 +run: copy reg 3 to effective address
204 +run: effective address is reg 0
205 +run: storing 0x000000af
206 
207 :(before "End Single-Byte Opcodes")
208 case 0x89: {  // copy r32 to r/m32
209   uint8_t modrm = next();
210   uint8_t reg2 = (modrm>>3)&0x7;
211   trace(2, "run") << "copy reg " << NUM(reg2) << " to effective address" << end();
212   int32_t* arg1 = effective_address(modrm);
213   *arg1 = Reg[reg2].i;
214   trace(2, "run") << "storing 0x" << HEXWORD << *arg1 << end();
215   break;
216 }
217 
218 //:: push
219 
220 :(scenario push_r32)
221 % Reg[ESP].u = 0x64;
222 % Reg[EBX].i = 0x0000000a;
223 # op  ModRM   SIB   displacement  immediate
224   53                                          # push EBX (reg 3) to stack
225 +run: push reg 3
226 +run: decrementing ESP to 0x00000060
227 +run: pushing value 0x0000000a
228 
229 :(before "End Single-Byte Opcodes")
230 case 0x50:
231 case 0x51:
232 case 0x52:
233 case 0x53:
234 case 0x54:
235 case 0x55:
236 case 0x56:
237 case 0x57: {  // push r32 to stack
238   uint8_t reg = op & 0x7;
239   trace(2, "run") << "push reg " << NUM(reg) << end();
240   push(Reg[reg].u);
241   break;
242 }
243 :(code)
244 void push(uint32_t val) {
245   Reg[ESP].u -= 4;
246   trace(2, "run") << "decrementing ESP to 0x" << HEXWORD << Reg[ESP].u << end();
247   trace(2, "run") << "pushing value 0x" << HEXWORD << val << end();
248   *reinterpret_cast<uint32_t*>(&Mem.at(Reg[ESP].u)) = val;
249 }
250 
251 //:: pop
252 
253 :(scenario pop_r32)
254 % Reg[ESP].u = 0x60;
255 % SET_WORD_IN_MEM(0x60, 0x0000000a);
256 # op  ModRM   SIB   displacement  immediate
257   5b                                          # pop stack to EBX (reg 3)
258 +run: pop into reg 3
259 +run: popping value 0x0000000a
260 +run: incrementing ESP to 0x00000064
261 
262 :(before "End Single-Byte Opcodes")
263 case 0x58:
264 case 0x59:
265 case 0x5a:
266 case 0x5b:
267 case 0x5c:
268 case 0x5d:
269 case 0x5e:
270 case 0x5f: {  // pop stack into r32
271   uint8_t reg = op & 0x7;
272   trace(2, "run") << "pop into reg " << NUM(reg) << end();
273   Reg[reg].u = pop();
274   break;
275 }
276 :(code)
277 uint32_t pop() {
278   uint32_t result = *reinterpret_cast<uint32_t*>(&Mem.at(Reg[ESP].u));
279   trace(2, "run") << "popping value 0x" << HEXWORD << result << end();
280   Reg[ESP].u += 4;
281   trace(2, "run") << "incrementing ESP to 0x" << HEXWORD << Reg[ESP].u << end();
282   return result;
283 }