main 68kinst.c
   1/*
   2 Copyright 2013 Michael Pavone
   3 This file is part of BlastEm.
   4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
   5*/
   6#include "68kinst.h"
   7#include <string.h>
   8#include <stdio.h>
   9
  10uint32_t sign_extend16(uint32_t val)
  11{
  12	return (val & 0x8000) ? val | 0xFFFF0000 : val;
  13}
  14
  15uint32_t sign_extend8(uint32_t val)
  16{
  17	return (val & 0x80) ? val | 0xFFFFFF00 : val;
  18}
  19
  20uint16_t *m68k_decode_op_ex(uint16_t *cur, uint8_t mode, uint8_t reg, uint8_t size, m68k_op_info *dst)
  21{
  22	uint16_t ext, tmp;
  23	dst->addr_mode = mode;
  24	switch(mode)
  25	{
  26	case MODE_REG:
  27	case MODE_AREG:
  28	case MODE_AREG_INDIRECT:
  29	case MODE_AREG_POSTINC:
  30	case MODE_AREG_PREDEC:
  31		dst->params.regs.pri = reg;
  32		break;
  33	case MODE_AREG_DISPLACE:
  34		ext = *(++cur);
  35		dst->params.regs.pri = reg;
  36		dst->params.regs.displacement = sign_extend16(ext);
  37		break;
  38	case MODE_AREG_INDEX_MEM:
  39		dst->params.regs.pri = reg;
  40		ext = *(++cur);
  41		dst->params.regs.sec = ext >> 11;//includes areg/dreg bit, reg num and word/long bit
  42#ifdef M68020
  43		dst->params.regs.scale = ext >> 9 & 3;
  44		if (ext & 0x100)
  45		{
  46			dst->params.regs.disp_sizes = ext >> 4 & 3;
  47			switch (dst->params.regs.disp_sizes)
  48			{
  49			case 0:
  50				//reserved
  51				return NULL;
  52			case 1:
  53				dst->params.regs.displacement = 0;
  54				break;
  55			case 2:
  56				dst->params.regs.displacement = sign_extend16(*(cur++));
  57				break;
  58			case 3:
  59				tmp = *(cur++);
  60				dst->params.regs.displacement = tmp << 16 | *(cur++);
  61				break;
  62			}
  63			if (ext & 0x3)
  64			{
  65				//memory indirect
  66				switch (ext & 0xC4)
  67				{
  68				case 0x00:
  69					dst->addr_mode = MODE_AREG_PREINDEX;
  70					break;
  71				case 0x04:
  72					dst->addr_mode = MODE_AREG_POSTINDEX;
  73					break;
  74				case 0x40:
  75					dst->addr_mode = MODE_AREG_MEM_INDIRECT;
  76					break;
  77				case 0x80:
  78					dst->addr_mode = MODE_PREINDEX;
  79					break;
  80				case 0x84:
  81					dst->addr_mode = MODE_POSTINDEX;
  82					break;
  83				case 0xC0:
  84					dst->addr_mode = MODE_MEM_INDIRECT;
  85					break;
  86				}
  87				dst->params.regs.disp_sizes |= ext << 4 & 0x30;
  88				switch (ext & 0x3)
  89				{
  90				case 0:
  91					//reserved
  92					return NULL;
  93				case 1:
  94					dst->params.regs.outer_disp = 0;
  95					break;
  96				case 2:
  97					dst->params.regs.outer_disp = sign_extend16(*(cur++));
  98					break;
  99				case 3:
 100					tmp = *(cur++);
 101					dst->params.regs.outer_disp = tmp << 16 | *(cur++);
 102					break;
 103				}
 104			} else {
 105				switch (ext >> 6 & 3)
 106				{
 107				case 0:
 108					dst->addr_mode = MODE_AREG_INDEX_BASE_DISP;
 109					break;
 110				case 1:
 111					dst->addr_mode = MODE_AREG_BASE_DISP;
 112					break;
 113				case 2:
 114					dst->addr_mode = MODE_INDEX_BASE_DISP;
 115					break;
 116				case 3:
 117					dst->addr_mode = MODE_BASE_DISP;
 118					break;
 119				}
 120			}
 121		} else {
 122#endif
 123			dst->addr_mode = MODE_AREG_INDEX_DISP8;
 124			dst->params.regs.displacement = sign_extend8(ext&0xFF);
 125#ifdef M68020
 126		}
 127#endif
 128		break;
 129	case MODE_PC_INDIRECT_ABS_IMMED:
 130		switch(reg)
 131		{
 132		case 0:
 133			dst->addr_mode = MODE_ABSOLUTE_SHORT;
 134			ext = *(++cur);
 135			dst->params.immed = sign_extend16(ext);
 136			break;
 137		case 1:
 138			dst->addr_mode = MODE_ABSOLUTE;
 139			ext = *(++cur);
 140			dst->params.immed = ext << 16 | *(++cur);
 141			break;
 142		case 3:
 143			ext = *(++cur);
 144			dst->params.regs.sec = ext >> 11;//includes areg/dreg bit, reg num and word/long bit
 145#ifdef M68020
 146			dst->params.regs.scale = ext >> 9 & 3;
 147			if (ext & 0x100)
 148			{
 149				dst->params.regs.disp_sizes = ext >> 4 & 3;
 150				switch (dst->params.regs.disp_sizes)
 151				{
 152				case 0:
 153					//reserved
 154					return NULL;
 155				case 1:
 156					dst->params.regs.displacement = 0;
 157					break;
 158				case 2:
 159					dst->params.regs.displacement = sign_extend16(*(cur++));
 160					break;
 161				case 3:
 162					tmp = *(cur++);
 163					dst->params.regs.displacement = tmp << 16 | *(cur++);
 164					break;
 165				}
 166				if (ext & 0x3)
 167				{
 168					//memory indirect
 169					switch (ext & 0xC4)
 170					{
 171					case 0x00:
 172						dst->addr_mode = MODE_PC_PREINDEX;
 173						break;
 174					case 0x04:
 175						dst->addr_mode = MODE_PC_POSTINDEX;
 176						break;
 177					case 0x40:
 178						dst->addr_mode = MODE_PC_MEM_INDIRECT;
 179						break;
 180					case 0x80:
 181						dst->addr_mode = MODE_ZPC_PREINDEX;
 182						break;
 183					case 0x84:
 184						dst->addr_mode = MODE_ZPC_POSTINDEX;
 185						break;
 186					case 0xC0:
 187						dst->addr_mode = MODE_ZPC_MEM_INDIRECT;
 188						break;
 189					}
 190					dst->params.regs.disp_sizes |= ext << 4 & 0x30;
 191					switch (ext & 0x3)
 192					{
 193					case 0:
 194						//reserved
 195						return NULL;
 196					case 1:
 197						dst->params.regs.outer_disp = 0;
 198						break;
 199					case 2:
 200						dst->params.regs.outer_disp = sign_extend16(*(cur++));
 201						break;
 202					case 3:
 203						tmp = *(cur++);
 204						dst->params.regs.outer_disp = tmp << 16 | *(cur++);
 205						break;
 206					}
 207				} else {
 208					switch (ext >> 6 & 3)
 209					{
 210					case 0:
 211						dst->addr_mode = MODE_PC_INDEX_BASE_DISP;
 212						break;
 213					case 1:
 214						dst->addr_mode = MODE_PC_BASE_DISP;
 215						break;
 216					case 2:
 217						dst->addr_mode = MODE_ZPC_INDEX_BASE_DISP;
 218						break;
 219					case 3:
 220						dst->addr_mode = MODE_ZPC_BASE_DISP;
 221						break;
 222					}
 223				}
 224			} else {
 225#endif
 226				dst->addr_mode = MODE_PC_INDEX_DISP8;
 227				dst->params.regs.displacement = sign_extend8(ext&0xFF);
 228#ifdef M68020
 229			}
 230#endif
 231			break;
 232		case 2:
 233			dst->addr_mode = MODE_PC_DISPLACE;
 234			ext = *(++cur);
 235			dst->params.regs.displacement = sign_extend16(ext);
 236			break;
 237		case 4:
 238			dst->addr_mode = MODE_IMMEDIATE;
 239			ext = *(++cur);
 240			switch (size)
 241			{
 242			case OPSIZE_BYTE:
 243				dst->params.immed = ext & 0xFF;
 244				break;
 245			case OPSIZE_WORD:
 246				dst->params.immed = ext;
 247				break;
 248			case OPSIZE_LONG:
 249				dst->params.immed = ext << 16 | *(++cur);
 250				break;
 251			}
 252			break;
 253		default:
 254			return NULL;
 255		}
 256		break;
 257	}
 258	return cur;
 259}
 260
 261uint8_t m68k_valid_immed_dst(m68k_op_info *dst)
 262{
 263	if (dst->addr_mode == MODE_AREG || dst->addr_mode == MODE_IMMEDIATE) {
 264		return 0;
 265	}
 266	return 1;
 267}
 268
 269uint8_t m68k_valid_immed_limited_dst(m68k_op_info *dst)
 270{
 271	if (dst->addr_mode == MODE_AREG || dst->addr_mode > MODE_ABSOLUTE) {
 272		return 0;
 273	}
 274	return 1;
 275}
 276
 277uint8_t m68k_valid_full_arith_dst(m68k_op_info *dst)
 278{
 279	if (dst->addr_mode < MODE_AREG_INDIRECT || dst->addr_mode > MODE_ABSOLUTE) {
 280		return 0;
 281	}
 282	return 1;
 283}
 284
 285uint8_t m68k_valid_movem_dst(m68k_op_info *dst)
 286{
 287	if (dst->addr_mode == MODE_REG || dst->addr_mode == MODE_AREG_POSTINC) {
 288		return 0;
 289	}
 290	return m68k_valid_immed_limited_dst(dst);
 291}
 292
 293uint16_t *m68k_decode_op(uint16_t *cur, uint8_t size, m68k_op_info *dst)
 294{
 295	uint8_t mode = (*cur >> 3) & 0x7;
 296	uint8_t reg = *cur & 0x7;
 297	return m68k_decode_op_ex(cur, mode, reg, size, dst);
 298}
 299
 300void m68k_decode_cond(uint16_t op, m68kinst * decoded)
 301{
 302	decoded->extra.cond = (op >> 0x8) & 0xF;
 303}
 304
 305uint8_t m68k_reg_quick_field(uint16_t op)
 306{
 307	return (op >> 9) & 0x7;
 308}
 309
 310uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
 311{
 312	uint16_t *start = istream;
 313	uint8_t optype = *istream >> 12;
 314	uint8_t size;
 315	uint8_t reg;
 316	uint8_t opmode;
 317	uint32_t immed;
 318	decoded->op = M68K_INVALID;
 319	decoded->src.addr_mode = decoded->dst.addr_mode = MODE_UNUSED;
 320	decoded->variant = VAR_NORMAL;
 321	decoded->address = address;
 322	switch(optype)
 323	{
 324	case BIT_MOVEP_IMMED:
 325		if ((*istream & 0x138) == 0x108) {
 326			//MOVEP
 327			decoded->op = M68K_MOVEP;
 328			decoded->extra.size = *istream & 0x40 ? OPSIZE_LONG : OPSIZE_WORD;
 329			if (*istream & 0x80) {
 330				//memory dest
 331				decoded->src.addr_mode = MODE_REG;
 332				decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
 333				decoded->dst.addr_mode = MODE_AREG_DISPLACE;
 334				decoded->dst.params.regs.pri = *istream & 0x7;
 335				decoded->dst.params.regs.displacement = *(++istream);
 336			} else {
 337				//memory source
 338				decoded->dst.addr_mode = MODE_REG;
 339				decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
 340				decoded->src.addr_mode = MODE_AREG_DISPLACE;
 341				decoded->src.params.regs.pri = *istream & 0x7;
 342				decoded->src.params.regs.displacement = *(++istream);
 343			}
 344		} else if (*istream & 0x100) {
 345			//BTST, BCHG, BCLR, BSET
 346			switch ((*istream >> 6) & 0x3)
 347			{
 348			case 0:
 349				decoded->op = M68K_BTST;
 350				break;
 351			case 1:
 352				decoded->op = M68K_BCHG;
 353				break;
 354			case 2:
 355				decoded->op = M68K_BCLR;
 356				break;
 357			case 3:
 358				decoded->op = M68K_BSET;
 359				break;
 360			}
 361			decoded->src.addr_mode = MODE_REG;
 362			decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
 363			decoded->extra.size = OPSIZE_BYTE;
 364			istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->dst));
 365			if (
 366				!istream || decoded->dst.addr_mode == MODE_AREG 
 367				|| (decoded->op != M68K_BTST && !m68k_valid_immed_limited_dst(&decoded->dst))
 368			) {
 369				decoded->op = M68K_INVALID;
 370				break;
 371			}
 372			if (decoded->dst.addr_mode == MODE_REG) {
 373				decoded->extra.size = OPSIZE_LONG;
 374			}
 375		} else if ((*istream & 0xF00) == 0x800) {
 376			//BTST, BCHG, BCLR, BSET
 377			switch ((*istream >> 6) & 0x3)
 378			{
 379			case 0:
 380				decoded->op = M68K_BTST;
 381				break;
 382			case 1:
 383				decoded->op = M68K_BCHG;
 384				break;
 385			case 2:
 386				decoded->op = M68K_BCLR;
 387				break;
 388			case 3:
 389				decoded->op = M68K_BSET;
 390				break;
 391			}
 392			opmode = (*istream >> 3) & 0x7;
 393			reg = *istream & 0x7;
 394			decoded->src.addr_mode = MODE_IMMEDIATE_WORD;
 395			decoded->src.params.immed = *(++istream) & 0xFF;
 396			decoded->extra.size = OPSIZE_BYTE;
 397			istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst));
 398			if (
 399				!istream || !m68k_valid_immed_dst(&decoded->dst)
 400				|| (decoded->op != M68K_BTST && !m68k_valid_immed_limited_dst(&decoded->dst))
 401			) {
 402				decoded->op = M68K_INVALID;
 403				break;
 404			}
 405			if (decoded->dst.addr_mode == MODE_REG) {
 406				decoded->extra.size = OPSIZE_LONG;
 407			}
 408		} else if ((*istream & 0xC0) == 0xC0) {
 409#ifdef M68020
 410			//CMP2, CHK2, CAS, CAS2, RTM, CALLM
 411#endif
 412		} else {
 413			switch ((*istream >> 9) & 0x7)
 414			{
 415			case 0:
 416				if ((*istream & 0xFF) == 0x3C) {
 417					decoded->op = M68K_ORI_CCR;
 418					decoded->extra.size = OPSIZE_BYTE;
 419					decoded->src.addr_mode = MODE_IMMEDIATE;
 420					decoded->src.params.immed = *(++istream) & 0xFF;
 421				} else if((*istream & 0xFF) == 0x7C) {
 422					decoded->op = M68K_ORI_SR;
 423					decoded->extra.size = OPSIZE_WORD;
 424					decoded->src.addr_mode = MODE_IMMEDIATE;
 425					decoded->src.params.immed = *(++istream);
 426				} else {
 427					decoded->op = M68K_OR;
 428					decoded->variant = VAR_IMMEDIATE;
 429					decoded->src.addr_mode = MODE_IMMEDIATE;
 430					decoded->extra.size = size = (*istream >> 6) & 3;
 431					reg = *istream & 0x7;
 432					opmode = (*istream >> 3) & 0x7;
 433					switch (size)
 434					{
 435					case OPSIZE_BYTE:
 436						decoded->src.params.immed = *(++istream) & 0xFF;
 437						break;
 438					case OPSIZE_WORD:
 439						decoded->src.params.immed = *(++istream);
 440						break;
 441					case OPSIZE_LONG:
 442						immed = *(++istream);
 443						decoded->src.params.immed = immed << 16 | *(++istream);
 444						break;
 445					}
 446					istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst));
 447					if (!istream || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
 448						decoded->op = M68K_INVALID;
 449						break;
 450					}
 451				}
 452				break;
 453			case 1:
 454				//ANDI, ANDI to CCR, ANDI to SR
 455				if ((*istream & 0xFF) == 0x3C) {
 456					decoded->op = M68K_ANDI_CCR;
 457					decoded->extra.size = OPSIZE_BYTE;
 458					decoded->src.addr_mode = MODE_IMMEDIATE;
 459					decoded->src.params.immed = *(++istream) & 0xFF;
 460				} else if((*istream & 0xFF) == 0x7C) {
 461					decoded->op = M68K_ANDI_SR;
 462					decoded->extra.size = OPSIZE_WORD;
 463					decoded->src.addr_mode = MODE_IMMEDIATE;
 464					decoded->src.params.immed = *(++istream);
 465				} else {
 466					decoded->op = M68K_AND;
 467					decoded->variant = VAR_IMMEDIATE;
 468					decoded->src.addr_mode = MODE_IMMEDIATE;
 469					decoded->extra.size = size = (*istream >> 6) & 3;
 470					reg = *istream & 0x7;
 471					opmode = (*istream >> 3) & 0x7;
 472					switch (size)
 473					{
 474					case OPSIZE_BYTE:
 475						decoded->src.params.immed = *(++istream) & 0xFF;
 476						break;
 477					case OPSIZE_WORD:
 478						decoded->src.params.immed = *(++istream);
 479						break;
 480					case OPSIZE_LONG:
 481						immed = *(++istream);
 482						decoded->src.params.immed = immed << 16 | *(++istream);
 483						break;
 484					}
 485					istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst));
 486					if (!istream || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
 487						decoded->op = M68K_INVALID;
 488						break;
 489					}
 490				}
 491				break;
 492			case 2:
 493				decoded->op = M68K_SUB;
 494				decoded->variant = VAR_IMMEDIATE;
 495				decoded->src.addr_mode = MODE_IMMEDIATE;
 496				decoded->extra.size = size = (*istream >> 6) & 3;
 497				reg = *istream & 0x7;
 498				opmode = (*istream >> 3) & 0x7;
 499				switch (size)
 500				{
 501				case OPSIZE_BYTE:
 502					decoded->src.params.immed = *(++istream) & 0xFF;
 503					break;
 504				case OPSIZE_WORD:
 505					decoded->src.params.immed = *(++istream);
 506					break;
 507				case OPSIZE_LONG:
 508					immed = *(++istream);
 509					decoded->src.params.immed = immed << 16 | *(++istream);
 510					break;
 511				}
 512				istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst));
 513				if (!istream || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
 514					decoded->op = M68K_INVALID;
 515					break;
 516				}
 517				break;
 518			case 3:
 519				decoded->op = M68K_ADD;
 520				decoded->variant = VAR_IMMEDIATE;
 521				decoded->src.addr_mode = MODE_IMMEDIATE;
 522				decoded->extra.size = size = (*istream >> 6) & 3;
 523				reg = *istream & 0x7;
 524				opmode = (*istream >> 3) & 0x7;
 525				switch (size)
 526				{
 527				case OPSIZE_BYTE:
 528					decoded->src.params.immed = *(++istream) & 0xFF;
 529					break;
 530				case OPSIZE_WORD:
 531					decoded->src.params.immed = *(++istream);
 532					break;
 533				case OPSIZE_LONG:
 534					immed = *(++istream);
 535					decoded->src.params.immed = immed << 16 | *(++istream);
 536					break;
 537				}
 538				istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst));
 539				if (!istream || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
 540					decoded->op = M68K_INVALID;
 541					break;
 542				}
 543				break;
 544			case 4:
 545				//BTST, BCHG, BCLR, BSET
 546				//Seems like this should be unnecessary since bit instructions are explicitly handled above
 547				//Possible this is redundant or the case above is overly restrictive
 548				//TODO: Investigate whether this can be removed
 549				switch ((*istream >> 6) & 0x3)
 550				{
 551				case 0:
 552					decoded->op = M68K_BTST;
 553					break;
 554				case 1:
 555					decoded->op = M68K_BCHG;
 556					break;
 557				case 2:
 558					decoded->op = M68K_BCLR;
 559					break;
 560				case 3:
 561					decoded->op = M68K_BSET;
 562					break;
 563				}
 564				decoded->src.addr_mode = MODE_IMMEDIATE_WORD;
 565				decoded->src.params.immed = *(++istream) & 0xFF;
 566				istream = m68k_decode_op(istream, OPSIZE_BYTE, &(decoded->dst));
 567				if (
 568					!istream || !m68k_valid_immed_dst(&decoded->dst) 
 569					|| (decoded->op != M68K_BTST && !m68k_valid_immed_limited_dst(&decoded->dst))
 570				) {
 571					decoded->op = M68K_INVALID;
 572					break;
 573				}
 574				break;
 575			case 5:
 576				//EORI, EORI to CCR, EORI to SR
 577				if ((*istream & 0xFF) == 0x3C) {
 578					decoded->op = M68K_EORI_CCR;
 579					decoded->extra.size = OPSIZE_BYTE;
 580					decoded->src.addr_mode = MODE_IMMEDIATE;
 581					decoded->src.params.immed = *(++istream) & 0xFF;
 582				} else if((*istream & 0xFF) == 0x7C) {
 583					decoded->op = M68K_EORI_SR;
 584					decoded->extra.size = OPSIZE_WORD;
 585					decoded->src.addr_mode = MODE_IMMEDIATE;
 586					decoded->src.params.immed = *(++istream);
 587				} else {
 588					decoded->op = M68K_EOR;
 589					decoded->variant = VAR_IMMEDIATE;
 590					decoded->src.addr_mode = MODE_IMMEDIATE;
 591					decoded->extra.size = size = (*istream >> 6) & 3;
 592					reg = *istream & 0x7;
 593					opmode = (*istream >> 3) & 0x7;
 594					switch (size)
 595					{
 596					case OPSIZE_BYTE:
 597						decoded->src.params.immed = *(++istream) & 0xFF;
 598						break;
 599					case OPSIZE_WORD:
 600						decoded->src.params.immed = *(++istream);
 601						break;
 602					case OPSIZE_LONG:
 603						immed = *(++istream);
 604						decoded->src.params.immed = immed << 16 | *(++istream);
 605						break;
 606					}
 607					istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst));
 608					if (!istream || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
 609						decoded->op = M68K_INVALID;
 610						break;
 611					}
 612				}
 613				break;
 614			case 6:
 615				decoded->op = M68K_CMP;
 616				decoded->variant = VAR_IMMEDIATE;
 617				decoded->extra.size = (*istream >> 6) & 0x3;
 618				decoded->src.addr_mode = MODE_IMMEDIATE;
 619				reg = *istream & 0x7;
 620				opmode = (*istream >> 3) & 0x7;
 621				switch (decoded->extra.size)
 622				{
 623				case OPSIZE_BYTE:
 624					decoded->src.params.immed = *(++istream) & 0xFF;
 625					break;
 626				case OPSIZE_WORD:
 627					decoded->src.params.immed = *(++istream);
 628					break;
 629				case OPSIZE_LONG:
 630					immed = *(++istream);
 631					decoded->src.params.immed = (immed << 16) | *(++istream);
 632					break;
 633				}
 634				istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst));
 635				if (!istream || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
 636					decoded->op = M68K_INVALID;
 637					break;
 638				}
 639				break;
 640			case 7:
 641#ifdef M68010
 642				decoded->op = M68K_MOVES;
 643				decoded->extra.size = *istream >> 6 & 0x3;
 644				immed = *(++istream);
 645				reg = immed  >> 12 & 0x7;
 646				opmode = immed & 0x8000 ? MODE_AREG : MODE_REG;
 647				if (immed & 0x800) {
 648					decoded->src.addr_mode = opmode;
 649					decoded->src.params.regs.pri = reg;
 650					m68k_decode_op_ex(istream, *start >> 3 & 0x7, *start & 0x7, decoded->extra.size, &(decoded->dst));
 651				} else {
 652					m68k_decode_op_ex(istream, *start >> 3 & 0x7, *start & 0x7, decoded->extra.size, &(decoded->src));
 653					decoded->dst.addr_mode = opmode;
 654					decoded->dst.params.regs.pri = reg;
 655				}
 656#endif
 657				break;
 658			}
 659		}
 660		break;
 661	case MOVE_BYTE:
 662	case MOVE_LONG:
 663	case MOVE_WORD:
 664		decoded->op = M68K_MOVE;
 665		decoded->extra.size = optype == MOVE_BYTE ? OPSIZE_BYTE : (optype == MOVE_WORD ? OPSIZE_WORD : OPSIZE_LONG);
 666		opmode = (*istream >> 6) & 0x7;
 667		reg = m68k_reg_quick_field(*istream);
 668		istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
 669		if (!istream || (decoded->src.addr_mode == MODE_AREG && optype == MOVE_BYTE)) {
 670			decoded->op = M68K_INVALID;
 671			break;
 672		}
 673		istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst));
 674		if (!istream || decoded->dst.addr_mode > MODE_ABSOLUTE || (decoded->dst.addr_mode == MODE_AREG && optype == MOVE_BYTE)) {
 675			decoded->op = M68K_INVALID;
 676			break;
 677		}
 678		break;
 679	case MISC:
 680
 681		if ((*istream & 0x1C0) == 0x1C0) {
 682			decoded->op = M68K_LEA;
 683			decoded->extra.size = OPSIZE_LONG;
 684			decoded->dst.addr_mode = MODE_AREG;
 685			decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
 686			istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
 687			if (
 688				!istream || decoded->src.addr_mode == MODE_REG || decoded->src.addr_mode == MODE_AREG 
 689				|| decoded->src.addr_mode == MODE_AREG_POSTINC || decoded->src.addr_mode == MODE_AREG_PREDEC
 690				|| decoded->src.addr_mode == MODE_IMMEDIATE
 691			) {
 692				decoded->op = M68K_INVALID;
 693				break;
 694			}
 695		} else {
 696			if (*istream & 0x100) {
 697				decoded->op = M68K_CHK;
 698				if ((*istream & 0x180) == 0x180) {
 699					decoded->extra.size = OPSIZE_WORD;
 700				} else {
 701					//only on M68020+
 702#ifdef M68020
 703					decoded->extra.size = OPSIZE_LONG;
 704#else
 705					decoded->op = M68K_INVALID;
 706					break;
 707#endif
 708				}
 709				decoded->dst.addr_mode = MODE_REG;
 710				decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
 711				istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
 712				if (!istream || decoded->src.addr_mode == MODE_AREG) {
 713					decoded->op = M68K_INVALID;
 714					break;
 715				}
 716			} else {
 717				opmode = (*istream >> 3) & 0x7;
 718				if ((*istream & 0xB80) == 0x880 && opmode != MODE_REG && opmode != MODE_AREG) {
 719					//TODO: Check for invalid modes that are dependent on direction
 720					decoded->op = M68K_MOVEM;
 721					decoded->extra.size = *istream & 0x40 ? OPSIZE_LONG : OPSIZE_WORD;
 722					reg = *istream & 0x7;
 723					if(*istream & 0x400) {
 724						decoded->dst.addr_mode = MODE_REG;
 725						decoded->dst.params.immed = *(++istream);
 726						istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->src));
 727						if (!istream || decoded->src.addr_mode == MODE_AREG_PREDEC || decoded->src.addr_mode == MODE_IMMEDIATE) {
 728							decoded->op = M68K_INVALID;
 729							break;
 730						}
 731						if (decoded->src.addr_mode == MODE_PC_DISPLACE || decoded->src.addr_mode == MODE_PC_INDEX_DISP8) {
 732							//adjust displacement to account for extra instruction word
 733							decoded->src.params.regs.displacement += 2;
 734						}
 735					} else {
 736						decoded->src.addr_mode = MODE_REG;
 737						decoded->src.params.immed = *(++istream);
 738						istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst));
 739						if (!istream || !m68k_valid_movem_dst(&decoded->dst)) {
 740							decoded->op = M68K_INVALID;
 741							break;
 742						}
 743					}
 744				} else {
 745					optype = (*istream >> 9) & 0x7;
 746					size = (*istream >> 6) & 0x3;
 747					switch(optype)
 748					{
 749					case 0:
 750						//Move from SR or NEGX
 751						if (size == OPSIZE_INVALID) {
 752							decoded->op = M68K_MOVE_FROM_SR;
 753							size = OPSIZE_WORD;
 754						} else {
 755							decoded->op = M68K_NEGX;
 756						}
 757						decoded->extra.size = size;
 758						istream= m68k_decode_op(istream, size, &(decoded->dst));
 759						if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
 760							decoded->op = M68K_INVALID;
 761							break;
 762						}
 763						break;
 764					case 1:
 765						//MOVE from CCR or CLR
 766						if (size == OPSIZE_INVALID) {
 767#ifdef M68010
 768							decoded->op = M68K_MOVE_FROM_CCR;
 769							size = OPSIZE_WORD;
 770#else
 771							break;
 772#endif
 773						} else {
 774							decoded->op = M68K_CLR;
 775						}
 776						decoded->extra.size = size;
 777						istream= m68k_decode_op(istream, size, &(decoded->dst));
 778						if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
 779							decoded->op = M68K_INVALID;
 780							break;
 781						}
 782						break;
 783					case 2:
 784						//MOVE to CCR or NEG
 785						if (size == OPSIZE_INVALID) {
 786							decoded->op = M68K_MOVE_CCR;
 787							size = OPSIZE_WORD;
 788							istream= m68k_decode_op(istream, size, &(decoded->src));
 789							if (!istream || decoded->src.addr_mode == MODE_AREG) {
 790								decoded->op = M68K_INVALID;
 791								break;
 792							}
 793						} else {
 794							decoded->op = M68K_NEG;
 795							istream= m68k_decode_op(istream, size, &(decoded->dst));
 796							if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
 797								decoded->op = M68K_INVALID;
 798								break;
 799							}
 800						}
 801						decoded->extra.size = size;
 802						break;
 803					case 3:
 804						//MOVE to SR or NOT
 805						if (size == OPSIZE_INVALID) {
 806							decoded->op = M68K_MOVE_SR;
 807							size = OPSIZE_WORD;
 808							istream= m68k_decode_op(istream, size, &(decoded->src));
 809							if (!istream || decoded->src.addr_mode == MODE_AREG) {
 810								decoded->op = M68K_INVALID;
 811								break;
 812							}
 813						} else {
 814							decoded->op = M68K_NOT;
 815							istream= m68k_decode_op(istream, size, &(decoded->dst));
 816							if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
 817								decoded->op = M68K_INVALID;
 818								break;
 819							}
 820						}
 821						decoded->extra.size = size;
 822						break;
 823					case 4:
 824						//EXT, EXTB, LINK.l, NBCD, SWAP, BKPT, PEA
 825						switch((*istream >> 3) & 0x3F)
 826						{
 827						case 1:
 828#ifdef M68020
 829							decoded->op = M68K_LINK;
 830							decoded->extra.size = OPSIZE_LONG;
 831							reg = *istream & 0x7;
 832							immed = *(++istream) << 16;
 833							immed |= *(++istream);
 834#endif
 835							break;
 836						case 8:
 837							decoded->op = M68K_SWAP;
 838							decoded->src.addr_mode = MODE_REG;
 839							decoded->src.params.regs.pri = *istream & 0x7;
 840							decoded->extra.size = OPSIZE_WORD;
 841							break;
 842						case 9:
 843#ifdef M68010
 844							decoded->op = M68K_BKPT;
 845							decoded->src.addr_mode = MODE_IMMEDIATE;
 846							decoded->extra.size = OPSIZE_UNSIZED;
 847							decoded->src.params.immed = *istream & 0x7;
 848#endif
 849							break;
 850						case 0x10:
 851							decoded->op = M68K_EXT;
 852							decoded->dst.addr_mode = MODE_REG;
 853							decoded->dst.params.regs.pri = *istream & 0x7;
 854							decoded->extra.size = OPSIZE_WORD;
 855							break;
 856						case 0x18:
 857							decoded->op = M68K_EXT;
 858							decoded->dst.addr_mode = MODE_REG;
 859							decoded->dst.params.regs.pri = *istream & 0x7;
 860							decoded->extra.size = OPSIZE_LONG;
 861							break;
 862						case 0x38:
 863#ifdef M68020
 864#endif
 865							break;
 866						default:
 867							if (!(*istream & 0x1C0)) {
 868								decoded->op = M68K_NBCD;
 869								decoded->extra.size = OPSIZE_BYTE;
 870								istream = m68k_decode_op(istream, OPSIZE_BYTE, &(decoded->dst));
 871								if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
 872									decoded->op = M68K_INVALID;
 873									break;
 874								}
 875							} else if((*istream & 0x1C0) == 0x40) {
 876								decoded->op = M68K_PEA;
 877								decoded->extra.size = OPSIZE_LONG;
 878								istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->src));
 879								if (
 880									!istream || decoded->src.addr_mode == MODE_REG || decoded->src.addr_mode == MODE_AREG 
 881									|| decoded->src.addr_mode == MODE_AREG_POSTINC || decoded->src.addr_mode == MODE_AREG_PREDEC
 882									|| decoded->src.addr_mode == MODE_IMMEDIATE
 883								) {
 884									decoded->op = M68K_INVALID;
 885									break;
 886								}
 887							}
 888						}
 889						break;
 890					case 5:
 891						//BGND, ILLEGAL, TAS, TST
 892						optype = *istream & 0xFF;
 893						if (optype == 0xFA) {
 894							//BGND - CPU32 only
 895						} else if (optype == 0xFC) {
 896							decoded->op = M68K_ILLEGAL;
 897							decoded->extra.size = OPSIZE_UNSIZED;
 898						} else {
 899							if (size == OPSIZE_INVALID) {
 900								decoded->op = M68K_TAS;
 901								decoded->extra.size = OPSIZE_BYTE;
 902								istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->dst));
 903								if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
 904									decoded->op = M68K_INVALID;
 905									break;
 906								}
 907							} else {
 908								decoded->op = M68K_TST;
 909								decoded->extra.size = size;
 910								istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
 911								if (!istream) {
 912									decoded->op = M68K_INVALID;
 913									break;
 914								}
 915#ifndef M68020
 916								if (!m68k_valid_immed_limited_dst(&decoded->src)) {
 917									decoded->op = M68K_INVALID;
 918									break;
 919								}
 920#endif
 921							}
 922						}
 923						break;
 924					case 6:
 925						//MULU, MULS, DIVU, DIVUL, DIVS, DIVSL
 926#ifdef M68020
 927						//TODO: Implement these for 68020+ support
 928#endif
 929						break;
 930					case 7:
 931						//TRAP, LINK.w, UNLNK, MOVE USP, RESET, NOP, STOP, RTE, RTD, RTS, TRAPV, RTR, MOVEC, JSR, JMP
 932						if (*istream & 0x80) {
 933							//JSR, JMP
 934							if (*istream & 0x40) {
 935								decoded->op = M68K_JMP;
 936							} else {
 937								decoded->op = M68K_JSR;
 938							}
 939							decoded->extra.size = OPSIZE_UNSIZED;
 940							istream = m68k_decode_op(istream, OPSIZE_UNSIZED, &(decoded->src));
 941							if (
 942								!istream 
 943								|| (decoded->src.addr_mode < MODE_AREG_DISPLACE && decoded->src.addr_mode != MODE_AREG_INDIRECT)
 944								|| decoded->src.addr_mode == MODE_IMMEDIATE
 945							) {
 946								decoded->op = M68K_INVALID;
 947								break;
 948							}
 949						} else {
 950							//it would appear bit 6 needs to be set for it to be a valid instruction here
 951							if (!(*istream & 0x40)) {
 952								decoded->op = M68K_INVALID;
 953								break;
 954							}
 955							switch((*istream >> 3) & 0x7)
 956							{
 957							case 0:
 958							case 1:
 959								//TRAP
 960								decoded->op = M68K_TRAP;
 961								decoded->extra.size = OPSIZE_UNSIZED;
 962								decoded->src.addr_mode = MODE_IMMEDIATE;
 963								decoded->src.params.immed = *istream & 0xF;
 964								break;
 965							case 2:
 966								//LINK.w
 967								decoded->op = M68K_LINK;
 968								decoded->extra.size = OPSIZE_WORD;
 969								decoded->src.addr_mode = MODE_AREG;
 970								decoded->src.params.regs.pri = *istream & 0x7;
 971								decoded->dst.addr_mode = MODE_IMMEDIATE;
 972								decoded->dst.params.immed = sign_extend16(*(++istream));
 973								break;
 974							case 3:
 975								//UNLK
 976								decoded->op = M68K_UNLK;
 977								decoded->extra.size = OPSIZE_UNSIZED;
 978								decoded->dst.addr_mode = MODE_AREG;
 979								decoded->dst.params.regs.pri = *istream & 0x7;
 980								break;
 981							case 4:
 982							case 5:
 983								//MOVE USP
 984								decoded->op = M68K_MOVE_USP;
 985								if (*istream & 0x8) {
 986									decoded->dst.addr_mode = MODE_AREG;
 987									decoded->dst.params.regs.pri = *istream & 0x7;
 988								} else {
 989									decoded->src.addr_mode = MODE_AREG;
 990									decoded->src.params.regs.pri = *istream & 0x7;
 991								}
 992								break;
 993							case 6:
 994								decoded->extra.size = OPSIZE_UNSIZED;
 995								switch(*istream & 0x7)
 996								{
 997								case 0:
 998									decoded->op = M68K_RESET;
 999									break;
1000								case 1:
1001									decoded->op = M68K_NOP;
1002									break;
1003								case 2:
1004									decoded->op = M68K_STOP;
1005									decoded->src.addr_mode = MODE_IMMEDIATE;
1006									decoded->src.params.immed =*(++istream);
1007									break;
1008								case 3:
1009									decoded->op = M68K_RTE;
1010									break;
1011								case 4:
1012#ifdef M68010
1013									decoded->op = M68K_RTD;
1014									decoded->src.addr_mode = MODE_IMMEDIATE;
1015									decoded->src.params.immed =*(++istream);
1016#endif
1017									break;
1018								case 5:
1019									decoded->op = M68K_RTS;
1020									break;
1021								case 6:
1022									decoded->op = M68K_TRAPV;
1023									break;
1024								case 7:
1025									decoded->op = M68K_RTR;
1026									break;
1027								}
1028								break;
1029							case 7:
1030								//MOVEC
1031#ifdef M68010
1032								decoded->op = M68K_MOVEC;
1033								immed = *(++istream);
1034								reg = immed >> 12 & 0x7;
1035								opmode = immed & 0x8000 ? MODE_AREG : MODE_REG;
1036								immed &= 0xFFF;
1037								if (immed & 0x800) {
1038									if (immed > MAX_HIGH_CR) {
1039										decoded->op = M68K_INVALID;
1040										break;
1041									} else {
1042										immed = immed - 0x800 + CR_USP;
1043									}
1044								} else {
1045									if (immed > MAX_LOW_CR) {
1046										decoded->op = M68K_INVALID;
1047										break;
1048									}
1049								}
1050								if (*start & 1) {
1051									decoded->src.addr_mode = opmode;
1052									decoded->src.params.regs.pri = reg;
1053									decoded->dst.params.immed = immed;
1054								} else {
1055									decoded->dst.addr_mode = opmode;
1056									decoded->dst.params.regs.pri = reg;
1057									decoded->src.params.immed = immed;
1058								}
1059#endif
1060								break;
1061							}
1062						}
1063						break;
1064					}
1065				}
1066			}
1067		}
1068		break;
1069	case QUICK_ARITH_LOOP:
1070		size = (*istream >> 6) & 3;
1071		if (size == 0x3) {
1072			//DBcc, TRAPcc or Scc
1073			m68k_decode_cond(*istream, decoded);
1074			if (((*istream >> 3) & 0x7) == 1) {
1075				decoded->op = M68K_DBCC;
1076				decoded->src.addr_mode = MODE_IMMEDIATE;
1077				decoded->dst.addr_mode = MODE_REG;
1078				decoded->dst.params.regs.pri = *istream & 0x7;
1079				decoded->src.params.immed = sign_extend16(*(++istream));
1080			} else if(((*istream >> 3) & 0x7) == 1 && (*istream & 0x7) > 1 && (*istream & 0x7) < 5) {
1081#ifdef M68020
1082				decoded->op = M68K_TRAPCC;
1083				decoded->src.addr_mode = MODE_IMMEDIATE;
1084				//TODO: Figure out what to do with OPMODE and optional extention words
1085#endif
1086			} else {
1087				decoded->op = M68K_SCC;
1088				decoded->extra.cond = (*istream >> 8) & 0xF;
1089				istream = m68k_decode_op(istream, OPSIZE_BYTE, &(decoded->dst));
1090				if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
1091					decoded->op = M68K_INVALID;
1092					break;
1093				}
1094			}
1095		} else {
1096			//ADDQ, SUBQ
1097			decoded->variant = VAR_QUICK;
1098			decoded->extra.size = size;
1099			decoded->src.addr_mode = MODE_IMMEDIATE;
1100			immed = m68k_reg_quick_field(*istream);
1101			if (!immed) {
1102				immed = 8;
1103			}
1104			decoded->src.params.immed = immed;
1105			if (*istream & 0x100) {
1106				decoded->op = M68K_SUB;
1107			} else {
1108				decoded->op = M68K_ADD;
1109			}
1110			istream = m68k_decode_op(istream, size, &(decoded->dst));
1111			if (!istream || decoded->dst.addr_mode > MODE_ABSOLUTE || (size == OPSIZE_BYTE && decoded->dst.addr_mode == MODE_AREG)) {
1112				decoded->op = M68K_INVALID;
1113				break;
1114			}
1115		}
1116		break;
1117	case BRANCH:
1118		m68k_decode_cond(*istream, decoded);
1119		decoded->op = decoded->extra.cond == COND_FALSE ? M68K_BSR : M68K_BCC;
1120		decoded->src.addr_mode = MODE_IMMEDIATE;
1121		immed = *istream & 0xFF;
1122		if (immed == 0) {
1123			decoded->variant = VAR_WORD;
1124			immed = *(++istream);
1125			immed = sign_extend16(immed);
1126#ifdef M68020
1127		} else if (immed == 0xFF) {
1128			decoded->variant = VAR_LONG;
1129			immed = *(++istream) << 16;
1130			immed |= *(++istream);
1131#endif
1132		} else {
1133			decoded->variant = VAR_BYTE;
1134			immed = sign_extend8(immed);
1135		}
1136		decoded->src.params.immed = immed;
1137		break;
1138	case MOVEQ:
1139		if (*istream & 0x100) {
1140			decoded->op = M68K_INVALID;
1141			break;
1142		}
1143		decoded->op = M68K_MOVE;
1144		decoded->variant = VAR_QUICK;
1145		decoded->extra.size = OPSIZE_LONG;
1146		decoded->src.addr_mode = MODE_IMMEDIATE;
1147		decoded->src.params.immed = sign_extend8(*istream & 0xFF);
1148		decoded->dst.addr_mode = MODE_REG;
1149		decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1150		immed = *istream & 0xFF;
1151		break;
1152	case OR_DIV_SBCD:
1153		//for OR, if opmode bit 2 is 1, then src = Dn, dst = <ea>
1154		opmode = (*istream >> 6) & 0x7;
1155		size = opmode & 0x3;
1156		if (size == OPSIZE_INVALID || (opmode & 0x4 && !(*istream & 0x30))) {
1157			switch(opmode)
1158			{
1159			case 3:
1160				decoded->op = M68K_DIVU;
1161				decoded->extra.size = OPSIZE_WORD;
1162				decoded->dst.addr_mode = MODE_REG;
1163				decoded->dst.params.regs.pri = (*istream >> 9) & 0x7;
1164				istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src));
1165				if (!istream || decoded->src.addr_mode == MODE_AREG) {
1166					decoded->op = M68K_INVALID;
1167					break;
1168				}
1169				break;
1170			case 4:
1171				decoded->op = M68K_SBCD;
1172				decoded->extra.size = OPSIZE_BYTE;
1173				decoded->dst.addr_mode = decoded->src.addr_mode = *istream & 0x8 ? MODE_AREG_PREDEC : MODE_REG;
1174				decoded->src.params.regs.pri = *istream & 0x7;
1175				decoded->dst.params.regs.pri = (*istream >> 9) & 0x7;
1176				break;
1177			case 5:
1178	#ifdef M68020
1179	#endif
1180				break;
1181			case 6:
1182	#ifdef M68020
1183	#endif
1184				break;
1185			case 7:
1186				decoded->op = M68K_DIVS;
1187				decoded->extra.size = OPSIZE_WORD;
1188				decoded->dst.addr_mode = MODE_REG;
1189				decoded->dst.params.regs.pri = (*istream >> 9) & 0x7;
1190				istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src));
1191				if (!istream || decoded->src.addr_mode == MODE_AREG) {
1192					decoded->op = M68K_INVALID;
1193					break;
1194				}
1195				break;
1196			}
1197		} else {
1198			decoded->op = M68K_OR;
1199			decoded->extra.size = size;
1200			if (opmode & 0x4) {
1201				decoded->src.addr_mode = MODE_REG;
1202				decoded->src.params.regs.pri = (*istream >> 9) & 0x7;
1203				istream = m68k_decode_op(istream, size, &(decoded->dst));
1204				if (!istream || !m68k_valid_full_arith_dst(&(decoded->dst))) {
1205					decoded->op = M68K_INVALID;
1206					break;
1207				}
1208			} else {
1209				decoded->dst.addr_mode = MODE_REG;
1210				decoded->dst.params.regs.pri = (*istream >> 9) & 0x7;
1211				istream = m68k_decode_op(istream, size, &(decoded->src));
1212				if (!istream || decoded->src.addr_mode == MODE_AREG) {
1213					decoded->op = M68K_INVALID;
1214					break;
1215				}
1216			}
1217		}
1218		break;
1219	case SUB_SUBX:
1220		size = (*istream >> 6) & 0x3;
1221		decoded->op = M68K_SUB;
1222		if (*istream & 0x100) {
1223			//<ea> destination, SUBA.l or SUBX
1224			if (*istream & 0x30 || size == OPSIZE_INVALID) {
1225				if (size == OPSIZE_INVALID) {
1226					//SUBA.l
1227					decoded->extra.size = OPSIZE_LONG;
1228					decoded->dst.addr_mode = MODE_AREG;
1229					decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1230					istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->src));
1231					if (!istream) {
1232						decoded->op = M68K_INVALID;
1233						break;
1234					}
1235				} else {
1236					decoded->extra.size = size;
1237					decoded->src.addr_mode = MODE_REG;
1238					decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
1239					istream = m68k_decode_op(istream, size, &(decoded->dst));
1240					if (!istream || !m68k_valid_full_arith_dst(&decoded->dst)) {
1241						decoded->op = M68K_INVALID;
1242						break;
1243					}
1244				}
1245			} else {
1246				//SUBX
1247				decoded->op = M68K_SUBX;
1248				decoded->extra.size = size;
1249				decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1250				decoded->src.params.regs.pri = *istream & 0x7;
1251				if (*istream & 0x8) {
1252					decoded->dst.addr_mode = decoded->src.addr_mode = MODE_AREG_PREDEC;
1253				} else {
1254					decoded->dst.addr_mode = decoded->src.addr_mode = MODE_REG;
1255				}
1256			}
1257		} else {
1258			if (size == OPSIZE_INVALID) {
1259				//SUBA.w
1260				decoded->extra.size = OPSIZE_WORD;
1261				decoded->dst.addr_mode = MODE_AREG;
1262			} else {
1263				decoded->extra.size = size;
1264				decoded->dst.addr_mode = MODE_REG;
1265			}
1266			decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1267			istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
1268			if (!istream || (decoded->src.addr_mode == MODE_AREG && decoded->extra.size == OPSIZE_BYTE)) {
1269				decoded->op = M68K_INVALID;
1270				break;
1271			}
1272		}
1273		break;
1274	case A_LINE:
1275		decoded->op = M68K_A_LINE_TRAP;
1276		break;
1277	case CMP_XOR:
1278		size = (*istream >> 6) & 0x3;
1279		decoded->op = M68K_CMP;
1280		if (*istream & 0x100) {
1281			//CMPM or CMPA.l or EOR
1282			if (size == OPSIZE_INVALID) {
1283				decoded->extra.size = OPSIZE_LONG;
1284				decoded->dst.addr_mode = MODE_AREG;
1285				decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1286				istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
1287				if (!istream) {
1288					decoded->op = M68K_INVALID;
1289					break;
1290				}
1291			} else {
1292				reg = m68k_reg_quick_field(*istream);
1293				istream = m68k_decode_op(istream, size, &(decoded->dst));
1294				if (!istream) {
1295					decoded->op = M68K_INVALID;
1296					break;
1297				}
1298				decoded->extra.size = size;
1299				if (decoded->dst.addr_mode == MODE_AREG) {
1300					//CMPM
1301					decoded->src.addr_mode = decoded->dst.addr_mode = MODE_AREG_POSTINC;
1302					decoded->src.params.regs.pri = decoded->dst.params.regs.pri;
1303					decoded->dst.params.regs.pri = reg;
1304				} else if (!m68k_valid_immed_limited_dst(&decoded->dst)){
1305					decoded->op = M68K_INVALID;
1306					break;
1307				} else {
1308					//EOR
1309					decoded->op = M68K_EOR;
1310					decoded->src.addr_mode = MODE_REG;
1311					decoded->src.params.regs.pri = reg;
1312				}
1313			}
1314		} else {
1315			//CMP or CMPA.w
1316			if (size == OPSIZE_INVALID) {
1317				decoded->extra.size = OPSIZE_WORD;
1318				decoded->dst.addr_mode = MODE_AREG;
1319			} else {
1320				decoded->extra.size = size;
1321				decoded->dst.addr_mode = MODE_REG;
1322			}
1323			decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1324			istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
1325			if (!istream || (decoded->src.addr_mode == MODE_AREG && decoded->extra.size == OPSIZE_BYTE)) {
1326				decoded->op = M68K_INVALID;
1327				break;
1328			}
1329		}
1330		break;
1331	case AND_MUL_ABCD_EXG:
1332		//page 575 for summary
1333		//EXG opmodes:
1334		//01000 -data regs
1335		//01001 -addr regs
1336		//10001 -one of each
1337		//AND opmodes:
1338		//operand order bit + 2 size bits (00 - 10)
1339		//no address register direct addressing
1340		//data register direct not allowed when <ea> is the source (operand order bit of 1)
1341		if (*istream & 0x100) {
1342			if ((*istream & 0xC0) == 0xC0) {
1343				decoded->op = M68K_MULS;
1344				decoded->extra.size = OPSIZE_WORD;
1345				decoded->dst.addr_mode = MODE_REG;
1346				decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1347				istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src));
1348				if (!istream || decoded->src.addr_mode == MODE_AREG) {
1349					decoded->op = M68K_INVALID;
1350					break;
1351				}
1352			} else if(!(*istream & 0xF0)) {
1353				decoded->op = M68K_ABCD;
1354				decoded->extra.size = OPSIZE_BYTE;
1355				decoded->src.params.regs.pri = *istream & 0x7;
1356				decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1357				decoded->dst.addr_mode = decoded->src.addr_mode = (*istream & 8) ? MODE_AREG_PREDEC : MODE_REG;
1358			} else if(!(*istream & 0x30)) {
1359				decoded->op = M68K_EXG;
1360				decoded->extra.size = OPSIZE_LONG;
1361				decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
1362				decoded->dst.params.regs.pri = *istream & 0x7;
1363				if (*istream & 0x8) {
1364					if (*istream & 0x80) {
1365						decoded->src.addr_mode = MODE_REG;
1366						decoded->dst.addr_mode = MODE_AREG;
1367					} else {
1368						decoded->src.addr_mode = decoded->dst.addr_mode = MODE_AREG;
1369					}
1370				} else if (*istream & 0x40) {
1371					decoded->src.addr_mode = decoded->dst.addr_mode = MODE_REG;
1372				} else {
1373					decoded->op = M68K_INVALID;
1374					break;
1375				}
1376			} else {
1377				decoded->op = M68K_AND;
1378				decoded->extra.size = (*istream >> 6) & 0x3;
1379				decoded->src.addr_mode = MODE_REG;
1380				decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
1381				istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->dst));
1382				if (!istream || !m68k_valid_full_arith_dst(&(decoded->dst))) {
1383					decoded->op = M68K_INVALID;
1384					break;
1385				}
1386			}
1387		} else {
1388			if ((*istream & 0xC0) == 0xC0) {
1389				decoded->op = M68K_MULU;
1390				decoded->extra.size = OPSIZE_WORD;
1391				decoded->dst.addr_mode = MODE_REG;
1392				decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1393				istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src));
1394				if (!istream || decoded->src.addr_mode == MODE_AREG) {
1395					decoded->op = M68K_INVALID;
1396					break;
1397				}
1398			} else {
1399				decoded->op = M68K_AND;
1400				decoded->extra.size = (*istream >> 6) & 0x3;
1401				decoded->dst.addr_mode = MODE_REG;
1402				decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1403				istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
1404				if (!istream || decoded->src.addr_mode == MODE_AREG) {
1405					decoded->op = M68K_INVALID;
1406					break;
1407				}
1408			}
1409		}
1410		break;
1411	case ADD_ADDX:
1412		size = (*istream >> 6) & 0x3;
1413		decoded->op = M68K_ADD;
1414		if (*istream & 0x100) {
1415			//<ea> destination, ADDA.l or ADDX
1416			if (*istream & 0x30 || size == OPSIZE_INVALID) {
1417				if (size == OPSIZE_INVALID) {
1418					//ADDA.l
1419					decoded->extra.size = OPSIZE_LONG;
1420					decoded->dst.addr_mode = MODE_AREG;
1421					decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1422					istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->src));
1423					if (!istream) {
1424						decoded->op = M68K_INVALID;
1425						break;
1426					}
1427				} else {
1428					decoded->extra.size = size;
1429					decoded->src.addr_mode = MODE_REG;
1430					decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
1431					istream = m68k_decode_op(istream, size, &(decoded->dst));
1432					if (!istream || !m68k_valid_full_arith_dst(&decoded->dst)) {
1433						decoded->op = M68K_INVALID;
1434						break;
1435					}
1436				}
1437			} else {
1438				//ADDX
1439				decoded->op = M68K_ADDX;
1440				decoded->extra.size = size;
1441				decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1442				decoded->src.params.regs.pri = *istream & 0x7;
1443				if (*istream & 0x8) {
1444					decoded->dst.addr_mode = decoded->src.addr_mode = MODE_AREG_PREDEC;
1445				} else {
1446					decoded->dst.addr_mode = decoded->src.addr_mode = MODE_REG;
1447				}
1448			}
1449		} else {
1450			if (size == OPSIZE_INVALID) {
1451				//ADDA.w
1452				decoded->extra.size = OPSIZE_WORD;
1453				decoded->dst.addr_mode = MODE_AREG;
1454			} else {
1455				decoded->extra.size = size;
1456				decoded->dst.addr_mode = MODE_REG;
1457			}
1458			decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1459			istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
1460			if (!istream || (decoded->src.addr_mode == MODE_AREG && decoded->extra.size == OPSIZE_BYTE)) {
1461				decoded->op = M68K_INVALID;
1462				break;
1463			}
1464		}
1465		break;
1466	case SHIFT_ROTATE:
1467		if ((*istream & 0x8C0) == 0xC0) {
1468			switch((*istream >> 8) & 0x7)
1469			{
1470			case 0:
1471				decoded->op = M68K_ASR;
1472				break;
1473			case 1:
1474				decoded->op = M68K_ASL;
1475				break;
1476			case 2:
1477				decoded->op = M68K_LSR;
1478				break;
1479			case 3:
1480				decoded->op = M68K_LSL;
1481				break;
1482			case 4:
1483				decoded->op = M68K_ROXR;
1484				break;
1485			case 5:
1486				decoded->op = M68K_ROXL;
1487				break;
1488			case 6:
1489				decoded->op = M68K_ROR;
1490				break;
1491			case 7:
1492				decoded->op = M68K_ROL;
1493				break;
1494			}
1495			decoded->extra.size = OPSIZE_WORD;
1496			istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->dst));
1497			if (!istream || !m68k_valid_full_arith_dst(&decoded->dst)) {
1498				decoded->op = M68K_INVALID;
1499				break;
1500			}
1501		} else if((*istream & 0xC0) != 0xC0) {
1502			switch(((*istream >> 2) & 0x6) | ((*istream >> 8) & 1))
1503			{
1504			case 0:
1505				decoded->op = M68K_ASR;
1506				break;
1507			case 1:
1508				decoded->op = M68K_ASL;
1509				break;
1510			case 2:
1511				decoded->op = M68K_LSR;
1512				break;
1513			case 3:
1514				decoded->op = M68K_LSL;
1515				break;
1516			case 4:
1517				decoded->op = M68K_ROXR;
1518				break;
1519			case 5:
1520				decoded->op = M68K_ROXL;
1521				break;
1522			case 6:
1523				decoded->op = M68K_ROR;
1524				break;
1525			case 7:
1526				decoded->op = M68K_ROL;
1527				break;
1528			}
1529			decoded->extra.size = (*istream >> 6) & 0x3;
1530			immed = (*istream >> 9) & 0x7;
1531			if (*istream & 0x20) {
1532				decoded->src.addr_mode = MODE_REG;
1533				decoded->src.params.regs.pri = immed;
1534			} else {
1535				decoded->src.addr_mode = MODE_IMMEDIATE;
1536				if (!immed) {
1537					immed = 8;
1538				}
1539				decoded->src.params.immed = immed;
1540				decoded->variant = VAR_QUICK;
1541			}
1542			decoded->dst.addr_mode = MODE_REG;
1543			decoded->dst.params.regs.pri = *istream & 0x7;
1544
1545		} else {
1546#ifdef M68020
1547			//TODO: Implement bitfield instructions for M68020+ support
1548			switch (*istream >> 8 & 7)
1549			{
1550			case 0:
1551				decoded->op = M68K_BFTST; //<ea>
1552				break;
1553			case 1:
1554				decoded->op = M68K_BFEXTU; //<ea>, Dn
1555				break;
1556			case 2:
1557				decoded->op = M68K_BFCHG; //<ea>
1558				break;
1559			case 3:
1560				decoded->op = M68K_BFEXTS; //<ea>, Dn
1561				break;
1562			case 4:
1563				decoded->op = M68K_BFCLR; //<ea>
1564				break;
1565			case 5:
1566				decoded->op = M68K_BFFFO; //<ea>, Dn
1567				break;
1568			case 6:
1569				decoded->op = M68K_BFSET; //<ea>
1570				break;
1571			case 7:
1572				decoded->op = M68K_BFINS; //Dn, <ea>
1573				break;
1574			}
1575			opmode = *istream >> 3 & 0x7;
1576			reg = *istream & 0x7;
1577			m68k_op_info *ea, *other;
1578			if (decoded->op == M68K_BFEXTU || decoded->op == M68K_BFEXTS || decoded->op == M68K_BFFFO)
1579			{
1580				ea = &(decoded->src);
1581				other = &(decoded->dst);
1582			} else {
1583				ea = &(decoded->dst);
1584				other = &(decoded->dst);
1585			}
1586			if (*istream & 0x100)
1587			{
1588				immed = *(istream++);
1589				other->addr_mode = MODE_REG;
1590				other->params.regs.pri = immed >> 12 & 0x7;
1591			} else {
1592				immed = *(istream++);
1593			}
1594			decoded->extra.size = OPSIZE_UNSIZED;
1595			istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, ea);
1596			ea->addr_mode |= M68K_FLAG_BITFIELD;
1597			ea->bitfield = immed & 0xFFF;
1598#endif
1599		}
1600		break;
1601	case F_LINE:
1602		//TODO: Decode FPU instructions for members of the 68K family with an FPU
1603		decoded->op = M68K_F_LINE_TRAP;
1604		break;
1605	}
1606	if (decoded->op == M68K_INVALID) {
1607		decoded->src.params.immed = *start;
1608		decoded->bytes = 2;
1609		return start + 1;
1610	}
1611	decoded->bytes = 2 * (istream + 1 - start);
1612	return istream+1;
1613}
1614
1615uint32_t m68k_branch_target(m68kinst * inst, uint32_t *dregs, uint32_t *aregs)
1616{
1617	if(inst->op == M68K_BCC || inst->op == M68K_BSR || inst->op == M68K_DBCC) {
1618		return inst->address + 2 + inst->src.params.immed;
1619	} else if(inst->op == M68K_JMP || inst->op == M68K_JSR) {
1620		uint32_t ret = 0;
1621		switch(inst->src.addr_mode)
1622		{
1623		case MODE_AREG_INDIRECT:
1624			ret = aregs[inst->src.params.regs.pri];
1625			break;
1626		case MODE_AREG_DISPLACE:
1627			ret = aregs[inst->src.params.regs.pri] + inst->src.params.regs.displacement;
1628			break;
1629		case MODE_AREG_INDEX_DISP8: {
1630			uint8_t sec_reg = inst->src.params.regs.sec >> 1 & 0x7;
1631			ret = aregs[inst->src.params.regs.pri];
1632			uint32_t * regfile = inst->src.params.regs.sec & 0x10 ? aregs : dregs;
1633			if (inst->src.params.regs.sec & 1) {
1634				//32-bit index register
1635				ret += regfile[sec_reg];
1636			} else {
1637				//16-bit index register
1638				if (regfile[sec_reg] & 0x8000) {
1639					ret += (0xFFFF0000 | regfile[sec_reg]);
1640				} else {
1641					ret += regfile[sec_reg];
1642				}
1643			}
1644			ret += inst->src.params.regs.displacement;
1645			break;
1646		}
1647		case MODE_PC_DISPLACE:
1648			ret = inst->src.params.regs.displacement + inst->address + 2;
1649			break;
1650		case MODE_PC_INDEX_DISP8: {
1651			uint8_t sec_reg = inst->src.params.regs.sec >> 1 & 0x7;
1652			ret = inst->address + 2;
1653			uint32_t * regfile = inst->src.params.regs.sec & 0x10 ? aregs : dregs;
1654			if (inst->src.params.regs.sec & 1) {
1655				//32-bit index register
1656				ret += regfile[sec_reg];
1657			} else {
1658				//16-bit index register
1659				if (regfile[sec_reg] & 0x8000) {
1660					ret += (0xFFFF0000 | regfile[sec_reg]);
1661				} else {
1662					ret += regfile[sec_reg];
1663				}
1664			}
1665			ret += inst->src.params.regs.displacement;
1666			break;
1667		}
1668		case MODE_ABSOLUTE:
1669		case MODE_ABSOLUTE_SHORT:
1670			ret = inst->src.params.immed;
1671			break;
1672		}
1673		return ret;
1674	}
1675	return 0;
1676}
1677
1678uint8_t m68k_is_branch(m68kinst * inst)
1679{
1680	return (inst->op == M68K_BCC && inst->extra.cond != COND_FALSE)
1681		|| (inst->op == M68K_DBCC && inst->extra.cond != COND_TRUE)
1682		|| inst->op == M68K_BSR || inst->op == M68K_JMP || inst->op == M68K_JSR;
1683}
1684
1685uint8_t m68k_is_noncall_branch(m68kinst * inst)
1686{
1687	return m68k_is_branch(inst) && inst->op != M68K_BSR && inst->op != M68K_JSR;
1688}
1689
1690
1691char * mnemonics[] = {
1692	"abcd",
1693	"add",
1694	"addx",
1695	"and",
1696	"andi",//ccr
1697	"andi",//sr
1698	"asl",
1699	"asr",
1700	"bcc",
1701	"bchg",
1702	"bclr",
1703	"bset",
1704	"bsr",
1705	"btst",
1706	"chk",
1707	"clr",
1708	"cmp",
1709	"dbcc",
1710	"divs",
1711	"divu",
1712	"eor",
1713	"eori",//ccr
1714	"eori",//sr
1715	"exg",
1716	"ext",
1717	"illegal",
1718	"jmp",
1719	"jsr",
1720	"lea",
1721	"link",
1722	"lsl",
1723	"lsr",
1724	"move",
1725	"move",//ccr
1726	"move",//from_sr
1727	"move",//sr
1728	"move",//usp
1729	"movem",
1730	"movep",
1731	"muls",
1732	"mulu",
1733	"nbcd",
1734	"neg",
1735	"negx",
1736	"nop",
1737	"not",
1738	"or",
1739	"ori",//ccr
1740	"ori",//sr
1741	"pea",
1742	"reset",
1743	"rol",
1744	"ror",
1745	"roxl",
1746	"roxr",
1747	"rte",
1748	"rtr",
1749	"rts",
1750	"sbcd",
1751	"scc",
1752	"stop",
1753	"sub",
1754	"subx",
1755	"swap",
1756	"tas",
1757	"trap",
1758	"trapv",
1759	"tst",
1760	"unlk",
1761	"invalid",
1762#ifdef M68010
1763	"bkpt",
1764	"move", //from ccr
1765	"movec",
1766	"moves",
1767	"rtd",
1768#endif
1769#ifdef M68020
1770	"bfchg",
1771	"bfclr",
1772	"bfexts",
1773	"bfextu",
1774	"bfffo",
1775	"bfins",
1776	"bfset",
1777	"bftst",
1778	"callm",
1779	"cas",
1780	"cas2",
1781	"chk2",
1782	"cmp2",
1783	"cpbcc",
1784	"cpdbcc",
1785	"cpgen",
1786	"cprestore",
1787	"cpsave",
1788	"cpscc",
1789	"cptrapcc",
1790	"divsl",
1791	"divul",
1792	"extb",
1793	"pack",
1794	"rtm",
1795	"trapcc",
1796	"unpk"
1797#endif
1798};
1799
1800char * cond_mnem[] = {
1801	"ra",
1802	"f",
1803	"hi",
1804	"ls",
1805	"cc",
1806	"cs",
1807	"ne",
1808	"eq",
1809	"vc",
1810	"vs",
1811	"pl",
1812	"mi",
1813	"ge",
1814	"lt",
1815	"gt",
1816	"le"
1817};
1818#ifdef M68010
1819char * cr_mnem[] = {
1820	"SFC",
1821	"DFC",
1822#ifdef M68020
1823	"CACR",
1824#endif
1825	"USP",
1826	"VBR",
1827#ifdef M68020
1828	"CAAR",
1829	"MSP",
1830	"ISP"
1831#endif
1832};
1833#endif
1834
1835int m68k_disasm_op(m68k_op_info *decoded, char *dst, int need_comma, uint8_t labels, uint32_t address, format_label_fun label_fun, void * data)
1836{
1837	char * c = need_comma ? "," : "";
1838	int ret = 0;
1839#ifdef M68020
1840	uint8_t addr_mode = decoded->addr_mode & (~M68K_FLAG_BITFIELD);
1841#else
1842	uint8_t addr_mode = decoded->addr_mode;
1843#endif
1844	switch(addr_mode)
1845	{
1846	case MODE_REG:
1847		ret = sprintf(dst, "%s d%d", c, decoded->params.regs.pri);
1848		break;
1849	case MODE_AREG:
1850		ret = sprintf(dst, "%s a%d", c, decoded->params.regs.pri);
1851		break;
1852	case MODE_AREG_INDIRECT:
1853		ret = sprintf(dst, "%s (a%d)", c, decoded->params.regs.pri);
1854		break;
1855	case MODE_AREG_POSTINC:
1856		ret = sprintf(dst, "%s (a%d)+", c, decoded->params.regs.pri);
1857		break;
1858	case MODE_AREG_PREDEC:
1859		ret = sprintf(dst, "%s -(a%d)", c, decoded->params.regs.pri);
1860		break;
1861	case MODE_AREG_DISPLACE:
1862		ret = sprintf(dst, "%s (%d, a%d)", c, decoded->params.regs.displacement, decoded->params.regs.pri);
1863		break;
1864	case MODE_AREG_INDEX_DISP8:
1865#ifdef M68020
1866		if (decoded->params.regs.scale)
1867		{
1868			ret = sprintf(dst, "%s (%d, a%d, %c%d.%c*%d)", c, decoded->params.regs.displacement, decoded->params.regs.pri, (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
1869		} else {
1870#endif
1871			ret = sprintf(dst, "%s (%d, a%d, %c%d.%c)", c, decoded->params.regs.displacement, decoded->params.regs.pri, (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w');
1872#ifdef M68020
1873		}
1874#endif
1875		break;
1876#ifdef M68020
1877	case MODE_AREG_INDEX_BASE_DISP:
1878		if (decoded->params.regs.disp_sizes > 1)
1879		{
1880			ret = sprintf(dst, "%s (%d.%c, a%d, %c%d.%c*%d)", c, decoded->params.regs.displacement,
1881			              decoded->params.regs.disp_sizes == 2 ? 'w' : 'l', decoded->params.regs.pri,
1882			              (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1883			              (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
1884		} else {
1885			ret = sprintf(dst, "%s (a%d, %c%d.%c*%d)", c, decoded->params.regs.pri,
1886			              (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1887			              (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
1888		}
1889		break;
1890	case MODE_AREG_PREINDEX:
1891		switch (decoded->params.regs.disp_sizes)
1892		{
1893		case 0x11:
1894			//no base displacement or outer displacement
1895			ret = sprintf(dst, "%s ([a%d, %c%d.%c*%d])", c, decoded->params.regs.pri,
1896						  (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1897						  (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
1898			break;
1899		case 0x12:
1900		case 0x13:
1901			//base displacement only
1902			ret = sprintf(dst, "%s ([%d.%c, a%d, %c%d.%c*%d])", c, decoded->params.regs.displacement,
1903			              decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri,
1904			              (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1905			              (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
1906			break;
1907		case 0x21:
1908		case 0x31:
1909			//outer displacement only
1910			ret = sprintf(dst, "%s ([a%d, %c%d.%c*%d], %d.%c)", c, decoded->params.regs.pri,
1911			              (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1912			              (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
1913			              decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
1914			break;
1915		case 0x22:
1916		case 0x23:
1917		case 0x32:
1918		case 0x33:
1919			//both outer and inner displacement
1920			ret = sprintf(dst, "%s ([%d.%c, a%d, %c%d.%c*%d], %d.%c)", c, decoded->params.regs.displacement,
1921			              decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri,
1922			              (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1923			              (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
1924			              decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
1925			break;
1926		}
1927		break;
1928	case MODE_AREG_POSTINDEX:
1929		switch (decoded->params.regs.disp_sizes)
1930		{
1931		case 0x11:
1932			//no base displacement or outer displacement
1933			ret = sprintf(dst, "%s ([a%d], %c%d.%c*%d)", c, decoded->params.regs.pri,
1934						  (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1935						  (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
1936			break;
1937		case 0x12:
1938		case 0x13:
1939			//base displacement only
1940			ret = sprintf(dst, "%s ([%d.%c, a%d], %c%d.%c*%d)", c, decoded->params.regs.displacement,
1941			              decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri,
1942			              (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1943			              (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
1944			break;
1945		case 0x21:
1946		case 0x31:
1947			//outer displacement only
1948			ret = sprintf(dst, "%s ([a%d], %c%d.%c*%d, %d.%c)", c, decoded->params.regs.pri,
1949			              (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1950			              (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
1951			              decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
1952			break;
1953		case 0x22:
1954		case 0x23:
1955		case 0x32:
1956		case 0x33:
1957			//both outer and inner displacement
1958			ret = sprintf(dst, "%s ([%d.%c, a%d], %c%d.%c*%d, %d.%c)", c, decoded->params.regs.displacement,
1959			              decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri,
1960			              (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1961			              (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
1962			              decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
1963			break;
1964		}
1965		break;
1966	case MODE_AREG_MEM_INDIRECT:
1967		switch (decoded->params.regs.disp_sizes)
1968		{
1969		case 0x11:
1970			//no base displacement or outer displacement
1971			ret = sprintf(dst, "%s ([a%d])", c, decoded->params.regs.pri);
1972			break;
1973		case 0x12:
1974		case 0x13:
1975			//base displacement only
1976			ret = sprintf(dst, "%s ([%d.%c, a%d])", c, decoded->params.regs.displacement,
1977			              decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri);
1978			break;
1979		case 0x21:
1980		case 0x31:
1981			//outer displacement only
1982			ret = sprintf(dst, "%s ([a%d], %d.%c)", c, decoded->params.regs.pri, decoded->params.regs.outer_disp,
1983			              decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
1984			break;
1985		case 0x22:
1986		case 0x23:
1987		case 0x32:
1988		case 0x33:
1989			//both outer and inner displacement
1990			ret = sprintf(dst, "%s ([%d.%c, a%d], %d.%c)", c, decoded->params.regs.displacement,
1991			              decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri,
1992			              decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
1993			break;
1994		}
1995		break;
1996	case MODE_AREG_BASE_DISP:
1997		if (decoded->params.regs.disp_sizes > 1)
1998		{
1999			ret = sprintf(dst, "%s (%d.%c, a%d)", c, decoded->params.regs.displacement,
2000			              decoded->params.regs.disp_sizes == 2 ? 'w' : 'l', decoded->params.regs.pri);
2001		} else {
2002			//this is a lossy representation of the encoded instruction
2003			//not sure if there's a better way to print it though
2004			ret = sprintf(dst, "%s (a%d)", c, decoded->params.regs.pri);
2005		}
2006		break;
2007	case MODE_INDEX_BASE_DISP:
2008		if (decoded->params.regs.disp_sizes > 1)
2009		{
2010			ret = sprintf(dst, "%s (%d.%c, %c%d.%c*%d)", c, decoded->params.regs.displacement,
2011			              decoded->params.regs.disp_sizes == 2 ? 'w' : 'l',
2012			              (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2013			              (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2014		} else {
2015			ret = sprintf(dst, "%s (%c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2016			              (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2017			              1 << decoded->params.regs.scale);
2018		}
2019		break;
2020	case MODE_PREINDEX:
2021		switch (decoded->params.regs.disp_sizes)
2022		{
2023		case 0x11:
2024			//no base displacement or outer displacement
2025			ret = sprintf(dst, "%s ([%c%d.%c*%d])", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2026			              (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2027			              1 << decoded->params.regs.scale);
2028			break;
2029		case 0x12:
2030		case 0x13:
2031			//base displacement only
2032			ret = sprintf(dst, "%s ([%d.%c, %c%d.%c*%d])", c, decoded->params.regs.displacement,
2033			              decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2034			              (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2035			              (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2036			break;
2037		case 0x21:
2038		case 0x31:
2039			//outer displacement only
2040			ret = sprintf(dst, "%s ([%c%d.%c*%d], %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2041			              (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2042			              1 << decoded->params.regs.scale, decoded->params.regs.outer_disp,
2043			              decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2044			break;
2045		case 0x22:
2046		case 0x23:
2047		case 0x32:
2048		case 0x33:
2049			//both outer and inner displacement
2050			ret = sprintf(dst, "%s ([%d.%c, %c%d.%c*%d], %d.%c)", c, decoded->params.regs.displacement,
2051			              decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2052			              (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2053			              (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
2054			              decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2055			break;
2056		}
2057		break;
2058	case MODE_POSTINDEX:
2059		switch (decoded->params.regs.disp_sizes)
2060		{
2061		case 0x11:
2062			//no base displacement or outer displacement
2063			ret = sprintf(dst, "%s ([], %c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2064			              (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2065			              1 << decoded->params.regs.scale);
2066			break;
2067		case 0x12:
2068		case 0x13:
2069			//base displacement only
2070			ret = sprintf(dst, "%s ([%d.%c], %c%d.%c*%d)", c, decoded->params.regs.displacement,
2071			              decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2072			              (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2073			              (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2074			break;
2075		case 0x21:
2076		case 0x31:
2077			//outer displacement only
2078			ret = sprintf(dst, "%s ([], %c%d.%c*%d, %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2079			              (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2080			              1 << decoded->params.regs.scale, decoded->params.regs.outer_disp,
2081			              decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2082			break;
2083		case 0x22:
2084		case 0x23:
2085		case 0x32:
2086		case 0x33:
2087			//both outer and inner displacement
2088			ret = sprintf(dst, "%s ([%d.%c], %c%d.%c*%d, %d.%c)", c, decoded->params.regs.displacement,
2089			              decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2090			              (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2091			              (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
2092			              decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2093			break;
2094		}
2095		break;
2096	case MODE_MEM_INDIRECT:
2097		switch (decoded->params.regs.disp_sizes)
2098		{
2099		case 0x11:
2100			//no base displacement or outer displacement
2101			ret = sprintf(dst, "%s ([])", c);
2102			break;
2103		case 0x12:
2104		case 0x13:
2105			//base displacement only
2106			ret = sprintf(dst, "%s ([%d.%c])", c, decoded->params.regs.displacement,
2107			              decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l');
2108			break;
2109		case 0x21:
2110		case 0x31:
2111			//outer displacement only
2112			ret = sprintf(dst, "%s ([], %d.%c)", c, decoded->params.regs.outer_disp,
2113			              decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2114			break;
2115		case 0x22:
2116		case 0x23:
2117		case 0x32:
2118		case 0x33:
2119			//both outer and inner displacement
2120			ret = sprintf(dst, "%s ([%d.%c], %d.%c)", c, decoded->params.regs.displacement,
2121			              decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.outer_disp,
2122			              decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2123			break;
2124		}
2125		break;
2126	case MODE_BASE_DISP:
2127		if (decoded->params.regs.disp_sizes > 1)
2128		{
2129			ret = sprintf(dst, "%s (%d.%c)", c, decoded->params.regs.displacement,
2130			              decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l');
2131		} else {
2132			ret = sprintf(dst, "%s ()", c);
2133		}
2134		break;
2135#endif
2136	case MODE_IMMEDIATE:
2137	case MODE_IMMEDIATE_WORD:
2138		ret = sprintf(dst, (decoded->params.immed <= 128 ? "%s #%d" : "%s #$%X"), c, decoded->params.immed);
2139		break;
2140	case MODE_ABSOLUTE_SHORT:
2141		if (labels) {
2142			ret = sprintf(dst, "%s ", c);
2143			ret += label_fun(dst+ret, decoded->params.immed, data);
2144			strcat(dst+ret, ".w");
2145			ret = ret + 2;
2146		} else {
2147			ret = sprintf(dst, "%s $%X.w", c, decoded->params.immed);
2148		}
2149		break;
2150	case MODE_ABSOLUTE:
2151		if (labels) {
2152			ret = sprintf(dst, "%s ", c);
2153			ret += label_fun(dst+ret, decoded->params.immed, data);
2154			strcat(dst+ret, ".l");
2155			ret = ret + 2;
2156		} else {
2157			ret = sprintf(dst, "%s $%X", c, decoded->params.immed);
2158		}
2159		break;
2160	case MODE_PC_DISPLACE:
2161		if (labels) {
2162			ret = sprintf(dst, "%s ", c);
2163			ret += label_fun(dst+ret, address + 2 + decoded->params.regs.displacement, data);
2164			strcat(dst+ret, "(pc)");
2165			ret = ret + 4;
2166		} else {
2167			ret = sprintf(dst, "%s (%d, pc)", c, decoded->params.regs.displacement);
2168		}
2169		break;
2170	case MODE_PC_INDEX_DISP8:
2171#ifdef M68020
2172		if (decoded->params.regs.scale)
2173		{
2174			ret = sprintf(dst, "%s (%d, pc, %c%d.%c*%d)", c, decoded->params.regs.displacement, (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2175		} else {
2176#endif
2177			ret = sprintf(dst, "%s (%d, pc, %c%d.%c)", c, decoded->params.regs.displacement, (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w');
2178#ifdef M68020
2179		}
2180#endif
2181		break;
2182#ifdef M68020
2183	case MODE_PC_INDEX_BASE_DISP:
2184		if (decoded->params.regs.disp_sizes > 1)
2185		{
2186			ret = sprintf(dst, "%s (%d.%c, pc, %c%d.%c*%d)", c, decoded->params.regs.displacement,
2187			              decoded->params.regs.disp_sizes == 2 ? 'w' : 'l',
2188			              (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2189			              (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2190		} else {
2191			ret = sprintf(dst, "%s (pc, %c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2192			              (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2193			              1 << decoded->params.regs.scale);
2194		}
2195		break;
2196	case MODE_PC_PREINDEX:
2197		switch (decoded->params.regs.disp_sizes)
2198		{
2199		case 0x11:
2200			//no base displacement or outer displacement
2201			ret = sprintf(dst, "%s ([pc, %c%d.%c*%d])", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2202			              (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2203			              1 << decoded->params.regs.scale);
2204			break;
2205		case 0x12:
2206		case 0x13:
2207			//base displacement only
2208			ret = sprintf(dst, "%s ([%d.%c, pc, %c%d.%c*%d])", c, decoded->params.regs.displacement,
2209			              decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2210			              (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2211			              (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2212			break;
2213		case 0x21:
2214		case 0x31:
2215			//outer displacement only
2216			ret = sprintf(dst, "%s ([pc, %c%d.%c*%d], %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2217			              (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2218			              1 << decoded->params.regs.scale, decoded->params.regs.outer_disp,
2219			              decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2220			break;
2221		case 0x22:
2222		case 0x23:
2223		case 0x32:
2224		case 0x33:
2225			//both outer and inner displacement
2226			ret = sprintf(dst, "%s ([%d.%c, pc, %c%d.%c*%d], %d.%c)", c, decoded->params.regs.displacement,
2227			              decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2228			              (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2229			              (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
2230			              decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2231			break;
2232		}
2233		break;
2234	case MODE_PC_POSTINDEX:
2235		switch (decoded->params.regs.disp_sizes)
2236		{
2237		case 0x11:
2238			//no base displacement or outer displacement
2239			ret = sprintf(dst, "%s ([pc], %c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2240			              (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2241			              1 << decoded->params.regs.scale);
2242			break;
2243		case 0x12:
2244		case 0x13:
2245			//base displacement only
2246			ret = sprintf(dst, "%s ([%d.%c, pc], %c%d.%c*%d)", c, decoded->params.regs.displacement,
2247			              decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2248			              (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2249			              (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2250			break;
2251		case 0x21:
2252		case 0x31:
2253			//outer displacement only
2254			ret = sprintf(dst, "%s ([pc], %c%d.%c*%d, %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2255			              (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2256			              1 << decoded->params.regs.scale, decoded->params.regs.outer_disp,
2257			              decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2258			break;
2259		case 0x22:
2260		case 0x23:
2261		case 0x32:
2262		case 0x33:
2263			//both outer and inner displacement
2264			ret = sprintf(dst, "%s ([%d.%c, pc], %c%d.%c*%d, %d.%c)", c, decoded->params.regs.displacement,
2265			              decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2266			              (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2267			              (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
2268			              decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2269			break;
2270		}
2271		break;
2272	case MODE_PC_MEM_INDIRECT:
2273		switch (decoded->params.regs.disp_sizes)
2274		{
2275		case 0x11:
2276			//no base displacement or outer displacement
2277			ret = sprintf(dst, "%s ([pc])", c);
2278			break;
2279		case 0x12:
2280		case 0x13:
2281			//base displacement only
2282			ret = sprintf(dst, "%s ([%d.%c, pc])", c, decoded->params.regs.displacement,
2283			              decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l');
2284			break;
2285		case 0x21:
2286		case 0x31:
2287			//outer displacement only
2288			ret = sprintf(dst, "%s ([pc], %d.%c)", c, decoded->params.regs.outer_disp,
2289			              decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2290			break;
2291		case 0x22:
2292		case 0x23:
2293		case 0x32:
2294		case 0x33:
2295			//both outer and inner displacement
2296			ret = sprintf(dst, "%s ([%d.%c, pc], %d.%c)", c, decoded->params.regs.displacement,
2297			              decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.outer_disp,
2298			              decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2299			break;
2300		}
2301		break;
2302	case MODE_PC_BASE_DISP:
2303		if (decoded->params.regs.disp_sizes > 1)
2304		{
2305			ret = sprintf(dst, "%s (%d.%c, pc)", c, decoded->params.regs.displacement,
2306			              decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l');
2307		} else {
2308			ret = sprintf(dst, "%s (pc)", c);
2309		}
2310		break;
2311	case MODE_ZPC_INDEX_BASE_DISP:
2312		if (decoded->params.regs.disp_sizes > 1)
2313		{
2314			ret = sprintf(dst, "%s (%d.%c, zpc, %c%d.%c*%d)", c, decoded->params.regs.displacement,
2315			              decoded->params.regs.disp_sizes == 2 ? 'w' : 'l',
2316			              (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2317			              (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2318		} else {
2319			ret = sprintf(dst, "%s (zpc, %c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2320			              (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2321			              1 << decoded->params.regs.scale);
2322		}
2323		break;
2324	case MODE_ZPC_PREINDEX:
2325		switch (decoded->params.regs.disp_sizes)
2326		{
2327		case 0x11:
2328			//no base displacement or outer displacement
2329			ret = sprintf(dst, "%s ([zpc, %c%d.%c*%d])", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2330			              (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2331			              1 << decoded->params.regs.scale);
2332			break;
2333		case 0x12:
2334		case 0x13:
2335			//base displacement only
2336			ret = sprintf(dst, "%s ([%d.%c, zpc, %c%d.%c*%d])", c, decoded->params.regs.displacement,
2337			              decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2338			              (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2339			              (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2340			break;
2341		case 0x21:
2342		case 0x31:
2343			//outer displacement only
2344			ret = sprintf(dst, "%s ([zpc, %c%d.%c*%d], %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2345			              (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2346			              1 << decoded->params.regs.scale, decoded->params.regs.outer_disp,
2347			              decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2348			break;
2349		case 0x22:
2350		case 0x23:
2351		case 0x32:
2352		case 0x33:
2353			//both outer and inner displacement
2354			ret = sprintf(dst, "%s ([%d.%c, zpc, %c%d.%c*%d], %d.%c)", c, decoded->params.regs.displacement,
2355			              decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2356			              (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2357			              (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
2358			              decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2359			break;
2360		}
2361		break;
2362	case MODE_ZPC_POSTINDEX:
2363		switch (decoded->params.regs.disp_sizes)
2364		{
2365		case 0x11:
2366			//no base displacement or outer displacement
2367			ret = sprintf(dst, "%s ([zpc], %c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2368			              (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2369			              1 << decoded->params.regs.scale);
2370			break;
2371		case 0x12:
2372		case 0x13:
2373			//base displacement only
2374			ret = sprintf(dst, "%s ([%d.%c, zpc], %c%d.%c*%d)", c, decoded->params.regs.displacement,
2375			              decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2376			              (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2377			              (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2378			break;
2379		case 0x21:
2380		case 0x31:
2381			//outer displacement only
2382			ret = sprintf(dst, "%s ([zpc], %c%d.%c*%d, %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2383			              (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2384			              1 << decoded->params.regs.scale, decoded->params.regs.outer_disp,
2385			              decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2386			break;
2387		case 0x22:
2388		case 0x23:
2389		case 0x32:
2390		case 0x33:
2391			//both outer and inner displacement
2392			ret = sprintf(dst, "%s ([%d.%c, zpc], %c%d.%c*%d, %d.%c)", c, decoded->params.regs.displacement,
2393			              decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2394			              (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2395			              (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
2396			              decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2397			break;
2398		}
2399		break;
2400	case MODE_ZPC_MEM_INDIRECT:
2401		switch (decoded->params.regs.disp_sizes)
2402		{
2403		case 0x11:
2404			//no base displacement or outer displacement
2405			ret = sprintf(dst, "%s ([zpc])", c);
2406			break;
2407		case 0x12:
2408		case 0x13:
2409			//base displacement only
2410			ret = sprintf(dst, "%s ([%d.%c, zpc])", c, decoded->params.regs.displacement,
2411			              decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l');
2412			break;
2413		case 0x21:
2414		case 0x31:
2415			//outer displacement only
2416			ret = sprintf(dst, "%s ([zpc], %d.%c)", c, decoded->params.regs.outer_disp,
2417			              decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2418			break;
2419		case 0x22:
2420		case 0x23:
2421		case 0x32:
2422		case 0x33:
2423			//both outer and inner displacement
2424			ret = sprintf(dst, "%s ([%d.%c, zpc], %d.%c)", c, decoded->params.regs.displacement,
2425			              decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.outer_disp,
2426			              decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2427			break;
2428		}
2429		break;
2430	case MODE_ZPC_BASE_DISP:
2431		if (decoded->params.regs.disp_sizes > 1)
2432		{
2433			ret = sprintf(dst, "%s (%d.%c, zpc)", c, decoded->params.regs.displacement,
2434			              decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l');
2435		} else {
2436			ret = sprintf(dst, "%s (zpc)", c);
2437		}
2438		break;
2439#endif
2440	default:
2441		ret = 0;
2442	}
2443#ifdef M68020
2444	if (decoded->addr_mode & M68K_FLAG_BITFIELD)
2445	{
2446		switch (decoded->bitfield & 0x820)
2447		{
2448		case 0:
2449			return ret + sprintf(dst+ret, " {$%X:%d}", decoded->bitfield >> 6 & 0x1F, decoded->bitfield & 0x1F ? decoded->bitfield & 0x1F : 32);
2450		case 0x20:
2451			return ret + sprintf(dst+ret, " {$%X:d%d}", decoded->bitfield >> 6 & 0x1F, decoded->bitfield & 0x7);
2452		case 0x800:
2453			return ret + sprintf(dst+ret, " {d%d:%d}", decoded->bitfield >> 6 & 0x7, decoded->bitfield & 0x1F ? decoded->bitfield & 0x1F : 32);
2454		case 0x820:
2455			return ret + sprintf(dst+ret, " {d%d:d%d}", decoded->bitfield >> 6 & 0x7, decoded->bitfield & 0x7);
2456		}
2457	}
2458#endif
2459	return ret;
2460}
2461
2462int m68k_disasm_movem_op(m68k_op_info *decoded, m68k_op_info *other, char *dst, int need_comma, uint8_t labels, uint32_t address, format_label_fun label_fun, void * data)
2463{
2464	int8_t dir, reg, bit, regnum, last=-1, lastreg, first=-1;
2465	char *rtype, *last_rtype;
2466	int oplen;
2467	if (decoded->addr_mode == MODE_REG) {
2468		if (other->addr_mode == MODE_AREG_PREDEC) {
2469			bit = 15;
2470			dir = -1;
2471		} else {
2472			dir = 1;
2473			bit = 0;
2474		}
2475		if (need_comma) {
2476			strcat(dst, ", ");
2477			oplen = 2;
2478		} else {
2479			strcat(dst, " ");
2480			oplen = 1;
2481		}
2482		for (reg=0; bit < 16 && bit > -1; bit += dir, reg++) {
2483			if (decoded->params.immed & (1 << bit)) {
2484				if (reg > 7) {
2485					rtype = "a";
2486					regnum = reg - 8;
2487				} else {
2488					rtype = "d";
2489					regnum = reg;
2490				}
2491				if (last >= 0 && last == regnum - 1 && lastreg == reg - 1) {
2492					last = regnum;
2493					lastreg = reg;
2494				} else if(last >= 0) {
2495					if (first != last) {
2496						oplen += sprintf(dst + oplen, "-%s%d/%s%d",last_rtype, last, rtype, regnum);
2497					} else {
2498						oplen += sprintf(dst + oplen, "/%s%d", rtype, regnum);
2499					}
2500					first = last = regnum;
2501					last_rtype = rtype;
2502					lastreg = reg;
2503				} else {
2504					oplen += sprintf(dst + oplen, "%s%d", rtype, regnum);
2505					first = last = regnum;
2506					last_rtype = rtype;
2507					lastreg = reg;
2508				}
2509			}
2510		}
2511		if (last >= 0 && last != first) {
2512			oplen += sprintf(dst + oplen, "-%s%d", last_rtype, last);
2513		}
2514		return oplen;
2515	} else {
2516		return m68k_disasm_op(decoded, dst, need_comma, labels, address, label_fun, data);
2517	}
2518}
2519
2520int m68k_default_label_fun(char * dst, uint32_t address, void * data)
2521{
2522	return sprintf(dst, "ADR_%X", address);
2523}
2524
2525int m68k_disasm_ex(m68kinst * decoded, char * dst, uint8_t labels, format_label_fun label_fun, void * data)
2526{
2527	int ret,op1len;
2528	uint8_t size;
2529	char * special_op = "CCR";
2530	switch (decoded->op)
2531	{
2532	case M68K_BCC:
2533	case M68K_DBCC:
2534	case M68K_SCC:
2535		ret = strlen(mnemonics[decoded->op]) - 2;
2536		memcpy(dst, mnemonics[decoded->op], ret);
2537		dst[ret] = 0;
2538		strcpy(dst+ret, cond_mnem[decoded->extra.cond]);
2539		ret = strlen(dst);
2540		if (decoded->op != M68K_SCC) {
2541			if (labels) {
2542				if (decoded->op == M68K_DBCC) {
2543					ret += sprintf(dst+ret, " d%d, ", decoded->dst.params.regs.pri);
2544					ret += label_fun(dst+ret, decoded->address + 2 + decoded->src.params.immed, data);
2545				} else {
2546					dst[ret++] = ' ';
2547					ret += label_fun(dst+ret, decoded->address + 2 + decoded->src.params.immed, data);
2548				}
2549			} else {
2550				if (decoded->op == M68K_DBCC) {
2551					ret += sprintf(dst+ret, " d%d, #%d <%X>", decoded->dst.params.regs.pri, decoded->src.params.immed, decoded->address + 2 + decoded->src.params.immed);
2552				} else {
2553					ret += sprintf(dst+ret, " #%d <%X>", decoded->src.params.immed, decoded->address + 2 + decoded->src.params.immed);
2554				}
2555			}
2556			return ret;
2557		}
2558		break;
2559	case M68K_BSR:
2560		if (labels) {
2561			ret = sprintf(dst, "bsr%s ", decoded->variant == VAR_BYTE ? ".s" : "");
2562			ret += label_fun(dst+ret, decoded->address + 2 + decoded->src.params.immed, data);
2563		} else {
2564			ret = sprintf(dst, "bsr%s #%d <%X>", decoded->variant == VAR_BYTE ? ".s" : "", decoded->src.params.immed, decoded->address + 2 + decoded->src.params.immed);
2565		}
2566		return ret;
2567	case M68K_MOVE_FROM_SR:
2568		ret = sprintf(dst, "%s", mnemonics[decoded->op]);
2569		ret += sprintf(dst + ret, " SR");
2570		ret += m68k_disasm_op(&(decoded->dst), dst + ret, 1, labels, decoded->address, label_fun, data);
2571		return ret;
2572	case M68K_ANDI_SR:
2573	case M68K_EORI_SR:
2574	case M68K_MOVE_SR:
2575	case M68K_ORI_SR:
2576		special_op = "SR";
2577	case M68K_ANDI_CCR:
2578	case M68K_EORI_CCR:
2579	case M68K_MOVE_CCR:
2580	case M68K_ORI_CCR:
2581		ret = sprintf(dst, "%s", mnemonics[decoded->op]);
2582		ret += m68k_disasm_op(&(decoded->src), dst + ret, 0, labels, decoded->address, label_fun, data);
2583		ret += sprintf(dst + ret, ", %s", special_op);
2584		return ret;
2585	case M68K_MOVE_USP:
2586		ret = sprintf(dst, "%s", mnemonics[decoded->op]);
2587		if (decoded->src.addr_mode != MODE_UNUSED) {
2588			ret += m68k_disasm_op(&(decoded->src), dst + ret, 0, labels, decoded->address, label_fun, data);
2589			ret += sprintf(dst + ret, ", USP");
2590		} else {
2591			ret += sprintf(dst + ret, "USP, ");
2592			ret += m68k_disasm_op(&(decoded->dst), dst + ret, 0, labels, decoded->address, label_fun, data);
2593		}
2594		return ret;
2595	case M68K_INVALID:
2596		ret = sprintf(dst, "dc.w $%X", decoded->src.params.immed);
2597		return ret;
2598#ifdef M68010
2599	case M68K_MOVEC:
2600		ret = sprintf(dst, "%s ", mnemonics[decoded->op]);
2601		if (decoded->src.addr_mode == MODE_UNUSED) {
2602			ret += sprintf(dst + ret, "%s, ", cr_mnem[decoded->src.params.immed]);
2603			ret += m68k_disasm_op(&(decoded->dst), dst + ret, 0, labels, decoded->address, label_fun, data);
2604		} else {
2605			ret += m68k_disasm_op(&(decoded->src), dst + ret, 0, labels, decoded->address, label_fun, data);
2606			ret += sprintf(dst + ret, ", %s", cr_mnem[decoded->dst.params.immed]);
2607		}
2608		return ret;
2609#endif
2610	default:
2611		size = decoded->extra.size;
2612		uint8_t is_quick = decoded->variant == VAR_QUICK && decoded->op != M68K_ASL && decoded->op != M68K_ASR 
2613			&& decoded->op != M68K_LSL && decoded->op != M68K_LSR && decoded->op != M68K_ROXR && decoded->op != M68K_ROXL
2614			&& decoded->op != M68K_ROR && decoded->op != M68K_ROL;
2615		ret = sprintf(dst, "%s%s%s",
2616				mnemonics[decoded->op],
2617				is_quick ? "q" : (decoded->variant == VAR_IMMEDIATE ? "i" : ""),
2618				size == OPSIZE_BYTE ? ".b" : (size == OPSIZE_WORD ? ".w" : (size == OPSIZE_LONG ? ".l" : "")));
2619	}
2620	if (decoded->op == M68K_MOVEM) {
2621		op1len = m68k_disasm_movem_op(&(decoded->src), &(decoded->dst), dst + ret, 0, labels, decoded->address, label_fun, data);
2622		ret += op1len;
2623		ret += m68k_disasm_movem_op(&(decoded->dst), &(decoded->src), dst + ret, op1len, labels, decoded->address, label_fun, data);
2624	} else {
2625		op1len = m68k_disasm_op(&(decoded->src), dst + ret, 0, labels, decoded->address, label_fun, data);
2626		ret += op1len;
2627		ret += m68k_disasm_op(&(decoded->dst), dst + ret, op1len, labels, decoded->address, label_fun, data);
2628	}
2629	return ret;
2630}
2631
2632int m68k_disasm(m68kinst * decoded, char * dst)
2633{
2634	return m68k_disasm_ex(decoded, dst, 0, NULL, NULL);
2635}
2636
2637int m68k_disasm_labels(m68kinst * decoded, char * dst, format_label_fun label_fun, void * data)
2638{
2639	if (!label_fun)
2640	{
2641		label_fun = m68k_default_label_fun;
2642	}
2643	return m68k_disasm_ex(decoded, dst, 1, label_fun, data);
2644}