]>
Commit | Line | Data |
---|---|---|
b7bcbe95 FB |
1 | /* |
2 | * ARM helper routines | |
5fafdf24 | 3 | * |
b7bcbe95 FB |
4 | * Copyright (c) 2005 CodeSourcery, LLC |
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 | */ | |
b7bcbe95 FB |
20 | #include "exec.h" |
21 | ||
b7bcbe95 FB |
22 | void raise_exception(int tt) |
23 | { | |
24 | env->exception_index = tt; | |
25 | cpu_loop_exit(); | |
26 | } | |
27 | ||
28 | /* thread support */ | |
29 | ||
30 | spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; | |
31 | ||
32 | void cpu_lock(void) | |
33 | { | |
34 | spin_lock(&global_cpu_lock); | |
35 | } | |
36 | ||
37 | void cpu_unlock(void) | |
38 | { | |
39 | spin_unlock(&global_cpu_lock); | |
40 | } | |
41 | ||
42 | /* VFP support. */ | |
43 | ||
44 | void do_vfp_abss(void) | |
45 | { | |
53cd6637 | 46 | FT0s = float32_abs(FT0s); |
b7bcbe95 FB |
47 | } |
48 | ||
49 | void do_vfp_absd(void) | |
50 | { | |
53cd6637 | 51 | FT0d = float64_abs(FT0d); |
b7bcbe95 FB |
52 | } |
53 | ||
54 | void do_vfp_sqrts(void) | |
55 | { | |
53cd6637 | 56 | FT0s = float32_sqrt(FT0s, &env->vfp.fp_status); |
b7bcbe95 FB |
57 | } |
58 | ||
59 | void do_vfp_sqrtd(void) | |
60 | { | |
53cd6637 | 61 | FT0d = float64_sqrt(FT0d, &env->vfp.fp_status); |
b7bcbe95 FB |
62 | } |
63 | ||
53cd6637 FB |
64 | /* XXX: check quiet/signaling case */ |
65 | #define DO_VFP_cmp(p, size) \ | |
b7bcbe95 FB |
66 | void do_vfp_cmp##p(void) \ |
67 | { \ | |
68 | uint32_t flags; \ | |
53cd6637 | 69 | switch(float ## size ## _compare_quiet(FT0##p, FT1##p, &env->vfp.fp_status)) {\ |
89344d5a | 70 | case 0: flags = 0x6; break;\ |
53cd6637 FB |
71 | case -1: flags = 0x8; break;\ |
72 | case 1: flags = 0x2; break;\ | |
73 | default: case 2: flags = 0x3; break;\ | |
74 | }\ | |
40f137e1 PB |
75 | env->vfp.xregs[ARM_VFP_FPSCR] = (flags << 28)\ |
76 | | (env->vfp.xregs[ARM_VFP_FPSCR] & 0x0fffffff); \ | |
b7bcbe95 | 77 | FORCE_RET(); \ |
53cd6637 FB |
78 | }\ |
79 | \ | |
b7bcbe95 FB |
80 | void do_vfp_cmpe##p(void) \ |
81 | { \ | |
53cd6637 FB |
82 | uint32_t flags; \ |
83 | switch(float ## size ## _compare(FT0##p, FT1##p, &env->vfp.fp_status)) {\ | |
89344d5a | 84 | case 0: flags = 0x6; break;\ |
53cd6637 FB |
85 | case -1: flags = 0x8; break;\ |
86 | case 1: flags = 0x2; break;\ | |
87 | default: case 2: flags = 0x3; break;\ | |
88 | }\ | |
40f137e1 PB |
89 | env->vfp.xregs[ARM_VFP_FPSCR] = (flags << 28)\ |
90 | | (env->vfp.xregs[ARM_VFP_FPSCR] & 0x0fffffff); \ | |
53cd6637 | 91 | FORCE_RET(); \ |
b7bcbe95 | 92 | } |
53cd6637 FB |
93 | DO_VFP_cmp(s, 32) |
94 | DO_VFP_cmp(d, 64) | |
95 | #undef DO_VFP_cmp | |
b7bcbe95 FB |
96 | |
97 | /* Convert host exception flags to vfp form. */ | |
53cd6637 | 98 | static inline int vfp_exceptbits_from_host(int host_bits) |
b7bcbe95 FB |
99 | { |
100 | int target_bits = 0; | |
101 | ||
53cd6637 | 102 | if (host_bits & float_flag_invalid) |
b7bcbe95 | 103 | target_bits |= 1; |
53cd6637 | 104 | if (host_bits & float_flag_divbyzero) |
b7bcbe95 | 105 | target_bits |= 2; |
53cd6637 | 106 | if (host_bits & float_flag_overflow) |
b7bcbe95 | 107 | target_bits |= 4; |
53cd6637 | 108 | if (host_bits & float_flag_underflow) |
b7bcbe95 | 109 | target_bits |= 8; |
53cd6637 | 110 | if (host_bits & float_flag_inexact) |
b7bcbe95 | 111 | target_bits |= 0x10; |
b7bcbe95 FB |
112 | return target_bits; |
113 | } | |
114 | ||
115 | /* Convert vfp exception flags to target form. */ | |
53cd6637 | 116 | static inline int vfp_exceptbits_to_host(int target_bits) |
b7bcbe95 FB |
117 | { |
118 | int host_bits = 0; | |
119 | ||
b7bcbe95 | 120 | if (target_bits & 1) |
53cd6637 | 121 | host_bits |= float_flag_invalid; |
b7bcbe95 | 122 | if (target_bits & 2) |
53cd6637 | 123 | host_bits |= float_flag_divbyzero; |
b7bcbe95 | 124 | if (target_bits & 4) |
53cd6637 | 125 | host_bits |= float_flag_overflow; |
b7bcbe95 | 126 | if (target_bits & 8) |
53cd6637 | 127 | host_bits |= float_flag_underflow; |
b7bcbe95 | 128 | if (target_bits & 0x10) |
53cd6637 | 129 | host_bits |= float_flag_inexact; |
b7bcbe95 FB |
130 | return host_bits; |
131 | } | |
132 | ||
133 | void do_vfp_set_fpscr(void) | |
134 | { | |
135 | int i; | |
136 | uint32_t changed; | |
137 | ||
40f137e1 PB |
138 | changed = env->vfp.xregs[ARM_VFP_FPSCR]; |
139 | env->vfp.xregs[ARM_VFP_FPSCR] = (T0 & 0xffc8ffff); | |
b7bcbe95 FB |
140 | env->vfp.vec_len = (T0 >> 16) & 7; |
141 | env->vfp.vec_stride = (T0 >> 20) & 3; | |
142 | ||
143 | changed ^= T0; | |
144 | if (changed & (3 << 22)) { | |
145 | i = (T0 >> 22) & 3; | |
146 | switch (i) { | |
147 | case 0: | |
53cd6637 | 148 | i = float_round_nearest_even; |
b7bcbe95 FB |
149 | break; |
150 | case 1: | |
53cd6637 | 151 | i = float_round_up; |
b7bcbe95 FB |
152 | break; |
153 | case 2: | |
53cd6637 | 154 | i = float_round_down; |
b7bcbe95 FB |
155 | break; |
156 | case 3: | |
53cd6637 | 157 | i = float_round_to_zero; |
b7bcbe95 FB |
158 | break; |
159 | } | |
53cd6637 | 160 | set_float_rounding_mode(i, &env->vfp.fp_status); |
b7bcbe95 FB |
161 | } |
162 | ||
53cd6637 FB |
163 | i = vfp_exceptbits_to_host((T0 >> 8) & 0x1f); |
164 | set_float_exception_flags(i, &env->vfp.fp_status); | |
b7bcbe95 FB |
165 | /* XXX: FZ and DN are not implemented. */ |
166 | } | |
167 | ||
168 | void do_vfp_get_fpscr(void) | |
169 | { | |
170 | int i; | |
171 | ||
40f137e1 | 172 | T0 = (env->vfp.xregs[ARM_VFP_FPSCR] & 0xffc8ffff) | (env->vfp.vec_len << 16) |
b7bcbe95 | 173 | | (env->vfp.vec_stride << 20); |
53cd6637 | 174 | i = get_float_exception_flags(&env->vfp.fp_status); |
b7bcbe95 FB |
175 | T0 |= vfp_exceptbits_from_host(i); |
176 | } | |
b5ff1b31 FB |
177 | |
178 | #if !defined(CONFIG_USER_ONLY) | |
179 | ||
180 | #define MMUSUFFIX _mmu | |
181 | #define GETPC() (__builtin_return_address(0)) | |
182 | ||
183 | #define SHIFT 0 | |
184 | #include "softmmu_template.h" | |
185 | ||
186 | #define SHIFT 1 | |
187 | #include "softmmu_template.h" | |
188 | ||
189 | #define SHIFT 2 | |
190 | #include "softmmu_template.h" | |
191 | ||
192 | #define SHIFT 3 | |
193 | #include "softmmu_template.h" | |
194 | ||
195 | /* try to fill the TLB and return an exception if error. If retaddr is | |
196 | NULL, it means that the function was called in C code (i.e. not | |
197 | from generated code or from helper.c) */ | |
198 | /* XXX: fix it to restore all registers */ | |
6ebbf390 | 199 | void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) |
b5ff1b31 FB |
200 | { |
201 | TranslationBlock *tb; | |
202 | CPUState *saved_env; | |
203 | target_phys_addr_t pc; | |
204 | int ret; | |
205 | ||
206 | /* XXX: hack to restore env in all cases, even if not called from | |
207 | generated code */ | |
208 | saved_env = env; | |
209 | env = cpu_single_env; | |
6ebbf390 | 210 | ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); |
b5ff1b31 FB |
211 | if (__builtin_expect(ret, 0)) { |
212 | if (retaddr) { | |
213 | /* now we have a real cpu fault */ | |
214 | pc = (target_phys_addr_t)retaddr; | |
215 | tb = tb_find_pc(pc); | |
216 | if (tb) { | |
217 | /* the PC is inside the translated code. It means that we have | |
218 | a virtual CPU fault */ | |
219 | cpu_restore_state(tb, env, pc, NULL); | |
220 | } | |
221 | } | |
222 | raise_exception(env->exception_index); | |
223 | } | |
224 | env = saved_env; | |
225 | } | |
226 | ||
227 | #endif |