📄 run.c
字号:
/* SPIM S20 MIPS simulator. Execute SPIM instructions. Copyright (C) 1990-2003 by James Larus (larus@cs.wisc.edu). ALL RIGHTS RESERVED. Changes for DOS and Windows versions by David A. Carley (dac@cs.wisc.edu) SPIM is distributed under the following conditions: You may make copies of SPIM for your own use and modify those copies. All copies of SPIM must retain my name and copyright notice. You may not sell SPIM or distributed SPIM in conjunction with a commerical product or service without the expressed written consent of James Larus. THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *//* $Header: /Software/SPIM/src/run.c 9 1/01/03 9:51p Larus $*/#ifdef mips#define _IEEE 1#include <nan.h>#else#define NaN(X) ((X) != (X))#endif#include <math.h>#include <stdio.h>#include "spim.h"#include "spim-utils.h"#include "inst.h"#include "mem.h"#include "reg.h"#include "sym-tbl.h"#include "y.tab.h"#include "mips-syscall.h"#include "run.h"int force_break = 0; /* For the execution env. to force an execution break */#ifndef _MSC_VERextern int errno;#endif#ifdef __STDC__long atol (const char *);#elselong atol ();#endif/* Local functions: */#ifdef __STDC__static void long_multiply (reg_word v1, reg_word v2);#elsestatic void long_multiply ();#endif#define SIGN_BIT(X) ((X) & 0x80000000)#define ARITH_OVFL(RESULT, OP1, OP2) (SIGN_BIT (OP1) == SIGN_BIT (OP2) \ && SIGN_BIT (OP1) != SIGN_BIT (RESULT))/* Executed delayed branch and jump instructions by running the instruction from the delay slot before transfering control. Note, in branches that don't jump, the instruction in the delay slot is executed by falling through normally. We take advantage of the MIPS architecture, which leaves undefined the result of executing a delayed instruction in a delay slot. Here we execute the second branch. */#define BRANCH_INST(TEST, TARGET) {if (TEST) \ { \ mem_addr target = (TARGET); \ if (delayed_branches) \ /* +4 since jump in delay slot */\ target += BYTES_PER_WORD; \ JUMP_INST (target) \ } \ }#define JUMP_INST(TARGET) {if (delayed_branches) \ run_spim (PC + BYTES_PER_WORD, 1, display); \ /* -4 since PC is bumped after this inst */ \ PC = (TARGET) - BYTES_PER_WORD; \ }/* Result from load is available immediate, but no program should ever have assumed otherwise because of exceptions.*/#define LOAD_INST(OP, ADDR, DEST_A, MASK) \ {reg_word tmp; \ OP (tmp, (ADDR)); \ *(DEST_A) = tmp & (MASK); \ }#define DELAYED_UPDATE(A, D) {if (delayed_addr1 != NULL) \ fatal_error("Two calls to DELAYED_UPDATE\n");\ delayed_addr1 = A; delayed_value1 = D; \ }#define DO_DELAYED_UPDATE() if (delayed_loads) \ { \ /* Check for delayed updates */ \ if (delayed_addr2 != NULL) \ *delayed_addr2 = delayed_value2; \ delayed_addr2 = delayed_addr1; \ delayed_value2 = delayed_value1; \ delayed_addr1 = NULL; \ }/* Run the program stored in memory, starting at address PC for STEPS_TO_RUN instruction executions. If flag DISPLAY is non-zero, print each instruction before it executes. Return non-zero if program's execution can continue. */#ifdef __STDC__intrun_spim (mem_addr initial_PC, int steps_to_run, int display)#elseintrun_spim (initial_PC, steps_to_run, display) mem_addr initial_PC; int steps_to_run; int display;#endif{ register instruction *inst; static reg_word *delayed_addr1 = NULL, delayed_value1; static reg_word *delayed_addr2 = NULL, delayed_value2; int step, step_size, next_step; PC = initial_PC; if (!bare_machine && mapped_io) next_step = IO_INTERVAL; else next_step = steps_to_run; /* Run to completion */ for (step_size = MIN (next_step, steps_to_run); steps_to_run > 0; steps_to_run -= step_size, step_size = MIN (next_step, steps_to_run)) { if (!bare_machine && mapped_io) /* Every IO_INTERVAL steps, check if memory-mapped IO registers have changed. */ check_memory_mapped_IO (); /* else run inner loop for all steps */ for (step = 0; step < step_size; step += 1) { if (force_break) { force_break = 0; return (1); } R[0] = 0; /* Maintain invariant value */ READ_MEM_INST (inst, PC); if (inst == NULL) return 0; if (exception_occurred) { exception_occurred = 0; EPC = ROUND_DOWN (PC, BYTES_PER_WORD); handle_exception(); continue; } else if (inst == NULL) run_error ("Attempt to execute non-instruction at 0x%08x\n", PC); else if (EXPR (inst) != NULL && EXPR (inst)->symbol != NULL && EXPR (inst)->symbol->addr == 0) { error ("Instruction references undefined symbol at 0x%08x\n", PC); print_inst (PC); run_error (""); } if (display) print_inst (PC);#ifdef TEST_ASM test_assembly (inst);#endif DO_DELAYED_UPDATE (); switch (OPCODE (inst)) { case Y_ADD_OP: { register reg_word vs = R[RS (inst)], vt = R[RT (inst)]; register reg_word sum = vs + vt; if (ARITH_OVFL (sum, vs, vt)) RAISE_EXCEPTION (OVF_EXCPT, break); R[RD (inst)] = sum; break; } case Y_ADDI_OP: { register reg_word vs = R[RS (inst)], imm = (short) IMM (inst); register reg_word sum = vs + imm; if (ARITH_OVFL (sum, vs, imm)) RAISE_EXCEPTION (OVF_EXCPT, break); R[RT (inst)] = sum; break; } case Y_ADDIU_OP: R[RT (inst)] = R[RS (inst)] + (short) IMM (inst); break; case Y_ADDU_OP: R[RD (inst)] = R[RS (inst)] + R[RT (inst)]; break; case Y_AND_OP: R[RD (inst)] = R[RS (inst)] & R[RT (inst)]; break; case Y_ANDI_OP: R[RT (inst)] = R[RS (inst)] & (0xffff & IMM (inst)); break; case Y_BC0F_OP: case Y_BC2F_OP: case Y_BC3F_OP: BRANCH_INST (CpCond[OPCODE (inst) - Y_BC0F_OP] == 0, PC + IDISP (inst)); break; case Y_BC0T_OP: case Y_BC2T_OP: case Y_BC3T_OP: BRANCH_INST (CpCond[OPCODE (inst) - Y_BC0T_OP] != 0, PC + IDISP (inst)); break; case Y_BEQ_OP: BRANCH_INST (R[RS (inst)] == R[RT (inst)], PC + IDISP (inst)); break; case Y_BGEZ_OP: BRANCH_INST (SIGN_BIT (R[RS (inst)]) == 0, PC + IDISP (inst)); break; case Y_BGEZAL_OP: if (delayed_branches) R[31] = PC + 2 * BYTES_PER_WORD; else R[31] = PC + BYTES_PER_WORD; BRANCH_INST (SIGN_BIT (R[RS (inst)]) == 0, PC + IDISP (inst)); break; case Y_BGTZ_OP: BRANCH_INST (R[RS (inst)] != 0 && SIGN_BIT (R[RS (inst)]) == 0, PC + IDISP (inst)); break; case Y_BLEZ_OP: BRANCH_INST (R[RS (inst)] == 0 || SIGN_BIT (R[RS (inst)]) != 0, PC + IDISP (inst)); break; case Y_BLTZ_OP: BRANCH_INST (SIGN_BIT (R[RS (inst)]) != 0, PC + IDISP (inst)); break; case Y_BLTZAL_OP: if (delayed_branches) R[31] = PC + 2 * BYTES_PER_WORD; else R[31] = PC + BYTES_PER_WORD; BRANCH_INST (SIGN_BIT (R[RS (inst)]) != 0, PC + IDISP (inst)); break; case Y_BNE_OP: BRANCH_INST (R[RS (inst)] != R[RT (inst)], PC + IDISP (inst)); break; case Y_BREAK_OP: if (RD (inst) == 1) /* Debugger breakpoint */ RAISE_EXCEPTION (BKPT_EXCPT, return (1)) else RAISE_EXCEPTION (BKPT_EXCPT, break); case Y_CFC0_OP: case Y_CFC2_OP: case Y_CFC3_OP: R[RT (inst)] = CCR[OPCODE (inst) - Y_CFC0_OP][RD (inst)]; break; case Y_COP0_OP: case Y_COP1_OP: case Y_COP2_OP: case Y_COP3_OP: CCR[OPCODE (inst) - Y_COP0_OP][RD (inst)] = R[RT (inst)]; break; case Y_CTC0_OP: case Y_CTC2_OP: case Y_CTC3_OP: CCR[OPCODE (inst) - Y_CTC0_OP][RD (inst)] = R[RT (inst)]; break; case Y_DIV_OP: /* The behavior of this instruction is undefined on divide by zero or overflow. */ if (R[RT (inst)] != 0 && (R[RS (inst)] != 0x80000000 && R[RT (inst)] != 0xffffffff)) { LO = (reg_word) R[RS (inst)] / (reg_word) R[RT (inst)]; HI = (reg_word) R[RS (inst)] % (reg_word) R[RT (inst)]; } break; case Y_DIVU_OP: /* The behavior of this instruction is undefined on divide by zero or overflow. */ if (R[RT (inst)] != 0 && (R[RS (inst)] != 0x80000000 && R[RT (inst)] != 0xffffffff)) { LO = ((u_reg_word) R[RS (inst)] / (u_reg_word) R[RT (inst)]); HI = ((u_reg_word) R[RS (inst)] % (u_reg_word) R[RT (inst)]); } break; case Y_J_OP: JUMP_INST (((PC & 0xf0000000) | TARGET (inst) << 2)); break; case Y_JAL_OP: if (delayed_branches) R[31] = PC + 2 * BYTES_PER_WORD; else R[31] = PC + BYTES_PER_WORD; JUMP_INST (((PC & 0xf0000000) | (TARGET (inst) << 2))); break; case Y_JALR_OP: { mem_addr tmp = R[RS (inst)]; if (delayed_branches) R[RD (inst)] = PC + 2 * BYTES_PER_WORD; else R[RD (inst)] = PC + BYTES_PER_WORD; JUMP_INST (tmp); } break; case Y_JR_OP: { mem_addr tmp = R[RS (inst)]; JUMP_INST (tmp); } break; case Y_LB_OP: LOAD_INST (READ_MEM_BYTE, R[BASE (inst)] + IOFFSET (inst), &R[RT (inst)], 0xffffffff); break; case Y_LBU_OP: LOAD_INST (READ_MEM_BYTE, R[BASE (inst)] + IOFFSET (inst), &R[RT (inst)], 0xff); break; case Y_LH_OP: LOAD_INST (READ_MEM_HALF, R[BASE (inst)] + IOFFSET (inst), &R[RT (inst)], 0xffffffff); break; case Y_LHU_OP: LOAD_INST (READ_MEM_HALF, R[BASE (inst)] + IOFFSET (inst), &R[RT (inst)], 0xffff); break; case Y_LUI_OP: R[RT (inst)] = (IMM (inst) << 16) & 0xffff0000; break; case Y_LW_OP: LOAD_INST (READ_MEM_WORD, R[BASE (inst)] + IOFFSET (inst), &R[RT (inst)], 0xffffffff); break; case Y_LWC0_OP: case Y_LWC2_OP: case Y_LWC3_OP: LOAD_INST (READ_MEM_WORD, R[BASE (inst)] + IOFFSET (inst), &CPR[OPCODE (inst) - Y_LWC0_OP][RT (inst)], 0xffffffff); break; case Y_LWL_OP: { register mem_addr addr = R[BASE (inst)] + IOFFSET (inst); reg_word word; /* Can't be register */ register int byte = addr & 0x3; reg_word reg_val = R[RT (inst)]; LOAD_INST (READ_MEM_WORD, addr & 0xfffffffc, &word, 0xffffffff); DO_DELAYED_UPDATE (); if ((!exception_occurred) || ((Cause >> 2) > LAST_REAL_EXCEPT))#ifdef BIGENDIAN switch (byte) { case 0: R[RT (inst)] = word; break; case 1: R[RT (inst)] = ((word & 0xffffff) << 8) | (reg_val & 0xff); break; case 2: R[RT (inst)] = ((word & 0xffff) << 16) | (reg_val & 0xffff); break; case 3: R[RT (inst)] = ((word & 0xff) << 24) | (reg_val & 0xffffff); break; }#else switch (byte) { case 0: R[RT (inst)] = ((word & 0xff) << 24) | (reg_val & 0xffffff); break; case 1: R[RT (inst)] = ((word & 0xffff) << 16) | (reg_val & 0xffff); break; case 2: R[RT (inst)] = ((word & 0xffffff) << 8) | (reg_val & 0xff); break; case 3: R[RT (inst)] = word; break; }#endif break; } case Y_LWR_OP: { register mem_addr addr = R[BASE (inst)] + IOFFSET (inst); reg_word word; /* Can't be register */ register int byte = addr & 0x3; reg_word reg_val = R[RT (inst)]; LOAD_INST (READ_MEM_WORD, addr & 0xfffffffc, &word, 0xffffffff); DO_DELAYED_UPDATE (); if ((!exception_occurred) || ((Cause >> 2) > LAST_REAL_EXCEPT))#ifdef BIGENDIAN switch (byte) { case 0: R[RT (inst)] = (reg_val & 0xffffff00) | ((unsigned)(word & 0xff000000) >> 24); break; case 1: R[RT (inst)] = (reg_val & 0xffff0000) | ((unsigned)(word & 0xffff0000) >> 16); break; case 2: R[RT (inst)] = (reg_val & 0xff000000) | ((unsigned)(word & 0xffffff00) >> 8); break; case 3: R[RT (inst)] = word; break; }#else switch (byte) { /* NB: The description of the little-endian case in Kane is totally wrong. */ case 0: /* 3 in book */ R[RT (inst)] = word; break; case 1: /* 0 in book */ R[RT (inst)] = (reg_val & 0xff000000) | ((word & 0xffffff00) >> 8); break; case 2: /* 1 in book */ R[RT (inst)] = (reg_val & 0xffff0000) | ((word & 0xffff0000) >> 16); break; case 3: /* 2 in book */ R[RT (inst)] = (reg_val & 0xffffff00) | ((word & 0xff000000) >> 24); break; }#endif break; } case Y_MFC0_OP: case Y_MFC2_OP: case Y_MFC3_OP: R[RT (inst)] = CPR[OPCODE (inst) - Y_MFC0_OP][RD (inst)]; break; case Y_MFHI_OP: R[RD (inst)] = HI; break; case Y_MFLO_OP: R[RD (inst)] = LO; break; case Y_MTC0_OP: case Y_MTC2_OP: case Y_MTC3_OP: CPR[OPCODE (inst) - Y_MTC0_OP][RD (inst)] = R[RT (inst)]; break; case Y_MTHI_OP: HI = R[RS (inst)]; break; case Y_MTLO_OP: LO = R[RS (inst)]; break; case Y_MULT_OP: { reg_word v1 = R[RS (inst)], v2 = R[RT (inst)]; int neg_sign = 0; if (v1 < 0) v1 = - v1, neg_sign = 1; if (v2 < 0) v2 = - v2, neg_sign = ! neg_sign; long_multiply (v1, v2); if (neg_sign) { LO = ~ LO; HI = ~ HI; LO += 1; if (LO == 0) HI += 1; } } break; case Y_MULTU_OP: long_multiply (R[RS (inst)], R[RT (inst)]); break; case Y_NOR_OP: R[RD (inst)] = ~ (R[RS (inst)] | R[RT (inst)]); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -