📄 cp0.c
字号:
/* * Cisco 7200 (Predator) simulation platform. * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) * * MIPS Coprocessor 0 (System Coprocessor) implementation. * We don't use the JIT here, since there is no high performance needed. */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/mman.h>#include <fcntl.h>#include "rbtree.h"#include "mips64.h"#include "dynamips.h"#include "memory.h"#include "device.h"#include "cp0.h"/* MIPS cp0 registers names */char *mips64_cp0_reg_names[MIPS64_CP0_REG_NR] = { "index" , "random", "entry_lo0", "entry_lo1", "context", "pagemask", "wired", "info", "badvaddr", "count", "entry_hi", "compare", "status", "cause", "epc", "prid", "config", "ll_addr", "watch_lo", "watch_hi", "xcontext", "cp0_r21", "cp0_r22", "cp0_r23", "cp0_r24", "cp0_r25", "ecc", "cache_err", "tag_lo", "tag_hi", "err_epc", "cp0_r31",};/* Get cp0 register index given its name */int cp0_get_reg_index(char *name){ int i; for(i=0;i<MIPS64_CP0_REG_NR;i++) if (!strcmp(mips64_cp0_reg_names[i],name)) return(i); return(-1);}/* Get the CPU operating mode (User,Supervisor or Kernel) - inline version */static forced_inline u_int cp0_get_mode_inline(cpu_mips_t *cpu){ mips_cp0_t *cp0 = &cpu->cp0; u_int cpu_mode; cpu_mode = cp0->reg[MIPS_CP0_STATUS] >> MIPS_CP0_STATUS_KSU_SHIFT; cpu_mode &= MIPS_CP0_STATUS_KSU_MASK; return(cpu_mode);}/* Get the CPU operating mode (User,Supervisor or Kernel) */u_int cp0_get_mode(cpu_mips_t *cpu){ return(cp0_get_mode_inline(cpu));}/* Check that we are running in kernel mode */int cp0_check_kernel_mode(cpu_mips_t *cpu){ u_int cpu_mode; cpu_mode = cp0_get_mode(cpu); if (cpu_mode != MIPS_CP0_STATUS_KM) { /* XXX Branch delay slot */ mips64_trigger_exception(cpu,MIPS_CP0_CAUSE_ILLOP,0); return(1); } return(0);}/* Get value of random register */static inline u_int cp0_get_random_reg(cpu_mips_t *cpu){ u_int wired; /* We use the virtual count register as a basic "random" value */ wired = cpu->cp0.reg[MIPS_CP0_WIRED]; return(wired + (cpu->cp0_virt_cnt_reg % (cpu->cp0.tlb_entries - wired)));}/* Get a cp0 register (fast version) */static inline m_uint64_t cp0_get_reg_fast(cpu_mips_t *cpu,u_int cp0_reg){ mips_cp0_t *cp0 = &cpu->cp0; m_uint32_t delta,res; switch(cp0_reg) { case MIPS_CP0_COUNT: delta = cpu->cp0_virt_cmp_reg - cpu->cp0_virt_cnt_reg; res = (m_uint32_t)cp0->reg[MIPS_CP0_COMPARE]; res -= cpu->vm->clock_divisor * delta; return(sign_extend(res,32));#if 1 case MIPS_CP0_COMPARE: return(sign_extend(cp0->reg[MIPS_CP0_COMPARE],32));#else /* really useful and logical ? */ case MIPS_CP0_COMPARE: delta = cpu->cp0_virt_cmp_reg - cpu->cp0_virt_cnt_reg; res = (m_uint32_t)cp0->reg[MIPS_CP0_COUNT]; res += (cpu->vm->clock_divisor * delta); return(res);#endif case MIPS_CP0_INFO: return(MIPS64_R7000_TLB64_ENABLE); case MIPS_CP0_RANDOM: return(cp0_get_random_reg(cpu)); default: return(cp0->reg[cp0_reg]); }}/* Get a cp0 register */m_uint64_t cp0_get_reg(cpu_mips_t *cpu,u_int cp0_reg){ return(cp0_get_reg_fast(cpu,cp0_reg));}/* Set a cp0 register */static inline void cp0_set_reg(cpu_mips_t *cpu,u_int cp0_reg,m_uint64_t val){ mips_cp0_t *cp0 = &cpu->cp0; m_uint32_t delta; switch(cp0_reg) { case MIPS_CP0_STATUS: case MIPS_CP0_CAUSE: cp0->reg[cp0_reg] = val; mips64_update_irq_flag(cpu); break; case MIPS_CP0_PAGEMASK: cp0->reg[cp0_reg] = val & MIPS_TLB_PAGE_MASK; break; case MIPS_CP0_COMPARE: mips64_clear_irq(cpu,7); mips64_update_irq_flag(cpu); cp0->reg[cp0_reg] = val; delta = val - cp0->reg[MIPS_CP0_COUNT]; cpu->cp0_virt_cnt_reg = 0; cpu->cp0_virt_cmp_reg = delta / cpu->vm->clock_divisor; break; case MIPS_CP0_COUNT: cp0->reg[cp0_reg] = val; delta = cp0->reg[MIPS_CP0_COMPARE] - val; cpu->cp0_virt_cnt_reg = 0; cpu->cp0_virt_cmp_reg = delta / cpu->vm->clock_divisor; break; case MIPS_CP0_TLB_HI: cp0->reg[cp0_reg] = val & MIPS_CP0_HI_SAFE_MASK; break; case MIPS_CP0_TLB_LO_0: case MIPS_CP0_TLB_LO_1: cp0->reg[cp0_reg] = val & MIPS_CP0_LO_SAFE_MASK; break; case MIPS_CP0_RANDOM: case MIPS_CP0_PRID: case MIPS_CP0_CONFIG: /* read only registers */ break; case MIPS_CP0_WIRED: cp0->reg[cp0_reg] = val & MIPS64_TLB_IDX_MASK; break; default: cp0->reg[cp0_reg] = val; }}/* Get a cp0 "set 1" register (R7000) */m_uint64_t cp0_s1_get_reg(cpu_mips_t *cpu,u_int cp0_s1_reg){ switch(cp0_s1_reg) { case MIPS_CP0_S1_CONFIG: return(0x7F << 25); case MIPS_CP0_S1_IPLLO: return(cpu->cp0.ipl_lo); case MIPS_CP0_S1_IPLHI: return(cpu->cp0.ipl_hi); case MIPS_CP0_S1_INTCTL: return(cpu->cp0.int_ctl); case MIPS_CP0_S1_DERRADDR0: return(cpu->cp0.derraddr0); case MIPS_CP0_S1_DERRADDR1: return(cpu->cp0.derraddr1); default: /* undefined register */ cpu_log(cpu,"CP0_S1","trying to read unknown register %u\n", cp0_s1_reg); return(0); }}/* Set a cp0 "set 1" register (R7000) */static inline void cp0_s1_set_reg(cpu_mips_t *cpu,u_int cp0_s1_reg, m_uint64_t val){ mips_cp0_t *cp0 = &cpu->cp0; switch(cp0_s1_reg) { case MIPS_CP0_S1_IPLLO: cp0->ipl_lo = val; break; case MIPS_CP0_S1_IPLHI: cp0->ipl_hi = val; break; case MIPS_CP0_S1_INTCTL: cp0->int_ctl = val; break; case MIPS_CP0_S1_DERRADDR0: cp0->derraddr0 = val; break; case MIPS_CP0_S1_DERRADDR1: cp0->derraddr1 = val; break; default: cpu_log(cpu,"CP0_S1","trying to set unknown register %u (val=0x%x)\n", cp0_s1_reg,val); }}/* DMFC0 */fastcall void cp0_exec_dmfc0(cpu_mips_t *cpu,u_int gp_reg,u_int cp0_reg){ cpu->gpr[gp_reg] = cp0_get_reg_fast(cpu,cp0_reg);}/* DMTC0 */fastcall void cp0_exec_dmtc0(cpu_mips_t *cpu,u_int gp_reg,u_int cp0_reg){ cp0_set_reg(cpu,cp0_reg,cpu->gpr[gp_reg]);}/* MFC0 */fastcall void cp0_exec_mfc0(cpu_mips_t *cpu,u_int gp_reg,u_int cp0_reg){ cpu->gpr[gp_reg] = sign_extend(cp0_get_reg_fast(cpu,cp0_reg),32);}/* MTC0 */fastcall void cp0_exec_mtc0(cpu_mips_t *cpu,u_int gp_reg,u_int cp0_reg){ cp0_set_reg(cpu,cp0_reg,cpu->gpr[gp_reg] & 0xffffffff);}/* CFC0 */fastcall void cp0_exec_cfc0(cpu_mips_t *cpu,u_int gp_reg,u_int cp0_reg){ cpu->gpr[gp_reg] = sign_extend(cp0_s1_get_reg(cpu,cp0_reg),32);}/* CTC0 */fastcall void cp0_exec_ctc0(cpu_mips_t *cpu,u_int gp_reg,u_int cp0_reg){ cp0_s1_set_reg(cpu,cp0_reg,cpu->gpr[gp_reg] & 0xffffffff);}/* Get the page size corresponding to a page mask */static inline m_uint32_t get_page_size(m_uint32_t page_mask){ return((page_mask + 0x2000) >> 1);}/* Write page size in buffer */static char *get_page_size_str(char *buffer,size_t len,m_uint32_t page_mask){ m_uint32_t page_size; page_size = get_page_size(page_mask); /* Mb ? */ if (page_size >= (1024*1024)) snprintf(buffer,len,"%uMB",page_size >> 20); else snprintf(buffer,len,"%uKB",page_size >> 10); return buffer;}/* Get the VPN2 mask */static forced_inline m_uint64_t cp0_get_vpn2_mask(cpu_mips_t *cpu){ if (cpu->addr_mode == 64)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -