Archelon Ischyros Archelon Inc.

Programming tools for your new processor

Texas Instruments TMS320C30/TMS320C40

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:

The file content shown below contains macros which must be expanded (using the widely available m4 macro preprocessor) to generate a CIF file for either the TMS320C30 or the TMS320C40 processor family.

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.



# @(#) c3x.cs 1.37 01/10/12 22:05:07 @(#) 
#
# CIF files for the C3X and C4X 
#
# Copyright (c) 1996-98, 2001 Archelon Inc. All Rights Reserved.
#

ifdef( `CPU', `', `define(`CPU', `C3X')' )
ifelse( CPU, `C3X', `define( `GPRS', `8' )', `define( `GPRS', `12' )')
ifelse( CPU, `C3X', `define( `LAST_GPR', `7' )', `define( `LAST_GPR', `11' )')

rom_init;
one_mem;
mau := 32;
code_locinc := 1;
data_locinc := 1;

int := long;
char := signed;
wchar := long;

data_pointer := long;
code_pointer := long;

double := float;

cost leaf = 0;

var push_size;
var frame_size;

# define macros to prevent floating point from being
# converted to IEEE format by the compiler
# because the C3x uses its own special floating point format.

expansion fmtf "\%f";
expansion fmtd "\%f";
expansion dataf "\tdef_float %1%n";
expansion datad "\tdef_double %1%n";

###

# 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.

# Extended-Precision Registers
# Stores either 32-bit integer or 40-bit floating point values.
#
# Float Format:
#	39:32	e		Exponent
#	31		s		Sign
#	30:0	f		Fraction
#
# Integer Format:
#	39:32			unchanged
#	31:0			signed/unsigned integer
#
# we declare these as 64-bits wide, to allow the compiler
# to do magical things when spilling and unspilling them

regset := R[ GPRS ]
	width = 64
	optype = int
	regtype = char, short, int, long, float
	expansion
		R = "r%2"
;

# Auxiliary Registers

regset := AR[8]
	width = 32
	optype = int, ptr
	regtype = char, short, int, long, ptr, codeptr
	expansion
		AR = "ar%2"
;

# Data Page Pointer
#	31:8			Reserved - always set 0
#	7:0				Page number of 64K words.

regset := DP
	width = 32
	optype = int
	regtype = int, long
	expansion
		DP = "dp"
;

# Index Registers

regset := IR[2]
	width = 32
	optype = int
	regtype = int, long
	expansion
		IR = "ir%2"
;

# Block-Size Register

regset := BK
	width = 32
	optype = int
	regtype = int, long
	expansion
		BK = "bk"
;

# Status Register
#	31:16			Reserved - undefined
#	15:14			Reserved - always reads 0
#	13		GIE		Global Interrupt Enable
#	12		CC		Cache Clear - write 1 invalidates caches, always reads 0.
#	11		CE		Cache Enable
#	10		CF		Cache Freeze
#	9				Reserved - always reads 0
#	8		RM		Repeat Mode flag
#	7		OVM		Overflow Mode flag
#	6		LUF		Latched floating point underflow flag.
#	5		LV		Latched overflow flag
#	4		UF		Floating point under flow.
#	3		N		Negative flag
#	2		Z		Zero flag
#	1		V		Overflow flag
#	0		C		Carry/barrow flag

regset := ST
	width = 32
	optype = int
	regtype = int, long
	expansion
		ST = "st"
;

# CPU/DMA Interrupt Enable Register
#	10:0			CPU interrupt enable bits
#	26:16			DMA interrupt enablea bits

regset := IE
	width = 32
	optype = int
	regtype = int, long
	expansion
		IE = "ie"
;

# CPU Interrupt Flag Register

regset := IF
	width = 32
	optype = int
	regtype = int, long
	expansion
		IF = "if"
;

# I/O Flags Register

regset := IOF
	width = 32
	optype = int
	regtype = int, long
	expansion
		IOF = "iof"
;

# Repeat Counter

regset := RC
	width = 32
	optype = int
	regtype = int, long
	expansion
		RC = "rc"
;

# Repeat Start Address Register

regset := RS
	width = 32
	optype = codeptr
	regtype = codeptr
	expansion
		RS = "rs"
;

# Repeat End Address Register

regset := RE
	width = 32
	optype = codeptr
	regtype = codeptr
	expansion
		RE = "re"
;

# Stack Pointer
# Always points to the last element pushed onto the stack.

regset := SP
	width = 32
	optype = ptr
	regtype = ptr
	expansion
		SP = "sp"
;

# Condition Codes

define( `MAX_CC', `7' )
define( `CC_C', `0' )
define( `CC_V', `1' )
define( `CC_Z', `2' )
define( `CC_N', `3' )
define( `CC_UF', `4' )
define( `CC_LV', `5' )
define( `CC_LUF', `6' )
define( `CC_ALL', `CC[0], CC[1], CC[2], CC[3], CC[4], CC[5], CC[6]' )

regset := CC [ MAX_CC ]
	width = 1;

spill writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
copy writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );

# Two machine words saved on stack : return address and frame pointer.
# The return address is pushed implicitly on the call 
# and popped implicitly on the return; 
# the frame pointer is pushed and popped explicitly by our 
# enter and exit code, and is therefore not accounted for here

stack
	push_args,
	no_stack_init,
	low_to_high,
	stkptr := SP,
	frameptr := AR[7],
	hw_farg_offset := 1,
	hw_lauto_offset := 1,
	push_pre_mod 
;

argreg := R[ 0 - 1 ];
argreg := AR[ 0 - 1 ];
scratch := R[ 0 - 4 ];
scratch := AR[ 0 - 4 ];
scratch := IR[ 0 - 1 ];
color := IR[ 0 - 1 ];
color := R[ 0 - LAST_GPR ];
color := AR[ 0 - 6 ];

define( `SCRATCHES', `writes( R[0], R[1], R[2], R[3], R[4], AR[0], AR[1], AR[2], AR[3], AR[4], IR[0], IR[1] )' )

### Operands

operand R			reg R;
operand AR			reg AR;
operand IX			reg IR;		  #note that we use IX, not IR */
operand BK			reg BK;
operand DP			reg DP;
operand IE			reg IE;
operand IF			reg IF;
operand IOF			reg IOF;
operand RC			reg RC;
operand RE			reg RE;
operand RS			reg RS;
operand ST			reg ST;
operand SP			reg SP;

operand zero		uconst 0;
operand pos_one		uconst 1;
operand neg_one		sconst -1;
operand p8			uconst 0 0xff;
operand m8			sconst -0xff -1;
operand u16			uconst 0 0xffff;
operand s16			sconst -0x7fff 0x7fff;
operand u32         uconst 0 0xffffffff;
operand s32         sconst -0x7fffffff 0x7fffffff;

operand f16			fconst -2.5600e2 2.5594e2;
operand f32			fconst -3.4028236e38 3.4028234e38;
operand f40			fconst -3.4028236691e38 3.4028236683e38;

operand data       	ptr;
operand code        codeptr;

# NOTE that direct addressing specifies the LSB 16 bits as part
# of the operand and that MSB are put into the page register.

operand addr		amode data expansion "@%2";
operand ldp_addr	amode data expansion "%2";

# Indirect and implied displacement of zero.

operand ind			amode AR expansion "*%1";

# Indirect and implied displacement of one.

operand pos_1		amode AR + pos_one expansion "*+%1(0x1)";
operand neg_1		amode AR + neg_one expansion "*-%1(0x1)";

# Indirect and displacement.

operand pos_n		amode AR + p8 expansion "*+%1(%2)";
operand neg_n		amode AR + m8 expansion "*-%1(-%2)";

# Indirect and index.

operand ind_ix		amode AR + IR expansion "*+%1(%3)";

# Indirect and implied adjustment of one.

operand preinc		amode ++ 1 AR expansion "*++%1";
operand predec		amode -- 1 AR expansion "*--%1";
operand postinc		amode AR ++ 1 expansion "*%1++";
operand postdec		amode AR -- 1 expansion "*%1--";

### Formats and Opcodes

format noargs;

opcode idle noargs;
opcode nop noargs;
opcode sigi noargs;
opcode swi noargs;

# Always

opcode retiu : ret noargs;

# Equality

opcode retieq : ret noargs reads( CC[CC_Z] );
opcode retine : ret noargs reads( CC[CC_Z] );

# Unsigned compare.

opcode retilo : ret noargs reads( CC[CC_C] );
opcode retils : ret noargs reads( CC[CC_C], CC[CC_Z] );
opcode retihi : ret noargs reads( CC[CC_C], CC[CC_Z] );
opcode retihs : ret noargs reads( CC[CC_C] );

# Signed compare.

opcode retilt : ret noargs reads( CC[CC_N] );
opcode retile : ret noargs reads( CC[CC_N], CC[CC_Z] );
opcode retigt : ret noargs reads( CC[CC_N], CC[CC_Z] );
opcode retige : ret noargs reads( CC[CC_N] );

# Condition flags.

opcode retic : ret noargs reads( CC[CC_C] );
opcode retinc : ret noargs reads( CC[CC_C] );
opcode retiz : ret noargs reads( CC[CC_Z] );
opcode retinz : ret noargs reads( CC[CC_Z] );
opcode retiv : ret noargs reads( CC[CC_V] );
opcode retinv : ret noargs reads( CC[CC_V] );
opcode retiuf : ret noargs reads( CC[CC_UF] );
opcode retinuf : ret noargs reads( CC[CC_UF] );
opcode retilv : ret noargs reads( CC[CC_LV] );
opcode retinlv : ret noargs reads( CC[CC_LV] );
opcode retiluf : ret noargs reads( CC[CC_LUF] );
opcode retinluf : ret noargs reads( CC[CC_LUF] );
opcode retizuf : ret noargs reads( CC[CC_Z], CC[CC_UF] );

# Always

opcode retsu : ret noargs;

# Equality

opcode retseq : ret noargs reads( CC[CC_Z] );
opcode retsne : ret noargs reads( CC[CC_Z] );

# Unsigned compare.

opcode retslo : ret noargs reads( CC[CC_C] );
opcode retsls : ret noargs reads( CC[CC_C], CC[CC_Z] );
opcode retshi : ret noargs reads( CC[CC_C], CC[CC_Z] );
opcode retshs : ret noargs reads( CC[CC_C] );

# Signed compare.

opcode retslt : ret noargs reads( CC[CC_N] );
opcode retsle : ret noargs reads( CC[CC_N], CC[CC_Z] );
opcode retsgt : ret noargs reads( CC[CC_N], CC[CC_Z] );
opcode retsge : ret noargs reads( CC[CC_N] );

# Condition flags.

opcode retsc : ret noargs reads( CC[CC_C] );
opcode retsnc : ret noargs reads( CC[CC_C] );
opcode retsz : ret noargs reads( CC[CC_Z] );
opcode retsnz : ret noargs reads( CC[CC_Z] );
opcode retsv : ret noargs reads( CC[CC_V] );
opcode retsnv : ret noargs reads( CC[CC_V] );
opcode retsuf : ret noargs reads( CC[CC_UF] );
opcode retsnuf : ret noargs reads( CC[CC_UF] );
opcode retslv : ret noargs reads( CC[CC_LV] );
opcode retsnlv : ret noargs reads( CC[CC_LV] );
opcode retsluf : ret noargs reads( CC[CC_LUF] );
opcode retsnluf : ret noargs reads( CC[CC_LUF] );
opcode retszuf : ret noargs reads( CC[CC_Z], CC[CC_UF] );



# immediate values are sign-extended

format ea_r
	src
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
		| addr | s16 | pos_n | neg_n | ind_ix | ind
	dest
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
;


# immediate values are NOT sign-extended

format ea_r_n
	src
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
		| addr | u16 | pos_n | neg_n | ind_ix | ind
	dest
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
;

opcode absi	ea_r
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode negb	ea_r
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode negi	ea_r
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode not ea_r_n
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );

opcode negf	ea_r
	writes( CC[CC_LUF], CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode norm	ea_r
	writes( CC[CC_LUF], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode rnd ea_r
	writes( CC[CC_LUF], CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );


# immediate values are sign-extended

format ea_r_2
	rsrc
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
		| addr | s16 | pos_n | neg_n | ind_ix | ind
	lsrcdest
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
;


# immediate values are NOT sign-extended

format ea_r_2n
	rsrc
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
		| addr | u16 | pos_n | neg_n | ind_ix | ind
	lsrcdest
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
;

opcode addc ea_r_2
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode addi ea_r_2
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode subb ea_r_2
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode subi ea_r_2
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode mpyi ea_r_2
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );

opcode andn ea_r_2n
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode and ea_r_2n
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode or ea_r_2n
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode xor ea_r_2n
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );

# If src shift count >= 0, then
#	left shift by count,
# else
#	right shift by -count.


opcode ash ea_r_2
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode lsh ea_r_2
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );

# We use the same format for the floating point instructions, relying on the
# fact that register set R is the only possible match for a float register.

opcode addf ea_r_2
	writes( CC[CC_LUF], CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode subf ea_r_2
	writes( CC[CC_LUF], CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode mpyf ea_r_2
	writes( CC[CC_LUF], CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );

format cmp_ea_r_2
	lsrc
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
		| addr | s16 | pos_n | neg_n | ind_ix | ind
	rsrc
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
;



# opcodes to do comparisons

opcode cmpi : compare cmp_ea_r_2
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode cmpi_da : compare cmp_ea_r_2
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );

opcode cmpf : compare cmp_ea_r_2
	writes( CC[CC_LUF], CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );

format rrr
	lsrc
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
	rsrc
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
	dest
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
;

format irr
	lsrc
		pos_1 | neg_1 | ind_ix | preinc | predec | postinc | postdec | ind
	rsrc
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
	dest
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
;

format rir
	lsrc
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
	rsrc
		pos_1 | neg_1 | ind_ix | preinc | predec | postinc | postdec | ind
	dest
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
;

format iir
	lsrc
		pos_1 | neg_1 | ind_ix | preinc | predec | postinc | postdec | ind
	rsrc
		pos_1 | neg_1 | ind_ix | preinc | predec | postinc | postdec | ind
	dest
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
;

opcode addc_rrr expansion "\taddc3 %3%5\n" rrr
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode addc_irr expansion "\taddc3 %3%5\n" irr
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode addc_rir expansion "\taddc3 %3%5\n" rir
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode addc_iir expansion "\taddc3 %3%5\n" iir
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );

opcode addi_rrr expansion "\taddi3 %3%5\n" rrr
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode addi_irr expansion "\taddi3 %3%5\n" irr
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode addi_rir expansion "\taddi3 %3%5\n" rir
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode addi_iir expansion "\taddi3 %3%5\n" iir
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );

opcode subb_rrr expansion "\tsubb3 %3%5\n" rrr
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode subb_irr expansion "\tsubb3 %3%5\n" irr
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode subb_rir expansion "\tsubb3 %3%5\n" rir
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode subb_iir expansion "\tsubb3 %3%5\n" iir
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );

opcode subi_rrr expansion "\tsubi3 %3%5\n" rrr
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode subi_irr expansion "\tsubi3 %3%5\n" irr
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode subi_rir expansion "\tsubi3 %3%5\n" rir
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode subi_iir expansion "\tsubi3 %3%5\n" iir
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );

opcode mpyi_rrr expansion "\tmpyi3 %3%5\n" rrr
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode mpyi_irr expansion "\tmpyi3 %3%5\n" irr
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode mpyi_rir expansion "\tmpyi3 %3%5\n" rir
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode mpyi_iir expansion "\tmpyi3 %3%5\n" iir
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );

opcode andn_rrr expansion "\tandn3 %3%5\n" rrr
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode andn_irr expansion "\tandn3 %3%5\n" irr
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode andn_rir expansion "\tandn3 %3%5\n" rir
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode andn_iir expansion "\tandn3 %3%5\n" iir
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );

opcode and_rrr expansion "\tand3 %3%5\n" rrr
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode and_irr expansion "\tand3 %3%5\n" irr
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode and_rir expansion "\tand3 %3%5\n" rir
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode and_iir expansion "\tand3 %3%5\n" iir
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );

opcode or_rrr expansion "\tor3 %3%5\n" rrr
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode or_irr expansion "\tor3 %3%5\n" irr
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode or_rir expansion "\tor3 %3%5\n" rir
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode or_iir expansion "\tor3 %3%5\n" iir
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );

opcode xor_rrr expansion "\txor3 %3%5\n" rrr
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode xor_irr expansion "\txor3 %3%5\n" irr
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode xor_rir expansion "\txor3 %3%5\n" rir
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode xor_iir expansion "\txor3 %3%5\n" iir
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );

opcode ash_rrr expansion "\tash3 %3%5\n" rrr
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode ash_irr expansion "\tash3 %3%5\n" irr
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode ash_rir expansion "\tash3 %3%5\n" rir
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode ash_iir expansion "\tash3 %3%5\n" iir
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );

opcode lsh_rrr expansion "\tlsh3 %3%5\n" rrr
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode lsh_irr expansion "\tlsh3 %3%5\n" irr
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode lsh_rir expansion "\tlsh3 %3%5\n" rir
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode lsh_iir expansion "\tlsh3 %3%5\n" iir
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );

opcode addf_rrr expansion "\taddf3 %3%5\n" rrr
	writes( CC[CC_LUF], CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode addf_irr expansion "\taddf3 %3%5\n" irr
	writes( CC[CC_LUF], CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode addf_rir expansion "\taddf3 %3%5\n" rir
	writes( CC[CC_LUF], CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode addf_iir expansion "\taddf3 %3%5\n" iir
	writes( CC[CC_LUF], CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );

opcode subf_rrr expansion "\tsubf3 %3%5\n" rrr
	writes( CC[CC_LUF], CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode subf_irr expansion "\tsubf3 %3%5\n" irr
	writes( CC[CC_LUF], CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode subf_rir expansion "\tsubf3 %3%5\n" rir
	writes( CC[CC_LUF], CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode subf_iir expansion "\tsubf3 %3%5\n" iir
	writes( CC[CC_LUF], CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );

opcode mpyf_rrr expansion "\tmpyf3 %3%5\n" rrr
	writes( CC[CC_LUF], CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode mpyf_irr expansion "\tmpyf3 %3%5\n" irr
	writes( CC[CC_LUF], CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode mpyf_rir expansion "\tmpyf3 %3%5\n" rir
	writes( CC[CC_LUF], CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode mpyf_iir expansion "\tmpyf3 %3%5\n" iir
	writes( CC[CC_LUF], CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );

format cmp_rrr
	lsrc
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
	rsrc
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
;

format cmp_irr
	lsrc
		pos_1 | neg_1 | ind_ix | preinc | predec | postinc | postdec | ind
	rsrc
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
;

format cmp_rir
	lsrc
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
	rsrc
		pos_1 | neg_1 | ind_ix | preinc | predec | postinc | postdec | ind
;

format cmp_iir
	lsrc
		pos_1 | neg_1 | ind_ix | preinc | predec | postinc | postdec | ind
	rsrc
		pos_1 | neg_1 | ind_ix | preinc | predec | postinc | postdec | ind
;

opcode cmpi_rrr : compare expansion "\tcmpi3 %3%5\n" rrr
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode cmpi_irr : compare expansion "\tcmpi3 %3%5\n" irr
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode cmpi_rir : compare expansion "\tcmpi3 %3%5\n" rir
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode cmpi_iir : compare expansion "\tcmpi3 %3%5\n" iir
	writes( CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );

opcode cmpf_rrr : compare expansion "\tcmpf3 %3%5\n" rrr
	writes( CC[CC_LUF], CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode cmpf_irr : compare expansion "\tcmpf3 %3%5\n" irr
	writes( CC[CC_LUF], CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode cmpf_rir : compare expansion "\tcmpf3 %3%5\n" rir
	writes( CC[CC_LUF], CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode cmpf_iir : compare expansion "\tcmpf3 %3%5\n" iir
	writes( CC[CC_LUF], CC[CC_LV], CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );

format ld_cond
	expansion "%1 %2, %3"
	string
		zero
	rsrc
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
		| addr | s16 | pos_n | neg_n | ind_ix | ind
	lsrcdest
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
;

opcode ldi_cond expansion "\tldi%3%5\n" ld_cond reads( CC_ALL );
opcode ldf_cond expansion "\tldf%3%5\n" ld_cond reads( CC_ALL );

format ld_ea_ri
	src
		R | s16 | s32 | u32
		| addr | pos_n | neg_n | ind_ix | ind
		| AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
	dest
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
;

format ld_ea_rf
	src
		R | s16 | s32 | u32
		| addr | pos_n | neg_n | ind_ix | ind
		| AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
	dest
		R
;

ifelse( CPU, `C3X', `', `opcode ldhi ld_ea_ri;' )

opcode ldi ld_ea_ri
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode lde ld_ea_rf;
opcode ldf ld_ea_rf
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode ldm ld_ea_rf;

format ld_imm
	src
		u32 | s32
	dest
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
;

opcode upper expansion "\tldp %3%5\n" ld_imm;
opcode lower expansion "\tldi %3%5\n" ld_imm
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );

format move
	src
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
	dest
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
;

opcode movei : nse expansion "\tldi %3%5\n" move
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode moveim : move expansion "\tldi %3%5\n" move
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode movef : nse expansion "\tldfu %3%5\n" move
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode movefm : move expansion "\tldfu %3%5\n" move
	writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );

format r_ea_2
	rsrc
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
	lsrc
		addr | pos_n | neg_n | ind_ix | ind
;

opcode sti r_ea_2;
opcode stf r_ea_2;

# All branch instructions are relative the start of the
# branch instruction (the current program counter) plus one.

expansion ifa ".ifa (%1 - . - 1), %3, %4\n";
expansion else ".else\n";
expansion endif ".endif\n";

format branch
	target src
		code
;

# Always

opcode bu : jump branch;

# Equality

opcode beq : cjump branch reads( CC[CC_Z] );
opcode bne : cjump branch reads( CC[CC_Z] );

# Unsigned compare.

opcode blo : cjump branch reads( CC[CC_C] );
opcode bls : cjump branch reads( CC[CC_C], CC[CC_Z] );
opcode bhi : cjump branch reads( CC[CC_C], CC[CC_Z] );
opcode bhs : cjump branch reads( CC[CC_C] );

# Signed compare.

opcode blt : cjump branch reads( CC[CC_N] );
opcode ble : cjump branch reads( CC[CC_N], CC[CC_Z] );
opcode bgt : cjump branch reads( CC[CC_N], CC[CC_Z] );
opcode bge : cjump branch reads( CC[CC_N] );

# Condition flags.

opcode bc : cjump branch reads( CC[CC_C] );
opcode bnc : cjump branch reads( CC[CC_C] );
opcode bz : cjump branch reads( CC[CC_Z] );
opcode bnz : cjump branch reads( CC[CC_Z] );
opcode bv : cjump branch reads( CC[CC_V] );
opcode bnv : cjump branch reads( CC[CC_V] );
opcode buf : cjump branch reads( CC[CC_UF] );
opcode bnuf : cjump branch reads( CC[CC_UF] );
opcode blv : cjump branch reads( CC[CC_LV] );
opcode bnlv : cjump branch reads( CC[CC_LV] );
opcode bluf : cjump branch reads( CC[CC_LUF] );
opcode bnluf : cjump branch reads( CC[CC_LUF] );
opcode bzuf : cjump branch reads( CC[CC_Z], CC[CC_UF] );

format jump
	target src
		code
;

# Always

opcode br : jump expansion "\t%if{%1;%2;\n\tbr %3;%2 %3}%5\n" jump : bu -32768 32767;

# Equality

opcode jeq : cjump expansion "\t%if{%1;%2;bne 1\n\tbr %3;%2 %3}%5\n"
	jump reads( CC[CC_Z] ) : beq -32768 32767;
opcode jne : cjump expansion "\t%if{%1;%2;beq 1\n\tbr %3;%2 %3}%5\n"
	jump reads( CC[CC_Z] ) : bne -32768 32767;

# Unsigned compare.

opcode jlo : cjump expansion "\t%if{%1;%2;bhs 1\n\tbr %3;%2 %3}%5\n"
	jump reads( CC[CC_C] ) : blo -32768 32767;
opcode jls : cjump expansion "\t%if{%1;%2;bhi 1\n\tbr %3;%2 %3}%5\n"
	jump reads( CC[CC_C], CC[CC_Z] ) : bls -32768 32767;
opcode jhi : cjump expansion "\t%if{%1;%2;bls 1\n\tbr %3;%2 %3}%5\n"
	jump reads( CC[CC_C], CC[CC_Z] ) : bhi -32768 32767;
opcode jhs : cjump expansion "\t%if{%1;%2;blo 1\n\tbr %3;%2 %3}%5\n"
	jump reads( CC[CC_C] ) : bhs -32768 32767;

# Signed compare.

opcode jlt : cjump expansion "\t%if{%1;%2;bge 1\n\tbr %3;%2 %3}%5\n"
	jump reads( CC[CC_N] ) : blt -32768 32767;
opcode jle : cjump expansion "\t%if{%1;%2;bgt 1\n\tbr %3;%2 %3}%5\n"
	jump reads( CC[CC_N], CC[CC_Z] ) : ble -32768 32767;
opcode jgt : cjump expansion "\t%if{%1;%2;ble 1\n\tbr %3;%2 %3}%5\n"
	jump reads( CC[CC_N], CC[CC_Z] ) : bgt -32768 32767;
opcode jge : cjump expansion "\t%if{%1;%2;blt 1\n\tbr %3;%2 %3}%5\n"
	jump reads( CC[CC_N] ) : bge -32768 32767;

# Condition flags.

opcode jc : cjump expansion "\t%if{%1;%2;bnc 1\n\tbr %3;%2 %3}%5\n"
	jump reads( CC[CC_C] ) : bc -32768 32767;
opcode jnc : cjump expansion "\t%if{%1;%2;bc 1\n\tbr %3;%2 %3}%5\n"
	jump reads( CC[CC_C] ) : bnc -32768 32767;
opcode jz : cjump expansion "\t%if{%1;%2;bnz 1\n\tbr %3;%2 %3}%5\n"
	jump reads( CC[CC_Z] ) : bz -32768 32767;
opcode jnz : cjump expansion "\t%if{%1;%2;bz 1\n\tbr %3;%2 %3}%5\n"
	jump reads( CC[CC_Z] ) : bnz -32768 32767;
opcode jv : cjump expansion "\t%if{%1;%2;bnv 1\n\tbr %3;%2 %3}%5\n"
	jump reads( CC[CC_V] ) : bv -32768 32767;
opcode jnv : cjump expansion "\t%if{%1;%2;bv 1\n\tbr %3;%2 %3}%5\n"
	jump reads( CC[CC_V] ) : bnv -32768 32767;
opcode juf : cjump expansion "\t%if{%1;%2;bnuf 1\n\tbr %3;%2 %3}%5\n"
	jump reads( CC[CC_UF] ) : buf -32768 32767;
opcode jnuf : cjump expansion "\t%if{%1;%2;buf 1\n\tbr %3;%2 %3}%5\n"
	jump reads( CC[CC_UF] ) : bnuf -32768 32767;
opcode jlv : cjump expansion "\t%if{%1;%2;bnlv 1\n\tbr %3;%2 %3}%5\n"
	jump reads( CC[CC_LV] ) : blv -32768 32767;
opcode jnlv : cjump expansion "\t%if{%1;%2;blv 1\n\tbr %3;%2 %3}%5\n"
	jump reads( CC[CC_LV] ) : bnlv -32768 32767;
opcode jluf : cjump expansion "\t%if{%1;%2;bnluf 1\n\tbr %3;%2 %3}%5\n"
	jump reads( CC[CC_LUF] ) : bluf -32768 32767;
opcode jnluf : cjump expansion "\t%if{%1;%2;bluf 1\n\tbr %3;%2 %3}%5\n"
	jump reads( CC[CC_LUF] ) : bnluf -32768 32767;

format call_ind
	src
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
;

opcode callu : call branch;
opcode call : call jump : callu -32768 32767;
opcode call_ind : call expansion "\tcallu %3%5\n" call_ind;
opcode call_long : call expansion "\tcall %3%5\n" jump;

format dbranch
	lsrc
		AR
	rsrc
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
		| code
;
	
# Always

opcode dbu : jump dbranch;

# Equality

opcode dbeq : cjump dbranch reads( CC[CC_Z] );
opcode dbne : cjump dbranch reads( CC[CC_Z] );

# Unsigned compare.

opcode dblo : cjump dbranch reads( CC[CC_C] );
opcode dbls : cjump dbranch reads( CC[CC_C], CC[CC_Z] );
opcode dbhi : cjump dbranch reads( CC[CC_C], CC[CC_Z] );
opcode dbhs : cjump dbranch reads( CC[CC_C] );

# Signed compare.

opcode dblt : cjump dbranch reads( CC[CC_N] );
opcode dble : cjump dbranch reads( CC[CC_N], CC[CC_Z] );
opcode dbgt : cjump dbranch reads( CC[CC_N], CC[CC_Z] );
opcode dbge : cjump dbranch reads( CC[CC_N] );

# Condition flags.

opcode dbc : cjump dbranch reads( CC[CC_C] );
opcode dbnc : cjump dbranch reads( CC[CC_C] );
opcode dbz : cjump dbranch reads( CC[CC_Z] );
opcode dbnz : cjump dbranch reads( CC[CC_Z] );
opcode dbv : cjump dbranch reads( CC[CC_V] );
opcode dbnv : cjump dbranch reads( CC[CC_V] );
opcode dbuf : cjump dbranch reads( CC[CC_UF] );
opcode dbnuf : cjump dbranch reads( CC[CC_UF] );
opcode dblv : cjump dbranch reads( CC[CC_LV] );
opcode dbnlv : cjump dbranch reads( CC[CC_LV] );
opcode dbluf : cjump dbranch reads( CC[CC_LUF] );
opcode dbnluf : cjump dbranch reads( CC[CC_LUF] );
opcode dbzuf : cjump dbranch reads( CC[CC_Z], CC[CC_UF] );

format fix_ea_r
	src
		R | addr | pos_n | neg_n | ind_ix | ind
	dest
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
;

opcode fix fix_ea_r;

format float_ea_r
	src
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
		| addr | s16 | pos_n | neg_n | ind_ix | ind
	dest
		R
;

opcode float float_ea_r;

format iack
	src
		addr | pos_n | neg_n | ind_ix | ind
;

opcode iack iack;

format ldp
	src
		ldp_addr
	dest
		DP
;

opcode ldp ldp;
	
format dst_reg
	dest
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
;

format srcdst_reg
	lsrcdest
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
;

opcode pop dst_reg writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );
opcode rol srcdst_reg writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode rolc srcdst_reg writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode ror srcdst_reg writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );
opcode rorc srcdst_reg writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V], CC[CC_C] );

format popf
	dest
		R
;

opcode popf popf writes( CC[CC_UF], CC[CC_N], CC[CC_Z], CC[CC_V] );

format src_reg
	src
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
;

opcode push src_reg;

format pushf
	src
		R
;

opcode pushf pushf;

format ea
	src
		R | AR | IX | DP | BK | ST | IE | IF | IOF | RC | RS | RE | SP
		| addr | s16 | pos_n | neg_n | ind_ix | ind
;

opcode rptb jump;
opcode rpts ea;

operand spilladdr		amode AR + p8 expansion "%1,%2";

format ldspill
	src spilladdr
	dest R
;

format stspill
	lsrc R
	rsrc spilladdr
;

expansion lds "*+%aref{,;1;%1}(%aref{,;2;%1}%cond{%2;%2}),%aref{,;3;%1}";
expansion sts "%aref{,;1;%1},*+%aref{,;2;%1}(%aref{,;3;%1}%cond{%2;%2})";

opcode ldspill
	expansion "\tldfu\t%lds{%3}\n\tldi\t%lds{%3;+1}%5\n"
	ldspill;

opcode stspill
	expansion "\tstf\t%sts{%3}\n\tsti\t%sts{%3;+1}%5\n"
	stspill;


### Code tables

code do_nothing
{
	$EVAL $dest, $left;
}

code enter
{
	$SET frame_size = $left;

	# Save frame pointer.

	push $reg(AR[7]);

	# Set new frame pointer.

	movei $reg(SP), $reg(AR[7]);
}

code exit
{
	# Restore the frame pointer

	pop $reg(AR[7]);
}

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

code nodouble
{
	$ERROR "Double support not implemented.";
}

code push
? type(float)
{
	$SET push_size = push_size + 1;
	pushf $left;
}
{
	$SET push_size = push_size + 1;
	push $left;
}

code pop
? type(float)
{
	$SET push_size = push_size - 1;
	popf $left;
}
{
	$SET push_size = push_size - 1;
	pop $left;
}

oper PUSH : ptr 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 push;
oper PUSH : double nodouble;

def_user_oper POP : unary side_effect;

oper POP : ptr 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 pop;
oper POP : double nodouble;

code save_regs
{


	# make room for local variables if any

	? is_abs_const( $right ) && ( frame_size > $right )
	{
		addi $mktree( frame_size - $right ), $reg(SP);
	}
	{}

	? must_preserve_reg(AR[0])
	{
		push $reg(AR[0]);
	}{}
	? must_preserve_reg(AR[1])
	{
		push $reg(AR[1]);
	}{}
	? must_preserve_reg(AR[2])
	{
		push $reg(AR[2]);
	}{}
	? must_preserve_reg(AR[3])
	{
		push $reg(AR[3]);
	}{}
	? must_preserve_reg(AR[4])
	{
		push $reg(AR[4]);
	}{}
	? must_preserve_reg(AR[5])
	{
		push $reg(AR[5]);
	}{}
	? must_preserve_reg(AR[6])
	{
		push $reg(AR[6]);
	}{}
	? must_preserve_reg(AR[7])
	{
		push $reg(AR[7]);
	}{}

	# First push the 32 LSBS (32:0) of the register followed
	# by the 32 MSBS (39:8) of the register.  (See restore_regs.)

	? must_preserve_reg(R[0])
	{
		push $reg(R[0]);
		pushf $reg(R[0]);
	}{}
	? must_preserve_reg(R[1])
	{
		push $reg(R[1]);
		pushf $reg(R[1]);
	}{}
	? must_preserve_reg(R[2])
	{
		push $reg(R[2]);
		pushf $reg(R[2]);
	}{}
	? must_preserve_reg(R[3])
	{
		push $reg(R[3]);
		pushf $reg(R[3]);
	}{}
	? must_preserve_reg(R[4])
	{
		push $reg(R[4]);
		pushf $reg(R[4]);
	}{}
	? must_preserve_reg(R[5])
	{
		push $reg(R[5]);
		pushf $reg(R[5]);
	}{}
	? must_preserve_reg(R[6])
	{
		push $reg(R[6]);
		pushf $reg(R[6]);
	}{}
	? must_preserve_reg(R[7])
	{
		push $reg(R[7]);
		pushf $reg(R[7]);
	}{}

ifelse( CPU, `C4X', `
	? must_preserve_reg(R[8])
	{
		push $reg(R[8]);
		pushf $reg(R[8]);
	}{}
	? must_preserve_reg(R[9])
	{
		push $reg(R[9]);
		pushf $reg(R[9]);
	}{}
	? must_preserve_reg(R[10])
	{
		push $reg(R[10]);
		pushf $reg(R[10]);
	}{}
	? must_preserve_reg(R[11])
	{
		push $reg(R[11]);
		pushf $reg(R[11]);
	}{}
' )

	? must_preserve_reg(IR[0])
	{
		push $reg(IR[0]);
	}{}
	? must_preserve_reg(IR[1])
	{
		push $reg(IR[1]);
	}{}

	? must_preserve_reg(BK)
	{
		push $reg(BK);
	}{}
	? must_preserve_reg(DP)
	{
		push $reg(DP);
	}{}
	? must_preserve_reg(IE)
	{
		push $reg(IE);
	}{}
	? must_preserve_reg(IF)
	{
		push $reg(IF);
	}{}
	? must_preserve_reg(IOF)
	{
		push $reg(IOF);
	}{}
	? must_preserve_reg(RC)
	{
		push $reg(RC);
	}{}
	? must_preserve_reg(RE)
	{
		push $reg(RE);
	}{}
	? must_preserve_reg(RS)
	{
		push $reg(RS);
	}{}
	? must_preserve_reg(ST)
	{
		push $reg(ST);
	}{}
	? must_preserve_reg(SP)
	{
		push $reg(SP);
	}{}

}

code restore_regs
{
	? must_preserve_reg(SP)
	{
		pop $reg(SP);
	}{}
	? must_preserve_reg(ST)
	{
		pop $reg(ST);
	}{}
	? must_preserve_reg(RS)
	{
		pop $reg(RS);
	}{}
	? must_preserve_reg(RE)
	{
		pop $reg(RE);
	}{}
	? must_preserve_reg(RC)
	{
		pop $reg(RC);
	}{}
	? must_preserve_reg(IOF)
	{
		pop $reg(IOF);
	}{}
	? must_preserve_reg(IF)
	{
		pop $reg(IF);
	}{}
	? must_preserve_reg(IE)
	{
		pop $reg(IE);
	}{}
	? must_preserve_reg(DP)
	{
		pop $reg(DP);
	}{}
	? must_preserve_reg(BK)
	{
		pop $reg(BK);
	}{}

	? must_preserve_reg(IR[1])
	{
		pop $reg(IR[1]);
	}{}
	? must_preserve_reg(IR[0])
	{
		pop $reg(IR[0]);
	}{}

	# First pop the 32 MSBs into 39:8 of the register; popf will
	# set 7:0 to zero; then pop 32 LSBs 31:0 of the register.

ifelse( CPU, `C4X', `
	? must_preserve_reg(R[11])
	{
		popf $reg(R[11]);
		pop $reg(R[11]);
	}{}
	? must_preserve_reg(R[10])
	{
		popf $reg(R[10]);
		pop $reg(R[10]);
	}{}
	? must_preserve_reg(R[9])
	{
		popf $reg(R[9]);
		pop $reg(R[9]);
	}{}
	? must_preserve_reg(R[8])
	{
		popf $reg(R[8]);
		pop $reg(R[8]);
	}{}
' )

	? must_preserve_reg(R[7])
	{
		popf $reg(R[7]);
		pop $reg(R[7]);
	}{}
	? must_preserve_reg(R[6])
	{
		popf $reg(R[6]);
		pop $reg(R[6]);
	}{}
	? must_preserve_reg(R[5])
	{
		popf $reg(R[5]);
		pop $reg(R[5]);
	}{}
	? must_preserve_reg(R[4])
	{
		popf $reg(R[4]);
		pop $reg(R[4]);
	}{}
	? must_preserve_reg(R[3])
	{
		popf $reg(R[3]);
		pop $reg(R[3]);
	}{}
	? must_preserve_reg(R[2])
	{
		popf $reg(R[2]);
		pop $reg(R[2]);
	}{}
	? must_preserve_reg(R[1])
	{
		popf $reg(R[1]);
		pop $reg(R[1]);
	}{}
	? must_preserve_reg(R[0])
	{
		popf $reg(R[0]);
		pop $reg(R[0]);
	}{}

	? must_preserve_reg(AR[7])
	{
		pop $reg(AR[7]);
	}{}
	? must_preserve_reg(AR[6])
	{
		pop $reg(AR[6]);
	}{}
	? must_preserve_reg(AR[5])
	{
		pop $reg(AR[5]);
	}{}
	? must_preserve_reg(AR[4])
	{
		pop $reg(AR[4]);
	}{}
	? must_preserve_reg(AR[3])
	{
		pop $reg(AR[3]);
	}{}
	? must_preserve_reg(AR[2])
	{
		pop $reg(AR[2]);
	}{}
	? must_preserve_reg(AR[1])
	{
		pop $reg(AR[1]);
	}{}
	? must_preserve_reg(AR[0])
	{
		pop $reg(AR[0]);
	}{}

	# remove space allocated for local variables, if any

	? is_abs_const($right) && (frame_size > $right)
	{
		subi $mktree( frame_size - $right ), $reg(SP);
	}
}

oper SAVE_REGS : void save_regs;
oper RESTORE_REGS : void restore_regs;

code noargs(opcode)
{
	opcode;
}

code jump(opcode)
{
    opcode $left;
}

code callind
? in_any_reg($left)
{
	call_ind $left;
}
{
	$EVAL $temp : ptr ulong, $left;
	call_ind $temp;
}

oper JUMP : void jump("br");

# switched call to call_long so we don't get .ifa generated for
# calls to external labels (which cannot be resolved by the assembler)
#   rpg 960307

oper CALLDIR : void jump("call_long");
oper CALLIND : void callind;
oper RET : void noargs("retsu");
oper RETI : void noargs("retiu");

code asgn(st,move)
? mem_ref($left) && ! (mem_ref($right) || in_any_reg($right))
{
	# Evaluate sub-expression NOW, before a possible need to set DP.

	$EVAL $temp, $right;
	$ASGN $dest, $left, $temp;
}
? mem_ref($left)
{
	st $right, $left;
	$EVAL $dest, $right;
}
? in_any_reg($left) && in_any_reg($right)
{
	? !in_same_set($left, $right)
	{
		move $right, $left;
	}
	{
		? type(float)
		{
			movefm $right, $left;
		}
		{
			moveim $right, $left;
		}
	}
	$EVAL	$dest,$right;
}
? in_any_reg( $left )
{
	$EVAL $left, $right;
	$EVAL $dest, $left;
}
{
	$ERROR "Unexpected case in code asgn";
}


# ASGN with type DOUBLE is a move or spill of a 40-bit register
# and $right must be a R register

code asgn_d 
? in_any_reg( $right ) && in_any_reg( $left )
{
	# this is a register-to-register move

	? in_reg_set( $right, "R" ) && in_reg_set( $left, "R" ) 
	{
		? ! in_same_reg( $right, $left )
		{

			# ldf moves all 40 bits of a GPR, except when the
			# exponent in the GPR is 0x80, in which case it
			# sets the destination to 0x80 00000000, so we use ldfu

			movef $right, $left;
		}
	}
	? !in_reg_set( $right, "R" ) 
	{
		$ERROR "move (double) not from an R register";
	}
	{
		$ERROR "move (double) not to an R register"
	}
}
? in_any_reg( $right ) 
{

	# this is register spill code

	? in_reg_set( $right, "R" ) 
	{
		# this is a 40-bit register spill; we use stf and sti

		stspill $right, $left;
	}
	{
		$ERROR "spill (double) not from an R register"
	}
}
{
	$ERROR "spill/move not from a register."
}

oper ASGN : ptr asgn("sti","movei");
oper ASGN : codeptr asgn("sti","movei");
oper ASGN : schar asgn("sti","movei");
oper ASGN : uchar asgn("sti","movei");
oper ASGN : sshort asgn("sti","movei");
oper ASGN : ushort asgn("sti","movei");
oper ASGN : slong asgn("sti","movei");
oper ASGN : ulong asgn("sti","movei");
oper ASGN : float asgn("stf","movef");
oper ASGN : double asgn_d;

code load(ld, move)
? in_any_reg($dest) && in_any_reg($src)
{
	? !in_same_set($src, $dest)
	{
		move $src, $dest;
	}
	{
		? type(float)
		{
			movefm $src, $dest;
		}
		{
			moveim $src, $dest;
		}
	}
}
? matches($src, s16)
{
	ldi $src, $dest;
}
? matches($src, f16)
{
	ldf $src, $dest;
}
? ! type(float) && is_abs_const($src)
{
ifelse( CPU, `C3X', `
	# C3X needs this slow code to load a large immediate value 
	# into a register

	ldi $src.msb, $dest;
	lsh 16, $dest;
	or $src.lsb, $dest;
', `
	# C4X can do this a bit faster than C3X

	ldhi $src.msb, $dest;
	or $src.lsb, $dest;
' )
}
? matches($src, addr)
{
	ld $src, $dest;
}
? is_float_const($src)
{
	ldf $src, $dest;
}
? mem_ref($src)
{
	ld $src, $dest;
}
{
	# Load sub-expression into register.

	$EVAL $temp, $src;
	$LOAD $dest, $temp;
}


# LOAD with type DOUBLE is an unspill of a 40-bit register
# and $dest must be a R register

code load_d
? in_any_reg( $dest )
{
	? in_reg_set( $dest, "R" )
	{
		# unspilling into a 40-bit register;
		# we load the float part first, since the
		# integer part will not clobber the exponent

		ldspill $left, $dest;
	}
	{
		$ERROR "load (double) not to an R register"
	}
}
{
	$ERROR "load (double) not to a register"
}


oper LOAD : ptr load("ldi", "movei");
oper LOAD : codeptr load("ldi", "movei");
oper LOAD : schar load("ldi", "movei");
oper LOAD : uchar load("ldi", "movei");
oper LOAD : sshort load("ldi", "movei");
oper LOAD : ushort load("ldi", "movei");
oper LOAD : slong load("ldi", "movei");
oper LOAD : ulong load("ldi", "movei");
oper LOAD : float load("ldf", "movef");
oper LOAD : double load_d;

code alu_equ(operation, opcode)
? ! in_any_reg($left)
{
	$EVAL $temp, $left;
	"$"|operation $dest, $temp, $right;
	$ASGN $nodest, $left, $temp;
}
{
	opcode $right, $left;
	$EVAL $dest, $left;
}

oper ADDEQ : ptr alu_equ("ADDEQ", "addi");
oper ADDEQ : codeptr alu_equ("ADDEQ", "addi");
oper ADDEQ : schar alu_equ("ADDEQ", "addi");
oper ADDEQ : uchar alu_equ("ADDEQ", "addi");
oper ADDEQ : sshort alu_equ("ADDEQ", "addi");
oper ADDEQ : ushort alu_equ("ADDEQ", "addi");
oper ADDEQ : slong alu_equ("ADDEQ", "addi");
oper ADDEQ : ulong alu_equ("ADDEQ", "addi");
oper ADDEQ : float alu_equ("ADDEQ", "addf");
oper ADDEQ : double nodouble;

oper SUBEQ : ptr alu_equ("SUBEQ", "subi");
oper SUBEQ : codeptr alu_equ("SUBEQ", "subi");
oper SUBEQ : schar alu_equ("SUBEQ", "subi");
oper SUBEQ : uchar alu_equ("SUBEQ", "subi");
oper SUBEQ : sshort alu_equ("SUBEQ", "subi");
oper SUBEQ : ushort alu_equ("SUBEQ", "subi");
oper SUBEQ : slong alu_equ("SUBEQ", "subi");
oper SUBEQ : ulong alu_equ("SUBEQ", "subi");
oper SUBEQ : float alu_equ("SUBEQ", "subf");
oper SUBEQ : double nodouble;

oper ANDEQ : ptr alu_equ("ANDEQ", "and");
oper ANDEQ : codeptr alu_equ("ANDEQ", "and");
oper ANDEQ : schar alu_equ("ANDEQ", "and");
oper ANDEQ : uchar alu_equ("ANDEQ", "and");
oper ANDEQ : sshort alu_equ("ANDEQ", "and");
oper ANDEQ : ushort alu_equ("ANDEQ", "and");
oper ANDEQ : slong alu_equ("ANDEQ", "and");
oper ANDEQ : ulong alu_equ("ANDEQ", "and");

oper EXOREQ : ptr alu_equ("EXOREQ", "xor");
oper EXOREQ : codeptr alu_equ("EXOREQ", "xor");
oper EXOREQ : schar alu_equ("EXOREQ", "xor");
oper EXOREQ : uchar alu_equ("EXOREQ", "xor");
oper EXOREQ : sshort alu_equ("EXOREQ", "xor");
oper EXOREQ : ushort alu_equ("EXOREQ", "xor");
oper EXOREQ : slong alu_equ("EXOREQ", "xor");
oper EXOREQ : ulong alu_equ("EXOREQ", "xor");

oper OREQ : ptr alu_equ("OREQ", "or");
oper OREQ : codeptr alu_equ("OREQ", "or");
oper OREQ : schar alu_equ("OREQ", "or");
oper OREQ : uchar alu_equ("OREQ", "or");
oper OREQ : sshort alu_equ("OREQ", "or");
oper OREQ : ushort alu_equ("OREQ", "or");
oper OREQ : slong alu_equ("OREQ", "or");
oper OREQ : ulong alu_equ("OREQ", "or");

code alu(opcode)
? in_any_reg($left) && in_any_reg($right)
{
	opcode|"_rrr" $right, $left, $dest;
}
? in_any_reg($left)
&& (matches($right, pos_1) || matches($right, neg_1)
   || matches($right, ind) || matches($right, ind_ix))
{
	opcode|"_irr" $right, $left, $dest;
}
? (matches($left, pos_1) || matches($left, neg_1)
   || matches($left, ind) || matches($left, ind_ix))
&& in_any_reg($right)
{
	opcode|"_rir" $right, $left, $dest;
}
? (matches($left, pos_1) || matches($left, neg_1)
   || matches($left, ind) || matches($left, ind_ix))
&& (matches($right, pos_1) || matches($right, neg_1)
   || matches($right, ind) || matches($right, ind_ix))
{
	opcode|"_iir" $right, $left, $dest;
}
{
	$EVAL $temp, $left;
	opcode $right, $temp;
	$EVAL $dest, $temp;
}

#
#	the following appeared to be a faster way to accomplish
#	the same thing, but it doesn't work if $right and $dest
#	are the same, or if $right contains a call that might 
#	clobber $dest.
#
#	it's safer to do it as above, and trust the register 
#	allocator to optimize those cases where the extra
#	step is not necessary
#
#	{
#		$EVAL $dest, $left;
#		opcode $right, $dest;
#	}


oper ADD : ptr alu("addi");
oper ADD : codeptr alu("addi");
oper ADD : schar alu("addi");
oper ADD : uchar alu("addi");
oper ADD : sshort alu("addi");
oper ADD : ushort alu("addi");
oper ADD : slong alu("addi");
oper ADD : ulong alu("addi");
oper ADD : float alu("addf");
oper ADD : double nodouble;

oper SUB : ptr alu("subi");
oper SUB : codeptr alu("subi");
oper SUB : schar alu("subi");
oper SUB : uchar alu("subi");
oper SUB : sshort alu("subi");
oper SUB : ushort alu("subi");
oper SUB : slong alu("subi");
oper SUB : ulong alu("subi");
oper SUB : float alu("subf");
oper SUB : double nodouble;

oper AND : ptr alu("and");
oper AND : codeptr alu("and");
oper AND : schar alu("and");
oper AND : uchar alu("and");
oper AND : sshort alu("and");
oper AND : ushort alu("and");
oper AND : slong alu("and");
oper AND : ulong alu("and");

oper EXOR : ptr alu("xor");
oper EXOR : codeptr alu("xor");
oper EXOR : schar alu("xor");
oper EXOR : uchar alu("xor");
oper EXOR : sshort alu("xor");
oper EXOR : ushort alu("xor");
oper EXOR : slong alu("xor");
oper EXOR : ulong alu("xor");

oper OR : ptr alu("or");
oper OR : codeptr alu("or");
oper OR : schar alu("or");
oper OR : uchar alu("or");
oper OR : sshort alu("or");
oper OR : ushort alu("or");
oper OR : slong alu("or");
oper OR : ulong alu("or");


# multiplication : mult_call
#	args: r[0-1]
#	result: r[0]
#	integer: clobbers: r[1]
#	float: this is not called for floats

opcode mult_call : call expansion "\tcall %3%5\n" jump
	reads( R[0], R[1] ) 
	writes( R[0], R[1] )
	SCRATCHES
	;


# division : div_call
#	args: r[0-1]
#	quotient: r[0]
#	integer : remainder: r[1]
#	float : clobbers: r[1]

opcode div_call : call expansion "\tcall %3%5\n" jump
	reads( R[0], R[1] ) 
	writes( R[0], R[1] )
	SCRATCHES
	;


code mult(sign)
ifelse( CPU, `C3X', ` #
# C3X Version
# The mpyi instruction does 24 * 24 bit unsigned multiply,
# so we have to call a routine for 32 * 32 bit multiply.
{
	$EXTERN lib = "_mul"|sign;

	$EVAL $tmp1, $left
	$EVAL $tmp2, $right
	$EVAL $reg(R[0]), $tmp1;
	$EVAL $reg(R[1]), $tmp2;

	mult_call lib;

	? oper( MULEQ )
	{
		$ASGN $dest, $left, $reg(R[0]);
	}
	{
		$EVAL $dest, $reg(R[0]);
	}
}
', `
# C4X Version
# The mpyi instruction does 32 * 32 bit unsigned multiply.
? ! in_any_reg($left)
{
	$EVAL $temp, $left;
	? oper( MULT ) 
	{
		$MULT $dest, $temp, $right;
	}
	{
		? side_effects( $left ) 
		{
			$ADDR $temp : ptr ulong, $left;
			$MULEQ $dest, $mktree( *$temp : ptr ulong ), $right;
		}
		? in_any_reg( $dest )
		{
			$MULEQ $dest, $temp, $right;
			$ASGN $nodest, $left, $dest;
		}
		{
			$MULEQ $temp, $temp, $right;
			$ASGN $nodest, $left, $temp;
		}
	}
}
? type(slong) || type(sshort) || type(schar)
{
	# Compute sign of product.

	 xor_rrr $left, $right, $sign;

	# Compute 32 LSBs of product.

	mpyi_rrr $left, $right, $temp;

	# Shift in the sign bit of the product.

	lsh 1, $temp;
	rol $sign;
	rorc $temp;
	? oper( MULEQ ) 
	{
		$ASGN $dest, $left, $temp;
	}
	{
		$EVAL $dest, $temp;
	}
}
{
	mpyi_rrr $left, $right, $temp;
	? oper( MULEQ )
	{
		$ASGN $dest, $left, $temp;
	}
	{
		$EVAL $dest, $temp;
	}
}
' )

oper MULEQ : ptr mult("u") rt_call;
oper MULEQ : codeptr mult("u") rt_call;
oper MULEQ : schar mult("s") rt_call;
oper MULEQ : uchar mult("u") rt_call;
oper MULEQ : sshort mult("s") rt_call;
oper MULEQ : ushort mult("u") rt_call;
oper MULEQ : slong mult("s") rt_call;
oper MULEQ : ulong mult("u") rt_call;
oper MULEQ : float alu_equ("MULEQ", "mpyf");
oper MULEQ : double nodouble;

oper MULT : ptr mult("u") rt_call;
oper MULT : codeptr mult("u") rt_call;
oper MULT : schar mult("s") rt_call;
oper MULT : uchar mult("u") rt_call;
oper MULT : sshort mult("s") rt_call;
oper MULT : ushort mult("u") rt_call;
oper MULT : slong mult("s") rt_call;
oper MULT : ulong mult("u") rt_call;
oper MULT : float alu("mpyf");
oper MULT : double nodouble;

code div_rem(sign)
{
	$EXTERN lib = "_div"|sign;

	$EVAL $tmp1, $left;
	$EVAL $tmp2, $right;
	$EVAL $reg(R[0]), $tmp1;
	$EVAL $reg(R[1]), $tmp2;

	div_call lib;

	? oper(REMEQ)
	{
		$ASGN $dest, $left, $reg(R[1]);
	}
	? oper(REM)
	{
		$EVAL $dest, $reg(R[1]);
	}
	? oper(DIVEQ)
	{
		$ASGN $dest, $left, $reg(R[0]);
	}
	{
		$EVAL $dest, $reg(R[0]);
	}
}

oper DIVEQ : ptr div_rem("u") rt_call;
oper DIVEQ : codeptr div_rem("u") rt_call;
oper DIVEQ : schar div_rem("s") rt_call;
oper DIVEQ : uchar div_rem("u") rt_call;
oper DIVEQ : sshort div_rem("s") rt_call;
oper DIVEQ : ushort div_rem("u") rt_call;
oper DIVEQ : slong div_rem("s") rt_call;
oper DIVEQ : ulong div_rem("u") rt_call;
oper DIVEQ : float div_rem("f") rt_call;
oper DIVEQ : double nodouble;

oper DIV : ptr div_rem("u") rt_call;
oper DIV : codeptr div_rem("u") rt_call;
oper DIV : schar div_rem("s") rt_call;
oper DIV : uchar div_rem("u") rt_call;
oper DIV : sshort div_rem("s") rt_call;
oper DIV : ushort div_rem("u") rt_call;
oper DIV : slong div_rem("s") rt_call;
oper DIV : ulong div_rem("u") rt_call;
oper DIV : float div_rem("f") rt_call;
oper DIV : double nodouble;

oper REMEQ : ptr div_rem("u") rt_call;
oper REMEQ : codeptr div_rem("u") rt_call;
oper REMEQ : schar div_rem("s") rt_call;
oper REMEQ : uchar div_rem("u") rt_call;
oper REMEQ : sshort div_rem("s") rt_call;
oper REMEQ : ushort div_rem("u") rt_call;
oper REMEQ : slong div_rem("s") rt_call;
oper REMEQ : ulong div_rem("u") rt_call;
# REMEQ undefined for float operands


oper REM : ptr div_rem("u") rt_call;
oper REM : codeptr div_rem("u") rt_call;
oper REM : schar div_rem("s") rt_call;
oper REM : uchar div_rem("u") rt_call;
oper REM : sshort div_rem("s") rt_call;
oper REM : ushort div_rem("u") rt_call;
oper REM : slong div_rem("s") rt_call;
oper REM : ulong div_rem("u") rt_call;
# REM undefined for float operands


code unary(opcode)
? matches($left, s16) || matches($left, f16)
{
	opcode $left, $dest;
}
? matches($left, f32) || is_abs_const($left)
{
	$LOAD $temp, $left;
	opcode $temp, $dest;
}
{
	opcode $left, $dest;
}
	
oper COMPL : ptr unary("not");
oper COMPL : codeptr unary("not");
oper COMPL : schar unary("not");
oper COMPL : uchar unary("not");
oper COMPL : sshort unary("not");
oper COMPL : ushort unary("not");
oper COMPL : slong unary("not");
oper COMPL : ulong unary("not");

oper UMINUS : ptr unary("negi");
oper UMINUS : codeptr unary("negi");
oper UMINUS : schar unary("negi");
oper UMINUS : uchar unary("negi");
oper UMINUS : sshort unary("negi");
oper UMINUS : ushort unary("negi");
oper UMINUS : slong unary("negi");
oper UMINUS : ulong unary("negi");
oper UMINUS : float unary("negf");
oper UMINUS : double nodouble;

code shifts_equ(operation)
? ! in_any_reg($left)
{
	$EVAL $temp, $left;
	"$"|operation $dest, $temp, $right;
	? oper(LSHEQ) || oper(RSHEQ) || oper(ARSEQ)
	{
		$ASGN $nodest, $left, $temp;
	}{}
}
? oper(LSHEQ)
{
	lsh $right, $left;
	$EVAL $dest, $left;
}
? oper(RSHEQ)
{
	# Positive count shift left, negative shift right.

	lsh $mktree(- $right), $left;
	$EVAL $dest, $left;
}
? oper(ARSEQ)
{
	# Positive count shift left, negative shift right.

	ash $mktree(- $right), $left;
	$EVAL $dest, $left;
}
{
	$ERROR "Unexpected case for shift-eq."
}

oper LSHEQ : ptr shifts_equ("LSHEQ");
oper LSHEQ : codeptr shifts_equ("LSHEQ");
oper LSHEQ : schar shifts_equ("LSHEQ");
oper LSHEQ : uchar shifts_equ("LSHEQ");
oper LSHEQ : sshort shifts_equ("LSHEQ");
oper LSHEQ : ushort shifts_equ("LSHEQ");
oper LSHEQ : slong shifts_equ("LSHEQ");
oper LSHEQ : ulong shifts_equ("LSHEQ");

oper RSHEQ : ptr shifts_equ("RSHEQ");
oper RSHEQ : codeptr shifts_equ("RSHEQ");
oper RSHEQ : schar shifts_equ("RSHEQ");
oper RSHEQ : uchar shifts_equ("RSHEQ");
oper RSHEQ : sshort shifts_equ("RSHEQ");
oper RSHEQ : ushort shifts_equ("RSHEQ");
oper RSHEQ : slong shifts_equ("RSHEQ");
oper RSHEQ : ulong shifts_equ("RSHEQ");

oper ARSEQ : ptr shifts_equ("ARSEQ");
oper ARSEQ : codeptr shifts_equ("ARSEQ");
oper ARSEQ : schar shifts_equ("ARSEQ");
oper ARSEQ : uchar shifts_equ("ARSEQ");
oper ARSEQ : sshort shifts_equ("ARSEQ");
oper ARSEQ : ushort shifts_equ("ARSEQ");
oper ARSEQ : slong shifts_equ("ARSEQ");
oper ARSEQ : ulong shifts_equ("ARSEQ");

code shifts_neq(operation)
? ! in_any_reg($left)
{
	$EVAL $temp, $left;
	"$"|operation $dest, $temp, $right;
}
? oper(LSHIFT)
{
	$EVAL $dest, $left;
	lsh $right, $dest;
}
? oper(RSHIFT)
{
	# Positive count shift left, negative shift right.

	$EVAL $dest, $left;
	lsh $mktree(- $right), $dest;
}
? oper(ARSHFT)
{
	# Positive count shift left, negative shift right.

	$EVAL $dest, $left;
	ash $mktree(- $right), $dest;
}
{
	$ERROR "Unexpected case for shift."
}

oper LSHIFT : ptr shifts_neq("LSHIFT");
oper LSHIFT : codeptr shifts_neq("LSHIFT");
oper LSHIFT : schar shifts_neq("LSHIFT");
oper LSHIFT : uchar shifts_neq("LSHIFT");
oper LSHIFT : sshort shifts_neq("LSHIFT");
oper LSHIFT : ushort shifts_neq("LSHIFT");
oper LSHIFT : slong shifts_neq("LSHIFT");
oper LSHIFT : ulong shifts_neq("LSHIFT");

oper RSHIFT : ptr shifts_neq("RSHIFT");
oper RSHIFT : codeptr shifts_neq("RSHIFT");
oper RSHIFT : schar shifts_neq("RSHIFT");
oper RSHIFT : uchar shifts_neq("RSHIFT");
oper RSHIFT : sshort shifts_neq("RSHIFT");
oper RSHIFT : ushort shifts_neq("RSHIFT");
oper RSHIFT : slong shifts_neq("RSHIFT");
oper RSHIFT : ulong shifts_neq("RSHIFT");

oper ARSHFT : ptr shifts_neq("ARSHFT");
oper ARSHFT : codeptr shifts_neq("ARSHFT");
oper ARSHFT : schar shifts_neq("ARSHFT");
oper ARSHFT : uchar shifts_neq("ARSHFT");
oper ARSHFT : sshort shifts_neq("ARSHFT");
oper ARSHFT : ushort shifts_neq("ARSHFT");
oper ARSHFT : slong shifts_neq("ARSHFT");
oper ARSHFT : ulong shifts_neq("ARSHFT");

code compari
? ! in_any_reg($left)
{
	$EVAL $temp, $left;
	$COMPARE $nodest, $temp, $right;
}
{
	cmpi $right, $left;
}

code comparf
? ! in_any_reg($left)
{
	$EVAL : float $temp, $left;
	$COMPARE : float $nodest, $temp, $right;
}
{
	cmpf $right, $left;
}

oper COMPARE : ptr compari;
oper COMPARE : codeptr compari;
oper COMPARE : schar compari;
oper COMPARE : uchar compari;
oper COMPARE : sshort compari;
oper COMPARE : ushort compari;
oper COMPARE : slong compari;
oper COMPARE : ulong compari;
oper COMPARE : float comparf;
oper COMPARE : double nodouble;

# $left == $right

oper BREQ : ptr 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 jump("jeq");
oper BREQ : double nodouble;

# $left != $right

oper BRNE : ptr 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 jump("jne");
oper BRNE : double nodouble;

# $left > $right

oper BRGT : ptr jump("jhi");
oper BRGT : codeptr jump("jhi");
oper BRGT : schar jump("jgt");
oper BRGT : uchar jump("jhi");
oper BRGT : sshort jump("jgt");
oper BRGT : ushort jump("jhi");
oper BRGT : slong jump("jgt");
oper BRGT : ulong jump("jhi");
oper BRGT : float jump("jgt");
oper BRGT : double nodouble;

# $left < $right

oper BRLT : ptr jump("jlo");
oper BRLT : codeptr jump("jlo");
oper BRLT : schar jump("jlt");
oper BRLT : uchar jump("jlo");
oper BRLT : sshort jump("jlt");
oper BRLT : ushort jump("jlo");
oper BRLT : slong jump("jlt");
oper BRLT : ulong jump("jlo");
oper BRLT : float jump("jlt");
oper BRLT : double nodouble;

# $left >= $right

oper BRGE : ptr jump("jhs");
oper BRGE : codeptr jump("jhs");
oper BRGE : schar jump("jge");
oper BRGE : uchar jump("jhs");
oper BRGE : sshort jump("jge");
oper BRGE : ushort jump("jhs");
oper BRGE : slong jump("jge");
oper BRGE : ulong jump("jhs");
oper BRGE : float jump("jge");
oper BRGE : double nodouble;

# $left <= $right

oper BRLE : ptr jump("jls");
oper BRLE : codeptr jump("jls");
oper BRLE : schar jump("jle");
oper BRLE : uchar jump("jls");
oper BRLE : sshort jump("jle");
oper BRLE : ushort jump("jls");
oper BRLE : slong jump("jle");
oper BRLE : ulong jump("jls");
oper BRLE : float jump("jle");
oper BRLE : double nodouble;

code test(type, test, opp)
{
	$COMPARE $nodest, $left, $right;
	ldi_cond test, 1, $dest;
	ldi_cond opp, 0, $dest;
}

oper EQ : ptr test("i", "eq", "ne");
oper EQ : codeptr test("i", "eq", "ne");
oper EQ : schar test("i", "eq", "ne");
oper EQ : uchar test("i", "eq", "ne");
oper EQ : sshort test("i", "eq", "ne");
oper EQ : ushort test("i", "eq", "ne");
oper EQ : slong test("i", "eq", "ne");
oper EQ : ulong test("i", "eq", "ne");
oper EQ : float test("f", "eq", "ne");
oper EQ : double nodouble;

oper NE : ptr test("i", "ne", "eq");
oper NE : codeptr test("i", "ne", "eq");
oper NE : schar test("i", "ne", "eq");
oper NE : uchar test("i", "ne", "eq");
oper NE : sshort test("i", "ne", "eq");
oper NE : ushort test("i", "ne", "eq");
oper NE : slong test("i", "ne", "eq");
oper NE : ulong test("i", "ne", "eq");
oper NE : float test("f", "ne", "eq");
oper NE : double nodouble;

oper GT : ptr test("i", "hi", "ls");
oper GT : codeptr test("i", "hi", "ls");
oper GT : schar test("i", "gt", "le");
oper GT : uchar test("i", "hi", "ls");
oper GT : sshort test("i", "gt", "le");
oper GT : ushort test("i", "hi", "ls");
oper GT : slong test("i", "gt", "le");
oper GT : ulong test("i", "hi", "ls");
oper GT : float test("f", "gt", "le");
oper GT : double nodouble;

oper LT : ptr test("i", "lo", "hs");
oper LT : codeptr test("i", "lo", "hs");
oper LT : schar test("i", "lt", "ge");
oper LT : uchar test("i", "lo", "hs");
oper LT : sshort test("i", "lt", "ge");
oper LT : ushort test("i", "lo", "hs");
oper LT : slong test("i", "lt", "ge");
oper LT : ulong test("i", "lo", "hs");
oper LT : float test("f", "lt", "ge");
oper LT : double nodouble;

oper GE : ptr test("i", "hs", "lo");
oper GE : codeptr test("i", "hs", "lo");
oper GE : schar test("i", "ge", "lt");
oper GE : uchar test("i", "hs", "lo");
oper GE : sshort test("i", "ge", "lt");
oper GE : ushort test("i", "hs", "lo");
oper GE : slong test("i", "ge", "lt");
oper GE : ulong test("i", "hs", "lo");
oper GE : float test("f", "ge", "lt");
oper GE : double nodouble;

oper LE : ptr test("i", "ls", "hi");
oper LE : codeptr test("i", "ls", "hi");
oper LE : schar test("i", "le", "gt");
oper LE : uchar test("i", "ls", "hi");
oper LE : sshort test("i", "le", "gt");
oper LE : ushort test("i", "ls", "hi");
oper LE : slong test("i", "le", "gt");
oper LE : ulong test("i", "ls", "hi");
oper LE : float test("f", "le", "gt");
oper LE : double nodouble;

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

	"$"|base_op $nodest, $left, $right;
	
	? oper(PREINC) || oper(PREDEC)
	{
		$EVAL $dest, $left;
	}
	{}
}

oper PREINC : ptr 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 pre_post("ADDEQ");
oper PREINC : double nodouble;

oper POSTINC : ptr 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 pre_post("ADDEQ");
oper POSTINC : double nodouble;

oper PREDEC : ptr 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 pre_post("SUBEQ");
oper PREDEC : double nodouble;

oper POSTDEC : ptr 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 pre_post("SUBEQ");
oper POSTDEC : double nodouble;


# typecasts from floating point


# cast float to unsigned long

code cast_float_to_unsigned
{
	$EVAL $t1, $left;
	fix $t1, $dest;
	negf $t1, $t2;
	fix $t2, $t2;
	negi $t2, $t2;
	ldi_cond "le", $t2, $dest;
}

# cast float to signed long:
# done with a run-time call

#	arg: r[0]
#	result: r[0]

#opcode cftl_call : call expansion "\tcall %3%5\n" jump
#	reads( R[0] ) 
#	writes( R[0] )
#	SCRATCHES
#	;

code cast_float_to_signed
{
#	$EXTERN lib = "_ftosi";
#
#	$EVAL $reg(R[0]), $left;
#	cftl_call lib
#	$EVAL $dest, $reg(R[0]);
	$EVAL $t1, $left;
	fix $t1, $t2;
	negf $t1, $t3;
	fix $t3, $t3;
	negi $t3, $t3;
	ldi_cond "le", $t3, $t2;
	$EVAL $dest, $t2;
}

# typecasts to floating point


# cast a signed int to float

code cast_long_to_float
? matches($left, s16)
{
	float $left, $dest;
}
? is_abs_const($left)
{
	$LOAD $temp, $left;
	float $temp, $dest;
}
{
	float $left, $dest;
}

# cast an unsigned int to float: 
# done with a run-time call

#	arg: r[0]
#	result: r[0]

#opcode cutf_call : call expansion "\tcall %3%5\n" jump
#	reads( R[0] ) 
#	writes( R[0] )
#	SCRATCHES
#	;

code cast_ulong_to_float
{
	$EVAL $t1, $left;
	$AND:ulong $t2, $t1, $mkconst(0x1);
	$RSHIFT:ulong $t3, $t1, $mkconst(0x1);
	float $t3, $t3;
	addf $t3, $t3;
	float $t2, $t2;
	addf $t2, $t3;
	$EVAL $dest, $t3;
#	$EXTERN lib = "_uitof";
#
#	$EVAL $reg(R[0]), $src;
#	cutf_call lib
#	$EVAL $dest, $reg(R[0]);
}

oper CAST_SCHAR : ptr do_nothing;
oper CAST_SCHAR : codeptr do_nothing;
oper CAST_SCHAR : schar do_nothing;
oper CAST_SCHAR : uchar do_nothing;
oper CAST_SCHAR : sshort do_nothing;
oper CAST_SCHAR : ushort do_nothing;
oper CAST_SCHAR : slong do_nothing;
oper CAST_SCHAR : ulong do_nothing;
oper CAST_SCHAR : float cast_long_to_float;
oper CAST_SCHAR : double nodouble;

oper CAST_UCHAR : ptr do_nothing;
oper CAST_UCHAR : codeptr do_nothing;
oper CAST_UCHAR : schar do_nothing;
oper CAST_UCHAR : uchar do_nothing;
oper CAST_UCHAR : sshort do_nothing;
oper CAST_UCHAR : ushort do_nothing;
oper CAST_UCHAR : slong do_nothing;
oper CAST_UCHAR : ulong do_nothing;
oper CAST_UCHAR : float cast_ulong_to_float;
oper CAST_UCHAR : double nodouble;

oper CAST_SSHORT : ptr do_nothing;
oper CAST_SSHORT : codeptr do_nothing;
oper CAST_SSHORT : schar do_nothing;
oper CAST_SSHORT : uchar do_nothing;
oper CAST_SSHORT : sshort do_nothing;
oper CAST_SSHORT : ushort do_nothing;
oper CAST_SSHORT : slong do_nothing;
oper CAST_SSHORT : ulong do_nothing;
oper CAST_SSHORT : float cast_long_to_float;
oper CAST_SSHORT : double nodouble;

oper CAST_USHORT : ptr do_nothing;
oper CAST_USHORT : codeptr do_nothing;
oper CAST_USHORT : schar do_nothing;
oper CAST_USHORT : uchar do_nothing;
oper CAST_USHORT : sshort do_nothing;
oper CAST_USHORT : ushort do_nothing;
oper CAST_USHORT : slong do_nothing;
oper CAST_USHORT : ulong do_nothing;
oper CAST_USHORT : float cast_ulong_to_float;
oper CAST_USHORT : double nodouble;

oper CAST_SLONG : ptr do_nothing;
oper CAST_SLONG : codeptr do_nothing;
oper CAST_SLONG : schar do_nothing;
oper CAST_SLONG : uchar do_nothing;
oper CAST_SLONG : sshort do_nothing;
oper CAST_SLONG : ushort do_nothing;
oper CAST_SLONG : slong do_nothing;
oper CAST_SLONG : ulong do_nothing;
oper CAST_SLONG : float cast_long_to_float;
oper CAST_SLONG : double nodouble;

oper CAST_ULONG : ptr do_nothing;
oper CAST_ULONG : codeptr do_nothing;
oper CAST_ULONG : schar do_nothing;
oper CAST_ULONG : uchar do_nothing;
oper CAST_ULONG : sshort do_nothing;
oper CAST_ULONG : ushort do_nothing;
oper CAST_ULONG : slong do_nothing;
oper CAST_ULONG : ulong do_nothing;
oper CAST_ULONG : float cast_ulong_to_float;
oper CAST_ULONG : double nodouble;

oper CAST_FLOAT : ptr cast_float_to_unsigned;
oper CAST_FLOAT : codeptr cast_float_to_unsigned;
oper CAST_FLOAT : schar cast_float_to_signed;
oper CAST_FLOAT : uchar cast_float_to_unsigned;
oper CAST_FLOAT : sshort cast_float_to_signed;
oper CAST_FLOAT : ushort cast_float_to_unsigned;
oper CAST_FLOAT : slong cast_float_to_signed;
oper CAST_FLOAT : ulong cast_float_to_unsigned;
oper CAST_FLOAT : float do_nothing;
oper CAST_FLOAT : double nodouble;

oper CAST_DOUBLE : ptr codeptr uchar ushort ulong nodouble;
oper CAST_DOUBLE : schar sshort slong nodouble;
oper CAST_DOUBLE : float double nodouble;

code blkmov
{
	$LABEL last_in_loop;

	$ADDR $to : ptr ulong, $left;
	$ADDR $from : ptr ulong, $right;

	# Nest loops by saving status and loop registers that may be in use.

	$PUSH : ulong $nodest, $reg(ST);
	$PUSH : ulong $nodest, $reg(RC);
	$PUSH : ulong $nodest, $reg(RE);
	$PUSH : ulong $nodest, $reg(RS);

	ldi $mktree( tsize($left) - 1 ), $reg(RC);
	rptb last_in_loop;
	ldi $mktree( *$from ), $temp : ulong;
	addi 1, $from;
	sti $temp, $mktree( *$to );
last_in_loop:
	addi 1, $to;

	$POP : ulong $nodest, $reg(RS);
	$POP : ulong $nodest, $reg(RE);
	$POP : ulong $nodest, $reg(RC);
	$POP : ulong $nodest, $reg(ST);

	$ADDR $dest, $left;
}

oper BLKMOV : struct blkmov;



Back to Archelon's Home Page