X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=sim%2Fsh%2Finterp.c;h=2f02e69382c7e39073be5a0bb7e30d1e001ede28;hb=00923338dec84505addaf9cdeca2e9c844757824;hp=981067804cd5c9e65ada75d7d0a1cf7da5fa7ffe;hpb=87acb4a7d15c490de7cde8f75463e70b963fa414;p=deliverable%2Fbinutils-gdb.git diff --git a/sim/sh/interp.c b/sim/sh/interp.c index 981067804c..2f02e69382 100644 --- a/sim/sh/interp.c +++ b/sim/sh/interp.c @@ -20,17 +20,58 @@ #include "config.h" +#include +#include +#include #include #ifdef HAVE_UNISTD_H #include #endif +#ifdef HAVE_MMAP +#include +# ifndef MAP_FAILED +# define MAP_FAILED -1 +# endif +# if !defined (MAP_ANONYMOUS) && defined (MAP_ANON) +# define MAP_ANONYMOUS MAP_ANON +# endif +#endif + +#ifdef HAVE_STRING_H +#include +#else +#ifdef HAVE_STRINGS_H +#include +#endif +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_TIME_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifndef _WIN32 +#include +#include +#endif -#include "sysdep.h" #include "bfd.h" #include "gdb/callback.h" #include "gdb/remote-sim.h" #include "gdb/sim-sh.h" +#include "sim-main.h" +#include "sim-base.h" +#include "sim-options.h" + /* This file is local - if newlib changes, then so should this. */ #include "syscall.h" @@ -53,9 +94,11 @@ #define SIGTRAP 5 #endif -extern unsigned char sh_jump_table[], sh_dsp_table[0x1000], ppi_table[]; +/* TODO: Stop using these names. */ +#undef SEXT +#undef SEXT32 -int sim_write (SIM_DESC sd, SIM_ADDR addr, unsigned char *buffer, int size); +extern unsigned short sh_jump_table[], sh_dsp_table[0x1000], ppi_table[]; #define O_RECOMPILE 85 #define DEFINE_TABLE @@ -65,98 +108,7 @@ int sim_write (SIM_DESC sd, SIM_ADDR addr, unsigned char *buffer, int size); for a quit. */ #define POLL_QUIT_INTERVAL 0x60000 -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) */ - } 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; - } - asregs; - int asints[40]; -} saved_state_type; - +/* TODO: Move into sim_cpu. */ saved_state_type saved_state; struct loop_bounds { unsigned char *start, *end; }; @@ -164,19 +116,15 @@ 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; +#define target_little_endian (CURRENT_TARGET_BYTE_ORDER == LITTLE_ENDIAN) static int global_endianw, endianb; static int target_dsp; -static int host_little_endian; +#define host_little_endian (CURRENT_HOST_BYTE_ORDER == LITTLE_ENDIAN) static char **prog_argv; static int maskw = 0; static int maskl = 0; -static SIM_OPEN_KIND sim_kind; -static char *myname; - - /* Short hand definitions of the registers */ #define SBIT(x) ((x)&sbit) @@ -191,6 +139,11 @@ static char *myname; #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 @@ -213,6 +166,8 @@ static char *myname; /* 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) @@ -227,6 +182,8 @@ static char *myname; #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) @@ -249,6 +206,16 @@ do { \ 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) @@ -289,8 +256,7 @@ count_argc (char **argv) } static void -set_fpscr1 (x) - int x; +set_fpscr1 (int x) { int old = saved_state.asregs.sregs.named.fpscr; saved_state.asregs.sregs.named.fpscr = (x); @@ -314,27 +280,23 @@ do { \ #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. */ -void -raise_exception (x) - int x; +static void +raise_exception (int x) { RAISE_EXCEPTION (x); } -void -raise_buserror () +static void +raise_buserror (void) { raise_exception (SIGBUS); } @@ -414,22 +376,16 @@ int valid[16]; #define UNDEF(x) #endif -static 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 void parse_and_set_memory_size (const char *str); +static int IOMEM (int addr, int write, int value); +static struct loop_bounds get_loop_bounds (int, int, unsigned char *, + unsigned char *, int, int); +static void process_wlat_addr (int, int); +static void process_wwat_addr (int, int); +static void process_wbat_addr (int, int); +static int process_rlat_addr (int); +static int process_rwat_addr (int); +static int process_rbat_addr (int); static host_callback *callback; @@ -439,8 +395,7 @@ static host_callback *callback; #define DR(n) (get_dr (n)) static double -get_dr (n) - int n; +get_dr (int n) { n = (n & ~1); if (host_little_endian) @@ -460,9 +415,7 @@ get_dr (n) #define SET_DR(n, EXP) set_dr ((n), (EXP)) static void -set_dr (n, exp) - int n; - double exp; +set_dr (int n, double exp) { n = (n & ~1); if (host_little_endian) @@ -555,8 +508,7 @@ set_dr (n, exp) } while (0) static void -set_sr (new_sr) - int new_sr; +set_sr (int new_sr) { /* do we need to swap banks */ int old_gpr = SR_MD && SR_RB; @@ -575,9 +527,8 @@ set_sr (new_sr) SET_MOD (MOD); } -static void INLINE -wlat_fast (memory, x, value, maskl) - unsigned char *memory; +static INLINE void +wlat_fast (unsigned char *memory, int x, int value, int maskl) { int v = value; unsigned int *p = (unsigned int *) (memory + x); @@ -585,9 +536,8 @@ wlat_fast (memory, x, value, maskl) *p = v; } -static void INLINE -wwat_fast (memory, x, value, maskw, endianw) - unsigned char *memory; +static INLINE void +wwat_fast (unsigned char *memory, int x, int value, int maskw, int endianw) { int v = value; unsigned short *p = (unsigned short *) (memory + (x ^ endianw)); @@ -595,9 +545,8 @@ wwat_fast (memory, x, value, maskw, endianw) *p = v; } -static void INLINE -wbat_fast (memory, x, value, maskb) - unsigned char *memory; +static INLINE void +wbat_fast (unsigned char *memory, int x, int value, int maskb) { unsigned char *p = memory + (x ^ endianb); WRITE_BUSERROR (x, maskb, value, process_wbat_addr); @@ -607,9 +556,8 @@ wbat_fast (memory, x, value, maskb) /* Read functions */ -static int INLINE -rlat_fast (memory, x, maskl) - unsigned char *memory; +static INLINE int +rlat_fast (unsigned char *memory, int x, int maskl) { unsigned int *p = (unsigned int *) (memory + x); READ_BUSERROR (x, maskl, process_rlat_addr); @@ -617,10 +565,8 @@ rlat_fast (memory, x, maskl) return *p; } -static int INLINE -rwat_fast (memory, x, maskw, endianw) - unsigned char *memory; - int x, maskw, endianw; +static INLINE int +rwat_fast (unsigned char *memory, int x, int maskw, int endianw) { unsigned short *p = (unsigned short *) (memory + (x ^ endianw)); READ_BUSERROR (x, maskw, process_rwat_addr); @@ -628,18 +574,16 @@ rwat_fast (memory, x, maskw, endianw) return *p; } -static int INLINE -riat_fast (insn_ptr, endianw) - unsigned char *insn_ptr; +static INLINE int +riat_fast (unsigned char *insn_ptr, int endianw) { unsigned short *p = (unsigned short *) ((size_t) insn_ptr ^ endianw); return *p; } -static int INLINE -rbat_fast (memory, x, maskb) - unsigned char *memory; +static INLINE int +rbat_fast (unsigned char *memory, int x, int maskb) { unsigned char *p = memory + (x ^ endianb); READ_BUSERROR (x, maskb, process_rbat_addr); @@ -662,11 +606,7 @@ rbat_fast (memory, x, maskb) #define RDAT(x, n) (do_rdat (memory, (x), (n), (maskl))) static int -do_rdat (memory, x, n, maskl) - char *memory; - int x; - int n; - int maskl; +do_rdat (unsigned char *memory, int x, int n, int maskl) { int f0; int f1; @@ -681,11 +621,7 @@ do_rdat (memory, x, n, maskl) #define WDAT(x, n) (do_wdat (memory, (x), (n), (maskl))) static int -do_wdat (memory, x, n, maskl) - char *memory; - int x; - int n; - int maskl; +do_wdat (unsigned char *memory, int x, int n, int maskl) { int f0; int f1; @@ -699,9 +635,7 @@ do_wdat (memory, x, n, maskl) } static void -process_wlat_addr (addr, value) - int addr; - int value; +process_wlat_addr (int addr, int value) { unsigned int *ptr; @@ -710,9 +644,7 @@ process_wlat_addr (addr, value) } static void -process_wwat_addr (addr, value) - int addr; - int value; +process_wwat_addr (int addr, int value) { unsigned short *ptr; @@ -721,9 +653,7 @@ process_wwat_addr (addr, value) } static void -process_wbat_addr (addr, value) - int addr; - int value; +process_wbat_addr (int addr, int value) { unsigned char *ptr; @@ -732,8 +662,7 @@ process_wbat_addr (addr, value) } static int -process_rlat_addr (addr) - int addr; +process_rlat_addr (int addr) { unsigned char *ptr; @@ -742,8 +671,7 @@ process_rlat_addr (addr) } static int -process_rwat_addr (addr) - int addr; +process_rwat_addr (int addr) { unsigned char *ptr; @@ -752,8 +680,7 @@ process_rwat_addr (addr) } static int -process_rbat_addr (addr) - int addr; +process_rbat_addr (int addr) { unsigned char *ptr; @@ -780,7 +707,8 @@ process_rbat_addr (addr) #define SET_NIP(x) nip = (x); CHECK_INSN_PTR (nip); -#define Delay_Slot(TEMPPC) iword = RIAT (TEMPPC); goto top; +static int in_delay_slot = 0; +#define Delay_Slot(TEMPPC) iword = RIAT (TEMPPC); in_delay_slot = 1; goto top; #define CHECK_INSN_PTR(p) \ do { \ @@ -802,7 +730,7 @@ do { \ #else #define MA(n) \ - do { memstalls += ((((int) PC & 3) != 0) ? (n) : ((n) - 1)); } while (0) + do { memstalls += ((((long) PC & 3) != 0) ? (n) : ((n) - 1)); } while (0) #define L(x) thislock = x; #define TL(x) if ((x) == prevlock) stalls++; @@ -810,7 +738,7 @@ do { \ #endif -#if defined(__GO32__) || defined(_WIN32) +#if defined(__GO32__) int sim_memory_size = 19; #else int sim_memory_size = 24; @@ -833,10 +761,7 @@ static int nsamples; #define SCI_TDRE 0x80 /* Transmit data register empty */ static int -IOMEM (addr, write, value) - int addr; - int write; - int value; +IOMEM (int addr, int write, int value) { if (write) { @@ -863,22 +788,21 @@ IOMEM (addr, write, value) } static int -get_now () +get_now (void) { return time ((long *) 0); } static int -now_persec () +now_persec (void) { return 1; } static FILE *profile_file; -static unsigned INLINE -swap (n) - unsigned n; +static INLINE unsigned +swap (unsigned n) { if (endianb) n = (n << 24 | (n & 0xff00) << 8 @@ -886,9 +810,8 @@ swap (n) return n; } -static unsigned short INLINE -swap16 (n) - unsigned short n; +static INLINE unsigned short +swap16 (unsigned short n) { if (endianb) n = n << 8 | (n & 0xff00) >> 8; @@ -896,8 +819,7 @@ swap16 (n) } static void -swapout (n) - int n; +swapout (int n) { if (profile_file) { @@ -908,8 +830,7 @@ swapout (n) } static void -swapout16 (n) - int n; +swapout16 (int n) { union { char b[4]; int n; } u; u.n = swap16 (n); @@ -919,15 +840,17 @@ swapout16 (n) /* Turn a pointer in a register into a pointer into real memory. */ static char * -ptr (x) - int x; +ptr (int x) { return (char *) (x + saved_state.asregs.memory); } +/* STR points to a zero-terminated string in target byte order. Return + the number of bytes that need to be converted to host byte order in order + to use this string as a zero-terminated string on the host. + (Not counting the rounding up needed to operate on entire words.) */ static int -strswaplen (str) - int str; +strswaplen (int str) { unsigned char *memory = saved_state.asregs.memory; int start, end; @@ -937,13 +860,11 @@ strswaplen (str) return 0; end = str; for (end = str; memory[end ^ endian]; end++) ; - return end - str; + return end - str + 1; } static void -strnswap (str, len) - int str; - int len; +strnswap (int str, int len) { int *start, *end; @@ -965,11 +886,8 @@ strnswap (str, len) return offset by which to adjust pc. */ static int -trap (i, regs, insn_ptr, memory, maskl, maskw, endianw) - int i; - int *regs; - unsigned char *insn_ptr; - unsigned char *memory; +trap (int i, int *regs, unsigned char *insn_ptr, unsigned char *memory, + int maskl, int maskw, int endianw) { switch (i) { @@ -1020,7 +938,7 @@ trap (i, regs, insn_ptr, memory, maskl, maskw, endianw) break; case SYS_wait: - regs[0] = wait (ptr (regs[5])); + regs[0] = wait ((int *) ptr (regs[5])); break; #endif /* !defined(__GO32__) && !defined(_WIN32) */ @@ -1153,7 +1071,7 @@ trap (i, regs, insn_ptr, memory, maskl, maskw, endianw) { /* Include the termination byte. */ int i = strlen (prog_argv[regs[5]]) + 1; - regs[0] = sim_write (0, regs[6], prog_argv[regs[5]], i); + regs[0] = sim_write (0, regs[6], (void *) prog_argv[regs[5]], i); } else regs[0] = -1; @@ -1181,6 +1099,12 @@ trap (i, regs, insn_ptr, memory, maskl, maskw, endianw) } break; + case 13: /* Set IBNR */ + IBNR = regs[0] & 0xffff; + break; + case 14: /* Set IBCR */ + IBCR = regs[0] & 0xffff; + break; case 0xc3: case 255: raise_exception (SIGTRAP); @@ -1191,22 +1115,8 @@ trap (i, regs, insn_ptr, memory, maskl, maskw, endianw) return 0; } -void -control_c (sig, code, scp, addr) - int sig; - int code; - char *scp; - char *addr; -{ - raise_exception (SIGINT); -} - -static int -div1 (R, iRn2, iRn1/*, T*/) - int *R; - int iRn1; - int iRn2; - /* int T;*/ +static void +div1 (int *R, int iRn2, int iRn1/*, int T*/) { unsigned long tmp0; unsigned char old_q, tmp1; @@ -1291,10 +1201,7 @@ div1 (R, iRn2, iRn1/*, T*/) } static void -dmul (sign, rm, rn) - int sign; - unsigned int rm; - unsigned int rn; +dmul (int sign, unsigned int rm, unsigned int rn) { unsigned long RnL, RnH; unsigned long RmL, RmH; @@ -1332,11 +1239,7 @@ dmul (sign, rm, rn) } static void -macw (regs, memory, n, m, endianw) - int *regs; - unsigned char *memory; - int m, n; - int endianw; +macw (int *regs, unsigned char *memory, int n, int m, int endianw) { long tempm, tempn; long prod, macl, sum; @@ -1370,20 +1273,12 @@ macw (regs, memory, n, m, endianw) } static void -macl (regs, memory, n, m) - int *regs; - unsigned char *memory; - int m, n; +macl (int *regs, unsigned char *memory, int n, int m) { long tempm, tempn; - long prod, macl, mach, sum; - long long ans,ansl,ansh,t; - unsigned long long high,low,combine; - union mac64 - { - long m[2]; /* mach and macl*/ - long long m64; /* 64 bit MAC */ - }mac64; + long macl, mach; + long long ans; + long long mac64; tempm = RSLAT (regs[m]); regs[m] += 4; @@ -1394,15 +1289,15 @@ macl (regs, memory, n, m) mach = MACH; macl = MACL; - mac64.m[0] = macl; - mac64.m[1] = mach; + mac64 = ((long long) macl & 0xffffffff) | + ((long long) mach & 0xffffffff) << 32; ans = (long long) tempm * (long long) tempn; /* Multiply 32bit * 32bit */ - mac64.m64 += ans; /* Accumulate 64bit + 64 bit */ + mac64 += ans; /* Accumulate 64bit + 64 bit */ - macl = mac64.m[0]; - mach = mac64.m[1]; + macl = (long) (mac64 & 0xffffffff); + mach = (long) ((mac64 >> 32) & 0xffffffff); if (S) /* Store only 48 bits of the result */ { @@ -1419,33 +1314,142 @@ macl (regs, memory, n, m) MACH = mach; } - -/* GET_LOOP_BOUNDS {EXTENDED} - These two functions compute the actual starting and ending point - of the repeat loop, based on the RS and RE registers (repeat start, - repeat stop). The extended version is called for LDRC, and the - regular version is called for SETRC. The difference is that for - LDRC, the loop start and end instructions are literally the ones - pointed to by RS and RE -- for SETRC, they're not (see docs). */ - -static struct loop_bounds -get_loop_bounds_ext (rs, re, memory, mem_end, maskw, endianw) - int rs, re; - unsigned char *memory, *mem_end; - int maskw, endianw; +enum { + B_BCLR = 0, + B_BSET = 1, + B_BST = 2, + B_BLD = 3, + B_BAND = 4, + B_BOR = 5, + B_BXOR = 6, + B_BLDNOT = 11, + B_BANDNOT = 12, + B_BORNOT = 13, + + MOVB_RM = 0x0000, + MOVW_RM = 0x1000, + MOVL_RM = 0x2000, + FMOV_RM = 0x3000, + MOVB_MR = 0x4000, + MOVW_MR = 0x5000, + MOVL_MR = 0x6000, + FMOV_MR = 0x7000, + MOVU_BMR = 0x8000, + MOVU_WMR = 0x9000, +}; + +/* Do extended displacement move instructions. */ +static void +do_long_move_insn (int op, int disp12, int m, int n, int *thatlock) { - struct loop_bounds loop; + int memstalls = 0; + int thislock = *thatlock; + int endianw = global_endianw; + int *R = &(saved_state.asregs.regs[0]); + unsigned char *memory = saved_state.asregs.memory; + int maskb = ~((saved_state.asregs.msize - 1) & ~0); + unsigned char *insn_ptr = PT2H (saved_state.asregs.pc); + + switch (op) { + case MOVB_RM: /* signed */ + WBAT (disp12 * 1 + R[n], R[m]); + break; + case MOVW_RM: + WWAT (disp12 * 2 + R[n], R[m]); + break; + case MOVL_RM: + WLAT (disp12 * 4 + R[n], R[m]); + break; + case FMOV_RM: /* floating point */ + if (FPSCR_SZ) + { + MA (1); + WDAT (R[n] + 8 * disp12, m); + } + else + WLAT (R[n] + 4 * disp12, FI (m)); + break; + case MOVB_MR: + R[n] = RSBAT (disp12 * 1 + R[m]); + L (n); + break; + case MOVW_MR: + R[n] = RSWAT (disp12 * 2 + R[m]); + L (n); + break; + case MOVL_MR: + R[n] = RLAT (disp12 * 4 + R[m]); + L (n); + break; + case FMOV_MR: + if (FPSCR_SZ) { + MA (1); + RDAT (R[m] + 8 * disp12, n); + } + else + SET_FI (n, RLAT (R[m] + 4 * disp12)); + break; + case MOVU_BMR: /* unsigned */ + R[n] = RBAT (disp12 * 1 + R[m]); + L (n); + break; + case MOVU_WMR: + R[n] = RWAT (disp12 * 2 + R[m]); + L (n); + break; + default: + RAISE_EXCEPTION (SIGINT); + exit (1); + } + saved_state.asregs.memstalls += memstalls; + *thatlock = thislock; +} - /* FIXME: should I verify RS < RE? */ - loop.start = PT2H (RS); /* FIXME not using the params? */ - loop.end = PT2H (RE & ~1); /* Ignore bit 0 of RE. */ - SKIP_INSN (loop.end); - if (loop.end >= mem_end) - loop.end = PT2H (0); - return loop; +/* Do binary logical bit-manipulation insns. */ +static void +do_blog_insn (int imm, int addr, int binop, + unsigned char *memory, int maskb) +{ + int oldval = RBAT (addr); + + switch (binop) { + case B_BCLR: /* bclr.b */ + WBAT (addr, oldval & ~imm); + break; + case B_BSET: /* bset.b */ + WBAT (addr, oldval | imm); + break; + case B_BST: /* bst.b */ + if (T) + WBAT (addr, oldval | imm); + else + WBAT (addr, oldval & ~imm); + break; + case B_BLD: /* bld.b */ + SET_SR_T ((oldval & imm) != 0); + break; + case B_BAND: /* band.b */ + SET_SR_T (T && ((oldval & imm) != 0)); + break; + case B_BOR: /* bor.b */ + SET_SR_T (T || ((oldval & imm) != 0)); + break; + case B_BXOR: /* bxor.b */ + SET_SR_T (T ^ ((oldval & imm) != 0)); + break; + case B_BLDNOT: /* bldnot.b */ + SET_SR_T ((oldval & imm) == 0); + break; + case B_BANDNOT: /* bandnot.b */ + SET_SR_T (T && ((oldval & imm) == 0)); + break; + case B_BORNOT: /* bornot.b */ + SET_SR_T (T || ((oldval & imm) == 0)); + break; + } } -float +static float fsca_s (int in, double (*f) (double)) { double rad = ldexp ((in & 0xffff), -15) * 3.141592653589793238462643383; @@ -1467,7 +1471,7 @@ fsca_s (int in, double (*f) (double)) return abs (upper - result) >= abs (lower - result) ? upper : lower; } -float +static float fsrra_s (float in) { double result = 1. / sqrt (in); @@ -1494,11 +1498,33 @@ fsrra_s (float in) return upper - result >= result - lower ? upper : lower; } + +/* GET_LOOP_BOUNDS {EXTENDED} + These two functions compute the actual starting and ending point + of the repeat loop, based on the RS and RE registers (repeat start, + repeat stop). The extended version is called for LDRC, and the + regular version is called for SETRC. The difference is that for + LDRC, the loop start and end instructions are literally the ones + pointed to by RS and RE -- for SETRC, they're not (see docs). */ + +static struct loop_bounds +get_loop_bounds_ext (int rs, int re, unsigned char *memory, + unsigned char *mem_end, int maskw, int endianw) +{ + struct loop_bounds loop; + + /* FIXME: should I verify RS < RE? */ + loop.start = PT2H (RS); /* FIXME not using the params? */ + loop.end = PT2H (RE & ~1); /* Ignore bit 0 of RE. */ + SKIP_INSN (loop.end); + if (loop.end >= mem_end) + loop.end = PT2H (0); + return loop; +} + static struct loop_bounds -get_loop_bounds (rs, re, memory, mem_end, maskw, endianw) - int rs, re; - unsigned char *memory, *mem_end; - int maskw, endianw; +get_loop_bounds (int rs, int re, unsigned char *memory, unsigned char *mem_end, + int maskw, int endianw) { struct loop_bounds loop; @@ -1537,24 +1563,43 @@ static void ppi_insn (); #include "ppi.c" -/* Set the memory size to the power of two provided. */ +/* Provide calloc / free versions that use an anonymous mmap. This can + significantly cut the start-up time when a large simulator memory is + required, because pages are only zeroed on demand. */ +#ifdef MAP_ANONYMOUS +static void * +mcalloc (size_t nmemb, size_t size) +{ + void *page; -void -sim_size (power) - int power; + if (nmemb != 1) + size *= nmemb; + return mmap (0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0); +} -{ - saved_state.asregs.msize = 1 << power; +#define mfree(start,length) munmap ((start), (length)) +#else +#define mcalloc calloc +#define mfree(start,length) free(start) +#endif + +/* Set the memory size to the power of two provided. */ +static void +sim_size (int power) +{ sim_memory_size = power; if (saved_state.asregs.memory) { - free (saved_state.asregs.memory); + mfree (saved_state.asregs.memory, saved_state.asregs.msize); } + saved_state.asregs.msize = 1 << power; + saved_state.asregs.memory = - (unsigned char *) calloc (64, saved_state.asregs.msize / 64); + (unsigned char *) mcalloc (1, saved_state.asregs.msize); if (!saved_state.asregs.memory) { @@ -1563,13 +1608,12 @@ sim_size (power) saved_state.asregs.msize); saved_state.asregs.msize = 1; - saved_state.asregs.memory = (unsigned char *) calloc (1, 1); + saved_state.asregs.memory = (unsigned char *) mcalloc (1, 1); } } static void -init_dsp (abfd) - struct bfd *abfd; +init_dsp (struct bfd *abfd) { int was_dsp = target_dsp; unsigned long mach = bfd_get_mach (abfd); @@ -1607,8 +1651,10 @@ init_dsp (abfd) saved_state.asregs.xyram_select = new_select; free (saved_state.asregs.xmem); free (saved_state.asregs.ymem); - saved_state.asregs.xmem = (unsigned char *) calloc (1, ram_area_size); - saved_state.asregs.ymem = (unsigned char *) calloc (1, ram_area_size); + saved_state.asregs.xmem = + (unsigned char *) calloc (1, ram_area_size); + saved_state.asregs.ymem = + (unsigned char *) calloc (1, ram_area_size); /* Disable use of X / Y mmeory if not allocated. */ if (! saved_state.asregs.xmem || ! saved_state.asregs.ymem) @@ -1642,11 +1688,15 @@ init_dsp (abfd) saved_state.asregs.yram_start = 1; } + if (saved_state.asregs.regstack == NULL) + saved_state.asregs.regstack = + calloc (512, sizeof *saved_state.asregs.regstack); + if (target_dsp != was_dsp) { int i, tmp; - for (i = sizeof sh_dsp_table - 1; i >= 0; i--) + for (i = (sizeof sh_dsp_table / sizeof sh_dsp_table[0]) - 1; i >= 0; i--) { tmp = sh_jump_table[0xf000 + i]; sh_jump_table[0xf000 + i] = sh_dsp_table[i]; @@ -1656,12 +1706,8 @@ init_dsp (abfd) } static void -init_pointers () +init_pointers (void) { - host_little_endian = 0; - * (char*) &host_little_endian = 1; - host_little_endian &= 1; - if (saved_state.asregs.msize != 1 << sim_memory_size) { sim_size (sim_memory_size); @@ -1688,7 +1734,7 @@ init_pointers () } static void -dump_profile () +dump_profile (void) { unsigned int minpc; unsigned int maxpc; @@ -1709,9 +1755,7 @@ dump_profile () } static void -gotcall (from, to) - int from; - int to; +gotcall (int from, int to) { swapout (from); swapout (to); @@ -1720,18 +1764,8 @@ gotcall (from, to) #define MMASKB ((saved_state.asregs.msize -1) & ~0) -int -sim_stop (sd) - SIM_DESC sd; -{ - raise_exception (SIGINT); - return 1; -} - void -sim_resume (sd, step, siggnal) - SIM_DESC sd; - int step, siggnal; +sim_resume (SIM_DESC sd, int step, int siggnal) { register unsigned char *insn_ptr; unsigned char *mem_end; @@ -1741,7 +1775,11 @@ sim_resume (sd, step, siggnal) register int memstalls = 0; register int insts = 0; register int prevlock; +#if 1 + int thislock; +#else register int thislock; +#endif register unsigned int doprofile; register int pollcount = 0; /* endianw is used for every insn fetch, hence it makes sense to cache it. @@ -1749,10 +1787,9 @@ sim_resume (sd, step, siggnal) register int endianw = global_endianw; int tick_start = get_now (); - void (*prev) (); void (*prev_fpe) (); - register unsigned char *jump_table = sh_jump_table; + register unsigned short *jump_table = sh_jump_table; register int *R = &(saved_state.asregs.regs[0]); /*register int T;*/ @@ -1766,7 +1803,6 @@ sim_resume (sd, step, siggnal) register unsigned char *memory; register unsigned int sbit = ((unsigned int) 1 << 31); - prev = signal (SIGINT, control_c); prev_fpe = signal (SIGFPE, SIG_IGN); init_pointers (); @@ -1824,6 +1860,7 @@ sim_resume (sd, step, siggnal) #include "code.c" + in_delay_slot = 0; insn_ptr = nip; if (--pollcount < 0) @@ -1901,15 +1938,10 @@ sim_resume (sd, step, siggnal) } signal (SIGFPE, prev_fpe); - signal (SIGINT, prev); } int -sim_write (sd, addr, buffer, size) - SIM_DESC sd; - SIM_ADDR addr; - unsigned char *buffer; - int size; +sim_write (SIM_DESC sd, SIM_ADDR addr, const unsigned char *buffer, int size) { int i; @@ -1923,11 +1955,7 @@ sim_write (sd, addr, buffer, size) } int -sim_read (sd, addr, buffer, size) - SIM_DESC sd; - SIM_ADDR addr; - unsigned char *buffer; - int size; +sim_read (SIM_DESC sd, SIM_ADDR addr, unsigned char *buffer, int size) { int i; @@ -1940,12 +1968,17 @@ sim_read (sd, addr, buffer, size) return size; } +static int gdb_bank_number; +enum { + REGBANK_MACH = 15, + REGBANK_IVN = 16, + REGBANK_PR = 17, + REGBANK_GBR = 18, + REGBANK_MACL = 19 +}; + int -sim_store_register (sd, rn, memory, length) - SIM_DESC sd; - int rn; - unsigned char *memory; - int length; +sim_store_register (SIM_DESC sd, int rn, unsigned char *memory, int length) { unsigned val; @@ -2050,6 +2083,12 @@ sim_store_register (sd, rn, memory, length) case SIM_SH_R2_BANK0_REGNUM: case SIM_SH_R3_BANK0_REGNUM: case SIM_SH_R4_BANK0_REGNUM: case SIM_SH_R5_BANK0_REGNUM: case SIM_SH_R6_BANK0_REGNUM: case SIM_SH_R7_BANK0_REGNUM: + if (saved_state.asregs.bfd_mach == bfd_mach_sh2a) + { + rn -= SIM_SH_R0_BANK0_REGNUM; + saved_state.asregs.regstack[gdb_bank_number].regs[rn] = val; + } + else if (SR_MD && SR_RB) Rn_BANK (rn - SIM_SH_R0_BANK0_REGNUM) = val; else @@ -2059,6 +2098,12 @@ sim_store_register (sd, rn, memory, length) case SIM_SH_R2_BANK1_REGNUM: case SIM_SH_R3_BANK1_REGNUM: case SIM_SH_R4_BANK1_REGNUM: case SIM_SH_R5_BANK1_REGNUM: case SIM_SH_R6_BANK1_REGNUM: case SIM_SH_R7_BANK1_REGNUM: + if (saved_state.asregs.bfd_mach == bfd_mach_sh2a) + { + rn -= SIM_SH_R0_BANK1_REGNUM; + saved_state.asregs.regstack[gdb_bank_number].regs[rn + 8] = val; + } + else if (SR_MD && SR_RB) saved_state.asregs.regs[rn - SIM_SH_R0_BANK1_REGNUM] = val; else @@ -2070,18 +2115,43 @@ sim_store_register (sd, rn, memory, length) case SIM_SH_R6_BANK_REGNUM: case SIM_SH_R7_BANK_REGNUM: SET_Rn_BANK (rn - SIM_SH_R0_BANK_REGNUM, val); break; + case SIM_SH_TBR_REGNUM: + TBR = val; + break; + case SIM_SH_IBNR_REGNUM: + IBNR = val; + break; + case SIM_SH_IBCR_REGNUM: + IBCR = val; + break; + case SIM_SH_BANK_REGNUM: + /* This is a pseudo-register maintained just for gdb. + It tells us what register bank gdb would like to read/write. */ + gdb_bank_number = val; + break; + case SIM_SH_BANK_MACL_REGNUM: + saved_state.asregs.regstack[gdb_bank_number].regs[REGBANK_MACL] = val; + break; + case SIM_SH_BANK_GBR_REGNUM: + saved_state.asregs.regstack[gdb_bank_number].regs[REGBANK_GBR] = val; + break; + case SIM_SH_BANK_PR_REGNUM: + saved_state.asregs.regstack[gdb_bank_number].regs[REGBANK_PR] = val; + break; + case SIM_SH_BANK_IVN_REGNUM: + saved_state.asregs.regstack[gdb_bank_number].regs[REGBANK_IVN] = val; + break; + case SIM_SH_BANK_MACH_REGNUM: + saved_state.asregs.regstack[gdb_bank_number].regs[REGBANK_MACH] = val; + break; default: return 0; } - return -1; + return length; } int -sim_fetch_register (sd, rn, memory, length) - SIM_DESC sd; - int rn; - unsigned char *memory; - int length; +sim_fetch_register (SIM_DESC sd, int rn, unsigned char *memory, int length) { int val; @@ -2185,6 +2255,12 @@ sim_fetch_register (sd, rn, memory, length) case SIM_SH_R2_BANK0_REGNUM: case SIM_SH_R3_BANK0_REGNUM: case SIM_SH_R4_BANK0_REGNUM: case SIM_SH_R5_BANK0_REGNUM: case SIM_SH_R6_BANK0_REGNUM: case SIM_SH_R7_BANK0_REGNUM: + if (saved_state.asregs.bfd_mach == bfd_mach_sh2a) + { + rn -= SIM_SH_R0_BANK0_REGNUM; + val = saved_state.asregs.regstack[gdb_bank_number].regs[rn]; + } + else val = (SR_MD && SR_RB ? Rn_BANK (rn - SIM_SH_R0_BANK0_REGNUM) : saved_state.asregs.regs[rn - SIM_SH_R0_BANK0_REGNUM]); @@ -2193,6 +2269,12 @@ sim_fetch_register (sd, rn, memory, length) case SIM_SH_R2_BANK1_REGNUM: case SIM_SH_R3_BANK1_REGNUM: case SIM_SH_R4_BANK1_REGNUM: case SIM_SH_R5_BANK1_REGNUM: case SIM_SH_R6_BANK1_REGNUM: case SIM_SH_R7_BANK1_REGNUM: + if (saved_state.asregs.bfd_mach == bfd_mach_sh2a) + { + rn -= SIM_SH_R0_BANK1_REGNUM; + val = saved_state.asregs.regstack[gdb_bank_number].regs[rn + 8]; + } + else val = (! SR_MD || ! SR_RB ? Rn_BANK (rn - SIM_SH_R0_BANK1_REGNUM) : saved_state.asregs.regs[rn - SIM_SH_R0_BANK1_REGNUM]); @@ -2203,25 +2285,44 @@ sim_fetch_register (sd, rn, memory, length) case SIM_SH_R6_BANK_REGNUM: case SIM_SH_R7_BANK_REGNUM: val = Rn_BANK (rn - SIM_SH_R0_BANK_REGNUM); break; + case SIM_SH_TBR_REGNUM: + val = TBR; + break; + case SIM_SH_IBNR_REGNUM: + val = IBNR; + break; + case SIM_SH_IBCR_REGNUM: + val = IBCR; + break; + case SIM_SH_BANK_REGNUM: + /* This is a pseudo-register maintained just for gdb. + It tells us what register bank gdb would like to read/write. */ + val = gdb_bank_number; + break; + case SIM_SH_BANK_MACL_REGNUM: + val = saved_state.asregs.regstack[gdb_bank_number].regs[REGBANK_MACL]; + break; + case SIM_SH_BANK_GBR_REGNUM: + val = saved_state.asregs.regstack[gdb_bank_number].regs[REGBANK_GBR]; + break; + case SIM_SH_BANK_PR_REGNUM: + val = saved_state.asregs.regstack[gdb_bank_number].regs[REGBANK_PR]; + break; + case SIM_SH_BANK_IVN_REGNUM: + val = saved_state.asregs.regstack[gdb_bank_number].regs[REGBANK_IVN]; + break; + case SIM_SH_BANK_MACH_REGNUM: + val = saved_state.asregs.regstack[gdb_bank_number].regs[REGBANK_MACH]; + break; default: return 0; } * (int *) memory = swap (val); - return -1; -} - -int -sim_trace (sd) - SIM_DESC sd; -{ - return 0; + return length; } void -sim_stop_reason (sd, reason, sigrc) - SIM_DESC sd; - enum sim_stop *reason; - int *sigrc; +sim_stop_reason (SIM_DESC sd, enum sim_stop *reason, int *sigrc) { /* The SH simulator uses SIGQUIT to indicate that the program has exited, so we must check for it here and translate it to exit. */ @@ -2238,9 +2339,7 @@ sim_stop_reason (sd, reason, sigrc) } void -sim_info (sd, verbose) - SIM_DESC sd; - int verbose; +sim_info (SIM_DESC sd, int verbose) { double timetaken = (double) saved_state.asregs.ticks / (double) now_persec (); @@ -2274,29 +2373,31 @@ sim_info (sd, verbose) } } -void -sim_set_profile (n) - int n; +static sim_cia +sh_pc_get (sim_cpu *cpu) { - saved_state.asregs.profile = n; + return saved_state.asregs.pc; } -void -sim_set_profile_size (n) - int n; +static void +sh_pc_set (sim_cpu *cpu, sim_cia pc) { - sim_profile_size = n; + saved_state.asregs.pc = pc; +} + +static void +free_state (SIM_DESC sd) +{ + if (STATE_MODULES (sd) != NULL) + sim_module_uninstall (sd); + sim_cpu_free_all (sd); + sim_state_free (sd); } SIM_DESC -sim_open (kind, cb, abfd, argv) - SIM_OPEN_KIND kind; - host_callback *cb; - struct bfd *abfd; - char **argv; +sim_open (SIM_OPEN_KIND kind, host_callback *cb, struct bfd *abfd, char **argv) { char **p; - int endian_set = 0; int i; union { @@ -2306,32 +2407,74 @@ sim_open (kind, cb, abfd, argv) } mem_word; - sim_kind = kind; - myname = argv[0]; + SIM_DESC sd = sim_state_alloc (kind, cb); + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + callback = cb; + /* The cpu data is kept in a separately allocated chunk of memory. */ + if (sim_cpu_alloc_all (sd, 1, /*cgen_cpu_max_extra_bytes ()*/0) != SIM_RC_OK) + { + free_state (sd); + return 0; + } + + if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK) + { + free_state (sd); + return 0; + } + + /* getopt will print the error message so we just have to exit if this fails. + FIXME: Hmmm... in the case of gdb we need getopt to call + print_filtered. */ + if (sim_parse_args (sd, argv) != SIM_RC_OK) + { + free_state (sd); + return 0; + } + + /* Check for/establish the a reference program image. */ + if (sim_analyze_program (sd, + (STATE_PROG_ARGV (sd) != NULL + ? *STATE_PROG_ARGV (sd) + : NULL), abfd) != SIM_RC_OK) + { + free_state (sd); + return 0; + } + + /* Configure/verify the target byte order and other runtime + configuration options. */ + if (sim_config (sd) != SIM_RC_OK) + { + sim_module_uninstall (sd); + return 0; + } + + if (sim_post_argv_init (sd) != SIM_RC_OK) + { + /* Uninstall the modules to avoid memory leaks, + file descriptor leaks, etc. */ + sim_module_uninstall (sd); + return 0; + } + + /* CPU specific initialization. */ + for (i = 0; i < MAX_NR_PROCESSORS; ++i) + { + SIM_CPU *cpu = STATE_CPU (sd, i); + + CPU_PC_FETCH (cpu) = sh_pc_get; + CPU_PC_STORE (cpu) = sh_pc_set; + } + for (p = argv + 1; *p != NULL; ++p) { - if (strcmp (*p, "-E") == 0) - { - ++p; - if (*p == NULL) - { - /* FIXME: This doesn't use stderr, but then the rest of the - file doesn't either. */ - callback->printf_filtered (callback, "Missing argument to `-E'.\n"); - return 0; - } - target_little_endian = strcmp (*p, "big") != 0; - endian_set = 1; - } - else if (isdigit (**p)) + if (isdigit (**p)) parse_and_set_memory_size (*p); } - if (abfd != NULL && ! endian_set) - target_little_endian = ! bfd_big_endian (abfd); - if (abfd) init_dsp (abfd); @@ -2343,13 +2486,11 @@ sim_open (kind, cb, abfd, argv) mem_word.c[i] = i; endianb = mem_word.i >> (target_little_endian ? 0 : 24) & 0xff; - /* fudge our descriptor for now */ - return (SIM_DESC) 1; + return sd; } static void -parse_and_set_memory_size (str) - char *str; +parse_and_set_memory_size (const char *str) { int n; @@ -2361,39 +2502,13 @@ parse_and_set_memory_size (str) } void -sim_close (sd, quitting) - SIM_DESC sd; - int quitting; +sim_close (SIM_DESC sd, int quitting) { /* nothing to do */ } SIM_RC -sim_load (sd, prog, abfd, from_tty) - SIM_DESC sd; - char *prog; - bfd *abfd; - int from_tty; -{ - extern bfd *sim_load_file (); /* ??? Don't know where this should live. */ - bfd *prog_bfd; - - prog_bfd = sim_load_file (sd, myname, callback, prog, abfd, - sim_kind == SIM_OPEN_DEBUG, - 0, sim_write); - if (prog_bfd == NULL) - return SIM_RC_FAIL; - if (abfd == NULL) - bfd_close (prog_bfd); - return SIM_RC_OK; -} - -SIM_RC -sim_create_inferior (sd, prog_bfd, argv, env) - SIM_DESC sd; - struct bfd *prog_bfd; - char **argv; - char **env; +sim_create_inferior (SIM_DESC sd, struct bfd *prog_bfd, char **argv, char **env) { /* Clear the registers. */ memset (&saved_state, 0, @@ -2403,6 +2518,13 @@ sim_create_inferior (sd, prog_bfd, argv, env) if (prog_bfd != NULL) saved_state.asregs.pc = bfd_get_start_address (prog_bfd); + /* Set the bfd machine type. */ + if (prog_bfd != NULL) + saved_state.asregs.bfd_mach = bfd_get_mach (prog_bfd); + + if (prog_bfd != NULL) + init_dsp (prog_bfd); + /* Record the program's arguments. */ prog_argv = argv; @@ -2410,11 +2532,9 @@ sim_create_inferior (sd, prog_bfd, argv, env) } void -sim_do_command (sd, cmd) - SIM_DESC sd; - char *cmd; +sim_do_command (SIM_DESC sd, const char *cmd) { - char *sms_cmd = "set-memory-size"; + const char *sms_cmd = "set-memory-size"; int cmdsize; if (cmd == NULL || *cmd == '\0') @@ -2440,10 +2560,3 @@ sim_do_command (sd, cmd) (callback->printf_filtered) (callback, "Error: \"%s\" is not a valid SH simulator command.\n", cmd); } } - -void -sim_set_callbacks (p) - host_callback *p; -{ - callback = p; -}