Archelon Ischyros Archelon Inc.

Programming tools for your new processor

Motorola 68000 Example Compiler Information File

The compiler generates instructions using code tables which you provide in a text file, called the Compiler Information File (CIF). This file describes the instructions of your machine and tells the compiler how to generate code for it. The information in the file includes descriptions of:

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

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


Back to Archelon's Home Page.


# @(#) m68000.cif 1.8 97/05/27 00:33:48 @(#)
#
# m68000.cif
#
# Copyright © 1995-1997 Archelon Inc. All Rights Reserved.
#

one_mem;
mau := 8;
code_locinc := 2;
data_locinc := 1;

align char := 1;
align short := 2;
align int := 2;
align long := 2;

int := short;
char := signed;
wchar := short;

data_pointer := long;
code_pointer := long;

var push_size;
var reg_list;

###
### The lowest numbered register set with scratch registers is used for
### the return value from a function.  Thus the order in which register
### sets are declared is significant.
###

# Data Registers
regset := D[8]
	width = 32
	optype = int
	regtype = char, short, int, long
	expansion
		D = "d%2"
;

# Address Registers
regset := A[8]
	width = 32
	optype = ptr, codeptr
	regtype = ptr, codeptr
	expansion
		A = "a%2",
		A[7] = "sp"
;

# Supervisor Stack Pointer
regset := SSP
	width = 32
	optype = ptr
	regtype = ptr
	expansion
		SSP = "ssp"
;

# User Stack Pointer
regset := USP
	width = 32
	optype = ptr
	regtype = ptr
	expansion
		USP = "usp"
;

# Program Counter
regset := PC
	width = 32
	optype = codeptr
	regtype = codeptr
	expansion
		PC = "pc"
;

# Status Register
#	15		T	Trace Mode
#	13		S	Supervisor State
#	10:8		Interrupt Mask
#	4		X	Extend
#	3		N	Negative
#	2		Z	Zero
#	1		V	Overflow
#	0		C	Carry/Borrow
regset := SR
	width = 16
	optype = int
	regtype = int
	expansion
		SR = "sr"
;
regset := CCR
	width = 8
	optype = int
	regtype = char
	expansion
		CCR = "ccr"
;

# Count 8 bytes for the return address and saved frame pointer.
stack 
	high_to_low,
	stkptr := A[7],
	frameptr := A[6],
	hw_farg_offset := 8
;

argreg := A[0-2];
argreg := D[0-2];
scratch := A[0-2];
scratch := D[0-2];
color := A[0-5];
color := D[0-7];

### Operands

operand A			reg A;
operand D			reg D;
operand PC			reg PC;
operand SR			reg SR;
operand CCR			reg CCR;
operand SSP			reg SSP;
operand USP			reg USP;

operand zero		uconst 0;
operand u3			uconst 1 8 expansion "#%1";
operand u8			uconst 0 0xff expansion "#%1";
operand s8			sconst -0x7f 0x7f expansion "#%1";
operand u16			uconst 0 0xffff expansion "#%1";
operand s16			sconst -0x7fff 0x7fff expansion "#%1";
operand u32			uconst 0 0xffffffff expansion "#%1";
operand s32			sconst -0x7fffffff 0x7fffffff expansion "#%1";

operand data		ptr expansion "#%1";
operand code		codeptr expansion "#%1";
operand label		codeptr;

operand addr		amode data expansion "%2";
operand ind			amode A expansion "(%1)";
operand ind_pi		amode A ++1 expansion "(%1)+";
operand ind_pi2		amode A ++2 expansion "(%1)+";
operand pd_ind		amode --1 A expansion "-(%1)";
operand pd_ind2		amode --2 A expansion "-(%1)";
operand ind_disp	amode A + s16 expansion "%2(%1)";
operand ind_ix		amode A + s8 + D expansion "%2(%1, %3)";
operand pc_disp		amode PC + s16 expansion "%2(%1)";
operand pc_ix		amode PC + s8 + D expansion "%2(%1, %3)";

operand ptr			reg A expansion "(%1)";

### Formats and Opcodes

format noargs;

opcode illegal noargs;
opcode nop noargs;
opcode reset noargs;
opcode rte : ret noargs;
opcode rtr : ret noargs;
opcode rts : ret noargs;
opcode stop noargs;
opcode trapv noargs;

# All branch instructions are relative the start of the
# branch instruction (the current program counter) plus two.
#
expansion ifa "\t.ifa (%1 - . - 2), %3, %4\n";

format branch
	target src
		label
;

opcode bcc : cjump branch;
opcode bcs : cjump branch;
opcode beq : cjump branch;
opcode bge : cjump branch;
opcode bgt : cjump branch;
opcode bhi : cjump branch;
opcode ble : cjump branch;
opcode bls : cjump branch;
opcode blt : cjump branch;
opcode bmi : cjump branch;
opcode bne : cjump branch;
opcode bpl : cjump branch;
opcode bvc : cjump branch;
opcode bvs : cjump branch;
opcode bra : jump branch;
opcode bsr : call branch;

opcode jcc : cjump expansion "\t%if{%1;%2;bcs 6\n\tjmp %3;%2 %3}\n" 
	branch : bcc -32768 32767;
opcode jcs : cjump expansion "\t%if{%1;%2;bcc 6\n\tjmp %3;%2 %3}\n" 
	branch : bcs -32768 32767;
opcode jeq : cjump expansion "\t%if{%1;%2;bne 6\n\tjmp %3;%2 %3}\n" 
	branch : beq -32768 32767;
opcode jge : cjump expansion "\t%if{%1;%2;blt 6\n\tjmp %3;%2 %3}\n" 
	branch : bge -32768 32767;
opcode jgt : cjump expansion "\t%if{%1;%2;ble 6\n\tjmp %3;%2 %3}\n" 
	branch : bgt -32768 32767;
opcode jhi : cjump expansion "\t%if{%1;%2;bls 6\n\tjmp %3;%2 %3}\n" 
	branch : bhi -32768 32767;
opcode jle : cjump expansion "\t%if{%1;%2;bgt 6\n\tjmp %3;%2 %3}\n" 
	branch : ble -32768 32767;
opcode jls : cjump expansion "\t%if{%1;%2;bhi 6\n\tjmp %3;%2 %3}\n" 
	branch : bls -32768 32767;
opcode jlt : cjump expansion "\t%if{%1;%2;bge 6\n\tjmp %3;%2 %3}\n" 
	branch : blt -32768 32767;
opcode jmi : cjump expansion "\t%if{%1;%2;bpl 6\n\tjmp %3;%2 %3}\n" 
	branch : bmi -32768 32767;
opcode jne : cjump expansion "\t%if{%1;%2;beq 6\n\tjmp %3;%2 %3}\n" 
	branch : bne -32768 32767;
opcode jpl : cjump expansion "\t%if{%1;%2;bmi 6\n\tjmp %3;%2 %3}\n" 
	branch : bpl -32768 32767;
opcode jvc : cjump expansion "\t%if{%1;%2;bvs 6\n\tjmp %3;%2 %3}\n" 
	branch : bvc -32768 32767;
opcode jvs : cjump expansion "\t%if{%1;%2;bvc 6\n\tjmp %3;%2 %3}\n" 
	branch : bvs -32768 32767;

opcode jmp : jump branch : bra -32768 32767;
opcode jsr : call branch : bsr -32768 32767;
opcode jsr_long : call expansion "\tjst %3\n" branch;

###
#format jump_indirect
#	lsrc
#		ind | ind_disp | ind_ix | label
#		| pc_disp | pc_ix
#;

format jump_indirect
	lsrc
		label | ptr
;

opcode jmp_ind : jump expansion "\tjmp %3\n" jump_indirect;
opcode jsr_ind : call expansion "\tjsr %3\n" jump_indirect;

format pd_pd
	expansion "%2, %1"
	lsrcdest
		pd_ind | pd_ind2
	rsrc
		pd_ind | pd_ind2
;
format d_d
	expansion "%2, %1"
	lsrcdest
		D
	rsrc
		D
;

opcode abcd_d expansion "\tabcd %3\n" d_d;
opcode abcd_pd expansion "\tabcd %3\n" pd_pd;

opcode sbcd_d expansion "\tsbcd %3\n" d_d;
opcode sbcd_pd expansion "\tsbcd %3\n" pd_pd;

format ea_da
	expansion "%2, %1"
	lsrcdest
		A | D
	rsrc
		A | D | ind_pi | ind_pi2 | pd_ind | pd_ind2
		| ind_disp | ind_ix | addr | ind
		| pc_disp | pc_ix | s16 | u16 | s32 | u32 | data | code
;
format ea_d
	expansion "%2, %1"
	lsrcdest
		D
	rsrc
		D | ind_pi | ind_pi2 | pd_ind | pd_ind2
		| ind_disp | ind_ix | addr | ind
		| pc_disp | pc_ix | s16 | u16 | s32 | u32 | data | code
;
format imm_ea
	expansion "%2, %1"
	lsrcdest
		D | ind_pi | ind_pi2 | pd_ind | pd_ind2
		| ind_disp | ind_ix | addr | ind
	rsrc
		s16 | u16 | s32 | u32 | data | code
;
		
format imm_sr
	expansion "%2, %1"
	lsrcdest
		CCR | SR
	rsrc
		u16
;
format d_ea
	expansion "%2, %1"
	lsrcdest
		D | ind_pi | ind_pi2 | pd_ind | pd_ind2
		| ind_disp | ind_ix | addr | ind
	rsrc
		D
;
format q_ea
	expansion "%2, %1"
	lsrcdest
		A | D | ind_pi | ind_pi2 | pd_ind |
		pd_ind2 | ind_disp | ind_ix | addr | ind
	rsrc
		u3
;

opcode add_b_da expansion "\tadd.b %3\n" ea_da;
opcode add_w_da expansion "\tadd.w %3\n" ea_da;
opcode add_l_da expansion "\tadd.l %3\n" ea_da;

opcode add_b_ea expansion "\tadd.b %3\n" d_ea;
opcode add_w_ea expansion "\tadd.w %3\n" d_ea;
opcode add_l_ea expansion "\tadd.l %3\n" d_ea;

opcode add_b_i expansion "\taddi.b %3\n" imm_ea;
opcode add_w_i expansion "\taddi.w %3\n" imm_ea;
opcode add_l_i expansion "\taddi.l %3\n" imm_ea;

opcode add_b_q expansion "\taddq.b %3\n" q_ea;
opcode add_w_q expansion "\taddq.w %3\n" q_ea;
opcode add_l_q expansion "\taddq.l %3\n" q_ea;

opcode add_b_xd expansion "\taddx.b %3\n" d_d;
opcode add_w_xd expansion "\taddx.w %3\n" d_d;
opcode add_l_xd expansion "\taddx.l %3\n" d_d;

opcode add_b_pd expansion "\taddx.b %3\n" pd_pd;
opcode add_w_pd expansion "\taddx.w %3\n" pd_pd;
opcode add_l_pd expansion "\taddx.l %3\n" pd_pd;

opcode sub_b_da expansion "\tsub.b %3\n" ea_da;
opcode sub_w_da expansion "\tsub.w %3\n" ea_da;
opcode sub_l_da expansion "\tsub.l %3\n" ea_da;

opcode sub_b_ea expansion "\tsub.b %3\n" d_ea;
opcode sub_w_ea expansion "\tsub.w %3\n" d_ea;
opcode sub_l_ea expansion "\tsub.l %3\n" d_ea;

opcode sub_b_i expansion "\tsubi.b %3\n" imm_ea;
opcode sub_w_i expansion "\tsubi.w %3\n" imm_ea;
opcode sub_l_i expansion "\tsubi.l %3\n" imm_ea;

opcode sub_b_q expansion "\tsubq.b %3\n" q_ea;
opcode sub_w_q expansion "\tsubq.w %3\n" q_ea;
opcode sub_l_q expansion "\tsubq.l %3\n" q_ea;

opcode sub_b_xd expansion "\tsubx.b %3\n" d_d;
opcode sub_w_xd expansion "\tsubx.w %3\n" d_d;
opcode sub_l_xd expansion "\tsubx.l %3\n" d_d;

opcode sub_b_pd expansion "\tsubx.b %3\n" pd_pd;
opcode sub_w_pd expansion "\tsubx.w %3\n" pd_pd;
opcode sub_l_pd expansion "\tsubx.l %3\n" pd_pd;

opcode and_b_d expansion "\tand.b %3\n" ea_d;
opcode and_w_d expansion "\tand.w %3\n" ea_d;
opcode and_l_d expansion "\tand.l %3\n" ea_d;
	
opcode and_b_i expansion "\tandi.b %3\n" imm_ea;
opcode and_w_i expansion "\tandi.w %3\n" imm_ea;
opcode and_l_i expansion "\tandi.l %3\n" imm_ea;
opcode and_sr expansion "\tandi.b %3\n" imm_sr;

opcode and_b_ea expansion "\tand.b %3\n" d_ea;
opcode and_w_ea expansion "\tand.w %3\n" d_ea;
opcode and_l_ea expansion "\tand.l %3\n" d_ea;

opcode or_b_d expansion "\tor.b %3\n" ea_d;
opcode or_w_d expansion "\tor.w %3\n" ea_d;
opcode or_l_d expansion "\tor.l %3\n" ea_d;
	
opcode or_b_i expansion "\tori.b %3\n" imm_ea;
opcode or_w_i expansion "\tori.w %3\n" imm_ea;
opcode or_l_i expansion "\tori.l %3\n" imm_ea;
opcode or_sr expansion "\tori.b %3\n" imm_sr;

opcode or_b_ea expansion "\tor.b %3\n" d_ea;
opcode or_w_ea expansion "\tor.w %3\n" d_ea;
opcode or_l_ea expansion "\tor.l %3\n" d_ea;

opcode eor_b_i expansion "\teori.b %3\n" imm_ea;
opcode eor_w_i expansion "\teori.w %3\n" imm_ea;
opcode eor_l_i expansion "\teori.l %3\n" imm_ea;
opcode eor_sr expansion "\teori.b %3\n" imm_sr;

opcode eor_b_ea expansion "\teor.b %3\n" d_ea;
opcode eor_w_ea expansion "\teor.w %3\n" d_ea;
opcode eor_l_ea expansion "\teor.l %3\n" d_ea;

format d3_d
	expansion "%2, %1"
	lsrcdest
		D
	rsrc
		D | u3
;
format ea
	lsrcdest
		ind_pi | ind_pi2 | pd_ind | pd_ind2
		| ind_disp | ind_ix | addr | ind
;
		
opcode asl_b_d expansion "\tasl.b %3\n" d3_d;
opcode asl_w_d expansion "\tasl.w %3\n" d3_d;
opcode asl_l_d expansion "\tasl.l %3\n" d3_d;

opcode asr_b_d expansion "\tasr.b %3\n" d3_d;
opcode asr_w_d expansion "\tasr.w %3\n" d3_d;
opcode asr_l_d expansion "\tasr.l %3\n" d3_d;

opcode asl_w_ea expansion "\tasl.w %3\n" ea;
opcode asr_w_ea expansion "\tasr.w %3\n" ea;

opcode lsl_b_d expansion "\tlsl.b %3\n" d3_d;
opcode lsl_w_d expansion "\tlsl.w %3\n" d3_d;
opcode lsl_l_d expansion "\tlsl.l %3\n" d3_d;

opcode lsr_b_d expansion "\tlsr.b %3\n" d3_d;
opcode lsr_w_d expansion "\tlsr.w %3\n" d3_d;
opcode lsr_l_d expansion "\tlsr.l %3\n" d3_d;

opcode lsl_w_ea expansion "\tlsl.w %3\n" ea;
opcode lsr_w_ea expansion "\tlsr.w %3\n" ea;

opcode rol_b_d expansion "\trol.b %3\n" d3_d;
opcode rol_w_d expansion "\trol.w %3\n" d3_d;
opcode rol_l_d expansion "\trol.l %3\n" d3_d;

opcode ror_b_d expansion "\tror.b %3\n" d3_d;
opcode ror_w_d expansion "\tror.w %3\n" d3_d;
opcode ror_l_d expansion "\tror.l %3\n" d3_d;

opcode rol_w_ea expansion "\trol.w %3\n" ea;
opcode ror_w_ea expansion "\tror.w %3\n" ea;

opcode roxl_b_d expansion "\troxl.b %3\n" d3_d;
opcode roxl_w_d expansion "\troxl.w %3\n" d3_d;
opcode roxl_l_d expansion "\troxl.l %3\n" d3_d;

opcode roxr_b_d expansion "\troxr.b %3\n" d3_d;
opcode roxr_w_d expansion "\troxr.w %3\n" d3_d;
opcode roxr_l_d expansion "\troxr.l %3\n" d3_d;

opcode roxl_w_ea expansion "\troxl.w %3\n" ea;
opcode roxr_w_ea expansion "\troxr.w %3\n" ea;

format source
	lsrcdest
		D | ind_pi | ind_pi2 | pd_ind | pd_ind2
		| ind_disp | ind_ix | addr | ind
;

opcode clr_b expansion "\tclr.b %3\n" source;
opcode clr_w expansion "\tclr.w %3\n" source;
opcode clr_l expansion "\tclr.l %3\n" source;

opcode nbcd source;

opcode neg_b expansion "\tneg.b %3\n" source;
opcode neg_w expansion "\tneg.w %3\n" source;
opcode neg_l expansion "\tneg.l %3\n" source;

opcode negx_b expansion "\tnegx.b %3\n" source;
opcode negx_w expansion "\tnegx.w %3\n" source;
opcode negx_l expansion "\tnegx.l %3\n" source;

opcode not_b expansion "\tnot.b %3\n" source;
opcode not_w expansion "\tnot.w %3\n" source;
opcode not_l expansion "\tnot.l %3\n" source;

opcode scc source;
opcode scs source;
opcode seq source;
opcode sf source;
opcode sge source;
opcode sgt source;
opcode shi source;
opcode sle source;
opcode sls source;
opcode slt source;
opcode smi source;
opcode sne source;
opcode spl source;
opcode st source;
opcode svc source;
opcode svs source;

opcode tas source;

opcode tst_b expansion "\ttst.b %3\n" source;
opcode tst_w expansion "\ttst.w %3\n" source;
opcode tst_l expansion "\ttst.l %3\n" source;

format u8_ea
	expansion "%2, %1"
	lsrcdest
		D | ind_pi | ind_pi2 | pd_ind | pd_ind2
		| ind_disp | ind_ix | addr | ind
	rsrc
		u8
;
	
opcode bchg_b_ea expansion "\tbchg %3\n" d_ea;
opcode bchg_l_d expansion "\tbchg %3\n" d_d;
opcode bchg_l_ea expansion "\tbchg %3\n" u8_ea;

opcode bclr_b_ea expansion "\tbclr %3\n" d_ea;
opcode bclr_l_d expansion "\tbclr %3\n" d_d;
opcode bclr_l_ea expansion "\tbclr %3\n" u8_ea;

opcode bset_b_ea expansion "\tbset %3\n" d_ea;
opcode bset_l_d expansion "\tbset %3\n" d_d;
opcode bset_l_ea expansion "\tbset %3\n" u8_ea;

opcode btst_b_ea expansion "\tbtst %3\n" d_ea;
opcode btst_l_d expansion "\tbtst %3\n" d_d;
opcode btst_l_ea expansion "\tbtst %3\n" u8_ea;

opcode chk ea_d;

