1238 lines
25 KiB
C++
1238 lines
25 KiB
C++
|
|
#include "st9.hpp"
|
|
|
|
#include <segregs.hpp>
|
|
int data_id;
|
|
|
|
const char *const ConditionCodes[] =
|
|
{
|
|
"UNKNOWN",
|
|
"f", // always false
|
|
"t", // always true
|
|
"c", // carry
|
|
"nc", // not carry
|
|
"z", // zero
|
|
"nz", // not zero
|
|
"pl", // plus
|
|
"mi", // minus
|
|
"ov", // overflow
|
|
"nov", // no overflow
|
|
"eq", // equal
|
|
"ne", // not equal
|
|
"ge", // greater than or equal
|
|
"lt", // less than
|
|
"gt", // greater than
|
|
"le", // less than or equal
|
|
"uge", // unsigned greated than or equal
|
|
"ul", // unsigned less than
|
|
"ugt", // unsigned greater than
|
|
"ule" // unsigned less than or equal
|
|
};
|
|
|
|
// ST9 registers names
|
|
static const char *const src_RegNames[] =
|
|
{
|
|
"R0",
|
|
"R1",
|
|
"R2",
|
|
"R3",
|
|
"R4",
|
|
"R5",
|
|
"R6",
|
|
"R7",
|
|
"R8",
|
|
"R9",
|
|
"R10",
|
|
"R11",
|
|
"R12",
|
|
"R13",
|
|
"R14",
|
|
"R15",
|
|
"R16",
|
|
"R17",
|
|
"R18",
|
|
"R19",
|
|
"R20",
|
|
"R21",
|
|
"R22",
|
|
"R23",
|
|
"R24",
|
|
"R25",
|
|
"R26",
|
|
"R27",
|
|
"R28",
|
|
"R29",
|
|
"R30",
|
|
"R31",
|
|
"R32",
|
|
"R33",
|
|
"R34",
|
|
"R35",
|
|
"R36",
|
|
"R37",
|
|
"R38",
|
|
"R39",
|
|
"R40",
|
|
"R41",
|
|
"R42",
|
|
"R43",
|
|
"R44",
|
|
"R45",
|
|
"R46",
|
|
"R47",
|
|
"R48",
|
|
"R49",
|
|
"R50",
|
|
"R51",
|
|
"R52",
|
|
"R53",
|
|
"R54",
|
|
"R55",
|
|
"R56",
|
|
"R57",
|
|
"R58",
|
|
"R59",
|
|
"R60",
|
|
"R61",
|
|
"R62",
|
|
"R63",
|
|
"R64",
|
|
"R65",
|
|
"R66",
|
|
"R67",
|
|
"R68",
|
|
"R69",
|
|
"R70",
|
|
"R71",
|
|
"R72",
|
|
"R73",
|
|
"R74",
|
|
"R75",
|
|
"R76",
|
|
"R77",
|
|
"R78",
|
|
"R79",
|
|
"R80",
|
|
"R81",
|
|
"R82",
|
|
"R83",
|
|
"R84",
|
|
"R85",
|
|
"R86",
|
|
"R87",
|
|
"R88",
|
|
"R89",
|
|
"R90",
|
|
"R91",
|
|
"R92",
|
|
"R93",
|
|
"R94",
|
|
"R95",
|
|
"R96",
|
|
"R97",
|
|
"R98",
|
|
"R99",
|
|
"R100",
|
|
"R101",
|
|
"R102",
|
|
"R103",
|
|
"R104",
|
|
"R105",
|
|
"R106",
|
|
"R107",
|
|
"R108",
|
|
"R109",
|
|
"R110",
|
|
"R111",
|
|
"R112",
|
|
"R113",
|
|
"R114",
|
|
"R115",
|
|
"R116",
|
|
"R117",
|
|
"R118",
|
|
"R119",
|
|
"R120",
|
|
"R121",
|
|
"R122",
|
|
"R123",
|
|
"R124",
|
|
"R125",
|
|
"R126",
|
|
"R127",
|
|
"R128",
|
|
"R129",
|
|
"R130",
|
|
"R131",
|
|
"R132",
|
|
"R133",
|
|
"R134",
|
|
"R135",
|
|
"R136",
|
|
"R137",
|
|
"R138",
|
|
"R139",
|
|
"R140",
|
|
"R141",
|
|
"R142",
|
|
"R143",
|
|
"R144",
|
|
"R145",
|
|
"R146",
|
|
"R147",
|
|
"R148",
|
|
"R149",
|
|
"R150",
|
|
"R151",
|
|
"R152",
|
|
"R153",
|
|
"R154",
|
|
"R155",
|
|
"R156",
|
|
"R157",
|
|
"R158",
|
|
"R159",
|
|
"R160",
|
|
"R161",
|
|
"R162",
|
|
"R163",
|
|
"R164",
|
|
"R165",
|
|
"R166",
|
|
"R167",
|
|
"R168",
|
|
"R169",
|
|
"R170",
|
|
"R171",
|
|
"R172",
|
|
"R173",
|
|
"R174",
|
|
"R175",
|
|
"R176",
|
|
"R177",
|
|
"R178",
|
|
"R179",
|
|
"R180",
|
|
"R181",
|
|
"R182",
|
|
"R183",
|
|
"R184",
|
|
"R185",
|
|
"R186",
|
|
"R187",
|
|
"R188",
|
|
"R189",
|
|
"R190",
|
|
"R191",
|
|
"R192",
|
|
"R193",
|
|
"R194",
|
|
"R195",
|
|
"R196",
|
|
"R197",
|
|
"R198",
|
|
"R199",
|
|
"R200",
|
|
"R201",
|
|
"R202",
|
|
"R203",
|
|
"R204",
|
|
"R205",
|
|
"R206",
|
|
"R207",
|
|
"R208",
|
|
"R209",
|
|
"R210",
|
|
"R211",
|
|
"R212",
|
|
"R213",
|
|
"R214",
|
|
"R215",
|
|
"R216",
|
|
"R217",
|
|
"R218",
|
|
"R219",
|
|
"R220",
|
|
"R221",
|
|
"R222",
|
|
"R223",
|
|
"R224",
|
|
"R225",
|
|
"R226",
|
|
"R227",
|
|
"R228",
|
|
"R229",
|
|
"R230",
|
|
"R231",
|
|
"R232",
|
|
"R233",
|
|
"R234",
|
|
"R235",
|
|
"R236",
|
|
"R237",
|
|
"R238",
|
|
"R239",
|
|
"R240",
|
|
"R241",
|
|
"R242",
|
|
"R243",
|
|
"R244",
|
|
"R245",
|
|
"R246",
|
|
"R247",
|
|
"R248",
|
|
"R249",
|
|
"R250",
|
|
"R251",
|
|
"R252",
|
|
"R253",
|
|
"R254",
|
|
"R255",
|
|
"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",
|
|
"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",
|
|
"RW",
|
|
"RP",
|
|
"csr",
|
|
"dpr0", "dpr1", "dpr2", "dpr3",
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
// returns a pointer to a ioport_t object if address was found in the config file.
|
|
// otherwise, returns NULL.
|
|
const ioport_t *st9_t::find_sym(ea_t address)
|
|
{
|
|
return find_ioport(ioh.ports, address);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void st9_t::patch_general_registers()
|
|
{
|
|
char b[15];
|
|
b[0] = '\0';
|
|
|
|
ushort style = idpflags & IDP_GR_DEC ? 0
|
|
: idpflags & IDP_GR_HEX ? 1
|
|
: idpflags & IDP_GR_BIN ? 2
|
|
: 3;
|
|
|
|
QASSERT(10079, style != 3);
|
|
|
|
msg("General register print style: %s\n",
|
|
style == 0 ? "decimal"
|
|
: style == 1 ? "hexadecimal"
|
|
: "binary");
|
|
|
|
CASSERT(sizeof(RegNames) == sizeof(src_RegNames));
|
|
memcpy(RegNames, src_RegNames, sizeof(src_RegNames));
|
|
dynamic_rgnames.resize(rR255 - rR1 + 1);
|
|
for ( int i = rR1; i <= rR255; i++ )
|
|
{
|
|
switch ( style )
|
|
{
|
|
// decimal
|
|
case 0:
|
|
qsnprintf(b, sizeof b, "R%d", i);
|
|
break;
|
|
|
|
// hexadecimal
|
|
case 1:
|
|
qsnprintf(b, sizeof b, "R0x%X", i);
|
|
break;
|
|
|
|
// binary
|
|
case 2:
|
|
{
|
|
static const int bits[] = { 128, 64, 32, 16, 8, 4, 2, 1 };
|
|
b[0] = 'R';
|
|
for ( int k = 0; k < 8; k++ )
|
|
b[k + 1] = (i & bits[k]) ? '1' : '0';
|
|
b[9] = 'b';
|
|
b[10] = '\0';
|
|
}
|
|
break;
|
|
}
|
|
dynamic_rgnames[i-rR1] = b;
|
|
RegNames[i] = dynamic_rgnames[i-rR1].begin();
|
|
}
|
|
ph.reg_names = RegNames;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// read all procmod data from the idb
|
|
void st9_t::load_from_idb()
|
|
{
|
|
idpflags = (uint32)helper.altval(-1);
|
|
ioh.restore_device();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
const char *st9_t::set_idp_options(
|
|
const char *keyword,
|
|
int /*value_type*/,
|
|
const void * /*value*/,
|
|
bool idb_loaded)
|
|
{
|
|
if ( keyword != NULL )
|
|
return IDPOPT_BADKEY;
|
|
|
|
static const char form[] =
|
|
"HELP\n"
|
|
"ST9 Related options :\n"
|
|
"\n"
|
|
" General registers print style\n"
|
|
"\n"
|
|
" Select the format which will be used by IDA to\n"
|
|
" to print general registers.\n"
|
|
"\n"
|
|
" For example,\n"
|
|
"\n"
|
|
" R10 (decimal) \n"
|
|
" R0x0A (hexadecimal) \n"
|
|
" R00001010b (binary) \n"
|
|
"\n"
|
|
"ENDHELP\n"
|
|
"ST9 related options\n"
|
|
"<##General registers print style##~D~ecimal (default):R>\n"
|
|
"<~H~exadecimal:R>\n"
|
|
"<~B~inary:R>>\n";
|
|
|
|
CASSERT(sizeof(print_style) == sizeof(ushort));
|
|
if ( ask_form(form, &print_style) )
|
|
{
|
|
idpflags = 0;
|
|
switch ( print_style )
|
|
{
|
|
case 0: idpflags |= IDP_GR_DEC; break;
|
|
case 1: idpflags |= IDP_GR_HEX; break;
|
|
case 2: idpflags |= IDP_GR_BIN; break;
|
|
}
|
|
if ( idpflags )
|
|
patch_general_registers();
|
|
}
|
|
if ( idb_loaded )
|
|
save_idpflags();
|
|
return IDPOPT_OK;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// get reference data from ri,
|
|
// check compliance of opval and the full value
|
|
static bool idaapi dpr_calc_reference_data(
|
|
ea_t *target,
|
|
ea_t *base,
|
|
ea_t from,
|
|
const refinfo_t &ri,
|
|
adiff_t opval)
|
|
{
|
|
if ( ri.base == BADADDR || ri.is_subtract() )
|
|
return false;
|
|
|
|
int dpr_reg = rDPR0 + ((opval >> 14) & 3);
|
|
sel_t page = get_sreg(from, dpr_reg);
|
|
if ( page == BADSEL )
|
|
return false;
|
|
|
|
ea_t addr = (page << 14) + (opval & 0x3FFF);
|
|
ea_t op_target = ri.base - ri.tdelta + addr;
|
|
if ( ri.target != BADADDR && ri.target != op_target )
|
|
return false;
|
|
|
|
*target = op_target;
|
|
*base = ri.base;
|
|
return true;
|
|
}
|
|
|
|
// complex format with DPR prefix
|
|
//lint -e{818} ... parameter 'opval' could be declared as pointing to const
|
|
static int idaapi dpr_gen_expr(
|
|
qstring * /*buf*/,
|
|
qstring *format,
|
|
ea_t /*ea*/,
|
|
int /*numop*/,
|
|
const refinfo_t &/*ri*/,
|
|
ea_t /*from*/,
|
|
adiff_t *opval,
|
|
ea_t * /*target*/,
|
|
ea_t * /*fullvalue*/,
|
|
int /*getn_flags*/)
|
|
{
|
|
int dpr_reg_num = (*opval >> 14) & 3;
|
|
format->sprnt(COLSTR("DPR%d:pof", SCOLOR_KEYWORD) "(%%s)", dpr_reg_num);
|
|
return 4; // continue standard processing
|
|
}
|
|
|
|
static const custom_refinfo_handler_t ref_dpr =
|
|
{
|
|
sizeof(custom_refinfo_handler_t),
|
|
"DPR",
|
|
"16-bit offset using DPRx register",
|
|
RHF_TGTOPT, // properties: the target can be BADADDR
|
|
dpr_gen_expr, // gen_expr
|
|
dpr_calc_reference_data, // calc_reference_data
|
|
NULL, // get_format
|
|
};
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
// 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(st9_t));
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// The kernel event notifications
|
|
// Here you may take desired actions upon some kernel events
|
|
ssize_t idaapi st9_t::on_event(ssize_t msgid, va_list va)
|
|
{
|
|
int code = 0;
|
|
switch ( msgid )
|
|
{
|
|
case processor_t::ev_init:
|
|
// this processor is big endian
|
|
inf_set_be(true);
|
|
helper.create(PROCMOD_NODE_NAME);
|
|
ref_dpr_id = register_custom_refinfo(&ref_dpr);
|
|
break;
|
|
|
|
case processor_t::ev_term:
|
|
unregister_custom_refinfo(ref_dpr_id);
|
|
clr_module_data(data_id);
|
|
break;
|
|
|
|
case processor_t::ev_newfile:
|
|
if ( inf_like_binary()
|
|
&& ask_yn(ASKBTN_YES,
|
|
"Do you want to split the loaded file contents into 64K banks?") == ASKBTN_YES )
|
|
{
|
|
segment_t *s = get_first_seg();
|
|
if ( s != NULL )
|
|
{
|
|
ssize_t total = (ssize_t)s->size();
|
|
ea_t ea = s->start_ea;
|
|
// align the segment start at the memory bank start
|
|
if ( (ea & 0xFFFF) != 0 )
|
|
{
|
|
ea_t start = ea & ~0xFFFF;
|
|
set_segm_start(ea, start, 0);
|
|
ea = start;
|
|
}
|
|
// each memory bank gets its own segment
|
|
while ( 1 )
|
|
{
|
|
set_segm_end(ea, ea+0x10000, 0);
|
|
total -= 0x10000;
|
|
ea += 0x10000;
|
|
if ( total <= 0 )
|
|
break;
|
|
add_segm(ea>>4, ea, ea+total, NULL, "CODE");
|
|
s = getseg(ea);
|
|
if ( !s->is_16bit() )
|
|
{
|
|
s->bitness = 0; // use 16-bit segments
|
|
s->update();
|
|
}
|
|
}
|
|
}
|
|
// check that a segment at 0...10000 exists
|
|
// if not, create it
|
|
s = get_first_seg();
|
|
if ( s == NULL || s->start_ea > 0x10000 )
|
|
add_segm(0, 0, 0x10000, NULL, "DATA");
|
|
}
|
|
// select_device(inf_like_binary() ? IORESP_ALL : (IORESP_ALL & ~IORESP_AREA));
|
|
// file_loaded = true;
|
|
save_idpflags();
|
|
patch_general_registers();
|
|
break;
|
|
|
|
case processor_t::ev_ending_undo:
|
|
case processor_t::ev_oldfile:
|
|
load_from_idb();
|
|
break;
|
|
|
|
case processor_t::ev_creating_segm:
|
|
{
|
|
segment_t *s = va_arg(va, segment_t *);
|
|
// set RW/RP segment registers initial values
|
|
s->defsr[rRW-ph.reg_first_sreg] = 0;
|
|
s->defsr[rRP-ph.reg_first_sreg] = BADSEL;
|
|
}
|
|
break;
|
|
|
|
case processor_t::ev_out_mnem:
|
|
{
|
|
outctx_t *ctx = va_arg(va, outctx_t *);
|
|
out_mnem(*ctx);
|
|
return 1;
|
|
}
|
|
|
|
case processor_t::ev_out_header:
|
|
{
|
|
outctx_t *ctx = va_arg(va, outctx_t *);
|
|
st9_header(*ctx);
|
|
return 1;
|
|
}
|
|
|
|
case processor_t::ev_out_footer:
|
|
{
|
|
outctx_t *ctx = va_arg(va, outctx_t *);
|
|
st9_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 *);
|
|
st9_segstart(*ctx, seg);
|
|
return 1;
|
|
}
|
|
|
|
case processor_t::ev_out_assumes:
|
|
{
|
|
outctx_t *ctx = va_arg(va, outctx_t *);
|
|
st9_assumes(*ctx);
|
|
return 1;
|
|
}
|
|
|
|
case processor_t::ev_ana_insn:
|
|
{
|
|
insn_t *out = va_arg(va, insn_t *);
|
|
return st9_ana(out);
|
|
}
|
|
|
|
case processor_t::ev_emu_insn:
|
|
{
|
|
const insn_t *insn = va_arg(va, const insn_t *);
|
|
return st9_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_create_func_frame:
|
|
{
|
|
func_t *pfn = va_arg(va, func_t *);
|
|
create_func_frame(pfn);
|
|
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;
|
|
}
|
|
|
|
case processor_t::ev_is_switch:
|
|
{
|
|
switch_info_t *si = va_arg(va, switch_info_t *);
|
|
const insn_t *insn = va_arg(va, const insn_t *);
|
|
return st9_is_switch(si, *insn) ? 1 : -1;
|
|
}
|
|
|
|
case processor_t::ev_is_cond_insn:
|
|
///< Is conditional instruction?
|
|
///< \param insn (const ::insn_t) instruction address
|
|
///< \retval 1 yes
|
|
///< \retval 0 not implemented
|
|
///< \retval -1 no
|
|
{
|
|
const insn_t *insn = va_arg(va, insn_t *);
|
|
return is_jmp_cc(insn->itype) ? 1 : -1;
|
|
}
|
|
|
|
case processor_t::ev_is_indirect_jump:
|
|
{
|
|
// jp, call, calls can have indirect register operands (rr), (RR)
|
|
const insn_t *insn = va_arg(va, insn_t *);
|
|
if ( insn->Op1.type != o_reg || !is_ind(insn->Op1) )
|
|
return 1; // no
|
|
if ( insn->itype == st9_jp || insn->itype == st9_call || insn->itype == st9_calls )
|
|
return 2; // yes
|
|
else
|
|
return 1; // no
|
|
}
|
|
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return code;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
//
|
|
// GNU ST9+ Assembler description
|
|
//
|
|
|
|
// gets a function name
|
|
static bool gnu_get_func_name(qstring *name, const func_t *pfn)
|
|
{
|
|
ea_t ea = pfn->start_ea;
|
|
if ( get_demangled_name(name, ea, inf_get_long_demnames(), DEMNAM_NAME) <= 0 )
|
|
return false;
|
|
|
|
tag_addr(name, ea, true);
|
|
return true;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// prints function header
|
|
static void idaapi gnu_func_header(outctx_t &ctx, func_t *pfn)
|
|
{
|
|
ctx.gen_func_header(pfn);
|
|
|
|
qstring name;
|
|
if ( gnu_get_func_name(&name, pfn) )
|
|
{
|
|
int saved_flags = ctx.forbid_annotations();
|
|
ctx.gen_printf(DEFAULT_INDENT,
|
|
COLSTR(".desc %s, %s", SCOLOR_ASMDIR),
|
|
name.begin(),
|
|
pfn->is_far() ? "far" : "near");
|
|
ctx.restore_ctxflags(saved_flags);
|
|
ctx.gen_printf(DEFAULT_INDENT, COLSTR(".proc %s", SCOLOR_ASMDIR), name.begin());
|
|
ctx.ctxflags |= CTXF_LABEL_OK;
|
|
}
|
|
ctx.gen_printf(0, COLSTR("%s:", SCOLOR_ASMDIR), name.begin());
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// prints function footer
|
|
//lint -esym(818,pfn)
|
|
static void idaapi gnu_func_footer(outctx_t &ctx, func_t *pfn)
|
|
{
|
|
qstring name;
|
|
if ( gnu_get_func_name(&name, pfn) )
|
|
{
|
|
ctx.gen_printf(DEFAULT_INDENT, COLSTR(".endproc", SCOLOR_ASMDIR) COLSTR("%s %s", SCOLOR_ASMDIR), ASH.cmnt, name.begin());
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
static const asm_t gnu_asm =
|
|
{
|
|
AS_COLON
|
|
|ASH_HEXF3 // hex 0x123 format
|
|
|ASB_BINF0 // bin 0110b format
|
|
|ASO_OCTF1 // oct 012345 format
|
|
|AS_ASCIIZ // don't display the final 0 in string declarations
|
|
|AS_ASCIIC // allow C-style escape sequences
|
|
|AS_1TEXT, // 1 text per line, no bytes
|
|
0,
|
|
"ST9 GNU Assembler",
|
|
0,
|
|
NULL, // no headers
|
|
".org", // origin directive
|
|
NULL, // end directive
|
|
";", // comment string
|
|
'"', // string delimiter
|
|
'\'', // char delimiter
|
|
"\\\"'", // special symbols in char and string constants
|
|
|
|
".string", // ascii string directive
|
|
".byte", // byte directive
|
|
".word", // word directive
|
|
".long", // dword (4 bytes)
|
|
NULL, // qword (8 bytes)
|
|
NULL, // oword (16 bytes)
|
|
|
|
// XXX
|
|
//
|
|
// .float and .double directives are supposed to be supported by the
|
|
// assembler, but when we try to assemble a file including those directives,
|
|
// we get this error message :
|
|
//
|
|
// /vob/st9plus/toolset/src/binutils/gas/config/tc-st9.c(4167): !!! STOP !!!
|
|
// -> !(Floating point convertion)
|
|
|
|
".float", // float (4 bytes)
|
|
".double", // double (8 bytes)
|
|
NULL, // tbyte (10/12 bytes)
|
|
NULL, // packed decimal real
|
|
NULL, // arrays (#h,#d,#v,#s(...)
|
|
"dfs %s", // uninited arrays
|
|
"equ", // Equ
|
|
NULL, // seg prefix
|
|
"$", // current IP (instruction pointer) symbol in assembler
|
|
gnu_func_header, // func_header
|
|
gnu_func_footer, // func_footer
|
|
".global", // public
|
|
NULL, // weak
|
|
NULL, // extrn
|
|
NULL, // comm
|
|
NULL, // get_type_name
|
|
NULL, // align
|
|
'(', ')', // lbrace, rbrace
|
|
"%", // mod
|
|
"&", // and
|
|
"|", // or
|
|
"^", // xor
|
|
"~", // not
|
|
"<<", // shl
|
|
">>", // shr
|
|
NULL, // sizeof
|
|
0, // flag2 ???
|
|
NULL, // comment close string
|
|
NULL, // low8 op
|
|
NULL, // high8 op
|
|
NULL, // low16 op
|
|
NULL // high16 op
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
//
|
|
// Alfred Arnold's Macro Assembler definition
|
|
//
|
|
|
|
static const asm_t asw_asm =
|
|
{
|
|
AS_COLON
|
|
|ASH_HEXF0 // hex 123h format
|
|
|ASB_BINF3 // bin 0b010 format
|
|
|ASO_OCTF5 // oct 123q format
|
|
|AS_1TEXT, // 1 text per line, no bytes
|
|
UAS_ASW,
|
|
"Alfred Arnold's Macro Assembler",
|
|
0,
|
|
NULL, // no headers
|
|
"ORG", // origin directive
|
|
"END", // end directive
|
|
";", // comment string
|
|
'"', // string delimiter
|
|
'\'', // char delimiter
|
|
"\\\"'", // special symbols in char and string constants
|
|
|
|
"DB", // ascii string directive
|
|
"DB", // byte directive (alias: DB)
|
|
"DW", // word directive (alias: DW)
|
|
"DD", // dword (4 bytes, alias: DD)
|
|
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(...)
|
|
"dfs %s", // uninited arrays
|
|
"equ", // Equ
|
|
NULL, // seg prefix
|
|
"$", // current IP (instruction pointer) symbol in assembler
|
|
NULL, // func_header
|
|
NULL, // func_footer
|
|
NULL, // public
|
|
NULL, // weak
|
|
NULL, // extrn
|
|
NULL, // comm
|
|
NULL, // get_type_name
|
|
NULL, // align
|
|
'(', ')', // lbrace, rbrace
|
|
"%", // mod
|
|
"&", // and
|
|
"|", // or
|
|
"^", // xor
|
|
"~", // not
|
|
"<<", // shl
|
|
">>", // shr
|
|
NULL, // sizeof
|
|
0, // flag2 ???
|
|
NULL, // comment close string
|
|
NULL, // low8 op
|
|
NULL, // high8 op
|
|
NULL, // low16 op
|
|
NULL // high16 op
|
|
};
|
|
|
|
static const asm_t *const asms[] = { &gnu_asm, &asw_asm, NULL };
|
|
|
|
//
|
|
// Short and long name for our module
|
|
//
|
|
#define FAMILY "ST9 Family:"
|
|
|
|
static const char *const shnames[] =
|
|
{
|
|
"st9",
|
|
NULL
|
|
};
|
|
|
|
static const char *const lnames[] =
|
|
{
|
|
FAMILY"SGS-Thomson ST9",
|
|
NULL
|
|
};
|
|
|
|
static const uchar retcode_1[] = { 0x46 }; // ret
|
|
static const uchar retcode_2[] = { 0xD3 }; // iret
|
|
static const uchar retcode_3[] = { 0xF6, 01 }; // rets
|
|
static const uchar retcode_4[] = { 0xEF, 31 }; // eret
|
|
|
|
static const bytes_t retcodes[] =
|
|
{
|
|
{ sizeof(retcode_1), retcode_1 },
|
|
{ sizeof(retcode_2), retcode_2 },
|
|
{ sizeof(retcode_3), retcode_3 },
|
|
{ sizeof(retcode_4), retcode_4 },
|
|
{ 0, NULL } // NULL terminated array
|
|
};
|
|
|
|
//-----------------------------------------------------------------------
|
|
// Processor Definition
|
|
//-----------------------------------------------------------------------
|
|
processor_t LPH =
|
|
{
|
|
IDP_INTERFACE_VERSION, // version
|
|
PLFM_ST9, // id
|
|
// flag
|
|
PR_RNAMESOK // can use register names for byte names
|
|
| 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
|
|
// 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, // array of short processor names
|
|
// the short names are used to specify the processor
|
|
// with the -p command line switch)
|
|
lnames, // array of long processor names
|
|
// the long names are used to build the processor type
|
|
// selection menu
|
|
|
|
asms, // array of target assemblers
|
|
|
|
notify, // the kernel event notification callback
|
|
|
|
src_RegNames, // Regsiter names
|
|
qnumber(src_RegNames),// Number of registers
|
|
|
|
rRW, rDPR3,
|
|
0, // size of a segment register
|
|
rCSR, rDPR0,
|
|
|
|
NULL, // No known code start sequences
|
|
retcodes,
|
|
|
|
0, st9_last,
|
|
Instructions, // instruc
|
|
0, // int tbyte_size; -- doesn't exist
|
|
{ 0, 7, 15, 0 }, // char real_width[4];
|
|
// number of symbols after decimal point
|
|
// 2byte float (0-does not exist)
|
|
// normal float
|
|
// normal double
|
|
// long double
|
|
st9_ret, // Icode of return instruction. It is ok to give any of possible return instructions
|
|
};
|