Files
sigmaker-ida/idasdk76/module/st9/out.cpp
2021-10-31 21:20:46 +02:00

586 lines
17 KiB
C++

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