📄 opcodes.c
字号:
/* * Copyright (C) 1996-1998 by the Board of Trustees * of Leland Stanford Junior University. * * This file is part of the SimOS distribution. * See LICENSE file for terms of the license. * *//**************************************************************** * opcodes.c * * Implementation of each MIPS instruction and declaration of the * table used to decode them. * * $Author: bosch $ * $Date: 1998/02/10 00:31:48 $ *****************************************************************/#include "simstats.h"#include "opcodes.h"#include "cpu.h"#include "cpu_state.h"#include "sim_error.h"#include "cp0.h"#include "fpu.h"#include "memref.h"#include "cpu_stats.h"#include "hw_events.h"#include "mdmx.h"#ifdef SOLO# include "solo.h"#endif#define OP(NAME) \Result NAME(Inst instr, CPUState *P)MipsOpcodeDesc mipsSpecOpcodes[];MipsOpcodeDesc mipsBcondOpcodes[];/* * CHECK_64BIT_ALLOWED() - Check to see if 64bit instructions are permitted, * if not raise an exception. */#if defined(SIM_MIPS64)#define CHECK_64BIT_ALLOWED(_p) \ if ((_p)->is32bitMode && !IS_KERNEL_MODE((_p))) { \ EXCEPTION((_p), EXC_II); \ return FAILURE; \ }#else#define CHECK_64BIT_ALLOWED(_p) \ if (1) { \ EXCEPTION((_p), EXC_II); \ return FAILURE; \ }#endif#define CURRENT_PC(_cpu) (pePtr[_cpu]->PC)extern Result MipsyReadMem(VA, void *, RefSize, RefFlavor);extern Result MipsyWriteMem(VA, void *, RefSize, RefFlavor);/* extern Result MipsyWriteByte(VA, byte); extern Result MipsyWriteHalf(VA, short); extern Result MipsyWriteWord(VA, uint data, RefFlavor); extern Result MipsyWriteDouble(VA, uint64, RefFlavor); */extern int FlashliteWQFull(int);static void LongMultiply32 (CPUState *, Reg32, Reg32);static void LongMultiply64 (CPUState *, Reg64, Reg64);static Result Prefetch(CPUState *, VA, uint);static Result CacheOp(CPUState *, uint, VA, PA);extern PA LLAddrs[MIPSY_MAX_CPUS];extern int numLLactive;/**************************************************************** * M A J O R O P C O D E S *****************************************************************/OP(specOp) { uint specialFunc = FUNC(instr); return mipsSpecOpcodes[specialFunc].func(instr, P);}OP(bcondOp) { uint bcondFunc = RT(instr); return mipsBcondOpcodes[bcondFunc].func(instr, P);}OP(addiOp){ int immediate = IMMED(instr); Reg_s contents_rs = P->R[RS(instr)]; Reg32_s result32 = (Reg32_s)contents_rs + SIGN_EXTEND32(16, immediate); if (ARITH_OVFL32(result32, (Reg32_s)contents_rs, SIGN_EXTEND32(16, immediate))) { EXCEPTION(P, EXC_OV); return FAILURE; } /* Don't write this value if there was an overflow */ P->R[RT(instr)] = result32; return SUCCESS;}OP(addiuOp){ int immediate = IMMED(instr); Reg_s contents_rs = P->R[RS(instr)]; P->R[RT(instr)] = (Reg32_s)contents_rs + SIGN_EXTEND32(16, immediate); return SUCCESS;}OP(andiOp){ int immediate = IMMED(instr); Reg_s contents_rs = P->R[RS(instr)]; P->R[RT(instr)] = contents_rs & (0x0000ffff & immediate); return SUCCESS;}OP(beqOp){ int immediate = IMMED(instr); Reg_s contents_rs = P->R[RS(instr)]; if (contents_rs == P->R[RT(instr)]) { P->branchTarget = P->nPC + (SIGN_EXTEND32(18, (immediate << 2))); P->branchStatus = BranchStatus_taken; } else { P->branchStatus = BranchStatus_nottaken; } return SUCCESS;}OP(beqlOp){ int immediate = IMMED(instr); Reg_s contents_rs = P->R[RS(instr)]; if (contents_rs == P->R[RT(instr)]) { P->branchTarget = P->nPC + (SIGN_EXTEND32(18, (immediate << 2))); P->branchStatus = BranchStatus_taken; } else { /* Skip instruction in delay slot */ P->nPC = P->nPC + 4; } return SUCCESS;}OP(bgtzOp){ int immediate = IMMED(instr); Reg_s contents_rs = P->R[RS(instr)]; if (!(SIGN_BIT(contents_rs)) && (contents_rs != 0)) { P->branchTarget = P->nPC + (SIGN_EXTEND32(18, (immediate << 2))); P->branchStatus = BranchStatus_taken; } else { P->branchStatus = BranchStatus_nottaken; } return SUCCESS;}OP(bgtzlOp){ int immediate = IMMED(instr); Reg_s contents_rs = P->R[RS(instr)]; if (!(SIGN_BIT(contents_rs)) && (contents_rs != 0)) { P->branchTarget = P->nPC + (SIGN_EXTEND32(18, (immediate << 2))); P->branchStatus = BranchStatus_taken; } else { /* Skip instruction in delay slot */ P->nPC = P->nPC + 4; } return SUCCESS;}OP(blezOp){ int immediate = IMMED(instr); Reg_s contents_rs = P->R[RS(instr)]; if ((SIGN_BIT(contents_rs) || (contents_rs == 0))) { P->branchTarget = P->nPC + (SIGN_EXTEND32(18, (immediate << 2))); P->branchStatus = BranchStatus_taken; } else { P->branchStatus = BranchStatus_nottaken; } return SUCCESS;}OP(blezlOp){ int immediate = IMMED(instr); Reg_s contents_rs = P->R[RS(instr)]; if ((SIGN_BIT(contents_rs) || (contents_rs == 0))) { P->branchTarget = P->nPC + (SIGN_EXTEND32(18, (immediate << 2))); P->branchStatus = BranchStatus_taken; } else { /* Skip instruction in delay slot */ P->nPC = P->nPC + 4; } return SUCCESS;}OP(bneOp){ int immediate = IMMED(instr); Reg_s contents_rs = P->R[RS(instr)]; if (contents_rs != P->R[RT(instr)]) { P->branchTarget = P->nPC + (SIGN_EXTEND32(18, (immediate << 2))); P->branchStatus = BranchStatus_taken; } else { P->branchStatus = BranchStatus_nottaken; } return SUCCESS;}OP(bnelOp){ int immediate = IMMED(instr); Reg_s contents_rs = P->R[RS(instr)]; if (contents_rs != P->R[RT(instr)]) { P->branchTarget = P->nPC + (SIGN_EXTEND32(18, (immediate << 2))); P->branchStatus = BranchStatus_taken; } else { /* Skip instruction in delay slot */ P->nPC = P->nPC + 4; } return SUCCESS;}OP(cacheOp){ int immediate = IMMED(instr); /* Be careful with this one. Mipsy's caches are physically indexed. */ VA vAddr; PA pAddr; uint tlbFlavor = TLB_READING; void *bdoorAddr = 0; Reg_s contents_rs = P->R[RS(instr)]; #ifdef IRIX6_4 if (!IS_KERNEL_MODE(P)) { /* is unusable only in kernel and or when the cu0 bit is set. */ CauseReg causeReg; StatusReg statusReg; statusReg.ts_data = P->CP0[C0_SR]; if (!statusReg.s32.ts_cu0) { causeReg.tc_data = P->CP0[C0_CAUSE]; causeReg.s32.tc_ce = 0; P->CP0[C0_CAUSE] = causeReg.tc_data; EXCEPTION(P, EXC_CPU); return FAILURE; } }#endif /* This is a reserved instruction, but I'm allowing it to be used in user mode. */ vAddr = SIGN_EXTEND(16, immediate) + contents_rs; if (TranslateVirtual(P, vAddr, &pAddr, &tlbFlavor,&bdoorAddr) != SUCCESS) { if (P->cpuStatus != cpu_running) { P->stalledInst = instr; STATS_SET(P->myNum, stallStart, MipsyReadTime(P->myNum)); } return FAILURE; } if (CacheOp(P, instr, vAddr, pAddr) != SUCCESS) { return FAILURE; } return SUCCESS;}OP(daddiOp) { int immediate = IMMED(instr); Reg_s contents_rs = P->R[RS(instr)]; Reg64_s result64 = contents_rs + SIGN_EXTEND64(16, immediate); CHECK_64BIT_ALLOWED(P); if (ARITH_OVFL64(result64, contents_rs, SIGN_EXTEND64(16, immediate))) { EXCEPTION(P, EXC_OV); return FAILURE; } /* Don't write this value if there was an overflow */ P->R[RT(instr)] = result64; return SUCCESS;}OP(daddiuOp){ int immediate = IMMED(instr); Reg_s contents_rs = P->R[RS(instr)]; CHECK_64BIT_ALLOWED(P); P->R[RT(instr)] = contents_rs + SIGN_EXTEND64(16,immediate); return SUCCESS; }OP(jOp){ int immediate = IMMED(instr); Reg_s contents_rs = P->R[RS(instr)]; P->branchTarget = (P->nPC & (Reg32_s)0xf0000000) | (TARGET(instr) << 2); P->branchStatus = BranchStatus_taken; return SUCCESS;}OP(jalOp){ int immediate = IMMED(instr); Reg_s contents_rs = P->R[RS(instr)]; P->R[REG_RA] = P->nPC + 4; P->branchTarget = (P->nPC & (Reg32_s)0xf0000000) | (TARGET(instr) << 2); P->branchStatus = BranchStatus_taken; return SUCCESS; }OP(lbOp){ int immediate = IMMED(instr); Reg_s contents_rs = P->R[RS(instr)]; byte data; VA vAddr; Reg base = P->R[RS(instr)]; vAddr = SIGN_EXTEND(16, immediate) + base; if (MipsyReadMem(vAddr, &data, BYTE_SZ, NO_FLAVOR) != SUCCESS) { if (P->cpuStatus != cpu_running) { P->stalledInst = instr; STATS_SET(P->myNum, stallStart, MipsyReadTime(P->myNum)); } return FAILURE; } else { P->R[RT(instr)] = SIGN_EXTEND(8, data); return SUCCESS; }}OP(lbuOp){ int immediate = IMMED(instr); Reg_s contents_rs = P->R[RS(instr)]; byte data; VA vAddr; Reg base = P->R[RS(instr)]; vAddr = SIGN_EXTEND(16, immediate) + base; if (MipsyReadMem(vAddr, &data, BYTE_SZ, NO_FLAVOR) != SUCCESS) { if (P->cpuStatus != cpu_running) { P->stalledInst = instr; STATS_SET(P->myNum, stallStart, MipsyReadTime(P->myNum)); } return FAILURE; } else { P->R[RT(instr)] = 0x000000ff & data; return SUCCESS; }}OP(lhOp){ int immediate = IMMED(instr); short data; VA vAddr; Reg base = P->R[RS(instr)]; Reg_s contents_rs = P->R[RS(instr)]; vAddr = SIGN_EXTEND(16, immediate) + base; if (vAddr & 0x00000001) { RECORD_EXCEPTION(P, EXC_RADE, E_VEC, vAddr, P->CP0[C0_TLBHI], P->CP0[C0_CTXT], P->CP0[C0_XCTXT]); /* EXCEPTION(P->myNum,EXC_RADE); */ return FAILURE; } if (MipsyReadMem(vAddr, &data, HALF_SZ, NO_FLAVOR) != SUCCESS) { if (P->cpuStatus != cpu_running) { P->stalledInst = instr; STATS_SET(P->myNum, stallStart, MipsyReadTime(P->myNum)); } return FAILURE; } else { P->R[RT(instr)] = SIGN_EXTEND(16,data); return SUCCESS; }}OP(lhuOp){ int immediate = IMMED(instr); Reg_s contents_rs = P->R[RS(instr)]; short data; VA vAddr; Reg base = P->R[RS(instr)]; vAddr = SIGN_EXTEND(16, immediate) + base; if (vAddr & 0x00000001) { RECORD_EXCEPTION(P, EXC_RADE, E_VEC, vAddr, P->CP0[C0_TLBHI], P->CP0[C0_CTXT], P->CP0[C0_XCTXT]); /* EXCEPTION(P->myNum,EXC_RADE); */ return FAILURE; } if (MipsyReadMem(vAddr, &data, HALF_SZ, NO_FLAVOR) != SUCCESS) { if (P->cpuStatus != cpu_running) { P->stalledInst = instr; STATS_SET(P->myNum, stallStart, MipsyReadTime(P->myNum)); } return FAILURE; } else { P->R[RT(instr)] = 0x0000ffff & data; return SUCCESS; }}OP(luiOp){ int immediate = IMMED(instr); P->R[RT(instr)] = immediate << 16; return SUCCESS;}OP(llOp){ int immediate = IMMED(instr); Reg32_s data; VA vAddr; Reg base = P->R[RS(instr)]; vAddr = SIGN_EXTEND(16, immediate) + base; if (vAddr & 0x00000003) { RECORD_EXCEPTION(P, EXC_RADE, E_VEC, vAddr, P->CP0[C0_TLBHI], P->CP0[C0_CTXT], P->CP0[C0_XCTXT]); /* EXCEPTION(P->myNum,EXC_RADE); */ return FAILURE; } if (UNCACHED_LL_SC) { if (!P->LLbit) { numLLactive++; } } P->LLbit = 1; if (MipsyReadMem(vAddr, &data, WORD_SZ, LL_FLAVOR) != SUCCESS) { if (P->cpuStatus != cpu_running) { P->stalledInst = instr; STATS_SET(P->myNum, stallStart, MipsyReadTime(P->myNum)); STATS_SET(P->myNum, syncStallStart, MipsyReadTime(P->myNum)); if (UNCACHED_LL_SC) { LLAddrs[P->myNum] = (PA) -1; if (P->LLbit) { numLLactive--; } } P->LLbit = 0; } return FAILURE; } else { P->R[RT(instr)] = data; STATS_INC(P->myNum, syncStats.lls, 1); STATS_ADD_INTERVAL(P->myNum, syncStats.llStallTime, syncStallStart); if (data & 1) STATS_INC(P->myNum, syncStats.llNonZero, 1); } return SUCCESS;}OP(lldOp){ int immediate = IMMED(instr); Reg64 data; VA vAddr; Reg base = P->R[RS(instr)]; CHECK_64BIT_ALLOWED(P); vAddr = SIGN_EXTEND(16, immediate) + base; if (vAddr & 0x00000007) { RECORD_EXCEPTION(P, EXC_RADE, E_VEC, vAddr, P->CP0[C0_TLBHI], P->CP0[C0_CTXT], P->CP0[C0_XCTXT]); return FAILURE; } if (UNCACHED_LL_SC) { if (!P->LLbit) { numLLactive++; } } P->LLbit = 1; if (MipsyReadMem(vAddr, &data, DOUBLE_SZ, LL_FLAVOR) != SUCCESS) { if (P->cpuStatus != cpu_running) { P->stalledInst = instr; STATS_SET(P->myNum, stallStart, MipsyReadTime(P->myNum)); STATS_SET(P->myNum, syncStallStart, MipsyReadTime(P->myNum)); if (UNCACHED_LL_SC) { LLAddrs[P->myNum] = (PA) -1; if (P->LLbit) { numLLactive--; } } P->LLbit = 0; } return FAILURE; } else { P->R[RT(instr)] = data; STATS_INC(P->myNum, syncStats.lls, 1); STATS_ADD_INTERVAL(P->myNum, syncStats.llStallTime, syncStallStart); if (data & 1) STATS_INC(P->myNum, syncStats.llNonZero, 1); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -