update to ida 7.6, add builds
This commit is contained in:
863
idasdk76/module/sam8/ana.cpp
Normal file
863
idasdk76/module/sam8/ana.cpp
Normal file
@@ -0,0 +1,863 @@
|
||||
/************************************************************************/
|
||||
/* Disassembler for Samsung SAM8 processors */
|
||||
/************************************************************************/
|
||||
|
||||
#include "sam8.hpp"
|
||||
|
||||
|
||||
/**
|
||||
* Register operand
|
||||
*/
|
||||
static void reg_operand(
|
||||
insn_t &insn,
|
||||
int op,
|
||||
bool indirect,
|
||||
bool workingReg,
|
||||
bool regPair,
|
||||
uint16 regNum)
|
||||
{
|
||||
// do it
|
||||
if ( !indirect )
|
||||
{
|
||||
insn.ops[op].type = o_reg;
|
||||
insn.ops[op].reg = regNum;
|
||||
insn.ops[op].fl_workingReg = workingReg;
|
||||
insn.ops[op].fl_regPair = regPair;
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.ops[op].type = o_phrase;
|
||||
insn.ops[op].phrase = fIndReg;
|
||||
insn.ops[op].v_phrase_reg = regNum;
|
||||
insn.ops[op].fl_workingReg = workingReg;
|
||||
insn.ops[op].fl_regPair = regPair;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Indexed register operand
|
||||
*/
|
||||
static void idx_reg_operand(insn_t &insn, int op, uint16 baseRegNum, uint16 idxRegNum)
|
||||
{
|
||||
insn.ops[op].type = o_phrase;
|
||||
insn.ops[op].phrase = fIdxReg;
|
||||
insn.ops[op].v_phrase_reg = baseRegNum;
|
||||
insn.ops[op].v_phrase_idxreg = idxRegNum;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Indexed address operand in code memory
|
||||
*/
|
||||
static void idx_cdata_operand(
|
||||
insn_t &insn,
|
||||
int op,
|
||||
int offset,
|
||||
int baseAddr,
|
||||
uint16 idxRegNum)
|
||||
{
|
||||
insn.ops[op].type = o_displ;
|
||||
insn.ops[op].phrase = fIdxCAddr;
|
||||
insn.ops[op].addr = baseAddr;
|
||||
insn.ops[op].v_phrase_idxreg = idxRegNum;
|
||||
insn.ops[op].dtype = dt_word;
|
||||
insn.ops[op].offb = (uchar)offset;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Indexed address operand in external (data) memory
|
||||
*/
|
||||
static void idx_edata_operand(
|
||||
insn_t &insn,
|
||||
int op,
|
||||
int offset,
|
||||
int baseAddr,
|
||||
uint16 idxRegNum)
|
||||
{
|
||||
insn.ops[op].type = o_displ;
|
||||
insn.ops[op].phrase = fIdxEAddr;
|
||||
insn.ops[op].addr = baseAddr;
|
||||
insn.ops[op].v_phrase_idxreg = idxRegNum;
|
||||
insn.ops[op].dtype = dt_word;
|
||||
insn.ops[op].offb = (uchar)offset;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register bit operand
|
||||
*/
|
||||
static void regbit_operand(insn_t &insn, int op, bool workingReg, uint16 regNum, int bit)
|
||||
{
|
||||
insn.ops[op].type = o_reg_bit;
|
||||
insn.ops[op].reg = regNum;
|
||||
insn.ops[op].fl_workingReg = workingReg;
|
||||
insn.ops[op].v_bit = bit;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Immediate operand
|
||||
*/
|
||||
static void imm_operand(insn_t &insn, int op, int offset, uint32 value, char dtype)
|
||||
{
|
||||
insn.ops[op].type = o_imm;
|
||||
insn.ops[op].value = value;
|
||||
insn.ops[op].dtype = dtype;
|
||||
insn.ops[op].offb = (uchar)offset;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Address operand in external (data) memory
|
||||
*/
|
||||
static void addr_edata_operand(insn_t &insn, int op, int offset, ea_t address)
|
||||
{
|
||||
insn.ops[op].type = o_emem;
|
||||
insn.ops[op].addr = address;
|
||||
insn.ops[op].offb = (uchar)offset;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Address operand in code memory
|
||||
*/
|
||||
static void addr_cdata_operand(insn_t &insn, int op, int offset, ea_t address)
|
||||
{
|
||||
insn.ops[op].type = o_cmem;
|
||||
insn.ops[op].addr = address;
|
||||
insn.ops[op].offb = (uchar)offset;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Code operand (e.g. JP destination)
|
||||
*/
|
||||
static void code_operand(insn_t &insn, int op, int offset, ea_t address)
|
||||
{
|
||||
insn.ops[op].type = o_near;
|
||||
insn.ops[op].addr = address;
|
||||
insn.ops[op].offb = (uchar)offset;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Indirect code operand in "zero" page
|
||||
*/
|
||||
static void ind_code_operand(insn_t &insn, int op, int offset, ea_t address)
|
||||
{
|
||||
insn.ops[op].type = o_cmem_ind;
|
||||
insn.ops[op].addr = address;
|
||||
insn.ops[op].offb = (uchar)offset;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finalise cmd data structure
|
||||
*/
|
||||
static int finalise_insn(insn_t &insn, uint16 opcode)
|
||||
{
|
||||
// final checks on operands
|
||||
for ( int i=0; i < 3; i++ )
|
||||
{
|
||||
// check reg pair operands are even
|
||||
if ( insn.ops[i].type == o_reg
|
||||
&& insn.ops[i].fl_regPair
|
||||
&& insn.ops[i].reg & 1 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// check idxreg is even
|
||||
if ( insn.ops[i].type == o_displ
|
||||
&& (insn.ops[i].phrase == fIdxCAddr
|
||||
|| insn.ops[i].phrase == fIdxEAddr)
|
||||
&& insn.ops[i].v_phrase_idxreg & 1 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// check workingReg is valid for register operands
|
||||
if ( insn.ops[i].type == o_reg
|
||||
&& insn.ops[i].fl_workingReg
|
||||
&& insn.ops[i].reg > 15 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// check workingReg is valid for indreg operands
|
||||
if ( insn.ops[i].type == o_phrase
|
||||
&& insn.ops[i].phrase == fIndReg
|
||||
&& insn.ops[i].fl_workingReg
|
||||
&& insn.ops[i].v_phrase_reg > 15 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// set opcode & set no condition code
|
||||
insn.itype = opcode;
|
||||
insn.c_condition = ccNone;
|
||||
|
||||
// return size
|
||||
return insn.size;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finalise cmd data structure, with condition code
|
||||
*/
|
||||
static int finalise_insn(insn_t &insn, uint16 opcode, uchar condition)
|
||||
{
|
||||
// do initial instruction setup
|
||||
if ( !finalise_insn(insn, opcode) )
|
||||
return 0;
|
||||
|
||||
// set return code
|
||||
insn.c_condition = condition;
|
||||
|
||||
// return size
|
||||
return insn.size;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the next LITTLE ENDIAN word.
|
||||
* For some reason this processor uses LITTLE ENDIAN OCCASIONALLY!!!
|
||||
*/
|
||||
static inline ushort next_word_le(insn_t &insn)
|
||||
{
|
||||
return insn.get_next_byte() | (insn.get_next_byte() << 8);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// analyze an basic instruction
|
||||
static int ana_basic(insn_t &insn)
|
||||
{
|
||||
// get the command code byte
|
||||
ushort code = insn.get_next_byte();
|
||||
|
||||
// decode the special case (annoying) instructions
|
||||
switch ( code )
|
||||
{
|
||||
case 0x30:
|
||||
reg_operand(insn, 0, true, false, true, insn.get_next_byte());
|
||||
return finalise_insn(insn, SAM8_JP);
|
||||
|
||||
case 0x31:
|
||||
{
|
||||
// need to decode second byte to determine exact type
|
||||
ushort tmp = insn.get_next_byte();
|
||||
switch ( tmp & 0x03 )
|
||||
{
|
||||
case 0:
|
||||
imm_operand(insn, 0, 1, tmp & 0xF0, dt_byte);
|
||||
return finalise_insn(insn, SAM8_SRP);
|
||||
|
||||
case 1:
|
||||
imm_operand(insn, 0, 1, tmp & 0xF8, dt_byte);
|
||||
return finalise_insn(insn, SAM8_SRP1);
|
||||
|
||||
case 2:
|
||||
imm_operand(insn, 0, 1, tmp & 0xF8, dt_byte);
|
||||
return finalise_insn(insn, SAM8_SRP0);
|
||||
|
||||
case 3:
|
||||
return 0; // invalid instruction
|
||||
}
|
||||
}
|
||||
// fallthrough
|
||||
|
||||
case 0x82: case 0x92: case 0x83: case 0x93:
|
||||
{
|
||||
// work out correct code
|
||||
ushort opcode = 0;
|
||||
switch ( code )
|
||||
{
|
||||
case 0x82: opcode = SAM8_PUSHUD; break;
|
||||
case 0x92: opcode = SAM8_POPUD; break;
|
||||
case 0x83: opcode = SAM8_PUSHUI; break;
|
||||
case 0x93: opcode = SAM8_POPUI; break;
|
||||
}
|
||||
|
||||
// setup operands
|
||||
if ( opcode == SAM8_POPUD || opcode == SAM8_POPUI )
|
||||
{
|
||||
reg_operand(insn, 1, true, false, false, insn.get_next_byte());
|
||||
reg_operand(insn, 0, false, false, false, insn.get_next_byte());
|
||||
}
|
||||
else
|
||||
{
|
||||
reg_operand(insn, 0, true, false, false, insn.get_next_byte());
|
||||
reg_operand(insn, 1, false, false, false, insn.get_next_byte());
|
||||
}
|
||||
return finalise_insn(insn, opcode);
|
||||
}
|
||||
|
||||
case 0xC2: case 0xD2:
|
||||
{
|
||||
// work out correct code
|
||||
ushort opcode = 0;
|
||||
switch ( code )
|
||||
{
|
||||
case 0xC2: opcode = SAM8_CPIJE; break;
|
||||
case 0xD2: opcode = SAM8_CPIJNE; break;
|
||||
}
|
||||
|
||||
// decode it
|
||||
ushort tmp = insn.get_next_byte();
|
||||
reg_operand(insn, 0, false, true, false, bottom_nibble(tmp));
|
||||
reg_operand(insn, 1, true, true, false, top_nibble(tmp));
|
||||
code_operand(insn, 2, 2, insn.ea + 3 + (char) insn.get_next_byte());
|
||||
return finalise_insn(insn, opcode);
|
||||
}
|
||||
|
||||
case 0xE2: case 0xF2: case 0xC3: case 0xD3: case 0xE3: case 0xF3:
|
||||
{
|
||||
// need the next byte to tell whether data or code memory
|
||||
ushort opcode = 0;
|
||||
ushort tmp = insn.get_next_byte();
|
||||
ushort operandT = top_nibble(tmp);
|
||||
ushort operandB = bottom_nibble(tmp);
|
||||
if ( operandB & 1 )
|
||||
{
|
||||
switch ( code )
|
||||
{
|
||||
case 0xE2: opcode = SAM8_LDED; break;
|
||||
case 0xF2: opcode = SAM8_LDEPD; break;
|
||||
case 0xC3: opcode = SAM8_LDE; break;
|
||||
case 0xD3: opcode = SAM8_LDE; break;
|
||||
case 0xE3: opcode = SAM8_LDEI; break;
|
||||
case 0xF3: opcode = SAM8_LDEPI; break;
|
||||
}
|
||||
operandB--;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch ( code )
|
||||
{
|
||||
case 0xE2: opcode = SAM8_LDCD; break;
|
||||
case 0xF2: opcode = SAM8_LDCPD; break;
|
||||
case 0xC3: opcode = SAM8_LDC; break;
|
||||
case 0xD3: opcode = SAM8_LDC; break;
|
||||
case 0xE3: opcode = SAM8_LDCI; break;
|
||||
case 0xF3: opcode = SAM8_LDCPI; break;
|
||||
}
|
||||
}
|
||||
|
||||
// decode it
|
||||
if ( code & 0x10 )
|
||||
{
|
||||
reg_operand(insn, 0, true, true, true, operandB);
|
||||
reg_operand(insn, 1, false, true, false, operandT);
|
||||
}
|
||||
else
|
||||
{
|
||||
reg_operand(insn, 0, false, true, false, operandT);
|
||||
reg_operand(insn, 1, true, true, true, operandB);
|
||||
}
|
||||
return finalise_insn(insn, opcode);
|
||||
}
|
||||
|
||||
case 0xD4:
|
||||
{
|
||||
// get indirect address & check it is valid
|
||||
ushort tmp = insn.get_next_byte();
|
||||
if ( tmp & 1 )
|
||||
return 0;
|
||||
|
||||
// generate operation
|
||||
ind_code_operand(insn, 0, 1, tmp);
|
||||
return finalise_insn(insn, SAM8_CALL);
|
||||
}
|
||||
|
||||
case 0xF4:
|
||||
reg_operand(insn, 0, true, false, true, insn.get_next_byte());
|
||||
return finalise_insn(insn, SAM8_CALL);
|
||||
|
||||
case 0xF6:
|
||||
code_operand(insn, 0, 1, insn.get_next_word());
|
||||
return finalise_insn(insn, SAM8_CALL);
|
||||
|
||||
case 0xE4:
|
||||
reg_operand(insn, 1, false, false, false, insn.get_next_byte());
|
||||
reg_operand(insn, 0, false, false, false, insn.get_next_byte());
|
||||
return finalise_insn(insn, SAM8_LD);
|
||||
|
||||
case 0xE5:
|
||||
reg_operand(insn, 1, true, false, false, insn.get_next_byte());
|
||||
reg_operand(insn, 0, false, false, false, insn.get_next_byte());
|
||||
return finalise_insn(insn, SAM8_LD);
|
||||
|
||||
case 0xF5:
|
||||
reg_operand(insn, 1, false, false, false, insn.get_next_byte());
|
||||
reg_operand(insn, 0, true, false, false, insn.get_next_byte());
|
||||
return finalise_insn(insn, SAM8_LD);
|
||||
|
||||
case 0xD5:
|
||||
return 0; // invalid instruction
|
||||
|
||||
case 0x87: case 0x97:
|
||||
{
|
||||
// get next byte
|
||||
ushort tmp = insn.get_next_byte();
|
||||
|
||||
// setup operands
|
||||
switch ( code )
|
||||
{
|
||||
case 0x87:
|
||||
reg_operand(insn, 0, false, true, false, top_nibble(tmp));
|
||||
idx_reg_operand(insn, 1, insn.get_next_byte(), bottom_nibble(tmp));
|
||||
break;
|
||||
|
||||
case 0x97:
|
||||
idx_reg_operand(insn, 0, insn.get_next_byte(), bottom_nibble(tmp));
|
||||
reg_operand(insn, 1, false, true, false, top_nibble(tmp));
|
||||
break;
|
||||
}
|
||||
|
||||
// finalise the instruction
|
||||
return finalise_insn(insn, SAM8_LD);
|
||||
}
|
||||
|
||||
case 0xd6:
|
||||
reg_operand(insn, 0, true, false, false, insn.get_next_byte());
|
||||
imm_operand(insn, 1, 2, insn.get_next_byte(), dt_byte);
|
||||
return finalise_insn(insn, SAM8_LD);
|
||||
|
||||
case 0xe6:
|
||||
reg_operand(insn, 0, false, false, false, insn.get_next_byte());
|
||||
imm_operand(insn, 1, 2, insn.get_next_byte(), dt_byte);
|
||||
return finalise_insn(insn, SAM8_LD);
|
||||
|
||||
case 0xc7:
|
||||
{
|
||||
ushort tmp = insn.get_next_byte();
|
||||
reg_operand(insn, 0, false, true, false, top_nibble(tmp));
|
||||
reg_operand(insn, 1, true, true, false, bottom_nibble(tmp));
|
||||
return finalise_insn(insn, SAM8_LD);
|
||||
}
|
||||
|
||||
case 0xd7:
|
||||
{
|
||||
ushort tmp = insn.get_next_byte();
|
||||
reg_operand(insn, 0, true, true, false, top_nibble(tmp));
|
||||
reg_operand(insn, 1, false, true, false, bottom_nibble(tmp));
|
||||
return finalise_insn(insn, SAM8_LD);
|
||||
}
|
||||
|
||||
case 0xa7: case 0xb7:
|
||||
{
|
||||
// extract data
|
||||
ushort tmp = insn.get_next_byte();
|
||||
|
||||
// decode opcode + setup operands
|
||||
ushort opcode;
|
||||
switch ( bottom_nibble(tmp) )
|
||||
{
|
||||
case 0:
|
||||
opcode = SAM8_LDC;
|
||||
switch ( code )
|
||||
{
|
||||
case 0xa7:
|
||||
reg_operand(insn, 0, false, true, false, top_nibble(tmp));
|
||||
addr_cdata_operand(insn, 1, 2, next_word_le(insn));
|
||||
break;
|
||||
|
||||
case 0xb7:
|
||||
addr_cdata_operand(insn, 0, 2, next_word_le(insn));
|
||||
reg_operand(insn, 1, false, true, false, top_nibble(tmp));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
opcode = SAM8_LDE;
|
||||
switch ( code )
|
||||
{
|
||||
case 0xa7:
|
||||
reg_operand(insn, 0, false, true, false, top_nibble(tmp));
|
||||
addr_edata_operand(insn, 1, 2, next_word_le(insn));
|
||||
break;
|
||||
|
||||
case 0xb7:
|
||||
addr_edata_operand(insn, 0, 2, next_word_le(insn));
|
||||
reg_operand(insn, 1, false, true, false, top_nibble(tmp));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// extract operand nibbles
|
||||
ushort operandT = top_nibble(tmp);
|
||||
ushort operandB = bottom_nibble(tmp);
|
||||
|
||||
// decode the correct opcode
|
||||
if ( operandB & 1 )
|
||||
{
|
||||
opcode = SAM8_LDE;
|
||||
operandB--;
|
||||
}
|
||||
else
|
||||
{
|
||||
opcode = SAM8_LDC;
|
||||
}
|
||||
|
||||
// generate operands
|
||||
switch ( code )
|
||||
{
|
||||
case 0xA7:
|
||||
reg_operand(insn, 0, false, true, false, operandT);
|
||||
if ( opcode == SAM8_LDC )
|
||||
idx_cdata_operand(insn, 1, 2, next_word_le(insn), operandB);
|
||||
else
|
||||
idx_edata_operand(insn, 1, 2, next_word_le(insn), operandB);
|
||||
break;
|
||||
|
||||
case 0xB7:
|
||||
if ( opcode == SAM8_LDC )
|
||||
idx_cdata_operand(insn, 0, 2, next_word_le(insn), operandB);
|
||||
else
|
||||
idx_edata_operand(insn, 0, 2, next_word_le(insn), operandB);
|
||||
reg_operand(insn, 1, false, true, false, operandT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// finalise instruction
|
||||
return finalise_insn(insn, opcode);
|
||||
}
|
||||
|
||||
case 0xE7: case 0xF7:
|
||||
{
|
||||
// extract data
|
||||
ushort tmp = insn.get_next_byte();
|
||||
ushort operandT = top_nibble(tmp);
|
||||
ushort operandB = bottom_nibble(tmp);
|
||||
|
||||
// decode the correct opcode
|
||||
ushort opcode;
|
||||
if ( operandB & 1 )
|
||||
{
|
||||
opcode = SAM8_LDE;
|
||||
operandB--;
|
||||
}
|
||||
else
|
||||
{
|
||||
opcode = SAM8_LDC;
|
||||
}
|
||||
|
||||
// generate operands
|
||||
switch ( code )
|
||||
{
|
||||
case 0xE7:
|
||||
reg_operand(insn, 0, false, true, false, operandT);
|
||||
if ( opcode == SAM8_LDC )
|
||||
idx_cdata_operand(insn, 1, 2, (int) (char) insn.get_next_byte(), operandB);
|
||||
else
|
||||
idx_edata_operand(insn, 1, 2, (int) (char) insn.get_next_byte(), operandB);
|
||||
break;
|
||||
|
||||
case 0xF7:
|
||||
if ( opcode == SAM8_LDC )
|
||||
idx_cdata_operand(insn, 0, 2, (int) (char) insn.get_next_byte(), operandB);
|
||||
else
|
||||
idx_edata_operand(insn, 0, 2, (int) (char) insn.get_next_byte(), operandB);
|
||||
reg_operand(insn, 1, false, true, false, operandT);
|
||||
break;
|
||||
}
|
||||
|
||||
// finalise the instruction
|
||||
return finalise_insn(insn, opcode);
|
||||
}
|
||||
|
||||
case 0x84: case 0x85: case 0x86:
|
||||
case 0x94: case 0x95: case 0x96:
|
||||
{
|
||||
// decode correct opcode
|
||||
ushort opcode = 0;
|
||||
switch ( top_nibble(code) )
|
||||
{
|
||||
case 8: opcode = SAM8_MULT; break;
|
||||
case 9: opcode = SAM8_DIV; break;
|
||||
}
|
||||
|
||||
// Now, generate instruction
|
||||
ushort src = insn.get_next_byte();
|
||||
ushort dst = insn.get_next_byte();
|
||||
reg_operand(insn, 0, false, false, true, dst);
|
||||
switch ( bottom_nibble(code) )
|
||||
{
|
||||
case 4: reg_operand(insn, 1, false, false, false, src); break;
|
||||
case 5: reg_operand(insn, 1, true, false, false, src); break;
|
||||
case 6: imm_operand(insn, 1, 1, src, dt_byte); break;
|
||||
}
|
||||
return finalise_insn(insn, opcode);
|
||||
}
|
||||
|
||||
case 0xC4: case 0xC5:
|
||||
{
|
||||
// get data
|
||||
ushort src = insn.get_next_byte();
|
||||
ushort dst = insn.get_next_byte();
|
||||
|
||||
// generate instruction
|
||||
reg_operand(insn, 0, false, false, true, dst);
|
||||
|
||||
// decode addrmode for opcode 2
|
||||
switch ( code )
|
||||
{
|
||||
case 0xC4: reg_operand(insn, 1, false, false, true, src); break;
|
||||
case 0xC5: reg_operand(insn, 1, true, false, false, src); break;
|
||||
}
|
||||
return finalise_insn(insn, SAM8_LDW);
|
||||
}
|
||||
|
||||
case 0xC6:
|
||||
reg_operand(insn, 0, false, false, true, insn.get_next_byte());
|
||||
imm_operand(insn, 1, 2, insn.get_next_word(), dt_word);
|
||||
return finalise_insn(insn, SAM8_LDW);
|
||||
|
||||
case 0x17:
|
||||
{
|
||||
// get data
|
||||
ushort operandA = insn.get_next_byte();
|
||||
ushort src = insn.get_next_byte();
|
||||
|
||||
// ensure operandA bit0 is 0
|
||||
if ( operandA & 1 )
|
||||
return 0;
|
||||
|
||||
// generate instruction
|
||||
reg_operand(insn, 0, false, true, false, top_nibble(operandA));
|
||||
regbit_operand(insn, 1, false, src, bottom_nibble(operandA) >> 1);
|
||||
return finalise_insn(insn, SAM8_BCP);
|
||||
}
|
||||
|
||||
case 0x37:
|
||||
{
|
||||
// get data
|
||||
ushort operandA = insn.get_next_byte();
|
||||
ushort dst = insn.get_next_byte();
|
||||
|
||||
// generate operands
|
||||
code_operand(insn, 0, 2, insn.ea + 3 + (char) dst);
|
||||
regbit_operand(insn, 1, true,
|
||||
top_nibble(operandA), bottom_nibble(operandA) >> 1);
|
||||
|
||||
// generate operand
|
||||
switch ( operandA & 1 )
|
||||
{
|
||||
case 0: return finalise_insn(insn, SAM8_BTJRF);
|
||||
case 1: return finalise_insn(insn, SAM8_BTJRT);
|
||||
}
|
||||
}
|
||||
// fallthrough
|
||||
|
||||
case 0x57:
|
||||
{
|
||||
// get data
|
||||
ushort operandA = insn.get_next_byte();
|
||||
|
||||
// ensure operandA bit0 is 0
|
||||
if ( operandA & 1 )
|
||||
return 0;
|
||||
|
||||
// generate instruction
|
||||
regbit_operand(insn, 0, true,
|
||||
top_nibble(operandA), bottom_nibble(operandA) >> 1);
|
||||
return finalise_insn(insn, SAM8_BITC);
|
||||
}
|
||||
|
||||
case 0x77:
|
||||
{
|
||||
// get data
|
||||
ushort operandA = insn.get_next_byte();
|
||||
|
||||
// generate instruction
|
||||
regbit_operand(insn, 0, true,
|
||||
top_nibble(operandA), bottom_nibble(operandA) >> 1);
|
||||
switch ( operandA & 1 )
|
||||
{
|
||||
case 0: return finalise_insn(insn, SAM8_BITR);
|
||||
case 1: return finalise_insn(insn, SAM8_BITS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Decode bit instructions
|
||||
if ( (bottom_nibble(code) == 7) && (top_nibble(code) < 8) )
|
||||
{
|
||||
static const uint16 codeTable[] =
|
||||
{
|
||||
SAM8_BOR, SAM8_null,
|
||||
SAM8_BXOR, SAM8_null,
|
||||
SAM8_LDB, SAM8_null,
|
||||
SAM8_BAND, SAM8_null
|
||||
};
|
||||
|
||||
// extract data
|
||||
ushort operandA = insn.get_next_byte();
|
||||
ushort operandB = insn.get_next_byte();
|
||||
|
||||
// generate instruction
|
||||
switch ( operandA & 1 )
|
||||
{
|
||||
case 0:
|
||||
reg_operand(insn, 0, false, true, false, top_nibble(operandA));
|
||||
regbit_operand(insn, 1, false, operandB, bottom_nibble(operandA) >> 1);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
regbit_operand(insn, 0, false, operandB, bottom_nibble(operandA) >> 1);
|
||||
reg_operand(insn, 1, false, true, false, top_nibble(operandA));
|
||||
break;
|
||||
}
|
||||
return finalise_insn(insn, codeTable[top_nibble(code)]);
|
||||
}
|
||||
|
||||
|
||||
// Do the instructions with stuff encoded in them
|
||||
switch ( bottom_nibble(code) )
|
||||
{
|
||||
case 0x08:
|
||||
reg_operand(insn, 0, false, true, false, top_nibble(code));
|
||||
reg_operand(insn, 1, false, false, false, insn.get_next_byte());
|
||||
return finalise_insn(insn, SAM8_LD);
|
||||
|
||||
case 0x09:
|
||||
reg_operand(insn, 0, false, false, false, insn.get_next_byte());
|
||||
reg_operand(insn, 1, false, true, false, top_nibble(code));
|
||||
return finalise_insn(insn, SAM8_LD);
|
||||
|
||||
case 0x0A:
|
||||
reg_operand(insn, 0, false, true, false, top_nibble(code));
|
||||
code_operand(insn, 1, 1, insn.ea + 2 + (char) insn.get_next_byte());
|
||||
return finalise_insn(insn, SAM8_DJNZ);
|
||||
|
||||
case 0x0B:
|
||||
code_operand(insn, 0, 1, insn.ea + 2 + (char) insn.get_next_byte());
|
||||
return finalise_insn(insn, SAM8_JR, top_nibble(code));
|
||||
|
||||
case 0x0C:
|
||||
reg_operand(insn, 0, false, true, false, top_nibble(code));
|
||||
imm_operand(insn, 1, 1, insn.get_next_byte(), dt_byte);
|
||||
return finalise_insn(insn, SAM8_LD);
|
||||
|
||||
case 0x0D:
|
||||
code_operand(insn, 0, 1, insn.get_next_word()); // UNSURE ****
|
||||
return finalise_insn(insn, SAM8_JP, top_nibble(code));
|
||||
|
||||
case 0x0E:
|
||||
reg_operand(insn, 0, false, true, false, top_nibble(code));
|
||||
return finalise_insn(insn, SAM8_INC);
|
||||
|
||||
case 0x0F:
|
||||
{
|
||||
static const uint16 codeTable[] =
|
||||
{
|
||||
SAM8_NEXT, SAM8_ENTER,
|
||||
SAM8_EXIT, SAM8_WFI,
|
||||
SAM8_SB0, SAM8_SB1,
|
||||
SAM8_IDLE, SAM8_STOP,
|
||||
SAM8_DI, SAM8_EI,
|
||||
SAM8_RET, SAM8_IRET,
|
||||
SAM8_RCF, SAM8_SCF,
|
||||
SAM8_CCF, SAM8_NOP
|
||||
};
|
||||
return finalise_insn(insn, codeTable[top_nibble(code)]);
|
||||
}
|
||||
}
|
||||
|
||||
// Do R/RR/IR-only mode instructions
|
||||
if ( bottom_nibble(code) < 2 )
|
||||
{
|
||||
static const uint16 codeTable[] =
|
||||
{
|
||||
SAM8_DEC, SAM8_RLC,
|
||||
SAM8_INC, SAM8_null,
|
||||
SAM8_DA, SAM8_POP,
|
||||
SAM8_COM, SAM8_PUSH,
|
||||
SAM8_DECW, SAM8_RL,
|
||||
SAM8_INCW, SAM8_CLR,
|
||||
SAM8_RRC, SAM8_SRA,
|
||||
SAM8_RR, SAM8_SWAP
|
||||
};
|
||||
// do the operand
|
||||
if ( code & 1 )
|
||||
{
|
||||
reg_operand(insn, 0, true, false, false, insn.get_next_byte());
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( (top_nibble(code) == 8) || (top_nibble(code) == 0xA) )
|
||||
reg_operand(insn, 0, false, false, true, insn.get_next_byte());
|
||||
else
|
||||
reg_operand(insn, 0, false, false, false, insn.get_next_byte());
|
||||
}
|
||||
|
||||
// finalise it
|
||||
return finalise_insn(insn, codeTable[top_nibble(code)]);
|
||||
}
|
||||
|
||||
// Decode arithmetic-style instructions
|
||||
if ( (bottom_nibble(code) > 1) && (bottom_nibble(code) < 7) )
|
||||
{
|
||||
static const uint16 codeTable[] =
|
||||
{
|
||||
SAM8_ADD, SAM8_ADC,
|
||||
SAM8_SUB, SAM8_SBC,
|
||||
SAM8_OR, SAM8_AND,
|
||||
SAM8_TCM, SAM8_TM,
|
||||
SAM8_null, SAM8_null,
|
||||
SAM8_CP, SAM8_XOR,
|
||||
SAM8_null, SAM8_null,
|
||||
SAM8_null, SAM8_null
|
||||
};
|
||||
ushort operandA = insn.get_next_byte();
|
||||
switch ( bottom_nibble(code) )
|
||||
{
|
||||
case 2:
|
||||
reg_operand(insn, 0, false, true, false, top_nibble(operandA));
|
||||
reg_operand(insn, 1, false, true, false, bottom_nibble(operandA));
|
||||
return finalise_insn(insn, codeTable[top_nibble(code)]);
|
||||
|
||||
case 3:
|
||||
reg_operand(insn, 0, false, true, false, top_nibble(operandA));
|
||||
reg_operand(insn, 1, true, true, false, bottom_nibble(operandA));
|
||||
return finalise_insn(insn, codeTable[top_nibble(code)]);
|
||||
|
||||
case 4:
|
||||
reg_operand(insn, 0, false, false, false, insn.get_next_byte());
|
||||
reg_operand(insn, 1, false, false, false, operandA);
|
||||
return finalise_insn(insn, codeTable[top_nibble(code)]);
|
||||
|
||||
case 5:
|
||||
reg_operand(insn, 0, false, false, false, insn.get_next_byte());
|
||||
reg_operand(insn, 1, true, false, false, operandA);
|
||||
return finalise_insn(insn, codeTable[top_nibble(code)]);
|
||||
|
||||
case 6:
|
||||
reg_operand(insn, 0, false, false, false, operandA);
|
||||
imm_operand(insn, 1, 1, insn.get_next_byte(), dt_byte);
|
||||
return finalise_insn(insn, codeTable[top_nibble(code)]);
|
||||
}
|
||||
}
|
||||
|
||||
// If we get here, we've got an invalid instruction
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// analyze an instruction
|
||||
int idaapi ana(insn_t *_insn)
|
||||
{
|
||||
insn_t &insn = *_insn;
|
||||
|
||||
// analyze it!
|
||||
return ana_basic(insn);
|
||||
}
|
||||
161
idasdk76/module/sam8/emu.cpp
Normal file
161
idasdk76/module/sam8/emu.cpp
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Disassembler for Samsung SAM87 processors
|
||||
*/
|
||||
|
||||
#include "sam8.hpp"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Handle an operand. What this function usually does:
|
||||
// - creates cross-references from the operand
|
||||
// (the kernel deletes all xrefs before calling emu())
|
||||
// - creates permanent comments
|
||||
// - if possible, specifies the operand type (for example, it may
|
||||
// create stack variables)
|
||||
// - anything else you might need to emulate or trace
|
||||
void sam8_t::handle_operand(const insn_t &insn, const op_t &x, bool loading)
|
||||
{
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_phrase: // no special handling for these types
|
||||
case o_reg:
|
||||
case o_reg_bit:
|
||||
break;
|
||||
|
||||
case o_imm:
|
||||
// this can't happen!
|
||||
if ( !loading )
|
||||
goto BAD_LOGIC;
|
||||
|
||||
// set immediate flag
|
||||
set_immd(insn.ea);
|
||||
|
||||
// if the value was converted to an offset, then create a data xref:
|
||||
if ( op_adds_xrefs(get_flags(insn.ea), x.n) )
|
||||
insn.add_off_drefs(x, dr_O, 0);
|
||||
break;
|
||||
|
||||
case o_displ:
|
||||
if ( x.phrase == fIdxCAddr )
|
||||
{
|
||||
insn.create_op_data(x.addr, x);
|
||||
insn.add_dref(x.addr, x.offb, loading ? dr_R : dr_W);
|
||||
}
|
||||
else
|
||||
{
|
||||
// create name
|
||||
char buf[256];
|
||||
qsnprintf(buf, sizeof(buf), "emem_%a", x.addr);
|
||||
set_name(SAM8_EDATASEG_START + x.addr, buf, SN_NOCHECK|SN_AUTO);
|
||||
|
||||
// setup data xrefs etc
|
||||
insn.create_op_data(SAM8_EDATASEG_START + x.addr, x);
|
||||
insn.add_dref(SAM8_EDATASEG_START + x.addr, x.offb, loading ? dr_R : dr_W);
|
||||
}
|
||||
break;
|
||||
|
||||
case o_emem:
|
||||
{
|
||||
// create variable name
|
||||
char buf[256];
|
||||
qsnprintf(buf, sizeof(buf), "emem_%a", x.addr);
|
||||
set_name(SAM8_EDATASEG_START + x.addr, buf, SN_NOCHECK|SN_AUTO);
|
||||
|
||||
// setup data xrefs etc
|
||||
insn.create_op_data(SAM8_EDATASEG_START + x.addr, x);
|
||||
insn.add_dref(SAM8_EDATASEG_START + x.addr, x.offb, loading ? dr_R : dr_W);
|
||||
break;
|
||||
}
|
||||
|
||||
case o_cmem:
|
||||
insn.create_op_data(x.addr, x);
|
||||
insn.add_dref(x.addr, x.offb, loading ? dr_R : dr_W);
|
||||
break;
|
||||
|
||||
case o_near:
|
||||
{
|
||||
// work out if it is a CALL, and add in a code xref
|
||||
bool iscall = has_insn_feature(insn.itype, CF_CALL);
|
||||
insn.add_cref(x.addr, x.offb, iscall ? fl_CN : fl_JN);
|
||||
|
||||
// if dest is a non-returning function, don't flow onto next op
|
||||
if ( flow && iscall )
|
||||
{
|
||||
if ( !func_does_return(x.addr) )
|
||||
flow = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case o_cmem_ind:
|
||||
// setup code xref/variable
|
||||
insn.create_op_data(x.addr, x.offb, dt_word);
|
||||
insn.add_dref(x.addr, x.offb, loading ? dr_R : dr_W);
|
||||
|
||||
// Now, since we KNOW this is an indirect code jump, turn
|
||||
// the word at the x.addr into an offset into a subroutine
|
||||
if ( is_mapped(x.addr) )
|
||||
{
|
||||
// get value stored in that address
|
||||
ushort destAddr = get_word(x.addr);
|
||||
|
||||
// add in cref & turn into offset
|
||||
add_cref(x.addr, destAddr, fl_JN);
|
||||
op_plain_offset(x.addr, 0, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
BAD_LOGIC:
|
||||
warning("%a (%s): bad optype", insn.ea, insn.get_canon_mnem(ph));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Emulate an instruction
|
||||
// This function should:
|
||||
// - create all xrefs from the instruction
|
||||
// - perform any additional analysis of the instruction/program
|
||||
// and convert the instruction operands, create comments, etc.
|
||||
// - create stack variables
|
||||
// - analyze the delayed branches and similar constructs
|
||||
|
||||
int sam8_t::emu(const insn_t &insn)
|
||||
{
|
||||
// setup
|
||||
uint32 Feature = insn.get_canon_feature(ph);
|
||||
flow = true;
|
||||
|
||||
// disable flow if CF_STOP set
|
||||
if ( Feature & CF_STOP )
|
||||
flow = false;
|
||||
|
||||
// you may emulate selected instructions with a greater care:
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case SAM8_JR: case SAM8_JP:
|
||||
// Do extended condition code checking on these instructions
|
||||
if ( insn.c_condition == ccNone || insn.c_condition == ccT )
|
||||
flow = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// deal with operands
|
||||
if ( Feature & CF_USE1 ) handle_operand(insn, insn.Op1, true);
|
||||
if ( Feature & CF_USE2 ) handle_operand(insn, insn.Op2, true);
|
||||
if ( Feature & CF_USE3 ) handle_operand(insn, insn.Op3, true);
|
||||
if ( Feature & CF_JUMP )
|
||||
remember_problem(PR_JUMP, insn.ea);
|
||||
if ( Feature & CF_CHG1 ) handle_operand(insn, insn.Op1, false);
|
||||
if ( Feature & CF_CHG2 ) handle_operand(insn, insn.Op2, false);
|
||||
if ( Feature & CF_CHG3 ) handle_operand(insn, insn.Op3, false);
|
||||
|
||||
// if the execution flow is not stopped here, then create
|
||||
// a xref to the next instruction.
|
||||
// Thus we plan to analyze the next instruction.
|
||||
if ( flow )
|
||||
add_cref(insn.ea, insn.ea + insn.size, fl_F);
|
||||
|
||||
// OK (actual code unimportant)
|
||||
return 1;
|
||||
}
|
||||
90
idasdk76/module/sam8/ins.cpp
Normal file
90
idasdk76/module/sam8/ins.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Disassembler for Samsung SAM8 processors
|
||||
*/
|
||||
|
||||
#include "sam8.hpp"
|
||||
|
||||
const instruc_t Instructions[] =
|
||||
{
|
||||
{ "", 0 }, // Unknown Operation
|
||||
{ "adc", CF_USE1|CF_USE2|CF_CHG1 }, // ADC dst, src
|
||||
{ "add", CF_USE1|CF_USE2|CF_CHG1 }, // ADD dst, src
|
||||
{ "and", CF_USE1|CF_USE2|CF_CHG1 }, // AND dst, src
|
||||
{ "band", CF_USE1|CF_USE2|CF_CHG1 }, // BAND dst, src.b BAND dst.b, src
|
||||
{ "bcp", CF_USE1|CF_USE2 }, // BCP dst, src.b
|
||||
{ "bitc", CF_USE1|CF_CHG1 }, // BITC dst.b
|
||||
{ "bitr", CF_CHG1 }, // BITR dst.b
|
||||
{ "bits", CF_CHG1 }, // BITS dst.b
|
||||
{ "bor", CF_USE1|CF_USE2|CF_CHG1 }, // BOR dst, src.b BOR dst.b, src
|
||||
{ "btjrf", CF_USE1|CF_USE2|CF_JUMP }, // BTJRF dst, src.b
|
||||
{ "btjrt", CF_USE1|CF_USE2|CF_JUMP }, // BTJRT dst, src.b
|
||||
{ "bxor", CF_USE1|CF_USE2|CF_CHG1 }, // BXOR dst, src.b BXOR dst.b, src
|
||||
{ "call", CF_USE1|CF_CALL }, // CALL dst
|
||||
{ "ccf", 0 }, // CCF
|
||||
{ "clr", CF_CHG1 }, // CLR dst
|
||||
{ "com", CF_USE1|CF_CHG1 }, // COM dst
|
||||
{ "cp", CF_USE1|CF_USE2 }, // CP dst, src
|
||||
{ "cpije", CF_USE1|CF_USE2|CF_USE3|CF_CHG2|CF_JUMP }, // CPIJE dst, src, RA
|
||||
{ "cpijne", CF_USE1|CF_USE2|CF_USE3|CF_CHG2|CF_JUMP }, // CPIJNE dst, src, RA
|
||||
{ "da", CF_USE1|CF_CHG1 }, // DA dst
|
||||
{ "dec", CF_USE1|CF_CHG1 }, // DEC dst
|
||||
{ "decw", CF_USE1|CF_CHG1 }, // DECW dst
|
||||
{ "di", 0 }, // DI
|
||||
{ "div", CF_USE1|CF_USE2|CF_CHG1 }, // DIV dst, src.b
|
||||
{ "djnz", CF_USE1|CF_USE2|CF_CHG1|CF_JUMP }, // DJNZ r, dst
|
||||
{ "ei", 0 }, // EI
|
||||
{ "enter", 0 }, // ENTER
|
||||
{ "exit", CF_STOP }, // EXIT
|
||||
{ "idle", 0 }, // IDLE
|
||||
{ "inc", CF_USE1|CF_CHG1 }, // INC dst
|
||||
{ "incw", CF_USE1|CF_CHG1 }, // INCW dst
|
||||
{ "iret", 0 }, // IRET
|
||||
{ "jp", CF_USE1|CF_JUMP }, // JP cc, dst
|
||||
{ "jr", CF_USE1|CF_JUMP }, // JR cc, dst
|
||||
{ "ld", CF_USE1|CF_USE2|CF_CHG1 }, // LD dst, src
|
||||
{ "ldb", CF_USE1|CF_USE2|CF_CHG1 }, // LDB dst, src.b LDB dst.b, src
|
||||
{ "ldc", CF_USE1|CF_USE2|CF_CHG1 }, // LDC dst, src
|
||||
{ "lde", CF_USE1|CF_USE2|CF_CHG1 }, // LDE dst, src
|
||||
{ "ldcd", CF_USE1|CF_USE2|CF_CHG1 }, // LDCD dst, src
|
||||
{ "lded", CF_USE1|CF_USE2|CF_CHG1 }, // LDED dst, src
|
||||
{ "ldci", CF_USE1|CF_USE2|CF_CHG1 }, // LDCI dst, src
|
||||
{ "ldei", CF_USE1|CF_USE2|CF_CHG1 }, // LDEI dst, src
|
||||
{ "ldcpd", CF_USE1|CF_USE2|CF_CHG1 }, // LDCPD dst, src
|
||||
{ "ldepd", CF_USE1|CF_USE2|CF_CHG1 }, // LDEPD dst, src
|
||||
{ "ldcpi", CF_USE1|CF_USE2|CF_CHG1 }, // LDCPI dst, src
|
||||
{ "ldepi", CF_USE1|CF_USE2|CF_CHG1 }, // LDEPI dst, src
|
||||
{ "ldw", CF_USE1|CF_USE2|CF_CHG1 }, // LDW dst, src
|
||||
{ "mult", CF_USE1|CF_USE2|CF_CHG1 }, // MULT dst, src
|
||||
{ "next", CF_STOP }, // NEXT
|
||||
{ "nop", 0 }, // NOP
|
||||
{ "or", CF_USE1|CF_USE2|CF_CHG1 }, // OR dst, src
|
||||
{ "pop", CF_CHG1 }, // POP dst
|
||||
{ "popud", CF_USE2|CF_CHG1|CF_CHG2 }, // POPUD dst, src
|
||||
{ "popui", CF_USE2|CF_CHG1|CF_CHG2 }, // POPUI dst, src
|
||||
{ "push", CF_USE1 }, // PUSH dst
|
||||
{ "pushud", CF_USE1|CF_USE2|CF_CHG1 }, // PUSHUD dst, src
|
||||
{ "pushui", CF_USE1|CF_USE2|CF_CHG1 }, // PUSHUI dst, src
|
||||
{ "rcf", 0 }, // RCF
|
||||
{ "ret", CF_STOP }, // RET
|
||||
{ "rl", CF_USE1|CF_CHG1|CF_SHFT }, // RL dst
|
||||
{ "rlc", CF_USE1|CF_CHG1|CF_SHFT }, // RLC dst
|
||||
{ "rr", CF_USE1|CF_CHG1|CF_SHFT }, // RR dst
|
||||
{ "rrc", CF_USE1|CF_CHG1|CF_SHFT }, // RRC dst
|
||||
{ "sb0", 0 }, // SB0
|
||||
{ "sb1", 0 }, // SB1
|
||||
{ "sbc", CF_USE1|CF_USE2|CF_CHG1 }, // SBC dst, src
|
||||
{ "scf", 0 }, // SCF
|
||||
{ "sra", CF_USE1|CF_CHG1|CF_SHFT }, // SRA dst
|
||||
{ "srp", CF_USE1 }, // SRP src
|
||||
{ "srp0", CF_USE1 }, // SRP0 src
|
||||
{ "srp1", CF_USE1 }, // SRP1 src
|
||||
{ "stop", 0 }, // STOP
|
||||
{ "sub", CF_USE1|CF_USE2|CF_CHG1 }, // SUB dst, src
|
||||
{ "swap", CF_USE1|CF_CHG1 }, // SWAP dst
|
||||
{ "tcm", CF_USE1|CF_USE2 }, // TCM dst, src
|
||||
{ "tm", CF_USE1|CF_USE2 }, // TM dst, src
|
||||
{ "wfi", 0 }, // WFI
|
||||
{ "xor", CF_USE1|CF_USE2|CF_CHG1 } // XOR dst, src
|
||||
};
|
||||
|
||||
CASSERT(qnumber(Instructions) == SAM8_last);
|
||||
98
idasdk76/module/sam8/ins.hpp
Normal file
98
idasdk76/module/sam8/ins.hpp
Normal file
@@ -0,0 +1,98 @@
|
||||
/************************************************************************/
|
||||
/* Disassembler for Samsung SAM8 processors */
|
||||
/************************************************************************/
|
||||
#ifndef __INSTRS_HPP
|
||||
#define __INSTRS_HPP
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* Instructions enumeration */
|
||||
/************************************************************************/
|
||||
extern const instruc_t Instructions[];
|
||||
enum nameNum
|
||||
{
|
||||
SAM8_null = 0, // Unknown Operation
|
||||
|
||||
SAM8_ADC, // Add with carry
|
||||
SAM8_ADD, // Add
|
||||
SAM8_AND, // Logical and
|
||||
SAM8_BAND, // Bit and
|
||||
SAM8_BCP, // Bit compare
|
||||
SAM8_BITC, // Bit complement
|
||||
SAM8_BITR, // Bit reset
|
||||
SAM8_BITS, // Bit set
|
||||
SAM8_BOR, // Bit or
|
||||
SAM8_BTJRF, // Bit test, jump relative on false
|
||||
SAM8_BTJRT, // Bit test, jump relative on true
|
||||
SAM8_BXOR, // Bit xor
|
||||
SAM8_CALL, // Call procedure
|
||||
SAM8_CCF, // Complement carry flag
|
||||
SAM8_CLR, // Clear
|
||||
SAM8_COM, // Complement
|
||||
SAM8_CP, // Compare
|
||||
SAM8_CPIJE, // Compare, increment, and jump on equal
|
||||
SAM8_CPIJNE, // Compare, increment, and jump on non-equal
|
||||
SAM8_DA, // Decimal adjust
|
||||
SAM8_DEC, // Decrement
|
||||
SAM8_DECW, // Decrement word
|
||||
SAM8_DI, // Disable interrupts
|
||||
SAM8_DIV, // Divide (unsigned)
|
||||
SAM8_DJNZ, // Decrement and jump if non-zero
|
||||
SAM8_EI, // Enable interrupts
|
||||
SAM8_ENTER, // Enter
|
||||
SAM8_EXIT, // Exit
|
||||
SAM8_IDLE, // Idle operation
|
||||
SAM8_INC, // Increment
|
||||
SAM8_INCW, // Increment word
|
||||
SAM8_IRET, // Interrupt return
|
||||
SAM8_JP, // Jump
|
||||
SAM8_JR, // Jump relative
|
||||
SAM8_LD, // Load
|
||||
SAM8_LDB, // Load bit
|
||||
SAM8_LDC, // Load program memory
|
||||
SAM8_LDE, // Load external data memory
|
||||
SAM8_LDCD, // Load program memory and decrement
|
||||
SAM8_LDED, // Load external data memory and decrement
|
||||
SAM8_LDCI, // Load program memory and increment
|
||||
SAM8_LDEI, // Load external data memory and increment
|
||||
SAM8_LDCPD, // Load program memory with pre-decrement
|
||||
SAM8_LDEPD, // Load external data memory with pre-decrement
|
||||
SAM8_LDCPI, // Load program memory with pre-increment
|
||||
SAM8_LDEPI, // Load external data memory with pre-increment
|
||||
SAM8_LDW, // Load word
|
||||
SAM8_MULT, // Multiply (unsigned)
|
||||
SAM8_NEXT, // Next
|
||||
SAM8_NOP, // No operation
|
||||
SAM8_OR, // Logical or
|
||||
SAM8_POP, // Pop from stack
|
||||
SAM8_POPUD, // Pop user stack (decrementing)
|
||||
SAM8_POPUI, // Pop user stack (incrementing)
|
||||
SAM8_PUSH, // Push to stack
|
||||
SAM8_PUSHUD, // Push user stack (decrementing)
|
||||
SAM8_PUSHUI, // Push user stack (incrementing)
|
||||
SAM8_RCF, // Reset carry flag
|
||||
SAM8_RET, // Return
|
||||
SAM8_RL, // Rotate left
|
||||
SAM8_RLC, // Rotate left through carry
|
||||
SAM8_RR, // Rotate right
|
||||
SAM8_RRC, // Rotate right through carry
|
||||
SAM8_SB0, // Select bank 0
|
||||
SAM8_SB1, // Select bank 1
|
||||
SAM8_SBC, // Subtract with carry
|
||||
SAM8_SCF, // Set carry flag
|
||||
SAM8_SRA, // Shift right arithmetic
|
||||
SAM8_SRP, // Set register pointer
|
||||
SAM8_SRP0, // Set register pointer 0
|
||||
SAM8_SRP1, // Set register pointer 1
|
||||
SAM8_STOP, // Stop operation
|
||||
SAM8_SUB, // Subtract
|
||||
SAM8_SWAP, // Swap nibbles
|
||||
SAM8_TCM, // Test complement under mask
|
||||
SAM8_TM, // Test under mask
|
||||
SAM8_WFI, // Wait for interrupt
|
||||
SAM8_XOR, // Logical exclusive or
|
||||
|
||||
SAM8_last
|
||||
};
|
||||
|
||||
#endif
|
||||
50
idasdk76/module/sam8/makefile
Normal file
50
idasdk76/module/sam8/makefile
Normal file
@@ -0,0 +1,50 @@
|
||||
PROC=sam8
|
||||
|
||||
include ../module.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)ana$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp \
|
||||
$(I)nalt.hpp $(I)name.hpp \
|
||||
$(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
|
||||
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)ua.hpp $(I)xref.hpp ../idaidp.hpp ana.cpp ins.hpp \
|
||||
sam8.hpp
|
||||
$(F)emu$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp \
|
||||
$(I)nalt.hpp $(I)name.hpp \
|
||||
$(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
|
||||
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)ua.hpp $(I)xref.hpp ../idaidp.hpp emu.cpp ins.hpp \
|
||||
sam8.hpp
|
||||
$(F)ins$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp \
|
||||
$(I)nalt.hpp $(I)name.hpp \
|
||||
$(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
|
||||
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)ua.hpp $(I)xref.hpp ../idaidp.hpp ins.cpp ins.hpp \
|
||||
sam8.hpp
|
||||
$(F)out$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp \
|
||||
$(I)nalt.hpp $(I)name.hpp \
|
||||
$(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
|
||||
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)ua.hpp $(I)xref.hpp ../idaidp.hpp ins.hpp out.cpp \
|
||||
sam8.hpp
|
||||
$(F)reg$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp \
|
||||
$(I)nalt.hpp $(I)name.hpp \
|
||||
$(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
|
||||
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)segregs.hpp $(I)ua.hpp $(I)xref.hpp ../idaidp.hpp \
|
||||
ins.hpp reg.cpp sam8.hpp
|
||||
265
idasdk76/module/sam8/out.cpp
Normal file
265
idasdk76/module/sam8/out.cpp
Normal file
@@ -0,0 +1,265 @@
|
||||
|
||||
#include "sam8.hpp"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
class out_sam8_t : public outctx_t
|
||||
{
|
||||
out_sam8_t(void) = delete; // not used
|
||||
public:
|
||||
void OutRegString(bool isWorkingReg, bool isPair, int regNum, int regBit = -1);
|
||||
void OutAddr(const op_t &x, ea_t ea, ea_t off, bool isSigned = false);
|
||||
bool out_operand(const op_t &x);
|
||||
void out_insn(void);
|
||||
};
|
||||
CASSERT(sizeof(out_sam8_t) == sizeof(outctx_t));
|
||||
|
||||
DECLARE_OUT_FUNCS_WITHOUT_OUTMNEM(out_sam8_t)
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_sam8_t::OutRegString(bool isWorkingReg, bool isPair, int regNum, int regBit)
|
||||
{
|
||||
char buf[256];
|
||||
|
||||
// if it is a working register, output it with an R in front
|
||||
if ( isWorkingReg )
|
||||
{
|
||||
if ( !isPair )
|
||||
qsnprintf(buf, sizeof(buf), "R%u", (unsigned int) regNum);
|
||||
else
|
||||
qsnprintf(buf, sizeof(buf), "RR%u", (unsigned int) regNum);
|
||||
}
|
||||
else
|
||||
{
|
||||
// output either working or non-working reg
|
||||
if ( !isPair )
|
||||
{
|
||||
// N.B. working registers start at 0xC0
|
||||
if ( regNum >= 0xC0 )
|
||||
qsnprintf(buf, sizeof(buf), "R%u", (unsigned int) (regNum - 0xC0));
|
||||
else
|
||||
qsnprintf(buf, sizeof(buf), "0%XH", regNum);
|
||||
}
|
||||
else
|
||||
{
|
||||
// N.B. working registers start at 0xC0
|
||||
if ( regNum >= 0xC0 )
|
||||
qsnprintf(buf, sizeof(buf), "RR%u", (unsigned int) regNum - 0xC0);
|
||||
else
|
||||
qsnprintf(buf, sizeof(buf), "0%XH", regNum);
|
||||
}
|
||||
}
|
||||
out_register(buf);
|
||||
|
||||
// output regBit if requested
|
||||
if ( regBit != -1 )
|
||||
{
|
||||
qsnprintf(buf, sizeof(buf), ".%i", regBit);
|
||||
out_line(buf, COLOR_DEFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_sam8_t::OutAddr(const op_t &x, ea_t ea, ea_t off, bool isSigned)
|
||||
{
|
||||
// try and find the real name expression
|
||||
if ( !out_name_expr(x, ea, off) )
|
||||
{
|
||||
// work out flags correctly
|
||||
uint32 flags = OOF_ADDR | OOFW_16;
|
||||
if ( isSigned )
|
||||
flags |= OOF_SIGNED;
|
||||
else
|
||||
flags |= OOFS_NOSIGN;
|
||||
|
||||
// if name wasn't found, just output the value & add to noname queue
|
||||
out_value(x, flags);
|
||||
remember_problem(PR_NONAME, insn.ea);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// generate the text representation of an operand
|
||||
|
||||
bool out_sam8_t::out_operand(const op_t &x)
|
||||
{
|
||||
// output operands
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_reg:
|
||||
OutRegString(x.fl_workingReg != 0, x.fl_regPair != 0, x.reg);
|
||||
break;
|
||||
|
||||
case o_reg_bit:
|
||||
OutRegString(x.fl_workingReg != 0, x.fl_regPair != 0, x.reg, (int)x.v_bit);
|
||||
break;
|
||||
|
||||
case o_imm:
|
||||
out_symbol('#');
|
||||
out_value(x, OOFS_IFSIGN | OOFW_IMM);
|
||||
break;
|
||||
|
||||
case o_cmem_ind:
|
||||
// this needs special treatment... has to have a # in front of it
|
||||
out_symbol('#');
|
||||
OutAddr(x, x.addr, x.addr);
|
||||
break;
|
||||
|
||||
case o_near:
|
||||
case o_cmem:
|
||||
OutAddr(x, x.addr, x.addr);
|
||||
break;
|
||||
|
||||
case o_emem:
|
||||
OutAddr(x, SAM8_EDATASEG_START + x.addr, x.addr);
|
||||
break;
|
||||
|
||||
case o_phrase:
|
||||
switch ( x.phrase )
|
||||
{
|
||||
case fIndReg:
|
||||
out_symbol('@');
|
||||
OutRegString(x.fl_workingReg != 0, x.fl_regPair != 0, x.v_phrase_reg);
|
||||
break;
|
||||
|
||||
case fIdxReg:
|
||||
out_symbol('#');
|
||||
OutRegString(false, false, x.v_phrase_reg);
|
||||
out_symbol('[');
|
||||
OutRegString(true, false, x.v_phrase_idxreg);
|
||||
out_symbol(']');
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case o_displ:
|
||||
switch ( x.phrase )
|
||||
{
|
||||
case fIdxCAddr:
|
||||
out_symbol('#');
|
||||
OutAddr(x, x.addr, x.addr, (x.addr > 0xffff));
|
||||
out_symbol('[');
|
||||
OutRegString(true, true, x.v_phrase_idxreg);
|
||||
out_symbol(']');
|
||||
break;
|
||||
|
||||
case fIdxEAddr:
|
||||
out_symbol('#');
|
||||
OutAddr(x, SAM8_EDATASEG_START + x.addr, x.addr, (x.addr > 0xffff));
|
||||
out_symbol('[');
|
||||
OutRegString(true, true, x.v_phrase_idxreg);
|
||||
out_symbol(']');
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// OK
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// generate a text representation of an instruction
|
||||
void out_sam8_t::out_insn(void)
|
||||
{
|
||||
// output instruction mnemonics
|
||||
out_mnemonic();
|
||||
|
||||
// check for JP/JR instruction with condition code
|
||||
// add the condition on as a pseudo operand if present
|
||||
if ( insn.itype == SAM8_JR
|
||||
|| insn.itype == SAM8_JP && insn.c_condition != ccNone )
|
||||
{
|
||||
// sanity check
|
||||
if ( insn.c_condition >= cc_last )
|
||||
{
|
||||
warning("%a (%s): Internal error: bad condition code %i",
|
||||
insn.ea, insn.get_canon_mnem(ph), insn.c_condition);
|
||||
return;
|
||||
}
|
||||
|
||||
// output the condition code normally
|
||||
out_keyword(ccNames[insn.c_condition]);
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
}
|
||||
|
||||
// output the first operand
|
||||
if ( insn.Op1.type != o_void )
|
||||
out_one_operand(0);
|
||||
|
||||
// output the second operand
|
||||
if ( insn.Op2.type != o_void )
|
||||
{
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_one_operand(1);
|
||||
}
|
||||
|
||||
// output the third operand
|
||||
if ( insn.Op3.type != o_void )
|
||||
{
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_one_operand(2);
|
||||
}
|
||||
flush_outbuf();
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// generate start of the disassembly
|
||||
void idaapi sam8_header(outctx_t &ctx)
|
||||
{
|
||||
ctx.gen_header(GH_PRINT_ALL_BUT_BYTESEX);
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// generate start of segment
|
||||
//lint -esym(1764, ctx) could be made const
|
||||
//lint -esym(818, Sarea) could be made const
|
||||
void sam8_t::sam8_segstart(outctx_t &ctx, segment_t *Sarea) const
|
||||
{
|
||||
// generate ORG directive if necessary
|
||||
if ( (inf_get_outflags() & OFLG_GEN_ORG) != 0 )
|
||||
{
|
||||
// get segment data
|
||||
size_t org = size_t(ctx.insn_ea - get_segm_base(Sarea));
|
||||
|
||||
// generate line
|
||||
if ( org != 0 )
|
||||
{
|
||||
char buf[MAX_NUMBUF];
|
||||
btoa(buf, sizeof(buf), org);
|
||||
ctx.gen_printf(DEFAULT_INDENT, COLSTR("%s %s", SCOLOR_ASMDIR), ash.origin, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// generate end of the disassembly
|
||||
void sam8_t::sam8_footer(outctx_t &ctx) const
|
||||
{
|
||||
// if assembler supplies end statement, output it
|
||||
if ( ash.end != NULL )
|
||||
{
|
||||
ctx.gen_empty_line();
|
||||
ctx.out_line(ash.end, COLOR_ASMDIR);
|
||||
ctx.flush_outbuf(DEFAULT_INDENT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// customised address output
|
||||
void idaapi sam8_out_data(outctx_t &ctx, bool analyze_only)
|
||||
{
|
||||
ea_t ea = ctx.insn_ea;
|
||||
// if addres is valid, use normal output function
|
||||
if ( is_loaded(ea) )
|
||||
ctx.out_data(analyze_only);
|
||||
else
|
||||
ctx.flush_buf(COLSTR("; db ?", SCOLOR_SYMBOL));
|
||||
}
|
||||
32
idasdk76/module/sam8/readme.txt
Normal file
32
idasdk76/module/sam8/readme.txt
Normal file
@@ -0,0 +1,32 @@
|
||||
IDA Processor module: SAM8
|
||||
|
||||
This is a processor module for Samsung SAM8-based microcontrollers
|
||||
|
||||
It supports the SAMA assembler available from http://www.cnatech.com/.
|
||||
The SAM8 has certain features that require extra support when generating
|
||||
ASM files. The accompanying "samaout" plugin should be used to generate
|
||||
valid ASM files for the SAMA assembler.
|
||||
|
||||
The module will create two segments, "cmem" and "emem".
|
||||
|
||||
The cmem segment contains "code memory", and will occupy addresses
|
||||
0 -> 0x10000.
|
||||
|
||||
The emem segment contains "external data memory", and will occupy addresses
|
||||
0x800000->0x810000. Since external data memory occupies the same address
|
||||
range as code memory, the module will remap external data accesses into the
|
||||
emem segment. The samaout plugin will convert any names in the emem
|
||||
segment into EQU definitions at the start of the outputted file.
|
||||
|
||||
test.asm contains (hopefully) all possible instructions supported by this
|
||||
processor, for unit testing purposes.
|
||||
|
||||
Andrew de Quincey
|
||||
adq@tardis.ed.ac.uk
|
||||
|
||||
|
||||
|
||||
Release history
|
||||
---------------
|
||||
|
||||
0.1 Initial release
|
||||
299
idasdk76/module/sam8/reg.cpp
Normal file
299
idasdk76/module/sam8/reg.cpp
Normal file
@@ -0,0 +1,299 @@
|
||||
#include "sam8.hpp"
|
||||
#include <segregs.hpp>
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// This old-style callback only returns the processor module object.
|
||||
static ssize_t idaapi notify(void *, int msgid, va_list)
|
||||
{
|
||||
if ( msgid == processor_t::ev_get_procmod )
|
||||
return size_t(new sam8_t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t idaapi sam8_t::on_event(ssize_t msgid, va_list va)
|
||||
{
|
||||
// deal with notification codes
|
||||
int code = 0;
|
||||
switch ( msgid )
|
||||
{
|
||||
case processor_t::ev_init:
|
||||
inf_set_be(true); // Set big endian mode in the IDA kernel
|
||||
break;
|
||||
|
||||
case processor_t::ev_newfile:
|
||||
{
|
||||
// create a new segment for code data
|
||||
segment_t seg;
|
||||
seg.start_ea = SAM8_CODESEG_START;
|
||||
seg.end_ea = SAM8_CODESEG_START + SAM8_CODESEG_SIZE;
|
||||
seg.sel = allocate_selector(seg.start_ea >> 4);
|
||||
seg.type = SEG_NORM;
|
||||
add_segm_ex(&seg, "code", NULL, ADDSEG_NOSREG|ADDSEG_OR_DIE);
|
||||
}
|
||||
{
|
||||
// create a new segment for the external data
|
||||
segment_t seg;
|
||||
seg.start_ea = SAM8_EDATASEG_START;
|
||||
seg.end_ea = SAM8_EDATASEG_START + SAM8_EDATASEG_SIZE;
|
||||
seg.sel = allocate_selector(seg.start_ea >> 4);
|
||||
seg.flags = SFL_HIDDEN;
|
||||
seg.type = SEG_BSS;
|
||||
add_segm_ex(&seg, "emem", NULL, ADDSEG_NOSREG|ADDSEG_OR_DIE);
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_out_header:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
sam8_header(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_footer:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
sam8_footer(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_segstart:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
segment_t *seg = va_arg(va, segment_t *);
|
||||
sam8_segstart(*ctx, seg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_ana_insn:
|
||||
{
|
||||
insn_t *out = va_arg(va, insn_t *);
|
||||
return ana(out);
|
||||
}
|
||||
|
||||
case processor_t::ev_emu_insn:
|
||||
{
|
||||
const insn_t *insn = va_arg(va, const insn_t *);
|
||||
return emu(*insn) ? 1 : -1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_insn:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
out_insn(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_operand:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
const op_t *op = va_arg(va, const op_t *);
|
||||
return out_opnd(*ctx, *op) ? 1 : -1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_data:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
bool analyze_only = va_argi(va, bool);
|
||||
sam8_out_data(*ctx, analyze_only);
|
||||
return 1;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Condition codes
|
||||
const char *const ccNames[] =
|
||||
{
|
||||
"F",
|
||||
"LT",
|
||||
"LE",
|
||||
"ULE",
|
||||
"OV",
|
||||
"MI",
|
||||
"EQ",
|
||||
"C",
|
||||
"T",
|
||||
"GE",
|
||||
"GT",
|
||||
"UGT",
|
||||
"NOV",
|
||||
"PL",
|
||||
"NE",
|
||||
"NC",
|
||||
};
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* Register names */
|
||||
/************************************************************************/
|
||||
static const char *const RegNames[] =
|
||||
{
|
||||
"cs","ds"
|
||||
};
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* Samsung Assembler - Version 1.42 */
|
||||
/* Copyright 1995,96 M.Y.Chong SAMSUNG ASIA PTE LTD */
|
||||
/* Semiconductor Division */
|
||||
/************************************************************************/
|
||||
|
||||
/************************************************************************/
|
||||
/* File headers for SAMA assembler */
|
||||
/************************************************************************/
|
||||
static const char *const sama_headers[] =
|
||||
{
|
||||
"",
|
||||
"; Filename of DEF file describing the chip in use",
|
||||
"CHIP <DEF Filename>",
|
||||
"",
|
||||
"; External memory EQU definitions",
|
||||
"; These will appear here when output using the samaout plugin",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* Definition of SAMA assembler */
|
||||
/************************************************************************/
|
||||
static const asm_t sama =
|
||||
{
|
||||
AS_COLON,
|
||||
0,
|
||||
"Samsung Assembler (SAMA) by Samsung Semiconductor Division",
|
||||
0,
|
||||
(const char**) sama_headers, // no headers
|
||||
"org",
|
||||
"end",
|
||||
|
||||
";", // comment string
|
||||
'\'', // string delimiter
|
||||
'\'', // char delimiter
|
||||
"+_*/%&|^()<>!+$@#.,\'\"?", // special symbols in char+string constants
|
||||
|
||||
"db", // ascii string directive
|
||||
"db", // byte directive
|
||||
"dw", // word directive
|
||||
NULL, // dword (4 bytes)
|
||||
NULL, // qword (8 bytes)
|
||||
NULL, // oword (16 bytes)
|
||||
NULL, // float (4 bytes)
|
||||
NULL, // double (8 bytes)
|
||||
NULL, // tbyte (10/12 bytes)
|
||||
NULL, // packed decimal real
|
||||
NULL, // arrays (#h,#d,#v,#s(...)
|
||||
NULL, // uninited arrays
|
||||
"equ", // equ
|
||||
NULL, // seg prefix
|
||||
"$",
|
||||
NULL, // func_header
|
||||
NULL, // func_footer
|
||||
NULL, // public
|
||||
NULL, // weak
|
||||
NULL, // extrn
|
||||
NULL, // comm
|
||||
NULL, // get_type_name
|
||||
NULL, // align
|
||||
'(', ')', // lbrace, rbrace
|
||||
NULL, // mod
|
||||
NULL, // and
|
||||
NULL, // or
|
||||
NULL, // xor
|
||||
"~", // not
|
||||
NULL, // shl
|
||||
NULL, // shr
|
||||
NULL, // sizeof
|
||||
0,
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
/* Assemblers supported by this module */
|
||||
/************************************************************************/
|
||||
static const asm_t *const asms[] = { &sama, NULL };
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* Short names of processor */
|
||||
/************************************************************************/
|
||||
static const char *const shnames[] =
|
||||
{
|
||||
"SAM8",
|
||||
NULL
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
/* Long names of processor */
|
||||
/************************************************************************/
|
||||
#define FAMILY "Samsung microcontrollers:"
|
||||
static const char *const lnames[] =
|
||||
{
|
||||
FAMILY"Samsung SAM8-based processors",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Opcodes of "return" instructions. This information will be used in 2 ways:
|
||||
// - if an instruction has the "return" opcode, its autogenerated label
|
||||
// will be "locret" rather than "loc".
|
||||
// - IDA will use the first "return" opcode to create empty subroutines.
|
||||
|
||||
static const uchar retcode_1[] = { 0xAF };
|
||||
static const uchar retcode_2[] = { 0xBF };
|
||||
|
||||
static const bytes_t retcodes[] =
|
||||
{
|
||||
{ sizeof(retcode_1), retcode_1 },
|
||||
{ sizeof(retcode_2), retcode_2 },
|
||||
{ 0, NULL } // NULL terminated array
|
||||
};
|
||||
|
||||
|
||||
// processor code for SAM8
|
||||
#define PLFM_SAM8 0x8020
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Processor Definition
|
||||
//-----------------------------------------------------------------------
|
||||
processor_t LPH =
|
||||
{
|
||||
IDP_INTERFACE_VERSION, // version
|
||||
PLFM_SAM8, // id
|
||||
// flag
|
||||
PR_RNAMESOK // can use register names for byte names
|
||||
| PR_BINMEM,
|
||||
// flag2
|
||||
0,
|
||||
8, // 8 bits in a byte for code segments
|
||||
8, // 8 bits in a byte for other segments
|
||||
|
||||
shnames, // array of short processor names
|
||||
// the short names are used to specify the processor
|
||||
// with the -p command line switch)
|
||||
lnames, // array of long processor names
|
||||
// the long names are used to build the processor type
|
||||
// selection menu
|
||||
|
||||
asms, // array of target assemblers
|
||||
|
||||
notify, // the kernel event notification callback
|
||||
|
||||
RegNames, // Register names
|
||||
qnumber(RegNames), // Number of registers
|
||||
|
||||
rVcs,rVds,
|
||||
0, // size of a segment register
|
||||
rVcs,rVds,
|
||||
|
||||
NULL, // No known code start sequences
|
||||
retcodes,
|
||||
|
||||
0,SAM8_last,
|
||||
Instructions, // instruc
|
||||
};
|
||||
103
idasdk76/module/sam8/sam8.hpp
Normal file
103
idasdk76/module/sam8/sam8.hpp
Normal file
@@ -0,0 +1,103 @@
|
||||
/************************************************************************/
|
||||
/* Disassembler for Samsung SAM8 processors */
|
||||
/************************************************************************/
|
||||
#ifndef _SAM8_HPP
|
||||
#define _SAM8_HPP
|
||||
|
||||
#include "../idaidp.hpp"
|
||||
#include "ins.hpp"
|
||||
|
||||
// special insn definitions
|
||||
#define fl_workingReg specflag1
|
||||
#define fl_regPair specflag2
|
||||
#define v_bit specval
|
||||
#define v_phrase_reg specval_shorts.low
|
||||
#define v_phrase_idxreg specval_shorts.high
|
||||
#define c_condition auxpref_u8[0]
|
||||
#define o_cmem o_mem
|
||||
#define o_cmem_ind o_idpspec1 // @code address in first 256 bytes
|
||||
#define o_emem o_idpspec2
|
||||
#define o_reg_bit o_idpspec3
|
||||
|
||||
// offset to code segment
|
||||
#define SAM8_CODESEG_START 0
|
||||
#define SAM8_CODESEG_SIZE 0x10000
|
||||
|
||||
// offset to external data segment
|
||||
#define SAM8_EDATASEG_START 0x800000
|
||||
#define SAM8_EDATASEG_SIZE 0x10000
|
||||
|
||||
// utility stuff
|
||||
#define top_nibble(VALUE) ((VALUE & 0xf0) >> 4)
|
||||
#define bottom_nibble(VALUE) (VALUE & 0xf)
|
||||
extern const char *const ccNames[];
|
||||
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* Registers (we'll be handling these with custom code ) */
|
||||
/************************************************************************/
|
||||
enum sam8_registers
|
||||
{
|
||||
rVcs, rVds // these 2 registers are required by the IDA kernel
|
||||
};
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* Indirect addressing modes without a displacement */
|
||||
/************************************************************************/
|
||||
enum sam8_phrases
|
||||
{
|
||||
fIndReg, // @register
|
||||
fIdxReg, // #reg[Rn]
|
||||
fIdxEAddr, // #addr[rr] (DATA)
|
||||
fIdxCAddr, // #addr[rr] (CODE)
|
||||
};
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* Condition codes */
|
||||
/************************************************************************/
|
||||
enum sam8_cc
|
||||
{
|
||||
ccNone = 0xff,
|
||||
ccF = 0,
|
||||
ccLT,
|
||||
ccLE,
|
||||
ccULE,
|
||||
ccOV,
|
||||
ccMI,
|
||||
ccEQ, // == Z
|
||||
ccC, // == ULT
|
||||
ccT,
|
||||
ccGE,
|
||||
ccGT,
|
||||
ccUGT,
|
||||
ccNOV,
|
||||
ccPL,
|
||||
ccNE, // == NZ
|
||||
ccUGE, // == NC
|
||||
cc_last,
|
||||
};
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* Common functions */
|
||||
/************************************************************************/
|
||||
void idaapi sam8_header(outctx_t &ctx);
|
||||
int idaapi ana(insn_t *_insn);
|
||||
void idaapi sam8_out_data(outctx_t &ctx, bool analyze_only);
|
||||
|
||||
/************************************************************************/
|
||||
struct sam8_t : public procmod_t
|
||||
{
|
||||
bool flow = false;
|
||||
|
||||
virtual ssize_t idaapi on_event(ssize_t msgid, va_list va) override;
|
||||
|
||||
void handle_operand(const insn_t &insn, const op_t &x, bool loading);
|
||||
int emu(const insn_t &insn);
|
||||
void sam8_segstart(outctx_t &ctx, segment_t *Sarea) const;
|
||||
void sam8_footer(outctx_t &ctx) const;
|
||||
};
|
||||
#endif
|
||||
342
idasdk76/module/sam8/test.asm
Normal file
342
idasdk76/module/sam8/test.asm
Normal file
@@ -0,0 +1,342 @@
|
||||
|
||||
CHIP DEF\S3C8454.DEF
|
||||
|
||||
LOOP EQU 030H
|
||||
|
||||
loc0:
|
||||
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
zp_test:
|
||||
dw 0100H
|
||||
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
|
||||
org 0100H
|
||||
|
||||
adc R1,R2
|
||||
adc R1, @R2
|
||||
adc 01H, 02H
|
||||
adc 01H, @02H
|
||||
adc 01H, #11H
|
||||
|
||||
add R1, R2
|
||||
add R1, @R2
|
||||
add 01H, 02H
|
||||
add 01H, @02H
|
||||
add 01H, #25H
|
||||
|
||||
and R1, R2
|
||||
and R1, @R2
|
||||
and 01H, 02H
|
||||
and 01H, @02H
|
||||
and 01H, #25H
|
||||
|
||||
band R1, 01H.1
|
||||
band 01H.1, R1
|
||||
|
||||
bcp R1, 01H.1
|
||||
|
||||
bitc R1.1
|
||||
|
||||
testback:
|
||||
bitr R1.1
|
||||
|
||||
bits R1.3
|
||||
|
||||
bor R1, 01H.1
|
||||
bor 01H.2, R1
|
||||
|
||||
btjrf testback, R1.3
|
||||
btjrf testforward, R1.3
|
||||
|
||||
btjrt testback, R1.1
|
||||
btjrt testforward, R1.2
|
||||
|
||||
|
||||
bxor R1, 01H.1
|
||||
bxor 01H.2, R1
|
||||
|
||||
testforward:
|
||||
|
||||
|
||||
call testback
|
||||
call testforward
|
||||
call @RR0
|
||||
call #loc0
|
||||
call #40H
|
||||
call 4000H
|
||||
|
||||
ccf
|
||||
|
||||
clr 00H
|
||||
clr @01H
|
||||
|
||||
com R1
|
||||
com @R1
|
||||
|
||||
testback2:
|
||||
cp R1, R2
|
||||
cp R1, @R2
|
||||
cp 01H, 02H
|
||||
cp 01H, @02H
|
||||
cp 01H, #25H
|
||||
|
||||
cpije R1, @R2, testback2
|
||||
cpije R1, @R2, testforward2
|
||||
|
||||
cpijne R1, @R2, testback2
|
||||
cpijne R1, @R2, testforward2
|
||||
|
||||
da R1
|
||||
da @R1
|
||||
testforward2:
|
||||
|
||||
dec R1
|
||||
dec @R1
|
||||
|
||||
decw RR0
|
||||
decw @R2
|
||||
|
||||
di
|
||||
|
||||
div RR0, R2
|
||||
div RR0, @R2
|
||||
div RR0, #20H
|
||||
div 20H, #20H
|
||||
|
||||
djnz R1, testback
|
||||
djnz R1, testforward_big
|
||||
|
||||
ei
|
||||
|
||||
enter
|
||||
|
||||
exit
|
||||
|
||||
idle
|
||||
|
||||
inc R0
|
||||
inc 00H
|
||||
inc @R0
|
||||
|
||||
incw RR0
|
||||
incw @20H
|
||||
|
||||
iret
|
||||
ret
|
||||
|
||||
testback3
|
||||
jp f, testforward_big
|
||||
jp t, testforward_big
|
||||
jp c, testforward_big
|
||||
jp nc, testforward_big
|
||||
jp z, testforward_big
|
||||
jp nz, testforward_big
|
||||
jp pl, testforward_big
|
||||
jp mi, testforward_big
|
||||
jp ov, testforward_big
|
||||
jp nov, testforward_big
|
||||
jp eq, testforward_big
|
||||
jp ne, testback
|
||||
jp ge, testback
|
||||
jp lt, testback
|
||||
jp gt, testback
|
||||
jp le, testback
|
||||
jp uge, testback
|
||||
jp ult, testback
|
||||
jp ugt, testback
|
||||
jp ule, testback
|
||||
jp @00H
|
||||
|
||||
jr f, testforward_big
|
||||
jr t, testforward_big
|
||||
jr c, testforward_big
|
||||
jr nc, testforward_big
|
||||
jr z, testforward_big
|
||||
jr nz, testforward_big
|
||||
jr pl, testforward_big
|
||||
jr mi, testforward_big
|
||||
jr ov, testforward_big
|
||||
jr nov, testforward_big
|
||||
jr eq, testback3
|
||||
jr ne, testback3
|
||||
jr ge, testback3
|
||||
jr lt, testback3
|
||||
jr gt, testback3
|
||||
jr le, testback3
|
||||
jr uge, testback3
|
||||
jr ult, testback3
|
||||
jr ugt, testback3
|
||||
jr ule, testback3
|
||||
|
||||
testforward_big: di
|
||||
|
||||
ld R0, #10H
|
||||
ld R0, 01H
|
||||
ld 01H, R0
|
||||
ld R1, @R0
|
||||
ld @R0, R1
|
||||
ld 00H, 01H
|
||||
ld 02H, @00H
|
||||
ld 00H, #0AH
|
||||
ld @00H, #10H
|
||||
ld @00H, 02H
|
||||
ld R0, #LOOP[R1]
|
||||
ld #LOOP[R0], R1
|
||||
|
||||
ldb R0, 00H.2
|
||||
ldb 00H.0, R0
|
||||
|
||||
ldc R0, @RR2
|
||||
ldc @RR2, R0
|
||||
ldc R0, #01H[RR2]
|
||||
ldc #01H[RR2], R0
|
||||
ldc R0, #1000H[RR2]
|
||||
ldc R0, 1104H
|
||||
ldc 1005H, R0
|
||||
ldc R0, #-20[RR2]
|
||||
ldc R0, #9000H[RR2]
|
||||
|
||||
lde R0, @RR2
|
||||
lde @RR2, R0
|
||||
lde R0, #01H[RR2]
|
||||
lde #01H[RR2], R0
|
||||
lde R0, #1000H[RR2]
|
||||
lde R0, 1104H
|
||||
lde 1005H, R0
|
||||
lde R0, #-20[RR2]
|
||||
|
||||
ldcd R8, @RR6
|
||||
|
||||
lded R8, @RR6
|
||||
|
||||
ldci R8, @RR6
|
||||
|
||||
ldei R8, @RR6
|
||||
|
||||
ldcpd @RR6, R0
|
||||
|
||||
ldepd @RR6, R0
|
||||
|
||||
ldcpi @RR6, R0
|
||||
|
||||
ldepi @RR6, R0
|
||||
|
||||
ldw RR6, RR4
|
||||
ldw 00H, 02H
|
||||
ldw RR2, @R7
|
||||
ldw 04H, @01H
|
||||
ldw RR6, #1234H
|
||||
ldw 02H, #0FEDH
|
||||
|
||||
mult 00H, 02H
|
||||
mult 00H, @01H
|
||||
mult 00H, #30H
|
||||
mult RR0, #30H
|
||||
|
||||
next
|
||||
|
||||
nop
|
||||
|
||||
or R1, R2
|
||||
or R1, @R2
|
||||
or 01H, 02H
|
||||
or 01H, @02H
|
||||
or 01H, #25H
|
||||
|
||||
pop 00H
|
||||
pop @00H
|
||||
|
||||
popud 02H, @00H
|
||||
|
||||
popui 02H, @00H
|
||||
|
||||
push 040H
|
||||
|
||||
push @40H
|
||||
|
||||
pushud @00H, 01H
|
||||
|
||||
pushui @00H, 01H
|
||||
|
||||
rcf
|
||||
|
||||
ret
|
||||
|
||||
rl 00H
|
||||
rl @01H
|
||||
|
||||
rlc 00H
|
||||
rlc @01H
|
||||
|
||||
rr 00H
|
||||
rr @01H
|
||||
|
||||
rrc 00H
|
||||
rrc @01H
|
||||
|
||||
sb0
|
||||
|
||||
sb1
|
||||
|
||||
sbc R1,R2
|
||||
sbc R1, @R2
|
||||
sbc 01H, 02H
|
||||
sbc 01H, @02H
|
||||
sbc 01H, #11H
|
||||
|
||||
scf
|
||||
|
||||
sra 00H
|
||||
sra @02H
|
||||
|
||||
srp #40H
|
||||
srp0 #50H
|
||||
srp1 #60H
|
||||
|
||||
stop
|
||||
|
||||
sub R1,R2
|
||||
sub R1, @R2
|
||||
sub 01H, 02H
|
||||
sub 01H, @02H
|
||||
sub 01H, #11H
|
||||
|
||||
swap 00H
|
||||
swap @02H
|
||||
|
||||
tcm R1,R2
|
||||
tcm R1, @R2
|
||||
tcm 01H, 02H
|
||||
tcm 01H, @02H
|
||||
tcm 01H, #11H
|
||||
|
||||
tm R1,R2
|
||||
tm R1, @R2
|
||||
tm 01H, 02H
|
||||
tm 01H, @02H
|
||||
tm 01H, #11H
|
||||
|
||||
wfi
|
||||
|
||||
xor R1,R2
|
||||
xor R1, @R2
|
||||
xor 01H, 02H
|
||||
xor 01H, @02H
|
||||
xor 01H, #11H
|
||||
|
||||
testcall: ret
|
||||
|
||||
END
|
||||
Reference in New Issue
Block a user