diff --git a/handwritten/hexagon_il_c/functions.c b/handwritten/hexagon_il_c/functions.c index f5c1f021..565ca26a 100644 --- a/handwritten/hexagon_il_c/functions.c +++ b/handwritten/hexagon_il_c/functions.c @@ -467,13 +467,13 @@ static void log_reg_write(RZ_BORROW HexInsnPktBundle *bundle, ut8 reg_num, HexRe pkt->il_op_stats.gpr_written |= (1 << reg_num); break; case HEX_REG_CLASS_CTR_REGS64: - if (hex_ctr_immut_masks[reg_num + 1] != HEX_IMMUTABLE_MASK) { + if (hex_ctr_immut_masks[reg_num + 1] != HEX_IMMUTABLE_REG) { pkt->il_op_stats.ctr_written |= (1 << (reg_num + 1)); } // fallthrough case HEX_REG_CLASS_MOD_REGS: case HEX_REG_CLASS_CTR_REGS: - if (hex_ctr_immut_masks[reg_num] != HEX_IMMUTABLE_MASK) { + if (hex_ctr_immut_masks[reg_num] != HEX_IMMUTABLE_REG) { pkt->il_op_stats.ctr_written |= (1 << reg_num); } break; @@ -537,6 +537,7 @@ RZ_IPI RZ_OWN RzILOpEffect *hex_write_reg(RZ_BORROW HexInsnPktBundle *bundle, co const char *low_name = NULL; RzILOpPure *high_val = NULL; RzILOpPure *low_val = NULL; + RzILOpEffect *p3_0_write_seq = NULL; // If C4 (P3:0) is written this is non-NULL. ut32 reg_num = hex_resolve_reg_enum_id(op->class, op->op.reg); ut32 dest_width = HEX_GPR_WIDTH; switch (op->class) { @@ -556,7 +557,7 @@ RZ_IPI RZ_OWN RzILOpEffect *hex_write_reg(RZ_BORROW HexInsnPktBundle *bundle, co low_val = CAST(HEX_GPR_WIDTH, IL_FALSE, val); break; case HEX_REG_CLASS_CTR_REGS64: - if (hex_ctr_immut_masks[reg_num + 1] != HEX_IMMUTABLE_MASK) { + if (hex_ctr_immut_masks[reg_num + 1] != HEX_IMMUTABLE_REG) { high_name = hex_get_reg_in_class(HEX_REG_CLASS_CTR_REGS, reg_num + 1, false, true, true); high_val = SHIFTR0(DUP(val), U8(HEX_GPR_WIDTH)); if (hex_ctr_immut_masks[reg_num + 1] != 0) { @@ -566,12 +567,25 @@ RZ_IPI RZ_OWN RzILOpEffect *hex_write_reg(RZ_BORROW HexInsnPktBundle *bundle, co // fallthrough case HEX_REG_CLASS_MOD_REGS: case HEX_REG_CLASS_CTR_REGS: - if (hex_ctr_immut_masks[reg_num] != HEX_IMMUTABLE_MASK) { + if (hex_ctr_immut_masks[reg_num] != HEX_IMMUTABLE_REG) { low_name = hex_get_reg_in_class(HEX_REG_CLASS_CTR_REGS, reg_num, false, true, true); low_val = CAST(HEX_GPR_WIDTH, IL_FALSE, val); if (hex_ctr_immut_masks[reg_num] != 0) { low_val = get_masked_reg_val(VARG(low_name), low_val, hex_ctr_immut_masks[reg_num]); } + if (reg_num == 4) { + HexOp pred_op = { 0 }; + pred_op.class = HEX_REG_CLASS_PRED_REGS; + pred_op.op.reg = 0; + p3_0_write_seq = hex_write_reg(bundle, &pred_op, CAST(8, IL_FALSE, DUP(low_val))); + pred_op.op.reg = 1; + p3_0_write_seq = SEQ2(hex_write_reg(bundle, &pred_op, CAST(8, IL_FALSE, SHIFTR0(DUP(low_val), U8(8)))), p3_0_write_seq); + pred_op.op.reg = 2; + p3_0_write_seq = SEQ2(hex_write_reg(bundle, &pred_op, CAST(8, IL_FALSE, SHIFTR0(DUP(low_val), U8(16)))), p3_0_write_seq); + pred_op.op.reg = 3; + p3_0_write_seq = SEQ2(hex_write_reg(bundle, &pred_op, CAST(8, IL_FALSE, SHIFTR0(DUP(low_val), U8(24)))), p3_0_write_seq); + break; + } } break; case HEX_REG_CLASS_PRED_REGS: @@ -587,6 +601,9 @@ RZ_IPI RZ_OWN RzILOpEffect *hex_write_reg(RZ_BORROW HexInsnPktBundle *bundle, co } RzILOpEffect *write_high = high_val ? SETG(high_name, CAST(dest_width, IL_FALSE, high_val)) : NULL; RzILOpEffect *write_low = low_val ? SETG(low_name, CAST(dest_width, IL_FALSE, low_val)) : NULL; + if (p3_0_write_seq) { + write_low = SEQ2(write_low, p3_0_write_seq); + } log_reg_write(bundle, reg_num, op->class, false, true); if (write_high && write_low) { @@ -606,7 +623,7 @@ static inline bool read_cond_faulty(RzILOpPure *low_val, RzILOpPure *high_val, u if (val_width == HEX_GPR64_WIDTH && !high_val) { return true; } - return false; + return false; } /** @@ -674,6 +691,20 @@ RZ_IPI RZ_OWN RzILOpPure *hex_read_reg(RZ_BORROW HexPkt *pkt, const HexOp *op, b // If read and writes overlap, return the new register for each read. tmp_reg = true; } + if (reg_num == 4) { + // C4 alias P3:0 register is the concatenation of all predicate registers. + HexOp pred_op = { 0 }; + pred_op.class = HEX_REG_CLASS_PRED_REGS; + pred_op.op.reg = 0; + low_val = hex_read_reg(pkt, &pred_op, tmp_reg); + pred_op.op.reg = 1; + low_val = APPEND(hex_read_reg(pkt, &pred_op, tmp_reg), low_val); + pred_op.op.reg = 2; + low_val = APPEND(hex_read_reg(pkt, &pred_op, tmp_reg), low_val); + pred_op.op.reg = 3; + low_val = APPEND(hex_read_reg(pkt, &pred_op, tmp_reg), low_val); + break; + } low_name = hex_get_reg_in_class(HEX_REG_CLASS_CTR_REGS, reg_num, false, tmp_reg, true); if (reg_num == 9) { low_val = U32(pkt->pkt_addr); diff --git a/handwritten/hexagon_il_h/declarations.h b/handwritten/hexagon_il_h/declarations.h index 21f1a5ec..253a897e 100644 --- a/handwritten/hexagon_il_h/declarations.h +++ b/handwritten/hexagon_il_h/declarations.h @@ -1,6 +1,17 @@ // SPDX-FileCopyrightText: 2022 Rot127 // SPDX-License-Identifier: LGPL-3.0-only +/// Immutable bits of CTR registers as in QEMU. +static const ut64 hex_ctr_immut_masks[32] = { + [HEX_REG_CTR_REGS_C8] = 0xc13000c0, // USR + [HEX_REG_CTR_REGS_C9] = HEX_IMMUTABLE_REG, // PC + [HEX_REG_CTR_REGS_C11] = 0x3f, // GP + [HEX_REG_CTR_REGS_C14] = HEX_IMMUTABLE_REG, // UPCYCLELO + [HEX_REG_CTR_REGS_C15] = HEX_IMMUTABLE_REG, // UPCYCLEHI + [HEX_REG_CTR_REGS_C30] = HEX_IMMUTABLE_REG, // UTIMERLO + [HEX_REG_CTR_REGS_C31] = HEX_IMMUTABLE_REG, // UTIMERHI +}; + RZ_IPI bool hex_shuffle_insns(RZ_INOUT HexPkt *p); RZ_IPI RzILOpEffect *hex_get_il_op(const ut32 addr, const bool get_pkt_op); RZ_IPI RZ_OWN RzILOpPure *hex_get_rf_property_val(const HexRegFieldProperty property, const HexRegField field); diff --git a/handwritten/hexagon_il_h/macros.h b/handwritten/hexagon_il_h/macros.h index ca18eceb..1941fa93 100644 --- a/handwritten/hexagon_il_h/macros.h +++ b/handwritten/hexagon_il_h/macros.h @@ -14,4 +14,7 @@ #define INC(val, size) ADD(val, UN(size, 1)) #define DEC(val, size) SUB(val, UN(size, 1)) #define HEX_STORE_SLOT_CANCELLED(pkt, slot) hex_cancel_slot(pkt, slot) -#define HEX_FCIRC_ADD(bundle, RxV, offset, mu, CS) hex_fcircadd(bundle, RxV, offset, mu, CS) \ No newline at end of file +#define HEX_FCIRC_ADD(bundle, RxV, offset, mu, CS) hex_fcircadd(bundle, RxV, offset, mu, CS) + +#define HEX_IMMUTABLE_REG (~0) +#define HEX_NOT_MASKED 0