// Register fetch and decode stage. static inline int rsp_rd_stage(struct rsp *rsp) { struct rsp_rdex_latch *rdex_latch = &rsp->pipeline.rdex_latch; struct rsp_ifrd_latch *ifrd_latch = &rsp->pipeline.ifrd_latch; uint32_t previous_insn_flags = rdex_latch->opcode.flags; uint32_t iw = ifrd_latch->iw; rdex_latch->common = ifrd_latch->common; rdex_latch->opcode = ifrd_latch->opcode; rdex_latch->iw = iw; // Check for load-use stalls. if (previous_insn_flags & OPCODE_INFO_LOAD) { const struct rsp_opcode *opcode = &rdex_latch->opcode; unsigned dest = rsp->pipeline.exdf_latch.result.dest; unsigned rs = GET_RS(iw); unsigned rt = GET_RT(iw); if (unlikely(dest && ( (dest == rs && (opcode->flags & OPCODE_INFO_NEEDRS)) || (dest == rt && (opcode->flags & OPCODE_INFO_NEEDRT)) ))) { static const struct rsp_opcode rsp_rf_kill_op = {RSP_OPCODE_SLL, 0x0}; rdex_latch->opcode = rsp_rf_kill_op; rdex_latch->iw = 0x00000000U; return 1; } } return 0; }
// Execution stage. cen64_flatten static inline void rsp_ex_stage(struct rsp *rsp) { struct rsp_dfwb_latch *dfwb_latch = &rsp->pipeline.dfwb_latch; struct rsp_exdf_latch *exdf_latch = &rsp->pipeline.exdf_latch; struct rsp_rdex_latch *rdex_latch = &rsp->pipeline.rdex_latch; uint32_t rs_reg, rt_reg, temp; unsigned rs, rt; uint32_t iw; exdf_latch->common = rdex_latch->common; if (rdex_latch->opcode.flags & OPCODE_INFO_VECTOR) return; iw = rdex_latch->iw; rs = GET_RS(iw); rt = GET_RT(iw); // Forward results from DF/WB. temp = rsp->regs[dfwb_latch->result.dest]; rsp->regs[dfwb_latch->result.dest] = dfwb_latch->result.result; rsp->regs[RSP_REGISTER_R0] = 0x00000000U; rs_reg = rsp->regs[rs]; rt_reg = rsp->regs[rt]; rsp->regs[dfwb_latch->result.dest] = temp; // Finally, execute the instruction. #ifdef PRINT_EXEC debug("%.8X: %s\n", rdex_latch->common.pc, rsp_opcode_mnemonics[rdex_latch->opcode.id]); #endif return rsp_function_table[rdex_latch->opcode.id]( rsp, iw, rs_reg, rt_reg); }
int interp_control() { uint32_t opcode = GET_OPCODE(if_id.inst); uint32_t address; switch (opcode) { case OPCODE_R : id_ex.reg_write = true; id_ex.reg_dst = GET_RD(if_id.inst); id_ex.rt = GET_RT(if_id.inst); id_ex.rs_value = regs[GET_RS(if_id.inst)]; id_ex.rt_value = regs[id_ex.rt]; id_ex.funct = GET_FUNCT(if_id.inst); id_ex.shamt = GET_SHAMT(if_id.inst); if (id_ex.funct == FUNCT_JR) { id_ex.jump = true; id_ex.jump_target = id_ex.rs_value; } break; case OPCODE_BEQ : id_ex.branch = true; id_ex.beq = true; id_ex.rt = GET_RT(if_id.inst); id_ex.rs_value = regs[GET_RS(if_id.inst)]; id_ex.rt_value = regs[id_ex.rt]; id_ex.sign_ext_imm = SIGN_EXTEND(GET_IMM(if_id.inst)); // INSTRUKTOR 0: no reason to updates fields that you dont use id_ex.funct = FUNCT_SUB; break; case OPCODE_BNE : id_ex.branch = true; id_ex.beq = false; id_ex.rt = GET_RT(if_id.inst); id_ex.rs_value = regs[GET_RS(if_id.inst)]; id_ex.rt_value = regs[id_ex.rt]; id_ex.sign_ext_imm = SIGN_EXTEND(GET_IMM(if_id.inst)); id_ex.funct = FUNCT_SUB; break; case OPCODE_LW : id_ex.mem_read = true; id_ex.reg_write = true; id_ex.alu_src = true; id_ex.mem_to_reg = true; id_ex.reg_dst = GET_RT(if_id.inst); id_ex.rt = GET_RT(if_id.inst); id_ex.rs_value = regs[GET_RS(if_id.inst)]; id_ex.rt_value = regs[id_ex.rt]; id_ex.sign_ext_imm = SIGN_EXTEND(GET_IMM(if_id.inst)); id_ex.funct = FUNCT_ADD; break; case OPCODE_SW : id_ex.mem_write = true; id_ex.alu_src = true; id_ex.rt = GET_RT(if_id.inst); id_ex.rs_value = regs[GET_RS(if_id.inst)]; id_ex.rt_value = regs[id_ex.rt]; id_ex.sign_ext_imm = SIGN_EXTEND(GET_IMM(if_id.inst)); id_ex.funct = FUNCT_ADD; break; case OPCODE_J : id_ex.jump = true; address = GET_ADDRESS(if_id.inst); id_ex.jump_target = (if_id.next_pc & MS_4B) | (address << 2); break; case OPCODE_JAL : id_ex.reg_write = true; id_ex.jump = true; address = GET_ADDRESS(if_id.inst); id_ex.jump_target = (if_id.next_pc & MS_4B) | (address << 2); id_ex.rs_value = 0; id_ex.rt_value = if_id.next_pc; id_ex.reg_dst = 31; id_ex.funct = FUNCT_ADD; break; // INSTRUKTOR -2: Make cases for all I-type and J-type instructions default: printf("ERROR: Unknown opcode in interp_control()\n"); return ERROR_UNKNOWN_OPCODE; } return 0; }
int mipsasm_resolve_labels(uint32_t *code, uint32_t *size, uint32_t offset) { uint32_t i = offset; uint32_t labels[MAX_LABEL_NUM]; memset(labels, 0xff, sizeof(labels)); while (i < *size) { uint32_t opcode = ntohl(code[i / 4]); if (GET_OP(opcode) != ASM_LABEL_OPCODE || GET_RS(opcode) || GET_RT(opcode) || !(opcode & ASM_LABEL_MARKER)) { i += 4; continue; } uint32_t label = opcode & ASM_LABEL_MASK; if (label >= MAX_LABEL_NUM) { fprintf(stderr, "%s: %02x: label %u exeeds %u\n", __func__, i, label, MAX_LABEL_NUM); return 1; } #ifdef MIPSASM_DEBUG printf("%s: %02x: label %u (opcode %08x)\n", __func__, i, label, opcode); #endif labels[label] = i / 4; *size -= 4; uint32_t *dest = code + (i / 4); memmove(dest, dest + 1, *size - i); } for (i = offset; i < *size; i += 4) { uint32_t opcode = ntohl(code[i / 4]); uint32_t op = GET_OP(opcode); switch (op) { case 0x01: case 0x04: case 0x05: case 0x06: case 0x07: break; default: continue; } uint32_t imm = opcode & 0xffff; if (!(imm & ASM_LABEL_MARKER)) { #ifdef MIPSASM_DEBUG printf("%s: %02x: skiping non-labeled branch to %02x\n", __func__, i, imm); #endif // skip unlabeled branchp instruction continue; } imm &= ASM_LABEL_MASK; if (imm > MAX_LABEL_NUM) { fprintf(stderr, "%s: %02x: branch refers to out-of-range label %u\n", __func__, i, imm); return 1; } uint32_t instr = labels[imm]; if (instr == UINT32_MAX) { fprintf(stderr, "%s: %02x: branch refers to undefined label %u\n", __func__, i, imm); return 1; } int32_t diff = (instr - (i / 4)) - 1; if (diff < INT16_MIN || diff > INT16_MAX) { fprintf(stderr, "%s: %02x: branch target %x out of range\n", __func__, i, diff); return 1; } opcode &= 0xffff0000; opcode |= (diff & 0xffff); code[i / 4] = htonl(opcode); #ifdef MIPSASM_DEBUG printf("%s: %02x: branch to %02x\n", __func__, i, (diff * 4) & 0xffff); #endif } return 0; }