update to ida 7.6, add builds
This commit is contained in:
354
idasdk76/module/z8/ana.cpp
Normal file
354
idasdk76/module/z8/ana.cpp
Normal file
@@ -0,0 +1,354 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Zilog Z8 module
|
||||
*
|
||||
*/
|
||||
|
||||
#include "z8.hpp"
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static int adjust_reg_alias(int reg_no, uint16 rp, bool mem)
|
||||
{
|
||||
// special case for Tycoint
|
||||
// we use the third nibble to map the registers to alternative names in 1000:2000
|
||||
// aliases for regs in the same WRG are placed next to each other in 256-byte blocks
|
||||
// e.g.
|
||||
// 1400-140F first alias group for regs 40-4F
|
||||
// 1410-141F second alias group for regs 40-4F
|
||||
// 1420-142F third alias group for regs 40-4F
|
||||
// ... etc
|
||||
int subbank_no = ((rp & 0xF00) >> 8) - 1;
|
||||
// assert: subbank_no in [-1, 0xE]
|
||||
if ( subbank_no >= 0 )
|
||||
{
|
||||
int wrg_no;
|
||||
if ( mem )
|
||||
{
|
||||
// WRG is the high nibble of the register number
|
||||
wrg_no = (reg_no & 0xF0) >> 4;
|
||||
if ( wrg_no < 0xF )
|
||||
reg_no &= 0xF;
|
||||
}
|
||||
else
|
||||
{
|
||||
// WRG is the high nibble of the RP
|
||||
wrg_no = (rp & 0xF0) >> 4;
|
||||
}
|
||||
if ( wrg_no < 0xF ) // don't alias system registers (F0-FF)
|
||||
reg_no += 0x1000 + wrg_no * 256 + subbank_no * 16;
|
||||
}
|
||||
return reg_no;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static void work_reg(const insn_t &insn, op_t &op, int reg_no, int dbl_reg = 0, int indir = 0 )
|
||||
{
|
||||
if ( dbl_reg )
|
||||
op.dtype = dt_word;
|
||||
|
||||
// do we have RP set?
|
||||
uint16 rp = get_rp(insn.ea);
|
||||
if ( rp == 0 )
|
||||
{
|
||||
// nope; use default working group (0)
|
||||
op.reg = (dbl_reg ? rRR0 : rR0) + reg_no;
|
||||
op.type = indir ? o_ind_reg : o_reg;
|
||||
}
|
||||
else
|
||||
{
|
||||
// use memory operand
|
||||
if ( (rp & 0xF) == 0 && (rp & 0xF00) != 0 )
|
||||
{
|
||||
reg_no = adjust_reg_alias(reg_no, rp, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// high nibble of rp is the working group (bank), low nibble is the extended register file
|
||||
reg_no += rp & 0xF0;
|
||||
reg_no += (rp & 0xF) << 8;
|
||||
}
|
||||
op.addr = reg_no;
|
||||
op.type = indir ? o_ind_mem : o_mem;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static void dir_reg(insn_t &insn, op_t &op, int dbl_reg = 0, int indir = 0)
|
||||
{
|
||||
uint tmp = insn.get_next_byte();
|
||||
if ( (tmp & 0xF0 ) == 0xE0 ) // Ex - special reg bank
|
||||
{
|
||||
work_reg(insn, op, tmp & 0xF, dbl_reg, indir);
|
||||
}
|
||||
else
|
||||
{
|
||||
// use memory operand
|
||||
uint16 rp = get_rp(insn.ea);
|
||||
if ( (rp & 0xF) == 0 && (rp & 0xF00) != 0 )
|
||||
tmp = adjust_reg_alias(tmp, rp, true);
|
||||
op.addr = tmp;
|
||||
op.type = indir ? o_ind_mem : o_mem;
|
||||
if ( dbl_reg )
|
||||
op.dtype = dt_word;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
int z8_t::z8_ana(insn_t *_insn)
|
||||
{
|
||||
insn_t &insn = *_insn;
|
||||
|
||||
insn.Op1.dtype = dt_byte;
|
||||
insn.Op2.dtype = dt_byte;
|
||||
|
||||
uint16 code = insn.get_next_byte();
|
||||
|
||||
uint16 nibble0 = (code & 0xF);
|
||||
uint16 nibble1 = (code >> 4);
|
||||
|
||||
char offc;
|
||||
uint16 tmp;
|
||||
|
||||
if ( nibble0 == 0xF ) // xF
|
||||
{
|
||||
static const char cmdxF[] =
|
||||
{
|
||||
Z8_null, Z8_null, Z8_null, Z8_null,
|
||||
Z8_null, Z8_null, Z8_stop, Z8_halt,
|
||||
Z8_di, Z8_ei, Z8_ret, Z8_iret,
|
||||
Z8_rcf, Z8_scf, Z8_ccf, Z8_nop
|
||||
};
|
||||
|
||||
insn.itype = cmdxF[nibble1];
|
||||
}
|
||||
else if ( nibble0 >= 8 ) // x8..xE
|
||||
{
|
||||
static const char cmdx8E[] =
|
||||
{
|
||||
Z8_ld, Z8_ld, Z8_djnz, Z8_jrcond, Z8_ld, Z8_jpcond, Z8_inc
|
||||
};
|
||||
|
||||
insn.itype = cmdx8E[nibble0-8];
|
||||
|
||||
if ( nibble0 == 8 || nibble0 == 0xA || nibble0 == 0xC || nibble0 == 0xE )
|
||||
{
|
||||
work_reg(insn, insn.Op1, nibble1);
|
||||
}
|
||||
|
||||
if ( nibble0 == 0xB || nibble0 == 0xD )
|
||||
{
|
||||
insn.Op1.type = o_phrase;
|
||||
insn.Op1.phrase = nibble1;
|
||||
}
|
||||
|
||||
switch ( nibble0 )
|
||||
{
|
||||
case 0x8: // ld r1,R2
|
||||
dir_reg(insn, insn.Op2);
|
||||
break;
|
||||
|
||||
case 0x9: // ld r2,R1
|
||||
dir_reg(insn, insn.Op1);
|
||||
work_reg(insn, insn.Op2, nibble1);
|
||||
break;
|
||||
|
||||
case 0xA: // djnz r1,RA
|
||||
case 0xB: // jr cc,RA
|
||||
offc = insn.get_next_byte();
|
||||
insn.Op2.addr = ushort(insn.ip + insn.size + offc); // signed addition
|
||||
insn.Op2.dtype = dt_word;
|
||||
insn.Op2.type = o_near;
|
||||
break;
|
||||
|
||||
case 0xC: // ld r1,#im
|
||||
insn.Op2.value = insn.get_next_byte();
|
||||
insn.Op2.type = o_imm;
|
||||
break;
|
||||
|
||||
case 0xD: // jp cc,DA
|
||||
insn.Op2.addr = insn.get_next_word();
|
||||
insn.Op2.dtype = dt_word;
|
||||
insn.Op2.type = o_near;
|
||||
}
|
||||
|
||||
if ( (nibble0 == 0xB || nibble0 == 0xD)
|
||||
&& (nibble1 == 0 || nibble1 == 8) )
|
||||
switch ( nibble1 )
|
||||
{
|
||||
case 0: // never true - seems as 2-byte NOP
|
||||
insn.Op1.type = o_void;
|
||||
insn.itype = Z8_nop;
|
||||
insn.Op2.type = o_void;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
insn.Op1 = insn.Op2;
|
||||
insn.itype--; // Z8_jpcond -> Z8_jp, Z8_jrcond -> Z8_jr
|
||||
insn.Op2.type = o_void;
|
||||
}
|
||||
}
|
||||
else if ( nibble0 >= 2 ) // x2..x7
|
||||
{
|
||||
static const char cmdx2[] =
|
||||
{
|
||||
Z8_add, Z8_adc, Z8_sub, Z8_sbc,
|
||||
Z8_or, Z8_and, Z8_tcm, Z8_tm,
|
||||
Z8_null, Z8_null, Z8_cp, Z8_xor,
|
||||
Z8_null, Z8_null, Z8_ld, Z8_null
|
||||
};
|
||||
|
||||
switch ( code )
|
||||
{
|
||||
case 0xD6:
|
||||
case 0xD4:
|
||||
insn.itype = Z8_call;
|
||||
insn.Op1.dtype = dt_word;
|
||||
|
||||
if ( code == 0xD6 )
|
||||
{
|
||||
insn.Op1.addr = insn.get_next_word();
|
||||
insn.Op1.type = o_near;
|
||||
}
|
||||
else // D4 - call @RR
|
||||
{
|
||||
dir_reg(insn, insn.Op1, 1, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC7:
|
||||
tmp = insn.get_next_byte();
|
||||
work_reg(insn, insn.Op1, tmp >> 4);
|
||||
insn.Op2.reg = tmp & 0xF;
|
||||
insn.Op2.type = o_displ;
|
||||
insn.Op2.addr = insn.get_next_byte();
|
||||
insn.itype = Z8_ld;
|
||||
break;
|
||||
|
||||
case 0xD7:
|
||||
tmp = insn.get_next_byte();
|
||||
work_reg(insn, insn.Op2, tmp >> 4);
|
||||
insn.Op1.reg = tmp & 0xF;
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.addr = insn.get_next_byte();
|
||||
insn.itype = Z8_ld;
|
||||
break;
|
||||
|
||||
case 0x82: case 0x83: case 0x92: case 0x93:
|
||||
tmp = insn.get_next_byte();
|
||||
insn.itype = (nibble0 == 2) ? Z8_lde : Z8_ldei;
|
||||
if ( nibble1 == 8 )
|
||||
{
|
||||
// r dst, lrr src
|
||||
work_reg(insn, insn.Op1, tmp >> 4, 0, nibble0 != 2);
|
||||
work_reg(insn, insn.Op2, tmp & 0xF, 1, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// lrr dst, r src
|
||||
work_reg(insn, insn.Op1, tmp & 0xF, 1, 1);
|
||||
work_reg(insn, insn.Op2, tmp >> 4, 0, nibble0 != 2);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC2: case 0xC3: case 0xD2: case 0xD3:
|
||||
tmp = insn.get_next_byte();
|
||||
insn.itype = (nibble0 == 2) ? Z8_ldc : Z8_ldci;
|
||||
if ( nibble1 == 0xC )
|
||||
{
|
||||
work_reg(insn, insn.Op1, tmp >> 4, 0, nibble0 != 2);
|
||||
work_reg(insn, insn.Op2, tmp & 0xF, 1, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
work_reg(insn, insn.Op1, tmp & 0xF, 1, 1);
|
||||
work_reg(insn, insn.Op2, tmp >> 4, 0, nibble0 != 2);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
insn.itype = cmdx2[nibble1];
|
||||
|
||||
switch ( nibble0 )
|
||||
{
|
||||
case 2: // r1,r2
|
||||
case 3: // r1,Ir2
|
||||
tmp = insn.get_next_byte();
|
||||
work_reg(insn, insn.Op1, tmp >> 4);
|
||||
work_reg(insn, insn.Op2, tmp & 0xF, 0, nibble0 != 2);
|
||||
break;
|
||||
|
||||
case 4: // R2,R1
|
||||
case 5: // IR2,R1
|
||||
dir_reg(insn, insn.Op2, 0, nibble0 == 5);
|
||||
dir_reg(insn, insn.Op1);
|
||||
break;
|
||||
|
||||
case 6: // R1,IM
|
||||
case 7: // IR1,IM
|
||||
dir_reg(insn, insn.Op1, 0, nibble0 == 7);
|
||||
insn.Op2.value = insn.get_next_byte();
|
||||
insn.Op2.type = o_imm;
|
||||
}
|
||||
|
||||
switch ( nibble1 )
|
||||
{
|
||||
case 0xF: // ld
|
||||
switch ( nibble0 )
|
||||
{
|
||||
case 3: // ld Ir1,r2
|
||||
insn.Op2.type = o_reg;
|
||||
insn.Op1.type = o_ind_reg;
|
||||
insn.itype = Z8_ld;
|
||||
break;
|
||||
|
||||
case 5: // ld R2,IR1
|
||||
{
|
||||
op_t tmp_op = insn.Op1;
|
||||
insn.Op1 = insn.Op2;
|
||||
insn.Op2 = tmp_op;
|
||||
insn.itype = Z8_ld;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xE: // ld
|
||||
if ( nibble0 != 2 )
|
||||
insn.itype = Z8_ld;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // x0..x1
|
||||
{ /*Z8_srp*/
|
||||
static const char cmdx01[] =
|
||||
{
|
||||
Z8_dec, Z8_rlc, Z8_inc, Z8_jp,
|
||||
Z8_da, Z8_pop, Z8_com, Z8_push,
|
||||
Z8_decw, Z8_rl, Z8_incw, Z8_clr,
|
||||
Z8_rrc, Z8_sra, Z8_rr, Z8_swap
|
||||
};
|
||||
|
||||
insn.itype = cmdx01[nibble1];
|
||||
switch ( code )
|
||||
{
|
||||
case 0x30: // jp @intmem
|
||||
dir_reg(insn, insn.Op1, 1, 1);
|
||||
break;
|
||||
|
||||
case 0x31: // srp #xx
|
||||
insn.itype = Z8_srp;
|
||||
insn.Op1.type = o_imm;
|
||||
insn.Op1.value = insn.get_next_byte();
|
||||
insn.Op1.flags |= OF_NUMBER;
|
||||
break;
|
||||
|
||||
default:
|
||||
dir_reg(insn, insn.Op1, (code == 0x80) || (code == 0xA0), nibble0);
|
||||
}
|
||||
}
|
||||
|
||||
if ( insn.itype == Z8_null )
|
||||
return 0; // unknown command
|
||||
return insn.size;
|
||||
}
|
||||
117
idasdk76/module/z8/emu.cpp
Normal file
117
idasdk76/module/z8/emu.cpp
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Zilog Z8 module
|
||||
*
|
||||
*/
|
||||
|
||||
#include "z8.hpp"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Calculate the target data address
|
||||
ea_t z8_t::map_addr(const insn_t &insn, asize_t off, int opnum, bool isdata) const
|
||||
{
|
||||
if ( isdata )
|
||||
{
|
||||
if ( is_off(get_flags(insn.ea), opnum) )
|
||||
return get_offbase(insn.ea, opnum) >> 4;
|
||||
return intmem + off;
|
||||
}
|
||||
return map_code_ea(insn, off, opnum);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void z8_t::handle_operand(const insn_t &insn, const op_t &x, bool isload)
|
||||
{
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_displ:
|
||||
case o_imm:
|
||||
if ( op_adds_xrefs(get_flags(insn.ea), x.n) )
|
||||
{
|
||||
int outf = x.type != o_imm ? OOF_ADDR|OOFW_16 : 0;
|
||||
insn.add_off_drefs(x, dr_O, outf|OOF_SIGNED);
|
||||
}
|
||||
break;
|
||||
|
||||
case o_mem:
|
||||
case o_ind_mem:
|
||||
case o_reg:
|
||||
case o_ind_reg:
|
||||
{
|
||||
ea_t dea;
|
||||
if ( x.type == o_mem || x.type == o_ind_mem )
|
||||
{
|
||||
dea = map_addr(insn, x.addr, x.n, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( x.reg >= rRR0 )
|
||||
dea = map_addr(insn, x.reg - rRR0, x.n, true);
|
||||
else
|
||||
dea = map_addr(insn, x.reg - rR0, x.n, true);
|
||||
}
|
||||
insn.create_op_data(dea, x);
|
||||
insn.add_dref(dea, x.offb, isload ? dr_R : dr_W);
|
||||
if ( !has_user_name(get_flags(dea)) && dea > intmem )
|
||||
{
|
||||
char buf[10];
|
||||
int num = dea - intmem;
|
||||
if ( num < 0x100 )
|
||||
{
|
||||
qsnprintf(buf, sizeof(buf), "R%d", num);
|
||||
}
|
||||
else if ( num < 0x1000 )
|
||||
{
|
||||
qsnprintf(buf, sizeof(buf), "ERF_%X_%d", num >> 8, num & 0xFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
int reg_no = ((num >> 4) & 0xF0) + (num & 0xF);
|
||||
int subbank_no = ((num >> 4) & 0xF) + 1;
|
||||
qsnprintf(buf, sizeof(buf), "R%d_%X", reg_no, subbank_no);
|
||||
}
|
||||
set_name(dea, buf, SN_NOCHECK|SN_NOWARN|SN_NODUMMY);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case o_near:
|
||||
{
|
||||
ea_t ea = map_code_ea(insn, x);
|
||||
int iscall = has_insn_feature(insn.itype, CF_CALL);
|
||||
insn.add_cref(ea, x.offb, iscall ? fl_CN : fl_JN);
|
||||
if ( flow && iscall )
|
||||
flow = func_does_return(ea);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int z8_t::z8_emu(const insn_t &insn)
|
||||
{
|
||||
uint32 Feature = insn.get_canon_feature(ph);
|
||||
|
||||
flow = (Feature & CF_STOP) == 0;
|
||||
|
||||
if ( Feature & CF_USE1 ) handle_operand(insn, insn.Op1, true);
|
||||
if ( Feature & CF_USE2 ) handle_operand(insn, insn.Op2, 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 ( flow )
|
||||
add_cref(insn.ea, insn.ea+insn.size, fl_F);
|
||||
|
||||
if ( insn.itype == Z8_srp // Set register pointer
|
||||
|| (insn.itype == Z8_pop && insn.Op1.type == o_mem && insn.Op1.addr == 0xFD) ) // popping RP
|
||||
{
|
||||
// set the RP value
|
||||
sel_t val = insn.itype == Z8_srp ? (insn.Op1.value & 0xFF) : BADSEL;
|
||||
split_sreg_range(insn.ea + insn.size, rRp, val, SR_auto, true);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
67
idasdk76/module/z8/ins.cpp
Normal file
67
idasdk76/module/z8/ins.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Zilog Z8 module
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
#include "ins.hpp"
|
||||
|
||||
const instruc_t Instructions[] =
|
||||
{
|
||||
{ "", 0 }, // Unknown Operation
|
||||
|
||||
{ "adc", CF_USE2|CF_USE1|CF_CHG1 }, // Add with carry
|
||||
{ "add", CF_USE2|CF_USE1|CF_CHG1 }, // Add
|
||||
{ "and", CF_USE2|CF_USE1|CF_CHG1 }, // Logical AND
|
||||
{ "call", CF_USE1|CF_CALL }, // Call procedure
|
||||
{ "ccf", 0 }, // Complement carry flag
|
||||
{ "clr", CF_CHG1 }, // Clear
|
||||
{ "com", CF_USE1|CF_CHG1 }, // Complement
|
||||
{ "cp", CF_USE2|CF_USE1 }, // Compare
|
||||
{ "da", CF_USE1|CF_CHG1 }, // Decimal adjust
|
||||
{ "dec", CF_USE1|CF_CHG1 }, // Decrement
|
||||
{ "decw", CF_USE1|CF_CHG1 }, // Decrement word
|
||||
{ "di", 0 }, // Disable interrupts
|
||||
{ "djnz", CF_USE2|CF_USE1|CF_CHG1 }, // Decrement and jump if non-zero
|
||||
{ "ei", 0 }, // Enable interrupts
|
||||
{ "halt", 0 }, // Enter HALT mode
|
||||
{ "inc", CF_USE1|CF_CHG1 }, // Increment
|
||||
{ "incw", CF_USE1|CF_CHG1 }, // Increment word
|
||||
{ "iret", CF_STOP }, // Return from interrupt
|
||||
// { "jp", CF_JUMP|CF_USE1|CF_STOP }, // Indirect jump
|
||||
{ "jp", CF_USE1|CF_STOP }, // Unconditional jump
|
||||
{ "jp", CF_USE2 }, // Conditional jump
|
||||
{ "jr", CF_USE1|CF_STOP }, // Relative jump
|
||||
{ "jr", CF_USE2 }, // Conditional relative jump
|
||||
{ "ld", CF_USE2|CF_USE1|CF_CHG1 }, // Load data
|
||||
{ "ldc", CF_USE2|CF_USE1|CF_CHG1 }, // Load constant
|
||||
{ "ldci", CF_USE2|CF_USE1|CF_CHG1 }, // Load constant with auto-increment
|
||||
{ "lde", CF_USE2|CF_USE1|CF_CHG1 }, // Load external data
|
||||
{ "ldei", CF_USE2|CF_USE1|CF_CHG1 }, // Load external data with auto-increment
|
||||
{ "nop", 0 }, // NOP
|
||||
{ "or", CF_USE2|CF_USE1|CF_CHG1 }, // Logical OR
|
||||
{ "pop", CF_CHG1 }, // Pop
|
||||
{ "push", CF_USE1 }, // Push
|
||||
{ "rcf", 0 }, // Reset carry flag
|
||||
{ "ret", CF_STOP }, // Return
|
||||
{ "rl", CF_SHFT|CF_USE1|CF_CHG1 }, // Rotate left
|
||||
{ "rlc", CF_SHFT|CF_USE1|CF_CHG1 }, // Rotate left through carry
|
||||
{ "rr", CF_SHFT|CF_USE1|CF_CHG1 }, // Rotate right
|
||||
{ "rrc", CF_SHFT|CF_USE1|CF_CHG1 }, // Rotate right through carry
|
||||
{ "sbc", CF_USE2|CF_USE1|CF_CHG1 }, // Subtract with carry
|
||||
{ "scf", 0 }, // Set carry flag
|
||||
{ "sra", CF_SHFT|CF_USE1|CF_CHG1 }, // Shift right arithmetic
|
||||
{ "srp", CF_USE1 }, // Set register pointer
|
||||
{ "stop", CF_STOP }, // Enter STOP mode
|
||||
{ "sub", CF_USE2|CF_USE1|CF_CHG1 }, // Subtract
|
||||
{ "swap", CF_USE1|CF_CHG1 }, // Swap nibbles
|
||||
{ "tm", CF_USE2|CF_USE1 }, // Test under mask
|
||||
{ "tcm", CF_USE2|CF_USE1 }, // Test complement under mask
|
||||
{ "xor", CF_USE2|CF_USE1|CF_CHG1 }, // Logical EXCLUSIVE OR
|
||||
{ "wdh", 0 }, // Enable WATCH-DOG in HALT mode
|
||||
{ "wdt", 0 } // Clear WATCH-DOG timer
|
||||
};
|
||||
|
||||
CASSERT(sizeof(Instructions)/sizeof(Instructions[0]) == Z8_last);
|
||||
69
idasdk76/module/z8/ins.hpp
Normal file
69
idasdk76/module/z8/ins.hpp
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Zilog Z8 module
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __INSTRS_HPP
|
||||
#define __INSTRS_HPP
|
||||
|
||||
extern const instruc_t Instructions[];
|
||||
|
||||
enum nameNum ENUM_SIZE(uint16)
|
||||
{
|
||||
Z8_null = 0, // Unknown Operation
|
||||
|
||||
Z8_adc, // Add with carry
|
||||
Z8_add, // Add
|
||||
Z8_and, // Logical AND
|
||||
Z8_call, // Call procedure
|
||||
Z8_ccf, // Complement carry flag
|
||||
Z8_clr, // Clear
|
||||
Z8_com, // Complement
|
||||
Z8_cp, // Compare
|
||||
Z8_da, // Decimal adjust
|
||||
Z8_dec, // Decrement
|
||||
Z8_decw, // Decrement word
|
||||
Z8_di, // Disable interrupts
|
||||
Z8_djnz, // Decrement and jump if non-zero
|
||||
Z8_ei, // Enable interrupts
|
||||
Z8_halt, // Enter HALT mode
|
||||
Z8_inc, // Increment
|
||||
Z8_incw, // Increment word
|
||||
Z8_iret, // Return from interrupt
|
||||
Z8_jp, // Unconditional jump
|
||||
Z8_jpcond, // Conditional jump
|
||||
Z8_jr, // Relative jump
|
||||
Z8_jrcond, // Conditional relative jump
|
||||
Z8_ld, // Load data
|
||||
Z8_ldc, // Load constant
|
||||
Z8_ldci, // Load constant with auto-increment
|
||||
Z8_lde, // Load external data
|
||||
Z8_ldei, // Load external data with auto-increment
|
||||
Z8_nop, // NOP
|
||||
Z8_or, // Logical OR
|
||||
Z8_pop, // Pop
|
||||
Z8_push, // Push
|
||||
Z8_rcf, // Reset carry flag
|
||||
Z8_ret, // Return
|
||||
Z8_rl, // Rotate left
|
||||
Z8_rlc, // Rotate left through carry
|
||||
Z8_rr, // Rotate right
|
||||
Z8_rrc, // Rotate right through carry
|
||||
Z8_sbc, // Subtract with carry
|
||||
Z8_scf, // Set carry flag
|
||||
Z8_sra, // Shift right arithmetic
|
||||
Z8_srp, // Set register pointer
|
||||
Z8_stop, // Enter STOP mode
|
||||
Z8_sub, // Subtract
|
||||
Z8_swap, // Swap nibbles
|
||||
Z8_tm, // Test under mask
|
||||
Z8_tcm, // Test complement under mask
|
||||
Z8_xor, // Logical EXCLUSIVE OR
|
||||
Z8_wdh, // Enable WATCH-DOG in HALT mode
|
||||
Z8_wdt, // Clear WATCH-DOG timer
|
||||
|
||||
Z8_last
|
||||
};
|
||||
|
||||
#endif
|
||||
52
idasdk76/module/z8/makefile
Normal file
52
idasdk76/module/z8/makefile
Normal file
@@ -0,0 +1,52 @@
|
||||
PROC=z8
|
||||
CONFIGS=z8.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)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 \
|
||||
../iohandler.hpp ana.cpp ins.hpp z8.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)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 \
|
||||
../iohandler.hpp emu.cpp ins.hpp z8.hpp
|
||||
$(F)ins$(O) : $(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)nalt.hpp \
|
||||
$(I)netnode.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)ua.hpp $(I)xref.hpp ins.cpp ins.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)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 \
|
||||
../iohandler.hpp ins.hpp out.cpp z8.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)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 \
|
||||
../iohandler.hpp ins.hpp reg.cpp z8.hpp
|
||||
211
idasdk76/module/z8/out.cpp
Normal file
211
idasdk76/module/z8/out.cpp
Normal file
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Zilog Z8 module
|
||||
*
|
||||
*/
|
||||
|
||||
#include "z8.hpp"
|
||||
|
||||
static const char *const phrases[] =
|
||||
{
|
||||
"F", "LT", "LE", "ULE", "OV", "MI", "Z", "C",
|
||||
"T", "GE", "GT", "UGT", "NOV", "PL", "NZ", "NC"
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
inline void z8_t::out_reg(outctx_t &ctx, int rgnum)
|
||||
{
|
||||
ctx.out_register(ph.reg_names[rgnum]);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void z8_t::z8_header(outctx_t &ctx)
|
||||
{
|
||||
ctx.gen_header(GH_PRINT_PROC_ASM_AND_BYTESEX);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void z8_t::z8_footer(outctx_t &ctx)
|
||||
{
|
||||
ctx.gen_empty_line();
|
||||
|
||||
ctx.out_line(ash.end, COLOR_ASMDIR);
|
||||
ctx.flush_outbuf(DEFAULT_INDENT);
|
||||
|
||||
ctx.gen_cmt_line("end of file");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//lint -esym(1764, ctx) could be made const
|
||||
//lint -esym(818, Srange) could be made const
|
||||
void z8_t::z8_segstart(outctx_t &ctx, segment_t *Srange)
|
||||
{
|
||||
qstring sname;
|
||||
get_visible_segm_name(&sname, Srange);
|
||||
|
||||
ctx.gen_cmt_line(COLSTR("segment %s", SCOLOR_AUTOCMT), sname.c_str());
|
||||
|
||||
ea_t org = ctx.insn_ea - get_segm_base(Srange);
|
||||
if ( org != 0 )
|
||||
{
|
||||
char buf[MAX_NUMBUF];
|
||||
btoa(buf, sizeof(buf), org);
|
||||
ctx.gen_cmt_line("%s %s", ash.origin, buf);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//lint -esym(818, seg) could be made const
|
||||
void z8_t::z8_segend(outctx_t &ctx, segment_t *seg)
|
||||
{
|
||||
qstring sname;
|
||||
get_visible_segm_name(&sname, seg);
|
||||
ctx.gen_cmt_line("end of '%s'", sname.c_str());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void idaapi out_insn(outctx_t &ctx)
|
||||
{
|
||||
ctx.out_mnemonic();
|
||||
|
||||
ctx.out_one_operand(0);
|
||||
|
||||
if ( ctx.insn.Op2.type != o_void )
|
||||
{
|
||||
ctx.out_symbol(',');
|
||||
ctx.out_char(' ');
|
||||
ctx.out_one_operand(1);
|
||||
}
|
||||
|
||||
ctx.out_immchar_cmts();
|
||||
ctx.flush_outbuf();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool z8_t::out_opnd(outctx_t &ctx, const op_t &x)
|
||||
{
|
||||
uval_t v;
|
||||
|
||||
z8_t &pm = *static_cast<z8_t *>(ctx.procmod);
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_imm:
|
||||
ctx.out_symbol('#');
|
||||
ctx.out_value(x, OOFW_IMM);
|
||||
break;
|
||||
|
||||
case o_ind_reg:
|
||||
ctx.out_symbol('@');
|
||||
// fallthrough
|
||||
|
||||
case o_reg:
|
||||
out_reg(ctx, x.reg);
|
||||
break;
|
||||
|
||||
case o_phrase:
|
||||
ctx.out_keyword(phrases[x.phrase]);
|
||||
break;
|
||||
|
||||
case o_displ:
|
||||
ctx.out_value(x, OOF_ADDR | OOFW_16);
|
||||
ctx.out_symbol('(');
|
||||
out_reg(ctx, x.reg);
|
||||
ctx.out_symbol(')');
|
||||
break;
|
||||
|
||||
case o_ind_mem:
|
||||
ctx.out_symbol('@');
|
||||
// fallthrough
|
||||
|
||||
case o_mem:
|
||||
case o_near:
|
||||
v = pm.map_addr(ctx.insn, x.addr, x.n, x.type != o_near);
|
||||
if ( !ctx.out_name_expr(x, v, x.addr) )
|
||||
{
|
||||
const char *name = pm.find_ioport(v);
|
||||
if ( name != NULL )
|
||||
{
|
||||
ctx.out_line(name, COLOR_IMPNAME);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.out_value(x, OOF_ADDR | OOF_NUMBER | OOFS_NOSIGN | OOFW_16);
|
||||
remember_problem(PR_NONAME, ctx.insn.ea);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case o_void:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
warning("out: %a: bad optype %d", ctx.insn.ea, x.type);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void out_equ(outctx_t &ctx, const char *name, const char *equ, uchar off)
|
||||
{
|
||||
ctx.out_line(name, COLOR_DNAME);
|
||||
ctx.out_char(' ');
|
||||
ctx.out_line(equ, COLOR_KEYWORD);
|
||||
ctx.out_char(' ');
|
||||
ctx.out_tagon(COLOR_NUMBER);
|
||||
ctx.out_btoa(off);
|
||||
ctx.out_tagoff(COLOR_NUMBER);
|
||||
ctx.ctxflags |= CTXF_LABEL_OK;
|
||||
ctx.flush_outbuf(0x80000000);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void z8_t::z8_data(outctx_t &ctx, bool analyze_only)
|
||||
{
|
||||
ea_t ea = ctx.insn_ea;
|
||||
segment_t *s = getseg(ea);
|
||||
if ( s != NULL && s->type == SEG_IMEM )
|
||||
{
|
||||
qstring name;
|
||||
if ( get_visible_name(&name, ea) > 0 )
|
||||
out_equ(ctx, name.begin(), ash.a_equ, uint16(ea - get_segm_base(s)));
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.out_data(analyze_only);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//lint -esym(1764, ctx) could be made const
|
||||
void z8_t::z8_assumes(outctx_t &ctx)
|
||||
{
|
||||
ea_t ea = ctx.insn_ea;
|
||||
segment_t *seg = getseg(ea);
|
||||
if ( (inf_get_outflags() & OFLG_GEN_ASSUME) == 0 || seg == NULL )
|
||||
return;
|
||||
// always show at the start of code segments
|
||||
bool seg_started = (ea == seg->start_ea) && (seg->type == SEG_CODE);
|
||||
|
||||
sreg_range_t sra;
|
||||
if ( !get_sreg_range(&sra, ea, rRp) )
|
||||
return;
|
||||
bool show = sra.start_ea == ea;
|
||||
if ( show )
|
||||
{
|
||||
sreg_range_t prev_sra;
|
||||
if ( get_prev_sreg_range(&prev_sra, ea, rRp) )
|
||||
show = sra.val != prev_sra.val;
|
||||
}
|
||||
if ( seg_started || show )
|
||||
{
|
||||
sel_t rp = sra.val;
|
||||
if ( rp == BADSEL )
|
||||
rp = 0;
|
||||
char num[MAX_NUMBUF];
|
||||
btoa(num, sizeof(num), rp);
|
||||
char nbuf[MAXSTR];
|
||||
qsnprintf(nbuf, sizeof(nbuf), COLSTR(".rp %s", SCOLOR_ASMDIR), num);
|
||||
ctx.flush_buf(nbuf, DEFAULT_INDENT);
|
||||
}
|
||||
}
|
||||
460
idasdk76/module/z8/reg.cpp
Normal file
460
idasdk76/module/z8/reg.cpp
Normal file
@@ -0,0 +1,460 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Zilog Z8 module
|
||||
*
|
||||
*/
|
||||
|
||||
#include "z8.hpp"
|
||||
#include <diskio.hpp>
|
||||
int data_id;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char *const RegNames[] =
|
||||
{
|
||||
"R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
|
||||
"R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15",
|
||||
"RR0", "RR1", "RR2", "RR3", "RR4", "RR5", "RR6", "RR7",
|
||||
"RR8", "RR9", "RR10", "RR11", "RR12", "RR13", "RR14", "RR15",
|
||||
"cs", "ds", "rp",
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
typedef struct
|
||||
{
|
||||
int off;
|
||||
const char *name; //lint !e958 padding is required to align members
|
||||
const char *cmt;
|
||||
} entry_t;
|
||||
|
||||
static const entry_t entries[] =
|
||||
{
|
||||
{ 0, "irq0", "DAV0, IRQ0, Comparator" },
|
||||
{ 2, "irq1", "DAV1, IRQ1" },
|
||||
{ 4, "irq2", "DAV2, IRQ2, TIN, Comparator" },
|
||||
{ 6, "irq3", "IRQ3, Serial in" },
|
||||
{ 8, "irq4", "T0, Serial out" },
|
||||
{ 10, "irq5", "T1" },
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static ea_t AdditionalSegment(size_t size, size_t offset, const char *name, const char *sclass, uchar stype)
|
||||
{
|
||||
segment_t s;
|
||||
s.start_ea = free_chunk(0, size, -0xF);
|
||||
s.end_ea = s.start_ea + size;
|
||||
s.sel = allocate_selector((s.start_ea-offset) >> 4);
|
||||
s.type = stype;
|
||||
add_segm_ex(&s, name, sclass, ADDSEG_NOSREG|ADDSEG_OR_DIE);
|
||||
return s.start_ea - offset;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// special handling for areas
|
||||
bool z8_iohandler_t::area_processing(ea_t start, ea_t end, const char *name, const char *aclass)
|
||||
{
|
||||
if ( start >= end )
|
||||
{
|
||||
warning("Error in definition of segment %s %s", aclass, name);
|
||||
return false;
|
||||
}
|
||||
if ( strcmp(aclass, "CODE") == 0 )
|
||||
{
|
||||
AdditionalSegment(end-start, start, name, aclass, SEG_CODE);
|
||||
}
|
||||
else if ( strcmp(aclass, "DATA") == 0 )
|
||||
{
|
||||
uchar type = stristr(name, "FSR") != NULL ? SEG_IMEM : SEG_DATA;
|
||||
AdditionalSegment(end-start, start, name, aclass, type);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
const char *z8_t::find_ioport(uval_t port)
|
||||
{
|
||||
const ioport_t *p = ::find_ioport(ioh.ports, port);
|
||||
return p ? p->name.c_str() : NULL;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static ea_t specialSeg(sel_t sel, bool make_imem = true)
|
||||
{
|
||||
segment_t *s = get_segm_by_sel(sel);
|
||||
|
||||
if ( s != NULL )
|
||||
{
|
||||
if ( make_imem && s->type != SEG_IMEM )
|
||||
{
|
||||
s->type = SEG_IMEM;
|
||||
s->update();
|
||||
}
|
||||
return s->start_ea;
|
||||
}
|
||||
return BADADDR;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void z8_t::setup_data_segment_pointers(void)
|
||||
{
|
||||
sel_t sel;
|
||||
if ( atos(&sel, "INTMEM") || atos(&sel, "RAM") )
|
||||
intmem = specialSeg(sel);
|
||||
else
|
||||
intmem = BADADDR;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool z8_t::select_device(int resp_info)
|
||||
{
|
||||
char cfgfile[QMAXFILE];
|
||||
ioh.get_cfg_filename(cfgfile, sizeof(cfgfile));
|
||||
if ( !choose_ioport_device(&ioh.device, cfgfile) )
|
||||
{
|
||||
ioh.device = NONEPROC;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !ioh.display_infotype_dialog(IORESP_ALL, &resp_info, cfgfile) )
|
||||
return false;
|
||||
|
||||
ioh.set_device_name(ioh.device.c_str(), resp_info & ~IORESP_PORT);
|
||||
setup_data_segment_pointers();
|
||||
|
||||
if ( (resp_info & IORESP_PORT) != 0 )
|
||||
{
|
||||
if ( intmem == BADADDR )
|
||||
{
|
||||
AdditionalSegment(0x1000, 0, "INTMEM", NULL, SEG_IMEM);
|
||||
setup_data_segment_pointers();
|
||||
}
|
||||
for ( int i=0; i < ioh.ports.size(); i++ )
|
||||
{
|
||||
const ioport_t &p = ioh.ports[i];
|
||||
ea_t ea = p.address + intmem;
|
||||
ea_t oldea = get_name_ea(BADADDR, p.name.c_str());
|
||||
if ( oldea != ea )
|
||||
{
|
||||
if ( oldea != BADADDR )
|
||||
set_name(oldea, NULL);
|
||||
del_items(ea, DELIT_EXPAND);
|
||||
set_name(ea, p.name.c_str(), SN_NODUMMY);
|
||||
}
|
||||
if ( !p.cmt.empty() )
|
||||
set_cmt(ea, p.cmt.c_str(), true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
const char *z8_t::set_idp_options(
|
||||
const char *keyword,
|
||||
int /*value_type*/,
|
||||
const void * /*value*/,
|
||||
bool /*idb_loaded*/)
|
||||
{
|
||||
if ( keyword != NULL )
|
||||
return IDPOPT_BADKEY;
|
||||
select_device(IORESP_PORT|IORESP_INT);
|
||||
return IDPOPT_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void z8_t::load_from_idb()
|
||||
{
|
||||
ioh.restore_device();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// 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(SET_MODULE_DATA(z8_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ssize_t idaapi z8_t::on_event(ssize_t msgid, va_list va)
|
||||
{
|
||||
int code = 0;
|
||||
switch ( msgid )
|
||||
{
|
||||
case processor_t::ev_init:
|
||||
helper.create(PROCMOD_NODE_NAME);
|
||||
inf_set_be(true); // MSB first
|
||||
break;
|
||||
|
||||
case processor_t::ev_term:
|
||||
ioh.ports.clear();
|
||||
clr_module_data(data_id);
|
||||
break;
|
||||
|
||||
case processor_t::ev_newfile:
|
||||
{
|
||||
segment_t *sptr = get_first_seg();
|
||||
if ( sptr != NULL )
|
||||
{
|
||||
if ( sptr->start_ea - get_segm_base(sptr) == 0 )
|
||||
{
|
||||
inf_set_start_ea(sptr->start_ea + 0xC);
|
||||
inf_set_start_ip(0xC);
|
||||
if ( !inf_like_binary() )
|
||||
{
|
||||
// set default entries
|
||||
for ( int i = 0; i < qnumber(entries); i++ )
|
||||
{
|
||||
ea_t ea = sptr->start_ea + entries[i].off;
|
||||
if ( is_mapped(ea) )
|
||||
{
|
||||
create_word(ea, 2);
|
||||
op_plain_offset(ea, 0, sptr->start_ea);
|
||||
ea_t ea1 = sptr->start_ea + get_word(ea);
|
||||
auto_make_proc(ea1);
|
||||
set_name(ea, entries[i].name, SN_NODUMMY);
|
||||
set_cmt(sptr->start_ea+get_word(ea), entries[i].cmt, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
set_segm_class(sptr, "CODE");
|
||||
}
|
||||
|
||||
select_device(IORESP_ALL);
|
||||
|
||||
if ( intmem == BADADDR )
|
||||
{
|
||||
AdditionalSegment(0x1000, 0, "INTMEM", NULL, SEG_IMEM);
|
||||
setup_data_segment_pointers();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_oldfile:
|
||||
load_from_idb();
|
||||
setup_data_segment_pointers();
|
||||
break;
|
||||
|
||||
case processor_t::ev_creating_segm:
|
||||
{ // default DS is equal to CS
|
||||
segment_t *sptr = va_arg(va, segment_t *);
|
||||
sptr->defsr[rVds-ph.reg_first_sreg] = sptr->sel;
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_out_header:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
z8_header(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_footer:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
z8_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 *);
|
||||
z8_segstart(*ctx, seg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_segend:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
segment_t *seg = va_arg(va, segment_t *);
|
||||
z8_segend(*ctx, seg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_assumes:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
z8_assumes(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_ana_insn:
|
||||
{
|
||||
insn_t *out = va_arg(va, insn_t *);
|
||||
return z8_ana(out);
|
||||
}
|
||||
|
||||
case processor_t::ev_emu_insn:
|
||||
{
|
||||
const insn_t *insn = va_arg(va, const insn_t *);
|
||||
return z8_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);
|
||||
z8_data(*ctx, analyze_only);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_set_idp_options:
|
||||
{
|
||||
const char *keyword = va_arg(va, const char *);
|
||||
int value_type = va_arg(va, int);
|
||||
const char *value = va_arg(va, const char *);
|
||||
const char **errmsg = va_arg(va, const char **);
|
||||
bool idb_loaded = va_argi(va, bool);
|
||||
const char *ret = set_idp_options(keyword, value_type, value, idb_loaded);
|
||||
if ( ret == IDPOPT_OK )
|
||||
return 1;
|
||||
if ( errmsg != NULL )
|
||||
*errmsg = ret;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const asm_t Z8asm =
|
||||
{
|
||||
AS_COLON,
|
||||
0,
|
||||
"Zilog Z8 assembler",
|
||||
0,
|
||||
NULL,
|
||||
".org",
|
||||
".end",
|
||||
|
||||
";", // comment string
|
||||
'\'', // string delimiter
|
||||
'\0', // char delimiter (no char consts)
|
||||
"\\\"'", // special symbols in char and string constants
|
||||
|
||||
".ascii", // ascii string directive
|
||||
".byte", // byte directive
|
||||
".word", // 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(...)
|
||||
".block %s", // 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
|
||||
NULL, // not
|
||||
NULL, // shl
|
||||
NULL, // shr
|
||||
NULL, // sizeof
|
||||
};
|
||||
|
||||
static const asm_t *const asms[] = { &Z8asm, NULL };
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
#define FAMILY "Zilog Z8 series:"
|
||||
static const char *const shnames[] = { "Z8", NULL };
|
||||
static const char *const lnames[] = { FAMILY"Zilog Z8 MCU", NULL };
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
static const uchar retcode[] = { 0xAF }; // ret
|
||||
static const uchar iretcode[] = { 0xBF }; // iret
|
||||
|
||||
static const bytes_t retcodes[] =
|
||||
{
|
||||
{ sizeof(retcode), retcode },
|
||||
{ sizeof(iretcode), iretcode },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Processor Definition
|
||||
//-----------------------------------------------------------------------
|
||||
processor_t LPH =
|
||||
{
|
||||
IDP_INTERFACE_VERSION, // version
|
||||
PLFM_Z8, // id
|
||||
// flag
|
||||
PRN_HEX
|
||||
| PR_RNAMESOK // can use register names for byte names
|
||||
| PR_SEGTRANS // segment translation is supported (map_code_ea)
|
||||
| PR_BINMEM // The module creates RAM/ROM segments for binary files
|
||||
// (the kernel shouldn't ask the user about their sizes and addresses)
|
||||
| PR_SEGS // has segment registers?
|
||||
| PR_SGROTHER, // the segment registers don't contain
|
||||
// the segment selectors, something else
|
||||
// flag2
|
||||
PR2_IDP_OPTS, // the module has processor-specific configuration options
|
||||
8, // 8 bits in a byte for code segments
|
||||
8, // 8 bits in a byte for other segments
|
||||
|
||||
shnames, // short processor names (null term)
|
||||
lnames, // long processor names (null term)
|
||||
|
||||
asms, // array of enabled assemblers
|
||||
|
||||
notify, // Various messages:
|
||||
|
||||
RegNames, // Register names
|
||||
qnumber(RegNames), // Number of registers
|
||||
|
||||
rVcs,rRp,
|
||||
1, // size of a segment register
|
||||
rVcs,rVds,
|
||||
|
||||
NULL, // No known code start sequences
|
||||
retcodes,
|
||||
|
||||
0, Z8_last,
|
||||
Instructions, // instruc
|
||||
0, // int tbyte_size; -- doesn't exist
|
||||
{ 0, 0, 0, 0 }, // char real_width[4];
|
||||
// number of symbols after decimal point
|
||||
// 2byte float (0-does not exist)
|
||||
// normal float
|
||||
// normal double
|
||||
// long double
|
||||
Z8_ret, // Icode of return instruction. It is ok to give any of possible return instructions
|
||||
};
|
||||
145
idasdk76/module/z8/z8.cfg
Normal file
145
idasdk76/module/z8/z8.cfg
Normal file
@@ -0,0 +1,145 @@
|
||||
; The format of the input file:
|
||||
; each device definition begins with a line like this:
|
||||
;
|
||||
; .devicename
|
||||
;
|
||||
; after it go the port definitions in this format:
|
||||
;
|
||||
; portname address
|
||||
;
|
||||
; the bit definitions (optional) are represented like this:
|
||||
;
|
||||
; portname.bitname bitnumber
|
||||
;
|
||||
; lines beginning with a space are ignored.
|
||||
; comment lines should be started with ';' character.
|
||||
;
|
||||
; the default device is specified at the start of the file
|
||||
;
|
||||
; .default device_name
|
||||
;
|
||||
; all lines non conforming to the format are passed to the callback function
|
||||
;
|
||||
; the processor definition may include the memory configuration.
|
||||
; the line format is:
|
||||
;
|
||||
; area CLASS AREA-NAME START:END
|
||||
;
|
||||
; where CLASS is anything, but please use one of CODE, DATA, BSS
|
||||
; START and END are addresses, the end address is not included
|
||||
|
||||
; Interrupt vectors are declared in the following way:
|
||||
|
||||
; interrupt NAME ADDRESS COMMENT
|
||||
|
||||
.default Z8
|
||||
|
||||
.Z8
|
||||
; http://www.zilog.com/docs/um0016.pdf
|
||||
; Z8 CPU User Manual
|
||||
|
||||
; MEMORY MAP
|
||||
area CODE code 0x0000:0x10000 ; code segment: up to 64K
|
||||
area DATA INTMEM 0x0000:0x01000 ; internal RAM/registers
|
||||
area DATA EXTMEM 0x0000:0x10000 ; external data: up to 64K
|
||||
|
||||
; Interrupt and reset vector assignments
|
||||
interrupt irq0 0x0 DAV0, IRQ0, Comparator
|
||||
interrupt irq1 0x2 DAV1, IRQ1
|
||||
interrupt irq2 0x4 DAV2, IRQ2, TIN, Comparator
|
||||
interrupt irq3 0x6 IRQ3, Serial in
|
||||
interrupt irq4 0x8 T0, Serial out
|
||||
interrupt irq5 0xA T1
|
||||
entry RESET 0xC Reset
|
||||
|
||||
; Registers
|
||||
; use the third nibble for the Expanded Register File (ERF) banks, e.g. 0xF0F for ERF F, register 0F
|
||||
p0 0x00 Port 0
|
||||
p1 0x01 Port 1
|
||||
p2 0x02 Port 2
|
||||
p3 0x03 Port 3
|
||||
sio 0xF0 Serial I/O
|
||||
tmr 0xF1 Timer mode
|
||||
t1 0xF2 Timer/counter 1
|
||||
pre1 0xF3 T1 prescaler
|
||||
t0 0xF4 Timer/counter 0
|
||||
pre0 0xF5 T0 prescaler
|
||||
p2m 0xF6 Port 2 mode register
|
||||
p3m 0xF7 Port 3 mode register
|
||||
p01m 0xF8 Ports 0-1 mode register
|
||||
ipr 0xF9 Interrupt priority register
|
||||
irq 0xFA Interrupt request register
|
||||
imr 0xFB Interrupt mask register
|
||||
flags 0xFC Program control flags
|
||||
rp 0xFD Register pointer
|
||||
sph 0xFE Stack pointer high byte
|
||||
spl 0xFF Stack pointer low byte
|
||||
|
||||
;Expanded Register Group F
|
||||
wdtmr 0xF0F Watch Dog Timer
|
||||
smr 0xF0B Stop Mode Recovery
|
||||
pcon 0xF00 PCON Register
|
||||
|
||||
;Expanded Register Group C
|
||||
scon 0xC02 SPI Control
|
||||
rxbuf 0xC01 SPI Tx/Rx Data
|
||||
scomp 0xC00 SPI Compare
|
||||
|
||||
.Z86C93
|
||||
; http://www.zilog.com/docs/z8/dc2508.pdf
|
||||
; Z86C93 Product Specification
|
||||
|
||||
; MEMORY MAP
|
||||
area CODE code 0x0000:0x10000 ; code segment: up to 64K
|
||||
area DATA INTMEM 0x0000:0x01000 ; internal RAM/registers
|
||||
area DATA EXTMEM 0x0000:0x10000 ; external data: up to 64K
|
||||
|
||||
; Interrupt and reset vector assignments
|
||||
interrupt irq0 0x0 DAV0, P32, T2
|
||||
interrupt irq1 0x2 P33
|
||||
interrupt irq2 0x4 DAV2, P31, TIN
|
||||
interrupt irq3 0x6 P30, Serial in
|
||||
interrupt irq4 0x8 T0, Serial out
|
||||
interrupt irq5 0xA T1
|
||||
entry RESET 0xC Reset
|
||||
|
||||
; Registers
|
||||
; use the third nibble for the Expanded Register File (ERF) banks, e.g. 0xF0F for ERF F, register 0F
|
||||
p0 0x00 Port 0
|
||||
p2 0x02 Port 2
|
||||
p3 0x03 Port 3
|
||||
sio 0xF0 Serial I/O
|
||||
tmr 0xF1 Timer mode
|
||||
t1 0xF2 Timer/counter 1
|
||||
pre1 0xF3 T1 prescaler
|
||||
t0 0xF4 Timer/counter 0
|
||||
pre0 0xF5 T0 prescaler
|
||||
p2m 0xF6 Port 2 mode register
|
||||
p3m 0xF7 Port 3 mode register
|
||||
p01m 0xF8 Ports 0-1 mode register
|
||||
ipr 0xF9 Interrupt priority register
|
||||
irq 0xFA Interrupt request register
|
||||
imr 0xFB Interrupt mask register
|
||||
flags 0xFC Program control flags
|
||||
rp 0xFD Register pointer
|
||||
sph 0xFE Stack pointer high byte
|
||||
spl 0xFF Stack pointer low byte
|
||||
|
||||
;Expanded Register Group E
|
||||
mreg0 0xE00 Multiply/Divide unit
|
||||
mreg1 0xE01 Multiply/Divide unit
|
||||
mreg2 0xE02 Multiply/Divide unit
|
||||
mreg3 0xE03 Multiply/Divide unit
|
||||
mreg4 0xE04 Multiply/Divide unit
|
||||
mreg5 0xE05 Multiply/Divide unit
|
||||
mdcon 0xE06 Multiply/Divide control register
|
||||
|
||||
;Expanded Register Group D
|
||||
t2tmr 0xD01 T2 timer mode register
|
||||
t1h 0xD02 Timer/counter 1 high byte
|
||||
t2pre 0xD03 T2 prescaler register
|
||||
t0h 0xD04 Timer/counter 0 high byte
|
||||
t2h 0xD06 Timer/counter 2 high byte
|
||||
t2l 0xD07 Timer/counter 2 low byte
|
||||
t2caph 0xD08
|
||||
t2capl 0xD09
|
||||
123
idasdk76/module/z8/z8.hpp
Normal file
123
idasdk76/module/z8/z8.hpp
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* .org
|
||||
* .word
|
||||
.equ
|
||||
* .end
|
||||
* .ascii
|
||||
* .byte
|
||||
* .block
|
||||
|
||||
*+ IM o_imm 12h
|
||||
* Ir o_ind_reg @R1
|
||||
* r o_reg R1
|
||||
* Irr o_ind_reg @RR1
|
||||
* RR o_reg RR1
|
||||
* cond o_phrase
|
||||
*+ IRR o_ind_mem @INTMEM_12
|
||||
*+ IR o_ind_mem @INTMEM_12
|
||||
*+ DA/RA o_near loc_1234
|
||||
*+ R o_mem INTMEM_12
|
||||
*+ X o_displ INTMEM_12(R1)
|
||||
|
||||
*
|
||||
* Interactive disassembler (IDA).
|
||||
* Zilog Z8 module
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _Z8_HPP
|
||||
#define _Z8_HPP
|
||||
|
||||
#include "../idaidp.hpp"
|
||||
#include "ins.hpp"
|
||||
#include <segregs.hpp>
|
||||
#include <diskio.hpp>
|
||||
#include "../iohandler.hpp"
|
||||
|
||||
#define PROCMOD_NAME z8
|
||||
#define PROCMOD_NODE_NAME "$ Zilog Z8"
|
||||
|
||||
//------------------------------------------------------------------
|
||||
struct z8_iohandler_t : public iohandler_t
|
||||
{
|
||||
z8_iohandler_t(netnode &nn) : iohandler_t(nn) {}
|
||||
virtual bool area_processing(ea_t start, ea_t end, const char *name, const char *aclass) override;
|
||||
};
|
||||
|
||||
struct z8_t : public procmod_t
|
||||
{
|
||||
netnode helper;
|
||||
z8_iohandler_t ioh = z8_iohandler_t(helper);
|
||||
ea_t intmem = BADADDR; // linear EA of the internal memory/registers segment
|
||||
bool flow = false;
|
||||
|
||||
virtual ssize_t idaapi on_event(ssize_t msgid, va_list va) override;
|
||||
|
||||
const char *find_ioport(uval_t port);
|
||||
void setup_data_segment_pointers(void);
|
||||
bool select_device(int resp_info);
|
||||
const char *idaapi set_idp_options(
|
||||
const char *keyword,
|
||||
int /*value_type*/,
|
||||
const void * /*value*/,
|
||||
bool /*idb_loaded*/);
|
||||
void load_from_idb();
|
||||
|
||||
// ana.cpp
|
||||
int z8_ana(insn_t *insn);
|
||||
|
||||
// emu.cpp
|
||||
int z8_emu(const insn_t &insn);
|
||||
void handle_operand(const insn_t &insn, const op_t &x, bool isload);
|
||||
ea_t map_addr(const insn_t &insn, asize_t off, int opnum, bool isdata) const;
|
||||
|
||||
// out.cpp
|
||||
void out_reg(outctx_t &ctx, int rgnum);
|
||||
bool out_opnd(outctx_t &ctx, const op_t &x);
|
||||
void z8_header(outctx_t &ctx);
|
||||
void z8_footer(outctx_t &ctx);
|
||||
void z8_segstart(outctx_t &ctx, segment_t *seg);
|
||||
void z8_segend(outctx_t &ctx, segment_t *seg);
|
||||
void z8_data(outctx_t &ctx, bool analyze_only);
|
||||
void z8_assumes(outctx_t &ctx);
|
||||
};
|
||||
extern int data_id;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// customization of insn_t structure:
|
||||
|
||||
#define o_ind_mem o_idpspec0 // @intmem
|
||||
#define o_ind_reg o_idpspec1 // @Rx
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
enum z8_registers
|
||||
{
|
||||
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,
|
||||
rVcs, rVds, rRp,
|
||||
};
|
||||
|
||||
enum z8_phrases
|
||||
{
|
||||
fF, fLT, fLE, fULE, fOV, fMI, fZ, fC,
|
||||
fTrue, fGE, fGT, fUGT, fNOV, fPL, fNZ, fNC
|
||||
};
|
||||
|
||||
struct predefined_t
|
||||
{
|
||||
uchar addr;
|
||||
const char *name;
|
||||
const char *cmt;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline uint16 get_rp(ea_t ea)
|
||||
{
|
||||
sel_t t = get_sreg(ea, rRp);
|
||||
return t != BADSEL ? t : 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user