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

1796
idasdk76/module/st9/ana.cpp Normal file

File diff suppressed because it is too large Load Diff

489
idasdk76/module/st9/emu.cpp Normal file
View File

@@ -0,0 +1,489 @@
#include "st9.hpp"
//----------------------------------------------------------------------
static sel_t calc_page(ea_t insn_ea, ushort addr)
{
return get_sreg(insn_ea, rDPR0+(addr>>14));
}
//----------------------------------------------------------------------
static ea_t calc_data_mem_without_mapping(ea_t insn_ea, ea_t addr)
{
sel_t page = calc_page(insn_ea, (ushort)addr);
if ( page == BADSEL )
return BADADDR;
ea_t ea = use_mapping((page<<14) + (addr & 0x3FFF));
return ea;
}
//----------------------------------------------------------------------
ea_t get_dest_addr(const insn_t &insn, const op_t &x)
{
if ( x.type == o_far )
return x.addr;
else if ( x.type == o_mem )
return calc_data_mem_without_mapping(insn.ea, x.addr);
else if ( x.type == o_near )
return to_ea(insn.cs, x.addr);
else
return BADADDR;
}
//----------------------------------------------------------------------
// Emulate an operand.
void st9_t::handle_operand(const insn_t &insn, const op_t &op, bool lwrite)
{
switch ( op.type )
{
// Code address
case o_near:
case o_far:
{
cref_t mode;
ea_t ea = get_dest_addr(insn, op);
// call or jump ?
if ( is_call_insn(insn) )
{
if ( !func_does_return(ea) )
flow = false;
mode = op.type == o_near ? fl_CN: fl_CF;
}
else
{
mode = op.type == o_near ? fl_JN: fl_JF;
}
insn.add_cref(ea, op.offb, mode);
}
break;
// Memory address
case o_mem:
{
ea_t ea = get_dest_addr(insn, op);
insn.add_dref(ea, op.offb, lwrite ? dr_W : dr_R);
insn.create_op_data(ea, op);
}
break;
// Immediate value
case o_imm:
{
set_immd(insn.ea);
flags_t F = get_flags(insn.ea);
// create a comment if this immediate is represented in the .cfg file
{
const ioport_t * port = find_sym(op.value);
if ( port != NULL && !has_cmt(F) )
set_cmt(insn.ea, port->cmt.c_str(), false);
}
// if the value was converted to an offset, then create a data xref:
if ( op_adds_xrefs(F, op.n) )
insn.add_off_drefs(op, dr_O, 0);
}
break;
// Displacement
case o_displ:
{
set_immd(insn.ea);
flags_t F = get_flags(insn.ea);
if ( op_adds_xrefs(F, op.n) )
{
ea_t ea = insn.add_off_drefs(op, dr_O, OOF_ADDR);
insn.create_op_data(ea, op);
}
// create stack variables if required
if ( may_create_stkvars() && !is_defarg(F, op.n) && op.reg == rrr14 )
{
func_t *pfn = get_func(insn.ea);
if ( pfn != NULL && pfn->flags & FUNC_FRAME )
{
adiff_t displ = (int16)op.addr;
if ( insn.create_stkvar(op, displ, STKVAR_VALID_SIZE) )
{
op_stkvar(insn.ea, op.n);
if ( insn.Op2.type == o_reg )
{
regvar_t *r = find_regvar(pfn, insn.ea, ph.reg_names[insn.Op2.reg]);
if ( r != NULL )
{
struc_t *s = get_frame(pfn);
member_t *m = get_stkvar(NULL, insn, op, displ);
if ( s != NULL && m != NULL )
{
char b[20];
qsnprintf(b, sizeof b, "%scopy", r->user);
set_member_name(s, m->soff, b);
}
}
}
}
}
}
}
break;
// Register - Phrase - Void: do nothing
case o_reg:
case o_phrase:
case o_void:
break;
default:
INTERR(10076);
}
}
//----------------------------------------------------------------------
// Emulate an instruction.
int st9_t::st9_emu(const insn_t &insn)
{
uint32 feature = insn.get_canon_feature(ph);
flow = ((feature & CF_STOP) == 0);
// is it "jump always"?
if ( is_jmp_cc(insn.itype) && insn.auxpref == cT )
flow = false;
if ( insn.Op1.type != o_void) handle_operand(insn, insn.Op1, (feature & CF_CHG1) != 0);
if ( insn.Op2.type != o_void) handle_operand(insn, insn.Op2, (feature & CF_CHG2) != 0);
if ( insn.Op3.type != o_void) handle_operand(insn, insn.Op3, (feature & CF_CHG3) != 0);
if ( flow )
add_cref(insn.ea, insn.ea + insn.size, fl_F);
// Following code will update the current value of the two virtual
// segment registers: RW (register window) and RP (register page).
bool rw_has_changed = false;
bool rp_has_changed = false;
switch ( insn.itype )
{
case st9_srp:
{
sel_t val = insn.Op1.value;
if ( val % 2 )
val--; // even reduced
split_sreg_range(insn.ea+insn.size, rRW, val | (val << 8), SR_auto);
}
rw_has_changed = true;
break;
case st9_srp0:
{
sel_t RW = get_sreg(insn.ea, rRW);
split_sreg_range(insn.ea+insn.size, rRW, insn.Op1.value | (RW & 0xFF00), SR_auto);
}
rw_has_changed = true;
break;
case st9_srp1:
{
sel_t RW = get_sreg(insn.ea, rRW);
split_sreg_range(insn.ea+insn.size, rRW, (insn.Op1.value << 8) | (RW & 0x00FF), SR_auto);
}
rw_has_changed = true;
break;
case st9_spp:
split_sreg_range(insn.ea+insn.size, rRP, insn.Op1.value, SR_auto);
rp_has_changed = true;
break;
}
// If RW / RP registers have changed, print a comment which explains the new mapping of
// the general registers.
flags_t F = get_flags(insn.ea);
if ( rw_has_changed && !has_cmt(F) )
{
char buf[MAXSTR];
sel_t RW = get_sreg(insn.ea+insn.size, rRW);
int low = RW & 0x00FF;
int high = (RW & 0xFF00) >> 8;
low *= 8;
high *= 8;
const char *const fmt =
"r0 -> R%d, r1 -> R%d, r2 -> R%d, r3 -> R%d, r4 -> R%d, r5 -> R%d, r6 -> R%d, r7 -> R%d,\n"
"r8 -> R%d, r9 -> R%d, r10 -> R%d, r11 -> R%d, r12 -> R%d, r13 -> R%d, r14 -> R%d, r15 -> R%d";
qsnprintf(buf, sizeof buf, fmt,
0 + low,
1 + low,
2 + low,
3 + low,
4 + low,
5 + low,
6 + low,
7 + low,
8 + high,
9 + high,
10 + high,
11 + high,
12 + high,
13 + high,
14 + high,
15 + high);
set_cmt(insn.ea, buf, false);
}
if ( rp_has_changed && !has_cmt(F) )
{
char buf[MAXSTR];
int rpval = get_sreg(insn.ea+insn.size, rRP);
qsnprintf(buf, sizeof buf, "Registers R240-R255 will now be referred to the page %d of paged registers",
rpval);
set_cmt(insn.ea, buf, false);
}
// reanalyze switch info
if ( insn.itype == st9_jp && get_auto_state() == AU_USED )
{
switch_info_t si;
if ( get_switch_info(&si, insn.ea) > 0 && !si.is_user_defined() )
{
delete_switch_table(insn.ea, si);
if ( st9_is_switch(&si, insn) )
{
set_switch_info(insn.ea, si);
create_switch_table(insn.ea, si);
}
else
{
del_switch_info(insn.ea);
}
}
}
return 1;
}
//----------------------------------------------------------------------
// Analyze an instruction
static ea_t next_insn(insn_t *insn, ea_t ea)
{
if ( decode_insn(insn, ea) == 0 )
return 0;
ea += insn->size;
return ea;
}
//------------------------------------------------------------------------
// does a far return instruction precede 'ea'?
static bool is_far_return(ea_t ea)
{
insn_t insn;
if ( decode_prev_insn(&insn, ea) != BADADDR )
return insn.itype == st9_rets;
return false;
}
//----------------------------------------------------------------------
// if a function ends with a far return, mark it as such
// NB: we only handle regular (non-chunked) functions
static void setup_far_func(func_t *pfn)
{
if ( (pfn->flags & FUNC_FAR) == 0 )
{
if ( is_far_return(pfn->end_ea) )
{
pfn->flags |= FUNC_FAR;
update_func(pfn);
}
}
}
//----------------------------------------------------------------------
// Create a function frame
bool st9_t::create_func_frame(func_t *pfn) const
{
setup_far_func(pfn);
ea_t ea = pfn->start_ea;
insn_t insn;
ea = next_insn(&insn, ea);
if ( !ea )
return 0;
/*
* Get the total frame size
*
* LINK rr14, #size
*/
if ( insn.itype != st9_link )
return 0;
int link_register = insn.Op1.reg;
size_t total_size = (size_t)insn.Op2.value;
/*
* Get arguments size
*
* LDW 0x??(rr14), RR??? a word
* LD '' a byte
*/
int args_size = 0;
for ( int i = 0; true; i++ )
{
insn_t ldi;
ea = next_insn(&ldi, ea);
if ( !ea )
return 0;
if ( ldi.Op1.type != o_displ || ldi.Op2.type != o_reg )
break;
if ( ldi.Op1.reg != link_register )
break;
if ( ldi.itype == st9_ld ) // byte
args_size++;
else if ( ldi.itype == st9_ldw ) // word
args_size += 2;
else
break;
char regvar[10];
qsnprintf(regvar, sizeof regvar, "arg_%d", i);
int err = add_regvar(pfn, ldi.ea, ldi.ea + ldi.size,
ph.reg_names[ldi.Op2.reg], regvar, NULL);
if ( err )
msg("add_regvar() failed : error %d\n", err);
}
//msg("LOCAL: %d\nARGS: %d\n", total_size - args_size, args_size);
pfn->flags |= FUNC_FRAME;
return add_frame(pfn, total_size - args_size, 0, args_size);
}
//------------------------------------------------------------------------
/*
GCC?-produced switch:
ldw ridx, rin [optional]
cpw rin, #n
jpugt default | jrugt default
addw ridx, ridx
spm
ldw rjmp, jtbl(ridx)
sdm
jp (rjmp)
jtbl: .word case0, case1, ...
*/
static ea_t check_prev_insn(int itype, insn_t &insn)
{
ea_t ea = decode_prev_insn(&insn, insn.ea);
if ( ea == BADADDR || insn.itype != itype )
return BADADDR;
return ea;
}
//--------------------------------------------------------------------------
static bool is_gcc_switch(switch_info_t *_si, insn_t &insn)
{
switch_info_t &si = *_si;
int rjmp, ridx;
// si.flags |= SWI_J32;
ea_t ea, jtbl_insn;
//
// Check jump insn and get register number
// jp (rjmp)
if ( insn.itype != st9_jp
|| insn.Op1.type != o_reg
|| !is_ind(insn.Op1) )
{
return false;
}
rjmp = insn.Op1.reg;
// sdm
ea = check_prev_insn(st9_sdm, insn);
if ( ea == BADADDR )
return false;
// ldw rjmp, jtbl(ridx)
ea = check_prev_insn(st9_ldw, insn);
if ( ea == BADADDR
|| !insn.Op1.is_reg(rjmp)
|| insn.Op2.type != o_displ )
return false;
ridx = insn.Op2.reg;
jtbl_insn = ea;
// this addr is offset in current code segment because of spm
si.jumps = to_ea(insn.cs, insn.Op2.addr);
// spm
ea = check_prev_insn(st9_spm, insn);
if ( ea == BADADDR )
return false;
// addw ridx, ridx
ea = check_prev_insn(st9_addw, insn);
if ( ea == BADADDR
|| !insn.Op1.is_reg(ridx)
|| !insn.Op2.is_reg(ridx) )
return false;
// jpugt default | jrugt default
ea = decode_prev_insn(&insn, ea);
if ( ea != BADADDR
&& is_jmp_cc(insn.itype)
&& insn.auxpref == cUGT )
{
si.defjump = get_dest_addr(insn, insn.Op1);
// cpw rin, #n
ea = check_prev_insn(st9_cpw, insn);
if ( ea == BADADDR
|| insn.Op2.type != o_imm )
return false;
int rin = insn.Op1.reg;
si.ncases = ushort(insn.Op2.value+1);
// is rin the same as ridx?
bool ok = insn.Op1.is_reg(ridx);
if ( !ok )
{
// check for preceding ldw ridx, rin
ea_t ea2 = decode_prev_insn(&insn, ea);
if ( ea2 != BADADDR
&& insn.itype == st9_ldw
&& insn.Op1.is_reg(ridx)
&& insn.Op2.is_reg(rin) )
ok = true;
}
if ( !ok )
return false;
si.set_expr(rin, insn.Op1.dtype);
}
//
// Everything ok.
//
msg("SWITCH %a: gcc_switch\n", insn.ea);
si.startea = ea;
si.set_jtable_element_size(2);
si.set_shift(0);
op_num(ea, 1); // cpw rin, #n
op_plain_offset(jtbl_insn, 1, to_ea(insn.cs, 0)); // ldw rjmp, jtbl(ridx)
return true;
}
bool st9_is_switch(switch_info_t *si, const insn_t &insn)
{
if ( insn.itype == st9_jp )
{
insn_t copy = insn;
return is_gcc_switch(si, copy);
}
return false;
}

113
idasdk76/module/st9/ins.cpp Normal file
View File

@@ -0,0 +1,113 @@
#include "st9.hpp"
const instruc_t Instructions[] =
{
{ "", 0 }, // Null instruction.
{ "ld", CF_CHG1|CF_USE2 }, // Load.
{ "ldw", CF_CHG1|CF_USE2 }, // Load word.
{ "ldpp", CF_CHG1|CF_USE2 }, // Load (using CSR) => (using CSR).
{ "ldpd", CF_CHG1|CF_USE2 }, // Load (using DPRx) => (using CSR).
{ "lddp", CF_CHG1|CF_USE2 }, // Load (using CSR) => (using DPRx).
{ "lddd", CF_CHG1|CF_USE2 }, // Load (using DPRx) => (using DPRx).
{ "add", CF_CHG1|CF_USE2 }, // Add.
{ "addw", CF_CHG1|CF_USE2 }, // Add Word.
{ "adc", CF_CHG1|CF_USE2 }, // Add with Carry.
{ "adcw", CF_CHG1|CF_USE2 }, // Add Word with Carry.
{ "sub", CF_CHG1|CF_USE2 }, // Substract.
{ "subw", CF_CHG1|CF_USE2 }, // Substract Word.
{ "sbc", CF_CHG1|CF_USE2 }, // Substract with Carry.
{ "sbcw", CF_CHG1|CF_USE2 }, // Substract Word with Carry.
{ "and", CF_CHG1|CF_USE2 }, // Logical AND.
{ "andw", CF_CHG1|CF_USE2 }, // Logical Word AND.
{ "or", CF_CHG1|CF_USE2 }, // Logical OR.
{ "orw", CF_CHG1|CF_USE2 }, // Logical Word OR.
{ "xor", CF_CHG1|CF_USE2 }, // Logical Exclusive OR.
{ "xorw", CF_CHG1|CF_USE2 }, // Logical Word Exclusive OR.
{ "cp", CF_USE1|CF_USE2 }, // Compare.
{ "cpw", CF_USE1|CF_USE2 }, // Compare Word.
{ "tm", CF_USE1|CF_USE2 }, // Test under Mask.
{ "tmw", CF_USE1|CF_USE2 }, // Test Word under Mask.
{ "tcm", CF_USE1|CF_USE2 }, // Test Complement under Mask.
{ "tcmw", CF_USE1|CF_USE2 }, // Test Word Complement under Mask.
{ "inc", CF_USE1|CF_CHG1 }, // Increment.
{ "incw", CF_USE1|CF_CHG1 }, // Increment Word.
{ "dec", CF_USE1|CF_CHG1 }, // Decrement.
{ "decw", CF_USE1|CF_CHG1 }, // Decrement Word.
{ "sla", CF_USE1|CF_CHG1 }, // Shift Left Arithmetic.
{ "slaw", CF_USE1|CF_CHG1 }, // Shift Word Left Arithmetic.
{ "sra", CF_USE1|CF_CHG1 }, // Shift Right Arithmetic.
{ "sraw", CF_USE1|CF_CHG1 }, // Shift Word Right Arithmetic.
{ "rrc", CF_USE1|CF_CHG1 }, // Rotate Right through Carry.
{ "rrcw", CF_USE1|CF_CHG1 }, // Rotate Word Right through Carry.
{ "rlc", CF_USE1|CF_CHG1 }, // Rotate Left through Carry.
{ "rlcw", CF_USE1|CF_CHG1 }, // Rotate Word Left through Carry.
{ "ror", CF_USE1|CF_CHG1 }, // Rotate Right.
{ "rol", CF_USE1|CF_CHG1 }, // Rotate Left.
{ "clr", CF_USE1|CF_CHG1 }, // Clear Register.
{ "cpl", CF_USE1|CF_CHG1 }, // Complement Register.
{ "swap", CF_USE1|CF_CHG1 }, // Swap Nibbles.
{ "da", CF_USE1|CF_CHG1 }, // Decimal ajust.
{ "push", CF_USE1 }, // Push on System Stack.
{ "pushw", CF_USE1 }, // Push Word on System Stack.
{ "pea", CF_USE1 }, // Push Effective Address on System Stack.
{ "pop", CF_CHG1 }, // Pop from System Stack.
{ "popw", CF_CHG1 }, // Pop Word from System Stack.
{ "pushu", CF_USE1 }, // Push on User Stack.
{ "pushuw", CF_USE1 }, // Push Word on User Stack.
{ "peau", CF_USE1 }, // Push Effective Address on User Stack.
{ "popu", CF_CHG1 }, // Pop from User Stack.
{ "popuw", CF_CHG1 }, // Pop Word from User Stack.
{ "link", CF_USE1|CF_USE2 }, // Move System Stack Pointer upward; support for high-level language.
{ "unlink", CF_USE1|CF_USE2 }, // Move System Stack Pointer backward; support for high-level language.
{ "linku", CF_USE1|CF_USE2 }, // Move User Stack Pointer upward; support for high-level language.
{ "unlinku", CF_USE1|CF_USE2 }, // Move User Stack Pointer backward; support for high-level language.
{ "mul", CF_USE1|CF_USE2|CF_CHG1 }, // Multiply 8x8.
{ "div", CF_USE1|CF_USE2|CF_CHG1 }, // Divide 8x8.
{ "divws", CF_USE1|CF_USE2|CF_USE3|CF_CHG1|CF_CHG2 }, // Divide Word Stepped 32/16.
{ "bset", CF_USE1|CF_CHG1 }, // Bit Set.
{ "bres", CF_USE1|CF_CHG1 }, // Bit Reset.
{ "bcpl", CF_USE1|CF_CHG1 }, // Bit Complement.
{ "btset", CF_USE1|CF_CHG1 }, // Bit Test and Set.
{ "bld", CF_USE1|CF_CHG1 }, // Bit Load.
{ "band", CF_USE1|CF_CHG1 }, // Bit AND.
{ "bor", CF_USE1|CF_CHG1 }, // Bit OR.
{ "bxor", CF_USE1|CF_CHG1 }, // Bit XOR.
{ "ret", CF_STOP }, // Return from Subroutine.
{ "rets", CF_STOP }, // Inter-segment Return to Subroutine.
{ "iret", CF_STOP }, // Return from Interrupt.
{ "jr", CF_USE1 }, // Jump Relative if Condition ``cc'' is Met.
{ "jp", CF_USE1 }, // Jump if Condition ``cc'' is Met.
{ "jp", CF_USE1|CF_JUMP|CF_STOP }, // Unconditional Jump.
{ "jps", CF_USE1|CF_JUMP|CF_STOP }, // Unconditional Inter-segment Jump.
{ "call", CF_USE1|CF_CALL|CF_JUMP }, // Unconditional Call.
{ "calls", CF_USE1|CF_CALL|CF_JUMP }, // Inter-segment Call to Subroutine.
{ "btjf", CF_USE1|CF_USE2 }, // Bit Test and Jump if False.
{ "btjt", CF_USE1|CF_USE2 }, // Bit Test and Jump if True.
{ "djnz", CF_USE1|CF_CHG1|CF_USE2 }, // Decrement a Working Register and Jump if Non Zero.
{ "dwjnz", CF_USE1|CF_CHG1|CF_USE2 }, // Decrement a Register Pair and Jump if Non Zero.
{ "cpjfi", CF_USE1|CF_USE2|CF_USE3 }, // Compare and Jump on False. Otherwise Post Increment.
{ "cpjti", CF_USE1|CF_USE2|CF_USE3 }, // Compare and Jump on True. Otherwise Post Increment.
{ "xch", CF_USE1|CF_USE2 }, // Exchange Registers.
{ "srp", CF_USE1 }, // Set Register Pointer Long (16 working registers).
{ "srp0", CF_USE1 }, // Set Register Pointer 0 (8 LSB working registers).
{ "srp1", CF_USE1 }, // Set Register Pointer 1 (8 MSB working registers).
{ "spp", CF_USE1 }, // Set Page Pointer.
{ "ext", CF_USE1|CF_CHG1 }, // Sign Extend.
{ "ei", 0 }, // Enable Interrupts.
{ "di", 0 }, // Disable Interrupts.
{ "scf", 0 }, // Set Carry Flag.
{ "rcf", 0 }, // Reset Carry Flag.
{ "ccf", 0 }, // Complement Carry Flag.
{ "spm", 0 }, // Select Extended Memory addressing scheme through CSR Register.
{ "sdm", 0 }, // Select Extended Memory addressing scheme through DPR Registers.
{ "nop", 0 }, // No Operation.
{ "wfi", 0 }, // Stop Program Execution and Wait for the next Enable Interrupt.
{ "halt", 0 }, // Stop Program Execution until System Reset.
{ "etrap", 0 }, // Undocumented instruction.
{ "eret", CF_STOP }, // Undocumented instruction.
{ "ald", 0 }, // PSEUDO INSTRUCTION. SHOULD NEVER BE USED.
{ "aldw", 0 } // PSEUDO INSTRUCTION. SHOULD NEVER BE USED.
};
CASSERT(qnumber(Instructions) == st9_last);

118
idasdk76/module/st9/ins.hpp Normal file
View File

@@ -0,0 +1,118 @@
#ifndef __INS_HPP
#define __INS_HPP
extern const instruc_t Instructions[];
enum nameNum ENUM_SIZE(uint16)
{
st9_null = 0, // Unknown Operation.
st9_ld, // Load.
st9_ldw, // Load word.
st9_ldpp, // Load (using CSR) => (using CSR).
st9_ldpd, // Load (using DPRx) => (using CSR).
st9_lddp, // Load (using CSR) => (using DPRx).
st9_lddd, // Load (using DPRx) => (using DPRx).
st9_add, // Add.
st9_addw, // Add Word.
st9_adc, // Add with Carry.
st9_adcw, // Add Word with Carry.
st9_sub, // Substract.
st9_subw, // Substract Word.
st9_sbc, // Substract with Carry.
st9_sbcw, // Substract Word with Carry.
st9_and, // Logical AND.
st9_andw, // Logical Word AND.
st9_or, // Logical OR.
st9_orw, // Logical Word OR.
st9_xor, // Logical Exclusive OR.
st9_xorw, // Logical Word Exclusive OR.
st9_cp, // Compare.
st9_cpw, // Compare Word.
st9_tm, // Test under Mask.
st9_tmw, // Test Word under Mask.
st9_tcm, // Test Complement under Mask.
st9_tcmw, // Test Word Complement under Mask.
st9_inc, // Increment.
st9_incw, // Increment Word.
st9_dec, // Decrement.
st9_decw, // Decrement Word.
st9_sla, // Shift Left Arithmetic.
st9_slaw, // Shift Word Left Arithmetic.
st9_sra, // Shift Right Arithmetic.
st9_sraw, // Shift Word Right Arithmetic.
st9_rrc, // Rotate Right through Carry.
st9_rrcw, // Rotate Word Right through Carry.
st9_rlc, // Rotate Left through Carry.
st9_rlcw, // Rotate Word Left through Carry.
st9_ror, // Rotate Right.
st9_rol, // Rotate Left.
st9_clr, // Clear Register.
st9_cpl, // Complement Register.
st9_swap, // Swap Nibbles.
st9_da, // Decimal ajust.
st9_push, // Push on System Stack.
st9_pushw, // Push Word on System Stack.
st9_pea, // Push Effective Address on System Stack.
st9_pop, // Pop from System Stack.
st9_popw, // Pop Word from System Stack.
st9_pushu, // Push on User Stack.
st9_pushuw, // Push Word on User Stack.
st9_peau, // Push Effective Address on User Stack.
st9_popu, // Pop from User Stack.
st9_popuw, // Pop Word from User Stack.
st9_link, // Move System Stack Pointer upward; support for high-level language.
st9_unlink, // Move System Stack Pointer backward; support for high-level language.
st9_linku, // Move User Stack Pointer upward; support for high-level language.
st9_unlinku, // Move User Stack Pointer backward; support for high-level language.
st9_mul, // Multiply 8x8.
st9_div, // Divide 8x8.
st9_divws, // Divide Word Stepped 32/16.
st9_bset, // Bit Set.
st9_bres, // Bit Reset .
st9_bcpl, // Bit Complement.
st9_btset, // Bit Test and Set.
st9_bld, // Bit Load.
st9_band, // Bit AND.
st9_bor, // Bit OR.
st9_bxor, // Bit XOR.
st9_ret, // Return from Subroutine.
st9_rets, // Inter-segment Return to Subroutine.
st9_iret, // Return from Interrupt.
st9_jrcc, // Jump Relative if Condition ``cc'' is Met.
st9_jpcc, // Jump if Condition ``cc'' is Met.
st9_jp, // Unconditional Jump.
st9_jps, // Unconditional Inter-segment Jump.
st9_call, // Unconditional Call.
st9_calls, // Inter-segment Call to Subroutine.
st9_btjf, // Bit Test and Jump if False.
st9_btjt, // Bit Test and Jump if True.
st9_djnz, // Decrement a Working Register and Jump if Non Zero.
st9_dwjnz, // Decrement a Register Pair and Jump if Non Zero.
st9_cpjfi, // Compare and Jump on False. Otherwise Post Increment.
st9_cpjti, // Compare and Jump on True. Otherwise Post Increment.
st9_xch, // Exchange Registers.
st9_srp, // Set Register Pointer Long (16 working registers).
st9_srp0, // Set Register Pointer 0 (8 LSB working registers).
st9_srp1, // Set Register Pointer 1 (8 MSB working registers).
st9_spp, // Set Page Pointer.
st9_ext, // Sign Extend.
st9_ei, // Enable Interrupts.
st9_di, // Disable Interrupts.
st9_scf, // Set Carry Flag.
st9_rcf, // Reset Carry Flag.
st9_ccf, // Complement Carry Flag.
st9_spm, // Select Extended Memory addressing scheme through CSR Register.
st9_sdm, // Select Extended Memory addressing scheme through DPR Registers.
st9_nop, // No Operation.
st9_wfi, // Stop Program Execution and Wait for the next Enable Interrupt.
st9_halt, // Stop Program Execution until System Reset.
st9_etrap, // Undocumented instruction.
st9_eret, // Undocumented instruction.
st9_ald, // PSEUDO INSTRUCTION. SHOULD NEVER BE USED.
st9_aldw, // PSEUDO INSTRUCTION. SHOULD NEVER BE USED.
st9_last
};
#endif /* __INS_HPP */

View File

@@ -0,0 +1,57 @@
PROC=st9
CONFIGS=st9.cfg
include ../module.mak
# MAKEDEP dependency list ------------------
$(F)ana$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp \
$(I)entry.hpp $(I)fpro.h $(I)frame.hpp $(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)struct.hpp $(I)ua.hpp $(I)xref.hpp \
../idaidp.hpp ../iohandler.hpp ana.cpp ins.hpp st9.hpp
$(F)emu$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp \
$(I)entry.hpp $(I)fpro.h $(I)frame.hpp $(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)struct.hpp $(I)ua.hpp $(I)xref.hpp \
../idaidp.hpp ../iohandler.hpp emu.cpp ins.hpp st9.hpp
$(F)ins$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp \
$(I)entry.hpp $(I)fpro.h $(I)frame.hpp $(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)struct.hpp $(I)ua.hpp $(I)xref.hpp \
../idaidp.hpp ../iohandler.hpp ins.cpp ins.hpp st9.hpp
$(F)out$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp \
$(I)entry.hpp $(I)fpro.h $(I)frame.hpp $(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)struct.hpp $(I)ua.hpp $(I)xref.hpp \
../idaidp.hpp ../iohandler.hpp ins.hpp out.cpp st9.hpp
$(F)reg$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp \
$(I)entry.hpp $(I)fpro.h $(I)frame.hpp $(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)struct.hpp $(I)ua.hpp $(I)xref.hpp \
../idaidp.hpp ../iohandler.hpp ins.hpp reg.cpp st9.hpp

585
idasdk76/module/st9/out.cpp Normal file
View File

@@ -0,0 +1,585 @@
#include "st9.hpp"
//----------------------------------------------------------------------
class out_st9_t : public outctx_t
{
out_st9_t(void) = delete; // not used
st9_t &pm() { return *static_cast<st9_t *>(procmod); }
public:
const char *get_general_register_description(const ushort reg) const;
void out_reg(ushort reg);
void out_reg(const op_t &op);
void out_imm(const op_t &op, bool no_shift = false);
void out_addr(const op_t &op, bool find_label = true);
bool out_operand(const op_t &x);
void out_insn(void);
void out_proc_mnem(void);
};
CASSERT(sizeof(out_st9_t) == sizeof(outctx_t));
DECLARE_OUT_FUNCS(out_st9_t)
//--------------------------------------------------------------------------
// Get description for a given general register.
// Description may change according to the current number of the registers page.
const char *out_st9_t::get_general_register_description(const ushort reg) const
{
if ( reg <= rRR239 && reg >= rRR224 )
{
// pairs of system registers (group E)
switch ( reg )
{
case rRR236: return "User Stack Pointer";
case rRR238: return "System Stack Pointer";
default: return NULL;
}
}
if ( reg <= rR239 && reg >= rR224 )
{
// system registers (group E)
switch ( reg )
{
case rR224: return "Port 0 Data Register (EMR2.5 == 0) or Data Page Register 0 (EMR2.5 == 1)";
case rR225: return "Port 1 Data Register (EMR2.5 == 0) or Data Page Register 1 (EMR2.5 == 1)";
case rR226: return "Port 2 Data Register (EMR2.5 == 0) or Data Page Register 2 (EMR2.5 == 1)";
case rR227: return "Port 3 Data Register (EMR2.5 == 0) or Data Page Register 3 (EMR2.5 == 1)";
case rR228: return "Port 4 Data Register";
case rR229: return "Port 5 Data Register";
case rR230: return "Central Interrupt Control Register";
case rR231: return "Flag Register";
case rR232: return "Pointer 0 Register";
case rR233: return "Pointer 1 Register";
case rR234: return "Page Pointer Register";
case rR235: return "Mode Register";
case rR236: return "User Stack Pointer High Register";
case rR237: return "User Stack Pointer Low Register";
case rR238: return "System Stack Pointer High Register";
case rR239: return "System Stack Pointer Low Register";
}
}
// only handle paged register below (group F)
if ( reg < rR240 || reg > rR255 )
return NULL;
switch ( get_sreg(insn.ea, rRP) )
{
// page: N/A
case BADSEL:
break;
// page: 0
case 0:
switch ( reg )
{
case rR241: return "Minor Register";
case rR242: return "External Interrupt Trigger Register";
case rR243: return "External Interrupt Pending Register";
case rR244: return "External Interrupt Mask-bit Register";
case rR245: return "External Interrupt Priority Level Register";
case rR246: return "External Interrupt Vector Register";
case rR247: return "Nested Interrupt Control";
case rR248: return "Watchdog Timer High Register";
case rR249: return "Watchdog Timer Low Register";
case rR250: return "Watchdog Timer Prescaler Register";
case rR251: return "Watchdog Timer Control Register";
case rR252: return "Wait Control Register";
case rR253: return "SPI Data Register";
case rR254: return "SPI Control Register";
}
break;
// page: 2
case 2:
switch ( reg )
{
case rR240: return "Port 0 Configuration Register 0";
case rR241: return "Port 0 Configuration Register 1";
case rR242: return "Port 0 Configuration Register 2";
case rR244: return "Port 1 Configuration Register 0";
case rR245: return "Port 1 Configuration Register 1";
case rR246: return "Port 1 Configuration Register 2";
case rR248: return "Port 2 Configuration Register 0";
case rR249: return "Port 2 Configuration Register 1";
case rR250: return "Port 2 Configuration Register 2";
}
break;
// page: 3
case 3:
switch ( reg )
{
case rR240: return "Port 4 Configuration Register 0";
case rR241: return "Port 4 Configuration Register 1";
case rR242: return "Port 4 Configuration Register 2";
case rR244: return "Port 5 Configuration Register 0";
case rR245: return "Port 5 Configuration Register 1";
case rR246: return "Port 5 Configuration Register 2";
case rR248: return "Port 6 Configuration Register 0";
case rR249: return "Port 6 Configuration Register 1";
case rR250: return "Port 6 Configuration Register 2";
case rR251: return "Port 6 Data Register";
case rR252: return "Port 7 Configuration Register 0";
case rR253: return "Port 7 Configuration Register 1";
case rR254: return "Port 7 Configuration Register 2";
case rR255: return "Port 7 Data Register";
}
break;
// page: 8, 10 or 12
case 8:
case 10:
case 12:
switch ( reg )
{
case rR240: return "Capture Load Register 0 High";
case rR241: return "Capture Load Register 0 Low";
case rR242: return "Capture Load Register 1 High";
case rR243: return "Capture Load Register 1 Low";
case rR244: return "Compare 0 Register High";
case rR245: return "Compare 0 Register Low";
case rR246: return "Compare 1 Register High";
case rR247: return "Compare 1 Register Low";
case rR248: return "Timer Control Register";
case rR249: return "Timer Mode Register";
case rR250: return "External Input Control Register";
case rR251: return "Prescaler Register";
case rR252: return "Output A Control Register";
case rR253: return "Output B Control Register";
case rR254: return "Flags Register";
case rR255: return "Interrupt/DMA Mask Register";
}
break;
// page: 9
case 9:
switch ( reg )
{
case rR240:
case rR244: return "DMA Counter Pointer Register";
case rR241:
case rR245: return "DMA Address Pointer Register";
case rR242:
case rR246: return "Interrupt Vector Register";
case rR243:
case rR247: return "Interrupt/DMA Control Register";
case rR248: return "I/O Connection Register";
}
break;
// page: 11
case 11:
switch ( reg )
{
case rR240: return "Counter High Byte Register";
case rR241: return "Counter Low Byte Register";
case rR242: return "Standard Timer Prescaler Register";
case rR243: return "Standard Timer Control Register";
}
break;
// page: 13
case 13:
switch ( reg )
{
case rR244: return "DMA Counter Pointer Register";
case rR245: return "DMA Address Pointer Register";
case rR246: return "Interrupt Vector Register";
case rR247: return "Interrupt/DMA Control Register";
}
break;
// page: 21
case 21:
switch ( reg )
{
case rR240: return "Data Page Register 0";
case rR241: return "Data Page Register 1";
case rR242: return "Data Page Register 2";
case rR243: return "Data Page Register 3";
case rR244: return "Code Segment Register";
case rR248: return "Interrupt Segment Register";
case rR249: return "DMA Segment Register";
case rR245: return "External Memory Register 1";
case rR246: return "External Memory Register 2";
}
break;
// page: 24 or 25
case 24:
case 25:
switch ( reg )
{
case rR240: return "Receiver DMA Transaction Counter Pointer";
case rR241: return "Receiver DMA Source Address Pointer";
case rR242: return "Transmitter DMA Transaction Counter Pointer";
case rR243: return "Transmitter DMA Source Address Pointer";
case rR244: return "Interrupt Vector Register";
case rR245: return "Address/Data Compare Register";
case rR246: return "Interrupt Mask Register";
case rR247: return "Interrupt Status Register";
case rR248: return "Receive/Transmitter Buffer Register";
case rR249: return "Interrupt/DMA Priority Register";
case rR250: return "Character Configuration Register";
case rR251: return "Clock Configuration Register";
case rR252: return "Baud Rate Generator High Register";
case rR253: return "Baud Rate Generator Low Register";
case rR254: return "Synchronous Input Control";
case rR255: return "Synchronous Output Control";
}
break;
// page: 43
case 43:
switch ( reg )
{
case rR248: return "Port 8 Configuration Register 0";
case rR249: return "Port 8 Configuration Register 1";
case rR250: return "Port 8 Configuration Register 2";
case rR251: return "Port 8 Data Register";
case rR252: return "Port 9 Configuration Register 0";
case rR253: return "Port 9 Configuration Register 1";
case rR254: return "Port 9 Configuration Register 2";
case rR255: return "Port 9 Data Register";
}
break;
// page: 55
case 55:
switch ( reg )
{
case rR240: return "Clock Control Register";
case rR242: return "Clock Flag Register";
case rR246: return "PLL Configuration Register";
}
break;
// page: 63
case 63:
switch ( reg )
{
case rR240: return "Channel 0 Data Register";
case rR241: return "Channel 1 Data Register";
case rR242: return "Channel 2 Data Register";
case rR243: return "Channel 3 Data Register";
case rR244: return "Channel 4 Data Register";
case rR245: return "Channel 5 Data Register";
case rR246: return "Channel 6 Data Register";
case rR247: return "Channel 7 Data Register";
case rR248: return "Channel 6 Lower Threshold Register";
case rR249: return "Channel 6 Lower Threshold Register";
case rR250: return "Channel 7 Upper Threshold Register";
case rR251: return "Channel 7 Upper Threshold Register";
case rR252: return "Compare Result Register";
case rR253: return "Control Logic Register";
case rR254: return "Interrupt Control Register";
case rR255: return "Interrupt Vector Register";
}
break;
}
return NULL;
}
//--------------------------------------------------------------------------
// Output a register
void out_st9_t::out_reg(ushort reg)
{
out_register(ph.reg_names[reg]);
if ( !has_cmt(F) )
{
const char *cmt = get_general_register_description(reg);
if ( cmt != NULL )
pm().gr_cmt = cmt;
}
}
//--------------------------------------------------------------------------
// Output an operand as a register
void out_st9_t::out_reg(const op_t &op)
{
out_reg(op.reg);
}
//--------------------------------------------------------------------------
// Output an operand as an immediate value
void out_st9_t::out_imm(const op_t &op, bool no_shift)
{
if ( !is_imm_no_shift(op) && !no_shift )
out_symbol('#');
out_value(op, OOFW_IMM);
}
//--------------------------------------------------------------------------
// Output an operand as an address
void out_st9_t::out_addr(const op_t &op, bool find_label)
{
ea_t full_addr = get_dest_addr(insn, op);
if ( !find_label || !out_name_expr(op, full_addr, BADADDR) )
out_value(op, OOF_ADDR | OOFS_NOSIGN | OOFW_16);
}
//--------------------------------------------------------------------------
// Generate disassembly header
void idaapi st9_header(outctx_t &ctx)
{
ctx.gen_header(GH_PRINT_ALL_BUT_BYTESEX);
}
//--------------------------------------------------------------------------
// Generate disassembly footer
void st9_t::st9_footer(outctx_t &ctx) const
{
if ( ash.end != NULL )
{
ctx.gen_empty_line();
ctx.out_line(ash.end, COLOR_ASMDIR);
qstring name;
if ( get_colored_name(&name, inf_get_start_ea()) > 0 )
{
ctx.out_char(' ');
ctx.out_line(name.begin());
}
ctx.flush_outbuf(DEFAULT_INDENT);
}
else
{
ctx.gen_cmt_line("end of file");
}
}
#define BEG_TAG(x) if ( is_ind(x)) out_symbol('(' )
#define END_TAG(x) if ( is_ind(x)) out_symbol(')' )
//--------------------------------------------------------------------------
// Output an operand
bool out_st9_t::out_operand(const op_t &op)
{
switch ( op.type )
{
// Data / Code memory address
case o_near:
case o_far:
case o_mem:
BEG_TAG(op);
out_addr(op);
END_TAG(op);
break;
// Immediate value
case o_imm:
BEG_TAG(op);
{
const ioport_t *port = pm().find_sym(op.value);
// this immediate is represented in the .cfg file
if ( port != NULL ) // otherwise, simply print the value
out_line(port->name.c_str(), COLOR_IMPNAME);
else // otherwise, simply print the value
out_imm(op);
}
END_TAG(op);
break;
// Displacement
case o_displ:
out_addr(op, false);
out_symbol('(');
out_reg(op);
out_symbol(')');
break;
// Register
case o_reg:
BEG_TAG(op);
out_reg(op);
END_TAG(op);
if ( is_reg_with_bit(op) )
{
out_symbol('.');
if ( is_bit_compl(op) )
out_symbol('!');
out_imm(op, true);
}
break;
// Phrase
case o_phrase:
switch ( op.specflag2 )
{
case fPI: // post increment
out_symbol('(');
out_reg(op);
out_symbol(')');
out_symbol('+');
break;
case fPD: // pre decrement
out_symbol('-');
out_symbol('(');
out_reg(op);
out_symbol(')');
break;
case fDISP: // displacement
out_reg(op);
out_symbol('(');
{
ushort reg = op.specflag2 << 8;
reg |= op.specflag3;
out_reg(reg);
}
out_symbol(')');
break;
default:
INTERR(10077);
}
break;
// No operand
case o_void:
break;
default:
INTERR(10078);
}
return 1;
}
//--------------------------------------------------------------------------
void out_st9_t::out_proc_mnem(void)
{
char postfix[5];
postfix[0] = '\0';
if ( is_jmp_cc(insn.itype) )
qstrncpy(postfix, ConditionCodes[insn.auxpref], sizeof(postfix));
out_mnem(8, postfix);
}
//--------------------------------------------------------------------------
// Output an instruction
void out_st9_t::out_insn(void)
{
out_mnemonic();
//
// print insn operands
//
out_one_operand(0); // output the first operand
if ( insn.Op2.type != o_void )
{
out_symbol(',');
out_char(' ');
out_one_operand(1);
}
if ( insn.Op3.type != o_void )
{
out_symbol(',');
out_char(' ');
out_one_operand(2);
}
// output a character representation of the immediate values
// embedded in the instruction as comments
out_immchar_cmts();
if ( pm().gr_cmt != NULL )
{
out_char(' ');
out_line(ash.cmnt, COLOR_AUTOCMT);
out_char(' ');
out_line(pm().gr_cmt, COLOR_AUTOCMT);
if ( ash.cmnt2 != NULL )
{
out_char(' ');
out_line(ash.cmnt2, COLOR_AUTOCMT);
}
pm().gr_cmt = NULL;
}
flush_outbuf();
}
//--------------------------------------------------------------------------
// Generate a segment header
//lint -esym(1764, ctx) could be made const
//lint -esym(818, Sarea) could be made const
void st9_t::st9_segstart(outctx_t &ctx, segment_t *Sarea) const
{
qstring sname;
get_visible_segm_name(&sname, Sarea);
const char *segname = sname.c_str();
if ( *segname == '_' )
segname++;
if ( ash.uflag & UAS_ASW )
ctx.gen_printf(DEFAULT_INDENT, COLSTR("SEGMENT %s", SCOLOR_ASMDIR), segname);
else
ctx.gen_printf(DEFAULT_INDENT, COLSTR(".section .%s", SCOLOR_ASMDIR), segname);
ea_t orgbase = ctx.insn_ea - get_segm_para(Sarea);
if ( orgbase != 0 )
{
char buf[MAX_NUMBUF];
btoa(buf, sizeof(buf), orgbase);
ctx.gen_printf(DEFAULT_INDENT, COLSTR("%s %s", SCOLOR_ASMDIR), ash.origin, buf);
}
}
//--------------------------------------------------------------------------
void st9_t::st9_assumes(outctx_t &ctx)
{
ea_t ea = ctx.insn_ea;
segment_t *sega = getseg(ea);
if ( (inf_get_outflags() & OFLG_GEN_ASSUME) == 0 || sega == NULL )
return;
bool seg_started = (ea == sega->start_ea);
for ( int i = rRW; i <= rDPR3; ++i )
{
if ( i == rCSR )
continue;
sreg_range_t sra;
if ( !get_sreg_range(&sra, ea, i) || sra.val == BADSEL )
continue;
bool show = sra.start_ea == ea;
if ( show )
{
sreg_range_t prev_sra;
if ( get_prev_sreg_range(&prev_sra, ea, i) )
show = sra.val != prev_sra.val;
}
if ( seg_started || show )
{
sel_t r = sra.val;
if ( i == rRW )
{
int rwhi = (r >> 8) & 0xFF;
int rwlo = r & 0xFF;
ctx.gen_cmt_line("Register window: (%d, %d)", rwhi, rwlo);
}
else if ( i == rRP )
{
ctx.gen_cmt_line("Register page: %d", (int)r);
}
else
{
char buf[MAX_NUMBUF];
btoa(buf, sizeof(buf), r);
ctx.gen_cmt_line("assume %s: %s (page 0x%a)",
ph.reg_names[i],
buf,
(r << 14));
}
}
}
}

