Repository URL to install this package:
Version:
9.0~241217-2.fc42 ▾
|
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-99 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* E-mail: ig@datarescue.com
*
* Microchip's PIC
*
*/
#include "pic.hpp"
#include <segregs.hpp>
#define PIC18_IP_RANGE 0x1FFFFF
//-------------------------------------------------------------------------
// it can replace one instruction with another without changing its size
void pic_t::simplify(insn_t &insn) const
{
switch ( insn.itype )
{
// movfw macro f ; Move Contents of File Reg to W
// movf f,0
// endm
// tstf macro f ; Test Contents of File Register
// movf f,1
// endm
case PIC_movf:
insn.itype = (insn.Op2.reg == W) ? PIC_movfw : PIC_tstf;
insn.Op2.type = o_void;
break;
// b macro k ; Branch to Address
// goto k
// endm
case PIC_goto:
insn.itype = PIC_b;
break;
// clrc macro ; Clear Carry
// bcf 3,0
// endm
// clrdc macro ; Clear Digit Carry
// bcf 3,1
// endm
// clrz macro ; Clear Zero
// bcf 3,2
// endm
case PIC_bcf:
if ( is_bank(insn) ) switch ( insn.Op2.value )
{
case 0: insn.itype = PIC_clrc; goto NOOP;
case 1: insn.itype = PIC_clrdc; goto NOOP;
case 2: insn.itype = PIC_clrz; goto NOOP;
NOOP:
insn.Op1.type = o_void;
insn.Op2.type = o_void;
break;
}
break;
// setc macro ; Set Carry
// bsf 3,0
// endm
// setdc macro ; Set Digit Carry
// bsf 3,1
// endm
// setz macro ; Set Zero
// bcf 3,2
// endm
case PIC_bsf:
if ( is_bank(insn) ) switch ( insn.Op2.value )
{
case 0: insn.itype = PIC_setc; goto NOOP;
case 1: insn.itype = PIC_setdc; goto NOOP;
case 2: insn.itype = PIC_setz; goto NOOP;
}
break;
// skpnc macro ; Skip on No Carry
// btfsc 3,0
// endm
// skpndc macro ; Skip on No Digit Carry
// btfsc 3,1
// endm
// skpnz macro ; Skip on No Zero
// btfsc 3,2
// endm
case PIC_btfsc:
if ( is_bank(insn) ) switch ( insn.Op2.value )
{
case 0: insn.itype = PIC_skpnc; goto NOOP;
case 1: insn.itype = PIC_skpndc; goto NOOP;
case 2: insn.itype = PIC_skpnz; goto NOOP;
}
break;
// skpc macro ; Skip on Carry
// btfss 3,0
// endm
// skpdc macro ; Skip on Digit Carry
// btfss 3,1
// endm
// skpz macro ; Skip on Zero
// btfss 3,2
// endm
case PIC_btfss:
if ( is_bank(insn) ) switch ( insn.Op2.value )
{
case 0: insn.itype = PIC_skpc; goto NOOP;
case 1: insn.itype = PIC_skpdc; goto NOOP;
case 2: insn.itype = PIC_skpz; goto NOOP;
}
break;
}
}
//-------------------------------------------------------------------------
// it returns true if the size of the instruction is changed
// INSN must be simplified
bool pic_t::build_macro(insn_t &insn, bool may_go_forward)
{
if ( !may_go_forward )
return false;
switch ( insn.itype )
{
// negf macro f,d ; Negate File Register Contents
// comf f,1
// incf f,d
// endm
case PIC_comf:
if ( insn.Op2.reg == F )
{
insn_t incf;
if ( decode_insn(&incf, insn.ea + insn.size) > 0
&& incf.itype == PIC_incf
&& incf.Op1.type == o_mem
&& incf.Op1.addr == insn.Op1.addr )
{
insn.itype = PIC_negf;
insn.Op2.reg = incf.Op2.reg;
insn.size += incf.size;
return true;
}
}
break;
// bnc macro k ; Branch on No Carry to k
// skpc
// goto k
// endm
// bndc macro k ; Branch on No Digit Carry to k
// skpdc
// goto k
// endm
// bnz macro k ; Branch on No Zero to Address
// skpz
// goto k
// endm
// bc macro k ; Branch on Carry to Address k
// skpnc
// goto k
// endm
// bdc macro k ; Branch on Digit Carry to k
// skpndc
// goto k
// endm
// bz macro k ; Branch on Zero to Address k
// skpnz
// goto k
// endm
// addcf macro f,d ; Add Carry to File Register
// skpnc
// incf f,d
// endm
// adddcf macro f,d ; Add Digit to File Register
// skpndc
// incf f,d
// endm
// subcf macro f,d ; Subtract Carry from File Reg
// skpnc
// decf f,d
// endm
case PIC_skpnc:
case PIC_skpndc:
case PIC_skpnz:
case PIC_skpc:
case PIC_skpdc:
case PIC_skpz:
{
insn_t ins2;
if ( decode_insn(&ins2, insn.ea + insn.size) == 0 )
break;
if ( ins2.itype == PIC_b )
{
insn.itype = insn.itype == PIC_skpc ? PIC_bnc
: insn.itype == PIC_skpdc ? PIC_bndc
: insn.itype == PIC_skpz ? PIC_bnz
: insn.itype == PIC_skpnc ? PIC_bc
: insn.itype == PIC_skpndc ? PIC_bdc
: PIC_bz;
insn.Op1 = ins2.Op1;
insn.size += ins2.size;
return true;
}
if ( ins2.itype == PIC_incf || ins2.itype == PIC_decf )
{
if ( insn.itype == PIC_skpnc && ins2.itype == PIC_incf )
insn.itype = PIC_addcf;
else if ( insn.itype == PIC_skpndc && ins2.itype == PIC_incf )
insn.itype = PIC_adddcf;
else if ( insn.itype == PIC_skpnc && ins2.itype == PIC_decf )
insn.itype = PIC_subcf;
else
break;
insn.Op1 = ins2.Op1;
insn.Op2 = ins2.Op2;
insn.size += ins2.size;
return true;
}
}
break;
}
return false;
}
//--------------------------------------------------------------------------
struct pic_mctr_t : public macro_constructor_t
{
pic_t ±
pic_mctr_t(pic_t &_pm) : pm(_pm) {}
bool idaapi build_macro(insn_t *insn, bool may_go_forward) override
{
return pm.build_macro(*insn, may_go_forward);
}
};
//--------------------------------------------------------------------------
int pic_t::ana(insn_t *_insn)
{
if ( _insn == nullptr )
return 0;
insn_t &insn = *_insn;
int len = basic_ana(insn);
if ( len == 0 )
return len;
if ( dosimple() )
simplify(insn);
pic_mctr_t mctr(*this);
mctr.construct_macro(&insn, ph.supports_macros() && inf_macros_enabled());
// if the instruction is too long, recreate it:
/*if ( insn.size == 1 && is_tail(get_flags(insn.ea+1)) )
{
auto_make_code(insn.ea);
auto_make_code(insn.ea+1);
ea_t saved = insn.ea;
del_items(insn.ea, DELIT_SIMPLE); // destroys insn.ea
insn.ea = saved;
}*/
return insn.size;
}
//--------------------------------------------------------------------------
static void opf12(insn_t &insn, int code)
{
insn.Op1.type = o_mem;
insn.Op1.dtype = dt_byte;
sel_t v = get_sreg(insn.ea, BANK);
if ( v == BADSEL )
v = 0;
insn.Op1.addr = (code & 0x1F) | (v << 5);
}
//--------------------------------------------------------------------------
static void opf14(insn_t &insn, int code)
{
insn.Op1.type = o_mem;
insn.Op1.dtype = dt_byte;
sel_t v = get_sreg(insn.ea, BANK);
if ( v == BADSEL )
v = 0;
insn.Op1.addr = (code & 0x7F) | (v << 7);
}
//--------------------------------------------------------------------------
static void opfa16(insn_t &insn, int code)
{
insn.Op1.type = o_mem;
insn.Op1.dtype = dt_byte;
if ( code & 0x0100 ) // if a == 1 (BSR)
{
sel_t v = get_sreg(insn.ea, BANK);
if ( v == BADSEL )
v = 0;
insn.Op1.addr = (v << 8) | (code & 0xFF);
}
else // if a == 0 (access bank)
{
insn.Op1.addr = code & 0xFF;
// The first 128 bytes are General Purpose
// RAM(from Bank 0).
// The second 128 bytes are Special
// Function Registers(from Bank 15).
if ( insn.Op1.addr >= 128 )
insn.Op1.addr = (15<<8) + insn.Op1.addr;
}
}
//--------------------------------------------------------------------------
static void basic_ana12(insn_t &insn, int code)
{
int b4;
switch ( code >> 10 )
{
case 0:
// 0000 0100 0000 CLRW Clear W
// 0000 0000 0000 NOP No Operation
// 0000 0000 0100 CLRWDT Clear Watchdog Timer
// 0000 0000 0010 OPTION Load OPTION register
// 0000 0000 0011 SLEEP Go into standby mode
if ( code == 0x040 )
insn.itype = PIC_clrw;
else if ( code == 0x000 )
insn.itype = PIC_nop;
else if ( code == 0x004 )
insn.itype = PIC_clrwdt;
else if ( code == 0x002 )
insn.itype = PIC_option;
else if ( code == 0x003 )
insn.itype = PIC_sleep;
else if ( ( code & 0xFF8 ) == 0 )
{
// 0000 0000 0fff TRIS f (4<f<8) Load TRIS Register
insn.itype = PIC_tris;
opf12(insn, code);
}
else if ( ( code & 0xF80 ) == 0 )
// 0000 001f ffff MOVWF f Move W to f
// 0000 011f ffff CLRF f Clear f
{
static const ushort codes[4] =
{
PIC_null, PIC_movwf, PIC_null, PIC_clrf
};
insn.itype = codes[(code>>5)&3];
opf12(insn, code);
}
else
{
// 0000 10df ffff SUBWF f, d Subtract W from f
// 0000 11df ffff DECF f, d Decrement f
// 0001 00df ffff IORWF f, d Inclusive OR W with f
// 0001 01df ffff ANDWF f, d AND W with f
// 0001 10df ffff XORWF f, d Exclusive OR W with f
// 0001 11df ffff ADDWF f, d Add W and f
// 0010 00df ffff MOVF f, d Move f
// 0010 01df ffff COMF f, d Complement f
// 0010 10df ffff INCF f, d Increment f
// 0010 11df ffff DECFSZ f, d Decrement f, Skip if 0
// 0011 00df ffff RRF f, d Rotate Right f through Carry
// 0011 01df ffff RLF f, d Rotate Left f through Carry
// 0011 10df ffff SWAPF f, d Swap nibbles in f
// 0011 11df ffff INCFSZ f, d Increment f, Skip if 0
b4 = code >> 6;
static const ushort codes[16] =
{
PIC_null, PIC_null, PIC_subwf, PIC_decf,
PIC_iorwf, PIC_andwf, PIC_xorwf, PIC_addwf,
PIC_movf, PIC_comf, PIC_incf, PIC_decfsz,
PIC_rrf, PIC_rlf, PIC_swapf, PIC_incfsz
};
insn.itype = codes[b4];
opf12(insn, code);
insn.Op2.type = o_reg;
insn.Op2.reg = (code & 0x20) ? F : W;
insn.Op2.dtype = dt_byte;
}
break;
case 1:
// 0100 bbbf ffff BCF f, b Bit Clear f
// 0101 bbbf ffff BSF f, b Bit Set f
// 0110 bbbf ffff BTFSC f, b Bit Test f, Skip if Clear
// 0111 bbbf ffff BTFSS f, b Bit Test f, Skip if Set
{
static const ushort codes[4] =
{
PIC_bcf, PIC_bsf, PIC_btfsc, PIC_btfss
};
insn.itype = codes[(code>>8)&3];
opf12(insn, code);
insn.Op2.type = o_imm;
insn.Op2.value = (code >> 5) & 7;
insn.Op2.dtype = dt_byte;
}
break;
case 2:
b4 = (code >> 8) & 0x3;
switch ( b4 )
{
case 0:
// 1000 kkkk kkkk RETLW k Return with literal in W
insn.itype = PIC_retlw;
insn.Op1.type = o_imm;
insn.Op1.value = code & 0xFF;
insn.Op1.dtype = dt_byte;
break;
case 1:
// 1001 kkkk kkkk CALL k Call subroutine
{
// old databases used status reg (PCLATH) for hight bit of the address
// new code uses BANK for that
// so we get both and try to guess
sel_t status = get_sreg(insn.ea, PCLATH);
sel_t bank = get_sreg(insn.ea, BANK);
if ( (status != BADSEL && status != 0) && (bank == BADSEL || bank == 0) )
bank = (status >> 5) & 3;
insn.itype = PIC_call;
insn.Op1.type = o_near;
insn.Op1.addr = (bank << 9) | (code & 0xFF);
insn.Op1.dtype = dt_code;
}
break;
default:
// 101k kkkk kkkk GOTO k Go to address
{
sel_t status = get_sreg(insn.ea, PCLATH);
sel_t bank = get_sreg(insn.ea, BANK);
if ( (status != BADSEL && status != 0) && (bank == BADSEL || bank == 0) )
bank = (status >> 5) & 3;
insn.itype = PIC_goto;
insn.Op1.type = o_near;
insn.Op1.addr = (bank << 9) | (code & 0x1FF);
insn.Op1.dtype = dt_code;
}
break;
}
break;
case 3:
// 1100 kkkk kkkk MOVLW k Move literal to W
// 1101 kkkk kkkk IORLW k Inclusive OR literal with W
// 1110 kkkk kkkk ANDLW k AND literal with W
// 1111 kkkk kkkk XORLW k Exclusive OR literal with W
{
static const ushort codes[4] =
{
PIC_movlw, PIC_iorlw, PIC_andlw, PIC_xorlw
};
insn.itype = codes[(code>>8)&3];
insn.Op1.type = o_imm;
insn.Op1.value = (uchar)code;
insn.Op1.dtype = dt_byte;
}
break;
}
}
//--------------------------------------------------------------------------
int32 get_signed(int32 byte, uint32 mask)
{
uint32 bits = mask >> 1;
uint32 sign = bits + 1;
if ( (byte & sign) != 0 ) // byte < 0
byte = (byte & bits) - sign;
else // byte >= 0
byte = byte & mask;
return byte;
}
//--------------------------------------------------------------------------
static void basic_ana14(insn_t &insn, int code)
{
int b4 = (code >> 8) & 0xF;
switch ( code >> 12 )
{
// 00 xxxx xxxx xxxx
case 0:
if ( b4 == 0 ) // 00 0000 xxxx xxxx
{
// 00 0000 1fff ffff MOVWF f Move W to f
if ( (code & 0x80) != 0 )
{
insn.itype = PIC_movwf;
opf14(insn, code);
break;
}
// 00 0000 0001 0nmm MOVIW Move INDFn to W
// 00 0000 0001 1nmm MOVWI Move W to INDFn
if ( (code >> 4) == 1 )
{
insn.itype = ((code >> 3) & 1) == 0 ? PIC_moviw : PIC_movwi;
insn.Op1.type = o_reg;
insn.Op1.reg = ((code & 0x4) == 0) ? FSR0 : FSR1;
insn.Op1.specflag1 = (code & 3) + 1;
insn.Op1.dtype = dt_byte;
break;
}
// 00 0000 001k kkkk MOVLB k Move literal to BSR
if ( (code >> 5) == 1 )
{
insn.itype = PIC_movlb;
insn.Op1.type = o_imm;
insn.Op1.value = code & 0x1F;
insn.Op1.dtype = dt_byte;
break;
}
// 00 0000 0000 0000 NOP No Operation
// 00 0000 0000 0001 RESET Software device Reset
// 00 0000 0000 1000 RETURN Return from Subroutine
// 00 0000 0000 1001 RETFIE Return from interrupt
// 00 0000 0000 1010 CALLW Call Subroutine with W
// 00 0000 0000 1011 BRW Relative Branch with W
// 00 0000 0110 0010 OPTION Load OPTION register
// 00 0000 0110 0011 SLEEP Go into standby mode
// 00 0000 0110 0100 CLRWDT Clear Watchdog Timer
// 00 0000 0110 0fff TRIS f (4<f<8) Load TRIS Register
if ( code == 0x0 )
{
insn.itype = PIC_nop;
}
else if ( code == 0x0001 )
{
insn.itype = PIC_reset;
}
else if ( code == 0x0008 )
{
insn.itype = PIC_return;
}
else if ( code == 0x000A )
{
insn.itype = PIC_callw;
}
else if ( code == 0x0009 )
{
insn.itype = PIC_retfie;
}
else if ( code == 0x000B )
{
insn.itype = PIC_brw;
sel_t w = get_sreg(insn.ea, W);
insn.Op1.type = o_near;
insn.Op1.value = insn.ea + w + 1; // PC + W + 1
insn.Op1.dtype = dt_code;
}
else if ( code == 0x0062 )
{
insn.itype = PIC_option;
}
else if ( code == 0x0063 )
{
insn.itype = PIC_sleep;
}
else if ( code == 0x0064 )
{
insn.itype = PIC_clrwdt;
}
else if ( code >= 0x0065 && code <= 0x0067 )
{
insn.itype = PIC_tris;
insn.Op1.type = o_imm;
insn.Op1.dtype = dt_byte;
insn.Op1.value = code & 7;
}
}
else if ( b4 == 1 ) // 00 0001 xxxx xxxx
{
// 00 0001 1fff ffff CLRF f Clear f
if ( code & 0x80 )
{
insn.itype = PIC_clrf;
opf14(insn, code);
}
// 00 0001 0xxx xxxx CLRW Clear W
else
{
insn.itype = PIC_clrw;
}
}
else
{
// 00 0010 dfff ffff SUBWF f, d Subtract W from f
// 00 0011 dfff ffff DECF f, d Decrement f
// 00 0100 dfff ffff IORWF f, d Inclusive OR W with f
// 00 0101 dfff ffff ANDWF f, d AND W with f
// 00 0110 dfff ffff XORWF f, d Exclusive OR W with f
// 00 0111 dfff ffff ADDWF f, d Add W and f
// 00 1000 dfff ffff MOVF f, d Move f
// 00 1001 dfff ffff COMF f, d Complement f
// 00 1010 dfff ffff INCF f, d Increment f
// 00 1011 dfff ffff DECFSZ f, d Decrement f, Skip if 0
// 00 1100 dfff ffff RRF f, d Rotate Right f through Carry
// 00 1101 dfff ffff RLF f, d Rotate Left f through Carry
// 00 1110 dfff ffff SWAPF f, d Swap nibbles in f
// 00 1111 dfff ffff INCFSZ f, d Increment f, Skip if 0
static const ushort codes[16] =
{
PIC_null, PIC_null, PIC_subwf, PIC_decf,
PIC_iorwf, PIC_andwf, PIC_xorwf, PIC_addwf,
PIC_movf, PIC_comf, PIC_incf, PIC_decfsz,
PIC_rrf, PIC_rlf, PIC_swapf, PIC_incfsz
};
insn.itype = codes[b4];
opf14(insn, code);
insn.Op2.type = o_reg;
insn.Op2.reg = (code & 0x80) ? F : W;
insn.Op2.dtype = dt_byte;
}
break;
// 01 xxxx xxxx xxxx
case 1:
// 01 00bb bfff ffff BCF f, b Bit Clear f
// 01 01bb bfff ffff BSF f, b Bit Set f
// 01 10bb bfff ffff BTFSC f, b Bit Test f, Skip if Clear
// 01 11bb bfff ffff BTFSS f, b Bit Test f, Skip if Set
{
static const ushort codes[4] =
{
PIC_bcf, PIC_bsf, PIC_btfsc, PIC_btfss
};
insn.itype = codes[(code >> 10) & 3];
opf14(insn, code);
insn.Op2.type = o_imm;
insn.Op2.value = (code >> 7) & 7;
insn.Op2.dtype = dt_byte;
}
break;
// 10 xxxx xxxx xxxx
case 2:
// 10 0kkk kkkk kkkk CALL k Call subroutine
// 10 1kkk kkkk kkkk GOTO k Go to address
{
// Get the content of PCLATH segment register. We use a mask to keep only bits 3 et 4. (The upper bits of PC are loaded from PCLATH<4:3>.)
sel_t pclath = get_sreg(insn.ea, PCLATH) & 0x18; // & 00011000b
insn.itype = (code & 0x800) ? PIC_goto : PIC_call;
insn.Op1.type = o_near;
// We have 000x x000 for pclath and 10 1kkk kkkk kkkk for code
// Operation : 000x x000 0000 0000 | 00 0kkk kkkk kkkk
// Result : 000x xkkk kkkk kkkk
insn.Op1.addr = (pclath << (11 - 3)) | (code & 0x7FF);
insn.Op1.dtype = dt_code;
}
break;
// 11 xxxx xxxx xxxx
case 3:
// 11 00xx kkkk kkkk MOVLW k Move literal to W
// 11 0001 1kkk kkkk MOVLP k Move literal to PCLATH
// 11 0001 0nkk kkkk ADDFSR n, k Add Literal to FSRn
// 11 001k kkkk kkkk BRA k Relative Branch
// 11 01xx kkkk kkkk RETLW k Return with literal in W
// 11 0111 dfff ffff ASRF f, d Arithmetic Right Shift
// 11 0101 dfff ffff LSLF f, d Logical Left Shift
// 11 0110 dfff ffff LSRF f, d Logical Right Shift
// 11 1000 kkkk kkkk IORLW k Inclusive OR literal with W
// 11 1001 kkkk kkkk ANDLW k AND literal with W
// 11 1010 kkkk kkkk XORLW k Exclusive OR literal with W
// 11 1011 dfff ffff SUBWFB f, d Subtract W from f with Borrow
// 11 1100 kkkk kkkk SUBLW k Subtract W from literal
// 11 1101 dfff ffff ADDWFC f, d Add with Carry W and f
// 11 111x kkkk kkkk ADDLW k Add literal and W
// 11 1111 0nkk kkkk MOVIW ?? Move INDFn to W
// 11 1111 1nkk kkkk MOVWI ?? Move W to INDFn
{
static const ushort codes[16] =
{
PIC_movlw, PIC_movlp, PIC_bra, PIC_bra,
PIC_retlw, PIC_lslf, PIC_lsrf, PIC_asrf,
PIC_iorlw, PIC_andlw, PIC_xorlw, PIC_subwfb,
PIC_sublw, PIC_addwfc, PIC_addlw, PIC_moviw
};
insn.itype = codes[b4];
switch ( insn.itype )
{
case PIC_movlp:
if ( ((code >> 7) & 1) == 0 ) // 11 0001 0nkk kkkk ADDFSR
{
insn.itype = PIC_addfsr;
insn.Op1.type = o_reg;
insn.Op1.reg = ((code & 0x40) == 0) ? FSR0 : FSR1;
insn.Op1.dtype = dt_byte;
insn.Op2.type = o_imm;
insn.Op2.value = get_signed(code, 0x3F);
insn.Op2.dtype = dt_byte;
}
else // 11 0001 1kkk kkkk MOVLP
{
insn.itype = PIC_movlp;
insn.Op1.type = o_imm;
insn.Op1.value = code & 0x7F;
insn.Op1.dtype = dt_byte;
}
break;
case PIC_bra:
insn.Op1.type = o_near;
insn.Op1.addr = insn.ea + 1 + get_signed(code, 0x01FF); // PC + 1 + operand value
insn.Op1.dtype = dt_code;
break;
case PIC_addwfc:
case PIC_asrf:
case PIC_lslf:
case PIC_lsrf:
case PIC_subwfb:
opf14(insn, code);
insn.Op2.type = o_reg;
insn.Op2.reg = ( (code & 0x80) != 0) ? F : W;
insn.Op2.dtype = dt_byte;
break;
case PIC_moviw:
if ( ((code >> 7) & 1) == 0 ) // 11 1111 0nkk kkkk MOVIW
insn.itype = PIC_moviw;
else // 11 1111 1nkk kkkk MOVWI
insn.itype = PIC_movwi;
insn.Op1.type = o_displ;
insn.Op1.phrase = ((code & 0x40) == 0) ? FSR0 : FSR1;
insn.Op1.addr = get_signed(code, 0x3F);
insn.Op1.dtype = dt_byte;
break;
default:
insn.Op1.type = o_imm;
insn.Op1.value = code & 0xFF;
insn.Op1.dtype = dt_byte;
break;
}
}
break;
}
}
//--------------------------------------------------------------------------
static void basic_ana16(insn_t &insn, int code)
{
if ( ( code >> 12 ) == 0 )
{
int b3 = code >> 4;
if ( b3 == 0 )
{
// 0000 0000 0000 0000 NOP No Operation
// 0000 0000 0000 0011 SLEEP Go into standby mode
// 0000 0000 0000 0100 CLRWDT Clear Watchdog Timer
// 0000 0000 0000 0101 PUSH Push top of return stack
// 0000 0000 0000 0110 POP Pop top of return stack
// 0000 0000 0000 0111 DAW Decimal Adjust W
// 0000 0000 0000 1000 TBLRD* Table Read
// 0000 0000 0000 1001 TBLRD*+ Table Read with post-increment
// 0000 0000 0000 1010 TBLRD*- Table Read with post-decrement
// 0000 0000 0000 1011 TBLRD+* Table Read with pre-increment
// 0000 0000 0000 1100 TBLWT* Table Write
// 0000 0000 0000 1101 TBLWT*+ Table Write with post-increment
// 0000 0000 0000 1110 TBLWT*- Table Write with post-decrement
// 0000 0000 0000 1111 TBLWT+* Table Write with pre-increment
static const ushort codes[16] =
{
PIC_nop, PIC_null, PIC_null, PIC_sleep,
PIC_clrwdt, PIC_push0, PIC_pop0, PIC_daw0,
PIC_tblrd0, PIC_tblrd0p, PIC_tblrd0m, PIC_tblrdp0,
PIC_tblwt0, PIC_tblwt0p, PIC_tblwt0m, PIC_tblwtp0
};
insn.itype = codes[code & 15];
}
else if ( b3 < 0x80 )
{
if ( ( code & 0xFFFC ) == 0x0010 )
{
// 0000 0000 0001 000s RETFIE s Return from interrupt enable
// 0000 0000 0001 001s RETURN s Return from Subroutine
insn.itype = (code & 0x2) ? PIC_return1 : PIC_retfie1;
if ( code & 1 )
{
insn.Op1.type = o_reg;
insn.Op1.reg = FAST;
}
else
{
insn.Op1.type = o_imm;
insn.Op1.value = 0;
}
insn.Op1.dtype = dt_byte;
}
else if ( code == 0x00FF )
{
// 0000 0000 1111 1111 RESET Software device Reset
insn.itype = PIC_reset0;
}
else if ( ( code & 0xFFF0 ) == 0x0100 )
{
// 0000 0001 0000 kkkk MOVLB k Move literal to BSR
insn.itype = PIC_movlb1;
insn.Op1.type = o_imm;
insn.Op1.value = code & 0xF;
insn.Op1.dtype = dt_byte;
}
else if ( ( code & 0xFE00 ) == 0x0200 )
{
// 0000 001a ffff ffff MULWF f, a Multiply W with f
insn.itype = PIC_mulwf2;
opfa16(insn, code);
insn.Op2.type = o_reg;
insn.Op2.reg = (code & 0x100) ? BANKED : ACCESS;
insn.Op2.dtype = dt_byte;
}
else if ( ( code & 0xFC00 ) == 0x0400 )
{
// 0000 01da ffff ffff DECF f, d, a Decrement f
insn.itype = PIC_decf3;
opfa16(insn, code);
insn.Op2.type = o_reg;
insn.Op2.reg = (code & 0x200) ? F : W;
insn.Op2.dtype = dt_byte;
insn.Op3.type = o_reg;
insn.Op3.reg = (code & 0x100) ? BANKED : ACCESS;
insn.Op3.dtype = dt_byte;
}
else
{
insn.itype = PIC_null;
}
}
else
{
// 0000 1000 kkkk kkkk SUBLW k Subtract W from literal
// 0000 1001 kkkk kkkk IORLW k Inclusive OR literal with W
// 0000 1010 kkkk kkkk XORLW k Exclusive OR literal with W
// 0000 1011 kkkk kkkk ANDLW k AND literal with W
// 0000 1100 kkkk kkkk RETLW k Return with literal in W
// 0000 1101 kkkk kkkk MULLW k Multiply literal with W
// 0000 1110 kkkk kkkk MOVLW k Move literal to W
// 0000 1111 kkkk kkkk ADDLW k Add literal and W
static const ushort codes[16] =
{
PIC_sublw, PIC_iorlw, PIC_xorlw, PIC_andlw,
PIC_retlw, PIC_mullw1, PIC_movlw, PIC_addlw
};
insn.itype = codes[(code>>8)&7];
insn.Op1.type = o_imm;
insn.Op1.value = (char)code;
insn.Op1.dtype = dt_byte;
}
}
else if ( ( code >> 14 ) <= 2 )
{
int b1 = code >> 12;
if ( b1 <= 5 )
{
// 0001 00da ffff ffff IORWF f, d, a Inclusive OR W with f
// 0001 01da ffff ffff ANDWF f, d, a AND W with f
// 0001 10da ffff ffff XORWF f, d, a Exclusive OR W with f
// 0001 11da ffff ffff COMF f, d, a Complement f
// 0010 00da ffff ffff ADDWFC f, d, a Add W and Carry to f
// 0010 01da ffff ffff ADDWF f, d, a Add W and f
// 0010 10da ffff ffff INCF f, d, a Increment f
// 0010 11da ffff ffff DECFSZ f, d, a Decrement f, Skip if 0
// 0011 00da ffff ffff RRCF f, d, a Rotate Right f through Carry
// 0011 01da ffff ffff RLCF f, d, a Rotate Left f through Carry
// 0011 10da ffff ffff SWAPF f, d, a Swap nibbles in f
// 0011 11da ffff ffff INCFSZ f, d, a Increment f, Skip if 0
// 0100 00da ffff ffff RRNCF f, d, a Rotate Right f
// 0100 01da ffff ffff RLNCF f, d, a Rotate Left f
// 0100 10da ffff ffff INFSNZ f, d, a Increment f, Skip if not 0
// 0100 11da ffff ffff DCFSNZ f, d, a Decrement f, Skip if not 0
// 0101 00da ffff ffff MOVF f, d, a Move f
// 0101 01da ffff ffff SUBFWB f, d, a Substract f from W with borrow
// 0101 10da ffff ffff SUBWFB f, d, a Substract W from f with borrow
// 0101 11da ffff ffff SUBWF f, d, a Substract W from f
static const ushort codes[24] =
{
PIC_null, PIC_null, PIC_null, PIC_null,
PIC_iorwf3, PIC_andwf3, PIC_xorwf3, PIC_comf3,
PIC_addwfc3, PIC_addwf3, PIC_incf3, PIC_decfsz3,
PIC_rrcf3, PIC_rlcf3, PIC_swapf3, PIC_incfsz,
PIC_rrncf3, PIC_rlncf3, PIC_infsnz3, PIC_dcfsnz3,
PIC_movf3, PIC_subfwb3, PIC_subwfb3, PIC_subwf3,
};
QASSERT(10097, (code>>10) < 24);
insn.itype = codes[code>>10];
opfa16(insn, code);
insn.Op2.type = o_reg;
insn.Op2.reg = (code & 0x200) ? F : W;
insn.Op2.dtype = dt_byte;
insn.Op3.type = o_reg;
insn.Op3.reg = (code & 0x100) ? BANKED : ACCESS;
insn.Op3.dtype = dt_byte;
}
else if ( b1 == 6 )
{
// 0110 000a ffff ffff CPFSLT f, a Compare f with W, Skip if <
// 0110 001a ffff ffff CPFSEQ f, a Compare f with W, Skip if ==
// 0110 010a ffff ffff CPFSGT f, a Compare f with W, Skip if >
// 0110 011a ffff ffff TSTFSZ f, a Test f, Skip if 0
// 0110 100a ffff ffff SETF f, a Set f
// 0110 101a ffff ffff CLRF f, a Clear f
// 0110 110a ffff ffff NEGF f, a Negate f
// 0110 111a ffff ffff MOVWF f, a Move W to f
static const ushort codes[8] =
{
PIC_cpfslt2, PIC_cpfseq2, PIC_cpfsgt2, PIC_tstfsz2,
PIC_setf2, PIC_clrf2, PIC_negf2, PIC_movwf2,
};
insn.itype = codes[(code>>9)&7];
opfa16(insn, code);
insn.Op2.type = o_reg;
insn.Op2.reg = (code & 0x100) ? BANKED : ACCESS;
insn.Op2.dtype = dt_byte;
}
else
{
// 0111 bbba ffff ffff BTG f, b, a Bit Toggle f
// 1000 bbba ffff ffff BSF f, b, a Bit Set f
// 1001 bbba ffff ffff BCF f, b, a Bit Clear f
// 1010 bbba ffff ffff BTFSS f, b, a Bit Test f, Skip if Set
// 1011 bbba ffff ffff BTFSC f, b, a Bit Test f, Skip if Clear
static const ushort codes[5] =
{
PIC_btg3, PIC_bsf3, PIC_bcf3, PIC_btfss3, PIC_btfsc3
};
QASSERT(10098, (b1-7) < 5);
insn.itype = codes[b1-7];
opfa16(insn, code);
insn.Op2.type = o_imm;
insn.Op2.value = (code >> 9) & 7;
insn.Op2.dtype = dt_byte;
insn.Op3.type = o_reg;
insn.Op3.reg = (code & 0x100) ? BANKED : ACCESS;
insn.Op3.dtype = dt_byte;
}
}
else
{
int b2 = ( code >> 12 ) & 3;
int b3 = ( code >> 8 ) & 0x0F;
switch ( b2 )
{
case 0:
// 1100 ffff ffff ffff 1111 ffff ffff ffff MOVFF fs, fd Move fs to fd
insn.itype = PIC_movff2;
insn.Op1.type = o_mem;
insn.Op1.dtype = dt_byte;
insn.Op1.addr = code & 0xFFF;
insn.Op2.type = o_mem;
insn.Op2.dtype = dt_byte;
insn.Op2.addr = insn.get_next_word() & 0xFFF;
break;
case 1:
// 1101 0nnn nnnn nnnn BRA n Branch unconditionally
// 1101 1nnn nnnn nnnn RCALL n Relative Call subroutine
insn.itype = (code & 0x800) ? PIC_rcall1 : PIC_bra1;
insn.Op1.type = o_near;
insn.Op1.addr = (insn.ea + 2 + 2 * get_signed(code,0x07FF)) & PIC18_IP_RANGE;
insn.Op1.dtype = dt_code;
break;
case 2:
if ( b3 <= 7 )
{
// 1110 0000 nnnn nnnn BZ n Branch if Zero
// 1110 0001 nnnn nnnn BNZ n Branch if not Zero
// 1110 0010 nnnn nnnn BC n Branch if Carry
// 1110 0011 nnnn nnnn BNC n Branch if not Carry
// 1110 0100 nnnn nnnn BOV n Branch if Overflow
// 1110 0101 nnnn nnnn BNOV n Branch if not Overflow
// 1110 0110 nnnn nnnn BN n Branch if Negative
// 1110 0111 nnnn nnnn BNN n Branch if not Negative
static const ushort codes[8] =
{
PIC_bz1, PIC_bnz1, PIC_bc1, PIC_bnc1,
PIC_bov1, PIC_bnov1, PIC_bn1, PIC_bnn1
};
insn.itype = codes[(code>>8)&7];
insn.Op1.type = o_near;
insn.Op1.addr = (insn.ea + 2 + 2 * get_signed(code,0x00FF)) & PIC18_IP_RANGE;
insn.Op1.dtype = dt_code;
}
else if ( b3 == 0xC || b3 == 0xD || b3 == 0xF )
{
// 1110 110s kkkk kkkk 1111 kkkk kkkk kkkk CALL n, s Call subroutine
// 1110 1111 kkkk kkkk 1111 kkkk kkkk kkkk GOTO n Go to address
static const ushort codes[4] =
{
PIC_call2, PIC_call2, PIC_null, PIC_goto
};
insn.itype = codes[(code>>8)&3];
insn.Op1.type = o_near;
insn.Op1.addr = ((insn.get_next_word() & 0xFFF) << 9) | ((code & 0x00FF) << 1);
insn.Op1.dtype = dt_code;
if ( insn.itype == PIC_call2 )
{
if ( code & 0x0100 )
{
insn.Op2.type = o_reg;
insn.Op2.reg = FAST;
}
else
{
insn.Op2.type = o_imm;
insn.Op2.value = 0;
}
insn.Op2.dtype = dt_byte;
}
}
else if ( ( code & 0xFFC0 ) == 0xEE00 )
{
// 1110 1110 00ff kkkk 1111 0000 kkkk kkkk LFSR f, k Move literal to FSR
insn.itype = PIC_lfsr2;
insn.Op1.type = o_reg;
insn.Op1.reg = FSR0 + ((code >> 4) & 3);
insn.Op1.dtype = dt_byte;
insn.Op2.type = o_imm;
insn.Op2.value = ((code&0xF) << 8 ) | (insn.get_next_word() & 0xFF);
insn.Op2.dtype = dt_word;
}
else
{
insn.itype = PIC_null;
}
break;
case 3:
// 1111 xxxx xxxx xxxx NOP No Operation
insn.itype = PIC_nop;
break;
}
}
}
//--------------------------------------------------------------------------
int pic_t::basic_ana(insn_t &insn)
{
int code;
switch ( ptype )
{
case PIC12:
code = get_wide_byte(insn.ea); insn.size = 1;
basic_ana12(insn, code);
break;
case PIC14:
code = get_wide_byte(insn.ea); insn.size = 1;
basic_ana14(insn, code);
break;
case PIC16:
code = insn.get_next_word();
basic_ana16(insn, code);
break;
default:
error("interr: ana");
}
if ( insn.itype == PIC_null )
return 0;
return insn.size;
}