📄 op_helper.c
字号:
/* * MIPS emulation helpers for qemu. * * Copyright (c) 2004-2005 Jocelyn Mayer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include "exec.h"#define MIPS_DEBUG_DISAS#define GETPC() (__builtin_return_address(0))/*****************************************************************************//* Exceptions processing helpers */void cpu_loop_exit(void){ longjmp(env->jmp_env, 1);}void do_raise_exception_err (uint32_t exception, int error_code){#if 1 if (logfile && exception < 0x100) fprintf(logfile, "%s: %d %d\n", __func__, exception, error_code);#endif env->exception_index = exception; env->error_code = error_code; T0 = 0; cpu_loop_exit();}void do_raise_exception (uint32_t exception){ do_raise_exception_err(exception, 0);}void do_restore_state (void *pc_ptr){ TranslationBlock *tb; unsigned long pc = (unsigned long) pc_ptr; tb = tb_find_pc (pc); cpu_restore_state (tb, env, pc, NULL);}void do_raise_exception_direct (uint32_t exception){ do_restore_state (GETPC ()); do_raise_exception_err (exception, 0);}#define MEMSUFFIX _raw#include "op_helper_mem.c"#undef MEMSUFFIX#if !defined(CONFIG_USER_ONLY)#define MEMSUFFIX _user#include "op_helper_mem.c"#undef MEMSUFFIX#define MEMSUFFIX _kernel#include "op_helper_mem.c"#undef MEMSUFFIX#endif/* 64 bits arithmetic for 32 bits hosts */#if (HOST_LONG_BITS == 32)static inline uint64_t get_HILO (void){ return ((uint64_t)env->HI << 32) | (uint64_t)env->LO;}static inline void set_HILO (uint64_t HILO){ env->LO = HILO & 0xFFFFFFFF; env->HI = HILO >> 32;}void do_mult (void){ set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);}void do_multu (void){ set_HILO((uint64_t)T0 * (uint64_t)T1);}void do_madd (void){ int64_t tmp; tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); set_HILO((int64_t)get_HILO() + tmp);}void do_maddu (void){ uint64_t tmp; tmp = ((uint64_t)T0 * (uint64_t)T1); set_HILO(get_HILO() + tmp);}void do_msub (void){ int64_t tmp; tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); set_HILO((int64_t)get_HILO() - tmp);}void do_msubu (void){ uint64_t tmp; tmp = ((uint64_t)T0 * (uint64_t)T1); set_HILO(get_HILO() - tmp);}#endif#if defined(CONFIG_USER_ONLY) void do_mfc0 (int reg, int sel){ cpu_abort(env, "mfc0 reg=%d sel=%d\n", reg, sel);}void do_mtc0 (int reg, int sel){ cpu_abort(env, "mtc0 reg=%d sel=%d\n", reg, sel);}void do_tlbwi (void){ cpu_abort(env, "tlbwi\n");}void do_tlbwr (void){ cpu_abort(env, "tlbwr\n");}void do_tlbp (void){ cpu_abort(env, "tlbp\n");}void do_tlbr (void){ cpu_abort(env, "tlbr\n");}#else/* CP0 helpers */void do_mfc0 (int reg, int sel){ const unsigned char *rn; if (sel != 0 && reg != 16 && reg != 28) { rn = "invalid"; goto print; } switch (reg) { case 0: T0 = env->CP0_index; rn = "Index"; break; case 1: T0 = cpu_mips_get_random(env); rn = "Random"; break; case 2: T0 = env->CP0_EntryLo0; rn = "EntryLo0"; break; case 3: T0 = env->CP0_EntryLo1; rn = "EntryLo1"; break; case 4: T0 = env->CP0_Context; rn = "Context"; break; case 5: T0 = env->CP0_PageMask; rn = "PageMask"; break; case 6: T0 = env->CP0_Wired; rn = "Wired"; break; case 8: T0 = env->CP0_BadVAddr; rn = "BadVaddr"; break; case 9: T0 = cpu_mips_get_count(env); rn = "Count"; break; case 10: T0 = env->CP0_EntryHi; rn = "EntryHi"; break; case 11: T0 = env->CP0_Compare; rn = "Compare"; break; case 12: T0 = env->CP0_Status; if (env->hflags & MIPS_HFLAG_UM) T0 |= (1 << CP0St_UM); if (env->hflags & MIPS_HFLAG_ERL) T0 |= (1 << CP0St_ERL); if (env->hflags & MIPS_HFLAG_EXL) T0 |= (1 << CP0St_EXL); rn = "Status"; break; case 13: T0 = env->CP0_Cause; rn = "Cause"; break; case 14: T0 = env->CP0_EPC; rn = "EPC"; break; case 15: T0 = env->CP0_PRid; rn = "PRid"; break; case 16: switch (sel) { case 0: T0 = env->CP0_Config0; rn = "Config"; break; case 1: T0 = env->CP0_Config1; rn = "Config1"; break; default: rn = "Unknown config register"; break; } break; case 17: T0 = env->CP0_LLAddr >> 4; rn = "LLAddr"; break; case 18: T0 = env->CP0_WatchLo; rn = "WatchLo"; break; case 19: T0 = env->CP0_WatchHi; rn = "WatchHi"; break; case 23: T0 = env->CP0_Debug; if (env->hflags & MIPS_HFLAG_DM) T0 |= 1 << CP0DB_DM; rn = "Debug"; break; case 24: T0 = env->CP0_DEPC; rn = "DEPC"; break; case 28: switch (sel) { case 0: T0 = env->CP0_TagLo; rn = "TagLo"; break; case 1: T0 = env->CP0_DataLo; rn = "DataLo"; break; default: rn = "unknown sel"; break; } break; case 30: T0 = env->CP0_ErrorEPC; rn = "ErrorEPC"; break; case 31: T0 = env->CP0_DESAVE; rn = "DESAVE"; break; default: rn = "unknown"; break; } print:#if defined MIPS_DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n", env->PC, rn, T0, reg, sel); }#endif return;}void do_mtc0 (int reg, int sel){ const unsigned char *rn; uint32_t val, old, mask; if (sel != 0 && reg != 16 && reg != 28) { val = -1; old = -1; rn = "invalid"; goto print; } switch (reg) { case 0: val = (env->CP0_index & 0x80000000) | (T0 & 0x0000000F); old = env->CP0_index; env->CP0_index = val; rn = "Index"; break; case 2: val = T0 & 0x03FFFFFFF; old = env->CP0_EntryLo0; env->CP0_EntryLo0 = val; rn = "EntryLo0"; break; case 3: val = T0 & 0x03FFFFFFF; old = env->CP0_EntryLo1; env->CP0_EntryLo1 = val; rn = "EntryLo1"; break; case 4: val = (env->CP0_Context & 0xFF000000) | (T0 & 0x00FFFFF0); old = env->CP0_Context; env->CP0_Context = val; rn = "Context"; break; case 5: val = T0 & 0x01FFE000; old = env->CP0_PageMask; env->CP0_PageMask = val; rn = "PageMask"; break; case 6: val = T0 & 0x0000000F; old = env->CP0_Wired; env->CP0_Wired = val; rn = "Wired"; break; case 9: val = T0; old = cpu_mips_get_count(env); cpu_mips_store_count(env, val); rn = "Count"; break; case 10: val = T0 & 0xFFFFF0FF; old = env->CP0_EntryHi; env->CP0_EntryHi = val; /* If the ASID changes, flush qemu's TLB. */ if ((old & 0xFF) != (val & 0xFF)) tlb_flush (env, 1); rn = "EntryHi"; break; case 11:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -