root / targetarm / op_helper.c @ 551bd27f
History  View  Annotate  Download (12.4 kB)
1 
/*


2 
* ARM helper routines

3 
*

4 
* Copyright (c) 20052007 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 021111307 USA

19 
*/

20 
#include "exec.h" 
21 
#include "helpers.h" 
22  
23 
#define SIGNBIT (uint32_t)0x80000000 
24 
#define SIGNBIT64 ((uint64_t)1 << 63) 
25  
26 
void raise_exception(int tt) 
27 
{ 
28 
env>exception_index = tt; 
29 
cpu_loop_exit(); 
30 
} 
31  
32 
/* thread support */

33  
34 
spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; 
35  
36 
void cpu_lock(void) 
37 
{ 
38 
spin_lock(&global_cpu_lock); 
39 
} 
40  
41 
void cpu_unlock(void) 
42 
{ 
43 
spin_unlock(&global_cpu_lock); 
44 
} 
45  
46 
uint32_t HELPER(neon_tbl)(uint32_t ireg, uint32_t def, 
47 
uint32_t rn, uint32_t maxindex) 
48 
{ 
49 
uint32_t val; 
50 
uint32_t tmp; 
51 
int index;

52 
int shift;

53 
uint64_t *table; 
54 
table = (uint64_t *)&env>vfp.regs[rn]; 
55 
val = 0;

56 
for (shift = 0; shift < 32; shift += 8) { 
57 
index = (ireg >> shift) & 0xff;

58 
if (index < maxindex) {

59 
tmp = (table[index >> 3] >> (index & 7)) & 0xff; 
60 
val = tmp << shift; 
61 
} else {

62 
val = def & (0xff << shift);

63 
} 
64 
} 
65 
return val;

66 
} 
67  
68 
#if !defined(CONFIG_USER_ONLY)

69  
70 
#define MMUSUFFIX _mmu

71  
72 
#define SHIFT 0 
73 
#include "softmmu_template.h" 
74  
75 
#define SHIFT 1 
76 
#include "softmmu_template.h" 
77  
78 
#define SHIFT 2 
79 
#include "softmmu_template.h" 
80  
81 
#define SHIFT 3 
82 
#include "softmmu_template.h" 
83  
84 
/* try to fill the TLB and return an exception if error. If retaddr is

85 
NULL, it means that the function was called in C code (i.e. not

86 
from generated code or from helper.c) */

87 
/* XXX: fix it to restore all registers */

88 
void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) 
89 
{ 
90 
TranslationBlock *tb; 
91 
CPUState *saved_env; 
92 
unsigned long pc; 
93 
int ret;

94  
95 
/* XXX: hack to restore env in all cases, even if not called from

96 
generated code */

97 
saved_env = env; 
98 
env = cpu_single_env; 
99 
ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);

100 
if (unlikely(ret)) {

101 
if (retaddr) {

102 
/* now we have a real cpu fault */

103 
pc = (unsigned long)retaddr; 
104 
tb = tb_find_pc(pc); 
105 
if (tb) {

106 
/* the PC is inside the translated code. It means that we have

107 
a virtual CPU fault */

108 
cpu_restore_state(tb, env, pc, NULL);

109 
} 
110 
} 
111 
raise_exception(env>exception_index); 
112 
} 
113 
env = saved_env; 
114 
} 
115 
#endif

116  
117 
/* FIXME: Pass an axplicit pointer to QF to CPUState, and move saturating

118 
instructions into helper.c */

119 
uint32_t HELPER(add_setq)(uint32_t a, uint32_t b) 
120 
{ 
121 
uint32_t res = a + b; 
122 
if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT))

123 
env>QF = 1;

124 
return res;

125 
} 
126  
127 
uint32_t HELPER(add_saturate)(uint32_t a, uint32_t b) 
128 
{ 
129 
uint32_t res = a + b; 
130 
if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) {

131 
env>QF = 1;

132 
res = ~(((int32_t)a >> 31) ^ SIGNBIT);

133 
} 
134 
return res;

135 
} 
136  
137 
uint32_t HELPER(sub_saturate)(uint32_t a, uint32_t b) 
138 
{ 
139 
uint32_t res = a  b; 
140 
if (((res ^ a) & SIGNBIT) && ((a ^ b) & SIGNBIT)) {

141 
env>QF = 1;

142 
res = ~(((int32_t)a >> 31) ^ SIGNBIT);

143 
} 
144 
return res;

145 
} 
146  
147 
uint32_t HELPER(double_saturate)(int32_t val) 
148 
{ 
149 
uint32_t res; 
150 
if (val >= 0x40000000) { 
151 
res = ~SIGNBIT; 
152 
env>QF = 1;

153 
} else if (val <= (int32_t)0xc0000000) { 
154 
res = SIGNBIT; 
155 
env>QF = 1;

156 
} else {

157 
res = val << 1;

158 
} 
159 
return res;

160 
} 
161  
162 
uint32_t HELPER(add_usaturate)(uint32_t a, uint32_t b) 
163 
{ 
164 
uint32_t res = a + b; 
165 
if (res < a) {

166 
env>QF = 1;

167 
res = ~0;

168 
} 
169 
return res;

170 
} 
171  
172 
uint32_t HELPER(sub_usaturate)(uint32_t a, uint32_t b) 
173 
{ 
174 
uint32_t res = a  b; 
175 
if (res > a) {

176 
env>QF = 1;

177 
res = 0;

178 
} 
179 
return res;

180 
} 
181  
182 
/* Signed saturation. */

