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 | 9 | |
10 | 10 | /* trap definitions */ |
11 | 11 | #define TT_ILL_INSN 0x02 |
12 | +#define TT_PRIV_INSN 0x03 | |
12 | 13 | #define TT_WIN_OVF 0x05 |
13 | 14 | #define TT_WIN_UNF 0x06 |
15 | +#define TT_FP_EXCP 0x08 | |
14 | 16 | #define TT_DIV_ZERO 0x2a |
15 | 17 | #define TT_TRAP 0x80 |
16 | 18 | |
... | ... | @@ -18,27 +20,101 @@ |
18 | 20 | #define PSR_ZERO (1<<22) |
19 | 21 | #define PSR_OVF (1<<21) |
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 | 93 | #define NWINDOWS 32 |
23 | 94 | |
24 | 95 | typedef struct CPUSPARCState { |
25 | 96 | uint32_t gregs[8]; /* general registers */ |
26 | 97 | uint32_t *regwptr; /* pointer to current register window */ |
27 | - double *regfptr; /* floating point registers */ | |
98 | + float fpr[32]; /* floating point registers */ | |
28 | 99 | uint32_t pc; /* program counter */ |
29 | 100 | uint32_t npc; /* next program counter */ |
30 | - uint32_t sp; /* stack pointer */ | |
31 | 101 | uint32_t y; /* multiply/divide register */ |
32 | 102 | uint32_t psr; /* processor state register */ |
103 | + uint32_t fsr; /* FPU state register */ | |
33 | 104 | uint32_t T2; |
34 | 105 | uint32_t cwp; /* index of current register window (extracted |
35 | 106 | from PSR) */ |
36 | 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 | 112 | jmp_buf jmp_env; |
38 | 113 | int user_mode_only; |
39 | 114 | int exception_index; |
40 | 115 | int interrupt_index; |
41 | 116 | int interrupt_request; |
117 | + uint32_t exception_next_pc; | |
42 | 118 | struct TranslationBlock *current_tb; |
43 | 119 | void *opaque; |
44 | 120 | /* NOTE: we allow 8 more registers to handle wrapping */ |
... | ... | @@ -51,6 +127,22 @@ typedef struct CPUSPARCState { |
51 | 127 | written */ |
52 | 128 | unsigned long mem_write_vaddr; /* target virtual addr at which the |
53 | 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 | 146 | } CPUSPARCState; |
55 | 147 | |
56 | 148 | CPUSPARCState *cpu_sparc_init(void); |
... | ... | @@ -61,7 +153,7 @@ struct siginfo; |
61 | 153 | int cpu_sparc_signal_handler(int hostsignum, struct siginfo *info, void *puc); |
62 | 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 | 157 | #include "cpu-all.h" |
66 | 158 | |
67 | 159 | #endif | ... | ... |
target-sparc/exec.h
... | ... | @@ -6,6 +6,12 @@ register struct CPUSPARCState *env asm(AREG0); |
6 | 6 | register uint32_t T0 asm(AREG1); |
7 | 7 | register uint32_t T1 asm(AREG2); |
8 | 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 | 16 | #include "cpu.h" |
11 | 17 | #include "exec-all.h" |
... | ... | @@ -14,4 +20,88 @@ void cpu_lock(void); |
14 | 20 | void cpu_unlock(void); |
15 | 21 | void cpu_loop_exit(void); |
16 | 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 | 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 | 117 | #define REGNAME o7 |
118 | 118 | #define REG (env->regwptr[7]) |
119 | 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 | 218 | #define EIP (env->pc) |
121 | 219 | |
122 | 220 | #define FLAG_SET(x) (env->psr&x)?1:0 |
221 | +#define FFLAG_SET(x) ((env->fsr&x)?1:0) | |
123 | 222 | |
124 | 223 | void OPPROTO op_movl_T0_0(void) |
125 | 224 | { |
... | ... | @@ -375,6 +474,7 @@ void OPPROTO op_sra(void) |
375 | 474 | T0 = ((int32_t) T0) >> T1; |
376 | 475 | } |
377 | 476 | |
477 | +#if 0 | |
378 | 478 | void OPPROTO op_st(void) |
379 | 479 | { |
380 | 480 | stl((void *) T0, T1); |
... | ... | @@ -440,6 +540,51 @@ void OPPROTO op_ldd(void) |
440 | 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 | 588 | void OPPROTO op_wry(void) |
444 | 589 | { |
445 | 590 | env->y = T0; |
... | ... | @@ -450,36 +595,56 @@ void OPPROTO op_rdy(void) |
450 | 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 | 648 | /* XXX: use another pointer for %iN registers to avoid slow wrapping |
484 | 649 | handling ? */ |
485 | 650 | void OPPROTO op_save(void) |
... | ... | @@ -525,6 +690,12 @@ void OPPROTO op_trapcc_T0(void) |
525 | 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 | 699 | void OPPROTO op_exit_tb(void) |
529 | 700 | { |
530 | 701 | EXIT_TB(); |
... | ... | @@ -612,6 +783,92 @@ void OPPROTO op_eval_bvc(void) |
612 | 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 | 872 | void OPPROTO op_movl_T2_0(void) |
616 | 873 | { |
617 | 874 | T2 = 0; |
... | ... | @@ -687,3 +944,119 @@ void OPPROTO op_flush_T0(void) |
687 | 944 | { |
688 | 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 | 51 | target_ulong npc; /* next PC: integer or DYNAMIC_PC or JUMP_PC */ |
52 | 52 | target_ulong jump_pc[2]; /* used when JUMP_PC pc value is used */ |
53 | 53 | int is_br; |
54 | + int mem_idx; | |
54 | 55 | struct TranslationBlock *tb; |
55 | 56 | } DisasContext; |
56 | 57 | |
... | ... | @@ -257,6 +258,96 @@ static GenOpFunc1 *gen_op_movl_TN_im[3] = { |
257 | 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 | 351 | static inline void gen_movl_imm_TN(int reg, int imm) |
261 | 352 | { |
262 | 353 | gen_op_movl_TN_im[reg] (imm); |
... | ... | @@ -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 | 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 | 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 | 621 | #define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), (b) - (a) + 1) |
433 | 622 | |
434 | 623 | static int sign_extend(int x, int len) |
... | ... | @@ -454,6 +643,7 @@ static void disas_sparc_insn(DisasContext * dc) |
454 | 643 | switch (xop) { |
455 | 644 | case 0x0: |
456 | 645 | case 0x1: /* UNIMPL */ |
646 | + default: | |
457 | 647 | goto illegal_insn; |
458 | 648 | case 0x2: /* BN+x */ |
459 | 649 | { |
... | ... | @@ -462,8 +652,13 @@ static void disas_sparc_insn(DisasContext * dc) |
462 | 652 | do_branch(dc, target, insn); |
463 | 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 | 662 | case 0x4: /* SETHI */ |
468 | 663 | gen_movl_imm_T0(target << 10); |
469 | 664 | gen_movl_T0_reg(rd); |
... | ... | @@ -492,12 +687,16 @@ static void disas_sparc_insn(DisasContext * dc) |
492 | 687 | rs1 = GET_FIELD(insn, 13, 17); |
493 | 688 | gen_movl_reg_T0(rs1); |
494 | 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 | 695 | } else { |
497 | 696 | rs2 = GET_FIELD(insn, 27, 31); |
498 | 697 | gen_movl_reg_T1(rs2); |
698 | + gen_op_add_T1_T0(); | |
499 | 699 | } |
500 | - gen_op_add_T1_T0(); | |
501 | 700 | save_state(dc); |
502 | 701 | cond = GET_FIELD(insn, 3, 6); |
503 | 702 | if (cond == 0x8) { |
... | ... | @@ -514,11 +713,167 @@ static void disas_sparc_insn(DisasContext * dc) |
514 | 713 | gen_op_rdy(); |
515 | 714 | gen_movl_T0_reg(rd); |
516 | 715 | break; |
716 | + case 15: /* stbar */ | |
717 | + break; /* no effect? */ | |
517 | 718 | default: |
518 | 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 | 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 | 877 | } else { |
523 | 878 | rs1 = GET_FIELD(insn, 13, 17); |
524 | 879 | gen_movl_reg_T0(rs1); |
... | ... | @@ -637,6 +992,32 @@ static void disas_sparc_insn(DisasContext * dc) |
637 | 992 | } |
638 | 993 | } |
639 | 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 | 1021 | case 0x38: /* jmpl */ |
641 | 1022 | { |
642 | 1023 | gen_op_add_T1_T0(); |
... | ... | @@ -649,6 +1030,24 @@ static void disas_sparc_insn(DisasContext * dc) |
649 | 1030 | dc->npc = DYNAMIC_PC; |
650 | 1031 | } |
651 | 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 | 1051 | case 0x3b: /* flush */ |
653 | 1052 | gen_op_add_T1_T0(); |
654 | 1053 | gen_op_flush_T0(); |
... | ... | @@ -679,60 +1078,157 @@ static void disas_sparc_insn(DisasContext * dc) |
679 | 1078 | gen_movl_reg_T0(rs1); |
680 | 1079 | if (IS_IMM) { /* immediate */ |
681 | 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 | 1085 | } else { /* register */ |
684 | 1086 | rs2 = GET_FIELD(insn, 27, 31); |
685 | 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 | 1092 | switch (xop) { |
690 | 1093 | case 0x0: /* load word */ |
691 | - gen_op_ld(); | |
1094 | + gen_op_ldst(ld); | |
692 | 1095 | break; |
693 | 1096 | case 0x1: /* load unsigned byte */ |
694 | - gen_op_ldub(); | |
1097 | + gen_op_ldst(ldub); | |
695 | 1098 | break; |
696 | 1099 | case 0x2: /* load unsigned halfword */ |
697 | - gen_op_lduh(); | |
1100 | + gen_op_ldst(lduh); | |
698 | 1101 | break; |
699 | 1102 | case 0x3: /* load double word */ |
700 | - gen_op_ldd(); | |
1103 | + gen_op_ldst(ldd); | |
701 | 1104 | gen_movl_T0_reg(rd + 1); |
702 | 1105 | break; |
703 | 1106 | case 0x9: /* load signed byte */ |
704 | - gen_op_ldsb(); | |
1107 | + gen_op_ldst(ldsb); | |
705 | 1108 | break; |
706 | 1109 | case 0xa: /* load signed halfword */ |
707 | - gen_op_ldsh(); | |
1110 | + gen_op_ldst(ldsh); | |
708 | 1111 | break; |
709 | 1112 | case 0xd: /* ldstub -- XXX: should be atomically */ |
710 | - gen_op_ldstub(); | |
1113 | + gen_op_ldst(ldstub); | |
711 | 1114 | break; |
712 | 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 | 1158 | break; |
715 | 1159 | } |
716 | 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 | 1176 | gen_movl_reg_T1(rd); |
719 | 1177 | switch (xop) { |
720 | 1178 | case 0x4: |
721 | - gen_op_st(); | |
1179 | + gen_op_ldst(st); | |
722 | 1180 | break; |
723 | 1181 | case 0x5: |
724 | - gen_op_stb(); | |
1182 | + gen_op_ldst(stb); | |
725 | 1183 | break; |
726 | 1184 | case 0x6: |
727 | - gen_op_sth(); | |
1185 | + gen_op_ldst(sth); | |
728 | 1186 | break; |
729 | 1187 | case 0x7: |
730 | 1188 | flush_T2(dc); |
731 | 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 | 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 | 1234 | /* default case for non jump instructions */ |
... | ... | @@ -753,30 +1249,59 @@ static void disas_sparc_insn(DisasContext * dc) |
753 | 1249 | save_state(dc); |
754 | 1250 | gen_op_exception(TT_ILL_INSN); |
755 | 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 | 1259 | static inline int gen_intermediate_code_internal(TranslationBlock * tb, |
759 | - int spc) | |
1260 | + int spc, CPUSPARCState *env) | |
760 | 1261 | { |
761 | 1262 | target_ulong pc_start, last_pc; |
762 | 1263 | uint16_t *gen_opc_end; |
763 | 1264 | DisasContext dc1, *dc = &dc1; |
1265 | + int j, lj = -1; | |
764 | 1266 | |
765 | 1267 | memset(dc, 0, sizeof(DisasContext)); |
766 | - if (spc) { | |
767 | - printf("SearchPC not yet supported\n"); | |
768 | - exit(0); | |
769 | - } | |
770 | 1268 | dc->tb = tb; |
771 | 1269 | pc_start = tb->pc; |
772 | 1270 | dc->pc = pc_start; |
773 | 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 | 1277 | gen_opc_ptr = gen_opc_buf; |
776 | 1278 | gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; |
777 | 1279 | gen_opparam_ptr = gen_opparam_buf; |
778 | 1280 | |
1281 | + env->access_type = ACCESS_CODE; | |
1282 | + | |
779 | 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 | 1305 | last_pc = dc->pc; |
781 | 1306 | disas_sparc_insn(dc); |
782 | 1307 | if (dc->is_br) |
... | ... | @@ -800,6 +1325,20 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, |
800 | 1325 | } |
801 | 1326 | } |
802 | 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 | 1342 | #ifdef DEBUG_DISAS |
804 | 1343 | if (loglevel & CPU_LOG_TB_IN_ASM) { |
805 | 1344 | fprintf(logfile, "--------------\n"); |
... | ... | @@ -814,17 +1353,18 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, |
814 | 1353 | } |
815 | 1354 | #endif |
816 | 1355 | |
1356 | + env->access_type = ACCESS_DATA; | |
817 | 1357 | return 0; |
818 | 1358 | } |
819 | 1359 | |
820 | 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 | 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 | 1370 | CPUSPARCState *cpu_sparc_init(void) |
... | ... | @@ -839,7 +1379,17 @@ CPUSPARCState *cpu_sparc_init(void) |
839 | 1379 | env->cwp = 0; |
840 | 1380 | env->wim = 1; |
841 | 1381 | env->regwptr = env->regbase + (env->cwp * 16); |
1382 | + env->access_type = ACCESS_DATA; | |
1383 | +#if defined(CONFIG_USER_ONLY) | |
842 | 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 | 1393 | cpu_single_env = env; |
844 | 1394 | return (env); |
845 | 1395 | } |
... | ... | @@ -870,10 +1420,20 @@ void cpu_sparc_dump_state(CPUSPARCState * env, FILE * f, int flags) |
870 | 1420 | env->regwptr[i + x * 8]); |
871 | 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 | 1432 | GET_FLAG(PSR_ZERO, 'Z'), GET_FLAG(PSR_OVF, 'V'), |
875 | 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 | 1439 | target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) | ... | ... |