diff gen_x86.c @ 241:2586d49ddd46

Implement EX, EXX and RST in Z80 core
author Mike Pavone <pavone@retrodev.com>
date Sun, 28 Apr 2013 13:45:17 -0700
parents d9bf8e61c33c
children 1788e3f29c28
line wrap: on
line diff
--- a/gen_x86.c	Sun Apr 28 13:45:00 2013 -0700
+++ b/gen_x86.c	Sun Apr 28 13:45:17 2013 -0700
@@ -24,7 +24,9 @@
 #define PRE_SIZE 0x66
 #define OP_JCC 0x70
 #define OP_IMMED_ARITH 0x80
+#define OP_XCHG 0x86
 #define OP_MOV 0x88
+#define OP_XCHG_AX 0x90
 #define OP_CDQ 0x99
 #define OP_PUSHF 0x9C
 #define OP_POPF 0x9D
@@ -120,7 +122,6 @@
 
 uint8_t * x86_rr_sizedir(uint8_t * out, uint16_t opcode, uint8_t src, uint8_t dst, uint8_t size)
 {
-	//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;
@@ -1184,6 +1185,49 @@
 	return out;
 }
 
+uint8_t * xchg_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
+{
+	//TODO: Use OP_XCHG_AX when one of the registers is AX, EAX or RAX
+	uint8_t tmp;
+	if (size == SZ_W) {
+		*(out++) = PRE_SIZE;
+	}
+	if (size == SZ_B && dst >= RSP && dst <= RDI) {
+		tmp = dst;
+		dst = src;
+		src = tmp;
+	}
+	if (size == SZ_Q || src >= R8 || dst >= R8 || (size == SZ_B && src >= RSP && src <= RDI)) {
+		*out = PRE_REX;
+		if (size == SZ_Q) {
+			*out |= REX_QUAD;
+		}
+		if (src >= R8) {
+			*out |= REX_REG_FIELD;
+			src -= (R8 - X86_R8);
+		}
+		if (dst >= R8) {
+			*out |= REX_RM_FIELD;
+			dst -= (R8 - X86_R8);
+		}
+		out++;
+	}
+	uint8_t opcode = OP_XCHG;
+	if (size == SZ_B) {
+		if (src >= AH && src <= BH) {
+			src -= (AH-X86_AH);
+		}
+		if (dst >= AH && dst <= BH) {
+			dst -= (AH-X86_AH);
+		}
+	} else {
+		opcode |= BIT_SIZE;
+	}
+	*(out++) = opcode;
+	*(out++) = MODE_REG_DIRECT | dst | (src << 3);
+	return out;
+}
+
 uint8_t * pushf(uint8_t * out)
 {
 	*(out++) = OP_PUSHF;