changeset 2133:8554751f17b5

Remove use of get_native_pointer in 68K instruction decoding in preparation for word RAM interleaving
author Michael Pavone <pavone@retrodev.com>
date Thu, 17 Mar 2022 22:41:42 -0700
parents 7451f970ee66
children 9caebcfeac72
files 68kinst.c 68kinst.h backend.h backend_x86.c debug.c gdb_remote.c m68k_core.c m68k_core.h
diffstat 8 files changed, 469 insertions(+), 401 deletions(-) [+]
line wrap: on
line diff
--- a/68kinst.c	Thu Mar 17 22:40:49 2022 -0700
+++ b/68kinst.c	Thu Mar 17 22:41:42 2022 -0700
@@ -17,7 +17,9 @@
 	return (val & 0x80) ? val | 0xFFFFFF00 : val;
 }
 
-uint16_t *m68k_decode_op_ex(uint16_t *cur, uint8_t mode, uint8_t reg, uint8_t size, m68k_op_info *dst)
+#define INVALID_ADDRESS 0xFFFFFFFF
+
+uint32_t m68k_decode_op_ex(uint16_t opcode, uint32_t address, m68k_fetch_fun fetch, void *data, uint8_t mode, uint8_t reg, uint8_t size, m68k_op_info *dst)
 {
 	uint16_t ext, tmp;
 	dst->addr_mode = mode;
@@ -31,13 +33,15 @@
 		dst->params.regs.pri = reg;
 		break;
 	case MODE_AREG_DISPLACE:
-		ext = *(++cur);
+		ext = fetch(address, data);
+		address += 2;
 		dst->params.regs.pri = reg;
 		dst->params.regs.displacement = sign_extend16(ext);
 		break;
 	case MODE_AREG_INDEX_MEM:
 		dst->params.regs.pri = reg;
-		ext = *(++cur);
+		ext = fetch(address, data);
+		address += 2;
 		dst->params.regs.sec = ext >> 11;//includes areg/dreg bit, reg num and word/long bit
 #ifdef M68020
 		dst->params.regs.scale = ext >> 9 & 3;
@@ -48,16 +52,19 @@
 			{
 			case 0:
 				//reserved
-				return NULL;
+				return INVALID_ADDRESS;
 			case 1:
 				dst->params.regs.displacement = 0;
 				break;
 			case 2:
-				dst->params.regs.displacement = sign_extend16(*(cur++));
+				dst->params.regs.displacement = sign_extend16(fetch(address, data));
+				address += 2;
 				break;
 			case 3:
-				tmp = *(cur++);
-				dst->params.regs.displacement = tmp << 16 | *(cur++);
+				tmp = fetch(address, data);
+				address += 2;
+				dst->params.regs.displacement = tmp << 16 | fetch(address, data);
+				address += 2;
 				break;
 			}
 			if (ext & 0x3)
@@ -89,16 +96,19 @@
 				{
 				case 0:
 					//reserved
-					return NULL;
+					return INVALID_ADDRESS;
 				case 1:
 					dst->params.regs.outer_disp = 0;
 					break;
 				case 2:
-					dst->params.regs.outer_disp = sign_extend16(*(cur++));
+					dst->params.regs.outer_disp = sign_extend16(fetch(address, data));
+					address += 2;
 					break;
 				case 3:
-					tmp = *(cur++);
-					dst->params.regs.outer_disp = tmp << 16 | *(cur++);
+					tmp = fetch(address, data);
+					address += 2;
+					dst->params.regs.outer_disp = tmp << 16 | fetch(address, data);
+					address += 2;
 					break;
 				}
 			} else {
@@ -131,16 +141,20 @@
 		{
 		case 0:
 			dst->addr_mode = MODE_ABSOLUTE_SHORT;
-			ext = *(++cur);
+			ext = fetch(address, data);
+			address += 2;
 			dst->params.immed = sign_extend16(ext);
 			break;
 		case 1:
 			dst->addr_mode = MODE_ABSOLUTE;
-			ext = *(++cur);
-			dst->params.immed = ext << 16 | *(++cur);
+			ext = fetch(address, data);
+			address += 2;
+			dst->params.immed = ext << 16 | fetch(address, data);
+			address += 2;
 			break;
 		case 3:
-			ext = *(++cur);
+			ext = fetch(address, data);
+			address += 2;
 			dst->params.regs.sec = ext >> 11;//includes areg/dreg bit, reg num and word/long bit
 #ifdef M68020
 			dst->params.regs.scale = ext >> 9 & 3;
@@ -151,16 +165,18 @@
 				{
 				case 0:
 					//reserved
-					return NULL;
+					return INVALID_ADDRESS;
 				case 1:
 					dst->params.regs.displacement = 0;
 					break;
 				case 2:
-					dst->params.regs.displacement = sign_extend16(*(cur++));
+					dst->params.regs.displacement = sign_extend16(fetch(address, data));
+					address += 2;
 					break;
 				case 3:
 					tmp = *(cur++);
-					dst->params.regs.displacement = tmp << 16 | *(cur++);
+					dst->params.regs.displacement = tmp << 16 | fetch(address, data);
+					address += 2;
 					break;
 				}
 				if (ext & 0x3)
@@ -192,16 +208,19 @@
 					{
 					case 0:
 						//reserved
-						return NULL;
+						return INVALID_ADDRESS;
 					case 1:
 						dst->params.regs.outer_disp = 0;
 						break;
 					case 2:
-						dst->params.regs.outer_disp = sign_extend16(*(cur++));
+						dst->params.regs.outer_disp = sign_extend16(fetch(address, data));
+						address += 2;
 						break;
 					case 3:
-						tmp = *(cur++);
-						dst->params.regs.outer_disp = tmp << 16 | *(cur++);
+						tmp = fetch(address, data);
+						address += 2;
+						dst->params.regs.outer_disp = tmp << 16 | fetch(address, data);
+						address += 2;
 						break;
 					}
 				} else {
@@ -231,12 +250,14 @@
 			break;
 		case 2:
 			dst->addr_mode = MODE_PC_DISPLACE;
-			ext = *(++cur);
+			ext = fetch(address, data);
+			address += 2;
 			dst->params.regs.displacement = sign_extend16(ext);
 			break;
 		case 4:
 			dst->addr_mode = MODE_IMMEDIATE;
-			ext = *(++cur);
+			ext = fetch(address, data);
+			address += 2;
 			switch (size)
 			{
 			case OPSIZE_BYTE:
@@ -246,16 +267,17 @@
 				dst->params.immed = ext;
 				break;
 			case OPSIZE_LONG:
-				dst->params.immed = ext << 16 | *(++cur);
+				dst->params.immed = ext << 16 | fetch(address, data);
+				address += 2;
 				break;
 			}
 			break;
 		default:
-			return NULL;
+			return INVALID_ADDRESS;
 		}
 		break;
 	}
-	return cur;
+	return address;
 }
 
 uint8_t m68k_valid_immed_dst(m68k_op_info *dst)
@@ -290,11 +312,11 @@
 	return m68k_valid_immed_limited_dst(dst);
 }
 
-uint16_t *m68k_decode_op(uint16_t *cur, uint8_t size, m68k_op_info *dst)
+uint32_t m68k_decode_op(uint16_t opcode, uint32_t address, m68k_fetch_fun fetch, void *data, uint8_t size, m68k_op_info *dst)
 {
-	uint8_t mode = (*cur >> 3) & 0x7;
-	uint8_t reg = *cur & 0x7;
-	return m68k_decode_op_ex(cur, mode, reg, size, dst);
+	uint8_t mode = (opcode >> 3) & 0x7;
+	uint8_t reg = opcode & 0x7;
+	return m68k_decode_op_ex(opcode, address, fetch, data, mode, reg, size, dst);
 }
 
 void m68k_decode_cond(uint16_t op, m68kinst * decoded)
@@ -307,10 +329,12 @@
 	return (op >> 9) & 0x7;
 }
 
-uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
+uint32_t m68k_decode(m68k_fetch_fun fetch, void *data, m68kinst * decoded, uint32_t address)
 {
-	uint16_t *start = istream;
-	uint8_t optype = *istream >> 12;
+	uint32_t start_address = address;
+	uint16_t opcode = fetch(address, data);
+	address += 2;
+	uint8_t optype = opcode >> 12;
 	uint8_t size;
 	uint8_t reg;
 	uint8_t opmode;
@@ -318,32 +342,34 @@
 	decoded->op = M68K_INVALID;
 	decoded->src.addr_mode = decoded->dst.addr_mode = MODE_UNUSED;
 	decoded->variant = VAR_NORMAL;
-	decoded->address = address;
+	decoded->address = start_address;
 	switch(optype)
 	{
 	case BIT_MOVEP_IMMED:
-		if ((*istream & 0x138) == 0x108) {
+		if ((opcode & 0x138) == 0x108) {
 			//MOVEP
 			decoded->op = M68K_MOVEP;
-			decoded->extra.size = *istream & 0x40 ? OPSIZE_LONG : OPSIZE_WORD;
-			if (*istream & 0x80) {
+			decoded->extra.size = opcode & 0x40 ? OPSIZE_LONG : OPSIZE_WORD;
+			if (opcode & 0x80) {
 				//memory dest
 				decoded->src.addr_mode = MODE_REG;
-				decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
+				decoded->src.params.regs.pri = m68k_reg_quick_field(opcode);
 				decoded->dst.addr_mode = MODE_AREG_DISPLACE;
-				decoded->dst.params.regs.pri = *istream & 0x7;
-				decoded->dst.params.regs.displacement = *(++istream);
+				decoded->dst.params.regs.pri = opcode & 0x7;
+				decoded->dst.params.regs.displacement = fetch(address, data);
+				address += 2;
 			} else {
 				//memory source
 				decoded->dst.addr_mode = MODE_REG;
-				decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
+				decoded->dst.params.regs.pri = m68k_reg_quick_field(opcode);
 				decoded->src.addr_mode = MODE_AREG_DISPLACE;
-				decoded->src.params.regs.pri = *istream & 0x7;
-				decoded->src.params.regs.displacement = *(++istream);
+				decoded->src.params.regs.pri = opcode & 0x7;
+				decoded->src.params.regs.displacement = fetch(address, data);
+				address += 2;
 			}
-		} else if (*istream & 0x100) {
+		} else if (opcode & 0x100) {
 			//BTST, BCHG, BCLR, BSET
-			switch ((*istream >> 6) & 0x3)
+			switch ((opcode >> 6) & 0x3)
 			{
 			case 0:
 				decoded->op = M68K_BTST;
@@ -359,11 +385,11 @@
 				break;
 			}
 			decoded->src.addr_mode = MODE_REG;
-			decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
+			decoded->src.params.regs.pri = m68k_reg_quick_field(opcode);
 			decoded->extra.size = OPSIZE_BYTE;
-			istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->dst));
+			address = m68k_decode_op(opcode, address, fetch, data, decoded->extra.size, &(decoded->dst));
 			if (
-				!istream || decoded->dst.addr_mode == MODE_AREG 
+				address == INVALID_ADDRESS || decoded->dst.addr_mode == MODE_AREG
 				|| (decoded->op != M68K_BTST && !m68k_valid_immed_limited_dst(&decoded->dst))
 			) {
 				decoded->op = M68K_INVALID;
@@ -372,9 +398,9 @@
 			if (decoded->dst.addr_mode == MODE_REG) {
 				decoded->extra.size = OPSIZE_LONG;
 			}
-		} else if ((*istream & 0xF00) == 0x800) {
+		} else if ((opcode & 0xF00) == 0x800) {
 			//BTST, BCHG, BCLR, BSET
-			switch ((*istream >> 6) & 0x3)
+			switch ((opcode >> 6) & 0x3)
 			{
 			case 0:
 				decoded->op = M68K_BTST;
@@ -389,14 +415,15 @@
 				decoded->op = M68K_BSET;
 				break;
 			}
-			opmode = (*istream >> 3) & 0x7;
-			reg = *istream & 0x7;
+			opmode = (opcode >> 3) & 0x7;
+			reg = opcode & 0x7;
 			decoded->src.addr_mode = MODE_IMMEDIATE_WORD;
-			decoded->src.params.immed = *(++istream) & 0xFF;
+			decoded->src.params.immed = fetch(address, data) & 0xFF;
+			address += 2;
 			decoded->extra.size = OPSIZE_BYTE;
-			istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst));
+			address = m68k_decode_op_ex(opcode, address, fetch, data, opmode, reg, decoded->extra.size, &(decoded->dst));
 			if (
-				!istream || !m68k_valid_immed_dst(&decoded->dst)
+				address == INVALID_ADDRESS || !m68k_valid_immed_dst(&decoded->dst)
 				|| (decoded->op != M68K_BTST && !m68k_valid_immed_limited_dst(&decoded->dst))
 			) {
 				decoded->op = M68K_INVALID;
@@ -405,46 +432,52 @@
 			if (decoded->dst.addr_mode == MODE_REG) {
 				decoded->extra.size = OPSIZE_LONG;
 			}
-		} else if ((*istream & 0xC0) == 0xC0) {
+		} else if ((opcode & 0xC0) == 0xC0) {
 #ifdef M68020
 			//CMP2, CHK2, CAS, CAS2, RTM, CALLM
 #endif
 		} else {
-			switch ((*istream >> 9) & 0x7)
+			switch ((opcode >> 9) & 0x7)
 			{
 			case 0:
-				if ((*istream & 0xFF) == 0x3C) {
+				if ((opcode & 0xFF) == 0x3C) {
 					decoded->op = M68K_ORI_CCR;
 					decoded->extra.size = OPSIZE_BYTE;
 					decoded->src.addr_mode = MODE_IMMEDIATE;
-					decoded->src.params.immed = *(++istream) & 0xFF;
-				} else if((*istream & 0xFF) == 0x7C) {
+					decoded->src.params.immed = fetch(address, data) & 0xFF;
+					address += 2;
+				} else if((opcode & 0xFF) == 0x7C) {
 					decoded->op = M68K_ORI_SR;
 					decoded->extra.size = OPSIZE_WORD;
 					decoded->src.addr_mode = MODE_IMMEDIATE;
-					decoded->src.params.immed = *(++istream);
+					decoded->src.params.immed = fetch(address, data);
+					address += 2;
 				} else {
 					decoded->op = M68K_OR;
 					decoded->variant = VAR_IMMEDIATE;
 					decoded->src.addr_mode = MODE_IMMEDIATE;
-					decoded->extra.size = size = (*istream >> 6) & 3;
-					reg = *istream & 0x7;
-					opmode = (*istream >> 3) & 0x7;
+					decoded->extra.size = size = (opcode >> 6) & 3;
+					reg = opcode & 0x7;
+					opmode = (opcode >> 3) & 0x7;
 					switch (size)
 					{
 					case OPSIZE_BYTE:
-						decoded->src.params.immed = *(++istream) & 0xFF;
+						decoded->src.params.immed = fetch(address, data) & 0xFF;
+						address += 2;
 						break;
 					case OPSIZE_WORD:
-						decoded->src.params.immed = *(++istream);
+						decoded->src.params.immed = fetch(address, data);
+						address += 2;
 						break;
 					case OPSIZE_LONG:
-						immed = *(++istream);
-						decoded->src.params.immed = immed << 16 | *(++istream);
+						immed = fetch(address, data);
+						address += 2;
+						decoded->src.params.immed = immed << 16 | fetch(address, data);
+						address += 2;
 						break;
 					}
-					istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst));
-					if (!istream || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
+					address = m68k_decode_op_ex(opcode, address, fetch, data, opmode, reg, size, &(decoded->dst));
+					if (address == INVALID_ADDRESS || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
 						decoded->op = M68K_INVALID;
 						break;
 					}
@@ -452,38 +485,44 @@
 				break;
 			case 1:
 				//ANDI, ANDI to CCR, ANDI to SR
-				if ((*istream & 0xFF) == 0x3C) {
+				if ((opcode & 0xFF) == 0x3C) {
 					decoded->op = M68K_ANDI_CCR;
 					decoded->extra.size = OPSIZE_BYTE;
 					decoded->src.addr_mode = MODE_IMMEDIATE;
-					decoded->src.params.immed = *(++istream) & 0xFF;
-				} else if((*istream & 0xFF) == 0x7C) {
+					decoded->src.params.immed = fetch(address, data) & 0xFF;
+					address += 2;
+				} else if((opcode & 0xFF) == 0x7C) {
 					decoded->op = M68K_ANDI_SR;
 					decoded->extra.size = OPSIZE_WORD;
 					decoded->src.addr_mode = MODE_IMMEDIATE;
-					decoded->src.params.immed = *(++istream);
+					decoded->src.params.immed = fetch(address, data);
+					address += 2;
 				} else {
 					decoded->op = M68K_AND;
 					decoded->variant = VAR_IMMEDIATE;
 					decoded->src.addr_mode = MODE_IMMEDIATE;
-					decoded->extra.size = size = (*istream >> 6) & 3;
-					reg = *istream & 0x7;
-					opmode = (*istream >> 3) & 0x7;
+					decoded->extra.size = size = (opcode >> 6) & 3;
+					reg = opcode & 0x7;
+					opmode = (opcode >> 3) & 0x7;
 					switch (size)
 					{
 					case OPSIZE_BYTE:
-						decoded->src.params.immed = *(++istream) & 0xFF;
+						decoded->src.params.immed = fetch(address, data) & 0xFF;
+						address += 2;
 						break;
 					case OPSIZE_WORD:
-						decoded->src.params.immed = *(++istream);
+						decoded->src.params.immed = fetch(address, data);
+						address += 2;
 						break;
 					case OPSIZE_LONG:
-						immed = *(++istream);
-						decoded->src.params.immed = immed << 16 | *(++istream);
+						immed = fetch(address, data);
+						address += 2;
+						decoded->src.params.immed = immed << 16 | fetch(address, data);
+						address += 2;
 						break;
 					}
-					istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst));
-					if (!istream || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
+					address = m68k_decode_op_ex(opcode, address, fetch, data, opmode, reg, size, &(decoded->dst));
+					if (address == INVALID_ADDRESS || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
 						decoded->op = M68K_INVALID;
 						break;
 					}
@@ -493,24 +532,28 @@
 				decoded->op = M68K_SUB;
 				decoded->variant = VAR_IMMEDIATE;
 				decoded->src.addr_mode = MODE_IMMEDIATE;
-				decoded->extra.size = size = (*istream >> 6) & 3;
-				reg = *istream & 0x7;
-				opmode = (*istream >> 3) & 0x7;
+				decoded->extra.size = size = (opcode >> 6) & 3;
+				reg = opcode & 0x7;
+				opmode = (opcode >> 3) & 0x7;
 				switch (size)
 				{
 				case OPSIZE_BYTE:
-					decoded->src.params.immed = *(++istream) & 0xFF;
+					decoded->src.params.immed = fetch(address, data) & 0xFF;
+					address += 2;
 					break;
 				case OPSIZE_WORD:
-					decoded->src.params.immed = *(++istream);
+					decoded->src.params.immed = fetch(address, data);
+					address += 2;
 					break;
 				case OPSIZE_LONG:
-					immed = *(++istream);
-					decoded->src.params.immed = immed << 16 | *(++istream);
+					immed = fetch(address, data);
+					address += 2;
+					decoded->src.params.immed = immed << 16 | fetch(address, data);
+					address += 2;
 					break;
 				}
-				istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst));
-				if (!istream || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
+				address = m68k_decode_op_ex(opcode, address, fetch, data, opmode, reg, size, &(decoded->dst));
+				if (address == INVALID_ADDRESS || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
 					decoded->op = M68K_INVALID;
 					break;
 				}
@@ -519,24 +562,28 @@
 				decoded->op = M68K_ADD;
 				decoded->variant = VAR_IMMEDIATE;
 				decoded->src.addr_mode = MODE_IMMEDIATE;
-				decoded->extra.size = size = (*istream >> 6) & 3;
-				reg = *istream & 0x7;
-				opmode = (*istream >> 3) & 0x7;
+				decoded->extra.size = size = (opcode >> 6) & 3;
+				reg = opcode & 0x7;
+				opmode = (opcode >> 3) & 0x7;
 				switch (size)
 				{
 				case OPSIZE_BYTE:
-					decoded->src.params.immed = *(++istream) & 0xFF;
+					decoded->src.params.immed = fetch(address, data) & 0xFF;
+					address += 2;
 					break;
 				case OPSIZE_WORD:
-					decoded->src.params.immed = *(++istream);
+					decoded->src.params.immed = fetch(address, data);
+					address += 2;
 					break;
 				case OPSIZE_LONG:
-					immed = *(++istream);
-					decoded->src.params.immed = immed << 16 | *(++istream);
+					immed = fetch(address, data);
+					address += 2;
+					decoded->src.params.immed = immed << 16 | fetch(address, data);
+					address += 2;
 					break;
 				}
-				istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst));
-				if (!istream || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
+				address = m68k_decode_op_ex(opcode, address, fetch, data, opmode, reg, size, &(decoded->dst));
+				if (address == INVALID_ADDRESS || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
 					decoded->op = M68K_INVALID;
 					break;
 				}
@@ -546,7 +593,7 @@
 				//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)
+				switch ((opcode >> 6) & 0x3)
 				{
 				case 0:
 					decoded->op = M68K_BTST;
@@ -562,10 +609,11 @@
 					break;
 				}
 				decoded->src.addr_mode = MODE_IMMEDIATE_WORD;
-				decoded->src.params.immed = *(++istream) & 0xFF;
-				istream = m68k_decode_op(istream, OPSIZE_BYTE, &(decoded->dst));
+				decoded->src.params.immed = fetch(address, data) & 0xFF;
+				address += 2;
+				address = m68k_decode_op(opcode, address, fetch, data, OPSIZE_BYTE, &(decoded->dst));
 				if (
-					!istream || !m68k_valid_immed_dst(&decoded->dst) 
+					address == INVALID_ADDRESS || !m68k_valid_immed_dst(&decoded->dst)
 					|| (decoded->op != M68K_BTST && !m68k_valid_immed_limited_dst(&decoded->dst))
 				) {
 					decoded->op = M68K_INVALID;
@@ -574,38 +622,44 @@
 				break;
 			case 5:
 				//EORI, EORI to CCR, EORI to SR
-				if ((*istream & 0xFF) == 0x3C) {
+				if ((opcode & 0xFF) == 0x3C) {
 					decoded->op = M68K_EORI_CCR;
 					decoded->extra.size = OPSIZE_BYTE;
 					decoded->src.addr_mode = MODE_IMMEDIATE;
-					decoded->src.params.immed = *(++istream) & 0xFF;
-				} else if((*istream & 0xFF) == 0x7C) {
+					decoded->src.params.immed = fetch(address, data) & 0xFF;
+					address += 2;
+				} else if((opcode & 0xFF) == 0x7C) {
 					decoded->op = M68K_EORI_SR;
 					decoded->extra.size = OPSIZE_WORD;
 					decoded->src.addr_mode = MODE_IMMEDIATE;
-					decoded->src.params.immed = *(++istream);
+					decoded->src.params.immed = fetch(address, data);
+					address += 2;
 				} else {
 					decoded->op = M68K_EOR;
 					decoded->variant = VAR_IMMEDIATE;
 					decoded->src.addr_mode = MODE_IMMEDIATE;
-					decoded->extra.size = size = (*istream >> 6) & 3;
-					reg = *istream & 0x7;
-					opmode = (*istream >> 3) & 0x7;
+					decoded->extra.size = size = (opcode >> 6) & 3;
+					reg = opcode & 0x7;
+					opmode = (opcode >> 3) & 0x7;
 					switch (size)
 					{
 					case OPSIZE_BYTE:
-						decoded->src.params.immed = *(++istream) & 0xFF;
+						decoded->src.params.immed = fetch(address, data) & 0xFF;
+						address += 2;
 						break;
 					case OPSIZE_WORD:
-						decoded->src.params.immed = *(++istream);
+						decoded->src.params.immed = fetch(address, data);
+						address += 2;
 						break;
 					case OPSIZE_LONG:
-						immed = *(++istream);
-						decoded->src.params.immed = immed << 16 | *(++istream);
+						immed = fetch(address, data);
+						address += 2;
+						decoded->src.params.immed = immed << 16 | fetch(address, data);
+						address += 2;
 						break;
 					}
-					istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst));
-					if (!istream || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
+					address = m68k_decode_op_ex(opcode, address, fetch, data, opmode, reg, size, &(decoded->dst));
+					if (address == INVALID_ADDRESS || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
 						decoded->op = M68K_INVALID;
 						break;
 					}
@@ -614,25 +668,29 @@
 			case 6:
 				decoded->op = M68K_CMP;
 				decoded->variant = VAR_IMMEDIATE;
-				decoded->extra.size = (*istream >> 6) & 0x3;
+				decoded->extra.size = (opcode >> 6) & 0x3;
 				decoded->src.addr_mode = MODE_IMMEDIATE;
-				reg = *istream & 0x7;
-				opmode = (*istream >> 3) & 0x7;
+				reg = opcode & 0x7;
+				opmode = (opcode >> 3) & 0x7;
 				switch (decoded->extra.size)
 				{
 				case OPSIZE_BYTE:
-					decoded->src.params.immed = *(++istream) & 0xFF;
+					decoded->src.params.immed = fetch(address, data) & 0xFF;
+					address += 2;
 					break;
 				case OPSIZE_WORD:
-					decoded->src.params.immed = *(++istream);
+					decoded->src.params.immed = fetch(address, data);
+					address += 2;
 					break;
 				case OPSIZE_LONG:
-					immed = *(++istream);
-					decoded->src.params.immed = (immed << 16) | *(++istream);
+					immed = fetch(address, data);
+					address += 2;
+					decoded->src.params.immed = (immed << 16) | fetch(address, data);
+					address += 2;
 					break;
 				}
-				istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst));
-				if (!istream || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
+				address = m68k_decode_op_ex(opcode, address, fetch, data, opmode, reg, decoded->extra.size, &(decoded->dst));
+				if (address == INVALID_ADDRESS || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
 					decoded->op = M68K_INVALID;
 					break;
 				}
@@ -640,16 +698,17 @@
 			case 7:
 #ifdef M68010
 				decoded->op = M68K_MOVES;
-				decoded->extra.size = *istream >> 6 & 0x3;
-				immed = *(++istream);
+				decoded->extra.size = opcode >> 6 & 0x3;
+				immed = fetch(address, data);
+				address += 2;
 				reg = immed  >> 12 & 0x7;
 				opmode = immed & 0x8000 ? MODE_AREG : MODE_REG;
 				if (immed & 0x800) {
 					decoded->src.addr_mode = opmode;
 					decoded->src.params.regs.pri = reg;
-					m68k_decode_op_ex(istream, *start >> 3 & 0x7, *start & 0x7, decoded->extra.size, &(decoded->dst));
+					address = m68k_decode_op_ex(opcode, address, fetch, data, *start >> 3 & 0x7, *start & 0x7, decoded->extra.size, &(decoded->dst));
 				} else {
-					m68k_decode_op_ex(istream, *start >> 3 & 0x7, *start & 0x7, decoded->extra.size, &(decoded->src));
+					address = m68k_decode_op_ex(opcode, address, fetch, data, *start >> 3 & 0x7, *start & 0x7, decoded->extra.size, &(decoded->src));
 					decoded->dst.addr_mode = opmode;
 					decoded->dst.params.regs.pri = reg;
 				}
@@ -663,29 +722,29 @@
 	case MOVE_WORD:
 		decoded->op = M68K_MOVE;
 		decoded->extra.size = optype == MOVE_BYTE ? OPSIZE_BYTE : (optype == MOVE_WORD ? OPSIZE_WORD : OPSIZE_LONG);
-		opmode = (*istream >> 6) & 0x7;
-		reg = m68k_reg_quick_field(*istream);
-		istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
-		if (!istream || (decoded->src.addr_mode == MODE_AREG && optype == MOVE_BYTE)) {
+		opmode = (opcode >> 6) & 0x7;
+		reg = m68k_reg_quick_field(opcode);
+		address = m68k_decode_op(opcode, address, fetch, data, decoded->extra.size, &(decoded->src));
+		if (address == INVALID_ADDRESS || (decoded->src.addr_mode == MODE_AREG && optype == MOVE_BYTE)) {
 			decoded->op = M68K_INVALID;
 			break;
 		}
-		istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst));
-		if (!istream || decoded->dst.addr_mode > MODE_ABSOLUTE || (decoded->dst.addr_mode == MODE_AREG && optype == MOVE_BYTE)) {
+		address = m68k_decode_op_ex(opcode, address, fetch, data, opmode, reg, decoded->extra.size, &(decoded->dst));
+		if (address == INVALID_ADDRESS || decoded->dst.addr_mode > MODE_ABSOLUTE || (decoded->dst.addr_mode == MODE_AREG && optype == MOVE_BYTE)) {
 			decoded->op = M68K_INVALID;
 			break;
 		}
 		break;
 	case MISC:
 
-		if ((*istream & 0x1C0) == 0x1C0) {
+		if ((opcode & 0x1C0) == 0x1C0) {
 			decoded->op = M68K_LEA;
 			decoded->extra.size = OPSIZE_LONG;
 			decoded->dst.addr_mode = MODE_AREG;
-			decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
-			istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
+			decoded->dst.params.regs.pri = m68k_reg_quick_field(opcode);
+			address = m68k_decode_op(opcode, address, fetch, data, decoded->extra.size, &(decoded->src));
 			if (
-				!istream || decoded->src.addr_mode == MODE_REG || decoded->src.addr_mode == MODE_AREG 
+				address == INVALID_ADDRESS || decoded->src.addr_mode == MODE_REG || decoded->src.addr_mode == MODE_AREG
 				|| decoded->src.addr_mode == MODE_AREG_POSTINC || decoded->src.addr_mode == MODE_AREG_PREDEC
 				|| decoded->src.addr_mode == MODE_IMMEDIATE
 			) {
@@ -693,9 +752,9 @@
 				break;
 			}
 		} else {
-			if (*istream & 0x100) {
+			if (opcode & 0x100) {
 				decoded->op = M68K_CHK;
-				if ((*istream & 0x180) == 0x180) {
+				if ((opcode & 0x180) == 0x180) {
 					decoded->extra.size = OPSIZE_WORD;
 				} else {
 					//only on M68020+
@@ -707,24 +766,25 @@
 #endif
 				}
 				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 || decoded->src.addr_mode == MODE_AREG) {
+				decoded->dst.params.regs.pri = m68k_reg_quick_field(opcode);
+				address = m68k_decode_op(opcode, address, fetch, data, decoded->extra.size, &(decoded->src));
+				if (address == INVALID_ADDRESS || decoded->src.addr_mode == MODE_AREG) {
 					decoded->op = M68K_INVALID;
 					break;
 				}
 			} else {
-				opmode = (*istream >> 3) & 0x7;
-				if ((*istream & 0xB80) == 0x880 && opmode != MODE_REG && opmode != MODE_AREG) {
+				opmode = (opcode >> 3) & 0x7;
+				if ((opcode & 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;
-					if(*istream & 0x400) {
+					decoded->extra.size = opcode & 0x40 ? OPSIZE_LONG : OPSIZE_WORD;
+					reg = opcode & 0x7;
+					if(opcode & 0x400) {
 						decoded->dst.addr_mode = MODE_REG;
-						decoded->dst.params.immed = *(++istream);
-						istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->src));
-						if (!istream || decoded->src.addr_mode == MODE_AREG_PREDEC || decoded->src.addr_mode == MODE_IMMEDIATE) {
+						decoded->dst.params.immed = fetch(address, data);
+						address += 2;
+						address = m68k_decode_op_ex(opcode, address, fetch, data, opmode, reg, decoded->extra.size, &(decoded->src));
+						if (address == INVALID_ADDRESS || decoded->src.addr_mode == MODE_AREG_PREDEC || decoded->src.addr_mode == MODE_IMMEDIATE) {
 							decoded->op = M68K_INVALID;
 							break;
 						}
@@ -734,16 +794,17 @@
 						}
 					} else {
 						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 || !m68k_valid_movem_dst(&decoded->dst)) {
+						decoded->src.params.immed = fetch(address, data);
+						address += 2;
+						address = m68k_decode_op_ex(opcode, address, fetch, data, opmode, reg, decoded->extra.size, &(decoded->dst));
+						if (address == INVALID_ADDRESS || !m68k_valid_movem_dst(&decoded->dst)) {
 							decoded->op = M68K_INVALID;
 							break;
 						}
 					}
 				} else {
-					optype = (*istream >> 9) & 0x7;
-					size = (*istream >> 6) & 0x3;
+					optype = (opcode >> 9) & 0x7;
+					size = (opcode >> 6) & 0x3;
 					switch(optype)
 					{
 					case 0:
@@ -755,8 +816,8 @@
 							decoded->op = M68K_NEGX;
 						}
 						decoded->extra.size = size;
-						istream= m68k_decode_op(istream, size, &(decoded->dst));
-						if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
+						address = m68k_decode_op(opcode, address, fetch, data, size, &(decoded->dst));
+						if (address == INVALID_ADDRESS || !m68k_valid_immed_limited_dst(&decoded->dst)) {
 							decoded->op = M68K_INVALID;
 							break;
 						}
@@ -774,8 +835,8 @@
 							decoded->op = M68K_CLR;
 						}
 						decoded->extra.size = size;
-						istream= m68k_decode_op(istream, size, &(decoded->dst));
-						if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
+						address = m68k_decode_op(opcode, address, fetch, data, size, &(decoded->dst));
+						if (address == INVALID_ADDRESS || !m68k_valid_immed_limited_dst(&decoded->dst)) {
 							decoded->op = M68K_INVALID;
 							break;
 						}
@@ -785,15 +846,15 @@
 						if (size == OPSIZE_INVALID) {
 							decoded->op = M68K_MOVE_CCR;
 							size = OPSIZE_WORD;
-							istream= m68k_decode_op(istream, size, &(decoded->src));
-							if (!istream || decoded->src.addr_mode == MODE_AREG) {
+							address = m68k_decode_op(opcode, address, fetch, data, size, &(decoded->src));
+							if (address == INVALID_ADDRESS || 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 || !m68k_valid_immed_limited_dst(&decoded->dst)) {
+							address = m68k_decode_op(opcode, address, fetch, data, size, &(decoded->dst));
+							if (address == INVALID_ADDRESS || !m68k_valid_immed_limited_dst(&decoded->dst)) {
 								decoded->op = M68K_INVALID;
 								break;
 							}
@@ -805,15 +866,15 @@
 						if (size == OPSIZE_INVALID) {
 							decoded->op = M68K_MOVE_SR;
 							size = OPSIZE_WORD;
-							istream= m68k_decode_op(istream, size, &(decoded->src));
-							if (!istream || decoded->src.addr_mode == MODE_AREG) {
+							address = m68k_decode_op(opcode, address, fetch, data, size, &(decoded->src));
+							if (address == INVALID_ADDRESS || 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 || !m68k_valid_immed_limited_dst(&decoded->dst)) {
+							address = m68k_decode_op(opcode, address, fetch, data, size, &(decoded->dst));
+							if (address == INVALID_ADDRESS || !m68k_valid_immed_limited_dst(&decoded->dst)) {
 								decoded->op = M68K_INVALID;
 								break;
 							}
@@ -822,21 +883,23 @@
 						break;
 					case 4:
 						//EXT, EXTB, LINK.l, NBCD, SWAP, BKPT, PEA
-						switch((*istream >> 3) & 0x3F)
+						switch((opcode >> 3) & 0x3F)
 						{
 						case 1:
 #ifdef M68020
 							decoded->op = M68K_LINK;
 							decoded->extra.size = OPSIZE_LONG;
-							reg = *istream & 0x7;
-							immed = *(++istream) << 16;
-							immed |= *(++istream);
+							reg = opcode & 0x7;
+							immed = fetch(address, data) << 16;
+							address += 2;
+							immed |= fetch(address, data);
+							address += 2;
 #endif
 							break;
 						case 8:
 							decoded->op = M68K_SWAP;
 							decoded->src.addr_mode = MODE_REG;
-							decoded->src.params.regs.pri = *istream & 0x7;
+							decoded->src.params.regs.pri = opcode & 0x7;
 							decoded->extra.size = OPSIZE_WORD;
 							break;
 						case 9:
@@ -844,19 +907,19 @@
 							decoded->op = M68K_BKPT;
 							decoded->src.addr_mode = MODE_IMMEDIATE;
 							decoded->extra.size = OPSIZE_UNSIZED;
-							decoded->src.params.immed = *istream & 0x7;
+							decoded->src.params.immed = opcode & 0x7;
 #endif
 							break;
 						case 0x10:
 							decoded->op = M68K_EXT;
 							decoded->dst.addr_mode = MODE_REG;
-							decoded->dst.params.regs.pri = *istream & 0x7;
+							decoded->dst.params.regs.pri = opcode & 0x7;
 							decoded->extra.size = OPSIZE_WORD;
 							break;
 						case 0x18:
 							decoded->op = M68K_EXT;
 							decoded->dst.addr_mode = MODE_REG;
-							decoded->dst.params.regs.pri = *istream & 0x7;
+							decoded->dst.params.regs.pri = opcode & 0x7;
 							decoded->extra.size = OPSIZE_LONG;
 							break;
 						case 0x38:
@@ -864,20 +927,20 @@
 #endif
 							break;
 						default:
-							if (!(*istream & 0x1C0)) {
+							if (!(opcode & 0x1C0)) {
 								decoded->op = M68K_NBCD;
 								decoded->extra.size = OPSIZE_BYTE;
-								istream = m68k_decode_op(istream, OPSIZE_BYTE, &(decoded->dst));
-								if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
+								address = m68k_decode_op(opcode, address, fetch, data, OPSIZE_BYTE, &(decoded->dst));
+								if (address == INVALID_ADDRESS || !m68k_valid_immed_limited_dst(&decoded->dst)) {
 									decoded->op = M68K_INVALID;
 									break;
 								}
-							} else if((*istream & 0x1C0) == 0x40) {
+							} else if((opcode & 0x1C0) == 0x40) {
 								decoded->op = M68K_PEA;
 								decoded->extra.size = OPSIZE_LONG;
-								istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->src));
+								address = m68k_decode_op(opcode, address, fetch, data, OPSIZE_LONG, &(decoded->src));
 								if (
-									!istream || decoded->src.addr_mode == MODE_REG || decoded->src.addr_mode == MODE_AREG 
+									address == INVALID_ADDRESS || decoded->src.addr_mode == MODE_REG || decoded->src.addr_mode == MODE_AREG
 									|| decoded->src.addr_mode == MODE_AREG_POSTINC || decoded->src.addr_mode == MODE_AREG_PREDEC
 									|| decoded->src.addr_mode == MODE_IMMEDIATE
 								) {
@@ -889,7 +952,7 @@
 						break;
 					case 5:
 						//BGND, ILLEGAL, TAS, TST
-						optype = *istream & 0xFF;
+						optype = opcode & 0xFF;
 						if (optype == 0xFA) {
 							//BGND - CPU32 only
 						} else if (optype == 0xFC) {
@@ -899,16 +962,16 @@
 							if (size == OPSIZE_INVALID) {
 								decoded->op = M68K_TAS;
 								decoded->extra.size = OPSIZE_BYTE;
-								istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->dst));
-								if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
+								address = m68k_decode_op(opcode, address, fetch, data, decoded->extra.size, &(decoded->dst));
+								if (address == INVALID_ADDRESS || !m68k_valid_immed_limited_dst(&decoded->dst)) {
 									decoded->op = M68K_INVALID;
 									break;
 								}
 							} else {
 								decoded->op = M68K_TST;
 								decoded->extra.size = size;
-								istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
-								if (!istream) {
+								address = m68k_decode_op(opcode, address, fetch, data, decoded->extra.size, &(decoded->src));
+								if (address == INVALID_ADDRESS) {
 									decoded->op = M68K_INVALID;
 									break;
 								}
@@ -929,17 +992,17 @@
 						break;
 					case 7:
 						//TRAP, LINK.w, UNLNK, MOVE USP, RESET, NOP, STOP, RTE, RTD, RTS, TRAPV, RTR, MOVEC, JSR, JMP
-						if (*istream & 0x80) {
+						if (opcode & 0x80) {
 							//JSR, JMP
-							if (*istream & 0x40) {
+							if (opcode & 0x40) {
 								decoded->op = M68K_JMP;
 							} else {
 								decoded->op = M68K_JSR;
 							}
 							decoded->extra.size = OPSIZE_UNSIZED;
-							istream = m68k_decode_op(istream, OPSIZE_UNSIZED, &(decoded->src));
+							address = m68k_decode_op(opcode, address, fetch, data, OPSIZE_UNSIZED, &(decoded->src));
 							if (
-								!istream 
+								address == INVALID_ADDRESS
 								|| (decoded->src.addr_mode < MODE_AREG_DISPLACE && decoded->src.addr_mode != MODE_AREG_INDIRECT)
 								|| decoded->src.addr_mode == MODE_IMMEDIATE
 							) {
@@ -948,11 +1011,11 @@
 							}
 						} else {
 							//it would appear bit 6 needs to be set for it to be a valid instruction here
-							if (!(*istream & 0x40)) {
+							if (!(opcode & 0x40)) {
 								decoded->op = M68K_INVALID;
 								break;
 							}
-							switch((*istream >> 3) & 0x7)
+							switch((opcode >> 3) & 0x7)
 							{
 							case 0:
 							case 1:
@@ -960,39 +1023,40 @@
 								decoded->op = M68K_TRAP;
 								decoded->extra.size = OPSIZE_UNSIZED;
 								decoded->src.addr_mode = MODE_IMMEDIATE;
-								decoded->src.params.immed = *istream & 0xF;
+								decoded->src.params.immed = opcode & 0xF;
 								break;
 							case 2:
 								//LINK.w
 								decoded->op = M68K_LINK;
 								decoded->extra.size = OPSIZE_WORD;
 								decoded->src.addr_mode = MODE_AREG;
-								decoded->src.params.regs.pri = *istream & 0x7;
+								decoded->src.params.regs.pri = opcode & 0x7;
 								decoded->dst.addr_mode = MODE_IMMEDIATE;
-								decoded->dst.params.immed = sign_extend16(*(++istream));
+								decoded->dst.params.immed = sign_extend16(fetch(address, data));
+								address += 2;
 								break;
 							case 3:
 								//UNLK
 								decoded->op = M68K_UNLK;
 								decoded->extra.size = OPSIZE_UNSIZED;
 								decoded->dst.addr_mode = MODE_AREG;
-								decoded->dst.params.regs.pri = *istream & 0x7;
+								decoded->dst.params.regs.pri = opcode & 0x7;
 								break;
 							case 4:
 							case 5:
 								//MOVE USP
 								decoded->op = M68K_MOVE_USP;
-								if (*istream & 0x8) {
+								if (opcode & 0x8) {
 									decoded->dst.addr_mode = MODE_AREG;
-									decoded->dst.params.regs.pri = *istream & 0x7;
+									decoded->dst.params.regs.pri = opcode & 0x7;
 								} else {
 									decoded->src.addr_mode = MODE_AREG;
-									decoded->src.params.regs.pri = *istream & 0x7;
+									decoded->src.params.regs.pri = opcode & 0x7;
 								}
 								break;
 							case 6:
 								decoded->extra.size = OPSIZE_UNSIZED;
-								switch(*istream & 0x7)
+								switch(opcode & 0x7)
 								{
 								case 0:
 									decoded->op = M68K_RESET;
@@ -1003,7 +1067,8 @@
 								case 2:
 									decoded->op = M68K_STOP;
 									decoded->src.addr_mode = MODE_IMMEDIATE;
-									decoded->src.params.immed =*(++istream);
+									decoded->src.params.immed =fetch(address, data);
+									address += 2;
 									break;
 								case 3:
 									decoded->op = M68K_RTE;
@@ -1012,7 +1077,8 @@
 #ifdef M68010
 									decoded->op = M68K_RTD;
 									decoded->src.addr_mode = MODE_IMMEDIATE;
-									decoded->src.params.immed =*(++istream);
+									decoded->src.params.immed =fetch(address, data);
+									address += 2;
 #endif
 									break;
 								case 5:
@@ -1030,7 +1096,8 @@
 								//MOVEC
 #ifdef M68010
 								decoded->op = M68K_MOVEC;
-								immed = *(++istream);
+								immed = fetch(address, data);
+								address += 2;
 								reg = immed >> 12 & 0x7;
 								opmode = immed & 0x8000 ? MODE_AREG : MODE_REG;
 								immed &= 0xFFF;
@@ -1067,17 +1134,18 @@
 		}
 		break;
 	case QUICK_ARITH_LOOP:
-		size = (*istream >> 6) & 3;
+		size = (opcode >> 6) & 3;
 		if (size == 0x3) {
 			//DBcc, TRAPcc or Scc
-			m68k_decode_cond(*istream, decoded);
-			if (((*istream >> 3) & 0x7) == 1) {
+			m68k_decode_cond(opcode, decoded);
+			if (((opcode >> 3) & 0x7) == 1) {
 				decoded->op = M68K_DBCC;
 				decoded->src.addr_mode = MODE_IMMEDIATE;
 				decoded->dst.addr_mode = MODE_REG;
-				decoded->dst.params.regs.pri = *istream & 0x7;
-				decoded->src.params.immed = sign_extend16(*(++istream));
-			} else if(((*istream >> 3) & 0x7) == 1 && (*istream & 0x7) > 1 && (*istream & 0x7) < 5) {
+				decoded->dst.params.regs.pri = opcode & 0x7;
+				decoded->src.params.immed = sign_extend16(fetch(address, data));
+				address += 2;
+			} else if(((opcode >> 3) & 0x7) == 1 && (opcode & 0x7) > 1 && (opcode & 0x7) < 5) {
 #ifdef M68020
 				decoded->op = M68K_TRAPCC;
 				decoded->src.addr_mode = MODE_IMMEDIATE;
@@ -1085,9 +1153,9 @@
 #endif
 			} else {
 				decoded->op = M68K_SCC;
-				decoded->extra.cond = (*istream >> 8) & 0xF;
-				istream = m68k_decode_op(istream, OPSIZE_BYTE, &(decoded->dst));
-				if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
+				decoded->extra.cond = (opcode >> 8) & 0xF;
+				address = m68k_decode_op(opcode, address, fetch, data, OPSIZE_BYTE, &(decoded->dst));
+				if (address == INVALID_ADDRESS || !m68k_valid_immed_limited_dst(&decoded->dst)) {
 					decoded->op = M68K_INVALID;
 					break;
 				}
@@ -1097,37 +1165,40 @@
 			decoded->variant = VAR_QUICK;
 			decoded->extra.size = size;
 			decoded->src.addr_mode = MODE_IMMEDIATE;
-			immed = m68k_reg_quick_field(*istream);
+			immed = m68k_reg_quick_field(opcode);
 			if (!immed) {
 				immed = 8;
 			}
 			decoded->src.params.immed = immed;
-			if (*istream & 0x100) {
+			if (opcode & 0x100) {
 				decoded->op = M68K_SUB;
 			} else {
 				decoded->op = M68K_ADD;
 			}
-			istream = m68k_decode_op(istream, size, &(decoded->dst));
-			if (!istream || decoded->dst.addr_mode > MODE_ABSOLUTE || (size == OPSIZE_BYTE && decoded->dst.addr_mode == MODE_AREG)) {
+			address = m68k_decode_op(opcode, address, fetch, data, size, &(decoded->dst));
+			if (address == INVALID_ADDRESS || decoded->dst.addr_mode > MODE_ABSOLUTE || (size == OPSIZE_BYTE && decoded->dst.addr_mode == MODE_AREG)) {
 				decoded->op = M68K_INVALID;
 				break;
 			}
 		}
 		break;
 	case BRANCH:
-		m68k_decode_cond(*istream, decoded);
+		m68k_decode_cond(opcode, decoded);
 		decoded->op = decoded->extra.cond == COND_FALSE ? M68K_BSR : M68K_BCC;
 		decoded->src.addr_mode = MODE_IMMEDIATE;
-		immed = *istream & 0xFF;
+		immed = opcode & 0xFF;
 		if (immed == 0) {
 			decoded->variant = VAR_WORD;
-			immed = *(++istream);
+			immed = fetch(address, data);
+			address += 2;
 			immed = sign_extend16(immed);
 #ifdef M68020
 		} else if (immed == 0xFF) {
 			decoded->variant = VAR_LONG;
-			immed = *(++istream) << 16;
-			immed |= *(++istream);
+			immed = fetch(address, data) << 16;
+			address += 2;
+			immed |= fetch(address, data);
+			address += 2;
 #endif
 		} else {
 			decoded->variant = VAR_BYTE;
@@ -1136,7 +1207,7 @@
 		decoded->src.params.immed = immed;
 		break;
 	case MOVEQ:
-		if (*istream & 0x100) {
+		if (opcode & 0x100) {
 			decoded->op = M68K_INVALID;
 			break;
 		}
@@ -1144,25 +1215,25 @@
 		decoded->variant = VAR_QUICK;
 		decoded->extra.size = OPSIZE_LONG;
 		decoded->src.addr_mode = MODE_IMMEDIATE;
-		decoded->src.params.immed = sign_extend8(*istream & 0xFF);
+		decoded->src.params.immed = sign_extend8(opcode & 0xFF);
 		decoded->dst.addr_mode = MODE_REG;
-		decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
-		immed = *istream & 0xFF;
+		decoded->dst.params.regs.pri = m68k_reg_quick_field(opcode);
+		immed = opcode & 0xFF;
 		break;
 	case OR_DIV_SBCD:
 		//for OR, if opmode bit 2 is 1, then src = Dn, dst = <ea>
-		opmode = (*istream >> 6) & 0x7;
+		opmode = (opcode >> 6) & 0x7;
 		size = opmode & 0x3;
-		if (size == OPSIZE_INVALID || (opmode & 0x4 && !(*istream & 0x30))) {
+		if (size == OPSIZE_INVALID || (opmode & 0x4 && !(opcode & 0x30))) {
 			switch(opmode)
 			{
 			case 3:
 				decoded->op = M68K_DIVU;
 				decoded->extra.size = OPSIZE_WORD;
 				decoded->dst.addr_mode = MODE_REG;
-				decoded->dst.params.regs.pri = (*istream >> 9) & 0x7;
-				istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src));
-				if (!istream || decoded->src.addr_mode == MODE_AREG) {
+				decoded->dst.params.regs.pri = (opcode >> 9) & 0x7;
+				address = m68k_decode_op(opcode, address, fetch, data, OPSIZE_WORD, &(decoded->src));
+				if (address == INVALID_ADDRESS || decoded->src.addr_mode == MODE_AREG) {
 					decoded->op = M68K_INVALID;
 					break;
 				}
@@ -1170,9 +1241,9 @@
 			case 4:
 				decoded->op = M68K_SBCD;
 				decoded->extra.size = OPSIZE_BYTE;
-				decoded->dst.addr_mode = decoded->src.addr_mode = *istream & 0x8 ? MODE_AREG_PREDEC : MODE_REG;
-				decoded->src.params.regs.pri = *istream & 0x7;
-				decoded->dst.params.regs.pri = (*istream >> 9) & 0x7;
+				decoded->dst.addr_mode = decoded->src.addr_mode = opcode & 0x8 ? MODE_AREG_PREDEC : MODE_REG;
+				decoded->src.params.regs.pri = opcode & 0x7;
+				decoded->dst.params.regs.pri = (opcode >> 9) & 0x7;
 				break;
 			case 5:
 	#ifdef M68020
@@ -1186,9 +1257,9 @@
 				decoded->op = M68K_DIVS;
 				decoded->extra.size = OPSIZE_WORD;
 				decoded->dst.addr_mode = MODE_REG;
-				decoded->dst.params.regs.pri = (*istream >> 9) & 0x7;
-				istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src));
-				if (!istream || decoded->src.addr_mode == MODE_AREG) {
+				decoded->dst.params.regs.pri = (opcode >> 9) & 0x7;
+				address = m68k_decode_op(opcode, address, fetch, data, OPSIZE_WORD, &(decoded->src));
+				if (address == INVALID_ADDRESS || decoded->src.addr_mode == MODE_AREG) {
 					decoded->op = M68K_INVALID;
 					break;
 				}
@@ -1199,17 +1270,17 @@
 			decoded->extra.size = size;
 			if (opmode & 0x4) {
 				decoded->src.addr_mode = MODE_REG;
-				decoded->src.params.regs.pri = (*istream >> 9) & 0x7;
-				istream = m68k_decode_op(istream, size, &(decoded->dst));
-				if (!istream || !m68k_valid_full_arith_dst(&(decoded->dst))) {
+				decoded->src.params.regs.pri = (opcode >> 9) & 0x7;
+				address = m68k_decode_op(opcode, address, fetch, data, size, &(decoded->dst));
+				if (address == INVALID_ADDRESS || !m68k_valid_full_arith_dst(&(decoded->dst))) {
 					decoded->op = M68K_INVALID;
 					break;
 				}
 			} else {
 				decoded->dst.addr_mode = MODE_REG;
-				decoded->dst.params.regs.pri = (*istream >> 9) & 0x7;
-				istream = m68k_decode_op(istream, size, &(decoded->src));
-				if (!istream || decoded->src.addr_mode == MODE_AREG) {
+				decoded->dst.params.regs.pri = (opcode >> 9) & 0x7;
+				address = m68k_decode_op(opcode, address, fetch, data, size, &(decoded->src));
+				if (address == INVALID_ADDRESS || decoded->src.addr_mode == MODE_AREG) {
 					decoded->op = M68K_INVALID;
 					break;
 				}
@@ -1217,27 +1288,27 @@
 		}
 		break;
 	case SUB_SUBX:
-		size = (*istream >> 6) & 0x3;
+		size = (opcode >> 6) & 0x3;
 		decoded->op = M68K_SUB;
-		if (*istream & 0x100) {
+		if (opcode & 0x100) {
 			//<ea> destination, SUBA.l or SUBX
-			if (*istream & 0x30 || size == OPSIZE_INVALID) {
+			if (opcode & 0x30 || size == OPSIZE_INVALID) {
 				if (size == OPSIZE_INVALID) {
 					//SUBA.l
 					decoded->extra.size = OPSIZE_LONG;
 					decoded->dst.addr_mode = MODE_AREG;
-					decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
-					istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->src));
-					if (!istream) {
+					decoded->dst.params.regs.pri = m68k_reg_quick_field(opcode);
+					address = m68k_decode_op(opcode, address, fetch, data, OPSIZE_LONG, &(decoded->src));
+					if (address == INVALID_ADDRESS) {
 						decoded->op = M68K_INVALID;
 						break;
 					}
 				} else {
 					decoded->extra.size = size;
 					decoded->src.addr_mode = MODE_REG;
-					decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
-					istream = m68k_decode_op(istream, size, &(decoded->dst));
-					if (!istream || !m68k_valid_full_arith_dst(&decoded->dst)) {
+					decoded->src.params.regs.pri = m68k_reg_quick_field(opcode);
+					address = m68k_decode_op(opcode, address, fetch, data, size, &(decoded->dst));
+					if (address == INVALID_ADDRESS || !m68k_valid_full_arith_dst(&decoded->dst)) {
 						decoded->op = M68K_INVALID;
 						break;
 					}
@@ -1246,9 +1317,9 @@
 				//SUBX
 				decoded->op = M68K_SUBX;
 				decoded->extra.size = size;
-				decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
-				decoded->src.params.regs.pri = *istream & 0x7;
-				if (*istream & 0x8) {
+				decoded->dst.params.regs.pri = m68k_reg_quick_field(opcode);
+				decoded->src.params.regs.pri = opcode & 0x7;
+				if (opcode & 0x8) {
 					decoded->dst.addr_mode = decoded->src.addr_mode = MODE_AREG_PREDEC;
 				} else {
 					decoded->dst.addr_mode = decoded->src.addr_mode = MODE_REG;
@@ -1263,9 +1334,9 @@
 				decoded->extra.size = size;
 				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 || (decoded->src.addr_mode == MODE_AREG && decoded->extra.size == OPSIZE_BYTE)) {
+			decoded->dst.params.regs.pri = m68k_reg_quick_field(opcode);
+			address = m68k_decode_op(opcode, address, fetch, data, decoded->extra.size, &(decoded->src));
+			if (address == INVALID_ADDRESS || (decoded->src.addr_mode == MODE_AREG && decoded->extra.size == OPSIZE_BYTE)) {
 				decoded->op = M68K_INVALID;
 				break;
 			}
@@ -1275,23 +1346,23 @@
 		decoded->op = M68K_A_LINE_TRAP;
 		break;
 	case CMP_XOR:
-		size = (*istream >> 6) & 0x3;
+		size = (opcode >> 6) & 0x3;
 		decoded->op = M68K_CMP;
-		if (*istream & 0x100) {
+		if (opcode & 0x100) {
 			//CMPM or CMPA.l or EOR
 			if (size == OPSIZE_INVALID) {
 				decoded->extra.size = OPSIZE_LONG;
 				decoded->dst.addr_mode = MODE_AREG;
-				decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
-				istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
-				if (!istream) {
+				decoded->dst.params.regs.pri = m68k_reg_quick_field(opcode);
+				address = m68k_decode_op(opcode, address, fetch, data, decoded->extra.size, &(decoded->src));
+				if (address == INVALID_ADDRESS) {
 					decoded->op = M68K_INVALID;
 					break;
 				}
 			} else {
-				reg = m68k_reg_quick_field(*istream);
-				istream = m68k_decode_op(istream, size, &(decoded->dst));
-				if (!istream) {
+				reg = m68k_reg_quick_field(opcode);
+				address = m68k_decode_op(opcode, address, fetch, data, size, &(decoded->dst));
+				if (address == INVALID_ADDRESS) {
 					decoded->op = M68K_INVALID;
 					break;
 				}
@@ -1320,9 +1391,9 @@
 				decoded->extra.size = size;
 				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 || (decoded->src.addr_mode == MODE_AREG && decoded->extra.size == OPSIZE_BYTE)) {
+			decoded->dst.params.regs.pri = m68k_reg_quick_field(opcode);
+			address = m68k_decode_op(opcode, address, fetch, data, decoded->extra.size, &(decoded->src));
+			if (address == INVALID_ADDRESS || (decoded->src.addr_mode == MODE_AREG && decoded->extra.size == OPSIZE_BYTE)) {
 				decoded->op = M68K_INVALID;
 				break;
 			}
@@ -1338,36 +1409,36 @@
 		//operand order bit + 2 size bits (00 - 10)
 		//no address register direct addressing
 		//data register direct not allowed when <ea> is the source (operand order bit of 1)
-		if (*istream & 0x100) {
-			if ((*istream & 0xC0) == 0xC0) {
+		if (opcode & 0x100) {
+			if ((opcode & 0xC0) == 0xC0) {
 				decoded->op = M68K_MULS;
 				decoded->extra.size = OPSIZE_WORD;
 				decoded->dst.addr_mode = MODE_REG;
-				decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
-				istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src));
-				if (!istream || decoded->src.addr_mode == MODE_AREG) {
+				decoded->dst.params.regs.pri = m68k_reg_quick_field(opcode);
+				address = m68k_decode_op(opcode, address, fetch, data, OPSIZE_WORD, &(decoded->src));
+				if (address == INVALID_ADDRESS || decoded->src.addr_mode == MODE_AREG) {
 					decoded->op = M68K_INVALID;
 					break;
 				}
-			} else if(!(*istream & 0xF0)) {
+			} else if(!(opcode & 0xF0)) {
 				decoded->op = M68K_ABCD;
 				decoded->extra.size = OPSIZE_BYTE;
-				decoded->src.params.regs.pri = *istream & 0x7;
-				decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
-				decoded->dst.addr_mode = decoded->src.addr_mode = (*istream & 8) ? MODE_AREG_PREDEC : MODE_REG;
-			} else if(!(*istream & 0x30)) {
+				decoded->src.params.regs.pri = opcode & 0x7;
+				decoded->dst.params.regs.pri = m68k_reg_quick_field(opcode);
+				decoded->dst.addr_mode = decoded->src.addr_mode = (opcode & 8) ? MODE_AREG_PREDEC : MODE_REG;
+			} else if(!(opcode & 0x30)) {
 				decoded->op = M68K_EXG;
 				decoded->extra.size = OPSIZE_LONG;
-				decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
-				decoded->dst.params.regs.pri = *istream & 0x7;
-				if (*istream & 0x8) {
-					if (*istream & 0x80) {
+				decoded->src.params.regs.pri = m68k_reg_quick_field(opcode);
+				decoded->dst.params.regs.pri = opcode & 0x7;
+				if (opcode & 0x8) {
+					if (opcode & 0x80) {
 						decoded->src.addr_mode = MODE_REG;
 						decoded->dst.addr_mode = MODE_AREG;
 					} else {
 						decoded->src.addr_mode = decoded->dst.addr_mode = MODE_AREG;
 					}
-				} else if (*istream & 0x40) {
+				} else if (opcode & 0x40) {
 					decoded->src.addr_mode = decoded->dst.addr_mode = MODE_REG;
 				} else {
 					decoded->op = M68K_INVALID;
@@ -1375,33 +1446,33 @@
 				}
 			} else {
 				decoded->op = M68K_AND;
-				decoded->extra.size = (*istream >> 6) & 0x3;
+				decoded->extra.size = (opcode >> 6) & 0x3;
 				decoded->src.addr_mode = MODE_REG;
-				decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
-				istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->dst));
-				if (!istream || !m68k_valid_full_arith_dst(&(decoded->dst))) {
+				decoded->src.params.regs.pri = m68k_reg_quick_field(opcode);
+				address = m68k_decode_op(opcode, address, fetch, data, decoded->extra.size, &(decoded->dst));
+				if (address == INVALID_ADDRESS || !m68k_valid_full_arith_dst(&(decoded->dst))) {
 					decoded->op = M68K_INVALID;
 					break;
 				}
 			}
 		} else {
-			if ((*istream & 0xC0) == 0xC0) {
+			if ((opcode & 0xC0) == 0xC0) {
 				decoded->op = M68K_MULU;
 				decoded->extra.size = OPSIZE_WORD;
 				decoded->dst.addr_mode = MODE_REG;
-				decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
-				istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src));
-				if (!istream || decoded->src.addr_mode == MODE_AREG) {
+				decoded->dst.params.regs.pri = m68k_reg_quick_field(opcode);
+				address = m68k_decode_op(opcode, address, fetch, data, OPSIZE_WORD, &(decoded->src));
+				if (address == INVALID_ADDRESS || decoded->src.addr_mode == MODE_AREG) {
 					decoded->op = M68K_INVALID;
 					break;
 				}
 			} else {
 				decoded->op = M68K_AND;
-				decoded->extra.size = (*istream >> 6) & 0x3;
+				decoded->extra.size = (opcode >> 6) & 0x3;
 				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 || decoded->src.addr_mode == MODE_AREG) {
+				decoded->dst.params.regs.pri = m68k_reg_quick_field(opcode);
+				address = m68k_decode_op(opcode, address, fetch, data, decoded->extra.size, &(decoded->src));
+				if (address == INVALID_ADDRESS || decoded->src.addr_mode == MODE_AREG) {
 					decoded->op = M68K_INVALID;
 					break;
 				}
@@ -1409,27 +1480,27 @@
 		}
 		break;
 	case ADD_ADDX:
-		size = (*istream >> 6) & 0x3;
+		size = (opcode >> 6) & 0x3;
 		decoded->op = M68K_ADD;
-		if (*istream & 0x100) {
+		if (opcode & 0x100) {
 			//<ea> destination, ADDA.l or ADDX
-			if (*istream & 0x30 || size == OPSIZE_INVALID) {
+			if (opcode & 0x30 || size == OPSIZE_INVALID) {
 				if (size == OPSIZE_INVALID) {
 					//ADDA.l
 					decoded->extra.size = OPSIZE_LONG;
 					decoded->dst.addr_mode = MODE_AREG;
-					decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
-					istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->src));
-					if (!istream) {
+					decoded->dst.params.regs.pri = m68k_reg_quick_field(opcode);
+					address = m68k_decode_op(opcode, address, fetch, data, OPSIZE_LONG, &(decoded->src));
+					if (address == INVALID_ADDRESS) {
 						decoded->op = M68K_INVALID;
 						break;
 					}
 				} else {
 					decoded->extra.size = size;
 					decoded->src.addr_mode = MODE_REG;
-					decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
-					istream = m68k_decode_op(istream, size, &(decoded->dst));
-					if (!istream || !m68k_valid_full_arith_dst(&decoded->dst)) {
+					decoded->src.params.regs.pri = m68k_reg_quick_field(opcode);
+					address = m68k_decode_op(opcode, address, fetch, data, size, &(decoded->dst));
+					if (address == INVALID_ADDRESS || !m68k_valid_full_arith_dst(&decoded->dst)) {
 						decoded->op = M68K_INVALID;
 						break;
 					}
@@ -1438,9 +1509,9 @@
 				//ADDX
 				decoded->op = M68K_ADDX;
 				decoded->extra.size = size;
-				decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
-				decoded->src.params.regs.pri = *istream & 0x7;
-				if (*istream & 0x8) {
+				decoded->dst.params.regs.pri = m68k_reg_quick_field(opcode);
+				decoded->src.params.regs.pri = opcode & 0x7;
+				if (opcode & 0x8) {
 					decoded->dst.addr_mode = decoded->src.addr_mode = MODE_AREG_PREDEC;
 				} else {
 					decoded->dst.addr_mode = decoded->src.addr_mode = MODE_REG;
@@ -1455,17 +1526,17 @@
 				decoded->extra.size = size;
 				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 || (decoded->src.addr_mode == MODE_AREG && decoded->extra.size == OPSIZE_BYTE)) {
+			decoded->dst.params.regs.pri = m68k_reg_quick_field(opcode);
+			address = m68k_decode_op(opcode, address, fetch, data, decoded->extra.size, &(decoded->src));
+			if (address == INVALID_ADDRESS || (decoded->src.addr_mode == MODE_AREG && decoded->extra.size == OPSIZE_BYTE)) {
 				decoded->op = M68K_INVALID;
 				break;
 			}
 		}
 		break;
 	case SHIFT_ROTATE:
-		if ((*istream & 0x8C0) == 0xC0) {
-			switch((*istream >> 8) & 0x7)
+		if ((opcode & 0x8C0) == 0xC0) {
+			switch((opcode >> 8) & 0x7)
 			{
 			case 0:
 				decoded->op = M68K_ASR;
@@ -1493,13 +1564,13 @@
 				break;
 			}
 			decoded->extra.size = OPSIZE_WORD;
-			istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->dst));
-			if (!istream || !m68k_valid_full_arith_dst(&decoded->dst)) {
+			address = m68k_decode_op(opcode, address, fetch, data, OPSIZE_WORD, &(decoded->dst));
+			if (address == INVALID_ADDRESS || !m68k_valid_full_arith_dst(&decoded->dst)) {
 				decoded->op = M68K_INVALID;
 				break;
 			}
-		} else if((*istream & 0xC0) != 0xC0) {
-			switch(((*istream >> 2) & 0x6) | ((*istream >> 8) & 1))
+		} else if((opcode & 0xC0) != 0xC0) {
+			switch(((opcode >> 2) & 0x6) | ((opcode >> 8) & 1))
 			{
 			case 0:
 				decoded->op = M68K_ASR;
@@ -1526,9 +1597,9 @@
 				decoded->op = M68K_ROL;
 				break;
 			}
-			decoded->extra.size = (*istream >> 6) & 0x3;
-			immed = (*istream >> 9) & 0x7;
-			if (*istream & 0x20) {
+			decoded->extra.size = (opcode >> 6) & 0x3;
+			immed = (opcode >> 9) & 0x7;
+			if (opcode & 0x20) {
 				decoded->src.addr_mode = MODE_REG;
 				decoded->src.params.regs.pri = immed;
 			} else {
@@ -1540,12 +1611,12 @@
 				decoded->variant = VAR_QUICK;
 			}
 			decoded->dst.addr_mode = MODE_REG;
-			decoded->dst.params.regs.pri = *istream & 0x7;
+			decoded->dst.params.regs.pri = opcode & 0x7;
 
 		} else {
 #ifdef M68020
 			//TODO: Implement bitfield instructions for M68020+ support
-			switch (*istream >> 8 & 7)
+			switch (opcode >> 8 & 7)
 			{
 			case 0:
 				decoded->op = M68K_BFTST; //<ea>
@@ -1572,8 +1643,8 @@
 				decoded->op = M68K_BFINS; //Dn, <ea>
 				break;
 			}
-			opmode = *istream >> 3 & 0x7;
-			reg = *istream & 0x7;
+			opmode = opcode >> 3 & 0x7;
+			reg = opcode & 0x7;
 			m68k_op_info *ea, *other;
 			if (decoded->op == M68K_BFEXTU || decoded->op == M68K_BFEXTS || decoded->op == M68K_BFFFO)
 			{
@@ -1583,16 +1654,18 @@
 				ea = &(decoded->dst);
 				other = &(decoded->dst);
 			}
-			if (*istream & 0x100)
+			if (opcode & 0x100)
 			{
-				immed = *(istream++);
+				immed = fetch(address, data);
+				address += 2;
 				other->addr_mode = MODE_REG;
 				other->params.regs.pri = immed >> 12 & 0x7;
 			} else {
-				immed = *(istream++);
+				immed = fetch(address, data);
+				address += 2;
 			}
 			decoded->extra.size = OPSIZE_UNSIZED;
-			istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, ea);
+			address = m68k_decode_op_ex(opcode, address, fetch, data, opmode, reg, decoded->extra.size, ea);
 			ea->addr_mode |= M68K_FLAG_BITFIELD;
 			ea->bitfield = immed & 0xFFF;
 #endif
@@ -1604,12 +1677,12 @@
 		break;
 	}
 	if (decoded->op == M68K_INVALID) {
-		decoded->src.params.immed = *start;
+		decoded->src.params.immed = opcode;
 		decoded->bytes = 2;
-		return start + 1;
+		return start_address + 2;
 	}
-	decoded->bytes = 2 * (istream + 1 - start);
-	return istream+1;
+	decoded->bytes = address - start_address;
+	return address;
 }
 
 uint32_t m68k_branch_target(m68kinst * inst, uint32_t *dregs, uint32_t *aregs)
@@ -2609,7 +2682,7 @@
 #endif
 	default:
 		size = decoded->extra.size;
-		uint8_t is_quick = decoded->variant == VAR_QUICK && decoded->op != M68K_ASL && decoded->op != M68K_ASR 
+		uint8_t is_quick = decoded->variant == VAR_QUICK && decoded->op != M68K_ASL && decoded->op != M68K_ASR
 			&& decoded->op != M68K_LSL && decoded->op != M68K_LSR && decoded->op != M68K_ROXR && decoded->op != M68K_ROXL
 			&& decoded->op != M68K_ROR && decoded->op != M68K_ROL;
 		ret = sprintf(dst, "%s%s%s",
--- a/68kinst.h	Thu Mar 17 22:40:49 2022 -0700
+++ b/68kinst.h	Thu Mar 17 22:41:42 2022 -0700
@@ -334,8 +334,9 @@
 } m68k_vector;
 
 typedef int (*format_label_fun)(char * dst, uint32_t address, void * data);
+typedef uint16_t (*m68k_fetch_fun)(uint32_t address, void *data);
 
-uint16_t * m68k_decode(uint16_t * istream, m68kinst * dst, uint32_t address);
+uint32_t m68k_decode(m68k_fetch_fun fetch, void *data, m68kinst * dst, uint32_t address);
 uint32_t m68k_branch_target(m68kinst * inst, uint32_t *dregs, uint32_t *aregs);
 uint8_t m68k_is_branch(m68kinst * inst);
 uint8_t m68k_is_noncall_branch(m68kinst * inst);
--- a/backend.h	Thu Mar 17 22:40:49 2022 -0700
+++ b/backend.h	Thu Mar 17 22:41:42 2022 -0700
@@ -92,6 +92,7 @@
 
 void retranslate_calc(cpu_options *opts);
 void patch_for_retranslate(cpu_options *opts, code_ptr native_address, code_ptr handler);
+void defer_translation(cpu_options *opts, uint32_t address, code_ptr handler);
 
 code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t num_chunks, ftype fun_type, code_ptr *after_inc);
 void * get_native_pointer(uint32_t address, void ** mem_pointers, cpu_options * opts);
--- a/backend_x86.c	Thu Mar 17 22:40:49 2022 -0700
+++ b/backend_x86.c	Thu Mar 17 22:41:42 2022 -0700
@@ -64,6 +64,12 @@
 	jmp(&tmp, handler);
 }
 
+void defer_translation(cpu_options *opts, uint32_t address, code_ptr handler)
+{
+	mov_ir(&opts->code, address, opts->scratch1, SZ_D);
+	jmp(&opts->code, handler);
+}
+
 void check_cycles(cpu_options * opts)
 {
 	code_info *code = &opts->code;
--- a/debug.c	Thu Mar 17 22:40:49 2022 -0700
+++ b/debug.c	Thu Mar 17 22:41:42 2022 -0700
@@ -785,32 +785,23 @@
 		case 'b':
 			if (input_buf[1] == 't') {
 				uint32_t stack = context->aregs[7];
-				if (stack >= 0xE00000) {
-					stack &= 0xFFFF;
-					uint8_t non_adr_count = 0;
-					do {
-						uint32_t bt_address = system->work_ram[stack/2] << 16 | system->work_ram[stack/2+1];
-						bt_address = get_instruction_start(context->options, bt_address - 2);
-						if (bt_address) {
-							stack += 4;
-							non_adr_count = 0;
-							uint16_t *bt_pc = NULL;
-							if (bt_address < 0x400000) {
-								bt_pc = system->cart + bt_address/2;
-							} else if(bt_address > 0xE00000) {
-								bt_pc = system->work_ram + (bt_address & 0xFFFF)/2;
-							}
-							m68k_decode(bt_pc, &inst, bt_address);
-							m68k_disasm(&inst, input_buf);
-							printf("%X: %s\n", bt_address, input_buf);
-						} else {
-							//non-return address value on stack can be word wide
-							stack += 2;
-							non_adr_count++;
-						}
-						stack &= 0xFFFF;
-					} while (stack && non_adr_count < 6);
-				}
+				uint8_t non_adr_count = 0;
+				do {
+					uint32_t bt_address = m68k_instruction_fetch(stack, context);
+					bt_address = get_instruction_start(context->options, bt_address - 2);
+					if (bt_address) {
+						stack += 4;
+						non_adr_count = 0;
+						m68k_decode(m68k_instruction_fetch, context, &inst, bt_address);
+						m68k_disasm(&inst, input_buf);
+						printf("%X: %s\n", bt_address, input_buf);
+					} else {
+						//non-return address value on stack can be word wide
+						stack += 2;
+						non_adr_count++;
+					}
+					//TODO: Make sure we don't wander into an invalid memory region
+				} while (stack && non_adr_count < 6);
 			} else {
 				param = find_param(input_buf);
 				if (!param) {
@@ -1126,12 +1117,7 @@
 		root->branch_t = root->branch_f = 0;
 	}
 
-	uint16_t * pc = get_native_pointer(address, (void **)context->mem_pointers, &context->options->gen);
-	if (!pc) {
-		fatal_error("Entered 68K debugger at address %X\n", address);
-	}
-	uint16_t * after_pc = m68k_decode(pc, &inst, address);
-	uint32_t after = address + (after_pc-pc)*2;
+	uint32_t after = m68k_decode(m68k_instruction_fetch, context, &inst, address);
 	int debugging = 1;
 	//Check if this is a user set breakpoint, or just a temporary one
 	bp_def ** this_bp = find_breakpoint(&root->breakpoints, address);
--- a/gdb_remote.c	Thu Mar 17 22:40:49 2022 -0700
+++ b/gdb_remote.c	Thu Mar 17 22:41:42 2022 -0700
@@ -186,12 +186,7 @@
 		}
 		m68kinst inst;
 		genesis_context *gen = context->system;
-		uint16_t * pc_ptr = get_native_pointer(pc, (void **)context->mem_pointers, &context->options->gen);
-		if (!pc_ptr) {
-			fatal_error("Entered gdb remote debugger stub at address %X\n", pc);
-		}
-		uint16_t * after_pc = m68k_decode(pc_ptr, &inst, pc & 0xFFFFFF);
-		uint32_t after = pc + (after_pc-pc_ptr)*2;
+		uint32_t after = m68k_decode(m68k_instruction_fetch, context, &inst, pc & 0xFFFFFF);
 
 		if (inst.op == M68K_RTS) {
 			after = (read_dma_value(context->aregs[7]/2) << 16) | read_dma_value(context->aregs[7]/2 + 1);
@@ -414,12 +409,7 @@
 			case 'S': {
 				m68kinst inst;
 				genesis_context *gen = context->system;
-				uint16_t * pc_ptr = get_native_pointer(pc, (void **)context->mem_pointers, &context->options->gen);
-				if (!pc_ptr) {
-					fatal_error("Entered gdb remote debugger stub at address %X\n", pc);
-				}
-				uint16_t * after_pc = m68k_decode(pc_ptr, &inst, pc & 0xFFFFFF);
-				uint32_t after = pc + (after_pc-pc_ptr)*2;
+				uint32_t after = m68k_decode(m68k_instruction_fetch, context, &inst, pc & 0xFFFFFF);
 
 				if (inst.op == M68K_RTS) {
 					after = (read_dma_value(context->aregs[7]/2) << 16) | read_dma_value(context->aregs[7]/2 + 1);
--- a/m68k_core.c	Thu Mar 17 22:40:49 2022 -0700
+++ b/m68k_core.c	Thu Mar 17 22:41:42 2022 -0700
@@ -768,6 +768,7 @@
 {
 	return inst->op == M68K_RTS || inst->op == M68K_RTE || inst->op == M68K_RTR || inst->op == M68K_JMP
 		|| inst->op == M68K_TRAP || inst->op == M68K_ILLEGAL || inst->op == M68K_INVALID
+		|| inst->op == M68K_F_LINE_TRAP || inst->op == M68K_A_LINE_TRAP
 		|| (inst->op == M68K_BCC && inst->extra.cond == COND_TRUE);
 }
 
@@ -1006,6 +1007,12 @@
 	}
 }
 
+uint16_t m68k_instruction_fetch(uint32_t address, void *vcontext)
+{
+	m68k_context *context = vcontext;
+	return read_word(address, (void **)context->mem_pointers, &context->options->gen, context);
+}
+
 void translate_m68k_stream(uint32_t address, m68k_context * context)
 {
 	m68kinst instbuf;
@@ -1014,32 +1021,36 @@
 	if(get_native_address(opts, address)) {
 		return;
 	}
-	uint16_t *encoded, *next;
+	memmap_chunk const *starting_chunk = NULL;
+	uint32_t next_address;
 	do {
 		if (opts->address_log) {
 			fprintf(opts->address_log, "%X\n", address);
 			fflush(opts->address_log);
 		}
 		do {
-			encoded = get_native_pointer(address, (void **)context->mem_pointers, &opts->gen);
-			if (!encoded) {
-				code_ptr start = code->cur;
-				translate_out_of_bounds(opts, address);
-				code_ptr after = code->cur;
-				map_native_address(context, address, start, 2, after-start);
-				break;
-			}
 			code_ptr existing = get_native_address(opts, address);
 			if (existing) {
 				jmp(code, existing);
 				break;
 			}
-			next = m68k_decode(encoded, &instbuf, address);
-			if (instbuf.op == M68K_INVALID) {
-				instbuf.src.params.immed = *encoded;
+			memmap_chunk const *chunk = find_map_chunk(address, &opts->gen, 0, NULL);
+			if (!starting_chunk) {
+				starting_chunk = chunk;
+			} else if (starting_chunk != chunk) {
+				if (chunk->flags & MMAP_CODE) {
+					code_ptr start = code->cur;
+					defer_translation(&opts->gen, address, opts->retrans_stub);
+					code_ptr after = code->cur;
+					map_native_address(context, address, start, 2, after-start);
+					break;
+				} else {
+					starting_chunk = chunk;
+				}
 			}
-			uint16_t m68k_size = (next-encoded)*2;
-			address += m68k_size;
+			next_address = m68k_decode(m68k_instruction_fetch, context, &instbuf, address);
+			uint16_t m68k_size = next_address - address;
+			address = next_address;
 			//char disbuf[1024];
 			//m68k_disasm(&instbuf, disbuf);
 			//printf("%X: %s\n", instbuf.address, disbuf);
@@ -1066,9 +1077,8 @@
 	code_ptr orig_start = get_native_address(context->options, address);
 	uint32_t orig = address;
 	code_info orig_code = {orig_start, orig_start + orig_size + 5, 0};
-	uint16_t *after, *inst = get_native_pointer(address, (void **)context->mem_pointers, &opts->gen);
 	m68kinst instbuf;
-	after = m68k_decode(inst, &instbuf, orig);
+	uint32_t after_address = m68k_decode(m68k_instruction_fetch, context, &instbuf, orig);
 	if (orig_size != MAX_NATIVE_SIZE) {
 		deferred_addr * orig_deferred = opts->gen.deferred;
 
@@ -1103,13 +1113,13 @@
 			}
 		}*/
 
-		map_native_address(context, instbuf.address, native_start, (after-inst)*2, MAX_NATIVE_SIZE);
+		map_native_address(context, instbuf.address, native_start, after_address - orig, MAX_NATIVE_SIZE);
 
 		jmp(&orig_code, native_start);
 		if (!m68k_is_terminal(&instbuf)) {
 			code_ptr native_end = code->cur;
 			code->cur = native_start + MAX_NATIVE_SIZE;
-			code_ptr rest = get_native_address_trans(context, orig + (after-inst)*2);
+			code_ptr rest = get_native_address_trans(context, after_address);
 			code_info tmp_code = {
 				.cur = native_end,
 				.last = native_start + MAX_NATIVE_SIZE,
@@ -1128,7 +1138,7 @@
 		orig_code = *code;
 		*code = tmp;
 		if (!m68k_is_terminal(&instbuf)) {
-			jmp(&orig_code, get_native_address_trans(context, orig + (after-inst)*2));
+			jmp(&orig_code, get_native_address_trans(context, after_address));
 		}
 		m68k_handle_deferred(context);
 		return orig_start;
--- a/m68k_core.h	Thu Mar 17 22:40:49 2022 -0700
+++ b/m68k_core.h	Thu Mar 17 22:41:42 2022 -0700
@@ -121,6 +121,7 @@
 void m68k_invalidate_code_range(m68k_context *context, uint32_t start, uint32_t end);
 void m68k_serialize(m68k_context *context, uint32_t pc, serialize_buffer *buf);
 void m68k_deserialize(deserialize_buffer *buf, void *vcontext);
+uint16_t m68k_instruction_fetch(uint32_t address, void *vcontext);
 
 #endif //M68K_CORE_H_