update to ida 7.6, add builds

This commit is contained in:
2021-10-31 21:20:46 +02:00
parent e0e0f2be99
commit b1809fe2d9
1408 changed files with 279193 additions and 302468 deletions

View 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);
}

View 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;
}

View 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);

View 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

View 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

View 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));
}

View 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

View 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
};

View 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

View 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