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

1305 lines
36 KiB
C++

/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-99 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* E-mail: ig@datarescue.com
*
*
*/
#include "hppa.hpp"
//--------------------------------------------------------------------------
struct cond_text_t
{
const char *text;
char c; // -1 means any value
char f; // -1 means any value
};
static const cond_text_t D3[] = // and D4 combined
{ // c f
{ "", 0, 0 }, // never
{ "=", 1, 0 }, // op1 is equal to op2 (word)
{ "<", 2, 0 }, // op1 is less than op2 (signed word)
{ "<=", 3, 0 }, // op1 is less than or equal to op2 (signed word)
{ "<<", 4, 0 }, // op1 is less than op2 (unsigned word)
{ "<<=", 5, 0 }, // op1 is less than or equal to op2 (unsigned word)
{ "sv", 6, 0 }, // op1 minus op2 overflows (signed word)
{ "od", 7, 0 }, // op1 minus op2 is odd
{ "tr", 0, 1 }, // always
{ "<>", 1, 1 }, // op1 is not equal to op2 (word)
{ ">=", 2, 1 }, // op1 is greater than or equal to op2 (signed word)
{ ">", 3, 1 }, // op1 is greater than op2 (signed word)
{ ">>=", 4, 1 }, // op1 is greater than or equal to op2 (unsigned word)
{ ">>", 5, 1 }, // op1 is greater than op2 (unsigned word)
{ "nsv", 6, 1 }, // op1 minus op2 does not overflow (signed word)
{ "ev", 7, 1 }, // op1 minus op2 is even
{ NULL },
};
static const cond_text_t D5[] = // f should be 0!
{ // c f
{ "*<<", 0, 0 }, // op1 is less than op2 (unsigned doubleword)
{ "*=", 1, 0 }, // op1 is equal to op2 (doubleword)
{ "*<", 2, 0 }, // op1 is less than op2 (signed doubleword)
{ "*<=", 3, 0 }, // op1 is less than or equal to op2 (signed doubleword)
{ "*>>=", 4, 0 }, // op1 is greater than or equal to op2 (unsigned doubleword)
{ "*<>", 5, 0 }, // op1 is not equal to op2 (doubleword)
{ "*>=", 6, 0 }, // op1 is greater than or equal to op2 (signed doubleword)
{ "*>", 7, 0 }, // op1 is greater than op2 (signed doubleword)
{ NULL },
};
static const cond_text_t D6[] = // and D7 combined
{ // c f
{ "", 0, 0 }, // never
{ "=", 1, 0 }, // op1 is equal to negative of op2 (word)
{ "<", 2, 0 }, // op1 is less than negative of op2 (signed word)
{ "<=", 3, 0 }, // op1 is less than or equal to negative of op2 (signed word)
{ "nuv", 4, 0 }, // op1 plus op2 does not overflow (unsigned word)
{ "znv", 5, 0 }, // op1 plus op2 is zero or no overflow (unsigned word)
{ "sv", 6, 0 }, // op1 plus op2 overflows (signed word)
{ "od", 7, 0 }, // op1 plus op2 is odd
{ "tr", 0, 1 }, // always
{ "<>", 1, 1 }, // op1 is not equal to negative of op2 (word)
{ ">=", 2, 1 }, // op1 is greater than or equal to negative of op2 (signed word)
{ ">", 3, 1 }, // op1 is greater than negative of op2 (signed word)
{ "uv", 4, 1 }, // op1 plus op2 overflows (unsigned word)
{ "vnz", 5, 1 }, // op1 plus op2 is nonzero and overflows (unsigned word)
{ "nsv", 6, 1 }, // op1 minus op2 does not overflow (signed word)
{ "ev", 7, 1 }, // op1 minus op2 is even
{ NULL },
};
static const cond_text_t D8[] = // d should be 0!
{ // c f
{ "", 0, 0 }, // never
{ "=", 1, 0 }, // op1 is equal to negative of op2 (word)
{ "<", 2, 0 }, // op1 is less than negative of op2 (signed word)
{ "<=", 3, 0 }, // op1 is less than or equal to negative of op2 (signed word)
{ "nuv", 4, 0 }, // op1 plus op2 does not overflow (unsigned word)
{ "*=", 5, 0 }, // op1 is equal to negative of op2 (doubleword)
{ "*<", 6, 0 }, // op1 is less than negative of op2 (signed doubleword)
{ "*<=", 7, 0 }, // op1 is less than or equal to negative of op2 (signed doubleword)
{ "tr", 0, 1 }, // always
{ "<>", 1, 1 }, // op1 is not equal to negative of op2 (word)
{ ">=", 2, 1 }, // op1 is greater than or equal to negative of op2 (signed word)
{ ">", 3, 1 }, // op1 is greater than negative of op2 (signed word)
{ "uv", 4, 1 }, // op1 plus op2 overflows (unsigned word)
{ "*<>", 5, 1 }, // op1 is not equal to negative of op2 (doubleword)
{ "*>=", 6, 1 }, // op1 is greater than or equal to negative of op2 (signed doubleword)
{ "*>", 7, 1 }, // op1 is greater than negative of op2 (signed doubleword)
{ NULL },
};
static const cond_text_t D9[] = // and D10 combined
{ // c f
{ "", 0, 0 }, // never
{ "=", 1, 0 }, // all bits in word are 0
{ "<", 2, 0 }, // leftmost bit in word is 1
{ "<=", 3, 0 }, // leftmost bit in word is 1 or all bits in word are 0
{ "od", 7, 0 }, // rightmost bit is 1
{ "tr", 0, 1 }, // always
{ "<>", 1, 1 }, // some bits in word are 1
{ ">=", 2, 1 }, // leftmost bit in word is 0
{ ">", 3, 1 }, // leftmost bit in word is 0 and some bits in word are 1
{ "ev", 7, 1 }, // rightmost bit is 0
};
static const cond_text_t D11[] = // and D12 combined
{ // c f
{ "", 0, 0 }, // never
{ "swz", 1, 0 }, // 64! some word zero
{ "sbz", 2, 0 }, // some byte zero
{ "shz", 3, 0 }, // some halfword zero
{ "sdc", 4, 0 }, // some digit carry
{ "swc", 5, 0 }, // 64! some word carry
{ "sbc", 6, 0 }, // some byte carry
{ "shc", 7, 0 }, // some halfword carry
{ "tr", 0, 1 }, // always
{ "nwz", 1, 1 }, // 64! no word zero
{ "nbz", 2, 1 }, // no byte zero
{ "nhz", 3, 1 }, // no halfword zero
{ "ndc", 4, 1 }, // no digit carry
{ "nwc", 5, 1 }, // 64! no word carry
{ "nbc", 6, 1 }, // no byte carry
{ "nhc", 7, 1 }, // no halfword carry
};
static const cond_text_t D13[] = // and D14 combined (f should be 0)
{ // c f
{ "", 0, 0 }, // never
{ "=", 1, 0 }, // all bits in word are 0
{ "<", 2, 0 }, // leftmost bit in word is 1
{ "od", 3, 0 }, // rightmost bit is 1
{ "tr", 4, 0 }, // always
{ "<>", 5, 0 }, // some bits in word are 1
{ ">=", 6, 0 }, // leftmost bit in word is 0
{ "ev", 7, 0 }, // rightmost bit is 0
};
static const cond_text_t D15[] = // (f should be 0)
{ // c f
{ "<", 0, 0 }, // leftmost bit in word is 1
{ ">=", 1, 0 }, // leftmost bit in word is 0
};
static char *append_conds(
const cond_text_t *table,
int c,
int f,
int d,
char *ptr,
char *end)
{
if ( !d && table == D11 && (c == 1 || c == 5) )
return NULL;
while ( table->text != NULL )
{
if ( table->c == c && table->f == f )
{
if ( table->text[0] != '\0' )
{
APPCHAR(ptr, end, ',');
if ( d != 0 )
APPCHAR(ptr, end, '*');
APPEND(ptr, end, table->text);
}
return ptr;
}
table++;
}
return NULL;
}
//--------------------------------------------------------------------------
// short displacement load and store instruction completers
static const char *h1_comp(int a, int m, int im5)
{
if ( m )
{
if ( a )
return ",mb"; // a=1 m=1
return im5
? ",ma" // a=0 m=1 im5 != 0
: ",o"; // a=0 m=1 im5 == 0
}
return ""; // m=0
}
//--------------------------------------------------------------------------
// store bytes instruction completers
static const char *h2_comp(int a, int m)
{
static const char *const suffixes[] =
{
"", // beginning case, don't modify base register
",b,m", // beginning case, modify base register
",e", // ending case, don't modify base register
",e,m" // ending case, modify base register
};
int idx = (a<<1) | m;
return suffixes[idx & 3];
}
//--------------------------------------------------------------------------
// indexed instruction completers
static const char *h3_comp(int u, int m)
{
static const char *const suffixes[] =
{
"", // no index shift, don't modify base register
",m", // no index shift, modify base register
",s", // shift index by data size, don't modify base register
",sm" // shift index by data size, modify base register
};
int idx = (u<<1) | m;
return suffixes[idx & 3];
}
//--------------------------------------------------------------------------
static char *append_cc(char *ptr, const char *end, int cc, bool isload)
{
static const char *const ld_suffixes[] = { "", NULL, ",sl", NULL };
static const char *const st_suffixes[] = { "", ",bc", ",sl", NULL };
const char *comp = (isload ? ld_suffixes : st_suffixes)[cc];
if ( comp == NULL )
return NULL;
APPEND(ptr, end, comp);
return ptr;
}
//--------------------------------------------------------------------------
static char *ldst_short(const insn_t &insn, uint32 code, char *ptr, const char *end)
{
int cc = (code>>10) & 3;
int m = (code & BIT26) ? 1 : 0;
int a = (code & BIT18) ? 1 : 0;
const char *comp;
if ( code & BIT19 )
{
int im5 = (code>>16) & 0x1F;
comp = h1_comp(a, m, im5);
}
else
{
int u = a;
comp = h3_comp(u, m);
}
bool isload;
switch ( insn.itype )
{
default:
INTERR(10125); //-V796 no break
case HPPA_cldd:
case HPPA_cldw:
case HPPA_ldb:
case HPPA_ldcd:
case HPPA_ldcw:
case HPPA_ldd:
case HPPA_ldda:
case HPPA_ldh:
case HPPA_ldw:
case HPPA_ldwa:
case HPPA_fldd:
case HPPA_fldw:
isload = true;
break;
case HPPA_stby:
case HPPA_stdby:
comp = h2_comp(a, m);
// no break
case HPPA_cstd:
case HPPA_cstw:
case HPPA_stb:
case HPPA_std:
case HPPA_stda:
case HPPA_sth:
case HPPA_stw:
case HPPA_stwa:
case HPPA_fstd:
case HPPA_fstw:
isload = false;
break;
}
APPEND(ptr, end, comp);
ptr = append_cc(ptr, end, cc, isload);
return ptr;
}
//--------------------------------------------------------------------------
static const char *const fpp_comp[] =
{
"false?", // 0
"false", // 1
"?", // 2
"!<=>", // 3
"=", // 4
"=T", // 5
"?=", // 6
"!<>", // 7
"!?>=", // 8
"<", // 9
"?<", // 10
"!>=", // 11
"!?>", // 12
"<=", // 13
"?<=", // 14
"!>", // 15
"!?<=", // 16
">", // 17
"?>", // 18
"!<=", // 19
"!?<", // 20
">=", // 21
"?>=", // 22
"!<", // 23
"!?=", // 24
"<>", // 25
"!=", // 26
"!=T", // 27
"!?", // 28
"<=>", // 29
"true?", // 30
"true", // 31
};
static const char *const fpp_test[] =
{
"", // 0
"acc", // 1
",rej", // 2
NULL, // 3
NULL, // 4
",acc8", // 5
",rej8", // 6
NULL, // 7
NULL, // 8
",acc6", // 9
NULL, // 10
NULL, // 11
NULL, // 12
",acc4", // 13
NULL, // 14
NULL, // 15
NULL, // 16
",acc2", // 17
NULL, // 18
NULL, // 19
NULL, // 20
NULL, // 21
NULL, // 22
NULL, // 23
NULL, // 24
NULL, // 25
NULL, // 26
NULL, // 27
NULL, // 28
NULL, // 29
NULL, // 30
NULL, // 31
};
static const char *const fpp_sngop[] =
{
"", // 0 or sgl
",dbl", // 1
NULL, // 2
",quad", // 3
};
//--------------------------------------------------------------------------
inline char *append_fmt(int fmt, char *ptr, const char *end)
{
if ( fmt == 2 || fmt > 3 )
return NULL;
APPEND(ptr, end, fpp_sngop[fmt]);
return ptr;
}
//--------------------------------------------------------------------------
char *hppa_t::build_insn_completer(const insn_t &insn, uint32 code, char *buf, size_t bufsize)
{
char *ptr = buf;
char *const end = buf + bufsize;
switch ( insn.itype )
{
case HPPA_ldo: // format 1 (special case)
case HPPA_ldi: // pseudo-op
case HPPA_nop: // pseudo-op
case HPPA_copy: // pseudo-op (ldo or or)
break;
case HPPA_ldb: // formats 1-5
case HPPA_ldcd:
case HPPA_ldcw:
case HPPA_ldd:
case HPPA_ldda:
case HPPA_ldh:
case HPPA_ldw:
case HPPA_ldwa:
case HPPA_stb:
case HPPA_stby:
case HPPA_std:
case HPPA_stda:
case HPPA_stdby:
case HPPA_sth:
case HPPA_stw:
case HPPA_stwa:
case HPPA_fldd:
case HPPA_fldw:
case HPPA_fstd:
case HPPA_fstw:
switch ( opcode(code) )
{
case 0x10: // format 1
case 0x11:
case 0x12:
case 0x18:
case 0x19:
case 0x1A:
case 0x17: // format 2
case 0x1F:
// nothing to do
break;
case 0x13: // ldw (mod)
case 0x1B: // stw (mod)
{
sval_t off = insn.itype == HPPA_ldw ? insn.Op1.addr : insn.Op2.addr;
APPEND(ptr, end, off < 0 ? ",mb" : ",ma");
}
break;
case 0x14: // format 3
case 0x1C:
{
int m = (code & BIT28) ? 1 : 0;
int a = (code & BIT29) ? 1 : 0;
int im10a = ((code >> 3) & 0x7FE) | (code & 1);
APPEND(ptr, end, h1_comp(a, m, im10a));
}
break;
case 0x16: // format 44 (fldw)
case 0x1E: // format 44 (fstw)
{
int m = 0;
int a = (code & BIT29) ? 1 : 0;
int im11a = ((code >> 2) & 0xFFE) | (code & 1);
APPEND(ptr, end, h1_comp(a, m, im11a));
}
break;
case 0x03: // formats 4 & 5
case 0x09: // formats 39 & 41
case 0x0B: // formats 39 & 41
ptr = ldst_short(insn, code, ptr, end);
break;
default:
interr(insn, "format1");
}
break;
case HPPA_addil: // format 7
case HPPA_ldil:
break;
case HPPA_hadd: // format 8 (special case)
case HPPA_hsub:
{
int sat = (code>>6) & 3;
static const char *const suffixes[4] = { ",us", ",ss", NULL, "" };
if ( sat == 2 )
return NULL;
APPEND(ptr, end, suffixes[sat]);
}
case HPPA_havg: // format 8 (special case2)
case HPPA_hshladd:
case HPPA_hshradd:
break;
case HPPA_add: // format 8
case HPPA_and:
case HPPA_andcm:
case HPPA_cmpclr:
case HPPA_dcor:
case HPPA_ds:
case HPPA_or:
case HPPA_shladd:
case HPPA_sub:
case HPPA_uaddcm:
case HPPA_uxor:
case HPPA_xor:
{
int c = (code>>13) & aux_cndc;
int f = (code & BIT19) ? 1 : 0; // aux_cndf
int d = (code & BIT26) ? 1 : 0; // aux_cndd
const cond_text_t *table = NULL;
switch ( insn.itype )
{
case HPPA_cmpclr:
case HPPA_ds:
table = D3;
break;
case HPPA_add:
case HPPA_shladd:
{
int e1 = (code>>10) & 3;
int e2 = (code & BIT23) ? 1 : 0;
if ( !e1 )
return NULL;
if ( e1 == 2 && e2 )
return NULL; // not defined
if ( e2 )
APPEND(ptr, end, d ? ",dc" : ",c");
static const char *const suffixes[4] = { "", "", ",l", ",tsv" };
APPEND(ptr, end, suffixes[e1]);
}
table = D6;
break;
case HPPA_sub:
{
int e1 = (code>>10) & 3;
int e2 = (code & BIT23) ? 1 : 0;
int e3 = (code>> 6) & 3;
if ( e1 != 1 && e1 != 3 )
return NULL;
if ( e3 != 0 && e3 != 3 )
return NULL;
if ( e2 && e3 )
return NULL;
if ( e2 )
APPEND(ptr, end, d ? ",db" : ",b");
if ( e3 )
APPEND(ptr, end, ",tc");
if ( e1 == 3 )
APPEND(ptr, end, ",tsv");
}
table = D3;
break;
case HPPA_or:
case HPPA_and:
case HPPA_andcm:
case HPPA_xor:
table = D9;
break;
case HPPA_uaddcm:
{
int e1 = (code>>6) & 3;
if ( e1 != 2 && e1 != 3 )
return NULL;
if ( e1 == 3 )
APPEND(ptr, end, ",tc");
}
table = D11;
break;
case HPPA_dcor:
{
int e1 = (code>>6) & 3;
if ( e1 != 2 && e1 != 3 )
return NULL;
if ( e1 == 3 )
APPEND(ptr, end, ",i");
}
table = D11;
break;
case HPPA_uxor:
table = D11;
if ( c > 3 )
return NULL; // disable carry conditions
break;
default:
interr(insn, "format8");
}
ptr = append_conds(table, c, f, d, ptr, end);
}
break;
case HPPA_addi: // format 9 (special case)
case HPPA_subi:
{
if ( (code & BIT20) != 0 )
APPEND(ptr, end, ",tsv");
if ( opcode(code) == 0x2C )
APPEND(ptr, end, ",tc");
int c = (code>>13) & 7;
int f = (code & BIT19) ? 1 : 0;
ptr = append_conds(insn.itype == HPPA_subi ? D3 : D6, c, f, 0, ptr, end);
}
break;
case HPPA_cmpiclr: // format 9
{
int c = (code>>13) & 7;
int f = (code & BIT19) ? 1 : 0;
int d = (code & BIT20) ? 1 : 0;
ptr = append_conds(D3, c, f, d, ptr, end);
}
break;
case HPPA_permh: // format 10
{
int c0 = (code>>13) & 3;
int c1 = (code>>10) & 3;
int c2 = (code>> 8) & 3;
int c3 = (code>> 6) & 3;
ptr += qsnprintf(ptr, end-ptr, ",%d%d%d%d", c0, c1, c2, c3);
}
break;
case HPPA_mixh: // format 10
case HPPA_mixw:
{
int ea = (code>>13) & 3;
if ( ea & 1 )
return NULL;
APPEND(ptr, end, ea ? ",r" : ",l");
}
break;
case HPPA_hshr: // format 10
{
int se = (code>>10) & 3;
if ( se < 2 )
return NULL;
if ( se == 2 )
APPEND(ptr, end, ",u");
}
case HPPA_hshl: // format 10 (special case)
break;
case HPPA_shrpd: // formats 11 & 14
case HPPA_shrpw:
ptr = append_conds(D13, (code>>13) & 7, 0, insn.itype == HPPA_shrpd, ptr, end);
break;
case HPPA_extrd: // formats 12 & 15
case HPPA_extrw:
case HPPA_shrd: // pseudo-op
case HPPA_shrw: // pseudo-op
if ( (code & BIT21) == 0 )
APPEND(ptr, end, ",u");
ptr = append_conds(D13, (code>>13) & 7, 0, insn.itype == HPPA_extrd, ptr, end);
break;
case HPPA_depd: // formats 13 & 16
case HPPA_depdi:
case HPPA_depw:
case HPPA_depwi:
case HPPA_shld: // pseudo-op
case HPPA_shlw: // pseudo-op
{
int nz = (code & BIT21) ? 1 : 0;
int c = (code>>13) & 7;
int d = 0;
switch ( insn.itype )
{
case HPPA_depd:
case HPPA_depdi:
++d;
case HPPA_depw:
case HPPA_depwi:
break;
default:
interr(insn, "format13");
}
if ( !nz && insn.itype < HPPA_call )
APPEND(ptr, end, ",z");
ptr = append_conds(D13, c, 0, d, ptr, end);
}
break;
case HPPA_addb: // format 17
case HPPA_addib:
case HPPA_cmpb:
case HPPA_cmpib:
case HPPA_movb:
case HPPA_movib:
{
int c = (code>>13) & 7;
int f = 0;
const cond_text_t *table = psw_w() ? D8 : D6;
switch ( opcode(code) )
{
case 0x20: // cmpb
case 0x21: // cmpib
case 0x27: // cmpb
table = D3;
case 0x28: // addb
case 0x29: // addib
break;
case 0x22: // cmpb
case 0x23: // cmpib
case 0x2F: // cmpb
table = D3;
// fallthrough
case 0x2A: // addb
case 0x2B: // addib
++f;
break;
case 0x32: // movb
case 0x33: // movib
table = D13;
break;
case 0x3B: // cmpib 64 bit
table = D5;
break;
default:
interr(insn, "format17");
}
ptr = append_conds(table, c, f, 0, ptr, end);
if ( ptr == NULL )
return NULL;
}
goto NULLIFY;
case HPPA_bb: // format 18
{
int c = (code & BIT16) ? 1 : 0;
int d = (code & BIT18) ? 1 : 0;
ptr = append_conds(D15, c, 0, d, ptr, end);
}
goto NULLIFY;
case HPPA_be: // format 19
if ( opcode(code) == 0x39 )
APPEND(ptr, end, ",l");
goto NULLIFY;
case HPPA_b: // format 20
if ( insn.Op2.type != o_void )
{
int subopcode = (code>>13) & 7;
if ( subopcode >= 6 )
goto BVE;
static const char *const suffixes[8] =
{
",l", ",gate", NULL, NULL,
",push", ",l", NULL, NULL
};
const char *s = suffixes[subopcode];
if ( s == NULL )
return NULL;
APPEND(ptr, end, s);
}
goto NULLIFY;
case HPPA_blr: // format 21
case HPPA_bv:
case HPPA_call: // pseudo-op
NULLIFY:
if ( (code & BIT30) != 0 )
APPEND(ptr, end, ",n");
break;
case HPPA_bve: // format 22
case HPPA_ret: // pseudo-op
BVE:
{
int subopcode = (code>>13) & 7;
if ( subopcode != 6 && subopcode != 7 )
return NULL;
if ( subopcode == 7 && insn.itype == HPPA_bve )
APPEND(ptr, end, ",l");
if ( (code & BIT31) != 0 )
APPEND(ptr, end, (subopcode == 7) ? ",push" : ",pop");
}
goto NULLIFY;
case HPPA_clrbts: // format 23
case HPPA_popbts:
case HPPA_pushbts:
case HPPA_pushnom:
break;
case HPPA_pdtlb: // formats 24 & 25 & 26
case HPPA_pitlb:
if ( (code & BIT21) != 0 )
APPEND(ptr, end, ",l");
// no break
case HPPA_fdc:
case HPPA_fdce:
case HPPA_fic:
case HPPA_fice:
case HPPA_lpa:
case HPPA_pdc:
case HPPA_pdtlbe:
case HPPA_pitlbe:
if ( (code & BIT26) != 0 )
APPEND(ptr, end, ",m");
case HPPA_lci: // format 24 (special case)
break;
case HPPA_probe: // format 24 (special case)
case HPPA_probei:
APPEND(ptr, end, (code & BIT25) != 0 ? ",w" : ",r");
break;
case HPPA_idtlbt: // format 26
case HPPA_iitlbt:
break;
case HPPA_break: // format 27
break;
case HPPA_diag: // format 28
break;
case HPPA_mfsp: // format 29
case HPPA_mtsp:
break;
case HPPA_ldsid: // format 30
break;
case HPPA_mtctl: // format 31
case HPPA_mtsar: // pseudo-op
case HPPA_mtsarcm:
break;
case HPPA_mfctl: // format 32
if ( (code & BIT17) != 0 )
APPEND(ptr, end, ",w");
case HPPA_mfia: // format 32 (special case)
break;
case HPPA_rfi: // format 33
{
int e1 = (code>>5) & 0xF;
if ( e1 != 0 && e1 != 5 )
return NULL;
if ( e1 == 5 )
APPEND(ptr, end, ",r");
}
case HPPA_mtsm: // format 33
case HPPA_rsm:
case HPPA_ssm:
case HPPA_sync:
case HPPA_syncdma:
break;
case HPPA_spop0: // format 34
{
int sfu = (code>> 6) & 7;
int sop1 = (code>>11) & 0x7FFF;
int sop2 = (code>> 0) & 0x1F;
uint32 sop = (sop1 << 5) | sop2;
ptr += qsnprintf(ptr, end-ptr, ",%d,", sfu);
ptr += btoa(ptr, end-ptr, sop);
}
goto NULLIFY2;
case HPPA_spop1: // format 35
{
int sfu = (code>> 6) & 7;
uint32 sop = (code>>11) & 0x7FFF;
ptr += qsnprintf(ptr, end-ptr, ",%d,", sfu);
ptr += btoa(ptr, end-ptr, sop);
}
goto NULLIFY2;
case HPPA_spop2: // format 36
{
int sfu = (code>> 6) & 7;
int sop1 = (code>>11) & 0x3FF;
int sop2 = (code>> 0) & 0x1F;
uint32 sop = (sop1 << 5) | sop2;
ptr += qsnprintf(ptr, end-ptr, ",%d,", sfu);
ptr += btoa(ptr, end-ptr, sop);
}
goto NULLIFY2;
case HPPA_spop3: // format 37
{
int sfu = (code>> 6) & 7;
int sop1 = (code>>11) & 0x1F;
int sop2 = (code>> 0) & 0x1F;
uint32 sop = (sop1 << 5) | sop2;
ptr += qsnprintf(ptr, end-ptr, ",%d,", sfu);
ptr += btoa(ptr, end-ptr, sop);
}
goto NULLIFY2;
case HPPA_copr: // format 38
{
int uid = (code>> 6) & 7;
uint32 sop = (code & 0x1F) | ((code>>4)&(0x1FFFF<<5));
ptr += qsnprintf(ptr, end-ptr, ",%d,", uid);
ptr += btoa(ptr, end-ptr, sop);
}
goto NULLIFY2;
case HPPA_pmdis: // format 55
NULLIFY2:
{
int n = (code & BIT26) ? 1 : 0;
if ( n != 0 )
APPEND(ptr, end, ",n");
}
break;
case HPPA_cldd: // formats 39 & 41
case HPPA_cldw:
case HPPA_cstd: // formats 40 & 42
case HPPA_cstw:
{
int uid = (code>> 6) & 7;
ptr += qsnprintf(ptr, end-ptr, ",%d", uid);
ptr = ldst_short(insn, code, ptr, end);
}
break;
case HPPA_fabs: // formats 45 & 49
case HPPA_fcpy:
case HPPA_fneg:
case HPPA_fnegabs:
case HPPA_frem:
case HPPA_frnd:
case HPPA_fsqrt:
case HPPA_fadd: // formats 48 & 52
case HPPA_fdiv:
case HPPA_fmpy:
case HPPA_fsub:
{
int fmt = 0;
switch ( opcode(code) )
{
case 0x0E: // formats 49 & 52
fmt = (code>>11) & 1;
break;
case 0x0C: // formats 45 & 48
fmt = (code>>11) & 3;
break;
default:
INTERR(10126);
}
ptr = append_fmt(fmt, ptr, end);
}
break;
case HPPA_fid: // format 45
break;
case HPPA_fcnv: // formats 46 & 50
{
int sub = (code>>15) & 7;
int df, sf;
if ( opcode(code) == 0x0E ) // format 50
{
df = (code>>13) & 1;
sf = (code>>11) & 1;
}
else // format 46
{
df = (code>>13) & 3;
sf = (code>>11) & 3;
}
if ( sf == 2 || df == 2 )
return NULL;
if ( (sub & 3) == 3 )
APPEND(ptr, end, ",t"); // with explicit round to zero
static const char *const cnv_fpp[] = { ",sgl", ",dbl", NULL, ",quad" };
static const char *const cnv_sfx[] = { ",w", ",dw", NULL, ",qw" };
static const char *const cnv_ufx[] = { ",uw", ",udw", NULL, ",uqw" };
const char *const *s1 = NULL;
const char *const *s2 = NULL;
switch ( sub )
{
case 0: // fpp->fpp
s1 = cnv_fpp;
s2 = cnv_fpp;
break;
case 2: // fpp->fix
case 3: // fpp->fix with explicit round to zero
s1 = cnv_fpp;
s2 = cnv_sfx;
break;
case 6: // fpp->unsigned fix
case 7: // fpp->unsigned fix with explicit round to zero
s1 = cnv_fpp;
s2 = cnv_ufx;
break;
case 4: // undefined
return NULL;
case 1: // fix->fpp
s1 = cnv_sfx;
s2 = cnv_fpp;
break;
case 5: // unsigned fix->fpp
s1 = cnv_ufx;
s2 = cnv_fpp;
break;
}
APPEND(ptr, end, s1[sf]);
APPEND(ptr, end, s2[df]);
}
break;
case HPPA_fcmp: // formats 47 & 51
if ( opcode(code) == 0x0C )
{
int fmt = (code>>11) & 3;
ptr = append_fmt(fmt, ptr, end);
if ( ptr == NULL )
return NULL;
}
{
int c = code & 0x1F;
APPCHAR(ptr, end, ',');
APPEND(ptr, end, fpp_comp[c]);
}
break;
case HPPA_ftest: // format 47
{
int y = (code>>13) & 7;
if ( y == 1 ) // queue test
{
int c = code & 0x1F;
const char *s = fpp_test[c];
if ( s == NULL )
return NULL;
APPEND(ptr, end, s);
}
}
break;
case HPPA_xmpyu: // format 52
break;
case HPPA_fmpyadd: // format 53
case HPPA_fmpysub:
{
int f = (code>>5) & 1;
if ( f == 0 )
APPEND(ptr, end, ",dbl");
}
break;
case HPPA_fmpyfadd: // format 54
case HPPA_fmpynfadd:
{
int f = (code>>11) & 1;
if ( f != 0 )
APPEND(ptr, end, ",dbl");
}
break;
default:
interr(insn, "build_insn_completer");
}
if ( ptr == NULL )
return NULL;
APPZERO(ptr, end);
return buf;
}
//----------------------------------------------------------------------
class out_hppa_t : public outctx_t
{
out_hppa_t(void) = delete; // not used
public:
void out_bad_address(ea_t addr);
void outreg(int r);
void out_ip_rel(int displ);
void out_memref(ea_t ea);
void resolve_possible_memref(const op_t &x);
bool out_operand(const op_t &x);
void out_insn(void);
void out_proc_mnem(void);
};
CASSERT(sizeof(out_hppa_t) == sizeof(outctx_t));
DECLARE_OUT_FUNCS(out_hppa_t)
//----------------------------------------------------------------------
void out_hppa_t::out_bad_address(ea_t addr)
{
out_tagon(COLOR_ERROR);
out_btoa(addr, 16);
out_tagoff(COLOR_ERROR);
remember_problem(PR_NONAME, insn.ea);
}
//----------------------------------------------------------------------
void out_hppa_t::outreg(int r)
{
bool right = false;
out_tagon(COLOR_REG);
if ( r >= F0+32 && r < F0+64 // fpp register half
&& insn.itype != HPPA_fmpyadd
&& insn.itype != HPPA_fmpysub )
{
r -= 32;
right = true;
}
out_line(ph.reg_names[r]);
if ( right )
out_char('r');
out_tagoff(COLOR_REG);
}
//----------------------------------------------------------------------
void out_hppa_t::out_ip_rel(int displ)
{
out_printf(COLSTR("%s+", SCOLOR_SYMBOL) COLSTR("%d", SCOLOR_NUMBER),
ash.a_curip, displ);
}
//----------------------------------------------------------------------
bool out_hppa_t::out_operand(const op_t &x)
{
switch ( x.type )
{
case o_void:
return 0;
case o_imm:
out_value(x, OOF_SIGNED|OOFS_IFSIGN|OOFW_IMM);
break;
case o_reg:
outreg(x.reg);
break;
case o_near:
{
ea_t ea = calc_mem(x.addr);
if ( ea == insn.ea+4 )
out_ip_rel(4);
else if ( !out_name_expr(x, ea, ea) )
out_bad_address(x.addr);
}
break;
case o_displ:
out_value(x, OOF_ADDR|OOFS_IFSIGN|OOF_SIGNED|OOFW_32);
// no break
case o_based:
OUT_PHRASE:
out_symbol('(');
if ( insn.auxpref & aux_space )
{
outreg(x.sid);
out_symbol(',');
}
outreg(x.phrase);
out_symbol(')');
break;
case o_phrase:
outreg(x.secreg);
goto OUT_PHRASE;
default:
interr(insn, "out");
break;
}
return 1;
}
//----------------------------------------------------------------------
void out_hppa_t::out_memref(ea_t ea)
{
out_char(' ');
out_line(ash.cmnt, COLOR_AUTOCMT);
out_char(' ');
if ( has_any_name(get_flags(ea)) )
{
qstring nbuf = get_colored_name(ea);
out_line(nbuf.c_str());
}
else
{
// do not sign extend values that fit 32 bits
#ifdef __EA64__
if ( int32(ea) == ea )
ea = uint32(ea);
#endif
out_printf("%0*a", 8, ea);
}
}
//----------------------------------------------------------------------
void out_hppa_t::resolve_possible_memref(const op_t &x)
{
hppa_t &pm = *static_cast<hppa_t *>(procmod);
ea_t ea = pm.calc_possible_memref(insn, x);
if ( ea != BADADDR )
out_memref(ea);
}
//----------------------------------------------------------------------
void out_hppa_t::out_proc_mnem(void)
{
hppa_t &pm = *static_cast<hppa_t *>(procmod);
char postfix[80];
uint32 code = get_dword(insn.ea);
char *pfx = pm.build_insn_completer(insn, code, postfix, sizeof(postfix));
out_mnem(16, pfx);
}
//----------------------------------------------------------------------
void out_hppa_t::out_insn(void)
{
// output instruction mnemonics
out_mnemonic();
int i;
bool comma = false;
for ( i=0; i < PROC_MAXOP; i++ )
{
if ( insn.ops[i].type == o_void )
continue;
if ( comma )
{
out_symbol(',');
out_char(' ');
}
comma = out_one_operand(i);
}
out_immchar_cmts();
if ( insn.Op1.type == o_displ )
resolve_possible_memref(insn.Op1);
if ( insn.Op2.type == o_displ )
resolve_possible_memref(insn.Op2);
flush_outbuf();
}
//--------------------------------------------------------------------------
//lint -esym(818, Srange) could be made const
void hppa_t::hppa_segstart(outctx_t &ctx, segment_t *Srange) const
{
const char *const predefined[] =
{
".text", // Text section
".data", // Data sections
".rdata",
".comm",
};
if ( is_spec_segm(Srange->type) )
return;
qstring sname;
qstring sclas;
get_segm_name(&sname, Srange);
get_segm_class(&sclas, Srange);
if ( !print_predefined_segname(ctx, &sname, predefined, qnumber(predefined)) )
ctx.gen_printf(DEFAULT_INDENT,
COLSTR(".section %s", SCOLOR_ASMDIR) "" COLSTR("%s %s", SCOLOR_AUTOCMT),
sname.c_str(),
ash.cmnt,
sclas.c_str());
}
//--------------------------------------------------------------------------
//lint -esym(1764, ctx) could be made const
void hppa_t::hppa_assumes(outctx_t &ctx) // function to produce assume directives
{
ea_t ea = ctx.insn_ea;
if ( (inf_get_outflags() & OFLG_GEN_ASSUME) == 0 || got == BADADDR )
return;
sreg_range_t sra;
if ( !get_sreg_range(&sra, ea, DPSEG) || sra.start_ea != ea )
return;
if ( sra.val == BADSEL )
ctx.gen_printf(DEFAULT_INDENT,
COLSTR("%s %s is unknown", SCOLOR_ASMDIR),
ash.cmnt, ph.reg_names[DPSEG]);
else
ctx.gen_printf(DEFAULT_INDENT,
COLSTR("%s %s = %0*a", SCOLOR_ASMDIR),
ash.cmnt, ph.reg_names[DPSEG], 8, got + sra.val);
}
//--------------------------------------------------------------------------
void idaapi hppa_segend(outctx_t &, segment_t *)
{
}
//--------------------------------------------------------------------------
void idaapi hppa_header(outctx_t &ctx)
{
ctx.gen_header(GH_PRINT_ALL);
}
//--------------------------------------------------------------------------
void hppa_t::hppa_footer(outctx_t &ctx) const
{
qstring nbuf = get_colored_name(inf_get_start_ea());
const char *name = nbuf.c_str();
const char *end = ash.end;
if ( end == NULL )
ctx.gen_printf(DEFAULT_INDENT, COLSTR("%s end %s",SCOLOR_AUTOCMT), ash.cmnt, name);
else
ctx.gen_printf(DEFAULT_INDENT,
COLSTR("%s",SCOLOR_ASMDIR) " " COLSTR("%s %s",SCOLOR_AUTOCMT),
ash.end, ash.cmnt, name);
}