format cmp_ea_da
	expansion "%2, %1"
	lsrc
		A | D
	rsrc
		A | D | ind_pi | ind_pi2 | pd_ind | pd_ind2
		| ind_disp | ind_ix | addr | ind
		| pc_disp | pc_ix | s16 | u16 | s32 | u32 | data | code
;
format cmp_imm_ea
	expansion "%2, %1"
	lsrc
		D | ind_pi | ind_pi2 | pd_ind | pd_ind2
		| ind_disp | ind_ix | addr | ind
	rsrc
		s16 | u16 | s32 | u32 | data | code
;
format cmp_pi_pi
	expansion "%2, %1"
	lsrc
		ind_pi | ind_pi2
	rsrc
		ind_pi | ind_pi2
;
	
# The assembler must handle aliases for CMPI and CMPA.
opcode cmp_b_da expansion "\tcmp.b %3\n" cmp_ea_da;
opcode cmp_w_da expansion "\tcmp.w %3\n" cmp_ea_da;
opcode cmp_l_da expansion "\tcmp.l %3\n" cmp_ea_da;

opcode cmp_b_ea expansion "\tcmpi.b %3\n" cmp_imm_ea;
opcode cmp_w_ea expansion "\tcmpi.w %3\n" cmp_imm_ea;
opcode cmp_l_ea expansion "\tcmpi.l %3\n" cmp_imm_ea;

opcode cmp_b_pi expansion "\tcmpm.b %3\n" cmp_pi_pi;
opcode cmp_w_pi expansion "\tcmpm.w %3\n" cmp_pi_pi;
opcode cmp_l_pi expansion "\tcmpm.l %3\n" cmp_pi_pi;

format repeat_until
	lsrcdest
		D
	rsrc
		label
;

opcode dbcc : cjump repeat_until;
opcode dbcs : cjump repeat_until;
opcode dbeq : cjump repeat_until;
opcode dbf : cjump repeat_until;
opcode dbge : cjump repeat_until;
opcode dbgt : cjump repeat_until;
opcode dbhi : cjump repeat_until;
opcode dble : cjump repeat_until;
opcode dbls : cjump repeat_until;
opcode dblt : cjump repeat_until;
opcode dbmi : cjump repeat_until;
opcode dbne : cjump repeat_until;
opcode dbpl : cjump repeat_until;
opcode dbvc : cjump repeat_until;
opcode dbvs : cjump repeat_until;
opcode dbra : cjump repeat_until;

opcode divs ea_d;
opcode divu ea_d;

opcode muls ea_d;
opcode mulu ea_d;

format da_da
	expansion "%2, %1"
	lsrc
		A | D
	rsrc
		A | D
;

opcode exg da_da;

format dreg
	lsrcdest
		D
;

opcode ext_w expansion "\text.w %3\n" dreg;
opcode ext_l expansion "\text.l %3\n" dreg;

opcode swap dreg;

format load_ea
	expansion "%2, %1"
	dest
		A
	src
		ind_disp | ind_ix | addr | pc_disp | pc_ix | ind
;

opcode lea load_ea;

format frame
	lsrcdest
		A
	rsrc
		s16
;

opcode link frame;

format load
	expansion "%2, %1"
	dest
		A | D
	src
		ind_pi | ind_pi2 | pd_ind | pd_ind2
		| ind_disp | ind_ix | addr | ind
		| pc_disp | pc_ix | s16 | u16 | s32 | u32 | data | code
;
format store
	expansion "%2, %1"
	dest
		ind_pi | ind_pi2 | pd_ind | pd_ind2
		| ind_disp | ind_ix | addr | ind
	src
		A | D | ind_pi | ind_pi2 | pd_ind | pd_ind2
		| ind_disp | ind_ix | addr | ind 
		| pc_disp | pc_ix | s16 | u16 | s32 | u32 | data | code
;
format move
	expansion "%2, %1"
	dest
		A | D
	src
		A | D
;

opcode load_b expansion "\tmove.b %3\n" load;
opcode load_w expansion "\tmove.w %3\n" load;
opcode load_l expansion "\tmove.l %3\n" load;

opcode store_b expansion "\tmove.b %3\n" store;
opcode store_w expansion "\tmove.w %3\n" store;
opcode store_l expansion "\tmove.l %3\n" store;

opcode move_b : move expansion "\tmove.b %3\n" move;
opcode move_w : move expansion "\tmove.w %3\n" move;
opcode move_l : move expansion "\tmove.l %3\n" move;

format load_sr
	expansion "%2, %1"
	dest
		CCR | SR
	src
		D | ind_pi | ind_pi2 | pd_ind | pd_ind2
		| ind_disp | ind_ix | addr | ind
		| pc_disp | pc_ix | s16 | u16
;
format store_sr
	expansion "%2, %1"
	dest
		D | ind_pi | ind_pi2 | pd_ind | pd_ind2
		| ind_disp | ind_ix | addr | ind
	src
		CCR | SR
;

opcode load_sr expansion "\tmove %3\n" load_sr;
opcode store_sr expansion "\tmove %3\n" store_sr;

format load_usp
	expansion "%2, %1"
	dest
		USP
	src
		A
;
format store_usp
	expansion "%2, %1"
	dest
		A
	src
		USP
;

opcode load_usp expansion "\tmove %3\n" load_usp;
opcode store_usp expansion "\tmove %3\n" store_usp;

format load_many
	expansion "%2, %1"
	string
		zero
	src
		ind_pi | ind_pi2 | pd_ind | pd_ind2
		| ind_disp | ind_ix | addr | pc_disp | pc_ix | ind
;
format store_many
	expansion "%2, %1"
	dest
		pd_ind | pd_ind2 | ind_disp | ind_ix | addr | ind
	string
		zero
;
	
opcode load_w_many expansion "\tmovem.w %3\n" load_many;
opcode load_l_many expansion "\tmovem.l %3\n" load_many;
opcode store_w_many expansion "\tmovem.w %3\n" store_many;
opcode store_l_many expansion "\tmovem.l %3\n" store_many;

format load_p
	expansion "%2, %1"
	dest
		D
	src
		ind_disp
;
format store_p
	expansion "%2, %1"
	dest
		ind_disp
	src
		D
;
		
opcode load_p expansion "\tmovep %3\n" load_p;
opcode store_p expansion "\tmovep %3\n" store_p;

format load_quick
	expansion "%2, %1"
	dest
		D
	src
		s8
;

opcode load_quick expansion "\tmoveq %3\n" load_quick;

format push_ea
	lsrc
		ind_disp | ind_ix | addr | pc_disp | pc_ix | ind
;

opcode pea push_ea;

format trap
	lsrc
		u8
;

opcode trap trap;

format areg
	lsrcdest
		A
;

opcode unlk areg;

### Code tables

code do_nothing
{
}

code nofloat
{
    $ERROR "Float and double support not implemented.";
}

code push
? type(slong) || type(ulong) || type(ptr) || type(codeptr)
{
	$SET push_size = push_size + 4;
	store_l $mktree(*--$reg(A[7]) : ptr uchar), $left;
}
? in_reg($left, CCR) || in_reg($left, SR)
{
	$SET push_size = push_size + 2;
	store_sr $mktree(*--$reg(A[7]) : ptr uchar), $left;
}
{
	$SET push_size = push_size + 2;
	store_w $mktree(*--$reg(A[7]) : ptr uchar), $left;
}

code pop
? type(slong) || type(ulong) || type(ptr) || type(codeptr)
{
	$SET push_size = push_size - 4;
	load_l $left, $mktree(*$reg(A[7]) : ptr uchar ++);
}
? in_reg($left, CCR) || in_reg($left, SR)
{
	$SET push_size = push_size - 2;
	load_sr $left, $mktree(*$reg(A[7]) : ptr uchar ++);
}
{
	$SET push_size = push_size - 2;
	load_w $left, $mktree(*$reg(A[7]) : ptr uchar ++);
}

oper PUSH : void push;
oper PUSH : ptr push;
oper PUSH : ptr2 push;
oper PUSH : codeptr push;
oper PUSH : schar push;
oper PUSH : uchar push;
oper PUSH : sshort push;
oper PUSH : ushort push;
oper PUSH : slong push;
oper PUSH : ulong push;
oper PUSH : float nofloat;
oper PUSH : double nofloat;
oper PUSH : longdbl nofloat;

def_user_oper POP : unary side_effect;

oper POP : void pop;
oper POP : ptr pop;
oper POP : ptr2 pop;
oper POP : codeptr pop;
oper POP : schar pop;
oper POP : uchar pop;
oper POP : sshort pop;
oper POP : ushort pop;
oper POP : slong pop;
oper POP : ulong pop;
oper POP : float nofloat;
oper POP : double nofloat;
oper POP : longdbl nofloat;

code enter
{
	link $reg(A[6]), $left;
}

code exit
{
	unlk $reg(A[6]);
}

oper ENTER : void enter;
oper EXIT : void exit;
oper ENTERI : void enter;
oper EXITI : void exit;

