From 63978407cb10dcb7543d60e443c6a277d75b0fb8 Mon Sep 17 00:00:00 2001 From: Joern Rennecke Date: Mon, 15 May 2000 21:12:42 +0000 Subject: [PATCH] sh-dsp support, simulator speedup by using host byte order: sim: * Makefile.in (interp.o): Depends on ppi.c . (ppi.c): New rule. * gencode.c (printonmatch, think, genopc): Deleted. (MAX_NR_STUFF): Now 42. (tab): Add SH-DSP CPU instructions. Amalgamate ldc / stc / lds / sts instructions with similar bit patterns. Fix opcodes of stc Rm_BANK,@-. Fix semantics of lds.l @+,MACH (no sign extend). (movsxy_tab): New array. For movs, change MMMM field to GGGG, and mmmm field to MMMM. Added entries for movx, movy and parallel processing insns. (ppi_tab): New array. (qfunc): Stabilize sort. (expand_opcode): Handle [01][01]NN, [01][01]xx and [01][01]yy. Handle 'M', 'G' 's' 'X', 'a', 'Y' and 'A'. (dumptable): Now takes three arguments. Changed all callers. Emit just one contigous jump table. (filltable): Now takes an argument. Changed all callers. Make index static. (ppi_moves, expand_ppi_code, ppi_filltable, ppi_gensim): New functions. (gensim_caselist): New function, broken out of gensim. Handle opcode fields 'x', 'y', 's', 'M', 'G', 'X', 'a', and 'Y'. Handle ref '9'. (gensim): Handle 'N' in code field and '8' in refs field. Call gensim_caselist - twice. (ppi_index): New static variable. (main): Unsupport default action. Add dsp support for -x / -s option. Add -p option. * interp.c (sh_jump_table, sh_dsp_table, ppi_table): Declare. (saved_state_type): Rearrange to allow amalgamated ldc / stc / lds / sts to work efficiently. (target_dsp): New static variable. (GBR, VBR, SSR, SPC, MACH, MACL): Reflect saved_state_type change. (FPUL, Rn_BANK, SET_Rn_BANK, M, Q, S, T, SR_BL, SR_RB): Likewise. (SR_MD, SR_RC, SET_SR_BIT, GET_SR, SET_RC, GET_FPSCR): Likewise. (RS, RE, MOD, MOD_ME, DSP_R): Likewise. (set_fpscr1): Likewise. Use target_dsp to check for dsp. (MOD_MSi, SIG_BUS_FETCH): Deleted. (CREG, SREG, PR, SR_MASK_DMY, SR_MASK_DMX, SR_DMY): New macros. (SR_DMX, DSR, MOD_DELTA, GET_DSP_GRD): Likewise. (SET_MOD): Reflect saved_state_type change. Set MOD_DELTA instead of MOD_MS, and encode SR_DMY / SR_DMX into high word of MOD_ME. (set_sr): Reflect saved_state_type change. Fix SR_RB handling. Use SET_MOD. (MA, L, TL, TB): Now controlled by ACE_FAST. (SEXT32): Just cast to int. (SIGN32): Fixed to only shift by 31. (CHECK_INSN_PTR): SIGBUS at insn fetch now represented by insn_end 0. (ppi_insn): Declare. (ppi.c): Include. (init_dsp): Set target_dsp. When it changes, switch end of sh_jump_table with sh_dsp_table. (sim_resume) Don't declare sh_jump_table0. Use sh_jump_table instead. Don't Declare PR if it's #defined. Fix single-stepping (Was broken in Mar 6 16:59:10 patch). (sim_store_register, sim_read_register): Translate accesses to reflect saved_state_type change. * interp.c (set_sr): Set sr. (SET_RC, MOD, MOD_MS, MOD_ME, SET_MOD, MOD_MS, MOD_ME): New macros. (set_fpscr1): Don't bank-switch fpu registers when simulating sh-dsp. (DSP_R): Fix definition. (sim_resume): Remove outdated SET_SR use. * interp.c (saved_state): New members for struct member asregs: rs, re, insn_end, xram_start, yram_start. (struct loop_bounds): New struct. (SKIP_INSN): New macro. (get_loop_bounds): New function. (endianw): Renamed to global_endianw. (maskw): negated bits. (PC): Now insn_ptr. (SR_MASK_RC, SR_RC_INCREMENT, SR_RC, RAISE_EXCEPTION): New macros. (RS, RE, DSP_R, DSP_GRD, A1, A0, X0, X1, Y0, Y1, M0, A1G): Likewise. (M1, A0G, RIAT, PT2H, PH2T, SET_NIP, CHECK_INSN_PTR): Likewise. (SIG_BUS_FETCH): Likewise (raise_exception, riat_fast): New functions. (raise_buserror, sim_stop): Use raise_exception. (PROCESS_SPECIAL_ADDRESS): Use xram_start / yram_start. (BUSERROR, WRITE_BUSERROR, READ_BUSERROR): Reverse sense of mask argument. (FP_OP, set_dr): Use RAISE_EXCEPTION. (wlat_fast, wwat_fast, wbat_fast, rlat_fast, rwat_fast, rbat_fast): Declare. Remove redundant masking. (wwat_fast, rwat_fast): Add argument endianw. Changed callers. (MA): Updated for change pc -> PC. (Delay_Slot): Use RIAT. (empty): Deleted. (trap): Remove argument little_endian. Add argument endianw. Changed all callers. Use raise_exception. (macw): Add argument endainw. Changed all callers. (init_dsp): New function, extended after broken out of init_pointers. (sim_resume): Replace pc with insn_ptr. Replace little_endian with endianw. Replace nia with nip. Reverse sense of maskb / maskw / maskl. Implement logic for zero-overhead loops. Don't try to interpret garbage when getting a SIGBUS at insn fetch. (sim_open): Call init_dsp. * gencode.c (tab): Use SET_NIP instead of nia = . Use PH2T / PT2H / RAISE_EXCEPTION where appropriate. Add extra cycles for brai, braf , bsr, bsrf, jmp, jsr. * interp.c (sim_store_register, sim_fetch_register): Do proper endianness switch. * interp.c (saved_state_type): New members for struct member asregs: xymem_select, xmem, ymem, xmem_offset, ymem_offset. (special_address): Delete. (BUSERROR): Now a two-argument predicate. (PROCESS_SPECIAL_ADDRESS, WRITE_BUSERROR, READ_BUSERROR): New macros. (wlat_little, wwat_little, wbat_any, wlat_big, wwat_big): Delete. (process_wlat_addr, process_wwat_addr): New functions. (process_wbat_addr, process_rlat_addr, process_rwat_addr): Likewise. (process_rbat_addr): Likewise. (wlat_fast, wwat_fast, wbat_fast): Use WRITE_BUSERROR. (rlat_little, rwat_little, rbat_any, rlat_big, rwat_big): Delete. (rlat_fast, rwat_fast, rbat_fast): Use READ_BUSERROR. (RWAT, RLAT, RBAT, WWAT, WLAT, WBAT): Delete SLOW versions. (do_rdat, trap): Delete SLOW code. (SEXT32, SIGN32): New macros. (swap, swap16): Now integer in - integer out. Changed all callers. (strswaplen, strnswap): Delete SLOW versions. (init_pointers): Initialize dsp memory selection (preliminary). (sim_store_register, sim_fetch_register): Use swap instead of big / little endian read / write functions. * interp.c (maskl): Deleted. (endianw, endianb): New variables. (special_address): Now inline. (bp_holder): Put raising of buserror there, rename to: (raise_buserror). (BUSERROR): Now yields a value. Changed all users. (wbat_big): Delete. (wlat_fast, wwat_fast, wbat_fast): New functions. (rlat_fast, rwat_fast, rbat_fast): Likewise. (RWAT, RLAT, RBAT, WWAT, WLAT, WBAT): Use new functions. (do_rdat, do_wdat): Likewise. Take maskl argument instead of little_endian one. Changed caller macros. (swap, swap16): Use w[rw]lat_big / w[rw]lat_little directly. (strswaplen, strnswap): New functions. (trap): Use them to fix up endian mismatches; disable SYS_execve and SYS_execv; fix double address translation for SYS_pipe and SYS_stat. (sym_write, sym_read): Add endianness translation. (sym_store_register, sym_fetch_register): Add maskl local variable. (sim_open): Set endianw and endianb. gdb: * sh-tdep.c (sh_dsp_reg_names, sh3_dsp_reg_names): New arrays. (sh_processor_type_table): Add entries for bfd_mach_sh_dsp and bfd_mach_sh3_dsp. (sh_show_regs): Floating point registers are called fr0-fr15. For sh4, display fpul, fpscr and fr0-fr15 / dr0-dr14 as appropriate. Handle sh-dsp and sh3-dsp. config/sh/tm-sh.h (REGISTER_VIRTUAL_TYPE): sh-dsp / sh3-dsp don't have floating point registers. (DSR_REGNUM, A0G_REGNUM, A0_REGNUM, A1G_REGNUM, A1_REGNUM): Define. (M0_REGNUM, M1_REGNUM, X0_REGNUM, X1_REGNUM, Y0_REGNUM): Likewise. (Y1_REGNUM, MOD_REGNUM, RS_REGNUM, RE_REGNUM, R0B_REGNUM): Likewise. --- gdb/ChangeLog | 14 + gdb/config/sh/tm-sh.h | 21 +- gdb/sh-tdep.c | 70 +- sim/sh/ChangeLog | 150 +++++ sim/sh/gencode.c | 1682 ++++++++++++++++++++++++++++++++++--------------- sim/sh/interp.c | 1195 ++++++++++++++++++++++++++--------- 6 files changed, 2324 insertions(+), 808 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index c5c15d8..129d505a 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,17 @@ +Mon May 15 21:27:27 2000 J"orn Rennecke + + * sh-tdep.c (sh_dsp_reg_names, sh3_dsp_reg_names): New arrays. + (sh_processor_type_table): Add entries for bfd_mach_sh_dsp and + bfd_mach_sh3_dsp. + (sh_show_regs): Floating point registers are called fr0-fr15. + For sh4, display fpul, fpscr and fr0-fr15 / dr0-dr14 as appropriate. + Handle sh-dsp and sh3-dsp. + config/sh/tm-sh.h (REGISTER_VIRTUAL_TYPE): sh-dsp / sh3-dsp + don't have floating point registers. + (DSR_REGNUM, A0G_REGNUM, A0_REGNUM, A1G_REGNUM, A1_REGNUM): Define. + (M0_REGNUM, M1_REGNUM, X0_REGNUM, X1_REGNUM, Y0_REGNUM): Likewise. + (Y1_REGNUM, MOD_REGNUM, RS_REGNUM, RE_REGNUM, R0B_REGNUM): Likewise. + 2000-05-15 Eli Zaretskii * Makefile.in (gdbtypes.o, varobj.o): Depend on wrapper.h. diff --git a/gdb/config/sh/tm-sh.h b/gdb/config/sh/tm-sh.h index ad26ec1..47256ae 100644 --- a/gdb/config/sh/tm-sh.h +++ b/gdb/config/sh/tm-sh.h @@ -101,8 +101,10 @@ extern CORE_ADDR sh_skip_prologue PARAMS ((CORE_ADDR)); of data in register N. */ #define REGISTER_VIRTUAL_TYPE(N) \ - ((((N) >= FP0_REGNUM && (N) <= FP15_REGNUM) \ - || (N) == FPUL_REGNUM) \ + (((((N) >= FP0_REGNUM && (N) <= FP15_REGNUM) \ + || (N) == FPUL_REGNUM) \ + && TARGET_ARCHITECTURE->mach != bfd_mach_sh_dsp \ + && TARGET_ARCHITECTURE->mach != bfd_mach_sh3_dsp) \ ? builtin_type_float : builtin_type_int) /* Initializer for an array of names of registers. @@ -135,12 +137,27 @@ extern char **sh_register_names; #define SR_REGNUM 22 #define FPUL_REGNUM 23 #define FPSCR_REGNUM 24 +#define DSR_REGNUM 24 #define FP0_REGNUM 25 #define FP15_REGNUM 40 +#define A0G_REGNUM 25 +#define A0_REGNUM 26 +#define A1G_REGNUM 27 +#define A1_REGNUM 28 +#define M0_REGNUM 29 +#define M1_REGNUM 30 +#define X0_REGNUM 31 +#define X1_REGNUM 32 +#define Y0_REGNUM 33 +#define Y1_REGNUM 34 +#define MOD_REGNUM 40 #define SSR_REGNUM 41 #define SPC_REGNUM 42 #define R0B0_REGNUM 43 #define R0B1_REGNUM 51 +#define RS_REGNUM 43 +#define RE_REGNUM 44 +#define R0B_REGNUM 51 #define NUM_REALREGS 59 diff --git a/gdb/sh-tdep.c b/gdb/sh-tdep.c index 1c98caf..941e13f 100644 --- a/gdb/sh-tdep.c +++ b/gdb/sh-tdep.c @@ -86,6 +86,30 @@ static char *sh3e_reg_names[] = { "r0b0", "r1b0", "r2b0", "r3b0", "r4b0", "r5b0", "r6b0", "r7b0", "r0b1", "r1b1", "r2b1", "r3b1", "r4b1", "r5b1", "r6b1", "r7b1", }; + +static char *sh_dsp_reg_names[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "pc", "pr", "gbr", "vbr", "mach", "macl", "sr", + "", "dsr", + "a0g", "a0", "a1g", "a1", "m0", "m1", "x0", "x1", + "y0", "y1", "", "", "", "", "", "mod", + "", "", + "rs", "re", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", +}; + +static char *sh3_dsp_reg_names[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "pc", "pr", "gbr", "vbr", "mach", "macl", "sr", + "", "dsr", + "a0g", "a0", "a1g", "a1", "m0", "m1", "x0", "x1", + "y0", "y1", "", "", "", "", "", "mod", + "ssr", "spc", + "rs", "re", "", "", "", "", "", "", + "r0b", "r1b", "r2b", "r3b", "r4b", "r5b", "r6b", "r7b", +}; /* *INDENT-ON* */ #ifdef _WIN32_WCE @@ -110,10 +134,18 @@ sh_processor_type_table[] = } , { + sh_dsp_reg_names, bfd_mach_sh_dsp + } + , + { sh3_reg_names, bfd_mach_sh3 } , { + sh3_dsp_reg_names, bfd_mach_sh3_dsp + } + , + { sh3e_reg_names, bfd_mach_sh3e } , @@ -648,18 +680,21 @@ sh_show_regs (args, from_tty) printf_filtered ("GBR=%08lx VBR=%08lx", (long) read_register (GBR_REGNUM), (long) read_register (VBR_REGNUM)); - if (cpu == bfd_mach_sh3 || cpu == bfd_mach_sh3e) + if (cpu == bfd_mach_sh3 || cpu == bfd_mach_sh3e || cpu == bfd_mach_sh3_dsp + || cpu == bfd_mach_sh4) { printf_filtered (" SSR=%08lx SPC=%08lx", (long) read_register (SSR_REGNUM), (long) read_register (SPC_REGNUM)); - if (cpu == bfd_mach_sh3e) + if (cpu == bfd_mach_sh3e || cpu == bfd_mach_sh4) { printf_filtered (" FPUL=%08lx FPSCR=%08lx", (long) read_register (FPUL_REGNUM), (long) read_register (FPSCR_REGNUM)); } } + if (cpu == bfd_mach_sh_dsp || cpu == bfd_mach_sh3_dsp) + printf_filtered (" DSR=%08lx", (long) read_register (DSR_REGNUM)); printf_filtered ("\nR0-R7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", (long) read_register (0), @@ -679,9 +714,13 @@ sh_show_regs (args, from_tty) (long) read_register (13), (long) read_register (14), (long) read_register (15)); - if (cpu == bfd_mach_sh3e) + if (cpu == bfd_mach_sh3e || cpu == bfd_mach_sh4) { - printf_filtered ("FP0-FP7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", + int pr = cpu == bfd_mach_sh4 && (read_register (FPSCR_REGNUM) & 0x80000); + + printf_filtered ((pr + ? "DR0-DR6 %08lx%08lx %08lx%08lx %08lx%08lx %08lx%08lx\n" + : "FP0-FP7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n"), (long) read_register (FP0_REGNUM + 0), (long) read_register (FP0_REGNUM + 1), (long) read_register (FP0_REGNUM + 2), @@ -690,7 +729,9 @@ sh_show_regs (args, from_tty) (long) read_register (FP0_REGNUM + 5), (long) read_register (FP0_REGNUM + 6), (long) read_register (FP0_REGNUM + 7)); - printf_filtered ("FP8-FP15 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", + printf_filtered ((pr + ? "DR8-DR14 %08lx%08lx %08lx%08lx %08lx%08lx %08lx%08lx\n" + : "FP8-FP15 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n"), (long) read_register (FP0_REGNUM + 8), (long) read_register (FP0_REGNUM + 9), (long) read_register (FP0_REGNUM + 10), @@ -700,6 +741,25 @@ sh_show_regs (args, from_tty) (long) read_register (FP0_REGNUM + 14), (long) read_register (FP0_REGNUM + 15)); } + /* FIXME: sh4 has more registers */ + if (cpu == bfd_mach_sh_dsp || cpu == bfd_mach_sh3_dsp) + { + printf_filtered ("A0G=%02lx A0=%08lx M0=%08lx X0=%08lx Y0=%08lx RS=%08lx MOD=%08lx\n", + (long) read_register (A0G_REGNUM) & 0xff, + (long) read_register (A0_REGNUM), + (long) read_register (M0_REGNUM), + (long) read_register (X0_REGNUM), + (long) read_register (Y0_REGNUM), + (long) read_register (RS_REGNUM), + (long) read_register (MOD_REGNUM)); + printf_filtered ("A1G=%02lx A1=%08lx M1=%08lx X1=%08lx Y1=%08lx RE=%08lx\n", + (long) read_register (A1G_REGNUM) & 0xff, + (long) read_register (A1_REGNUM), + (long) read_register (M1_REGNUM), + (long) read_register (X1_REGNUM), + (long) read_register (Y1_REGNUM), + (long) read_register (RE_REGNUM)); + } } /* Function: extract_return_value diff --git a/sim/sh/ChangeLog b/sim/sh/ChangeLog index 3a7cc82..ba45674 100644 --- a/sim/sh/ChangeLog +++ b/sim/sh/ChangeLog @@ -1,3 +1,153 @@ +Mon May 15 22:04:51 2000 J"orn Rennecke + +sh-dsp support, simulator speedup by using host byte order: + + * Makefile.in (interp.o): Depends on ppi.c . + (ppi.c): New rule. + * gencode.c (printonmatch, think, genopc): Deleted. + (MAX_NR_STUFF): Now 42. + (tab): Add SH-DSP CPU instructions. + Amalgamate ldc / stc / lds / sts instructions with similar + bit patterns. Fix opcodes of stc Rm_BANK,@-. + Fix semantics of lds.l @+,MACH (no sign extend). + (movsxy_tab): New array. + For movs, change MMMM field to GGGG, and mmmm field to MMMM. + Added entries for movx, movy and parallel processing insns. + (ppi_tab): New array. + (qfunc): Stabilize sort. + (expand_opcode): Handle [01][01]NN, [01][01]xx and [01][01]yy. + Handle 'M', 'G' 's' 'X', 'a', 'Y' and 'A'. + (dumptable): Now takes three arguments. Changed all callers. + Emit just one contigous jump table. + (filltable): Now takes an argument. Changed all callers. + Make index static. + (ppi_moves, expand_ppi_code, ppi_filltable, ppi_gensim): New functions. + (gensim_caselist): New function, broken out of gensim. + Handle opcode fields 'x', 'y', 's', 'M', 'G', 'X', 'a', and 'Y'. + Handle ref '9'. + (gensim): Handle 'N' in code field and '8' in refs field. + Call gensim_caselist - twice. + (ppi_index): New static variable. + (main): Unsupport default action. + Add dsp support for -x / -s option. Add -p option. + * interp.c (sh_jump_table, sh_dsp_table, ppi_table): Declare. + (saved_state_type): Rearrange to allow amalgamated ldc / stc / + lds / sts to work efficiently. + (target_dsp): New static variable. + (GBR, VBR, SSR, SPC, MACH, MACL): Reflect saved_state_type change. + (FPUL, Rn_BANK, SET_Rn_BANK, M, Q, S, T, SR_BL, SR_RB): Likewise. + (SR_MD, SR_RC, SET_SR_BIT, GET_SR, SET_RC, GET_FPSCR): Likewise. + (RS, RE, MOD, MOD_ME, DSP_R): Likewise. + (set_fpscr1): Likewise. Use target_dsp to check for dsp. + (MOD_MSi, SIG_BUS_FETCH): Deleted. + (CREG, SREG, PR, SR_MASK_DMY, SR_MASK_DMX, SR_DMY): New macros. + (SR_DMX, DSR, MOD_DELTA, GET_DSP_GRD): Likewise. + (SET_MOD): Reflect saved_state_type change. Set MOD_DELTA instead + of MOD_MS, and encode SR_DMY / SR_DMX into high word of MOD_ME. + (set_sr): Reflect saved_state_type change. Fix SR_RB handling. + Use SET_MOD. + (MA, L, TL, TB): Now controlled by ACE_FAST. + (SEXT32): Just cast to int. + (SIGN32): Fixed to only shift by 31. + (CHECK_INSN_PTR): SIGBUS at insn fetch now represented by insn_end 0. + (ppi_insn): Declare. + (ppi.c): Include. + (init_dsp): Set target_dsp. When it changes, switch end of + sh_jump_table with sh_dsp_table. + (sim_resume) Don't declare sh_jump_table0. Use sh_jump_table instead. + Don't Declare PR if it's #defined. + Fix single-stepping (Was broken in Mar 6 16:59:10 patch). + (sim_store_register, sim_read_register): Translate accesses to + reflect saved_state_type change. + + * interp.c (set_sr): Set sr. + (SET_RC, MOD, MOD_MS, MOD_ME, SET_MOD, MOD_MS, MOD_ME): New macros. + (set_fpscr1): Don't bank-switch fpu registers when simulating sh-dsp. + (DSP_R): Fix definition. + (sim_resume): Remove outdated SET_SR use. + + * interp.c (saved_state): New members for struct member asregs: + rs, re, insn_end, xram_start, yram_start. + (struct loop_bounds): New struct. + (SKIP_INSN): New macro. + (get_loop_bounds): New function. + (endianw): Renamed to global_endianw. + (maskw): negated bits. + (PC): Now insn_ptr. + (SR_MASK_RC, SR_RC_INCREMENT, SR_RC, RAISE_EXCEPTION): New macros. + (RS, RE, DSP_R, DSP_GRD, A1, A0, X0, X1, Y0, Y1, M0, A1G): Likewise. + (M1, A0G, RIAT, PT2H, PH2T, SET_NIP, CHECK_INSN_PTR): Likewise. + (SIG_BUS_FETCH): Likewise + (raise_exception, riat_fast): New functions. + (raise_buserror, sim_stop): Use raise_exception. + (PROCESS_SPECIAL_ADDRESS): Use xram_start / yram_start. + (BUSERROR, WRITE_BUSERROR, READ_BUSERROR): + Reverse sense of mask argument. + (FP_OP, set_dr): Use RAISE_EXCEPTION. + (wlat_fast, wwat_fast, wbat_fast, rlat_fast, rwat_fast, rbat_fast): + Declare. Remove redundant masking. + (wwat_fast, rwat_fast): Add argument endianw. Changed callers. + (MA): Updated for change pc -> PC. + (Delay_Slot): Use RIAT. + (empty): Deleted. + (trap): Remove argument little_endian. Add argument endianw. + Changed all callers. Use raise_exception. + (macw): Add argument endainw. Changed all callers. + (init_dsp): New function, extended after broken out of init_pointers. + (sim_resume): Replace pc with insn_ptr. Replace little_endian with + endianw. Replace nia with nip. Reverse sense of maskb / maskw / + maskl. Implement logic for zero-overhead loops. Don't try to + interpret garbage when getting a SIGBUS at insn fetch. + (sim_open): Call init_dsp. + * gencode.c (tab): Use SET_NIP instead of nia = . Use PH2T / PT2H / + RAISE_EXCEPTION where appropriate. + Add extra cycles for brai, braf , bsr, bsrf, jmp, jsr. + + * interp.c (sim_store_register, sim_fetch_register): + Do proper endianness switch. + + * interp.c (saved_state_type): New members for struct member asregs: + xymem_select, xmem, ymem, xmem_offset, ymem_offset. + (special_address): Delete. + (BUSERROR): Now a two-argument predicate. + (PROCESS_SPECIAL_ADDRESS, WRITE_BUSERROR, READ_BUSERROR): New macros. + (wlat_little, wwat_little, wbat_any, wlat_big, wwat_big): Delete. + (process_wlat_addr, process_wwat_addr): New functions. + (process_wbat_addr, process_rlat_addr, process_rwat_addr): Likewise. + (process_rbat_addr): Likewise. + (wlat_fast, wwat_fast, wbat_fast): Use WRITE_BUSERROR. + (rlat_little, rwat_little, rbat_any, rlat_big, rwat_big): Delete. + (rlat_fast, rwat_fast, rbat_fast): Use READ_BUSERROR. + (RWAT, RLAT, RBAT, WWAT, WLAT, WBAT): Delete SLOW versions. + (do_rdat, trap): Delete SLOW code. + (SEXT32, SIGN32): New macros. + (swap, swap16): Now integer in - integer out. Changed all callers. + (strswaplen, strnswap): Delete SLOW versions. + (init_pointers): Initialize dsp memory selection (preliminary). + (sim_store_register, sim_fetch_register): Use swap instead of + big / little endian read / write functions. + + * interp.c (maskl): Deleted. + (endianw, endianb): New variables. + (special_address): Now inline. + (bp_holder): Put raising of buserror there, rename to: + (raise_buserror). + (BUSERROR): Now yields a value. Changed all users. + (wbat_big): Delete. + (wlat_fast, wwat_fast, wbat_fast): New functions. + (rlat_fast, rwat_fast, rbat_fast): Likewise. + (RWAT, RLAT, RBAT, WWAT, WLAT, WBAT): Use new functions. + (do_rdat, do_wdat): Likewise. Take maskl argument instead of + little_endian one. Changed caller macros. + (swap, swap16): Use w[rw]lat_big / w[rw]lat_little directly. + (strswaplen, strnswap): New functions. + (trap): Use them to fix up endian mismatches; + disable SYS_execve and SYS_execv; fix double address translation for + SYS_pipe and SYS_stat. + (sym_write, sym_read): Add endianness translation. + (sym_store_register, sym_fetch_register): Add maskl local variable. + (sim_open): Set endianw and endianb. + Thu Sep 2 18:15:53 1999 Andrew Cagney * configure: Regenerated to track ../common/aclocal.m4 changes. diff --git a/sim/sh/gencode.c b/sim/sh/gencode.c index 3aa3918..02605fc 100644 --- a/sim/sh/gencode.c +++ b/sim/sh/gencode.c @@ -25,13 +25,13 @@ -s generates the simulator code jump table -d generates a define table -x generates the simulator code switch statement - default generates the opcode tables + default used to generate the opcode tables */ #include -#define MAX_NR_STUFF 20 +#define MAX_NR_STUFF 42 typedef struct { @@ -86,51 +86,55 @@ op tab[] = { "", "", "bf ", "10001011i8p1....", "if (!T) {", - " nia = PC + 4 + (SEXT(i) * 2);", + " SET_NIP (PC + 4 + (SEXT(i) * 2));", " cycles += 2;", "}", }, { "", "", "bf.s ", "10001111i8p1....", "if (!T) {", - " nia = PC + 4 + (SEXT (i) * 2);", + " SET_NIP (PC + 4 + (SEXT (i) * 2));", " cycles += 2;", " Delay_Slot (PC + 2);", "}", }, { "", "", "bra ", "1010i12.........", - "nia = PC + 4 + (SEXT12 (i) * 2);", + "SET_NIP (PC + 4 + (SEXT12 (i) * 2));", + "cycles += 2;", "Delay_Slot (PC + 2);", }, { "", "n", "braf ", "0000nnnn00100011", - "nia = PC + 4 + R[n];", + "SET_NIP (PC + 4 + R[n]);", + "cycles += 2;", "Delay_Slot (PC + 2);", }, { "", "", "bsr ", "1011i12.........", - "PR = PC + 4;", - "nia = PC + 4 + (SEXT12 (i) * 2);", + "PR = PH2T (PC + 4);", + "SET_NIP (PC + 4 + (SEXT12 (i) * 2));", + "cycles += 2;", "Delay_Slot (PC + 2);", }, { "", "n", "bsrf ", "0000nnnn00000011", - "PR = PC + 4;", - "nia = PC + 4 + R[n];", + "PR = PH2T (PC) + 4;", + "SET_NIP (PC + 4 + R[n]);", + "cycles += 2;", "Delay_Slot (PC + 2);", }, { "", "", "bt ", "10001001i8p1....", "if (T) {", - " nia = PC + 4 + (SEXT (i) * 2);", + " SET_NIP (PC + 4 + (SEXT (i) * 2));", " cycles += 2;", "}", }, { "", "", "bt.s ", "10001101i8p1....", "if (T) {", - " nia = PC + 4 + (SEXT (i) * 2);", + " SET_NIP (PC + 4 + (SEXT (i) * 2));", " cycles += 2;", " Delay_Slot (PC + 2);", "}", @@ -247,7 +251,7 @@ op tab[] = /* sh4 */ { "", "", "fcnvds ,FPUL", "1111nnnn10111101", "if (! FPSCR_PR || n & 1)", - " saved_state.asregs.exception = SIGILL;", + " RAISE_EXCEPTION (SIGILL);", "else", "{", " union", @@ -263,7 +267,7 @@ op tab[] = /* sh4 */ { "", "", "fcnvsd FPUL,", "1111nnnn10101101", "if (! FPSCR_PR || n & 1)", - " saved_state.asregs.exception = SIGILL;", + " RAISE_EXCEPTION (SIGILL);", "else", "{", " union", @@ -285,7 +289,7 @@ op tab[] = /* sh4 */ { "", "", "fipr ,", "1111nnmm11101101", "/* FIXME: not implemented */", - "saved_state.asregs.exception = SIGILL;", + "RAISE_EXCEPTION (SIGILL);", "/* FIXME: check for DP and (n & 1) == 0? */", }, @@ -486,37 +490,30 @@ op tab[] = }, { "", "n", "jmp @", "0100nnnn00101011", - "nia = R[n];", + "SET_NIP (PT2H (R[n]));", + "cycles += 2;", "Delay_Slot (PC + 2);", }, { "", "n", "jsr @", "0100nnnn00001011", - "PR = PC + 4;", - "nia = R[n];", + "PR = PH2T (PC + 4);", "if (~doprofile)", - " gotcall (PR, nia);", + " gotcall (PR, R[n]);", + "SET_NIP (PT2H (R[n]));", + "cycles += 2;", "Delay_Slot (PC + 2);", }, - { "", "n", "ldc ,GBR", "0100nnnn00011110", - "GBR = R[n];", + { "", "n", "ldc ,", "0100nnnnmmmm1110", + "CREG (m) = R[n];", "/* FIXME: user mode */", }, { "", "n", "ldc ,SR", "0100nnnn00001110", "SET_SR (R[n]);", "/* FIXME: user mode */", }, - { "", "n", "ldc ,VBR", "0100nnnn00101110", - "VBR = R[n];", - "/* FIXME: user mode */", - }, - { "", "n", "ldc ,SSR", "0100nnnn00111110", - "SSR = R[n];", - "/* FIXME: user mode */", - }, - { "", "n", "ldc ,SPC", "0100nnnn01001110", - "SPC = R[n];", - "/* FIXME: user mode */", + { "", "n", "ldc ,MOD", "0100nnnn01011110", + "SET_MOD (R[n]);", }, #if 0 { "", "n", "ldc ,DBR", "0100nnnn11111010", @@ -524,41 +521,9 @@ op tab[] = "/* FIXME: user mode */", }, #endif - { "", "n", "ldc ,R0_BANK", "0100nnnn10001110", - "SET_Rn_BANK (0, R[n]);", - "/* FIXME: user mode */", - }, - { "", "n", "ldc ,R1_BANK", "0100nnnn10011110", - "SET_Rn_BANK (1, R[n]);", - "/* FIXME: user mode */", - }, - { "", "n", "ldc ,R2_BANK", "0100nnnn10101110", - "SET_Rn_BANK (2, R[n]);", - "/* FIXME: user mode */", - }, - { "", "n", "ldc ,R3_BANK", "0100nnnn10111110", - "SET_Rn_BANK (3, R[n]);", - "/* FIXME: user mode */", - }, - { "", "n", "ldc ,R4_BANK", "0100nnnn11001110", - "SET_Rn_BANK (4, R[n]);", - "/* FIXME: user mode */", - }, - { "", "n", "ldc ,R5_BANK", "0100nnnn11011110", - "SET_Rn_BANK (5, R[n]);", - "/* FIXME: user mode */", - }, - { "", "n", "ldc ,R6_BANK", "0100nnnn11101110", - "SET_Rn_BANK (6, R[n]);", - "/* FIXME: user mode */", - }, - { "", "n", "ldc ,R7_BANK", "0100nnnn11111110", - "SET_Rn_BANK (7, R[n]);", - "/* FIXME: user mode */", - }, - { "", "n", "ldc.l @+,GBR", "0100nnnn00010111", + { "", "n", "ldc.l @+,", "0100nnnnmmmm0111", "MA (1);", - "GBR = RLAT (R[n]);", + "CREG (m) = RLAT (R[n]);", "R[n] += 4;", "/* FIXME: user mode */", }, @@ -568,23 +533,10 @@ op tab[] = "R[n] += 4;", "/* FIXME: user mode */", }, - { "", "n", "ldc.l @+,VBR", "0100nnnn00100111", + { "", "n", "ldc.l @+,MOD", "0100nnnn01010111", "MA (1);", - "VBR = RLAT (R[n]);", + "SET_MOD (RLAT (R[n]));", "R[n] += 4;", - "/* FIXME: user mode */", - }, - { "", "n", "ldc.l @+,SSR", "0100nnnn00110111", - "MA (1);", - "SSR = RLAT (R[n]);", - "R[n] += 4;", - "/* FIXME: user mode */", - }, - { "", "n", "ldc.l @+,SPC", "0100nnnn01000111", - "MA (1);", - "SPC = RLAT (R[n]);", - "R[n] += 4;", - "/* FIXME: user mode */", }, #if 0 { "", "n", "ldc.l @+,DBR", "0100nnnn11110110", @@ -594,112 +546,45 @@ op tab[] = "/* FIXME: user mode */", }, #endif - { "", "n", "ldc.l @+,R0_BANK", "0100nnnn10000111", - "MA (1);", - "SET_Rn_BANK (0, RLAT (R[n]));", - "R[n] += 4;", - "/* FIXME: user mode */", - }, - { "", "n", "ldc.l @+,R1_BANK", "0100nnnn10010111", - "MA (1);", - "SET_Rn_BANK (1, RLAT (R[n]));", - "R[n] += 4;", - "/* FIXME: user mode */", - }, - { "", "n", "ldc.l @+,R2_BANK", "0100nnnn10100111", - "MA (1);", - "SET_Rn_BANK (2, RLAT (R[n]));", - "R[n] += 4;", - "/* FIXME: user mode */", - }, - { "", "n", "ldc.l @+,R3_BANK", "0100nnnn10110111", - "MA (1);", - "SET_Rn_BANK (3, RLAT (R[n]));", - "R[n] += 4;", - "/* FIXME: user mode */", - }, - { "", "n", "ldc.l @+,R4_BANK", "0100nnnn11000111", - "MA (1);", - "SET_Rn_BANK (4, RLAT (R[n]));", - "R[n] += 4;", - "/* FIXME: user mode */", - }, - { "", "n", "ldc.l @+,R5_BANK", "0100nnnn11010111", - "MA (1);", - "SET_Rn_BANK (5, RLAT (R[n]));", - "R[n] += 4;", - "/* FIXME: user mode */", - }, - { "", "n", "ldc.l @+,R6_BANK", "0100nnnn11100111", - "MA (1);", - "SET_Rn_BANK (6, RLAT (R[n]));", - "R[n] += 4;", - "/* FIXME: user mode */", + + /* sh-dsp */ + { "", "", "ldre @(,PC)", "10001110i8p1....", + "RE = SEXT (i) * 2 + 4 + PH2T (PC);", }, - { "", "n", "ldc.l @+,R7_BANK", "0100nnnn11110111", - "MA (1);", - "SET_Rn_BANK (7, RLAT (R[n]));", - "R[n] += 4;", - "/* FIXME: user mode */", + { "", "", "ldrs @(,PC)", "10001100i8p1....", + "RS = SEXT (i) * 2 + 4 + PH2T (PC);", }, - /* sh3e */ - { "", "", "lds ,FPUL", "0100nnnn01011010", - "FPUL = R[n];", + { "", "n", "lds ,", "0100nnnnssss1010", + "SREG (m) = R[n];", }, - /* sh3e */ - { "", "", "lds.l @+,FPUL", "0100nnnn01010110", + { "", "n", "lds.l @+,", "0100nnnnssss0110", "MA (1);", - "FPUL = RLAT(R[n]);", + "SREG (m) = RLAT(R[n]);", "R[n] += 4;", }, - /* sh3e */ - { "", "", "lds ,FPSCR", "0100nnnn01101010", + /* sh3e / sh-dsp (lds ,DSR) */ + { "", "n", "lds ,FPSCR", "0100nnnn01101010", "SET_FPSCR(R[n]);", }, - /* sh3e */ - { "", "", "lds.l @+,FPSCR", "0100nnnn01100110", + /* sh3e / sh-dsp (lds.l @+,DSR) */ + { "", "n", "lds.l @+,FPSCR", "0100nnnn01100110", "MA (1);", "SET_FPSCR (RLAT(R[n]));", "R[n] += 4;", }, - { "", "n", "lds ,MACH", "0100nnnn00001010", - "MACH = R[n];", - }, - { "", "n", "lds ,MACL", "0100nnnn00011010", - "MACL= R[n];", - }, - { "", "n", "lds ,PR", "0100nnnn00101010", - "PR = R[n];", - }, - { "", "n", "lds.l @+,MACH", "0100nnnn00000110", - "MA (1);", - "MACH = SEXT(RLAT(R[n]));", - "R[n]+=4;", - }, - { "", "n", "lds.l @+,MACL", "0100nnnn00010110", - "MA (1);", - "MACL = RLAT(R[n]);", - "R[n]+=4;", - }, - { "", "n", "lds.l @+,PR", "0100nnnn00100110", - "MA (1);", - "PR = RLAT(R[n]);", - "R[n]+=4;;", - }, - { "", "", "ldtlb", "0000000000111000", "/* FIXME: XXX*/ abort();", }, { "", "nm", "mac.l @+,@+", "0000nnnnmmmm1111", - "trap (255,R0,memory,maskl,maskw,little_endian);", + "trap (255,R0,memory,maskl,maskw, endianw);", "/* FIXME: mac.l support */", }, { "", "nm", "mac.w @+,@+", "0100nnnnmmmm1111", - "macw(R0,memory,n,m);", + "macw(R0,memory,n,m,endianw);", }, { "n", "", "mov #,", "1110nnnni8*1....", @@ -764,7 +649,7 @@ op tab[] = }, { "n", "", "mov.l @(,PC),", "1101nnnni8p4....", "MA (1);", - "R[n] = RLAT((PC & ~3) + 4 + i);", + "R[n] = RLAT ((PH2T (PC) & ~3) + 4 + i);", "L (n);", }, { "n", "m", "mov.l @(,),", "0101nnnnmmmmi4*4", @@ -817,7 +702,7 @@ op tab[] = }, { "n", "", "mov.w @(,PC),", "1001nnnni8p2....", "MA (1);", - "R[n] = RSWAT (PC + 4 + i);", + "R[n] = RSWAT (PH2T (PC + 4 + i));", "L (n);", }, { "0", "m", "mov.w @(,),R0", "10000101mmmmi4*2", @@ -864,12 +749,12 @@ op tab[] = }, { "0", "", "mova @(,PC),R0", "11000111i8p4....", - "R0 = ((i + 4 + PC) & ~0x3);", + "R0 = ((i + 4 + PH2T (PC)) & ~0x3);", }, { "0", "", "movca.l @R0, ", "0000nnnn11000011", "/* FIXME: Not implemented */", - "saved_state.asregs.exception = SIGILL;", + "RAISE_EXCEPTION (SIGILL);", }, { "n", "", "movt ", "0000nnnn00101001", @@ -917,12 +802,12 @@ op tab[] = { "0", "", "ocbi @", "0000nnnn10010011", "/* FIXME: Not implemented */", - "saved_state.asregs.exception = SIGILL;", + "RAISE_EXCEPTION (SIGILL);", }, { "0", "", "ocbp @", "0000nnnn10100011", "/* FIXME: Not implemented */", - "saved_state.asregs.exception = SIGILL;", + "RAISE_EXCEPTION (SIGILL);", }, { "", "n", "ocbwb @", "0000nnnn10110011", @@ -974,23 +859,43 @@ op tab[] = #if 0 /* SH-[12] */ "int tmp = PC;", - "nia = RLAT (R[15]) + 2;", + "SET_NIP (PT2H (RLAT (R[15]) + 2));", "R[15] += 4;", "SET_SR (RLAT (R[15]) & 0x3f3);", "R[15] += 4;", "Delay_Slot (PC + 2);", #else - "nia = SPC;", "SET_SR (SSR);", + "SET_NIP (PT2H (SPC));", + "cycles += 2;", "Delay_Slot (PC + 2);", #endif }, { "", "", "rts", "0000000000001011", - "nia = PR;", + "SET_NIP (PT2H (PR));", + "cycles += 2;", "Delay_Slot (PC + 2);", }, + /* sh-dsp */ + { "", "n", "setrc ", "0100nnnn00010100", + "SET_RC (R[n]);", + }, + { "", "n", "setrc #", "10000010i8*1....", + /* It would be more realistic to let loop_start point to some static + memory that contains an illegal opcode and then give a bus error when + the loop is eventually encountered, but it seems not only simpler, + but also more debugging-friendly to just catch the failure here. */ + "if (BUSERROR (RS | RE, maskw))", + " RAISE_EXCEPTION (SIGILL);", + "else {", + " SET_RC (i);", + " loop = get_loop_bounds (RS, RE, memory, mem_end, maskw, endianw);", + " CHECK_INSN_PTR (insn_ptr);", + "}", + }, + { "", "", "sets", "0000000001011000", "SET_SR_S (1);", }, @@ -1048,25 +953,14 @@ op tab[] = }, { "", "", "sleep", "0000000000011011", - "trap (0xc3, R0, memory, maskl, maskw, little_endian);", - "nia = PC;", + "nip = PC;", + "trap (0xc3, R0, memory, maskl, maskw, endianw);", }, - { "n", "", "stc GBR,", "0000nnnn00010010", - "R[n] = GBR;", - }, - { "n", "", "stc SR,", "0000nnnn00000010", - "R[n] = GET_SR ();", - }, - { "n", "", "stc VBR,", "0000nnnn00100010", - "R[n] = VBR;", - }, - { "n", "", "stc SSR,", "0000nnnn00110010", - "R[n] = SSR;", - }, - { "n", "", "stc SPC,", "0000nnnn01000010", - "R[n] = SPC;", + { "n", "", "stc ,", "0000nnnnmmmm0010", + "R[n] = CREG (m);", }, + #if 0 { "n", "", "stc SGR,", "0000nnnn00111010", "R[n] = SGR;", @@ -1075,54 +969,10 @@ op tab[] = "R[n] = DBR;", }, #endif - { "n", "", "stc R0_BANK,", "0000nnnn10000010", - "R[n] = Rn_BANK (0);", - }, - { "n", "", "stc R1_BANK,", "0000nnnn10010010", - "R[n] = Rn_BANK (1);", - }, - { "n", "", "stc R2_BANK,", "0000nnnn10100010", - "R[n] = Rn_BANK (2);", - }, - { "n", "", "stc R3_BANK,", "0000nnnn10110010", - "R[n] = Rn_BANK (3);", - }, - { "n", "", "stc R4_BANK,", "0000nnnn11000010", - "R[n] = Rn_BANK (4);", - }, - { "n", "", "stc R5_BANK,", "0000nnnn11010010", - "R[n] = Rn_BANK (5);", - }, - { "n", "", "stc R6_BANK,", "0000nnnn11100010", - "R[n] = Rn_BANK (6);", - }, - { "n", "", "stc R7_BANK,", "0000nnnn11110010", - "R[n] = Rn_BANK (7);", - }, - { "n", "n", "stc.l GBR,@-", "0100nnnn00010011", + { "n", "n", "stc.l ,@-", "0100nnnnmmmm0011", "MA (1);", "R[n] -= 4;", - "WLAT (R[n], GBR);;", - }, - { "n", "n", "stc.l SR,@-", "0100nnnn00000011", - "MA (1);", - "R[n] -= 4;", - "WLAT (R[n], GET_SR());", - }, - { "n", "n", "stc.l VBR,@-", "0100nnnn00100011", - "MA (1);", - "R[n] -= 4;", - "WLAT (R[n], VBR);", - }, - { "n", "n", "stc.l SSR,@-", "0100nnnn00110011", - "MA (1);", - "R[n] -= 4;", - "WLAT (R[n], SSR);", - }, - { "n", "n", "stc.l SPC,@-", "0100nnnn01000011", - "MA (1);", - "R[n] -= 4;", - "WLAT (R[n], SPC);", + "WLAT (R[n], CREG (m));", }, #if 0 { "n", "n", "stc.l SGR,@-", "0100nnnn00110010", @@ -1136,91 +986,14 @@ op tab[] = "WLAT (R[n], DBR);", }, #endif - { "n", "", "stc R0_BANK,@-", "0100nnnn10000010", - "MA (1);", - "R[n] -= 4;", - "WLAT (R[n], Rn_BANK (0));", - }, - { "n", "", "stc R1_BANK,@-", "0100nnnn10010010", - "MA (1);", - "R[n] -= 4;", - "WLAT (R[n], Rn_BANK (1));", - }, - { "n", "", "stc R2_BANK,@-", "0100nnnn10100010", - "MA (1);", - "R[n] -= 4;", - "WLAT (R[n], Rn_BANK (2));", - }, - { "n", "", "stc R3_BANK,@-", "0100nnnn10110010", - "MA (1);", - "R[n] -= 4;", - "WLAT (R[n], Rn_BANK (3));", - }, - { "n", "", "stc R4_BANK,@-", "0100nnnn11000010", - "MA (1);", - "R[n] -= 4;", - "WLAT (R[n], Rn_BANK (4));", - }, - { "n", "", "stc R5_BANK,@-", "0100nnnn11010010", - "MA (1);", - "R[n] -= 4;", - "WLAT (R[n], Rn_BANK (5));", - }, - { "n", "", "stc R6_BANK,@-", "0100nnnn11100010", - "MA (1);", - "R[n] -= 4;", - "WLAT (R[n], Rn_BANK (6));", - }, - { "n", "", "stc R7_BANK,@-", "0100nnnn11110010", - "MA (1);", - "R[n] -= 4;", - "WLAT (R[n], Rn_BANK (7));", - }, - /* sh3e */ - { "", "", "sts FPUL,", "0000nnnn01011010", - "R[n] = FPUL;", - }, - /* sh3e */ - { "", "", "sts.l FPUL,@-", "0100nnnn01010010", - "MA (1);", - "R[n] -= 4;", - "WLAT (R[n], FPUL);", + { "n", "", "sts ,", "0000nnnnssss1010", + "R[n] = SREG (m);", }, - /* sh3e */ - { "", "", "sts FPSCR,", "0000nnnn01101010", - "R[n] = GET_FPSCR ();", - }, - /* sh3e */ - { "", "", "sts.l FPSCR,@-", "0100nnnn01100010", + { "n", "n", "sts.l ,@-", "0100nnnnssss0010", "MA (1);", "R[n] -= 4;", - "WLAT (R[n], GET_FPSCR ());", - }, - - { "n", "", "sts MACH,", "0000nnnn00001010", - "R[n] = MACH;", - }, - { "n", "", "sts MACL,", "0000nnnn00011010", - "R[n] = MACL;", - }, - { "n", "", "sts PR,", "0000nnnn00101010", - "R[n] = PR;", - }, - { "n", "n", "sts.l MACH,@-", "0100nnnn00000010", - "MA (1);", - "R[n] -= 4;", - "WLAT (R[n], MACH);", - }, - { "n", "n", "sts.l MACL,@-", "0100nnnn00010010", - "MA (1);", - "R[n] -= 4;", - "WLAT (R[n], MACL);", - }, - { "n", "n", "sts.l PR,@-", "0100nnnn00100010", - "MA (1);", - "R[n] -= 4;", - "WLAT (R[n], PR);", + "WLAT (R[n], SREG (m));", }, { "n", "nm", "sub ,", "0011nnnnmmmm1000", @@ -1264,7 +1037,7 @@ op tab[] = "if (i==0xc3)", " PC-=2;", "if (i<20||i==34||i==0xc3)", - " trap(i,R,memory,maskl,maskw,little_endian);", + " trap(i,R,memory,maskl,maskw,endianw);", "else {", " R[15]-=4;", " WLAT(R[15],GET_SR());", @@ -1275,18 +1048,18 @@ op tab[] = #else "if (i == 0xc3)", " {", - " nia = PC;", - " trap (i, R, memory, maskl, maskw, little_endian);", + " nip = PC;", + " trap (i, R, memory, maskl, maskw,endianw);", " }", "else if (i < 20 || i==34 || i==0xc3)", - " trap (i, R, memory, maskl, maskw, little_endian);", + " trap (i, R, memory, maskl, maskw,endianw);", "else if (!SR_BL) {", " /* FIXME: TRA = (imm << 2); */", " SSR = GET_SR();", - " SPC = PC + 2;", + " SPC = PH2T (PC + 2);", " SET_SR (GET_SR() | SR_MASK_MD | SR_MASK_BL | SR_MASK_RB);", " /* FIXME: EXPEVT = 0x00000160; */", - " nia = VBR + 0x00000100;", + " SET_NIP (PT2H (VBR + 0x00000100));", "}", #endif }, @@ -1331,6 +1104,711 @@ op tab[] = {0, 0}}; +op movsxy_tab[] = +{ +/* If this is disabled, the simulator speeds up by about 12% on a + 450 MHz PIII - 9% with ACE_FAST. + Maybe we should have separate simulator loops? */ +#if 1 + { "n", "n", "movs.w @-,", "111101NNMMMM0000", + "MA (1);", + "R[n] -= 2;", + "DSP_R (m) = RSWAT (R[n]) << 16;", + "DSP_GRD (m) = SIGN32 (DSP_R (m));", + }, + { "", "n", "movs.w @,", "111101NNMMMM0100", + "MA (1);", + "DSP_R (m) = RSWAT (R[n]) << 16;", + "DSP_GRD (m) = SIGN32 (DSP_R (m));", + }, + { "n", "n", "movs.w @+,", "111101NNMMMM1000", + "MA (1);", + "DSP_R (m) = RSWAT (R[n]) << 16;", + "DSP_GRD (m) = SIGN32 (DSP_R (m));", + "R[n] += 2;", + }, + { "n", "n8","movs.w @+REG_8,", "111101NNMMMM1100", + "MA (1);", + "DSP_R (m) = RSWAT (R[n]) << 16;", + "DSP_GRD (m) = SIGN32 (DSP_R (m));", + "R[n] += R[8];", + }, + { "n", "n", "movs.w @-,", "111101NNGGGG0000", + "MA (1);", + "R[n] -= 2;", + "DSP_R (m) = RSWAT (R[n]);", + }, + { "", "n", "movs.w @,", "111101NNGGGG0100", + "MA (1);", + "DSP_R (m) = RSWAT (R[n]);", + }, + { "n", "n", "movs.w @+,", "111101NNGGGG1000", + "MA (1);", + "DSP_R (m) = RSWAT (R[n]);", + "R[n] += 2;", + }, + { "n", "n8","movs.w @+REG_8,", "111101NNGGGG1100", + "MA (1);", + "DSP_R (m) = RSWAT (R[n]);", + "R[n] += R[8];", + }, + { "n", "n", ",movs.w @-", "111101NNMMMM0001", + "MA (1);", + "R[n] -= 2;", + "WWAT (R[n], DSP_R (m) >> 16);", + }, + { "", "n", "movs.w ,@", "111101NNMMMM0101", + "MA (1);", + "WWAT (R[n], DSP_R (m) >> 16);", + }, + { "n", "n", "movs.w ,@+", "111101NNMMMM1001", + "MA (1);", + "WWAT (R[n], DSP_R (m) >> 16);", + "R[n] += 2;", + }, + { "n", "n8","movs.w ,@+REG_8", "111101NNMMMM1101", + "MA (1);", + "WWAT (R[n], DSP_R (m) >> 16);", + "R[n] += R[8];", + }, + { "n", "n", "movs.w ,@-", "111101NNGGGG0001", + "MA (1);", + "R[n] -= 2;", + "WWAT (R[n], SEXT (DSP_R (m)));", + }, + { "", "n", "movs.w ,@", "111101NNGGGG0101", + "MA (1);", + "WWAT (R[n], SEXT (DSP_R (m)));", + }, + { "n", "n", "movs.w ,@+", "111101NNGGGG1001", + "MA (1);", + "WWAT (R[n], SEXT (DSP_R (m)));", + "R[n] += 2;", + }, + { "n", "n8","movs.w ,@+REG_8", "111101NNGGGG1101", + "MA (1);", + "WWAT (R[n], SEXT (DSP_R (m)));", + "R[n] += R[8];", + }, + { "n", "n", "movs.l @-,", "111101NNMMMM0010", + "MA (1);", + "R[n] -= 4;", + "DSP_R (m) = RLAT (R[n]);", + "DSP_GRD (m) = SIGN32 (DSP_R (m));", + }, + { "", "n", "movs.l @,", "111101NNMMMM0110", + "MA (1);", + "DSP_R (m) = RLAT (R[n]);", + "DSP_GRD (m) = SIGN32 (DSP_R (m));", + }, + { "n", "n", "movs.l @+,", "111101NNMMMM1010", + "MA (1);", + "DSP_R (m) = RLAT (R[n]);", + "DSP_GRD (m) = SIGN32 (DSP_R (m));", + "R[n] += 4;", + }, + { "n", "n8","movs.l @+REG_8,", "111101NNMMMM1110", + "MA (1);", + "DSP_R (m) = RLAT (R[n]);", + "DSP_GRD (m) = SIGN32 (DSP_R (m));", + "R[n] += R[8];", + }, + { "n", "n", ",movs.l @-", "111101NNMMMM0011", + "MA (1);", + "R[n] -= 4;", + "WLAT (R[n], DSP_R (m));", + }, + { "", "n", "movs.l ,@", "111101NNMMMM0111", + "MA (1);", + "WLAT (R[n], DSP_R (m));", + }, + { "n", "n", "movs.l ,@+", "111101NNMMMM1011", + "MA (1);", + "WLAT (R[n], DSP_R (m));", + "R[n] += 4;", + }, + { "n", "n8","movs.l ,@+REG_8", "111101NNMMMM1111", + "MA (1);", + "WLAT (R[n], DSP_R (m));", + "R[n] += R[8];", + }, + { "n", "n", ",movs.l @-", "111101NNGGGG0011", + "MA (1);", + "R[n] -= 4;", + "WLAT (R[n], SEXT (DSP_R (m)));", + }, + { "", "n", "movs.l ,@", "111101NNGGGG0111", + "MA (1);", + "WLAT (R[n], SEXT (DSP_R (m)));", + }, + { "n", "n", "movs.l ,@+", "111101NNGGGG1011", + "MA (1);", + "WLAT (R[n], SEXT (DSP_R (m)));", + "R[n] += 4;", + }, + { "n", "n8","movs.l ,@+REG_8", "111101NNGGGG1111", + "MA (1);", + "WLAT (R[n], SEXT (DSP_R (m)));", + "R[n] += R[8];", + }, + { "", "n", "movx.w @,", "111100xxXX000100", + "DSP_R (m) = RSWAT (R[n]) << 16;", + "iword &= 0xfd53; goto top;", + }, + { "n", "n", "movx.w @+,", "111100xxXX001000", + "DSP_R (m) = RSWAT (R[n]) << 16;", + "R[n] += ((R[n] & 0xffff) == MOD_ME) ? MOD_DELTA : 2;", + "iword &= 0xfd53; goto top;", + }, + { "n", "n8","movx.w @+REG_8,", "111100xxXX001000", + "DSP_R (m) = RSWAT (R[n]) << 16;", + "R[n] += ((R[n] & 0xffff) == MOD_ME) ? MOD_DELTA : R[8];", + "iword &= 0xfd53; goto top;", + }, + { "", "n", "movx.w ,@", "111100xxaa100100", + "WWAT (R[n], DSP_R (m) >> 16);", + "iword &= 0xfd53; goto top;", + }, + { "n", "n", "movx.w ,@+", "111100xxaa101000", + "WWAT (R[n], DSP_R (m) >> 16);", + "R[n] += ((R[n] & 0xffff) == MOD_ME) ? MOD_DELTA : 2;", + "iword &= 0xfd53; goto top;", + }, + { "n", "n8","movx.w ,@+REG_8","111100xxaa101000", + "WWAT (R[n], DSP_R (m) >> 16);", + "R[n] += ((R[n] & 0xffff) == MOD_ME) ? MOD_DELTA : R[8];", + "iword &= 0xfd53; goto top;", + }, + { "", "n", "movy.w @,", "111100yyYY000001", + "DSP_R (m) = RSWAT (R[n]) << 16;", + }, + { "n", "n", "movy.w @+,", "111100yyYY000010", + "DSP_R (m) = RSWAT (R[n]) << 16;", + "R[n] += ((R[n] | ~0xffff) == MOD_ME) ? MOD_DELTA : 2;", + }, + { "n", "n9","movy.w @+REG_9,", "111100yyYY000010", + "DSP_R (m) = RSWAT (R[n]) << 16;", + "R[n] += ((R[n] | ~0xffff) == MOD_ME) ? MOD_DELTA : R[9];", + }, + { "", "n", "movy.w ,@", "111100yyAA010001", + "WWAT (R[n], DSP_R (m) >> 16);", + }, + { "n", "n", "movy.w ,@+", "111100yyAA010010", + "WWAT (R[n], DSP_R (m) >> 16);", + "R[n] += ((R[n] | ~0xffff) == MOD_ME) ? MOD_DELTA : 2;", + }, + { "n", "n9", "movy.w ,@+REG_9", "111100yyAA010010", + "WWAT (R[n], DSP_R (m) >> 16);", + "R[n] += ((R[n] | ~0xffff) == MOD_ME) ? MOD_DELTA : R[9];", + }, + { "", "", "nopx nopy", "1111000000000000", + "/* nop */", + }, + { "", "", "ppi", "1111100000000000", + "ppi_insn (RIAT (nip));", + "nip += 2;", + "iword &= 0xf7ff; goto top;", + }, +#endif + {0, 0}}; + +op ppi_tab[] = +{ + { "","", "pshl #,dz", "00000iiim16.zzzz", + "int Sz = DSP_R (z) & 0xffff0000;", + "", + "if (i < 16)", + " res = Sz << i;", + "else if (i >= 128 - 16)", + " res = Sz >> 128 - i;", + "else" + " {", + " RAISE_EXCEPTION (SIGILL);", + " return;", + " }", + "res &= 0xffff0000;", + "res_grd = 0;", + "goto logical;", + }, + { "","", "psha #,dz", "00010iiim32.zzzz", + "int Sz = DSP_R (z);", + "int Sz_grd = GET_DSP_GRD (z);", + "", + "if (i < 32)", + " {", + " if (i == 32)" + " {", + " res = 0;", + " res_grd = Sz;", + " }", + " else", + " {", + " res = Sz << i;", + " res_grd = Sz_grd << i | (unsigned) Sz >> 32 - i;", + " }", + " res_grd = SEXT (res_grd);", + " carry = res_grd & 1;", + " }", + "else if (i >= 96)", + " {", + " i = 128 - i;", + " if (i == 32)" + " {", + " res_grd = SIGN32 (Sz_grd);", + " res = Sz_grd;", + " }", + " else", + " {", + " res = Sz >> i | Sz_grd << 32 - i;", + " res_grd = Sz_grd >> i;", + " }", + " carry = Sz >> (i - 1) & 1;", + " }", + "else" + " {", + " RAISE_EXCEPTION (SIGILL);", + " return;", + " }", + "COMPUTE_OVERFLOW;", + "greater_equal = 0;", + }, + { "","", "pmuls Se,Sf,Dg", "0100eeffxxyygguu", + "res = (DSP_R (e)) >> 16 * (DSP_R (f) >> 16) * 2;", + "if (res == 0x80000000)", + " res = 0x7fffffff;", + "DSP_R (g) = res;", + "DSP_GRD (g) = SIGN32 (res);", + "return;", + }, + { "","", "psub Sx,Sy,Du pmuls Se,Sf,Dg", "0110eeffxxyygguu", + "int Sx = DSP_R (x);", + "int Sx_grd = GET_DSP_GRD (x);", + "int Sy = DSP_R (y);", + "int Sy_grd = SIGN32 (Sy);", + "", + "res = (DSP_R (e)) >> 16 * (DSP_R (f) >> 16) * 2;", + "if (res == 0x80000000)", + " res = 0x7fffffff;", + "DSP_R (g) = res;", + "DSP_GRD (g) = SIGN32 (res);", + "", + "z = u;", + "res = Sx - Sy;", + "carry = (unsigned) res > (unsigned) Sx;", + "res_grd = Sx_grd - Sy_grd - carry;", + "COMPUTE_OVERFLOW;", + "ADD_SUB_GE;", + }, + { "","", "padd Sx,Sy,Du pmuls Se,Sf,Dg", "0111eeffxxyygguu", + "int Sx = DSP_R (x);", + "int Sx_grd = GET_DSP_GRD (x);", + "int Sy = DSP_R (y);", + "int Sy_grd = SIGN32 (Sy);", + "", + "res = (DSP_R (e)) >> 16 * (DSP_R (f) >> 16) * 2;", + "if (res == 0x80000000)", + " res = 0x7fffffff;", + "DSP_R (g) = res;", + "DSP_GRD (g) = SIGN32 (res);", + "", + "z = u;", + "res = Sx + Sy;", + "carry = (unsigned) res < (unsigned) Sx;", + "res_grd = Sx_grd + Sy_grd + carry;", + "COMPUTE_OVERFLOW;", + }, + { "","", "psubc Sx,Sy,Dz", "10100000xxyyzzzz", + "int Sx = DSP_R (x);", + "int Sx_grd = GET_DSP_GRD (x);", + "int Sy = DSP_R (y);", + "int Sy_grd = SIGN32 (Sy);", + "", + "res = Sx - Sy - (DSR & 1);", + "carry = (unsigned) res > (unsigned) Sx || (res == Sx && Sy);", + "res_grd = Sx_grd + Sy_grd + carry;", + "COMPUTE_OVERFLOW;", + "ADD_SUB_GE;", + "DSR &= ~0xf1;\n", + "if (res || res_grd)\n", + " DSR |= greater_equal | res_grd >> 2 & DSR_MASK_N | overflow;\n", + "else\n", + " DSR |= DSR_MASK_Z | overflow;\n", + "DSR |= carry;\n", + "goto assign_z;\n", + }, + { "","", "paddc Sx,Sy,Dz", "10110000xxyyzzzz", + "int Sx = DSP_R (x);", + "int Sx_grd = GET_DSP_GRD (x);", + "int Sy = DSP_R (y);", + "int Sy_grd = SIGN32 (Sy);", + "", + "res = Sx + Sy + (DSR & 1);", + "carry = (unsigned) res < (unsigned) Sx || (res == Sx && Sy);", + "res_grd = Sx_grd + Sy_grd + carry;", + "COMPUTE_OVERFLOW;", + "ADD_SUB_GE;", + "DSR &= ~0xf1;\n", + "if (res || res_grd)\n", + " DSR |= greater_equal | res_grd >> 2 & DSR_MASK_N | overflow;\n", + "else\n", + " DSR |= DSR_MASK_Z | overflow;\n", + "DSR |= carry;\n", + "goto assign_z;\n", + }, + { "","", "pcmp Sx,Sy", "10000100xxyy....", + "int Sx = DSP_R (x);", + "int Sx_grd = GET_DSP_GRD (x);", + "int Sy = DSP_R (y);", + "int Sy_grd = SIGN32 (Sy);", + "", + "z = 17; /* Ignore result. */", + "res = Sx - Sy;", + "carry = (unsigned) res > (unsigned) Sx;", + "res_grd = Sx_grd - Sy_grd - carry;", + "COMPUTE_OVERFLOW;", + "ADD_SUB_GE;", + }, + { "","", "pwsb Sx,Sy,Dz", "10100100xxyyzzzz", + }, + { "","", "pwad Sx,Sy,Dz", "10110100xxyyzzzz", + }, + { "","", "pabs Sx,Dz", "10001000xx..zzzz", + "res = DSP_R (x);", + "res_grd = GET_DSP_GRD (x);", + "if (res >= 0)", + " carry = 0;", + "else", + " {", + " res = -res;", + " carry = (res != 0); /* The manual has a bug here. */", + " res_grd = -res_grd - carry;", + " }", + "COMPUTE_OVERFLOW;", + "/* ??? The re-computing of overflow after", + " saturation processing is specific to pabs. */", + "overflow = res_grd != SIGN32 (res) ? DSR_MASK_V : 0;", + "ADD_SUB_GE;", + }, + { "","", "prnd Sx,Dz", "10011000xx..zzzz", + "int Sx = DSP_R (x);", + "int Sx_grd = GET_DSP_GRD (x);", + "", + "res = Sx + 0x8000;", + "carry = (unsigned) res < (unsigned) Sx;", + "res_grd = Sx_grd + carry;", + "COMPUTE_OVERFLOW;", + "ADD_SUB_GE;", + }, + { "","", "pabs Sy,Dz", "10101000..yyzzzz", + "res = DSP_R (y);", + "res_grd = 0;", + "overflow = 0;", + "greater_equal = DSR_MASK_G;", + "if (res >= 0)", + " carry = 0;", + "else", + " {", + " res = -res;", + " carry = 1;", + " if (res < 0)", + " {", + " if (S)", + " res = 0x7fffffff;", + " else", + " {", + " overflow = DSR_MASK_V;", + " greater_equal = 0;", + " }", + " }", + " }", + }, + { "","", "prnd Sy,Dz", "10111000..yyzzzz", + "int Sy = DSP_R (y);", + "int Sy_grd = SIGN32 (Sy);", + "", + "res = Sy + 0x8000;", + "carry = (unsigned) res < (unsigned) Sy;", + "res_grd = Sy_grd + carry;", + "COMPUTE_OVERFLOW;", + "ADD_SUB_GE;", + }, + { "","", "(if cc) pshl Sx,Sy,Dz", "100000ccxxyyzzzz", + "int Sx = DSP_R (x) & 0xffff0000;", + "int Sy = DSP_R (y) >> 16 & 0x7f;", + "", + "if (Sy < 16)", + " res = Sx << Sy;", + "else if (Sy >= 128 - 16)", + " res = Sx >> 128 - Sy;", + "else" + " {", + " RAISE_EXCEPTION (SIGILL);", + " return;", + " }", + "goto cond_logical;", + }, + { "","", "(if cc) psha Sx,Sy,Dz", "100100ccxxyyzzzz", + "int Sx = DSP_R (x);", + "int Sx_grd = GET_DSP_GRD (x);", + "int Sy = DSP_R (y) >> 16 & 0x7f;", + "", + "if (Sy < 32)", + " {", + " if (Sy == 32)" + " {", + " res = 0;", + " res_grd = Sx;", + " }", + " else", + " {", + " res = Sx << Sy;", + " res_grd = Sx_grd << Sy | (unsigned) Sx >> 32 - Sy;", + " }", + " res_grd = SEXT (res_grd);", + " carry = res_grd & 1;", + " }", + "else if (Sy >= 96)", + " {", + " Sy = 128 - Sy;", + " if (Sy == 32)" + " {", + " res_grd = SIGN32 (Sx_grd);", + " res = Sx_grd;", + " }", + " else", + " {", + " res = Sx >> Sy | Sx_grd << 32 - Sy;", + " res_grd = Sx_grd >> Sy;", + " }", + " carry = Sx >> (Sy - 1) & 1;", + " }", + "else" + " {", + " RAISE_EXCEPTION (SIGILL);", + " return;", + " }", + "COMPUTE_OVERFLOW;", + "greater_equal = 0;", + }, + { "","", "(if cc) psub Sx,Sy,Dz", "101000ccxxyyzzzz", + "int Sx = DSP_R (x);", + "int Sx_grd = GET_DSP_GRD (x);", + "int Sy = DSP_R (y);", + "int Sy_grd = SIGN32 (Sy);", + "", + "res = Sx - Sy;", + "carry = (unsigned) res > (unsigned) Sx;", + "res_grd = Sx_grd - Sy_grd - carry;", + "COMPUTE_OVERFLOW;", + "ADD_SUB_GE;", + }, + { "","", "(if cc) padd Sx,Sy,Dz", "101100ccxxyyzzzz", + "int Sx = DSP_R (x);", + "int Sx_grd = GET_DSP_GRD (x);", + "int Sy = DSP_R (y);", + "int Sy_grd = SIGN32 (Sy);", + "", + "res = Sx + Sy;", + "carry = (unsigned) res < (unsigned) Sx;", + "res_grd = Sx_grd + Sy_grd + carry;", + "COMPUTE_OVERFLOW;", + "ADD_SUB_GE;", + }, + { "","", "(if cc) pand Sx,Sy,Dz", "100101ccxxyyzzzz", + "res = DSP_R (x) & DSP_R (y);", + "cond_logical:", + "res &= 0xffff0000;", + "res_grd = 0;", + "if (iword & 0x200)\n", + " goto assign_z;\n", + "logical:", + "carry = 0;", + "overflow = 0;", + "greater_equal = 0;", + "DSR &= ~0xf1;\n", + "if (res)\n", + " DSR |= res >> 26 & DSR_MASK_N;\n", + "else\n", + " DSR |= DSR_MASK_Z;\n", + "goto assign_dc;\n", + }, + { "","", "(if cc) pxor Sx,Sy,Dz", "101001ccxxyyzzzz", + "res = DSP_R (x) ^ DSP_R (y);", + "goto cond_logical;", + }, + { "","", "(if cc) por Sx,Sy,Dz", "101101ccxxyyzzzz", + "res = DSP_R (x) | DSP_R (y);", + "goto cond_logical;", + }, + { "","", "(if cc) pdec Sx,Dz", "100010ccxx..zzzz", + "int Sx = DSP_R (x);", + "int Sx_grd = GET_DSP_GRD (x);", + "", + "res = Sx - 0x10000;", + "carry = res > Sx;", + "res_grd = Sx_grd - carry;", + "COMPUTE_OVERFLOW;", + "ADD_SUB_GE;", + "res &= 0xffff0000;", + }, + { "","", "(if cc) pinc Sx,Dz", "100110ccxx..zzzz", + "int Sx = DSP_R (x);", + "int Sx_grd = GET_DSP_GRD (x);", + "", + "res = Sx + 0x10000;", + "carry = res < Sx;", + "res_grd = Sx_grd + carry;", + "COMPUTE_OVERFLOW;", + "ADD_SUB_GE;", + "res &= 0xffff0000;", + }, + { "","", "(if cc) pdec Sy,Dz", "101010cc..yyzzzz", + "int Sy = DSP_R (y);", + "int Sy_grd = SIGN32 (Sy);", + "", + "res = Sy - 0x10000;", + "carry = res > Sy;", + "res_grd = Sy_grd - carry;", + "COMPUTE_OVERFLOW;", + "ADD_SUB_GE;", + "res &= 0xffff0000;", + }, + { "","", "(if cc) pinc Sy,Dz", "101110cc..yyzzzz", + "int Sy = DSP_R (y);", + "int Sy_grd = SIGN32 (Sy);", + "", + "res = Sy + 0x10000;", + "carry = res < Sy;", + "res_grd = Sy_grd + carry;", + "COMPUTE_OVERFLOW;", + "ADD_SUB_GE;", + "res &= 0xffff0000;", + }, + { "","", "(if cc) pclr Dz", "100011cc....zzzz", + "res = 0;", + "res_grd = 0;", + "carry = 0;", + "overflow = 0;", + "greater_equal = 1;", + }, + { "","", "(if cc) pdmsb Sx,Dz", "100111ccxx..zzzz", + "unsigned Sx = DSP_R (x);", + "int Sx_grd = GET_DSP_GRD (x);", + "int i = 16;" + "", + "if (Sx_grd < 0)", + " {", + " Sx_grd = ~Sx_grd;", + " Sx = ~Sx;", + " }", + "if (Sx_grd)", + " {", + " Sx = Sx_grd;", + " res = -2;", + " }", + "else if (Sx)", + " res = 30;", + "else", + " res = 31;", + "do" + " {", + " if (Sx & ~0 << i)", + " {", + " res -= i;", + " Sx >>= i;", + " }", + " }", + "while (i >>= 1);", + "res <<= 16;", + "res_grd = SIGN32 (res);", + "carry = 0;", + "overflow = 0;", + "ADD_SUB_GE;", + }, + { "","", "(if cc) pdmsb Sy,Dz", "101111cc..yyzzzz", + "unsigned Sy = DSP_R (y);", + "int i;" + "", + "if (Sy < 0)", + " Sy = ~Sy;", + "Sy <<= 1;", + "res = 31;", + "do" + " {", + " if (Sy & ~0 << i)", + " {", + " res -= i;", + " Sy >>= i;", + " }", + " }", + "while (i >>= 1);", + "res <<= 16;", + "res_grd = SIGN32 (res);", + "carry = 0;", + "overflow = 0;", + "ADD_SUB_GE;", + }, + { "","", "(if cc) pneg Sx,Dz", "110010ccxx..zzzz", + "int Sx = DSP_R (x);", + "int Sx_grd = GET_DSP_GRD (x);", + "", + "res = 0 - Sx;", + "carry = res != 0;", + "res_grd = 0 - Sx_grd - carry;", + "COMPUTE_OVERFLOW;", + "ADD_SUB_GE;", + }, + { "","", "(if cc) pcopy Sx,Dz", "110110ccxx..zzzz", + "res = DSP_R (x);", + "res_grd = GET_DSP_GRD (x);", + "carry = 0;", + "COMPUTE_OVERFLOW;", + "ADD_SUB_GE;", + }, + { "","", "(if cc) pneg Sy,Dz", "111010cc..yyzzzz", + "int Sy = DSP_R (y);", + "int Sy_grd = SIGN32 (Sy);", + "", + "res = 0 - Sy;", + "carry = res != 0;", + "res_grd = 0 - Sy_grd - carry;", + "COMPUTE_OVERFLOW;", + "ADD_SUB_GE;", + }, + { "","", "(if cc) pcopy Sy,Dz", "111110cc..yyzzzz", + "res = DSP_R (y);", + "res_grd = SIGN32 (res);", + "carry = 0;", + "COMPUTE_OVERFLOW;", + "ADD_SUB_GE;", + }, + { "","", "(if cc) psts MACH,Dz", "110011cc....zzzz", + "res = MACH;", + "res_grd = SIGN32 (res);", + "goto assign_z;", + }, + { "","", "(if cc) psts MACL,Dz", "110111cc....zzzz", + "res = MACL;", + "res_grd = SIGN32 (res);", + "goto assign_z;", + }, + { "","", "(if cc) plds Dz,MACH", "111011cc....zzzz", + "if (0xa05f >> z & 1)", + " RAISE_EXCEPTION (SIGILL);", + "else", + " MACH = DSP_R (z);", + "return;", + }, + { "","", "(if cc) plds Dz,MACL", "111111cc....zzzz", + "if (0xa05f >> z & 1)", + " RAISE_EXCEPTION (SIGILL);", + "else", + " MACL = DSP_R (z) = res;", + "return;", + }, + {0, 0} +}; + /* Tables of things to put into enums for sh-opc.h */ static char *nibble_type_list[] = { @@ -1423,6 +1901,8 @@ qfunc (a, b) { char bufa[9]; char bufb[9]; + int diff; + memcpy (bufa, a->code, 4); memcpy (bufa + 4, a->code + 12, 4); bufa[8] = 0; @@ -1430,7 +1910,10 @@ qfunc (a, b) memcpy (bufb, b->code, 4); memcpy (bufb + 4, b->code + 12, 4); bufb[8] = 0; - return (strcmp (bufa, bufb)); + diff = strcmp (bufa, bufb); + /* Stabilize the sort, so that later entries can override more general + preceding entries. */ + return diff ? diff : a - b; } static void @@ -1448,118 +1931,6 @@ sorttab () } static void -printonmatch (ptr, a, rep) - char **ptr; - char *a; - char *rep; -{ - int l = strlen (a); - if (strncmp (*ptr, a, l) == 0) - { - printf ("%s", rep); - *ptr += l; - if (**ptr) - printf (","); - } -} - - -static -void -think (o) - op *o; -{ - char *n; - char *p; - - printf ("{\""); - n = o->name; - while (*n && *n != ' ') - { - printf ("%c", *n); - n++; - } - printf ("\",{"); - - p = n; - - if (!*p) - { - printf ("0"); - } - while (*p) - { - while (*p == ',' || *p == ' ') - p++; - printonmatch (&p, "#", "A_IMM"); - printonmatch (&p, "R0", "A_R0"); - printonmatch (&p, "", "A_REG_N"); - printonmatch (&p, "@+", "A_INC_N"); - printonmatch (&p, "@", "A_IND_N"); - printonmatch (&p, "@-", "A_DEC_N"); - printonmatch (&p, "", " A_REG_M"); - printonmatch (&p, "@+", "A_INC_M"); - printonmatch (&p, "@", "A_IND_M"); - printonmatch (&p, "@-", "A_DEC_M"); - printonmatch (&p, "@(,PC)", "A_DISP_PC"); - printonmatch (&p, "@(,)", "A_DISP_REG_M"); - printonmatch (&p, "@(,)", "A_DISP_REG_N"); - printonmatch (&p, "@(R0,)", "A_IND_R0_REG_N"); - printonmatch (&p, "@(R0,)", "A_IND_R0_REG_M"); - printonmatch (&p, "@(,GBR)", "A_DISP_GBR"); - printonmatch (&p, "@(R0,GBR)", "A_R0_GBR"); - printonmatch (&p, "", "A_BDISP8"); - printonmatch (&p, "", "A_BDISP12"); - printonmatch (&p, "SR", "A_SR"); - printonmatch (&p, "GBR", "A_GBR"); - printonmatch (&p, "VBR", "A_VBR"); - printonmatch (&p, "SSR", "A_SSR"); - printonmatch (&p, "SPC", "A_SPC"); - printonmatch (&p, "MACH", "A_MACH"); - printonmatch (&p, "MACL", "A_MACL"); - printonmatch (&p, "PR", "A_PR"); - - } - printf ("},{"); - - p = o->code; - while (*p) - { - printonmatch (&p, "0000", "HEX_0"); - printonmatch (&p, "0001", "HEX_1"); - printonmatch (&p, "0010", "HEX_2"); - printonmatch (&p, "0011", "HEX_3"); - printonmatch (&p, "0100", "HEX_4"); - printonmatch (&p, "0101", "HEX_5"); - printonmatch (&p, "0110", "HEX_6"); - printonmatch (&p, "0111", "HEX_7"); - - printonmatch (&p, "1000", "HEX_8"); - printonmatch (&p, "1001", "HEX_9"); - printonmatch (&p, "1010", "HEX_A"); - printonmatch (&p, "1011", "HEX_B"); - printonmatch (&p, "1100", "HEX_C"); - printonmatch (&p, "1101", "HEX_D"); - printonmatch (&p, "1110", "HEX_E"); - printonmatch (&p, "1111", "HEX_F"); - printonmatch (&p, "i8*1....", "IMM_8"); - printonmatch (&p, "i4*1", "IMM_4"); - printonmatch (&p, "i8p4....", "PCRELIMM_8BY4"); - printonmatch (&p, "i8p2....", "PCRELIMM_8BY2"); - printonmatch (&p, "i8*2....", "IMM_8BY2"); - printonmatch (&p, "i4*2", "IMM_4BY2"); - printonmatch (&p, "i8*4....", "IMM_8BY4"); - printonmatch (&p, "i4*4", "IMM_4BY4"); - printonmatch (&p, "i12.........", "BRANCH_12"); - printonmatch (&p, "i8p1....", "BRANCH_8"); - printonmatch (&p, "nnnn", "REG_N"); - printonmatch (&p, "mmmm", "REG_M"); - - } - printf ("}},\n"); -} - -static void gengastab () { op *p; @@ -1572,35 +1943,6 @@ gengastab () } - -static void -genopc () -{ - op *p; - make_enum_list ("sh_nibble_type", nibble_type_list); - make_enum_list ("sh_arg_type", arg_type_list); - - printf ("typedef struct {\n"); - printf ("char *name;\n"); - printf ("sh_arg_type arg[3];\n"); - printf ("sh_nibble_type nibbles[4];\n"); - printf ("} sh_opcode_info;\n"); - printf ("#ifdef DEFINE_TABLE\n"); - printf ("sh_opcode_info sh_table[]={\n"); - for (p = tab; p->name; p++) - { - printf ("\n/* %s %-20s*/", p->code, p->name); - think (p); - } - printf ("0};\n"); - printf ("#endif\n"); -} - - - - - - /* Convert a string of 4 binary digits into an int */ static @@ -1647,12 +1989,28 @@ expand_opcode (shift, val, i, s) case '0': case '1': { - - int n = bton (s); - if (n >= 0) - { - expand_opcode (shift - 4, val | (n << shift), i, s + 4); - } + int m, mv; + + val |= bton (s) << shift; + if (s[2] == '0' || s[2] == '1') + expand_opcode (shift - 4, val, i, s + 4); + else if (s[2] == 'N') + for (j = 0; j < 4; j++) + expand_opcode (shift - 4, val | (j << shift), i, s + 4); + else if (s[2] == 'x') + for (j = 0; j < 4; j += 2) + for (m = 0; m < 32; m++) + { + /* Ignore illegal nopy */ + if ((m & 7) == 0 && m != 0) + continue; + mv = m & 3 | (m & 4) << 2 | (m & 8) << 3 | (m & 16) << 4; + expand_opcode (shift - 4, val | mv | (j << shift), i, + s + 4); + } + else if (s[2] == 'y') + for (j = 0; j < 2; j++) + expand_opcode (shift - 4, val | (j << shift), i, s + 4); break; } case 'n': @@ -1663,6 +2021,37 @@ expand_opcode (shift, val, i, s) } break; + case 'M': + /* A1, A0,X0,X1,Y0,Y1,M0,A1G,M1,M1G */ + for (j = 5; j < 16; j++) + if (j != 6) + expand_opcode (shift - 4, val | (j << shift), i, s + 4); + break; + case 'G': + /* A1G, A0G: */ + for (j = 13; j <= 15; j +=2) + expand_opcode (shift - 4, val | (j << shift), i, s + 4); + break; + case 's': + /* System registers mach, macl, pr: */ + for (j = 0; j < 3; j++) + expand_opcode (shift - 4, val | (j << shift), i, s + 4); + /* System registers fpul, fpscr/dsr, a0, x0, x1, y0, y1: */ + for (j = 5; j < 12; j++) + expand_opcode (shift - 4, val | (j << shift), i, s + 4); + break; + case 'X': + case 'a': + val |= bton (s) << shift; + for (j = 0; j < 16; j += 8) + expand_opcode (shift - 4, val | (j << shift), i, s + 4); + break; + case 'Y': + case 'A': + val |= bton (s) << shift; + for (j = 0; j < 8; j += 4) + expand_opcode (shift - 4, val | (j << shift), i, s + 4); + break; default: for (j = 0; j < (1 << (shift + 4)); j++) @@ -1677,18 +2066,22 @@ expand_opcode (shift, val, i, s) statement entry. */ static void -dumptable () +dumptable (name, size, start) + char *name; + int size; + int start; { int lump = 256; int online = 16; - int i = 0; + int i = start; - while (i < 1 << 16) + printf ("unsigned char %s[%d]={\n", name, size); + while (i < start + size) { int j = 0; - printf ("unsigned char sh_jump_table%x[%d]={\n", i, lump); + printf ("/* 0x%x */\n", i); while (j < lump) { @@ -1705,37 +2098,46 @@ dumptable () printf ("\n"); } i += j; - printf ("};\n"); } - + printf ("};\n"); } static void -filltable () +filltable (p) + op *p; { - op *p; - int index = 1; + static int index = 1; sorttab (); - for (p = tab; p->name; p++) + for (; p->name; p++) { p->index = index++; expand_opcode (12, 0, p->index, p->code); } } +/* Table already contais all the switch case tags for 16-bit opcode double + data transfer (ddt) insns, and the switch case tag for processing parallel + processing insns (ppi) for code 0xf800 (ppi nopx nopy). Copy the + latter tag to represent all combinations of ppi with ddt. */ static void -gensim () +ppi_moves () { - op *p; - int j; + int i; - printf ("{\n"); - printf (" switch (jump_table[iword]) {\n"); + for (i = 0xf000; i < 0xf400; i++) + if (table[i]) + table[i + 0x800] = table[0xf800]; +} - for (p = tab; p->name; p++) +static void +gensim_caselist (p) + op *p; +{ + for (; p->name; p++) { + int j; int sextbit = -1; int needm = 0; int needn = 0; @@ -1752,6 +2154,8 @@ gensim () { case '0': case '1': + s += 2; + break; case '.': s += 4; break; @@ -1760,11 +2164,43 @@ gensim () needn = 1; s += 4; break; + case 'N': + printf (" int n = (((iword >> 8) - 2) & 0x3) + 2;\n"); + s += 2; + break; + case 'x': + printf (" int n = ((iword >> 9) & 1) + 4;\n"); + needn = 1; + s += 2; + break; + case 'y': + printf (" int n = ((iword >> 8) & 1) + 4;\n"); + needn = 1; + s += 2; + break; case 'm': - printf (" int m = (iword >>4) & 0xf;\n"); needm = 1; + case 's': + case 'M': + case 'G': + printf (" int m = (iword >>4) & 0xf;\n"); s += 4; - + break; + case 'X': + printf (" int m = ((iword >> 7) & 1) + 8;\n"); + s += 2; + break; + case 'a': + printf (" int m = 7 - ((iword >> 6) & 2);\n"); + s += 2; + break; + case 'Y': + printf (" int m = ((iword >> 6) & 1) + 10;\n"); + s += 2; + break; + case 'A': + printf (" int m = 7 - ((iword >> 5) & 2);\n"); + s += 2; break; case 'i': @@ -1820,6 +2256,8 @@ gensim () for (r = p->refs; *r; r++) { if (*r == '0') printf(" CREF(0);\n"); + if (*r == '8') printf(" CREF(8);\n"); + if (*r == '9') printf(" CREF(9);\n"); if (*r == 'n') printf(" CREF(n);\n"); if (*r == 'm') printf(" CREF(m);\n"); } @@ -1849,20 +2287,30 @@ gensim () printf (" break;\n"); printf (" }\n"); } +} + +static void +gensim () +{ + printf ("{\n"); + printf (" switch (jump_table[iword]) {\n"); + + gensim_caselist (tab); + gensim_caselist (movsxy_tab); + printf (" default:\n"); printf (" {\n"); - printf (" saved_state.asregs.exception = SIGILL;\n"); + printf (" RAISE_EXCEPTION (SIGILL);\n"); printf (" }\n"); printf (" }\n"); printf ("}\n"); } - static void gendefines () { op *p; - filltable(); + filltable (tab); for (p = tab; p->name; p++) { char *s = p->name; @@ -1880,6 +2328,234 @@ gendefines () } } +static int ppi_index; + +/* Take an ppi code, expand all varying fields in it and fill all the + right entries in 'table' with the opcode index. */ + +static void +expand_ppi_code (val, i, s) + int val; + int i; + char *s; +{ + int j; + + for (;;) + { + switch (s[0]) + { + /* The last eight bits are disregarded for the switch table. */ + case 'm': + case 'x': + case '.': + table[val] = i; + return; + case '0': + val += val; + s++; + break; + case '1': + val += val + 1; + s++; + break; + case 'i': + case 'e': case 'f': + val += val; + s++; + expand_ppi_code (val, i, s); + val++; + break; + case 'c': + val <<= 2; + s += 2; + val++; + expand_ppi_code (val, ppi_index++, s); + val++; + expand_ppi_code (val, i, s); + val++; + break; + } + } +} + +static void +ppi_filltable () +{ + op *p; + ppi_index = 1; + + for (p = ppi_tab; p->name; p++) + { + p->index = ppi_index++; + expand_ppi_code (0, p->index, p->code); + } +} + +static void +ppi_gensim () +{ + op *p = ppi_tab; + + printf ("#define DSR_MASK_G 0x80\n"); + printf ("#define DSR_MASK_Z 0x40\n"); + printf ("#define DSR_MASK_N 0x20\n"); + printf ("#define DSR_MASK_V 0x10\n"); + printf ("\n"); + printf ("#define COMPUTE_OVERFLOW do {\\\n"); + printf (" overflow = res_grd != SIGN32 (res) ? DSR_MASK_V : 0; \\\n"); + printf (" if (overflow && S) \\\n"); + printf (" { \\\n"); + printf (" if (res_grd & 0x80) \\\n"); + printf (" { \\\n"); + printf (" res = 0x80000000; \\\n"); + printf (" res_grd |= 0xff; \\\n"); + printf (" } \\\n"); + printf (" else \\\n"); + printf (" { \\\n"); + printf (" res = 0x7fffffff; \\\n"); + printf (" res_grd &= ~0xff; \\\n"); + printf (" } \\\n"); + printf (" overflow = 0; \\\n"); + printf (" } \\\n"); + printf ("} while (0)\n"); + printf ("\n"); + printf ("#define ADD_SUB_GE \\\n"); + printf (" (greater_equal = ~(overflow << 3 & res_grd) & DSR_MASK_G)\n"); + printf ("\n"); + printf ("static void\n"); + printf ("ppi_insn (iword)\n"); + printf (" int iword;\n"); + printf ("{\n"); + printf (" static char e_tab[] = { 8, 9, 10, 5};\n"); + printf (" static char f_tab[] = {10, 11, 8, 5};\n"); + printf (" static char x_tab[] = { 8, 9, 7, 5};\n"); + printf (" static char y_tab[] = {10, 11, 12, 14};\n"); + printf (" static char g_tab[] = {12, 14, 7, 5};\n"); + printf (" static char u_tab[] = { 8, 10, 7, 5};\n"); + printf ("\n"); + printf (" int z;\n"); + printf (" int res, res_grd;\n"); + printf (" int carry, overflow, greater_equal;\n"); + printf ("\n"); + printf (" switch (ppi_table[iword >> 8]) {\n"); + + for (; p->name; p++) + { + int shift, j; + int cond = 0; + int havedecl = 0; + + char *s = p->code; + + printf (" /* %s %s */\n", p->name, p->code); + printf (" case %d: \n", p->index); + + printf (" {\n"); + for (shift = 16; *s; ) + { + switch (*s) + { + case 'i': + printf (" int i = (iword >> 4) & 0x7f;\n"); + s += 6; + break; + case 'e': + case 'f': + case 'x': + case 'y': + case 'g': + case 'u': + shift -= 2; + printf (" int %c = %c_tab[(iword >> %d) & 3];\n", + *s, *s, shift); + havedecl = 1; + s += 2; + break; + case 'c': + printf (" if ((((iword >> 8) ^ DSR) & 1) == 0)\n"); + printf ("\tbreak;\n"); + printf (" }\n"); + printf (" case %d: \n", p->index + 1); + printf (" {\n"); + cond = 1; + case '0': + case '1': + case '.': + shift -= 2; + s += 2; + break; + case 'z': + if (havedecl) + printf ("\n"); + printf (" z = iword & 0xf;\n"); + havedecl = 2; + s += 4; + break; + } + } + if (havedecl == 1) + printf ("\n"); + else if (havedecl == 2) + printf (" {\n"); + for (j = 0; j < MAX_NR_STUFF; j++) + { + if (p->stuff[j]) + { + printf (" %s%s\n", + (havedecl == 2 ? " " : ""), + p->stuff[j]); + } + } + if (havedecl == 2) + printf (" }\n"); + if (cond) + { + printf (" if (iword & 0x200)\n"); + printf (" goto assign_z;\n"); + } + printf (" break;\n"); + printf (" }\n"); + } + + printf (" default:\n"); + printf (" {\n"); + printf (" RAISE_EXCEPTION (SIGILL);\n"); + printf (" return;\n"); + printf (" }\n"); + printf (" }\n"); + printf (" DSR &= ~0xf1;\n"); + printf (" if (res || res_grd)\n"); + printf (" DSR |= greater_equal | res_grd >> 2 & DSR_MASK_N | overflow;\n"); + printf (" else\n"); + printf (" DSR |= DSR_MASK_Z | overflow;\n"); + printf (" assign_dc:\n"); + printf (" switch (DSR >> 1 & 7)\n"); + printf (" {\n"); + printf (" case 0: /* Carry Mode */\n"); + printf (" DSR |= carry;\n"); + printf (" case 1: /* Negative Value Mode */\n"); + printf (" DSR |= res_grd >> 7 & 1;\n"); + printf (" case 2: /* Zero Value Mode */\n"); + printf (" DSR |= DSR >> 6 & 1;\n"); + printf (" case 3: /* Overflow mode\n"); + printf (" DSR |= overflow >> 4;\n"); + printf (" case 4: /* Signed Greater Than Mode */\n"); + printf (" DSR |= DSR >> 7 & 1;\n"); + printf (" case 4: /* Signed Greater Than Or Equal Mode */\n"); + printf (" DSR |= greater_equal >> 7;\n"); + printf (" }\n"); + printf (" assign_z:\n"); + printf (" if (0xa05f >> z & 1)\n"); + printf (" {\n"); + printf (" RAISE_EXCEPTION (SIGILL);\n"); + printf (" return;\n"); + printf (" }\n"); + printf (" DSP_R (z) = res;\n"); + printf (" DSP_GRD (z) = res_grd;\n"); + printf ("}\n"); +} + int main (ac, av) int ac; @@ -1913,19 +2589,31 @@ main (ac, av) } else if (strcmp (av[1], "-s") == 0) { - filltable (); - dumptable (); + filltable (tab); + dumptable ("sh_jump_table", 1 << 16, 0); + + memset (table, 0, sizeof table); + filltable (movsxy_tab); + ppi_moves (); + dumptable ("sh_dsp_table", 1 << 12, 0xf000); + memset (table, 0, sizeof table); + ppi_filltable (); + dumptable ("ppi_table", 1 << 8, 0); } else if (strcmp (av[1], "-x") == 0) { - filltable (); + filltable (tab); + filltable (movsxy_tab); gensim (); } + else if (strcmp (av[1], "-p") == 0) + { + ppi_filltable (); + ppi_gensim (); + } } else - { - genopc (); - } + fprintf (stderr, "Opcode table generation no longer supported.\n"); return 0; } diff --git a/sim/sh/interp.c b/sim/sh/interp.c index 4d7c5cf..1844227 100644 --- a/sim/sh/interp.c +++ b/sim/sh/interp.c @@ -52,6 +52,8 @@ #define SIGTRAP 5 #endif +extern unsigned char sh_jump_table[], sh_dsp_table[0x1000], ppi_table[]; + #define O_RECOMPILE 85 #define DEFINE_TABLE #define DISASSEMBLER_TABLE @@ -65,27 +67,31 @@ typedef union struct { - /* On targets like sparc-sun-solaris, fregs will be aligned on a 64 bit - boundary (because of the d member). To avoid padding between - registers - which whould make the job of sim_fetch_register harder, - we add padding at the start. */ - int pad_dummy; int regs[16]; int pc; - int pr; - - int gbr; - int vbr; - int mach; - int macl; - - int sr; - - int fpul; - - int fpscr; - /* sh3e */ + /* 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]; @@ -94,10 +100,28 @@ typedef union } fregs[2]; - int ssr; - int spc; - /* sh3 */ - int bank[2][8]; + /* 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]; + } named; + int i[16]; + } cregs; + + unsigned char *insn_end; int ticks; int stalls; @@ -117,6 +141,11 @@ typedef union 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]; @@ -124,16 +153,18 @@ typedef union 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; #if 1 -static int maskl = ~0; -static int maskw = ~0; +static int maskw = 0; #endif static SIM_OPEN_KIND sim_kind; @@ -150,27 +181,32 @@ static char *myname; #define UR (unsigned int)R #define UR (unsigned int)R #define SR0 saved_state.asregs.regs[0] -#define GBR saved_state.asregs.gbr -#define VBR saved_state.asregs.vbr -#define SSR saved_state.asregs.ssr -#define SPC saved_state.asregs.spc -#define MACH saved_state.asregs.mach -#define MACL saved_state.asregs.macl -#define FPUL saved_state.asregs.fpul +#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 SSR saved_state.asregs.cregs.named.ssr +#define SPC saved_state.asregs.cregs.named.spc +#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 pc +#define PC insn_ptr -/* Alternate bank of registers r0-r6 */ +/* Alternate bank of registers r0-r7 */ /* Note: code controling SR handles flips between BANK0 and BANK1 */ -#define Rn_BANK(n) (saved_state.asregs.bank[!SR_RB][(n)]) -#define SET_Rn_BANK(n, EXP) do { saved_state.asregs.bank[!SR_RB][(n)] = (EXP); } while (0) +#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_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) @@ -180,23 +216,28 @@ static char *myname; #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 M ((saved_state.asregs.sr & SR_MASK_M) != 0) -#define Q ((saved_state.asregs.sr & SR_MASK_Q) != 0) -#define S ((saved_state.asregs.sr & SR_MASK_S) != 0) -#define T ((saved_state.asregs.sr & SR_MASK_T) != 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 SR_BL ((saved_state.asregs.sr & SR_MASK_BL) != 0) -#define SR_RB ((saved_state.asregs.sr & SR_MASK_RB) != 0) -#define SR_MD ((saved_state.asregs.sr & SR_MASK_MD) != 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.sr |= (BIT); \ + saved_state.asregs.cregs.named.sr |= (BIT); \ else \ - saved_state.asregs.sr &= ~(BIT); \ + saved_state.asregs.cregs.named.sr &= ~(BIT); \ } while (0) #define SET_SR_M(EXP) SET_SR_BIT ((EXP), SR_MASK_M) @@ -204,28 +245,14 @@ do { \ #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 GET_SR() (saved_state.asregs.sr - 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) -static void -set_sr (new_sr) - int new_sr; -{ - /* do we need to swap banks */ - int old_gpr = (SR_MD ? !SR_RB : 0); - int new_gpr = ((new_sr & SR_MASK_MD) - ? (new_sr & SR_MASK_RB) == 0 - : 0); - if (old_gpr != new_gpr) - { - int i; - for (i = 0; i < 8; i++) - { - saved_state.asregs.bank[old_gpr][i] = saved_state.asregs.regs[i]; - saved_state.asregs.regs[i] = saved_state.asregs.bank[new_gpr][i]; - } - } -} +#define SET_RC(x) \ + (saved_state.asregs.cregs.named.sr \ + = saved_state.asregs.cregs.named.sr & 0xf000ffff | ((x) & 0xfff) << 16) /* Manipulate FPSCR */ @@ -241,10 +268,12 @@ static void set_fpscr1 (x) int x; { - int old = saved_state.asregs.fpscr; - saved_state.asregs.fpscr = (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.fpscr ^ old) & FPSCR_MASK_FR) + 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]; @@ -252,12 +281,14 @@ set_fpscr1 (x) } } -#define GET_FPSCR() (saved_state.asregs.fpscr) +/* 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 () @@ -265,41 +296,80 @@ fail () abort (); } -int -special_address (addr, bits_written, data) - void *addr; - int bits_written, data; -{ - 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 1; - /* We can't do anything useful with the other stuff, so fail. */ - return 0; -} +#define RAISE_EXCEPTION(x) \ + (saved_state.asregs.exception = x, saved_state.asregs.insn_end = 0) -/* This function exists solely for the purpose of setting a breakpoint to +/* This function exists mainly for the purpose of setting a breakpoint to catch simulated bus errors when running the simulator under GDB. */ void -bp_holder () +raise_exception (x) + int x; +{ + RAISE_EXCEPTION(x); +} + +void +raise_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, bits_written, data) \ - if (addr & ~mask) \ +#define BUSERROR(addr, mask) ((addr) & (mask)) + +#define WRITE_BUSERROR(addr, mask, data, addr_func) \ + do \ { \ - if (special_address (addr, bits_written, data)) \ - return; \ - saved_state.asregs.exception = SIGBUS; \ - bp_holder (); \ - } + 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, @@ -321,8 +391,21 @@ int valid[16]; #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 host_callback *callback; @@ -383,13 +466,37 @@ set_dr (n, exp) #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. */ +#define MOD_ME DSP_GRD (17) +#define MOD_DELTA DSP_GRD (18) #define FP_OP(n, OP, m) \ { \ if (FPSCR_PR) \ { \ if (((n) & 1) || ((m) & 1)) \ - saved_state.asregs.exception = SIGILL; \ + RAISE_EXCEPTION (SIGILL); \ else \ SET_DR(n, (DR(n) OP DR(m))); \ } \ @@ -402,7 +509,7 @@ set_dr (n, exp) if (FPSCR_PR) \ { \ if ((n) & 1) \ - saved_state.asregs.exception = SIGILL; \ + RAISE_EXCEPTION (SIGILL); \ else \ SET_DR(n, (OP (DR(n)))); \ } \ @@ -415,7 +522,7 @@ set_dr (n, exp) if (FPSCR_PR) \ { \ if (((n) & 1) || ((m) & 1)) \ - saved_state.asregs.exception = SIGILL; \ + RAISE_EXCEPTION (SIGILL); \ else \ SET_SR_T (DR(n) OP DR(m)); \ } \ @@ -423,180 +530,137 @@ set_dr (n, exp) SET_SR_T (FR(n) OP FR(m)); \ } while (0) - - -static void INLINE -wlat_little (memory, x, value, maskl) - unsigned char *memory; -{ - int v = value; - unsigned char *p = memory + ((x) & maskl); - BUSERROR(x, maskl, 32, v); - p[3] = v >> 24; - p[2] = v >> 16; - p[1] = v >> 8; - p[0] = v; -} - -static void INLINE -wwat_little (memory, x, value, maskw) - unsigned char *memory; -{ - int v = value; - unsigned char *p = memory + ((x) & maskw); - BUSERROR(x, maskw, 16, v); - - p[1] = v >> 8; - p[0] = v; -} - -static void INLINE -wbat_any (memory, x, value, maskb) - unsigned char *memory; +static void +set_sr (new_sr) + int new_sr; { - unsigned char *p = memory + (x & maskb); - if (x > 0x5000000) - IOMEM (x, 1, value); - BUSERROR(x, maskb, 8, value); - - p[0] = value; + /* do we need to swap banks */ + int old_gpr = SR_MD && SR_RB; + int new_gpr = (new_sr & SR_MASK_MD) && (new_sr & SR_MASK_RB); + if (old_gpr != new_gpr) + { + int i, tmp; + for (i = 0; i < 8; i++) + { + tmp = saved_state.asregs.cregs.named.bank[i]; + saved_state.asregs.cregs.named.bank[i] = saved_state.asregs.regs[i]; + saved_state.asregs.regs[i] = tmp; + } + } + saved_state.asregs.cregs.named.sr = new_sr; + SET_MOD (MOD); } static void INLINE -wlat_big (memory, x, value, maskl) +wlat_fast (memory, x, value, maskl) unsigned char *memory; { int v = value; - unsigned char *p = memory + ((x) & maskl); - BUSERROR(x, maskl, 32, v); - - p[0] = v >> 24; - p[1] = v >> 16; - p[2] = v >> 8; - p[3] = v; + unsigned int *p = (unsigned int *)(memory + x); + WRITE_BUSERROR (x, maskl, v, process_wlat_addr); + *p = v; } static void INLINE -wwat_big (memory, x, value, maskw) +wwat_fast (memory, x, value, maskw, endianw) unsigned char *memory; { int v = value; - unsigned char *p = memory + ((x) & maskw); - BUSERROR(x, maskw, 16, v); - - p[0] = v >> 8; - p[1] = v; + unsigned short *p = (unsigned short *)(memory + (x ^ endianw)); + WRITE_BUSERROR (x, maskw, v, process_wwat_addr); + *p = v; } static void INLINE -wbat_big (memory, x, value, maskb) +wbat_fast (memory, x, value, maskb) unsigned char *memory; { - unsigned char *p = memory + (x & maskb); - BUSERROR(x, maskb, 8, value); + unsigned char *p = memory + (x ^ endianb); + WRITE_BUSERROR (x, maskb, value, process_wbat_addr); - if (x > 0x5000000) - IOMEM (x, 1, value); p[0] = value; } /* Read functions */ static int INLINE -rlat_little (memory, x, maskl) +rlat_fast (memory, x, maskl) unsigned char *memory; { - unsigned char *p = memory + ((x) & maskl); - BUSERROR(x, maskl, -32, -1); + unsigned int *p = (unsigned int *)(memory + x); + READ_BUSERROR (x, maskl, process_rlat_addr); - return (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]; + return *p; } static int INLINE -rwat_little (memory, x, maskw) +rwat_fast (memory, x, maskw, endianw) unsigned char *memory; + int x, maskw, endianw; { - unsigned char *p = memory + ((x) & maskw); - BUSERROR(x, maskw, -16, -1); + unsigned short *p = (unsigned short *)(memory + (x ^ endianw)); + READ_BUSERROR (x, maskw, process_rwat_addr); - return (p[1] << 8) | p[0]; + return *p; } static int INLINE -rbat_any (memory, x, maskb) - unsigned char *memory; -{ - unsigned char *p = memory + ((x) & maskb); - BUSERROR(x, maskb, -8, -1); - - return p[0]; -} - -static int INLINE -rlat_big (memory, x, maskl) - unsigned char *memory; +riat_fast (insn_ptr, endianw) + unsigned char *insn_ptr; { - unsigned char *p = memory + ((x) & maskl); - BUSERROR(x, maskl, -32, -1); + unsigned short *p = (unsigned short *)((size_t) insn_ptr ^ endianw); - return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + return *p; } static int INLINE -rwat_big (memory, x, maskw) +rbat_fast (memory, x, maskb) unsigned char *memory; { - unsigned char *p = memory + ((x) & maskw); - BUSERROR(x, maskw, -16, -1); + unsigned char *p = memory + (x ^ endianb); + READ_BUSERROR (x, maskb, process_rbat_addr); - return (p[0] << 8) | p[1]; + return *p; } -#define RWAT(x) (little_endian ? rwat_little(memory, x, maskw): rwat_big(memory, x, maskw)) -#define RLAT(x) (little_endian ? rlat_little(memory, x, maskl): rlat_big(memory, x, maskl)) -#define RBAT(x) (rbat_any (memory, x, maskb)) -#define WWAT(x,v) (little_endian ? wwat_little(memory, x, v, maskw): wwat_big(memory, x, v, maskw)) -#define WLAT(x,v) (little_endian ? wlat_little(memory, x, v, maskl): wlat_big(memory, x, v, maskl)) -#define WBAT(x,v) (wbat_any (memory, x, v, maskb)) +#define RWAT(x) (rwat_fast (memory, x, maskw, endianw)) +#define RLAT(x) (rlat_fast (memory, x, maskl)) +#define RBAT(x) (rbat_fast (memory, x, maskb)) +#define RIAT(p) (riat_fast ((p), endianw)) +#define WWAT(x,v) (wwat_fast (memory, x, v, maskw, endianw)) +#define WLAT(x,v) (wlat_fast (memory, x, v, maskl)) +#define WBAT(x,v) (wbat_fast (memory, x, v, maskb)) #define RUWAT(x) (RWAT(x) & 0xffff) #define RSWAT(x) ((short)(RWAT(x))) #define RSBAT(x) (SEXT(RBAT(x))) -#define RDAT(x, n) (do_rdat (memory, (x), (n), (little_endian))) +#define RDAT(x, n) (do_rdat (memory, (x), (n), (maskl))) static int -do_rdat (memory, x, n, little_endian) +do_rdat (memory, x, n, maskl) char *memory; int x; int n; - int little_endian; + int maskl; { int f0; int f1; int i = (n & 1); int j = (n & ~1); - if (little_endian) - { - f0 = rlat_little (memory, x + 0, maskl); - f1 = rlat_little (memory, x + 4, maskl); - } - else - { - f0 = rlat_big (memory, x + 0, maskl); - f1 = rlat_big (memory, x + 4, maskl); - } + f0 = rlat_fast (memory, x + 0, maskl); + f1 = rlat_fast (memory, x + 4, maskl); saved_state.asregs.fregs[i].i[(j + 0)] = f0; saved_state.asregs.fregs[i].i[(j + 1)] = f1; return 0; } -#define WDAT(x, n) (do_wdat (memory, (x), (n), (little_endian))) +#define WDAT(x, n) (do_wdat (memory, (x), (n), (maskl))) static int -do_wdat (memory, x, n, little_endian) +do_wdat (memory, x, n, maskl) char *memory; int x; int n; - int little_endian; + int maskl; { int f0; int f1; @@ -604,34 +668,123 @@ do_wdat (memory, x, n, little_endian) int j = (n & ~1); f0 = saved_state.asregs.fregs[i].i[(j + 0)]; f1 = saved_state.asregs.fregs[i].i[(j + 1)]; - if (little_endian) - { - wlat_little (memory, (x + 0), f0, maskl); - wlat_little (memory, (x + 4), f1, maskl); - } - else - { - wlat_big (memory, (x + 0), f0, maskl); - wlat_big (memory, (x + 4), f1, maskl); - } + wlat_fast (memory, (x + 0), f0, maskl); + wlat_fast (memory, (x + 4), f1, maskl); return 0; } +static void +process_wlat_addr (addr, value) + int addr; + int value; +{ + unsigned int *ptr; + + PROCESS_SPECIAL_ADDRESS (addr, endianb, ptr, 32, 3, value, ); + *ptr = value; +} + +static void +process_wwat_addr (addr, value) + int addr; + int value; +{ + unsigned short *ptr; + + PROCESS_SPECIAL_ADDRESS (addr, endianb, ptr, 16, 1, value, ); + *ptr = value; +} + +static void +process_wbat_addr (addr, value) + int addr; + int value; +{ + unsigned char *ptr; + + PROCESS_SPECIAL_ADDRESS (addr, endianb, ptr, 8, 0, value, ); + *ptr = value; +} -#define MA(n) do { memstalls += (((pc & 3) != 0) ? (n) : ((n) - 1)); } while (0) +static int +process_rlat_addr (addr) + int addr; +{ + unsigned char *ptr; + + PROCESS_SPECIAL_ADDRESS (addr, endianb, ptr, -32, 3, -1, 0); + return *ptr; +} + +static int +process_rwat_addr (addr) + int addr; +{ + unsigned char *ptr; + + PROCESS_SPECIAL_ADDRESS (addr, endianb, ptr, -16, 1, -1, 0); + return *ptr; +} + +static int +process_rbat_addr (addr) + int addr; +{ + unsigned char *ptr; + + PROCESS_SPECIAL_ADDRESS (addr, endianb, ptr, -8, 0, -1, 0); + return *ptr; +} #define SEXT(x) (((x & 0xff) ^ (~0x7f))+0x80) #define SEXT12(x) (((x & 0xfff) ^ 0x800) - 0x800) #define SEXTW(y) ((int)((short)y)) +#if 0 +#define SEXT32(x) ((int)((x & 0xffffffff) ^ 0x80000000U) - 0x7fffffff - 1) +#else +#define SEXT32(x) ((int)(x)) +#endif +#define SIGN32(x) (SEXT32 (x) >> 31) + +/* convert pointer from target to host value. */ +#define PT2H(x) ((x) + memory) +/* convert pointer from host to target value. */ +#define PH2T(x) ((x) - memory) + +#define SKIP_INSN(p) ((p) += ((RIAT (p) & 0xfc00) == 0xf800 ? 4 : 2)) -#define Delay_Slot(TEMPPC) iword = RUWAT(TEMPPC); goto top; +#define SET_NIP(x) nip = (x); CHECK_INSN_PTR (nip); -int empty[16]; +#define Delay_Slot(TEMPPC) iword = RIAT (TEMPPC); goto top; + +#define CHECK_INSN_PTR(p) \ +do { \ + if (saved_state.asregs.exception || PH2T (p) & maskw) \ + saved_state.asregs.insn_end = 0; \ + else if (p < loop.end) \ + saved_state.asregs.insn_end = loop.end; \ + else \ + saved_state.asregs.insn_end = mem_end; \ +} while (0) + +#ifdef ACE_FAST + +#define MA(n) +#define L(x) +#define TL(x) +#define TB(x) + +#else + +#define MA(n) \ + do { memstalls += ((((int) PC & 3) != 0) ? (n) : ((n) - 1)); } while (0) #define L(x) thislock = x; #define TL(x) if ((x) == prevlock) stalls++; #define TB(x,y) if ((x) == prevlock || (y)==prevlock) stalls++; +#endif + #if defined(__GO32__) || defined(_WIN32) int sim_memory_size = 19; #else @@ -698,22 +851,23 @@ now_persec () static FILE *profile_file; -static void -swap (memory, n) - unsigned char *memory; - int n; +static unsigned INLINE +swap (n) + unsigned n; { - int little_endian = target_little_endian; - WLAT (0, n); + if (endianb) + n = (n << 24 | (n & 0xff00) << 8 + | (n & 0xff0000) >> 8 | (n & 0xff000000) >> 24); + return n; } -static void -swap16 (memory, n) - unsigned char *memory; - int n; +static unsigned short INLINE +swap16 (n) + unsigned short n; { - int little_endian = target_little_endian; - WWAT (0, n); + if (endianb) + n = n << 8 | (n & 0xff00) >> 8; + return n; } static void @@ -722,9 +876,9 @@ swapout (n) { if (profile_file) { - char b[4]; - swap (b, n); - fwrite (b, 4, 1, profile_file); + union { char b[4]; int n; } u; + u.n = swap (n); + fwrite (u.b, 4, 1, profile_file); } } @@ -732,9 +886,9 @@ static void swapout16 (n) int n; { - char b[4]; - swap16 (b, n); - fwrite (b, 2, 1, profile_file); + union { char b[4]; int n; } u; + u.n = swap16 (n); + fwrite (u.b, 2, 1, profile_file); } /* Turn a pointer in a register into a pointer into real memory. */ @@ -746,10 +900,46 @@ ptr (x) return (char *) (x + saved_state.asregs.memory); } +static int +strswaplen (str) + int str; +{ + unsigned char *memory = saved_state.asregs.memory; + int start, end; + int endian = endianb; + + if (! endian) + return 0; + end = str; + for (end = str; memory[end ^ endian]; end++) ; + return end - str; +} + +static void +strnswap (str, len) + int str; + int len; +{ + int *start, *end; + + if (! endianb || ! len) + return; + start = (int *) ptr (str & ~3); + end = (int *) ptr (str + len); + do + { + int old = *start; + *start = (old << 24 | (old & 0xff00) << 8 + | (old & 0xff0000) >> 8 | (old & 0xff000000) >> 24); + start++; + } + while (start < end); +} + /* Simulate a monitor trap, put the result into r0 and errno into r1 */ static void -trap (i, regs, memory, maskl, maskw, little_endian) +trap (i, regs, memory, maskl, maskw, endianw) int i; int *regs; unsigned char *memory; @@ -760,7 +950,7 @@ trap (i, regs, memory, maskl, maskw, little_endian) printf ("%c", regs[0]); break; case 2: - saved_state.asregs.exception = SIGQUIT; + raise_exception (SIGQUIT); break; case 3: /* FIXME: for backwards compat, should be removed */ case 34: @@ -776,40 +966,42 @@ trap (i, regs, memory, maskl, maskw, little_endian) case SYS_fork: regs[0] = fork (); break; +/* This would work only if endianness matched between host and target. + Besides, it's quite dangerous. */ +#if 0 case SYS_execve: regs[0] = execve (ptr (regs[5]), (char **)ptr (regs[6]), (char **)ptr (regs[7])); break; case SYS_execv: regs[0] = execve (ptr (regs[5]),(char **) ptr (regs[6]), 0); break; +#endif case SYS_pipe: { - char *buf; - int host_fd[2]; - - buf = ptr (regs[5]); - - regs[0] = pipe (host_fd); - - WLAT (buf, host_fd[0]); - buf += 4; - WLAT (buf, host_fd[1]); + regs[0] = (BUSERROR (regs[5], maskl) + ? -EINVAL + : pipe ((int *) ptr (regs[5]))); } break; case SYS_wait: regs[0] = wait (ptr (regs[5])); break; -#endif +#endif /* !defined(__GO32__) && !defined(_WIN32) */ case SYS_read: - regs[0] = callback->read (callback, regs[5], ptr (regs[6]), regs[7]); + strnswap (regs[6], regs[7]); + regs[0] + = callback->read (callback, regs[5], ptr (regs[6]), regs[7]); + strnswap (regs[6], regs[7]); break; case SYS_write: + strnswap (regs[6], regs[7]); if (regs[5] == 1) regs[0] = (int)callback->write_stdout (callback, ptr(regs[6]), regs[7]); else regs[0] = (int)callback->write (callback, regs[5], ptr (regs[6]), regs[7]); + strnswap (regs[6], regs[7]); break; case SYS_lseek: regs[0] = callback->lseek (callback,regs[5], regs[6], regs[7]); @@ -818,11 +1010,16 @@ trap (i, regs, memory, maskl, maskw, little_endian) regs[0] = callback->close (callback,regs[5]); break; case SYS_open: - regs[0] = callback->open (callback,ptr (regs[5]), regs[6]); - break; + { + int len = strswaplen (regs[5]); + strnswap (regs[5], len); + regs[0] = callback->open (callback,ptr (regs[5]), regs[6]); + strnswap (regs[5], len); + break; + } case SYS_exit: /* EXIT - caller can look in r5 to work out the reason */ - saved_state.asregs.exception = SIGQUIT; + raise_exception (SIGQUIT); regs[0] = regs[5]; break; @@ -830,11 +1027,14 @@ trap (i, regs, memory, maskl, maskw, little_endian) /* stat system call */ { struct stat host_stat; - char *buf; + int buf; + int len = strswaplen (regs[5]); + strnswap (regs[5], len); regs[0] = stat (ptr (regs[5]), &host_stat); + strnswap (regs[5], len); - buf = ptr (regs[6]); + buf = regs[6]; WWAT (buf, host_stat.st_dev); buf += 2; @@ -873,17 +1073,35 @@ trap (i, regs, memory, maskl, maskw, little_endian) #ifndef _WIN32 case SYS_chown: - regs[0] = chown (ptr (regs[5]), regs[6], regs[7]); - break; + { + int len = strswaplen (regs[5]); + + strnswap (regs[5], len); + regs[0] = chown (ptr (regs[5]), regs[6], regs[7]); + strnswap (regs[5], len); + break; + } #endif /* _WIN32 */ case SYS_chmod: - regs[0] = chmod (ptr (regs[5]), regs[6]); - break; + { + int len = strswaplen (regs[5]); + + strnswap (regs[5], len); + regs[0] = chmod (ptr (regs[5]), regs[6]); + strnswap (regs[5], len); + break; + } case SYS_utime: - /* Cast the second argument to void *, to avoid type mismatch - if a prototype is present. */ - regs[0] = utime (ptr (regs[5]), (void *) ptr (regs[6])); - break; + { + /* Cast the second argument to void *, to avoid type mismatch + if a prototype is present. */ + int len = strswaplen (regs[5]); + + strnswap (regs[5], len); + regs[0] = utime (ptr (regs[5]), (void *) ptr (regs[6])); + strnswap (regs[5], len); + break; + } default: abort (); } @@ -894,7 +1112,7 @@ trap (i, regs, memory, maskl, maskw, little_endian) case 0xc3: case 255: - saved_state.asregs.exception = SIGTRAP; + raise_exception (SIGTRAP); break; } @@ -907,7 +1125,7 @@ control_c (sig, code, scp, addr) char *scp; char *addr; { - saved_state.asregs.exception = SIGINT; + raise_exception (SIGINT); } static int @@ -1041,12 +1259,12 @@ dmul (sign, rm, rn) } static void -macw (regs, memory, n, m) +macw (regs, memory, n, m, endianw) int *regs; unsigned char *memory; int m, n; + int endianw; { - int little_endian = target_little_endian; long tempm, tempn; long prod, macl, sum; @@ -1078,6 +1296,50 @@ macw (regs, memory, n, m) MACL = sum; } +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; +{ + struct loop_bounds loop; + + if (SR_RC) + { + if (RS >= RE) + { + loop.start = PT2H (RE - 4); + SKIP_INSN (loop.start); + loop.end = loop.start; + if (RS - RE == 0) + SKIP_INSN (loop.end); + if (RS - RE <= 2) + SKIP_INSN (loop.end); + SKIP_INSN (loop.end); + } + else + { + loop.start = PT2H (RS); + loop.end = PT2H (RE - 4); + SKIP_INSN (loop.end); + SKIP_INSN (loop.end); + SKIP_INSN (loop.end); + SKIP_INSN (loop.end); + } + if (loop.end >= mem_end) + loop.end = PT2H (0); + } + else + loop.end = PT2H (0); + + return loop; +} + +static void +ppi_insn(); + +#include "ppi.c" + /* Set the memory size to the power of two provided. */ void @@ -1109,6 +1371,92 @@ sim_size (power) } static void +init_dsp (abfd) + struct _bfd *abfd; +{ + int was_dsp = target_dsp; + unsigned long mach = bfd_get_mach (abfd); + + if (mach == bfd_mach_sh_dsp || mach == bfd_mach_sh3_dsp) + { + int ram_area_size, xram_start, yram_start; + int new_select; + + target_dsp = 1; + if (mach == bfd_mach_sh_dsp) + { + /* SH7410 (orig. sh-sdp): + 4KB each for X & Y memory; + On-chip X RAM 0x0800f000-0x0800ffff + On-chip Y RAM 0x0801f000-0x0801ffff */ + xram_start = 0x0800f000; + ram_area_size = 0x1000; + } + if (mach == bfd_mach_sh3_dsp) + { + /* SH7612: + 8KB each for X & Y memory; + On-chip X RAM 0x1000e000-0x1000ffff + On-chip Y RAM 0x1001e000-0x1001ffff */ + xram_start = 0x1000e000; + ram_area_size = 0x2000; + } + yram_start = xram_start + 0x10000; + new_select = ~(ram_area_size - 1); + if (saved_state.asregs.xyram_select != new_select) + { + 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); + + /* Disable use of X / Y mmeory if not allocated. */ + if (! saved_state.asregs.xmem || ! saved_state.asregs.ymem) + { + saved_state.asregs.xyram_select = 0; + if (saved_state.asregs.xmem) + free (saved_state.asregs.xmem); + if (saved_state.asregs.ymem) + free (saved_state.asregs.ymem); + } + } + saved_state.asregs.xram_start = xram_start; + saved_state.asregs.yram_start = yram_start; + saved_state.asregs.xmem_offset = saved_state.asregs.xmem - xram_start; + saved_state.asregs.ymem_offset = saved_state.asregs.ymem - yram_start; + } + else + { + target_dsp = 0; + if (saved_state.asregs.xyram_select) + { + saved_state.asregs.xyram_select = 0; + free (saved_state.asregs.xmem); + free (saved_state.asregs.ymem); + } + } + + if (! saved_state.asregs.xyram_select) + { + saved_state.asregs.xram_start = 1; + saved_state.asregs.yram_start = 1; + } + + if (target_dsp != was_dsp) + { + int i, tmp; + + for (i = sizeof sh_dsp_table - 1; i >= 0; i--) + { + tmp = sh_jump_table[0xf000 + i]; + sh_jump_table[0xf000 + i] = sh_dsp_table[i]; + sh_dsp_table[i] = tmp; + } + } +} + +static void init_pointers () { host_little_endian = 0; @@ -1177,7 +1525,7 @@ int sim_stop (sd) SIM_DESC sd; { - saved_state.asregs.exception = SIGINT; + raise_exception (SIGINT); return 1; } @@ -1186,7 +1534,9 @@ sim_resume (sd, step, siggnal) SIM_DESC sd; int step, siggnal; { - register unsigned int pc; + register unsigned char *insn_ptr; + unsigned char *mem_end; + struct loop_bounds loop; register int cycles = 0; register int stalls = 0; register int memstalls = 0; @@ -1195,22 +1545,25 @@ sim_resume (sd, step, siggnal) register int thislock; register unsigned int doprofile; register int pollcount = 0; - register int little_endian = target_little_endian; + /* endianw is used for every insn fetch, hence it makes sense to cache it. + endianb is used less often. */ + register int endianw = global_endianw; int tick_start = get_now (); void (*prev) (); void (*prev_fpe) (); - extern unsigned char sh_jump_table0[]; - register unsigned char *jump_table = sh_jump_table0; + register unsigned char *jump_table = sh_jump_table; register int *R = &(saved_state.asregs.regs[0]); /*register int T;*/ +#ifndef PR register int PR; +#endif - register int maskb = ((saved_state.asregs.msize - 1) & ~0); - register int maskw = ((saved_state.asregs.msize - 1) & ~1); - register int maskl = ((saved_state.asregs.msize - 1) & ~3); + register int maskb = ~((saved_state.asregs.msize - 1) & ~0); + register int maskw = ~((saved_state.asregs.msize - 1) & ~1); + register int maskl = ~((saved_state.asregs.msize - 1) & ~3); register unsigned char *memory; register unsigned int sbit = ((unsigned int) 1 << 31); @@ -1218,20 +1571,18 @@ sim_resume (sd, step, siggnal) prev_fpe = signal (SIGFPE, SIG_IGN); init_pointers (); + saved_state.asregs.exception = 0; memory = saved_state.asregs.memory; + mem_end = memory + saved_state.asregs.msize; - if (step) - { - saved_state.asregs.exception = SIGTRAP; - } - else - { - saved_state.asregs.exception = 0; - } + loop = get_loop_bounds (RS, RE, memory, mem_end, maskw, endianw); + insn_ptr = PT2H (saved_state.asregs.pc); + CHECK_INSN_PTR (insn_ptr); - pc = saved_state.asregs.pc; - PR = saved_state.asregs.pr; +#ifndef PR + PR = saved_state.asregs.sregs.named.pr; +#endif /*T = GET_SR () & SR_MASK_T;*/ prevlock = saved_state.asregs.prevlock; thislock = saved_state.asregs.thislock; @@ -1242,11 +1593,26 @@ sim_resume (sd, step, siggnal) if (doprofile == 0) doprofile = ~0; - do + loop: + if (step && insn_ptr < saved_state.asregs.insn_end) + { + if (saved_state.asregs.exception) + /* This can happen if we've already been single-stepping and + encountered a loop end. */ + saved_state.asregs.insn_end = insn_ptr; + else + { + saved_state.asregs.exception = SIGTRAP; + saved_state.asregs.insn_end = insn_ptr + 2; + } + } + + while (insn_ptr < saved_state.asregs.insn_end) { - register unsigned int iword = RUWAT (pc); + register unsigned int iword = RIAT (insn_ptr); register unsigned int ult; - register unsigned int nia = pc + 2; + register unsigned char *nip = insn_ptr + 2; + #ifndef ACE_FAST insts++; #endif @@ -1255,7 +1621,7 @@ sim_resume (sd, step, siggnal) #include "code.c" - pc = nia; + insn_ptr = nip; if (--pollcount < 0) { @@ -1279,7 +1645,7 @@ sim_resume (sd, step, siggnal) cycles -= doprofile; if (saved_state.asregs.profile_hist) { - int n = pc >> PROFILE_SHIFT; + int n = PH2T (insn_ptr) >> PROFILE_SHIFT; if (n < nsamples) { int i = saved_state.asregs.profile_hist[n]; @@ -1291,23 +1657,37 @@ sim_resume (sd, step, siggnal) } #endif } - while (!saved_state.asregs.exception); + if (saved_state.asregs.insn_end == loop.end) + { + saved_state.asregs.cregs.named.sr += SR_RC_INCREMENT; + if (SR_RC) + insn_ptr = loop.start; + else + { + saved_state.asregs.insn_end = mem_end; + loop.end = PT2H (0); + } + goto loop; + } if (saved_state.asregs.exception == SIGILL || saved_state.asregs.exception == SIGBUS) { - pc -= 2; + insn_ptr -= 2; } + /* Check for SIGBUS due to insn fetch. */ + else if (! saved_state.asregs.exception) + saved_state.asregs.exception == SIGBUS; saved_state.asregs.ticks += get_now () - tick_start; saved_state.asregs.cycles += cycles; saved_state.asregs.stalls += stalls; saved_state.asregs.memstalls += memstalls; saved_state.asregs.insts += insts; - saved_state.asregs.pc = pc; - /* restore the T and other cached SR bits */ - SET_SR (GET_SR()); - saved_state.asregs.pr = PR; + saved_state.asregs.pc = PH2T (insn_ptr); +#ifndef PR + saved_state.asregs.sregs.named.pr = PR; +#endif saved_state.asregs.prevlock = prevlock; saved_state.asregs.thislock = thislock; @@ -1334,7 +1714,7 @@ sim_write (sd, addr, buffer, size) for (i = 0; i < size; i++) { - saved_state.asregs.memory[MMASKB & (addr + i)] = buffer[i]; + saved_state.asregs.memory[(MMASKB & (addr + i)) ^ endianb] = buffer[i]; } return size; } @@ -1352,13 +1732,11 @@ sim_read (sd, addr, buffer, size) for (i = 0; i < size; i++) { - buffer[i] = saved_state.asregs.memory[MMASKB & (addr + i)]; + buffer[i] = saved_state.asregs.memory[(MMASKB & (addr + i)) ^ endianb]; } return size; } -/* We have to add one to RN as an index into asints because of the padding - added at the start of asregs. */ int sim_store_register (sd, rn, memory, length) SIM_DESC sd; @@ -1366,14 +1744,108 @@ sim_store_register (sd, rn, memory, length) unsigned char *memory; int length; { - int little_endian; + unsigned val; + init_pointers (); - little_endian = target_little_endian; - if (&saved_state.asints[rn+1] - == &saved_state.asregs.fpscr) - set_fpscr1 (RLAT(0)); - else - saved_state.asints[rn+1] = RLAT(0); + val = swap (* (int *)memory); + switch (rn) + { + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: + case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: + saved_state.asregs.regs[rn] = val; + break; + case 16: + saved_state.asregs.pc = val; + break; + case 17: + PR = val; + break; + case 18: + GBR = val; + break; + case 19: + VBR = val; + break; + case 20: + MACH = val; + break; + case 21: + MACL = val; + break; + case 22: + SET_SR (val); + break; + case 23: + FPUL = val; + break; + case 24: + SET_FPSCR (val); + break; + case 25: + if (target_dsp) + A0G = val; + else case 26: + if (target_dsp) + A0 = val; + else case 27: + if (target_dsp) + A1G = val; + else case 28: + if (target_dsp) + A1 = val; + else case 29: + if (target_dsp) + M0 = val; + else case 30: + if (target_dsp) + M1 = val; + else case 31: + if (target_dsp) + X0 = val; + else case 32: + if (target_dsp) + X1 = val; + else case 33: + if (target_dsp) + Y0 = val; + else case 34: + if (target_dsp) + Y1 = val; + else case 40: + if (target_dsp) + SET_MOD (val); + else case 35: case 36: case 37: case 38: case 39: + SET_FI (rn - 25, val); + break; + case 41: + SSR = val; + break; + case 42: + SPC = val; + break; + /* The rn_bank idiosyncracies are not due to hardware differences, but to + a weird aliasing naming scheme for sh3 / sh3e / sh4. */ + case 43: + if (target_dsp) + RS = val; + else case 44: + if (target_dsp) + RE = val; + else case 45: case 46: case 47: case 48: case 49: case 50: + if (SR_MD && SR_RB) + Rn_BANK (rn - 43) = val; + else + saved_state.asregs.regs[rn - 43] = val; + break; + case 51: case 52: case 53: case 54: case 55: case 56: case 57: case 58: + if (target_dsp || ! SR_MD || ! SR_RB) + SET_Rn_BANK (rn - 51, val); + else + saved_state.asregs.regs[rn - 51] = val; + break; + default: + return 0; + } return -1; } @@ -1384,10 +1856,106 @@ sim_fetch_register (sd, rn, memory, length) unsigned char *memory; int length; { - int little_endian; + int val; + init_pointers (); - little_endian = target_little_endian; - WLAT (0, saved_state.asints[rn+1]); + switch (rn) + { + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: + case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: + val = saved_state.asregs.regs[rn]; + break; + case 16: + val = saved_state.asregs.pc; + break; + case 17: + val = PR; + break; + case 18: + val = GBR; + break; + case 19: + val = VBR; + break; + case 20: + val = MACH; + break; + case 21: + val = MACL; + break; + case 22: + val = GET_SR (); + break; + case 23: + val = FPUL; + break; + case 24: + val = GET_FPSCR (); + break; + case 25: + val = target_dsp ? SEXT (A0G) : FI (0); + break; + case 26: + val = target_dsp ? A0 : FI (1); + break; + case 27: + val = target_dsp ? SEXT (A1G) : FI (2); + break; + case 28: + val = target_dsp ? A1 : FI (3); + break; + case 29: + val = target_dsp ? M0 : FI (4); + break; + case 30: + val = target_dsp ? M1 : FI (5); + break; + case 31: + val = target_dsp ? X0 : FI (6); + break; + case 32: + val = target_dsp ? X1 : FI (7); + break; + case 33: + val = target_dsp ? Y0 : FI (8); + break; + case 34: + val = target_dsp ? Y1 : FI (9); + break; + case 35: case 36: case 37: case 38: case 39: + val = FI (rn - 25); + break; + case 40: + val = target_dsp ? MOD : FI (15); + break; + case 41: + val = SSR; + break; + case 42: + val = SPC; + break; + /* The rn_bank idiosyncracies are not due to hardware differences, but to + a weird aliasing naming scheme for sh3 / sh3e / sh4. */ + case 43: + if (target_dsp) + val = RS; + else case 44: + if (target_dsp) + val = RE; + else case 45: case 46: case 47: case 48: case 49: case 50: + val = (SR_MD && SR_RB + ? Rn_BANK (rn - 43) + : saved_state.asregs.regs[rn - 43]); + break; + case 51: case 52: case 53: case 54: case 55: case 56: case 57: case 58: + val = (target_dsp || ! SR_MD || ! SR_RB + ? Rn_BANK (rn - 51) + : saved_state.asregs.regs[rn - 51]); + break; + default: + return 0; + } + * (int *) memory = swap (val); return -1; } @@ -1477,6 +2045,14 @@ sim_open (kind, cb, abfd, argv) { char **p; int endian_set = 0; + int i; + union + { + int i; + short s[2]; + char c[4]; + } + mem_word; sim_kind = kind; myname = argv[0]; @@ -1504,6 +2080,17 @@ sim_open (kind, cb, abfd, argv) if (abfd != NULL && ! endian_set) target_little_endian = ! bfd_big_endian (abfd); + if (abfd) + init_dsp (abfd); + + for (i = 4; (i -= 2) >= 0; ) + mem_word.s[i >> 1] = i; + global_endianw = mem_word.i >> (target_little_endian ? 0 : 16) & 0xffff; + + for (i = 4; --i >= 0; ) + mem_word.c[i] = i; + endianb = mem_word.i >> (target_little_endian ? 0 : 24) & 0xff; + /* fudge our descriptor for now */ return (SIM_DESC) 1; } -- 2.7.4