1237
idasdk76/module/st9/reg.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
.default ST9
.ST9
DUMMY 0x12345678 Dummy port

700
idasdk76/module/st9/st9.hpp Normal file
View File

@@ -0,0 +1,700 @@
#ifndef __ST9_HPP
#define __ST9_HPP
#include "../idaidp.hpp"
#include "ins.hpp"
#include <diskio.hpp>
#include <frame.hpp>
#include <segregs.hpp>
#include <struct.hpp>
#include "../iohandler.hpp"
#define PROCMOD_NAME st9
#define PROCMOD_NODE_NAME "$ st9"
// Operand flags
#define OP_IS_IND 0x00000001 // Operand is indirect, and should be
// printed between ().
#define OP_IMM_NO_SHIFT 0x00000002 // Operand is immediate, and should not
// be prefixed by the '#' character.
#define OP_REG_WITH_BIT 0x00000004 // Operand is register, and a bit number can be
// found in the "value" field.
#define OP_BIT_COMPL 0x00000008 // Bit number is a complement, and should be
// prefixed by the '!' character.
#define OP_DISPL_FUNC_ARG 0x00000010 // Operand is a displacement, and should be considered
// as a function argument variable.
// Flags for ash.uFlag
#define UAS_ASW 0x00000001 // current assembler is ASW.
inline bool is_ind(const op_t &op)
{
return (op.specflag1 & OP_IS_IND) != 0;
}
inline bool is_imm_no_shift(const op_t &op)
{
return op.type == o_imm && (op.specflag1 & OP_IMM_NO_SHIFT) != 0;
}
inline bool is_reg_with_bit(const op_t &op)
{
return op.type == o_reg && (op.specflag1 & OP_REG_WITH_BIT) != 0;
}
inline bool is_bit_compl(const op_t &op)
{
return (op.specflag1 & OP_BIT_COMPL) != 0;
}
// ST9+ registers :
enum st9_registers
{
rR0,
rR1,
rR2,
rR3,
rR4,
rR5,
rR6,
rR7,
rR8,
rR9,
rR10,
rR11,
rR12,
rR13,
rR14,
rR15,
rR16,
rR17,
rR18,
rR19,
rR20,
rR21,
rR22,
rR23,
rR24,
rR25,
rR26,
rR27,
rR28,
rR29,
rR30,
rR31,
rR32,
rR33,
rR34,
rR35,
rR36,
rR37,
rR38,
rR39,
rR40,
rR41,
rR42,
rR43,
rR44,
rR45,
rR46,
rR47,
rR48,
rR49,
rR50,
rR51,
rR52,
rR53,
rR54,
rR55,
rR56,
rR57,
rR58,
rR59,
rR60,
rR61,
rR62,
rR63,
rR64,
rR65,
rR66,
rR67,
rR68,
rR69,
rR70,
rR71,
rR72,
rR73,
rR74,
rR75,
rR76,
rR77,
rR78,
rR79,
rR80,
rR81,
rR82,
rR83,
rR84,
rR85,
rR86,
rR87,
rR88,
rR89,
rR90,
rR91,
rR92,
rR93,
rR94,
rR95,
rR96,
rR97,
rR98,
rR99,
rR100,
rR101,
rR102,
rR103,
rR104,
rR105,
rR106,
rR107,
rR108,
rR109,
rR110,
rR111,
rR112,
rR113,
rR114,
rR115,
rR116,
rR117,
rR118,
rR119,
rR120,
rR121,
rR122,
rR123,
rR124,
rR125,
rR126,
rR127,
rR128,
rR129,
rR130,
rR131,
rR132,
rR133,
rR134,
rR135,
rR136,
rR137,
rR138,
rR139,
rR140,
rR141,
rR142,
rR143,
rR144,
rR145,
rR146,
rR147,
rR148,
rR149,
rR150,
rR151,
rR152,
rR153,
rR154,
rR155,
rR156,
rR157,
rR158,
rR159,
rR160,
rR161,
rR162,
rR163,
rR164,
rR165,
rR166,
rR167,
rR168,
rR169,
rR170,
rR171,
rR172,
rR173,
rR174,
rR175,
rR176,
rR177,
rR178,
rR179,
rR180,
rR181,
rR182,
rR183,
rR184,
rR185,
rR186,
rR187,
rR188,
rR189,
rR190,
rR191,
rR192,
rR193,
rR194,
rR195,
rR196,
rR197,
rR198,
rR199,
rR200,
rR201,
rR202,
rR203,
rR204,
rR205,
rR206,
rR207,
rR208,
rR209,
rR210,
rR211,
rR212,
rR213,
rR214,
rR215,
rR216,
rR217,
rR218,
rR219,
rR220,
rR221,
rR222,
rR223,
rR224,
rR225,
rR226,
rR227,
rR228,
rR229,
rR230,
rR231,
rR232,
rR233,
rR234,
rR235,
rR236,
rR237,
rR238,
rR239,
rR240,
rR241,
rR242,
rR243,
rR244,
rR245,
rR246,
rR247,
rR248,
rR249,
rR250,
rR251,
rR252,
rR253,
rR254,
rR255,
rRR0,
rRR1,
rRR2,
rRR3,
rRR4,
rRR5,
rRR6,
rRR7,
rRR8,
rRR9,
rRR10,
rRR11,
rRR12,
rRR13,
rRR14,
rRR15,
rRR16,
rRR17,
rRR18,
rRR19,
rRR20,
rRR21,
rRR22,
rRR23,
rRR24,
rRR25,
rRR26,
rRR27,
rRR28,
rRR29,
rRR30,
rRR31,
rRR32,
rRR33,
rRR34,
rRR35,
rRR36,
rRR37,
rRR38,
rRR39,
rRR40,
rRR41,
rRR42,
rRR43,
rRR44,
rRR45,
rRR46,
rRR47,
rRR48,
rRR49,
rRR50,
rRR51,
rRR52,
rRR53,
rRR54,
rRR55,
rRR56,
rRR57,
rRR58,
rRR59,
rRR60,
rRR61,
rRR62,
rRR63,
rRR64,
rRR65,
rRR66,
rRR67,
rRR68,
rRR69,
rRR70,
rRR71,
rRR72,
rRR73,
rRR74,
rRR75,
rRR76,
rRR77,
rRR78,
rRR79,
rRR80,
rRR81,
rRR82,
rRR83,
rRR84,
rRR85,
rRR86,
rRR87,
rRR88,
rRR89,
rRR90,
rRR91,
rRR92,
rRR93,
rRR94,
rRR95,
rRR96,
rRR97,
rRR98,
rRR99,
rRR100,
rRR101,
rRR102,
rRR103,
rRR104,
rRR105,
rRR106,
rRR107,
rRR108,
rRR109,
rRR110,
rRR111,
rRR112,
rRR113,
rRR114,
rRR115,
rRR116,
rRR117,
rRR118,
rRR119,
rRR120,
rRR121,
rRR122,
rRR123,
rRR124,
rRR125,
rRR126,
rRR127,
rRR128,
rRR129,
rRR130,
rRR131,
rRR132,
rRR133,
rRR134,
rRR135,
rRR136,
rRR137,
rRR138,
rRR139,
rRR140,
rRR141,
rRR142,
rRR143,
rRR144,
rRR145,
rRR146,
rRR147,
rRR148,
rRR149,
rRR150,
rRR151,
rRR152,
rRR153,
rRR154,
rRR155,
rRR156,
rRR157,
rRR158,
rRR159,
rRR160,
rRR161,
rRR162,
rRR163,
rRR164,
rRR165,
rRR166,
rRR167,
rRR168,
rRR169,
rRR170,
rRR171,
rRR172,
rRR173,
rRR174,
rRR175,
rRR176,
rRR177,
rRR178,
rRR179,
rRR180,
rRR181,
rRR182,
rRR183,
rRR184,
rRR185,
rRR186,
rRR187,
rRR188,
rRR189,
rRR190,
rRR191,
rRR192,
rRR193,
rRR194,
rRR195,
rRR196,
rRR197,
rRR198,
rRR199,
rRR200,
rRR201,
rRR202,
rRR203,
rRR204,
rRR205,
rRR206,
rRR207,
rRR208,
rRR209,
rRR210,
rRR211,
rRR212,
rRR213,
rRR214,
rRR215,
rRR216,
rRR217,
rRR218,
rRR219,
rRR220,
rRR221,
rRR222,
rRR223,
rRR224,
rRR225,
rRR226,
rRR227,
rRR228,
rRR229,
rRR230,
rRR231,
rRR232,
rRR233,
rRR234,
rRR235,
rRR236,
rRR237,
rRR238,
rRR239,
rRR240,
rRR241,
rRR242,
rRR243,
rRR244,
rRR245,
rRR246,
rRR247,
rRR248,
rRR249,
rRR250,
rRR251,
rRR252,
rRR253,
rRR254,
rRR255,
rr0,
rr1,
rr2,
rr3,
rr4,
rr5,
rr6,
rr7,
rr8,
rr9,
rr10,
rr11,
rr12,
rr13,
rr14,
rr15,
rrr0,
rrr1,
rrr2,
rrr3,
rrr4,
rrr5,
rrr6,
rrr7,
rrr8,
rrr9,
rrr10,
rrr11,
rrr12,
rrr13,
rrr14,
rrr15,
rRW, // register window number
rRP, // register page
rCSR, // code segment register
rDPR0, rDPR1, rDPR2, rDPR3, // Data page registers
st9_lastreg = rDPR3,
};
// ST9 condition codes
enum st9_cond_codes
{
cUNKNOWN,
cF, // always false
cT, // always true
cC, // carry
cNC, // not carry
cZ, // zero
cNZ, // not zero
cPL, // plus
cMI, // minus
cOV, // overflow
cNOV, // no overflow
cEQ, // equal
cNE, // not equal
cGE, // greater than or equal
cLT, // less than
cGT, // greater than
cLE, // less than or equal
cUGE, // unsigned greated than or equal
cUL, // unsigned less than
cUGT, // unsigned greater than
cULE // unsigned less than or equal
};
enum st9_phrases ENUM_SIZE(uint8)
{
fPI, // post incrementation (rr)+
fPD, // pre decrementation -(rr)
fDISP // displacement rrx(rry)
};
inline bool is_jmp_cc(int insn)
{
return insn == st9_jpcc || insn == st9_jrcc;
}
//------------------------------------------------------------------
struct st9_iohandler_t : public iohandler_t
{
struct st9_t &pm;
st9_iohandler_t(st9_t &_pm, netnode &nn) : iohandler_t(nn), pm(_pm) {}
};
struct st9_t : public procmod_t
{
// The netnode helper.
// Using this node we will save current configuration information in the
// IDA database.
netnode helper;
st9_iohandler_t ioh = st9_iohandler_t(*this, helper);
const char *RegNames[st9_lastreg + 1];
qstrvec_t dynamic_rgnames; // dynamically generated names for rR1..rR255
const char *gr_cmt = nullptr;
int ref_dpr_id; // id of refinfo handler
#define IDP_GR_DEC 0x0001 // print general registers in decimal format
#define IDP_GR_HEX 0x0002 // print general registers in hexadecimal format
#define IDP_GR_BIN 0x0004 // print general registers in binary format
uint32 idpflags = IDP_GR_DEC;
ushort print_style = 3;
bool flow;
virtual ssize_t idaapi on_event(ssize_t msgid, va_list va) override;
const ioport_t *find_sym(ea_t address);
void patch_general_registers();
const char *set_idp_options(
const char *keyword,
int /*value_type*/,
const void * /*value*/,
bool idb_loaded);
int st9_emu(const insn_t &insn);
void handle_operand(const insn_t &insn, const op_t &op, bool lwrite);
bool create_func_frame(func_t *pfn) const;
void st9_assumes(outctx_t &ctx);
void st9_footer(outctx_t &ctx) const;
void st9_segstart(outctx_t &ctx, segment_t *Sarea) const;
void save_idpflags() { helper.altset(-1, idpflags); }
void load_from_idb();
};
extern int data_id;
// exporting our routines
void idaapi st9_header(outctx_t &ctx);
int idaapi st9_ana(insn_t *insn);
ea_t get_dest_addr(const insn_t &insn, const op_t &x);
bool st9_is_switch(switch_info_t *si, const insn_t &insn);
extern const char *const ConditionCodes[];
#endif /* __ST9_HPP */