changeset 61:918468c623e9

Add support for BTST instruction (untested), absolute addressing mode for instructions other than move (untested) and fix decoding of MOVEM.
author Mike Pavone <pavone@retrodev.com>
date Wed, 19 Dec 2012 20:23:59 -0800
parents 6ffea8607730
children b37cb596bc21
files 68kinst.c 68kinst.h gen_x86.c gen_x86.h m68k_to_x86.c
diffstat 5 files changed, 192 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/68kinst.c	Tue Dec 18 23:55:10 2012 -0800
+++ b/68kinst.c	Wed Dec 19 20:23:59 2012 -0800
@@ -124,8 +124,11 @@
 			}
 			decoded->src.addr_mode = MODE_REG;
 			decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
-			decoded->extra.size = OPSIZE_LONG;
-			istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->dst));
+			decoded->extra.size = OPSIZE_BYTE;
+			istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->dst));
+			if (decoded->dst.addr_mode == MODE_REG) {
+				decoded->extra.size = OPSIZE_LONG;
+			}
 		} else if ((*istream & 0xF00) == 0x800) {
 			//BTST, BCHG, BCLR, BSET
 			switch ((*istream >> 6) & 0x3)
@@ -145,10 +148,13 @@
 			}
 			opmode = (*istream >> 3) & 0x7;
 			reg = *istream & 0x7;
-			decoded->src.addr_mode = MODE_IMMEDIATE;
+			decoded->src.addr_mode = MODE_IMMEDIATE_WORD;
 			decoded->src.params.immed = *(++istream) & 0xFF;
 			decoded->extra.size = OPSIZE_BYTE;
