Archelon Ischyros Archelon Inc.

Programming tools for your new processor

Motorola 68000 Example Machine Description File

The compactor uses the Machine Definition File (MDF) to translate the compiler output into microcode or instruction encodings specifically for your machine. The MDF contains:

For more information about the MDF, see the Technical Overview.

You can reach us by email at info@archelon.com.


Back to Archelon's Home Page.


/* @(#) m68000.mdf 1.3 97/05/27 00:25:04 @(#)
 *
 * m68000.mdf
 *
 * Copyright © 1996-97 Archelon Inc. All Rights Reserved.
 */

.wordsize 16;
.noop "nop";

/*
 * Field definitions
 */

.field
WORD [16] {
	.constant;
}
.location WORD 0;

.mop
msw(a) {
	.expansion "WORD# .bits(16, 31,", WORD, ")";

	WORD = a;
}

.mop
lsw(a) {
	.expansion "WORD# .bits(0, 15,", WORD, ")";

	WORD = a;
}

/*
 * Effective Address
 */
.field
ZREG [3] {
	.mnemonics {
		d0			= 0;
		d1			= 1;
		d2			= 2;
		d3			= 3;
		d4			= 4;
		d5			= 5;
		d6			= 6;
		d7			= 7;

		a0			= 0;
		a1			= 1;
		a2			= 2;
		a3			= 3;
		a4			= 4;
		a5			= 5;
		a6			= 6;
		a7			= 7;
		sp			= 7;

		zreg_word	= 0;
		zreg_long	= 1;
		zreg_disp	= 2;
		zreg_index	= 3;
		zreg_imm	= 4;
		zreg_sr		= 4;
	}
}
.location ZREG 0;

.field
ZMODE [3] {
	.mnemonics {
		/*
		 * put an underbar in front of a couple of mnemonics
		 * in order to avoid conflicts with variable names,
		 * due to mcpack becoming more careful in checking
		 * for name redeclaration. rpg 970525
		 */
		dreg		= 0;
		areg		= 1;
		ind			= 2;
		postinc		= 3;
		predec		= 4;
		disp		= 5;
		index		= 6;
		zreg		= 7;
	}
}
.location ZMODE 0;

.field
S_REG [3] {
	.same_as ZREG;
}
.location S_REG 0;

.field
S_MODE [3] {
	.same_as ZMODE;
}
.location S_MODE 3;

.field
D_MODE [3] {
	.same_as D_MODE;
}
.location D_MODE 6;

.field
D_REG [3] {
	.same_as ZREG;
}
.location D_REG 9;

.field
SIZE [2] {
	.mnemonics {
		byte			= 0;
		word			= 1;
		long			= 2;

		size_filler		= 3;
	}
	.default word;
}
.location SIZE 6;

.field
COND [4] {
	.mnemonics {
		true			= 0;
		always			= 1;
		false			= 1;
		subroutine		= 2;
		high			= 2;
		low_same		= 3;
		carry_clear		= 4;
		carry_set		= 5;
		not_equal		= 6;
		equal			= 7;
		overflow_clear	= 8;
		overflow_set	= 9;
		plus			= 10;
		minus			= 11;
		greater_equal	= 12;
		less_than		= 13;
		greater_than	= 14;
		less_equal		= 15;

	}
}
.location COND 8;

/*
 * Address Register Indirect with Index 
 */
.field
INDEX [1, 3, 1] {
	.mnemonics {
		Xd0			= 0, 0, 0;
		Xd1			= 0, 1, 0;
		Xd2			= 0, 2, 0;
		Xd3			= 0, 3, 0;
		Xd4			= 0, 4, 0;
		Xd5			= 0, 5, 0;
		Xd6			= 0, 6, 0;
		Xd7			= 0, 7, 0;

		Xd0.w		= 0, 0, 0;
		Xd1.w		= 0, 1, 0;
		Xd2.w		= 0, 2, 0;
		Xd3.w		= 0, 3, 0;
		Xd4.w		= 0, 4, 0;
		Xd5.w		= 0, 5, 0;
		Xd6.w		= 0, 6, 0;
		Xd7.w		= 0, 7, 0;

		Xd0.l		= 0, 0, 1;
		Xd1.l		= 0, 1, 1;
		Xd2.l		= 0, 2, 1;
		Xd3.l		= 0, 3, 1;
		Xd4.l		= 0, 4, 1;
		Xd5.l		= 0, 5, 1;
		Xd6.l		= 0, 6, 1;
		Xd7.l		= 0, 7, 1;

		Xa0			= 1, 0, 0;
		Xa1			= 1, 1, 0;
		Xa2			= 1, 2, 0;
		Xa3			= 1, 3, 0;
		Xa4			= 1, 4, 0;
		Xa5			= 1, 5, 0;
		Xa6			= 1, 6, 0;
		Xa7			= 1, 7, 0;
		Xsp			= 1, 7, 0;

		Xa0.w		= 1, 0, 0;
		Xa1.w		= 1, 1, 0;
		Xa2.w		= 1, 2, 0;
		Xa3.w		= 1, 3, 0;
		Xa4.w		= 1, 4, 0;
		Xa5.w		= 1, 5, 0;
		Xa6.w		= 1, 6, 0;
		Xa7.w		= 1, 7, 0;
		Xsp.w		= 1, 7, 0;

		Xa0.l		= 1, 0, 1;
		Xa1.l		= 1, 1, 1;
		Xa2.l		= 1, 2, 1;
		Xa3.l		= 1, 3, 1;
		Xa4.l		= 1, 4, 1;
		Xa5.l		= 1, 5, 1;
		Xa6.l		= 1, 6, 1;
		Xa7.l		= 1, 7, 1;
		Xsp.l		= 1, 7, 1;
	}
}
.location INDEX 15, 12, 11;

.field
DISP [.signed 8] {
	.constant;
}
.location DISP 0;

.mop
index(ea) {
	.numvar start, finish;
	.expansion INDEX, "DISP#", DISP;

	start = .search(ea, ", *");
	finish = .search(ea, "[)]") - 2;

	INDEX = .concat("X", .substr(ea, start, finish));
	DISP = .substr(ea, 0, .search(ea, "[(]") - 2);
}

.func
extension(ea, size, mode, reg) {
	.select (mode) {
	.case "index":
		index(ea);
		.break;

	.case "disp":
		lsw(.substr(ea, 0, .search(ea, "[(]") - 2));
		.break;

	.case "zreg":
		.select (reg) {
		.case zreg_index:
			index(ea);
			.break;

		.case zreg_disp:
			lsw(.substr(ea, 0, .search(ea, "[(]") - 2));
			.break;

		.case zreg_long:
			msw(ea);
		.case zreg_word:
			lsw(ea);
			.break;

		.case zreg_imm:
			.if (size :: "long")
				msw(.substr(ea, 1));
			lsw(.substr(ea, 1));
			.break;
		}
	}
}

