ghidra/Ghidra/Processors/PIC/data/languages/pic12_instructions.sinc

625 lines
16 KiB
Plaintext

#
# PIC-12 Instruction Section
# includes token definitions, macros, sub-constructors and instruction definitions
#
# Little-endian bit numbering
define token instr16(16)
op12 = (0,11)
op6 = (6,11)
op4 = (8,11)
op3 = (9,11)
d = (5,5)
b3 = (5,7)
f5 = (0,4)
f5h = (4,4)
k8 = (0,7)
k9 = (0,8)
;
#
# Unsupported Operations
#
define pcodeop clearWatchDogTimer;
define pcodeop sleep;
#
# MACROS
#
# Pack status bits into STATUS register
macro packStatus() {
# STATUS = (PA << $(STATUS_PA0_BIT))
# | (Z << $(STATUS_Z_BIT))
# | (DC << $(STATUS_DC_BIT))
# | (C << $(STATUS_C_BIT));
}
# Unpack status bits from STATUS register
macro unpackStatus() {
# PA = (STATUS & $(STATUS_PA_MASK)) >> $(STATUS_PA0_BIT);
# Z = ((STATUS & $(STATUS_Z_MASK)) != 0);
# DC = ((STATUS & $(STATUS_DC_MASK)) != 0);
# C = ((STATUS & $(STATUS_C_MASK)) != 0);
}
macro setResultFlags(result) {
Z = (result == 0);
}
macro setAddCCarryFlag(op1,op2) {
C = (carry(op1,C) || carry(op2,op1 + C));
}
macro setAddCDigitCarryFlag(op1,op2) {
# op1 and op2 are assumed to be 8-bit values
local tmp1 = op1 << 4;
local tmp2 = op2 << 4;
DC = (carry(tmp1,DC) || carry(tmp2,tmp1 + DC));
}
macro setAddCFlags(op1,op2) {
setAddCCarryFlag(op1,op2);
setAddCDigitCarryFlag(op1,op2);
}
macro setAddFlags(op1,op2) {
C = carry(op1,op2);
DC = carry(op1<<4,op2<<4);
}
macro setSubtractCCarryFlag(op1,op2) {
local notC = ~C;
C = ((op1 < notC) || (op2 < (op1 - notC)));
}
macro setSubtractCDigitCarryFlag(op1,op2) {
# op1 and op2 are assumed to be 8-bit values
local notDC = ~DC;
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);
}
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));
}
macro push(val) { # TODO: Uncertain about this !!
*[HWSTACK]:2 STKPTR = val;
STKPTR = STKPTR + 2;
}
macro pop(val) { # TODO: Uncertain about this !!
STKPTR = STKPTR - 2;
val = *[HWSTACK]:2 STKPTR;
}
#
# SUB-CONSTRUCTORS
#
# File register index (f5!=0): bank selection determined by FSR<5:6> bits
fREGLoc: f5 is f5 {
addr:1 = (FSR & $(FSR_BSEL_MASK)) + f5;
export *[DATA]:1 addr;
}
# File register index (f5=0): INDF use implies indirect data access using FSR value
fREGLoc: "INDF" is f5=0 {
addr:1 = FSR; # only low order 7-bits are used for indirect address
export *[DATA]:1 addr;
}
# File register index : low 16-bytes of each bank always mapped to Bank-0
fREGLoc: f5 is f5h=0x0 & f5 { export *[DATA]:1 f5; }
# Special File Registers which have been mirrored into the register space
# to improve decompiler results
fREGLoc: "STATUS" is f5=0x03 { packStatus(); export STATUS; }
fREGLoc: "FSR" is f5=0x04 { export FSR; }
fREGLoc: "PCL" is f5=0x02 { export PCL; }
# File register index (bank selection determined by RP bits in STATUS reg)
srcREG: fREGLoc is fREGLoc { export fREGLoc; }
#srcREG: "STATUS" is f5=0x03 { packStatus(); export STATUS; }
#srcREG: "FSR" is f5=0x04 { export FSR; }
srcREG: "PCL" is f5=0x02 {
# PCL and PA1:PA0 is latched
addr:2 = inst_start >> 1; # Compenstate for CODE wordsize
PCL = addr:1;
addr = (addr >> 9) & 0x3;
PA = addr:1;
export PCL;
}
# Destination register (either srcREG or W)
destREG: "0" is d=0 { export W; }
destREG: "1" is d=1 & srcREG { export srcREG; }
#destREG: "1" is d=1 & f5=0x03 { export STATUS; }
#destREG: "1" is d=1 & f5=0x04 { export FSR; }
#destREG: "1" is d=1 & f5=0x02 {
# # Storing to PCL causes a branch,
# # PC<8> is always cleared for CALL and modifying instructions.
# # The MOVWF, ADDWF, BSF and BCF definition below has a specific case to handle this write to PCL
# export PCL;
#}
#destREG: "1" is d=1 & f5=0x00 & fREGLoc {
# # INDF use (indirect data access)
# export *[DATA]:1 fREGLoc;
#}
# Destination operand representation (w: W register is destination; f: specified srcREG is destination)
D: "w" is d=0 { }
D: "f" is d=1 { }
# Absolute addresses generated from k8 or k9 and STATUS.PA
absAddr8: k8 is k8 {
addr:2 = (zext(PA) << 9) + k8;
export addr;
}
absAddr9: k9 is k9 {
addr:2 = (zext(PA) << 9) + k9;
export addr;
}
# Skip instruction address
skipInst: inst_skip is op12 [ inst_skip = inst_next + 1; ] {export *[CODE]:2 inst_skip; }
# Immediate Data (Literal operation)
imm8: "#"k8 is k8 { export *[const]:1 k8; }
# Bit identifier
bit: "#"b3 is b3 { export *[const]:1 b3; }
# PC register write - instruction must set PC with PCLATH/PCL and perform branch operation
pcl: "PC" is f5=0x02 { export PCL; }
# STATUS register
status: "STATUS" is f5=0x03 { export STATUS; }
#
# BYTE-ORIENTED FILE REGISTER OPERATIONS
#
:ADDWF srcREG, D is op6=0x07 & srcREG & D & destREG {
# ---- 0001 11df ffff
# 0000 0001 1100 0000 -> ADDWF INDF, 0
# 0000 0001 1110 0000 -> ADDWF INDF, 1
# 0000 0001 1101 0010 -> ADDWF 0x12, 0
# 0000 0001 1111 0010 -> ADDWF 0x12, 1
tmp:1 = srcREG;
setAddFlags(W, tmp);
tmp = W + tmp;
destREG = tmp;
setResultFlags(tmp);
}
:ADDWF pcl, D is op6=0x07 & D & pcl {
# ---- 0001 11df ffff
# 0000 0001 1110 0010 -> ADDWF PCL, w, ACCESS
addr:2 = (inst_start >> 1) & 0x3f; # shift compenstates for CODE wordsize
tmpLo:1 = addr:1;
PA = addr(1);
setAddFlags(tmpLo, W);
tmpLo = tmpLo + W;
setResultFlags(tmpLo);
addr = (zext(PA) << 9) + zext(tmpLo);
PCL = tmpLo;
goto [addr];
}
:ANDLW imm8 is op4=0xe & imm8 {
# ---- 1110 kkkk kkkk
# 0000 1110 0001 0010 -> ANDLW #0x12
W = W & imm8;
setResultFlags(W);
}
:ANDWF srcREG, D is op6=0x05 & srcREG & D & destREG {
# ---- 0001 01df ffff
# 0000 0001 0100 0000 -> ANDWF INDF, 0
# 0000 0001 0110 0000 -> ANDWF INDF, 1
# 0000 0001 0101 0010 -> ANDWF 0x12, 0
# 0000 0001 0111 0010 -> ANDWF 0x12, 1
tmp:1 = W & srcREG;
destREG = tmp;
setResultFlags(tmp);
}
:BCF srcREG, bit is op4=0x4 & bit & srcREG {
# ---- 0100 bbbf ffff
# 0000 0100 1000 0000 -> BCF INDF, #0x4
# 0000 0100 1001 0010 -> BCF 0x12, #0x4
local bitmask = ~(1 << bit);
srcREG = srcREG & bitmask;
}
:BCF status, bit is op4=0x4 & b3=0 & bit & status {
# ---- 0100 bbbf ffff
# 0000 0100 0000 0000 -> BCF STATUS, #C
C = 0;
local bitmask = ~(1 << bit);
STATUS = STATUS & bitmask;
}
:BCF status, bit is op4=0x4 & b3=1 & bit & status {
# ---- 0100 bbbf ffff
# 0000 0100 0010 0000 -> BCF STATUS, #DC
DC = 0;
local bitmask = ~(1 << bit);
STATUS = STATUS & bitmask;
}
:BCF status, bit is op4=0x4 & b3=2 & bit & status {
# ---- 0100 bbbf ffff
# 0000 0100 0100 0000 -> BCF STATUS, #Z
Z = 0;
local bitmask = ~(1 << bit);
STATUS = STATUS & bitmask;
}
:BCF status, bit is op4=0x4 & b3=5 & bit & status {
# ---- 0100 bbbf ffff
# 0000 0100 1010 0000 -> BCF STATUS, #PA0
PA = PA & 0x1;
local bitmask = ~(1 << bit);
STATUS = STATUS & bitmask;
}
:BCF status, bit is op4=0x4 & b3=6 & bit & status {
# ---- 0100 bbbf ffff
# 0000 0100 1100 0000 -> BCF STATUS, #PA1
PA = PA & 0x2;
local bitmask = ~(1 << bit);
STATUS = STATUS & bitmask;
}
:BSF srcREG, bit is op4=0x5 & bit & srcREG {
# ---- 0101 bbbf ffff
# 0000 0101 1000 0000 -> BSF INDF, #0x4
# 0000 0101 1001 0010 -> BSF 0x12, #0x4
local bitmask = 1 << bit;
srcREG = srcREG | bitmask;
}
:BSF status, bit is op4=0x5 & b3=0 & bit & status {
# ---- 0101 bbbf ffff
# 0000 0101 0000 0000 -> BSF STATUS, #C
C = 1;
local bitmask = 1 << bit;
STATUS = STATUS | bitmask;
}
:BSF status, bit is op4=0x5 & b3=1 & bit & status {
# ---- 0101 bbbf ffff
# 0000 0101 0010 0000 -> BSF STATUS, #DC
DC = 1;
local bitmask = 1 << bit;
STATUS = STATUS | bitmask;
}
:BSF status, bit is op4=0x5 & b3=2 & bit & status {
# ---- 0101 bbbf ffff
# 0000 0101 0100 0000 -> BSF STATUS, #Z
Z = 1;
local bitmask = 1 << bit;
STATUS = STATUS | bitmask;
}
:BSF status, bit is op4=0x5 & b3=5 & bit & status {
# ---- 0101 bbbf ffff
# 0000 0101 1010 0000 -> BSF STATUS, #PA0
PA = PA | 0x1;
local bitmask = 1 << bit;
STATUS = STATUS | bitmask;
}
:BSF status, bit is op4=0x5 & b3=6 & bit & status {
# ---- 0101 bbbf ffff
# 0000 0101 1100 0000 -> BSF STATUS, #PA1
PA = PA | 0x2;
local bitmask = 1 << bit;
STATUS = STATUS | bitmask;
}
:BTFSC srcREG, bit is op4=0x6 & bit & srcREG & skipInst {
# ---- 0110 bbbf ffff
# 0000 0110 1000 0000 -> BTFSC INDF, #0x4
# 0000 0110 1001 0010 -> BTFSC 0x12, #0x4
local bitmask = 1 << bit;
local tmp = srcREG & bitmask;
if (tmp == 0) goto skipInst;
}
:BTFSC status, bit is op4=0x6 & b3=0 & bit & status & skipInst {
# ---- 0110 bbbf ffff
# 0000 0110 0000 0000 -> BTFSC STATUS, #C
if (C == 0) goto skipInst;
}
:BTFSC status, bit is op4=0x6 & b3=1 & bit & status & skipInst {
# ---- 0110 bbbf ffff
# 0000 0110 0010 0000 -> BTFSC STATUS, #DC
if (DC == 0) goto skipInst;
}
:BTFSC status, bit is op4=0x6 & b3=2 & bit & status & skipInst {
# ---- 0110 bbbf ffff
# 0000 0110 0100 0000 -> BTFSC STATUS, #Z
if (Z == 0) goto skipInst;
}
:BTFSS srcREG, bit is op4=0x7 & bit & srcREG & skipInst {
# ---- 0111 bbbf ffff
# 0000 0111 1000 0000 -> BTFSS INDF, #0x4
# 0000 0111 1001 0010 -> BTFSS 0x12, #0x4
local bitmask = 1 << bit;
local tmp = srcREG & bitmask;
if (tmp != 0) goto skipInst;
}
:BTFSS status, bit is op4=0x7 & b3=0 & bit & status & skipInst {
# ---- 0111 bbbf ffff
# 0000 0111 0000 0000 -> BTFSS STATUS, #C
if (C != 0) goto skipInst;
}
:BTFSS status, bit is op4=0x7 & b3=1 & bit & status & skipInst {
# ---- 0111 bbbf ffff
# 0000 0111 0010 0000 -> BTFSS STATUS, #DC
if (DC != 0) goto skipInst;
}
:BTFSS status, bit is op4=0x7 & b3=2 & bit & status & skipInst {
# ---- 0111 bbbf ffff
# 0000 0111 0100 0000 -> BTFSS STATUS, #Z
if (Z != 0) goto skipInst;
}
:CALL absAddr8 is op4=0x9 & absAddr8 {
# ---- 1001 kkkk kkkk
# 0000 1001 0010 0011 -> CALL 0x23
# 0000 1001 0001 0000 -> CALL 0x10
push(&:2 inst_next);
call [absAddr8];
}
:CLRF srcREG is op6=0x01 & d=1 & srcREG {
# ---- 0000 011f ffff
# 0000 0000 0110 0000 -> CLRF INDF
# 0000 0000 0111 0010 -> CLRF 0x12
srcREG = 0;
Z = 1;
}
:CLRW is op6=0x01 & d=0 & f5=0 {
# ---- 0000 0100 0000
# 0000 0001 0000 0000 -> CLRW
W = 0;
Z = 1;
}
:CLRWDT is op12=0x0004 {
# ---- 0000 0000 0100
# Clear Watchdog Timer - Not Implemented
clearWatchDogTimer();
}
:COMF srcREG, D is op6=0x09 & srcREG & D & destREG {
# ---- 0010 01df ffff
# 0000 0010 0100 0000 -> COMF INDF, 0
# 0000 0010 0110 0000 -> COMF INDF, 1
# 0000 0010 0101 0010 -> COMF 0x12, 0
# 0000 0010 0111 0010 -> COMF 0x12, 1
tmp:1 = ~srcREG;
destREG = tmp;
setResultFlags(tmp);
}
:DECF srcREG, D is op6=0x03 & srcREG & D & destREG {
# ---- 0000 11df ffff
# 0000 0000 1100 0000 -> DECF INDF, 0
# 0000 0000 1110 0000 -> DECF INDF, 1
# 0000 0000 1101 0010 -> DECF 0x12, 0
# 0000 0000 1111 0010 -> DECF 0x12, 1
tmp:1 = srcREG - 1;
destREG = tmp;
setResultFlags(tmp);
}
:DECFSZ srcREG, D is op6=0x0b & srcREG & D & destREG & skipInst {
# ---- 0010 11df ffff
# 0000 0010 1100 0000 -> DECFSZ INDF, 0
# 0000 0010 1110 0000 -> DECFSZ INDF, 1
# 0000 0010 1101 0010 -> DECFSZ 0x12, 0
# 0000 0010 1111 0010 -> DECFSZ 0x12, 1
tmp:1 = srcREG - 1;
destREG = tmp;
if (tmp == 0) goto skipInst;
}
:GOTO absAddr9 is op3=0x5 & absAddr9 {
# ---- 101k kkkk kkkk
# 0000 1011 0010 0011 -> GOTO 0x123
# 0000 1010 0001 0000 -> GOTO 0x10
goto [absAddr9];
}
:INCF srcREG, D is op6=0x0a & srcREG & D & destREG {
# ---- 0010 10df ffff
# 0000 0010 1000 0000 -> INCF INDF, 0
# 0000 0010 1010 0000 -> INCF INDF, 1
# 0000 0010 1001 0010 -> INCF 0x12, 0
# 0000 0010 1011 0010 -> INCF 0x12, 1
tmp:1 = srcREG + 1;
destREG = tmp;
setResultFlags(tmp);
}
:INCFSZ srcREG, D is op6=0x0f & srcREG & D & destREG & skipInst {
# ---- 0011 11df ffff
# 0000 0011 1100 0000 -> INCFSZ INDF, 0
# 0000 0011 1110 0000 -> INCFSZ INDF, 1
# 0000 0011 1101 0010 -> INCFSZ 0x12, 0
# 0000 0011 1111 0010 -> INCFSZ 0x12, 1
tmp:1 = srcREG + 1;
destREG = tmp;
if (tmp == 0) goto skipInst;
}
:IORLW imm8 is op4=0xd & imm8 {
# ---- 1101 kkkk kkkk
# 0000 1101 0001 0010 -> IORLW #0x12
W = W | imm8;
setResultFlags(W);
}
:IORWF srcREG, D is op6=0x04 & srcREG & D & destREG {
# ---- 0001 00df ffff
# 0000 0001 0000 0000 -> IORWF INDF, 0
# 0000 0001 0010 0000 -> IORWF INDF, 1
# 0000 0001 0001 0010 -> IORWF 0x20, 0
# 0000 0001 0011 0010 -> IORWF 0x20, 1
tmp:1 = W | srcREG;
destREG = tmp;
setResultFlags(tmp);
}
:MOVLW imm8 is op4=0xc & imm8 {
# ---- 1100 kkkk kkkk
# 0000 1100 0001 0010 -> MOVLW #0x12
W = imm8;
}
:MOVF srcREG, D is op6=0x08 & srcREG & D & destREG {
# ---- 0010 00df ffff
# 0000 0010 0000 0000 -> MOVF INDF, 0
# 0000 0010 0010 0000 -> MOVF INDF, 1
# 0000 0010 0001 0010 -> MOVF 0x12, 0
# 0000 0010 0011 0010 -> MOVF 0x12, 1
tmp:1 = srcREG;
destREG = tmp;
setResultFlags(tmp);
}
:MOVWF srcREG is op6=0x00 & d=1 & srcREG {
# ---- 0000 001f ffff
# 0000 0000 0010 0000 -> MOVWF INDF
# 0000 0000 0011 0010 -> MOVWF 0x12
srcREG = W;
}
:MOVWF pcl is op6=0x00 & pcl {
# ---- 0000 001f ffff
# 0000 0000 0010 0010 -> MOVWF PCL
PCL = W;
addr:2 = (zext(PA) << 9) + zext(PCL);
goto [addr];
}
:NOP is op12=0x00 {
# ---- 0000 0000 0000
}
:OPTION is op12=0x0002 {
# ---- 0000 0000 0010
OPTION = W;
}
:RETLW imm8 is op4=0x8 & imm8 {
# ---- 1000 kkkk kkkk
# 0000 1000 0001 0010 -> RETLW #0x12
W = imm8;
retAddr:2 = 0;
pop(retAddr);
return [retAddr];
}
:RLF srcREG, D is op6=0x0d & srcREG & D & destREG {
# ---- 0011 01df ffff
# 0000 0011 0100 0000 -> RLF INDF, 0
# 0000 0011 0110 0000 -> RLF INDF, 1
# 0000 0011 0101 0010 -> RLF 0x12, 0
# 0000 0011 0111 0010 -> RLF 0x12, 1
local tmpC = C;
tmp:1 = srcREG;
C = (tmp s< 0);
tmp = (tmp << 1) | tmpC;
destREG = tmp;
setResultFlags(tmp);
}
:RRF srcREG, D is op6=0x0c & srcREG & D & destREG {
# ---- 0011 00df ffff
# 0000 0011 0000 0000 -> RRF INDF, 0
# 0000 0011 0010 0000 -> RRF INDF, 1
# 0000 0011 0001 0010 -> RRF 0x12, 0
# 0000 0011 0011 0010 -> RRF 0x12, 1
local tmpC = C << 7;
tmp:1 = srcREG;
C = (tmp & 1) != 0;
tmp = (tmp >> 1) | tmpC;
destREG = tmp;
setResultFlags(tmp);
}
:SLEEP is op12=0x0003 {
# ---- 0000 0000 0011
# Sleep - Not Implemented
sleep();
}
:SUBWF srcREG, D is op6=0x02 & srcREG & D & destREG {
# ---- 0000 10df ffff
# 0000 0000 1000 0000 -> SUBWF INDF, 0
# 0000 0000 1010 0000 -> SUBWF INDF, 1
# 0000 0000 1001 0010 -> SUBWF 0x12, 0
# 0000 0000 1011 0010 -> SUBWF 0x12, 1
tmp:1 = srcREG;
setSubtractFlags(tmp, W);
tmp = tmp - W;
destREG = tmp;
setResultFlags(tmp);
}
:SWAPF srcREG, D is op6=0x0e & srcREG & D & destREG {
# ---- 0011 10df ffff
# 0000 0011 1000 0000 -> SUBWF INDF, 0
# 0000 0011 1010 0000 -> SUBWF INDF, 1
# 0000 0011 1001 0010 -> SUBWF 0x12, 0
# 0000 0011 1011 0010 -> SUBWF 0x12, 1
tmp:1 = srcREG;
destREG = (tmp << 4) | (tmp >> 4);
}
:XORLW imm8 is op4=0xf & imm8 {
# ---- 1111 kkkk kkkk
# 0000 1111 0001 0010 -> XORLW #0x12
W = imm8 ^ W;
setResultFlags(W);
}
:XORWF srcREG, D is op6=0x06 & srcREG & D & destREG {
# ---- 0001 10df ffff
# 0000 0001 1000 0000 -> XORWF INDF, 0
# 0000 0001 1010 0000 -> XORWF INDF, 1
# 0000 0001 1001 0010 -> XORWF 0x12, 0
# 0000 0001 1011 0010 -> XORWF 0x12, 1
tmp:1 = W ^ srcREG;
destREG = tmp;
setResultFlags(tmp);
}