1701 lines
48 KiB
Plaintext
1701 lines
48 KiB
Plaintext
#
|
|
# 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];
|
|
}
|