-			istream = m68k_decode_op_ex(istream, opmode, reg, OPSIZE_BYTE, &(decoded->dst));
+			istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst));
+			if (decoded->dst.addr_mode == MODE_REG) {
+				decoded->extra.size = OPSIZE_LONG;
+			}
 		} else if ((*istream & 0xC0) == 0xC0) {
 #ifdef M68020
 			//CMP2, CHK2, CAS, CAS2, RTM, CALLM
@@ -407,7 +413,8 @@
 				decoded->dst.addr_mode = m68k_reg_quick_field(*istream);
 			} else {
 				opmode = (*istream >> 3) & 0x7;
-				if ((*istream & 0xB80) == 0x880 && opmode != MODE_REG && opmode != MODE_AREG && opmode != MODE_AREG_POSTINC) {
+				if ((*istream & 0xB80) == 0x880 && opmode != MODE_REG && opmode != MODE_AREG) {
+					//TODO: Check for invalid modes that are dependent on direction
 					decoded->op = M68K_MOVEM;
 					decoded->extra.size = *istream & 0x40 ? OPSIZE_LONG : OPSIZE_WORD;
 					reg = *istream & 0x7;
@@ -1143,6 +1150,7 @@
 	case MODE_AREG_DISPLACE:
 		return sprintf(dst, "%s (a%d, %d)", c, decoded->params.regs.pri, decoded->params.regs.displacement);
 	case MODE_IMMEDIATE:
+	case MODE_IMMEDIATE_WORD:
 		return sprintf(dst, "%s #%d", c, decoded->params.immed);
 	case MODE_ABSOLUTE_SHORT:
 		return sprintf(dst, "%s $%X.w", c, decoded->params.immed);
--- a/68kinst.h	Tue Dec 18 23:55:10 2012 -0800
+++ b/68kinst.h	Wed Dec 19 20:23:59 2012 -0800
@@ -128,6 +128,7 @@
 	MODE_PC_DISPLACE,
 	MODE_PC_INDEX,
 	MODE_IMMEDIATE,
+	MODE_IMMEDIATE_WORD,//used to indicate an immediate operand that only uses a single extension word even for a long operation
 	MODE_UNUSED
 } m68k_addr_modes;
 
--- a/gen_x86.c	Tue Dec 18 23:55:10 2012 -0800
+++ b/gen_x86.c	Wed Dec 19 20:23:59 2012 -0800
@@ -40,6 +40,8 @@
 
 #define OP2_JCC 0x80
 #define OP2_SETCC 0x90
+#define OP2_BT 0xA3
+#define OP2_BTX_I 0xBA
 
 #define OP_EX_ADDI 0x0
 #define OP_EX_ORI  0x1
@@ -59,6 +61,11 @@
 #define OP_EX_SAL 0x6 //identical to SHL
 #define OP_EX_SAR 0x7
 
+#define OP_EX_BT  0x4
+#define OP_EX_BTS 0x5
+#define OP_EX_BTR 0x6
+#define OP_EX_BTC 0x7
+
 #define BIT_IMMED_RAX 0x4
 #define BIT_DIR 0x2
 #define BIT_SIZE 0x1
@@ -880,6 +887,106 @@
 	return out;
 }
 
+uint8_t * bt_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
+{
+	if (size == SZ_W) {
+		*(out++) = PRE_SIZE;
+	}
+	if (size == SZ_Q || src >= R8 || dst >= R8) {
+		*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++;
+	}
+	*(out++) = PRE_2BYTE;
+	*(out++) = OP2_BT;
+	*(out++) = MODE_REG_DIRECT | dst | (src << 3);
+	return out;
+}
+
+uint8_t * bt_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_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_BT;
+	*(out++) = MODE_REG_DISPLACE8 | dst_base | (src << 3);
+	*(out++) = dst_disp;
+	return out;
+}
+
+uint8_t * bt_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size)
+{
+	if (size == SZ_W) {
+		*(out++) = PRE_SIZE;
+	}
+	if (size == SZ_Q || dst >= R8) {
+		*out = PRE_REX;
+		if (size == SZ_Q) {
+			*out |= REX_QUAD;
+		}
+		if (dst >= R8) {
+			*out |= REX_RM_FIELD;
+			dst -= (R8 - X86_R8);
+		}
+		out++;
+	}
+	*(out++) = PRE_2BYTE;
+	*(out++) = OP2_BTX_I;
+	*(out++) = MODE_REG_DIRECT | dst | (OP_EX_BT << 3);
+	*(out++) = val;
+	return out;
+}
+
+uint8_t * bt_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t dst_disp, uint8_t size)
+{
+	if (size == SZ_W) {
+		*(out++) = PRE_SIZE;
+	}
+	if (size == SZ_Q || dst_base >= R8) {
+		*out = PRE_REX;
+		if (size == SZ_Q) {
+			*out |= REX_QUAD;
+		}
+		if (dst_base >= R8) {
+			*out |= REX_RM_FIELD;
+			dst_base -= (R8 - X86_R8);
+		}
+		out++;
+	}
+	*(out++) = PRE_2BYTE;
+	*(out++) = OP2_BTX_I;
+	*(out++) = MODE_REG_DISPLACE8 | dst_base | (OP_EX_BT << 3);
+	*(out++) = dst_disp;
+	*(out++) = val;
+	return out;
+}
+
 uint8_t * jcc(uint8_t * out, uint8_t cc, uint8_t * dest)
 {
 	ptrdiff_t disp = dest-(out+2);
--- a/gen_x86.h	Tue Dec 18 23:55:10 2012 -0800
+++ b/gen_x86.h	Wed Dec 19 20:23:59 2012 -0800
@@ -136,6 +136,10 @@
 uint8_t * pop_r(uint8_t * out, uint8_t reg);
 uint8_t * setcc_r(uint8_t * out, uint8_t cc, uint8_t dst);
 uint8_t * setcc_rind(uint8_t * out, uint8_t cc, uint8_t dst);
+uint8_t * bt_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size);
+uint8_t * bt_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t dst_disp, uint8_t size);
+uint8_t * bt_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size);
+uint8_t * bt_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t dst_disp, uint8_t size);
 uint8_t * jcc(uint8_t * out, uint8_t cc, uint8_t *dest);
 uint8_t * jmp(uint8_t * out, uint8_t *dest);
 uint8_t * call(uint8_t * out, uint8_t * fun);
