Commit e8af50a30e89e5cfdc1b2a2fa8fab3ce463a4790
1 parent
525d67bc
full system SPARC emulation (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1083 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
8 changed files
with
1845 additions
and
57 deletions
target-sparc/cpu.h
| @@ -9,8 +9,10 @@ | @@ -9,8 +9,10 @@ | ||
| 9 | 9 | ||
| 10 | /* trap definitions */ | 10 | /* trap definitions */ |
| 11 | #define TT_ILL_INSN 0x02 | 11 | #define TT_ILL_INSN 0x02 |
| 12 | +#define TT_PRIV_INSN 0x03 | ||
| 12 | #define TT_WIN_OVF 0x05 | 13 | #define TT_WIN_OVF 0x05 |
| 13 | #define TT_WIN_UNF 0x06 | 14 | #define TT_WIN_UNF 0x06 |
| 15 | +#define TT_FP_EXCP 0x08 | ||
| 14 | #define TT_DIV_ZERO 0x2a | 16 | #define TT_DIV_ZERO 0x2a |
| 15 | #define TT_TRAP 0x80 | 17 | #define TT_TRAP 0x80 |
| 16 | 18 | ||
| @@ -18,27 +20,101 @@ | @@ -18,27 +20,101 @@ | ||
| 18 | #define PSR_ZERO (1<<22) | 20 | #define PSR_ZERO (1<<22) |
| 19 | #define PSR_OVF (1<<21) | 21 | #define PSR_OVF (1<<21) |
| 20 | #define PSR_CARRY (1<<20) | 22 | #define PSR_CARRY (1<<20) |
| 23 | +#define PSR_ICC (PSR_NEG|PSR_ZERO|PSR_OVF|PSR_CARRY) | ||
| 24 | +#define PSR_S (1<<7) | ||
| 25 | +#define PSR_PS (1<<6) | ||
| 26 | +#define PSR_ET (1<<5) | ||
| 27 | +#define PSR_CWP 0x1f | ||
| 28 | +/* Fake impl 0, version 4 */ | ||
| 29 | +#define GET_PSR(env) ((0<<28) | (4<<24) | env->psr | (env->psrs? PSR_S : 0) | (env->psrs? PSR_PS : 0) |(env->psret? PSR_ET : 0) | env->cwp) | ||
| 30 | + | ||
| 31 | +/* Trap base register */ | ||
| 32 | +#define TBR_BASE_MASK 0xfffff000 | ||
| 33 | + | ||
| 34 | +/* Fcc */ | ||
| 35 | +#define FSR_RD1 (1<<31) | ||
| 36 | +#define FSR_RD0 (1<<30) | ||
| 37 | +#define FSR_RD_MASK (FSR_RD1 | FSR_RD0) | ||
| 38 | +#define FSR_RD_NEAREST 0 | ||
| 39 | +#define FSR_RD_ZERO FSR_RD0 | ||
| 40 | +#define FSR_RD_POS FSR_RD1 | ||
| 41 | +#define FSR_RD_NEG (FSR_RD1 | FSR_RD0) | ||
| 42 | + | ||
| 43 | +#define FSR_NVM (1<<27) | ||
| 44 | +#define FSR_OFM (1<<26) | ||
| 45 | +#define FSR_UFM (1<<25) | ||
| 46 | +#define FSR_DZM (1<<24) | ||
| 47 | +#define FSR_NXM (1<<23) | ||
| 48 | +#define FSR_TEM_MASK (FSR_NVM | FSR_OFM | FSR_UFM | FSR_DZM | FSR_NXM) | ||
| 49 | + | ||
| 50 | +#define FSR_NVA (1<<9) | ||
| 51 | +#define FSR_OFA (1<<8) | ||
| 52 | +#define FSR_UFA (1<<7) | ||
| 53 | +#define FSR_DZA (1<<6) | ||
| 54 | +#define FSR_NXA (1<<5) | ||
| 55 | +#define FSR_AEXC_MASK (FSR_NVA | FSR_OFA | FSR_UFA | FSR_DZA | FSR_NXA) | ||
| 56 | + | ||
| 57 | +#define FSR_NVC (1<<4) | ||
| 58 | +#define FSR_OFC (1<<3) | ||
| 59 | +#define FSR_UFC (1<<2) | ||
| 60 | +#define FSR_DZC (1<<1) | ||
| 61 | +#define FSR_NXC (1<<0) | ||
| 62 | +#define FSR_CEXC_MASK (FSR_NVC | FSR_OFC | FSR_UFC | FSR_DZC | FSR_NXC) | ||
| 63 | + | ||
| 64 | +#define FSR_FTT2 (1<<16) | ||
| 65 | +#define FSR_FTT1 (1<<15) | ||
| 66 | +#define FSR_FTT0 (1<<14) | ||
| 67 | +#define FSR_FTT_MASK (FSR_FTT2 | FSR_FTT1 | FSR_FTT0) | ||
| 68 | + | ||
| 69 | +#define FSR_FCC1 (1<<11) | ||
| 70 | +#define FSR_FCC0 (1<<10) | ||
| 71 | + | ||
| 72 | +/* MMU */ | ||
| 73 | +#define MMU_E (1<<0) | ||
| 74 | +#define MMU_NF (1<<1) | ||
| 75 | + | ||
| 76 | +#define PTE_ENTRYTYPE_MASK 3 | ||
| 77 | +#define PTE_ACCESS_MASK 0x1c | ||
| 78 | +#define PTE_ACCESS_SHIFT 2 | ||
| 79 | +#define PTE_ADDR_MASK 0xffffff00 | ||
| 80 | + | ||
| 81 | +#define PG_ACCESSED_BIT 5 | ||
| 82 | +#define PG_MODIFIED_BIT 6 | ||
| 83 | +#define PG_CACHE_BIT 7 | ||
| 84 | + | ||
| 85 | +#define PG_ACCESSED_MASK (1 << PG_ACCESSED_BIT) | ||
| 86 | +#define PG_MODIFIED_MASK (1 << PG_MODIFIED_BIT) | ||
| 87 | +#define PG_CACHE_MASK (1 << PG_CACHE_BIT) | ||
| 88 | + | ||
| 89 | +#define ACCESS_DATA 0 | ||
| 90 | +#define ACCESS_CODE 1 | ||
| 91 | +#define ACCESS_MMU 2 | ||
| 21 | 92 | ||
| 22 | #define NWINDOWS 32 | 93 | #define NWINDOWS 32 |
| 23 | 94 | ||
| 24 | typedef struct CPUSPARCState { | 95 | typedef struct CPUSPARCState { |
| 25 | uint32_t gregs[8]; /* general registers */ | 96 | uint32_t gregs[8]; /* general registers */ |
| 26 | uint32_t *regwptr; /* pointer to current register window */ | 97 | uint32_t *regwptr; /* pointer to current register window */ |
| 27 | - double *regfptr; /* floating point registers */ | 98 | + float fpr[32]; /* floating point registers */ |
| 28 | uint32_t pc; /* program counter */ | 99 | uint32_t pc; /* program counter */ |
| 29 | uint32_t npc; /* next program counter */ | 100 | uint32_t npc; /* next program counter */ |
| 30 | - uint32_t sp; /* stack pointer */ | ||
| 31 | uint32_t y; /* multiply/divide register */ | 101 | uint32_t y; /* multiply/divide register */ |
| 32 | uint32_t psr; /* processor state register */ | 102 | uint32_t psr; /* processor state register */ |
| 103 | + uint32_t fsr; /* FPU state register */ | ||
| 33 | uint32_t T2; | 104 | uint32_t T2; |
| 34 | uint32_t cwp; /* index of current register window (extracted | 105 | uint32_t cwp; /* index of current register window (extracted |
| 35 | from PSR) */ | 106 | from PSR) */ |
| 36 | uint32_t wim; /* window invalid mask */ | 107 | uint32_t wim; /* window invalid mask */ |
| 108 | + uint32_t tbr; /* trap base register */ | ||
| 109 | + int psrs; /* supervisor mode (extracted from PSR) */ | ||
| 110 | + int psrps; /* previous supervisor mode */ | ||
| 111 | + int psret; /* enable traps */ | ||
| 37 | jmp_buf jmp_env; | 112 | jmp_buf jmp_env; |
| 38 | int user_mode_only; | 113 | int user_mode_only; |
| 39 | int exception_index; | 114 | int exception_index; |
| 40 | int interrupt_index; | 115 | int interrupt_index; |
| 41 | int interrupt_request; | 116 | int interrupt_request; |
| 117 | + uint32_t exception_next_pc; | ||
| 42 | struct TranslationBlock *current_tb; | 118 | struct TranslationBlock *current_tb; |
| 43 | void *opaque; | 119 | void *opaque; |
| 44 | /* NOTE: we allow 8 more registers to handle wrapping */ | 120 | /* NOTE: we allow 8 more registers to handle wrapping */ |
| @@ -51,6 +127,22 @@ typedef struct CPUSPARCState { | @@ -51,6 +127,22 @@ typedef struct CPUSPARCState { | ||
| 51 | written */ | 127 | written */ |
| 52 | unsigned long mem_write_vaddr; /* target virtual addr at which the | 128 | unsigned long mem_write_vaddr; /* target virtual addr at which the |
| 53 | memory was written */ | 129 | memory was written */ |
| 130 | + /* 0 = kernel, 1 = user (may have 2 = kernel code, 3 = user code ?) */ | ||
| 131 | + CPUTLBEntry tlb_read[2][CPU_TLB_SIZE]; | ||
| 132 | + CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; | ||
| 133 | + int error_code; | ||
| 134 | + int access_type; | ||
| 135 | + /* MMU regs */ | ||
| 136 | + uint32_t mmuregs[16]; | ||
| 137 | + /* temporary float registers */ | ||
| 138 | + float ft0, ft1, ft2; | ||
| 139 | + double dt0, dt1, dt2; | ||
| 140 | + | ||
| 141 | + /* ice debug support */ | ||
| 142 | + uint32_t breakpoints[MAX_BREAKPOINTS]; | ||
| 143 | + int nb_breakpoints; | ||
| 144 | + int singlestep_enabled; /* XXX: should use CPU single step mode instead */ | ||
| 145 | + | ||
| 54 | } CPUSPARCState; | 146 | } CPUSPARCState; |
| 55 | 147 | ||
| 56 | CPUSPARCState *cpu_sparc_init(void); | 148 | CPUSPARCState *cpu_sparc_init(void); |
| @@ -61,7 +153,7 @@ struct siginfo; | @@ -61,7 +153,7 @@ struct siginfo; | ||
| 61 | int cpu_sparc_signal_handler(int hostsignum, struct siginfo *info, void *puc); | 153 | int cpu_sparc_signal_handler(int hostsignum, struct siginfo *info, void *puc); |
| 62 | void cpu_sparc_dump_state(CPUSPARCState *env, FILE *f, int flags); | 154 | void cpu_sparc_dump_state(CPUSPARCState *env, FILE *f, int flags); |
| 63 | 155 | ||
| 64 | -#define TARGET_PAGE_BITS 13 | 156 | +#define TARGET_PAGE_BITS 12 /* 4k */ |
| 65 | #include "cpu-all.h" | 157 | #include "cpu-all.h" |
| 66 | 158 | ||
| 67 | #endif | 159 | #endif |
target-sparc/exec.h
| @@ -6,6 +6,12 @@ register struct CPUSPARCState *env asm(AREG0); | @@ -6,6 +6,12 @@ register struct CPUSPARCState *env asm(AREG0); | ||
| 6 | register uint32_t T0 asm(AREG1); | 6 | register uint32_t T0 asm(AREG1); |
| 7 | register uint32_t T1 asm(AREG2); | 7 | register uint32_t T1 asm(AREG2); |
| 8 | register uint32_t T2 asm(AREG3); | 8 | register uint32_t T2 asm(AREG3); |
| 9 | +#define FT0 (env->ft0) | ||
| 10 | +#define FT1 (env->ft1) | ||
| 11 | +#define FT2 (env->ft2) | ||
| 12 | +#define DT0 (env->dt0) | ||
| 13 | +#define DT1 (env->dt1) | ||
| 14 | +#define DT2 (env->dt2) | ||
| 9 | 15 | ||
| 10 | #include "cpu.h" | 16 | #include "cpu.h" |
| 11 | #include "exec-all.h" | 17 | #include "exec-all.h" |
| @@ -14,4 +20,88 @@ void cpu_lock(void); | @@ -14,4 +20,88 @@ void cpu_lock(void); | ||
| 14 | void cpu_unlock(void); | 20 | void cpu_unlock(void); |
| 15 | void cpu_loop_exit(void); | 21 | void cpu_loop_exit(void); |
| 16 | void helper_flush(target_ulong addr); | 22 | void helper_flush(target_ulong addr); |
| 23 | +void helper_ld_asi(int asi, int size, int sign); | ||
| 24 | +void helper_st_asi(int asi, int size, int sign); | ||
| 25 | +void helper_rett(void); | ||
| 26 | +void helper_stfsr(void); | ||
| 27 | +void set_cwp(int new_cwp); | ||
| 28 | +void do_fabss(void); | ||
| 29 | +void do_fsqrts(void); | ||
| 30 | +void do_fsqrtd(void); | ||
| 31 | +void do_fcmps(void); | ||
| 32 | +void do_fcmpd(void); | ||
| 33 | +void do_interrupt(int intno, int is_int, int error_code, | ||
| 34 | + unsigned int next_eip, int is_hw); | ||
| 35 | +void raise_exception_err(int exception_index, int error_code); | ||
| 36 | +void raise_exception(int tt); | ||
| 37 | +void memcpy32(uint32_t *dst, const uint32_t *src); | ||
| 38 | + | ||
| 39 | +/* XXX: move that to a generic header */ | ||
| 40 | +#if !defined(CONFIG_USER_ONLY) | ||
| 41 | + | ||
| 42 | +#define ldul_user ldl_user | ||
| 43 | +#define ldul_kernel ldl_kernel | ||
| 44 | + | ||
| 45 | +#define ACCESS_TYPE 0 | ||
| 46 | +#define MEMSUFFIX _kernel | ||
| 47 | +#define DATA_SIZE 1 | ||
| 48 | +#include "softmmu_header.h" | ||
| 49 | + | ||
| 50 | +#define DATA_SIZE 2 | ||
| 51 | +#include "softmmu_header.h" | ||
| 52 | + | ||
| 53 | +#define DATA_SIZE 4 | ||
| 54 | +#include "softmmu_header.h" | ||
| 55 | + | ||
| 56 | +#define DATA_SIZE 8 | ||
| 57 | +#include "softmmu_header.h" | ||
| 58 | +#undef ACCESS_TYPE | ||
| 59 | +#undef MEMSUFFIX | ||
| 60 | + | ||
| 61 | +#define ACCESS_TYPE 1 | ||
| 62 | +#define MEMSUFFIX _user | ||
| 63 | +#define DATA_SIZE 1 | ||
| 64 | +#include "softmmu_header.h" | ||
| 65 | + | ||
| 66 | +#define DATA_SIZE 2 | ||
| 67 | +#include "softmmu_header.h" | ||
| 68 | + | ||
| 69 | +#define DATA_SIZE 4 | ||
| 70 | +#include "softmmu_header.h" | ||
| 71 | + | ||
| 72 | +#define DATA_SIZE 8 | ||
| 73 | +#include "softmmu_header.h" | ||
| 74 | +#undef ACCESS_TYPE | ||
| 75 | +#undef MEMSUFFIX | ||
| 76 | + | ||
| 77 | +/* these access are slower, they must be as rare as possible */ | ||
| 78 | +#define ACCESS_TYPE 2 | ||
| 79 | +#define MEMSUFFIX _data | ||
| 80 | +#define DATA_SIZE 1 | ||
| 81 | +#include "softmmu_header.h" | ||
| 82 | + | ||
| 83 | +#define DATA_SIZE 2 | ||
| 84 | +#include "softmmu_header.h" | ||
| 85 | + | ||
| 86 | +#define DATA_SIZE 4 | ||
| 87 | +#include "softmmu_header.h" | ||
| 88 | + | ||
| 89 | +#define DATA_SIZE 8 | ||
| 90 | +#include "softmmu_header.h" | ||
| 91 | +#undef ACCESS_TYPE | ||
| 92 | +#undef MEMSUFFIX | ||
| 93 | + | ||
| 94 | +#define ldub(p) ldub_data(p) | ||
| 95 | +#define ldsb(p) ldsb_data(p) | ||
| 96 | +#define lduw(p) lduw_data(p) | ||
| 97 | +#define ldsw(p) ldsw_data(p) | ||
| 98 | +#define ldl(p) ldl_data(p) | ||
| 99 | +#define ldq(p) ldq_data(p) | ||
| 100 | + | ||
| 101 | +#define stb(p, v) stb_data(p, v) | ||
| 102 | +#define stw(p, v) stw_data(p, v) | ||
| 103 | +#define stl(p, v) stl_data(p, v) | ||
| 104 | +#define stq(p, v) stq_data(p, v) | ||
| 105 | + | ||
| 106 | +#endif /* !defined(CONFIG_USER_ONLY) */ | ||
| 17 | #endif | 107 | #endif |
target-sparc/fop_template.h
0 โ 100644
| 1 | +/* | ||
| 2 | + * SPARC micro operations (templates for various register related | ||
| 3 | + * operations) | ||
| 4 | + * | ||
| 5 | + * Copyright (c) 2003 Fabrice Bellard | ||
| 6 | + * | ||
| 7 | + * This library is free software; you can redistribute it and/or | ||
| 8 | + * modify it under the terms of the GNU Lesser General Public | ||
| 9 | + * License as published by the Free Software Foundation; either | ||
| 10 | + * version 2 of the License, or (at your option) any later version. | ||
| 11 | + * | ||
| 12 | + * This library is distributed in the hope that it will be useful, | ||
| 13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | + * Lesser General Public License for more details. | ||
| 16 | + * | ||
| 17 | + * You should have received a copy of the GNU Lesser General Public | ||
| 18 | + * License along with this library; if not, write to the Free Software | ||
| 19 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 20 | + */ | ||
| 21 | + | ||
| 22 | +/* floating point registers moves */ | ||
| 23 | +void OPPROTO glue(op_load_fpr_FT0_fpr, REGNAME)(void) | ||
| 24 | +{ | ||
| 25 | + FT0 = REG; | ||
| 26 | +} | ||
| 27 | + | ||
| 28 | +void OPPROTO glue(op_store_FT0_fpr_fpr, REGNAME)(void) | ||
| 29 | +{ | ||
| 30 | + REG = FT0; | ||
| 31 | +} | ||
| 32 | + | ||
| 33 | +void OPPROTO glue(op_load_fpr_FT1_fpr, REGNAME)(void) | ||
| 34 | +{ | ||
| 35 | + FT1 = REG; | ||
| 36 | +} | ||
| 37 | + | ||
| 38 | +void OPPROTO glue(op_store_FT1_fpr_fpr, REGNAME)(void) | ||
| 39 | +{ | ||
| 40 | + REG = FT1; | ||
| 41 | +} | ||
| 42 | + | ||
| 43 | +void OPPROTO glue(op_load_fpr_FT2_fpr, REGNAME)(void) | ||
| 44 | +{ | ||
| 45 | + FT2 = REG; | ||
| 46 | +} | ||
| 47 | + | ||
| 48 | +void OPPROTO glue(op_store_FT2_fpr_fpr, REGNAME)(void) | ||
| 49 | +{ | ||
| 50 | + REG = FT2; | ||
| 51 | +} | ||
| 52 | + | ||
| 53 | +/* double floating point registers moves */ | ||
| 54 | +#if 0 | ||
| 55 | +#define CPU_DOUBLE_U_DEF | ||
| 56 | +typedef union { | ||
| 57 | + double d; | ||
| 58 | + struct { | ||
| 59 | + uint32_t lower; | ||
| 60 | + uint32_t upper; | ||
| 61 | + } l; | ||
| 62 | + uint64_t ll; | ||
| 63 | +} CPU_DoubleU; | ||
| 64 | +#endif /* CPU_DOUBLE_U_DEF */ | ||
| 65 | + | ||
| 66 | +void OPPROTO glue(op_load_fpr_DT0_fpr, REGNAME)(void) | ||
| 67 | +{ | ||
| 68 | + CPU_DoubleU u; | ||
| 69 | + uint32_t *p = (uint32_t *)® | ||
| 70 | + u.l.lower = *(p +1); | ||
| 71 | + u.l.upper = *p; | ||
| 72 | + DT0 = u.d; | ||
| 73 | +} | ||
| 74 | + | ||
| 75 | +void OPPROTO glue(op_store_DT0_fpr_fpr, REGNAME)(void) | ||
| 76 | +{ | ||
| 77 | + CPU_DoubleU u; | ||
| 78 | + uint32_t *p = (uint32_t *)® | ||
| 79 | + u.d = DT0; | ||
| 80 | + *(p +1) = u.l.lower; | ||
| 81 | + *p = u.l.upper; | ||
| 82 | +} | ||
| 83 | + | ||
| 84 | +void OPPROTO glue(op_load_fpr_DT1_fpr, REGNAME)(void) | ||
| 85 | +{ | ||
| 86 | + CPU_DoubleU u; | ||
| 87 | + uint32_t *p = (uint32_t *)® | ||
| 88 | + u.l.lower = *(p +1); | ||
| 89 | + u.l.upper = *p; | ||
| 90 | + DT1 = u.d; | ||
| 91 | +} | ||
| 92 | + | ||
| 93 | +void OPPROTO glue(op_store_DT1_fpr_fpr, REGNAME)(void) | ||
| 94 | +{ | ||
| 95 | + CPU_DoubleU u; | ||
| 96 | + uint32_t *p = (uint32_t *)® | ||
| 97 | + u.d = DT1; | ||
| 98 | + *(p +1) = u.l.lower; | ||
| 99 | + *p = u.l.upper; | ||
| 100 | +} | ||
| 101 | + | ||
| 102 | +void OPPROTO glue(op_load_fpr_DT2_fpr, REGNAME)(void) | ||
| 103 | +{ | ||
| 104 | + CPU_DoubleU u; | ||
| 105 | + uint32_t *p = (uint32_t *)® | ||
| 106 | + u.l.lower = *(p +1); | ||
| 107 | + u.l.upper = *p; | ||
| 108 | + DT2 = u.d; | ||
| 109 | +} | ||
| 110 | + | ||
| 111 | +void OPPROTO glue(op_store_DT2_fpr_fpr, REGNAME)(void) | ||
| 112 | +{ | ||
| 113 | + CPU_DoubleU u; | ||
| 114 | + uint32_t *p = (uint32_t *)® | ||
| 115 | + u.d = DT2; | ||
| 116 | + *(p +1) = u.l.lower; | ||
| 117 | + *p = u.l.upper; | ||
| 118 | +} | ||
| 119 | + | ||
| 120 | +#undef REG | ||
| 121 | +#undef REGNAME |
target-sparc/helper.c
0 โ 100644
| 1 | +/* | ||
| 2 | + * sparc helpers | ||
| 3 | + * | ||
| 4 | + * Copyright (c) 2003 Fabrice Bellard | ||
| 5 | + * | ||
| 6 | + * This library is free software; you can redistribute it and/or | ||
| 7 | + * modify it under the terms of the GNU Lesser General Public | ||
| 8 | + * License as published by the Free Software Foundation; either | ||
| 9 | + * version 2 of the License, or (at your option) any later version. | ||
| 10 | + * | ||
| 11 | + * This library is distributed in the hope that it will be useful, | ||
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | + * Lesser General Public License for more details. | ||
| 15 | + * | ||
| 16 | + * You should have received a copy of the GNU Lesser General Public | ||
| 17 | + * License along with this library; if not, write to the Free Software | ||
| 18 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | + */ | ||
| 20 | +#include "exec.h" | ||
| 21 | + | ||
| 22 | +#define DEBUG_PCALL | ||
| 23 | + | ||
| 24 | +#if 0 | ||
| 25 | +#define raise_exception_err(a, b)\ | ||
| 26 | +do {\ | ||
| 27 | + fprintf(logfile, "raise_exception line=%d\n", __LINE__);\ | ||
| 28 | + (raise_exception_err)(a, b);\ | ||
| 29 | +} while (0) | ||
| 30 | +#endif | ||
| 31 | + | ||
| 32 | +/* Sparc MMU emulation */ | ||
| 33 | +int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, | ||
| 34 | + int is_user, int is_softmmu); | ||
| 35 | + | ||
| 36 | + | ||
| 37 | +/* thread support */ | ||
| 38 | + | ||
| 39 | +spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; | ||
| 40 | + | ||
| 41 | +void cpu_lock(void) | ||
| 42 | +{ | ||
| 43 | + spin_lock(&global_cpu_lock); | ||
| 44 | +} | ||
| 45 | + | ||
| 46 | +void cpu_unlock(void) | ||
| 47 | +{ | ||
| 48 | + spin_unlock(&global_cpu_lock); | ||
| 49 | +} | ||
| 50 | + | ||
| 51 | +#if 0 | ||
| 52 | +void cpu_loop_exit(void) | ||
| 53 | +{ | ||
| 54 | + /* NOTE: the register at this point must be saved by hand because | ||
| 55 | + longjmp restore them */ | ||
| 56 | + longjmp(env->jmp_env, 1); | ||
| 57 | +} | ||
| 58 | +#endif | ||
| 59 | + | ||
| 60 | +#if !defined(CONFIG_USER_ONLY) | ||
| 61 | + | ||
| 62 | +#define MMUSUFFIX _mmu | ||
| 63 | +#define GETPC() (__builtin_return_address(0)) | ||
| 64 | + | ||
| 65 | +#define SHIFT 0 | ||
| 66 | +#include "softmmu_template.h" | ||
| 67 | + | ||
| 68 | +#define SHIFT 1 | ||
| 69 | +#include "softmmu_template.h" | ||
| 70 | + | ||
| 71 | +#define SHIFT 2 | ||
| 72 | +#include "softmmu_template.h" | ||
| 73 | + | ||
| 74 | +#define SHIFT 3 | ||
| 75 | +#include "softmmu_template.h" | ||
| 76 | + | ||
| 77 | + | ||
| 78 | +/* try to fill the TLB and return an exception if error. If retaddr is | ||
| 79 | + NULL, it means that the function was called in C code (i.e. not | ||
| 80 | + from generated code or from helper.c) */ | ||
| 81 | +/* XXX: fix it to restore all registers */ | ||
| 82 | +void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr) | ||
| 83 | +{ | ||
| 84 | + TranslationBlock *tb; | ||
| 85 | + int ret; | ||
| 86 | + unsigned long pc; | ||
| 87 | + CPUState *saved_env; | ||
| 88 | + | ||
| 89 | + /* XXX: hack to restore env in all cases, even if not called from | ||
| 90 | + generated code */ | ||
| 91 | + saved_env = env; | ||
| 92 | + env = cpu_single_env; | ||
| 93 | + | ||
| 94 | + ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, is_user, 1); | ||
| 95 | + if (ret) { | ||
| 96 | + if (retaddr) { | ||
| 97 | + /* now we have a real cpu fault */ | ||
| 98 | + pc = (unsigned long)retaddr; | ||
| 99 | + tb = tb_find_pc(pc); | ||
| 100 | + if (tb) { | ||
| 101 | + /* the PC is inside the translated code. It means that we have | ||
| 102 | + a virtual CPU fault */ | ||
| 103 | + cpu_restore_state(tb, env, pc, NULL); | ||
| 104 | + } | ||
| 105 | + } | ||
| 106 | + raise_exception_err(ret, env->error_code); | ||
| 107 | + } | ||
| 108 | + env = saved_env; | ||
| 109 | +} | ||
| 110 | +#endif | ||
| 111 | + | ||
| 112 | +static const int access_table[8][8] = { | ||
| 113 | + { 0, 0, 0, 0, 2, 0, 3, 3 }, | ||
| 114 | + { 0, 0, 0, 0, 2, 0, 0, 0 }, | ||
| 115 | + { 2, 2, 0, 0, 0, 2, 3, 3 }, | ||
| 116 | + { 2, 2, 0, 0, 0, 2, 0, 0 }, | ||
| 117 | + { 2, 0, 2, 0, 2, 2, 3, 3 }, | ||
| 118 | + { 2, 0, 2, 0, 2, 0, 2, 0 }, | ||
| 119 | + { 2, 2, 2, 0, 2, 2, 3, 3 }, | ||
| 120 | + { 2, 2, 2, 0, 2, 2, 2, 0 } | ||
| 121 | +}; | ||
| 122 | + | ||
| 123 | +/* 1 = write OK */ | ||
| 124 | +static const int rw_table[2][8] = { | ||
| 125 | + { 0, 1, 0, 1, 0, 1, 0, 1 }, | ||
| 126 | + { 0, 1, 0, 1, 0, 0, 0, 0 } | ||
| 127 | +}; | ||
| 128 | + | ||
| 129 | + | ||
| 130 | +/* Perform address translation */ | ||
| 131 | +int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, | ||
| 132 | + int is_user, int is_softmmu) | ||
| 133 | +{ | ||
| 134 | + int exception = 0; | ||
| 135 | + int access_type, access_perms = 0, access_index = 0; | ||
| 136 | + uint8_t *pde_ptr; | ||
| 137 | + uint32_t pde, virt_addr; | ||
| 138 | + int error_code = 0, is_dirty, prot, ret = 0; | ||
| 139 | + unsigned long paddr, vaddr, page_offset; | ||
| 140 | + | ||
| 141 | + access_type = env->access_type; | ||
| 142 | + if (env->user_mode_only) { | ||
| 143 | + /* user mode only emulation */ | ||
| 144 | + ret = -2; | ||
| 145 | + goto do_fault; | ||
| 146 | + } | ||
| 147 | + | ||
| 148 | + virt_addr = address & TARGET_PAGE_MASK; | ||
| 149 | + if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */ | ||
| 150 | + paddr = address; | ||
| 151 | + page_offset = address & (TARGET_PAGE_SIZE - 1); | ||
| 152 | + prot = PAGE_READ | PAGE_WRITE; | ||
| 153 | + goto do_mapping; | ||
| 154 | + } | ||
| 155 | + | ||
| 156 | + /* SPARC reference MMU table walk: Context table->L1->L2->PTE */ | ||
| 157 | + /* Context base + context number */ | ||
| 158 | + pde_ptr = phys_ram_base + (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4); | ||
| 159 | + env->access_type = ACCESS_MMU; | ||
| 160 | + pde = ldl_raw(pde_ptr); | ||
| 161 | + | ||
| 162 | + /* Ctx pde */ | ||
| 163 | + switch (pde & PTE_ENTRYTYPE_MASK) { | ||
| 164 | + case 0: /* Invalid */ | ||
| 165 | + error_code = 1; | ||
| 166 | + goto do_fault; | ||
| 167 | + case 2: /* PTE, maybe should not happen? */ | ||
| 168 | + case 3: /* Reserved */ | ||
| 169 | + error_code = 4; | ||
| 170 | + goto do_fault; | ||
| 171 | + case 1: /* L1 PDE */ | ||
| 172 | + pde_ptr = phys_ram_base + ((address >> 22) & ~3) + ((pde & ~3) << 4); | ||
| 173 | + pde = ldl_raw(pde_ptr); | ||
| 174 | + | ||
| 175 | + switch (pde & PTE_ENTRYTYPE_MASK) { | ||
| 176 | + case 0: /* Invalid */ | ||
| 177 | + error_code = 1; | ||
| 178 | + goto do_fault; | ||
| 179 | + case 3: /* Reserved */ | ||
| 180 | + error_code = 4; | ||
| 181 | + goto do_fault; | ||
| 182 | + case 1: /* L2 PDE */ | ||
| 183 | + pde_ptr = phys_ram_base + ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); | ||
| 184 | + pde = ldl_raw(pde_ptr); | ||
| 185 | + | ||
| 186 | + switch (pde & PTE_ENTRYTYPE_MASK) { | ||
| 187 | + case 0: /* Invalid */ | ||
| 188 | + error_code = 1; | ||
| 189 | + goto do_fault; | ||
| 190 | + case 3: /* Reserved */ | ||
| 191 | + error_code = 4; | ||
| 192 | + goto do_fault; | ||
| 193 | + case 1: /* L3 PDE */ | ||
| 194 | + pde_ptr = phys_ram_base + ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); | ||
| 195 | + pde = ldl_raw(pde_ptr); | ||
| 196 | + | ||
| 197 | + switch (pde & PTE_ENTRYTYPE_MASK) { | ||
| 198 | + case 0: /* Invalid */ | ||
| 199 | + error_code = 1; | ||
| 200 | + goto do_fault; | ||
| 201 | + case 1: /* PDE, should not happen */ | ||
| 202 | + case 3: /* Reserved */ | ||
| 203 | + error_code = 4; | ||
| 204 | + goto do_fault; | ||
| 205 | + case 2: /* L3 PTE */ | ||
| 206 | + virt_addr = address & TARGET_PAGE_MASK; | ||
| 207 | + page_offset = (address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1); | ||
| 208 | + } | ||
| 209 | + break; | ||
| 210 | + case 2: /* L2 PTE */ | ||
| 211 | + virt_addr = address & ~0x3ffff; | ||
| 212 | + page_offset = address & 0x3ffff; | ||
| 213 | + } | ||
| 214 | + break; | ||
| 215 | + case 2: /* L1 PTE */ | ||
| 216 | + virt_addr = address & ~0xffffff; | ||
| 217 | + page_offset = address & 0xffffff; | ||
| 218 | + } | ||
| 219 | + } | ||
| 220 | + | ||
| 221 | + /* update page modified and dirty bits */ | ||
| 222 | + is_dirty = rw && !(pde & PG_MODIFIED_MASK); | ||
| 223 | + if (!(pde & PG_ACCESSED_MASK) || is_dirty) { | ||
| 224 | + pde |= PG_ACCESSED_MASK; | ||
| 225 | + if (is_dirty) | ||
| 226 | + pde |= PG_MODIFIED_MASK; | ||
| 227 | + stl_raw(pde_ptr, pde); | ||
| 228 | + } | ||
| 229 | + | ||
| 230 | + /* check access */ | ||
| 231 | + access_index = (rw << 2) | ((access_type == ACCESS_CODE)? 2 : 0) | (is_user? 0 : 1); | ||
| 232 | + access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT; | ||
| 233 | + error_code = access_table[access_index][access_perms]; | ||
| 234 | + if (error_code) | ||
| 235 | + goto do_fault; | ||
| 236 | + | ||
| 237 | + /* the page can be put in the TLB */ | ||
| 238 | + prot = PAGE_READ; | ||
| 239 | + if (pde & PG_MODIFIED_MASK) { | ||
| 240 | + /* only set write access if already dirty... otherwise wait | ||
| 241 | + for dirty access */ | ||
| 242 | + if (rw_table[is_user][access_perms]) | ||
| 243 | + prot |= PAGE_WRITE; | ||
| 244 | + } | ||
| 245 | + | ||
| 246 | + /* Even if large ptes, we map only one 4KB page in the cache to | ||
| 247 | + avoid filling it too fast */ | ||
| 248 | + virt_addr = address & TARGET_PAGE_MASK; | ||
| 249 | + paddr = ((pde & PTE_ADDR_MASK) << 4) + page_offset; | ||
| 250 | + | ||
| 251 | + do_mapping: | ||
| 252 | + env->access_type = access_type; | ||
| 253 | + vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1)); | ||
| 254 | + | ||
| 255 | + ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu); | ||
| 256 | + return ret; | ||
| 257 | + | ||
| 258 | + do_fault: | ||
| 259 | + env->access_type = access_type; | ||
| 260 | + if (env->mmuregs[3]) /* Fault status register */ | ||
| 261 | + env->mmuregs[3] = 1; /* overflow (not read before another fault) */ | ||
| 262 | + env->mmuregs[3] |= (access_index << 5) | (error_code << 2) | 2; | ||
| 263 | + env->mmuregs[4] = address; /* Fault address register */ | ||
| 264 | + | ||
| 265 | + if (env->mmuregs[0] & MMU_NF) // No fault | ||
| 266 | + return 0; | ||
| 267 | + | ||
| 268 | + env->exception_index = exception; | ||
| 269 | + env->error_code = error_code; | ||
| 270 | + return error_code; | ||
| 271 | +} | ||
| 272 | + | ||
| 273 | +void memcpy32(uint32_t *dst, const uint32_t *src) | ||
| 274 | +{ | ||
| 275 | + dst[0] = src[0]; | ||
| 276 | + dst[1] = src[1]; | ||
| 277 | + dst[2] = src[2]; | ||
| 278 | + dst[3] = src[3]; | ||
| 279 | + dst[4] = src[4]; | ||
| 280 | + dst[5] = src[5]; | ||
| 281 | + dst[6] = src[6]; | ||
| 282 | + dst[7] = src[7]; | ||
| 283 | +} | ||
| 284 | + | ||
| 285 | +void set_cwp(int new_cwp) | ||
| 286 | +{ | ||
| 287 | + /* put the modified wrap registers at their proper location */ | ||
| 288 | + if (env->cwp == (NWINDOWS - 1)) | ||
| 289 | + memcpy32(env->regbase, env->regbase + NWINDOWS * 16); | ||
| 290 | + env->cwp = new_cwp; | ||
| 291 | + /* put the wrap registers at their temporary location */ | ||
| 292 | + if (new_cwp == (NWINDOWS - 1)) | ||
| 293 | + memcpy32(env->regbase + NWINDOWS * 16, env->regbase); | ||
| 294 | + env->regwptr = env->regbase + (new_cwp * 16); | ||
| 295 | +} | ||
| 296 | + | ||
| 297 | +/* | ||
| 298 | + * Begin execution of an interruption. is_int is TRUE if coming from | ||
| 299 | + * the int instruction. next_eip is the EIP value AFTER the interrupt | ||
| 300 | + * instruction. It is only relevant if is_int is TRUE. | ||
| 301 | + */ | ||
| 302 | +void do_interrupt(int intno, int is_int, int error_code, | ||
| 303 | + unsigned int next_eip, int is_hw) | ||
| 304 | +{ | ||
| 305 | + int cwp; | ||
| 306 | + | ||
| 307 | +#ifdef DEBUG_PCALL | ||
| 308 | + if (loglevel & CPU_LOG_INT) { | ||
| 309 | + static int count; | ||
| 310 | + fprintf(logfile, "%6d: v=%02x e=%04x i=%d pc=%08x npc=%08x SP=%08x\n", | ||
| 311 | + count, intno, error_code, is_int, | ||
| 312 | + env->pc, | ||
| 313 | + env->npc, env->gregs[7]); | ||
| 314 | +#if 0 | ||
| 315 | + cpu_sparc_dump_state(env, logfile, 0); | ||
| 316 | + { | ||
| 317 | + int i; | ||
| 318 | + uint8_t *ptr; | ||
| 319 | + fprintf(logfile, " code="); | ||
| 320 | + ptr = env->pc; | ||
| 321 | + for(i = 0; i < 16; i++) { | ||
| 322 | + fprintf(logfile, " %02x", ldub(ptr + i)); | ||
| 323 | + } | ||
| 324 | + fprintf(logfile, "\n"); | ||
| 325 | + } | ||
| 326 | +#endif | ||
| 327 | + count++; | ||
| 328 | + } | ||
| 329 | +#endif | ||
| 330 | + env->psret = 0; | ||
| 331 | + cwp = (env->cwp - 1) & (NWINDOWS - 1); | ||
| 332 | + set_cwp(cwp); | ||
| 333 | + env->regwptr[9] = env->pc; | ||
| 334 | + env->regwptr[10] = env->npc; | ||
| 335 | + env->psrps = env->psrs; | ||
| 336 | + env->psrs = 1; | ||
| 337 | + env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4); | ||
| 338 | + env->pc = env->tbr; | ||
| 339 | + env->npc = env->pc + 4; | ||
| 340 | + env->exception_index = 0; | ||
| 341 | +} | ||
| 342 | + | ||
| 343 | +void raise_exception_err(int exception_index, int error_code) | ||
| 344 | +{ | ||
| 345 | + raise_exception(exception_index); | ||
| 346 | +} |
target-sparc/op.c
| @@ -117,9 +117,108 @@ | @@ -117,9 +117,108 @@ | ||
| 117 | #define REGNAME o7 | 117 | #define REGNAME o7 |
| 118 | #define REG (env->regwptr[7]) | 118 | #define REG (env->regwptr[7]) |
| 119 | #include "op_template.h" | 119 | #include "op_template.h" |
| 120 | + | ||
| 121 | +#define REGNAME f0 | ||
| 122 | +#define REG (env->fpr[0]) | ||
| 123 | +#include "fop_template.h" | ||
| 124 | +#define REGNAME f1 | ||
| 125 | +#define REG (env->fpr[1]) | ||
| 126 | +#include "fop_template.h" | ||
| 127 | +#define REGNAME f2 | ||
| 128 | +#define REG (env->fpr[2]) | ||
| 129 | +#include "fop_template.h" | ||
| 130 | +#define REGNAME f3 | ||
| 131 | +#define REG (env->fpr[3]) | ||
| 132 | +#include "fop_template.h" | ||
| 133 | +#define REGNAME f4 | ||
| 134 | +#define REG (env->fpr[4]) | ||
| 135 | +#include "fop_template.h" | ||
| 136 | +#define REGNAME f5 | ||
| 137 | +#define REG (env->fpr[5]) | ||
| 138 | +#include "fop_template.h" | ||
| 139 | +#define REGNAME f6 | ||
| 140 | +#define REG (env->fpr[6]) | ||
| 141 | +#include "fop_template.h" | ||
| 142 | +#define REGNAME f7 | ||
| 143 | +#define REG (env->fpr[7]) | ||
| 144 | +#include "fop_template.h" | ||
| 145 | +#define REGNAME f8 | ||
| 146 | +#define REG (env->fpr[8]) | ||
| 147 | +#include "fop_template.h" | ||
| 148 | +#define REGNAME f9 | ||
| 149 | +#define REG (env->fpr[9]) | ||
| 150 | +#include "fop_template.h" | ||
| 151 | +#define REGNAME f10 | ||
| 152 | +#define REG (env->fpr[10]) | ||
| 153 | +#include "fop_template.h" | ||
| 154 | +#define REGNAME f11 | ||
| 155 | +#define REG (env->fpr[11]) | ||
| 156 | +#include "fop_template.h" | ||
| 157 | +#define REGNAME f12 | ||
| 158 | +#define REG (env->fpr[12]) | ||
| 159 | +#include "fop_template.h" | ||
| 160 | +#define REGNAME f13 | ||
| 161 | +#define REG (env->fpr[13]) | ||
| 162 | +#include "fop_template.h" | ||
| 163 | +#define REGNAME f14 | ||
| 164 | +#define REG (env->fpr[14]) | ||
| 165 | +#include "fop_template.h" | ||
| 166 | +#define REGNAME f15 | ||
| 167 | +#define REG (env->fpr[15]) | ||
| 168 | +#include "fop_template.h" | ||
| 169 | +#define REGNAME f16 | ||
| 170 | +#define REG (env->fpr[16]) | ||
| 171 | +#include "fop_template.h" | ||
| 172 | +#define REGNAME f17 | ||
| 173 | +#define REG (env->fpr[17]) | ||
| 174 | +#include "fop_template.h" | ||
| 175 | +#define REGNAME f18 | ||
| 176 | +#define REG (env->fpr[18]) | ||
| 177 | +#include "fop_template.h" | ||
| 178 | +#define REGNAME f19 | ||
| 179 | +#define REG (env->fpr[19]) | ||
| 180 | +#include "fop_template.h" | ||
| 181 | +#define REGNAME f20 | ||
| 182 | +#define REG (env->fpr[20]) | ||
| 183 | +#include "fop_template.h" | ||
| 184 | +#define REGNAME f21 | ||
| 185 | +#define REG (env->fpr[21]) | ||
| 186 | +#include "fop_template.h" | ||
| 187 | +#define REGNAME f22 | ||
| 188 | +#define REG (env->fpr[22]) | ||
| 189 | +#include "fop_template.h" | ||
| 190 | +#define REGNAME f23 | ||
| 191 | +#define REG (env->fpr[23]) | ||
| 192 | +#include "fop_template.h" | ||
| 193 | +#define REGNAME f24 | ||
| 194 | +#define REG (env->fpr[24]) | ||
| 195 | +#include "fop_template.h" | ||
| 196 | +#define REGNAME f25 | ||
| 197 | +#define REG (env->fpr[25]) | ||
| 198 | +#include "fop_template.h" | ||
| 199 | +#define REGNAME f26 | ||
| 200 | +#define REG (env->fpr[26]) | ||
| 201 | +#include "fop_template.h" | ||
| 202 | +#define REGNAME f27 | ||
| 203 | +#define REG (env->fpr[27]) | ||
| 204 | +#include "fop_template.h" | ||
| 205 | +#define REGNAME f28 | ||
| 206 | +#define REG (env->fpr[28]) | ||
| 207 | +#include "fop_template.h" | ||
| 208 | +#define REGNAME f29 | ||
| 209 | +#define REG (env->fpr[29]) | ||
| 210 | +#include "fop_template.h" | ||
| 211 | +#define REGNAME f30 | ||
| 212 | +#define REG (env->fpr[30]) | ||
| 213 | +#include "fop_template.h" | ||
| 214 | +#define REGNAME f31 | ||
| 215 | +#define REG (env->fpr[31]) | ||
| 216 | +#include "fop_template.h" | ||
| 217 | + | ||
| 120 | #define EIP (env->pc) | 218 | #define EIP (env->pc) |
| 121 | 219 | ||
| 122 | #define FLAG_SET(x) (env->psr&x)?1:0 | 220 | #define FLAG_SET(x) (env->psr&x)?1:0 |
| 221 | +#define FFLAG_SET(x) ((env->fsr&x)?1:0) | ||
| 123 | 222 | ||
| 124 | void OPPROTO op_movl_T0_0(void) | 223 | void OPPROTO op_movl_T0_0(void) |
| 125 | { | 224 | { |
| @@ -375,6 +474,7 @@ void OPPROTO op_sra(void) | @@ -375,6 +474,7 @@ void OPPROTO op_sra(void) | ||
| 375 | T0 = ((int32_t) T0) >> T1; | 474 | T0 = ((int32_t) T0) >> T1; |
| 376 | } | 475 | } |
| 377 | 476 | ||
| 477 | +#if 0 | ||
| 378 | void OPPROTO op_st(void) | 478 | void OPPROTO op_st(void) |
| 379 | { | 479 | { |
| 380 | stl((void *) T0, T1); | 480 | stl((void *) T0, T1); |
| @@ -440,6 +540,51 @@ void OPPROTO op_ldd(void) | @@ -440,6 +540,51 @@ void OPPROTO op_ldd(void) | ||
| 440 | T0 = ldl((void *) (T0 + 4)); | 540 | T0 = ldl((void *) (T0 + 4)); |
| 441 | } | 541 | } |
| 442 | 542 | ||
| 543 | +void OPPROTO op_stf(void) | ||
| 544 | +{ | ||
| 545 | + stfl((void *) T0, FT0); | ||
| 546 | +} | ||
| 547 | + | ||
| 548 | +void OPPROTO op_stdf(void) | ||
| 549 | +{ | ||
| 550 | + stfq((void *) T0, DT0); | ||
| 551 | +} | ||
| 552 | + | ||
| 553 | +void OPPROTO op_ldf(void) | ||
| 554 | +{ | ||
| 555 | + FT0 = ldfl((void *) T0); | ||
| 556 | +} | ||
| 557 | + | ||
| 558 | +void OPPROTO op_lddf(void) | ||
| 559 | +{ | ||
| 560 | + DT0 = ldfq((void *) T0); | ||
| 561 | +} | ||
| 562 | +#else | ||
| 563 | +/* Load and store */ | ||
| 564 | +#define MEMSUFFIX _raw | ||
| 565 | +#include "op_mem.h" | ||
| 566 | +#if !defined(CONFIG_USER_ONLY) | ||
| 567 | +#define MEMSUFFIX _user | ||
| 568 | +#include "op_mem.h" | ||
| 569 | + | ||
| 570 | +#define MEMSUFFIX _kernel | ||
| 571 | +#include "op_mem.h" | ||
| 572 | +#endif | ||
| 573 | +#endif | ||
| 574 | + | ||
| 575 | +void OPPROTO op_ldfsr(void) | ||
| 576 | +{ | ||
| 577 | + env->fsr = *((uint32_t *) &FT0); | ||
| 578 | + FORCE_RET(); | ||
| 579 | +} | ||
| 580 | + | ||
| 581 | +void OPPROTO op_stfsr(void) | ||
| 582 | +{ | ||
| 583 | + *((uint32_t *) &FT0) = env->fsr; | ||
| 584 | + helper_stfsr(); | ||
| 585 | + FORCE_RET(); | ||
| 586 | +} | ||
| 587 | + | ||
| 443 | void OPPROTO op_wry(void) | 588 | void OPPROTO op_wry(void) |
| 444 | { | 589 | { |
| 445 | env->y = T0; | 590 | env->y = T0; |
| @@ -450,36 +595,56 @@ void OPPROTO op_rdy(void) | @@ -450,36 +595,56 @@ void OPPROTO op_rdy(void) | ||
| 450 | T0 = env->y; | 595 | T0 = env->y; |
| 451 | } | 596 | } |
| 452 | 597 | ||
| 453 | -void raise_exception(int tt) | 598 | +void OPPROTO op_rdwim(void) |
| 454 | { | 599 | { |
| 455 | - env->exception_index = tt; | ||
| 456 | - cpu_loop_exit(); | ||
| 457 | -} | 600 | + T0 = env->wim; |
| 601 | +} | ||
| 602 | + | ||
| 603 | +void OPPROTO op_wrwim(void) | ||
| 604 | +{ | ||
| 605 | + env->wim = T0; | ||
| 606 | + FORCE_RET(); | ||
| 607 | +} | ||
| 608 | + | ||
| 609 | +void OPPROTO op_rdpsr(void) | ||
| 610 | +{ | ||
| 611 | + T0 = GET_PSR(env); | ||
| 612 | + FORCE_RET(); | ||
| 613 | +} | ||
| 614 | + | ||
| 615 | +void OPPROTO op_wrpsr(void) | ||
| 616 | +{ | ||
| 617 | + env->psr = T0 & ~PSR_ICC; | ||
| 618 | + env->psrs = (T0 & PSR_S)? 1 : 0; | ||
| 619 | + env->psrps = (T0 & PSR_PS)? 1 : 0; | ||
| 620 | + env->psret = (T0 & PSR_ET)? 1 : 0; | ||
| 621 | + env->cwp = (T0 & PSR_CWP); | ||
| 622 | + FORCE_RET(); | ||
| 623 | +} | ||
| 624 | + | ||
| 625 | +void OPPROTO op_rdtbr(void) | ||
| 626 | +{ | ||
| 627 | + T0 = env->tbr; | ||
| 628 | +} | ||
| 458 | 629 | ||
| 459 | -void memcpy32(uint32_t *dst, const uint32_t *src) | 630 | +void OPPROTO op_wrtbr(void) |
| 460 | { | 631 | { |
| 461 | - dst[0] = src[0]; | ||
| 462 | - dst[1] = src[1]; | ||
| 463 | - dst[2] = src[2]; | ||
| 464 | - dst[3] = src[3]; | ||
| 465 | - dst[4] = src[4]; | ||
| 466 | - dst[5] = src[5]; | ||
| 467 | - dst[6] = src[6]; | ||
| 468 | - dst[7] = src[7]; | 632 | + env->tbr = T0; |
| 633 | + FORCE_RET(); | ||
| 469 | } | 634 | } |
| 470 | 635 | ||
| 471 | -static inline void set_cwp(int new_cwp) | 636 | +void OPPROTO op_rett(void) |
| 472 | { | 637 | { |
| 473 | - /* put the modified wrap registers at their proper location */ | ||
| 474 | - if (env->cwp == (NWINDOWS - 1)) | ||
| 475 | - memcpy32(env->regbase, env->regbase + NWINDOWS * 16); | ||
| 476 | - env->cwp = new_cwp; | ||
| 477 | - /* put the wrap registers at their temporary location */ | ||
| 478 | - if (new_cwp == (NWINDOWS - 1)) | ||
| 479 | - memcpy32(env->regbase + NWINDOWS * 16, env->regbase); | ||
| 480 | - env->regwptr = env->regbase + (new_cwp * 16); | 638 | + helper_rett(); |
| 639 | + FORCE_RET(); | ||
| 481 | } | 640 | } |
| 482 | 641 | ||
| 642 | +void raise_exception(int tt) | ||
| 643 | +{ | ||
| 644 | + env->exception_index = tt; | ||
| 645 | + cpu_loop_exit(); | ||
| 646 | +} | ||
| 647 | + | ||
| 483 | /* XXX: use another pointer for %iN registers to avoid slow wrapping | 648 | /* XXX: use another pointer for %iN registers to avoid slow wrapping |
| 484 | handling ? */ | 649 | handling ? */ |
| 485 | void OPPROTO op_save(void) | 650 | void OPPROTO op_save(void) |
| @@ -525,6 +690,12 @@ void OPPROTO op_trapcc_T0(void) | @@ -525,6 +690,12 @@ void OPPROTO op_trapcc_T0(void) | ||
| 525 | FORCE_RET(); | 690 | FORCE_RET(); |
| 526 | } | 691 | } |
| 527 | 692 | ||
| 693 | +void OPPROTO op_debug(void) | ||
| 694 | +{ | ||
| 695 | + env->exception_index = EXCP_DEBUG; | ||
| 696 | + cpu_loop_exit(); | ||
| 697 | +} | ||
| 698 | + | ||
| 528 | void OPPROTO op_exit_tb(void) | 699 | void OPPROTO op_exit_tb(void) |
| 529 | { | 700 | { |
| 530 | EXIT_TB(); | 701 | EXIT_TB(); |
| @@ -612,6 +783,92 @@ void OPPROTO op_eval_bvc(void) | @@ -612,6 +783,92 @@ void OPPROTO op_eval_bvc(void) | ||
| 612 | T2 = !(env->psr & PSR_OVF); | 783 | T2 = !(env->psr & PSR_OVF); |
| 613 | } | 784 | } |
| 614 | 785 | ||
| 786 | +/* FCC1:FCC0: 0 =, 1 <, 2 >, 3 u */ | ||
| 787 | + | ||
| 788 | +void OPPROTO op_eval_fbne(void) | ||
| 789 | +{ | ||
| 790 | +// !0 | ||
| 791 | + T2 = (env->fsr & (FSR_FCC1 | FSR_FCC0)); /* L or G or U */ | ||
| 792 | +} | ||
| 793 | + | ||
| 794 | +void OPPROTO op_eval_fblg(void) | ||
| 795 | +{ | ||
| 796 | +// 1 or 2 | ||
| 797 | + T2 = FFLAG_SET(FSR_FCC0) ^ FFLAG_SET(FSR_FCC1); | ||
| 798 | +} | ||
| 799 | + | ||
| 800 | +void OPPROTO op_eval_fbul(void) | ||
| 801 | +{ | ||
| 802 | +// 1 or 3 | ||
| 803 | + T2 = FFLAG_SET(FSR_FCC0); | ||
| 804 | +} | ||
| 805 | + | ||
| 806 | +void OPPROTO op_eval_fbl(void) | ||
| 807 | +{ | ||
| 808 | +// 1 | ||
| 809 | + T2 = FFLAG_SET(FSR_FCC0) & !FFLAG_SET(FSR_FCC1); | ||
| 810 | +} | ||
| 811 | + | ||
| 812 | +void OPPROTO op_eval_fbug(void) | ||
| 813 | +{ | ||
| 814 | +// 2 or 3 | ||
| 815 | + T2 = FFLAG_SET(FSR_FCC1); | ||
| 816 | +} | ||
| 817 | + | ||
| 818 | +void OPPROTO op_eval_fbg(void) | ||
| 819 | +{ | ||
| 820 | +// 2 | ||
| 821 | + T2 = !FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1); | ||
| 822 | +} | ||
| 823 | + | ||
| 824 | +void OPPROTO op_eval_fbu(void) | ||
| 825 | +{ | ||
| 826 | +// 3 | ||
| 827 | + T2 = FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1); | ||
| 828 | +} | ||
| 829 | + | ||
| 830 | +void OPPROTO op_eval_fbe(void) | ||
| 831 | +{ | ||
| 832 | +// 0 | ||
| 833 | + T2 = !FFLAG_SET(FSR_FCC0) & !FFLAG_SET(FSR_FCC1); | ||
| 834 | +} | ||
| 835 | + | ||
| 836 | +void OPPROTO op_eval_fbue(void) | ||
| 837 | +{ | ||
| 838 | +// 0 or 3 | ||
| 839 | + T2 = !(FFLAG_SET(FSR_FCC1) ^ FFLAG_SET(FSR_FCC0)); | ||
| 840 | +} | ||
| 841 | + | ||
| 842 | +void OPPROTO op_eval_fbge(void) | ||
| 843 | +{ | ||
| 844 | +// 0 or 2 | ||
| 845 | + T2 = !FFLAG_SET(FSR_FCC0); | ||
| 846 | +} | ||
| 847 | + | ||
| 848 | +void OPPROTO op_eval_fbuge(void) | ||
| 849 | +{ | ||
| 850 | +// !1 | ||
| 851 | + T2 = !(FFLAG_SET(FSR_FCC0) & !FFLAG_SET(FSR_FCC1)); | ||
| 852 | +} | ||
| 853 | + | ||
| 854 | +void OPPROTO op_eval_fble(void) | ||
| 855 | +{ | ||
| 856 | +// 0 or 1 | ||
| 857 | + T2 = !FFLAG_SET(FSR_FCC1); | ||
| 858 | +} | ||
| 859 | + | ||
| 860 | +void OPPROTO op_eval_fbule(void) | ||
| 861 | +{ | ||
| 862 | +// !2 | ||
| 863 | + T2 = !(!FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1)); | ||
| 864 | +} | ||
| 865 | + | ||
| 866 | +void OPPROTO op_eval_fbo(void) | ||
| 867 | +{ | ||
| 868 | +// !3 | ||
| 869 | + T2 = !(FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1)); | ||
| 870 | +} | ||
| 871 | + | ||
| 615 | void OPPROTO op_movl_T2_0(void) | 872 | void OPPROTO op_movl_T2_0(void) |
| 616 | { | 873 | { |
| 617 | T2 = 0; | 874 | T2 = 0; |
| @@ -687,3 +944,119 @@ void OPPROTO op_flush_T0(void) | @@ -687,3 +944,119 @@ void OPPROTO op_flush_T0(void) | ||
| 687 | { | 944 | { |
| 688 | helper_flush(T0); | 945 | helper_flush(T0); |
| 689 | } | 946 | } |
| 947 | + | ||
| 948 | +void OPPROTO op_fnegs(void) | ||
| 949 | +{ | ||
| 950 | + FT0 = -FT1; | ||
| 951 | +} | ||
| 952 | + | ||
| 953 | +void OPPROTO op_fabss(void) | ||
| 954 | +{ | ||
| 955 | + do_fabss(); | ||
| 956 | +} | ||
| 957 | + | ||
| 958 | +void OPPROTO op_fsqrts(void) | ||
| 959 | +{ | ||
| 960 | + do_fsqrts(); | ||
| 961 | +} | ||
| 962 | + | ||
| 963 | +void OPPROTO op_fsqrtd(void) | ||
| 964 | +{ | ||
| 965 | + do_fsqrtd(); | ||
| 966 | +} | ||
| 967 | + | ||
| 968 | +void OPPROTO op_fmuls(void) | ||
| 969 | +{ | ||
| 970 | + FT0 *= FT1; | ||
| 971 | +} | ||
| 972 | + | ||
| 973 | +void OPPROTO op_fmuld(void) | ||
| 974 | +{ | ||
| 975 | + DT0 *= DT1; | ||
| 976 | +} | ||
| 977 | + | ||
| 978 | +void OPPROTO op_fsmuld(void) | ||
| 979 | +{ | ||
| 980 | + DT0 = FT0 * FT1; | ||
| 981 | +} | ||
| 982 | + | ||
| 983 | +void OPPROTO op_fadds(void) | ||
| 984 | +{ | ||
| 985 | + FT0 += FT1; | ||
| 986 | +} | ||
| 987 | + | ||
| 988 | +void OPPROTO op_faddd(void) | ||
| 989 | +{ | ||
| 990 | + DT0 += DT1; | ||
| 991 | +} | ||
| 992 | + | ||
| 993 | +void OPPROTO op_fsubs(void) | ||
| 994 | +{ | ||
| 995 | + FT0 -= FT1; | ||
| 996 | +} | ||
| 997 | + | ||
| 998 | +void OPPROTO op_fsubd(void) | ||
| 999 | +{ | ||
| 1000 | + DT0 -= DT1; | ||
| 1001 | +} | ||
| 1002 | + | ||
| 1003 | +void OPPROTO op_fdivs(void) | ||
| 1004 | +{ | ||
| 1005 | + FT0 /= FT1; | ||
| 1006 | +} | ||
| 1007 | + | ||
| 1008 | +void OPPROTO op_fdivd(void) | ||
| 1009 | +{ | ||
| 1010 | + DT0 /= DT1; | ||
| 1011 | +} | ||
| 1012 | + | ||
| 1013 | +void OPPROTO op_fcmps(void) | ||
| 1014 | +{ | ||
| 1015 | + do_fcmps(); | ||
| 1016 | +} | ||
| 1017 | + | ||
| 1018 | +void OPPROTO op_fcmpd(void) | ||
| 1019 | +{ | ||
| 1020 | + do_fcmpd(); | ||
| 1021 | +} | ||
| 1022 | + | ||
| 1023 | +void OPPROTO op_fitos(void) | ||
| 1024 | +{ | ||
| 1025 | + FT0 = (float) *((int32_t *)&FT1); | ||
| 1026 | +} | ||
| 1027 | + | ||
| 1028 | +void OPPROTO op_fdtos(void) | ||
| 1029 | +{ | ||
| 1030 | + FT0 = (float) DT1; | ||
| 1031 | +} | ||
| 1032 | + | ||
| 1033 | +void OPPROTO op_fitod(void) | ||
| 1034 | +{ | ||
| 1035 | + DT0 = (double) *((int32_t *)&FT1); | ||
| 1036 | +} | ||
| 1037 | + | ||
| 1038 | +void OPPROTO op_fstod(void) | ||
| 1039 | +{ | ||
| 1040 | + DT0 = (double) FT1; | ||
| 1041 | +} | ||
| 1042 | + | ||
| 1043 | +void OPPROTO op_fstoi(void) | ||
| 1044 | +{ | ||
| 1045 | + *((int32_t *)&FT0) = (int32_t) FT1; | ||
| 1046 | +} | ||
| 1047 | + | ||
| 1048 | +void OPPROTO op_fdtoi(void) | ||
| 1049 | +{ | ||
| 1050 | + *((int32_t *)&FT0) = (int32_t) DT1; | ||
| 1051 | +} | ||
| 1052 | + | ||
| 1053 | +void OPPROTO op_ld_asi() | ||
| 1054 | +{ | ||
| 1055 | + helper_ld_asi(PARAM1, PARAM2, PARAM3); | ||
| 1056 | +} | ||
| 1057 | + | ||
| 1058 | +void OPPROTO op_st_asi() | ||
| 1059 | +{ | ||
| 1060 | + helper_st_asi(PARAM1, PARAM2, PARAM3); | ||
| 1061 | +} | ||
| 1062 | + |
target-sparc/op_helper.c
0 โ 100644
| 1 | +#include <math.h> | ||
| 2 | +#include <fenv.h> | ||
| 3 | +#include "exec.h" | ||
| 4 | + | ||
| 5 | +void OPPROTO do_fabss(void) | ||
| 6 | +{ | ||
| 7 | + FT0 = fabsf(FT1); | ||
| 8 | +} | ||
| 9 | + | ||
| 10 | +void OPPROTO do_fsqrts(void) | ||
| 11 | +{ | ||
| 12 | + FT0 = sqrtf(FT1); | ||
| 13 | +} | ||
| 14 | + | ||
| 15 | +void OPPROTO do_fsqrtd(void) | ||
| 16 | +{ | ||
| 17 | + DT0 = sqrt(DT1); | ||
| 18 | +} | ||
| 19 | + | ||
| 20 | +void OPPROTO do_fcmps (void) | ||
| 21 | +{ | ||
| 22 | + if (isnan(FT0) || isnan(FT1)) { | ||
| 23 | + T0 = FSR_FCC1 | FSR_FCC0; | ||
| 24 | + } else if (FT0 < FT1) { | ||
| 25 | + T0 = FSR_FCC0; | ||
| 26 | + } else if (FT0 > FT1) { | ||
| 27 | + T0 = FSR_FCC1; | ||
| 28 | + } else { | ||
| 29 | + T0 = 0; | ||
| 30 | + } | ||
| 31 | + env->fsr = T0; | ||
| 32 | +} | ||
| 33 | + | ||
| 34 | +void OPPROTO do_fcmpd (void) | ||
| 35 | +{ | ||
| 36 | + if (isnan(DT0) || isnan(DT1)) { | ||
| 37 | + T0 = FSR_FCC1 | FSR_FCC0; | ||
| 38 | + } else if (DT0 < DT1) { | ||
| 39 | + T0 = FSR_FCC0; | ||
| 40 | + } else if (DT0 > DT1) { | ||
| 41 | + T0 = FSR_FCC1; | ||
| 42 | + } else { | ||
| 43 | + T0 = 0; | ||
| 44 | + } | ||
| 45 | + env->fsr = T0; | ||
| 46 | +} | ||
| 47 | + | ||
| 48 | +void OPPROTO helper_ld_asi(int asi, int size, int sign) | ||
| 49 | +{ | ||
| 50 | + switch(asi) { | ||
| 51 | + case 3: /* MMU probe */ | ||
| 52 | + T1 = 0; | ||
| 53 | + return; | ||
| 54 | + case 4: /* read MMU regs */ | ||
| 55 | + { | ||
| 56 | + int temp, reg = (T0 >> 8) & 0xf; | ||
| 57 | + | ||
| 58 | + temp = env->mmuregs[reg]; | ||
| 59 | + if (reg == 3 || reg == 4) /* Fault status, addr cleared on read*/ | ||
| 60 | + env->mmuregs[reg] = 0; | ||
| 61 | + T1 = temp; | ||
| 62 | + } | ||
| 63 | + return; | ||
| 64 | + case 0x20 ... 0x2f: /* MMU passthrough */ | ||
| 65 | + { | ||
| 66 | + int temp; | ||
| 67 | + | ||
| 68 | + cpu_physical_memory_read(T0, (void *) &temp, size); | ||
| 69 | + bswap32s(&temp); | ||
| 70 | + T1 = temp; | ||
| 71 | + } | ||
| 72 | + return; | ||
| 73 | + default: | ||
| 74 | + T1 = 0; | ||
| 75 | + return; | ||
| 76 | + } | ||
| 77 | +} | ||
| 78 | + | ||
| 79 | +void OPPROTO helper_st_asi(int asi, int size, int sign) | ||
| 80 | +{ | ||
| 81 | + switch(asi) { | ||
| 82 | + case 3: /* MMU flush */ | ||
| 83 | + return; | ||
| 84 | + case 4: /* write MMU regs */ | ||
| 85 | + { | ||
| 86 | + int reg = (T0 >> 8) & 0xf; | ||
| 87 | + if (reg == 0) { | ||
| 88 | + env->mmuregs[reg] &= ~(MMU_E | MMU_NF); | ||
| 89 | + env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF); | ||
| 90 | + } else | ||
| 91 | + env->mmuregs[reg] = T1; | ||
| 92 | + return; | ||
| 93 | + } | ||
| 94 | + case 0x20 ... 0x2f: /* MMU passthrough */ | ||
| 95 | + { | ||
| 96 | + int temp = T1; | ||
| 97 | + | ||
| 98 | + bswap32s(&temp); | ||
| 99 | + cpu_physical_memory_write(T0, (void *) &temp, size); | ||
| 100 | + } | ||
| 101 | + return; | ||
| 102 | + default: | ||
| 103 | + return; | ||
| 104 | + } | ||
| 105 | +} | ||
| 106 | + | ||
| 107 | +void OPPROTO helper_rett() | ||
| 108 | +{ | ||
| 109 | + int cwp; | ||
| 110 | + env->psret = 1; | ||
| 111 | + cwp = (env->cwp + 1) & (NWINDOWS - 1); | ||
| 112 | + if (env->wim & (1 << cwp)) { | ||
| 113 | + raise_exception(TT_WIN_UNF); | ||
| 114 | + } | ||
| 115 | + set_cwp(cwp); | ||
| 116 | + env->psrs = env->psrps; | ||
| 117 | +} | ||
| 118 | + | ||
| 119 | +void helper_stfsr(void) | ||
| 120 | +{ | ||
| 121 | + switch (env->fsr & FSR_RD_MASK) { | ||
| 122 | + case FSR_RD_NEAREST: | ||
| 123 | + fesetround(FE_TONEAREST); | ||
| 124 | + break; | ||
| 125 | + case FSR_RD_ZERO: | ||
| 126 | + fesetround(FE_TOWARDZERO); | ||
| 127 | + break; | ||
| 128 | + case FSR_RD_POS: | ||
| 129 | + fesetround(FE_UPWARD); | ||
| 130 | + break; | ||
| 131 | + case FSR_RD_NEG: | ||
| 132 | + fesetround(FE_DOWNWARD); | ||
| 133 | + break; | ||
| 134 | + } | ||
| 135 | +} |
target-sparc/op_mem.h
0 โ 100644
| 1 | +/*** Integer load ***/ | ||
| 2 | +#define SPARC_LD_OP(name, qp) \ | ||
| 3 | +void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void) \ | ||
| 4 | +{ \ | ||
| 5 | + T1 = glue(qp, MEMSUFFIX)((void *)T0); \ | ||
| 6 | +} | ||
| 7 | + | ||
| 8 | +#define SPARC_ST_OP(name, op) \ | ||
| 9 | +void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void) \ | ||
| 10 | +{ \ | ||
| 11 | + glue(op, MEMSUFFIX)((void *)T0, T1); \ | ||
| 12 | +} | ||
| 13 | + | ||
| 14 | +SPARC_LD_OP(ld, ldl); | ||
| 15 | +SPARC_LD_OP(ldub, ldub); | ||
| 16 | +SPARC_LD_OP(lduh, lduw); | ||
| 17 | +SPARC_LD_OP(ldsb, ldsb); | ||
| 18 | +SPARC_LD_OP(ldsh, ldsw); | ||
| 19 | + | ||
| 20 | +/*** Integer store ***/ | ||
| 21 | +SPARC_ST_OP(st, stl); | ||
| 22 | +SPARC_ST_OP(stb, stb); | ||
| 23 | +SPARC_ST_OP(sth, stw); | ||
| 24 | + | ||
| 25 | +void OPPROTO glue(op_std, MEMSUFFIX)(void) | ||
| 26 | +{ | ||
| 27 | + glue(stl, MEMSUFFIX)((void *) T0, T1); | ||
| 28 | + glue(stl, MEMSUFFIX)((void *) (T0 + 4), T2); | ||
| 29 | +} | ||
| 30 | + | ||
| 31 | +void OPPROTO glue(op_ldstub, MEMSUFFIX)(void) | ||
| 32 | +{ | ||
| 33 | + T1 = glue(ldub, MEMSUFFIX)((void *) T0); | ||
| 34 | + glue(stb, MEMSUFFIX)((void *) T0, 0xff); /* XXX: Should be Atomically */ | ||
| 35 | +} | ||
| 36 | + | ||
| 37 | +void OPPROTO glue(op_swap, MEMSUFFIX)(void) | ||
| 38 | +{ | ||
| 39 | + unsigned int tmp = glue(ldl, MEMSUFFIX)((void *) T0); | ||
| 40 | + glue(stl, MEMSUFFIX)((void *) T0, T1); /* XXX: Should be Atomically */ | ||
| 41 | + T1 = tmp; | ||
| 42 | +} | ||
| 43 | + | ||
| 44 | +void OPPROTO glue(op_ldd, MEMSUFFIX)(void) | ||
| 45 | +{ | ||
| 46 | + T1 = glue(ldl, MEMSUFFIX)((void *) T0); | ||
| 47 | + T0 = glue(ldl, MEMSUFFIX)((void *) (T0 + 4)); | ||
| 48 | +} | ||
| 49 | + | ||
| 50 | +/*** Floating-point store ***/ | ||
| 51 | +void OPPROTO glue(op_stf, MEMSUFFIX) (void) | ||
| 52 | +{ | ||
| 53 | + glue(stfl, MEMSUFFIX)((void *) T0, FT0); | ||
| 54 | +} | ||
| 55 | + | ||
| 56 | +void OPPROTO glue(op_stdf, MEMSUFFIX) (void) | ||
| 57 | +{ | ||
| 58 | + glue(stfq, MEMSUFFIX)((void *) T0, DT0); | ||
| 59 | +} | ||
| 60 | + | ||
| 61 | +/*** Floating-point load ***/ | ||
| 62 | +void OPPROTO glue(op_ldf, MEMSUFFIX) (void) | ||
| 63 | +{ | ||
| 64 | + FT0 = glue(ldfl, MEMSUFFIX)((void *) T0); | ||
| 65 | +} | ||
| 66 | + | ||
| 67 | +void OPPROTO glue(op_lddf, MEMSUFFIX) (void) | ||
| 68 | +{ | ||
| 69 | + DT0 = glue(ldfq, MEMSUFFIX)((void *) T0); | ||
| 70 | +} | ||
| 71 | +#undef MEMSUFFIX |
target-sparc/translate.c
| @@ -51,6 +51,7 @@ typedef struct DisasContext { | @@ -51,6 +51,7 @@ typedef struct DisasContext { | ||
| 51 | target_ulong npc; /* next PC: integer or DYNAMIC_PC or JUMP_PC */ | 51 | target_ulong npc; /* next PC: integer or DYNAMIC_PC or JUMP_PC */ |
| 52 | target_ulong jump_pc[2]; /* used when JUMP_PC pc value is used */ | 52 | target_ulong jump_pc[2]; /* used when JUMP_PC pc value is used */ |
| 53 | int is_br; | 53 | int is_br; |
| 54 | + int mem_idx; | ||
| 54 | struct TranslationBlock *tb; | 55 | struct TranslationBlock *tb; |
| 55 | } DisasContext; | 56 | } DisasContext; |
| 56 | 57 | ||
| @@ -257,6 +258,96 @@ static GenOpFunc1 *gen_op_movl_TN_im[3] = { | @@ -257,6 +258,96 @@ static GenOpFunc1 *gen_op_movl_TN_im[3] = { | ||
| 257 | gen_op_movl_T2_im | 258 | gen_op_movl_T2_im |
| 258 | }; | 259 | }; |
| 259 | 260 | ||
| 261 | +#define GEN32(func, NAME) \ | ||
| 262 | +static GenOpFunc *NAME ## _table [32] = { \ | ||
| 263 | +NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ | ||
| 264 | +NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ | ||
| 265 | +NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ | ||
| 266 | +NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ | ||
| 267 | +NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ | ||
| 268 | +NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ | ||
| 269 | +NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ | ||
| 270 | +NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ | ||
| 271 | +}; \ | ||
| 272 | +static inline void func(int n) \ | ||
| 273 | +{ \ | ||
| 274 | + NAME ## _table[n](); \ | ||
| 275 | +} | ||
| 276 | + | ||
| 277 | +/* floating point registers moves */ | ||
| 278 | +GEN32(gen_op_load_fpr_FT0, gen_op_load_fpr_FT0_fprf); | ||
| 279 | +GEN32(gen_op_load_fpr_FT1, gen_op_load_fpr_FT1_fprf); | ||
| 280 | +GEN32(gen_op_load_fpr_FT2, gen_op_load_fpr_FT2_fprf); | ||
| 281 | +GEN32(gen_op_store_FT0_fpr, gen_op_store_FT0_fpr_fprf); | ||
| 282 | +GEN32(gen_op_store_FT1_fpr, gen_op_store_FT1_fpr_fprf); | ||
| 283 | +GEN32(gen_op_store_FT2_fpr, gen_op_store_FT2_fpr_fprf); | ||
| 284 | + | ||
| 285 | +GEN32(gen_op_load_fpr_DT0, gen_op_load_fpr_DT0_fprf); | ||
| 286 | +GEN32(gen_op_load_fpr_DT1, gen_op_load_fpr_DT1_fprf); | ||
| 287 | +GEN32(gen_op_load_fpr_DT2, gen_op_load_fpr_DT2_fprf); | ||
| 288 | +GEN32(gen_op_store_DT0_fpr, gen_op_store_DT0_fpr_fprf); | ||
| 289 | +GEN32(gen_op_store_DT1_fpr, gen_op_store_DT1_fpr_fprf); | ||
| 290 | +GEN32(gen_op_store_DT2_fpr, gen_op_store_DT2_fpr_fprf); | ||
| 291 | + | ||
| 292 | +#if defined(CONFIG_USER_ONLY) | ||
| 293 | +#define gen_op_ldst(name) gen_op_##name##_raw() | ||
| 294 | +#define OP_LD_TABLE(width) | ||
| 295 | +#define supervisor(dc) 0 | ||
| 296 | +#else | ||
| 297 | +#define gen_op_ldst(name) (*gen_op_##name[dc->mem_idx])() | ||
| 298 | +#define OP_LD_TABLE(width) \ | ||
| 299 | +static GenOpFunc *gen_op_##width[] = { \ | ||
| 300 | + &gen_op_##width##_user, \ | ||
| 301 | + &gen_op_##width##_kernel, \ | ||
| 302 | +}; \ | ||
| 303 | + \ | ||
| 304 | +static void gen_op_##width##a(int insn, int is_ld, int size, int sign) \ | ||
| 305 | +{ \ | ||
| 306 | + int asi; \ | ||
| 307 | + \ | ||
| 308 | + asi = GET_FIELD(insn, 19, 26); \ | ||
| 309 | + switch (asi) { \ | ||
| 310 | + case 10: /* User data access */ \ | ||
| 311 | + gen_op_##width##_user(); \ | ||
| 312 | + break; \ | ||
| 313 | + case 11: /* Supervisor data access */ \ | ||
| 314 | + gen_op_##width##_kernel(); \ | ||
| 315 | + break; \ | ||
| 316 | + case 0x20 ... 0x2f: /* MMU passthrough */ \ | ||
| 317 | + if (is_ld) \ | ||
| 318 | + gen_op_ld_asi(asi, size, sign); \ | ||
| 319 | + else \ | ||
| 320 | + gen_op_st_asi(asi, size, sign); \ | ||
| 321 | + break; \ | ||
| 322 | + default: \ | ||
| 323 | + if (is_ld) \ | ||
| 324 | + gen_op_ld_asi(asi, size, sign); \ | ||
| 325 | + else \ | ||
| 326 | + gen_op_st_asi(asi, size, sign); \ | ||
| 327 | + break; \ | ||
| 328 | + } \ | ||
| 329 | +} | ||
| 330 | + | ||
| 331 | +#define supervisor(dc) (dc->mem_idx == 1) | ||
| 332 | +#endif | ||
| 333 | + | ||
| 334 | +OP_LD_TABLE(ld); | ||
| 335 | +OP_LD_TABLE(st); | ||
| 336 | +OP_LD_TABLE(ldub); | ||
| 337 | +OP_LD_TABLE(lduh); | ||
| 338 | +OP_LD_TABLE(ldsb); | ||
| 339 | +OP_LD_TABLE(ldsh); | ||
| 340 | +OP_LD_TABLE(stb); | ||
| 341 | +OP_LD_TABLE(sth); | ||
| 342 | +OP_LD_TABLE(std); | ||
| 343 | +OP_LD_TABLE(ldstub); | ||
| 344 | +OP_LD_TABLE(swap); | ||
| 345 | +OP_LD_TABLE(ldd); | ||
| 346 | +OP_LD_TABLE(stf); | ||
| 347 | +OP_LD_TABLE(stdf); | ||
| 348 | +OP_LD_TABLE(ldf); | ||
| 349 | +OP_LD_TABLE(lddf); | ||
| 350 | + | ||
| 260 | static inline void gen_movl_imm_TN(int reg, int imm) | 351 | static inline void gen_movl_imm_TN(int reg, int imm) |
| 261 | { | 352 | { |
| 262 | gen_op_movl_TN_im[reg] (imm); | 353 | gen_op_movl_TN_im[reg] (imm); |
| @@ -391,6 +482,60 @@ static void gen_cond(int cond) | @@ -391,6 +482,60 @@ static void gen_cond(int cond) | ||
| 391 | } | 482 | } |
| 392 | } | 483 | } |
| 393 | 484 | ||
| 485 | +static void gen_fcond(int cond) | ||
| 486 | +{ | ||
| 487 | + switch (cond) { | ||
| 488 | + case 0x0: | ||
| 489 | + gen_op_movl_T2_0(); | ||
| 490 | + break; | ||
| 491 | + case 0x1: | ||
| 492 | + gen_op_eval_fbne(); | ||
| 493 | + break; | ||
| 494 | + case 0x2: | ||
| 495 | + gen_op_eval_fblg(); | ||
| 496 | + break; | ||
| 497 | + case 0x3: | ||
| 498 | + gen_op_eval_fbul(); | ||
| 499 | + break; | ||
| 500 | + case 0x4: | ||
| 501 | + gen_op_eval_fbl(); | ||
| 502 | + break; | ||
| 503 | + case 0x5: | ||
| 504 | + gen_op_eval_fbug(); | ||
| 505 | + break; | ||
| 506 | + case 0x6: | ||
| 507 | + gen_op_eval_fbg(); | ||
| 508 | + break; | ||
| 509 | + case 0x7: | ||
| 510 | + gen_op_eval_fbu(); | ||
| 511 | + break; | ||
| 512 | + case 0x8: | ||
| 513 | + gen_op_movl_T2_1(); | ||
| 514 | + break; | ||
| 515 | + case 0x9: | ||
| 516 | + gen_op_eval_fbe(); | ||
| 517 | + break; | ||
| 518 | + case 0xa: | ||
| 519 | + gen_op_eval_fbue(); | ||
| 520 | + break; | ||
| 521 | + case 0xb: | ||
| 522 | + gen_op_eval_fbge(); | ||
| 523 | + break; | ||
| 524 | + case 0xc: | ||
| 525 | + gen_op_eval_fbuge(); | ||
| 526 | + break; | ||
| 527 | + case 0xd: | ||
| 528 | + gen_op_eval_fble(); | ||
| 529 | + break; | ||
| 530 | + case 0xe: | ||
| 531 | + gen_op_eval_fbule(); | ||
| 532 | + break; | ||
| 533 | + default: | ||
| 534 | + case 0xf: | ||
| 535 | + gen_op_eval_fbo(); | ||
| 536 | + break; | ||
| 537 | + } | ||
| 538 | +} | ||
| 394 | 539 | ||
| 395 | static void do_branch(DisasContext * dc, uint32_t target, uint32_t insn) | 540 | static void do_branch(DisasContext * dc, uint32_t target, uint32_t insn) |
| 396 | { | 541 | { |
| @@ -429,6 +574,50 @@ static void do_branch(DisasContext * dc, uint32_t target, uint32_t insn) | @@ -429,6 +574,50 @@ static void do_branch(DisasContext * dc, uint32_t target, uint32_t insn) | ||
| 429 | } | 574 | } |
| 430 | } | 575 | } |
| 431 | 576 | ||
| 577 | +static void do_fbranch(DisasContext * dc, uint32_t target, uint32_t insn) | ||
| 578 | +{ | ||
| 579 | + unsigned int cond = GET_FIELD(insn, 3, 6), a = (insn & (1 << 29)); | ||
| 580 | + target += (uint32_t) dc->pc; | ||
| 581 | + if (cond == 0x0) { | ||
| 582 | + /* unconditional not taken */ | ||
| 583 | + if (a) { | ||
| 584 | + dc->pc = dc->npc + 4; | ||
| 585 | + dc->npc = dc->pc + 4; | ||
| 586 | + } else { | ||
| 587 | + dc->pc = dc->npc; | ||
| 588 | + dc->npc = dc->pc + 4; | ||
| 589 | + } | ||
| 590 | + } else if (cond == 0x8) { | ||
| 591 | + /* unconditional taken */ | ||
| 592 | + if (a) { | ||
| 593 | + dc->pc = target; | ||
| 594 | + dc->npc = dc->pc + 4; | ||
| 595 | + } else { | ||
| 596 | + dc->pc = dc->npc; | ||
| 597 | + dc->npc = target; | ||
| 598 | + } | ||
| 599 | + } else { | ||
| 600 | + flush_T2(dc); | ||
| 601 | + gen_fcond(cond); | ||
| 602 | + if (a) { | ||
| 603 | + gen_op_branch_a((long)dc->tb, target, dc->npc); | ||
| 604 | + dc->is_br = 1; | ||
| 605 | + } else { | ||
| 606 | + dc->pc = dc->npc; | ||
| 607 | + dc->jump_pc[0] = target; | ||
| 608 | + dc->jump_pc[1] = dc->npc + 4; | ||
| 609 | + dc->npc = JUMP_PC; | ||
| 610 | + } | ||
| 611 | + } | ||
| 612 | +} | ||
| 613 | + | ||
| 614 | +static void gen_debug(DisasContext *s, uint32_t pc) | ||
| 615 | +{ | ||
| 616 | + gen_op_jmp_im(pc); | ||
| 617 | + gen_op_debug(); | ||
| 618 | + s->is_br = 1; | ||
| 619 | +} | ||
| 620 | + | ||
| 432 | #define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), (b) - (a) + 1) | 621 | #define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), (b) - (a) + 1) |
| 433 | 622 | ||
| 434 | static int sign_extend(int x, int len) | 623 | static int sign_extend(int x, int len) |
| @@ -454,6 +643,7 @@ static void disas_sparc_insn(DisasContext * dc) | @@ -454,6 +643,7 @@ static void disas_sparc_insn(DisasContext * dc) | ||
| 454 | switch (xop) { | 643 | switch (xop) { |
| 455 | case 0x0: | 644 | case 0x0: |
| 456 | case 0x1: /* UNIMPL */ | 645 | case 0x1: /* UNIMPL */ |
| 646 | + default: | ||
| 457 | goto illegal_insn; | 647 | goto illegal_insn; |
| 458 | case 0x2: /* BN+x */ | 648 | case 0x2: /* BN+x */ |
| 459 | { | 649 | { |
| @@ -462,8 +652,13 @@ static void disas_sparc_insn(DisasContext * dc) | @@ -462,8 +652,13 @@ static void disas_sparc_insn(DisasContext * dc) | ||
| 462 | do_branch(dc, target, insn); | 652 | do_branch(dc, target, insn); |
| 463 | goto jmp_insn; | 653 | goto jmp_insn; |
| 464 | } | 654 | } |
| 465 | - case 0x3: /* FBN+x */ | ||
| 466 | - break; | 655 | + case 0x6: /* FBN+x */ |
| 656 | + { | ||
| 657 | + target <<= 2; | ||
| 658 | + target = sign_extend(target, 22); | ||
| 659 | + do_fbranch(dc, target, insn); | ||
| 660 | + goto jmp_insn; | ||
| 661 | + } | ||
| 467 | case 0x4: /* SETHI */ | 662 | case 0x4: /* SETHI */ |
| 468 | gen_movl_imm_T0(target << 10); | 663 | gen_movl_imm_T0(target << 10); |
| 469 | gen_movl_T0_reg(rd); | 664 | gen_movl_T0_reg(rd); |
| @@ -492,12 +687,16 @@ static void disas_sparc_insn(DisasContext * dc) | @@ -492,12 +687,16 @@ static void disas_sparc_insn(DisasContext * dc) | ||
| 492 | rs1 = GET_FIELD(insn, 13, 17); | 687 | rs1 = GET_FIELD(insn, 13, 17); |
| 493 | gen_movl_reg_T0(rs1); | 688 | gen_movl_reg_T0(rs1); |
| 494 | if (IS_IMM) { | 689 | if (IS_IMM) { |
| 495 | - gen_movl_imm_T1(GET_FIELD(insn, 25, 31)); | 690 | + rs2 = GET_FIELD(insn, 25, 31); |
| 691 | + if (rs2 != 0) { | ||
| 692 | + gen_movl_imm_T1(rs2); | ||
| 693 | + gen_op_add_T1_T0(); | ||
| 694 | + } | ||
| 496 | } else { | 695 | } else { |
| 497 | rs2 = GET_FIELD(insn, 27, 31); | 696 | rs2 = GET_FIELD(insn, 27, 31); |
| 498 | gen_movl_reg_T1(rs2); | 697 | gen_movl_reg_T1(rs2); |
| 698 | + gen_op_add_T1_T0(); | ||
| 499 | } | 699 | } |
| 500 | - gen_op_add_T1_T0(); | ||
| 501 | save_state(dc); | 700 | save_state(dc); |
| 502 | cond = GET_FIELD(insn, 3, 6); | 701 | cond = GET_FIELD(insn, 3, 6); |
| 503 | if (cond == 0x8) { | 702 | if (cond == 0x8) { |
| @@ -514,11 +713,167 @@ static void disas_sparc_insn(DisasContext * dc) | @@ -514,11 +713,167 @@ static void disas_sparc_insn(DisasContext * dc) | ||
| 514 | gen_op_rdy(); | 713 | gen_op_rdy(); |
| 515 | gen_movl_T0_reg(rd); | 714 | gen_movl_T0_reg(rd); |
| 516 | break; | 715 | break; |
| 716 | + case 15: /* stbar */ | ||
| 717 | + break; /* no effect? */ | ||
| 517 | default: | 718 | default: |
| 518 | goto illegal_insn; | 719 | goto illegal_insn; |
| 519 | } | 720 | } |
| 721 | +#if !defined(CONFIG_USER_ONLY) | ||
| 722 | + } else if (xop == 0x29) { | ||
| 723 | + if (!supervisor(dc)) | ||
| 724 | + goto priv_insn; | ||
| 725 | + gen_op_rdpsr(); | ||
| 726 | + gen_movl_T0_reg(rd); | ||
| 727 | + break; | ||
| 728 | + } else if (xop == 0x2a) { | ||
| 729 | + if (!supervisor(dc)) | ||
| 730 | + goto priv_insn; | ||
| 731 | + gen_op_rdwim(); | ||
| 732 | + gen_movl_T0_reg(rd); | ||
| 733 | + break; | ||
| 734 | + } else if (xop == 0x2b) { | ||
| 735 | + if (!supervisor(dc)) | ||
| 736 | + goto priv_insn; | ||
| 737 | + gen_op_rdtbr(); | ||
| 738 | + gen_movl_T0_reg(rd); | ||
| 739 | + break; | ||
| 740 | +#endif | ||
| 520 | } else if (xop == 0x34 || xop == 0x35) { /* FPU Operations */ | 741 | } else if (xop == 0x34 || xop == 0x35) { /* FPU Operations */ |
| 521 | - goto illegal_insn; | 742 | + rs1 = GET_FIELD(insn, 13, 17); |
| 743 | + rs2 = GET_FIELD(insn, 27, 31); | ||
| 744 | + xop = GET_FIELD(insn, 18, 26); | ||
| 745 | + switch (xop) { | ||
| 746 | + case 0x1: /* fmovs */ | ||
| 747 | + gen_op_load_fpr_FT0(rs2); | ||
| 748 | + gen_op_store_FT0_fpr(rd); | ||
| 749 | + break; | ||
| 750 | + case 0x5: /* fnegs */ | ||
| 751 | + gen_op_load_fpr_FT1(rs2); | ||
| 752 | + gen_op_fnegs(); | ||
| 753 | + gen_op_store_FT0_fpr(rd); | ||
| 754 | + break; | ||
| 755 | + case 0x9: /* fabss */ | ||
| 756 | + gen_op_load_fpr_FT1(rs2); | ||
| 757 | + gen_op_fabss(); | ||
| 758 | + gen_op_store_FT0_fpr(rd); | ||
| 759 | + break; | ||
| 760 | + case 0x29: /* fsqrts */ | ||
| 761 | + gen_op_load_fpr_FT1(rs2); | ||
| 762 | + gen_op_fsqrts(); | ||
| 763 | + gen_op_store_FT0_fpr(rd); | ||
| 764 | + break; | ||
| 765 | + case 0x2a: /* fsqrtd */ | ||
| 766 | + gen_op_load_fpr_DT1(rs2); | ||
| 767 | + gen_op_fsqrtd(); | ||
| 768 | + gen_op_store_DT0_fpr(rd); | ||
| 769 | + break; | ||
| 770 | + case 0x41: | ||
| 771 | + gen_op_load_fpr_FT0(rs1); | ||
| 772 | + gen_op_load_fpr_FT1(rs2); | ||
| 773 | + gen_op_fadds(); | ||
| 774 | + gen_op_store_FT0_fpr(rd); | ||
| 775 | + break; | ||
| 776 | + case 0x42: | ||
| 777 | + gen_op_load_fpr_DT0(rs1); | ||
| 778 | + gen_op_load_fpr_DT1(rs2); | ||
| 779 | + gen_op_faddd(); | ||
| 780 | + gen_op_store_DT0_fpr(rd); | ||
| 781 | + break; | ||
| 782 | + case 0x45: | ||
| 783 | + gen_op_load_fpr_FT0(rs1); | ||
| 784 | + gen_op_load_fpr_FT1(rs2); | ||
| 785 | + gen_op_fsubs(); | ||
| 786 | + gen_op_store_FT0_fpr(rd); | ||
| 787 | + break; | ||
| 788 | + case 0x46: | ||
| 789 | + gen_op_load_fpr_DT0(rs1); | ||
| 790 | + gen_op_load_fpr_DT1(rs2); | ||
| 791 | + gen_op_fsubd(); | ||
| 792 | + gen_op_store_DT0_fpr(rd); | ||
| 793 | + break; | ||
| 794 | + case 0x49: | ||
| 795 | + gen_op_load_fpr_FT0(rs1); | ||
| 796 | + gen_op_load_fpr_FT1(rs2); | ||
| 797 | + gen_op_fmuls(); | ||
| 798 | + gen_op_store_FT0_fpr(rd); | ||
| 799 | + break; | ||
| 800 | + case 0x4a: | ||
| 801 | + gen_op_load_fpr_DT0(rs1); | ||
| 802 | + gen_op_load_fpr_DT1(rs2); | ||
| 803 | + gen_op_fmuld(); | ||
| 804 | + gen_op_store_DT0_fpr(rd); | ||
| 805 | + break; | ||
| 806 | + case 0x4d: | ||
| 807 | + gen_op_load_fpr_FT0(rs1); | ||
| 808 | + gen_op_load_fpr_FT1(rs2); | ||
| 809 | + gen_op_fdivs(); | ||
| 810 | + gen_op_store_FT0_fpr(rd); | ||
| 811 | + break; | ||
| 812 | + case 0x4e: | ||
| 813 | + gen_op_load_fpr_DT0(rs1); | ||
| 814 | + gen_op_load_fpr_DT1(rs2); | ||
| 815 | + gen_op_fdivd(); | ||
| 816 | + gen_op_store_DT0_fpr(rd); | ||
| 817 | + break; | ||
| 818 | + case 0x51: | ||
| 819 | + gen_op_load_fpr_FT0(rs1); | ||
| 820 | + gen_op_load_fpr_FT1(rs2); | ||
| 821 | + gen_op_fcmps(); | ||
| 822 | + break; | ||
| 823 | + case 0x52: | ||
| 824 | + gen_op_load_fpr_DT0(rs1); | ||
| 825 | + gen_op_load_fpr_DT1(rs2); | ||
| 826 | + gen_op_fcmpd(); | ||
| 827 | + break; | ||
| 828 | + case 0x55: /* fcmpes */ | ||
| 829 | + gen_op_load_fpr_FT0(rs1); | ||
| 830 | + gen_op_load_fpr_FT1(rs2); | ||
| 831 | + gen_op_fcmps(); /* XXX */ | ||
| 832 | + break; | ||
| 833 | + case 0x56: /* fcmped */ | ||
| 834 | + gen_op_load_fpr_DT0(rs1); | ||
| 835 | + gen_op_load_fpr_DT1(rs2); | ||
| 836 | + gen_op_fcmpd(); /* XXX */ | ||
| 837 | + break; | ||
| 838 | + case 0x69: | ||
| 839 | + gen_op_load_fpr_FT0(rs1); | ||
| 840 | + gen_op_load_fpr_FT1(rs2); | ||
| 841 | + gen_op_fsmuld(); | ||
| 842 | + gen_op_store_DT0_fpr(rd); | ||
| 843 | + break; | ||
| 844 | + case 0xc4: | ||
| 845 | + gen_op_load_fpr_FT1(rs2); | ||
| 846 | + gen_op_fitos(); | ||
| 847 | + gen_op_store_FT0_fpr(rd); | ||
| 848 | + break; | ||
| 849 | + case 0xc6: | ||
| 850 | + gen_op_load_fpr_DT1(rs2); | ||
| 851 | + gen_op_fdtos(); | ||
| 852 | + gen_op_store_FT0_fpr(rd); | ||
| 853 | + break; | ||
| 854 | + case 0xc8: | ||
| 855 | + gen_op_load_fpr_FT1(rs2); | ||
| 856 | + gen_op_fitod(); | ||
| 857 | + gen_op_store_DT0_fpr(rd); | ||
| 858 | + break; | ||
| 859 | + case 0xc9: | ||
| 860 | + gen_op_load_fpr_FT1(rs2); | ||
| 861 | + gen_op_fstod(); | ||
| 862 | + gen_op_store_DT0_fpr(rd); | ||
| 863 | + break; | ||
| 864 | + case 0xd1: | ||
| 865 | + gen_op_load_fpr_FT1(rs2); | ||
| 866 | + gen_op_fstoi(); | ||
| 867 | + gen_op_store_FT0_fpr(rd); | ||
| 868 | + break; | ||
| 869 | + case 0xd2: | ||
| 870 | + gen_op_load_fpr_DT1(rs2); | ||
| 871 | + gen_op_fdtoi(); | ||
| 872 | + gen_op_store_FT0_fpr(rd); | ||
| 873 | + break; | ||
| 874 | + default: | ||
| 875 | + goto illegal_insn; | ||
| 876 | + } | ||
| 522 | } else { | 877 | } else { |
| 523 | rs1 = GET_FIELD(insn, 13, 17); | 878 | rs1 = GET_FIELD(insn, 13, 17); |
| 524 | gen_movl_reg_T0(rs1); | 879 | gen_movl_reg_T0(rs1); |
| @@ -637,6 +992,32 @@ static void disas_sparc_insn(DisasContext * dc) | @@ -637,6 +992,32 @@ static void disas_sparc_insn(DisasContext * dc) | ||
| 637 | } | 992 | } |
| 638 | } | 993 | } |
| 639 | break; | 994 | break; |
| 995 | +#if !defined(CONFIG_USER_ONLY) | ||
| 996 | + case 0x31: | ||
| 997 | + { | ||
| 998 | + if (!supervisor(dc)) | ||
| 999 | + goto priv_insn; | ||
| 1000 | + gen_op_xor_T1_T0(); | ||
| 1001 | + gen_op_wrpsr(); | ||
| 1002 | + } | ||
| 1003 | + break; | ||
| 1004 | + case 0x32: | ||
| 1005 | + { | ||
| 1006 | + if (!supervisor(dc)) | ||
| 1007 | + goto priv_insn; | ||
| 1008 | + gen_op_xor_T1_T0(); | ||
| 1009 | + gen_op_wrwim(); | ||
| 1010 | + } | ||
| 1011 | + break; | ||
| 1012 | + case 0x33: | ||
| 1013 | + { | ||
| 1014 | + if (!supervisor(dc)) | ||
| 1015 | + goto priv_insn; | ||
| 1016 | + gen_op_xor_T1_T0(); | ||
| 1017 | + gen_op_wrtbr(); | ||
| 1018 | + } | ||
| 1019 | + break; | ||
| 1020 | +#endif | ||
| 640 | case 0x38: /* jmpl */ | 1021 | case 0x38: /* jmpl */ |
| 641 | { | 1022 | { |
| 642 | gen_op_add_T1_T0(); | 1023 | gen_op_add_T1_T0(); |
| @@ -649,6 +1030,24 @@ static void disas_sparc_insn(DisasContext * dc) | @@ -649,6 +1030,24 @@ static void disas_sparc_insn(DisasContext * dc) | ||
| 649 | dc->npc = DYNAMIC_PC; | 1030 | dc->npc = DYNAMIC_PC; |
| 650 | } | 1031 | } |
| 651 | goto jmp_insn; | 1032 | goto jmp_insn; |
| 1033 | +#if !defined(CONFIG_USER_ONLY) | ||
| 1034 | + case 0x39: /* rett */ | ||
| 1035 | + { | ||
| 1036 | + if (!supervisor(dc)) | ||
| 1037 | + goto priv_insn; | ||
| 1038 | + gen_op_add_T1_T0(); | ||
| 1039 | + gen_op_movl_npc_T0(); | ||
| 1040 | + gen_op_rett(); | ||
| 1041 | +#if 0 | ||
| 1042 | + dc->pc = dc->npc; | ||
| 1043 | + dc->npc = DYNAMIC_PC; | ||
| 1044 | +#endif | ||
| 1045 | + } | ||
| 1046 | +#if 0 | ||
| 1047 | + goto jmp_insn; | ||
| 1048 | +#endif | ||
| 1049 | + break; | ||
| 1050 | +#endif | ||
| 652 | case 0x3b: /* flush */ | 1051 | case 0x3b: /* flush */ |
| 653 | gen_op_add_T1_T0(); | 1052 | gen_op_add_T1_T0(); |
| 654 | gen_op_flush_T0(); | 1053 | gen_op_flush_T0(); |
| @@ -679,60 +1078,157 @@ static void disas_sparc_insn(DisasContext * dc) | @@ -679,60 +1078,157 @@ static void disas_sparc_insn(DisasContext * dc) | ||
| 679 | gen_movl_reg_T0(rs1); | 1078 | gen_movl_reg_T0(rs1); |
| 680 | if (IS_IMM) { /* immediate */ | 1079 | if (IS_IMM) { /* immediate */ |
| 681 | rs2 = GET_FIELDs(insn, 19, 31); | 1080 | rs2 = GET_FIELDs(insn, 19, 31); |
| 682 | - gen_movl_imm_T1(rs2); | 1081 | + if (rs2 != 0) { |
| 1082 | + gen_movl_imm_T1(rs2); | ||
| 1083 | + gen_op_add_T1_T0(); | ||
| 1084 | + } | ||
| 683 | } else { /* register */ | 1085 | } else { /* register */ |
| 684 | rs2 = GET_FIELD(insn, 27, 31); | 1086 | rs2 = GET_FIELD(insn, 27, 31); |
| 685 | gen_movl_reg_T1(rs2); | 1087 | gen_movl_reg_T1(rs2); |
| 1088 | + gen_op_add_T1_T0(); | ||
| 686 | } | 1089 | } |
| 687 | - gen_op_add_T1_T0(); | ||
| 688 | - if (xop < 4 || xop > 7) { | 1090 | + if (xop < 4 || (xop > 7 && xop < 0x14) || \ |
| 1091 | + (xop > 0x17 && xop < 0x20)) { | ||
| 689 | switch (xop) { | 1092 | switch (xop) { |
| 690 | case 0x0: /* load word */ | 1093 | case 0x0: /* load word */ |
| 691 | - gen_op_ld(); | 1094 | + gen_op_ldst(ld); |
| 692 | break; | 1095 | break; |
| 693 | case 0x1: /* load unsigned byte */ | 1096 | case 0x1: /* load unsigned byte */ |
| 694 | - gen_op_ldub(); | 1097 | + gen_op_ldst(ldub); |
| 695 | break; | 1098 | break; |
| 696 | case 0x2: /* load unsigned halfword */ | 1099 | case 0x2: /* load unsigned halfword */ |
| 697 | - gen_op_lduh(); | 1100 | + gen_op_ldst(lduh); |
| 698 | break; | 1101 | break; |
| 699 | case 0x3: /* load double word */ | 1102 | case 0x3: /* load double word */ |
| 700 | - gen_op_ldd(); | 1103 | + gen_op_ldst(ldd); |
| 701 | gen_movl_T0_reg(rd + 1); | 1104 | gen_movl_T0_reg(rd + 1); |
| 702 | break; | 1105 | break; |
| 703 | case 0x9: /* load signed byte */ | 1106 | case 0x9: /* load signed byte */ |
| 704 | - gen_op_ldsb(); | 1107 | + gen_op_ldst(ldsb); |
| 705 | break; | 1108 | break; |
| 706 | case 0xa: /* load signed halfword */ | 1109 | case 0xa: /* load signed halfword */ |
| 707 | - gen_op_ldsh(); | 1110 | + gen_op_ldst(ldsh); |
| 708 | break; | 1111 | break; |
| 709 | case 0xd: /* ldstub -- XXX: should be atomically */ | 1112 | case 0xd: /* ldstub -- XXX: should be atomically */ |
| 710 | - gen_op_ldstub(); | 1113 | + gen_op_ldst(ldstub); |
| 711 | break; | 1114 | break; |
| 712 | case 0x0f: /* swap register with memory. Also atomically */ | 1115 | case 0x0f: /* swap register with memory. Also atomically */ |
| 713 | - gen_op_swap(); | 1116 | + gen_op_ldst(swap); |
| 1117 | + break; | ||
| 1118 | + case 0x10: /* load word alternate */ | ||
| 1119 | + if (!supervisor(dc)) | ||
| 1120 | + goto priv_insn; | ||
| 1121 | + gen_op_lda(insn, 1, 4, 0); | ||
| 1122 | + break; | ||
| 1123 | + case 0x11: /* load unsigned byte alternate */ | ||
| 1124 | + if (!supervisor(dc)) | ||
| 1125 | + goto priv_insn; | ||
| 1126 | + gen_op_lduba(insn, 1, 1, 0); | ||
| 1127 | + break; | ||
| 1128 | + case 0x12: /* load unsigned halfword alternate */ | ||
| 1129 | + if (!supervisor(dc)) | ||
| 1130 | + goto priv_insn; | ||
| 1131 | + gen_op_lduha(insn, 1, 2, 0); | ||
| 1132 | + break; | ||
| 1133 | + case 0x13: /* load double word alternate */ | ||
| 1134 | + if (!supervisor(dc)) | ||
| 1135 | + goto priv_insn; | ||
| 1136 | + gen_op_ldda(insn, 1, 8, 0); | ||
| 1137 | + gen_movl_T0_reg(rd + 1); | ||
| 1138 | + break; | ||
| 1139 | + case 0x19: /* load signed byte alternate */ | ||
| 1140 | + if (!supervisor(dc)) | ||
| 1141 | + goto priv_insn; | ||
| 1142 | + gen_op_ldsba(insn, 1, 1, 1); | ||
| 1143 | + break; | ||
| 1144 | + case 0x1a: /* load signed halfword alternate */ | ||
| 1145 | + if (!supervisor(dc)) | ||
| 1146 | + goto priv_insn; | ||
| 1147 | + gen_op_ldsha(insn, 1, 2 ,1); | ||
| 1148 | + break; | ||
| 1149 | + case 0x1d: /* ldstuba -- XXX: should be atomically */ | ||
| 1150 | + if (!supervisor(dc)) | ||
| 1151 | + goto priv_insn; | ||
| 1152 | + gen_op_ldstuba(insn, 1, 1, 0); | ||
| 1153 | + break; | ||
| 1154 | + case 0x1f: /* swap reg with alt. memory. Also atomically */ | ||
| 1155 | + if (!supervisor(dc)) | ||
| 1156 | + goto priv_insn; | ||
| 1157 | + gen_op_swapa(insn, 1, 4, 0); | ||
| 714 | break; | 1158 | break; |
| 715 | } | 1159 | } |
| 716 | gen_movl_T1_reg(rd); | 1160 | gen_movl_T1_reg(rd); |
| 717 | - } else if (xop < 8) { | 1161 | + } else if (xop >= 0x20 && xop < 0x24) { |
| 1162 | + switch (xop) { | ||
| 1163 | + case 0x20: /* load fpreg */ | ||
| 1164 | + gen_op_ldst(ldf); | ||
| 1165 | + gen_op_store_FT0_fpr(rd); | ||
| 1166 | + break; | ||
| 1167 | + case 0x21: /* load fsr */ | ||
| 1168 | + gen_op_ldfsr(); | ||
| 1169 | + break; | ||
| 1170 | + case 0x23: /* load double fpreg */ | ||
| 1171 | + gen_op_ldst(lddf); | ||
| 1172 | + gen_op_store_DT0_fpr(rd); | ||
| 1173 | + break; | ||
| 1174 | + } | ||
| 1175 | + } else if (xop < 8 || (xop >= 0x14 && xop < 0x18)) { | ||
| 718 | gen_movl_reg_T1(rd); | 1176 | gen_movl_reg_T1(rd); |
| 719 | switch (xop) { | 1177 | switch (xop) { |
| 720 | case 0x4: | 1178 | case 0x4: |
| 721 | - gen_op_st(); | 1179 | + gen_op_ldst(st); |
| 722 | break; | 1180 | break; |
| 723 | case 0x5: | 1181 | case 0x5: |
| 724 | - gen_op_stb(); | 1182 | + gen_op_ldst(stb); |
| 725 | break; | 1183 | break; |
| 726 | case 0x6: | 1184 | case 0x6: |
| 727 | - gen_op_sth(); | 1185 | + gen_op_ldst(sth); |
| 728 | break; | 1186 | break; |
| 729 | case 0x7: | 1187 | case 0x7: |
| 730 | flush_T2(dc); | 1188 | flush_T2(dc); |
| 731 | gen_movl_reg_T2(rd + 1); | 1189 | gen_movl_reg_T2(rd + 1); |
| 732 | - gen_op_std(); | 1190 | + gen_op_ldst(std); |
| 1191 | + break; | ||
| 1192 | + case 0x14: | ||
| 1193 | + if (!supervisor(dc)) | ||
| 1194 | + goto priv_insn; | ||
| 1195 | + gen_op_sta(insn, 0, 4, 0); | ||
| 1196 | + break; | ||
| 1197 | + case 0x15: | ||
| 1198 | + if (!supervisor(dc)) | ||
| 1199 | + goto priv_insn; | ||
| 1200 | + gen_op_stba(insn, 0, 1, 0); | ||
| 1201 | + break; | ||
| 1202 | + case 0x16: | ||
| 1203 | + if (!supervisor(dc)) | ||
| 1204 | + goto priv_insn; | ||
| 1205 | + gen_op_stha(insn, 0, 2, 0); | ||
| 1206 | + break; | ||
| 1207 | + case 0x17: | ||
| 1208 | + if (!supervisor(dc)) | ||
| 1209 | + goto priv_insn; | ||
| 1210 | + flush_T2(dc); | ||
| 1211 | + gen_movl_reg_T2(rd + 1); | ||
| 1212 | + gen_op_stda(insn, 0, 8, 0); | ||
| 733 | break; | 1213 | break; |
| 734 | } | 1214 | } |
| 735 | - } | 1215 | + } else if (xop > 0x23 && xop < 0x28) { |
| 1216 | + switch (xop) { | ||
| 1217 | + case 0x24: | ||
| 1218 | + gen_op_load_fpr_FT0(rd); | ||
| 1219 | + gen_op_ldst(stf); | ||
| 1220 | + break; | ||
| 1221 | + case 0x25: | ||
| 1222 | + gen_op_stfsr(); | ||
| 1223 | + break; | ||
| 1224 | + case 0x27: | ||
| 1225 | + gen_op_load_fpr_DT0(rd); | ||
| 1226 | + gen_op_ldst(stdf); | ||
| 1227 | + break; | ||
| 1228 | + } | ||
| 1229 | + } else if (xop > 0x33 && xop < 0x38) { | ||
| 1230 | + /* Co-processor */ | ||
| 1231 | + } | ||
| 736 | } | 1232 | } |
| 737 | } | 1233 | } |
| 738 | /* default case for non jump instructions */ | 1234 | /* default case for non jump instructions */ |
| @@ -753,30 +1249,59 @@ static void disas_sparc_insn(DisasContext * dc) | @@ -753,30 +1249,59 @@ static void disas_sparc_insn(DisasContext * dc) | ||
| 753 | save_state(dc); | 1249 | save_state(dc); |
| 754 | gen_op_exception(TT_ILL_INSN); | 1250 | gen_op_exception(TT_ILL_INSN); |
| 755 | dc->is_br = 1; | 1251 | dc->is_br = 1; |
| 1252 | + return; | ||
| 1253 | + priv_insn: | ||
| 1254 | + save_state(dc); | ||
| 1255 | + gen_op_exception(TT_PRIV_INSN); | ||
| 1256 | + dc->is_br = 1; | ||
| 756 | } | 1257 | } |
| 757 | 1258 | ||
| 758 | static inline int gen_intermediate_code_internal(TranslationBlock * tb, | 1259 | static inline int gen_intermediate_code_internal(TranslationBlock * tb, |
| 759 | - int spc) | 1260 | + int spc, CPUSPARCState *env) |
| 760 | { | 1261 | { |
| 761 | target_ulong pc_start, last_pc; | 1262 | target_ulong pc_start, last_pc; |
| 762 | uint16_t *gen_opc_end; | 1263 | uint16_t *gen_opc_end; |
| 763 | DisasContext dc1, *dc = &dc1; | 1264 | DisasContext dc1, *dc = &dc1; |
| 1265 | + int j, lj = -1; | ||
| 764 | 1266 | ||
| 765 | memset(dc, 0, sizeof(DisasContext)); | 1267 | memset(dc, 0, sizeof(DisasContext)); |
| 766 | - if (spc) { | ||
| 767 | - printf("SearchPC not yet supported\n"); | ||
| 768 | - exit(0); | ||
| 769 | - } | ||
| 770 | dc->tb = tb; | 1268 | dc->tb = tb; |
| 771 | pc_start = tb->pc; | 1269 | pc_start = tb->pc; |
| 772 | dc->pc = pc_start; | 1270 | dc->pc = pc_start; |
| 773 | dc->npc = (target_ulong) tb->cs_base; | 1271 | dc->npc = (target_ulong) tb->cs_base; |
| 774 | - | 1272 | +#if defined(CONFIG_USER_ONLY) |
| 1273 | + dc->mem_idx = 0; | ||
| 1274 | +#else | ||
| 1275 | + dc->mem_idx = ((env->psrs) != 0); | ||
| 1276 | +#endif | ||
| 775 | gen_opc_ptr = gen_opc_buf; | 1277 | gen_opc_ptr = gen_opc_buf; |
| 776 | gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; | 1278 | gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; |
| 777 | gen_opparam_ptr = gen_opparam_buf; | 1279 | gen_opparam_ptr = gen_opparam_buf; |
| 778 | 1280 | ||
| 1281 | + env->access_type = ACCESS_CODE; | ||
| 1282 | + | ||
| 779 | do { | 1283 | do { |
| 1284 | + if (env->nb_breakpoints > 0) { | ||
| 1285 | + for(j = 0; j < env->nb_breakpoints; j++) { | ||
| 1286 | + if (env->breakpoints[j] == dc->pc) { | ||
| 1287 | + gen_debug(dc, dc->pc); | ||
| 1288 | + break; | ||
| 1289 | + } | ||
| 1290 | + } | ||
| 1291 | + } | ||
| 1292 | + if (spc) { | ||
| 1293 | + if (loglevel > 0) | ||
| 1294 | + fprintf(logfile, "Search PC...\n"); | ||
| 1295 | + j = gen_opc_ptr - gen_opc_buf; | ||
| 1296 | + if (lj < j) { | ||
| 1297 | + lj++; | ||
| 1298 | + while (lj < j) | ||
| 1299 | + gen_opc_instr_start[lj++] = 0; | ||
| 1300 | + gen_opc_pc[lj] = dc->pc; | ||
| 1301 | + gen_opc_npc[lj] = dc->npc; | ||
| 1302 | + gen_opc_instr_start[lj] = 1; | ||
| 1303 | + } | ||
| 1304 | + } | ||
| 780 | last_pc = dc->pc; | 1305 | last_pc = dc->pc; |
| 781 | disas_sparc_insn(dc); | 1306 | disas_sparc_insn(dc); |
| 782 | if (dc->is_br) | 1307 | if (dc->is_br) |
| @@ -800,6 +1325,20 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, | @@ -800,6 +1325,20 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, | ||
| 800 | } | 1325 | } |
| 801 | } | 1326 | } |
| 802 | *gen_opc_ptr = INDEX_op_end; | 1327 | *gen_opc_ptr = INDEX_op_end; |
| 1328 | + if (spc) { | ||
| 1329 | + j = gen_opc_ptr - gen_opc_buf; | ||
| 1330 | + lj++; | ||
| 1331 | + while (lj <= j) | ||
| 1332 | + gen_opc_instr_start[lj++] = 0; | ||
| 1333 | + tb->size = 0; | ||
| 1334 | +#if 0 | ||
| 1335 | + if (loglevel > 0) { | ||
| 1336 | + page_dump(logfile); | ||
| 1337 | + } | ||
| 1338 | +#endif | ||
| 1339 | + } else { | ||
| 1340 | + tb->size = dc->npc - pc_start; | ||
| 1341 | + } | ||
| 803 | #ifdef DEBUG_DISAS | 1342 | #ifdef DEBUG_DISAS |
| 804 | if (loglevel & CPU_LOG_TB_IN_ASM) { | 1343 | if (loglevel & CPU_LOG_TB_IN_ASM) { |
| 805 | fprintf(logfile, "--------------\n"); | 1344 | fprintf(logfile, "--------------\n"); |
| @@ -814,17 +1353,18 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, | @@ -814,17 +1353,18 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, | ||
| 814 | } | 1353 | } |
| 815 | #endif | 1354 | #endif |
| 816 | 1355 | ||
| 1356 | + env->access_type = ACCESS_DATA; | ||
| 817 | return 0; | 1357 | return 0; |
| 818 | } | 1358 | } |
| 819 | 1359 | ||
| 820 | int gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb) | 1360 | int gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb) |
| 821 | { | 1361 | { |
| 822 | - return gen_intermediate_code_internal(tb, 0); | 1362 | + return gen_intermediate_code_internal(tb, 0, env); |
| 823 | } | 1363 | } |
| 824 | 1364 | ||
| 825 | int gen_intermediate_code_pc(CPUSPARCState * env, TranslationBlock * tb) | 1365 | int gen_intermediate_code_pc(CPUSPARCState * env, TranslationBlock * tb) |
| 826 | { | 1366 | { |
| 827 | - return gen_intermediate_code_internal(tb, 1); | 1367 | + return gen_intermediate_code_internal(tb, 1, env); |
| 828 | } | 1368 | } |
| 829 | 1369 | ||
| 830 | CPUSPARCState *cpu_sparc_init(void) | 1370 | CPUSPARCState *cpu_sparc_init(void) |
| @@ -839,7 +1379,17 @@ CPUSPARCState *cpu_sparc_init(void) | @@ -839,7 +1379,17 @@ CPUSPARCState *cpu_sparc_init(void) | ||
| 839 | env->cwp = 0; | 1379 | env->cwp = 0; |
| 840 | env->wim = 1; | 1380 | env->wim = 1; |
| 841 | env->regwptr = env->regbase + (env->cwp * 16); | 1381 | env->regwptr = env->regbase + (env->cwp * 16); |
| 1382 | + env->access_type = ACCESS_DATA; | ||
| 1383 | +#if defined(CONFIG_USER_ONLY) | ||
| 842 | env->user_mode_only = 1; | 1384 | env->user_mode_only = 1; |
| 1385 | +#else | ||
| 1386 | + /* Emulate Prom */ | ||
| 1387 | + env->psrs = 1; | ||
| 1388 | + env->pc = 0x4000; | ||
| 1389 | + env->npc = env->pc + 4; | ||
| 1390 | + env->mmuregs[0] = (0x10<<24) | MMU_E; /* Impl 1, ver 0, MMU Enabled */ | ||
| 1391 | + env->mmuregs[1] = 0x3000 >> 4; /* MMU Context table */ | ||
| 1392 | +#endif | ||
| 843 | cpu_single_env = env; | 1393 | cpu_single_env = env; |
| 844 | return (env); | 1394 | return (env); |
| 845 | } | 1395 | } |
| @@ -870,10 +1420,20 @@ void cpu_sparc_dump_state(CPUSPARCState * env, FILE * f, int flags) | @@ -870,10 +1420,20 @@ void cpu_sparc_dump_state(CPUSPARCState * env, FILE * f, int flags) | ||
| 870 | env->regwptr[i + x * 8]); | 1420 | env->regwptr[i + x * 8]); |
| 871 | fprintf(f, "\n"); | 1421 | fprintf(f, "\n"); |
| 872 | } | 1422 | } |
| 873 | - fprintf(f, "psr: 0x%08x -> %c%c%c%c wim: 0x%08x\n", env->psr | env->cwp, | 1423 | + fprintf(f, "\nFloating Point Registers:\n"); |
| 1424 | + for (i = 0; i < 32; i++) { | ||
| 1425 | + if ((i & 3) == 0) | ||
| 1426 | + fprintf(f, "%%f%02d:", i); | ||
| 1427 | + fprintf(f, " %016lf", env->fpr[i]); | ||
| 1428 | + if ((i & 3) == 3) | ||
| 1429 | + fprintf(f, "\n"); | ||
| 1430 | + } | ||
| 1431 | + fprintf(f, "psr: 0x%08x -> %c%c%c%c %c%c%c wim: 0x%08x\n", GET_PSR(env), | ||
| 874 | GET_FLAG(PSR_ZERO, 'Z'), GET_FLAG(PSR_OVF, 'V'), | 1432 | GET_FLAG(PSR_ZERO, 'Z'), GET_FLAG(PSR_OVF, 'V'), |
| 875 | GET_FLAG(PSR_NEG, 'N'), GET_FLAG(PSR_CARRY, 'C'), | 1433 | GET_FLAG(PSR_NEG, 'N'), GET_FLAG(PSR_CARRY, 'C'), |
| 876 | - env->wim); | 1434 | + env->psrs?'S':'-', env->psrps?'P':'-', |
| 1435 | + env->psret?'E':'-', env->wim); | ||
| 1436 | + fprintf(f, "fsr: 0x%08x\n", env->fsr); | ||
| 877 | } | 1437 | } |
| 878 | 1438 | ||
| 879 | target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) | 1439 | target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) |