changeset 1458:b81428ef0396

Fix a bunch of 68K instruction decoder bugs revealed by r57shell/realmonster's test ROM
author Michael Pavone <pavone@retrodev.com>
date Wed, 06 Sep 2017 22:14:51 -0700
parents bbba92f56f47
children 34ebc6dab75c
files 68kinst.c
diffstat 1 files changed, 37 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/68kinst.c	Wed Aug 30 01:58:22 2017 -0700
+++ b/68kinst.c	Wed Sep 06 22:14:51 2017 -0700
@@ -274,6 +274,14 @@
 	return 1;
 }
 
+uint8_t m68k_valid_movem_dst(m68k_op_info *dst)
+{
+	if (dst->addr_mode == MODE_REG || dst->addr_mode == MODE_AREG_POSTINC) {
+		return 0;
+	}
+	return m68k_valid_immed_limited_dst(dst);
+}
+
 uint16_t *m68k_decode_op(uint16_t *cur, uint8_t size, m68k_op_info *dst)
 {
 	uint8_t mode = (*cur >> 3) & 0x7;
@@ -346,7 +354,10 @@
 			decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
 			decoded->extra.size = OPSIZE_BYTE;
 			istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->dst));
-			if (!istream) {
+			if (
+				!istream || decoded->dst.addr_mode == MODE_AREG 
+				|| (decoded->op != M68K_BTST && !m68k_valid_immed_limited_dst(&decoded->dst))
+			) {
 				decoded->op = M68K_INVALID;
 				break;
 			}
@@ -376,7 +387,7 @@
 			decoded->src.params.immed = *(++istream) & 0xFF;
 			decoded->extra.size = OPSIZE_BYTE;
 			istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst));
-			if (!istream) {
+			if (!istream || !m68k_valid_immed_dst(&decoded->dst)) {
 				decoded->op = M68K_INVALID;
 				break;
 			}
@@ -521,6 +532,9 @@
 				break;
 			case 4:
 				//BTST, BCHG, BCLR, BSET
+				//Seems like this should be unnecessary since bit instructions are explicitly handled above
+				//Possible this is redundant or the case above is overly restrictive
+				//TODO: Investigate whether this can be removed
 				switch ((*istream >> 6) & 0x3)
 				{
 				case 0:
@@ -536,10 +550,13 @@
 					decoded->op = M68K_BSET;
 					break;
 				}
-				decoded->src.addr_mode = MODE_IMMEDIATE;
+				decoded->src.addr_mode = MODE_IMMEDIATE_WORD;
 				decoded->src.params.immed = *(++istream) & 0xFF;
 				istream = m68k_decode_op(istream, OPSIZE_BYTE, &(decoded->dst));
-				if (!istream) {
+				if (
+					!istream || !m68k_valid_immed_dst(&decoded->dst) 
+					|| (decoded->op != M68K_BTST && !m68k_valid_immed_limited_dst(&decoded->dst))
+				) {
 					decoded->op = M68K_INVALID;
 					break;
 				}
@@ -643,7 +660,7 @@
 			break;
 		}
 		istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst));
-		if (!istream || decoded->dst.addr_mode == MODE_IMMEDIATE) {
+		if (!istream || decoded->dst.addr_mode > MODE_ABSOLUTE || (decoded->dst.addr_mode == MODE_AREG && optype == MOVE_BYTE)) {
 			decoded->op = M68K_INVALID;
 			break;
 		}
@@ -681,7 +698,7 @@
 				decoded->dst.addr_mode = MODE_REG;
 				decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
 				istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
-				if (!istream) {
+				if (!istream || decoded->src.addr_mode == MODE_AREG) {
 					decoded->op = M68K_INVALID;
 					break;
 				}
@@ -708,7 +725,7 @@
 						decoded->src.addr_mode = MODE_REG;
 						decoded->src.params.immed = *(++istream);
 						istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst));
-						if (!istream) {
+						if (!istream || !m68k_valid_movem_dst(&decoded->dst)) {
 							decoded->op = M68K_INVALID;
 							break;
 						}
@@ -728,7 +745,7 @@
 						}
 						decoded->extra.size = size;
 						istream= m68k_decode_op(istream, size, &(decoded->dst));
-						if (!istream) {
+						if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
 							decoded->op = M68K_INVALID;
 							break;
 						}
@@ -747,7 +764,7 @@
 						}
 						decoded->extra.size = size;
 						istream= m68k_decode_op(istream, size, &(decoded->dst));
-						if (!istream) {
+						if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
 							decoded->op = M68K_INVALID;
 							break;
 						}
@@ -758,14 +775,14 @@
 							decoded->op = M68K_MOVE_CCR;
 							size = OPSIZE_WORD;
 							istream= m68k_decode_op(istream, size, &(decoded->src));
-							if (!istream) {
+							if (!istream || decoded->src.addr_mode == MODE_AREG) {
 								decoded->op = M68K_INVALID;
 								break;
 							}
 						} else {
 							decoded->op = M68K_NEG;
 							istream= m68k_decode_op(istream, size, &(decoded->dst));
-							if (!istream) {
+							if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
 								decoded->op = M68K_INVALID;
 								break;
 							}
@@ -778,14 +795,14 @@
 							decoded->op = M68K_MOVE_SR;
 							size = OPSIZE_WORD;
 							istream= m68k_decode_op(istream, size, &(decoded->src));
-							if (!istream) {
+							if (!istream || decoded->src.addr_mode == MODE_AREG) {
 								decoded->op = M68K_INVALID;
 								break;
 							}
 						} else {
 							decoded->op = M68K_NOT;
 							istream= m68k_decode_op(istream, size, &(decoded->dst));
-							if (!istream) {
+							if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
 								decoded->op = M68K_INVALID;
 								break;
 							}
@@ -840,7 +857,7 @@
 								decoded->op = M68K_NBCD;
 								decoded->extra.size = OPSIZE_BYTE;
 								istream = m68k_decode_op(istream, OPSIZE_BYTE, &(decoded->dst));
-								if (!istream) {
+								if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
 									decoded->op = M68K_INVALID;
 									break;
 								}
@@ -884,6 +901,12 @@
 									decoded->op = M68K_INVALID;
 									break;
 								}
+#ifndef M68020
+								if (!m68k_valid_immed_limited_dst(&decoded->src)) {
+									decoded->op = M68K_INVALID;
+									break;
+								}
+#endif
 							}
 						}
 						break;