asm: implement instruction decoding

This commit is contained in:
2025-05-12 15:49:53 +01:00
parent c1ba6e78bc
commit fe23529c6b
2 changed files with 81 additions and 6 deletions

View File

@@ -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;
}