asm: implement instruction decoding
This commit is contained in:
@@ -1,8 +1,11 @@
|
||||
#ifndef IVY_ASM_INSTR_H_
|
||||
#define IVY_ASM_INSTR_H_
|
||||
|
||||
#include <blue/core/endian.h>
|
||||
#include <ivy/misc.h>
|
||||
#include <ivy/opcode.h>
|
||||
#include <ivy/status.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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
|
||||
|
||||
61
asm/instr.c
61
asm/instr.c
@@ -22,11 +22,12 @@
|
||||
.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_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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user