/* * Interactive disassembler (IDA). * Intel 80196 module * */ #include "i196.hpp" //-------------------------------------------------------------------------- static const predefined_t iregs[] = { { 0x00, "ZERO_REG", "Zero register" }, { 0x08, "INT_MASK", "Interrupt mask register" }, { 0x09, "INT_PEND", "Interrupt pending register" }, { 0x0F, "IOPORT1", "Input/output port 1" }, { 0x10, "IOPORT2", "Input/output port 2" }, { 0x12, "INT_PEND1", "Interrupt pending register 1" }, { 0x13, "INT_MASK1", "Interrupt mask register 1" }, { 0x14, "WSR", "Window selection register" }, { 0x15, "WSR1", "Window selection register 1" }, { 0x18, "SP", "Stack pointer" }, { 0x00, NULL, NULL } }; //-------------------------------------------------------------------------- /* 80196 memory map * * 0000-03FF - register file * 0000 - CPU SFRs * 0018 - SP (LO) * 0019 - SP (HI) * 001A - Register RAM * 0100 - Register RAM (upper file) * 0400-1FFD - ext memory * 1FFE - port 3 (word) * 1FFF - port 4 (word) * 2000-207F - special purpose memory * 2000 - lower int vectors * 2000 - INT00 - Timer overflow * 2002 - INT01 - A/D conversion complete * 2004 - INT02 - HSI data available * 2006 - INT03 - High speed output * 2008 - INT04 - HSI.0 * 200A - INT05 - Software timer * 200C - INT06 - Serial port * 200E - INT07 - EXTINT * 2010 - Software trap * 2012 - Unimplemented opcode * 2014 - reserved (FF) * 2018 - CCB * D0 - PD - Power down * D1 - BW0 - Bus width control * D2 - WR - Write strobe mode * D3 - ALE - Addres valid strobe mode * D45 - IRC - Internal ready control * D67 - LOC - Lock bits * 2019 - reserved (20) * 201A - reserved (FF) * 2020 - security key * 2030 - upper int vectors * 2030 - INT08 - Transmit * 2032 - INT09 - Receive * 2034 - INT10 - HSI FIFO 4 * 2036 - INT11 - Timer 2 capture * 2038 - INT12 - Timer 2 overflow * 203A - INT13 - EXTINT1 * 203C - INT14 - HSI FIFO FULL * 203E - INT15 - NMI * 2040 - PTS vectors * 2040 - INT00 - Timer overflow * 2042 - INT01 - A/D conversion complete * 2044 - INT02 - HSI data available * 2046 - INT03 - High speed output * 2048 - INT04 - HSI.0 * 204A - INT05 - Software timer * 204C - INT06 - Serial port * 204E - INT07 - EXTINT * 2050 - INT08 - Transmit * 2052 - INT09 - Receive * 2054 - INT10 - HSI FIFO 4 * 2056 - INT11 - Timer 2 capture * 2058 - INT12 - Timer 2 overflow * 205A - INT13 - EXTINT1 * 205C - INT14 - HSI FIFO FULL * 205E - reserved (FF) * 2080-FFFF - program/ext memory */ #define I196F_CMT 0 // global comment #define I196F_OFF 1 // offset to code #define I196F_BTS 2 // byte(s) struct entry_t { char type; int off; //lint !e958 padding is required to align members const char *name; const char *cmt; }; static const char cmt01[] = "Timer overflow"; static const char cmt02[] = "A/D conversion complete"; static const char cmt03[] = "HSI data available"; static const char cmt04[] = "High speed output"; static const char cmt05[] = "HSI.0"; static const char cmt06[] = "Software timer"; static const char cmt07[] = "Serial port"; static const char cmt08[] = "EXTINT"; static const char cmt09[] = "reserved (FF)"; static const char cmt10[] = "Transmit"; static const char cmt11[] = "Receive"; static const char cmt12[] = "HSI FIFO 4"; static const char cmt13[] = "Timer 2 capture"; static const char cmt14[] = "Timer 2 overflow"; static const char cmt15[] = "EXTINT1"; static const char cmt16[] = "HSI FIFO FULL"; static entry_t const entries[] = { // // { I196F_CMT, 0x2000, 0, "\nlower int vectors\n" }, { I196F_OFF, 0x2000, "Int00", cmt01 }, { I196F_OFF, 0x2002, "Int01", cmt02 }, { I196F_OFF, 0x2004, "Int02", cmt03 }, { I196F_OFF, 0x2006, "Int03", cmt04 }, { I196F_OFF, 0x2008, "Int04", cmt05 }, { I196F_OFF, 0x200A, "Int05", cmt06 }, { I196F_OFF, 0x200C, "Int06", cmt07 }, { I196F_OFF, 0x200E, "Int07", cmt08 }, { I196F_OFF, 0x2010, "Trap", "Software trap" }, { I196F_OFF, 0x2012, "NoOpCode", "Unimplemented opcode" }, { I196F_CMT, 0x2014, 0, 0 }, // empty line { I196F_BTS, 0x2014, 0, cmt09 }, { I196F_BTS, 0x2018, "CCB", "D0 - PD - Power down\n" "D1 - BW0 - Bus width control\n" "D2 - WR - Write strobe mode\n" "D3 - ALE - Addres valid strobe mode\n" "D45 - IRC - Internal ready control\n" "D67 - LOC - Lock bits" }, { I196F_BTS, 0x2019, 0, "reserved (20)" }, { I196F_BTS, 0x201A, 0, cmt09 }, { I196F_BTS, 0x2020, 0, "security key" }, { I196F_CMT, 0x2030, 0, "\nupper int vectors\n" }, { I196F_OFF, 0x2030, "Int08", cmt10 }, { I196F_OFF, 0x2032, "Int09", cmt11 }, { I196F_OFF, 0x2034, "Int10", cmt12 }, { I196F_OFF, 0x2036, "Int11", cmt13 }, { I196F_OFF, 0x2038, "Int12", cmt14 }, { I196F_OFF, 0x203A, "Int13", cmt15 }, { I196F_OFF, 0x203C, "Int14", cmt16 }, { I196F_OFF, 0x203E, "Int15", "NMI" }, { I196F_CMT, 0x2040, 0, "\nPTS vectors\n" }, { I196F_OFF, 0x2040, "PTS_Int00", cmt01 }, { I196F_OFF, 0x2042, "PTS_Int01", cmt02 }, { I196F_OFF, 0x2044, "PTS_Int02", cmt03 }, { I196F_OFF, 0x2046, "PTS_Int03", cmt04 }, { I196F_OFF, 0x2048, "PTS_Int04", cmt05 }, { I196F_OFF, 0x204A, "PTS_Int05", cmt06 }, { I196F_OFF, 0x204C, "PTS_Int06", cmt07 }, { I196F_OFF, 0x204E, "PTS_Int07", cmt08 }, { I196F_OFF, 0x2050, "PTS_Int08", cmt10 }, { I196F_OFF, 0x2052, "PTS_Int09", cmt11 }, { I196F_OFF, 0x2054, "PTS_Int10", cmt12 }, { I196F_OFF, 0x2056, "PTS_Int11", cmt13 }, { I196F_OFF, 0x2058, "PTS_Int12", cmt14 }, { I196F_OFF, 0x205A, "PTS_Int13", cmt15 }, { I196F_OFF, 0x205C, "PTS_Int14", cmt16 }, { I196F_CMT, 0x205E, 0, 0 }, { I196F_BTS, 0x205E, 0, cmt09 }, // { I196F_CMT, 0x2080, 0, "\nProgram entry point\n" }, { I196F_CMT, 0x2080, 0, 0 } }; //-------------------------------------------------------------------------- static const char *const RegNames[] = { "cs", "ds", "WSR", "WSR1" }; //------------------------------------------------------------------------ static bool idaapi can_have_type(const op_t &x) // returns 1 - operand can have { switch ( x.type ) { case o_void: case o_reg: case o_indirect: case o_indirect_inc: case o_bit: case o_mem: case o_near: return 0; // case o_phrase: can have type because of ASI or 0 struct offsets } return 1; } //---------------------------------------------------------------------- // This old-style callback only returns the processor module object. static ssize_t idaapi notify(void *, int msgid, va_list) { if ( msgid == processor_t::ev_get_procmod ) return size_t(new i196_t); return 0; } //-------------------------------------------------------------------------- ssize_t idaapi i196_t::on_event(ssize_t msgid, va_list va) { switch ( msgid ) { case processor_t::ev_newfile: { // if necessary, add to ida.cfg: // #ifdef __80196__ // DUMMY_NAMES_TYPE = NM_SHORT // #endif segment_t *sptr = get_first_seg(); if ( sptr != NULL ) set_segm_class(sptr, "CODE"); ea_t ea, ea1; for ( int i = 0; i < qnumber(entries); i++ ) { ea = to_ea(inf_get_baseaddr(), entries[i].off); if ( is_mapped(ea) ) { switch ( entries[i].type ) { case I196F_BTS: if ( i < qnumber(entries)-1 ) { create_byte(ea, entries[i+1].off-entries[i].off); set_cmt(ea, entries[i].cmt, 0); } break; case I196F_CMT: if ( entries[i].cmt != NULL ) add_extra_cmt(ea, true, "%s", entries[i].cmt); else add_extra_line(ea, true, ""); break; case I196F_OFF: create_word(ea, 2); op_plain_offset(ea, 0, to_ea(inf_get_baseaddr(), 0)); ea1 = to_ea(inf_get_baseaddr(), get_word(ea)); auto_make_proc(ea1); // add a simple comment // after function is created, it will be converted // to function comment set_cmt(ea1, entries[i].cmt, 1); } set_name(ea, entries[i].name, SN_NODUMMY); } } ea = to_ea(inf_get_baseaddr(), 0x2080); if ( is_mapped(ea) ) { inf_set_start_ea(ea); inf_set_start_ip(0x2080); } segment_t s; s.start_ea = to_ea(inf_get_baseaddr(), 0); s.end_ea = to_ea(inf_get_baseaddr(), 0x400); s.sel = inf_get_baseaddr(); s.type = SEG_IMEM; // internal memory add_segm_ex(&s, "INTMEM", NULL, ADDSEG_OR_DIE); const predefined_t *ptr; for ( ptr = iregs; ptr->name != NULL; ptr++ ) { ea = to_ea(inf_get_baseaddr(), ptr->addr); ea_t oldea = get_name_ea(BADADDR, ptr->name); if ( oldea != ea ) { if ( oldea != BADADDR ) set_name(oldea, NULL); del_items(ea, DELIT_EXPAND); set_name(ea, ptr->name, SN_NODUMMY); } if ( ptr->cmt != NULL ) set_cmt(ea, ptr->cmt, 1); } } // create_16bit_data(0x18, 2); // SP always word break; case processor_t::ev_creating_segm: // default DS is equal to Base Address { segment_t *sg = va_arg(va, segment_t *); sg->defsr[rVds-ph.reg_first_sreg] = inf_get_baseaddr(); } break; case processor_t::ev_ending_undo: // restore ptype extended = ph.get_proc_index(); goto SETFLAG; case processor_t::ev_newprc: extended = va_arg(va,int) != 0; SETFLAG: if ( !extended ) ph.flag &= ~PR_SEGS; else ph.flag |= PR_SEGS; break; case processor_t::ev_out_header: { outctx_t *ctx = va_arg(va, outctx_t *); i196_header(*ctx); return 1; } case processor_t::ev_out_footer: { outctx_t *ctx = va_arg(va, outctx_t *); i196_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 *); i196_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 *); i196_segend(*ctx, seg); return 1; } case processor_t::ev_ana_insn: { insn_t *out = va_arg(va, insn_t *); return ana(out); } case processor_t::ev_emu_insn: { const insn_t *insn = va_arg(va, const insn_t *); return emu(*insn) ? 1 : -1; } case processor_t::ev_out_insn: { outctx_t *ctx = va_arg(va, outctx_t *); out_insn(*ctx); return 1; } case processor_t::ev_out_operand: { outctx_t *ctx = va_arg(va, outctx_t *); const op_t *op = va_arg(va, const op_t *); return out_opnd(*ctx, *op) ? 1 : -1; } case processor_t::ev_can_have_type: { const op_t *op = va_arg(va, const op_t *); return can_have_type(*op) ? 1 : -1; } default: break; } return 0; } //-------------------------------------------------------------------------- // Could not find a standard assembler for this CPU :( static const asm_t unkasm = { AS_COLON | ASH_HEXF0, 0, "Abstract Assembler", 0, NULL, "org", "end", ";", // comment string '\'', // string delimiter '\0', // char delimiter (no char consts) "\\\"'", // special symbols in char and string constants "db", // ascii string directive "db", // byte directive "dw", // word directive "dd", // 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(...) "ds %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 "and", // and "or", // or NULL, // xor "not", // not NULL, // shl NULL, // shr "SIZE", // sizeof }; static const asm_t *const asms[] = { &unkasm, NULL }; //-------------------------------------------------------------------------- #define FAMILY "Intel 196 series:" static const char *const shnames[] = { "80196", "80196NP", NULL }; static const char *const lnames[] = { FAMILY"Intel 80196", "Intel 80196NP", NULL }; //-------------------------------------------------------------------------- static const uchar retcode[] = { 0xF0 }; // ret static const bytes_t retcodes[] = { { sizeof(retcode), retcode }, { 0, NULL } }; //----------------------------------------------------------------------- // Processor Definition //----------------------------------------------------------------------- processor_t LPH = { IDP_INTERFACE_VERSION, // version PLFM_80196, // id // flag PRN_HEX | PR_USE32 | PR_SEGS | PR_BINMEM | PR_RNAMESOK, // flag2 0, 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,WSR1, 2, // size of a segment register rVcs,rVds, NULL, // No known code start sequences retcodes, 0, I196_last, Instructions, // instruc };