#include "cpu/exec.h" #include "cpu/rtl.h" /* shared by all helper functions */ DecodeInfo decoding; rtlreg_t t0, t1, t2, t3, at; void decoding_set_jmp(bool is_jmp) { decoding.is_jmp = is_jmp; } #define make_DopHelper_funcname(name) concat(decode_op_, name) #define make_DopHelper(name) void make_DopHelper_funcname(name) (vaddr_t *eip, Operand *op, bool load_val) /* Refer to Appendix A in i386 manual for the explanations of these abbreviations */ /* Ib, Iv */ static inline make_DopHelper(I) { /* eip here is pointing to the immediate */ op->type = OP_TYPE_IMM; op->imm = instr_fetch(eip, op->width); rtl_li(&op->val, op->imm); #ifdef DEBUG snprintf(op->str, OP_STR_SIZE, "$0x%x", op->imm); #endif } /* I386 manual does not contain this abbreviation, but it is different from * the one above from the view of implementation. So we use another helper * function to decode it. */ /* sign immediate */ static inline make_DopHelper(SI) { assert(op->width == 1 || op->width == 4); op->type = OP_TYPE_IMM; /* TODO: Use instr_fetch() to read `op->width' bytes of memory * pointed by `eip'. Interpret the result as a signed immediate, * and assign it to op->simm. * op->simm = ??? */ op->simm = instr_fetch(eip, op->width); rtl_li(&op->val, op->simm); #ifdef DEBUG snprintf(op->str, OP_STR_SIZE, "$0x%x", op->simm); #endif } /* I386 manual does not contain this abbreviation. * It is convenient to merge them into a single helper function. */ /* AL/eAX */ static inline make_DopHelper(a) { op->type = OP_TYPE_REG; op->reg = R_EAX; if (load_val) { rtl_lr(&op->val, R_EAX, op->width); } #ifdef DEBUG snprintf(op->str, OP_STR_SIZE, "%%%s", reg_name(R_EAX, op->width)); #endif } /* This helper function is use to decode register encoded in the opcode. */ /* XX: AL, AH, BL, BH, CL, CH, DL, DH * eXX: eAX, eCX, eDX, eBX, eSP, eBP, eSI, eDI */ static inline make_DopHelper(r) { op->type = OP_TYPE_REG; op->reg = decoding.opcode & 0x7; if (load_val) { rtl_lr(&op->val, op->reg, op->width); } #ifdef DEBUG snprintf(op->str, OP_STR_SIZE, "%%%s", reg_name(op->reg, op->width)); #endif } /* I386 manual does not contain this abbreviation. * We decode everything of modR/M byte by one time. */ /* Eb, Ew, Ev * Gb, Gv * Cd, * M * Rd * Sw */ static inline void make_DopHelper_funcname(rm)(vaddr_t *eip, Operand *rm, bool load_rm_val, Operand *reg, bool load_reg_val) { read_ModR_M(eip, rm, load_rm_val, reg, load_reg_val); } /* Ob, Ov */ static inline make_DopHelper(O) { op->type = OP_TYPE_MEM; rtl_li(&op->addr, instr_fetch(eip, 4)); if (load_val) { rtl_lm(&op->val, &op->addr, op->width); } #ifdef DEBUG snprintf(op->str, OP_STR_SIZE, "0x%x", op->addr); #endif } /* Eb <- Gb * Ev <- Gv */ make_DHelper(G2E) { make_DopHelper_funcname(rm)(eip, id_dest, true, id_src, true); } make_DHelper(mov_G2E) { make_DopHelper_funcname(rm)(eip, id_dest, false, id_src, true); } /* Gb <- Eb * Gv <- Ev */ make_DHelper(E2G) { make_DopHelper_funcname(rm)(eip, id_src, true, id_dest, true); } make_DHelper(mov_E2G) { make_DopHelper_funcname(rm)(eip, id_src, true, id_dest, false); } make_DHelper(lea_M2G) { make_DopHelper_funcname(rm)(eip, id_src, false, id_dest, false); } /* AL <- Ib * eAX <- Iv */ make_DHelper(I2a) { make_DopHelper_funcname(a)(eip, id_dest, true); make_DopHelper_funcname(I)(eip, id_src, true); } /* Gv <- EvIb * Gv <- EvIv * use for imul */ make_DHelper(I_E2G) { make_DopHelper_funcname(rm)(eip, id_src2, true, id_dest, false); make_DopHelper_funcname(I)(eip, id_src, true); } /* Eb <- Ib * Ev <- Iv */ make_DHelper(I2E) { make_DopHelper_funcname(rm)(eip, id_dest, true, NULL, false); make_DopHelper_funcname(I)(eip, id_src, true); } make_DHelper(mov_I2E) { make_DopHelper_funcname(rm)(eip, id_dest, false, NULL, false); make_DopHelper_funcname(I)(eip, id_src, true); } /* XX <- Ib * eXX <- Iv */ make_DHelper(I2r) { make_DopHelper_funcname(r)(eip, id_dest, true); make_DopHelper_funcname(I)(eip, id_src, true); } make_DHelper(mov_I2r) { make_DopHelper_funcname(r)(eip, id_dest, false); make_DopHelper_funcname(I)(eip, id_src, true); } /* used by unary operations */ make_DHelper(I) { make_DopHelper_funcname(I)(eip, id_dest, true); } make_DHelper(r) { make_DopHelper_funcname(r)(eip, id_dest, true); } make_DHelper(E) { make_DopHelper_funcname(rm)(eip, id_dest, true, NULL, false); } make_DHelper(setcc_E) { make_DopHelper_funcname(rm)(eip, id_dest, false, NULL, false); } make_DHelper(gp7_E) { make_DopHelper_funcname(rm)(eip, id_dest, false, NULL, false); } /* used by test in group3 */ make_DHelper(test_I) { make_DopHelper_funcname(I)(eip, id_src, true); } make_DHelper(SI2E) { assert(id_dest->width == 2 || id_dest->width == 4); make_DopHelper_funcname(rm)(eip, id_dest, true, NULL, false); id_src->width = 1; make_DopHelper_funcname(SI)(eip, id_src, true); if (id_dest->width == 2) { id_src->val &= 0xffff; } } make_DHelper(SI_E2G) { assert(id_dest->width == 2 || id_dest->width == 4); make_DopHelper_funcname(rm)(eip, id_src2, true, id_dest, false); id_src->width = 1; make_DopHelper_funcname(SI)(eip, id_src, true); if (id_dest->width == 2) { id_src->val &= 0xffff; } } make_DHelper(gp2_1_E) { make_DopHelper_funcname(rm)(eip, id_dest, true, NULL, false); id_src->type = OP_TYPE_IMM; id_src->imm = 1; rtl_li(&id_src->val, 1); #ifdef DEBUG sprintf(id_src->str, "$1"); #endif } make_DHelper(gp2_cl2E) { make_DopHelper_funcname(rm)(eip, id_dest, true, NULL, false); id_src->type = OP_TYPE_REG; id_src->reg = R_CL; rtl_lr(&id_src->val, R_CL, 1); #ifdef DEBUG sprintf(id_src->str, "%%cl"); #endif } make_DHelper(gp2_Ib2E) { make_DopHelper_funcname(rm)(eip, id_dest, true, NULL, false); id_src->width = 1; make_DopHelper_funcname(I)(eip, id_src, true); } /* Ev <- GvIb * use for shld/shrd */ make_DHelper(Ib_G2E) { make_DopHelper_funcname(rm)(eip, id_dest, true, id_src2, true); id_src->width = 1; make_DopHelper_funcname(I)(eip, id_src, true); } /* Ev <- GvCL * use for shld/shrd */ make_DHelper(cl_G2E) { make_DopHelper_funcname(rm)(eip, id_dest, true, id_src2, true); id_src->type = OP_TYPE_REG; id_src->reg = R_CL; rtl_lr(&id_src->val, R_CL, 1); #ifdef DEBUG sprintf(id_src->str, "%%cl"); #endif } make_DHelper(O2a) { make_DopHelper_funcname(O)(eip, id_src, true); make_DopHelper_funcname(a)(eip, id_dest, false); } make_DHelper(a2O) { make_DopHelper_funcname(a)(eip, id_src, true); make_DopHelper_funcname(O)(eip, id_dest, false); } make_DHelper(J) { make_DopHelper_funcname(SI)(eip, id_dest, false); rlib::println("debug: J decoder: id_dest=", *id_dest); rtl_sext(&id_dest->imm, &id_dest->imm, id_dest->width); // the target address can be computed in the decode stage decoding.jmp_eip = id_dest->simm + *eip; } make_DHelper(push_SI) { make_DopHelper_funcname(SI)(eip, id_dest, true); } make_DHelper(in_I2a) { id_src->width = 1; make_DopHelper_funcname(I)(eip, id_src, true); make_DopHelper_funcname(a)(eip, id_dest, false); } make_DHelper(in_dx2a) { id_src->type = OP_TYPE_REG; id_src->reg = R_DX; rtl_lr(&id_src->val, R_DX, 2); #ifdef DEBUG sprintf(id_src->str, "(%%dx)"); #endif make_DopHelper_funcname(a)(eip, id_dest, false); } make_DHelper(out_a2I) { make_DopHelper_funcname(a)(eip, id_src, true); id_dest->width = 1; make_DopHelper_funcname(I)(eip, id_dest, true); } make_DHelper(out_a2dx) { make_DopHelper_funcname(a)(eip, id_src, true); id_dest->type = OP_TYPE_REG; id_dest->reg = R_DX; rtl_lr(&id_dest->val, R_DX, 2); #ifdef DEBUG sprintf(id_dest->str, "(%%dx)"); #endif } void operand_write(Operand *op, rtlreg_t* src) { if (op->type == OP_TYPE_REG) { rtl_sr(op->reg, src, op->width); } else if (op->type == OP_TYPE_MEM) { rtl_sm(&op->addr, src, op->width); } else { assert(0); } }