diff gen_x86.c @ 343:467bfa17004a

Mostly working runtime generation of memory map read/write functions
author Mike Pavone <pavone@retrodev.com>
date Sat, 18 May 2013 11:44:42 -0700
parents 1788e3f29c28
children ad493d38964e
line wrap: on
line diff
--- a/gen_x86.c	Thu May 16 09:37:53 2013 -0700
+++ b/gen_x86.c	Sat May 18 11:44:42 2013 -0700
@@ -2,6 +2,7 @@
 #include "68kinst.h"
 #include <stddef.h>
 #include <stdio.h>
+#include <stdlib.h>
 
 #define REX_RM_FIELD 0x1
 #define REX_SIB_FIELD 0x2
@@ -220,6 +221,58 @@
 	return out;
 }
 
+uint8_t * x86_rrdisp32_sizedir(uint8_t * out, uint16_t opcode, uint8_t reg, uint8_t base, int32_t disp, uint8_t size, uint8_t dir)
+{
+	//TODO: Deal with the fact that AH, BH, CH and DH can only be in the R/M param when there's a REX prefix
+	uint8_t tmp;
+	if (size == SZ_W) {
+		*(out++) = PRE_SIZE;
+	}
+	if (size == SZ_Q || reg >= R8 || base >= R8 || (size == SZ_B && reg >= RSP && reg <= RDI)) {
+		*out = PRE_REX;
+		if (reg >= AH && reg <= BH) {
+			fprintf(stderr, "attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
+			exit(1);
+		}
+		if (size == SZ_Q) {
+			*out |= REX_QUAD;
+		}
+		if (reg >= R8) {
+			*out |= REX_REG_FIELD;
+			reg -= (R8 - X86_R8);
+		}
+		if (base >= R8) {
+			*out |= REX_RM_FIELD;
+			base -= (R8 - X86_R8);
+		}
+		out++;
+	}
+	if (size == SZ_B) {
+		if (reg >= AH && reg <= BH) {
+			reg -= (AH-X86_AH);
+		}
+	} else {
+		opcode |= BIT_SIZE;
+	}
+	opcode |= dir;
+	if (opcode >= 0x100) {
+		*(out++) = opcode >> 8;
+		*(out++) = opcode;
+	} else {
+		*(out++) = opcode;
+	}
+	*(out++) = MODE_REG_DISPLACE32 | base | (reg << 3);
+	if (base == RSP) {
+		//add SIB byte, with no index and RSP as base
+		*(out++) = (RSP << 3) | RSP;
+	}
+	*(out++) = disp;
+	*(out++) = disp >> 8;
+	*(out++) = disp >> 16;
+	*(out++) = disp >> 24;
+	return out;
+}
+
 uint8_t * x86_rrind_sizedir(uint8_t * out, uint8_t opcode, uint8_t reg, uint8_t base, uint8_t size, uint8_t dir)
 {
 	//TODO: Deal with the fact that AH, BH, CH and DH can only be in the R/M param when there's a REX prefix
@@ -262,6 +315,54 @@
 	return out;
 }
 
+uint8_t * x86_rrindex_sizedir(uint8_t * out, uint8_t opcode, uint8_t reg, uint8_t base, uint8_t index, uint8_t scale, uint8_t size, uint8_t dir)
+{
+	//TODO: Deal with the fact that AH, BH, CH and DH can only be in the R/M param when there's a REX prefix
+	uint8_t tmp;
+	if (size == SZ_W) {
+		*(out++) = PRE_SIZE;
+	}
+	if (size == SZ_Q || reg >= R8 || base >= R8 || (size == SZ_B && reg >= RSP && reg <= RDI)) {
+		*out = PRE_REX;
+		if (reg >= AH && reg <= BH) {
+			fprintf(stderr, "attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
+			exit(1);
+		}
+		if (size == SZ_Q) {
+			*out |= REX_QUAD;
+		}
+		if (reg >= R8) {
+			*out |= REX_REG_FIELD;
+			reg -= (R8 - X86_R8);
+		}
+		if (base >= R8) {
+			*out |= REX_RM_FIELD;
+			base -= (R8 - X86_R8);
+		}
+		if (index >= R8) {
+			*out |= REX_SIB_FIELD;
+			index -= (R8 - X86_R8);
+		}
+		out++;
+	}
+	if (size == SZ_B) {
+		if (reg >= AH && reg <= BH) {
+			reg -= (AH-X86_AH);
+		}
+	} else {
+		opcode |= BIT_SIZE;
+	}
+	*(out++) = opcode | dir;
+	*(out++) = MODE_REG_INDIRECT | base | (RSP << 3);
+	if (base == RSP) {
+		if (scale == 4) {
+			scale = 3;
+		}
+		*(out++) = scale << 6 | (index << 3) | base;
+	}
+	return out;
+}
+
 uint8_t * x86_r_size(uint8_t * out, uint8_t opcode, uint8_t opex, uint8_t dst, uint8_t size)
 {
 	uint8_t tmp;
@@ -949,6 +1050,16 @@
 	return x86_rrdisp8_sizedir(out, OP_MOV, dst, src_base, disp, size, BIT_DIR);
 }
 
+uint8_t * mov_rrdisp32(uint8_t * out, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
+{
+	return x86_rrdisp32_sizedir(out, OP_MOV, src, dst_base, disp, size, 0);
+}
+
+uint8_t * mov_rdisp32r(uint8_t * out, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
+{
+	return x86_rrdisp32_sizedir(out, OP_MOV, dst, src_base, disp, size, BIT_DIR);
+}
+
 uint8_t * mov_rrind(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
 {
 	return x86_rrind_sizedir(out, OP_MOV, src, dst, size, 0);
@@ -959,6 +1070,16 @@
 	return x86_rrind_sizedir(out, OP_MOV, dst, src, size, BIT_DIR);
 }
 
+uint8_t * mov_rrindex(uint8_t * out, uint8_t src, uint8_t dst_base, uint8_t dst_index, uint8_t scale, uint8_t size)
+{
+	return x86_rrindex_sizedir(out, OP_MOV, src, dst_base, dst_index, scale, size, 0);
+}
+
+uint8_t * mov_rindexr(uint8_t * out, uint8_t src_base, uint8_t src_index, uint8_t scale, uint8_t dst, uint8_t size)
+{
+	return x86_rrindex_sizedir(out, OP_MOV, dst, src_base, src_index, scale, size, BIT_DIR);
+}
+
 uint8_t * mov_ir(uint8_t * out, int64_t val, uint8_t dst, uint8_t size)
 {	
 	uint8_t sign_extend = 0;
@@ -1370,6 +1491,36 @@
 	return out;
 }
 
+uint8_t * bit_rrdisp32(uint8_t * out, uint8_t op2, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size)
+{
+	if (size == SZ_W) {
+		*(out++) = PRE_SIZE;
+	}
+	if (size == SZ_Q || src >= R8 || dst_base >= R8) {
+		*out = PRE_REX;
+		if (size == SZ_Q) {
+			*out |= REX_QUAD;
+		}
+		if (src >= R8) {
+			*out |= REX_REG_FIELD;
+			src -= (R8 - X86_R8);
+		}
+		if (dst_base >= R8) {
+			*out |= REX_RM_FIELD;
+			dst_base -= (R8 - X86_R8);
+		}
+		out++;
+	}
+	*(out++) = PRE_2BYTE;
+	*(out++) = op2;
+	*(out++) = MODE_REG_DISPLACE32 | dst_base | (src << 3);
+	*(out++) = dst_disp;
+	*(out++) = dst_disp >> 8;
+	*(out++) = dst_disp >> 16;
+	*(out++) = dst_disp >> 24;
+	return out;
+}
+
 uint8_t * bit_ir(uint8_t * out, uint8_t op_ex, uint8_t val, uint8_t dst, uint8_t size)
 {
 	if (size == SZ_W) {
@@ -1427,6 +1578,11 @@
 	return bit_rrdisp8(out, OP2_BT, src, dst_base, dst_disp, size);
 }
 
+uint8_t * bt_rrdisp32(uint8_t * out, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size)
+{
+	return bit_rrdisp32(out, OP2_BT, src, dst_base, dst_disp, size);
+}
+
 uint8_t * bt_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size)
 {
 	return bit_ir(out, OP_EX_BT, val, dst, size);