Files
2021-10-31 21:20:46 +02:00

901 lines
27 KiB
C++

/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-98 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* E-mail: ig@estar.msk.su, ig@datarescue.com
* FIDO: 2:50620/209
*
*/
#include "i51.hpp"
#include <entry.hpp>
#include <segregs.hpp>
int data_id;
//--------------------------------------------------------------------------
static const char *const RegNames[] =
{
"A", "AB", "B",
"R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
"R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15",
"WR0", "WR2", "WR4", "WR6", "WR8", "WR10", "WR12", "WR14",
"WR16", "WR18", "WR20", "WR22", "WR24", "WR26", "WR28", "WR30",
"DR0", "DR4", "DR8", "DR12", "DR16", "DR20", "DR24", "DR28",
"DR32", "DR36", "DR40", "DR44", "DR48", "DR52", "DPX", "SPX",
"DPTR","C", "PC",
"EPTR", "PR0", "PR1",
"cs","ds"
};
//----------------------------------------------------------------------
static const char cfgname[] = "i51.cfg";
void i51_iohandler_t::get_cfg_filename(char *buf, size_t bufsize)
{
qstrncpy(buf, cfgname, bufsize);
}
void i51_iohandler_t::apply_io_port(ea_t ea, const char *name, const char *cmt)
{
if ( ea >= 0x80 && ea < 0x100 )
{
// specail mapping alg for i51 FSR regs
segment_t *s = get_segm_by_name("FSR");
if ( s != NULL )
{
ea_t map = ea + s->start_ea - 0x80;
if ( is_mapped(map) )
ea = map;
}
}
set_name(ea, name, SN_NODUMMY);
set_cmt(ea, cmt, true);
}
bool i51_iohandler_t::segment_created(ea_t start, ea_t end, const char *word, const char *)
{
if ( stristr(word, "FSR") != NULL || stristr(word, "RAM") != NULL )
{
pm.AdditionalSegment(end-start, start, word);
return true;
}
return false;
}
//------------------------------------------------------------------
const char *i51_t::set_idp_options(
const char *keyword,
int /*value_type*/,
const void * /*value*/,
bool /*idb_loaded*/)
{
if ( keyword != NULL )
return IDPOPT_BADKEY;
iohandler_t::parse_area_line0_t cb(ioh);
if ( choose_ioport_device2(&ioh.device, cfgname, &cb) )
ioh.set_device_name(ioh.device.c_str(), IORESP_PORT|IORESP_INT);
return IDPOPT_OK;
}
//------------------------------------------------------------------
const ioport_bit_t *i51_t::find_bit(ea_t address, int bit)
{
return find_ioport_bit(ioh.ports, address, bit);
}
//----------------------------------------------------------------------
bool i51_t::IsPredefined(const char *name)
{
for ( int i=0; i < ioh.ports.size(); i++ )
{
const ioport_t &p = ioh.ports[i];
if ( p.name == name )
return true;
for ( int j=0; j < p.bits.size(); j++ )
if ( p.bits[j].name == name )
return true;
}
return false;
}
//----------------------------------------------------------------------
struct entry_t
{
char proc;
char off;
const char *name; //lint !e958 padding is required to align members
const char *cmt;
};
static const entry_t entries[] =
{
{ prc_51, 0x03, "extint0", "External interrupt 0 (INT0 / EX0)" },
{ prc_51, 0x0B, "timint0", "Timer interrupt 0 (TIM0)" },
{ prc_51, 0x13, "extint1", "External interrupt 1 (INT1 / EX1)" },
{ prc_51, 0x1B, "timint1", "Timer interrupt 1 (TIM1)" },
{ prc_51, 0x23, "serint", "Serial port interrupt (SERIAL)" },
{ prc_51, 0x2B, "timint2", "Timer interrupt 2 (TIM2) (52 or higher)" },
{ prc_51, 0x33, "pcaint", "PCA (programmable counter array) interrupt\n(only 51f or higher)" },
{ prc_930, 0x43, "usbhub", "USB Hub/SOF (isochronous end point) (only 930)" },
{ prc_930, 0x4B, "usbfun", "USB Function (non-isochronous end point) (only 930)" },
{ prc_930, 0x53, "usbglb", "USB Global Suspend/Resume and USB Reset (only 930)" },
{ prc_251, 0x7B, "trapint", "TRAP (program interrupt) (only 251 or 930)" }
};
//----------------------------------------------------------------------
// Get linear address of a special segment
// sel - selector of the segment
static ea_t specialSeg(segment_t *s)
{
if ( s->type != SEG_IMEM ) // is the segment type correct? - no
{
s->type = SEG_IMEM; // fix it
s->update();
}
return s->start_ea;
}
//----------------------------------------------------------------------
ea_t i51_t::AdditionalSegment(size_t size, size_t offset, const char *name) const
{
segment_t s;
s.start_ea = (ptype > prc_51)
? (inf_get_max_ea() + 0xF) & ~0xF
: free_chunk(0, size, 0xF);
s.end_ea = s.start_ea + size;
s.sel = allocate_selector((s.start_ea-offset) >> 4);
s.type = SEG_IMEM; // internal memory
add_segm_ex(&s, name, NULL, ADDSEG_NOSREG|ADDSEG_OR_DIE);
return s.start_ea - offset;
}
//----------------------------------------------------------------------
void i51_t::setup_data_segment_pointers(void)
{
segment_t *s = get_segm_by_name("INTMEM");
if ( s == NULL )
s = get_segm_by_name("RAM");
if ( s != NULL )
intmem = specialSeg(s);
s = get_segm_by_name("SFR");
if ( s == NULL )
s = get_segm_by_name("FSR");
if ( s != NULL )
sfrmem = specialSeg(s) - 0x80;
}
//--------------------------------------------------------------------------
void i51_t::load_from_idb()
{
ioh.restore_device();
// restore ptype
ptype = processor_subtype_t(ph.get_proc_index());
setup_data_segment_pointers();
}
//--------------------------------------------------------------------------
ssize_t idaapi idb_listener_t::on_event(ssize_t code, va_list)
{
switch ( code )
{
case idb_event::segm_moved: // A segment is moved
// Fix processor dependent address sensitive information
{
// ea_t from = va_arg(va, ea_t);
// ea_t to = va_arg(va, ea_t);
// asize_t size = va_arg(va, asize_t);
// bool changed_netmap = va_argi(va, bool);
// Add commands to adjust your internal variables here
// Most of the time this callback will be empty
//
// If you keep information in a netnode's altval array, you can use
// node.altshift(from, s->start_ea, s->end_ea - s->start_ea);
//
// If you have a variables pointing to somewhere in the disassembled program memory,
// you can adjust it like this:
//
// if ( var >= from && var < from+size )
// var += to - from;
}
break;
}
return 0;
}
//----------------------------------------------------------------------
// 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(i51_t));
return 0;
}
ssize_t idaapi i51_t::on_event(ssize_t msgid, va_list va)
{
int code = 0;
switch ( msgid )
{
case processor_t::ev_init:
hook_event_listener(HT_IDB, &idb_listener, &LPH);
helper.create(PROCMOD_NODE_NAME);
inf_set_be(true); // Set a big endian mode of the IDA kernel
break;
case processor_t::ev_term:
ioh.ports.clear();
unhook_event_listener(HT_IDB, &idb_listener);
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);
inf_set_start_ip(0);
for ( int i=0; i < qnumber(entries); i++ )
{
if ( entries[i].proc > ptype )
continue;
ea_t ea = inf_get_start_ea()+entries[i].off;
if ( is_mapped(ea) && get_byte(ea) != 0xFF )
{
add_entry(ea, ea, entries[i].name, 1);
set_cmt(ea, entries[i].cmt, 1);
}
}
}
}
segment_t *scode = get_first_seg();
set_segm_class(scode, "CODE");
if ( ptype > prc_51 )
{
AdditionalSegment(0x10000-256-128, 256+128, "RAM");
if ( scode != NULL )
{
ea_t align = (scode->end_ea + 0xFFF) & ~0xFFF;
if ( getseg(align-7) == scode ) // the code segment size is
{ // multiple of 4K or near it
uchar b0 = get_byte(align-8);
// 251:
// 0 : 1-source, 0-binary mode
// 6,7: must be 1s
// 82930:
// 0 : 1-source, 0-binary mode
// 7 : must be 1s
// uchar b1 = get_byte(align-7);
// 251
// 0: eprommap 0 - FE2000..FE4000 is mapped into 00E000..100000
// 1 - .............. is not mapped ...............
// 1: must be 1
// 3:
// 2: must be 1
// 4: intr 1 - upon interrupt PC,PSW are pushed into stack
// 0 - upon interrupt only PC is pushed into stack
// 5: must be 1
// 6: must be 1
// 7: must be 1
// 82930:
// 3: must be 1
// 5: must be 1
// 6: must be 1
// 7: must be 1
// msg("b0=%x b1=%x\n", b0, b1);
// if ( (b0 & 0x80) == 0x80 && (b1 & 0xEA) == 0xEA )
{ // the init bits are correct
char pname[IDAINFO_PROCNAME_SIZE];
inf_get_procname(pname, sizeof(pname));
char ntype = (b0 & 1) ? 's' : 'b';
char *ptr = tail(pname)-1;
if ( ntype != *ptr
&& ask_yn(ASKBTN_YES,
"HIDECANCEL\n"
"The input file seems to be for the %s mode of the processor.\n"
"Do you want to change the current processor type?",
ntype == 's' ? "source" : "binary") > 0 )
{
*ptr = ntype;
first_time = true;
set_processor_type(pname, SETPROC_USER);
}
}
}
}
}
// the default data segment will be INTMEM
{
segment_t *s = getseg(intmem);
if ( s != NULL )
set_default_dataseg(s->sel);
}
iohandler_t::parse_area_line0_t cb(ioh);
if ( choose_ioport_device2(&ioh.device, cfgname, &cb) )
ioh.set_device_name(ioh.device.c_str(), IORESP_ALL);
if ( get_segm_by_name("RAM") == NULL )
AdditionalSegment(256, 0, "RAM");
if ( get_segm_by_name("FSR") == NULL )
AdditionalSegment(128, 128, "FSR");
setup_data_segment_pointers();
}
break;
case processor_t::ev_ending_undo:
case processor_t::ev_oldfile:
load_from_idb();
break;
case processor_t::ev_creating_segm:
// make the default DS point to INTMEM
// (8051 specific issue)
{
segment_t *newseg = va_arg(va, segment_t *);
segment_t *intseg = getseg(intmem);
if ( intseg != NULL )
newseg->defsr[rVds-ph.reg_first_sreg] = intseg->sel;
}
break;
case processor_t::ev_newprc:
{
processor_subtype_t prcnum = processor_subtype_t(va_arg(va, int));
// bool keep_cfg = va_argi(va, bool);
if ( !first_time && prcnum != ptype )
{
warning("Sorry, it is not possible to change" // (this is 8051 specific)
" the processor mode on the fly."
" Please reload the input file"
" if you want to change the processor.");
code = -1;
break;
}
first_time = false;
ptype = prcnum;
}
break;
case processor_t::ev_newasm: // new assembler type
ioh.restore_device();
break;
case processor_t::ev_is_sane_insn:
// is the instruction sane for the current file type?
// arg: int no_crefs
// 1: the instruction has no code refs to it.
// ida just tries to convert unexplored bytes
// to an instruction (but there is no other
// reason to convert them into an instruction)
// -1: the instruction is created because
// of some coderef, user request or another
// weighty reason.
// The instruction is in 'cmd'
// returns: 1-ok, <=0-no, the instruction isn't
// likely to appear in the program
{
const insn_t *insn = va_arg(va, insn_t *);
int reason = va_arg(va, int);
return is_sane_insn(*insn, reason) == 1 ? 1 : -1;
}
case processor_t::ev_out_header:
{
outctx_t *ctx = va_arg(va, outctx_t *);
i51_header(*ctx);
return 1;
}
case processor_t::ev_out_footer:
{
outctx_t *ctx = va_arg(va, outctx_t *);
i51_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 *);
i51_segstart(*ctx, seg);
return 1;
}
case processor_t::ev_ana_insn:
{
insn_t *out = va_arg(va, insn_t *);
return ana(out);
}
case processor_t::ev_emu_insn:
{
const insn_t *insn = va_arg(va, const insn_t *);
return emu(*insn) ? 1 : -1;
}
case processor_t::ev_out_insn:
{
outctx_t *ctx = va_arg(va, outctx_t *);
out_insn(*ctx);
return 1;
}
case processor_t::ev_out_operand:
{
outctx_t *ctx = va_arg(va, outctx_t *);
const op_t *op = va_arg(va, const op_t *);
return out_opnd(*ctx, *op) ? 1 : -1;
}
case processor_t::ev_out_data:
{
outctx_t *ctx = va_arg(va, outctx_t *);
bool analyze_only = va_argi(va, bool);
i51_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;
}
//-----------------------------------------------------------------------
// ASMI
//-----------------------------------------------------------------------
static const asm_t asmi =
{
AS_COLON | ASH_HEXF3 | AS_1TEXT | AS_NCHRE | ASO_OCTF1 | AS_RELSUP,
UAS_PSAM | UAS_NOSEG | UAS_AUBIT | UAS_PBIT | UAS_NOENS,
"ASMI",
0,
NULL, // no headers
".equ $, ",
".end",
";", // comment string
'"', // string delimiter
'\'', // char delimiter
"\\\"'", // special symbols in char and string constants
".text", // 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(...)
".byte 0xFF;(array %s)", // uninited arrays
".equ", // equ
NULL, // seg prefix
"$", // curip
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
};
//-----------------------------------------------------------------------
// 8051 Macro Assembler - Version 4.02a
// Copyright (C) 1985 by 2500 A.D. Software, Inc.
//-----------------------------------------------------------------------
static const asm_t adasm =
{
AS_COLON | ASH_HEXF0,
UAS_PBIT | UAS_SECT,
"8051 Macro Assembler by 2500 A.D. Software",
0,
NULL, // no headers
"org",
"end",
";", // comment string
'"', // string delimiter
'\'', // char delimiter
"\\\"'", // special symbols in char and string constants
"db", // ascii string directive
"db", // byte directive
"dw", // word directive
"long", // 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
"reg", // equ
NULL, // seg prefix
"$", // curip
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
0, // flag2
NULL, // close comment
COLSTR("<", SCOLOR_SYMBOL) "%s", // low8
COLSTR(">", SCOLOR_SYMBOL) "%s", // high8
NULL, // low16
NULL, // high16
};
//-----------------------------------------------------------------------
// PseudoSam
//-----------------------------------------------------------------------
static const char *const ps_headers[] =
{
".code",
NULL
};
static const asm_t pseudosam =
{
AS_COLON | ASH_HEXF1 | AS_N2CHR,
UAS_PBIT | UAS_PSAM | UAS_SELSG,
"PseudoSam by PseudoCode",
0,
ps_headers,
".org",
".end",
";", // comment string
'"', // string delimiter
'\'', // char delimiter
"\\\"'", // special symbols in char and string constants
".db", // ascii string directive
".db", // byte directive
".dw", // word directive
NULL, // dword (4 bytes)
NULL, // qword (8 bytes)
NULL, // oword (16 bytes)
NULL, // float (4 bytes)
NULL, // double (8 bytes)
NULL, // tbyte (10/12 bytes)
NULL, // packed decimal real
NULL, // arrays (#h,#d,#v,#s(...)
".rs %s", // uninited arrays
".equ", // equ
NULL, // seg prefix
"$", // curip
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
};
//-----------------------------------------------------------------------
// Cross-16 assembler definiton
//-----------------------------------------------------------------------
static const char *const cross16_headers[] =
{
"cpu \"8051.tbl\"",
NULL
};
static const asm_t cross16 =
{
AS_COLON | ASH_HEXF0 | AS_NHIAS,
UAS_PBIT | UAS_NOSEG | UAS_NOBIT | UAS_EQCLN,
"Cross-16 by Universal Cross-Assemblers",
0,
cross16_headers,
"org",
"end",
";", // comment string
'"', // string delimiter
'\0', // char delimiter (no char consts)
"\\\"'", // special symbols in char and string constants
"dfb", // ascii string directive
"dfb", // byte directive
"dwm", // 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(...)
"dfs %s", // uninited arrays
"equ", // Equ
NULL, // seg prefix
"$", // curip
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
};
//-----------------------------------------------------------------------
// 8051 Cross-Assembler by MetaLink Corporation
//-----------------------------------------------------------------------
static const asm_t mcross =
{
AS_COLON | ASH_HEXF0 | AS_NHIAS,
UAS_NOSEG | UAS_CDSEG | UAS_AUBIT | UAS_NODS | UAS_NOENS,
"8051 Cross-Assembler by MetaLink Corporation",
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
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(...)
"ds %s", // uninited arrays
"equ", // Equ
NULL, // seg prefix
"$", // curip
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
};
//-----------------------------------------------------------------------
// TASM assembler definiton
//-----------------------------------------------------------------------
static const char *const tasm_headers[] =
{
".msfirst",
NULL
};
static const asm_t tasm =
{
AS_COLON | AS_N2CHR | AS_1TEXT,
UAS_PBIT | UAS_NOENS | UAS_EQCLN | UAS_NOSEG,
"Table Driven Assembler (TASM) by Speech Technology Inc.",
0,
tasm_headers,
".org",
".end",
";", // comment string
'"', // string delimiter
'\'', // char delimiter
"\\\"'", // special symbols in char and string constants
".text", // ascii string directive
".db", // byte directive
".dw", // word directive
NULL, // dword (4 bytes)
NULL, // qword (8 bytes)
NULL, // oword (16 bytes)
NULL, // float (4 bytes)
NULL, // double (8 bytes)
NULL, // tbyte (10/12 bytes)
NULL, // packed decimal real
NULL, // arrays (#h,#d,#v,#s(...)
".block %s", // uninited arrays
".equ",
NULL, // seg prefix
"$", // curip
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
NULL, // sizeof
};
static const asm_t *const asms[] =
{
&asmi, &adasm, &pseudosam, &cross16, &mcross, &tasm, NULL
};
//-----------------------------------------------------------------------
// The short and long names of the supported processors
#define FAMILY "Intel 51 series:"
static const char *const shnames[] =
{
"8051",
"80251b",
"80251s",
"80930b",
"80930s",
"8051mx",
NULL
};
static const char *const lnames[] =
{
FAMILY"Intel 8051",
"Intel 80251 in binary mode",
"Intel 80251 in source mode",
"Intel 80930 in binary mode",
"Intel 80930 in source mode",
"Intel 8051MX",
NULL
};
//--------------------------------------------------------------------------
// Opcodes of "return" instructions. This information will be used in 2 ways:
// - if an instruction has the "return" opcode, its autogenerated label
// will be "locret" rather than "loc".
// - IDA will use the first "return" opcode to create empty subroutines.
static const uchar retcode_1[] = { 0x22 };
static const uchar retcode_2[] = { 0x32 };
static const bytes_t retcodes[] =
{
{ sizeof(retcode_1), retcode_1 },
{ sizeof(retcode_2), retcode_2 },
{ 0, NULL } // NULL terminated array
};
//-----------------------------------------------------------------------
// Processor Definition
//-----------------------------------------------------------------------
processor_t LPH =
{
IDP_INTERFACE_VERSION, // version
PLFM_8051, // id
// flag
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)
// 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
RegNames, // Regsiter names
qnumber(RegNames), // Number of registers
rVcs,rVds,
0, // size of a segment register
rVcs,rVds,
NULL, // No known code start sequences
retcodes,
0,I51_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
I51_ret, // Icode of return instruction. It is ok to give any of possible return instructions
};