# The Stack Frame 
#
#	high-mem:	[ func. arg. n	]
#				< saved PC		>
#				< saved A6 (FP)	>
#				[ SR or CCR 	]
#				[ D0 ...		]
#				[ ... D7		]
#				[ A0 ...		]
#				[ ... A7		]
#	low-mem:	[ local data	]	<- A7 (SP)
#
code frame
{
	$SET reg_list = 0;

	? must_preserve_reg(A[7])
	{
		$SET reg_list = reg_list & 0x8000;
	}{}
# Don't count A6 (frame pointer) since that is handle in the 
# enter/exit code by the link/unlk instructions.
#	? must_preserve_reg(A[6])
#	{
#		$SET reg_list = reg_list & 0x4000;
#	}{}
	? must_preserve_reg(A[5])
	{
		$SET reg_list = reg_list & 0x2000;
	}{}
	? must_preserve_reg(A[4])
	{
		$SET reg_list = reg_list & 0x1000;
	}{}
	? must_preserve_reg(A[3])
	{
		$SET reg_list = reg_list & 0x0800;
	}{}
	? must_preserve_reg(A[2])
	{
		$SET reg_list = reg_list & 0x0400;
	}{}
	? must_preserve_reg(A[1])
	{
		$SET reg_list = reg_list & 0x0200;
	}{}
	? must_preserve_reg(A[0])
	{
		$SET reg_list = reg_list & 0x0100;
	}{}

	? must_preserve_reg(D[7])
	{
		$SET reg_list = reg_list & 0x0080;
	}{}
	? must_preserve_reg(D[6])
	{
		$SET reg_list = reg_list & 0x0040;
	}{}
	? must_preserve_reg(D[5])
	{
		$SET reg_list = reg_list & 0x0020;
	}{}
	? must_preserve_reg(D[4])
	{
		$SET reg_list = reg_list & 0x0010;
	}{}
	? must_preserve_reg(D[3])
	{
		$SET reg_list = reg_list & 0x0008;
	}{}
	? must_preserve_reg(D[2])
	{
		$SET reg_list = reg_list & 0x0004;
	}{}
	? must_preserve_reg(D[1])
	{
		$SET reg_list = reg_list & 0x0002;
	}{}
	? must_preserve_reg(D[0])
	{
		$SET reg_list = reg_list & 0x0001;
	}{}

	? must_preserve_reg(CCR) 
	{
		? oper(SAVE_REGS)
		{
			store_sr $mktree(*$reg(A[6]) : ptr ushort), $reg(CCR);
		}
		{
			load_sr $mktree(*$reg(A[6]) : ptr ushort), $reg(CCR);
		}
	}
	? must_preserve_reg(SR) 
	{
		? oper(SAVE_REGS)
		{
			store_sr $mktree(*$reg(A[6]) : ptr ushort), $reg(CCR);
		}
		{
			load_sr $mktree(*$reg(A[6]) : ptr ushort), $reg(CCR);
		}
	}{}

	? reg_list != 0
	{
		? oper(SAVE_REGS)
		{
			store_l_many 
				$mktree(*($reg(A[7]) : ptr uchar + $left)), 
				$mkconst(reg_list);
		}
		{
			load_l_many 
				$mkconst(reg_list), 
				$mktree(*($reg(A[7]) : ptr uchar + $left));
		}
	}{}
}

oper SAVE_REGS : void frame;
oper RESTORE_REGS : void frame;

code noargs(opcode)
{
	opcode;
}

code jump(opcode)
{
	opcode $left;
}

oper JUMP : void jump("jmp");
oper CALLDIR : void jump("jsr");
oper CALLIND : void jump("jsr_ind");
oper RET : void noargs("rts");
oper RETI : void noargs("rti");

code asgn
? mem_ref($left) && ! (mem_ref($right) || in_any_reg($right))
{
	# Handle storing result of a sub-expression.
	$LOAD $temp(D), $right;
	$ASGN $dest, $left, $temp;
}
? mem_ref($left)
{
	? in_reg($right, CCR) || in_reg($right, SR)
	{
		store_sr $left, $right;
	}
	? type(slong) || type(ulong) || type(ptr) || type(codeptr)
	{
		store_l $left, $right;
	}
	? type(sshort) || type(ushort)
	{
		store_w $left, $right;
	}
	? type(schar) || type(uchar)
	{
		store_b $left, $right;
	}
	{
		$ERROR "Unexpected case for memory store.";
	}

	$EVAL $dest, $right;
}
{
	$LOAD $left, $right;
	$EVAL $dest, $left;
}

oper ASGN : void asgn;
oper ASGN : ptr asgn;
oper ASGN : ptr2 asgn;
oper ASGN : codeptr asgn;
oper ASGN : schar asgn;
oper ASGN : uchar asgn;
oper ASGN : sshort asgn;
oper ASGN : ushort asgn;
oper ASGN : slong asgn;
oper ASGN : ulong asgn;
oper ASGN : float nofloat;
oper ASGN : double nofloat;
oper ASGN : longdbl nofloat;

code load
? in_reg($dest, CCR) || in_reg($dest, SR)
{
	load_sr $dest, $right;
}
? in_any_reg($dest) && in_any_reg($src)
{
	? type(slong) || type(ulong) || type(ptr) || type(codeptr)
	{
		move_l $dest, $src;
	}
	? type(sshort) || type(ushort)
	{
		move_w $dest, $src;
	}
	? (type(schar) || type(uchar)) 
	&& in_reg_set($dest, D) && in_reg_set($src, D)
	{
		move_b $dest, $src;
	}
	{
		$ERROR "Unexpected case for register-to-register move.";
	}
}
? ! in_reg_set($dest, D) && matches($src, zero) 
{
	? type(slong) || type(ulong) || type(codeptr) || type(ptr)
	{
		clr_l $dest;
	}
	? (type(sshort) || type(ushort) || type(schar) || type(uchar)) 
	{
		clr_w $dest;
	}
	{
		$ERROR "Unexpected case clear-effective-address.";
	}
}
? in_reg_set($dest, D) && matches($src, s8)
{
	load_quick $dest, $src;
}
? in_reg_set($dest, A) 
&& mem_ref($src) && ! (matches($src, pd_ind)
	|| matches($src,pd_ind2)
	|| matches($src, ind_pi) 
	|| matches( $src, ind_pi2))
{
	lea $dest, $src;
}
? in_any_reg($dest) && (mem_ref($src)
|| matches($src, s16) || matches($src, u16) || matches($src, data)
|| matches($src, s32) || matches($src, u32) || matches($src, code))
{
	? type(slong) || type(ulong) || type(codeptr) || type(ptr)
	{
		load_l $dest, $src;
	}
	? type(sshort) || type(ushort)
	{
		load_w $dest, $src;
	}
	? (type(schar) || type(uchar)) && in_reg_set($dest, D)
	{
		load_b $dest, $src;
		? mem_ref($src)
		{
			ext_w $dest;
		}
	}
	{
		$ERROR "Unexpected case memory-to-register move.";
	}
}
{
	$EVAL $temp(D), $src;
	$LOAD $dest, $temp;
}
	
oper LOAD : void load;
oper LOAD : ptr load;
oper LOAD : ptr2 load;
oper LOAD : codeptr load;
oper LOAD : schar load;
oper LOAD : uchar load;
oper LOAD : sshort load;
oper LOAD : ushort load;
oper LOAD : slong load;
oper LOAD : ulong load;
oper LOAD : float nofloat;
oper LOAD : double nofloat;
oper LOAD : longdbl nofloat;

code add_sub_equ(opcode)
? matches($right, u3)
{
	opcode|"_q" $left, $right;
	$EVAL $dest, $left;
}
? mem_ref($left) 
&& (matches($right, s16) || matches($right, u16)
|| matches($right, s32) || matches($right, u32))
{
	opcode|"_i" $left, $right;
	$EVAL $dest, $left;
}
? in_reg_set($left, D) || in_reg_set($left, A)
{
	opcode|"_da" $left, $right;
	$EVAL $dest, $left;
}
{
	opcode|"_ea" $left, $right;
	$EVAL $dest, $left;
}

oper ADDEQ : void add_sub_equ("add_l");
oper ADDEQ : ptr add_sub_equ("add_l");
oper ADDEQ : ptr2 add_sub_equ("add_l");
oper ADDEQ : codeptr add_sub_equ("add_l");
oper ADDEQ : schar add_sub_equ("add_w");
oper ADDEQ : uchar add_sub_equ("add_w");
oper ADDEQ : sshort add_sub_equ("add_w");
oper ADDEQ : ushort add_sub_equ("add_w");
oper ADDEQ : slong add_sub_equ("add_l");
oper ADDEQ : ulong add_sub_equ("add_l");
oper ADDEQ : float nofloat;
oper ADDEQ : double nofloat;
oper ADDEQ : longdbl nofloat;

oper SUBEQ : void add_sub_equ("sub_l");
oper SUBEQ : ptr add_sub_equ("sub_l");
oper SUBEQ : ptr2 add_sub_equ("sub_l");
oper SUBEQ : codeptr add_sub_equ("sub_l");
oper SUBEQ : schar add_sub_equ("sub_w");
oper SUBEQ : uchar add_sub_equ("sub_w");
oper SUBEQ : sshort add_sub_equ("sub_w");
oper SUBEQ : ushort add_sub_equ("sub_w");
oper SUBEQ : slong add_sub_equ("sub_l");
oper SUBEQ : ulong add_sub_equ("sub_l");
oper SUBEQ : float nofloat;
oper SUBEQ : double nofloat;
oper SUBEQ : longdbl nofloat;

code and_eor_or_equ(operation, opcode)
? in_reg_set($left, A)
{
	$EVAL $temp(D), $left;
	"$"|operation $dest, $temp, $right;
}
? (matches($right, s16) || matches($right, u16)
|| matches($right, s32) || matches($right, u32))
{
	? (in_reg_set($left, CCR) || in_reg_set($left, SR)) && matches($right, u16)
	{
		opcode|"_sr" $left, $right;
	}
	{
		opcode|"_i" $left, $right;
	}
	$EVAL $dest, $left;
}
? in_reg_set($left, D) && ! (oper(EXOR) || oper(EXOREQ))
{
	opcode|"_d" $left, $right;
	$EVAL $dest, $left;
}
? ! in_reg_set($left, A)
{
	opcode|"_ea" $left, $right;
	$EVAL $dest, $left;
}
{
	$ERROR "Unexpected case for and_eor_or_equ."
}

oper ANDEQ : void and_eor_or_equ("ANDEQ", "and_l");
oper ANDEQ : ptr and_eor_or_equ("ANDEQ", "and_l");
oper ANDEQ : ptr2 and_eor_or_equ("ANDEQ", "and_l");
oper ANDEQ : codeptr and_eor_or_equ("ANDEQ", "and_l");
oper ANDEQ : schar and_eor_or_equ("ANDEQ", "and_w");
oper ANDEQ : uchar and_eor_or_equ("ANDEQ", "and_w");
oper ANDEQ : sshort and_eor_or_equ("ANDEQ", "and_w");
oper ANDEQ : ushort and_eor_or_equ("ANDEQ", "and_w");
oper ANDEQ : slong and_eor_or_equ("ANDEQ", "and_l");
oper ANDEQ : ulong and_eor_or_equ("ANDEQ", "and_l");
oper ANDEQ : float nofloat;
oper ANDEQ : double nofloat;
oper ANDEQ : longdbl nofloat;

oper EXOREQ : void and_eor_or_equ("EXOREQ", "eor_l");
oper EXOREQ : ptr and_eor_or_equ("EXOREQ", "eor_l");
oper EXOREQ : ptr2 and_eor_or_equ("EXOREQ", "eor_l");
oper EXOREQ : codeptr and_eor_or_equ("EXOREQ", "eor_l");
oper EXOREQ : schar and_eor_or_equ("EXOREQ", "eor_w");
oper EXOREQ : uchar and_eor_or_equ("EXOREQ", "eor_w");
oper EXOREQ : sshort and_eor_or_equ("EXOREQ", "eor_w");
oper EXOREQ : ushort and_eor_or_equ("EXOREQ", "eor_w");
oper EXOREQ : slong and_eor_or_equ("EXOREQ", "eor_l");
oper EXOREQ : ulong and_eor_or_equ("EXOREQ", "eor_l");
oper EXOREQ : float nofloat;
oper EXOREQ : double nofloat;
oper EXOREQ : longdbl nofloat;

oper OREQ : void and_eor_or_equ("OREQ", "or_l");
oper OREQ : ptr and_eor_or_equ("OREQ", "or_l");
oper OREQ : ptr2 and_eor_or_equ("OREQ", "or_l");
oper OREQ : codeptr and_eor_or_equ("OREQ", "or_l");
oper OREQ : schar and_eor_or_equ("OREQ", "or_w");
oper OREQ : uchar and_eor_or_equ("OREQ", "or_w");
oper OREQ : sshort and_eor_or_equ("OREQ", "or_w");
oper OREQ : ushort and_eor_or_equ("OREQ", "or_w");
oper OREQ : slong and_eor_or_equ("OREQ", "or_l");
oper OREQ : ulong and_eor_or_equ("OREQ", "or_l");
oper OREQ : float nofloat;
oper OREQ : double nofloat;
oper OREQ : longdbl nofloat;
	
code alu(operation)
? in_any_reg($dest) && ! in_same_reg($dest, $left)
{
	$EVAL $temp(D), $left;
	"$"|operation $dest, $temp, $right;
}
{
	"$"|operation $dest, $left, $right;
}

oper ADD : void alu("ADDEQ");
oper ADD : ptr alu("ADDEQ");
oper ADD : ptr2 alu("ADDEQ");
oper ADD : codeptr alu("ADDEQ");
oper ADD : schar alu("ADDEQ");
oper ADD : uchar alu("ADDEQ");
oper ADD : sshort alu("ADDEQ");
oper ADD : ushort alu("ADDEQ");
oper ADD : slong alu("ADDEQ");
oper ADD : ulong alu("ADDEQ");
oper ADD : float nofloat;
oper ADD : double nofloat;
oper ADD : longdbl nofloat;

oper SUB : void alu("SUBEQ");
oper SUB : ptr alu("SUBEQ");
oper SUB : ptr2 alu("SUBEQ");
oper SUB : codeptr alu("SUBEQ");
oper SUB : schar alu("SUBEQ");
oper SUB : uchar alu("SUBEQ");
oper SUB : sshort alu("SUBEQ");
oper SUB : ushort alu("SUBEQ");
oper SUB : slong alu("SUBEQ");
oper SUB : ulong alu("SUBEQ");
oper SUB : float nofloat;
oper SUB : double nofloat;
oper SUB : longdbl nofloat;

oper AND : void alu("ANDEQ");
oper AND : ptr alu("ANDEQ");
oper AND : ptr2 alu("ANDEQ");
oper AND : codeptr alu("ANDEQ");
oper AND : schar alu("ANDEQ");
oper AND : uchar alu("ANDEQ");
oper AND : sshort alu("ANDEQ");
oper AND : ushort alu("ANDEQ");
oper AND : slong alu("ANDEQ");
oper AND : ulong alu("ANDEQ");
oper AND : float nofloat;
oper AND : double nofloat;
oper AND : longdbl nofloat;

oper OR : void alu("OREQ");
oper OR : ptr alu("OREQ");
oper OR : ptr2 alu("OREQ");
oper OR : codeptr alu("OREQ");
oper OR : schar alu("OREQ");
oper OR : uchar alu("OREQ");
oper OR : sshort alu("OREQ");
oper OR : ushort alu("OREQ");
oper OR : slong alu("OREQ");
oper OR : ulong alu("OREQ");
oper OR : float nofloat;
oper OR : double nofloat;
oper OR : longdbl nofloat;

oper EXOR : void alu("EXOREQ");
oper EXOR : ptr alu("EXOREQ");
oper EXOR : ptr2 alu("EXOREQ");
oper EXOR : codeptr alu("EXOREQ");
oper EXOR : schar alu("EXOREQ");
oper EXOR : uchar alu("EXOREQ");
oper EXOR : sshort alu("EXOREQ");
oper EXOR : ushort alu("EXOREQ");
oper EXOR : slong alu("EXOREQ");
oper EXOR : ulong alu("EXOREQ");
oper EXOR : float nofloat;
oper EXOR : double nofloat;
oper EXOR : longdbl nofloat;

code unary(opcode)
? in_reg_set($left, D) || mem_ref($left)
{
	opcode $left;
	$EVAL $dest, $left;
}
{
	$EVAL $temp(D), $left;
	opcode $temp;
	$EVAL $dest, $temp;
}

oper COMPL : void unary("not_l");
oper COMPL : ptr unary("not_l");
oper COMPL : ptr2 unary("not_l");
oper COMPL : codeptr unary("not_l");
oper COMPL : schar unary("not_w");
oper COMPL : uchar unary("not_w");
oper COMPL : sshort unary("not_w");
oper COMPL : ushort unary("not_w");
oper COMPL : slong unary("not_l");
oper COMPL : ulong unary("not_l");
oper COMPL : float nofloat;
oper COMPL : double nofloat;
oper COMPL : longdbl nofloat;

oper UMINUS : void unary("neg_l");
oper UMINUS : ptr unary("neg_l");
oper UMINUS : ptr2 unary("neg_l");
oper UMINUS : codeptr unary("neg_l");
oper UMINUS : schar unary("neg_w");
oper UMINUS : uchar unary("neg_w");
oper UMINUS : sshort unary("neg_w");
oper UMINUS : ushort unary("neg_w");
oper UMINUS : slong unary("neg_l");
oper UMINUS : ulong unary("neg_l");
oper UMINUS : float nofloat;
oper UMINUS : double nofloat;
oper UMINUS : longdbl nofloat;

code shifts(operation, opcode, size)
? (matches($right, s16) || matches($right, u16)) && $right < 0
{
    $ERROR "Cannot shift by negative constant.";
}
? (matches($right, s16) || matches($right, u16)) && $right == 0
{
    $EVAL $dest, $left;
}
? (type(sshort) || type(ushort)) && mem_ref($left)
&& (matches($right, s16) || matches($right, u16)) && $right == 1
{
	opcode|"_w_ea" $left;
	$EVAL $dest, $left;
}
? ! in_reg_set($left, D) 
{
	$EVAL $temp(D), $left;
	"$"|operation $temp, $temp, $right;
	$EVAL $dest, $temp;
}
{
	? in_reg_set($right, D) || matches($right, u3)
	{
		opcode|"_"|size|"_d" $left, $right;
	}
	{
		$EVAL $count(D), $right;
		opcode|"_"|size|"_d" $left, $count;
	}

	$EVAL $dest, $left;
}

oper LSHIFT : void shifts("LSHIFT", "asl", "l");
oper LSHIFT : ptr shifts("LSHIFT", "asl", "l");
oper LSHIFT : ptr2 shifts("LSHIFT", "asl", "l");
oper LSHIFT : codeptr shifts("LSHIFT", "asl", "l");
oper LSHIFT : schar shifts("LSHIFT", "asl", "b");
oper LSHIFT : uchar shifts("LSHIFT", "asl", "b");
oper LSHIFT : sshort shifts("LSHIFT", "asl", "w");
oper LSHIFT : ushort shifts("LSHIFT", "asl", "w");
oper LSHIFT : slong shifts("LSHIFT", "asl", "l");
oper LSHIFT : ulong shifts("LSHIFT", "asl", "l");
oper LSHIFT : float nofloat;
oper LSHIFT : double nofloat;
oper LSHIFT : longdbl nofloat;

oper RSHIFT : void shifts("RSHIFT", "lsr", "l");
oper RSHIFT : ptr shifts("RSHIFT", "lsr", "l");
oper RSHIFT : ptr2 shifts("RSHIFT", "lsr", "l");
oper RSHIFT : codeptr shifts("RSHIFT", "lsr", "l");
oper RSHIFT : schar shifts("RSHIFT", "lsr", "b");
oper RSHIFT : uchar shifts("RSHIFT", "lsr", "b");
oper RSHIFT : sshort shifts("RSHIFT", "lsr", "w");
oper RSHIFT : ushort shifts("RSHIFT", "lsr", "w");
oper RSHIFT : slong shifts("RSHIFT", "lsr", "l");
oper RSHIFT : ulong shifts("RSHIFT", "lsr", "l");
oper RSHIFT : float nofloat;
oper RSHIFT : double nofloat;
oper RSHIFT : longdbl nofloat;

oper ARSHFT : void shifts("ARSHFT", "asr", "l");
oper ARSHFT : ptr shifts("ARSHFT", "asr", "l");
oper ARSHFT : ptr2 shifts("ARSHFT", "asr", "l");
oper ARSHFT : codeptr shifts("ARSHFT", "asr", "l");
oper ARSHFT : schar shifts("ARSHFT", "asr", "b");
oper ARSHFT : uchar shifts("ARSHFT", "asr", "b");
oper ARSHFT : sshort shifts("ARSHFT", "asr", "w");
oper ARSHFT : ushort shifts("ARSHFT", "asr", "w");
oper ARSHFT : slong shifts("ARSHFT", "asr", "l");
oper ARSHFT : ulong shifts("ARSHFT", "asr", "l");
oper ARSHFT : float nofloat;
oper ARSHFT : double nofloat;
oper ARSHFT : longdbl nofloat;

oper LSHEQ : void shifts("LSHEQ", "asl", "l");
oper LSHEQ : ptr shifts("LSHEQ", "asl", "l");
oper LSHEQ : ptr2 shifts("LSHEQ", "asl", "l");
oper LSHEQ : codeptr shifts("LSHEQ", "asl", "l");
oper LSHEQ : schar shifts("LSHEQ", "asl", "b");
oper LSHEQ : uchar shifts("LSHEQ", "asl", "b");
oper LSHEQ : sshort shifts("LSHEQ", "asl", "w");
oper LSHEQ : ushort shifts("LSHEQ", "asl", "w");
oper LSHEQ : slong shifts("LSHEQ", "asl", "l");
oper LSHEQ : ulong shifts("LSHEQ", "asl", "l");
oper LSHEQ : float nofloat;
oper LSHEQ : double nofloat;
oper LSHEQ : longdbl nofloat;

oper RSHEQ : void shifts("RSHEQ", "lsr", "l");
oper RSHEQ : ptr shifts("RSHEQ", "lsr", "l");
oper RSHEQ : ptr2 shifts("RSHEQ", "lsr", "l");
oper RSHEQ : codeptr shifts("RSHEQ", "lsr", "l");
oper RSHEQ : schar shifts("RSHEQ", "lsr", "b");
oper RSHEQ : uchar shifts("RSHEQ", "lsr", "b");
oper RSHEQ : sshort shifts("RSHEQ", "lsr", "w");
oper RSHEQ : ushort shifts("RSHEQ", "lsr", "w");
oper RSHEQ : slong shifts("RSHEQ", "lsr", "l");
oper RSHEQ : ulong shifts("RSHEQ", "lsr", "l");
oper RSHEQ : float nofloat;
oper RSHEQ : double nofloat;
oper RSHEQ : longdbl nofloat;

oper ARSEQ : void shifts("ARSEQ", "asr", "l");
oper ARSEQ : ptr shifts("ARSEQ", "asr", "l");
oper ARSEQ : ptr2 shifts("ARSEQ", "asr", "l");
oper ARSEQ : codeptr shifts("ARSEQ", "asr", "l");
oper ARSEQ : schar shifts("ARSEQ", "asr", "b");
oper ARSEQ : uchar shifts("ARSEQ", "asr", "b");
oper ARSEQ : sshort shifts("ARSEQ", "asr", "w");
oper ARSEQ : ushort shifts("ARSEQ", "asr", "w");
oper ARSEQ : slong shifts("ARSEQ", "asr", "l");
oper ARSEQ : ulong shifts("ARSEQ", "asr", "l");
oper ARSEQ : float nofloat;
oper ARSEQ : double nofloat;
oper ARSEQ : longdbl nofloat;

code compare(size)
? ! in_any_reg($left)
{
	$EVAL $temp(D), $left;
	$COMPARE $nodest, $temp, $right;
}
? (matches($right, s16) || matches($right, u16)
|| matches($right, s32) || matches($right, u32)) && ! in_reg_set($left, A)
{
	? $right == 0
	{
		"tst"|size $left;
	}
	{
		"cmp"|size|"_ea" $left, $right;
	}
}
{
	"cmp"|size|"_da" $left, $right;
}
	
code compare_reverse
{
    $COMPARE $dest, $right, $left;
}

oper COMPARE : void compare("_l");
oper COMPARE : ptr compare("_l");
oper COMPARE : ptr2 compare("_l");
oper COMPARE : codeptr compare("_l");
oper COMPARE : schar compare("_b");
oper COMPARE : uchar compare("_b");
oper COMPARE : sshort compare("_w");
oper COMPARE : ushort compare("_w");
oper COMPARE : slong compare("_l");
oper COMPARE : ulong compare("_l");
oper COMPARE : float nofloat;
oper COMPARE : double nofloat;
oper COMPARE : longdbl nofloat;

oper COMPARE_GT : void compare_reverse;
oper COMPARE_GT : ptr compare_reverse;
oper COMPARE_GT : ptr2 compare_reverse;
oper COMPARE_GT : codeptr compare_reverse;
oper COMPARE_GT : schar compare_reverse;
oper COMPARE_GT : uchar compare_reverse;
oper COMPARE_GT : sshort compare_reverse;
oper COMPARE_GT : ushort compare_reverse;
oper COMPARE_GT : slong compare_reverse;
oper COMPARE_GT : ulong compare_reverse;
oper COMPARE_GT : float nofloat;
oper COMPARE_GT : double nofloat;
oper COMPARE_GT : longdbl nofloat;

oper COMPARE_LE : void compare_reverse;
oper COMPARE_LE : ptr compare_reverse;
oper COMPARE_LE : ptr2 compare_reverse;
oper COMPARE_LE : codeptr compare_reverse;
oper COMPARE_LE : schar compare_reverse;
oper COMPARE_LE : uchar compare_reverse;
oper COMPARE_LE : sshort compare_reverse;
oper COMPARE_LE : ushort compare_reverse;
oper COMPARE_LE : slong compare_reverse;
oper COMPARE_LE : ulong compare_reverse;
oper COMPARE_LE : float nofloat;
oper COMPARE_LE : double nofloat;
oper COMPARE_LE : longdbl nofloat;

oper BREQ : void jump("jeq");
oper BREQ : ptr jump("jeq");
oper BREQ : ptr2 jump("jeq");
oper BREQ : codeptr jump("jeq");
oper BREQ : schar jump("jeq");
oper BREQ : uchar jump("jeq");
oper BREQ : sshort jump("jeq");
oper BREQ : ushort jump("jeq");
oper BREQ : slong jump("jeq");
oper BREQ : ulong jump("jeq");
oper BREQ : float nofloat;
oper BREQ : double nofloat;
oper BREQ : longdbl nofloat;

oper BRNE : void jump("jne");
oper BRNE : ptr jump("jne");
oper BRNE : ptr2 jump("jne");
oper BRNE : codeptr jump("jne");
oper BRNE : schar jump("jne");
oper BRNE : uchar jump("jne");
oper BRNE : sshort jump("jne");
oper BRNE : ushort jump("jne");
oper BRNE : slong jump("jne");
oper BRNE : ulong jump("jne");
oper BRNE : float nofloat;
oper BRNE : double nofloat;
oper BRNE : longdbl nofloat;

# $left > $right := $right < $left
#
# Invert operand order for these tests - see COMPARE_GT.
# For the M68000, we could have easily used "jhi" and "jgt", but
# we choose to demonstrate what is involved when reversing operands.
#
oper BRGT : void jump("jcs");
oper BRGT : ptr jump("jcs");
oper BRGT : ptr2 jump("jcs");
oper BRGT : codeptr jump("jcs");
oper BRGT : schar jump("jlt");
oper BRGT : uchar jump("jcs");
oper BRGT : sshort jump("jlt");
oper BRGT : ushort jump("jcs");
oper BRGT : slong jump("jlt");
oper BRGT : ulong jump("jcs");
oper BRGT : float nofloat;
oper BRGT : double nofloat;
oper BRGT : longdbl nofloat;

# $left < $right
#
# Note that the carry flag is a true borrow flag on the M68000.  On some
# CPUs the carry flag is strictly a carry flag, because the CPU performs
# subtraction by adding the 2's complement of one of the operands, ie.
# A - B = A + (-B); so for unsigned comparisons, we'd test for carry-clear.
#
oper BRLT : void jump("jcs");
oper BRLT : ptr jump("jcs");
oper BRLT : ptr2 jump("jcs");
oper BRLT : codeptr jump("jcs");
oper BRLT : schar jump("jlt");
oper BRLT : uchar jump("jcs");
oper BRLT : sshort jump("jlt");
oper BRLT : ushort jump("jcs");
oper BRLT : slong jump("jlt");
oper BRLT : ulong jump("jcs");
oper BRLT : float nofloat;
oper BRLT : double nofloat;
oper BRLT : longdbl nofloat;

# $left >= $right
oper BRGE : void jump("jcc");
oper BRGE : ptr jump("jcc");
oper BRGE : ptr2 jump("jcc");
oper BRGE : codeptr jump("jcc");
oper BRGE : schar jump("jge");
oper BRGE : uchar jump("jcc");
oper BRGE : sshort jump("jge");
oper BRGE : ushort jump("jcc");
oper BRGE : slong jump("jge");
oper BRGE : ulong jump("jcc");
oper BRGE : float nofloat;
oper BRGE : double nofloat;
oper BRGE : longdbl nofloat;

# $left <= $right := $right >= $left
#
# Invert operand order for these tests - see COMPARE_LE.
# For the M68000, we could have easily used "jls" and "jle", but
# we choose to demonstrate what is involved when reversing operands.
#
oper BRLE : void jump("jcc");
oper BRLE : ptr jump("jcc");
oper BRLE : ptr2 jump("jcc");
oper BRLE : codeptr jump("jcc");
oper BRLE : schar jump("jge");
oper BRLE : uchar jump("jcc");
oper BRLE : sshort jump("jge");
oper BRLE : ushort jump("jcc");
oper BRLE : slong jump("jge");
oper BRLE : ulong jump("jcc");
oper BRLE : float nofloat;
oper BRLE : double nofloat;
oper BRLE : longdbl nofloat;

