917 lines
20 KiB
Plaintext
917 lines
20 KiB
Plaintext
#
|
|
# PIC-17C7xx Instruction Section
|
|
# includes token definitions, macros, sub-constructors and instruction definitions
|
|
#
|
|
|
|
# 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)
|
|
op16 = (0,15)
|
|
op8 = (8,15)
|
|
op7 = (9,15)
|
|
op6 = (10,15)
|
|
op5 = (11,15)
|
|
op3 = (13,15)
|
|
t = (9,9)
|
|
d = (8,8)
|
|
s = (8,8)
|
|
i = (8,8)
|
|
b3 = (8,10)
|
|
p5_4 = (12,12)
|
|
p5_3 = (11,11)
|
|
p5 = (8,12)
|
|
p5reg = (8,12)
|
|
u4hi = (4,7)
|
|
u4lo = (0,3)
|
|
f8 = (0,7)
|
|
f8hi = (5,7)
|
|
f8_4 = (4,4)
|
|
f8_3 = (3,3)
|
|
f8reg = (0,4)
|
|
k8 = (0,7)
|
|
k8_h = (4,7)
|
|
k8_l = (0,3)
|
|
k13 = (0,12)
|
|
;
|
|
|
|
attach variables [ f8reg p5reg ] [
|
|
INDF0 FSR0 PCL PCLATH ALUSTA T0STA CPUSTA INTSTA
|
|
INDF1 FSR1 WREG TMR0L TMR0H TBLPTRL TBLPTRH BSR
|
|
_ _ _ _ _ _ _ _
|
|
PRODL PRODH _ _ _ _ _ _
|
|
];
|
|
|
|
attach variables [ t ] [ TBLATL TBLATH ];
|
|
|
|
#
|
|
# Special PIC-17 Operations
|
|
#
|
|
|
|
# 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) {
|
|
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]:2 STKPTR = val;
|
|
STKPTR = STKPTR + 2;
|
|
}
|
|
|
|
macro pop(rval) { # TODO: Uncertain about this !!
|
|
# CheckStackUnderflow();
|
|
STKPTR = STKPTR - 2;
|
|
rval = *[HWSTACK]:2 STKPTR;
|
|
}
|
|
|
|
#
|
|
# SUB-CONSTRUCTORS
|
|
#
|
|
|
|
# PC register write - instruction must set PCLATH/PCL and perform branch operation
|
|
fPC: "PC" is f8=0x02 { export PCL; }
|
|
pPC: "PC" is p5=0x02 { export PCL; }
|
|
|
|
# ALUSTA register
|
|
fALUSTA: f8reg is f8=0x04 & f8reg { export f8reg; }
|
|
#pALUSTA: p5reg is p5=0x04 & p5reg { export p5reg; }
|
|
|
|
#
|
|
# f Register subconstructors
|
|
#
|
|
|
|
# 0x00-0x0f Unbanked registers
|
|
fREGLoc: f8reg is f8hi=0 & f8_4=0 & f8reg { export f8reg; }
|
|
|
|
# 0x10-0x1f Banked registers
|
|
fREGLoc: f8 is f8hi=0 & f8_4=1 & f8_3=0 & f8 { ptr:2 = (zext(BSR & 0x0f) << 8) + f8; export *[DATA]:1 ptr; }
|
|
|
|
# 0x18-0x19 Unbanked registers (PRODL,PRODH)
|
|
fREGLoc: f8reg is f8=0x18 & f8reg { export f8reg; }
|
|
fREGLoc: f8reg is f8=0x19 & f8reg { export f8reg; }
|
|
|
|
# Unbanked general purpose RAM
|
|
fREGLoc: f8 is f8hi=0 & f8_4=1 & f8_3=1 & f8 { export *[DATA]:1 f8; }
|
|
|
|
# Banked general purpose RAM
|
|
fREGLoc: f8 is f8 { ptr:2 = (zext(BSR & 0xf0) << 4) + f8; export *[DATA]:1 ptr; }
|
|
|
|
|
|
# Indirect File Register access - INDF0
|
|
fREGLoc: f8reg is f8=0x00 & f8reg {
|
|
addr:1 = FSR0;
|
|
val:1 = ((FS10 == 0x1) * 1) + ((FS10 == 0x0) * -1);
|
|
FSR0 = addr + val;
|
|
export *[DATA]:1 addr;
|
|
}
|
|
|
|
# Indirect File Register access - INDF1
|
|
fREGLoc: f8reg is f8=0x08 & f8reg {
|
|
addr:1 = FSR1;
|
|
val:1 = ((FS32 == 0x1) * 1) + ((FS32 == 0x0) * -1);
|
|
FSR1 = addr + val;
|
|
export *[DATA]:1 addr;
|
|
}
|
|
|
|
|
|
#
|
|
# p Register subconstructors
|
|
#
|
|
|
|
# 0x00-0x0f Unbanked registers
|
|
pREGLoc: p5reg is p5_4=0 & p5reg { export p5reg; }
|
|
|
|
# 0x10-0x17 Banked registers
|
|
pREGLoc: p5 is p5_4=1 & p5_3=0 & p5 { ptr:2 = (zext(BSR & 0x0f) << 8) + p5; export *[DATA]:1 ptr; }
|
|
|
|
# 0x18-0x19 Unbanked registers (PRODL,PRODH)
|
|
pREGLoc: p5reg is p5=0x18 & p5reg { export p5reg; }
|
|
pREGLoc: p5reg is p5=0x19 & p5reg { export p5reg; }
|
|
|
|
# Unbanked general purpose RAM
|
|
pREGLoc: p5 is p5_4=1 & p5_3=1 & p5 { export *[DATA]:1 p5; }
|
|
|
|
# Indirect File Register access - INDF0
|
|
pREGLoc: p5reg is p5=0x00 & p5reg {
|
|
addr:1 = FSR0;
|
|
val:1 = ((FS10 == 0x1) * 1) + ((FS10 == 0x0) * -1);
|
|
FSR0 = addr + val;
|
|
export *[DATA]:1 addr;
|
|
}
|
|
|
|
# Indirect File Register access - INDF1
|
|
pREGLoc: p5reg is p5=0x08 & p5reg {
|
|
addr:1 = FSR1;
|
|
val:1 = ((FS32 == 0x1) * 1) + ((FS32 == 0x0) * -1);
|
|
FSR1 = addr + val;
|
|
export *[DATA]:1 addr;
|
|
}
|
|
|
|
|
|
# Direct File register data
|
|
srcFREG: fREGLoc is fREGLoc { export fREGLoc; }
|
|
|
|
# PCL read - latch PC into PCL and PCLATH
|
|
srcFREG: "PC" is f8=0x02 {
|
|
PCLAT = inst_start;
|
|
export PCL;
|
|
}
|
|
|
|
# Destination register (always fREGLoc)
|
|
destFREG: fREGLoc is fREGLoc { export fREGLoc; }
|
|
|
|
# Destination register (either fREGLoc or WREG)
|
|
destREG: "0" is d=0 { export WREG; }
|
|
destREG: "1" is d=1 & fREGLoc { export fREGLoc; }
|
|
|
|
# Direct File register data
|
|
srcPREG: pREGLoc is pREGLoc { export pREGLoc; }
|
|
|
|
# PCL read - latch PC into PCL and PCLATH
|
|
srcPREG: "PC" is p5=0x02 {
|
|
PCLAT = inst_start;
|
|
export PCL;
|
|
}
|
|
|
|
# Destination register (always pREGLoc)
|
|
destPREG: pREGLoc is pREGLoc { export pREGLoc; }
|
|
|
|
# Destination operand representation (w: W register is destination; f: specified fREG is destination)
|
|
D: "w" is d=0 { }
|
|
D: "f" is d=1 { }
|
|
|
|
# s-flag used by those instructions which can optionally store result in both srcFREG and WREG
|
|
S: "0" is s=0 { }
|
|
S: "1" is s=1 { }
|
|
|
|
# Table read/write i-flag
|
|
I: "0" is i=0 { }
|
|
I: "1" is i=1 { }
|
|
|
|
# Table read/write t-flag identifies table latch register (high or low byte)
|
|
T: t is t { export t; }
|
|
|
|
# Relative instruction location with an 8K page
|
|
shortAddr: nLoc is k13 [ nLoc = (inst_next & 0xe000) + k13; ] {
|
|
tmp:2 = nLoc:2 >> 8;
|
|
PCLATH = tmp:1;
|
|
export *[CODE]:2 nLoc;
|
|
}
|
|
|
|
# Absolute instruction location within 64K space (PCLATH contain upper 8-bits)
|
|
longAddr: k8 is k8 {
|
|
addr:2 = (zext(PCLATH) << 8) + k8;
|
|
export addr;
|
|
}
|
|
|
|
# Skip instruction address
|
|
skipInst: inst_skip is op16 [ inst_skip = inst_next + 1; ] {export *[CODE]:2 inst_skip; }
|
|
|
|
# Immediate Data (Literal operation)
|
|
imm8: "#"k8 is k8 { export *[const]:1 k8; }
|
|
imm8h: "#"k8_h is k8_h { export *[const]:1 k8_h; }
|
|
imm8l: "#"k8_l is k8_l { export *[const]:1 k8_l; }
|
|
|
|
# Bit identifier
|
|
bit: "#"b3 is b3 { export *[const]:1 b3; }
|
|
|
|
|
|
#
|
|
# Instructions
|
|
#
|
|
|
|
:ADDLW imm8 is op8=0xb1 & imm8 {
|
|
# 1011 0001 kkkk kkkk
|
|
tmp1:1 = WREG;
|
|
tmp2:1 = imm8;
|
|
setAddFlags(tmp1, tmp2);
|
|
local tmp = tmp1 + tmp2;
|
|
WREG = tmp;
|
|
setResultFlags(tmp);
|
|
}
|
|
|
|
:ADDWF srcFREG, D is op7=0x07 & D & srcFREG & destREG {
|
|
# 0000 111d ffff ffff
|
|
tmp1:1 = srcFREG; # read only once!
|
|
tmp2:1 = WREG;
|
|
setAddFlags(tmp1, tmp2);
|
|
local tmp = tmp1 + tmp2;
|
|
destREG = tmp;
|
|
setResultFlags(tmp);
|
|
}
|
|
|
|
:ADDWF fPC, D is op7=0x07 & D & d=1 & fPC {
|
|
# 0000 111d ffff ffff
|
|
# 0000 1110 ffff ffff -> ADDWF PCL, w
|
|
addr:2 = inst_start >> 1; # Compenstate for CODE wordsize
|
|
addrHi:1 = addr(1);
|
|
PCLATH = addrHi;
|
|
addrLo:1 = addr:1;
|
|
tmpW:1 = WREG;
|
|
setAddFlags(addrLo, tmpW);
|
|
addrLo = addrLo + tmpW;
|
|
addr = (zext(addrHi) << 8) + zext(addrLo);
|
|
setResultFlags(addrLo);
|
|
goto [addr];
|
|
}
|
|
|
|
:ADDWFC srcFREG, D is op7=0x08 & D & srcFREG & destREG {
|
|
# 0001 000d ffff ffff
|
|
local tmpC = C & 1;
|
|
tmp1:1 = srcFREG; # read only once!
|
|
tmp2:1 = WREG;
|
|
setAddCFlags(tmp1, tmp2);
|
|
local tmp = tmp1 + tmp2 + tmpC;
|
|
destREG = tmp;
|
|
setResultFlags(tmp);
|
|
}
|
|
|
|
:ANDLW imm8 is op8=0xb5 & imm8 {
|
|
# 1011 0101 kkkk kkkk
|
|
tmp:1 = WREG & imm8;
|
|
WREG = tmp;
|
|
setResultFlags(tmp);
|
|
}
|
|
|
|
:ANDWF srcFREG, D is op7=0x05 & D & srcFREG & destREG {
|
|
# 0000 101d ffff ffff
|
|
tmp:1 = srcFREG & WREG;
|
|
destREG = tmp;
|
|
setResultFlags(tmp);
|
|
}
|
|
|
|
:BCF srcFREG, bit is op5=0x11 & bit & srcFREG {
|
|
# 1000 1bbb ffff ffff
|
|
local bitmask = ~(1 << bit);
|
|
srcFREG = srcFREG & bitmask;
|
|
}
|
|
|
|
:BCF fALUSTA, bit is op5=0x11 & b3=0 & fALUSTA & bit {
|
|
# 1000 1000 0000 0100 -> BCF ALUSTA, #C
|
|
C = 0;
|
|
}
|
|
|
|
:BCF fALUSTA, bit is op5=0x11 & b3=1 & fALUSTA & bit {
|
|
# 1000 1001 0000 0100 -> BCF ALUSTA, #DC
|
|
DC = 0;
|
|
}
|
|
|
|
:BCF fALUSTA, bit is op5=0x11 & b3=2 & fALUSTA & bit {
|
|
# 1000 1010 0000 0100 -> BCF ALUSTA, #Z
|
|
Z = 0;
|
|
}
|
|
|
|
:BCF fALUSTA, bit is op5=0x11 & b3=3 & fALUSTA & bit {
|
|
# 1000 1011 0000 0100 -> BCF ALUSTA, #OV
|
|
OV = 0;
|
|
}
|
|
|
|
:BCF fALUSTA, bit is op5=0x11 & b3=4 & fALUSTA & bit {
|
|
# 1000 1100 0000 0100 -> BCF ALUSTA, #FS0
|
|
FS10 = FS10 & 0x2;
|
|
}
|
|
|
|
:BCF fALUSTA, bit is op5=0x11 & b3=5 & fALUSTA & bit {
|
|
# 1000 1101 0000 0100 -> BCF ALUSTA, #FS1
|
|
FS10 = FS10 & 0x1;
|
|
}
|
|
|
|
:BCF fALUSTA, bit is op5=0x11 & b3=6 & fALUSTA & bit {
|
|
# 1000 1110 0000 0100 -> BCF ALUSTA, #FS2
|
|
FS32 = FS32 & 0x2;
|
|
}
|
|
|
|
:BCF fALUSTA, bit is op5=0x11 & b3=7 & fALUSTA & bit {
|
|
# 1000 1111 0000 0100 -> BCF ALUSTA, #FS3
|
|
FS32 = FS32 & 0x1;
|
|
}
|
|
|
|
:BSF srcFREG, bit is op5=0x10 & bit & srcFREG {
|
|
# 1000 0bbb ffff ffff
|
|
local bitmask = 1 << bit;
|
|
srcFREG = srcFREG | bitmask;
|
|
}
|
|
|
|
:BSF fALUSTA, bit is op5=0x10 & b3=0 & bit & fALUSTA {
|
|
# 1000 0000 0000 0100 -> BSF ALUSTA, #C
|
|
C = 1;
|
|
}
|
|
|
|
:BSF fALUSTA, bit is op5=0x10 & b3=1 & bit & fALUSTA {
|
|
# 1000 0000 0000 0100 -> BSF ALUSTA, #DC
|
|
DC = 1;
|
|
}
|
|
|
|
:BSF fALUSTA, bit is op5=0x10 & b3=2 & bit & fALUSTA {
|
|
# 1000 0000 0000 0100 -> BSF ALUSTA, #Z
|
|
Z = 1;
|
|
}
|
|
|
|
:BSF fALUSTA, bit is op5=0x10 & b3=3 & bit & fALUSTA {
|
|
# 1000 0000 0000 0100 -> BSF ALUSTA, #OV
|
|
OV = 1;
|
|
}
|
|
|
|
:BSF fALUSTA, bit is op5=0x10 & b3=4 & bit & fALUSTA {
|
|
# 1000 0000 0000 0100 -> BSF ALUSTA, #FS0
|
|
FS10 = FS10 | 0x1;
|
|
}
|
|
|
|
:BSF fALUSTA, bit is op5=0x10 & b3=5 & bit & fALUSTA {
|
|
# 1000 0000 0000 0100 -> BSF ALUSTA, #FS1
|
|
FS10 = FS10 | 0x2;
|
|
}
|
|
|
|
:BSF fALUSTA, bit is op5=0x10 & b3=6 & bit & fALUSTA {
|
|
# 1000 0000 0000 0100 -> BSF ALUSTA, #FS2
|
|
FS32 = FS32 | 0x1;
|
|
}
|
|
|
|
:BSF fALUSTA, bit is op5=0x10 & b3=7 & bit & fALUSTA {
|
|
# 1000 0000 0000 0100 -> BSF ALUSTA, #FS3
|
|
FS32 = FS32 | 0x2;
|
|
}
|
|
|
|
:BTFSC srcFREG, bit is op5=0x13 & bit & srcFREG & skipInst {
|
|
# 1001 1bbb ffff ffff
|
|
local bitmask = 1 << bit;
|
|
local tmp = srcFREG & bitmask;
|
|
if (tmp == 0) goto skipInst;
|
|
}
|
|
|
|
:BTFSC fALUSTA, bit is op5=0x13 & b3=0 & bit & fALUSTA & skipInst {
|
|
# 1001 1000 0000 0100 -> BTFSC STATUS, #C
|
|
if (C == 0) goto skipInst;
|
|
}
|
|
|
|
:BTFSC fALUSTA, bit is op5=0x13 & b3=1 & bit & fALUSTA & skipInst {
|
|
# 1001 1001 0000 0100 -> BTFSC STATUS, #DC
|
|
if (DC == 0) goto skipInst;
|
|
}
|
|
|
|
:BTFSC fALUSTA, bit is op5=0x13 & b3=2 & bit & fALUSTA & skipInst {
|
|
# 1001 1010 0000 0100 -> BTFSC STATUS, #Z
|
|
if (Z == 0) goto skipInst;
|
|
}
|
|
|
|
:BTFSC fALUSTA, bit is op5=0x13 & b3=3 & bit & fALUSTA & skipInst {
|
|
# 1001 1011 0000 0100 -> BTFSC STATUS, #OV
|
|
if (OV == 0) goto skipInst;
|
|
}
|
|
|
|
:BTFSS srcFREG, bit is op5=0x12 & bit & srcFREG & skipInst {
|
|
# 1001 0bbb ffff ffff
|
|
local bitmask = 1 << bit;
|
|
local tmp = srcFREG & bitmask;
|
|
if (tmp != 0) goto skipInst;
|
|
}
|
|
|
|
:BTFSS fALUSTA, bit is op5=0x12 & b3=0 & bit & fALUSTA & skipInst {
|
|
# 1001 1000 0000 0100 -> BTFSS STATUS, #C
|
|
if (C != 0) goto skipInst;
|
|
}
|
|
|
|
:BTFSS fALUSTA, bit is op5=0x12 & b3=1 & bit & fALUSTA & skipInst {
|
|
# 1001 1001 0000 0100 -> BTFSS STATUS, #DC
|
|
if (DC != 0) goto skipInst;
|
|
}
|
|
|
|
:BTFSS fALUSTA, bit is op5=0x12 & b3=2 & bit & fALUSTA & skipInst {
|
|
# 1001 1010 0000 0100 -> BTFSS STATUS, #Z
|
|
if (Z != 0) goto skipInst;
|
|
}
|
|
|
|
:BTFSS fALUSTA, bit is op5=0x12 & b3=3 & bit & fALUSTA & skipInst {
|
|
# 1001 1011 0000 0100 -> BTFSS STATUS, #OV
|
|
if (OV != 0) goto skipInst;
|
|
}
|
|
|
|
:BTG srcFREG, bit is op5=0x7 & bit & srcFREG & skipInst {
|
|
# 0011 1bbb ffff ffff
|
|
local bitmask = 1 << bit;
|
|
tmp:1 = srcFREG;
|
|
srcFREG = ~(tmp & bitmask) | (tmp & ~bitmask);
|
|
}
|
|
|
|
:CALL shortAddr is op3=0x7 & shortAddr {
|
|
# 111k kkkk kkkk kkkk
|
|
push(&:2 inst_next);
|
|
call shortAddr;
|
|
}
|
|
|
|
# Special case for Call which appears to correspond to uninitialized
|
|
:BADCALL shortAddr is op16=0xffff & shortAddr { addr:2 = shortAddr; return [addr]; }
|
|
|
|
:CLRF destFREG, S is op7=0x14 & s=0 & S & destFREG {
|
|
# 0010 1000 ffff ffff
|
|
destFREG = 0;
|
|
WREG = 0;
|
|
}
|
|
|
|
:CLRF destFREG, S is op7=0x14 & s=1 & S & destFREG {
|
|
# 0010 1001 ffff ffff
|
|
destFREG = 0;
|
|
}
|
|
|
|
:CLRF fALUSTA, S is op7=0x14 & s=0 & S & fALUSTA {
|
|
# 0010 1000 0000 0100
|
|
C = 0;
|
|
DC = 0;
|
|
Z = 0;
|
|
OV = 0;
|
|
FS10 = 0;
|
|
FS32 = 0;
|
|
WREG = 0;
|
|
}
|
|
|
|
:CLRF fALUSTA, S is op7=0x14 & s=1 & S & fALUSTA {
|
|
# 0010 1001 0000 0100
|
|
C = 0;
|
|
DC = 0;
|
|
Z = 0;
|
|
OV = 0;
|
|
FS10 = 0;
|
|
FS32 = 0;
|
|
}
|
|
|
|
:CLRWDT is op16=0x0004 {
|
|
# 0000 0000 0000 0100
|
|
clearWatchDogTimer();
|
|
}
|
|
|
|
:COMF srcFREG, D is op7=0x09 & D & srcFREG & destREG {
|
|
# 0001 001d ffff ffff
|
|
tmp:1 = ~srcFREG;
|
|
destREG = tmp;
|
|
setResultFlags(tmp);
|
|
}
|
|
|
|
:CPFSEQ srcFREG is op8=0x31 & srcFREG & skipInst {
|
|
# 0011 0001 ffff ffff
|
|
if (srcFREG == WREG) goto skipInst;
|
|
}
|
|
|
|
:CPFSGT srcFREG is op8=0x32 & srcFREG & skipInst {
|
|
# 0011 0010 ffff ffff
|
|
if (srcFREG > WREG) goto skipInst;
|
|
}
|
|
|
|
:CPFSLT srcFREG is op8=0x30 & srcFREG & skipInst {
|
|
# 0011 0000 ffff ffff
|
|
if (srcFREG < WREG) goto skipInst;
|
|
}
|
|
|
|
:DAW destFREG, S is op7=0x17 & s=0 & S & destFREG {
|
|
# 0010 1110 ffff ffff
|
|
tmp:1 = decimalAdjust(WREG);
|
|
destFREG = tmp;
|
|
WREG = tmp;
|
|
}
|
|
|
|
:DAW destFREG, S is op7=0x17 & s=1 & S & destFREG {
|
|
# 0010 1111 ffff ffff
|
|
tmp:1 = decimalAdjust(WREG);
|
|
destFREG = tmp;
|
|
setResultFlags(tmp);
|
|
}
|
|
|
|
:DECF srcFREG, D is op7=0x03 & D & srcFREG & destREG {
|
|
# 0000 011d ffff ffff
|
|
tmp:1 = srcFREG;
|
|
setSubtractFlags(tmp, 1);
|
|
tmp = tmp - 1;
|
|
destREG = tmp;
|
|
setResultFlags(tmp);
|
|
}
|
|
|
|
:DECFSZ srcFREG, D is op7=0x0b & D & srcFREG & destREG & skipInst {
|
|
# 0001 011d ffff ffff
|
|
val:1 = srcFREG - 1;
|
|
destREG = val;
|
|
if (val == 0) goto skipInst;
|
|
}
|
|
|
|
:DCFSNZ srcFREG, D is op7=0x13 & D & srcFREG & destREG & skipInst {
|
|
# 0010 011d ffff ffff
|
|
val:1 = srcFREG - 1;
|
|
destREG = val;
|
|
if (val != 0) goto skipInst;
|
|
}
|
|
|
|
:GOTO shortAddr is op3=0x6 & shortAddr {
|
|
# 110k kkkk kkkk kkkk
|
|
goto shortAddr;
|
|
}
|
|
|
|
:INCF srcFREG, D is op7=0x0a & D & srcFREG & destREG {
|
|
# 0001 010d ffff ffff
|
|
tmp:1 = srcFREG; # read once only!
|
|
setAddFlags(tmp, 1);
|
|
tmp = tmp + 1;
|
|
destREG = tmp;
|
|
setResultFlags(tmp);
|
|
}
|
|
|
|
:INCFSZ srcFREG, D is op7=0x0f & D & srcFREG & destREG & skipInst {
|
|
# 0001 111d ffff ffff
|
|
val:1 = srcFREG + 1;
|
|
destREG = val;
|
|
if (val == 0) goto skipInst;
|
|
}
|
|
|
|
:INFSNZ srcFREG, D is op7=0x12 & D & srcFREG & destREG & skipInst {
|
|
# 0010 010d ffff ffff
|
|
val:1 = srcFREG + 1;
|
|
destREG = val;
|
|
if (val != 0) goto skipInst;
|
|
}
|
|
|
|
:IORLW imm8 is op8=0xb3 & imm8 {
|
|
# 1011 0011 kkkk kkkk
|
|
tmp:1 = WREG | imm8;
|
|
WREG = tmp;
|
|
setResultFlags(tmp);
|
|
}
|
|
|
|
:IORWF srcFREG, D is op7=0x04 & D & srcFREG & destREG {
|
|
# 0000 100d ffff ffff
|
|
tmp:1 = WREG | srcFREG;
|
|
destREG = tmp;
|
|
setResultFlags(tmp);
|
|
}
|
|
|
|
:LCALL longAddr is op8=0xb7 & longAddr {
|
|
# 1011 0111 kkkk kkkk
|
|
push(&:2 inst_next);
|
|
call [longAddr];
|
|
}
|
|
|
|
:MOVFP srcFREG, destPREG is op3=0x3 & srcFREG & destPREG {
|
|
# 011p pppp ffff ffff
|
|
destPREG = srcFREG;
|
|
}
|
|
|
|
:MOVFP srcFREG, pPC is op3=0x3 & srcFREG & pPC {
|
|
# 0110 0010 ffff ffff
|
|
addr:2 = (zext(PCLATH) << 8) + zext(srcFREG);
|
|
goto [addr];
|
|
}
|
|
|
|
:MOVLB imm8l is op8=0xb8 & u4hi=0 & imm8l {
|
|
# 1011 1000 0000 kkkk
|
|
BSR = (BSR & 0xf0) | imm8l;
|
|
}
|
|
|
|
:MOVLR imm8h is op7=0x5d & u4lo=0 & imm8h {
|
|
# 1011 101x kkkk 0000
|
|
BSR = (BSR & 0x0f) | (imm8h << 4);
|
|
}
|
|
|
|
:MOVLW imm8 is op8=0xb0 & imm8 {
|
|
# 1011 0000 kkkk kkkk
|
|
WREG = imm8;
|
|
}
|
|
|
|
:MOVPF srcPREG, destFREG is op3=0x2 & srcPREG & destFREG {
|
|
# 010p pppp ffff ffff
|
|
tmp:1 = srcPREG;
|
|
destFREG = tmp;
|
|
setResultFlags(tmp);
|
|
}
|
|
|
|
:MOVPF srcPREG, fPC is op3=0x2 & srcPREG & fPC {
|
|
tmp:1 = srcPREG;
|
|
addr:2 = (zext(PCLATH) << 8) + zext(tmp);
|
|
setResultFlags(tmp);
|
|
goto [addr];
|
|
}
|
|
|
|
:MOVWF destFREG is op8=0x01 & destFREG {
|
|
# 0000 0001 ffff ffff
|
|
destFREG = WREG;
|
|
}
|
|
|
|
:MOVWF fPC is op8=0x01 & fPC {
|
|
addr:2 = (zext(PCLATH) << 8) + zext(WREG);
|
|
goto [addr];
|
|
}
|
|
|
|
:MULLW imm8 is op8=0xbc & imm8 {
|
|
# 1011 1100 kkkk kkkk
|
|
PROD = zext(WREG) * zext(imm8);
|
|
}
|
|
|
|
:MULLWF srcFREG is op8=0x34 & srcFREG {
|
|
# 0011 0100 ffff ffff
|
|
PROD = zext(WREG) * zext(srcFREG);
|
|
}
|
|
|
|
:NEGW destFREG, S is op7=0x16 & s=0 & S & destFREG {
|
|
# 0010 110s ffff ffff
|
|
tmp:1 = -WREG;
|
|
destFREG = tmp;
|
|
WREG = tmp;
|
|
C = (tmp s< 0);
|
|
OV = sborrow(0,tmp);
|
|
setResultFlags(tmp);
|
|
}
|
|
|
|
:NEGW destFREG, S is op7=0x16 & s=1 & S & destFREG {
|
|
# 0010 110s ffff ffff
|
|
tmp:1 = -WREG;
|
|
destFREG = tmp;
|
|
C = (tmp s< 0);
|
|
OV = sborrow(0,tmp);
|
|
setResultFlags(tmp);
|
|
}
|
|
|
|
:NOP is op16=0x0 { }
|
|
|
|
:RETFIE is op16=0x0005 {
|
|
# 0000 0000 0000 0101
|
|
retAddr:2 = 0;
|
|
pop(retAddr);
|
|
return [retAddr];
|
|
}
|
|
|
|
:RETLW imm8 is op8=0xb6 & imm8 {
|
|
# 1011 0110 kkkk kkkk
|
|
WREG = imm8;
|
|
retAddr:2 = 0;
|
|
pop(retAddr);
|
|
return [retAddr];
|
|
}
|
|
|
|
:RETURN is op16=0x0002 {
|
|
# 0000 0000 0000 0010
|
|
retAddr:2 = 0;
|
|
pop(retAddr);
|
|
return [retAddr];
|
|
}
|
|
|
|
:RLCF srcFREG, D is op7=0x0d & D & srcFREG & destREG {
|
|
# 0001 101d ffff ffff
|
|
local tmpC = C;
|
|
val:1 = srcFREG;
|
|
C = (val s< 0);
|
|
val = (val << 1) | tmpC;
|
|
destREG = val;
|
|
}
|
|
|
|
:RLNCF srcFREG, D is op7=0x11 & D & srcFREG & destREG {
|
|
# 0010 001d ffff ffff
|
|
tmp:1 = srcFREG << 1;
|
|
destREG = tmp;
|
|
}
|
|
|
|
:RRCF srcFREG, D is op7=0x0c & D & srcFREG & destREG {
|
|
# 0001 100d ffff ffff
|
|
local tmpC = C << 7;
|
|
tmp:1 = srcFREG;
|
|
C = (tmp & 1) != 0;
|
|
tmp = (tmp >> 1) | tmpC;
|
|
destREG = tmp;
|
|
}
|
|
|
|
:RRNCF srcFREG, D is op7=0x10 & D & srcFREG & destREG {
|
|
# 0010 000d ffff ffff
|
|
tmp:1 = srcFREG >> 1;
|
|
destREG = tmp;
|
|
}
|
|
|
|
:SETF destFREG, S is op7=0x15 & s=0 & S & destFREG {
|
|
# 0010 1010 ffff ffff
|
|
destFREG = 0xff;
|
|
WREG = 0xff;
|
|
}
|
|
|
|
:SETF destFREG, S is op7=0x15 & s=1 & S & destFREG {
|
|
# 0010 1011 ffff ffff
|
|
destFREG = 0xff;
|
|
}
|
|
|
|
:SETF fALUSTA, S is op7=0x15 & s=0 & S & fALUSTA {
|
|
# 0010 1010 0000 0100
|
|
C = 1;
|
|
DC = 1;
|
|
Z = 1;
|
|
OV = 1;
|
|
FS10 = 0x3;
|
|
FS32 = 0x3;
|
|
WREG = 0xff;
|
|
}
|
|
|
|
:SETF fALUSTA, S is op7=0x15 & s=1 & S & fALUSTA {
|
|
# 0010 1011 0000 0100
|
|
C = 1;
|
|
DC = 1;
|
|
Z = 1;
|
|
OV = 1;
|
|
FS10 = 0x3;
|
|
FS32 = 0x3;
|
|
}
|
|
|
|
:SLEEP is op16=0x0003 {
|
|
# 0000 0000 0000 0011
|
|
sleep();
|
|
}
|
|
|
|
:SUBLW imm8 is op8=0xb2 & imm8 {
|
|
# 1011 0010 kkkk kkkk
|
|
tmp:1 = imm8;
|
|
tmpW:1 = WREG;
|
|
setSubtractFlags(tmp, tmpW);
|
|
tmp = tmp - tmpW;
|
|
WREG = tmp;
|
|
setResultFlags(tmp);
|
|
}
|
|
|
|
:SUBWF srcFREG, D is op7=0x02 & D & srcFREG & destREG {
|
|
# 0000 010d ffff ffff
|
|
tmp:1 = srcFREG;
|
|
tmpW:1 = WREG;
|
|
setSubtractFlags(tmp, tmpW);
|
|
tmp = tmp - tmpW;
|
|
destREG = tmp;
|
|
setResultFlags(tmp);
|
|
}
|
|
|
|
:SUBWFB srcFREG, D is op7=0x01 & D & srcFREG & destREG {
|
|
# 0000 001d ffff ffff
|
|
local notC = ~(C & 1);
|
|
tmp:1 = srcFREG;
|
|
tmpW:1 = WREG;
|
|
setSubtractCFlags(tmp, tmpW);
|
|
tmp = tmp - tmpW - notC;
|
|
destREG = tmp;
|
|
setResultFlags(tmp);
|
|
}
|
|
|
|
:SWAPF srcFREG, D is op7=0x0e & D & srcFREG & destREG {
|
|
# 0001 110d ffff ffff
|
|
tmp:1 = srcFREG;
|
|
destREG = (tmp << 4) | (tmp >> 4);
|
|
}
|
|
|
|
:TABLRD T, I, destFREG is op6=0x2a & T & I & i & destFREG {
|
|
# 1010 10ti ffff ffff
|
|
destFREG = T;
|
|
ptr:2 = TBLPTR;
|
|
TBLAT = *[CODE]:2 ptr;
|
|
TBLPTR = ptr + i;
|
|
}
|
|
|
|
:TABLWT T, I, srcFREG is op6=0x2b & T & I & i & srcFREG {
|
|
# 1010 11ti ffff ffff
|
|
T = srcFREG;
|
|
ptr:2 = TBLPTR;
|
|
*[CODE]:2 ptr = TBLAT;
|
|
TBLPTR = ptr + i;
|
|
}
|
|
|
|
:TLRD T, destFREG is op6=0x28 & T & destFREG {
|
|
# 1010 00tx ffff ffff
|
|
destFREG = T;
|
|
}
|
|
|
|
:TLWT T, srcFREG is op6=0x29 & T & srcFREG {
|
|
# 1010 01tx ffff ffff
|
|
T = srcFREG;
|
|
}
|
|
|
|
:TSTFSZ srcFREG is op8=0x33 & srcFREG & skipInst {
|
|
# 0011 0011 ffff ffff
|
|
if (srcFREG == 0) goto skipInst;
|
|
}
|
|
|
|
:XORLW imm8 is op8=0xb4 & imm8 {
|
|
# 1011 0100 kkkk kkkk
|
|
tmp:1 = WREG ^ imm8;
|
|
WREG = tmp;
|
|
setResultFlags(tmp);
|
|
}
|
|
|
|
:XORWF srcFREG, D is op7=0x06 & D & srcFREG & destREG {
|
|
# 0000 110d ffff ffff
|
|
tmp:1 = WREG ^ srcFREG;
|
|
destREG = tmp;
|
|
setResultFlags(tmp);
|
|
}
|