Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 31 additions & 3 deletions arch/RISCV/RISCVMapping.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "../../cs_simple_types.h"
#include "../../utils.h"

#include "RISCVBaseInfo.h"
#include "RISCVMapping.h"

#define GET_INSTRINFO_ENUM
Expand Down Expand Up @@ -53,11 +54,38 @@ void RISCV_add_cs_detail_0(MCInst *MI, riscv_op_group opgroup, unsigned OpNum)
{
if (!detail_is_set(MI))
return;
// are not "true" arguments and has no Capstone equivalent
// Rounding mode: store in detail, not as a regular operand.
if (opgroup == RISCV_OP_GROUP_FRMArg ||
opgroup == RISCV_OP_GROUP_FRMArgLegacy)
opgroup == RISCV_OP_GROUP_FRMArgLegacy) {
unsigned frm = (unsigned)MCInst_getOperand(MI, OpNum)->ImmVal;
riscv_rounding_mode rm;
switch (frm) {
case RISCVFPRndMode_RNE:
rm = RISCV_RM_RNE;
break;
case RISCVFPRndMode_RTZ:
rm = RISCV_RM_RTZ;
break;
case RISCVFPRndMode_RDN:
rm = RISCV_RM_RDN;
break;
case RISCVFPRndMode_RUP:
rm = RISCV_RM_RUP;
break;
case RISCVFPRndMode_RMM:
rm = RISCV_RM_RMM;
break;
case RISCVFPRndMode_DYN:
rm = RISCV_RM_DYN;
break;
default:
rm = RISCV_RM_INVALID;
break;
}
RISCV_get_detail(MI)->rounding_mode = rm;
return;

}

// unmasked instructions, the mask register is not real
if (opgroup == RISCV_OP_GROUP_VMaskReg) {
MCOperand *mask = MCInst_getOperand(MI, OpNum);
Expand Down
8 changes: 5 additions & 3 deletions bindings/python/capstone/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1325,9 +1325,11 @@ def __gen_detail(self):
elif arch == CS_ARCH_BPF:
(self.operands) = bpf.get_arch_info(self._raw.detail.contents.arch.bpf)
elif arch == CS_ARCH_RISCV:
(self.need_effective_addr, self.operands) = riscv.get_arch_info(
self._raw.detail.contents.arch.riscv
)
(
self.need_effective_addr,
self.operands,
self.rounding_mode,
) = riscv.get_arch_info(self._raw.detail.contents.arch.riscv)
elif arch == CS_ARCH_SH:
(self.sh_insn, self.sh_size, self.operands) = sh.get_arch_info(
self._raw.detail.contents.arch.sh
Expand Down
7 changes: 6 additions & 1 deletion bindings/python/capstone/riscv.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,13 @@ class CsRISCV(ctypes.Structure):
("need_effective_addr", ctypes.c_bool),
("op_count", ctypes.c_uint8),
("operands", RISCVOp * 8),
("rounding_mode", ctypes.c_uint),
)


def get_arch_info(a):
return (a.need_effective_addr, copy_ctypes_list(a.operands[: a.op_count]))
return (
a.need_effective_addr,
copy_ctypes_list(a.operands[: a.op_count]),
a.rounding_mode,
)
9 changes: 9 additions & 0 deletions bindings/python/capstone/riscv_const.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@
RISCV_OP_FP = CS_OP_FP
RISCV_OP_CSR = CS_OP_SPECIAL

# Floating-point rounding mode for RISC-V FP instructions
RISCV_RM_INVALID = 0
RISCV_RM_RNE = 1
RISCV_RM_RTZ = 2
RISCV_RM_RDN = 3
RISCV_RM_RUP = 4
RISCV_RM_RMM = 5
RISCV_RM_DYN = 6

# RISCV registers

RISCV_REG_INVALID = 0
Expand Down
5 changes: 5 additions & 0 deletions bindings/python/cstest_py/src/cstest_py/details.py
Original file line number Diff line number Diff line change
Expand Up @@ -1329,6 +1329,11 @@ def test_expected_hppa(actual: CsInsn, expected: dict) -> bool:


def test_expected_riscv(actual: CsInsn, expected: dict) -> bool:
if "rounding_mode" in expected and not compare_enum(
actual.rounding_mode, expected.get("rounding_mode"), "rounding_mode"
):
return False

if "operands" not in expected:
return True
elif not compare_uint32(
Expand Down
9 changes: 9 additions & 0 deletions cstool/cstool_riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,14 @@ void print_insn_detail_riscv(csh handle, cs_insn *ins)
}
}

if (riscv->rounding_mode != RISCV_RM_INVALID) {
static const char *const rm_str[] = {
[RISCV_RM_RNE] = "rne", [RISCV_RM_RTZ] = "rtz",
[RISCV_RM_RDN] = "rdn", [RISCV_RM_RUP] = "rup",
[RISCV_RM_RMM] = "rmm", [RISCV_RM_DYN] = "dyn",
};
printf("\trounding_mode: %s\n", rm_str[riscv->rounding_mode]);
}

printf("\n");
}
1 change: 1 addition & 0 deletions docs/cs_v6_release_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ Nonetheless, we hope this additional information is useful to you.
- Added `reg_access` capstone callback to return all read and written registers for the instructions, including registers used as part of memory operands.
* Note that `reg_access` does NOT treat CSRs as registers, detailed reasons for why can be found in [the PR implementing the feature](https://github.com/capstone-engine/capstone/pull/2895)
* Note that `reg_access` does NOT treat reading the PC's value as reading a register, detailed reasons for why can be found in [the PR implementing the feature](https://github.com/capstone-engine/capstone/pull/2895)
- Added `rounding_mode` field to `cs_riscv` struct inside details struct (`insn->detail->riscv->rounding_mode`) for float and double instructions.

> [!NOTE]
> All `CS_MODE_RISCV_*` extensions above are disabled by default unless enabled by their option name or the corresponding command line flag in cstool. Any other extension is always enabled and can't be disabled.
Expand Down
13 changes: 13 additions & 0 deletions include/capstone/riscv.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,17 @@ extern "C" {
#pragma warning(disable : 4201)
#endif

//> Floating-point rounding mode for RISC-V FP instructions
typedef enum riscv_rounding_mode {
RISCV_RM_INVALID = 0, ///< not applicable (no rounding mode)
RISCV_RM_RNE, ///< round to nearest, ties to even
RISCV_RM_RTZ, ///< round towards zero
RISCV_RM_RDN, ///< round down (towards -infinity)
RISCV_RM_RUP, ///< round up (towards +infinity)
RISCV_RM_RMM, ///< round to nearest, ties to max magnitude
RISCV_RM_DYN, ///< dynamic rounding mode (use frm CSR)
} riscv_rounding_mode;

//> Operand type for instruction's operands
typedef enum riscv_op_type {
RISCV_OP_INVALID = CS_OP_INVALID, ///< = CS_OP_INVALID (Uninitialized).
Expand Down Expand Up @@ -65,6 +76,8 @@ typedef struct cs_riscv {
// or 0 when instruction has no operand.
uint8_t op_count;
cs_riscv_op operands[NUM_RISCV_OPS]; // operands for this instruction.
// FP rounding mode, or RISCV_RM_INVALID.
riscv_rounding_mode rounding_mode;
} cs_riscv;

//> RISCV registers
Expand Down
4 changes: 4 additions & 0 deletions suite/cstest/include/test_detail_riscv.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,17 @@ static const cyaml_schema_value_t test_detail_riscv_op_schema = {
typedef struct {
TestDetailRISCVOp **operands;
uint32_t operands_count;
char *rounding_mode;
} TestDetailRISCV;

static const cyaml_schema_field_t test_detail_riscv_mapping_schema[] = {
CYAML_FIELD_SEQUENCE(
"operands", CYAML_FLAG_POINTER | CYAML_FLAG_OPTIONAL,
TestDetailRISCV, operands, &test_detail_riscv_op_schema, 0,
CYAML_UNLIMITED), // 0-MAX options
CYAML_FIELD_STRING_PTR(
"rounding_mode", CYAML_FLAG_POINTER | CYAML_FLAG_OPTIONAL,
TestDetailRISCV, rounding_mode, 0, CYAML_UNLIMITED),
CYAML_FIELD_END
};

Expand Down
7 changes: 7 additions & 0 deletions suite/cstest/include/test_mapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -1493,6 +1493,13 @@ static const cs_enum_id_map cs_enum_map[] = {
{ .str = "RISCV_OP_IMM", .val = RISCV_OP_IMM },
{ .str = "RISCV_OP_MEM", .val = RISCV_OP_MEM },
{ .str = "RISCV_OP_REG", .val = RISCV_OP_REG },
{ .str = "RISCV_RM_DYN", .val = RISCV_RM_DYN },
{ .str = "RISCV_RM_INVALID", .val = RISCV_RM_INVALID },
{ .str = "RISCV_RM_RDN", .val = RISCV_RM_RDN },
{ .str = "RISCV_RM_RMM", .val = RISCV_RM_RMM },
{ .str = "RISCV_RM_RNE", .val = RISCV_RM_RNE },
{ .str = "RISCV_RM_RTZ", .val = RISCV_RM_RTZ },
{ .str = "RISCV_RM_RUP", .val = RISCV_RM_RUP },
{ .str = "SH_GRP_BRANCH_RELATIVE", .val = SH_GRP_BRANCH_RELATIVE },
{ .str = "SH_GRP_CALL", .val = SH_GRP_CALL },
{ .str = "SH_GRP_INT", .val = SH_GRP_INT },
Expand Down
5 changes: 5 additions & 0 deletions suite/cstest/src/test_detail_riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ void test_detail_riscv_free(TestDetailRISCV *detail)
test_detail_riscv_op_free(detail->operands[i]);
}
cs_mem_free(detail->operands);
cs_mem_free(detail->rounding_mode);
cs_mem_free(detail);
}

Expand All @@ -40,6 +41,8 @@ TestDetailRISCV *test_detail_riscv_clone(const TestDetailRISCV *detail)
clone->operands[i] =
test_detail_riscv_op_clone(detail->operands[i]);
}
clone->rounding_mode =
detail->rounding_mode ? strdup(detail->rounding_mode) : NULL;

return clone;
}
Expand Down Expand Up @@ -115,5 +118,7 @@ bool test_expected_riscv(csh *handle, const cs_riscv *actual,
}
}

compare_enum_ret(actual->rounding_mode, expected->rounding_mode, false);

return true;
}
2 changes: 2 additions & 0 deletions tests/details/riscv.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -907,6 +907,7 @@ test_cases:
- asm_text: "fadd.s ft5, ft6, ft7, dyn"
details:
riscv:
rounding_mode: RISCV_RM_DYN
operands:
- type: RISCV_OP_REG
reg: ft5
Expand All @@ -932,6 +933,7 @@ test_cases:
- asm_text: "fmin.s fa0, fa1, fa2"
details:
riscv:
rounding_mode: RISCV_RM_INVALID
operands:
- type: RISCV_OP_REG
reg: fa0
Expand Down
Loading