code equals(operation, opcode)
? (in_reg_set($left, D) || mem_ref($left))
&& (matches($right, s32) || matches($right, u32))
{
	$EVAL : ulong $dest, 0;
	cmp_l_ea $left, $right;
	opcode $dest;
	neg_b $dest;
}
? ! in_reg_set($left, D)
{
	$EVAL $temp(D) : ulong, $left;
	"$"|operation $temp, $right;
}
? matches($right, zero) 
{
	$EVAL : ulong $dest, 0;
	tst_l $left;
	opcode $dest;
	neg_b $dest;
}
{
	$EVAL : ulong $dest, 0;
	cmp_l_da $left, $right;
	opcode $dest;
	neg_b $dest;
}
	
oper EQ : void equals("EQ", "seq");
oper EQ : ptr equals("EQ", "seq");
oper EQ : ptr2 equals("EQ", "seq");
oper EQ : codeptr equals("EQ", "seq");
oper EQ : schar equals("EQ", "seq");
oper EQ : uchar equals("EQ", "seq");
oper EQ : sshort equals("EQ", "seq");
oper EQ : ushort equals("EQ", "seq");
oper EQ : slong equals("EQ", "seq");
oper EQ : ulong equals("EQ", "seq");
oper EQ : float nofloat;
oper EQ : double nofloat;
oper EQ : longdbl nofloat;
	
oper NE : void equals("NE", "sne");
oper NE : ptr equals("NE", "sne");
oper NE : ptr2 equals("NE", "sne");
oper NE : codeptr equals("NE", "sne");
oper NE : schar equals("NE", "sne");
oper NE : uchar equals("NE", "sne");
oper NE : sshort equals("NE", "sne");
oper NE : ushort equals("NE", "sne");
oper NE : slong equals("NE", "sne");
oper NE : ulong equals("NE", "sne");
oper NE : float nofloat;
oper NE : double nofloat;
oper NE : longdbl nofloat;

code pre_post(base_operation)
{
	? oper(POSTINC) || oper(POSTDEC)
	{
		$EVAL $dest, $left;
	}

	"$"|base_operation $nodest, $left, $right;

	? oper(PREINC) || oper(PREDEC)
	{
		$EVAL $dest, $left;
	}
}

oper PREINC : void pre_post("ADDEQ");
oper PREINC : ptr pre_post("ADDEQ");
oper PREINC : ptr2 pre_post("ADDEQ");
oper PREINC : codeptr pre_post("ADDEQ");
oper PREINC : schar pre_post("ADDEQ");
oper PREINC : uchar pre_post("ADDEQ");
oper PREINC : sshort pre_post("ADDEQ");
oper PREINC : ushort pre_post("ADDEQ");
oper PREINC : slong pre_post("ADDEQ");
oper PREINC : ulong pre_post("ADDEQ");
oper PREINC : float nofloat;
oper PREINC : double nofloat;
oper PREINC : longdbl nofloat;

oper POSTINC : void pre_post("ADDEQ");
oper POSTINC : ptr pre_post("ADDEQ");
oper POSTINC : ptr2 pre_post("ADDEQ");
oper POSTINC : codeptr pre_post("ADDEQ");
oper POSTINC : schar pre_post("ADDEQ");
oper POSTINC : uchar pre_post("ADDEQ");
oper POSTINC : sshort pre_post("ADDEQ");
oper POSTINC : ushort pre_post("ADDEQ");
oper POSTINC : slong pre_post("ADDEQ");
oper POSTINC : ulong pre_post("ADDEQ");
oper POSTINC : float nofloat;
oper POSTINC : double nofloat;
oper POSTINC : longdbl nofloat;

oper PREDEC : void pre_post("SUBEQ");
oper PREDEC : ptr pre_post("SUBEQ");
oper PREDEC : ptr2 pre_post("SUBEQ");
oper PREDEC : codeptr pre_post("SUBEQ");
oper PREDEC : schar pre_post("SUBEQ");
oper PREDEC : uchar pre_post("SUBEQ");
oper PREDEC : sshort pre_post("SUBEQ");
oper PREDEC : ushort pre_post("SUBEQ");
oper PREDEC : slong pre_post("SUBEQ");
oper PREDEC : ulong pre_post("SUBEQ");
oper PREDEC : float nofloat;
oper PREDEC : double nofloat;
oper PREDEC : longdbl nofloat;

oper POSTDEC : void pre_post("SUBEQ");
oper POSTDEC : ptr pre_post("SUBEQ");
oper POSTDEC : ptr2 pre_post("SUBEQ");
oper POSTDEC : codeptr pre_post("SUBEQ");
oper POSTDEC : schar pre_post("SUBEQ");
oper POSTDEC : uchar pre_post("SUBEQ");
oper POSTDEC : sshort pre_post("SUBEQ");
oper POSTDEC : ushort pre_post("SUBEQ");
oper POSTDEC : slong pre_post("SUBEQ");
oper POSTDEC : ulong pre_post("SUBEQ");
oper POSTDEC : float nofloat;
oper POSTDEC : double nofloat;
oper POSTDEC : longdbl nofloat;

code cast_to_larger_type
{
	? tsize($src) <= 2 && (type(ushort) || type(ulong))
	{
		$EVAL $dest, 0;
	}

	$EVAL $dest, $src;

	? tsize($src) == 1 && (type(sshort) || type(slong))
	{
		ext_w $dest;
	}{}
	? tsize($src) <= 2 && type(slong)
	{
		ext_l $dest;
	}{}
}

code cast_to_char
? (type(schar) || type(uchar)) && tsize($src) == 1
{
	$EVAL $dest, $src;
}
? in_reg_set($src, D)
{
	move_b $dest, $src;
}
? mem_ref($src) 
{
	$ADDR $addr : ptr uchar, $src;
	load_b $dest, $mktree(*($addr + (tsize($src)-1)));
}
{
	$EVAL $temp(D), $src;
	move_b $dest, $temp;
}
	
code cast_to_short
? (type(sshort) || type(ushort)) && tsize($src) == 2
{
	$EVAL $dest, $src;
}
? in_reg_set($src, D)
{
	move_w $dest, $src;
}
? mem_ref($src) 
{
	$ADDR $addr : ptr uchar, $src;
	load_w $dest, $mktree(*($addr + (tsize($src)-2)));
}
{
	$EVAL $temp(D), $src;
	move_w $dest, $temp;
}

oper CAST_SCHAR : void cast_to_larger_type;
oper CAST_SCHAR : ptr cast_to_larger_type;
oper CAST_SCHAR : ptr2 cast_to_larger_type;
oper CAST_SCHAR : codeptr cast_to_larger_type;
oper CAST_SCHAR : schar cast_to_char;
oper CAST_SCHAR : uchar cast_to_char;
oper CAST_SCHAR : sshort cast_to_larger_type;
oper CAST_SCHAR : ushort cast_to_larger_type;
oper CAST_SCHAR : slong cast_to_larger_type;
oper CAST_SCHAR : ulong cast_to_larger_type;
oper CAST_SCHAR : float nofloat;
oper CAST_SCHAR : double nofloat;
oper CAST_SCHAR : longdbl nofloat;

oper CAST_UCHAR : void cast_to_larger_type;
oper CAST_UCHAR : ptr cast_to_larger_type;
oper CAST_UCHAR : ptr2 cast_to_larger_type;
oper CAST_UCHAR : codeptr cast_to_larger_type;
oper CAST_UCHAR : schar cast_to_char;
oper CAST_UCHAR : uchar cast_to_char;
oper CAST_UCHAR : sshort cast_to_larger_type;
oper CAST_UCHAR : ushort cast_to_larger_type;
oper CAST_UCHAR : slong cast_to_larger_type;
oper CAST_UCHAR : ulong cast_to_larger_type;
oper CAST_UCHAR : float nofloat;
oper CAST_UCHAR : double nofloat;
oper CAST_UCHAR : longdbl nofloat;

oper CAST_SSHORT : void cast_to_larger_type;
oper CAST_SSHORT : ptr cast_to_larger_type;
oper CAST_SSHORT : ptr2 cast_to_larger_type;
oper CAST_SSHORT : codeptr cast_to_larger_type;
oper CAST_SSHORT : schar cast_to_char;
oper CAST_SSHORT : uchar cast_to_char;
oper CAST_SSHORT : sshort cast_to_short;
oper CAST_SSHORT : ushort cast_to_short;
oper CAST_SSHORT : slong cast_to_larger_type;
oper CAST_SSHORT : ulong cast_to_larger_type;
oper CAST_SSHORT : float nofloat;
oper CAST_SSHORT : double nofloat;
oper CAST_SSHORT : longdbl nofloat;

oper CAST_USHORT : void cast_to_larger_type;
oper CAST_USHORT : ptr cast_to_larger_type;
oper CAST_USHORT : ptr2 cast_to_larger_type;
oper CAST_USHORT : codeptr cast_to_larger_type;
oper CAST_USHORT : schar cast_to_char;
oper CAST_USHORT : uchar cast_to_char;
oper CAST_USHORT : sshort cast_to_short;
oper CAST_USHORT : ushort cast_to_short;
oper CAST_USHORT : slong cast_to_larger_type;
oper CAST_USHORT : ulong cast_to_larger_type;
oper CAST_USHORT : float nofloat;
oper CAST_USHORT : double nofloat;
oper CAST_USHORT : longdbl nofloat;

oper CAST_SLONG : void cast_to_larger_type;
oper CAST_SLONG : ptr cast_to_larger_type;
oper CAST_SLONG : ptr2 cast_to_larger_type;
oper CAST_SLONG : codeptr cast_to_larger_type;
oper CAST_SLONG : schar cast_to_char;
oper CAST_SLONG : uchar cast_to_char;
oper CAST_SLONG : sshort cast_to_short;
oper CAST_SLONG : ushort cast_to_short;
oper CAST_SLONG : slong cast_to_larger_type;
oper CAST_SLONG : ulong cast_to_larger_type;
oper CAST_SLONG : float nofloat;
oper CAST_SLONG : double nofloat;
oper CAST_SLONG : longdbl nofloat;

oper CAST_ULONG : void cast_to_larger_type;
oper CAST_ULONG : ptr cast_to_larger_type;
oper CAST_ULONG : ptr2 cast_to_larger_type;
oper CAST_ULONG : codeptr cast_to_larger_type;
oper CAST_ULONG : schar cast_to_char;
oper CAST_ULONG : uchar cast_to_char;
oper CAST_ULONG : sshort cast_to_short;
oper CAST_ULONG : ushort cast_to_short;
oper CAST_ULONG : slong cast_to_larger_type;
oper CAST_ULONG : ulong cast_to_larger_type;
oper CAST_ULONG : float nofloat;
oper CAST_ULONG : double nofloat;
oper CAST_ULONG : longdbl nofloat;

oper CAST_FLOAT : void nofloat;
oper CAST_FLOAT : ptr nofloat;
oper CAST_FLOAT : ptr2 nofloat;
oper CAST_FLOAT : codeptr nofloat;
oper CAST_FLOAT : schar nofloat;
oper CAST_FLOAT : uchar nofloat;
oper CAST_FLOAT : sshort nofloat;
oper CAST_FLOAT : ushort nofloat;
oper CAST_FLOAT : slong nofloat;
oper CAST_FLOAT : ulong nofloat;
oper CAST_FLOAT : float nofloat;
oper CAST_FLOAT : double nofloat;
oper CAST_FLOAT : longdbl nofloat;

oper CAST_DOUBLE : void nofloat;
oper CAST_DOUBLE : ptr nofloat;
oper CAST_DOUBLE : ptr2 nofloat;
oper CAST_DOUBLE : codeptr nofloat;
oper CAST_DOUBLE : schar nofloat;
oper CAST_DOUBLE : uchar nofloat;
oper CAST_DOUBLE : sshort nofloat;
oper CAST_DOUBLE : ushort nofloat;
oper CAST_DOUBLE : slong nofloat;
oper CAST_DOUBLE : ulong nofloat;
oper CAST_DOUBLE : float nofloat;
oper CAST_DOUBLE : double nofloat;
oper CAST_DOUBLE : longdbl nofloat;

oper CAST_LONGDBL : void nofloat;
oper CAST_LONGDBL : ptr nofloat;
oper CAST_LONGDBL : ptr2 nofloat;
oper CAST_LONGDBL : codeptr nofloat;
oper CAST_LONGDBL : schar nofloat;
oper CAST_LONGDBL : uchar nofloat;
oper CAST_LONGDBL : sshort nofloat;
oper CAST_LONGDBL : ushort nofloat;
oper CAST_LONGDBL : slong nofloat;
oper CAST_LONGDBL : ulong nofloat;
oper CAST_LONGDBL : float nofloat;
oper CAST_LONGDBL : double nofloat;
oper CAST_LONGDBL : longdbl nofloat;

code alu_equate(operation)
{
    "$"|operation $temp(D), $left, $right;
    $ASGN $dest, $left, $temp;
}

code mult(size)
? type(slong) || type(ulong)
{
	$EXTERN lib = "_mul"|size|"l";

	$EVAL $reg(D[0]), $left;
	$EVAL $reg(D[1]), $right;

	jsr_long lib;

	$EVAL $dest, $reg(D[0]);
}
? ! in_reg_set($left, D)
{
	$EVAL $temp(D), $left;
	$MULT $dest, $temp, $right;
}
? mem_ref($right) || in_reg_set($right, D) || matches($right, u16)
{
	"mul"|size $left, $right;
	$EVAL $dest, $left;
}
{
	$EVAL $temp(D), $right;
	$MULT $dest, $left, $temp;
}

oper MULT : void mult("u");
oper MULT : ptr mult("u");
oper MULT : ptr2 mult("u");
oper MULT : codeptr mult("u");
oper MULT : schar mult("s");
oper MULT : uchar mult("u");
oper MULT : sshort mult("s");
oper MULT : ushort mult("u");
oper MULT : slong mult("s");
oper MULT : ulong mult("u");
oper MULT : float nofloat;
oper MULT : double nofloat;
oper MULT : longdbl nofloat;
 
oper MULEQ : void alu_equate("MULT");
oper MULEQ : ptr alu_equate("MULT");
oper MULEQ : ptr2 alu_equate("MULT");
oper MULEQ : codeptr alu_equate("MULT");
oper MULEQ : schar alu_equate("MULT");
oper MULEQ : uchar alu_equate("MULT");
oper MULEQ : sshort alu_equate("MULT");
oper MULEQ : ushort alu_equate("MULT");
oper MULEQ : slong alu_equate("MULT");
oper MULEQ : ulong alu_equate("MULT");
oper MULEQ : float nofloat;
oper MULEQ : double nofloat;
oper MULEQ : longdbl nofloat;

code div_rem(operation, size)
? type(ulong) || type(slong)
{
    $EXTERN lib = "_div"|size|"l";

    $EVAL $reg(D[0]), $left;
    $EVAL $reg(D[1]), $right;

	jsr_long lib;

    ? oper(REM) || oper(REMEQ)
    {
        $EVAL $dest, $reg(D[0]);
    }
    {
        $EVAL $dest, $reg(D[1]);
    }
}
? ! in_reg_set($left, D)
{
	$EVAL $temp(D), $left;
	"$"|operation $dest, $temp, $right;
}
? mem_ref($right) || in_reg_set($right, D) || matches($right, u16)
{
	"div"|size $left, $right;

	? oper(REM) || oper(REMEQ)
	{
		swap $left;
	}
	$EVAL : ushort $dest, $left;
}
{
	$EVAL $temp(D), $right;
	"$"|operation $dest, $left, $temp;
}

oper DIV : void div_rem("DIV", "u");
oper DIV : ptr div_rem("DIV", "u");
oper DIV : ptr2 div_rem("DIV", "u");
oper DIV : codeptr div_rem("DIV", "u");
oper DIV : schar div_rem("DIV", "s");
oper DIV : uchar div_rem("DIV", "u");
oper DIV : sshort div_rem("DIV", "s");
oper DIV : ushort div_rem("DIV", "u");
oper DIV : slong div_rem("DIV", "s");
oper DIV : ulong div_rem("DIV", "u");
oper DIV : float nofloat;
oper DIV : double nofloat;
oper DIV : longdbl nofloat;

oper REM : void div_rem("REM", "u");
oper REM : ptr div_rem("REM", "u");
oper REM : ptr2 div_rem("REM", "u");
oper REM : codeptr div_rem("REM", "u");
oper REM : schar div_rem("REM", "s");
oper REM : uchar div_rem("REM", "u");
oper REM : sshort div_rem("REM", "s");
oper REM : ushort div_rem("REM", "u");
oper REM : slong div_rem("REM", "s");
oper REM : ulong div_rem("REM", "u");
oper REM : float nofloat;
oper REM : double nofloat;
oper REM : longdbl nofloat;

oper DIVEQ : void alu_equate("DIV");
oper DIVEQ : ptr alu_equate("DIV");
oper DIVEQ : ptr2 alu_equate("DIV");
oper DIVEQ : codeptr alu_equate("DIV");
oper DIVEQ : schar alu_equate("DIV");
oper DIVEQ : uchar alu_equate("DIV");
oper DIVEQ : sshort alu_equate("DIV");
oper DIVEQ : ushort alu_equate("DIV");
oper DIVEQ : slong alu_equate("DIV");
oper DIVEQ : ulong alu_equate("DIV");
oper DIVEQ : float nofloat;
oper DIVEQ : double nofloat;
oper DIVEQ : longdbl nofloat;

oper REMEQ : void alu_equate("REM");
oper REMEQ : ptr alu_equate("REM");
oper REMEQ : ptr2 alu_equate("REM");
oper REMEQ : codeptr alu_equate("REM");
oper REMEQ : schar alu_equate("REM");
oper REMEQ : uchar alu_equate("REM");
oper REMEQ : sshort alu_equate("REM");
oper REMEQ : ushort alu_equate("REM");
oper REMEQ : slong alu_equate("REM");
oper REMEQ : ulong alu_equate("REM");
oper REMEQ : float nofloat;
oper REMEQ : double nofloat;
oper REMEQ : longdbl nofloat;

code blkmov
? tsize($left) <= 1
{
	store_b $left, $right;
	$ADDR $dest, $left;
}
? tsize($left) == 2
{
	store_w $left, $right;
	$ADDR $dest, $left;
}
? tsize($left) == 4
{
	store_l $left, $right;
	$ADDR $dest, $left;
}
{
	$LABEL loop;
	$LABEL test;

	$ADDR $to(A) : ptr ulong, $left;
	$ADDR $from(A) : ptr ulong, $right;

	# Copy multiples of 4 bytes.
	$EVAL $count(D) : ulong, $mkconst(tsize($left) / 4);

	jmp test;
loop:
	store_l $mktree(*$to : ptr ulong ++), $mktree(*$from : ptr ulong ++);
test:
	dbra $count, loop;

	# Should we copy a trailing word?
	? tsize($left) & 2
	{
		store_w $mktree(*$to : ptr ushort ++), $mktree(*$from : ptr ushort ++);
	}{}

	# Should we copy a trailing byte?
	? tsize($left) & 1
	{
		store_b $mktree(*$to : ptr uchar ++), $mktree(*$from : ptr uchar ++);
	}{}
	
	$ADDR $dest, $left;
}

oper BLKMOV : struct blkmov;

Back to Archelon's Home Page