183 
static inline uint32_t do_ssat(int32_t val, int shift) 
184 
{ 
185 
int32_t top; 
186 
uint32_t mask; 
187  
188 
shift = PARAM1; 
189 
top = val >> shift; 
190 
mask = (1u << shift)  1; 
191 
if (top > 0) { 
192 
env>QF = 1;

193 
return mask;

194 
} else if (top < 1) { 
195 
env>QF = 1;

196 
return ~mask;

197 
} 
198 
return val;

199 
} 
200  
201 
/* Unsigned saturation. */

202 
static inline uint32_t do_usat(int32_t val, int shift) 
203 
{ 
204 
uint32_t max; 
205  
206 
shift = PARAM1; 
207 
max = (1u << shift)  1; 
208 
if (val < 0) { 
209 
env>QF = 1;

210 
return 0; 
211 
} else if (val > max) { 
212 
env>QF = 1;

213 
return max;

214 
} 
215 
return val;

216 
} 
217  
218 
/* Signed saturate. */

219 
uint32_t HELPER(ssat)(uint32_t x, uint32_t shift) 
220 
{ 
221 
return do_ssat(x, shift);

222 
} 
223  
224 
/* Dual halfword signed saturate. */

225 
uint32_t HELPER(ssat16)(uint32_t x, uint32_t shift) 
226 
{ 
227 
uint32_t res; 
228  
229 
res = (uint16_t)do_ssat((int16_t)x, shift); 
230 
res = do_ssat(((int32_t)x) >> 16, shift) << 16; 
231 
return res;

232 
} 
233  
234 
/* Unsigned saturate. */

235 
uint32_t HELPER(usat)(uint32_t x, uint32_t shift) 
236 
{ 
237 
return do_usat(x, shift);

238 
} 
239  
240 
/* Dual halfword unsigned saturate. */

241 
uint32_t HELPER(usat16)(uint32_t x, uint32_t shift) 
242 
{ 
243 
uint32_t res; 
244  
245 
res = (uint16_t)do_usat((int16_t)x, shift); 
246 
res = do_usat(((int32_t)x) >> 16, shift) << 16; 
247 
return res;

248 
} 
249  
250 
void HELPER(wfi)(void) 
251 
{ 
252 
env>exception_index = EXCP_HLT; 
253 
env>halted = 1;

254 
cpu_loop_exit(); 
255 
} 
256  
257 
void HELPER(exception)(uint32_t excp)

258 
{ 
259 
env>exception_index = excp; 
260 
cpu_loop_exit(); 
261 
} 
262  
263 
uint32_t HELPER(cpsr_read)(void)

264 
{ 
265 
return cpsr_read(env) & ~CPSR_EXEC;

266 
} 
267  
268 
void HELPER(cpsr_write)(uint32_t val, uint32_t mask)

269 
{ 
270 
cpsr_write(env, val, mask); 
271 
} 
272  
273 
/* Access to user mode registers from privileged modes. */

274 
uint32_t HELPER(get_user_reg)(uint32_t regno) 
275 
{ 
276 
uint32_t val; 
277  
278 
if (regno == 13) { 
279 
val = env>banked_r13[0];

280 
} else if (regno == 14) { 
281 
val = env>banked_r14[0];

282 
} else if (regno >= 8 
283 
&& (env>uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {

284 
val = env>usr_regs[regno  8];

285 
} else {

286 
val = env>regs[regno]; 
287 
} 
288 
return val;

289 
} 
290  
291 
void HELPER(set_user_reg)(uint32_t regno, uint32_t val)

292 
{ 
293 
if (regno == 13) { 
294 
env>banked_r13[0] = val;

295 
} else if (regno == 14) { 
296 
env>banked_r14[0] = val;

297 
} else if (regno >= 8 
298 
&& (env>uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {

299 
env>usr_regs[regno  8] = val;

300 
} else {

301 
env>regs[regno] = val; 
302 
} 
303 
} 
304  
305 
/* ??? Flag setting arithmetic is awkward because we need to do comparisons.

306 
The only way to do that in TCG is a conditional branch, which clobbers

307 
all our temporaries. For now implement these as helper functions. */

308  
309 
uint32_t HELPER (add_cc)(uint32_t a, uint32_t b) 
310 
{ 
311 
uint32_t result; 
312 
result = T0 + T1; 
313 
env>NF = env>ZF = result; 
314 
env>CF = result < a; 
315 
env>VF = (a ^ b ^ 1) & (a ^ result);

316 
return result;

317 
} 
318  
319 
uint32_t HELPER(adc_cc)(uint32_t a, uint32_t b) 
320 
{ 
321 
uint32_t result; 
322 
if (!env>CF) {

323 
result = a + b; 
324 
env>CF = result < a; 
325 
} else {

326 
result = a + b + 1;

327 
env>CF = result <= a; 
328 
} 
329 
env>VF = (a ^ b ^ 1) & (a ^ result);

330 
env>NF = env>ZF = result; 
331 
return result;

332 
} 
333  
334 
uint32_t HELPER(sub_cc)(uint32_t a, uint32_t b) 
335 
{ 
336 
uint32_t result; 
337 
result = a  b; 
338 
env>NF = env>ZF = result; 
339 
env>CF = a >= b; 
340 
env>VF = (a ^ b) & (a ^ result); 
341 
return result;

342 
} 
343  
344 
uint32_t HELPER(sbc_cc)(uint32_t a, uint32_t b) 
345 
{ 
346 
uint32_t result; 
347 
if (!env>CF) {

348 
result = a  b  1;

349 
env>CF = a > b; 
350 
} else {

351 
result = a  b; 
352 
env>CF = a >= b; 
353 
} 
354 
env>VF = (a ^ b) & (a ^ result); 
355 
env>NF = env>ZF = result; 
356 
return result;

357 
} 
358  
359 
/* Similarly for variable shift instructions. */

360  
361 
uint32_t HELPER(shl)(uint32_t x, uint32_t i) 
362 
{ 
363 
int shift = i & 0xff; 
364 
if (shift >= 32) 
365 
return 0; 
366 
return x << shift;

367 
} 
368  
369 
uint32_t HELPER(shr)(uint32_t x, uint32_t i) 
370 
{ 
371 
int shift = i & 0xff; 
372 
if (shift >= 32) 
373 
return 0; 
374 
return (uint32_t)x >> shift;

375 
} 
376  
377 
uint32_t HELPER(sar)(uint32_t x, uint32_t i) 
378 
{ 
379 
int shift = i & 0xff; 
380 
if (shift >= 32) 
381 
shift = 31;

382 
return (int32_t)x >> shift;

383 
} 
384  
385 
uint32_t HELPER(ror)(uint32_t x, uint32_t i) 
386 
{ 
387 
int shift = i & 0xff; 
388 
if (shift == 0) 
389 
return x;

390 
return (x >> shift)  (x << (32  shift)); 
391 
} 
392  
393 
uint32_t HELPER(shl_cc)(uint32_t x, uint32_t i) 
394 
{ 
395 
int shift = i & 0xff; 
396 
if (shift >= 32) { 
397 
if (shift == 32) 
398 
env>CF = x & 1;

399 
else

400 
env>CF = 0;

401 
return 0; 
402 
} else if (shift != 0) { 
403 
env>CF = (x >> (32  shift)) & 1; 
404 
return x << shift;

405 
} 
406 
return x;

407 
} 
408  
409 
uint32_t HELPER(shr_cc)(uint32_t x, uint32_t i) 
410 
{ 
411 
int shift = i & 0xff; 
412 
if (shift >= 32) { 
413 
if (shift == 32) 
414 
env>CF = (x >> 31) & 1; 
415 
else

416 
env>CF = 0;

417 
return 0; 
418 
} else if (shift != 0) { 
419 
env>CF = (x >> (shift  1)) & 1; 
420 
return x >> shift;

421 
} 
422 
return x;

423 
} 
424  
425 
uint32_t HELPER(sar_cc)(uint32_t x, uint32_t i) 
426 
{ 
427 
int shift = i & 0xff; 
428 
if (shift >= 32) { 
429 
env>CF = (x >> 31) & 1; 
430 
return (int32_t)x >> 31; 
431 
} else if (shift != 0) { 
432 
env>CF = (x >> (shift  1)) & 1; 
433 
return (int32_t)x >> shift;

434 
} 
435 
return x;

436 
} 
437  
438 
uint32_t HELPER(ror_cc)(uint32_t x, uint32_t i) 
439 
{ 
440 
int shift1, shift;

441 
shift1 = i & 0xff;

442 
shift = shift1 & 0x1f;

443 
if (shift == 0) { 
444 
if (shift1 != 0) 
445 
env>CF = (x >> 31) & 1; 
446 
return x;

447 
} else {

448 
env>CF = (x >> (shift  1)) & 1; 
449 
return ((uint32_t)x >> shift)  (x << (32  shift)); 
450 
} 
451 
} 
452  
453 
uint64_t HELPER(neon_add_saturate_s64)(uint64_t src1, uint64_t src2) 
454 
{ 
455 
uint64_t res; 
456  
457 
res = src1 + src2; 
458 
if (((res ^ src1) & SIGNBIT64) && !((src1 ^ src2) & SIGNBIT64)) {

459 
env>QF = 1;

460 
res = ((int64_t)src1 >> 63) ^ ~SIGNBIT64;

461 
} 
462 
return res;

463 
} 
464  
465 
uint64_t HELPER(neon_add_saturate_u64)(uint64_t src1, uint64_t src2) 
466 
{ 
467 
uint64_t res; 
468  
469 
res = src1 + src2; 
470 
if (res < src1) {

471 
env>QF = 1;

472 
res = ~(uint64_t)0;

473 
} 
474 
return res;

475 
} 
476  
477 
uint64_t HELPER(neon_sub_saturate_s64)(uint64_t src1, uint64_t src2) 
478 
{ 
479 
uint64_t res; 
480  
481 
res = src1  src2; 
482 
if (((res ^ src1) & SIGNBIT64) && ((src1 ^ src2) & SIGNBIT64)) {

483 
env>QF = 1;

484 
res = ((int64_t)src1 >> 63) ^ ~SIGNBIT64;

485 
} 
486 
return res;

487 
} 
488  
489 
uint64_t HELPER(neon_sub_saturate_u64)(uint64_t src1, uint64_t src2) 
490 
{ 
491 
uint64_t res; 
492  
493 
if (src1 < src2) {

494 
env>QF = 1;

495 
res = 0;

496 
} else {

497 
res = src1  src2; 
498 
} 
499 
return res;

500 
} 
501  
502 
/* These need to return a pair of value, so still use T0/T1. */

503 
/* Transpose. Argument order is rather strange to avoid special casing

504 
the tranlation code.

505 
On input T0 = rm, T1 = rd. On output T0 = rd, T1 = rm */

506 
void HELPER(neon_trn_u8)(void) 
507 
{ 
508 
uint32_t rd; 
509 
uint32_t rm; 
510 
rd = ((T0 & 0x00ff00ff) << 8)  (T1 & 0x00ff00ff); 
511 
rm = ((T1 & 0xff00ff00) >> 8)  (T0 & 0xff00ff00); 
512 
T0 = rd; 
513 
T1 = rm; 
514 
FORCE_RET(); 
515 
} 
516  
517 
void HELPER(neon_trn_u16)(void) 
518 
{ 
519 
uint32_t rd; 
520 
uint32_t rm; 
521 
rd = (T0 << 16)  (T1 & 0xffff); 
522 
rm = (T1 >> 16)  (T0 & 0xffff0000); 
523 
T0 = rd; 
524 
T1 = rm; 
525 
FORCE_RET(); 
526 
} 
527  
528 
/* Worker routines for zip and unzip. */

529 
void HELPER(neon_unzip_u8)(void) 
530 
{ 
531 
uint32_t rd; 
532 
uint32_t rm; 
533 
rd = (T0 & 0xff)  ((T0 >> 8) & 0xff00) 
534 
 ((T1 << 16) & 0xff0000)  ((T1 << 8) & 0xff000000); 
535 
rm = ((T0 >> 8) & 0xff)  ((T0 >> 16) & 0xff00) 
536 
 ((T1 << 8) & 0xff0000)  (T1 & 0xff000000); 
537 
T0 = rd; 
538 
T1 = rm; 
539 
FORCE_RET(); 
540 
} 
541  
542 
void HELPER(neon_zip_u8)(void) 
543 
{ 
544 
uint32_t rd; 
545 
uint32_t rm; 
546 
rd = (T0 & 0xff)  ((T1 << 8) & 0xff00) 
547 
 ((T0 << 16) & 0xff0000)  ((T1 << 24) & 0xff000000); 
548 
rm = ((T0 >> 16) & 0xff)  ((T1 >> 8) & 0xff00) 
549 
 ((T0 >> 8) & 0xff0000)  (T1 & 0xff000000); 
550 
T0 = rd; 
551 
T1 = rm; 
552 
FORCE_RET(); 
553 
} 
554  
555 
void HELPER(neon_zip_u16)(void) 
556 
{ 
557 
uint32_t tmp; 
558  
559 
tmp = (T0 & 0xffff)  (T1 << 16); 
560 
T1 = (T1 & 0xffff0000)  (T0 >> 16); 
561 
T0 = tmp; 
562 
FORCE_RET(); 
563 
} 