blob: a73c6eafe0876d33c96e7c7d1ec62b20d448ddcb [file] [log] [blame]
/* 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 int 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 SignExtend32(val, 21) << 11;
}
/* Extract a 12 bit constant from branch instructions. */
static int extract_12(unsigned word)
{
return 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 int extract_17(unsigned word)
{
return 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 int extract_22(unsigned word)
{
return 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++];
assert(hppa->mod_num <= HPPA_MAX_MODIFIERS_LEN);
mod->type = HPPA_MOD_STR;
assert(strlen(modifier) <= HPPA_STR_MODIFIER_LEN);
strcpy(mod->str_mod, modifier);
}
}
static void push_int_modifier(hppa_ext *hppa, uint64_t modifier)
{
hppa_modifier *mod = &hppa->modifiers[hppa->mod_num++];
assert(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");
// fallthough
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, uint32_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);
uint32_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 {
uint32_t 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);
// fallthough
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);
// fallthough
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");
// fallthough
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)) {
uint32_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)) {
uint32_t 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