diff --git a/asm/include/ivy/asm/instr.h b/asm/include/ivy/asm/instr.h index a611c6f..3fbe4f2 100644 --- a/asm/include/ivy/asm/instr.h +++ b/asm/include/ivy/asm/instr.h @@ -1,8 +1,11 @@ #ifndef IVY_ASM_INSTR_H_ #define IVY_ASM_INSTR_H_ +#include #include #include +#include +#include #define R_MASK_OP 0x01800C03u #define R_MASK_R1 0x000003FCu @@ -17,11 +20,18 @@ (((i) & ~R_MASK_OP) | (op & 0x03u) | ((op & 0x0Cu) << 8) \ | ((op & 0x30u) << 19)) +#define R_GET_OPCODE(i) \ + (((i) & 0x03u) | (((i) >> 8) & 0x0Cu) | (((i) >> 19) & 0x30u)) + #define R_SET_R1(i, r) (((i) & ~R_MASK_R1) | ((r & 0xFFu) << 2)) #define R_SET_R2(i, r) (((i) & ~R_MASK_R2) | ((r & 0xFFu) << 12)) #define R_SET_R3(i, r) \ (((i) & ~R_MASK_R3) | ((r & 0x01u) << 22) | ((r & 0xFEu) << 24)) +#define R_GET_R1(i) (((i) >> 2) & 0xFFu) +#define R_GET_R2(i) (((i) >> 12) & 0xFFu) +#define R_GET_R3(i) (((i) >> 22) & 0x01u) | (((i) >> 24) & 0xFEu) + #define R_SET_D1(i, r) \ (((i) & ~R_MASK_D1) | ((r & 0x07u) << 20) | ((r & 0x3F8u) << 22)) #define R_SET_D2(i, r) \ @@ -30,6 +40,12 @@ (((i) & ~R_MASK_D3) | ((r & 0xFFu) << 2) | ((r & 0x7FF00u) << 4) \ | ((r & 0x3F80000u) << 6)) +#define R_GET_D1(i) ((((i) >> 20) & 0x07u) | (((i) >> 22) & 0x3F8u)) +#define R_GET_D2(i) ((((i) >> 12) & 0x7FFu) | (((i) >> 14) & 0x3F800u)) +#define R_GET_D3(i) \ + ((((i) >> 2) & 0xFFu) | (((i) >> 4) & 0x7FF00u) \ + | (((i) >> 6) & 0x3F80000u)) + enum ivy_instr_layout { IVY_INSTR_X = 0, IVY_INSTR_D, @@ -69,4 +85,6 @@ struct ivy_instr { IVY_API const struct ivy_instr_definition *ivy_instr_find( enum ivy_instr_id id, const enum ivy_instr_operand_type operands[4]); +IVY_API enum ivy_status ivy_instr_decode(b_i32 instr, struct ivy_instr *out); + #endif diff --git a/asm/instr.c b/asm/instr.c index e291cb0..da38e83 100644 --- a/asm/instr.c +++ b/asm/instr.c @@ -10,23 +10,24 @@ } #define INSTR1(id, l, op, a0) \ - [IVY_OP_##op] = { \ + [IVY_OP_##op] = { \ .i_id = IVY_INSTR_##id, \ .i_layout = IVY_INSTR_##l, \ .i_opcode = IVY_OP_##op, \ - .i_operand = {IVY_INSTR_OPERAND_##a0,}, \ + .i_operand = {IVY_INSTR_OPERAND_##a0,}, \ } #define INSTR2(id, l, op, a0, a1) \ - [IVY_OP_##op] = { \ + [IVY_OP_##op] = { \ .i_id = IVY_INSTR_##id, \ .i_layout = IVY_INSTR_##l, \ - .i_opcode = IVY_OP_ ##op, \ - .i_operand = {IVY_INSTR_OPERAND_##a0, IVY_INSTR_OPERAND_##a1,}, \ + .i_opcode = IVY_OP_ ##op, \ + .i_operand = {IVY_INSTR_OPERAND_##a0, IVY_INSTR_OPERAND_##a1,},\ } #define INSTR3(id, l, op, a0, a1, a2) \ - [IVY_OP_##op] = {.i_id = IVY_INSTR_##id, \ + [IVY_OP_##op] = { \ + .i_id = IVY_INSTR_##id, \ .i_layout = IVY_INSTR_##l, \ .i_opcode = IVY_OP_##op, \ .i_operand = { \ @@ -95,6 +96,17 @@ static const struct ivy_instr_definition instructions[] = { static const size_t nr_instructions = sizeof instructions / sizeof instructions[0]; /* clang-format on */ +static long sign_extend(long v, unsigned int width) +{ + long mask = 1U << (width - 1); + + if (v & mask) { + return v | ~(mask - 1); + } + + return v; +} + const struct ivy_instr_definition *ivy_instr_find( enum ivy_instr_id id, const enum ivy_instr_operand_type operands[4]) { @@ -126,3 +138,48 @@ const struct ivy_instr_definition *ivy_instr_find( return NULL; } + +enum ivy_status ivy_instr_decode(b_i32 x, struct ivy_instr *out) +{ + uint32_t instr = b_i32_btoh(x); + unsigned int opcode = R_GET_OPCODE(instr); + if (opcode >= nr_instructions) { + return IVY_ERR_INVALID_VALUE; + } + + const struct ivy_instr_definition *instr_def = &instructions[opcode]; + if (instr_def->i_id == IVY_INSTR_NONE) { + return IVY_ERR_INVALID_VALUE; + } + + out->i_op = instr_def; + + switch (instr_def->i_layout) { + case IVY_INSTR_X: + break; + case IVY_INSTR_D: + out->i_arg[0] = sign_extend(R_GET_D3(instr), 26); + break; + case IVY_INSTR_R1: + out->i_arg[0] = R_GET_R1(instr); + break; + case IVY_INSTR_R1D: + out->i_arg[0] = R_GET_R1(instr); + out->i_arg[1] = sign_extend(R_GET_D2(instr), 18); + break; + case IVY_INSTR_R2D: + out->i_arg[0] = R_GET_R1(instr); + out->i_arg[1] = R_GET_R2(instr); + out->i_arg[2] = sign_extend(R_GET_D1(instr), 10); + break; + case IVY_INSTR_R3: + out->i_arg[0] = R_GET_R1(instr); + out->i_arg[1] = R_GET_R2(instr); + out->i_arg[2] = R_GET_R3(instr); + break; + default: + break; + } + + return IVY_OK; +}