📄 inst.c
字号:
expr->bits = -1; return (expr);}/* Return an instruction expression for a constant VALUE. */imm_expr *const_imm_expr (int32 value){ return (make_imm_expr (value, NULL, 0));}/* Return a shallow copy of the EXPRESSION with the offset field incremented by the given amount. */imm_expr *incr_expr_offset (imm_expr *expr, int32 value){ imm_expr *new_expr = copy_imm_expr (expr); new_expr->offset += value; return (new_expr);}/* Return the value of the EXPRESSION. */int32eval_imm_expr (imm_expr *expr){ int32 value; if (expr->symbol == NULL) value = expr->offset; else if (SYMBOL_IS_DEFINED (expr->symbol)) { value = expr->offset + expr->symbol->addr; if (expr->symbol->gp_flag) /* Addr is offset from $gp */ value += gp_midpoint; } else { error ("Evaluated undefined symbol: %s\n", expr->symbol->name); value = 0; } if (expr->bits > 0) return ((value >> 16) & 0xffff); /* Use upper bits of result */ else if (expr->bits < 0) return (value & 0xffff); /* Use lower bits */ else return (value);}/* Print the EXPRESSION. */static voidformat_imm_expr (str_stream *ss, imm_expr *expr, int base_reg){ if (expr->symbol != NULL) { ss_printf (ss, "%s", expr->symbol->name); } if (expr->pc_relative) ss_printf (ss, "-0x%08x", (unsigned int)-expr->offset); else if (expr->offset < -10) ss_printf (ss, "-%d (-0x%08x)", -expr->offset, (unsigned int)-expr->offset); else if (expr->offset > 10) ss_printf (ss, "+%d (0x%08x)", expr->offset, (unsigned int)expr->offset); if (base_reg != -1 && expr->symbol != NULL && (expr->offset > 10 || expr->offset < -10)) { if (expr->offset == 0 && base_reg != 0) ss_printf (ss, "+0"); if (expr->offset != 0 || base_reg != 0) ss_printf (ss, "($%d)", base_reg); }}/* Return non-zero if the EXPRESSION is a constant 0. */intzero_imm (imm_expr *expr){ return (expr->offset == 0 && expr->symbol == NULL);}/* Return an address expression of the form SYMBOL +/- IOFFSET (REGISTER). Any of the three parts may be omitted. */addr_expr *make_addr_expr (int offs, char *sym, int reg_no){ addr_expr *expr = (addr_expr *) xmalloc (sizeof (addr_expr)); label *lab; if (reg_no == 0 && sym != NULL && (lab = lookup_label (sym))->gp_flag) { expr->reg_no = REG_GP; expr->imm = make_imm_expr (offs + lab->addr - gp_midpoint, NULL, 0); } else { expr->reg_no = (unsigned char)reg_no; expr->imm = make_imm_expr (offs, (sym ? str_copy (sym) : sym), 0); } return (expr);}imm_expr *addr_expr_imm (addr_expr *expr){ return (expr->imm);}intaddr_expr_reg (addr_expr *expr){ return (expr->reg_no);}/* Map between a SPIM instruction and the binary representation of the instruction. *//* Maintain a table mapping from internal opcode (i_opcode) to actual opcode (a_opcode). Table must be sorted before first use since its entries are alphabetical on name, not ordered by opcode. *//* Map from internal opcode -> real opcode */static name_val_val i_opcode_tbl [] = {#undef OP#define OP(NAME, I_OPCODE, TYPE, A_OPCODE) {NAME, I_OPCODE, (int)A_OPCODE},#include "op.h"};/* Sort the opcode table on their key (the interal opcode value). */static voidsort_i_opcode_table (){ qsort (i_opcode_tbl, sizeof (i_opcode_tbl) / sizeof (name_val_val), sizeof (name_val_val), (QSORT_FUNC) compare_pair_value);}#define REGS(R,O) (((R) & 0x1f) << O)int32inst_encode (instruction *inst){ int32 a_opcode = 0; name_val_val *entry; if (inst == NULL) return (0); entry = map_int_to_name_val_val (i_opcode_tbl, sizeof (i_opcode_tbl) / sizeof (name_val_val), OPCODE (inst)); if (entry == NULL) return 0; a_opcode = entry->value2; entry = map_int_to_name_val_val (name_tbl, sizeof (name_tbl) / sizeof (name_val_val), OPCODE (inst)); switch (entry->value2) { case BC_TYPE_INST: return (a_opcode | REGS (CC (inst) << 2, 16) | (IOFFSET (inst) & 0xffff)); case B1_TYPE_INST: return (a_opcode | REGS (RS (inst), 21) | (IOFFSET (inst) & 0xffff)); case I1s_TYPE_INST: return (a_opcode | REGS (RS (inst), 21) | (IMM (inst) & 0xffff)); case I1t_TYPE_INST: return (a_opcode | REGS (RS (inst), 21) | REGS (RT (inst), 16) | (IMM (inst) & 0xffff)); case I2_TYPE_INST: case B2_TYPE_INST: return (a_opcode | REGS (RS (inst), 21) | REGS (RT (inst), 16) | (IMM (inst) & 0xffff)); case I2a_TYPE_INST: return (a_opcode | REGS (BASE (inst), 21) | REGS (RT (inst), 16) | (IOFFSET (inst) & 0xffff)); case R1s_TYPE_INST: return (a_opcode | REGS (RS (inst), 21)); case R1d_TYPE_INST: return (a_opcode | REGS (RD (inst), 11)); case R2td_TYPE_INST: return (a_opcode | REGS (RT (inst), 16) | REGS (RD (inst), 11)); case R2st_TYPE_INST: return (a_opcode | REGS (RS (inst), 21) | REGS (RT (inst), 16)); case R2ds_TYPE_INST: return (a_opcode | REGS (RS (inst), 21) | REGS (RD (inst), 11)); case R2sh_TYPE_INST: return (a_opcode | REGS (RT (inst), 16) | REGS (RD (inst), 11) | REGS (SHAMT (inst), 6)); case R3_TYPE_INST: return (a_opcode | REGS (RS (inst), 21) | REGS (RT (inst), 16) | REGS (RD (inst), 11)); case R3sh_TYPE_INST: return (a_opcode | REGS (RS (inst), 21) | REGS (RT (inst), 16) | REGS (RD (inst), 11)); case FP_I2a_TYPE_INST: return (a_opcode | REGS (BASE (inst), 21) | REGS (RT (inst), 16) | (IOFFSET (inst) & 0xffff)); case FP_R2ds_TYPE_INST: return (a_opcode | REGS (FS (inst), 11) | REGS (FD (inst), 6)); case FP_R2ts_TYPE_INST: return (a_opcode | REGS (RT (inst), 16) | REGS (FS (inst), 11)); case FP_CMP_TYPE_INST: return (a_opcode | REGS (FT (inst), 16) | REGS (FS (inst), 11) | (COND (inst) & 0xf)); case FP_R3_TYPE_INST: return (a_opcode | REGS (FT (inst), 16) | REGS (FS (inst), 11) | REGS (FD (inst), 6)); case FP_MOVC_TYPE_INST: return (a_opcode | REGS (CC (inst), 18) | REGS (FS (inst), 11) | REGS (FD (inst), 6)); case J_TYPE_INST: return (a_opcode | TARGET (inst)); case NOARG_TYPE_INST: return (a_opcode); default: fatal_error ("Unknown instruction type in inst_encoding\n"); return (0); /* Not reached */ }}/* Maintain a table mapping from actual opcode to interal opcode. Table must be sorted before first use since its entries are alphabetical on name, not ordered by opcode. *//* Map from internal opcode -> real opcode */static name_val_val a_opcode_tbl [] = {#undef OP#define OP(NAME, I_OPCODE, TYPE, A_OPCODE) {NAME, (int)A_OPCODE, (int)I_OPCODE},#include "op.h"};/* Sort the opcode table on their key (the interal opcode value). */static voidsort_a_opcode_table (){ qsort (a_opcode_tbl, sizeof (a_opcode_tbl) / sizeof (name_val_val), sizeof (name_val_val), (QSORT_FUNC) compare_pair_value);}instruction *inst_decode (int32 val){ int32 a_opcode = val & 0xfc000000; name_val_val *entry; int32 i_opcode; if (a_opcode == 0) /* SPECIAL */ a_opcode |= (val & 0x3f); else if (a_opcode == 0x04000000) /* BCOND */ a_opcode |= (val & 0x001f0000); else if (a_opcode == 0x40000000) /* COP0 */ a_opcode |= (val & 0x03e00000) | (val & 0x1f); else if (a_opcode == 0x44000000) /* COP1 */ { a_opcode |= (val & 0x03e00000); if ((val & 0xff000000) == 0x45000000) a_opcode |= (val & 0x00010000); /* BC1f/t */ else a_opcode |= (val & 0x3f); } else if (a_opcode == 0x48000000 /* COPz */ || a_opcode == 0x4c000000) a_opcode |= (val & 0x03e00000); entry = map_int_to_name_val_val (a_opcode_tbl, sizeof (a_opcode_tbl) / sizeof (name_val_val), a_opcode); if (entry == NULL) return (mk_r_inst (val, 0, 0, 0, 0, 0)); /* Invalid inst */ i_opcode = entry->value2; switch (map_int_to_name_val_val (name_tbl, sizeof (name_tbl) / sizeof (name_val_val), i_opcode)->value2) { case BC_TYPE_INST: return (mk_i_inst (val, i_opcode, BIN_RS(val), BIN_RT(val), val & 0xffff)); case B1_TYPE_INST: return (mk_i_inst (val, i_opcode, BIN_RS(val), 0, val & 0xffff)); case I1s_TYPE_INST: return (mk_i_inst (val, i_opcode, BIN_RS(val), 0, val & 0xffff)); case I1t_TYPE_INST: return (mk_i_inst (val, i_opcode, BIN_RS(val), BIN_RT(val), val & 0xffff)); case I2_TYPE_INST: case B2_TYPE_INST: return (mk_i_inst (val, i_opcode, BIN_RS(val), BIN_RT(val), val & 0xffff)); case I2a_TYPE_INST: return (mk_i_inst (val, i_opcode, BIN_RS(val), BIN_RT(val), val & 0xffff)); case R1s_TYPE_INST: return (mk_r_inst (val, i_opcode, BIN_RS(val), 0, 0, 0)); case R1d_TYPE_INST: return (mk_r_inst (val, i_opcode, 0, 0, BIN_RD(val), 0)); case R2td_TYPE_INST: return (mk_r_inst (val, i_opcode, 0, BIN_RT(val), BIN_RD(val), 0)); case R2st_TYPE_INST: return (mk_r_inst (val, i_opcode, BIN_RS(val), BIN_RT(val), 0, 0)); case R2ds_TYPE_INST: return (mk_r_inst (val, i_opcode, BIN_RS(val), 0, BIN_RD(val), 0)); case R2sh_TYPE_INST: return (mk_r_inst (val, i_opcode, 0, BIN_RT(val), BIN_RD(val), BIN_SA(val))); case R3_TYPE_INST: return (mk_r_inst (val, i_opcode, BIN_RS(val), BIN_RT(val), BIN_RD(val), 0)); case R3sh_TYPE_INST: return(mk_r_inst (val, i_opcode, BIN_RS(val), BIN_RT(val), BIN_RD(val), 0)); case FP_I2a_TYPE_INST: return (mk_i_inst (val, i_opcode, BIN_BASE(val), BIN_FT(val), val & 0xffff)); case FP_R2ds_TYPE_INST: return (mk_r_inst (val, i_opcode, BIN_FS(val), 0, BIN_FD(val), 0)); case FP_R2ts_TYPE_INST: return (mk_r_inst (val, i_opcode, 0, BIN_RT(val), BIN_FS(val), 0)); case FP_CMP_TYPE_INST: { instruction *inst = mk_r_inst (val, i_opcode, BIN_FS (val), BIN_FT (val), 0, 0); SET_COND (inst, val & 0xf); return (inst); } case FP_R3_TYPE_INST: return (mk_r_inst (val, i_opcode, BIN_FS(val), BIN_FT(val), BIN_FD(val), 0)); case FP_MOVC_TYPE_INST: return (mk_r_inst (val, i_opcode, BIN_FS(val), BIN_RT(val), BIN_FD(val), 0)); case J_TYPE_INST: return (mk_j_inst (val, i_opcode, val & 0x2ffffff)); case NOARG_TYPE_INST: return (mk_r_inst (val, i_opcode, 0, 0, 0, 0)); default: return (mk_r_inst (val, 0, 0, 0, 0, 0)); /* Invalid inst */ }}static instruction *mk_r_inst (int32 val, int opcode, int rs, int rt, int rd, int shamt){ instruction *inst = (instruction *) zmalloc (sizeof (instruction)); SET_OPCODE (inst, opcode); SET_RS (inst, rs); SET_RT (inst, rt); SET_RD (inst, rd); SET_SHAMT (inst, shamt); SET_ENCODING (inst, val); SET_EXPR (inst, NULL); return (inst);}static instruction *mk_i_inst (int32 val, int opcode, int rs, int rt, int offset){ instruction *inst = (instruction *) zmalloc (sizeof (instruction)); SET_OPCODE (inst, opcode); SET_RS (inst, rs); SET_RT (inst, rt); SET_IOFFSET (inst, offset); SET_ENCODING (inst, val); SET_EXPR (inst, NULL); return (inst);}static instruction *mk_j_inst (int32 val, int opcode, int target){ instruction *inst = (instruction *) zmalloc (sizeof (instruction)); SET_OPCODE (inst, opcode); SET_TARGET (inst, target); SET_ENCODING (inst, val); SET_EXPR (inst, NULL); return (inst);}/* Code to test encode/decode of instructions. */voidtest_assembly (instruction *inst){ instruction *new_inst = inst_decode (inst_encode (inst)); inst_cmp (inst, new_inst); free_inst (new_inst);}static voidinst_cmp (instruction *inst1, instruction *inst2){ static str_stream ss; ss_clear (&ss); if (memcmp (inst1, inst2, sizeof (instruction) - 4) != 0) { ss_printf (&ss, "=================== Not Equal ===================\n"); format_an_inst (&ss, inst1, 0); format_an_inst (&ss, inst2, 0); ss_printf (&ss, "=================== Not Equal ===================\n"); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -