📄 frv.c
字号:
/* frv simulator support code Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004 Free Software Foundation, Inc. Contributed by Red Hat.This file is part of the GNU simulators.This program is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public License alongwith this program; if not, write to the Free Software Foundation, Inc.,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#define WANT_CPU#define WANT_CPU_FRVBF#include "sim-main.h"#include "cgen-mem.h"#include "cgen-ops.h"#include "cgen-engine.h"#include "cgen-par.h"#include "bfd.h"#include "gdb/sim-frv.h"#include <math.h>/* Maintain a flag in order to know when to write the address of the next VLIW instruction into the LR register. Used by JMPL. JMPIL, and CALL insns. */int frvbf_write_next_vliw_addr_to_LR;/* The contents of BUF are in target byte order. */intfrvbf_fetch_register (SIM_CPU *current_cpu, int rn, unsigned char *buf, int len){ if (SIM_FRV_GR0_REGNUM <= rn && rn <= SIM_FRV_GR63_REGNUM) { int hi_available, lo_available; int grn = rn - SIM_FRV_GR0_REGNUM; frv_gr_registers_available (current_cpu, &hi_available, &lo_available); if ((grn < 32 && !lo_available) || (grn >= 32 && !hi_available)) return 0; else SETTSI (buf, GET_H_GR (grn)); } else if (SIM_FRV_FR0_REGNUM <= rn && rn <= SIM_FRV_FR63_REGNUM) { int hi_available, lo_available; int frn = rn - SIM_FRV_FR0_REGNUM; frv_fr_registers_available (current_cpu, &hi_available, &lo_available); if ((frn < 32 && !lo_available) || (frn >= 32 && !hi_available)) return 0; else SETTSI (buf, GET_H_FR (frn)); } else if (rn == SIM_FRV_PC_REGNUM) SETTSI (buf, GET_H_PC ()); else if (SIM_FRV_SPR0_REGNUM <= rn && rn <= SIM_FRV_SPR4095_REGNUM) { /* Make sure the register is implemented. */ FRV_REGISTER_CONTROL *control = CPU_REGISTER_CONTROL (current_cpu); int spr = rn - SIM_FRV_SPR0_REGNUM; if (! control->spr[spr].implemented) return 0; SETTSI (buf, GET_H_SPR (spr)); } else { SETTSI (buf, 0xdeadbeef); return 0; } return len;}/* The contents of BUF are in target byte order. */intfrvbf_store_register (SIM_CPU *current_cpu, int rn, unsigned char *buf, int len){ if (SIM_FRV_GR0_REGNUM <= rn && rn <= SIM_FRV_GR63_REGNUM) { int hi_available, lo_available; int grn = rn - SIM_FRV_GR0_REGNUM; frv_gr_registers_available (current_cpu, &hi_available, &lo_available); if ((grn < 32 && !lo_available) || (grn >= 32 && !hi_available)) return 0; else SET_H_GR (grn, GETTSI (buf)); } else if (SIM_FRV_FR0_REGNUM <= rn && rn <= SIM_FRV_FR63_REGNUM) { int hi_available, lo_available; int frn = rn - SIM_FRV_FR0_REGNUM; frv_fr_registers_available (current_cpu, &hi_available, &lo_available); if ((frn < 32 && !lo_available) || (frn >= 32 && !hi_available)) return 0; else SET_H_FR (frn, GETTSI (buf)); } else if (rn == SIM_FRV_PC_REGNUM) SET_H_PC (GETTSI (buf)); else if (SIM_FRV_SPR0_REGNUM <= rn && rn <= SIM_FRV_SPR4095_REGNUM) { /* Make sure the register is implemented. */ FRV_REGISTER_CONTROL *control = CPU_REGISTER_CONTROL (current_cpu); int spr = rn - SIM_FRV_SPR0_REGNUM; if (! control->spr[spr].implemented) return 0; SET_H_SPR (spr, GETTSI (buf)); } else return 0; return len;}/* Cover fns to access the general registers. */USIfrvbf_h_gr_get_handler (SIM_CPU *current_cpu, UINT gr){ frv_check_gr_access (current_cpu, gr); return CPU (h_gr[gr]);}voidfrvbf_h_gr_set_handler (SIM_CPU *current_cpu, UINT gr, USI newval){ frv_check_gr_access (current_cpu, gr); if (gr == 0) return; /* Storing into gr0 has no effect. */ CPU (h_gr[gr]) = newval;}/* Cover fns to access the floating point registers. */SFfrvbf_h_fr_get_handler (SIM_CPU *current_cpu, UINT fr){ frv_check_fr_access (current_cpu, fr); return CPU (h_fr[fr]);}voidfrvbf_h_fr_set_handler (SIM_CPU *current_cpu, UINT fr, SF newval){ frv_check_fr_access (current_cpu, fr); CPU (h_fr[fr]) = newval;}/* Cover fns to access the general registers as double words. */static UINTcheck_register_alignment (SIM_CPU *current_cpu, UINT reg, int align_mask){ if (reg & align_mask) { SIM_DESC sd = CPU_STATE (current_cpu); switch (STATE_ARCHITECTURE (sd)->mach) { /* Note: there is a discrepancy between V2.2 of the FR400 instruction manual and the various FR4xx LSI specs. The former claims that unaligned registers cause a register_exception while the latter say it's an illegal_instruction. The LSI specs appear to be correct; in fact, the FR4xx series is not documented as having a register_exception. */ case bfd_mach_fr400: case bfd_mach_fr450: case bfd_mach_fr550: frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION); break; case bfd_mach_frvtomcat: case bfd_mach_fr500: case bfd_mach_frv: frv_queue_register_exception_interrupt (current_cpu, FRV_REC_UNALIGNED); break; default: break; } reg &= ~align_mask; } return reg;}static UINTcheck_fr_register_alignment (SIM_CPU *current_cpu, UINT reg, int align_mask){ if (reg & align_mask) { SIM_DESC sd = CPU_STATE (current_cpu); switch (STATE_ARCHITECTURE (sd)->mach) { /* See comment in check_register_alignment(). */ case bfd_mach_fr400: case bfd_mach_fr450: case bfd_mach_fr550: frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION); break; case bfd_mach_frvtomcat: case bfd_mach_fr500: case bfd_mach_frv: { struct frv_fp_exception_info fp_info = { FSR_NO_EXCEPTION, FTT_INVALID_FR }; frv_queue_fp_exception_interrupt (current_cpu, & fp_info); } break; default: break; } reg &= ~align_mask; } return reg;}static UINTcheck_memory_alignment (SIM_CPU *current_cpu, SI address, int align_mask){ if (address & align_mask) { SIM_DESC sd = CPU_STATE (current_cpu); switch (STATE_ARCHITECTURE (sd)->mach) { /* See comment in check_register_alignment(). */ case bfd_mach_fr400: case bfd_mach_fr450: frv_queue_data_access_error_interrupt (current_cpu, address); break; case bfd_mach_frvtomcat: case bfd_mach_fr500: case bfd_mach_frv: frv_queue_mem_address_not_aligned_interrupt (current_cpu, address); break; default: break; } address &= ~align_mask; } return address;}DIfrvbf_h_gr_double_get_handler (SIM_CPU *current_cpu, UINT gr){ DI value; if (gr == 0) return 0; /* gr0 is always 0. */ /* Check the register alignment. */ gr = check_register_alignment (current_cpu, gr, 1); value = GET_H_GR (gr); value <<= 32; value |= (USI) GET_H_GR (gr + 1); return value;}voidfrvbf_h_gr_double_set_handler (SIM_CPU *current_cpu, UINT gr, DI newval){ if (gr == 0) return; /* Storing into gr0 has no effect. */ /* Check the register alignment. */ gr = check_register_alignment (current_cpu, gr, 1); SET_H_GR (gr , (newval >> 32) & 0xffffffff); SET_H_GR (gr + 1, (newval ) & 0xffffffff);}/* Cover fns to access the floating point register as double words. */DFfrvbf_h_fr_double_get_handler (SIM_CPU *current_cpu, UINT fr){ union { SF as_sf[2]; DF as_df; } value; /* Check the register alignment. */ fr = check_fr_register_alignment (current_cpu, fr, 1); if (CURRENT_HOST_BYTE_ORDER == LITTLE_ENDIAN) { value.as_sf[1] = GET_H_FR (fr); value.as_sf[0] = GET_H_FR (fr + 1); } else { value.as_sf[0] = GET_H_FR (fr); value.as_sf[1] = GET_H_FR (fr + 1); } return value.as_df;}voidfrvbf_h_fr_double_set_handler (SIM_CPU *current_cpu, UINT fr, DF newval){ union { SF as_sf[2]; DF as_df; } value; /* Check the register alignment. */ fr = check_fr_register_alignment (current_cpu, fr, 1); value.as_df = newval; if (CURRENT_HOST_BYTE_ORDER == LITTLE_ENDIAN) { SET_H_FR (fr , value.as_sf[1]); SET_H_FR (fr + 1, value.as_sf[0]); } else { SET_H_FR (fr , value.as_sf[0]); SET_H_FR (fr + 1, value.as_sf[1]); }}/* Cover fns to access the floating point register as integer words. */USIfrvbf_h_fr_int_get_handler (SIM_CPU *current_cpu, UINT fr){ union { SF as_sf; USI as_usi; } value; value.as_sf = GET_H_FR (fr); return value.as_usi;}voidfrvbf_h_fr_int_set_handler (SIM_CPU *current_cpu, UINT fr, USI newval){ union { SF as_sf; USI as_usi; } value; value.as_usi = newval; SET_H_FR (fr, value.as_sf);}/* Cover fns to access the coprocessor registers as double words. */DIfrvbf_h_cpr_double_get_handler (SIM_CPU *current_cpu, UINT cpr){ DI value; /* Check the register alignment. */ cpr = check_register_alignment (current_cpu, cpr, 1); value = GET_H_CPR (cpr); value <<= 32; value |= (USI) GET_H_CPR (cpr + 1); return value;}voidfrvbf_h_cpr_double_set_handler (SIM_CPU *current_cpu, UINT cpr, DI newval){ /* Check the register alignment. */ cpr = check_register_alignment (current_cpu, cpr, 1); SET_H_CPR (cpr , (newval >> 32) & 0xffffffff); SET_H_CPR (cpr + 1, (newval ) & 0xffffffff);}/* Cover fns to write registers as quad words. */voidfrvbf_h_gr_quad_set_handler (SIM_CPU *current_cpu, UINT gr, SI *newval){ if (gr == 0) return; /* Storing into gr0 has no effect. */ /* Check the register alignment. */ gr = check_register_alignment (current_cpu, gr, 3); SET_H_GR (gr , newval[0]); SET_H_GR (gr + 1, newval[1]); SET_H_GR (gr + 2, newval[2]); SET_H_GR (gr + 3, newval[3]);}voidfrvbf_h_fr_quad_set_handler (SIM_CPU *current_cpu, UINT fr, SI *newval){ /* Check the register alignment. */ fr = check_fr_register_alignment (current_cpu, fr, 3); SET_H_FR (fr , newval[0]); SET_H_FR (fr + 1, newval[1]); SET_H_FR (fr + 2, newval[2]); SET_H_FR (fr + 3, newval[3]);}voidfrvbf_h_cpr_quad_set_handler (SIM_CPU *current_cpu, UINT cpr, SI *newval){ /* Check the register alignment. */ cpr = check_register_alignment (current_cpu, cpr, 3); SET_H_CPR (cpr , newval[0]); SET_H_CPR (cpr + 1, newval[1]); SET_H_CPR (cpr + 2, newval[2]); SET_H_CPR (cpr + 3, newval[3]);}/* Cover fns to access the special purpose registers. */USIfrvbf_h_spr_get_handler (SIM_CPU *current_cpu, UINT spr){ /* Check access restrictions. */ frv_check_spr_read_access (current_cpu, spr); switch (spr) { case H_SPR_PSR: return spr_psr_get_handler (current_cpu); case H_SPR_TBR: return spr_tbr_get_handler (current_cpu); case H_SPR_BPSR: return spr_bpsr_get_handler (current_cpu); case H_SPR_CCR: return spr_ccr_get_handler (current_cpu); case H_SPR_CCCR: return spr_cccr_get_handler (current_cpu); case H_SPR_SR0: case H_SPR_SR1: case H_SPR_SR2: case H_SPR_SR3: return spr_sr_get_handler (current_cpu, spr); break; default: return CPU (h_spr[spr]); } return 0;}voidfrvbf_h_spr_set_handler (SIM_CPU *current_cpu, UINT spr, USI newval){ FRV_REGISTER_CONTROL *control; USI mask; USI oldval; /* Check access restrictions. */ frv_check_spr_write_access (current_cpu, spr); /* Only set those fields which are writeable. */ control = CPU_REGISTER_CONTROL (current_cpu); mask = control->spr[spr].read_only_mask; oldval = GET_H_SPR (spr); newval = (newval & ~mask) | (oldval & mask); /* Some registers are represented by individual components which are referenced more often than the register itself. */ switch (spr) { case H_SPR_PSR: spr_psr_set_handler (current_cpu, newval); break; case H_SPR_TBR: spr_tbr_set_handler (current_cpu, newval); break; case H_SPR_BPSR: spr_bpsr_set_handler (current_cpu, newval); break; case H_SPR_CCR: spr_ccr_set_handler (current_cpu, newval); break; case H_SPR_CCCR: spr_cccr_set_handler (current_cpu, newval); break; case H_SPR_SR0: case H_SPR_SR1: case H_SPR_SR2: case H_SPR_SR3: spr_sr_set_handler (current_cpu, spr, newval); break; case H_SPR_IHSR8: frv_cache_reconfigure (current_cpu, CPU_INSN_CACHE (current_cpu)); break; default: CPU (h_spr[spr]) = newval; break; }}/* Cover fns to access the gr_hi and gr_lo registers. */UHIfrvbf_h_gr_hi_get_handler (SIM_CPU *current_cpu, UINT gr){ return (GET_H_GR(gr) >> 16) & 0xffff;}voidfrvbf_h_gr_hi_set_handler (SIM_CPU *current_cpu, UINT gr, UHI newval){ USI value = (GET_H_GR (gr) & 0xffff) | (newval << 16); SET_H_GR (gr, value);}UHIfrvbf_h_gr_lo_get_handler (SIM_CPU *current_cpu, UINT gr){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -