#
# PIC-18 Instruction Section
#   includes token definitions, macros, sub-constructors and instruction definitions
#

# The bytes are imported from the file in a 16-bit little-endian word format.  This, combined
# with the little-endian mode used by this language results in an unusual instruction format.
# The 16-bit instruction token uses what appears to be big endian bit numbering, whereas the 
# 32-bit instruction token uses somewhat of a hybrid bit numbering (see below).

# 16-bit instruction token uses big-endian bit numbering which agrees with
# instruction bit numbering with PIC documentation.
# 	15-14-13-12-11-10-9-8-7-6-5-4-3-2-1-0 
define token instr16(16)
	op4 =	(12,15)
	op5 =	(11,15)
	op6 =	(10,15)
	op8 =	(8,15)
	op12 =	(4,15)
	op16 =	(0,15)
	d =		(9,9)
	a =		(8,8)
	_xfsr =	(6,7)
	xfsr =	(6,7)
	f8_57 =	(5,7)
	f8 =	(0,7)
	freg =	(0,7)
	b3 =	(9,11)
	k8 =	(0,7)
	k6 =	(0,5)
	n11 =	(0,10) signed
	n8 =	(0,7)  signed
	s_0 =	(0,0)
;

# 32-bit instruction token uses a hybrid bit numbering:
#   Natural bit numbering (used by documentation):
#		31-30-29-28-27-26-25-24-23-22-21-20-19-18-17-16-15-14-13-12-11-10-09-08-07-06-05-04-03-02-01-00
#	Hybrid bit nubering used by token:
#		15-14-13-12-11-10-09-08-07-06-05-04-03-02-01-00-31-30-29-28-27-26-25-24-23-22-21-20-19-18-17-16
define token instr32(32)
	lop4 =	(12,15)
	lop5 =	(11,15)
	lop7 =	(9,15)
	lop8 =	(8,15)
	lop9 =	(7,15)
	lop10 =	(6,15)
	_fsr =	(4,5)
	fsr =	(4,5)
	kh =	(0,3)
	s_8 =	(8,8)
	n20_l =	(0,7)	# low order 8 bits of n20
	zs =	(0,6)
	fs_h =	(8,11)
	fs_57 =	(5,7)
	fs =	(0,11)
	fsreg =	(0,7)
	qual4 =	(28,31)
	qual8 =	(24,31)
	fd_h =	(24,27)
	fd_57 =	(21,23)
	fd =	(16,27)
	fdreg =	(16,23)
	kl =	(16,23)
	n20_h =	(16,27)  # high order 12 bits of n20
	zd =	(16,22)
;

attach variables [ freg fsreg fdreg ] [
	BAD		_		_		_		_		_		_		_		_		_		_		_		_		_		_		_
	_		_		_		_		_		_		_		_		_		_		_		_		_		_		_		_
	_		_		_		_		_		_		_		_		_		_		_		_		_		_		_		_
	_		_		_		_		_		_		_		_		_		_		_		_		_		_		_		_
	_		_		_		_		_		_		_		_		_		_		_		_		_		_		_		_
	_		_		_		_		_		_		_		_		_		_		_		_		_		_		_		_
	sfrF60	sfrF61	sfrF62	sfrF63	sfrF64	sfrF65	sfrF66	sfrF67	sfrF68	sfrF69	sfrF6A	RCSTA2	TXSTA2	TXREG2	RCREG2	SPBREG2
	CCP5CON	CCP5RL	CCPR5H	CCP4CON	CCPR4L	CCPR4H	T4CON	PR4		TMR4	sfrF79	sfrF7A	sfrF7B	sfrF7C	sfrF7D	sfrF7E	sfrF7F
	PORTA	PORTB	PORTC	PORTD	PORTE	PORTF	PORTG	PORTH	PORTJ	LATA	LATB	LATC	LATD	LATE	LATF	LATG
	LATH	LATJ	TRISA	TRISB	TRISC	TRISD	TRISE	TRISF	TRISG	TRISH	TRISJ	sfrF9B	MEMCON	PIE1	PIR1	IPR1
	PIE2	PIR2	IPR2	PIE3	PIR3	IPR3	EECON1	EECON2	EEDATA	EEADR	EEADRH	RCSTA1	TXSTA1	TXREG1	RCREG1	SPBRG1
	PSPCON	T3CON	TMR3L	TMR3H	CMCON	CVRCON	sfrFB6	CCP3CON	CCP3RL	CCP3RH	CCP2CON	CCPR2L	CCPR2H	CCP1CON	CCPR1L	CCPR1H
	ADCON2	ADCON1	ADCON0	ADRESL	ADRESH	SSPCON2	SSPCON1	SSPSTAT	SSPADD	SSPBUF	T2CON	PR2		TMR2	T1CON	TMR1L	TMR1H
	RCON	WDTCON	LVDCON	OSCCON	sfrFD4	T0CON	TMR0L	TMR0H	STATUS	FSR2L	FSR2H	PLUSW2	PREINC2	POSTDEC2 POSTINC2 INDF2
	BSR		FSR1L	FSR1H	PLUSW1	PREINC1	POSTDEC1 POSTINC1 INDF1	WREG	FSR0L	FSR0H	PLUSW0	PREINC0	POSTDEC0 POSTINC0 INDF0
	INTCON3	INTCON2	INTCON	PRODL	PRODH	TABLAT	TBLPTRL	TBLPTRH	TBLPTRU	PCL		PCLATH	PCLATU	STKPTR	TOSL	TOSH	TOSU 
];

# attach variables [ _fsr _xfsr ] [ FSR0 FSR1 FSR2 _ ];

#
# Special PIC-18 Operations
#

# If stack is full (SP==0x1F) STKFUL gets set, if STVREN is set the processor will reset
#define pcodeop CheckStackFull;

# If stack is empty (SP==0) STKUNF gets set, if STVREN is set the processor will reset
#define pcodeop CheckStackUnderflow;

# Return a decimal adjusted value for the value provided (see DAW instruction)
define pcodeop decimalAdjust;

# Perform a Master Clear Reset
define pcodeop reset;

define pcodeop clearWatchDogTimer;

define pcodeop sleep;

#
# MACROS
#

macro setResultFlags(result) {
	N = (result s< 0);
	Z = (result == 0);
}

macro setAddCOverflowFlag(op1,op2) {
	local tmpC = C & 1;
	OV = scarry(op1,tmpC) || scarry(op2,op1 + tmpC);
}

macro setAddCCarryFlag(op1,op2) {
	local tmpC = C & 1;
	C = carry(op1,tmpC) || carry(op2,op1 + tmpC);
}

macro setAddCDigitCarryFlag(op1,op2) {
	# op1 and op2 are assumed to be 8-bit values
	local tmp1 = op1 << 4;
	local tmp2 = op2 << 4;
	local tmpDC = DC & 1;
	DC = carry(tmp1,tmpDC) || carry(tmp2,tmp1 + tmpDC);
}

macro setAddCFlags(op1,op2) {
	setAddCCarryFlag(op1,op2);
	setAddCDigitCarryFlag(op1,op2);
	setAddCOverflowFlag(op1,op2);
}

macro setAddFlags(op1,op2) {
	C = carry(op1,op2);
	DC = carry(op1<<4,op2<<4);
	OV = scarry(op1,op2);
}

macro setSubtractCOverflowFlag(op1,op2) {
	local notC = ~(C & 1);
	OV = sborrow(op1,notC) || sborrow(op2,op1 - notC);
}

macro setSubtractCCarryFlag(op1,op2) {
	local notC = ~(C & 1);
	C = (op1 < notC) || (op2 < (op1 - notC));
}

macro setSubtractCDigitCarryFlag(op1,op2) {
	# op1 and op2 are assumed to be 8-bit values
	local notDC = ~(DC & 1);
	local tmp1 = op1 << 4;
	local tmp2 = op2 << 4;
	local tmp3 = (tmp1 - notDC) << 4;
	DC = (tmp1 < notDC) || (tmp2 < tmp3);
}

macro setSubtractCFlags(op1,op2) {
	setSubtractCCarryFlag(op1,op2);
	setSubtractCDigitCarryFlag(op1,op2);
	setSubtractCOverflowFlag(op1,op2);
}

macro setSubtractFlags(op1,op2) {
	# op1 and op2 are assumed to be 8-bit values
	# NOTE:  carry flag is SET if there is NO borrow
	C = (op1 >= op2);
	DC = ((op1<<4) < (op2<<4));
	OV = sborrow(op1,op2);
}

macro push(val) {	# TODO: Uncertain about this !!
#	CheckStackFull();
	*[HWSTACK]:4 STKPTR = val;
	STKPTR = STKPTR + 4;
}

macro pop(rval) {	# TODO: Uncertain about this !!
#	CheckStackUnderflow();
	STKPTR = STKPTR - 4;
	rval = *[HWSTACK]:4 STKPTR;
}

#
# SUB-CONSTRUCTORS
#

# PC register write - instruction must set PCLATH/PCL and perform branch operation
pcl: "PC" 			is a=0 & f8=0xf9				{ export PCL; }

# STATUS register
status: freg 		is a=0 & f8=0xd8 & freg				{ export STATUS; }

# File Register specified by an 8-bit file register offset within Bank specified by BSR
fREGLoc: f8	is a=1 & f8									{ # (Banked mode) 
	addr:2 = (zext(BSR) << 8) + f8; 
	export *[DATA]:1 addr; 
}

# File Register specified by an 8-bit offset within "Access Bank"
# The partitioning of the access bank may differ between specific PIC18 chips.
# Some partition at 0x80 (i.e., PIC18Cxx2), while more advanced PIC18 chips partition at 0x60 (i.e., PIC18Fxx20).
# This implementation partitions the access bank mode at 0x60.
#
#  TODO: Need to add another language PIC18C that has the SFR start at 0xf80
#
fREGLoc: f8			is a=0 & f8_57=0x0 & f8					{ export *[DATA]:1 f8; } # 0x00-0x1f   (Access mode)
fREGLoc: f8			is a=0 & f8_57=0x1 & f8					{ export *[DATA]:1 f8; } # 0x20-0x3f   (Access mode)
fREGLoc: f8			is a=0 & f8_57=0x2 & f8					{ export *[DATA]:1 f8; } # 0x40-0x5f   (Access mode)
fREGLoc: freg		is a=0 & freg							{ export freg; }		 # 0xf60-0xfff (Access mode)

# TOSL - access mirrored into stack space using STKPTR
fREGLoc: freg			is a=0 & f8=0xfd & freg				{
	addr:1 = STKPTR + 1;
	export *[HWSTACK]:1 addr;
}

# TOSH - access mirrored into stack space using STKPTR
fREGLoc: freg			is a=0 & f8=0xfe & freg				{
	addr:1 = STKPTR + 2;
	export *[HWSTACK]:1 addr;
}

# TOSU - access mirrored into stack space using STKPTR
fREGLoc: freg			is a=0 & f8=0xff & freg				{
	addr:1 = STKPTR + 3;
	export *[HWSTACK]:1 addr;
}

# Indirect File Register access - INDF0
fREGLoc: freg		is a=0 & f8=0xef & freg					{ 
	addr:2 = FSR0;
	export *[DATA]:1 addr; 
}

# Indirect File Register access - INDF1
fREGLoc: freg		is a=0 & f8=0xe7 & freg					{
	addr:2 = FSR1;
	export *[DATA]:1 addr; 
}

# Indirect File Register access - INDF2
fREGLoc: freg		is a=0 & f8=0xdf & freg					{ 
	addr:2 = FSR2;
	export *[DATA]:1 addr; 
}

# Post-increment File Register access - POSTINC0
fREGLoc: freg		is a=0 & f8=0xee & freg					{ 
	addr:2 = FSR0;
	FSR0 = FSR0 + 1;
	export *[DATA]:1 addr; 
}

# Post-increment File Register access - POSTINC1
fREGLoc: freg		is a=0 & f8=0xe6 & freg					{
	addr:2 = FSR1;
	FSR1 = FSR1 + 1;
	export *[DATA]:1 addr; 
}

# Post-increment File Register access - POSTINC2
fREGLoc: freg		is a=0 & f8=0xde & freg					{ 
	addr:2 = FSR2;
	FSR2 = FSR2 + 1;
	export *[DATA]:1 addr; 
}

# Post-decrement File Register access - POSTDEC0
fREGLoc: freg		is a=0 & f8=0xed & freg					{ 
	addr:2 = FSR0;
	FSR0 = FSR0 - 1;
	export *[DATA]:1 addr; 
}

# Post-decrement File Register access - POSTDEC1
fREGLoc: freg		is a=0 & f8=0xe5 & freg					{
	addr:2 = FSR1;
	FSR1 = FSR1 - 1;
	export *[DATA]:1 addr; 
}

# Post-decrement File Register access - POSTDEC2
fREGLoc: freg		is a=0 & f8=0xdd & freg					{ 
	addr:2 = FSR2;
	FSR2 = FSR2 - 1;
	export *[DATA]:1 addr; 
}

# Pre-increment File Register access - PREINC0
fREGLoc: freg		is a=0 & f8=0xec & freg					{ 
	FSR0 = FSR0 + 1;
	addr:2 = FSR0;
	export *[DATA]:1 addr; 
}

# Pre-increment File Register access - PREINC1
fREGLoc: freg		is a=0 & f8=0xe4 & freg					{
	FSR1 = FSR1 + 1;
	addr:2 = FSR1;
	export *[DATA]:1 addr; 
}

# Pre-increment File Register access - PREINC2
fREGLoc: freg		is a=0 & f8=0xdc & freg					{ 
	FSR2 = FSR2 + 1;
	addr:2 = FSR2;
	export *[DATA]:1 addr; 
}

# Pre-increment w/WREG-Offset File Register access - PLUSW0
fREGLoc: freg		is a=0 & f8=0xeb & freg					{ 
	FSR0 = FSR0 + 1;
	addr:2 = FSR0 + sext(WREG);
	export *[DATA]:1 addr; 
}

# Pre-increment w/WREG-Offset File Register access - PLUSW1
fREGLoc: freg		is a=0 & f8=0xe3 & freg					{
	FSR1 = FSR1 + 1;
	addr:2 = FSR1 + sext(WREG);
	export *[DATA]:1 addr; 
}

# Pre-increment w/WREG-Offset File Register access - PLUSW2
fREGLoc: freg		is a=0 & f8=0xdb & freg					{ 
	FSR2 = FSR2 + 1;
	addr:2 = FSR2 + sext(WREG);
	export *[DATA]:1 addr; 
}

# Direct File register data
srcREG: fREGLoc		is fREGLoc									{ export fREGLoc; }

# PCL read - latch PC into PCL, PCLATH, and PCLATU
srcREG: "PC"		is a=0 & f8=0xf9						{
	PCLAT = inst_start;
	export PCL; 
}

# Destination register (either srcREG or WREG)
destREG: "0"	is d=0											{ export WREG; }
destREG: "1"	is d=1 & srcREG									{ export srcREG; }
#destREG: "1"	is d=1 & f8=0xf9						{ 
#	# Storing to PCL must write the PC using both the stored PCL (PC<7:0>), PCLATH (PC<15:8>) and PCLATU (PC<21:16>)
#	# The ADDWF and MOVWF definitions below have a specific case to handle this write to PCL
#	export PCL; 
#}

# Destination operand representation (w: W register is destination; f: specified fREG is destination)
D: "w"		is d=0										{ }
D: "f"		is d=1										{ }

# Source File Registers specified by a 12-bit absolute offsets within 32-bit instriction
srcREG32: fs	is fs											{ export *[DATA]:1 fs; } # 0x000-0xeff
srcREG32: fs	is fs_h=0xf & fs_57=0 & fs						{ export *[DATA]:1 fs; } # 0xf00-0xf1f
srcREG32: fs	is fs_h=0xf & fs_57=1 & fs						{ export *[DATA]:1 fs; } # 0xf20-0xf3f
srcREG32: fs	is fs_h=0xf & fs_57=2 & fs						{ export *[DATA]:1 fs; } # 0xf40-0xf5f
srcREG32: fsreg	is fs_h=0xf & fsreg								{ export fsreg; } 		 # 0xf60-0xfff

# PCL read - latch PC into PCL, PCLATH, and PCLATU
srcREG32: "PC" is fs=0xff9										{
	PCLAT = inst_start;
	export PCL; 
}

# TOSL - access mirrored into stack space using STKPTR
srcREG32: fsreg			is fs=0xffd & fsreg				{
	addr:1 = STKPTR + 1;
	export *[HWSTACK]:1 addr;
}

# TOSH - access mirrored into stack space using STKPTR
srcREG32: fsreg			is fs=0xffe & fsreg				{
	addr:1 = STKPTR + 2;
	export *[HWSTACK]:1 addr;
}

# TOSU - access mirrored into stack space using STKPTR
srcREG32: fsreg			is fs=0xfff & fsreg				{
	addr:1 = STKPTR + 3;
	export *[HWSTACK]:1 addr;
}

# Indirect File Register access - INDF0
srcREG32: fsreg		is fs=0xfef & fsreg					{ 
	addr:2 = FSR0;
	export *[DATA]:1 addr; 
}

# Indirect File Register access - INDF1
srcREG32: fsreg		is fs=0xfe7 & fsreg					{
	addr:2 = FSR1;
	export *[DATA]:1 addr; 
}

# Indirect File Register access - INDF2
srcREG32: fsreg		is fs=0xfdf & fsreg					{ 
	addr:2 = FSR2;
	export *[DATA]:1 addr; 
}

# Post-increment File Register access - POSTINC0
srcREG32: fsreg		is fs=0xfee & fsreg					{ 
	addr:2 = FSR0;
	FSR0 = FSR0 + 1;
	export *[DATA]:1 addr; 
}

# Post-increment File Register access - POSTINC1
srcREG32: fsreg		is fs=0xfe6 & fsreg					{
	addr:2 = FSR1;
	FSR1 = FSR1 + 1;
	export *[DATA]:1 addr; 
}

# Post-increment File Register access - POSTINC2
srcREG32: fsreg		is fs=0xfde & fsreg					{ 
	addr:2 = FSR2;
	FSR2 = FSR2 + 1;
	export *[DATA]:1 addr; 
}

# Post-decrement File Register access - POSTDEC0
srcREG32: fsreg		is fs=0xfed & fsreg					{ 
	addr:2 = FSR0;
	FSR0 = FSR0 - 1;
	export *[DATA]:1 addr; 
}

# Post-decrement File Register access - POSTDEC1
srcREG32: fsreg		is fs=0xfe5 & fsreg					{
	addr:2 = FSR1;
	FSR1 = FSR1 - 1;
	export *[DATA]:1 addr; 
}

# Post-decrement File Register access - POSTDEC2
srcREG32: fsreg		is fs=0xfdd & fsreg					{ 
	addr:2 = FSR2;
	FSR2 = FSR2 - 1;
	export *[DATA]:1 addr; 
}

# Pre-increment File Register access - PREINC0
srcREG32: fsreg		is fs=0xfec & fsreg					{ 
	FSR0 = FSR0 + 1;
	addr:2 = FSR0;
	export *[DATA]:1 addr; 
}

# Pre-increment File Register access - PREINC1
srcREG32: fsreg		is fs=0xfe4 & fsreg					{
	FSR1 = FSR1 + 1;
	addr:2 = FSR1;
	export *[DATA]:1 addr; 
}

# Pre-increment File Register access - PREINC2
srcREG32: fsreg		is fs=0xfdc & fsreg					{ 
	FSR2 = FSR2 + 1;
	addr:2 = FSR2;
	export *[DATA]:1 addr; 
}

# Pre-increment w/WREG-Offset File Register access - PLUSW0
srcREG32: fsreg		is fs=0xfeb & fsreg					{ 
	FSR0 = FSR0 + 1;
	addr:2 = FSR0 + sext(WREG);
	export *[DATA]:1 addr; 
}

# Pre-increment w/WREG-Offset File Register access - PLUSW1
srcREG32: fsreg		is fs=0xfe3 & fsreg					{
	FSR1 = FSR1 + 1;
	addr:2 = FSR1 + sext(WREG);
	export *[DATA]:1 addr; 
}

# Pre-increment w/WREG-Offset File Register access - PLUSW2
srcREG32: fsreg		is fs=0xfdb & fsreg					{ 
	FSR2 = FSR2 + 1;
	addr:2 = FSR2 + sext(WREG);
	export *[DATA]:1 addr; 
}

# Destination File Registers specified by a 12-bit absolute offsets within 32-bit instriction
destREG32: fd	is fd											{ export *[DATA]:1 fd; } # 0x000-0xeff
destREG32: fd	is fd_h=0xf & fd_57=0 & fd						{ export *[DATA]:1 fd; } # 0xf00-0xf1f
destREG32: fd	is fd_h=0xf & fd_57=1 & fd						{ export *[DATA]:1 fd; } # 0xf20-0xf3f
destREG32: fd	is fd_h=0xf & fd_57=2 & fd						{ export *[DATA]:1 fd; } # 0xf40-0xf5f
destREG32: fdreg is fd_h=0xf & fdreg							{ export fdreg; } 		 # 0xf60-0xfff

#destREG32: "PCL"	is fd=0xff9						{ 
#	# Storing to PCL must write the PC using both the stored PCL (PC<7:0>), PCLATH (PC<15:8>) and PCLATU (PC<21:16>)
#	# The MOVFF and MOVSF definitions below have a specific case to handle this write to PCL
#	export PCL; 
#}

# TOSL - access mirrored into stack space using STKPTR
destREG32: fdreg			is fd=0xffd & fdreg				{
	addr:1 = STKPTR + 1;
	export *[HWSTACK]:1 addr;
}

# TOSH - access mirrored into stack space using STKPTR
destREG32: fdreg			is fd=0xffe & fdreg				{
	addr:1 = STKPTR + 2;
	export *[HWSTACK]:1 addr;
}

# TOSU - access mirrored into stack space using STKPTR
destREG32: fdreg			is fd=0xfff & fdreg				{
	addr:1 = STKPTR + 3;
	export *[HWSTACK]:1 addr;
}

# Indirect File Register access - INDF0
destREG32: fdreg		is fd=0xfef & fdreg					{ 
	addr:2 = FSR0;
	export *[DATA]:1 addr; 
}

# Indirect File Register access - INDF1
destREG32: fdreg		is fd=0xfe7 & fdreg					{
	addr:2 = FSR1;
	export *[DATA]:1 addr; 
}

# Indirect File Register access - INDF2
destREG32: fdreg		is fd=0xfdf & fdreg					{ 
	addr:2 = FSR2;
	export *[DATA]:1 addr; 
}

# Post-increment File Register access - POSTINC0
destREG32: fdreg		is fd=0xfee & fdreg					{ 
	addr:2 = FSR0;
	FSR0 = FSR0 + 1;
	export *[DATA]:1 addr; 
}

# Post-increment File Register access - POSTINC1
destREG32: fdreg		is fd=0xfe6 & fdreg					{
	addr:2 = FSR1;
	FSR1 = FSR1 + 1;
	export *[DATA]:1 addr; 
}

# Post-increment File Register access - POSTINC2
destREG32: fdreg		is fd=0xfde & fdreg					{ 
	addr:2 = FSR2;
	FSR2 = FSR2 + 1;
	export *[DATA]:1 addr; 
}

# Post-decrement File Register access - POSTDEC0
destREG32: fdreg		is fd=0xfed & fdreg					{ 
	addr:2 = FSR0;
	FSR0 = FSR0 - 1;
	export *[DATA]:1 addr; 
}

# Post-decrement File Register access - POSTDEC1
destREG32: fdreg		is fd=0xfe5 & fdreg					{
	addr:2 = FSR1;
	FSR1 = FSR1 - 1;
	export *[DATA]:1 addr; 
}

# Post-decrement File Register access - POSTDEC2
destREG32: fdreg		is fd=0xfdd & fdreg					{ 
	addr:2 = FSR2;
	FSR2 = FSR2 - 1;
	export *[DATA]:1 addr; 
}

# Pre-increment File Register access - PREINC0
destREG32: fdreg		is fd=0xfec & fdreg					{ 
	FSR0 = FSR0 + 1;
	addr:2 = FSR0;
	export *[DATA]:1 addr; 
}

# Pre-increment File Register access - PREINC1
destREG32: fdreg		is fd=0xfe4 & fdreg					{
	FSR1 = FSR1 + 1;
	addr:2 = FSR1;
	export *[DATA]:1 addr; 
}

# Pre-increment File Register access - PREINC2
destREG32: fdreg		is fd=0xfdc & fdreg					{ 
	FSR2 = FSR2 + 1;
	addr:2 = FSR2;
	export *[DATA]:1 addr; 
}

# Pre-increment w/WREG-Offset File Register access - PLUSW0
destREG32: fdreg		is fd=0xfeb & fdreg					{ 
	FSR0 = FSR0 + 1;
	addr:2 = FSR0 + sext(WREG);
	export *[DATA]:1 addr; 
}

# Pre-increment w/WREG-Offset File Register access - PLUSW1
destREG32: fdreg		is fd=0xfe3 & fdreg					{
	FSR1 = FSR1 + 1;
	addr:2 = FSR1 + sext(WREG);
	export *[DATA]:1 addr; 
}

# Pre-increment w/WREG-Offset File Register access - PLUSW2
destREG32: fdreg		is fd=0xfdb & fdreg					{ 
	FSR2 = FSR2 + 1;
	addr:2 = FSR2 + sext(WREG);
	export *[DATA]:1 addr; 
}

# Absolute 20-bit instruction location constructed from nl:8 and nh:12
absAddr21: nLoc	is n20_h & n20_l 	[ nLoc  = (n20_h << 9) + (n20_l << 1); ] { export *[CODE]:2 nLoc; }

# Relative 8-bit and 11-bit instruction offsets
relAddr8: nLoc	is n8				[ nLoc = inst_next + (n8 << 1); ] 	{ export *[CODE]:2 nLoc; }
relAddr11: nLoc is n11				[ nLoc = inst_next + (n11 << 1); ] 	{ export *[CODE]:2 nLoc; }

# Skip instruction address (could jump into middle of 32-bit instruction which appears as NOP)
skipInst: inst_skip	is op16	[ inst_skip = inst_next + 2; ]		{export *[CODE]:2 inst_skip; }

# Immediate Data (Literal operation)
imm6: "#"k6		is k6											{ export *[const]:1 k6; }
imm8: "#"k8		is k8											{ export *[const]:1 k8; }
imm12: "#"kVal	is kl & kh	[ kVal = (kh << 8) + kl; ]			{ export *[const]:2 kVal; }

# Bit identifier
bit: "#"b3		is b3											{ export *[const]:1 b3; }

# FSR Register (see LFSR)
FSRn: "FSR0"	is fsr=0 & _fsr									{ export FSR0; }
FSRn: "FSR1"	is fsr=1 & _fsr									{ export FSR1; }
FSRn: "FSR2"	is fsr=2 & _fsr									{ export FSR2; }

# FSR Register (see Extended Instructions)
xFSRn: "FSR0"	is xfsr=0 & _xfsr								{ export FSR0; }
xFSRn: "FSR1"	is xfsr=1 & _xfsr								{ export FSR1; }
xFSRn: "FSR2"	is xfsr=2 & _xfsr								{ export FSR2; }

# Source and Destination FSR2 Indexed Operand
ZS: zs"[FSR2]"		is zs										{ fsLoc:2 = FSR2 + zs; export *[DATA]:1 fsLoc; }
ZD: zd"[FSR2]"		is zd										{ fdLoc:2 = FSR2 + zd; export *[DATA]:1 fdLoc; }

# Access Bank mode
A: "ACCESS"			is a=0										{ }
A: "BANKED"			is a=1										{ }

#
# BYTE-ORIENTED FILE REGISTER OPERATIONS
#

:ADDWF srcREG, D, A		is op6=0x09 & srcREG & A & destREG & D	{
	#  0010 01da ffff ffff
	#  0010 0100 0000 0000  ->  ADDWF DAT_DATA_0000, w, ACCESS
	#  0010 0101 0000 0000  ->  ADDWF REG0x0, w, BANKED
	#  0010 0100 1101 1000  ->  ADDWF STATUS, w, ACCESS
	#  0010 0101 1101 1000  ->  ADDWF REG0xD8, w, BANKED
	#  0010 0110 0000 0000  ->  ADDWF DAT_DATA_0000, f, ACCESS
	#  0010 0111 0000 0000  ->  ADDWF REG0x0, f, BANKED
	#  0010 0110 1101 1000  ->  ADDWF STATUS, f, ACCESS
	#  0010 0111 1101 1000  ->  ADDWF REG0xD8, f, BANKED
	#  0010 0100 1111 1001	->	ADDWF PC, w, ACCESS
	tmp:1 = srcREG; # read only once!
	setAddFlags(tmp, WREG); 
	tmp = tmp + WREG;
	destREG = tmp;
	setResultFlags(tmp);
}

:ADDWF pcl, D, A		is op6=0x09 & A & D & d=1 & pcl	{
	#  0010 01da ffff ffff
	#  0010 0110 1111 1001  ->  ADDWF PC, f, ACCESS
	addr:3 = inst_start;
	PCLAT = addr;
	addrHi:2 = addr(1);
	addrLo:1 = addr:1;
	tmpW:1 = WREG;
	setAddFlags(addrLo, tmpW);
	addrLo = addrLo + tmpW;
	addr = (zext(addrHi) << 8) + zext(addrLo);
	setResultFlags(addrLo);
	goto [addr];
}

:ADDWFC srcREG, D, A 		is op6=0x08 & srcREG & destREG & D & A	{ 
	#  0010 00da ffff ffff
	#  0010 0000 0000 0000  ->  ADDWFC DAT_DATA_0000, w, ACCESS
	#  0010 0001 0000 0000  ->  ADDWFC REG0x0, w, BANKED
	#  0010 0000 1101 1000  ->  ADDWFC STATUS, w, ACCESS
	#  0010 0001 1101 1000  ->  ADDWFC REG0xD8, w, BANKED
	#  0010 0010 0000 0000  ->  ADDWFC DAT_DATA_0000, f, ACCESS
	#  0010 0011 0000 0000  ->  ADDWFC REG0x0, f, BANKED
	#  0010 0010 1101 1000  ->  ADDWFC STATUS, f, ACCESS
	#  0010 0011 1101 1000  ->  ADDWFC REG0xD8, f, BANKED
	local tmpC = C & 1;
	tmp:1 = srcREG;
	setAddCFlags(tmp, WREG); 
	tmp = tmp + WREG + tmpC;
	destREG = tmp;
	setResultFlags(tmp);
}

:ANDWF srcREG, D, A 		is op6=0x05 & srcREG & destREG & D & A	{ 
	#  0001 01da ffff ffff
	#  0001 0100 0000 0000  ->	ANDWF DAT_DATA_0000, w, ACCESS
	#  0001 0101 0000 0000  ->	ANDWF REG0x0, w, BANKED
	#  0001 0100 1101 1000  ->	ANDWF STATUS, w, ACCESS
	#  0001 0101 1101 1000  ->	ANDWF REG0xD8, w, BANKED
	#  0001 0110 0000 0000  ->	ANDWF DAT_DATA_0000, f, ACCESS
	#  0001 0111 0000 0000  ->	ANDWF REG0x0, f, BANKED
	#  0001 0110 1101 1000  ->	ANDWF STATUS, f, ACCESS
	#  0001 0111 1101 1000  ->	ANDWF REG0xD8, f, BANKED
	tmp:1 = srcREG & WREG;
	destREG = tmp;
	setResultFlags(tmp);
}

:CLRF srcREG, A			is op6=0x1a & d=1	& srcREG & A	{ 
	#  0110 101a ffff ffff
	#  0110 1010 0000 0000  ->	CLRF DAT_DATA_0000, 0
	#  0110 1011 0000 0000  ->	CLRF REG0x0, 1
	#  0110 1010 1101 1000  ->	CLRF STATUS, 0
	#  0110 1011 1101 1000  ->	CLRF REG0xD8, 1
	srcREG = 0;
	Z = 1;
}

:COMF srcREG, D, A		is op6=0x07 & srcREG & destREG & D & A		{ 
	#  0001 11da ffff ffff
	#  0001 1100 0000 0000  ->	COMF DAT_DATA_0000, w, ACCESS
	#  0001 1101 0000 0000  ->	COMF REG0x0, w, BANKED
	#  0001 1100 1101 1000  ->	COMF STATUS, w, ACCESS
	#  0001 1101 1101 1000  ->	COMF REG0xD8, w, BANKED
	#  0001 1110 0000 0000  ->	COMF DAT_DATA_0000, f, ACCESS
	#  0001 1111 0000 0000  ->	COMF REG0x0, f, BANKED
	#  0001 1110 1101 1000  ->	COMF STATUS, f, ACCESS
	#  0001 1111 1101 1000  ->	COMF REG0xD8, f, BANKED
	tmp:1 = ~srcREG;
	destREG = tmp;
	setResultFlags(tmp);
}

:CPFSEQ srcREG, A			is op6=0x18 & d=1 & srcREG & A & skipInst	{ 
	#  0110 001a ffff ffff
	#  0110 0010 0000 0000  ->	CPFSEQ DAT_DATA_0000, 0
	#  0110 0011 0000 0000  ->	CPFSEQ REG0x0, 1
	#  0110 0010 1101 1000  ->	CPFSEQ STATUS, 0
	#  0110 0011 1101 1000  ->	CPFSEQ REG0xD8, 1
	if (srcREG == WREG) goto skipInst;
}

:CPFSGT srcREG, A			is op6=0x19 & d=0 & srcREG & A & skipInst	{ 
	#  0110 010a ffff ffff
	#  0110 0100 0000 0000  ->	CPFSGT DAT_DATA_0000, 0
	#  0110 0101 0000 0000  ->	CPFSGT REG0x0, 1
	#  0110 0100 1101 1000  ->	CPFSGT STATUS, 0
	#  0110 0101 1101 1000  ->	CPFSGT REG0xD8, 1
	if (srcREG > WREG) goto skipInst;
}

:CPFSLT srcREG, A			is op6=0x18 & d=0 & srcREG & A & skipInst	{ 
	#  0110 000a ffff ffff
	#  0110 0000 0000 0000  ->	CPFSLT DAT_DATA_0000, 0
	#  0110 0001 0000 0000  ->	CPFSLT REG0x0, 1
	#  0110 0000 1101 1000  ->	CPFSLT STATUS, 0
	#  0110 0001 1101 1000  ->	CPFSLT REG0xD8, 1
	if (srcREG < WREG) goto skipInst;
}

:DECF srcREG, D, A		is op6=0x01 & srcREG & destREG & D & A	{ 
	#  0000 01da ffff ffff
	#  0000 0100 0000 0000  ->  DECF DAT_DATA_0000, w, ACCESS
	#  0000 0101 0000 0000  ->  DECF REG0x0, w, BANKED
	#  0000 0100 1101 1000  ->  DECF STATUS, w, ACCESS
	#  0000 0101 1101 1000  ->  DECF REG0xD8, w, BANKED
	#  0000 0110 0000 0000  ->  DECF DAT_DATA_0000, f, ACCESS
	#  0000 0111 0000 0000  ->  DECF REG0x0, f, BANKED
	#  0000 0110 1101 1000  ->  DECF STATUS, f, ACCESS
	#  0000 0111 1101 1000  ->  DECF REG0xD8, f, BANKED
	tmp:1 = srcREG;
	setSubtractFlags(tmp, 1); 
	tmp = tmp - 1;
	destREG = tmp;
	setResultFlags(tmp);
}

:DECFSZ srcREG, D, A		is op6=0x0b & srcREG & destREG & D & A & skipInst	{ 
	#  0010 11da ffff ffff
	#  0010 1100 0000 0000  ->  DECFSZ DAT_DATA_0000, w, ACCESS
	#  0010 1101 0000 0000  ->  DECFSZ REG0x0, w, BANKED
	#  0010 1100 1101 1000  ->  DECFSZ STATUS, w, ACCESS
	#  0010 1101 1101 1000  ->  DECFSZ REG0xD8, w, BANKED
	#  0010 1110 0000 0000  ->  DECFSZ DAT_DATA_0000, f, ACCESS
	#  0010 1111 0000 0000  ->  DECFSZ REG0x0, f, BANKED
	#  0010 1110 1101 1000  ->  DECFSZ STATUS, f, ACCESS
	#  0010 1111 1101 1000  ->  DECFSZ REG0xD8, f, BANKED
	tmp:1 = srcREG - 1;
	destREG = tmp;
	if (tmp == 0) goto skipInst;
}

:DCFSNZ srcREG, D, A		is op6=0x13 & srcREG & destREG & D & A & skipInst	{ 
	#  0100 11da ffff ffff
	#  0100 1100 0000 0000  ->  DCFSNZ DAT_DATA_0000, w, ACCESS
	#  0100 1101 0000 0000  ->  DCFSNZ REG0x0, w, BANKED
	#  0100 1100 1101 1000  ->  DCFSNZ STATUS, w, ACCESS
	#  0100 1101 1101 1000  ->  DCFSNZ REG0xD8, w, BANKED
	#  0100 1110 0000 0000  ->  DCFSNZ DAT_DATA_0000, f, ACCESS
	#  0100 1111 0000 0000  ->  DCFSNZ REG0x0, f, BANKED
	#  0100 1110 1101 1000  ->  DCFSNZ STATUS, f, ACCESS
	#  0100 1111 1101 1000  ->  DCFSNZ REG0xD8, f, BANKED
	tmp:1 = srcREG - 1;
	destREG = tmp;
	if (tmp != 0) goto skipInst;
}

:INCF srcREG, D, A		is op6=0x0a & srcREG & destREG & D & A	{ 
	#  0010 10da ffff ffff
	#  0010 1000 0000 0000  ->  INCF DAT_DATA_0000, w, ACCESS
	#  0010 1001 0000 0000  ->  INCF REG0x0, w, BANKED
	#  0010 1000 1101 1000  ->  INCF STATUS, w, ACCESS
	#  0010 1001 1101 1000  ->  INCF REG0xD8, w, BANKED
	#  0010 1010 0000 0000  ->  INCF DAT_DATA_0000, f, ACCESS
	#  0010 1011 0000 0000  ->  INCF REG0x0, f, BANKED
	#  0010 1010 1101 1000  ->  INCF STATUS, f, ACCESS
	#  0010 1011 1101 1000  ->  INCF REG0xD8, f, BANKED
	tmp:1 = srcREG; # read once only!
	setAddFlags(tmp, 1); 
	tmp = tmp + 1;
	destREG = tmp;
	setResultFlags(tmp);
}

:INCFSZ srcREG, D, A	is op6=0x0f & srcREG & destREG & D & A & skipInst	{ 
	#  0011 11da ffff ffff
	#  0011 1100 0000 0000  ->  INCFSZ DAT_DATA_0000, w, ACCESS
	#  0011 1101 0000 0000  ->  INCFSZ REG0x0, w, BANKED
	#  0011 1100 1101 1000  ->  INCFSZ STATUS, w, ACCESS
	#  0011 1101 1101 1000  ->  INCFSZ REG0xD8, w, BANKED
	#  0011 1110 0000 0000  ->  INCFSZ DAT_DATA_0000, f, ACCESS
	#  0011 1111 0000 0000  ->  INCFSZ REG0x0, f, BANKED
	#  0011 1110 1101 1000  ->  INCFSZ STATUS, f, ACCESS
	#  0011 1111 1101 1000  ->  INCFSZ REG0xD8, f, BANKED
	tmp:1 = srcREG + 1;
	destREG = tmp;
	if (tmp == 0) goto skipInst;
}

:INFSNZ srcREG, D, A		is op6=0x12 & srcREG & destREG & D & A & skipInst		{ 
	#  0100 10da ffff ffff
	#  0100 1000 0000 0000  ->  INFSNZ DAT_DATA_0000, w, ACCESS
	#  0100 1001 0000 0000  ->  INFSNZ REG0x0, w, BANKED
	#  0100 1000 1101 1000  ->  INFSNZ STATUS, w, ACCESS
	#  0100 1001 1101 1000  ->  INFSNZ REG0xD8, w, BANKED
	#  0100 1010 0000 0000  ->  INFSNZ DAT_DATA_0000, f, ACCESS
	#  0100 1011 0000 0000  ->  INFSNZ REG0x0, f, BANKED
	#  0100 1010 1101 1000  ->  INFSNZ STATUS, f, ACCESS
	#  0100 1011 1101 1000  ->  INFSNZ REG0xD8, f, BANKED
	tmp:1 = srcREG + 1;
	destREG = tmp;
	if (tmp != 0) goto skipInst;
}

:IORWF srcREG, D, A		is op6=0x04	& srcREG & destREG & D & A		{ 
	#  0001 00da ffff ffff
	#  0001 0000 0000 0000  ->	IORWF DAT_DATA_0000, w, ACCESS
	#  0001 0001 0000 0000  ->	IORWF REG0x0, w, BANKED
	#  0001 0000 1101 1000  ->	IORWF STATUS, w, ACCESS
	#  0001 0001 1101 1000  ->	IORWF REG0xD8, w, BANKED
	#  0001 0010 0000 0000  ->	IORWF DAT_DATA_0000, f, ACCESS
	#  0001 0011 0000 0000  ->	IORWF REG0x0, f, BANKED
	#  0001 0010 1101 1000  ->	IORWF STATUS, f, ACCESS
	#  0001 0011 1101 1000  ->	IORWF REG0xD8, f, BANKED
	tmp:1 = srcREG | WREG;
	destREG = tmp;
	setResultFlags(tmp);
}

:MOVF srcREG, D, A		is op6=0x14	& srcREG & destREG & D & A		{ 
	#  0101 00da ffff ffff
	#  0101 0000 0000 0000  ->	MOVF DAT_DATA_0000, w, ACCESS
	#  0101 0001 0000 0000  ->	MOVF REG0x0, w, BANKED
	#  0101 0000 1101 1000  ->	MOVF STATUS, w, ACCESS
	#  0101 0001 1101 1000  ->	MOVF REG0xD8, w, BANKED
	#  0101 0010 0000 0000  ->	MOVF DAT_DATA_0000, f, ACCESS
	#  0101 0011 0000 0000  ->	MOVF REG0x0, f, BANKED
	#  0101 0010 1101 1000  ->	MOVF STATUS, f, ACCESS
	#  0101 0011 1101 1000  ->	MOVF REG0xD8, f, BANKED
	
	#  0101 0000 1110 1111  ->	MOVF INDF0, w, ACCESS
	#  0101 0000 1110 0111  ->	MOVF INDF1, w, ACCESS
	#  0101 0000 1101 1111  ->	MOVF INDF2, w, ACCESS
	
	tmp:1 = srcREG;
	destREG = tmp;
	setResultFlags(tmp);
}

:MOVFF srcREG32, destREG32	is lop4=0x0c & srcREG32 & qual4=0x0f & destREG32	{ 
	#  1100 ssss ssss ssss 1111 dddd dddd dddd
	#  1100 0000 0000 0000 1111 1111 1101 1000 -> MOVFF DAT_DATA_0000, STATUS
	destREG32 = srcREG32;
}

:MOVFF srcREG32, destREG32	is lop4=0x0c & srcREG32 & qual4=0x0f & destREG32 & fd=0xff9	{ 
	#  1100 ssss ssss ssss 1111 dddd dddd dddd
	#  1100 0000 0000 0000 1111 1111 1111 1001 -> MOVFF DAT_DATA_0000, PCL
	addr:3 = (zext(PCLATU) << 16) + (zext(PCLATH) << 8) + zext(srcREG32);
	goto [addr];
}

:MOVWF srcREG, A			is op6=0x1b & d=0x1	& srcREG & A	{ 
	#  0110 111a ffff ffff
	#  0110 1110 0000 0000  ->	MOVWF DAT_DATA_0000, 0
	#  0110 1111 0000 0000  ->	MOVWF REG0x0, 1
	#  0110 1110 1101 1000  ->	MOVWF STATUS, 0
	#  0110 1111 1101 1000  ->	MOVWF REG0xD8, 1
	srcREG = WREG;
}

:MOVWF pcl, A			is op6=0x1b & A & pcl	{ 
	#  0110 111a ffff ffff
	#  0110 1110 1111 1001  ->	MOVWF PCL, 0
	addr:3 = (zext(PCLATU) << 16) + (zext(PCLATH) << 8) + zext(WREG);
	goto [addr];
}

:MULWF srcREG, A			is op6=0x00 & d=0x1	& srcREG & A	{ 
	#  0000 001a ffff ffff
	#  0000 0010 0000 0000  ->	MULWF DAT_DATA_0000, 0
	#  0000 0011 0000 0000  ->	MULWF REG0x0, 1
	#  0000 0010 1101 1000  ->	MULWF STATUS, 0
	#  0000 0011 1101 1000  ->	MULWF REG0xD8, 1
	tmp1:2 = zext(srcREG);
	tmp2:2 = zext(WREG);
	PROD = tmp1 * tmp2;
}

:NEGF srcREG, A			is op6=0x1b & d=0x0	& srcREG & A	{ 
	#  0110 110a ffff ffff
	#  0110 1100 0000 0000  ->	NEGF DAT_DATA_0000, 0
	#  0110 1101 0000 0000  ->	NEGF REG0x0, 1
	#  0110 1100 1101 1000  ->	NEGF STATUS, 0
	#  0110 1101 1101 1000  ->	NEGF REG0xD8, 1
	tmp:1 = -srcREG;
	srcREG = tmp;
	C = (tmp s> 0);
	OV = sborrow(0,tmp);
	setResultFlags(tmp);
}

:RLCF srcREG, D, A		is op6=0x0d	& srcREG & destREG & D & A		{ 
	#  0011 01da ffff ffff
	#  0011 0100 0000 0000  ->	RLCF DAT_DATA_0000, w, ACCESS
	#  0011 0101 0000 0000  ->	RLCF REG0x0, w, BANKED
	#  0011 0100 1101 1000  ->	RLCF STATUS, w, ACCESS
	#  0011 0101 1101 1000  ->	RLCF REG0xD8, w, BANKED
	#  0011 0110 0000 0000  ->	RLCF DAT_DATA_0000, f, ACCESS
	#  0011 0111 0000 0000  ->	RLCF REG0x0, f, BANKED
	#  0011 0110 1101 1000  ->	RLCF STATUS, f, ACCESS
	#  0011 0111 1101 1000  ->	RLCF REG0xD8, f, BANKED
	local tmpC = C & 1;
	tmp:1 = srcREG;
	C = (tmp s< 0);
	tmp = (tmp << 1) | tmpC;
	destREG = tmp;
	setResultFlags(tmp);
}

:RLNCF srcREG, D, A		is op6=0x11	& srcREG & destREG & D & A		{ 
	#  0100 01da ffff ffff
	#  0100 0100 0000 0000  ->	RLNCF DAT_DATA_0000, w, ACCESS
	#  0100 0101 0000 0000  ->	RLNCF REG0x0, w, BANKED
	#  0100 0100 1101 1000  ->	RLNCF STATUS, w, ACCESS
	#  0100 0101 1101 1000  ->	RLNCF REG0xD8, w, BANKED
	#  0100 0110 0000 0000  ->	RLNCF DAT_DATA_0000, f, ACCESS
	#  0100 0111 0000 0000  ->	RLNCF REG0x0, f, BANKED
	#  0100 0110 1101 1000  ->	RLNCF STATUS, f, ACCESS
	#  0100 0111 1101 1000  ->	RLNCF REG0xD8, f, BANKED
	tmp:1 = srcREG << 1;
	destREG = tmp;
	setResultFlags(tmp);
}

:RRCF srcREG, D, A		is op6=0x0c	& srcREG & destREG & D & A		{ 
	#  0011 00da ffff ffff
	#  0011 0000 0000 0000  ->	RRCF DAT_DATA_0000, w, ACCESS
	#  0011 0001 0000 0000  ->	RRCF REG0x0, w, BANKED
	#  0011 0000 1101 1000  ->	RRCF STATUS, w, ACCESS
	#  0011 0001 1101 1000  ->	RRCF REG0xD8, w, BANKED
	#  0011 0010 0000 0000  ->	RRCF DAT_DATA_0000, f, ACCESS
	#  0011 0011 0000 0000  ->	RRCF REG0x0, f, BANKED
	#  0011 0010 1101 1000  ->	RRCF STATUS, f, ACCESS
	#  0011 0011 1101 1000  ->	RRCF REG0xD8, f, BANKED
	local tmpC = C << 7;
	tmp:1 = srcREG;
	C = (tmp & 1);
	tmp = (tmp >> 1) | tmpC;
	destREG = tmp;
	setResultFlags(tmp);
}

:RRNCF srcREG, D, A		is op6=0x10	& srcREG & destREG & D & A		{ 
	#  0100 00da ffff ffff
	#  0100 0000 0000 0000  ->	RRNCF DAT_DATA_0000, w, ACCESS
	#  0100 0001 0000 0000  ->	RRNCF REG0x0, w, BANKED
	#  0100 0000 1101 1000  ->	RRNCF STATUS, w, ACCESS
	#  0100 0001 1101 1000  ->	RRNCF REG0xD8, w, BANKED
	#  0100 0010 0000 0000  ->	RRNCF DAT_DATA_0000, f, ACCESS
	#  0100 0011 0000 0000  ->	RRNCF REG0x0, f, BANKED
	#  0100 0010 1101 1000  ->	RRNCF STATUS, f, ACCESS
	#  0100 0011 1101 1000  ->	RRNCF REG0xD8, f, BANKED
	tmp:1 = srcREG >> 1;
	destREG = tmp;
	setResultFlags(tmp);
}

:SETF srcREG, A			is op6=0x1a & d=0x0	& srcREG & A	{ 
	#  0110 100a ffff ffff
	#  0110 1000 0000 0000  ->	SETF DAT_DATA_0000, 0
	#  0110 1001 0000 0000  ->	SETF REG0x0, 1
	#  0110 1000 1101 1000  ->	SETF STATUS, 0
	#  0110 1001 1101 1000  ->	SETF REG0xD8, 1
	srcREG = 0xff;
}

:SUBFWB srcREG, D, A		is op6=0x15	& srcREG & destREG & D & A		{ 
	#  0101 01da ffff ffff
	#  0101 0100 0000 0000  ->	SUBFWB DAT_DATA_0000, w, ACCESS
	#  0101 0101 0000 0000  ->	SUBFWB REG0x0, w, BANKED
	#  0101 0100 1101 1000  ->	SUBFWB STATUS, w, ACCESS
	#  0101 0101 1101 1000  ->	SUBFWB REG0xD8, w, BANKED
	#  0101 0110 0000 0000  ->	SUBFWB DAT_DATA_0000, f, ACCESS
	#  0101 0111 0000 0000  ->	SUBFWB REG0x0, f, BANKED
	#  0101 0110 1101 1000  ->	SUBFWB STATUS, f, ACCESS
	#  0101 0111 1101 1000  ->	SUBFWB REG0xD8, f, BANKED
	local notC = ~(C & 1);
	tmp:1 = srcREG;
	setSubtractCFlags(WREG, tmp); 
	tmp = WREG - tmp - notC;
	destREG = tmp;
	setResultFlags(tmp);
}

:SUBWF srcREG, D, A		is op6=0x17	& srcREG & destREG & D & A		{ 
	#  0101 11da ffff ffff
	#  0101 1100 0000 0000  ->	SUBWF DAT_DATA_0000, w, ACCESS
	#  0101 1101 0000 0000  ->	SUBWF REG0x0, w, BANKED
	#  0101 1100 1101 1000  ->	SUBWF STATUS, w, ACCESS
	#  0101 1101 1101 1000  ->	SUBWF REG0xD8, w, BANKED
	#  0101 1110 0000 0000  ->	SUBWF DAT_DATA_0000, f, ACCESS
	#  0101 1111 0000 0000  ->	SUBWF REG0x0, f, BANKED
	#  0101 1110 1101 1000  ->	SUBWF STATUS, f, ACCESS
	#  0101 1111 1101 1000  ->	SUBWF REG0xD8, f, BANKED
	tmp:1 = srcREG;
	setSubtractFlags(tmp, WREG); 
	tmp = tmp - WREG;
	destREG = tmp;
	setResultFlags(tmp);
}

:SUBWFB srcREG, D, A		is op6=0x16	& srcREG & destREG & D & A		{ 
	#  0101 10da ffff ffff
	#  0101 1000 0000 0000  ->	SUBWFB DAT_DATA_0000, w, ACCESS
	#  0101 1001 0000 0000  ->	SUBWFB REG0x0, w, BANKED
	#  0101 1000 1101 1000  ->	SUBWFB STATUS, w, ACCESS
	#  0101 1001 1101 1000  ->	SUBWFB REG0xD8, w, BANKED
	#  0101 1010 0000 0000  ->	SUBWFB DAT_DATA_0000, f, ACCESS
	#  0101 1011 0000 0000  ->	SUBWFB REG0x0, f, BANKED
	#  0101 1010 1101 1000  ->	SUBWFB STATUS, f, ACCESS
	#  0101 1011 1101 1000  ->	SUBWFB REG0xD8, f, BANKED
	local notC = ~(C & 1);
	tmp:1 = srcREG;
	setSubtractCFlags(tmp, WREG); 
	tmp = tmp - WREG - notC;
	destREG = tmp;
	setResultFlags(tmp);
}

:SWAPF srcREG, D, A		is op6=0x0e	& srcREG & destREG & D & A		{ 
	#  0011 10da ffff ffff
	#  0011 1000 0000 0000  ->	SWAPF DAT_DATA_0000, w, ACCESS
	#  0011 1001 0000 0000  ->	SWAPF REG0x0, w, BANKED
	#  0011 1000 1101 1000  ->	SWAPF STATUS, w, ACCESS
	#  0011 1001 1101 1000  ->	SWAPF REG0xD8, w, BANKED
	#  0011 1010 0000 0000  ->	SWAPF DAT_DATA_0000, f, ACCESS
	#  0011 1011 0000 0000  ->	SWAPF REG0x0, f, BANKED
	#  0011 1010 1101 1000  ->	SWAPF STATUS, f, ACCESS
	#  0011 1011 1101 1000  ->	SWAPF REG0xD8, f, BANKED
	tmp:1 = srcREG;
	destREG = (tmp << 4) | (tmp >> 4);	
}

:TSTFSZ srcREG, A			is op6=0x19 & d=0x1	& srcREG & A & skipInst	{ 
	#  0110 011a ffff ffff
	#  0110 0110 0000 0000  ->	TSTFSZ DAT_DATA_0000, 0
	#  0110 0111 0000 0000  ->	TSTFSZ REG0x0, 1
	#  0110 0110 1101 1000  ->	TSTFSZ STATUS, 0
	#  0110 0111 1101 1000  ->	TSTFSZ REG0xD8, 1
	if (srcREG == 0) goto skipInst;
}

:XORWF srcREG, D, A		is op6=0x06	& srcREG & destREG & D & A		{ 
	#  0001 10da ffff ffff
	#  0001 1000 0000 0000  ->	XORWF DAT_DATA_0000, w, ACCESS
	#  0001 1001 0000 0000  ->	XORWF REG0x0, w, BANKED
	#  0001 1000 1101 1000  ->	XORWF STATUS, w, ACCESS
	#  0001 1001 1101 1000  ->	XORWF REG0xD8, w, BANKED
	#  0001 1010 0000 0000  ->	XORWF DAT_DATA_0000, f, ACCESS
	#  0001 1011 0000 0000  ->	XORWF REG0x0, f, BANKED
	#  0001 1010 1101 1000  ->	XORWF STATUS, f, ACCESS
	#  0001 1011 1101 1000  ->	XORWF REG0xD8, f, BANKED
	tmp:1 = WREG ^ srcREG;
	destREG = tmp;
	setResultFlags(tmp);
}


#
# BIT-ORIENTED FILE REGISTER OPERATIONS
#

:BCF srcREG, bit, A			is op4=0x09	& srcREG & bit & A	{ 
	#  1001 bbba ffff ffff
	#  1001 0010 0000 0000	->	BCF DAT_DATA_0000, #0x1, 0
	#  1001 0101 0000 0000  ->	BCF REG0x0, #0x2, 1
	#  1001 0010 1101 1000  ->	BCF STATUS, #0x1, 0
	#  1001 0101 1101 1000  ->	BCF REG0xD8, #0x2, 1
	local bitmask = ~(1 << bit);
	srcREG = srcREG & bitmask;
}

:BCF status, bit, A			is op4=0x09	& status & b3=0 & bit & A	{ 
	#  1001 bbba ffff ffff
	#  1001 0000 1101 1000  ->	BCF STATUS, #C, 0
	C = 0;
	local bitmask = ~(1 << bit);
	STATUS = STATUS & bitmask;
}

:BCF status, bit, A			is op4=0x09	& status & b3=1 & bit & A	{ 
	#  1001 bbba ffff ffff
	#  1001 0010 1101 1000  ->	BCF STATUS, #DC, 0
	DC = 0;
	local bitmask = ~(1 << bit);
	STATUS = STATUS & bitmask;
}

:BCF status, bit, A			is op4=0x09	& status & b3=2 & bit & A	{ 
	#  1001 bbba ffff ffff
	#  1001 0100 1101 1000  ->	BCF STATUS, #Z, 0
	Z = 0;
	local bitmask = ~(1 << bit);
	STATUS = STATUS & bitmask;
}

:BCF status, bit, A			is op4=0x09	& status & b3=3 & bit & A	{ 
	#  1001 bbba ffff ffff
	#  1001 0110 1101 1000  ->	BCF STATUS, #OV, 0
	OV = 0;
	local bitmask = ~(1 << bit);
	STATUS = STATUS & bitmask;
}

:BCF status, bit, A			is op4=0x09	& status & b3=4 & bit & A	{ 
	#  1001 bbba ffff ffff
	#  1001 1000 1101 1000  ->	BCF STATUS, #N, 0
	N = 0;
	local bitmask = ~(1 << bit);
	STATUS = STATUS & bitmask;
}

:BSF srcREG, bit, A			is op4=0x08	& srcREG & bit & A	{ 
	#  1000 bbba ffff ffff
	#  1000 0010 0000 0000	->	BSF DAT_DATA_0000, #0x1, 0
	#  1000 0101 0000 0000  ->	BSF REG0x0, #0x2, 1
	#  1000 0010 1101 1000  ->	BSF STATUS, #0x1, 0
	#  1000 0101 1101 1000  ->	BSF REG0xD8, #0x2, 1	
	local bitmask = 1 << bit;
	srcREG = srcREG | bitmask;
}

:BSF status, bit, A			is op4=0x08	& status & b3=0 & bit & A	{ 
	#  1000 bbba ffff ffff
	#  1000 0000 1101 1000  ->	BSF STATUS, #C, 0
	C = 1;
	local bitmask = 1 << bit;
	STATUS = STATUS | bitmask;
}

:BSF status, bit, A			is op4=0x08	& status & b3=1 & bit & A	{ 
	#  1000 bbba ffff ffff
	#  1000 0010 1101 1000  ->	BSF STATUS, #DC, 0
	DC = 1;
	local bitmask = 1 << bit;
	STATUS = STATUS | bitmask;
}

:BSF status, bit, A			is op4=0x08	& status & b3=2 & bit & A	{ 
	#  1000 bbba ffff ffff
	#  1000 0100 1101 1000  ->	BSF STATUS, #Z, 0
	Z = 1;
	local bitmask = 1 << bit;
	STATUS = STATUS | bitmask;
}

:BSF status, bit, A			is op4=0x08	& status & b3=3 & bit & A	{ 
	#  1000 bbba ffff ffff
	#  1000 0110 1101 1000  ->	BSF STATUS, #OV, 0
	OV = 1;
	local bitmask = 1 << bit;
	STATUS = STATUS | bitmask;
}

:BSF status, bit, A			is op4=0x08	& status & b3=4 & bit & A	{ 
	#  1000 bbba ffff ffff
	#  1000 1000 1101 1000  ->	BSF STATUS, #N, 0
	N = 1;
	local bitmask = 1 << bit;
	STATUS = STATUS | bitmask;
}

:BTFSC srcREG, bit, A		is op4=0x0b	& srcREG & bit & A & skipInst	{ 
	#  1011 bbba ffff ffff
	#  1011 0010 0000 0000	->	BTFSC DAT_DATA_0000, #0x1, 0
	#  1011 0101 0000 0000  ->	BTFSC REG0x0, #0x2, 1
	#  1011 0010 1101 1000  ->	BTFSC STATUS, #0x1, 0
	#  1011 0101 1101 1000  ->	BTFSC REG0xD8, #0x2, 1	
	local bitmask = 1 << bit;
	local tmp = srcREG & bitmask;
	if (tmp == 0) goto skipInst;
}

:BTFSC status, bit, A		is op4=0x0b & b3=0 & bit & status & A & skipInst				{
	#  1011 bbba ffff ffff
	#  1011 0000 1101 1000  ->	BTFSC STATUS, #C, 0
	if ((C & 1) == 0) goto skipInst;
}

:BTFSC status, bit, A		is op4=0x0b & b3=1 & bit & status & A & skipInst				{
	#  1011 bbba ffff ffff
	#  1011 0000 1101 1000	->	BTFSC STATUS, #DC, 0
	if ((DC & 1) == 0) goto skipInst;
}

:BTFSC status, bit, A		is op4=0x0b & b3=2 & bit & status & A & skipInst				{
	#  1011 bbba ffff ffff
	#  1011 0000 1101 1000	->	BTFSC STATUS, #Z, 0
	if ((Z & 1) == 0) goto skipInst;
}

:BTFSC status, bit, A		is op4=0x0b & b3=3 & bit & status & A & skipInst				{
	#  1011 bbba ffff ffff
	#  1011 0110 1101 1000	->	BTFSC STATUS, #OV, 0
	if ((OV & 1) == 0) goto skipInst;
}

:BTFSC status, bit, A		is op4=0x0b & b3=4 & bit & status & A & skipInst				{
	#  1011 bbba ffff ffff
	#  1011 1000 1101 1000	->	BTFSC STATUS, #N, 0
	if ((N & 1) == 0) goto skipInst;
}

:BTFSS srcREG, bit, A		is op4=0x0a	& srcREG & bit & A & skipInst	{ 
	#  1010 bbba ffff ffff
	#  1010 0010 0000 0000	->	BTFSS DAT_DATA_0000, #0x1, 0
	#  1010 0101 0000 0000  ->	BTFSS REG0x0, #0x2, 1
	#  1010 0010 1101 1000  ->	BTFSS STATUS, #0x1, 0
	#  1010 0101 1101 1000  ->	BTFSS REG0xD8, #0x2, 1	
	local bitmask = 1 << bit;
	local tmp = srcREG & bitmask;
	if (tmp != 0) goto skipInst;
}

:BTFSS status, bit, A		is op4=0x0a	& b3=0 & bit & status & A & skipInst	{ 
	#  1010 bbba ffff ffff
	#  1010 0000 1101 1000  ->	BTFSS STATUS, #C, 0	
	if ((C & 1) != 0) goto skipInst;
}

:BTFSS status, bit, A		is op4=0x0a	& b3=1 & bit & status & A & skipInst	{ 
	#  1010 bbba ffff ffff
	#  1010 0010 1101 1000  ->	BTFSS STATUS, #DC, 0	
	if ((DC & 1) != 0) goto skipInst;
}

:BTFSS status, bit, A		is op4=0x0a	& b3=2 & bit & status & A & skipInst	{ 
	#  1010 bbba ffff ffff
	#  1010 0100 1101 1000  ->	BTFSS STATUS, #Z, 0	
	if ((Z & 1) != 0) goto skipInst;
}

:BTFSS status, bit, A		is op4=0x0a	& b3=3 & bit & status & A & skipInst	{ 
	#  1010 bbba ffff ffff
	#  1010 0110 1101 1000  ->	BTFSS STATUS, #OV, 0	
	if ((OV & 1) != 0) goto skipInst;
}

:BTFSS status, bit, A		is op4=0x0a	& b3=4 & bit & status & A & skipInst	{ 
	#  1010 bbba ffff ffff
	#  1010 1000 1101 1000  ->	BTFSS STATUS, #N, 0	
	if ((N & 1) != 0) goto skipInst;
}

:BTG srcREG, bit, A			is op4=0x07	& srcREG & bit & A	{ 
	#  0111 bbba ffff ffff
	#  0111 0010 0000 0000	->	BTG DAT_DATA_0000, #0x1, 0
	#  0111 0101 0000 0000  ->	BTG REG0x0, #0x2, 1
	#  0111 0010 1101 1000  ->	BTG STATUS, #0x1, 0
	#  0111 0101 1101 1000  ->	BTG REG0xD8, #0x2, 1	
	local bitmask = 1 << bit;
	tmp:1 = srcREG;
	srcREG = ~(tmp & bitmask) | (tmp & ~bitmask);
}

#
# CONTROL OPERATIONS
#

:BC relAddr8			is op8=0xe2	& relAddr8		{ 
	#  1110 0010 nnnn nnnn
	#  1110 0010 0001 0000	->	BC LAB_CODE_XXXX
	if ((C & 1) != 0) goto relAddr8;
}

:BN relAddr8			is op8=0xe6	& relAddr8		{ 
	#  1110 0110 nnnn nnnn
	#  1110 0110 0001 0000	->	BN LAB_CODE_XXXX
	if ((N & 1) != 0) goto relAddr8;
}

:BNC relAddr8			is op8=0xe3	& relAddr8		{ 
	#  1110 0011 nnnn nnnn
	#  1110 0011 0001 0000	->	BNC LAB_CODE_XXXX
	if ((C & 1) == 0) goto relAddr8;
}

:BNN relAddr8			is op8=0xe7	& relAddr8		{ 
	#  1110 0111 nnnn nnnn
	#  1110 0111 0001 0000	->	BNN LAB_CODE_XXXX
	if ((N & 1) == 0) goto relAddr8;
}

:BNOV relAddr8			is op8=0xe5	& relAddr8		{ 
	#  1110 0101 nnnn nnnn
	#  1110 0101 0001 0000	->	BNOV LAB_CODE_XXXX
	if ((OV & 1) == 0) goto relAddr8;
}

:BNZ relAddr8			is op8=0xe1	& relAddr8		{ 
	#  1110 0001 nnnn nnnn
	#  1110 0001 0001 0000	->	BNZ LAB_CODE_XXXX
	if ((Z & 1) == 0) goto relAddr8;
}

:BOV relAddr8			is op8=0xe4	& relAddr8		{ 
	#  1110 0100 nnnn nnnn
	#  1110 0100 0001 0000	->	BOV LAB_CODE_XXXX
	if ((OV & 1) != 0) goto relAddr8;
}

:BRA relAddr11			is op5=0x1a	& relAddr11		{ 
	#  1101 0nnn nnnn nnnn
	#  1101 0001 0001 0000	->	BRA LAB_CODE_XXXX  (inst_next+0x220)
	goto relAddr11;	
}

:BZ relAddr8			is op8=0xe0 & relAddr8		{ 
	#  1110 0000 nnnn nnnn
	#  1110 0000 0001 0000	->	BZ LAB_CODE_XXXX
	if ((Z & 1) != 0) goto relAddr8;
}

:CALL absAddr21, s_8		is lop8=0xec & absAddr21 & s_8	{ 
	#  1110 110s kkkk kkkk 1111 kkkk kkkk kkkk
	#  1110 1100 0100 0101 1111 0001 0010 0011	->	CALL SUB_CODE_02468a, 0
	push(&:3 inst_next);
	call absAddr21;
}

:CALL absAddr21, s_8		is lop8=0xed & absAddr21 & s_8	{ 
	#  1110 110s kkkk kkkk 1111 kkkk kkkk kkkk
	#  1110 1101 0100 0101 1111 0001 0010 0011	->	CALL SUB_CODE_02468a, 1
	WS = WREG;
	STATUSS = STATUS;
	BSRS = BSR;
	push(&:3 inst_next);
	call absAddr21;
} 

:CLRWDT					is op16=0x0004				{
	#  0000 0000 0000 0100
	clearWatchDogTimer();
}

:DAW					is op16=0x0007				{ 
	#  0000 0000 0000 0111
	tmp:1 = decimalAdjust(WREG);
	WREG = tmp;
	setResultFlags(tmp);
}

:GOTO absAddr21			is lop8=0xef & absAddr21 	{ 
	# 1110 1111 kkkk kkkk 1111 kkkk kkkk kkkk
	# 1110 1111 0100 0101 1111 0001 0010 0011	->	GOTO LAB_CODE_02468a
	goto absAddr21;
} 

:NOP					is op16=0x0000				{ }

:NOP					is op4=0x0f					{ }

:POP					is op16=0x0006				{ 
	#  0000 0000 0000 0110
	tmp:4 = 0;
	pop(tmp);
}

:PUSH					is op16=0x0005				{ 
	#  0000 0000 0000 0101
	push(&:3 inst_next);
}

:RCALL relAddr11		is op5=0x1b	& relAddr11		{ 
	#  1101 1nnn nnnn nnnn
	#  1101 1001 0000 0000	->	CALL SUB_CODE_XXXX
	push(&:3 inst_next);
	call relAddr11;
}

:RESET					is op16=0x00ff				{ 
	#  0000 0000 1111 1111
	reset();
}

:RETFIE s_0				is op16=0x0010 & s_0			{ # TODO: Set GIE/GIEH and/or PEIE/GIEL
	#  0000 0000 0001 0000
	retAddr:4 = 0;
	pop(retAddr);
	return [retAddr];
}

:RETFIE s_0			is op16=0x0011 & s_0				{  # TODO: Set GIE/GIEH and/or PEIE/GIEL
	#  0000 0000 0001 0001
	WREG = WS;
	STATUS = STATUSS;
	BSR = BSRS;
	retAddr:4 = 0;
	pop(retAddr);
	return [retAddr];
}

:RETURN s_0				is op16=0x0012 & s_0				{ 
	#  0000 0000 0001 0010
	retAddr:4 = 0;
	pop(retAddr);
	return [retAddr];
}

:RETURN s_0				is op16=0x0013 & s_0				{ 
	#  0000 0000 0001 0011
	WREG = WS;
	STATUS = STATUSS;
	BSR = BSRS;
	retAddr:4 = 0;
	pop(retAddr);
	return [retAddr];
}

:SLEEP					is op16=0x0003				{ 
	#  0000 0000 0000 0011
	sleep();
}

#
# LITERAL OPERATIONS
#

:ADDLW imm8				is op8=0x0f & imm8			{ 
	#  0000 1111 kkkk kkkk
	#  0000 1111 0001 0010	->	ADDLW #0x12
	setAddFlags(imm8, WREG); 
	WREG = WREG + imm8;
	setResultFlags(WREG);
}

:ANDLW imm8				is op8=0xb & imm8			{ 
	#  0000 1011 kkkk kkkk
	#  0000 1011 0001 0010	->	ANDLW #0x12
	WREG = WREG & imm8;
	setResultFlags(WREG);
}

:IORLW imm8				is op8=0x9 & imm8			{ 
	#  0000 1001 kkkk kkkk
	#  0000 1001 0001 0010	->	IORLW #0x12
	WREG = WREG | imm8;
	setResultFlags(WREG);
}

:LFSR FSRn, imm12		is lop10=0x3b8 & fsr<3 & FSRn & imm12	{ 
	#  1110 1110 00ff kkkk 1111 0000 kkkk kkkk
	#  1110 1110 0001 0001 1111 0000 0010 0011	->	LFSR FSR1, 0x123
	FSRn = imm12;
}

:MOVLB imm8				is op8=0x01 & imm8		{ # Manual is inconsistent imm4 vs. imm8
	#  0000 0001 kkkk kkkk
	#  0000 0001 0001 0010	->	MOVLB #0x12
	BSR = imm8;
}

:MOVLW imm8				is op8=0x0e & imm8			{ 
	#  0000 1110 kkkk kkkk
	#  0000 1110 0001 0010	->	MOVLW #0x12
	WREG = imm8;
}

:MULLW imm8				is op8=0x0d & imm8			{ 
	#  0000 1101 kkkk kkkk
	#  0000 1101 0001 0010	->	MULLW #0x12
	tmp1:2 = zext(imm8);
	tmp2:2 = zext(WREG);
	PROD = tmp1 * tmp2;
}

:RETLW imm8				is op8=0x0c & imm8			{ 
	#  0000 1100 kkkk kkkk
	#  0000 1100 0001 0010	->	RETLW #0x12
	WREG = imm8;
	retAddr:4 = 0;
	pop(retAddr);
	return [retAddr];
}

:SUBLW imm8				is op8=0x08 & imm8			{ 
	#  0000 1000 kkkk kkkk
	#  0000 1000 0001 0010	->	SUBLW #0x12
	setSubtractFlags(imm8, WREG); 
	WREG = imm8 - WREG;
	setResultFlags(WREG);
}

:XORLW imm8				is op8=0x0a & imm8			{ 
	#  0000 1010 kkkk kkkk
	#  0000 1010 0001 0010	->	XORLW #0x12
	WREG = WREG ^ imm8;
	setResultFlags(WREG);
}

#
# DATA MEMORY <-> PROGRAM MEMORY OPERATIONS
#

:TBLRD*					is op16=0x0008				{
	#  0000 0000 0000 1000 
	ptr:3 = TBLPTR;
	TABLAT = *[CODE] ptr;
}

:TBLRD*+				is op16=0x0009				{ 
	#  0000 0000 0000 1001 
	ptr:3 = TBLPTR;
	TABLAT = *[CODE] ptr;
	ptr = ptr + 1;
	TBLPTR = ptr;
}

:TBLRD*-				is op16=0x000a				{ 
	#  0000 0000 0000 1010 
	ptr:3 = TBLPTR;
	TABLAT = *[CODE] ptr;
	ptr = ptr - 1;
	TBLPTR = ptr;
}

:TBLRD+*				is op16=0x000b				{ 
	#  0000 0000 0000 1011
	ptr:3 = TBLPTR;
	ptr = ptr + 1;
	TBLPTR = ptr;
	TABLAT = *[CODE] ptr;
}

:TBLWT*					is op16=0x000c				{ 
	#  0000 0000 0000 1100
	ptr:3 = TBLPTR;
	*[CODE] ptr = TABLAT;
}

:TBLWT*+				is op16=0x000d				{ 
	#  0000 0000 0000 1101
	ptr:3 = TBLPTR;
	*[CODE] ptr = TABLAT;
	TBLPTR = ptr + 1;
}

:TBLWT*-				is op16=0x000e				{ 
	#  0000 0000 0000 1110
	ptr:3 = TBLPTR;
	*[CODE] ptr = TABLAT;
	TBLPTR = ptr - 1;
}

:TBLWT+*				is op16=0x000f				{ 
	#  0000 0000 0000 1111
	ptr:3 = TBLPTR;
	ptr = ptr + 1;
	TBLPTR = ptr;
	*[CODE] ptr = TABLAT;
}

#
# EXTENDED INSTRUCTION SET
#

:ADDFSR xFSRn, imm6	is op8=0xe8 & xfsr<3 & xFSRn & imm6	{ 
	#  1110 1000 ffkk kkkk
	#  1110 1000 1001 0010	->	ADDFSR FSR2, #0x12
	xFSRn = xFSRn + zext(imm6);
}

:ADDULNK imm6		is op8=0xe8 & xfsr=3 & imm6	{ 
	#  1110 1000 11kk kkkk
	#  1110 1000 1101 0010	->	ADDULNK #0x12
	retAddr:4 = 0;
	pop(retAddr);
	FSR2 = FSR2 + zext(imm6);
	return [retAddr];
}

:CALLW				is op16=0x0014				{ 
	#  0000 0000 0001 0100
	loc:3 = (zext(PCLATU) << 16) | (zext(PCLATH) << 8) | zext(WREG);
	push(&:3 inst_next);
	call [loc];
}

:MOVSF ZS, destREG32	is lop9=0x1d6 & ZS & qual4=0xf & destREG32	{ 
	#  1110 1011 0zzz zzzz 1111 ffff ffff ffff
	#  1110 1011 0001 0010 1111 0001 0010 0011	->	MOVSF 0x12[FSR2], DAT_DATA_0123
	destREG32 = ZS;
}

:MOVSF ZS, destREG32	is lop9=0x1d6 & ZS & qual4=0xf & destREG32 & fd=0xff9	{ 
	#  1110 1011 0zzz zzzz 1111 ffff ffff ffff
	#  1110 1011 0001 0010 1111 1111 1111 1001	->	MOVSF 0x12[FSR2], PCL
	addr:3 = (zext(PCLATU) << 16) + (zext(PCLATH) << 8) + zext(ZS);
	goto [addr];
}

:MOVSS ZS, ZD		is lop9=0x1d7 & ZS & ZD		{
	#  1110 1011 1sss ssss 1111 xxxx xddd dddd
	#    s: corresponds to zs
	#    d: corresponds to zd
	#    x: appear to be unused bits (don't care)
	#  1110 1011 1001 0010 1111 1111 1100 0101	->	MOVSS 0x12[FSR2], 0x45[FSR2] 	
	ZD = ZS;
}

:PUSHL imm8			is op8=0xfa & imm8			{ 
	#  1111 1010 kkkk kkkk
	#  1111 1010 0001 0010	->	PUSHL #0x12
	local loc = FSR2;
	*[DATA]:1 loc = imm8;
	FSR2 = loc - 1;
}

:SUBFSR xFSRn, imm6	is op8=0xe9 & xfsr<3 & xFSRn & imm6	{ 
	#  1110 1001 ffkk kkkk
	#  1110 1001 0101 0010	-> SUBFSR FSR1, 0x12
	xFSRn = xFSRn - zext(imm6);
}

:SUBULNK imm6		is op8=0xe9 & xfsr=3 & imm6	{ 
	#  1110 1001 11kk kkkk
	#  1110 1001 1101 0010	->	SUBULNK #0x12
	retAddr:4 = 0;
	pop(retAddr);
	FSR2 = FSR2 - zext(imm6);
	return [retAddr];
}
