Mercurial > repos > blastem
comparison gen_x86.c @ 15:c0f339564819
Make x86 generator generic with respect to operand size for immediate parameters.
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Tue, 27 Nov 2012 22:43:32 -0800 |
parents | 2bdad0f52f42 |
children | 3e7bfde7606e |
comparison
equal
deleted
inserted
replaced
14:2bdad0f52f42 | 15:c0f339564819 |
---|---|
27 #define OP_PUSHF 0x9C | 27 #define OP_PUSHF 0x9C |
28 #define OP_POPF 0x9D | 28 #define OP_POPF 0x9D |
29 #define OP_MOV_I8R 0xB0 | 29 #define OP_MOV_I8R 0xB0 |
30 #define OP_MOV_IR 0xB8 | 30 #define OP_MOV_IR 0xB8 |
31 #define OP_RETN 0xC3 | 31 #define OP_RETN 0xC3 |
32 #define OP_MOV_IEA 0xC6 | |
32 #define OP_CALL 0xE8 | 33 #define OP_CALL 0xE8 |
33 #define OP_CALL_EA 0xFF | 34 #define OP_CALL_EA 0xFF |
34 | 35 |
35 #define OP2_JCC 0x80 | 36 #define OP2_JCC 0x80 |
36 #define OP2_SETCC 0x90 | 37 #define OP2_SETCC 0x90 |
195 *(out++) = opcode | dir; | 196 *(out++) = opcode | dir; |
196 *(out++) = MODE_REG_INDIRECT | base | (reg << 3); | 197 *(out++) = MODE_REG_INDIRECT | base | (reg << 3); |
197 return out; | 198 return out; |
198 } | 199 } |
199 | 200 |
200 uint8_t * x86_i8r(uint8_t * out, uint8_t opcode, uint8_t op_ex, uint8_t al_opcode, uint8_t val, uint8_t dst) | 201 uint8_t * x86_ir(uint8_t * out, uint8_t opcode, uint8_t op_ex, uint8_t al_opcode, int32_t val, uint8_t dst, uint8_t size) |
201 { | 202 { |
202 if (dst == RAX) { | 203 uint8_t sign_extend = 0; |
204 if ((size == SZ_D || size == SZ_Q) && val <= 0x7F && val >= -0x80) { | |
205 sign_extend = 1; | |
206 opcode |= BIT_DIR; | |
207 } | |
208 if (size == SZ_W) { | |
209 *(out++) = PRE_SIZE; | |
210 } | |
211 if (dst == RAX && !sign_extend) { | |
212 if (size != SZ_B) { | |
213 al_opcode |= BIT_SIZE; | |
214 if (size == SZ_Q) { | |
215 *out = PRE_REX | REX_QUAD; | |
216 } | |
217 } | |
203 *(out++) = al_opcode | BIT_IMMED_RAX; | 218 *(out++) = al_opcode | BIT_IMMED_RAX; |
204 } else { | 219 } else { |
220 if (size == SZ_Q || dst >= R8 || (size == SZ_B && dst >= RSP && dst <= RDI)) { | |
221 *out = PRE_REX; | |
222 if (size == SZ_Q) { | |
223 *out |= REX_QUAD; | |
224 } | |
225 if (dst >= R8) { | |
226 *out |= REX_RM_FIELD; | |
227 dst -= (R8 - X86_R8); | |
228 } | |
229 out++; | |
230 } | |
205 if (dst >= AH && dst <= BH) { | 231 if (dst >= AH && dst <= BH) { |
206 dst -= (AH-X86_AH); | 232 dst -= (AH-X86_AH); |
207 } else if(dst >= R8) { | 233 } |
208 *(out++) = PRE_REX | REX_RM_FIELD; | 234 if (size != SZ_B) { |
235 opcode |= BIT_SIZE; | |
209 } | 236 } |
210 *(out++) = opcode; | 237 *(out++) = opcode; |
211 *(out++) = MODE_REG_DIRECT | dst | (op_ex << 3); | 238 *(out++) = MODE_REG_DIRECT | dst | (op_ex << 3); |
212 } | 239 } |
213 *(out++) = val; | 240 *(out++) = val; |
214 return out; | 241 if (size != SZ_B && !sign_extend) { |
215 } | |
216 | |
217 uint8_t * x86_i32r(uint8_t * out, uint8_t opcode, uint8_t op_ex, uint8_t al_opcode, int32_t val, uint8_t dst) | |
218 { | |
219 uint8_t sign_extend = 0; | |
220 if (val <= 0x7F && val >= -0x80) { | |
221 sign_extend = 1; | |
222 opcode |= BIT_DIR; | |
223 } | |
224 if (dst == RAX && !sign_extend) { | |
225 *(out++) = al_opcode | BIT_IMMED_RAX | BIT_SIZE; | |
226 } else { | |
227 if(dst >= R8) { | |
228 *(out++) = PRE_REX | REX_RM_FIELD; | |
229 } | |
230 *(out++) = opcode | BIT_SIZE; | |
231 *(out++) = MODE_REG_DIRECT | dst | (op_ex << 3); | |
232 } | |
233 *(out++) = val; | |
234 if (!sign_extend) { | |
235 val >>= 8; | 242 val >>= 8; |
236 *(out++) = val; | 243 *(out++) = val; |
244 if (size != SZ_W) { | |
245 val >>= 8; | |
246 *(out++) = val; | |
247 val >>= 8; | |
248 *(out++) = val; | |
249 } | |
250 } | |
251 return out; | |
252 } | |
253 | |
254 | |
255 uint8_t * add_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) | |
256 { | |
257 return x86_rr_sizedir(out, OP_ADD, src, dst, size); | |
258 } | |
259 | |
260 uint8_t * add_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size) | |
261 { | |
262 return x86_ir(out, OP_IMMED_ARITH, OP_EX_ADDI, OP_ADD, val, dst, size); | |
263 } | |
264 | |
265 uint8_t * or_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) | |
266 { | |
267 return x86_rr_sizedir(out, OP_OR, src, dst, size); | |
268 } | |
269 uint8_t * or_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size) | |
270 { | |
271 return x86_ir(out, OP_IMMED_ARITH, OP_EX_ORI, OP_OR, val, dst, size); | |
272 } | |
273 | |
274 uint8_t * and_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) | |
275 { | |
276 return x86_rr_sizedir(out, OP_AND, src, dst, size); | |
277 } | |
278 | |
279 uint8_t * and_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size) | |
280 { | |
281 return x86_ir(out, OP_IMMED_ARITH, OP_EX_ANDI, OP_AND, val, dst, size); | |
282 } | |
283 | |
284 uint8_t * xor_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) | |
285 { | |
286 return x86_rr_sizedir(out, OP_XOR, src, dst, size); | |
287 } | |
288 | |
289 uint8_t * xor_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size) | |
290 { | |
291 return x86_ir(out, OP_IMMED_ARITH, OP_EX_XORI, OP_XOR, val, dst, size); | |
292 } | |
293 | |
294 uint8_t * sub_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) | |
295 { | |
296 return x86_rr_sizedir(out, OP_SUB, src, dst, size); | |
297 } | |
298 | |
299 uint8_t * sub_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size) | |
300 { | |
301 return x86_ir(out, OP_IMMED_ARITH, OP_EX_SUBI, OP_SUB, val, dst, size); | |
302 } | |
303 | |
304 uint8_t * cmp_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) | |
305 { | |
306 return x86_rr_sizedir(out, OP_CMP, src, dst, size); | |
307 } | |
308 | |
309 uint8_t * cmp_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size) | |
310 { | |
311 return x86_ir(out, OP_IMMED_ARITH, OP_EX_CMPI, OP_CMP, val, dst, size); | |
312 } | |
313 | |
314 uint8_t * mov_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) | |
315 { | |
316 return x86_rr_sizedir(out, OP_MOV, src, dst, size); | |
317 } | |
318 | |
319 uint8_t * mov_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size) | |
320 { | |
321 return x86_rrdisp8_sizedir(out, OP_MOV, src, dst_base, disp, size, 0); | |
322 } | |
323 | |
324 uint8_t * mov_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size) | |
325 { | |
326 return x86_rrdisp8_sizedir(out, OP_MOV, dst, src_base, disp, size, BIT_DIR); | |
327 } | |
328 | |
329 uint8_t * mov_rrind(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) | |
330 { | |
331 return x86_rrind_sizedir(out, OP_MOV, src, dst, size, 0); | |
332 } | |
333 | |
334 uint8_t * mov_rindr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) | |
335 { | |
336 return x86_rrind_sizedir(out, OP_MOV, dst, src, size, BIT_DIR); | |
337 } | |
338 | |
339 uint8_t * mov_ir(uint8_t * out, int64_t val, uint8_t dst, uint8_t size) | |
340 { | |
341 uint8_t sign_extend = 0; | |
342 if (size == SZ_Q && val <= 0x7FFFFFFF && val >= -2147483648) { | |
343 sign_extend = 1; | |
344 } | |
345 if (size == SZ_W) { | |
346 *(out++) = PRE_SIZE; | |
347 } | |
348 if (size == SZ_Q || dst >= R8 || (size == SZ_B && dst >= RSP && dst <= RDI)) { | |
349 *out = PRE_REX; | |
350 if (size == SZ_Q) { | |
351 *out |= REX_QUAD; | |
352 } | |
353 if (dst >= R8) { | |
354 *out |= REX_RM_FIELD; | |
355 dst -= (R8 - X86_R8); | |
356 } | |
357 out++; | |
358 } | |
359 if (dst >= AH && dst <= BH) { | |
360 dst -= (AH-X86_AH); | |
361 } | |
362 if (size == SZ_B) { | |
363 *(out++) = OP_MOV_I8R; | |
364 } else if (size == SZ_Q && sign_extend) { | |
365 *(out++) = OP_MOV_IEA | BIT_SIZE; | |
366 *(out++) = MODE_REG_DIRECT | dst; | |
367 } else { | |
368 *(out++) = OP_MOV_IR; | |
369 } | |
370 *(out++) = val; | |
371 if (size != SZ_B) { | |
237 val >>= 8; | 372 val >>= 8; |
238 *(out++) = val; | 373 *(out++) = val; |
239 val >>= 8; | 374 if (size != SZ_W) { |
240 *(out++) = val; | 375 val >>= 8; |
241 } | 376 *(out++) = val; |
242 return out; | 377 val >>= 8; |
243 } | 378 *(out++) = val; |
244 | 379 if (size == SZ_Q && !sign_extend) { |
245 uint8_t * add_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) | 380 val >>= 8; |
246 { | 381 *(out++) = val; |
247 return x86_rr_sizedir(out, OP_ADD, src, dst, size); | 382 val >>= 8; |
248 } | 383 *(out++) = val; |
249 | 384 val >>= 8; |
250 uint8_t * add_i8r(uint8_t * out, uint8_t val, uint8_t dst) | 385 *(out++) = val; |
251 { | 386 val >>= 8; |
252 return x86_i8r(out, OP_IMMED_ARITH, OP_EX_ADDI, OP_ADD, val, dst); | 387 *(out++) = val; |
253 } | 388 } |
254 | 389 } |
255 uint8_t * add_i32r(uint8_t * out, int32_t val, uint8_t dst) | 390 } |
256 { | |
257 return x86_i32r(out, OP_IMMED_ARITH, OP_EX_ADDI, OP_ADD, val, dst); | |
258 } | |
259 | |
260 uint8_t * or_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) | |
261 { | |
262 return x86_rr_sizedir(out, OP_OR, src, dst, size); | |
263 } | |
264 | |
265 uint8_t * or_i8r(uint8_t * out, uint8_t val, uint8_t dst) | |
266 { | |
267 return x86_i8r(out, OP_IMMED_ARITH, OP_EX_ORI, OP_OR, val, dst); | |
268 } | |
269 | |
270 uint8_t * or_i32r(uint8_t * out, int32_t val, uint8_t dst) | |
271 { | |
272 return x86_i32r(out, OP_IMMED_ARITH, OP_EX_ORI, OP_OR, val, dst); | |
273 } | |
274 | |
275 uint8_t * and_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) | |
276 { | |
277 return x86_rr_sizedir(out, OP_AND, src, dst, size); | |
278 } | |
279 | |
280 uint8_t * and_i8r(uint8_t * out, uint8_t val, uint8_t dst) | |
281 { | |
282 return x86_i8r(out, OP_IMMED_ARITH, OP_EX_ANDI, OP_AND, val, dst); | |
283 } | |
284 | |
285 uint8_t * and_i32r(uint8_t * out, int32_t val, uint8_t dst) | |
286 { | |
287 return x86_i32r(out, OP_IMMED_ARITH, OP_EX_ANDI, OP_AND, val, dst); | |
288 } | |
289 | |
290 uint8_t * xor_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) | |
291 { | |
292 return x86_rr_sizedir(out, OP_XOR, src, dst, size); | |
293 } | |
294 | |
295 uint8_t * xor_i8r(uint8_t * out, uint8_t val, uint8_t dst) | |
296 { | |
297 return x86_i8r(out, OP_IMMED_ARITH, OP_EX_XORI, OP_XOR, val, dst); | |
298 } | |
299 | |
300 uint8_t * xor_i32r(uint8_t * out, int32_t val, uint8_t dst) | |
301 { | |
302 return x86_i32r(out, OP_IMMED_ARITH, OP_EX_XORI, OP_XOR, val, dst); | |
303 } | |
304 | |
305 uint8_t * sub_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) | |
306 { | |
307 return x86_rr_sizedir(out, OP_SUB, src, dst, size); | |
308 } | |
309 | |
310 uint8_t * sub_i8r(uint8_t * out, uint8_t val, uint8_t dst) | |
311 { | |
312 return x86_i8r(out, OP_IMMED_ARITH, OP_EX_SUBI, OP_SUB, val, dst); | |
313 } | |
314 | |
315 uint8_t * sub_i32r(uint8_t * out, int32_t val, uint8_t dst) | |
316 { | |
317 return x86_i32r(out, OP_IMMED_ARITH, OP_EX_SUBI, OP_SUB, val, dst); | |
318 } | |
319 | |
320 | |
321 uint8_t * cmp_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) | |
322 { | |
323 return x86_rr_sizedir(out, OP_CMP, src, dst, size); | |
324 } | |
325 | |
326 uint8_t * cmp_i8r(uint8_t * out, uint8_t val, uint8_t dst) | |
327 { | |
328 return x86_i8r(out, OP_IMMED_ARITH, OP_EX_CMPI, OP_CMP, val, dst); | |
329 } | |
330 | |
331 uint8_t * cmp_i32r(uint8_t * out, int32_t val, uint8_t dst) | |
332 { | |
333 return x86_i32r(out, OP_IMMED_ARITH, OP_EX_CMPI, OP_CMP, val, dst); | |
334 } | |
335 | |
336 uint8_t * mov_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) | |
337 { | |
338 return x86_rr_sizedir(out, OP_MOV, src, dst, size); | |
339 } | |
340 | |
341 uint8_t * mov_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size) | |
342 { | |
343 return x86_rrdisp8_sizedir(out, OP_MOV, src, dst_base, disp, size, 0); | |
344 } | |
345 | |
346 uint8_t * mov_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size) | |
347 { | |
348 return x86_rrdisp8_sizedir(out, OP_MOV, dst, src_base, disp, size, BIT_DIR); | |
349 } | |
350 | |
351 uint8_t * mov_rrind(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) | |
352 { | |
353 return x86_rrind_sizedir(out, OP_MOV, src, dst, size, 0); | |
354 } | |
355 | |
356 uint8_t * mov_rindr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) | |
357 { | |
358 return x86_rrind_sizedir(out, OP_MOV, dst, src, size, BIT_DIR); | |
359 } | |
360 | |
361 uint8_t * mov_i8r(uint8_t * out, uint8_t val, uint8_t dst) | |
362 { | |
363 if (dst >= AH && dst <= BH) { | |
364 dst -= AH - X86_AH; | |
365 } else if (dst >= RSP && dst <= RDI) { | |
366 *(out++) = PRE_REX; | |
367 } else if (dst >= R8) { | |
368 *(out++) = PRE_REX | REX_RM_FIELD; | |
369 dst -= R8 - X86_R8; | |
370 } | |
371 *(out++) = OP_MOV_I8R | dst; | |
372 *(out++) = val; | |
373 return out; | |
374 } | |
375 | |
376 uint8_t * mov_i16r(uint8_t * out, uint16_t val, uint8_t dst) | |
377 { | |
378 *(out++) = PRE_SIZE; | |
379 if (dst >= R8) { | |
380 *(out++) = PRE_REX | REX_RM_FIELD; | |
381 dst -= R8 - X86_R8; | |
382 } | |
383 *(out++) = OP_MOV_IR | dst; | |
384 *(out++) = val; | |
385 val >>= 8; | |
386 *(out++) = val; | |
387 return out; | |
388 } | |
389 | |
390 uint8_t * mov_i32r(uint8_t * out, uint32_t val, uint8_t dst) | |
391 { | |
392 if (dst >= R8) { | |
393 *(out++) = PRE_REX | REX_RM_FIELD; | |
394 dst -= R8 - X86_R8; | |
395 } | |
396 *(out++) = OP_MOV_IR | dst; | |
397 *(out++) = val; | |
398 val >>= 8; | |
399 *(out++) = val; | |
400 val >>= 8; | |
401 *(out++) = val; | |
402 val >>= 8; | |
403 *(out++) = val; | |
404 return out; | 391 return out; |
405 } | 392 } |
406 | 393 |
407 uint8_t * pushf(uint8_t * out) | 394 uint8_t * pushf(uint8_t * out) |
408 { | 395 { |