📄 interp.c
字号:
/* Simulator for the Renesas (formerly Hitachi) / SuperH Inc. SH architecture. Written by Steve Chamberlain of Cygnus Support. sac@cygnus.com This file is part of SH sim THIS SOFTWARE IS NOT COPYRIGHTED Cygnus offers the following for use in the public domain. Cygnus makes no warranty with regard to the software or it's performance and the user accepts the software "AS IS" with all faults. CYGNUS DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.*/#include "config.h"#include <signal.h>#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#include "sysdep.h"#include "bfd.h"#include "gdb/callback.h"#include "gdb/remote-sim.h"#include "gdb/sim-sh.h"/* This file is local - if newlib changes, then so should this. */#include "syscall.h"#include <math.h>#ifdef _WIN32#include <float.h> /* Needed for _isnan() */#define isnan _isnan#endif#ifndef SIGBUS#define SIGBUS SIGSEGV#endif#ifndef SIGQUIT#define SIGQUIT SIGTERM#endif#ifndef SIGTRAP#define SIGTRAP 5#endifextern unsigned short sh_jump_table[], sh_dsp_table[0x1000], ppi_table[];int sim_write (SIM_DESC sd, SIM_ADDR addr, unsigned char *buffer, int size);#define O_RECOMPILE 85#define DEFINE_TABLE#define DISASSEMBLER_TABLE/* Define the rate at which the simulator should poll the host for a quit. */#define POLL_QUIT_INTERVAL 0x60000typedef struct{ int regs[20];} regstacktype;typedef union{ struct { int regs[16]; int pc; /* System registers. For sh-dsp this also includes A0 / X0 / X1 / Y0 / Y1 which are located in fregs, i.e. strictly speaking, these are out-of-bounds accesses of sregs.i . This wart of the code could be fixed by making fregs part of sregs, and including pc too - to avoid alignment repercussions - but this would cause very onerous union / structure nesting, which would only be managable with anonymous unions and structs. */ union { struct { int mach; int macl; int pr; int dummy3, dummy4; int fpul; /* A1 for sh-dsp - but only for movs etc. */ int fpscr; /* dsr for sh-dsp */ } named; int i[7]; } sregs; /* sh3e / sh-dsp */ union fregs_u { float f[16]; double d[8]; int i[16]; } fregs[2]; /* Control registers; on the SH4, ldc / stc is privileged, except when accessing gbr. */ union { struct { int sr; int gbr; int vbr; int ssr; int spc; int mod; /* sh-dsp */ int rs; int re; /* sh3 */ int bank[8]; int dbr; /* debug base register */ int sgr; /* saved gr15 */ int ldst; /* load/store flag (boolean) */ int tbr; int ibcr; /* sh2a bank control register */ int ibnr; /* sh2a bank number register */ } named; int i[16]; } cregs; unsigned char *insn_end; int ticks; int stalls; int memstalls; int cycles; int insts; int prevlock; int thislock; int exception; int end_of_registers; int msize;#define PROFILE_FREQ 1#define PROFILE_SHIFT 2 int profile; unsigned short *profile_hist; unsigned char *memory; int xyram_select, xram_start, yram_start; unsigned char *xmem; unsigned char *ymem; unsigned char *xmem_offset; unsigned char *ymem_offset; unsigned long bfd_mach; regstacktype *regstack; } asregs; int asints[40];} saved_state_type;saved_state_type saved_state;struct loop_bounds { unsigned char *start, *end; };/* These variables are at file scope so that functions other than sim_resume can use the fetch/store macros */static int target_little_endian;static int global_endianw, endianb;static int target_dsp;static int host_little_endian;static char **prog_argv;static int maskw = 0;static int maskl = 0;static SIM_OPEN_KIND sim_kind;static char *myname;static int tracing = 0;/* Short hand definitions of the registers */#define SBIT(x) ((x)&sbit)#define R0 saved_state.asregs.regs[0]#define Rn saved_state.asregs.regs[n]#define Rm saved_state.asregs.regs[m]#define UR0 (unsigned int) (saved_state.asregs.regs[0])#define UR (unsigned int) R#define UR (unsigned int) R#define SR0 saved_state.asregs.regs[0]#define CREG(n) (saved_state.asregs.cregs.i[(n)])#define GBR saved_state.asregs.cregs.named.gbr#define VBR saved_state.asregs.cregs.named.vbr#define DBR saved_state.asregs.cregs.named.dbr#define TBR saved_state.asregs.cregs.named.tbr#define IBCR saved_state.asregs.cregs.named.ibcr#define IBNR saved_state.asregs.cregs.named.ibnr#define BANKN (saved_state.asregs.cregs.named.ibnr & 0x1ff)#define ME ((saved_state.asregs.cregs.named.ibnr >> 14) & 0x3)#define SSR saved_state.asregs.cregs.named.ssr#define SPC saved_state.asregs.cregs.named.spc#define SGR saved_state.asregs.cregs.named.sgr#define SREG(n) (saved_state.asregs.sregs.i[(n)])#define MACH saved_state.asregs.sregs.named.mach#define MACL saved_state.asregs.sregs.named.macl#define PR saved_state.asregs.sregs.named.pr#define FPUL saved_state.asregs.sregs.named.fpul#define PC insn_ptr/* Alternate bank of registers r0-r7 *//* Note: code controling SR handles flips between BANK0 and BANK1 */#define Rn_BANK(n) (saved_state.asregs.cregs.named.bank[(n)])#define SET_Rn_BANK(n, EXP) do { saved_state.asregs.cregs.named.bank[(n)] = (EXP); } while (0)/* Manipulate SR */#define SR_MASK_BO (1 << 14)#define SR_MASK_CS (1 << 13)#define SR_MASK_DMY (1 << 11)#define SR_MASK_DMX (1 << 10)#define SR_MASK_M (1 << 9)#define SR_MASK_Q (1 << 8)#define SR_MASK_I (0xf << 4)#define SR_MASK_S (1 << 1)#define SR_MASK_T (1 << 0)#define SR_MASK_BL (1 << 28)#define SR_MASK_RB (1 << 29)#define SR_MASK_MD (1 << 30)#define SR_MASK_RC 0x0fff0000#define SR_RC_INCREMENT -0x00010000#define BO ((saved_state.asregs.cregs.named.sr & SR_MASK_BO) != 0)#define CS ((saved_state.asregs.cregs.named.sr & SR_MASK_CS) != 0)#define M ((saved_state.asregs.cregs.named.sr & SR_MASK_M) != 0)#define Q ((saved_state.asregs.cregs.named.sr & SR_MASK_Q) != 0)#define S ((saved_state.asregs.cregs.named.sr & SR_MASK_S) != 0)#define T ((saved_state.asregs.cregs.named.sr & SR_MASK_T) != 0)#define LDST ((saved_state.asregs.cregs.named.ldst) != 0)#define SR_BL ((saved_state.asregs.cregs.named.sr & SR_MASK_BL) != 0)#define SR_RB ((saved_state.asregs.cregs.named.sr & SR_MASK_RB) != 0)#define SR_MD ((saved_state.asregs.cregs.named.sr & SR_MASK_MD) != 0)#define SR_DMY ((saved_state.asregs.cregs.named.sr & SR_MASK_DMY) != 0)#define SR_DMX ((saved_state.asregs.cregs.named.sr & SR_MASK_DMX) != 0)#define SR_RC ((saved_state.asregs.cregs.named.sr & SR_MASK_RC))/* Note: don't use this for privileged bits */#define SET_SR_BIT(EXP, BIT) \do { \ if ((EXP) & 1) \ saved_state.asregs.cregs.named.sr |= (BIT); \ else \ saved_state.asregs.cregs.named.sr &= ~(BIT); \} while (0)#define SET_SR_BO(EXP) SET_SR_BIT ((EXP), SR_MASK_BO)#define SET_SR_CS(EXP) SET_SR_BIT ((EXP), SR_MASK_CS)#define SET_BANKN(EXP) \do { \ IBNR = (IBNR & 0xfe00) | (EXP & 0x1f); \} while (0)#define SET_ME(EXP) \do { \ IBNR = (IBNR & 0x3fff) | ((EXP & 0x3) << 14); \} while (0)#define SET_SR_M(EXP) SET_SR_BIT ((EXP), SR_MASK_M)#define SET_SR_Q(EXP) SET_SR_BIT ((EXP), SR_MASK_Q)#define SET_SR_S(EXP) SET_SR_BIT ((EXP), SR_MASK_S)#define SET_SR_T(EXP) SET_SR_BIT ((EXP), SR_MASK_T)#define SET_LDST(EXP) (saved_state.asregs.cregs.named.ldst = ((EXP) != 0))/* stc currently relies on being able to read SR without modifications. */#define GET_SR() (saved_state.asregs.cregs.named.sr - 0)#define SET_SR(x) set_sr (x)#define SET_RC(x) \ (saved_state.asregs.cregs.named.sr \ = saved_state.asregs.cregs.named.sr & 0xf000ffff | ((x) & 0xfff) << 16)/* Manipulate FPSCR */#define FPSCR_MASK_FR (1 << 21)#define FPSCR_MASK_SZ (1 << 20)#define FPSCR_MASK_PR (1 << 19)#define FPSCR_FR ((GET_FPSCR () & FPSCR_MASK_FR) != 0)#define FPSCR_SZ ((GET_FPSCR () & FPSCR_MASK_SZ) != 0)#define FPSCR_PR ((GET_FPSCR () & FPSCR_MASK_PR) != 0)/* Count the number of arguments in an argv. */static intcount_argc (char **argv){ int i; if (! argv) return -1; for (i = 0; argv[i] != NULL; ++i) continue; return i;}static voidset_fpscr1 (x) int x;{ int old = saved_state.asregs.sregs.named.fpscr; saved_state.asregs.sregs.named.fpscr = (x); /* swap the floating point register banks */ if ((saved_state.asregs.sregs.named.fpscr ^ old) & FPSCR_MASK_FR /* Ignore bit change if simulating sh-dsp. */ && ! target_dsp) { union fregs_u tmpf = saved_state.asregs.fregs[0]; saved_state.asregs.fregs[0] = saved_state.asregs.fregs[1]; saved_state.asregs.fregs[1] = tmpf; }}/* sts relies on being able to read fpscr directly. */#define GET_FPSCR() (saved_state.asregs.sregs.named.fpscr)#define SET_FPSCR(x) \do { \ set_fpscr1 (x); \} while (0)#define DSR (saved_state.asregs.sregs.named.fpscr)int fail (){ abort ();}#define RAISE_EXCEPTION(x) \ (saved_state.asregs.exception = x, saved_state.asregs.insn_end = 0)#define RAISE_EXCEPTION_IF_IN_DELAY_SLOT() \ if (in_delay_slot) RAISE_EXCEPTION (SIGILL)/* This function exists mainly for the purpose of setting a breakpoint to catch simulated bus errors when running the simulator under GDB. */voidraise_exception (x) int x;{ RAISE_EXCEPTION (x);}voidraise_buserror (){ raise_exception (SIGBUS);}#define PROCESS_SPECIAL_ADDRESS(addr, endian, ptr, bits_written, \ forbidden_addr_bits, data, retval) \do { \ if (addr & forbidden_addr_bits) \ { \ raise_buserror (); \ return retval; \ } \ else if ((addr & saved_state.asregs.xyram_select) \ == saved_state.asregs.xram_start) \ ptr = (void *) &saved_state.asregs.xmem_offset[addr ^ endian]; \ else if ((addr & saved_state.asregs.xyram_select) \ == saved_state.asregs.yram_start) \ ptr = (void *) &saved_state.asregs.ymem_offset[addr ^ endian]; \ else if ((unsigned) addr >> 24 == 0xf0 \ && bits_written == 32 && (data & 1) == 0) \ /* This invalidates (if not associative) or might invalidate \ (if associative) an instruction cache line. This is used for \ trampolines. Since we don't simulate the cache, this is a no-op \ as far as the simulator is concerned. */ \ return retval; \ else \ { \ if (bits_written == 8 && addr > 0x5000000) \ IOMEM (addr, 1, data); \ /* We can't do anything useful with the other stuff, so fail. */ \ raise_buserror (); \ return retval; \ } \} while (0)/* FIXME: sim_resume should be renamed to sim_engine_run. sim_resume being implemented by ../common/sim_resume.c and the below should make a call to sim_engine_halt */#define BUSERROR(addr, mask) ((addr) & (mask))#define WRITE_BUSERROR(addr, mask, data, addr_func) \ do \ { \ if (addr & mask) \ { \ addr_func (addr, data); \ return; \ } \ } \ while (0)#define READ_BUSERROR(addr, mask, addr_func) \ do \ { \ if (addr & mask) \ return addr_func (addr); \ } \ while (0)/* Define this to enable register lifetime checking. The compiler generates "add #0,rn" insns to mark registers as invalid, the simulator uses this info to call fail if it finds a ref to an invalid register before a def #define PARANOID*/#ifdef PARANOIDint valid[16];#define CREF(x) if (!valid[x]) fail ();#define CDEF(x) valid[x] = 1;#define UNDEF(x) valid[x] = 0;#else#define CREF(x)#define CDEF(x)#define UNDEF(x)#endifstatic void parse_and_set_memory_size PARAMS ((char *str));static int IOMEM PARAMS ((int addr, int write, int value));static struct loop_bounds get_loop_bounds PARAMS ((int, int, unsigned char *, unsigned char *, int, int));static void process_wlat_addr PARAMS ((int, int));static void process_wwat_addr PARAMS ((int, int));static void process_wbat_addr PARAMS ((int, int));static int process_rlat_addr PARAMS ((int));static int process_rwat_addr PARAMS ((int));static int process_rbat_addr PARAMS ((int));static void INLINE wlat_fast PARAMS ((unsigned char *, int, int, int));static void INLINE wwat_fast PARAMS ((unsigned char *, int, int, int, int));static void INLINE wbat_fast PARAMS ((unsigned char *, int, int, int));static int INLINE rlat_fast PARAMS ((unsigned char *, int, int));static int INLINE rwat_fast PARAMS ((unsigned char *, int, int, int));static int INLINE rbat_fast PARAMS ((unsigned char *, int, int));static host_callback *callback;/* Floating point registers */#define DR(n) (get_dr (n))static doubleget_dr (n) int n;{ n = (n & ~1); if (host_little_endian) { union { int i[2]; double d; } dr; dr.i[1] = saved_state.asregs.fregs[0].i[n + 0]; dr.i[0] = saved_state.asregs.fregs[0].i[n + 1]; return dr.d; } else return (saved_state.asregs.fregs[0].d[n >> 1]);}#define SET_DR(n, EXP) set_dr ((n), (EXP))static voidset_dr (n, exp) int n; double exp;{ n = (n & ~1); if (host_little_endian) { union { int i[2]; double d; } dr; dr.d = exp; saved_state.asregs.fregs[0].i[n + 0] = dr.i[1]; saved_state.asregs.fregs[0].i[n + 1] = dr.i[0]; } else saved_state.asregs.fregs[0].d[n >> 1] = exp;}#define SET_FI(n,EXP) (saved_state.asregs.fregs[0].i[(n)] = (EXP))#define FI(n) (saved_state.asregs.fregs[0].i[(n)])#define FR(n) (saved_state.asregs.fregs[0].f[(n)])#define SET_FR(n,EXP) (saved_state.asregs.fregs[0].f[(n)] = (EXP))#define XD_TO_XF(n) ((((n) & 1) << 5) | ((n) & 0x1e))#define XF(n) (saved_state.asregs.fregs[(n) >> 5].i[(n) & 0x1f])#define SET_XF(n,EXP) (saved_state.asregs.fregs[(n) >> 5].i[(n) & 0x1f] = (EXP))#define RS saved_state.asregs.cregs.named.rs#define RE saved_state.asregs.cregs.named.re#define MOD (saved_state.asregs.cregs.named.mod)#define SET_MOD(i) \(MOD = (i), \ MOD_ME = (unsigned) MOD >> 16 | (SR_DMY ? ~0xffff : (SR_DMX ? 0 : 0x10000)), \ MOD_DELTA = (MOD & 0xffff) - ((unsigned) MOD >> 16))#define DSP_R(n) saved_state.asregs.sregs.i[(n)]#define DSP_GRD(n) DSP_R ((n) + 8)#define GET_DSP_GRD(n) ((n | 2) == 7 ? SEXT (DSP_GRD (n)) : SIGN32 (DSP_R (n)))#define A1 DSP_R (5)#define A0 DSP_R (7)#define X0 DSP_R (8)#define X1 DSP_R (9)#define Y0 DSP_R (10)#define Y1 DSP_R (11)#define M0 DSP_R (12)#define A1G DSP_R (13)#define M1 DSP_R (14)#define A0G DSP_R (15)/* DSP_R (16) / DSP_GRD (16) are used as a fake destination for pcmp. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -