00cc9309cb
de6e324bdseparate emu thread10d3daf86Roms List improvements95d202f37Let's make the rom list process on a separate thread so the emulator doesnt take ages to load.fc306967fWow the ROM Header was just completely busted. Game list view works nowbad1691eefuck this shit2b59e5f46game list in progressd26417b83remappable inputs in progressac4af8106inpute72abc240update readme430139dc9Qt6 frontend3080d4d45Fix this small bug too08cd13b85Cop0 unused functions do not actually pose a threat (as per manual). They don't do anything, so shall we.61bb4fb44make idle loop detection a little more specific with where the load goesb037de4c3SAZDFsdff12e81e73eneed to figure out why n64-systemtest loops indefinitely at some address that appears to be valid (i think it's me not invalidating the cache properly)204f0e13bidle skipping seems to work!cb8bb634asdkfjlasdf58e5c89c1Fix compilation issue on my machine (no idea)24fb2898eattempting more serious idle skipping214719577Place rsp.Step inside cached interpreter. Gains about 3 more fpsbb97dcc23mmmmm920b77d38wjkhasdfjhkasdf430ccdab4it's a start...4f42a673aCached interpreter plays Mario 64. Start looking into RSP as wellc9a030787idle skipping works!5fbda03cenew idea366637abaIdle skipping... maybe?609fa2fb0Cache instructions implemented but broken lmao. Commented out for nowe140a6d12- Stop using inheritance for CPU, instead use composition. - Introduce KAIZEN_JIT_ENABLED optional define instead of relying on __aarch64__ and the like. - More cache work68e613057prep cache impl811b4d809fix clang formatfda755f7didkd5024ebbfsmall MI refactor in preparation of (eventually) implementing the RDRAM interface properly694b45341Merge commit '206dcdedf195fb320913584180edb12c7731e396' as 'external/SDL'206dcdedfSquashed 'external/SDL/' content from commit 4d17b99d0a4d16e1cb4need to update sdl848b19920Fix compilation errordb61b5299Merge commit 'e94a94559f28e49678fbcf72199a5258137b0fe9' as 'external/imgui'e94a94559Squashed 'external/imgui/' content from commit 02e9b8cac52edb3757need to update imguic1a705e86Emulate weird JALR behaviour4b4c32f4bFix exception for "unusable COP1" in 4 instructions i missed accidentally (again)df5828142Bug putting 0s in the log everywheref8b580048Make isviewer a sink to file8241e9735Fix exception for "unusable COP1" in 4 instructions i missed accidentallyb29715f20small changesd9a620bc1make use of my new small utility library0d1aa938eAdd 'external/ircolib/' from commit 'ce3cd726c8df8388d554abf8bb55d55020eb4450'e64eb40b3Fuck git git-subtree-dir: external/ircolib git-subtree-split:de6e324bde
3838 lines
86 KiB
C
3838 lines
86 KiB
C
/* Capstone Disassembly Engine */
|
|
/* By Dmitry Sibirtsev <sibirtsevdl@gmail.com>, 2023 */
|
|
|
|
#ifdef CAPSTONE_HAS_HPPA
|
|
|
|
#include <string.h>
|
|
#include <stddef.h> // offsetof macro
|
|
#include <stdio.h>
|
|
#include "HPPADisassembler.h"
|
|
#include "HPPAConstants.h"
|
|
|
|
#include "../../Mapping.h"
|
|
#include "../../MathExtras.h"
|
|
#include "../../utils.h"
|
|
|
|
#define CMPLT_HAS_MODIFY_BIT(CMPLT) (((CMPLT)&1) == 1)
|
|
|
|
#define HPPA_EXT_REF(MI) (&MI->hppa_ext)
|
|
|
|
static const char *const compare_cond_names[] = {
|
|
"", "=", "<", "<=", "<<", "<<=", "sv", "od",
|
|
"tr", "<>", ">=", ">", ">>=", ">>", "nsv", "ev"
|
|
};
|
|
static const char *const compare_cond_64_names[] = {
|
|
"*", "*=", "*<", "*<=", "*<<", "*<<=", "*sv", "*od",
|
|
"*tr", "*<>", "*>=", "*>", "*>>=", "*>>", "*nsv", "*ev"
|
|
};
|
|
static const char *const cmpib_cond_64_names[] = { "*<<", "*=", "*<", "*<=",
|
|
"*>>=", "*<>", "*>=", "*>" };
|
|
static const char *const add_cond_names[] = {
|
|
"", "=", "<", "<=", "nuv", "znv", "sv", "od",
|
|
"tr", "<>", ">=", ">", "uv", "vnz", "nsv", "ev"
|
|
};
|
|
static const char *const add_cond_64_names[] = {
|
|
"*", "*=", "*<", "*<=", "*nuv", "*znv", "*sv", "*od",
|
|
"*tr", "*<>", "*>=", "*>", "*uv", "*vnz", "*nsv", "*ev"
|
|
};
|
|
static const char *const wide_add_cond_names[] = {
|
|
"*", "=", "<", "<=", "nuv", "*=", "*<", "*<=",
|
|
"tr", "<>", ">=", ">", "uv", "*<>", "*>=", "*>"
|
|
};
|
|
static const char *const logical_cond_names[] = {
|
|
"", "=", "<", "<=", "", "", "", "od",
|
|
"tr", "<>", ">=", ">", "", "", "", "ev"
|
|
};
|
|
static const char *const logical_cond_64_names[] = {
|
|
"*", "*=", "*<", "*<=", "", "", "", "*od",
|
|
"*tr", "*<>", "*>=", "*>", "", "", "", "*ev"
|
|
};
|
|
static const char *const unit_cond_names[] = { "", "swz", "sbz", "shz",
|
|
"sdc", "swc", "sbc", "shc",
|
|
"tr", "nwz", "nbz", "nhz",
|
|
"ndc", "nwc", "nbc", "nhc" };
|
|
static const char *const unit_cond_64_names[] = {
|
|
"*", "*swz", "*sbz", "*shz", "*sdc", "*swc", "*sbc", "*shc",
|
|
"*tr", "*nwz", "*nbz", "*nhz", "*ndc", "*nwc", "*nbc", "*nhc"
|
|
};
|
|
static const char *const shift_cond_names[] = { "", "=", "<", "od",
|
|
"tr", "<>", ">=", "ev" };
|
|
static const char *const shift_cond_64_names[] = { "*", "*=", "*<", "*od",
|
|
"*tr", "*<>", "*>=", "*ev" };
|
|
static const char *const index_compl_names[] = { "", "m", "s", "sm" };
|
|
static const char *const short_ldst_compl_names[] = { "", "ma", "", "mb" };
|
|
static const char *const short_bytes_compl_names[] = { "", "b,m", "e", "e,m" };
|
|
static const char *const float_format_names[] = { "sgl", "dbl", "", "quad" };
|
|
static const char *const float_cond_names[] = {
|
|
"", "acc", "rej", "", "", "acc8", "rej8", "", "", "acc6", "",
|
|
"", "", "acc4", "", "", "", "acc2", "", "", "", "",
|
|
"", "", "", "", "", "", "", "", "", ""
|
|
};
|
|
static const char *const fcnv_fixed_names[] = { "w", "dw", "", "qw" };
|
|
static const char *const fcnv_ufixed_names[] = { "uw", "udw", "", "uqw" };
|
|
static const char *const float_comp_names[] = {
|
|
"false?", "false", "?", "!<=>", "=", "=t", "?=", "!<>",
|
|
"!?>=", "<", "?<", "!>=", "!?>", "<=", "?<=", "!>",
|
|
"!?<=", ">", "?>", "!<=", "!?<", ">=", "?>=", "!<",
|
|
"!?=", "<>", "!=", "!=t", "!?", "<=>", "true?", "true"
|
|
};
|
|
static const char *const signed_unsigned_names[] = { "u", "s" };
|
|
static const char *const saturation_names[] = { "us", "ss", "", "" };
|
|
static const char *const add_compl_names[] = { "", "", "l", "tsv" };
|
|
|
|
#define CREATE_GR_REG(MI, gr) MCOperand_CreateReg0(MI, gr + HPPA_REG_GR0)
|
|
#define CREATE_SR_REG(MI, sr) MCOperand_CreateReg0(MI, sr + HPPA_REG_SR0)
|
|
#define CREATE_CR_REG(MI, cr) MCOperand_CreateReg0(MI, cr + HPPA_REG_CR0)
|
|
#define CREATE_FPR_REG(MI, fpr) MCOperand_CreateReg0(MI, fpr + HPPA_REG_FPR0)
|
|
#define CREATE_FPE_REG(MI, fpe) MCOperand_CreateReg0(MI, fpe + HPPA_REG_FPE0)
|
|
#define CREATE_SP_FPR_REG(MI, fpr) \
|
|
MCOperand_CreateReg0(MI, fpr + HPPA_REG_SP_FPR0)
|
|
|
|
static void create_float_reg_spec(MCInst *MI, uint32_t reg, uint32_t fpe_flag)
|
|
{
|
|
if (fpe_flag == 1) {
|
|
CREATE_FPE_REG(MI, reg);
|
|
} else {
|
|
CREATE_FPR_REG(MI, reg);
|
|
}
|
|
}
|
|
|
|
/* Get at various relevant fields of an instruction word. */
|
|
|
|
#define MASK_5 0x1f
|
|
#define MASK_10 0x3ff
|
|
#define MASK_11 0x7ff
|
|
#define MASK_14 0x3fff
|
|
#define MASK_16 0xffff
|
|
#define MASK_21 0x1fffff
|
|
|
|
/* Routines to extract various sized constants out of hppa
|
|
instructions. */
|
|
|
|
/* Extract a 3-bit space register number from a be, ble, mtsp or mfsp. */
|
|
static int extract_3(unsigned word)
|
|
{
|
|
return get_insn_field(word, 18, 18) << 2 | get_insn_field(word, 16, 17);
|
|
}
|
|
|
|
static int extract_5_load(unsigned word)
|
|
{
|
|
return LowSignExtend64(word >> 16 & MASK_5, 5);
|
|
}
|
|
|
|
/* Extract the immediate field from a st{bhw}s instruction. */
|
|
|
|
static int extract_5_store(unsigned word)
|
|
{
|
|
return LowSignExtend64(word & MASK_5, 5);
|
|
}
|
|
|
|
/* Extract an 11 bit immediate field. */
|
|
|
|
static int extract_11(unsigned word)
|
|
{
|
|
return LowSignExtend64(word & MASK_11, 11);
|
|
}
|
|
|
|
/* Extract a 14 bit immediate field. */
|
|
|
|
static int extract_14(unsigned word)
|
|
{
|
|
return LowSignExtend64(word & MASK_14, 14);
|
|
}
|
|
|
|
/* Extract a 16 bit immediate field. */
|
|
|
|
static int extract_16(unsigned word, bool wide)
|
|
{
|
|
int m15, m0, m1;
|
|
|
|
m0 = get_insn_bit(word, 16);
|
|
m1 = get_insn_bit(word, 17);
|
|
m15 = get_insn_bit(word, 31);
|
|
word = (word >> 1) & 0x1fff;
|
|
if (wide) {
|
|
word = word | (m15 << 15) | ((m15 ^ m0) << 14) |
|
|
((m15 ^ m1) << 13);
|
|
} else {
|
|
word = word | (m15 << 15) | (m15 << 14) | (m15 << 13);
|
|
}
|
|
return SignExtend32(word, 16);
|
|
}
|
|
|
|
/* Extract a 21 bit constant. */
|
|
|
|
static int32_t extract_21(unsigned word)
|
|
{
|
|
int val;
|
|
|
|
word &= MASK_21;
|
|
word <<= 11;
|
|
val = get_insn_field(word, 20, 20);
|
|
val <<= 11;
|
|
val |= get_insn_field(word, 9, 19);
|
|
val <<= 2;
|
|
val |= get_insn_field(word, 5, 6);
|
|
val <<= 5;
|
|
val |= get_insn_field(word, 0, 4);
|
|
val <<= 2;
|
|
val |= get_insn_field(word, 7, 8);
|
|
return (uint32_t) SignExtend32(val, 21) << 11;
|
|
}
|
|
|
|
/* Extract a 12 bit constant from branch instructions. */
|
|
|
|
static int32_t extract_12(unsigned word)
|
|
{
|
|
return (uint32_t) SignExtend32(get_insn_field(word, 19, 28) |
|
|
get_insn_field(word, 29, 29) << 10 |
|
|
(word & 0x1) << 11,
|
|
12)
|
|
<< 2;
|
|
}
|
|
|
|
/* Extract a 17 bit constant from branch instructions, returning the
|
|
19 bit signed value. */
|
|
|
|
static int32_t extract_17(unsigned word)
|
|
{
|
|
return (uint32_t) SignExtend32(get_insn_field(word, 19, 28) |
|
|
get_insn_field(word, 29, 29) << 10 |
|
|
get_insn_field(word, 11, 15) << 11 |
|
|
(word & 0x1) << 16,
|
|
17)
|
|
<< 2;
|
|
}
|
|
|
|
static int32_t extract_22(unsigned word)
|
|
{
|
|
return (uint32_t) SignExtend32(get_insn_field(word, 19, 28) |
|
|
get_insn_field(word, 29, 29) << 10 |
|
|
get_insn_field(word, 11, 15) << 11 |
|
|
get_insn_field(word, 6, 10) << 16 |
|
|
(word & 0x1) << 21,
|
|
22)
|
|
<< 2;
|
|
}
|
|
|
|
static void push_str_modifier(hppa_ext *hppa, const char *modifier)
|
|
{
|
|
if (strcmp(modifier, "")) {
|
|
hppa_modifier *mod = &hppa->modifiers[hppa->mod_num++];
|
|
CS_ASSERT_RET(hppa->mod_num <= HPPA_MAX_MODIFIERS_LEN);
|
|
mod->type = HPPA_MOD_STR;
|
|
CS_ASSERT_RET(strlen(modifier) < HPPA_STR_MODIFIER_LEN);
|
|
strncpy(mod->str_mod, modifier, HPPA_STR_MODIFIER_LEN - 1);
|
|
}
|
|
}
|
|
|
|
static void push_int_modifier(hppa_ext *hppa, uint64_t modifier)
|
|
{
|
|
hppa_modifier *mod = &hppa->modifiers[hppa->mod_num++];
|
|
CS_ASSERT_RET(hppa->mod_num <= HPPA_MAX_MODIFIERS_LEN);
|
|
mod->type = HPPA_MOD_INT;
|
|
mod->int_mod = modifier;
|
|
}
|
|
|
|
static void fill_sysop_insn_name(MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t ext8 = get_insn_field(insn, 19, 26);
|
|
uint32_t ext5 = get_insn_field(insn, 11, 15);
|
|
if (MODE_IS_HPPA_20(MI->csh->mode)) {
|
|
switch (ext8) {
|
|
case 0xa5:
|
|
MCInst_setOpcode(MI, HPPA_INS_MFIA);
|
|
return;
|
|
case 0xc6:
|
|
MCInst_setOpcode(MI, HPPA_INS_MTSARCM);
|
|
return;
|
|
case 0x65:
|
|
push_str_modifier(HPPA_EXT_REF(MI), "r");
|
|
// fallthrough
|
|
case 0x60:
|
|
MCInst_setOpcode(MI, HPPA_INS_RFI);
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch (ext8) {
|
|
case 0x00:
|
|
MCInst_setOpcode(MI, HPPA_INS_BREAK);
|
|
break;
|
|
case 0x20:
|
|
if (ext5 == 0x00) {
|
|
MCInst_setOpcode(MI, HPPA_INS_SYNC);
|
|
} else if (ext5 == 0x10) {
|
|
MCInst_setOpcode(MI, HPPA_INS_SYNCDMA);
|
|
}
|
|
break;
|
|
case 0x60:
|
|
MCInst_setOpcode(MI, HPPA_INS_RFI);
|
|
break;
|
|
case 0x65:
|
|
MCInst_setOpcode(MI, HPPA_INS_RFIR);
|
|
break;
|
|
case 0x6b:
|
|
MCInst_setOpcode(MI, HPPA_INS_SSM);
|
|
break;
|
|
case 0x73:
|
|
MCInst_setOpcode(MI, HPPA_INS_RSM);
|
|
break;
|
|
case 0xc3:
|
|
MCInst_setOpcode(MI, HPPA_INS_MTSM);
|
|
break;
|
|
case 0x85:
|
|
MCInst_setOpcode(MI, HPPA_INS_LDSID);
|
|
break;
|
|
case 0xc1:
|
|
MCInst_setOpcode(MI, HPPA_INS_MTSP);
|
|
break;
|
|
case 0x25:
|
|
MCInst_setOpcode(MI, HPPA_INS_MFSP);
|
|
break;
|
|
case 0xc2:
|
|
MCInst_setOpcode(MI, HPPA_INS_MTCTL);
|
|
break;
|
|
case 0x45:
|
|
MCInst_setOpcode(MI, HPPA_INS_MFCTL);
|
|
if (get_insn_bit(insn, 17) == 1 &&
|
|
MODE_IS_HPPA_20(MI->csh->mode)) {
|
|
push_str_modifier(HPPA_EXT_REF(MI), "w");
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static bool decode_sysop(const cs_struct *ud, MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t ext8 = get_insn_field(insn, 19, 26);
|
|
uint32_t ext5 = get_insn_field(insn, 11, 15);
|
|
uint32_t r1 = get_insn_field(insn, 6, 10);
|
|
uint32_t r2 = get_insn_field(insn, 11, 15);
|
|
uint32_t t = get_insn_field(insn, 27, 31);
|
|
uint32_t s = extract_3(insn);
|
|
if (MODE_IS_HPPA_20(MI->csh->mode)) {
|
|
switch (ext8) {
|
|
case 0xa5:
|
|
if (ext5 != 0) {
|
|
return false;
|
|
}
|
|
CREATE_GR_REG(MI, t);
|
|
return true;
|
|
case 0xc6:
|
|
CREATE_GR_REG(MI, r2);
|
|
return true;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch (ext8) {
|
|
case 0x00:
|
|
MCOperand_CreateImm0(MI, t);
|
|
MCOperand_CreateImm0(MI, get_insn_field(insn, 6, 18));
|
|
return true;
|
|
case 0x20:
|
|
if (ext5 != 0x00 && ext5 != 0x10) {
|
|
return false;
|
|
}
|
|
// fallthrough
|
|
case 0x60:
|
|
case 0x65:
|
|
return true;
|
|
case 0x6b:
|
|
case 0x73:
|
|
MCOperand_CreateImm0(MI, get_insn_field(insn, 9, 15));
|
|
CREATE_GR_REG(MI, t);
|
|
return true;
|
|
case 0xc3:
|
|
CREATE_GR_REG(MI, r2);
|
|
return true;
|
|
case 0x85:
|
|
CREATE_SR_REG(MI, s);
|
|
CREATE_GR_REG(MI, r1);
|
|
CREATE_GR_REG(MI, t);
|
|
return true;
|
|
case 0xc1:
|
|
CREATE_GR_REG(MI, r2);
|
|
CREATE_SR_REG(MI, s);
|
|
return true;
|
|
case 0x25:
|
|
if (ext5 != 0) {
|
|
return false;
|
|
}
|
|
CREATE_SR_REG(MI, s);
|
|
CREATE_GR_REG(MI, t);
|
|
return true;
|
|
case 0xc2:
|
|
CREATE_GR_REG(MI, r2);
|
|
CREATE_CR_REG(MI, r1);
|
|
return true;
|
|
case 0x45:
|
|
if (ext5 != 0) {
|
|
return false;
|
|
}
|
|
if (get_insn_bit(insn, 17) == 1 && MODE_IS_HPPA_20(ud->mode) &&
|
|
r1 != 11) {
|
|
return false;
|
|
}
|
|
CREATE_CR_REG(MI, r1);
|
|
CREATE_GR_REG(MI, t);
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static void fill_memmgmt_insn_name(MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t ext = get_insn_field(insn, 19, 25);
|
|
if (MODE_IS_HPPA_20(MI->csh->mode)) {
|
|
switch (ext) {
|
|
case 0x20:
|
|
MCInst_setOpcode(MI, HPPA_INS_IITLBT);
|
|
return;
|
|
case 0x18:
|
|
MCInst_setOpcode(MI, HPPA_INS_PITLB);
|
|
push_str_modifier(HPPA_EXT_REF(MI), "l");
|
|
return;
|
|
case 0x60:
|
|
MCInst_setOpcode(MI, HPPA_INS_IDTLBT);
|
|
return;
|
|
case 0x58:
|
|
MCInst_setOpcode(MI, HPPA_INS_PDTLB);
|
|
push_str_modifier(HPPA_EXT_REF(MI), "l");
|
|
return;
|
|
case 0x4f:
|
|
MCInst_setOpcode(MI, HPPA_INS_FIC);
|
|
return;
|
|
case 0x46:
|
|
if (get_insn_bit(insn, 18) == 0) {
|
|
MCInst_setOpcode(MI, HPPA_INS_PROBE);
|
|
} else {
|
|
MCInst_setOpcode(MI, HPPA_INS_PROBEI);
|
|
};
|
|
push_str_modifier(HPPA_EXT_REF(MI), "r");
|
|
return;
|
|
case 0x47:
|
|
if (get_insn_bit(insn, 18) == 0) {
|
|
MCInst_setOpcode(MI, HPPA_INS_PROBE);
|
|
} else {
|
|
MCInst_setOpcode(MI, HPPA_INS_PROBEI);
|
|
};
|
|
push_str_modifier(HPPA_EXT_REF(MI), "w");
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch (ext) {
|
|
case 0x00:
|
|
MCInst_setOpcode(MI, HPPA_INS_IITLBP);
|
|
break;
|
|
case 0x01:
|
|
MCInst_setOpcode(MI, HPPA_INS_IITLBA);
|
|
break;
|
|
case 0x08:
|
|
MCInst_setOpcode(MI, HPPA_INS_PITLB);
|
|
break;
|
|
case 0x09:
|
|
MCInst_setOpcode(MI, HPPA_INS_PITLBE);
|
|
break;
|
|
case 0x0a:
|
|
MCInst_setOpcode(MI, HPPA_INS_FIC);
|
|
break;
|
|
case 0x0b:
|
|
MCInst_setOpcode(MI, HPPA_INS_FICE);
|
|
break;
|
|
case 0x40:
|
|
MCInst_setOpcode(MI, HPPA_INS_IDTLBP);
|
|
break;
|
|
case 0x41:
|
|
MCInst_setOpcode(MI, HPPA_INS_IDTLBA);
|
|
break;
|
|
case 0x48:
|
|
MCInst_setOpcode(MI, HPPA_INS_PDTLB);
|
|
break;
|
|
case 0x49:
|
|
MCInst_setOpcode(MI, HPPA_INS_PDTLBE);
|
|
break;
|
|
case 0x4a:
|
|
MCInst_setOpcode(MI, HPPA_INS_FDC);
|
|
break;
|
|
case 0x4b:
|
|
MCInst_setOpcode(MI, HPPA_INS_FDCE);
|
|
break;
|
|
case 0x4e:
|
|
MCInst_setOpcode(MI, HPPA_INS_PDC);
|
|
break;
|
|
case 0x46:
|
|
if (get_insn_bit(insn, 18) == 0) {
|
|
MCInst_setOpcode(MI, HPPA_INS_PROBER);
|
|
} else {
|
|
MCInst_setOpcode(MI, HPPA_INS_PROBERI);
|
|
};
|
|
break;
|
|
case 0x47:
|
|
if (get_insn_bit(insn, 18) == 0) {
|
|
MCInst_setOpcode(MI, HPPA_INS_PROBEW);
|
|
} else {
|
|
MCInst_setOpcode(MI, HPPA_INS_PROBEWI);
|
|
};
|
|
break;
|
|
case 0x4d:
|
|
MCInst_setOpcode(MI, HPPA_INS_LPA);
|
|
break;
|
|
case 0x4c:
|
|
MCInst_setOpcode(MI, HPPA_INS_LCI);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void fill_memmgmt_mods(uint32_t insn, hppa_ext *hppa_ext, cs_mode mode)
|
|
{
|
|
uint8_t cmplt = get_insn_bit(insn, 26);
|
|
uint32_t ext = get_insn_field(insn, 19, 25);
|
|
if (MODE_IS_HPPA_20(mode)) {
|
|
switch (ext) {
|
|
case 0x18:
|
|
case 0x58:
|
|
case 0x4f:
|
|
goto success;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch (ext) {
|
|
case 0x08:
|
|
case 0x09:
|
|
case 0x0a:
|
|
case 0x0b:
|
|
case 0x48:
|
|
case 0x49:
|
|
case 0x4a:
|
|
case 0x4b:
|
|
case 0x4e:
|
|
case 0x4d:
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
success:
|
|
if (CMPLT_HAS_MODIFY_BIT(cmplt)) {
|
|
hppa_ext->b_writeble = true;
|
|
}
|
|
push_str_modifier(hppa_ext, index_compl_names[cmplt]);
|
|
}
|
|
|
|
static bool decode_memmgmt(const cs_struct *ud, MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t ext = get_insn_field(insn, 19, 25);
|
|
uint32_t b = get_insn_field(insn, 6, 10);
|
|
uint32_t r = get_insn_field(insn, 11, 15);
|
|
uint32_t s3 = extract_3(insn);
|
|
uint32_t s2 = get_insn_field(insn, 16, 17);
|
|
uint32_t t = get_insn_field(insn, 27, 31);
|
|
if (ext > 0x20 && get_insn_bit(insn, 18) == 1 &&
|
|
(ext != 0x46 && ext != 0x47)) {
|
|
if (MODE_IS_HPPA_20(ud->mode)) {
|
|
if (ext != 0x4a) {
|
|
return false;
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
if (MODE_IS_HPPA_20(ud->mode)) {
|
|
switch (ext) {
|
|
case 0x20:
|
|
case 0x60:
|
|
CREATE_GR_REG(MI, r);
|
|
CREATE_GR_REG(MI, b);
|
|
goto success;
|
|
case 0x58:
|
|
case 0x4f:
|
|
CREATE_GR_REG(MI, r);
|
|
CREATE_SR_REG(MI, s2);
|
|
CREATE_GR_REG(MI, b);
|
|
goto success;
|
|
case 0x18:
|
|
CREATE_GR_REG(MI, r);
|
|
CREATE_SR_REG(MI, s3);
|
|
CREATE_GR_REG(MI, b);
|
|
goto success;
|
|
case 0x4a:
|
|
if (get_insn_bit(insn, 18) == 1) {
|
|
MCOperand_CreateImm0(MI, LowSignExtend64(r, 5));
|
|
} else {
|
|
CREATE_GR_REG(MI, r);
|
|
}
|
|
CREATE_SR_REG(MI, s2);
|
|
CREATE_GR_REG(MI, b);
|
|
goto success;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch (ext) {
|
|
case 0x00:
|
|
case 0x01:
|
|
case 0x08:
|
|
case 0x09:
|
|
case 0x0a:
|
|
case 0x0b:
|
|
CREATE_GR_REG(MI, r);
|
|
CREATE_SR_REG(MI, s3);
|
|
CREATE_GR_REG(MI, b);
|
|
break;
|
|
case 0x40:
|
|
case 0x41:
|
|
case 0x48:
|
|
case 0x49:
|
|
case 0x4a:
|
|
case 0x4b:
|
|
case 0x4e:
|
|
CREATE_GR_REG(MI, r);
|
|
CREATE_SR_REG(MI, s2);
|
|
CREATE_GR_REG(MI, b);
|
|
break;
|
|
case 0x46:
|
|
case 0x47:
|
|
CREATE_SR_REG(MI, s2);
|
|
CREATE_GR_REG(MI, b);
|
|
if (get_insn_bit(insn, 18) == 0) {
|
|
CREATE_GR_REG(MI, r);
|
|
} else {
|
|
MCOperand_CreateImm0(MI, r);
|
|
}
|
|
CREATE_GR_REG(MI, t);
|
|
break;
|
|
case 0x4d:
|
|
case 0x4c:
|
|
CREATE_GR_REG(MI, r);
|
|
CREATE_SR_REG(MI, s2);
|
|
CREATE_GR_REG(MI, b);
|
|
CREATE_GR_REG(MI, t);
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
success:
|
|
fill_memmgmt_mods(insn, HPPA_EXT_REF(MI), MI->csh->mode);
|
|
return true;
|
|
}
|
|
|
|
static void fill_alu_insn_name(MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t ext = get_insn_field(insn, 20, 25);
|
|
if (MODE_IS_HPPA_20(MI->csh->mode)) {
|
|
switch (ext) {
|
|
case 0x28:
|
|
case 0x38:
|
|
case 0x1c:
|
|
case 0x3c:
|
|
MCInst_setOpcode(MI, HPPA_INS_ADD);
|
|
return;
|
|
case 0x19:
|
|
case 0x29:
|
|
case 0x39:
|
|
case 0x1a:
|
|
case 0x2a:
|
|
case 0x3a:
|
|
case 0x1b:
|
|
case 0x2b:
|
|
case 0x3b:
|
|
MCInst_setOpcode(MI, HPPA_INS_SHLADD);
|
|
return;
|
|
case 0x30:
|
|
case 0x13:
|
|
case 0x33:
|
|
case 0x14:
|
|
case 0x34:
|
|
MCInst_setOpcode(MI, HPPA_INS_SUB);
|
|
return;
|
|
case 0x22:
|
|
MCInst_setOpcode(MI, HPPA_INS_CMPCLR);
|
|
return;
|
|
case 0x27:
|
|
MCInst_setOpcode(MI, HPPA_INS_UADDCM);
|
|
return;
|
|
case 0x2f:
|
|
MCInst_setOpcode(MI, HPPA_INS_DCOR);
|
|
return;
|
|
case 0x0f:
|
|
case 0x0d:
|
|
case 0x0c:
|
|
MCInst_setOpcode(MI, HPPA_INS_HADD);
|
|
return;
|
|
case 0x07:
|
|
case 0x05:
|
|
case 0x04:
|
|
MCInst_setOpcode(MI, HPPA_INS_HSUB);
|
|
return;
|
|
case 0x0b:
|
|
MCInst_setOpcode(MI, HPPA_INS_HAVG);
|
|
return;
|
|
case 0x1d:
|
|
case 0x1e:
|
|
case 0x1f:
|
|
MCInst_setOpcode(MI, HPPA_INS_HSHLADD);
|
|
return;
|
|
case 0x15:
|
|
case 0x16:
|
|
case 0x17:
|
|
MCInst_setOpcode(MI, HPPA_INS_HSHRADD);
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch (ext) {
|
|
case 0x18:
|
|
MCInst_setOpcode(MI, HPPA_INS_ADD);
|
|
break;
|
|
case 0x38:
|
|
MCInst_setOpcode(MI, HPPA_INS_ADDO);
|
|
break;
|
|
case 0x1c:
|
|
MCInst_setOpcode(MI, HPPA_INS_ADDC);
|
|
break;
|
|
case 0x3c:
|
|
MCInst_setOpcode(MI, HPPA_INS_ADDCO);
|
|
break;
|
|
case 0x19:
|
|
MCInst_setOpcode(MI, HPPA_INS_SH1ADD);
|
|
break;
|
|
case 0x39:
|
|
MCInst_setOpcode(MI, HPPA_INS_SH1ADDO);
|
|
break;
|
|
case 0x1a:
|
|
MCInst_setOpcode(MI, HPPA_INS_SH2ADD);
|
|
break;
|
|
case 0x3a:
|
|
MCInst_setOpcode(MI, HPPA_INS_SH2ADDO);
|
|
break;
|
|
case 0x1b:
|
|
MCInst_setOpcode(MI, HPPA_INS_SH3ADD);
|
|
break;
|
|
case 0x3b:
|
|
MCInst_setOpcode(MI, HPPA_INS_SH3ADDO);
|
|
break;
|
|
case 0x10:
|
|
MCInst_setOpcode(MI, HPPA_INS_SUB);
|
|
break;
|
|
case 0x30:
|
|
MCInst_setOpcode(MI, HPPA_INS_SUBO);
|
|
break;
|
|
case 0x13:
|
|
MCInst_setOpcode(MI, HPPA_INS_SUBT);
|
|
break;
|
|
case 0x33:
|
|
MCInst_setOpcode(MI, HPPA_INS_SUBTO);
|
|
break;
|
|
case 0x14:
|
|
MCInst_setOpcode(MI, HPPA_INS_SUBB);
|
|
break;
|
|
case 0x34:
|
|
MCInst_setOpcode(MI, HPPA_INS_SUBBO);
|
|
break;
|
|
case 0x11:
|
|
MCInst_setOpcode(MI, HPPA_INS_DS);
|
|
break;
|
|
case 0x00:
|
|
MCInst_setOpcode(MI, HPPA_INS_ANDCM);
|
|
break;
|
|
case 0x08:
|
|
MCInst_setOpcode(MI, HPPA_INS_AND);
|
|
break;
|
|
case 0x09:
|
|
MCInst_setOpcode(MI, HPPA_INS_OR);
|
|
break;
|
|
case 0x0a:
|
|
MCInst_setOpcode(MI, HPPA_INS_XOR);
|
|
break;
|
|
case 0x0e:
|
|
MCInst_setOpcode(MI, HPPA_INS_UXOR);
|
|
break;
|
|
case 0x22:
|
|
MCInst_setOpcode(MI, HPPA_INS_COMCLR);
|
|
break;
|
|
case 0x26:
|
|
MCInst_setOpcode(MI, HPPA_INS_UADDCM);
|
|
break;
|
|
case 0x27:
|
|
MCInst_setOpcode(MI, HPPA_INS_UADDCMT);
|
|
break;
|
|
case 0x28:
|
|
MCInst_setOpcode(MI, HPPA_INS_ADDL);
|
|
break;
|
|
case 0x29:
|
|
MCInst_setOpcode(MI, HPPA_INS_SH1ADDL);
|
|
break;
|
|
case 0x2a:
|
|
MCInst_setOpcode(MI, HPPA_INS_SH2ADDL);
|
|
break;
|
|
case 0x2b:
|
|
MCInst_setOpcode(MI, HPPA_INS_SH3ADDL);
|
|
break;
|
|
case 0x2e:
|
|
MCInst_setOpcode(MI, HPPA_INS_DCOR);
|
|
break;
|
|
case 0x2f:
|
|
MCInst_setOpcode(MI, HPPA_INS_IDCOR);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void fill_alu_mods(uint32_t insn, hppa_ext *hppa_ext, cs_mode mode)
|
|
{
|
|
uint32_t cond = (get_insn_field(insn, 19, 19) << 3) |
|
|
get_insn_field(insn, 16, 18);
|
|
uint32_t ext = get_insn_field(insn, 20, 25);
|
|
if (MODE_IS_HPPA_20(mode)) {
|
|
uint32_t e1 = get_insn_field(insn, 20, 21);
|
|
uint32_t e2 = get_insn_bit(insn, 23);
|
|
uint32_t e3 = get_insn_field(insn, 24, 25);
|
|
uint32_t d = get_insn_bit(insn, 26);
|
|
switch (ext) {
|
|
case 0x18:
|
|
case 0x28:
|
|
case 0x38:
|
|
case 0x1c:
|
|
case 0x3c:
|
|
if (e2 == 1) {
|
|
if (d == 1) {
|
|
push_str_modifier(hppa_ext, "dc");
|
|
} else {
|
|
push_str_modifier(hppa_ext, "c");
|
|
}
|
|
}
|
|
// fallthrough
|
|
case 0x19:
|
|
case 0x29:
|
|
case 0x39:
|
|
case 0x1a:
|
|
case 0x2a:
|
|
case 0x3a:
|
|
case 0x1b:
|
|
case 0x2b:
|
|
case 0x3b:
|
|
push_str_modifier(hppa_ext, add_compl_names[e1]);
|
|
if (d == 1) {
|
|
push_str_modifier(hppa_ext,
|
|
add_cond_64_names[cond]);
|
|
} else {
|
|
push_str_modifier(hppa_ext,
|
|
add_cond_names[cond]);
|
|
}
|
|
return;
|
|
case 0x10:
|
|
case 0x30:
|
|
case 0x13:
|
|
case 0x33:
|
|
case 0x14:
|
|
case 0x34:
|
|
if (e2 == 1) {
|
|
if (d == 1) {
|
|
push_str_modifier(hppa_ext, "db");
|
|
} else {
|
|
push_str_modifier(hppa_ext, "b");
|
|
}
|
|
}
|
|
if (e1 == 3) {
|
|
push_str_modifier(hppa_ext, "tsv");
|
|
}
|
|
if (e3 == 3) {
|
|
push_str_modifier(hppa_ext, "tc");
|
|
}
|
|
// fallthrough
|
|
case 0x22:
|
|
if (d == 1) {
|
|
push_str_modifier(hppa_ext,
|
|
compare_cond_64_names[cond]);
|
|
} else {
|
|
push_str_modifier(hppa_ext,
|
|
compare_cond_names[cond]);
|
|
}
|
|
return;
|
|
case 0x00:
|
|
case 0x08:
|
|
case 0x09:
|
|
case 0x0a:
|
|
if (d == 1) {
|
|
push_str_modifier(hppa_ext,
|
|
logical_cond_64_names[cond]);
|
|
} else {
|
|
push_str_modifier(hppa_ext,
|
|
logical_cond_names[cond]);
|
|
}
|
|
return;
|
|
case 0x27:
|
|
push_str_modifier(hppa_ext, "tc");
|
|
goto unit_cond;
|
|
case 0x2f:
|
|
push_str_modifier(hppa_ext, "i");
|
|
// fallthrough
|
|
case 0x26:
|
|
case 0x0e:
|
|
case 0x2e:
|
|
unit_cond:
|
|
if (d == 1) {
|
|
push_str_modifier(hppa_ext,
|
|
unit_cond_64_names[cond]);
|
|
} else {
|
|
push_str_modifier(hppa_ext,
|
|
unit_cond_names[cond]);
|
|
}
|
|
return;
|
|
case 0x0d:
|
|
case 0x0c:
|
|
case 0x05:
|
|
case 0x04:
|
|
push_str_modifier(hppa_ext, saturation_names[e3]);
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch (ext) {
|
|
case 0x18:
|
|
case 0x38:
|
|
case 0x1c:
|
|
case 0x3c:
|
|
case 0x19:
|
|
case 0x39:
|
|
case 0x1a:
|
|
case 0x3a:
|
|
case 0x3b:
|
|
case 0x28:
|
|
case 0x29:
|
|
case 0x2a:
|
|
case 0x2b:
|
|
push_str_modifier(hppa_ext, add_cond_names[cond]);
|
|
break;
|
|
case 0x10:
|
|
case 0x30:
|
|
case 0x13:
|
|
case 0x33:
|
|
case 0x14:
|
|
case 0x34:
|
|
case 0x11:
|
|
case 0x22:
|
|
push_str_modifier(hppa_ext, compare_cond_names[cond]);
|
|
break;
|
|
case 0x00:
|
|
case 0x08:
|
|
case 0x09:
|
|
case 0x0a:
|
|
push_str_modifier(hppa_ext, logical_cond_names[cond]);
|
|
break;
|
|
case 0x0e:
|
|
case 0x26:
|
|
case 0x27:
|
|
case 0x2e:
|
|
case 0x2f:
|
|
push_str_modifier(hppa_ext, unit_cond_names[cond]);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static bool decode_alu(const cs_struct *ud, MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t ext = get_insn_field(insn, 20, 25);
|
|
uint32_t r1 = get_insn_field(insn, 11, 15);
|
|
uint32_t r2 = get_insn_field(insn, 6, 10);
|
|
uint32_t t = get_insn_field(insn, 27, 31);
|
|
if (MODE_IS_HPPA_20(ud->mode)) {
|
|
switch (ext) {
|
|
case 0x19:
|
|
case 0x29:
|
|
case 0x39:
|
|
case 0x1a:
|
|
case 0x2a:
|
|
case 0x3a:
|
|
case 0x1b:
|
|
case 0x2b:
|
|
case 0x3b:
|
|
case 0x1d:
|
|
case 0x1e:
|
|
case 0x1f:
|
|
case 0x15:
|
|
case 0x16:
|
|
case 0x17:
|
|
case 0x0f:
|
|
case 0x0d:
|
|
case 0x0c:
|
|
case 0x07:
|
|
case 0x05:
|
|
case 0x04:
|
|
case 0x0b:
|
|
CREATE_GR_REG(MI, r1);
|
|
if (ext > 0x10) {
|
|
MCOperand_CreateImm0(
|
|
MI, get_insn_field(insn, 24, 25));
|
|
}
|
|
CREATE_GR_REG(MI, r2);
|
|
CREATE_GR_REG(MI, t);
|
|
goto success;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
switch (ext) {
|
|
case 0x18:
|
|
case 0x38:
|
|
case 0x1c:
|
|
case 0x3c:
|
|
case 0x19:
|
|
case 0x39:
|
|
case 0x1a:
|
|
case 0x3a:
|
|
case 0x1b:
|
|
case 0x3b:
|
|
case 0x10:
|
|
case 0x30:
|
|
case 0x13:
|
|
case 0x33:
|
|
case 0x14:
|
|
case 0x34:
|
|
case 0x11:
|
|
case 0x00:
|
|
case 0x08:
|
|
case 0x09:
|
|
case 0x0a:
|
|
case 0x0e:
|
|
case 0x22:
|
|
case 0x26:
|
|
case 0x27:
|
|
case 0x28:
|
|
case 0x29:
|
|
case 0x2a:
|
|
case 0x2b:
|
|
CREATE_GR_REG(MI, r1);
|
|
// fallthrough
|
|
case 0x2e:
|
|
case 0x2f:
|
|
CREATE_GR_REG(MI, r2);
|
|
CREATE_GR_REG(MI, t);
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
success:
|
|
fill_alu_mods(insn, HPPA_EXT_REF(MI), MI->csh->mode);
|
|
return true;
|
|
}
|
|
|
|
static void fill_idxmem_insn_name(MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t ext = get_insn_field(insn, 22, 25);
|
|
if (MODE_IS_HPPA_20(MI->csh->mode)) {
|
|
switch (ext) {
|
|
case 0x00:
|
|
MCInst_setOpcode(MI, HPPA_INS_LDB);
|
|
return;
|
|
case 0x01:
|
|
MCInst_setOpcode(MI, HPPA_INS_LDH);
|
|
return;
|
|
case 0x02:
|
|
MCInst_setOpcode(MI, HPPA_INS_LDW);
|
|
return;
|
|
case 0x03:
|
|
MCInst_setOpcode(MI, HPPA_INS_LDD);
|
|
return;
|
|
case 0x04:
|
|
MCInst_setOpcode(MI, HPPA_INS_LDDA);
|
|
return;
|
|
case 0x05:
|
|
MCInst_setOpcode(MI, HPPA_INS_LDCD);
|
|
return;
|
|
case 0x06:
|
|
MCInst_setOpcode(MI, HPPA_INS_LDWA);
|
|
return;
|
|
case 0x07:
|
|
MCInst_setOpcode(MI, HPPA_INS_LDCW);
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
if (get_insn_bit(insn, 19) == 1) {
|
|
switch (ext) {
|
|
case 0x08:
|
|
MCInst_setOpcode(MI, HPPA_INS_STB);
|
|
return;
|
|
case 0x09:
|
|
MCInst_setOpcode(MI, HPPA_INS_STH);
|
|
return;
|
|
case 0x0a:
|
|
MCInst_setOpcode(MI, HPPA_INS_STW);
|
|
return;
|
|
case 0x0b:
|
|
MCInst_setOpcode(MI, HPPA_INS_STD);
|
|
return;
|
|
case 0x0c:
|
|
MCInst_setOpcode(MI, HPPA_INS_STBY);
|
|
return;
|
|
case 0x0d:
|
|
MCInst_setOpcode(MI, HPPA_INS_STDBY);
|
|
return;
|
|
case 0x0e:
|
|
MCInst_setOpcode(MI, HPPA_INS_STWA);
|
|
return;
|
|
case 0x0f:
|
|
MCInst_setOpcode(MI, HPPA_INS_STDA);
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (get_insn_bit(insn, 19) == 0) {
|
|
switch (ext) {
|
|
case 0x00:
|
|
MCInst_setOpcode(MI, HPPA_INS_LDBX);
|
|
break;
|
|
case 0x01:
|
|
MCInst_setOpcode(MI, HPPA_INS_LDHX);
|
|
break;
|
|
case 0x02:
|
|
MCInst_setOpcode(MI, HPPA_INS_LDWX);
|
|
break;
|
|
case 0x07:
|
|
MCInst_setOpcode(MI, HPPA_INS_LDCWX);
|
|
break;
|
|
case 0x06:
|
|
MCInst_setOpcode(MI, HPPA_INS_LDWAX);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else {
|
|
switch (ext) {
|
|
case 0x00:
|
|
MCInst_setOpcode(MI, HPPA_INS_LDBS);
|
|
break;
|
|
case 0x01:
|
|
MCInst_setOpcode(MI, HPPA_INS_LDHS);
|
|
break;
|
|
case 0x02:
|
|
MCInst_setOpcode(MI, HPPA_INS_LDWS);
|
|
break;
|
|
case 0x07:
|
|
MCInst_setOpcode(MI, HPPA_INS_LDCWS);
|
|
break;
|
|
case 0x06:
|
|
MCInst_setOpcode(MI, HPPA_INS_LDWAS);
|
|
break;
|
|
case 0x08:
|
|
MCInst_setOpcode(MI, HPPA_INS_STBS);
|
|
break;
|
|
case 0x09:
|
|
MCInst_setOpcode(MI, HPPA_INS_STHS);
|
|
break;
|
|
case 0x0a:
|
|
MCInst_setOpcode(MI, HPPA_INS_STWS);
|
|
break;
|
|
case 0x0c:
|
|
MCInst_setOpcode(MI, HPPA_INS_STBYS);
|
|
break;
|
|
case 0x0e:
|
|
MCInst_setOpcode(MI, HPPA_INS_STWAS);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void fill_idxmem_mods(uint32_t insn, hppa_ext *hppa_ext, cs_mode mode,
|
|
uint32_t im5)
|
|
{
|
|
uint32_t cmplt = (get_insn_bit(insn, 18) << 1) | get_insn_bit(insn, 26);
|
|
uint32_t cc = get_insn_field(insn, 20, 21);
|
|
uint32_t ext = get_insn_field(insn, 22, 25);
|
|
if (CMPLT_HAS_MODIFY_BIT(cmplt)) {
|
|
hppa_ext->b_writeble = true;
|
|
}
|
|
if (get_insn_bit(insn, 19) == 0) {
|
|
switch (ext) {
|
|
case 0x00:
|
|
case 0x01:
|
|
case 0x02:
|
|
case 0x03:
|
|
case 0x04:
|
|
case 0x06:
|
|
push_str_modifier(hppa_ext, index_compl_names[cmplt]);
|
|
if (cc == 2) {
|
|
push_str_modifier(hppa_ext, "sl");
|
|
}
|
|
break;
|
|
case 0x05:
|
|
case 0x07:
|
|
push_str_modifier(hppa_ext, index_compl_names[cmplt]);
|
|
if (cc == 1) {
|
|
push_str_modifier(hppa_ext, "co");
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else {
|
|
switch (ext) {
|
|
case 0x00:
|
|
case 0x01:
|
|
case 0x02:
|
|
case 0x03:
|
|
case 0x04:
|
|
case 0x06:
|
|
if (cmplt == 1 && im5 == 0) {
|
|
push_str_modifier(hppa_ext, "o");
|
|
} else {
|
|
push_str_modifier(
|
|
hppa_ext,
|
|
short_ldst_compl_names[cmplt]);
|
|
}
|
|
if (cc == 2) {
|
|
push_str_modifier(hppa_ext, "sl");
|
|
}
|
|
break;
|
|
case 0x05:
|
|
case 0x07:
|
|
if (cmplt == 1 && im5 == 0) {
|
|
push_str_modifier(hppa_ext, "o");
|
|
} else {
|
|
push_str_modifier(
|
|
hppa_ext,
|
|
short_ldst_compl_names[cmplt]);
|
|
}
|
|
if (cc == 1) {
|
|
push_str_modifier(hppa_ext, "co");
|
|
}
|
|
break;
|
|
case 0x08:
|
|
case 0x09:
|
|
case 0x0a:
|
|
case 0x0b:
|
|
case 0x0e:
|
|
case 0x0f:
|
|
if (cmplt == 1 && im5 == 0) {
|
|
push_str_modifier(hppa_ext, "o");
|
|
} else {
|
|
push_str_modifier(
|
|
hppa_ext,
|
|
short_ldst_compl_names[cmplt]);
|
|
}
|
|
if (cc == 1) {
|
|
push_str_modifier(hppa_ext, "bc");
|
|
} else if (cc == 2) {
|
|
push_str_modifier(hppa_ext, "sl");
|
|
}
|
|
break;
|
|
case 0x0c:
|
|
case 0x0d:
|
|
push_str_modifier(hppa_ext,
|
|
short_bytes_compl_names[cmplt]);
|
|
if (cc == 1) {
|
|
push_str_modifier(hppa_ext, "bc");
|
|
} else if (cc == 2) {
|
|
push_str_modifier(hppa_ext, "sl");
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static bool decode_idxmem(const cs_struct *ud, MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t ext = get_insn_field(insn, 22, 25);
|
|
uint32_t im5;
|
|
uint32_t r = get_insn_field(insn, 11, 15);
|
|
uint32_t b = get_insn_field(insn, 6, 10);
|
|
uint32_t t = get_insn_field(insn, 27, 31);
|
|
uint32_t s = get_insn_field(insn, 16, 17);
|
|
if (MODE_IS_HPPA_20(ud->mode)) {
|
|
if (get_insn_bit(insn, 19) == 0) {
|
|
switch (ext) {
|
|
case 0x03:
|
|
case 0x05:
|
|
case 0x04:
|
|
CREATE_GR_REG(MI, r);
|
|
if (ext != 0x04) {
|
|
CREATE_SR_REG(MI, s);
|
|
}
|
|
CREATE_GR_REG(MI, b);
|
|
CREATE_GR_REG(MI, t);
|
|
fill_idxmem_mods(insn, HPPA_EXT_REF(MI),
|
|
ud->mode, -1);
|
|
return true;
|
|
default:
|
|
break;
|
|
}
|
|
} else {
|
|
switch (ext) {
|
|
case 0x03:
|
|
case 0x05:
|
|
case 0x04:
|
|
im5 = extract_5_load(insn);
|
|
MCOperand_CreateImm0(MI, im5);
|
|
if (ext != 0x04) {
|
|
CREATE_SR_REG(MI, s);
|
|
}
|
|
CREATE_GR_REG(MI, b);
|
|
CREATE_GR_REG(MI, t);
|
|
fill_idxmem_mods(insn, HPPA_EXT_REF(MI),
|
|
ud->mode, im5);
|
|
return true;
|
|
case 0x0b:
|
|
case 0x0d:
|
|
case 0x0f:
|
|
im5 = extract_5_store(insn);
|
|
CREATE_GR_REG(MI, r);
|
|
MCOperand_CreateImm0(MI, im5);
|
|
if (ext != 0x0f) {
|
|
CREATE_SR_REG(MI, s);
|
|
}
|
|
CREATE_GR_REG(MI, b);
|
|
fill_idxmem_mods(insn, HPPA_EXT_REF(MI),
|
|
ud->mode, im5);
|
|
return true;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (get_insn_bit(insn, 19) == 0) {
|
|
switch (ext) {
|
|
case 0x00:
|
|
case 0x01:
|
|
case 0x02:
|
|
case 0x07:
|
|
case 0x06:
|
|
CREATE_GR_REG(MI, r);
|
|
if (ext != 0x06) {
|
|
CREATE_SR_REG(MI, s);
|
|
}
|
|
CREATE_GR_REG(MI, b);
|
|
CREATE_GR_REG(MI, t);
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
fill_idxmem_mods(insn, HPPA_EXT_REF(MI), ud->mode, -1);
|
|
return true;
|
|
} else {
|
|
switch (ext) {
|
|
case 0x00:
|
|
case 0x01:
|
|
case 0x02:
|
|
case 0x07:
|
|
case 0x06:
|
|
im5 = extract_5_load(insn);
|
|
MCOperand_CreateImm0(MI, im5);
|
|
if (ext != 0x06) {
|
|
CREATE_SR_REG(MI, s);
|
|
}
|
|
CREATE_GR_REG(MI, b);
|
|
CREATE_GR_REG(MI, t);
|
|
break;
|
|
case 0x08:
|
|
case 0x09:
|
|
case 0x0a:
|
|
case 0x0c:
|
|
case 0x0e:
|
|
im5 = extract_5_store(insn);
|
|
CREATE_GR_REG(MI, r);
|
|
MCOperand_CreateImm0(MI, im5);
|
|
if (ext != 0x0e) {
|
|
CREATE_SR_REG(MI, s);
|
|
}
|
|
CREATE_GR_REG(MI, b);
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
if (MODE_IS_HPPA_20(ud->mode)) {
|
|
fill_idxmem_mods(insn, HPPA_EXT_REF(MI), ud->mode, im5);
|
|
} else {
|
|
fill_idxmem_mods(insn, HPPA_EXT_REF(MI), ud->mode, -1);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
static void fill_ldst_dw_insn_name(MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t opcode = insn >> 26;
|
|
uint32_t ext = get_insn_bit(insn, 30);
|
|
if (opcode == 0x14) {
|
|
if (ext == 0) {
|
|
MCInst_setOpcode(MI, HPPA_INS_LDD);
|
|
} else {
|
|
MCInst_setOpcode(MI, HPPA_INS_FLDD);
|
|
}
|
|
} else {
|
|
if (ext == 0) {
|
|
MCInst_setOpcode(MI, HPPA_INS_STD);
|
|
} else {
|
|
MCInst_setOpcode(MI, HPPA_INS_FSTD);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void fill_ldst_dw_mods(uint32_t insn, hppa_ext *hppa_ext, uint32_t im)
|
|
{
|
|
uint32_t cmplt = (get_insn_bit(insn, 29) << 1) | get_insn_bit(insn, 28);
|
|
if (cmplt == 1 && im == 0) {
|
|
push_str_modifier(hppa_ext, "o");
|
|
} else {
|
|
push_str_modifier(hppa_ext, short_ldst_compl_names[cmplt]);
|
|
}
|
|
}
|
|
|
|
static bool decode_ldst_dw(const cs_struct *ud, MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t opcode = insn >> 26;
|
|
uint32_t im = extract_16(insn, MODE_IS_HPPA_20W(ud->mode));
|
|
im &= ~7;
|
|
uint32_t ext = get_insn_bit(insn, 30);
|
|
uint32_t r = get_insn_field(insn, 11, 15);
|
|
uint32_t b = get_insn_field(insn, 6, 10);
|
|
uint32_t s = get_insn_field(insn, 16, 17);
|
|
if (opcode == HPPA_OP_TYPE_LOADDW) {
|
|
MCOperand_CreateImm0(MI, im);
|
|
CREATE_SR_REG(MI, s);
|
|
CREATE_GR_REG(MI, b);
|
|
if (ext == 0) {
|
|
CREATE_GR_REG(MI, r);
|
|
} else {
|
|
CREATE_FPR_REG(MI, r);
|
|
}
|
|
} else {
|
|
if (ext == 0) {
|
|
CREATE_GR_REG(MI, r);
|
|
} else {
|
|
CREATE_FPR_REG(MI, r);
|
|
}
|
|
MCOperand_CreateImm0(MI, im);
|
|
CREATE_SR_REG(MI, s);
|
|
CREATE_GR_REG(MI, b);
|
|
}
|
|
fill_ldst_dw_mods(insn, HPPA_EXT_REF(MI), im);
|
|
return true;
|
|
}
|
|
|
|
static void fill_ldst_w_insn_name(MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t opcode = insn >> 26;
|
|
uint32_t ext = get_insn_bit(insn, 29);
|
|
if (opcode == 0x17) {
|
|
if (ext == 0) {
|
|
MCInst_setOpcode(MI, HPPA_INS_FLDW);
|
|
} else {
|
|
MCInst_setOpcode(MI, HPPA_INS_LDW);
|
|
}
|
|
} else {
|
|
if (ext == 0) {
|
|
MCInst_setOpcode(MI, HPPA_INS_FSTW);
|
|
} else {
|
|
MCInst_setOpcode(MI, HPPA_INS_STW);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void fill_ldst_w_mods(uint32_t insn, hppa_ext *hppa_ext, int32_t im)
|
|
{
|
|
if (im >= 0) {
|
|
push_str_modifier(hppa_ext, "mb");
|
|
} else {
|
|
push_str_modifier(hppa_ext, "ma");
|
|
}
|
|
}
|
|
|
|
static bool decode_ldst_w(const cs_struct *ud, MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t opcode = insn >> 26;
|
|
uint32_t ext = get_insn_bit(insn, 29);
|
|
int32_t im = extract_16(insn, MODE_IS_HPPA_20W(ud->mode));
|
|
im &= ~3;
|
|
uint32_t r = get_insn_field(insn, 11, 15);
|
|
uint32_t b = get_insn_field(insn, 6, 10);
|
|
uint32_t s = get_insn_field(insn, 16, 17);
|
|
if (opcode == 0x17) {
|
|
MCOperand_CreateImm0(MI, im);
|
|
CREATE_SR_REG(MI, s);
|
|
CREATE_GR_REG(MI, b);
|
|
if (ext == 1) {
|
|
CREATE_GR_REG(MI, r);
|
|
} else {
|
|
CREATE_FPR_REG(MI, r);
|
|
}
|
|
} else {
|
|
if (ext == 1) {
|
|
CREATE_GR_REG(MI, r);
|
|
} else {
|
|
CREATE_FPR_REG(MI, r);
|
|
}
|
|
MCOperand_CreateImm0(MI, im);
|
|
CREATE_SR_REG(MI, s);
|
|
CREATE_GR_REG(MI, b);
|
|
}
|
|
if (ext == 1) {
|
|
fill_ldst_w_mods(insn, HPPA_EXT_REF(MI), im);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static void fill_arith_imm_insn_name(MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t opcode = insn >> 26;
|
|
if (MODE_IS_HPPA_20(MI->csh->mode)) {
|
|
switch (opcode) {
|
|
case 0x2d:
|
|
case 0x2c:
|
|
MCInst_setOpcode(MI, HPPA_INS_ADDI);
|
|
return;
|
|
case 0x25:
|
|
MCInst_setOpcode(MI, HPPA_INS_SUBI);
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
if (get_insn_bit(insn, 20) == 0) {
|
|
switch (opcode) {
|
|
case 0x2d:
|
|
MCInst_setOpcode(MI, HPPA_INS_ADDI);
|
|
break;
|
|
case 0x2c:
|
|
MCInst_setOpcode(MI, HPPA_INS_ADDIT);
|
|
break;
|
|
case 0x25:
|
|
MCInst_setOpcode(MI, HPPA_INS_SUBI);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else {
|
|
switch (opcode) {
|
|
case 0x2d:
|
|
MCInst_setOpcode(MI, HPPA_INS_ADDIO);
|
|
break;
|
|
case 0x2c:
|
|
MCInst_setOpcode(MI, HPPA_INS_ADDITO);
|
|
break;
|
|
case 0x25:
|
|
MCInst_setOpcode(MI, HPPA_INS_SUBIO);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void fill_arith_imm_insn_mods(uint32_t insn, hppa_ext *hppa_ext,
|
|
cs_mode mode)
|
|
{
|
|
uint32_t opcode = insn >> 26;
|
|
uint32_t cond = (get_insn_bit(insn, 19) << 3) |
|
|
get_insn_field(insn, 16, 18);
|
|
uint32_t cmplt = get_insn_bit(insn, 20);
|
|
if (MODE_IS_HPPA_20(mode)) {
|
|
if (cmplt == 1) {
|
|
push_str_modifier(hppa_ext, "tsv");
|
|
}
|
|
if (opcode == 0x2c) {
|
|
push_str_modifier(hppa_ext, "tc");
|
|
}
|
|
}
|
|
switch (opcode) {
|
|
case 0x2d:
|
|
case 0x2c:
|
|
push_str_modifier(hppa_ext, add_cond_names[cond]);
|
|
break;
|
|
case 0x25:
|
|
push_str_modifier(hppa_ext, compare_cond_names[cond]);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static bool decode_arith_imm(const cs_struct *ud, MCInst *MI, uint32_t insn)
|
|
{
|
|
MCOperand_CreateImm0(MI, extract_11(insn));
|
|
CREATE_GR_REG(MI, get_insn_field(insn, 6, 10));
|
|
CREATE_GR_REG(MI, get_insn_field(insn, 11, 15));
|
|
fill_arith_imm_insn_mods(insn, HPPA_EXT_REF(MI), ud->mode);
|
|
return true;
|
|
}
|
|
|
|
static void fill_shexdep0_insn_name(MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t ext = get_insn_field(insn, 19, 21);
|
|
uint32_t d = get_insn_bit(insn, 22);
|
|
if (MODE_IS_HPPA_20(MI->csh->mode)) {
|
|
switch (ext) {
|
|
case 0x01:
|
|
case 0x03:
|
|
MCInst_setOpcode(MI, HPPA_INS_SHRPD);
|
|
return;
|
|
case 0x02:
|
|
MCInst_setOpcode(MI, HPPA_INS_SHRPW);
|
|
return;
|
|
case 0x06:
|
|
case 0x07:
|
|
MCInst_setOpcode(MI, HPPA_INS_EXTRW);
|
|
return;
|
|
case 0x00:
|
|
if (d == 0) {
|
|
MCInst_setOpcode(MI, HPPA_INS_SHRPW);
|
|
} else {
|
|
MCInst_setOpcode(MI, HPPA_INS_SHRPD);
|
|
}
|
|
return;
|
|
case 0x04:
|
|
case 0x05:
|
|
if (d == 0) {
|
|
MCInst_setOpcode(MI, HPPA_INS_EXTRW);
|
|
} else {
|
|
MCInst_setOpcode(MI, HPPA_INS_EXTRD);
|
|
}
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
switch (ext) {
|
|
case 0x00:
|
|
MCInst_setOpcode(MI, HPPA_INS_VSHD);
|
|
break;
|
|
case 0x02:
|
|
MCInst_setOpcode(MI, HPPA_INS_SHD);
|
|
break;
|
|
case 0x04:
|
|
MCInst_setOpcode(MI, HPPA_INS_VEXTRU);
|
|
break;
|
|
case 0x05:
|
|
MCInst_setOpcode(MI, HPPA_INS_VEXTRS);
|
|
break;
|
|
case 0x06:
|
|
MCInst_setOpcode(MI, HPPA_INS_EXTRU);
|
|
break;
|
|
case 0x07:
|
|
MCInst_setOpcode(MI, HPPA_INS_EXTRS);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void fill_shexdep0_mods(uint32_t insn, hppa_ext *hppa_ext, cs_mode mode)
|
|
{
|
|
uint32_t cond = get_insn_field(insn, 16, 18);
|
|
uint32_t ext = get_insn_field(insn, 19, 21);
|
|
uint32_t d = get_insn_bit(insn, 22);
|
|
|
|
if (ext >= 0x04 && MODE_IS_HPPA_20(mode)) {
|
|
push_str_modifier(hppa_ext, signed_unsigned_names[ext & 1]);
|
|
}
|
|
|
|
if (MODE_IS_HPPA_20(mode)) {
|
|
switch (ext) {
|
|
case 0x00:
|
|
case 0x04:
|
|
case 0x05:
|
|
if (d == 0) {
|
|
break;
|
|
}
|
|
// fallthrough
|
|
case 0x01:
|
|
case 0x03:
|
|
push_str_modifier(hppa_ext, shift_cond_64_names[cond]);
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
push_str_modifier(hppa_ext, shift_cond_names[cond]);
|
|
}
|
|
|
|
static bool decode_shexdep0(const cs_struct *ud, MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t ext = get_insn_field(insn, 19, 21);
|
|
uint32_t cp = get_insn_bit(insn, 20);
|
|
uint32_t cpos = get_insn_field(insn, 22, 26);
|
|
uint32_t sa = 63 - ((cp << 5) | cpos);
|
|
uint32_t r1 = get_insn_field(insn, 11, 15);
|
|
uint32_t r2 = get_insn_field(insn, 6, 10);
|
|
uint32_t clen_t = get_insn_field(insn, 27, 31);
|
|
if (MODE_IS_HPPA_20(ud->mode)) {
|
|
switch (ext) {
|
|
case 0x01:
|
|
case 0x00:
|
|
case 0x03:
|
|
case 0x02:
|
|
CREATE_GR_REG(MI, r1);
|
|
CREATE_GR_REG(MI, r2);
|
|
if (ext <= 0x01) {
|
|
CREATE_CR_REG(MI, 11);
|
|
HPPA_EXT_REF(MI)->is_alternative = true;
|
|
} else {
|
|
MCOperand_CreateImm0(MI, sa);
|
|
}
|
|
CREATE_GR_REG(MI, clen_t);
|
|
break;
|
|
case 0x06:
|
|
case 0x07:
|
|
case 0x04:
|
|
case 0x05:
|
|
CREATE_GR_REG(MI, r2);
|
|
if (ext >= 0x06) {
|
|
MCOperand_CreateImm0(MI, cpos);
|
|
} else {
|
|
CREATE_CR_REG(MI, 11);
|
|
HPPA_EXT_REF(MI)->is_alternative = true;
|
|
}
|
|
MCOperand_CreateImm0(MI, 32 - clen_t);
|
|
CREATE_GR_REG(MI, r1);
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
} else {
|
|
switch (ext) {
|
|
case 0x00:
|
|
case 0x02:
|
|
CREATE_GR_REG(MI, r1);
|
|
CREATE_GR_REG(MI, r2);
|
|
if (ext == 0x02) {
|
|
MCOperand_CreateImm0(MI, 31 - cpos);
|
|
}
|
|
CREATE_GR_REG(MI, clen_t);
|
|
break;
|
|
case 0x04:
|
|
case 0x05:
|
|
case 0x06:
|
|
case 0x07:
|
|
CREATE_GR_REG(MI, r2);
|
|
if (ext >= 0x06) {
|
|
MCOperand_CreateImm0(MI, cpos);
|
|
}
|
|
MCOperand_CreateImm0(MI, 32 - clen_t);
|
|
CREATE_GR_REG(MI, r1);
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
fill_shexdep0_mods(insn, HPPA_EXT_REF(MI), ud->mode);
|
|
return true;
|
|
}
|
|
|
|
static void fill_shexdep1_insn_name(MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t ext = get_insn_field(insn, 19, 21);
|
|
uint32_t d = get_insn_bit(insn, 22);
|
|
if (MODE_IS_HPPA_20(MI->csh->mode)) {
|
|
switch (ext) {
|
|
case 0x02:
|
|
case 0x03:
|
|
MCInst_setOpcode(MI, HPPA_INS_DEPW);
|
|
break;
|
|
case 0x06:
|
|
case 0x07:
|
|
MCInst_setOpcode(MI, HPPA_INS_DEPWI);
|
|
break;
|
|
case 0x00:
|
|
case 0x01:
|
|
if (d == 0) {
|
|
MCInst_setOpcode(MI, HPPA_INS_DEPW);
|
|
} else {
|
|
MCInst_setOpcode(MI, HPPA_INS_DEPD);
|
|
}
|
|
break;
|
|
case 0x04:
|
|
case 0x05:
|
|
if (d == 0) {
|
|
MCInst_setOpcode(MI, HPPA_INS_DEPWI);
|
|
} else {
|
|
MCInst_setOpcode(MI, HPPA_INS_DEPDI);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else {
|
|
switch (ext) {
|
|
case 0x00:
|
|
MCInst_setOpcode(MI, HPPA_INS_ZVDEP);
|
|
break;
|
|
case 0x01:
|
|
MCInst_setOpcode(MI, HPPA_INS_VDEP);
|
|
break;
|
|
case 0x02:
|
|
MCInst_setOpcode(MI, HPPA_INS_ZDEP);
|
|
break;
|
|
case 0x03:
|
|
MCInst_setOpcode(MI, HPPA_INS_DEP);
|
|
break;
|
|
case 0x04:
|
|
MCInst_setOpcode(MI, HPPA_INS_ZVDEPI);
|
|
break;
|
|
case 0x05:
|
|
MCInst_setOpcode(MI, HPPA_INS_VDEPI);
|
|
break;
|
|
case 0x06:
|
|
MCInst_setOpcode(MI, HPPA_INS_ZDEPI);
|
|
break;
|
|
case 0x07:
|
|
MCInst_setOpcode(MI, HPPA_INS_DEPI);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void fill_shexdep1_mods(uint32_t insn, hppa_ext *hppa_ext, cs_mode mode)
|
|
{
|
|
uint32_t cond = get_insn_field(insn, 16, 18);
|
|
uint32_t cmplt = get_insn_bit(insn, 21);
|
|
uint32_t ext = get_insn_field(insn, 19, 21);
|
|
if (MODE_IS_HPPA_20(mode)) {
|
|
if (cmplt == 0) {
|
|
push_str_modifier(hppa_ext, "z");
|
|
}
|
|
switch (ext) {
|
|
case 0x00:
|
|
case 0x01:
|
|
case 0x04:
|
|
case 0x05:
|
|
push_str_modifier(hppa_ext, shift_cond_64_names[cond]);
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
push_str_modifier(hppa_ext, shift_cond_names[cond]);
|
|
}
|
|
|
|
static bool decode_shexdep1(const cs_struct *ud, MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t ext = get_insn_field(insn, 19, 21);
|
|
uint32_t cl = get_insn_bit(insn, 23);
|
|
uint32_t clen = get_insn_field(insn, 27, 31);
|
|
uint32_t len = (cl + 1) * 32 - clen;
|
|
uint32_t r = get_insn_field(insn, 11, 15);
|
|
uint32_t t = get_insn_field(insn, 6, 10);
|
|
uint32_t cpos = get_insn_field(insn, 22, 26);
|
|
if (MODE_IS_HPPA_20(ud->mode)) {
|
|
switch (ext) {
|
|
case 0x02:
|
|
case 0x03:
|
|
case 0x06:
|
|
case 0x07:
|
|
if (ext >= 0x06) {
|
|
MCOperand_CreateImm0(MI, LowSignExtend64(r, 5));
|
|
} else {
|
|
CREATE_GR_REG(MI, r);
|
|
}
|
|
MCOperand_CreateImm0(MI, 31 - cpos);
|
|
MCOperand_CreateImm0(MI, 32 - clen);
|
|
CREATE_GR_REG(MI, t);
|
|
break;
|
|
case 0x00:
|
|
case 0x01:
|
|
case 0x04:
|
|
case 0x05:
|
|
if (ext >= 0x04) {
|
|
MCOperand_CreateImm0(MI, LowSignExtend64(r, 5));
|
|
} else {
|
|
CREATE_GR_REG(MI, r);
|
|
}
|
|
CREATE_CR_REG(MI, 11);
|
|
HPPA_EXT_REF(MI)->is_alternative = true;
|
|
MCOperand_CreateImm0(MI, len);
|
|
CREATE_GR_REG(MI, t);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else {
|
|
switch (ext) {
|
|
case 0x00:
|
|
case 0x01:
|
|
case 0x02:
|
|
case 0x03:
|
|
CREATE_GR_REG(MI, r);
|
|
if (ext >= 0x02) {
|
|
MCOperand_CreateImm0(MI, 31 - cpos);
|
|
}
|
|
MCOperand_CreateImm0(MI, 32 - clen);
|
|
CREATE_GR_REG(MI, t);
|
|
break;
|
|
case 0x04:
|
|
case 0x05:
|
|
case 0x06:
|
|
case 0x07:
|
|
MCOperand_CreateImm0(MI, LowSignExtend64(r, 5));
|
|
if (ext >= 0x06) {
|
|
MCOperand_CreateImm0(MI, 31 - cpos);
|
|
}
|
|
MCOperand_CreateImm0(MI, 32 - clen);
|
|
CREATE_GR_REG(MI, t);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
fill_shexdep1_mods(insn, HPPA_EXT_REF(MI), ud->mode);
|
|
return true;
|
|
}
|
|
|
|
static void fill_shexdep2_mods(uint32_t insn, hppa_ext *hppa_ext)
|
|
{
|
|
uint32_t cmplt = get_insn_bit(insn, 21);
|
|
uint32_t cond = get_insn_field(insn, 16, 18);
|
|
push_str_modifier(hppa_ext, signed_unsigned_names[cmplt]);
|
|
push_str_modifier(hppa_ext, shift_cond_64_names[cond]);
|
|
}
|
|
|
|
static bool decode_shexdep2(MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t pos = (get_insn_bit(insn, 20) << 5) |
|
|
get_insn_field(insn, 22, 26);
|
|
uint32_t cl = get_insn_bit(insn, 19);
|
|
uint32_t clen = get_insn_field(insn, 27, 31);
|
|
uint32_t len = (cl + 1) * 32 - clen;
|
|
CREATE_GR_REG(MI, get_insn_field(insn, 6, 10));
|
|
MCOperand_CreateImm0(MI, pos);
|
|
MCOperand_CreateImm0(MI, len);
|
|
CREATE_GR_REG(MI, get_insn_field(insn, 11, 15));
|
|
fill_shexdep2_mods(insn, HPPA_EXT_REF(MI));
|
|
return true;
|
|
}
|
|
|
|
static void fill_shexdep3_mods(uint32_t insn, hppa_ext *hppa_ext)
|
|
{
|
|
uint32_t cmplt = get_insn_bit(insn, 21);
|
|
uint32_t cond = get_insn_field(insn, 16, 18);
|
|
if (cmplt == 0) {
|
|
push_str_modifier(hppa_ext, "z");
|
|
}
|
|
push_str_modifier(hppa_ext, shift_cond_64_names[cond]);
|
|
}
|
|
|
|
static bool decode_shexdep3(const cs_struct *ud, MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t opcode = insn >> 26;
|
|
if (opcode == HPPA_OP_TYPE_SHEXDEP3) {
|
|
MCInst_setOpcode(MI, HPPA_INS_DEPD);
|
|
} else {
|
|
MCInst_setOpcode(MI, HPPA_INS_DEPDI);
|
|
}
|
|
uint32_t pos = 63 - ((get_insn_bit(insn, 20) << 5) |
|
|
get_insn_field(insn, 22, 26));
|
|
uint32_t cl = get_insn_bit(insn, 19);
|
|
uint32_t clen = get_insn_field(insn, 27, 31);
|
|
uint32_t len = (cl + 1) * 32 - clen;
|
|
if (opcode == HPPA_OP_TYPE_SHEXDEP3) {
|
|
CREATE_GR_REG(MI, get_insn_field(insn, 11, 15));
|
|
} else {
|
|
MCOperand_CreateImm0(
|
|
MI, LowSignExtend64(get_insn_field(insn, 11, 15), 5));
|
|
}
|
|
MCOperand_CreateImm0(MI, pos);
|
|
MCOperand_CreateImm0(MI, len);
|
|
CREATE_GR_REG(MI, get_insn_field(insn, 6, 10));
|
|
fill_shexdep3_mods(insn, HPPA_EXT_REF(MI));
|
|
return true;
|
|
}
|
|
|
|
static void fill_multmed_insn_name(MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t bit_16 = get_insn_bit(insn, 16);
|
|
uint32_t ext = (get_insn_field(insn, 17, 18) << 2) |
|
|
get_insn_field(insn, 20, 21);
|
|
if (bit_16 == 0) {
|
|
MCInst_setOpcode(MI, HPPA_INS_PERMH);
|
|
return;
|
|
}
|
|
switch (ext) {
|
|
case 0x02:
|
|
MCInst_setOpcode(MI, HPPA_INS_HSHL);
|
|
break;
|
|
case 0x0a:
|
|
case 0x0b:
|
|
MCInst_setOpcode(MI, HPPA_INS_HSHR);
|
|
break;
|
|
case 0x00:
|
|
case 0x08:
|
|
MCInst_setOpcode(MI, HPPA_INS_MIXW);
|
|
break;
|
|
case 0x01:
|
|
case 0x09:
|
|
MCInst_setOpcode(MI, HPPA_INS_MIXH);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void fill_multmed_mods(uint32_t insn, hppa_ext *hppa_ext)
|
|
{
|
|
uint32_t bit_16 = get_insn_bit(insn, 16);
|
|
uint32_t ext = (get_insn_field(insn, 17, 18) << 2) |
|
|
get_insn_field(insn, 20, 21);
|
|
uint32_t eb = get_insn_field(insn, 20, 21);
|
|
uint32_t ea = get_insn_field(insn, 17, 18);
|
|
if (bit_16 == 0) {
|
|
char c[5];
|
|
snprintf(c, sizeof(c), "%d%d%d%d", get_insn_field(insn, 17, 18),
|
|
get_insn_field(insn, 20, 21),
|
|
get_insn_field(insn, 22, 23),
|
|
get_insn_field(insn, 24, 25));
|
|
push_str_modifier(hppa_ext, c);
|
|
return;
|
|
}
|
|
switch (ext) {
|
|
case 0x0a:
|
|
case 0x0b:
|
|
if (eb >= 2) {
|
|
push_str_modifier(hppa_ext,
|
|
signed_unsigned_names[eb - 2]);
|
|
}
|
|
break;
|
|
case 0x00:
|
|
case 0x08:
|
|
case 0x01:
|
|
case 0x09:
|
|
if (ea == 2) {
|
|
push_str_modifier(hppa_ext, "l");
|
|
} else if (ea == 0) {
|
|
push_str_modifier(hppa_ext, "r");
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static bool decode_multmed(MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t bit_16 = get_insn_bit(insn, 16);
|
|
uint32_t ext = (get_insn_field(insn, 17, 18) << 2) |
|
|
get_insn_field(insn, 20, 21);
|
|
uint32_t r1 = get_insn_field(insn, 11, 15);
|
|
uint32_t r2 = get_insn_field(insn, 6, 10);
|
|
uint32_t t = get_insn_field(insn, 27, 31);
|
|
uint32_t sa = get_insn_field(insn, 22, 25);
|
|
if (bit_16 == 0) {
|
|
CREATE_GR_REG(MI, r2);
|
|
CREATE_GR_REG(MI, t);
|
|
goto success;
|
|
}
|
|
switch (ext) {
|
|
case 0x02:
|
|
case 0x0a:
|
|
case 0x0b:
|
|
if (ext >= 0x0a) {
|
|
CREATE_GR_REG(MI, r2);
|
|
} else {
|
|
CREATE_GR_REG(MI, r1);
|
|
}
|
|
MCOperand_CreateImm0(MI, sa);
|
|
CREATE_GR_REG(MI, t);
|
|
break;
|
|
case 0x00:
|
|
case 0x08:
|
|
case 0x01:
|
|
case 0x09:
|
|
CREATE_GR_REG(MI, r1);
|
|
CREATE_GR_REG(MI, r2);
|
|
CREATE_GR_REG(MI, t);
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
success:
|
|
fill_multmed_mods(insn, HPPA_EXT_REF(MI));
|
|
return true;
|
|
}
|
|
|
|
static void fill_branch_insn_name(MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t ext = get_insn_field(insn, 16, 18);
|
|
uint32_t bit_19 = get_insn_bit(insn, 19);
|
|
if (MODE_IS_HPPA_20(MI->csh->mode)) {
|
|
if (insn == 0xe8004005) {
|
|
MCInst_setOpcode(MI, HPPA_INS_CLRBTS);
|
|
return;
|
|
} else if (insn == 0xe8004001) {
|
|
MCInst_setOpcode(MI, HPPA_INS_PUSHNOM);
|
|
return;
|
|
}
|
|
|
|
switch (ext) {
|
|
case 0x00:
|
|
case 0x01:
|
|
case 0x04:
|
|
case 0x05:
|
|
MCInst_setOpcode(MI, HPPA_INS_B);
|
|
return;
|
|
case 0x06:
|
|
if (bit_19 == 0) {
|
|
MCInst_setOpcode(MI, HPPA_INS_BV);
|
|
} else {
|
|
MCInst_setOpcode(MI, HPPA_INS_BVE);
|
|
}
|
|
return;
|
|
case 0x07:
|
|
if (bit_19 == 1) {
|
|
MCInst_setOpcode(MI, HPPA_INS_BVE);
|
|
}
|
|
return;
|
|
case 0x02:
|
|
if (get_insn_field(insn, 19, 29) == 0 &&
|
|
get_insn_bit(insn, 31) == 0) {
|
|
MCInst_setOpcode(MI, HPPA_INS_BLR);
|
|
return;
|
|
}
|
|
if (get_insn_field(insn, 19, 31) == 1) {
|
|
MCInst_setOpcode(MI, HPPA_INS_PUSHBTS);
|
|
return;
|
|
}
|
|
if (bit_19 == 0 &&
|
|
get_insn_field(insn, 29, 31) == 0x5) {
|
|
MCInst_setOpcode(MI, HPPA_INS_POPBTS);
|
|
return;
|
|
}
|
|
return;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
switch (ext) {
|
|
case 0x00:
|
|
MCInst_setOpcode(MI, HPPA_INS_BL);
|
|
break;
|
|
case 0x01:
|
|
MCInst_setOpcode(MI, HPPA_INS_GATE);
|
|
break;
|
|
case 0x02:
|
|
MCInst_setOpcode(MI, HPPA_INS_BLR);
|
|
break;
|
|
case 0x06:
|
|
MCInst_setOpcode(MI, HPPA_INS_BV);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void fill_branch_mods(uint32_t insn, hppa_ext *hppa_ext, cs_mode mode)
|
|
{
|
|
uint32_t ext = get_insn_field(insn, 16, 18);
|
|
uint32_t n = get_insn_bit(insn, 30);
|
|
uint32_t p = get_insn_bit(insn, 31);
|
|
if (MODE_IS_HPPA_20(mode)) {
|
|
switch (ext) {
|
|
case 0x00:
|
|
case 0x05:
|
|
push_str_modifier(hppa_ext, "l");
|
|
// fallthrough
|
|
case 0x02:
|
|
break;
|
|
case 0x01:
|
|
push_str_modifier(hppa_ext, "gate");
|
|
break;
|
|
case 0x04:
|
|
push_str_modifier(hppa_ext, "l");
|
|
push_str_modifier(hppa_ext, "push");
|
|
break;
|
|
case 0x06:
|
|
case 0x07:
|
|
if (get_insn_bit(insn, 19) == 0) {
|
|
break;
|
|
}
|
|
if (ext == 7) {
|
|
push_str_modifier(hppa_ext, "l");
|
|
hppa_ext->is_alternative = true;
|
|
if (p == 1) {
|
|
push_str_modifier(hppa_ext, "push");
|
|
}
|
|
} else {
|
|
if (p == 1) {
|
|
push_str_modifier(hppa_ext, "pop");
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
if (n == 1) {
|
|
push_str_modifier(hppa_ext, "n");
|
|
}
|
|
}
|
|
|
|
static bool decode_branch(const cs_struct *ud, MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t ext = get_insn_field(insn, 16, 18);
|
|
uint32_t t = get_insn_field(insn, 6, 10);
|
|
uint32_t i = get_insn_field(insn, 20, 28);
|
|
uint32_t r = get_insn_field(insn, 11, 15);
|
|
uint32_t bit_19 = get_insn_bit(insn, 19);
|
|
if (MODE_IS_HPPA_20(ud->mode)) {
|
|
if (insn == 0xe8004005 || insn == 0xe8004001) {
|
|
return true;
|
|
}
|
|
|
|
switch (ext) {
|
|
case 0x01:
|
|
case 0x00:
|
|
MCOperand_CreateImm0(MI, extract_17(insn));
|
|
CREATE_GR_REG(MI, t);
|
|
break;
|
|
case 0x04:
|
|
case 0x05:
|
|
MCOperand_CreateImm0(MI, extract_22(insn));
|
|
CREATE_GR_REG(MI, t);
|
|
break;
|
|
case 0x02:
|
|
if (bit_19 == 1) {
|
|
return false;
|
|
}
|
|
if (get_insn_field(insn, 20, 31) == 1 && t == 0) {
|
|
CREATE_GR_REG(MI, r);
|
|
break;
|
|
}
|
|
if (r == 0 && t == 0 &&
|
|
get_insn_field(insn, 29, 31) == 0x5) {
|
|
MCOperand_CreateImm0(MI, i);
|
|
break;
|
|
}
|
|
if (get_insn_bit(insn, 31) == 0 &&
|
|
get_insn_field(insn, 19, 29) == 0) {
|
|
CREATE_GR_REG(MI, r);
|
|
CREATE_GR_REG(MI, t);
|
|
break;
|
|
}
|
|
return false;
|
|
case 0x06:
|
|
if (bit_19 == 0) {
|
|
CREATE_GR_REG(MI, r);
|
|
}
|
|
CREATE_GR_REG(MI, t);
|
|
break;
|
|
case 0x07:
|
|
if (bit_19 == 1) {
|
|
CREATE_GR_REG(MI, t);
|
|
CREATE_GR_REG(MI, 2);
|
|
break;
|
|
}
|
|
// fallthrough
|
|
default:
|
|
return false;
|
|
}
|
|
fill_branch_mods(insn, HPPA_EXT_REF(MI), ud->mode);
|
|
return true;
|
|
} else {
|
|
switch (ext) {
|
|
case 0x00:
|
|
case 0x01:
|
|
MCOperand_CreateImm0(MI, extract_17(insn));
|
|
CREATE_GR_REG(MI, t);
|
|
break;
|
|
case 0x02:
|
|
case 0x06:
|
|
CREATE_GR_REG(MI, r);
|
|
CREATE_GR_REG(MI, t);
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
fill_branch_mods(insn, HPPA_EXT_REF(MI), ud->mode);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
static void fill_corpdw_insn_name(MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t ext = (get_insn_field(insn, 19, 19) << 1) |
|
|
get_insn_field(insn, 22, 22);
|
|
uint32_t opcode = insn >> 26;
|
|
uint32_t uid = get_insn_field(insn, 23, 25);
|
|
if (MODE_IS_HPPA_20(MI->csh->mode)) {
|
|
if (opcode == 0x09) {
|
|
switch (ext) {
|
|
case 0x00:
|
|
case 0x02:
|
|
if (uid <= 0x01) {
|
|
MCInst_setOpcode(MI, HPPA_INS_FLDW);
|
|
} else {
|
|
MCInst_setOpcode(MI, HPPA_INS_CLDW);
|
|
}
|
|
return;
|
|
case 0x01:
|
|
case 0x03:
|
|
if (uid <= 0x01) {
|
|
MCInst_setOpcode(MI, HPPA_INS_FSTW);
|
|
} else {
|
|
MCInst_setOpcode(MI, HPPA_INS_CSTW);
|
|
}
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
} else {
|
|
switch (ext) {
|
|
case 0x00:
|
|
case 0x02:
|
|
if (uid == 0x00) {
|
|
MCInst_setOpcode(MI, HPPA_INS_FLDD);
|
|
} else {
|
|
MCInst_setOpcode(MI, HPPA_INS_CLDD);
|
|
}
|
|
return;
|
|
case 0x01:
|
|
case 0x03:
|
|
if (uid == 0x00) {
|
|
MCInst_setOpcode(MI, HPPA_INS_FSTD);
|
|
} else {
|
|
MCInst_setOpcode(MI, HPPA_INS_CSTD);
|
|
}
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (opcode == 0x09) {
|
|
switch (ext) {
|
|
case 0x00:
|
|
MCInst_setOpcode(MI, HPPA_INS_CLDWX);
|
|
break;
|
|
case 0x01:
|
|
MCInst_setOpcode(MI, HPPA_INS_CSTWX);
|
|
break;
|
|
case 0x02:
|
|
MCInst_setOpcode(MI, HPPA_INS_CLDWS);
|
|
break;
|
|
case 0x03:
|
|
MCInst_setOpcode(MI, HPPA_INS_CSTWS);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else {
|
|
switch (ext) {
|
|
case 0x00:
|
|
MCInst_setOpcode(MI, HPPA_INS_CLDDX);
|
|
break;
|
|
case 0x01:
|
|
MCInst_setOpcode(MI, HPPA_INS_CSTDX);
|
|
break;
|
|
case 0x02:
|
|
MCInst_setOpcode(MI, HPPA_INS_CLDDS);
|
|
break;
|
|
case 0x03:
|
|
MCInst_setOpcode(MI, HPPA_INS_CSTDS);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static inline bool coprdw_has_uid_mod(uint32_t opcode, uint32_t uid)
|
|
{
|
|
return !((opcode == HPPA_OP_TYPE_COPRW && uid <= 0x01) ||
|
|
(opcode == HPPA_OP_TYPE_COPRDW && uid == 0x00));
|
|
}
|
|
|
|
static void fill_corpdw_mods(uint32_t insn, uint32_t im, hppa_ext *hppa_ext,
|
|
cs_mode mode)
|
|
{
|
|
uint32_t uid = get_insn_field(insn, 23, 25);
|
|
uint32_t cmplt = (get_insn_bit(insn, 18) << 1) | get_insn_bit(insn, 26);
|
|
uint32_t cc = get_insn_field(insn, 20, 21);
|
|
uint32_t ext = (get_insn_bit(insn, 19) << 1) | get_insn_bit(insn, 22);
|
|
uint32_t opcode = insn >> 26;
|
|
|
|
if (coprdw_has_uid_mod(opcode, uid)) {
|
|
push_int_modifier(hppa_ext, uid);
|
|
}
|
|
if (CMPLT_HAS_MODIFY_BIT(cmplt)) {
|
|
hppa_ext->b_writeble = true;
|
|
}
|
|
|
|
switch (ext) {
|
|
case 0x00:
|
|
case 0x01:
|
|
push_str_modifier(hppa_ext, index_compl_names[cmplt]);
|
|
break;
|
|
case 0x02:
|
|
case 0x03:
|
|
if (MODE_IS_HPPA_20(mode)) {
|
|
if (cmplt == 1 && im == 0) {
|
|
push_str_modifier(hppa_ext, "o");
|
|
break;
|
|
}
|
|
}
|
|
push_str_modifier(hppa_ext, short_ldst_compl_names[cmplt]);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if ((ext & 1) == 1 && cc == 1) {
|
|
push_str_modifier(hppa_ext, "bc");
|
|
}
|
|
if (cc == 2) {
|
|
push_str_modifier(hppa_ext, "sl");
|
|
}
|
|
}
|
|
|
|
static bool decode_corpdw(const cs_struct *ud, MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t ext = (get_insn_bit(insn, 19) << 1) | get_insn_bit(insn, 22);
|
|
uint32_t x = get_insn_field(insn, 11, 15);
|
|
uint32_t b = get_insn_field(insn, 6, 10);
|
|
uint32_t s = get_insn_field(insn, 16, 17);
|
|
uint32_t t = get_insn_field(insn, 27, 31);
|
|
uint32_t opcode = MCInst_getOpcode(MI);
|
|
switch (ext) {
|
|
case 0x00:
|
|
case 0x02:
|
|
if (ext == 0x02) {
|
|
x = LowSignExtend64(x, 5);
|
|
MCOperand_CreateImm0(MI, x);
|
|
} else {
|
|
CREATE_GR_REG(MI, x);
|
|
}
|
|
CREATE_SR_REG(MI, s);
|
|
CREATE_GR_REG(MI, b);
|
|
if (opcode == HPPA_INS_FLDW || opcode == HPPA_INS_FLDD) {
|
|
CREATE_FPR_REG(MI, t);
|
|
} else {
|
|
CREATE_GR_REG(MI, t);
|
|
}
|
|
break;
|
|
case 0x01:
|
|
case 0x03:
|
|
if (opcode == HPPA_INS_FSTW || opcode == HPPA_INS_FSTD) {
|
|
CREATE_FPR_REG(MI, t);
|
|
} else {
|
|
CREATE_GR_REG(MI, t);
|
|
}
|
|
if (ext == 0x03) {
|
|
x = LowSignExtend64(x, 5);
|
|
MCOperand_CreateImm0(MI, x);
|
|
} else {
|
|
CREATE_GR_REG(MI, x);
|
|
}
|
|
CREATE_SR_REG(MI, s);
|
|
CREATE_GR_REG(MI, b);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
fill_corpdw_mods(insn, x, HPPA_EXT_REF(MI), ud->mode);
|
|
return true;
|
|
}
|
|
|
|
static void fill_spop_insn_name(MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t ext = get_insn_field(insn, 21, 22);
|
|
switch (ext) {
|
|
case 0x00:
|
|
MCInst_setOpcode(MI, HPPA_INS_SPOP0);
|
|
break;
|
|
case 0x01:
|
|
MCInst_setOpcode(MI, HPPA_INS_SPOP1);
|
|
break;
|
|
case 0x02:
|
|
MCInst_setOpcode(MI, HPPA_INS_SPOP2);
|
|
break;
|
|
case 0x03:
|
|
MCInst_setOpcode(MI, HPPA_INS_SPOP3);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void fill_spop_mods(uint32_t insn, uint32_t ext, hppa_ext *hppa_ext)
|
|
{
|
|
uint32_t sfu = get_insn_field(insn, 23, 25);
|
|
uint32_t n = get_insn_field(insn, 26, 26);
|
|
uint32_t sop;
|
|
|
|
push_int_modifier(hppa_ext, sfu);
|
|
switch (ext) {
|
|
case 0x00:
|
|
sop = (get_insn_field(insn, 6, 20) << 5) |
|
|
get_insn_field(insn, 27, 31);
|
|
break;
|
|
case 0x01:
|
|
sop = get_insn_field(insn, 6, 20);
|
|
break;
|
|
case 0x02:
|
|
sop = (get_insn_field(insn, 11, 20) << 5) |
|
|
get_insn_field(insn, 27, 31);
|
|
break;
|
|
case 0x03:
|
|
sop = (get_insn_field(insn, 16, 20) << 5) |
|
|
get_insn_field(insn, 27, 31);
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
push_int_modifier(hppa_ext, sop);
|
|
if (n == 1) {
|
|
push_str_modifier(hppa_ext, "n");
|
|
}
|
|
}
|
|
|
|
static bool decode_spop(const cs_struct *ud, MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t ext = get_insn_field(insn, 21, 22);
|
|
uint32_t r2 = get_insn_field(insn, 11, 15);
|
|
uint32_t r1 = get_insn_field(insn, 6, 10);
|
|
uint32_t t = get_insn_field(insn, 27, 31);
|
|
switch (ext) {
|
|
case 0x00:
|
|
break;
|
|
case 0x01:
|
|
CREATE_GR_REG(MI, t);
|
|
break;
|
|
case 0x02:
|
|
CREATE_GR_REG(MI, r1);
|
|
break;
|
|
case 0x03:
|
|
CREATE_GR_REG(MI, r2);
|
|
CREATE_GR_REG(MI, r1);
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
fill_spop_mods(insn, ext, HPPA_EXT_REF(MI));
|
|
return true;
|
|
}
|
|
|
|
static void fill_copr_insn_name(MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t class = get_insn_field(insn, 21, 22);
|
|
uint32_t uid = get_insn_field(insn, 23, 25);
|
|
uint32_t subop;
|
|
if (MODE_IS_HPPA_20(MI->csh->mode)) {
|
|
if (uid == 0) {
|
|
if (class == 0) {
|
|
subop = get_insn_field(insn, 16, 18);
|
|
switch (subop) {
|
|
case 0x00:
|
|
MCInst_setOpcode(MI, HPPA_INS_FID);
|
|
return;
|
|
case 0x06:
|
|
MCInst_setOpcode(MI, HPPA_INS_FNEG);
|
|
return;
|
|
case 0x07:
|
|
MCInst_setOpcode(MI, HPPA_INS_FNEGABS);
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
} else if (class == 1) {
|
|
subop = get_insn_field(insn, 14, 16);
|
|
if (subop != 4) {
|
|
MCInst_setOpcode(MI, HPPA_INS_FCNV);
|
|
return;
|
|
}
|
|
} else if (class == 2) {
|
|
if (get_insn_bit(insn, 26) == 0) {
|
|
MCInst_setOpcode(MI, HPPA_INS_FCMP);
|
|
} else {
|
|
MCInst_setOpcode(MI, HPPA_INS_FTEST);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (uid == 0) {
|
|
if (class == 0) {
|
|
subop = get_insn_field(insn, 16, 18);
|
|
switch (subop) {
|
|
case 0x00:
|
|
MCInst_setOpcode(MI, HPPA_INS_COPR);
|
|
return;
|
|
case 0x02:
|
|
MCInst_setOpcode(MI, HPPA_INS_FCPY);
|
|
return;
|
|
case 0x03:
|
|
MCInst_setOpcode(MI, HPPA_INS_FABS);
|
|
return;
|
|
case 0x04:
|
|
MCInst_setOpcode(MI, HPPA_INS_FSQRT);
|
|
return;
|
|
case 0x05:
|
|
MCInst_setOpcode(MI, HPPA_INS_FRND);
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
} else if (class == 1) {
|
|
subop = get_insn_field(insn, 15, 16);
|
|
switch (subop) {
|
|
case 0x00:
|
|
MCInst_setOpcode(MI, HPPA_INS_FCNVFF);
|
|
return;
|
|
case 0x01:
|
|
MCInst_setOpcode(MI, HPPA_INS_FCNVXF);
|
|
return;
|
|
case 0x02:
|
|
MCInst_setOpcode(MI, HPPA_INS_FCNVFX);
|
|
return;
|
|
case 0x03:
|
|
MCInst_setOpcode(MI, HPPA_INS_FCNVFXT);
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
} else if (class == 2) {
|
|
subop = get_insn_field(insn, 16, 18);
|
|
switch (subop) {
|
|
case 0x00:
|
|
MCInst_setOpcode(MI, HPPA_INS_FCMP);
|
|
return;
|
|
case 0x01:
|
|
MCInst_setOpcode(MI, HPPA_INS_FTEST);
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
} else if (class == 3) {
|
|
subop = get_insn_field(insn, 16, 18);
|
|
switch (subop) {
|
|
case 0x00:
|
|
MCInst_setOpcode(MI, HPPA_INS_FADD);
|
|
return;
|
|
case 0x01:
|
|
MCInst_setOpcode(MI, HPPA_INS_FSUB);
|
|
return;
|
|
case 0x02:
|
|
MCInst_setOpcode(MI, HPPA_INS_FMPY);
|
|
return;
|
|
case 0x03:
|
|
MCInst_setOpcode(MI, HPPA_INS_FDIV);
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
} else if (uid == 2) {
|
|
subop = get_insn_field(insn, 18, 22);
|
|
switch (subop) {
|
|
case 0x01:
|
|
MCInst_setOpcode(MI, HPPA_INS_PMDIS);
|
|
return;
|
|
case 0x03:
|
|
MCInst_setOpcode(MI, HPPA_INS_PMENB);
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
MCInst_setOpcode(MI, HPPA_INS_COPR);
|
|
}
|
|
|
|
static void fill_copr_mods(uint32_t insn, uint32_t uid, uint32_t class,
|
|
hppa_ext *hppa_ext, uint32_t subop, cs_mode mode)
|
|
{
|
|
uint32_t n = get_insn_field(insn, 26, 26);
|
|
uint32_t sf = get_insn_field(insn, 19, 20);
|
|
uint32_t df = get_insn_field(insn, 17, 18);
|
|
if (MODE_IS_HPPA_20(mode)) {
|
|
if (uid == 0) {
|
|
if (class == 0) {
|
|
switch (subop) {
|
|
case 0x00:
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
} else if (class == 1) {
|
|
switch (subop) {
|
|
case 0x00:
|
|
push_str_modifier(
|
|
hppa_ext,
|
|
float_format_names[sf]);
|
|
push_str_modifier(
|
|
hppa_ext,
|
|
float_format_names[df]);
|
|
return;
|
|
case 0x01:
|
|
push_str_modifier(hppa_ext,
|
|
fcnv_fixed_names[sf]);
|
|
push_str_modifier(
|
|
hppa_ext,
|
|
float_format_names[df]);
|
|
return;
|
|
case 0x03:
|
|
push_str_modifier(hppa_ext, "t");
|
|
// fallthrough
|
|
case 0x02:
|
|
push_str_modifier(
|
|
hppa_ext,
|
|
float_format_names[sf]);
|
|
push_str_modifier(hppa_ext,
|
|
fcnv_fixed_names[df]);
|
|
return;
|
|
case 0x05:
|
|
push_str_modifier(
|
|
hppa_ext,
|
|
fcnv_ufixed_names[sf]);
|
|
push_str_modifier(
|
|
hppa_ext,
|
|
float_format_names[df]);
|
|
return;
|
|
case 0x07:
|
|
push_str_modifier(hppa_ext, "t");
|
|
// fallthrough
|
|
case 0x06:
|
|
push_str_modifier(
|
|
hppa_ext,
|
|
float_format_names[sf]);
|
|
push_str_modifier(
|
|
hppa_ext,
|
|
fcnv_ufixed_names[df]);
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (uid == 0) {
|
|
if (class == 0) {
|
|
switch (subop) {
|
|
case 0x00:
|
|
push_int_modifier(hppa_ext, 0);
|
|
push_int_modifier(hppa_ext, 0);
|
|
if (n == 1) {
|
|
push_str_modifier(hppa_ext, "n");
|
|
}
|
|
break;
|
|
case 0x02:
|
|
case 0x03:
|
|
case 0x04:
|
|
case 0x05:
|
|
case 0x06:
|
|
case 0x07:
|
|
push_str_modifier(hppa_ext,
|
|
float_format_names[sf]);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else if (class == 1) {
|
|
push_str_modifier(hppa_ext, float_format_names[sf]);
|
|
push_str_modifier(hppa_ext, float_format_names[df]);
|
|
} else if (class == 2) {
|
|
uint32_t cond = get_insn_field(insn, 27, 31);
|
|
if (n == 1 && subop == 1) {
|
|
push_str_modifier(hppa_ext,
|
|
float_cond_names[cond]);
|
|
}
|
|
if (n == 0) {
|
|
push_str_modifier(hppa_ext,
|
|
float_format_names[sf]);
|
|
push_str_modifier(hppa_ext,
|
|
float_comp_names[cond]);
|
|
}
|
|
} else if (class == 3) {
|
|
push_str_modifier(hppa_ext, float_format_names[sf]);
|
|
}
|
|
} else if (uid == 2) {
|
|
if (n == 1) {
|
|
push_str_modifier(hppa_ext, "n");
|
|
}
|
|
} else {
|
|
uid = get_insn_field(insn, 23, 25);
|
|
uint32_t sop = (get_insn_field(insn, 6, 22) << 5) |
|
|
get_insn_field(insn, 27, 31);
|
|
push_int_modifier(hppa_ext, uid);
|
|
push_int_modifier(hppa_ext, sop);
|
|
if (n == 1) {
|
|
push_str_modifier(hppa_ext, "n");
|
|
}
|
|
}
|
|
}
|
|
|
|
static bool decode_copr(const cs_struct *ud, MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t class = get_insn_field(insn, 21, 22);
|
|
uint32_t uid = get_insn_field(insn, 23, 25);
|
|
uint32_t subop;
|
|
uint32_t r1 = get_insn_field(insn, 6, 10);
|
|
uint32_t r2 = get_insn_field(insn, 11, 15);
|
|
uint32_t t = get_insn_field(insn, 27, 31);
|
|
if (MODE_IS_HPPA_20(ud->mode)) {
|
|
if (uid == 0) {
|
|
if (class == 0) {
|
|
subop = get_insn_field(insn, 16, 18);
|
|
if (subop == 0x01) {
|
|
return false;
|
|
}
|
|
if (subop >= 0x02) {
|
|
CREATE_FPR_REG(MI, r1);
|
|
CREATE_FPR_REG(MI, t);
|
|
}
|
|
} else if (class == 1) {
|
|
subop = get_insn_field(insn, 14, 16);
|
|
if (subop == 0x04) {
|
|
return false;
|
|
}
|
|
CREATE_FPR_REG(MI, r1);
|
|
CREATE_FPR_REG(MI, t);
|
|
} else if (class == 2) {
|
|
uint32_t n = get_insn_bit(insn, 26);
|
|
subop = get_insn_field(insn, 16, 18);
|
|
if (n == 0) {
|
|
CREATE_FPR_REG(MI, r1);
|
|
CREATE_FPR_REG(MI, r2);
|
|
if (subop != 0) {
|
|
MCOperand_CreateImm0(MI,
|
|
subop - 1);
|
|
HPPA_EXT_REF(MI)
|
|
->is_alternative = true;
|
|
}
|
|
} else {
|
|
if (subop != 1) {
|
|
MCOperand_CreateImm0(
|
|
MI, (subop ^ 1) - 1);
|
|
HPPA_EXT_REF(MI)
|
|
->is_alternative = true;
|
|
}
|
|
}
|
|
} else {
|
|
subop = get_insn_field(insn, 16, 18);
|
|
if (subop >= 4) {
|
|
return false;
|
|
}
|
|
CREATE_FPR_REG(MI, r1);
|
|
CREATE_FPR_REG(MI, r2);
|
|
CREATE_FPR_REG(MI, t);
|
|
}
|
|
fill_copr_mods(insn, uid, class, HPPA_EXT_REF(MI),
|
|
subop, ud->mode);
|
|
return true;
|
|
}
|
|
}
|
|
if (uid == 0) {
|
|
if (class == 0) {
|
|
subop = get_insn_field(insn, 16, 18);
|
|
switch (subop) {
|
|
case 0x02:
|
|
case 0x03:
|
|
case 0x04:
|
|
case 0x05:
|
|
CREATE_FPR_REG(MI, r1);
|
|
CREATE_FPR_REG(MI, t);
|
|
// fallthrough
|
|
case 0x00:
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
} else if (class == 1) {
|
|
subop = get_insn_field(insn, 15, 16);
|
|
switch (subop) {
|
|
case 0x00:
|
|
case 0x01:
|
|
case 0x02:
|
|
case 0x03:
|
|
CREATE_FPR_REG(MI, r1);
|
|
CREATE_FPR_REG(MI, t);
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
} else if (class == 2) {
|
|
subop = get_insn_field(insn, 16, 18);
|
|
switch (subop) {
|
|
case 0x00:
|
|
CREATE_FPR_REG(MI, r1);
|
|
CREATE_FPR_REG(MI, r2);
|
|
// fallthrough
|
|
case 0x01:
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
} else {
|
|
subop = get_insn_field(insn, 16, 18);
|
|
switch (subop) {
|
|
case 0x00:
|
|
case 0x01:
|
|
case 0x02:
|
|
case 0x03:
|
|
CREATE_FPR_REG(MI, r1);
|
|
CREATE_FPR_REG(MI, r2);
|
|
CREATE_FPR_REG(MI, t);
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
fill_copr_mods(insn, uid, class, HPPA_EXT_REF(MI), subop,
|
|
ud->mode);
|
|
return true;
|
|
} else if (uid == 2) {
|
|
subop = get_insn_field(insn, 18, 22);
|
|
switch (subop) {
|
|
case 0x01:
|
|
case 0x03:
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
fill_copr_mods(insn, uid, class, HPPA_EXT_REF(MI), -1, ud->mode);
|
|
return true;
|
|
}
|
|
|
|
static void fill_float_insn_name(MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t class = get_insn_field(insn, 21, 22);
|
|
uint32_t subop;
|
|
if (MODE_IS_HPPA_20(MI->csh->mode)) {
|
|
if (class == 0) {
|
|
subop = get_insn_field(insn, 16, 18);
|
|
switch (subop) {
|
|
case 0x06:
|
|
MCInst_setOpcode(MI, HPPA_INS_FNEG);
|
|
return;
|
|
case 0x07:
|
|
MCInst_setOpcode(MI, HPPA_INS_FNEGABS);
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
} else if (class == 1) {
|
|
subop = get_insn_field(insn, 14, 16);
|
|
if (subop == 0x04) {
|
|
return;
|
|
}
|
|
MCInst_setOpcode(MI, HPPA_INS_FCNV);
|
|
return;
|
|
} else if (class == 2) {
|
|
MCInst_setOpcode(MI, HPPA_INS_FCMP);
|
|
return;
|
|
}
|
|
}
|
|
if (class == 0) {
|
|
subop = get_insn_field(insn, 16, 18);
|
|
switch (subop) {
|
|
case 0x02:
|
|
MCInst_setOpcode(MI, HPPA_INS_FCPY);
|
|
break;
|
|
case 0x03:
|
|
MCInst_setOpcode(MI, HPPA_INS_FABS);
|
|
break;
|
|
case 0x04:
|
|
MCInst_setOpcode(MI, HPPA_INS_FSQRT);
|
|
break;
|
|
case 0x05:
|
|
MCInst_setOpcode(MI, HPPA_INS_FRND);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else if (class == 1) {
|
|
subop = get_insn_field(insn, 15, 16);
|
|
switch (subop) {
|
|
case 0x00:
|
|
MCInst_setOpcode(MI, HPPA_INS_FCNVFF);
|
|
break;
|
|
case 0x01:
|
|
MCInst_setOpcode(MI, HPPA_INS_FCNVXF);
|
|
break;
|
|
case 0x02:
|
|
MCInst_setOpcode(MI, HPPA_INS_FCNVFX);
|
|
break;
|
|
case 0x03:
|
|
MCInst_setOpcode(MI, HPPA_INS_FCNVFXT);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else if (class == 2) {
|
|
subop = get_insn_field(insn, 16, 18);
|
|
if (subop == 0x00) {
|
|
MCInst_setOpcode(MI, HPPA_INS_FCMP);
|
|
}
|
|
} else if (class == 3) {
|
|
subop = get_insn_field(insn, 16, 18);
|
|
uint32_t fixed = get_insn_field(insn, 23, 23);
|
|
if (fixed == 0) {
|
|
switch (subop) {
|
|
case 0x00:
|
|
MCInst_setOpcode(MI, HPPA_INS_FADD);
|
|
break;
|
|
case 0x01:
|
|
MCInst_setOpcode(MI, HPPA_INS_FSUB);
|
|
break;
|
|
case 0x02:
|
|
MCInst_setOpcode(MI, HPPA_INS_FMPY);
|
|
break;
|
|
case 0x03:
|
|
MCInst_setOpcode(MI, HPPA_INS_FDIV);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else {
|
|
if (subop == 0x02) {
|
|
MCInst_setOpcode(MI, HPPA_INS_XMPYU);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void fill_float_mods(uint32_t insn, uint32_t class, hppa_ext *hppa_ext,
|
|
uint32_t subop, cs_mode mode)
|
|
{
|
|
uint32_t sf = get_insn_field(insn, 19, 20);
|
|
uint32_t df = get_insn_field(insn, 17, 18);
|
|
|
|
if (MODE_IS_HPPA_20(mode)) {
|
|
if (class == 1) {
|
|
switch (subop) {
|
|
case 0x00:
|
|
push_str_modifier(hppa_ext,
|
|
float_format_names[sf]);
|
|
push_str_modifier(hppa_ext,
|
|
float_format_names[df]);
|
|
return;
|
|
case 0x01:
|
|
push_str_modifier(hppa_ext,
|
|
fcnv_fixed_names[sf]);
|
|
push_str_modifier(hppa_ext,
|
|
float_format_names[df]);
|
|
return;
|
|
case 0x03:
|
|
push_str_modifier(hppa_ext, "t");
|
|
// fallthrough
|
|
case 0x02:
|
|
push_str_modifier(hppa_ext,
|
|
float_format_names[sf]);
|
|
push_str_modifier(hppa_ext,
|
|
fcnv_fixed_names[df]);
|
|
return;
|
|
case 0x05:
|
|
push_str_modifier(hppa_ext,
|
|
fcnv_ufixed_names[sf]);
|
|
push_str_modifier(hppa_ext,
|
|
float_format_names[df]);
|
|
return;
|
|
case 0x07:
|
|
push_str_modifier(hppa_ext, "t");
|
|
// fallthrough
|
|
case 0x06:
|
|
push_str_modifier(hppa_ext,
|
|
float_format_names[sf]);
|
|
push_str_modifier(hppa_ext,
|
|
fcnv_ufixed_names[df]);
|
|
return;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (class == 0) {
|
|
uint32_t fmt = get_insn_field(insn, 19, 20);
|
|
push_str_modifier(hppa_ext, float_format_names[fmt]);
|
|
} else if (class == 1) {
|
|
push_str_modifier(hppa_ext, float_format_names[sf]);
|
|
push_str_modifier(hppa_ext, float_format_names[df]);
|
|
} else if (class == 2) {
|
|
uint32_t fmt = get_insn_field(insn, 20, 20);
|
|
uint32_t cond = get_insn_field(insn, 27, 31);
|
|
push_str_modifier(hppa_ext, float_format_names[fmt]);
|
|
push_str_modifier(hppa_ext, float_cond_names[cond]);
|
|
} else if (class == 3) {
|
|
if (get_insn_field(insn, 23, 23) == 0) {
|
|
uint32_t fmt = get_insn_field(insn, 20, 20);
|
|
push_str_modifier(hppa_ext, float_format_names[fmt]);
|
|
}
|
|
}
|
|
}
|
|
|
|
static bool decode_float(const cs_struct *ud, MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t class = get_insn_field(insn, 21, 22);
|
|
uint32_t subop;
|
|
uint32_t r1 = get_insn_field(insn, 6, 10);
|
|
uint32_t r1_fpe = get_insn_bit(insn, 24);
|
|
uint32_t r2 = get_insn_field(insn, 11, 15);
|
|
uint32_t r2_fpe = get_insn_bit(insn, 19);
|
|
uint32_t t = get_insn_field(insn, 27, 31);
|
|
uint32_t t_fpe = get_insn_bit(insn, 25);
|
|
if (MODE_IS_HPPA_20(ud->mode)) {
|
|
if (class == 0) {
|
|
subop = get_insn_field(insn, 16, 18);
|
|
if (subop >= 0x02) {
|
|
create_float_reg_spec(MI, r1, r1_fpe);
|
|
create_float_reg_spec(MI, t, t_fpe);
|
|
fill_float_mods(insn, class, HPPA_EXT_REF(MI),
|
|
subop, ud->mode);
|
|
return true;
|
|
}
|
|
} else if (class == 1) {
|
|
subop = get_insn_field(insn, 14, 16);
|
|
if (subop == 0x04) {
|
|
return false;
|
|
}
|
|
create_float_reg_spec(MI, r1, r1_fpe);
|
|
create_float_reg_spec(MI, t, t_fpe);
|
|
fill_float_mods(insn, class, HPPA_EXT_REF(MI), subop,
|
|
ud->mode);
|
|
return true;
|
|
} else if (class == 2) {
|
|
subop = get_insn_field(insn, 16, 18);
|
|
create_float_reg_spec(MI, r1, r1_fpe);
|
|
create_float_reg_spec(MI, r2, r2_fpe);
|
|
if (subop != 0) {
|
|
MCOperand_CreateImm0(MI, subop - 1);
|
|
}
|
|
fill_float_mods(insn, class, HPPA_EXT_REF(MI), subop,
|
|
ud->mode);
|
|
return true;
|
|
}
|
|
}
|
|
if (class == 0) {
|
|
subop = get_insn_field(insn, 16, 18);
|
|
switch (subop) {
|
|
case 0x02:
|
|
case 0x03:
|
|
case 0x04:
|
|
case 0x05:
|
|
create_float_reg_spec(MI, r1, r1_fpe);
|
|
create_float_reg_spec(MI, t, t_fpe);
|
|
fill_float_mods(insn, class, HPPA_EXT_REF(MI), subop,
|
|
ud->mode);
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
} else if (class == 1) {
|
|
subop = get_insn_field(insn, 15, 16);
|
|
if (subop <= 0x03) {
|
|
create_float_reg_spec(MI, r1, r1_fpe);
|
|
create_float_reg_spec(MI, t, t_fpe);
|
|
fill_float_mods(insn, class, HPPA_EXT_REF(MI), subop,
|
|
ud->mode);
|
|
return true;
|
|
}
|
|
} else if (class == 2) {
|
|
subop = get_insn_field(insn, 16, 18);
|
|
switch (subop) {
|
|
case 0x00:
|
|
create_float_reg_spec(MI, r1, r1_fpe);
|
|
create_float_reg_spec(MI, r2, r2_fpe);
|
|
fill_float_mods(insn, class, HPPA_EXT_REF(MI), subop,
|
|
ud->mode);
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
} else if (class == 3) {
|
|
subop = get_insn_field(insn, 16, 18);
|
|
uint32_t fixed = get_insn_field(insn, 23, 23);
|
|
if ((fixed == 0 && subop <= 0x03) ||
|
|
(fixed == 1 && subop == 0x02)) {
|
|
create_float_reg_spec(MI, r1, r1_fpe);
|
|
create_float_reg_spec(MI, r2, r2_fpe);
|
|
create_float_reg_spec(MI, t, t_fpe);
|
|
fill_float_mods(insn, class, HPPA_EXT_REF(MI), subop,
|
|
ud->mode);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static void fill_fpfused_insn_name(MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t subop = get_insn_bit(insn, 26);
|
|
if (subop == 0x00) {
|
|
MCInst_setOpcode(MI, HPPA_INS_FMPYFADD);
|
|
} else {
|
|
MCInst_setOpcode(MI, HPPA_INS_FMPYNFADD);
|
|
}
|
|
}
|
|
|
|
static void fill_fpfused_mods(uint32_t insn, hppa_ext *hppa_ext)
|
|
{
|
|
uint32_t fmt = get_insn_bit(insn, 20);
|
|
push_str_modifier(hppa_ext, float_format_names[fmt]);
|
|
}
|
|
|
|
static bool decode_fpfused(const cs_struct *ud, MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t r1 = get_insn_field(insn, 6, 10);
|
|
uint32_t r1_fpe = get_insn_bit(insn, 24);
|
|
uint32_t r2 = get_insn_field(insn, 11, 15);
|
|
uint32_t r2_fpe = get_insn_bit(insn, 19);
|
|
uint32_t ra = (get_insn_field(insn, 16, 18) << 2) |
|
|
get_insn_field(insn, 21, 22);
|
|
uint32_t ra_fpe = get_insn_bit(insn, 23);
|
|
uint32_t t = get_insn_field(insn, 27, 31);
|
|
uint32_t t_fpe = get_insn_bit(insn, 25);
|
|
create_float_reg_spec(MI, r1, r1_fpe);
|
|
create_float_reg_spec(MI, r2, r2_fpe);
|
|
create_float_reg_spec(MI, ra, ra_fpe);
|
|
create_float_reg_spec(MI, t, t_fpe);
|
|
fill_fpfused_mods(insn, HPPA_EXT_REF(MI));
|
|
return true;
|
|
}
|
|
|
|
static void fill_action_and_branch_insn_name(MCInst *MI, uint32_t opcode)
|
|
{
|
|
if (MODE_IS_HPPA_20(MI->csh->mode)) {
|
|
switch (opcode) {
|
|
case HPPA_OP_TYPE_CMPBT:
|
|
case HPPA_OP_TYPE_CMPBF:
|
|
case HPPA_OP_TYPE_CMPBDWT:
|
|
case HPPA_OP_TYPE_CMPBDWF:
|
|
MCInst_setOpcode(MI, HPPA_INS_CMPB);
|
|
return;
|
|
case HPPA_OP_TYPE_CMPIBT:
|
|
case HPPA_OP_TYPE_CMPIBF:
|
|
case HPPA_OP_TYPE_CMPIBDW:
|
|
MCInst_setOpcode(MI, HPPA_INS_CMPIB);
|
|
return;
|
|
case HPPA_OP_TYPE_ADDBT:
|
|
case HPPA_OP_TYPE_ADDBF:
|
|
MCInst_setOpcode(MI, HPPA_INS_ADDB);
|
|
return;
|
|
case HPPA_OP_TYPE_ADDIBT:
|
|
case HPPA_OP_TYPE_ADDIBF:
|
|
MCInst_setOpcode(MI, HPPA_INS_ADDIB);
|
|
return;
|
|
case HPPA_OP_TYPE_BBS:
|
|
MCInst_setOpcode(MI, HPPA_INS_BB);
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
switch (opcode) {
|
|
case HPPA_OP_TYPE_CMPBT:
|
|
MCInst_setOpcode(MI, HPPA_INS_COMBT);
|
|
break;
|
|
case HPPA_OP_TYPE_CMPBF:
|
|
MCInst_setOpcode(MI, HPPA_INS_COMBF);
|
|
break;
|
|
case HPPA_OP_TYPE_CMPIBT:
|
|
MCInst_setOpcode(MI, HPPA_INS_COMIBT);
|
|
break;
|
|
case HPPA_OP_TYPE_CMPIBF:
|
|
MCInst_setOpcode(MI, HPPA_INS_COMIBF);
|
|
break;
|
|
case HPPA_OP_TYPE_ADDBT:
|
|
MCInst_setOpcode(MI, HPPA_INS_ADDBT);
|
|
break;
|
|
case HPPA_OP_TYPE_ADDBF:
|
|
MCInst_setOpcode(MI, HPPA_INS_ADDBF);
|
|
break;
|
|
case HPPA_OP_TYPE_ADDIBT:
|
|
MCInst_setOpcode(MI, HPPA_INS_ADDIBT);
|
|
break;
|
|
case HPPA_OP_TYPE_ADDIBF:
|
|
MCInst_setOpcode(MI, HPPA_INS_ADDIBF);
|
|
break;
|
|
case HPPA_OP_TYPE_MOVB:
|
|
MCInst_setOpcode(MI, HPPA_INS_MOVB);
|
|
break;
|
|
case HPPA_OP_TYPE_MOVIB:
|
|
MCInst_setOpcode(MI, HPPA_INS_MOVIB);
|
|
break;
|
|
case HPPA_OP_TYPE_BBS:
|
|
MCInst_setOpcode(MI, HPPA_INS_BVB);
|
|
break;
|
|
case HPPA_OP_TYPE_BB:
|
|
MCInst_setOpcode(MI, HPPA_INS_BB);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void fill_action_and_branch_mods(uint32_t insn, uint32_t opcode,
|
|
hppa_ext *hppa_ext, cs_mode mode)
|
|
{
|
|
uint32_t cond = get_insn_field(insn, 16, 18);
|
|
uint32_t n = get_insn_bit(insn, 30);
|
|
uint32_t d = get_insn_bit(insn, 18);
|
|
|
|
if (MODE_IS_HPPA_20(mode)) {
|
|
switch (opcode) {
|
|
case HPPA_OP_TYPE_CMPBT:
|
|
case HPPA_OP_TYPE_CMPIBT:
|
|
push_str_modifier(hppa_ext, compare_cond_names[cond]);
|
|
break;
|
|
case HPPA_OP_TYPE_CMPBF:
|
|
case HPPA_OP_TYPE_CMPIBF:
|
|
push_str_modifier(hppa_ext,
|
|
compare_cond_names[cond + 8]);
|
|
break;
|
|
case HPPA_OP_TYPE_CMPBDWT:
|
|
push_str_modifier(hppa_ext,
|
|
compare_cond_64_names[cond]);
|
|
break;
|
|
case HPPA_OP_TYPE_CMPBDWF:
|
|
push_str_modifier(hppa_ext,
|
|
compare_cond_64_names[cond + 8]);
|
|
break;
|
|
case HPPA_OP_TYPE_CMPIBDW:
|
|
push_str_modifier(hppa_ext, cmpib_cond_64_names[cond]);
|
|
break;
|
|
case HPPA_OP_TYPE_ADDBT:
|
|
case HPPA_OP_TYPE_ADDIBT:
|
|
if (MODE_IS_HPPA_20W(mode)) {
|
|
push_str_modifier(hppa_ext,
|
|
wide_add_cond_names[cond]);
|
|
} else {
|
|
push_str_modifier(hppa_ext,
|
|
add_cond_names[cond]);
|
|
}
|
|
break;
|
|
case HPPA_OP_TYPE_ADDBF:
|
|
case HPPA_OP_TYPE_ADDIBF:
|
|
if (MODE_IS_HPPA_20W(mode)) {
|
|
push_str_modifier(
|
|
hppa_ext,
|
|
wide_add_cond_names[cond + 8]);
|
|
} else {
|
|
push_str_modifier(hppa_ext,
|
|
add_cond_names[cond + 8]);
|
|
}
|
|
break;
|
|
case HPPA_OP_TYPE_BBS:
|
|
case HPPA_OP_TYPE_BB:
|
|
if (d == 0) {
|
|
push_str_modifier(hppa_ext,
|
|
shift_cond_names[cond]);
|
|
} else {
|
|
push_str_modifier(hppa_ext,
|
|
shift_cond_64_names[cond]);
|
|
}
|
|
break;
|
|
case HPPA_OP_TYPE_MOVB:
|
|
case HPPA_OP_TYPE_MOVIB:
|
|
push_str_modifier(hppa_ext, shift_cond_names[cond]);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (n == 1) {
|
|
push_str_modifier(hppa_ext, "n");
|
|
}
|
|
return;
|
|
}
|
|
switch (opcode) {
|
|
case HPPA_OP_TYPE_CMPBT:
|
|
case HPPA_OP_TYPE_CMPBF:
|
|
case HPPA_OP_TYPE_CMPIBT:
|
|
case HPPA_OP_TYPE_CMPIBF:
|
|
push_str_modifier(hppa_ext, compare_cond_names[cond]);
|
|
break;
|
|
case HPPA_OP_TYPE_ADDBT:
|
|
case HPPA_OP_TYPE_ADDBF:
|
|
case HPPA_OP_TYPE_ADDIBT:
|
|
case HPPA_OP_TYPE_ADDIBF:
|
|
push_str_modifier(hppa_ext, add_cond_names[cond]);
|
|
break;
|
|
case HPPA_OP_TYPE_MOVB:
|
|
case HPPA_OP_TYPE_MOVIB:
|
|
case HPPA_OP_TYPE_BBS:
|
|
case HPPA_OP_TYPE_BB:
|
|
push_str_modifier(hppa_ext, shift_cond_names[cond]);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (n == 1) {
|
|
push_str_modifier(hppa_ext, "n");
|
|
}
|
|
}
|
|
|
|
static bool fill_action_and_branch(const cs_struct *ud, MCInst *MI,
|
|
uint32_t insn)
|
|
{
|
|
uint32_t opcode = insn >> 26;
|
|
uint32_t r1 = get_insn_field(insn, 6, 10);
|
|
uint32_t r2 = get_insn_field(insn, 11, 15);
|
|
if (MODE_IS_HPPA_20(ud->mode)) {
|
|
switch (opcode) {
|
|
case HPPA_OP_TYPE_CMPBT:
|
|
case HPPA_OP_TYPE_CMPBF:
|
|
case HPPA_OP_TYPE_CMPBDWT:
|
|
case HPPA_OP_TYPE_CMPBDWF:
|
|
case HPPA_OP_TYPE_ADDBT:
|
|
case HPPA_OP_TYPE_ADDBF:
|
|
case HPPA_OP_TYPE_MOVB:
|
|
CREATE_GR_REG(MI, r2);
|
|
CREATE_GR_REG(MI, r1);
|
|
MCOperand_CreateImm0(MI, extract_12(insn));
|
|
break;
|
|
case HPPA_OP_TYPE_CMPIBT:
|
|
case HPPA_OP_TYPE_CMPIBF:
|
|
case HPPA_OP_TYPE_CMPIBDW:
|
|
case HPPA_OP_TYPE_ADDIBT:
|
|
case HPPA_OP_TYPE_ADDIBF:
|
|
case HPPA_OP_TYPE_MOVIB:
|
|
MCOperand_CreateImm0(MI, LowSignExtend64(r2, 5));
|
|
CREATE_GR_REG(MI, r1);
|
|
MCOperand_CreateImm0(MI, extract_12(insn));
|
|
break;
|
|
case HPPA_OP_TYPE_BBS:
|
|
case HPPA_OP_TYPE_BB:
|
|
CREATE_GR_REG(MI, r2);
|
|
if ((opcode & 1) == 1) {
|
|
MCOperand_CreateImm0(MI, r1);
|
|
} else {
|
|
CREATE_CR_REG(MI, 11);
|
|
}
|
|
MCOperand_CreateImm0(MI, extract_12(insn));
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
fill_action_and_branch_mods(insn, opcode, HPPA_EXT_REF(MI),
|
|
ud->mode);
|
|
return true;
|
|
}
|
|
if ((opcode & 1) == 0 || opcode == HPPA_OP_TYPE_BB) {
|
|
CREATE_GR_REG(MI, r2);
|
|
} else {
|
|
MCOperand_CreateImm0(MI, LowSignExtend64(r2, 5));
|
|
}
|
|
if (opcode == HPPA_OP_TYPE_BB) {
|
|
MCOperand_CreateImm0(MI, r1);
|
|
} else if (opcode != HPPA_OP_TYPE_BBS) {
|
|
CREATE_GR_REG(MI, r1);
|
|
}
|
|
MCOperand_CreateImm0(MI, extract_12(insn));
|
|
fill_action_and_branch_mods(insn, opcode, HPPA_EXT_REF(MI), ud->mode);
|
|
return true;
|
|
}
|
|
|
|
static void fill_load_insn_name(MCInst *MI, uint32_t opcode)
|
|
{
|
|
switch (opcode) {
|
|
case HPPA_OP_TYPE_LDB:
|
|
MCInst_setOpcode(MI, HPPA_INS_LDB);
|
|
break;
|
|
case HPPA_OP_TYPE_LDH:
|
|
MCInst_setOpcode(MI, HPPA_INS_LDH);
|
|
break;
|
|
case HPPA_OP_TYPE_LDW:
|
|
MCInst_setOpcode(MI, HPPA_INS_LDW);
|
|
break;
|
|
case HPPA_OP_TYPE_LDWM:
|
|
if (MODE_IS_HPPA_20(MI->csh->mode)) {
|
|
MCInst_setOpcode(MI, HPPA_INS_LDW);
|
|
} else {
|
|
MCInst_setOpcode(MI, HPPA_INS_LDWM);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void fill_store_insn_name(MCInst *MI, uint32_t opcode)
|
|
{
|
|
switch (opcode) {
|
|
case HPPA_OP_TYPE_STB:
|
|
MCInst_setOpcode(MI, HPPA_INS_STB);
|
|
break;
|
|
case HPPA_OP_TYPE_STH:
|
|
MCInst_setOpcode(MI, HPPA_INS_STH);
|
|
break;
|
|
case HPPA_OP_TYPE_STW:
|
|
MCInst_setOpcode(MI, HPPA_INS_STW);
|
|
break;
|
|
case HPPA_OP_TYPE_STWM:
|
|
if (MODE_IS_HPPA_20(MI->csh->mode)) {
|
|
MCInst_setOpcode(MI, HPPA_INS_STW);
|
|
} else {
|
|
MCInst_setOpcode(MI, HPPA_INS_STWM);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static bool decode_cmpclr(const cs_struct *ud, MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t cond = (get_insn_bit(insn, 19) << 3) |
|
|
get_insn_field(insn, 16, 18);
|
|
uint32_t d = get_insn_bit(insn, 20);
|
|
if (MODE_IS_HPPA_20(ud->mode)) {
|
|
MCInst_setOpcode(MI, HPPA_INS_CMPICLR);
|
|
} else {
|
|
MCInst_setOpcode(MI, HPPA_INS_COMICLR);
|
|
}
|
|
|
|
MCOperand_CreateImm0(MI,
|
|
LowSignExtend64(get_insn_field(insn, 21, 31), 11));
|
|
CREATE_GR_REG(MI, get_insn_field(insn, 6, 10));
|
|
CREATE_GR_REG(MI, get_insn_field(insn, 11, 15));
|
|
|
|
if (d == 0) {
|
|
push_str_modifier(HPPA_EXT_REF(MI), compare_cond_names[cond]);
|
|
} else {
|
|
push_str_modifier(HPPA_EXT_REF(MI),
|
|
compare_cond_64_names[cond]);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool decode_be(const cs_struct *ud, MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t opcode = insn >> 26;
|
|
uint32_t n = get_insn_bit(insn, 30);
|
|
bool mode = MODE_IS_HPPA_20(ud->mode);
|
|
if (opcode == HPPA_OP_TYPE_BLE) {
|
|
if (!mode) {
|
|
MCInst_setOpcode(MI, HPPA_INS_BLE);
|
|
} else {
|
|
MCInst_setOpcode(MI, HPPA_INS_BE);
|
|
push_str_modifier(HPPA_EXT_REF(MI), "l");
|
|
HPPA_EXT_REF(MI)->is_alternative = true;
|
|
}
|
|
} else {
|
|
MCInst_setOpcode(MI, HPPA_INS_BE);
|
|
}
|
|
|
|
MCOperand_CreateImm0(MI, extract_17(insn));
|
|
CREATE_SR_REG(MI, extract_3(insn));
|
|
CREATE_GR_REG(MI, get_insn_field(insn, 6, 10));
|
|
if (opcode == HPPA_OP_TYPE_BLE && mode) {
|
|
CREATE_SR_REG(MI, 0);
|
|
CREATE_GR_REG(MI, 31);
|
|
}
|
|
if (n == 1) {
|
|
push_str_modifier(HPPA_EXT_REF(MI), "n");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool decode_float_ldst(const cs_struct *ud, MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t opcode = insn >> 26;
|
|
uint32_t a = get_insn_bit(insn, 29);
|
|
uint32_t disp = extract_16(insn, MODE_IS_HPPA_20W(ud->mode));
|
|
disp &= ~3;
|
|
|
|
if (opcode == HPPA_OP_TYPE_FLDW) {
|
|
MCInst_setOpcode(MI, HPPA_INS_FLDW);
|
|
MCOperand_CreateImm0(MI, disp);
|
|
CREATE_SR_REG(MI, get_insn_field(insn, 16, 17));
|
|
CREATE_GR_REG(MI, get_insn_field(insn, 6, 10));
|
|
CREATE_FPR_REG(MI, get_insn_field(insn, 11, 15));
|
|
} else {
|
|
MCInst_setOpcode(MI, HPPA_INS_FSTW);
|
|
CREATE_FPR_REG(MI, get_insn_field(insn, 11, 15));
|
|
MCOperand_CreateImm0(MI, disp);
|
|
CREATE_SR_REG(MI, get_insn_field(insn, 16, 17));
|
|
CREATE_GR_REG(MI, get_insn_field(insn, 6, 10));
|
|
}
|
|
|
|
if (a == 0) {
|
|
push_str_modifier(HPPA_EXT_REF(MI), "ma");
|
|
} else {
|
|
push_str_modifier(HPPA_EXT_REF(MI), "mb");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool decode_fmpy(const cs_struct *ud, MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t opcode = insn >> 26;
|
|
uint32_t rm1 = get_insn_field(insn, 6, 10);
|
|
uint32_t rm2 = get_insn_field(insn, 11, 15);
|
|
uint32_t ta = get_insn_field(insn, 16, 20);
|
|
uint32_t ra = get_insn_field(insn, 21, 25);
|
|
uint32_t tm = get_insn_field(insn, 27, 31);
|
|
uint32_t fmt = get_insn_field(insn, 26, 26);
|
|
|
|
if (opcode == HPPA_OP_TYPE_FMPYADD) {
|
|
MCInst_setOpcode(MI, HPPA_INS_FMPYADD);
|
|
} else {
|
|
MCInst_setOpcode(MI, HPPA_INS_FMPYSUB);
|
|
}
|
|
|
|
if (fmt == 0) {
|
|
push_str_modifier(HPPA_EXT_REF(MI), "dbl");
|
|
CREATE_FPR_REG(MI, rm1);
|
|
CREATE_FPR_REG(MI, rm2);
|
|
CREATE_FPR_REG(MI, tm);
|
|
CREATE_FPR_REG(MI, ra);
|
|
CREATE_FPR_REG(MI, ta);
|
|
} else {
|
|
push_str_modifier(HPPA_EXT_REF(MI), "sgl");
|
|
CREATE_SP_FPR_REG(MI, rm1);
|
|
CREATE_SP_FPR_REG(MI, rm2);
|
|
CREATE_SP_FPR_REG(MI, tm);
|
|
CREATE_SP_FPR_REG(MI, ra);
|
|
CREATE_SP_FPR_REG(MI, ta);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool decode_load(const cs_struct *ud, MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t opcode = insn >> 26;
|
|
if (MODE_IS_HPPA_20(ud->mode)) {
|
|
int32_t d = extract_16(insn, MODE_IS_HPPA_20W(ud->mode));
|
|
if (opcode == HPPA_OP_TYPE_LDWM) {
|
|
if (d < 0) {
|
|
push_str_modifier(HPPA_EXT_REF(MI), "mb");
|
|
} else {
|
|
push_str_modifier(HPPA_EXT_REF(MI), "ma");
|
|
}
|
|
}
|
|
MCOperand_CreateImm0(MI, d);
|
|
} else {
|
|
MCOperand_CreateImm0(MI, extract_14(insn));
|
|
}
|
|
CREATE_SR_REG(MI, get_insn_field(insn, 16, 17));
|
|
CREATE_GR_REG(MI, get_insn_field(insn, 6, 10));
|
|
CREATE_GR_REG(MI, get_insn_field(insn, 11, 15));
|
|
return true;
|
|
}
|
|
|
|
static bool decode_store(const cs_struct *ud, MCInst *MI, uint32_t insn)
|
|
{
|
|
uint32_t opcode = insn >> 26;
|
|
CREATE_GR_REG(MI, get_insn_field(insn, 11, 15));
|
|
if (MODE_IS_HPPA_20(ud->mode)) {
|
|
int d = extract_16(insn, MODE_IS_HPPA_20W(ud->mode));
|
|
if (opcode == HPPA_OP_TYPE_STWM) {
|
|
if (d < 0) {
|
|
push_str_modifier(HPPA_EXT_REF(MI), "mb");
|
|
} else {
|
|
push_str_modifier(HPPA_EXT_REF(MI), "ma");
|
|
}
|
|
}
|
|
MCOperand_CreateImm0(MI, d);
|
|
} else {
|
|
MCOperand_CreateImm0(MI, extract_14(insn));
|
|
}
|
|
CREATE_SR_REG(MI, get_insn_field(insn, 16, 17));
|
|
CREATE_GR_REG(MI, get_insn_field(insn, 6, 10));
|
|
return true;
|
|
}
|
|
|
|
static bool getInstruction(const cs_struct *ud, const uint8_t *code,
|
|
size_t code_len, MCInst *MI)
|
|
{
|
|
if (code_len < 4)
|
|
return false;
|
|
|
|
MCInst_clear(MI);
|
|
|
|
uint32_t full_insn = readBytes32(MI, code);
|
|
uint8_t opcode = full_insn >> 26;
|
|
|
|
if (MODE_IS_HPPA_20(ud->mode)) {
|
|
switch (opcode) {
|
|
case HPPA_OP_TYPE_LOADDW:
|
|
case HPPA_OP_TYPE_STOREDW:
|
|
fill_ldst_dw_insn_name(MI, full_insn);
|
|
return decode_ldst_dw(ud, MI, full_insn);
|
|
case HPPA_OP_TYPE_LOADW:
|
|
case HPPA_OP_TYPE_STOREW:
|
|
fill_ldst_w_insn_name(MI, full_insn);
|
|
return decode_ldst_w(ud, MI, full_insn);
|
|
case HPPA_OP_TYPE_SHEXDEP2:
|
|
MCInst_setOpcode(MI, HPPA_INS_EXTRD);
|
|
return decode_shexdep2(MI, full_insn);
|
|
case HPPA_OP_TYPE_SHEXDEP3:
|
|
case HPPA_OP_TYPE_SHEXDEP4:
|
|
return decode_shexdep3(ud, MI, full_insn);
|
|
case HPPA_OP_TYPE_MULTMED:
|
|
fill_multmed_insn_name(MI, full_insn);
|
|
return decode_multmed(MI, full_insn);
|
|
case HPPA_OP_TYPE_FPFUSED:
|
|
fill_fpfused_insn_name(MI, full_insn);
|
|
return decode_fpfused(ud, MI, full_insn);
|
|
case HPPA_OP_TYPE_FLDW:
|
|
case HPPA_OP_TYPE_FSTW:
|
|
return decode_float_ldst(ud, MI, full_insn);
|
|
case HPPA_OP_TYPE_CMPBDWT:
|
|
case HPPA_OP_TYPE_CMPBDWF:
|
|
case HPPA_OP_TYPE_CMPIBDW:
|
|
fill_action_and_branch_insn_name(MI, opcode);
|
|
return fill_action_and_branch(ud, MI, full_insn);
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch (opcode) {
|
|
case HPPA_OP_TYPE_SYSOP:
|
|
fill_sysop_insn_name(MI, full_insn);
|
|
return decode_sysop(ud, MI, full_insn);
|
|
case HPPA_OP_TYPE_MEMMGMT:
|
|
fill_memmgmt_insn_name(MI, full_insn);
|
|
return decode_memmgmt(ud, MI, full_insn);
|
|
case HPPA_OP_TYPE_ALU:
|
|
fill_alu_insn_name(MI, full_insn);
|
|
return decode_alu(ud, MI, full_insn);
|
|
case HPPA_OP_TYPE_IDXMEM:
|
|
fill_idxmem_insn_name(MI, full_insn);
|
|
return decode_idxmem(ud, MI, full_insn);
|
|
case HPPA_OP_TYPE_ADDIT:
|
|
case HPPA_OP_TYPE_ADDI:
|
|
case HPPA_OP_TYPE_SUBI:
|
|
fill_arith_imm_insn_name(MI, full_insn);
|
|
return decode_arith_imm(ud, MI, full_insn);
|
|
case HPPA_OP_TYPE_SHEXDEP0:
|
|
fill_shexdep0_insn_name(MI, full_insn);
|
|
return decode_shexdep0(ud, MI, full_insn);
|
|
case HPPA_OP_TYPE_SHEXDEP1:
|
|
fill_shexdep1_insn_name(MI, full_insn);
|
|
return decode_shexdep1(ud, MI, full_insn);
|
|
case HPPA_OP_TYPE_BRANCH:
|
|
fill_branch_insn_name(MI, full_insn);
|
|
return decode_branch(ud, MI, full_insn);
|
|
case HPPA_OP_TYPE_COPRW:
|
|
case HPPA_OP_TYPE_COPRDW:
|
|
fill_corpdw_insn_name(MI, full_insn);
|
|
return decode_corpdw(ud, MI, full_insn);
|
|
case HPPA_OP_TYPE_SPOP:
|
|
fill_spop_insn_name(MI, full_insn);
|
|
return decode_spop(ud, MI, full_insn);
|
|
case HPPA_OP_TYPE_COPR:
|
|
fill_copr_insn_name(MI, full_insn);
|
|
return decode_copr(ud, MI, full_insn);
|
|
case HPPA_OP_TYPE_FLOAT:
|
|
fill_float_insn_name(MI, full_insn);
|
|
return decode_float(ud, MI, full_insn);
|
|
case HPPA_OP_TYPE_DIAG:
|
|
MCInst_setOpcode(MI, HPPA_INS_DIAG);
|
|
MCOperand_CreateImm0(MI, get_insn_field(full_insn, 6, 31));
|
|
return true;
|
|
case HPPA_OP_TYPE_FMPYADD:
|
|
case HPPA_OP_TYPE_FMPYSUB:
|
|
return decode_fmpy(ud, MI, full_insn);
|
|
case HPPA_OP_TYPE_LDIL:
|
|
case HPPA_OP_TYPE_ADDIL:
|
|
if (opcode == HPPA_OP_TYPE_LDIL) {
|
|
MCInst_setOpcode(MI, HPPA_INS_LDIL);
|
|
} else {
|
|
MCInst_setOpcode(MI, HPPA_INS_ADDIL);
|
|
}
|
|
MCOperand_CreateImm0(MI, extract_21(full_insn));
|
|
CREATE_GR_REG(MI, get_insn_field(full_insn, 6, 10));
|
|
return true;
|
|
case HPPA_OP_TYPE_LDO:
|
|
MCInst_setOpcode(MI, HPPA_INS_LDO);
|
|
if (MODE_IS_HPPA_20(ud->mode)) {
|
|
MCOperand_CreateImm0(
|
|
MI, extract_16(full_insn,
|
|
MODE_IS_HPPA_20W(ud->mode)));
|
|
} else {
|
|
MCOperand_CreateImm0(MI, extract_14(full_insn));
|
|
}
|
|
CREATE_GR_REG(MI, get_insn_field(full_insn, 6, 10));
|
|
CREATE_GR_REG(MI, get_insn_field(full_insn, 11, 15));
|
|
return true;
|
|
case HPPA_OP_TYPE_LDB:
|
|
case HPPA_OP_TYPE_LDH:
|
|
case HPPA_OP_TYPE_LDW:
|
|
case HPPA_OP_TYPE_LDWM:
|
|
fill_load_insn_name(MI, opcode);
|
|
return decode_load(ud, MI, full_insn);
|
|
case HPPA_OP_TYPE_STB:
|
|
case HPPA_OP_TYPE_STH:
|
|
case HPPA_OP_TYPE_STW:
|
|
case HPPA_OP_TYPE_STWM:
|
|
fill_store_insn_name(MI, opcode);
|
|
return decode_store(ud, MI, full_insn);
|
|
case HPPA_OP_TYPE_CMPBT:
|
|
case HPPA_OP_TYPE_CMPBF:
|
|
case HPPA_OP_TYPE_ADDBT:
|
|
case HPPA_OP_TYPE_ADDBF:
|
|
case HPPA_OP_TYPE_MOVB:
|
|
case HPPA_OP_TYPE_CMPIBT:
|
|
case HPPA_OP_TYPE_CMPIBF:
|
|
case HPPA_OP_TYPE_ADDIBT:
|
|
case HPPA_OP_TYPE_ADDIBF:
|
|
case HPPA_OP_TYPE_MOVIB:
|
|
case HPPA_OP_TYPE_BBS:
|
|
case HPPA_OP_TYPE_BB:
|
|
fill_action_and_branch_insn_name(MI, opcode);
|
|
return fill_action_and_branch(ud, MI, full_insn);
|
|
case HPPA_OP_TYPE_CMPICLR:
|
|
return decode_cmpclr(ud, MI, full_insn);
|
|
case HPPA_OP_TYPE_BE:
|
|
case HPPA_OP_TYPE_BLE:
|
|
return decode_be(ud, MI, full_insn);
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void init_details(MCInst *MI)
|
|
{
|
|
cs_detail *detail = get_detail(MI);
|
|
if (detail) {
|
|
memset(detail, 0, offsetof(cs_detail, hppa) + sizeof(cs_hppa));
|
|
}
|
|
}
|
|
|
|
bool HPPA_getInstruction(csh ud, const uint8_t *code, size_t code_len,
|
|
MCInst *instr, uint16_t *size, uint64_t address,
|
|
void *info)
|
|
{
|
|
cs_struct *cs = (cs_struct *)ud;
|
|
init_details(instr);
|
|
if (!getInstruction(cs, code, code_len, instr)) {
|
|
*size = 0;
|
|
return false;
|
|
}
|
|
*size = 4;
|
|
return true;
|
|
}
|
|
|
|
#endif
|