#include #include #define INSTR0(id, l, op) \ [IVY_OP_##op] = { \ .i_id = IVY_INSTR_##id, \ .i_layout = IVY_INSTR_##l, \ .i_opcode = IVY_OP_##op, \ .i_operand = {}, \ } #define INSTR1(id, l, op, a0) \ [IVY_OP_##op] = { \ .i_id = IVY_INSTR_##id, \ .i_layout = IVY_INSTR_##l, \ .i_opcode = IVY_OP_##op, \ .i_operand = {IVY_INSTR_OPERAND_##a0,}, \ } #define INSTR2(id, l, op, a0, a1) \ [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,},\ } #define INSTR3(id, l, op, a0, a1, a2) \ [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, \ IVY_INSTR_OPERAND_##a2, \ }, \ } /* clang-format off */ static const struct ivy_instr_definition instructions[] = { INSTR2(LDR, R1D, LDR_SP_REG, REGISTER, SP_INDEX_REG), INSTR2(LDR, R1D, LDR_SP_CONST, REGISTER, SP_INDEX_CONST), INSTR2(LDR, R1D, LDR_BP_REG, REGISTER, BP_INDEX_REG), INSTR2(LDR, R1D, LDR_BP_CONST, REGISTER, BP_INDEX_CONST), INSTR2(LDR, R1D, LDR_SELF_REG, REGISTER, SELF_INDEX_REG), INSTR2(LDR, R1D, LDR_SELF_CONST, REGISTER, SELF_INDEX_CONST), INSTR2(LDR, R1D, LDR_POOL_REG, REGISTER, POOL_INDEX_REG), INSTR2(LDR, R1D, LDR_POOL_CONST, REGISTER, POOL_INDEX_CONST), INSTR2(LDR, R1D, LDR_CONST, REGISTER, CONST), INSTR2(STR, R1D, STR_SP_REG, REGISTER, SP_INDEX_REG), INSTR2(STR, R1D, STR_SP_CONST, REGISTER, SP_INDEX_CONST), INSTR2(STR, R1D, STR_BP_REG, REGISTER, BP_INDEX_REG), INSTR2(STR, R1D, STR_BP_CONST, REGISTER, BP_INDEX_CONST), INSTR2(STR, R1D, STR_SELF_REG, REGISTER, SELF_INDEX_REG), INSTR2(STR, R1D, STR_SELF_CONST, REGISTER, SELF_INDEX_CONST), INSTR1(PUSH, R1, PUSH_REG, REGISTER), INSTR1(PUSH, R1, PUSH_CONST, CONST), INSTR1(POP, R1, POP, REGISTER), INSTR3(MSG, R3, MSG_REG, REGISTER, REGISTER, REGISTER), INSTR3(MSG, R2D, MSG_CONST, REGISTER, REGISTER, CONST), INSTR3(ADD, R3, ADD, REGISTER, REGISTER, REGISTER), INSTR3(SUB, R3, SUB, REGISTER, REGISTER, REGISTER), INSTR3(MUL, R3, MUL, REGISTER, REGISTER, REGISTER), INSTR3(DIV, R3, DIV, REGISTER, REGISTER, REGISTER), INSTR2(C_EQ, R2, C_EQ, REGISTER, REGISTER), INSTR2(C_NE, R2, C_NE, REGISTER, REGISTER), INSTR2(C_LT, R2, C_LT, REGISTER, REGISTER), INSTR2(C_LE, R2, C_LE, REGISTER, REGISTER), INSTR2(C_GT, R2, C_GT, REGISTER, REGISTER), INSTR2(C_GE, R2, C_GE, REGISTER, REGISTER), INSTR1(BR, D, BR, CONST), INSTR1(BR_T, D, BR_T, CONST), INSTR1(BR_F, D, BR_F, CONST), INSTR2(OB_C, R2, OB_C_REG, REGISTER, POOL_INDEX_REG), INSTR2(OB_C, R1D, OB_C_CONST, REGISTER, POOL_INDEX_CONST), INSTR1(OB_E, R1, OB_E, REGISTER), INSTR2(LAM_C, R2, LAM_C_REG, REGISTER, POOL_INDEX_REG), INSTR2(LAM_C, R1D, LAM_C_CONST, REGISTER, POOL_INDEX_CONST), INSTR2(IT_G, R2, IT_G, REGISTER, REGISTER), INSTR1(IT_N, R1, IT_N, REGISTER), INSTR1(IT_V, R1, IT_V, REGISTER), INSTR0(RET, X, RET), INSTR0(RET_N, X, RET_N), }; 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]) { if (operands[3] != IVY_INSTR_OPERAND_NONE) { return NULL; } for (size_t i = 0; i < nr_instructions; i++) { const struct ivy_instr_definition *def = &instructions[i]; if (def->i_id != id) { continue; } if (def->i_operand[0] != operands[0]) { continue; } if (def->i_operand[1] != operands[1]) { continue; } if (def->i_operand[2] != operands[2]) { continue; } return def; } 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; }