--- a/m68k_to_x86.c	Tue Dec 18 23:55:10 2012 -0800
+++ b/m68k_to_x86.c	Wed Dec 19 20:23:59 2012 -0800
@@ -175,8 +175,9 @@
 		ea->base = SCRATCH1;
 		break;
 	case MODE_IMMEDIATE:
+	case MODE_IMMEDIATE_WORD:
 		if (inst->variant != VAR_QUICK) {
-			if (inst->extra.size == OPSIZE_LONG) {
+			if (inst->extra.size == OPSIZE_LONG && inst->src.addr_mode == MODE_IMMEDIATE) {
 				out = cycles(out, BUS);
 				out = check_cycles(out);
 			}
@@ -254,6 +255,32 @@
 		ea->mode = MODE_REG_DIRECT;
 		ea->base = SCRATCH1;
 		break;
+	case MODE_ABSOLUTE:
+	case MODE_ABSOLUTE_SHORT:
+		//Add cycles for reading address from instruction stream
+		if (inst->dst.addr_mode == MODE_ABSOLUTE) {
+			out = cycles(out, BUS*2);
+		} else {
+			out = cycles(out, BUS);
+		}
+		out = mov_ir(out, inst->dst.params.immed, SCRATCH1, SZ_D);
+		out = push_r(out, SCRATCH1);
+		switch (inst->extra.size)
+		{
+		case OPSIZE_BYTE:
+			out = call(out, (char *)m68k_read_byte_scratch1);
+			break;
+		case OPSIZE_WORD:
+			out = call(out, (char *)m68k_read_word_scratch1);
+			break;
+		case OPSIZE_LONG:
+			out = call(out, (char *)m68k_read_long_scratch1);
+			break;
+		}
+		out = pop_r(out, SCRATCH2);
+		ea->mode = MODE_REG_DIRECT;
+		ea->base = SCRATCH1;
+		break;
 	default:
 		printf("address mode %d not implemented (dst)\n", inst->dst.addr_mode);
 		exit(1);
@@ -1010,7 +1037,46 @@
 	case M68K_BCHG:
 	case M68K_BCLR:
 	case M68K_BSET:
+		break;
 	case M68K_BTST:
+		dst = cycles(dst, inst->extra.size == OPSIZE_BYTE ? 4 : 6);
+		if (src_op.mode == MODE_IMMEDIATE) {
+			if (inst->extra.size == OPSIZE_BYTE) {
+				src_op.disp &= 0x7;
+			}
+			if (dst_op.mode == MODE_REG_DIRECT) {
+				dst = bt_ir(dst, src_op.disp, dst_op.base, SZ_D);
+			} else {
+				dst = bt_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, SZ_D);
+			}
+		} else {
+			if (src_op.mode == MODE_REG_DISPLACE8) {
+				if (dst_op.base == SCRATCH1) {
+					dst = push_r(dst, SCRATCH2);
+					dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH2, SZ_B);
+					src_op.base = SCRATCH1;
+				} else {
+					dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH1, SZ_B);
+					src_op.base = SCRATCH1;
+				}
+			}
+			if (inst->extra.size == OPSIZE_BYTE) {
+				dst = and_ir(dst, 0x7, src_op.base, SZ_B);
+			}
+			if (dst_op.mode == MODE_REG_DIRECT) {
+				dst = bt_rr(dst, src_op.base, dst_op.base, SZ_D);
+			} else {
+				dst = bt_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, SZ_D);
+			}
+		}
+		//x86 sets the carry flag to the value of the bit tested
+		//68K sets the zero flag to the complement of the bit tested
+		dst = setcc_r(dst, CC_NC, FLAG_Z);
+		if (src_op.base == SCRATCH2) {
+			dst = pop_r(dst, SCRATCH2);
+		}
+		dst = m68k_save_result(inst, dst, opts);
+		break;
 	case M68K_CHK:
 		break;
 	case M68K_CMP:
@@ -1096,7 +1162,6 @@
 		dst = mov_rr(dst, CONTEXT, RDI, SZ_Q);
 		dst = call(dst, (uint8_t *)print_regs_exit);
 		break;
-	case M68K_JMP:
 	case M68K_JSR:
 	case M68K_LEA:
 	case M68K_LINK: