home *** CD-ROM | disk | FTP | other *** search
- /* SPIM S20 MIPS simulator.
- Execute SPIM instructions.
- Copyright (C) 1990 by James Larus (larus@cs.wisc.edu).
-
- SPIM is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 1, or (at your option) any
- later version.
-
- SPIM is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNU CC; see the file COPYING. If not, write to James R.
- Larus, Computer Sciences Department, University of Wisconsin--Madison,
- 1210 West Dayton Street, Madison, WI 53706, USA or to the Free
- Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-
- /* $Header: /var/home/cs354/.spim/RCS/run.c,v 1.4 1992/10/12 11:34:13 cs354 Exp $
- */
-
-
- #ifdef mips
- #define _IEEE 1
- #include <nan.h>
- #include <syscall.h>
- #include "mips-syscall.h"
- #else
- #define NaN(X) 0
- #endif
-
- #include <math.h>
- #include <stdio.h>
- #ifndef WIN32
- #ifndef MACINTOSH
- #include <X11/Intrinsic.h>
- #include <X11/StringDefs.h>
- #endif
- #endif
-
- #include "spim.h"
- #include "inst.h"
- #include "mem.h"
- #include "reg.h"
- #include "sym_tbl.h"
- #ifdef WIN32
- #include "spim-sys.h"
- #include "y_tab.h"
- extern int IntCheck();
- #else
- #ifdef MACINTOSH
- #include "spim-sys.h"
- #include "y_tab.h"
- #else
- #include "spim-syscall.h"
- #include "y.tab.h"
- #endif
- #endif
-
- /* Exported functions: */
-
- int run_spim (mem_addr initial_PC, register int steps, int display);
-
-
- /* Local functions: */
-
- static void long_multiply (reg_word v1, reg_word v2);
-
-
- /* Imported variables: */
-
- extern char *ex_file_name;
- extern int errno;
- extern int errno_addr;
- int program_break;
-
- /* Delayed branch instructions set delay_PC to the address of their
- target and then execute another instruction.
-
- Note that we take advantage of the MIPS architecture, which leaves
- undefined the result of executing a delayed instruction in a delay
- slot. Here we just execute the second branch. */
-
-
- #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 (bare_machine) \
- { \
- /* Check for delayed updates */ \
- if (delayed_addr2 != NULL) \
- *delayed_addr2 = delayed_value2; \
- delayed_addr2 = delayed_addr1; \
- delayed_value2 = delayed_value1; \
- delayed_addr1 = NULL; \
- }
-
- #define SIGN_BIT(X) ((X) & 0x80000000)
-
- #define ARITH_OVFL(RESULT, OP1, OP2) (SIGN_BIT (OP1) == SIGN_BIT (OP2) \
- && SIGN_BIT (OP1) != SIGN_BIT (RESULT))
-
- #define LOAD_INST(OP, ADDR, DEST_A, MASK) \
- {reg_word tmp = 0; \
- OP (tmp, (ADDR)); \
- tmp &= (MASK); \
- if (bare_machine) \
- { \
- DELAYED_UPDATE ((DEST_A), tmp); \
- run_spim (PC+BYTES_PER_WORD, 1, display);\
- PC -= BYTES_PER_WORD; \
- } \
- else \
- *(DEST_A) = tmp; \
- }
-
- #define BRANCH_INST(TEST, VALUE) {mem_addr delay_PC = -1; \
- if (TEST) \
- delay_PC = VALUE; \
- if (bare_machine) \
- run_spim (PC+BYTES_PER_WORD, 1, display);\
- if (delay_PC != -1) \
- PC = delay_PC; \
- }
-
-
- #define JUMP_INST(VALUE) {if (bare_machine) \
- run_spim (PC+BYTES_PER_WORD, 1, display); \
- PC = VALUE - BYTES_PER_WORD; \
- }
-
-
-
- /* Run a program stored at PC for N steps. If display FLAG is
- non-zero, print each instruction before it executes. Return non-zero
- if program's execution can continue. */
-
- int run_spim (mem_addr initial_PC, register int steps, int display)
- {
- static reg_word *delayed_addr1 = NULL, delayed_value1;
- static reg_word *delayed_addr2 = NULL, delayed_value2;
- register instruction *inst;
-
-
- PC = initial_PC;
- while (steps -- != 0) {
-
- #ifdef WIN32
-
- /* look at the message queue for the "running..." dialog box; if
- * the interrupt button has been pressed, RunPeek() is true */
-
- if(IntCheck())
- control_c_seen();
- #endif
-
- #ifdef MACINTOSH
-
- /* Good idea, Scott! Let's do the same damn thing on the Mac. */
- /* Of course, the implementation is totally different.... */
-
- if ( IntCheck() )
- control_c_seen();
-
- #endif
-
- R [0] = 0; /* Maintain invariant value */
-
- READ_MEM_INST (inst, PC);
-
- if (exception_occurred)
- {
- exception_occurred = 0;
- EPC = PC & 0xfffffffc; /* Round down */
- PC = EXCEPTION_ADDR;
- continue;
- }
- else if (inst == NULL) {
- sprintf(mess_buff,
- "Attempt to execute non-instruction at 0x%08x\n", PC);
- run_error (mess_buff);
- }
- else if (EXPR (inst) != NULL
- && EXPR (inst)->symbol != NULL
- && EXPR (inst)->symbol->addr == 0)
- {
- sprintf(mess_buff,
- "Instruction references undefined symbol at 0x%08x\n", PC);
- error (mess_buff);
- 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 + (SIGN_EX (IOFFSET (inst)) << 2));
- break;
-
- case Y_BC0T_OP:
- case Y_BC2T_OP:
- case Y_BC3T_OP:
- BRANCH_INST (CpCond[OPCODE (inst) - Y_BC0T_OP] != 0,
- PC + (SIGN_EX (IOFFSET (inst)) << 2));
- break;
-
- case Y_BEQ_OP:
- BRANCH_INST (R[RS (inst)] == R[RT (inst)],
- PC + (SIGN_EX (IOFFSET (inst)) << 2));
- break;
-
- case Y_BGEZ_OP:
- BRANCH_INST (SIGN_BIT (R[RS (inst)]) == 0,
- PC + (SIGN_EX (IOFFSET (inst)) << 2));
- break;
-
- case Y_BGEZAL_OP:
- if (bare_machine)
- R[31] = PC + 2 * BYTES_PER_WORD;
- else
- R[31] = PC + BYTES_PER_WORD;
- BRANCH_INST (SIGN_BIT (R[RS (inst)]) == 0,
- PC + (SIGN_EX (IOFFSET (inst)) << 2));
- break;
-
- case Y_BGTZ_OP:
- BRANCH_INST (R[RS (inst)] != 0 && SIGN_BIT (R[RS (inst)]) == 0,
- PC + (SIGN_EX (IOFFSET (inst)) << 2));
- break;
-
- case Y_BLEZ_OP:
- BRANCH_INST (R[RS (inst)] == 0 || SIGN_BIT (R[RS (inst)]) != 0,
- PC + (SIGN_EX (IOFFSET (inst)) << 2));
- break;
-
- case Y_BLTZ_OP:
- BRANCH_INST (SIGN_BIT (R[RS (inst)]) != 0,
- PC + (SIGN_EX (IOFFSET (inst)) << 2));
- break;
-
- case Y_BLTZAL_OP:
- if (bare_machine)
- R[31] = PC + 2 * BYTES_PER_WORD;
- else
- R[31] = PC + BYTES_PER_WORD;
- BRANCH_INST (SIGN_BIT (R[RS (inst)]) != 0,
- PC + (SIGN_EX (IOFFSET (inst)) << 2));
- break;
-
- case Y_BNE_OP:
- BRANCH_INST (R[RS (inst)] != R[RT (inst)],
- PC + (SIGN_EX (IOFFSET (inst)) << 2));
- break;
-
- case Y_BREAK_OP:
- if (RD (inst) == 1)
- RAISE_EXCEPTION (BKPT_EXCPT, return (1)) /* Debugger breakpoint */
- 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:
- if (R[RT (inst)] != 0)
- {
- LO = (long) R[RS (inst)] / (long) R[RT (inst)];
- HI = (long) R[RS (inst)] % (long) R[RT (inst)];
- }
- break;
-
- case Y_DIVU_OP:
- if (R[RT (inst)] != 0)
- {
- LO = (unsigned long) R[RS (inst)] / (unsigned long) R[RT (inst)];
- HI = (unsigned long) R[RS (inst)] % (unsigned long) R[RT (inst)];
- }
- break;
-
- case Y_J_OP:
- JUMP_INST (((PC & 0xf0000000) | TARGET (inst) << 2));
- break;
-
- case Y_JAL_OP:
- if (bare_machine)
- 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 (bare_machine)
- 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)
- | ((word & 0xff000000) >> 24);
- break;
-
- case 1:
- R[RT (inst)] = (reg_val & 0xffff0000)
- | ((word & 0xffff0000) >> 16);
- break;
-
- case 2:
- R[RT (inst)] = (reg_val & 0xff000000)
- | ((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)] = reg_val;
- 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;
-
- case Y_OR_OP:
- R[RD (inst)] = R[RS (inst)] | R[RT (inst)];
- break;
-
- case Y_ORI_OP:
- R[RT (inst)] = R[RS (inst)] | (0xffff & IMM (inst));
- break;
-
- case Y_RFE_OP:
- Status_Reg = (Status_Reg & 0xfffffff0) | ((Status_Reg & 0x3c) >> 2);
- break;
-
- case Y_SB_OP:
- SET_MEM_BYTE (R[BASE (inst)] + IOFFSET (inst), R[RT (inst)]);
- break;
-
- case Y_SH_OP:
- SET_MEM_HALF (R[BASE (inst)] + IOFFSET (inst), R[RT (inst)]);
- break;
-
- case Y_SLL_OP:
- {
- int shamt = SHAMT (inst);
-
- if (shamt >= 0 && shamt < 32)
- R[RD (inst)] = R[RT (inst)] << shamt;
- else
- R[RD (inst)] = R[RT (inst)];
- break;
- }
-
- case Y_SLLV_OP:
- {
- int shamt = (R[RS (inst)] & 0x1f);
-
- if (shamt >= 0 && shamt < 32)
- R[RD (inst)] = R[RT (inst)] << shamt;
- else
- R[RD (inst)] = R[RT (inst)];
- break;
- }
-
- case Y_SLT_OP:
- if (R[RS (inst)] < R[RT (inst)])
- R[RD (inst)] = 1;
- else
- R[RD (inst)] = 0;
- break;
-
- case Y_SLTI_OP:
- if (R[RS (inst)] < (short) IMM (inst))
- R[RT (inst)] = 1;
- else
- R[RT (inst)] = 0;
- break;
-
- case Y_SLTIU_OP:
- {
- int x = (short) IMM (inst);
-
- if ((unsigned long) R[RS (inst)] < (unsigned long) x)
- R[RT (inst)] = 1;
- else
- R[RT (inst)] = 0;
- break;
- }
-
- case Y_SLTU_OP:
- if ((unsigned long) R[RS (inst)] < (unsigned long) R[RT (inst)])
- R[RD (inst)] = 1;
- else
- R[RD (inst)] = 0;
- break;
-
- case Y_SRA_OP:
- {
- int shamt = SHAMT (inst);
- long val = R[RT (inst)];
-
- if (shamt >= 0 && shamt < 32)
- R[RD (inst)] = val >> shamt;
- else
- R[RD (inst)] = val;
- break;
- }
-
- case Y_SRAV_OP:
- {
- int shamt = R[RS (inst)] & 0x1f;
- long val = R[RT (inst)];
-
- if (shamt >= 0 && shamt < 32)
- R[RD (inst)] = val >> shamt;
- else
- R[RD (inst)] = val;
- break;
- }
-
- case Y_SRL_OP:
- {
- int shamt = SHAMT (inst);
- unsigned long val = R[RT (inst)];
-
- if (shamt >= 0 && shamt < 32)
- R[RD (inst)] = val >> shamt;
- else
- R[RD (inst)] = val;
- break;
- }
-
- case Y_SRLV_OP:
- {
- int shamt = R[RS (inst)] & 0x1f;
- unsigned long val = R[RT (inst)];
-
- if (shamt >= 0 && shamt < 32)
- R[RD (inst)] = val >> shamt;
- else
- R[RD (inst)] = val;
- break;
- }
-
- case Y_SUB_OP:
- {
- register reg_word vs = R[RS (inst)], vt = R[RT (inst)];
- register reg_word diff = vs - vt;
-
- if (SIGN_BIT (vs) != SIGN_BIT (vt)
- && SIGN_BIT (vs) != SIGN_BIT (diff))
- RAISE_EXCEPTION (OVF_EXCPT, break);
- R[RD (inst)] = diff;
- break;
- }
-
- case Y_SUBU_OP:
- R[RD (inst)] = (unsigned long) R[RS (inst)]
- - (unsigned long) R[RT (inst)];
- break;
-
- case Y_SW_OP:
- SET_MEM_WORD (R[BASE (inst)] + IOFFSET (inst), R[RT (inst)]);
- break;
-
- case Y_SWC0_OP:
- case Y_SWC2_OP:
- case Y_SWC3_OP:
- SET_MEM_WORD (R[BASE (inst)] + IOFFSET (inst),
- CPR [OPCODE (inst) - Y_SWC0_OP] [RT (inst)]);
- break;
-
- case Y_SWL_OP:
- {
- register mem_addr addr = R[BASE (inst)] + IOFFSET (inst);
- mem_word data;
- reg_word reg = R[RT (inst)];
- register int byte = addr & 0x3;
-
- READ_MEM_WORD (data, (addr & 0xfffffffc));
- #ifdef BIGENDIAN
- switch (byte)
- {
- case 0:
- data = reg;
- break;
-
- case 1:
- data = (data & 0xff000000) | (reg >> 8 & 0xffffff);
- break;
-
- case 2:
- data = (data & 0xffff0000) | (reg >> 16 & 0xffff);
- break;
-
- case 3:
- data = (data & 0xffffff00) | (reg >> 24 & 0xff);
- break;
- }
- #else
- switch (byte)
- {
- case 0:
- data = (data & 0xffffff00) | (reg >> 24 & 0xff);
- break;
-
- case 1:
- data = (data & 0xffff0000) | (reg >> 16 & 0xffff);
- break;
-
- case 2:
- data = (data & 0xff000000) | (reg >> 8 & 0xffffff);
- break;
-
- case 3:
- data = reg;
- break;
- }
- #endif
- SET_MEM_WORD (addr & 0xfffffffc, data);
- break;
- }
-
- case Y_SWR_OP:
- {
- register mem_addr addr = R[BASE (inst)] + IOFFSET (inst);
- mem_word data;
- reg_word reg = R[RT (inst)];
- register int byte = addr & 0x3;
-
- READ_MEM_WORD (data, (addr & 0xfffffffc));
- #ifdef BIGENDIAN
- switch (byte)
- {
- case 0:
- data = ((reg << 24) & 0xff000000) | (data & 0xffffff);
- break;
-
- case 1:
- data = ((reg << 16) & 0xffff0000) | (data & 0xffff);
- break;
-
- case 2:
- data = ((reg << 8) & 0xffffff00) | (data & 0xff) ;
- break;
-
- case 3:
- data = reg;
- break;
- }
- #else
- switch (byte)
- {
- case 0:
- data = reg;
- break;
-
- case 1:
- data = ((reg << 8) & 0xffffff00) | (data & 0xff) ;
- break;
-
- case 2:
- data = ((reg << 16) & 0xffff0000) | (data & 0xffff);
- break;
-
- case 3:
- data = ((reg << 24) & 0xff000000) | (data & 0xffffff);
- break;
- }
- #endif
- SET_MEM_WORD (addr & 0xfffffffc, data);
- break;
- }
-
- case Y_SYSCALL_OP:
- #ifdef mips
- if (!source_file)
- {
- /* Use actual MIPS system calls after translating arguments
- from simulated memory to actual memory.*/
- if (R[REG_V0] > MAX_SYSCALL)
- {
- run_error(sprintf(mess_buff,
- "Illegal system call: %d\n", R[REG_V0]));
- break;
- }
- switch(syscall_table[R[REG_V0]].syscall_type)
- {
- case BAD_SYSCALL:
- run_error (sprintf(mess_buff,
- "Unknown system call: %d\n", R[REG_V0]));
- break;
-
- case UNIX_SYSCALL:
- {
- int arg0, arg1, arg2, arg3;
-
- arg0 = SYSCALL_ARG(arg0, REG_A0);
- arg1 = SYSCALL_ARG(arg1, REG_A1);
- arg2 = SYSCALL_ARG(arg2, REG_A2);
- arg3 = SYSCALL_ARG(arg3, REG_A3);
-
- R[REG_RES] = syscall(R[REG_V0], arg0, arg1, arg2, arg3);
- if (errno_addr != 0)
- SET_MEM_WORD(errno_addr, errno);
- break;
- }
-
- case SPC_SYSCALL:
- /* These special syscalls need to be simulated by SPIM */
- switch(R[REG_V0])
- {
- case SYS_exit:
- return(0);
- break;
-
- case SYS_sbrk:
- {
- expand_data (R[REG_A0]);
- R[REG_RES] = program_break;
- program_break += R[REG_A0];
- break;
- }
-
- case SYS_brk:
- /* Round up to 4096 byte (page) boundary */
- if (((int) R[REG_A0] - (int) data_top) > 0)
- expand_data (ROUND(R[REG_A0], 4096) - (int) data_top);
- R[REG_RES] = program_break;
- program_break = ROUND (R[REG_A0], 4096);
- break;
-
- default:
- run_error (sprintf(mess_buff,
- "Unknown special system call: %d\n", R[REG_V0]));
- break;
- }
- break;
-
- default:
- run_error(sprintf(mess_buff,
- "Unknown type for syscall: %d\n", R[REG_V0]));
- break;
- }
- }
- else
- #endif
- {
- /* It is a true pleasure to write an operating system in a
- high-level language! */
-
- /* Dummy system calls for SPIMs assembly option */
- switch (R[REG_V0])
- {
- case PRINT_INT_SYSCALL:
- sprintf(mess_buff, "%d", R[REG_A0]);
- write_output (console_out, mess_buff);
- break;
-
- case PRINT_FLOAT_SYSCALL:
- {
- float val = FPR_S (REG_FA0);
-
- sprintf(mess_buff, "%f", val);
- write_output (console_out, mess_buff);
- break;
- }
-
- case PRINT_DOUBLE_SYSCALL:
- sprintf(mess_buff, "%f", FPR[REG_FA0/2]);
- write_output (console_out, mess_buff);
- break;
-
- case PRINT_STRING_SYSCALL:
- sprintf(mess_buff, "%s", MEM_ADDRESS (R[REG_A0]));
- write_output (console_out, mess_buff);
- break;
-
- case PRINT_CHARACTER_SYSCALL:
- sprintf(mess_buff, "%c", R[REG_A0]);
- write_output (console_out, mess_buff);
- break;
-
- case READ_INT_SYSCALL:
- {
- static char str [256];
-
- read_input (str, 256);
- R[REG_RES] = atol (str);
- break;
- }
-
- case READ_FLOAT_SYSCALL:
- {
- static char str [256];
-
- read_input (str, 256);
- FGR [REG_FRES] = (float) atof (str);
- break;
- }
-
- case READ_DOUBLE_SYSCALL:
- {
- static char str [256];
-
- read_input (str, 256);
- FPR [REG_FRES] = atof (str);
- break;
- }
-
- case READ_STRING_SYSCALL:
- {
- read_input ((char *) MEM_ADDRESS (R[REG_A0]), R[REG_A1]);
- break;
- }
-
- case READ_CHARACTER_SYSCALL:
- {
- char str[2];
-
- read_input (str , 2);
- if (*str == '\0')
- *str = '\n'; /* makes xspim = spim */
- R[REG_V0] = (long)*str;
- break;
- }
-
- case SBRK_SYSCALL:
- {
- mem_addr x = data_top;
- expand_data (R[REG_A0]);
- R[REG_RES] = x;
- break;
- }
-
- case EXIT_SYSCALL:
- return (0);
-
- default:
- sprintf(mess_buff, "Unknown system call: %d\n",
- R[REG_V0]);
- run_error (mess_buff);
- break;
- }
- }
- break;
-
- case Y_TLBP_OP:
- case Y_TLBR_OP:
- case Y_TLBWI_OP:
- case Y_TLBWR_OP:
- fatal_error ("Unimplemented operation\n");
- break;
-
- case Y_XOR_OP:
- R[RD (inst)] = R[RS (inst)] ^ R[RT (inst)];
- break;
-
- case Y_XORI_OP:
- R[RT (inst)] = R[RS (inst)] ^ (0xffff & IMM (inst));
- break;
-
-
- /* FPA Operations */
-
-
- case Y_ABS_S_OP:
- SET_FPR_S (FD (inst), fabs (FPR_S (FS (inst))));
- break;
-
- case Y_ABS_D_OP:
- SET_FPR_D (FD (inst), fabs (FPR_D (FS (inst))));
- break;
-
- case Y_ADD_S_OP:
- SET_FPR_S (FD (inst), FPR_S (FS (inst)) + FPR_S (FT (inst)));
- /* Should trap on inexact/overflow/underflow */
- break;
-
- case Y_ADD_D_OP:
- SET_FPR_D (FD (inst), FPR_D (FS (inst)) + FPR_D (FT (inst)));
- /* Should trap on inexact/overflow/underflow */
- break;
-
- case Y_BC1F_OP:
- BRANCH_INST (FpCond == 0, PC + (SIGN_EX (IOFFSET (inst)) << 2));
- break;
-
- case Y_BC1T_OP:
- BRANCH_INST (FpCond == 1, PC + (SIGN_EX (IOFFSET (inst)) << 2));
- break;
-
- case Y_C_F_S_OP:
- case Y_C_UN_S_OP:
- case Y_C_EQ_S_OP:
- case Y_C_UEQ_S_OP:
- case Y_C_OLE_S_OP:
- case Y_C_ULE_S_OP:
- case Y_C_SF_S_OP:
- case Y_C_NGLE_S_OP:
- case Y_C_SEQ_S_OP:
- case Y_C_NGL_S_OP:
- case Y_C_LT_S_OP:
- case Y_C_NGE_S_OP:
- case Y_C_LE_S_OP:
- case Y_C_NGT_S_OP:
- {
- float v1 = FPR_S (FS (inst)), v2 = FPR_S (FT (inst));
- double dv1 = v1, dv2 = v2;
- int less, equal, unordered;
- int cond = COND (inst);
-
- if (NaN (dv1) || NaN (dv2))
- {
- less = 0;
- equal = 0;
- unordered = 1;
- if (cond & COND_IN)
- RAISE_EXCEPTION (INVALID_EXCEPT, break);
- }
- else
- {
- less = v1 < v2;
- equal = v1 == v2;
- unordered = 0;
- }
- FpCond = 0;
- if (cond & COND_LT)
- FpCond |= less;
- if (cond & COND_EQ)
- FpCond |= equal;
- if (cond & COND_UN)
- FpCond |= unordered;
- }
- break;
-
- case Y_C_F_D_OP:
- case Y_C_UN_D_OP:
- case Y_C_EQ_D_OP:
- case Y_C_UEQ_D_OP:
- case Y_C_OLE_D_OP:
- case Y_C_ULE_D_OP:
- case Y_C_SF_D_OP:
- case Y_C_NGLE_D_OP:
- case Y_C_SEQ_D_OP:
- case Y_C_NGL_D_OP:
- case Y_C_LT_D_OP:
- case Y_C_NGE_D_OP:
- case Y_C_LE_D_OP:
- case Y_C_NGT_D_OP:
- {
- double v1 = FPR_D (FS (inst)), v2 = FPR_D (FT (inst));
- int less, equal, unordered;
- int cond = COND (inst);
-
- if (NaN (v1) || NaN (v2))
- {
- less = 0;
- equal = 0;
- unordered = 1;
- if (cond & COND_IN)
- RAISE_EXCEPTION (INVALID_EXCEPT, break);
- }
- else
- {
- less = v1 < v2;
- equal = v1 == v2;
- unordered = 0;
- }
- FpCond = 0;
- if (cond & COND_LT)
- FpCond |= less;
- if (cond & COND_EQ)
- FpCond |= equal;
- if (cond & COND_UN)
- FpCond |= unordered;
- }
- break;
-
- case Y_CFC1_OP:
- R[RT (inst)] = FCR[RD (inst)]; /* RD not FS */
- break;
-
- case Y_CTC1_OP:
- FCR[RD (inst)] = R[RT (inst)]; /* RD not FS */
- break;
-
- case Y_CVT_D_S_OP:
- {
- double val = FPR_S (FS (inst));
-
- SET_FPR_D (FD (inst), val);
- break;
- }
-
- case Y_CVT_D_W_OP:
- {
- double val = FPR_W (FS (inst));
-
- SET_FPR_D (FD (inst), val);
- break;
- }
-
- case Y_CVT_S_D_OP:
- {
- float val = FPR_D (FS (inst));
-
- SET_FPR_S (FD (inst), val);
- break;
- }
-
- case Y_CVT_S_W_OP:
- {
- float val = FPR_W (FS (inst));
-
- SET_FPR_S (FD (inst), val);
- break;
- }
-
- case Y_CVT_W_D_OP:
- {
- int val = FPR_D (FS (inst));
-
- SET_FPR_W (FD (inst), val);
- break;
- }
-
- case Y_CVT_W_S_OP:
- {
- int val = FPR_S (FS (inst));
-
- SET_FPR_W (FD (inst), val);
- break;
- }
-
- case Y_DIV_S_OP:
- SET_FPR_S (FD (inst), FPR_S (FS (inst)) / FPR_S (FT (inst)));
- break;
-
- case Y_DIV_D_OP:
- SET_FPR_D (FD (inst), FPR_D (FS (inst)) / FPR_D (FT (inst)));
- break;
-
- case Y_LWC1_OP:
- {
- reg_word *wp = (reg_word *) &FGR [FT (inst)];
-
- LOAD_INST (READ_MEM_WORD, R[BASE (inst)] + IOFFSET (inst), wp,
- 0xffffffff);
- break;
- }
-
- case Y_MFC1_OP:
- {
- float val = FGR [RD (inst)]; /* RD not FS */
- reg_word *vp = (reg_word *) &val;
-
- R[RT (inst)] = *vp; /* Fool coercion */
- break;
- }
-
- case Y_MOV_S_OP:
- SET_FPR_S (FD (inst), FPR_S (FS (inst)));
- break;
-
- case Y_MOV_D_OP:
- SET_FPR_D (FD (inst), FPR_D (FS (inst)));
- break;
-
- case Y_MTC1_OP:
- {
- reg_word word = R[RT (inst)];
- float *wp = (float *) &word;
-
- FGR [RD (inst)] = *wp; /* RD not FS, fool coercion */
- break;
- }
-
- case Y_MUL_S_OP:
- SET_FPR_S (FD (inst), FPR_S (FS (inst)) * FPR_S (FT (inst)));
- break;
-
- case Y_MUL_D_OP:
- SET_FPR_D (FD (inst), FPR_D (FS (inst)) * FPR_D (FT (inst)));
- break;
-
- case Y_NEG_S_OP:
- SET_FPR_S (FD (inst), -FPR_S (FS (inst)));
- break;
-
- case Y_NEG_D_OP:
- SET_FPR_D (FD (inst), -FPR_D (FS (inst)));
- break;
-
- case Y_SUB_S_OP:
- SET_FPR_S (FD (inst), FPR_S (FS (inst)) - FPR_S (FT (inst)));
- break;
-
- case Y_SUB_D_OP:
- SET_FPR_D (FD (inst), FPR_D (FS (inst)) - FPR_D (FT (inst)));
- break;
-
- case Y_SWC1_OP:
- {
- float val = FGR [RT (inst)];
- reg_word *vp = (reg_word *) &val;
-
- SET_MEM_WORD (R[BASE (inst)] + IOFFSET (inst), *vp);
- break;
- }
- default:
- sprintf(mess_buff, "Unknown instruction type: %d\n",
- OPCODE (inst));
- fatal_error (mess_buff);
- break;
- }
-
- PC += BYTES_PER_WORD;
-
- if (exception_occurred && ((Cause >> 2) > LAST_REAL_EXCEPT))
- EPC = PC - BYTES_PER_WORD;
-
- if (exception_occurred && !quiet)
- {
- sprintf(mess_buff, "Exception occurred at PC=0x%08x\n", EPC);
- error (mess_buff);
-
- switch (Cause >> 2)
- {
- case INT_EXCPT:
- error (" Interrupt exception");
- break;
-
- case ADDRL_EXCPT:
- sprintf(mess_buff,
- " Unaligned address in inst/data fetch: 0x%08x\n",
- BadVAddr);
- error (mess_buff);
- break;
-
- case ADDRS_EXCPT:
- sprintf(mess_buff, " Unaligned address in store: 0x%08x\n",
- BadVAddr);
- error (mess_buff);
- break;
-
- case IBUS_EXCPT:
- sprintf(mess_buff, " Bad address in text read: 0x%08x\n",
- BadVAddr);
- error (mess_buff);
- break;
-
- case DBUS_EXCPT:
- sprintf(mess_buff,
- " Bad address in data/stack read: 0x%08x\n", BadVAddr);
- error (mess_buff);
- break;
-
- case BKPT_EXCPT:
- break;
-
- case SYSCALL_EXCPT:
- error (" Error in syscall");
- break;
-
- case RI_EXCPT:
- error (" Reserved instruction execution");
- break;
-
- case OVF_EXCPT:
- error (" Arithmetic overflow");
- break;
-
- case CLOCK_EXCPT:
- error (" Clock interrupt\n");
- break;
-
- case IO_EXCPT:
- error (" IO interrupt\n");
- break;
-
- default:
- sprintf(mess_buff, "Unknown exception: %d\n", Cause >> 2);
- error (mess_buff);
- break;
- }
- exception_occurred = 0;
- PC = EXCEPTION_ADDR;
- }
- } /* End of while */
-
- /* Executed enought steps, return, but are able to continue. */
- return (1);
- }
-
- /* Multiply two 32-bit numbers, V1 and V2, to produce a 64 bit result in
- the HI/LO registers. The algorithm is high-school math:
-
- A B
- x C D
- ------
- AD || BD
- AC || CB || 0
-
- where A and B are the high and low short words of V1, C and D are the short
- words of V2, AD is the product of A and D, and X || Y is (X << 16) + Y.
- Since the algorithm is programmed in C, we need to be careful not to
- overflow. */
-
- static void long_multiply (reg_word v1, reg_word v2)
- {
- register long a, b, c, d;
- register long x, y;
-
- a = (v1 >> 16) & 0xffff;
- b = v1 & 0xffff;
- c = (v2 >> 16) & 0xffff;
- d = v2 & 0xffff;
-
- LO = b * d; /* BD */
- x = a * d + c * b; /* AD + CB */
- y = ((LO >> 16) & 0xffff) + x;
-
- LO = (LO & 0xffff) | ((y & 0xffff) << 16);
- HI = (y >> 16) & 0xffff;
-
- HI += a * c; /* AC */
- }
-