]>
Commit | Line | Data |
---|---|---|
b7bcbe95 FB |
1 | /* |
2 | * ARM helper routines | |
3 | * | |
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 | }\ | |
b7bcbe95 FB |
75 | env->vfp.fpscr = (flags << 28) | (env->vfp.fpscr & 0x0fffffff); \ |
76 | FORCE_RET(); \ | |
53cd6637 FB |
77 | }\ |
78 | \ | |
b7bcbe95 FB |
79 | void do_vfp_cmpe##p(void) \ |
80 | { \ | |
53cd6637 FB |
81 | uint32_t flags; \ |
82 | switch(float ## size ## _compare(FT0##p, FT1##p, &env->vfp.fp_status)) {\ | |
89344d5a | 83 | case 0: flags = 0x6; break;\ |
53cd6637 FB |
84 | case -1: flags = 0x8; break;\ |
85 | case 1: flags = 0x2; break;\ | |
86 | default: case 2: flags = 0x3; break;\ | |
87 | }\ | |
b7bcbe95 | 88 | env->vfp.fpscr = (flags << 28) | (env->vfp.fpscr & 0x0fffffff); \ |
53cd6637 | 89 | FORCE_RET(); \ |
b7bcbe95 | 90 | } |
53cd6637 FB |
91 | DO_VFP_cmp(s, 32) |
92 | DO_VFP_cmp(d, 64) | |
93 | #undef DO_VFP_cmp | |
b7bcbe95 FB |
94 | |
95 | /* Convert host exception flags to vfp form. */ | |
53cd6637 | 96 | static inline int vfp_exceptbits_from_host(int host_bits) |
b7bcbe95 FB |
97 | { |
98 | int target_bits = 0; | |
99 | ||
53cd6637 | 100 | if (host_bits & float_flag_invalid) |
b7bcbe95 | 101 | target_bits |= 1; |
53cd6637 | 102 | if (host_bits & float_flag_divbyzero) |
b7bcbe95 | 103 | target_bits |= 2; |
53cd6637 | 104 | if (host_bits & float_flag_overflow) |
b7bcbe95 | 105 | target_bits |= 4; |
53cd6637 | 106 | if (host_bits & float_flag_underflow) |
b7bcbe95 | 107 | target_bits |= 8; |
53cd6637 | 108 | if (host_bits & float_flag_inexact) |
b7bcbe95 | 109 | target_bits |= 0x10; |
b7bcbe95 FB |
110 | return target_bits; |
111 | } | |
112 | ||
113 | /* Convert vfp exception flags to target form. */ | |
53cd6637 | 114 | static inline int vfp_exceptbits_to_host(int target_bits) |
b7bcbe95 FB |
115 | { |
116 | int host_bits = 0; | |
117 | ||
b7bcbe95 | 118 | if (target_bits & 1) |
53cd6637 | 119 | host_bits |= float_flag_invalid; |
b7bcbe95 | 120 | if (target_bits & 2) |
53cd6637 | 121 | host_bits |= float_flag_divbyzero; |
b7bcbe95 | 122 | if (target_bits & 4) |
53cd6637 | 123 | host_bits |= float_flag_overflow; |
b7bcbe95 | 124 | if (target_bits & 8) |
53cd6637 | 125 | host_bits |= float_flag_underflow; |
b7bcbe95 | 126 | if (target_bits & 0x10) |
53cd6637 | 127 | host_bits |= float_flag_inexact; |
b7bcbe95 FB |
128 | return host_bits; |
129 | } | |
130 | ||
131 | void do_vfp_set_fpscr(void) | |
132 | { | |
133 | int i; | |
134 | uint32_t changed; | |
135 | ||
136 | changed = env->vfp.fpscr; | |
137 | env->vfp.fpscr = (T0 & 0xffc8ffff); | |
138 | env->vfp.vec_len = (T0 >> 16) & 7; | |
139 | env->vfp.vec_stride = (T0 >> 20) & 3; | |
140 | ||
141 | changed ^= T0; | |
142 | if (changed & (3 << 22)) { | |
143 | i = (T0 >> 22) & 3; | |
144 | switch (i) { | |
145 | case 0: | |
53cd6637 | 146 | i = float_round_nearest_even; |
b7bcbe95 FB |
147 | break; |
148 | case 1: | |
53cd6637 | 149 | i = float_round_up; |
b7bcbe95 FB |
150 | break; |
151 | case 2: | |
53cd6637 | 152 | i = float_round_down; |
b7bcbe95 FB |
153 | break; |
154 | case 3: | |
53cd6637 | 155 | i = float_round_to_zero; |
b7bcbe95 FB |
156 | break; |
157 | } | |
53cd6637 | 158 | set_float_rounding_mode(i, &env->vfp.fp_status); |
b7bcbe95 FB |
159 | } |
160 | ||
53cd6637 FB |
161 | i = vfp_exceptbits_to_host((T0 >> 8) & 0x1f); |
162 | set_float_exception_flags(i, &env->vfp.fp_status); | |
b7bcbe95 FB |
163 | /* XXX: FZ and DN are not implemented. */ |
164 | } | |
165 | ||
166 | void do_vfp_get_fpscr(void) | |
167 | { | |
168 | int i; | |
169 | ||
170 | T0 = (env->vfp.fpscr & 0xffc8ffff) | (env->vfp.vec_len << 16) | |
171 | | (env->vfp.vec_stride << 20); | |
53cd6637 | 172 | i = get_float_exception_flags(&env->vfp.fp_status); |
b7bcbe95 FB |
173 | T0 |= vfp_exceptbits_from_host(i); |
174 | } | |
b5ff1b31 FB |
175 | |
176 | #if !defined(CONFIG_USER_ONLY) | |
177 | ||
178 | #define MMUSUFFIX _mmu | |
179 | #define GETPC() (__builtin_return_address(0)) | |
180 | ||
181 | #define SHIFT 0 | |
182 | #include "softmmu_template.h" | |
183 | ||
184 | #define SHIFT 1 | |
185 | #include "softmmu_template.h" | |
186 | ||
187 | #define SHIFT 2 | |
188 | #include "softmmu_template.h" | |
189 | ||
190 | #define SHIFT 3 | |
191 | #include "softmmu_template.h" | |
192 | ||
193 | /* try to fill the TLB and return an exception if error. If retaddr is | |
194 | NULL, it means that the function was called in C code (i.e. not | |
195 | from generated code or from helper.c) */ | |
196 | /* XXX: fix it to restore all registers */ | |
197 | void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) | |
198 | { | |
199 | TranslationBlock *tb; | |
200 | CPUState *saved_env; | |
201 | target_phys_addr_t pc; | |
202 | int ret; | |
203 | ||
204 | /* XXX: hack to restore env in all cases, even if not called from | |
205 | generated code */ | |
206 | saved_env = env; | |
207 | env = cpu_single_env; | |
208 | ret = cpu_arm_handle_mmu_fault(env, addr, is_write, is_user, 1); | |
209 | if (__builtin_expect(ret, 0)) { | |
210 | if (retaddr) { | |
211 | /* now we have a real cpu fault */ | |
212 | pc = (target_phys_addr_t)retaddr; | |
213 | tb = tb_find_pc(pc); | |
214 | if (tb) { | |
215 | /* the PC is inside the translated code. It means that we have | |
216 | a virtual CPU fault */ | |
217 | cpu_restore_state(tb, env, pc, NULL); | |
218 | } | |
219 | } | |
220 | raise_exception(env->exception_index); | |
221 | } | |
222 | env = saved_env; | |
223 | } | |
224 | ||
225 | #endif |