/*
 * OPCODE12 D_REG D_MODE S_MODE S_REG
 * OPCODE12 COND DISP
 */
.field
OPCODE12 [4] {
	.mnemonics {
		bit			= 0;
		movep		= 0;
		move_b		= 1;
		move_l		= 2;
		move_w		= 3;
		chk			= 4;
		lea			= 4;
		branch		= 6;
		set			= 5;
		dec_branch	= 5;
	}
}
.location OPCODE12 12;

/*
 * MOP functions, describing low-level encodings.
 */

.mop
opcode12(code, d_reg, d_mode, s_mode, s_reg) {
	.expansion OPCODE12, D_REG, D_MODE, S_MODE, S_REG;

	OPCODE12 = code;
	D_REG = d_reg;
	D_MODE = d_mode;
	S_MODE = s_mode;
	S_REG = s_reg;
}

.mop
branch(cond, brdisp) {
	.expansion OPCODE12, COND, "DISP#", DISP;

	OPCODE12 = branch;
	COND = cond;
	DISP = brdisp;
}

.mop
set_dbra(code, cond, mode, reg) {
	.expansion OPCODE12, COND, SIZE, S_MODE, S_REG;

	OPCODE12 = code;
	COND = cond;
	SIZE = size_filler;
	S_MODE = mode;
	S_REG = reg;
}

/*
 * OPCODE12A D_REG S_MODE S_REG
 */
.field
OPCODE12A [4, 3] {
	.mnemonics {
		btst_imm			= 0, 0;
		bchg_imm			= 0, 1;
		bclr_imm			= 0, 2;
		bset_imm			= 0, 3;

		btst_reg			= 0, 4;
		bchg_reg			= 0, 5;
		bclr_reg			= 0, 6;
		bset_reg			= 0, 7;

		movep_w_mem_reg		= 0, 4;
		movep_l_mem_reg		= 0, 5;
		movep_w_reg_mem		= 0, 6;
		movep_l_reg_mem		= 0, 7;

		divu				= 8, 3;
		divs				= 8, 7;

		suba_word			= 9, 3;
		suba_long			= 9, 7;

		cmpa_word			= 11, 3;
		cmpa_long			= 11, 7;

		mulu				= 12, 3;
		muls				= 12, 7;

		adda_word			= 13, 3;
		adda_long			= 13, 7;
	}
}
.location OPCODE12A 12, 6;

.mop
opcode12a(code, d_reg, s_mode, s_reg) {
	.expansion OPCODE12A, D_REG, S_MODE, S_REG;

	OPCODE12A = code;
	D_REG = d_reg;
	S_MODE = s_mode;
	S_REG = s_reg;
}

/*
 * OPCODE12B D_REG SIZE S_MODE S_REG
 */
.field
OPCODE12B [4, 1] {
	.mnemonics {
		addq			= 5, 0;
		subq			= 5, 1;
		moveq			= 7, 1;
		or_reg_ea		= 8, 0;
		or_ea_reg		= 8, 1;
		sub_reg_ea		= 9, 0;
		sub_ea_reg		= 9, 1;
		cmp_ea_reg		= 11, 0;
		eor_reg_ea		= 11, 1;
		and_reg_ea		= 12, 0;
		and_ea_reg		= 12, 1;
		add_reg_ea		= 13, 0;
		add_ea_reg		= 13, 1;
	}
}
.location OPCODE12B 12, 8;

.mop
opcode12b(code, data, size, s_mode, s_reg) {
	.expansion OPCODE12B, D_REG, SIZE, S_MODE, S_REG;

	OPCODE12B = code;
	D_REG = data;
	SIZE = size;
	S_MODE = s_mode;
	S_REG = s_reg;
}

.mop
op_moveq(data, reg) {
	.expansion OPCODE12B, D_REG, "DISP#", DISP;

	OPCODE12B = moveq;
	D_REG = reg;
	DISP = data;
}

/*
 * OPCODE12C D_REG SIZE S_REG
 */
.field
OPCODE12C [4, 1, 3] {
	.mnemonics {
		subx_reg_reg	= 9, 1, 0;
		subx_mem_mem	= 9, 1, 1;

		cmpm			= 11, 1, 1;
		
		addx_reg_reg	= 13, 1, 0;
		addx_mem_mem	= 13, 1, 1;

		asr_imm			= 14, 0, 0;
		lsr_imm			= 14, 0, 1;
		roxr_imm		= 14, 0, 2;
		ror_imm			= 14, 0, 3;

		asr_reg			= 14, 0, 4;
		lsr_reg			= 14, 0, 5;
		roxr_reg		= 14, 0, 6;
		ror_reg			= 14, 0, 7;

		asl_imm			= 14, 1, 0;
		lsl_imm			= 14, 1, 1;
		roxl_imm		= 14, 1, 2;
		rol_imm			= 14, 1, 3;

		asl_reg			= 14, 1, 4;
		lsl_reg			= 14, 1, 5;
		roxl_reg		= 14, 1, 6;
		rol_reg			= 14, 1, 7;
	}
}
.location OPCODE12C 12, 8, 3;

.mop
opcode12c(code, d_reg, size, s_reg) {
	.expansion OPCODE12C, D_REG, SIZE, S_REG;

	OPCODE12C = code;
	D_REG = d_reg;
	SIZE = size;
	S_REG = s_reg;
}

/*
 * OPCODE12D D_REG S_REG
 */
.field
OPCODE12D [4, 6] {
	.mnemonics {
		sbcd_reg_reg	= 8, 040;
		sbcd_mem_mem	= 8, 041;

		abcd_reg_reg	= 12, 040;
		abcd_mem_mem	= 12, 041;

		ext_dreg_dreg	= 12, 050;
		ext_areg_areg	= 12, 051;
		ext_dreg_areg	= 12, 061;
	}
}
.location OPCODE12D 12, 3;

.mop
opcode12d(code, d_reg, s_reg) {
	.expansion OPCODE12D, D_REG, S_REG;

	OPCODE12D = code;
	D_REG = d_reg;
	S_REG = s_reg;
}

/*
 * OPCODE8 SIZE S_EA;
 */
.field
OPCODE8 [8] {
	.mnemonics {
		ori			= 0x00;
		andi		= 0x02;
		subi		= 0x04;
		addi		= 0x05;
		eori		= 0x0a;
		cmpi		= 0x0c;
		negx		= 0x40;
		clr			= 0x42;
		neg			= 0x44;
		not			= 0x46;
		tst			= 0x4a;
	}
}
.location OPCODE8 8;

.mop
opcode8(code, size, mode, reg) {
	.expansion OPCODE8, SIZE, S_MODE, S_REG;

	OPCODE8 = code;
	SIZE = size;
	S_MODE = mode;
	S_REG = reg;
}

.strvar sm_mode, sm_reg;

.func 
set_mode_reg(ea) {
	.numvar num;

	.if (.search(ea, "[(](a[0-7]|sp)[)][+]") == 5) {
		sm_reg = .substr(ea, 1, 2);
		sm_mode = "postinc";
		.done;
	}

	.if (.search(ea, "-[(](a[0-7]|sp)[)]") == 5) {
		sm_reg = .substr(ea, 2, 3);
		sm_mode = "predec";
		.done;
	}

	.if (.search(ea, "[(](a[0-7]|sp)[)]") == 4) {
		sm_reg = .substr(ea, 1, 2);
		sm_mode = "ind";
		.done;
	}

	.if (.search(ea, "(a[0-7]|sp)") == 2) {
		sm_reg = ea;
		sm_mode = "areg";
		.done;
	}

	.if (.search(ea, "d[0-7]") == 2) {
		sm_reg = ea;
		sm_mode = "dreg";
		.done;
	}

	.if (2 < .search(ea, "[(](a[0-7]|sp)[)]")) {
		num = .search(ea, "a[0-7]|sp");
		sm_reg = .substr(ea, num-2, num-1);
		sm_mode = "disp";
		.done;
	}

	.if (2 < .search(ea, "[(](a[0-7]|sp), *([ad][0-7]|sp)([.][wl])?[)]")) {
		num = .search(ea, "a[0-7]|sp");
		sm_reg = .substr(ea, num-2, num-1);
		sm_mode = "index";
		.done;
	}

	sm_mode = "zreg";

	.if (2 < .search(ea, "[(]pc[)]$")) {
		sm_reg = "zreg_disp";
		.done;
	}

	.if (2 < .search(ea, "[(]pc, *([ad][0-7]|sp)([.][wl])?[)]")) {
		sm_reg = "zreg_index";
		.done;
	}

	.if (.substr(ea, 0, 0) :: "#") {
		sm_reg = "zreg_imm";
		.done;
	}

	.if (ea :: "ccr" || ea :: "sr") {
		sm_reg = "zreg_sr";
		.done;
	}

	.if (.numeric(ea)) {
		num = .number(ea);
		.if (-32768 <= num && num <= 32767) {
			sm_reg = "zreg_word";
			.done;
		}
	}

	sm_reg = "zreg_long";
}

.func
chk_dst(mode, reg) {
	.if (mode :: "areg")
		.done 0;

	.select (reg) {
	.case "zreg_disp":
	.case "zreg_index":
	.case "zreg_imm":
		.done 0;
	}

	.done 1;
}

.func
chk_ea(mode, reg) {
	.select (mode) {
	.case zreg:
		.if (reg :: "zreg_imm" || reg :: "zreg_sr")
	.case dreg:
	.case areg:
	.case postinc:
	.case predec:
			.done 0;
	}

	.done 1;
}

.func
chk_movem_reg_mem(mode, reg) {
	.select (mode) {
	.case zreg:
		.if (reg :: "zreg_word" || reg :: "zreg_long")
			.done 1;
	.case dreg:
	.case areg:
	.case postinc:
		.done 0;
	}

	.done 1;
}

.func
chk_movem_mem_reg(mode, reg) {
	.done chk_ea(mode, reg) || mode :: "postinc";
}

/*
 * OPCODE4 VECTOR
 */
.field
OPCODE4 [12] {
	.mnemonics {
		trap		= 0x4e4;
	}
}
.location OPCODE4 4;

.field
VECTOR [4] {
	.constant;
}
.location VECTOR 0;

.mop
opcode4(code, vec) {
	.expansion OPCODE4, "VECTOR#", VECTOR;

	OPCODE4 = code;
	VECTOR = vec;
}

.vop
trap(num) {
	.numvar vec;

	.if (.numeric(num))
		vec = num;
	.elif (.substr(num, 0, 0) :: "#" && .numeric(.substr(num, 1)))
		vec = .substr(num, 1);
	.else
		.error("Invalid trap operand :", num);

	.if (vec < 0 || 15 < vec) 
		.error("Value out of range (0-15) :", num);

	opcode4(trap, vec);
}

/*
 * OPCODE0
 */
.field
OPCODE0 [16] {
	.mnemonics {
		illegal		= 0x4afc;
		reset		= 0x4e70;
		nop			= 0x4e71;
		stop		= 0x4e72;
		rte			= 0x4e73;
		rtd			= 0x4e74;
		rts			= 0x4e75;
		trapv		= 0x4e76;
		rtr			= 0x4e77;
	}
	.default nop;
}

.mop
opcode0(code) {
	.expansion OPCODE0;

	OPCODE0 = code;
}

.vop
illegal() {
	opcode0(illegal);
}

.vop
reset() {
	opcode0(reset);
}

.vop
nop() {
	opcode0(nop);
}

.vop
stop() {
	opcode0(stop);
}

.vop
rte() {
	opcode0(rte);
}

.vop
rtd() {
	opcode0(rtd);
}

.vop
rtr() {
	opcode0(rtr);
}

.vop
rts() {
	opcode0(rts);
}

.vop
trapv() {
	opcode0(trapv);
}

.func
do_opcode8(code, size, src, dst) {
	.strvar sz;

	set_mode_reg(dst);

	.if (! chk_dst(sm_mode, sm_reg))
		.error("Invalid destination operand :", dst);

	.select (dst) {
	.case "ccr":
		sz = byte;
		.break;
	.case "sr":
		sz = word;
		.break;
	.default:
		sz = size;
	}

	.bundle {
		opcode8(code, sz, sm_mode, sm_reg);

		.if (.substr(src, 0, 0) :: "#") 
			extension(src, sz, zreg, zreg_imm);

		extension(dst, sz, sm_mode, sm_reg);
	}
}

/*
 * VOP functions, describing the high-level instruction set.
 */

.vop
ori(imm, dst) {
	do_opcode8(ori, word, imm, dst);
}
.vop
ori.b(imm, dst) {
	do_opcode8(ori, byte, imm, dst);
}
.vop
ori.w(imm, dst) {
	do_opcode8(ori, word, imm, dst);
}
.vop
ori.l(imm, dst) {
	do_opcode8(ori, long, imm, dst);
}

.vop
andi(imm, dst) {
	do_opcode8(andi, word, imm, dst);
}
.vop
andi.b(imm, dst) {
	do_opcode8(andi, byte, imm, dst);
}
.vop
andi.w(imm, dst) {
	do_opcode8(andi, word, imm, dst);
}
.vop
andi.l(imm, dst) {
	do_opcode8(andi, long, imm, dst);
}

.vop
eori(imm, dst) {
	do_opcode8(eori, word, imm, dst);
}
.vop
eori.b(imm, dst) {
	do_opcode8(eori, byte, imm, dst);
}
.vop
eori.w(imm, dst) {
	do_opcode8(eori, word, imm, dst);
}
.vop
eori.l(imm, dst) {
	do_opcode8(eori, long, imm, dst);
}

.vop
subi(imm, dst) {
	do_opcode8(subi, word, imm, dst);
}
.vop
subi.b(imm, dst) {
	do_opcode8(subi, byte, imm, dst);
}
.vop
subi.w(imm, dst) {
	do_opcode8(subi, word, imm, dst);
}
.vop
subi.l(imm, dst) {
	do_opcode8(subi, long, imm, dst);
}

.vop
addi(imm, dst) {
	do_opcode8(addi, word, imm, dst);
}
.vop
addi.b(imm, dst) {
	do_opcode8(addi, byte, imm, dst);
}
.vop
addi.w(imm, dst) {
	do_opcode8(addi, word, imm, dst);
}
.vop
addi.l(imm, dst) {
	do_opcode8(addi, long, imm, dst);
}

.func
do_bit(code, src, dst) {
	set_mode_reg(dst);

	.if (.search(src, "d[0-7]") == 2) 
		.bundle {
			opcode12a(.concat(code, "_reg"), src, sm_mode, sm_reg);
			extension(dst, "", sm_mode, sm_reg);
		}
	.elif (.substr(src, 0, 0) :: "#") 
		.bundle {
			opcode12a(.concat(code, "_imm"), d4, sm_mode, sm_reg);
			extension(src, word, zreg, zreg_imm);
		}
	.else
		.error("Invalid source operand :", src);
}

.vop
btst(src, dst) {
	do_bit("btst", src, dst);
}
.vop
bchg(src, dst) {
	do_bit("bchg", src, dst);
}
.vop
bclr(src, dst) {
	do_bit("bclr", src, dst);
}
.vop
bset(src, dst) {
	do_bit("bset", src, dst);
}

.vop
cmpi(imm, dst) {
	do_opcode8(cmpi, word, imm, dst);
}
.vop
cmpi.b(imm, dst) {
	do_opcode8(cmpi, byte, imm, dst);
}
.vop
cmpi.w(imm, dst) {
	do_opcode8(cmpi, word, imm, dst);
}
.vop
cmpi.l(imm, dst) {
	do_opcode8(cmpi, long, imm, dst);
}

.vop
negx(dst) {
	do_opcode8(negx, word, "", dst);
}
.vop
negx.b(dst) {
	do_opcode8(negx, byte, "", dst);
}
.vop
negx.w(dst) {
	do_opcode8(negx, word, "", dst);
}
.vop
negx.l(dst) {
	do_opcode8(negx, long, "", dst);
}

.vop
clr(dst) {
	do_opcode8(clr, word, "", dst);
}
.vop
clr.b(dst) {
	do_opcode8(clr, byte, "", dst);
}
.vop
clr.w(dst) {
	do_opcode8(clr, word, "", dst);
}
.vop
clr.l(dst) {
	do_opcode8(clr, long, "", dst);
}

.vop
neg(dst) {
	do_opcode8(neg, word, "", dst);
}
.vop
neg.b(dst) {
	do_opcode8(neg, byte, "", dst);
}
.vop
neg.w(dst) {
	do_opcode8(neg, word, "", dst);
}
.vop
neg.l(dst) {
	do_opcode8(neg, long, "", dst);
}

.vop
not(dst) {
	do_opcode8(not, word, "", dst);
}
.vop
not.b(dst) {
	do_opcode8(not, byte, "", dst);
}
.vop
not.w(dst) {
	do_opcode8(not, word, "", dst);
}
.vop
not.l(dst) {
	do_opcode8(not, long, "", dst);
}

.vop
tst(dst) {
	do_opcode8(tst, word, "", dst);
}
.vop
tst.b(dst) {
	do_opcode8(tst, byte, "", dst);
}
.vop
tst.w(dst) {
	do_opcode8(tst, word, "", dst);
}
.vop
tst.l(dst) {
	do_opcode8(tst, long, "", dst);
}

/*
 * OPCODE6 S_MODE S_REG
 */
.field
OPCODE6 [10] {
	.mnemonics {
		move_from_sr	= 00403;
		move_from_ccr	= 00413;
		move_to_ccr		= 00423;
		move_to_sr		= 00433;

		nbcd			= 00440;
		pea				= 00441;
		movem_w_reg_mem	= 00442;
		movem_l_reg_mem	= 00443;
		tas				= 00453;

		movem_w_mem_reg	= 00462;
		movem_l_mem_reg	= 00463;
		jsr				= 00472;
		jmp				= 00473;

		asr_mem			= 01603;
		asl_mem			= 01607;
		lsr_mem			= 01613;
		lsl_mem			= 01617;
		roxr_mem		= 01623;
		roxl_mem		= 01627;
		ror_mem			= 01633;
		rol_mem			= 01637;
	}
}
.location OPCODE6 6;

.mop
opcode6(code, mode, reg) {
	.expansion OPCODE6, S_MODE, S_REG;

	OPCODE6 = code;
	S_MODE = mode;
	S_REG = reg;
}

.func
do_opcode6(code, test, ea) {
	set_mode_reg(ea);

	.select (test) {
	.case 0:
		.if (! chk_dst(sm_mode, sm_reg))
			.error("Invalid destination operand :", ea);
		.break;
	.case 1:
		.if (sm_mode :: "areg")
			.error("Invalid source operand :", ea);
		.break;
	.case 2:
		.if (! chk_ea(sm_mode, sm_reg))
			.error("Invalid operand :", ea);
		.break;
	.case 3:
		.if (! chk_dst(sm_mode, sm_reg) || sm_mode :: "dreg")
			.error("Invalid destination operand :", ea);
		.break;
	}

	.bundle {
		opcode6(code, sm_mode, sm_reg);
		extension(ea, word, sm_mode, sm_reg);
	}
}
			
.vop
nbcd(dst) {
	do_opcode6(nbcd, 0, dst);
}
			
.vop
pea(ea) {
	do_opcode6(pea, 2, ea);
}

.vop
tas(dst) {
	do_opcode6(tas, 0, dst);
}

.vop
jsr(ea) {
	do_opcode6(jsr, 2, ea);
}

.vop
jmp(ea) {
	do_opcode6(jmp, 2, ea);
}

/*
 * OPCODE3 S_REG
 */
.field
OPCODE3 [13] {
	.mnemonics {
		swap			= 04410;
		ext_w			= 04420;
		ext_l			= 04430;
		link			= 04712;
		unlk			= 04713;
		move_to_usp		= 04714;
		move_from_usp	= 04715;
	}
}
.location OPCODE3 3;

.mop
opcode3(code, reg) {
	.expansion OPCODE3, S_REG;

	OPCODE3 = code;
	S_REG = reg;
}

.func
do_opcode3(code, op_areg, op_reg) {
	set_mode_reg(op_reg);

	.if ((op_areg && sm_mode !: "areg") || (!op_areg && sm_mode !: "dreg"))
		.error("Invalid operand :", op_reg);

	opcode3(code, op_reg);
}

.vop
swap(op_dreg) {
	do_opcode3(swap, 0, op_dreg);
}

.vop
ext(op_dreg) {
	do_opcode3(ext_w, 0, op_dreg);
}
.vop
ext.w(op_dreg) {
	do_opcode3(ext_w, 0, op_dreg);
}
.vop
ext.l(op_dreg) {
	do_opcode3(ext_l, 0, op_dreg);
}

.vop
unlk(op_areg) {
	do_opcode3(unlk, 1, op_areg);
}
	
.vop
link(op_areg, op_disp) {
	set_mode_reg(op_areg);

	.if (sm_mode !: "areg")
		.error("Invalid operand :", op_areg);

	.bundle {
		opcode3(link, sm_reg);
		extension(op_disp, word, zreg, zreg_imm);
	}
}
	
.func
do_move(code, size, src, dst) {
	.strvar s_reg, s_mode;

	set_mode_reg(src);
	s_mode = sm_mode;
	s_reg = sm_reg;
	set_mode_reg(dst);

	.if (! chk_dst(sm_mode, sm_reg) && sm_mode !: "areg")
		.error("Invalid destination operand :", dst);

	.bundle {
		opcode12(code, sm_reg, sm_mode, s_mode, s_reg);
		extension(src, size, s_mode, s_reg);
		extension(dst, "", sm_mode, sm_reg);
	}
}

.vop
move(src, dst) {
	.select (src) {
	.case "ccr":
		do_opcode6(move_from_ccr, 0, dst);
		.done;
	.case "sr":
		do_opcode6(move_from_sr, 0, dst);
		.done;
	.case "usp":
		do_opcode3(move_from_usp, 1, dst);
		.done;
	}

	.select (dst) {
	.case "ccr":
		do_opcode6(move_to_ccr, 1, src);
		.done;
	.case "sr":
		do_opcode6(move_to_sr, 1, src);
		.done;
	.case "usp":
		do_opcode3(move_to_usp, 1, src);
		.done;
	}

	do_move(move_w, word, src, dst);
}
.vop
move.b(src, dst) {
	do_move(move_b, byte, src, dst);
}
.vop
move.w(src, dst) {
	do_move(move_w, word, src, dst);
}
.vop
move.l(src, dst) {
	do_move(move_l, long, src, dst);
}
.vop
movea(src, dst) {
	do_move(move_w, word, src, dst);
}
.vop
movea.w(src, dst) {
	do_move(move_w, word, src, dst);
}
.vop
movea.l(src, dst) {
	do_move(move_l, long, src, dst);
}

.vop
chk(src, dst) {
	.strvar d_reg;

	set_mode_reg(dst);
	d_reg = sm_reg;

	.if (sm_mode !: "dreg")
		.error("Invalid destination operand :", dst);

	set_mode_reg(src);
	
	.if (sm_mode :: "areg")
		.error("Invalid source operand :", src);

	.bundle {
		opcode12(chk, d_reg, index, sm_mode, sm_reg);
		extension(src, word, sm_mode, sm_reg);
	}
}

.vop
lea(src, dst) {
	.strvar d_reg;

	set_mode_reg(dst);
	d_reg = sm_reg;

	.if (sm_mode !: "areg")
		.error("Invalid destination operand :", dst);

	set_mode_reg(src);
	
	.if (! chk_ea(sm_mode, sm_reg))
		.error("Invalid source operand :", src);

	.bundle {
		opcode12(chk, d_reg, index, sm_mode, sm_reg);
		extension(src, word, sm_mode, sm_reg);
	}
}

.func
do_movep(code, src, dst) {
	.strvar d_reg, d_mode;

	set_mode_reg(dst);
	d_mode = sm_mode;
	d_reg = sm_reg;
	set_mode_reg(src);

	.if (d_mode !: sm_mode) {
		.select (sm_mode) {
		.case dreg:
			.bundle {
				opcode12a(.concat(code, "_reg_mem"), sm_reg, areg, d_reg);
				extension(dst, "", disp, d_reg);
			}
			.done;
		.case disp:
			.bundle {
				opcode12a(.concat(code, "_mem_reg"), d_reg, areg, sm_reg);
				extension(src, "", disp, sm_reg);
			}
			.done;
		}
	}

	.error("Invalid combination of operands :", src, ",", dst);
}

.vop
movep(src, dst) {
	do_movep("movep_w", src, dst);
}
.vop
movep.w(src, dst) {
	do_movep("movep_w", src, dst);
}
.vop
movep.l(src, dst) {
	do_movep("movep_l", src, dst);
}

.func
reglist(regs, reverse) {
	.strvar str;
	.numvar count, shift, mask, len, scan;

	mask = 0;
	len = .search(regs, ".*");

	.for (scan = 0; scan < len; ) {
		str = .substr(regs, scan, scan+1);
		shift = .value(str);
		scan = scan + 2;
		count = 1;

		.if (.search(regs, "-[0-7]", scan) == scan+2) {
			count =  .number(.substr(regs, scan+1, scan+1)) - shift + 1;
			scan = scan + 2;
		}

		.if (.substr(regs, scan, scan) :: "/")
			scan = scan + 1;

		.if (.substr(str, 0, 0) :: "a")
			shift = shift + 8;

		.for ( ; 0 < count; count = count - 1) {
			mask = mask | (1 << shift);
			shift = shift + 1;
		}
	}

	.if (reverse) {
		scan = 0;
		.for (count = 0; count < 16; count = count + 1) {
			scan = scan << 1;
			.if (mask & 1)
				scan = scan | 1;
			mask = mask >> 1;
		}
		mask = scan;
	}

	.done .string(mask);
}

.func
do_movem(code, src, dst) {
	.strvar s_reg, s_mode, list;

	set_mode_reg(src);
	s_mode = sm_mode;
	s_reg = sm_reg;
	set_mode_reg(dst);


	.if (chk_movem_reg_mem(sm_mode, sm_reg)
	&& (s_mode :: "dreg" || s_mode :: "areg" || s_reg :: "zreg_imm")) {
		.if (s_reg :: "zreg_imm")
			list = .substr(src, 1);
		.else
			list = reglist(src, sm_mode :: "predec");

		.bundle {
			opcode6(.concat(code, "_reg_mem"), sm_mode, sm_reg);
			lsw(list);
			extension(dst, "", sm_mode, sm_reg);
		}
		.done;
	}

	.if (chk_movem_mem_reg(s_mode, s_reg)
	&& (sm_mode :: "dreg" || sm_mode :: "areg" || sm_reg :: "zreg_imm")) {
		.if (sm_reg :: "zreg_imm")
			list = .substr(dst, 1);
		.else
			list = reglist(dst, 0);

		.bundle {
			opcode6(.concat(code, "_mem_reg"), s_mode, s_reg);
			lsw(list);
			extension(src, "", s_mode, s_reg);
		}
		.done;
	}

	.error("Invalid combination of operands :", src, ",", dst);
}

.vop
movem(src, dst) {
	do_movem("movem_w", src, dst);
}
.vop
movem.w(src, dst) {
	do_movem("movem_w", src, dst);
}
.vop
movem.l(src, dst) {
	do_movem("movem_l", src, dst);
}

.func
do_branch(cond, label) {
	.numvar dx;

	.if (.numeric(label)) {
		/* Explicit displacement. */
		dx = .number(label);

		.if (-128 <= dx && dx <= 127) 
			branch(cond, dx);
		.else 
			.bundle {
				branch(cond, 0);
				lsw(dx);
			}
	} .else {
		/* Distance between label and program counter.
		 *
		 * The displacement is relative the start of the 
		 * branch instruction plus two.
		 */
		.output(".ifa (", label, "- . - 2), -128, 127");
		
		branch(cond, .concat("(", .concat(label, " - . - 2)")));
		
		.output(".else");
			
		.bundle {
			branch(cond, 0);
			lsw(.concat(label, " - ."));
		}

		.output(".endif");
	}
}

.vop
bra(label) {
	do_branch(always, label);
}
.vop
bsr(label) {
	do_branch(subroutine, label);
}
.vop
bhi(label) {
	do_branch(high, label);
}
.vop
bls(label) {
	do_branch(low_same, label);
}
.vop
bcc(label) {
	do_branch(carry_clear, label);
}
.vop
bhs(label) {
	do_branch(carry_clear, label);
}
.vop
bcs(label) {
	do_branch(carry_set, label);
}
.vop
blo(label) {
	do_branch(carry_set, label);
}
.vop
bne(label) {
	do_branch(not_equal, label);
}
.vop
beq(label) {
	do_branch(equal, label);
}
.vop
bvc(label) {
	do_branch(overflow_clear, label);
}
.vop
bvs(label) {
	do_branch(overflow_set, label);
}
.vop
bpl(label) {
	do_branch(plus, label);
}
.vop
bmi(label) {
	do_branch(minus, label);
}
.vop
bge(label) {
	do_branch(greater_equal, label);
}
.vop
blt(label) {
	do_branch(less_than, label);
}
.vop
bgt(label) {
	do_branch(greater_than, label);
}
.vop
ble(label) {
	do_branch(less_equal, label);
}

.func
do_quick(code, size, src, dst) {
	.numvar data;

	.if (.substr(src, 0, 0) :: "#") {
		data = .number(.substr(src, 1));
		.if (data == 8)
			data = 0;
		.elif (data < 1 || 7 < data)
			.error("Operand", src, "is out of range (1..8).");
	} .else {
		.error("Invalid source operand :", src);
	}

	set_mode_reg(dst);

	.if (! chk_dst(sm_mode, sm_reg) && sm_mode !: "areg")
		.error("Invalid destination operand :", dst);

	.if (sm_mode :: "areg" && size :: "byte")
		.error("Invalid size attribute for address register.");

	.bundle {
		opcode12b(code, data, size, sm_mode, sm_reg);
		extension(dst, "", sm_mode, sm_reg);
	}
}

.vop
addq(src, dst) {
	do_quick(addq, word, src, dst);
}
.vop
addq.b(src, dst) {
	do_quick(addq, byte, src, dst);
}
.vop
addq.w(src, dst) {
	do_quick(addq, word, src, dst);
}
.vop
addq.l(src, dst) {
	do_quick(addq, long, src, dst);
}

.vop
subq(src, dst) {
	do_quick(subq, word, src, dst);
}
.vop
subq.b(src, dst) {
	do_quick(subq, byte, src, dst);
}
.vop
subq.w(src, dst) {
	do_quick(subq, word, src, dst);
}
.vop
subq.l(src, dst) {
	do_quick(subq, long, src, dst);
}

.vop
moveq(src, dst) {
	.numvar data;

	.if (.substr(src, 0, 0) :: "#") {
		data = .number(.substr(src, 1));

		.if (data < -128 || 127 < data)
			.error("Operand", src, "is out of range (-128..127).");
	} .else {
		.error("Invalid source operand :", src);
	}

	set_mode_reg(dst);

	.if (sm_mode !: "dreg")
		.error("Invalid destination operand :", dst);

	op_moveq(data, sm_reg);
}

.func
do_set(cond, dst) {
	set_mode_reg(dst);

	.if (! chk_dst(sm_mode, sm_reg))
		.error("Invalid destination operand :", dst);

	.bundle {
		set_dbra(set, cond, sm_mode, sm_reg);
		extension(dst, "", sm_mode, sm_reg);
	}
}

.vop
st(dst) {
	do_set(true, dst);
}
.vop
sf(dst) {
	do_set(false, dst);
}
.vop
shi(dst) {
	do_set(high, dst);
}
.vop
sls(dst) {
	do_set(low_same, dst);
}
.vop
scc(dst) {
	do_set(carry_clear, dst);
}
.vop
shs(dst) {
	do_set(carry_clear, dst);
}
.vop
scs(dst) {
	do_set(carry_set, dst);
}
.vop
slo(dst) {
	do_set(carry_set, dst);
}
.vop
sne(dst) {
	do_set(not_equal, dst);
}
.vop
seq(dst) {
	do_set(equal, dst);
}
.vop
svc(dst) {
	do_set(overflow_clear, dst);
}
.vop
svs(dst) {
	do_set(overflow_set, dst);
}
.vop
spl(dst) {
	do_set(plus, dst);
}
.vop
smi(dst) {
	do_set(minus, dst);
}
.vop
sge(dst) {
	do_set(greater_equal, dst);
}
.vop
slt(dst) {
	do_set(less_than, dst);
}
.vop
sgt(dst) {
	do_set(greater_than, dst);
}
.vop
sle(dst) {
	do_set(less_equal, dst);
}

.func
do_db(cond, src, label) {
	.numvar dx;

	set_mode_reg(src);

	.if (sm_mode !: "dreg")
		.error("Invalid destination operand :", src);

	.if (.numeric(label)) {
		/* Explicit displacement. */
		dx = .number(label);

		.bundle {
			set_dbra(dec_branch, cond, areg, sm_reg);
			lsw(dx);
		}
	} .else {
		/* Distance between label and program counter.
		 *
		 * The displacement is relative the start of the 
		 * branch instruction plus two.
		 */
		.bundle {
			set_dbra(dec_branch, cond, areg, sm_reg);
			lsw(.concat(label, " - ."));
		}
	}
}

.vop
dbra(src, label) {
	do_db(always, src, label);
}
.vop
dbt(src, label) {
	do_db(true, src, label);
}
.vop
dbf(src, label) {
	do_db(false, src, label);
}
.vop
dbhi(src, label) {
	do_db(high, src, label);
}
.vop
dbls(src, label) {
	do_db(low_same, src, label);
}
.vop
dbcc(src, label) {
	do_db(carry_clear, src, label);
}
.vop
dbhs(src, label) {
	do_db(carry_clear, src, label);
}
.vop
dbcs(src, label) {
	do_db(carry_set, src, label);
}
.vop
dblo(src, label) {
	do_db(carry_set, src, label);
}
.vop
dbne(src, label) {
	do_db(not_equal, src, label);
}
.vop
dbeq(src, label) {
	do_db(equal, src, label);
}
.vop
dbvc(src, label) {
	do_db(overflow_clear, src, label);
}
.vop
dbvs(src, label) {
	do_db(overflow_set, src, label);
}
.vop
dbpl(src, label) {
	do_db(plus, src, label);
}
.vop
dbmi(src, label) {
	do_db(minus, src, label);
}
.vop
dbge(src, label) {
	do_db(greater_equal, src, label);
}
.vop
dblt(src, label) {
	do_db(less_than, src, label);
}
.vop
dbgt(src, label) {
	do_db(greater_than, src, label);
}
.vop
dble(src, label) {
	do_db(less_equal, src, label);
}

.func
do_alu(code, size, src, dst) {
	.numvar data;
	.strvar s_mode, s_reg, num;

	set_mode_reg(src);
	s_mode = sm_mode;
	s_reg = sm_reg;
	set_mode_reg(dst);

	num = .substr(src, 1);

	.if (sm_mode :: "dreg" && code !: "eor") {
		/* Check for faster forms of immediate-to-register instructions. */
		.if (s_reg :: "zreg_imm") {
			.if ((code :: "add" || code :: "sub") && .numeric(num)) {
				data = .number(num);
				.if (1 <= data && data <= 8) {
					do_quick(.concat(code, "q"), size, src, dst);
					.done;
				}
			} 

			do_opcode8(.concat(code, "i"), size, src, dst);
		} .else {
			.bundle {
				opcode12b(.concat(code, "_ea_reg"), sm_reg, size, s_mode, s_reg);
				extension(src, size, s_mode, s_reg);
			}
		}
	} .elif (sm_mode :: "areg") {
		.if (size :: byte)
			.error("Invalid operand size.");

		.select (code) {
		.case "add":
		.case "sub":
			.if (s_reg :: "zreg_imm" && .numeric(num)) {
				data = .number(num);
				.if (1 <= data && data <= 8) {
					do_quick(.concat(code, "q"), size, src, dst);
					.break;
				}
			}
			/* fall-through */
		.case "cmp":
			.bundle {
				opcode12a(
					.concat(code, .concat("a_", size)), sm_reg, s_mode, s_reg);
				extension(src, size, s_mode, s_reg);
			}
			.break;
		.default:
			.error("Invalid destination operand :", dst);
		}
	} .elif (s_mode :: "dreg" && code !: "cmp") {
		.bundle {
			opcode12b(.concat(code, "_reg_ea"), s_reg, size, sm_mode, sm_reg);
			extension(dst, size, sm_mode, sm_reg);
		}
	} .else {
		.error("Invalid combination of operands :", src, ",", dst);
	}
}

.vop
or(src, dst) {
	do_alu("or", word, src, dst);
}
.vop
or.b(src, dst) {
	do_alu("or", byte, src, dst);
}
.vop
or.w(src, dst) {
	do_alu("or", word, src, dst);
}
.vop
or.l(src, dst) {
	do_alu("or", long, src, dst);
}

.vop
sub(src, dst) {
	do_alu("sub", word, src, dst);
}
.vop
sub.b(src, dst) {
	do_alu("sub", byte, src, dst);
}
.vop
sub.w(src, dst) {
	do_alu("sub", word, src, dst);
}
.vop
sub.l(src, dst) {
	do_alu("sub", long, src, dst);
}

.vop
and(src, dst) {
	do_alu("and", word, src, dst);
}
.vop
and.b(src, dst) {
	do_alu("and", byte, src, dst);
}
.vop
and.w(src, dst) {
	do_alu("and", word, src, dst);
}
.vop
and.l(src, dst) {
	do_alu("and", long, src, dst);
}

.vop
add(src, dst) {
	do_alu("add", word, src, dst);
}
.vop
add.b(src, dst) {
	do_alu("add", byte, src, dst);
}
.vop
add.w(src, dst) {
	do_alu("add", word, src, dst);
}
.vop
add.l(src, dst) {
	do_alu("add", long, src, dst);
}

.vop
cmp(src, dst) {
	do_alu("cmp", word, src, dst);
}
.vop
cmp.b(src, dst) {
	do_alu("cmp", byte, src, dst);
}
.vop
cmp.w(src, dst) {
	do_alu("cmp", word, src, dst);
}
.vop
cmp.l(src, dst) {
	do_alu("cmp", long, src, dst);
}

.vop
eor(src, dst) {
	do_alu("eor", word, src, dst);
}
.vop
eor.b(src, dst) {
	do_alu("eor", byte, src, dst);
}
.vop
eor.w(src, dst) {
	do_alu("eor", word, src, dst);
}
.vop
eor.l(src, dst) {
	do_alu("eor", long, src, dst);
}

.vop
adda(src, dst) {
	do_alu("add", word, src, dst);
}
.vop
adda.w(src, dst) {
	do_alu("add", word, src, dst);
}
.vop
adda.l(src, dst) {
	do_alu("add", long, src, dst);
}

.vop
suba(src, dst) {
	do_alu("sub", word, src, dst);
}
.vop
suba.w(src, dst) {
	do_alu("sub", word, src, dst);
}
.vop
suba.l(src, dst) {
	do_alu("sub", long, src, dst);
}

.vop
cmpa(src, dst) {
	do_alu("cmp", word, src, dst);
}
.vop
cmpa.w(src, dst) {
	do_alu("cmp", word, src, dst);
}
.vop
cmpa.l(src, dst) {
	do_alu("cmp", long, src, dst);
}

.func
div_mul(code, src, dst) {
	.if (.search(dst, "d[0-7]") != 2) 
		.error("Invalid destination operand :", dst);

	set_mode_reg(src);

	.if (sm_mode :: "areg")
		.error("Invalid source operand :", src);

	.bundle {
		opcode12a(code, dst, sm_mode, sm_reg);
		extension(src, "", sm_mode, sm_reg);
	}
}

.vop
divu(src, dst) {
	div_mul(divu, src, dst);
}
.vop
divs(src, dst) {
	div_mul(divs, src, dst);
}

.vop
mulu(src, dst) {
	div_mul(mulu, src, dst);
}
.vop
muls(src, dst) {
	div_mul(muls, src, dst);
}

.func
do_shift(code, size, src, dst) {
	.numvar data;

	.if (dst :: "") {
		do_opcode6(.concat(code, "_mem"), 3, src);
		.done;
	}

	.if (.search(dst, "d[0-7]") != 2)
		.error("Invalid destination operand :", dst);

	.if (.substr(src, 0, 0) :: "#") {
		data = .number(.substr(src, 1));
		.if (data == 8)
			data = 0;
		.elif (data < 1 || 7 < data)
			.error("Operand", src, "is out of range (1..8).");
		opcode12c(.concat(code, "_imm"), data, size, dst);
	} .elif (.search(src, "d[0-7]") == 2) {
		opcode12c(.concat(code, "_reg"), src, size, dst);
	} .else {
		.error("Invalid source operand :", src);
	}
}

.vop
asr(src, dst) {
	do_shift("asr", word, src, dst);
}
.vop
asr.b(src, dst) {
	do_shift("asr", byte, src, dst);
}
.vop
asr.w(src, dst) {
	do_shift("asr", word, src, dst);
}
.vop
asr.l(src, dst) {
	do_shift("asr", long, src, dst);
}

.vop
asl(src, dst) {
	do_shift("asl", word, src, dst);
}
.vop
asl.b(src, dst) {
	do_shift("asl", byte, src, dst);
}
.vop
asl.w(src, dst) {
	do_shift("asl", word, src, dst);
}
.vop
asl.l(src, dst) {
	do_shift("asl", long, src, dst);
}

.vop
lsr(src, dst) {
	do_shift("lsr", word, src, dst);
}
.vop
lsr.b(src, dst) {
	do_shift("lsr", byte, src, dst);
}
.vop
lsr.w(src, dst) {
	do_shift("lsr", word, src, dst);
}
.vop
lsr.l(src, dst) {
	do_shift("lsr", long, src, dst);
}

.vop
lsl(src, dst) {
	do_shift("lsl", word, src, dst);
}
.vop
lsl.b(src, dst) {
	do_shift("lsl", byte, src, dst);
}
.vop
lsl.w(src, dst) {
	do_shift("lsl", word, src, dst);
}
.vop
lsl.l(src, dst) {
	do_shift("lsl", long, src, dst);
}

.vop
roxr(src, dst) {
	do_shift("roxr", word, src, dst);
}
.vop
roxr.b(src, dst) {
	do_shift("roxr", byte, src, dst);
}
.vop
roxr.w(src, dst) {
	do_shift("roxr", word, src, dst);
}
.vop
roxr.l(src, dst) {
	do_shift("roxr", long, src, dst);
}

.vop
roxl(src, dst) {
	do_shift("roxl", word, src, dst);
}
.vop
roxl.b(src, dst) {
	do_shift("roxl", byte, src, dst);
}
.vop
roxl.w(src, dst) {
	do_shift("roxl", word, src, dst);
}
.vop
roxl.l(src, dst) {
	do_shift("roxl", long, src, dst);
}

.vop
ror(src, dst) {
	do_shift("ror", word, src, dst);
}
.vop
ror.b(src, dst) {
	do_shift("ror", byte, src, dst);
}
.vop
ror.w(src, dst) {
	do_shift("ror", word, src, dst);
}
.vop
ror.l(src, dst) {
	do_shift("ror", long, src, dst);
}

.vop
rol(src, dst) {
	do_shift("rol", word, src, dst);
}
.vop
rol.b(src, dst) {
	do_shift("rol", byte, src, dst);
}
.vop
rol.w(src, dst) {
	do_shift("rol", word, src, dst);
}
.vop
rol.l(src, dst) {
	do_shift("rol", long, src, dst);
}

.func
do_opcode12c(code, size, src, dst) {
	.strvar s_mode, s_reg;

	set_mode_reg(src);
	s_mode = sm_mode;
	s_reg = sm_reg;
	set_mode_reg(dst);

	.if (code :: "cmpm" && s_mode :: "postinc" && sm_mode :: "postinc") 
		opcode12c(code, sm_reg, size, s_reg); 
	.elif (s_mode :: "predec" && sm_mode :: "predec") 
		opcode12c(.concat(code, "_mem_mem"), sm_reg, size, s_reg);
	.elif (s_mode :: "dreg" && sm_mode :: "dreg")
		opcode12c(.concat(code, "_reg_reg"), sm_reg, size, s_reg); 
	.else 
		.error("Invalid combination of operands :", src, ",", dst);
}

.vop
addx(src, dst) {
	do_opcode12c("addx", word, src, dst);
}
.vop
addx.b(src, dst) {
	do_opcode12c("addx", byte, src, dst);
}
.vop
addx.w(src, dst) {
	do_opcode12c("addx", word, src, dst);
}
.vop
addx.l(src, dst) {
	do_opcode12c("addx", long, src, dst);
}

.vop
subx(src, dst) {
	do_opcode12c("subx", word, src, dst);
}
.vop
subx.b(src, dst) {
	do_opcode12c("subx", byte, src, dst);
}
.vop
subx.w(src, dst) {
	do_opcode12c("subx", word, src, dst);
}
.vop
subx.l(src, dst) {
	do_opcode12c("subx", long, src, dst);
}

.vop
cmpm(src, dst) {
	do_opcode12c("cmpm", word, src, dst);
}
.vop
cmpm.b(src, dst) {
	do_opcode12c("cmpm", byte, src, dst);
}
.vop
cmpm.w(src, dst) {
	do_opcode12c("cmpm", word, src, dst);
}
.vop
cmpm.l(src, dst) {
	do_opcode12c("cmpm", long, src, dst);
}

.func
do_opcode12d(code, src, dst) {
	.strvar s_mode, s_reg;

	set_mode_reg(src);
	s_mode = sm_mode;
	s_reg = sm_reg;
	set_mode_reg(dst);

	.if (code :: "ext") {
		.if (s_mode :: "dreg" && sm_mode :: "dreg")
			opcode12d(.concat(code, "_dreg_dreg"), sm_reg, s_reg); 
		.elif (s_mode :: "areg" && sm_mode :: "areg")
			opcode12d(.concat(code, "_areg_areg"), sm_reg, s_reg); 
		.elif (s_mode :: "dreg" && sm_mode :: "areg")
			opcode12d(.concat(code, "_dreg_areg"), s_reg, sm_reg); 
		.elif (s_mode :: "areg" && sm_mode :: "dreg")
			opcode12d(.concat(code, "_dreg_areg"), sm_reg, s_reg); 
		.else
			.error("Invalid combination of operands :", src, ",", dst);
	} .elif (s_mode :: "predec" && sm_mode :: "predec") 
		opcode12d(.concat(code, "_mem_mem"), sm_reg, s_reg);
	.elif (s_mode :: "dreg" && sm_mode :: "dreg")
		opcode12d(.concat(code, "_reg_reg"), sm_reg, s_reg); 
	.else 
		.error("Invalid combination of operands :", src, ",", dst);
}

.vop
sbcd(src, dst) {
	do_opcode12d("sbcd", src, dst);
}
.vop
abcd(src, dst) {
	do_opcode12d("abcd", src, dst);
}
.vop
exg(src, dst) {
	do_opcode12d("ext", src, dst);
}


Back to Archelon's Home Page