]>
Commit | Line | Data |
---|---|---|
2c0262af FB |
1 | /* |
2 | * ARM micro operations | |
5fafdf24 | 3 | * |
2c0262af | 4 | * Copyright (c) 2003 Fabrice Bellard |
9ee6e8bb | 5 | * Copyright (c) 2005-2007 CodeSourcery, LLC |
2c0262af FB |
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 | #include "exec.h" | |
22 | ||
23 | #define REGNAME r0 | |
24 | #define REG (env->regs[0]) | |
25 | #include "op_template.h" | |
26 | ||
27 | #define REGNAME r1 | |
28 | #define REG (env->regs[1]) | |
29 | #include "op_template.h" | |
30 | ||
31 | #define REGNAME r2 | |
32 | #define REG (env->regs[2]) | |
33 | #include "op_template.h" | |
34 | ||
35 | #define REGNAME r3 | |
36 | #define REG (env->regs[3]) | |
37 | #include "op_template.h" | |
38 | ||
39 | #define REGNAME r4 | |
40 | #define REG (env->regs[4]) | |
41 | #include "op_template.h" | |
42 | ||
43 | #define REGNAME r5 | |
44 | #define REG (env->regs[5]) | |
45 | #include "op_template.h" | |
46 | ||
47 | #define REGNAME r6 | |
48 | #define REG (env->regs[6]) | |
49 | #include "op_template.h" | |
50 | ||
51 | #define REGNAME r7 | |
52 | #define REG (env->regs[7]) | |
53 | #include "op_template.h" | |
54 | ||
55 | #define REGNAME r8 | |
56 | #define REG (env->regs[8]) | |
57 | #include "op_template.h" | |
58 | ||
59 | #define REGNAME r9 | |
60 | #define REG (env->regs[9]) | |
61 | #include "op_template.h" | |
62 | ||
63 | #define REGNAME r10 | |
64 | #define REG (env->regs[10]) | |
65 | #include "op_template.h" | |
66 | ||
67 | #define REGNAME r11 | |
68 | #define REG (env->regs[11]) | |
69 | #include "op_template.h" | |
70 | ||
71 | #define REGNAME r12 | |
72 | #define REG (env->regs[12]) | |
73 | #include "op_template.h" | |
74 | ||
75 | #define REGNAME r13 | |
76 | #define REG (env->regs[13]) | |
77 | #include "op_template.h" | |
78 | ||
79 | #define REGNAME r14 | |
80 | #define REG (env->regs[14]) | |
81 | #include "op_template.h" | |
82 | ||
83 | #define REGNAME r15 | |
84 | #define REG (env->regs[15]) | |
99c475ab | 85 | #define SET_REG(x) REG = x & ~(uint32_t)1 |
2c0262af FB |
86 | #include "op_template.h" |
87 | ||
99c475ab FB |
88 | void OPPROTO op_bx_T0(void) |
89 | { | |
90 | env->regs[15] = T0 & ~(uint32_t)1; | |
91 | env->thumb = (T0 & 1) != 0; | |
92 | } | |
93 | ||
2c0262af FB |
94 | void OPPROTO op_movl_T0_0(void) |
95 | { | |
96 | T0 = 0; | |
97 | } | |
98 | ||
99 | void OPPROTO op_movl_T0_im(void) | |
100 | { | |
101 | T0 = PARAM1; | |
102 | } | |
103 | ||
104 | void OPPROTO op_movl_T1_im(void) | |
105 | { | |
106 | T1 = PARAM1; | |
107 | } | |
108 | ||
7ff4d218 FB |
109 | void OPPROTO op_mov_CF_T1(void) |
110 | { | |
111 | env->CF = ((uint32_t)T1) >> 31; | |
112 | } | |
113 | ||
2c0262af FB |
114 | void OPPROTO op_movl_T2_im(void) |
115 | { | |
116 | T2 = PARAM1; | |
117 | } | |
118 | ||
119 | void OPPROTO op_addl_T1_im(void) | |
120 | { | |
121 | T1 += PARAM1; | |
122 | } | |
123 | ||
124 | void OPPROTO op_addl_T1_T2(void) | |
125 | { | |
126 | T1 += T2; | |
127 | } | |
128 | ||
129 | void OPPROTO op_subl_T1_T2(void) | |
130 | { | |
131 | T1 -= T2; | |
132 | } | |
133 | ||
134 | void OPPROTO op_addl_T0_T1(void) | |
135 | { | |
136 | T0 += T1; | |
137 | } | |
138 | ||
139 | void OPPROTO op_addl_T0_T1_cc(void) | |
140 | { | |
141 | unsigned int src1; | |
142 | src1 = T0; | |
143 | T0 += T1; | |
144 | env->NZF = T0; | |
145 | env->CF = T0 < src1; | |
146 | env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0); | |
147 | } | |
148 | ||
149 | void OPPROTO op_adcl_T0_T1(void) | |
150 | { | |
151 | T0 += T1 + env->CF; | |
152 | } | |
153 | ||
154 | void OPPROTO op_adcl_T0_T1_cc(void) | |
155 | { | |
156 | unsigned int src1; | |
157 | src1 = T0; | |
158 | if (!env->CF) { | |
159 | T0 += T1; | |
160 | env->CF = T0 < src1; | |
161 | } else { | |
162 | T0 += T1 + 1; | |
163 | env->CF = T0 <= src1; | |
164 | } | |
165 | env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0); | |
166 | env->NZF = T0; | |
167 | FORCE_RET(); | |
168 | } | |
169 | ||
170 | #define OPSUB(sub, sbc, res, T0, T1) \ | |
171 | \ | |
172 | void OPPROTO op_ ## sub ## l_T0_T1(void) \ | |
173 | { \ | |
174 | res = T0 - T1; \ | |
175 | } \ | |
176 | \ | |
177 | void OPPROTO op_ ## sub ## l_T0_T1_cc(void) \ | |
178 | { \ | |
179 | unsigned int src1; \ | |
180 | src1 = T0; \ | |
181 | T0 -= T1; \ | |
182 | env->NZF = T0; \ | |
183 | env->CF = src1 >= T1; \ | |
184 | env->VF = (src1 ^ T1) & (src1 ^ T0); \ | |
185 | res = T0; \ | |
186 | } \ | |
187 | \ | |
188 | void OPPROTO op_ ## sbc ## l_T0_T1(void) \ | |
189 | { \ | |
190 | res = T0 - T1 + env->CF - 1; \ | |
191 | } \ | |
192 | \ | |
193 | void OPPROTO op_ ## sbc ## l_T0_T1_cc(void) \ | |
194 | { \ | |
195 | unsigned int src1; \ | |
196 | src1 = T0; \ | |
197 | if (!env->CF) { \ | |
198 | T0 = T0 - T1 - 1; \ | |
78573df6 | 199 | env->CF = src1 > T1; \ |
2c0262af FB |
200 | } else { \ |
201 | T0 = T0 - T1; \ | |
78573df6 | 202 | env->CF = src1 >= T1; \ |
2c0262af FB |
203 | } \ |
204 | env->VF = (src1 ^ T1) & (src1 ^ T0); \ | |
205 | env->NZF = T0; \ | |
206 | res = T0; \ | |
207 | FORCE_RET(); \ | |
208 | } | |
209 | ||
210 | OPSUB(sub, sbc, T0, T0, T1) | |
211 | ||
212 | OPSUB(rsb, rsc, T0, T1, T0) | |
213 | ||
214 | void OPPROTO op_andl_T0_T1(void) | |
215 | { | |
216 | T0 &= T1; | |
217 | } | |
218 | ||
219 | void OPPROTO op_xorl_T0_T1(void) | |
220 | { | |
221 | T0 ^= T1; | |
222 | } | |
223 | ||
224 | void OPPROTO op_orl_T0_T1(void) | |
225 | { | |
226 | T0 |= T1; | |
227 | } | |
228 | ||
229 | void OPPROTO op_bicl_T0_T1(void) | |
230 | { | |
231 | T0 &= ~T1; | |
232 | } | |
233 | ||
9ee6e8bb PB |
234 | void OPPROTO op_notl_T0(void) |
235 | { | |
236 | T0 = ~T0; | |
237 | } | |
238 | ||
2c0262af FB |
239 | void OPPROTO op_notl_T1(void) |
240 | { | |
241 | T1 = ~T1; | |
242 | } | |
243 | ||
244 | void OPPROTO op_logic_T0_cc(void) | |
245 | { | |
246 | env->NZF = T0; | |
247 | } | |
248 | ||
249 | void OPPROTO op_logic_T1_cc(void) | |
250 | { | |
251 | env->NZF = T1; | |
252 | } | |
253 | ||
254 | #define EIP (env->regs[15]) | |
255 | ||
256 | void OPPROTO op_test_eq(void) | |
257 | { | |
258 | if (env->NZF == 0) | |
e50e6a20 | 259 | GOTO_LABEL_PARAM(1);; |
2c0262af FB |
260 | FORCE_RET(); |
261 | } | |
262 | ||
263 | void OPPROTO op_test_ne(void) | |
264 | { | |
265 | if (env->NZF != 0) | |
e50e6a20 | 266 | GOTO_LABEL_PARAM(1);; |
2c0262af FB |
267 | FORCE_RET(); |
268 | } | |
269 | ||
270 | void OPPROTO op_test_cs(void) | |
271 | { | |
272 | if (env->CF != 0) | |
e50e6a20 | 273 | GOTO_LABEL_PARAM(1); |
2c0262af FB |
274 | FORCE_RET(); |
275 | } | |
276 | ||
277 | void OPPROTO op_test_cc(void) | |
278 | { | |
279 | if (env->CF == 0) | |
e50e6a20 | 280 | GOTO_LABEL_PARAM(1); |
2c0262af FB |
281 | FORCE_RET(); |
282 | } | |
283 | ||
284 | void OPPROTO op_test_mi(void) | |
285 | { | |
286 | if ((env->NZF & 0x80000000) != 0) | |
e50e6a20 | 287 | GOTO_LABEL_PARAM(1); |
2c0262af FB |
288 | FORCE_RET(); |
289 | } | |
290 | ||
291 | void OPPROTO op_test_pl(void) | |
292 | { | |
293 | if ((env->NZF & 0x80000000) == 0) | |
e50e6a20 | 294 | GOTO_LABEL_PARAM(1); |
2c0262af FB |
295 | FORCE_RET(); |
296 | } | |
297 | ||
298 | void OPPROTO op_test_vs(void) | |
299 | { | |
300 | if ((env->VF & 0x80000000) != 0) | |
e50e6a20 | 301 | GOTO_LABEL_PARAM(1); |
2c0262af FB |
302 | FORCE_RET(); |
303 | } | |
304 | ||
305 | void OPPROTO op_test_vc(void) | |
306 | { | |
307 | if ((env->VF & 0x80000000) == 0) | |
e50e6a20 | 308 | GOTO_LABEL_PARAM(1); |
2c0262af FB |
309 | FORCE_RET(); |
310 | } | |
311 | ||
312 | void OPPROTO op_test_hi(void) | |
313 | { | |
314 | if (env->CF != 0 && env->NZF != 0) | |
e50e6a20 | 315 | GOTO_LABEL_PARAM(1); |
2c0262af FB |
316 | FORCE_RET(); |
317 | } | |
318 | ||
319 | void OPPROTO op_test_ls(void) | |
320 | { | |
321 | if (env->CF == 0 || env->NZF == 0) | |
e50e6a20 | 322 | GOTO_LABEL_PARAM(1); |
2c0262af FB |
323 | FORCE_RET(); |
324 | } | |
325 | ||
326 | void OPPROTO op_test_ge(void) | |
327 | { | |
328 | if (((env->VF ^ env->NZF) & 0x80000000) == 0) | |
e50e6a20 | 329 | GOTO_LABEL_PARAM(1); |
2c0262af FB |
330 | FORCE_RET(); |
331 | } | |
332 | ||
333 | void OPPROTO op_test_lt(void) | |
334 | { | |
335 | if (((env->VF ^ env->NZF) & 0x80000000) != 0) | |
e50e6a20 | 336 | GOTO_LABEL_PARAM(1); |
2c0262af FB |
337 | FORCE_RET(); |
338 | } | |
339 | ||
340 | void OPPROTO op_test_gt(void) | |
341 | { | |
342 | if (env->NZF != 0 && ((env->VF ^ env->NZF) & 0x80000000) == 0) | |
e50e6a20 | 343 | GOTO_LABEL_PARAM(1); |
2c0262af FB |
344 | FORCE_RET(); |
345 | } | |
346 | ||
347 | void OPPROTO op_test_le(void) | |
348 | { | |
349 | if (env->NZF == 0 || ((env->VF ^ env->NZF) & 0x80000000) != 0) | |
e50e6a20 | 350 | GOTO_LABEL_PARAM(1); |
2c0262af FB |
351 | FORCE_RET(); |
352 | } | |
353 | ||
9ee6e8bb PB |
354 | void OPPROTO op_test_T0(void) |
355 | { | |
356 | if (T0) | |
357 | GOTO_LABEL_PARAM(1); | |
358 | FORCE_RET(); | |
359 | } | |
360 | void OPPROTO op_testn_T0(void) | |
361 | { | |
362 | if (!T0) | |
363 | GOTO_LABEL_PARAM(1); | |
364 | FORCE_RET(); | |
365 | } | |
366 | ||
c53be334 | 367 | void OPPROTO op_goto_tb0(void) |
2c0262af | 368 | { |
c53be334 | 369 | GOTO_TB(op_goto_tb0, PARAM1, 0); |
e50e6a20 FB |
370 | } |
371 | ||
c53be334 | 372 | void OPPROTO op_goto_tb1(void) |
e50e6a20 | 373 | { |
c53be334 | 374 | GOTO_TB(op_goto_tb1, PARAM1, 1); |
2c0262af FB |
375 | } |
376 | ||
377 | void OPPROTO op_exit_tb(void) | |
378 | { | |
379 | EXIT_TB(); | |
380 | } | |
381 | ||
b5ff1b31 | 382 | void OPPROTO op_movl_T0_cpsr(void) |
2c0262af | 383 | { |
9ee6e8bb PB |
384 | /* Execution state bits always read as zero. */ |
385 | T0 = cpsr_read(env) & ~CPSR_EXEC; | |
b5ff1b31 | 386 | FORCE_RET(); |
2c0262af FB |
387 | } |
388 | ||
b5ff1b31 | 389 | void OPPROTO op_movl_T0_spsr(void) |
2c0262af | 390 | { |
b5ff1b31 FB |
391 | T0 = env->spsr; |
392 | } | |
393 | ||
394 | void OPPROTO op_movl_spsr_T0(void) | |
395 | { | |
396 | uint32_t mask = PARAM1; | |
397 | env->spsr = (env->spsr & ~mask) | (T0 & mask); | |
398 | } | |
399 | ||
400 | void OPPROTO op_movl_cpsr_T0(void) | |
401 | { | |
402 | cpsr_write(env, T0, PARAM1); | |
403 | FORCE_RET(); | |
2c0262af FB |
404 | } |
405 | ||
406 | void OPPROTO op_mul_T0_T1(void) | |
407 | { | |
408 | T0 = T0 * T1; | |
409 | } | |
410 | ||
411 | /* 64 bit unsigned mul */ | |
412 | void OPPROTO op_mull_T0_T1(void) | |
413 | { | |
414 | uint64_t res; | |
2e134c9c | 415 | res = (uint64_t)T0 * (uint64_t)T1; |
2c0262af FB |
416 | T1 = res >> 32; |
417 | T0 = res; | |
418 | } | |
419 | ||
420 | /* 64 bit signed mul */ | |
421 | void OPPROTO op_imull_T0_T1(void) | |
422 | { | |
423 | uint64_t res; | |
163a7cb6 | 424 | res = (int64_t)((int32_t)T0) * (int64_t)((int32_t)T1); |
2c0262af FB |
425 | T1 = res >> 32; |
426 | T0 = res; | |
427 | } | |
428 | ||
99c475ab FB |
429 | /* 48 bit signed mul, top 32 bits */ |
430 | void OPPROTO op_imulw_T0_T1(void) | |
431 | { | |
432 | uint64_t res; | |
433 | res = (int64_t)((int32_t)T0) * (int64_t)((int32_t)T1); | |
434 | T0 = res >> 16; | |
435 | } | |
436 | ||
2c0262af FB |
437 | void OPPROTO op_addq_T0_T1(void) |
438 | { | |
439 | uint64_t res; | |
440 | res = ((uint64_t)T1 << 32) | T0; | |
441 | res += ((uint64_t)(env->regs[PARAM2]) << 32) | (env->regs[PARAM1]); | |
442 | T1 = res >> 32; | |
443 | T0 = res; | |
444 | } | |
445 | ||
99c475ab FB |
446 | void OPPROTO op_addq_lo_T0_T1(void) |
447 | { | |
448 | uint64_t res; | |
449 | res = ((uint64_t)T1 << 32) | T0; | |
450 | res += (uint64_t)(env->regs[PARAM1]); | |
451 | T1 = res >> 32; | |
452 | T0 = res; | |
453 | } | |
454 | ||
9ee6e8bb PB |
455 | /* Dual 16-bit accumulate. */ |
456 | void OPPROTO op_addq_T0_T1_dual(void) | |
457 | { | |
458 | uint64_t res; | |
459 | res = ((uint64_t)(env->regs[PARAM2]) << 32) | (env->regs[PARAM1]); | |
460 | res += (int32_t)T0; | |
461 | res += (int32_t)T1; | |
462 | env->regs[PARAM1] = (uint32_t)res; | |
463 | env->regs[PARAM2] = res >> 32; | |
464 | } | |
465 | ||
466 | /* Dual 16-bit subtract accumulate. */ | |
467 | void OPPROTO op_subq_T0_T1_dual(void) | |
468 | { | |
469 | uint64_t res; | |
470 | res = ((uint64_t)(env->regs[PARAM2]) << 32) | (env->regs[PARAM1]); | |
471 | res += (int32_t)T0; | |
472 | res -= (int32_t)T1; | |
473 | env->regs[PARAM1] = (uint32_t)res; | |
474 | env->regs[PARAM2] = res >> 32; | |
475 | } | |
476 | ||
2c0262af FB |
477 | void OPPROTO op_logicq_cc(void) |
478 | { | |
479 | env->NZF = (T1 & 0x80000000) | ((T0 | T1) != 0); | |
480 | } | |
481 | ||
482 | /* memory access */ | |
483 | ||
b5ff1b31 FB |
484 | #define MEMSUFFIX _raw |
485 | #include "op_mem.h" | |
2c0262af | 486 | |
b5ff1b31 FB |
487 | #if !defined(CONFIG_USER_ONLY) |
488 | #define MEMSUFFIX _user | |
489 | #include "op_mem.h" | |
490 | #define MEMSUFFIX _kernel | |
491 | #include "op_mem.h" | |
492 | #endif | |
2c0262af | 493 | |
9ee6e8bb PB |
494 | void OPPROTO op_clrex(void) |
495 | { | |
496 | cpu_lock(); | |
497 | helper_clrex(env); | |
498 | cpu_unlock(); | |
499 | } | |
500 | ||
2c0262af FB |
501 | /* shifts */ |
502 | ||
9ee6e8bb PB |
503 | /* Used by NEON. */ |
504 | void OPPROTO op_shll_T0_im(void) | |
505 | { | |
506 | T1 = T1 << PARAM1; | |
507 | } | |
508 | ||
2c0262af | 509 | /* T1 based */ |
1e8d4eec | 510 | |
2c0262af FB |
511 | void OPPROTO op_shll_T1_im(void) |
512 | { | |
513 | T1 = T1 << PARAM1; | |
514 | } | |
515 | ||
516 | void OPPROTO op_shrl_T1_im(void) | |
517 | { | |
518 | T1 = (uint32_t)T1 >> PARAM1; | |
519 | } | |
520 | ||
1e8d4eec FB |
521 | void OPPROTO op_shrl_T1_0(void) |
522 | { | |
523 | T1 = 0; | |
524 | } | |
525 | ||
2c0262af FB |
526 | void OPPROTO op_sarl_T1_im(void) |
527 | { | |
528 | T1 = (int32_t)T1 >> PARAM1; | |
529 | } | |
530 | ||
1e8d4eec FB |
531 | void OPPROTO op_sarl_T1_0(void) |
532 | { | |
533 | T1 = (int32_t)T1 >> 31; | |
534 | } | |
535 | ||
2c0262af FB |
536 | void OPPROTO op_rorl_T1_im(void) |
537 | { | |
538 | int shift; | |
539 | shift = PARAM1; | |
540 | T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); | |
541 | } | |
542 | ||
88920f34 FB |
543 | void OPPROTO op_rrxl_T1(void) |
544 | { | |
545 | T1 = ((uint32_t)T1 >> 1) | ((uint32_t)env->CF << 31); | |
546 | } | |
547 | ||
2c0262af FB |
548 | /* T1 based, set C flag */ |
549 | void OPPROTO op_shll_T1_im_cc(void) | |
550 | { | |
551 | env->CF = (T1 >> (32 - PARAM1)) & 1; | |
552 | T1 = T1 << PARAM1; | |
553 | } | |
554 | ||
555 | void OPPROTO op_shrl_T1_im_cc(void) | |
556 | { | |
557 | env->CF = (T1 >> (PARAM1 - 1)) & 1; | |
558 | T1 = (uint32_t)T1 >> PARAM1; | |
559 | } | |
560 | ||
1e8d4eec FB |
561 | void OPPROTO op_shrl_T1_0_cc(void) |
562 | { | |
563 | env->CF = (T1 >> 31) & 1; | |
564 | T1 = 0; | |
565 | } | |
566 | ||
2c0262af FB |
567 | void OPPROTO op_sarl_T1_im_cc(void) |
568 | { | |
569 | env->CF = (T1 >> (PARAM1 - 1)) & 1; | |
570 | T1 = (int32_t)T1 >> PARAM1; | |
571 | } | |
572 | ||
1e8d4eec FB |
573 | void OPPROTO op_sarl_T1_0_cc(void) |
574 | { | |
575 | env->CF = (T1 >> 31) & 1; | |
576 | T1 = (int32_t)T1 >> 31; | |
577 | } | |
578 | ||
2c0262af FB |
579 | void OPPROTO op_rorl_T1_im_cc(void) |
580 | { | |
581 | int shift; | |
582 | shift = PARAM1; | |
583 | env->CF = (T1 >> (shift - 1)) & 1; | |
584 | T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); | |
585 | } | |
586 | ||
88920f34 FB |
587 | void OPPROTO op_rrxl_T1_cc(void) |
588 | { | |
589 | uint32_t c; | |
590 | c = T1 & 1; | |
591 | T1 = ((uint32_t)T1 >> 1) | ((uint32_t)env->CF << 31); | |
592 | env->CF = c; | |
593 | } | |
594 | ||
2c0262af FB |
595 | /* T2 based */ |
596 | void OPPROTO op_shll_T2_im(void) | |
597 | { | |
598 | T2 = T2 << PARAM1; | |
599 | } | |
600 | ||
601 | void OPPROTO op_shrl_T2_im(void) | |
602 | { | |
603 | T2 = (uint32_t)T2 >> PARAM1; | |
604 | } | |
605 | ||
1e8d4eec FB |
606 | void OPPROTO op_shrl_T2_0(void) |
607 | { | |
608 | T2 = 0; | |
609 | } | |
610 | ||
2c0262af FB |
611 | void OPPROTO op_sarl_T2_im(void) |
612 | { | |
613 | T2 = (int32_t)T2 >> PARAM1; | |
614 | } | |
615 | ||
1e8d4eec FB |
616 | void OPPROTO op_sarl_T2_0(void) |
617 | { | |
618 | T2 = (int32_t)T2 >> 31; | |
619 | } | |
620 | ||
2c0262af FB |
621 | void OPPROTO op_rorl_T2_im(void) |
622 | { | |
623 | int shift; | |
624 | shift = PARAM1; | |
625 | T2 = ((uint32_t)T2 >> shift) | (T2 << (32 - shift)); | |
626 | } | |
627 | ||
1e8d4eec FB |
628 | void OPPROTO op_rrxl_T2(void) |
629 | { | |
630 | T2 = ((uint32_t)T2 >> 1) | ((uint32_t)env->CF << 31); | |
631 | } | |
632 | ||
2c0262af FB |
633 | /* T1 based, use T0 as shift count */ |
634 | ||
635 | void OPPROTO op_shll_T1_T0(void) | |
636 | { | |
637 | int shift; | |
638 | shift = T0 & 0xff; | |
639 | if (shift >= 32) | |
640 | T1 = 0; | |
641 | else | |
642 | T1 = T1 << shift; | |
643 | FORCE_RET(); | |
644 | } | |
645 | ||
646 | void OPPROTO op_shrl_T1_T0(void) | |
647 | { | |
648 | int shift; | |
649 | shift = T0 & 0xff; | |
650 | if (shift >= 32) | |
651 | T1 = 0; | |
652 | else | |
653 | T1 = (uint32_t)T1 >> shift; | |
654 | FORCE_RET(); | |
655 | } | |
656 | ||
657 | void OPPROTO op_sarl_T1_T0(void) | |
658 | { | |
659 | int shift; | |
660 | shift = T0 & 0xff; | |
661 | if (shift >= 32) | |
662 | shift = 31; | |
663 | T1 = (int32_t)T1 >> shift; | |
664 | } | |
665 | ||
666 | void OPPROTO op_rorl_T1_T0(void) | |
667 | { | |
668 | int shift; | |
669 | shift = T0 & 0x1f; | |
670 | if (shift) { | |
671 | T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); | |
672 | } | |
673 | FORCE_RET(); | |
674 | } | |
675 | ||
676 | /* T1 based, use T0 as shift count and compute CF */ | |
677 | ||
678 | void OPPROTO op_shll_T1_T0_cc(void) | |
679 | { | |
680 | int shift; | |
681 | shift = T0 & 0xff; | |
682 | if (shift >= 32) { | |
683 | if (shift == 32) | |
684 | env->CF = T1 & 1; | |
685 | else | |
686 | env->CF = 0; | |
687 | T1 = 0; | |
688 | } else if (shift != 0) { | |
689 | env->CF = (T1 >> (32 - shift)) & 1; | |
690 | T1 = T1 << shift; | |
691 | } | |
692 | FORCE_RET(); | |
693 | } | |
694 | ||
695 | void OPPROTO op_shrl_T1_T0_cc(void) | |
696 | { | |
697 | int shift; | |
698 | shift = T0 & 0xff; | |
699 | if (shift >= 32) { | |
700 | if (shift == 32) | |
701 | env->CF = (T1 >> 31) & 1; | |
702 | else | |
703 | env->CF = 0; | |
704 | T1 = 0; | |
705 | } else if (shift != 0) { | |
706 | env->CF = (T1 >> (shift - 1)) & 1; | |
707 | T1 = (uint32_t)T1 >> shift; | |
708 | } | |
709 | FORCE_RET(); | |
710 | } | |
711 | ||
712 | void OPPROTO op_sarl_T1_T0_cc(void) | |
713 | { | |
714 | int shift; | |
715 | shift = T0 & 0xff; | |
716 | if (shift >= 32) { | |
717 | env->CF = (T1 >> 31) & 1; | |
718 | T1 = (int32_t)T1 >> 31; | |
1b1afeb9 | 719 | } else if (shift != 0) { |
2c0262af FB |
720 | env->CF = (T1 >> (shift - 1)) & 1; |
721 | T1 = (int32_t)T1 >> shift; | |
722 | } | |
723 | FORCE_RET(); | |
724 | } | |
725 | ||
726 | void OPPROTO op_rorl_T1_T0_cc(void) | |
727 | { | |
728 | int shift1, shift; | |
729 | shift1 = T0 & 0xff; | |
730 | shift = shift1 & 0x1f; | |
731 | if (shift == 0) { | |
732 | if (shift1 != 0) | |
733 | env->CF = (T1 >> 31) & 1; | |
734 | } else { | |
735 | env->CF = (T1 >> (shift - 1)) & 1; | |
736 | T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); | |
737 | } | |
738 | FORCE_RET(); | |
739 | } | |
740 | ||
99c475ab FB |
741 | /* misc */ |
742 | void OPPROTO op_clz_T0(void) | |
743 | { | |
744 | int count; | |
745 | for (count = 32; T0 > 0; count--) | |
746 | T0 = T0 >> 1; | |
747 | T0 = count; | |
748 | FORCE_RET(); | |
749 | } | |
750 | ||
751 | void OPPROTO op_sarl_T0_im(void) | |
752 | { | |
753 | T0 = (int32_t)T0 >> PARAM1; | |
754 | } | |
755 | ||
b5ff1b31 FB |
756 | /* Sign/zero extend */ |
757 | void OPPROTO op_sxth_T0(void) | |
99c475ab FB |
758 | { |
759 | T0 = (int16_t)T0; | |
760 | } | |
761 | ||
b5ff1b31 | 762 | void OPPROTO op_sxth_T1(void) |
99c475ab FB |
763 | { |
764 | T1 = (int16_t)T1; | |
765 | } | |
766 | ||
b5ff1b31 FB |
767 | void OPPROTO op_sxtb_T1(void) |
768 | { | |
769 | T1 = (int8_t)T1; | |
770 | } | |
771 | ||
772 | void OPPROTO op_uxtb_T1(void) | |
773 | { | |
774 | T1 = (uint8_t)T1; | |
775 | } | |
776 | ||
777 | void OPPROTO op_uxth_T1(void) | |
778 | { | |
779 | T1 = (uint16_t)T1; | |
780 | } | |
781 | ||
782 | void OPPROTO op_sxtb16_T1(void) | |
783 | { | |
784 | uint32_t res; | |
785 | res = (uint16_t)(int8_t)T1; | |
786 | res |= (uint32_t)(int8_t)(T1 >> 16) << 16; | |
787 | T1 = res; | |
788 | } | |
789 | ||
790 | void OPPROTO op_uxtb16_T1(void) | |
791 | { | |
792 | uint32_t res; | |
793 | res = (uint16_t)(uint8_t)T1; | |
794 | res |= (uint32_t)(uint8_t)(T1 >> 16) << 16; | |
795 | T1 = res; | |
796 | } | |
797 | ||
99c475ab FB |
798 | #define SIGNBIT (uint32_t)0x80000000 |
799 | /* saturating arithmetic */ | |
800 | void OPPROTO op_addl_T0_T1_setq(void) | |
801 | { | |
802 | uint32_t res; | |
803 | ||
804 | res = T0 + T1; | |
805 | if (((res ^ T0) & SIGNBIT) && !((T0 ^ T1) & SIGNBIT)) | |
806 | env->QF = 1; | |
807 | ||
808 | T0 = res; | |
809 | FORCE_RET(); | |
810 | } | |
811 | ||
812 | void OPPROTO op_addl_T0_T1_saturate(void) | |
813 | { | |
814 | uint32_t res; | |
815 | ||
816 | res = T0 + T1; | |
817 | if (((res ^ T0) & SIGNBIT) && !((T0 ^ T1) & SIGNBIT)) { | |
818 | env->QF = 1; | |
819 | if (T0 & SIGNBIT) | |
820 | T0 = 0x80000000; | |
821 | else | |
822 | T0 = 0x7fffffff; | |
823 | } | |
824 | else | |
825 | T0 = res; | |
3b46e624 | 826 | |
99c475ab FB |
827 | FORCE_RET(); |
828 | } | |
829 | ||
830 | void OPPROTO op_subl_T0_T1_saturate(void) | |
831 | { | |
832 | uint32_t res; | |
833 | ||
834 | res = T0 - T1; | |
835 | if (((res ^ T0) & SIGNBIT) && ((T0 ^ T1) & SIGNBIT)) { | |
836 | env->QF = 1; | |
837 | if (T0 & SIGNBIT) | |
567d4107 | 838 | T0 = 0x80000000; |
99c475ab FB |
839 | else |
840 | T0 = 0x7fffffff; | |
841 | } | |
842 | else | |
843 | T0 = res; | |
3b46e624 | 844 | |
99c475ab FB |
845 | FORCE_RET(); |
846 | } | |
847 | ||
ff8263a9 FB |
848 | void OPPROTO op_double_T1_saturate(void) |
849 | { | |
850 | int32_t val; | |
851 | ||
852 | val = T1; | |
853 | if (val >= 0x40000000) { | |
854 | T1 = 0x7fffffff; | |
855 | env->QF = 1; | |
856 | } else if (val <= (int32_t)0xc0000000) { | |
857 | T1 = 0x80000000; | |
858 | env->QF = 1; | |
859 | } else { | |
860 | T1 = val << 1; | |
861 | } | |
862 | FORCE_RET(); | |
863 | } | |
864 | ||
9ee6e8bb PB |
865 | /* Unsigned saturating arithmetic for NEON. */ |
866 | void OPPROTO op_addl_T0_T1_usaturate(void) | |
867 | { | |
868 | uint32_t res; | |
869 | ||
870 | res = T0 + T1; | |
871 | if (res < T0) { | |
872 | env->QF = 1; | |
873 | T0 = 0xffffffff; | |
874 | } else { | |
875 | T0 = res; | |
876 | } | |
877 | ||
878 | FORCE_RET(); | |
879 | } | |
880 | ||
881 | void OPPROTO op_subl_T0_T1_usaturate(void) | |
882 | { | |
883 | uint32_t res; | |
884 | ||
885 | res = T0 - T1; | |
886 | if (res > T0) { | |
887 | env->QF = 1; | |
888 | T0 = 0; | |
889 | } else { | |
890 | T0 = res; | |
891 | } | |
892 | ||
893 | FORCE_RET(); | |
894 | } | |
895 | ||
896 | /* Thumb shift by immediate */ | |
897 | void OPPROTO op_shll_T0_im_thumb_cc(void) | |
99c475ab FB |
898 | { |
899 | int shift; | |
900 | shift = PARAM1; | |
901 | if (shift != 0) { | |
aa268ea6 | 902 | env->CF = (T0 >> (32 - shift)) & 1; |
99c475ab FB |
903 | T0 = T0 << shift; |
904 | } | |
905 | env->NZF = T0; | |
906 | FORCE_RET(); | |
907 | } | |
908 | ||
9ee6e8bb PB |
909 | void OPPROTO op_shll_T0_im_thumb(void) |
910 | { | |
911 | T0 = T0 << PARAM1; | |
912 | FORCE_RET(); | |
913 | } | |
914 | ||
915 | void OPPROTO op_shrl_T0_im_thumb_cc(void) | |
99c475ab FB |
916 | { |
917 | int shift; | |
918 | ||
919 | shift = PARAM1; | |
920 | if (shift == 0) { | |
aa268ea6 | 921 | env->CF = ((uint32_t)T0) >> 31; |
99c475ab FB |
922 | T0 = 0; |
923 | } else { | |
924 | env->CF = (T0 >> (shift - 1)) & 1; | |
925 | T0 = T0 >> shift; | |
926 | } | |
5899f386 | 927 | env->NZF = T0; |
99c475ab FB |
928 | FORCE_RET(); |
929 | } | |
930 | ||
9ee6e8bb PB |
931 | void OPPROTO op_shrl_T0_im_thumb(void) |
932 | { | |
933 | int shift; | |
934 | ||
935 | shift = PARAM1; | |
936 | if (shift == 0) { | |
937 | T0 = 0; | |
938 | } else { | |
939 | T0 = T0 >> shift; | |
940 | } | |
941 | FORCE_RET(); | |
942 | } | |
943 | ||
944 | void OPPROTO op_sarl_T0_im_thumb_cc(void) | |
99c475ab FB |
945 | { |
946 | int shift; | |
947 | ||
948 | shift = PARAM1; | |
949 | if (shift == 0) { | |
950 | T0 = ((int32_t)T0) >> 31; | |
951 | env->CF = T0 & 1; | |
952 | } else { | |
953 | env->CF = (T0 >> (shift - 1)) & 1; | |
954 | T0 = ((int32_t)T0) >> shift; | |
955 | } | |
956 | env->NZF = T0; | |
957 | FORCE_RET(); | |
958 | } | |
959 | ||
9ee6e8bb PB |
960 | void OPPROTO op_sarl_T0_im_thumb(void) |
961 | { | |
962 | int shift; | |
963 | ||
964 | shift = PARAM1; | |
965 | if (shift == 0) { | |
966 | env->CF = T0 & 1; | |
967 | } else { | |
968 | T0 = ((int32_t)T0) >> shift; | |
969 | } | |
970 | FORCE_RET(); | |
971 | } | |
972 | ||
2c0262af FB |
973 | /* exceptions */ |
974 | ||
975 | void OPPROTO op_swi(void) | |
976 | { | |
977 | env->exception_index = EXCP_SWI; | |
978 | cpu_loop_exit(); | |
979 | } | |
980 | ||
981 | void OPPROTO op_undef_insn(void) | |
982 | { | |
983 | env->exception_index = EXCP_UDEF; | |
984 | cpu_loop_exit(); | |
985 | } | |
986 | ||
1fddef4b FB |
987 | void OPPROTO op_debug(void) |
988 | { | |
989 | env->exception_index = EXCP_DEBUG; | |
990 | cpu_loop_exit(); | |
991 | } | |
992 | ||
9332f9da FB |
993 | void OPPROTO op_wfi(void) |
994 | { | |
995 | env->exception_index = EXCP_HLT; | |
996 | env->halted = 1; | |
997 | cpu_loop_exit(); | |
998 | } | |
999 | ||
06c949e6 PB |
1000 | void OPPROTO op_bkpt(void) |
1001 | { | |
1002 | env->exception_index = EXCP_BKPT; | |
1003 | cpu_loop_exit(); | |
1004 | } | |
1005 | ||
9ee6e8bb PB |
1006 | void OPPROTO op_exception_exit(void) |
1007 | { | |
1008 | env->exception_index = EXCP_EXCEPTION_EXIT; | |
1009 | cpu_loop_exit(); | |
1010 | } | |
1011 | ||
b7bcbe95 FB |
1012 | /* VFP support. We follow the convention used for VFP instrunctions: |
1013 | Single precition routines have a "s" suffix, double precision a | |
1014 | "d" suffix. */ | |
2c0262af | 1015 | |
b7bcbe95 | 1016 | #define VFP_OP(name, p) void OPPROTO op_vfp_##name##p(void) |
2c0262af | 1017 | |
53cd6637 | 1018 | #define VFP_BINOP(name) \ |
b7bcbe95 FB |
1019 | VFP_OP(name, s) \ |
1020 | { \ | |
53cd6637 | 1021 | FT0s = float32_ ## name (FT0s, FT1s, &env->vfp.fp_status); \ |
b7bcbe95 FB |
1022 | } \ |
1023 | VFP_OP(name, d) \ | |
1024 | { \ | |
53cd6637 | 1025 | FT0d = float64_ ## name (FT0d, FT1d, &env->vfp.fp_status); \ |
b7bcbe95 | 1026 | } |
53cd6637 FB |
1027 | VFP_BINOP(add) |
1028 | VFP_BINOP(sub) | |
1029 | VFP_BINOP(mul) | |
1030 | VFP_BINOP(div) | |
b7bcbe95 FB |
1031 | #undef VFP_BINOP |
1032 | ||
1033 | #define VFP_HELPER(name) \ | |
1034 | VFP_OP(name, s) \ | |
1035 | { \ | |
1036 | do_vfp_##name##s(); \ | |
1037 | } \ | |
1038 | VFP_OP(name, d) \ | |
1039 | { \ | |
1040 | do_vfp_##name##d(); \ | |
1041 | } | |
1042 | VFP_HELPER(abs) | |
1043 | VFP_HELPER(sqrt) | |
1044 | VFP_HELPER(cmp) | |
1045 | VFP_HELPER(cmpe) | |
1046 | #undef VFP_HELPER | |
1047 | ||
1048 | /* XXX: Will this do the right thing for NANs. Should invert the signbit | |
1049 | without looking at the rest of the value. */ | |
1050 | VFP_OP(neg, s) | |
1051 | { | |
53cd6637 | 1052 | FT0s = float32_chs(FT0s); |
b7bcbe95 FB |
1053 | } |
1054 | ||
1055 | VFP_OP(neg, d) | |
1056 | { | |
53cd6637 | 1057 | FT0d = float64_chs(FT0d); |
b7bcbe95 FB |
1058 | } |
1059 | ||
1060 | VFP_OP(F1_ld0, s) | |
1061 | { | |
53cd6637 FB |
1062 | union { |
1063 | uint32_t i; | |
1064 | float32 s; | |
1065 | } v; | |
1066 | v.i = 0; | |
1067 | FT1s = v.s; | |
b7bcbe95 FB |
1068 | } |
1069 | ||
1070 | VFP_OP(F1_ld0, d) | |
1071 | { | |
53cd6637 FB |
1072 | union { |
1073 | uint64_t i; | |
1074 | float64 d; | |
1075 | } v; | |
1076 | v.i = 0; | |
1077 | FT1d = v.d; | |
b7bcbe95 FB |
1078 | } |
1079 | ||
1080 | /* Helper routines to perform bitwise copies between float and int. */ | |
53cd6637 | 1081 | static inline float32 vfp_itos(uint32_t i) |
b7bcbe95 FB |
1082 | { |
1083 | union { | |
1084 | uint32_t i; | |
53cd6637 | 1085 | float32 s; |
b7bcbe95 FB |
1086 | } v; |
1087 | ||
1088 | v.i = i; | |
1089 | return v.s; | |
1090 | } | |
1091 | ||
53cd6637 | 1092 | static inline uint32_t vfp_stoi(float32 s) |
b7bcbe95 FB |
1093 | { |
1094 | union { | |
1095 | uint32_t i; | |
53cd6637 | 1096 | float32 s; |
b7bcbe95 FB |
1097 | } v; |
1098 | ||
1099 | v.s = s; | |
1100 | return v.i; | |
1101 | } | |
1102 | ||
9ee6e8bb PB |
1103 | static inline float64 vfp_itod(uint64_t i) |
1104 | { | |
1105 | union { | |
1106 | uint64_t i; | |
1107 | float64 d; | |
1108 | } v; | |
1109 | ||
1110 | v.i = i; | |
1111 | return v.d; | |
1112 | } | |
1113 | ||
1114 | static inline uint64_t vfp_dtoi(float64 d) | |
1115 | { | |
1116 | union { | |
1117 | uint64_t i; | |
1118 | float64 d; | |
1119 | } v; | |
1120 | ||
1121 | v.d = d; | |
1122 | return v.i; | |
1123 | } | |
1124 | ||
b7bcbe95 FB |
1125 | /* Integer to float conversion. */ |
1126 | VFP_OP(uito, s) | |
1127 | { | |
53cd6637 | 1128 | FT0s = uint32_to_float32(vfp_stoi(FT0s), &env->vfp.fp_status); |
b7bcbe95 FB |
1129 | } |
1130 | ||
1131 | VFP_OP(uito, d) | |
1132 | { | |
53cd6637 | 1133 | FT0d = uint32_to_float64(vfp_stoi(FT0s), &env->vfp.fp_status); |
b7bcbe95 FB |
1134 | } |
1135 | ||
1136 | VFP_OP(sito, s) | |
1137 | { | |
53cd6637 | 1138 | FT0s = int32_to_float32(vfp_stoi(FT0s), &env->vfp.fp_status); |
b7bcbe95 FB |
1139 | } |
1140 | ||
1141 | VFP_OP(sito, d) | |
1142 | { | |
53cd6637 | 1143 | FT0d = int32_to_float64(vfp_stoi(FT0s), &env->vfp.fp_status); |
b7bcbe95 FB |
1144 | } |
1145 | ||
1146 | /* Float to integer conversion. */ | |
1147 | VFP_OP(toui, s) | |
1148 | { | |
53cd6637 | 1149 | FT0s = vfp_itos(float32_to_uint32(FT0s, &env->vfp.fp_status)); |
b7bcbe95 FB |
1150 | } |
1151 | ||
1152 | VFP_OP(toui, d) | |
1153 | { | |
53cd6637 | 1154 | FT0s = vfp_itos(float64_to_uint32(FT0d, &env->vfp.fp_status)); |
b7bcbe95 FB |
1155 | } |
1156 | ||
1157 | VFP_OP(tosi, s) | |
1158 | { | |
53cd6637 | 1159 | FT0s = vfp_itos(float32_to_int32(FT0s, &env->vfp.fp_status)); |
b7bcbe95 FB |
1160 | } |
1161 | ||
1162 | VFP_OP(tosi, d) | |
1163 | { | |
53cd6637 | 1164 | FT0s = vfp_itos(float64_to_int32(FT0d, &env->vfp.fp_status)); |
b7bcbe95 FB |
1165 | } |
1166 | ||
1167 | /* TODO: Set rounding mode properly. */ | |
1168 | VFP_OP(touiz, s) | |
1169 | { | |
53cd6637 | 1170 | FT0s = vfp_itos(float32_to_uint32_round_to_zero(FT0s, &env->vfp.fp_status)); |
b7bcbe95 FB |
1171 | } |
1172 | ||
1173 | VFP_OP(touiz, d) | |
1174 | { | |
53cd6637 | 1175 | FT0s = vfp_itos(float64_to_uint32_round_to_zero(FT0d, &env->vfp.fp_status)); |
b7bcbe95 FB |
1176 | } |
1177 | ||
1178 | VFP_OP(tosiz, s) | |
1179 | { | |
53cd6637 | 1180 | FT0s = vfp_itos(float32_to_int32_round_to_zero(FT0s, &env->vfp.fp_status)); |
b7bcbe95 FB |
1181 | } |
1182 | ||
1183 | VFP_OP(tosiz, d) | |
2c0262af | 1184 | { |
53cd6637 | 1185 | FT0s = vfp_itos(float64_to_int32_round_to_zero(FT0d, &env->vfp.fp_status)); |
2c0262af FB |
1186 | } |
1187 | ||
b7bcbe95 FB |
1188 | /* floating point conversion */ |
1189 | VFP_OP(fcvtd, s) | |
2c0262af | 1190 | { |
53cd6637 | 1191 | FT0d = float32_to_float64(FT0s, &env->vfp.fp_status); |
2c0262af FB |
1192 | } |
1193 | ||
b7bcbe95 FB |
1194 | VFP_OP(fcvts, d) |
1195 | { | |
53cd6637 | 1196 | FT0s = float64_to_float32(FT0d, &env->vfp.fp_status); |
b7bcbe95 FB |
1197 | } |
1198 | ||
9ee6e8bb PB |
1199 | /* VFP3 fixed point conversion. */ |
1200 | #define VFP_CONV_FIX(name, p, ftype, itype, sign) \ | |
1201 | VFP_OP(name##to, p) \ | |
1202 | { \ | |
1203 | ftype tmp; \ | |
1204 | tmp = sign##int32_to_##ftype ((itype)vfp_##p##toi(FT0##p), \ | |
1205 | &env->vfp.fp_status); \ | |
1206 | FT0##p = ftype##_scalbn(tmp, PARAM1, &env->vfp.fp_status); \ | |
1207 | } \ | |
1208 | VFP_OP(to##name, p) \ | |
1209 | { \ | |
1210 | ftype tmp; \ | |
1211 | tmp = ftype##_scalbn(FT0##p, PARAM1, &env->vfp.fp_status); \ | |
1212 | FT0##p = vfp_ito##p((itype)ftype##_to_##sign##int32_round_to_zero(tmp, \ | |
1213 | &env->vfp.fp_status)); \ | |
1214 | } | |
1215 | ||
1216 | VFP_CONV_FIX(sh, d, float64, int16, ) | |
1217 | VFP_CONV_FIX(sl, d, float64, int32, ) | |
1218 | VFP_CONV_FIX(uh, d, float64, uint16, u) | |
1219 | VFP_CONV_FIX(ul, d, float64, uint32, u) | |
1220 | VFP_CONV_FIX(sh, s, float32, int16, ) | |
1221 | VFP_CONV_FIX(sl, s, float32, int32, ) | |
1222 | VFP_CONV_FIX(uh, s, float32, uint16, u) | |
1223 | VFP_CONV_FIX(ul, s, float32, uint32, u) | |
1224 | ||
b7bcbe95 FB |
1225 | /* Get and Put values from registers. */ |
1226 | VFP_OP(getreg_F0, d) | |
1227 | { | |
53cd6637 | 1228 | FT0d = *(float64 *)((char *) env + PARAM1); |
b7bcbe95 FB |
1229 | } |
1230 | ||
1231 | VFP_OP(getreg_F0, s) | |
1232 | { | |
53cd6637 | 1233 | FT0s = *(float32 *)((char *) env + PARAM1); |
b7bcbe95 FB |
1234 | } |
1235 | ||
1236 | VFP_OP(getreg_F1, d) | |
1237 | { | |
53cd6637 | 1238 | FT1d = *(float64 *)((char *) env + PARAM1); |
b7bcbe95 FB |
1239 | } |
1240 | ||
1241 | VFP_OP(getreg_F1, s) | |
1242 | { | |
53cd6637 | 1243 | FT1s = *(float32 *)((char *) env + PARAM1); |
b7bcbe95 FB |
1244 | } |
1245 | ||
1246 | VFP_OP(setreg_F0, d) | |
1247 | { | |
53cd6637 | 1248 | *(float64 *)((char *) env + PARAM1) = FT0d; |
b7bcbe95 FB |
1249 | } |
1250 | ||
1251 | VFP_OP(setreg_F0, s) | |
1252 | { | |
53cd6637 | 1253 | *(float32 *)((char *) env + PARAM1) = FT0s; |
b7bcbe95 FB |
1254 | } |
1255 | ||
1256 | void OPPROTO op_vfp_movl_T0_fpscr(void) | |
1257 | { | |
1258 | do_vfp_get_fpscr (); | |
1259 | } | |
1260 | ||
1261 | void OPPROTO op_vfp_movl_T0_fpscr_flags(void) | |
1262 | { | |
40f137e1 | 1263 | T0 = env->vfp.xregs[ARM_VFP_FPSCR] & (0xf << 28); |
b7bcbe95 FB |
1264 | } |
1265 | ||
1266 | void OPPROTO op_vfp_movl_fpscr_T0(void) | |
1267 | { | |
1268 | do_vfp_set_fpscr(); | |
1269 | } | |
1270 | ||
40f137e1 PB |
1271 | void OPPROTO op_vfp_movl_T0_xreg(void) |
1272 | { | |
1273 | T0 = env->vfp.xregs[PARAM1]; | |
1274 | } | |
1275 | ||
1276 | void OPPROTO op_vfp_movl_xreg_T0(void) | |
1277 | { | |
1278 | env->vfp.xregs[PARAM1] = T0; | |
1279 | } | |
1280 | ||
b7bcbe95 FB |
1281 | /* Move between FT0s to T0 */ |
1282 | void OPPROTO op_vfp_mrs(void) | |
1283 | { | |
1284 | T0 = vfp_stoi(FT0s); | |
1285 | } | |
1286 | ||
1287 | void OPPROTO op_vfp_msr(void) | |
1288 | { | |
1289 | FT0s = vfp_itos(T0); | |
1290 | } | |
1291 | ||
1292 | /* Move between FT0d and {T0,T1} */ | |
1293 | void OPPROTO op_vfp_mrrd(void) | |
1294 | { | |
1295 | CPU_DoubleU u; | |
3b46e624 | 1296 | |
b7bcbe95 FB |
1297 | u.d = FT0d; |
1298 | T0 = u.l.lower; | |
1299 | T1 = u.l.upper; | |
1300 | } | |
1301 | ||
1302 | void OPPROTO op_vfp_mdrr(void) | |
1303 | { | |
1304 | CPU_DoubleU u; | |
3b46e624 | 1305 | |
b7bcbe95 FB |
1306 | u.l.lower = T0; |
1307 | u.l.upper = T1; | |
1308 | FT0d = u.d; | |
1309 | } | |
1310 | ||
9ee6e8bb PB |
1311 | /* Load immediate. PARAM1 is the 32 most significant bits of the value. */ |
1312 | void OPPROTO op_vfp_fconstd(void) | |
1313 | { | |
1314 | CPU_DoubleU u; | |
1315 | u.l.upper = PARAM1; | |
1316 | u.l.lower = 0; | |
1317 | FT0d = u.d; | |
1318 | } | |
1319 | ||
1320 | void OPPROTO op_vfp_fconsts(void) | |
1321 | { | |
1322 | FT0s = vfp_itos(PARAM1); | |
1323 | } | |
1324 | ||
c1713132 | 1325 | /* Copy the most significant bit of T0 to all bits of T1. */ |
b5ff1b31 | 1326 | void OPPROTO op_signbit_T1_T0(void) |
b7bcbe95 | 1327 | { |
b5ff1b31 | 1328 | T1 = (int32_t)T0 >> 31; |
b7bcbe95 FB |
1329 | } |
1330 | ||
c1713132 AZ |
1331 | void OPPROTO op_movl_cp_T0(void) |
1332 | { | |
1333 | helper_set_cp(env, PARAM1, T0); | |
1334 | FORCE_RET(); | |
1335 | } | |
1336 | ||
1337 | void OPPROTO op_movl_T0_cp(void) | |
1338 | { | |
1339 | T0 = helper_get_cp(env, PARAM1); | |
1340 | FORCE_RET(); | |
1341 | } | |
1342 | ||
b5ff1b31 | 1343 | void OPPROTO op_movl_cp15_T0(void) |
b7bcbe95 | 1344 | { |
b5ff1b31 FB |
1345 | helper_set_cp15(env, PARAM1, T0); |
1346 | FORCE_RET(); | |
b7bcbe95 FB |
1347 | } |
1348 | ||
b5ff1b31 | 1349 | void OPPROTO op_movl_T0_cp15(void) |
b7bcbe95 | 1350 | { |
b5ff1b31 FB |
1351 | T0 = helper_get_cp15(env, PARAM1); |
1352 | FORCE_RET(); | |
b7bcbe95 FB |
1353 | } |
1354 | ||
b5ff1b31 FB |
1355 | /* Access to user mode registers from privileged modes. */ |
1356 | void OPPROTO op_movl_T0_user(void) | |
b7bcbe95 | 1357 | { |
b5ff1b31 FB |
1358 | int regno = PARAM1; |
1359 | if (regno == 13) { | |
1360 | T0 = env->banked_r13[0]; | |
1361 | } else if (regno == 14) { | |
1362 | T0 = env->banked_r14[0]; | |
1363 | } else if ((env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) { | |
1364 | T0 = env->usr_regs[regno - 8]; | |
1365 | } else { | |
1366 | T0 = env->regs[regno]; | |
1367 | } | |
1368 | FORCE_RET(); | |
1369 | } | |
1370 | ||
1371 | ||
1372 | void OPPROTO op_movl_user_T0(void) | |
1373 | { | |
1374 | int regno = PARAM1; | |
1375 | if (regno == 13) { | |
1376 | env->banked_r13[0] = T0; | |
1377 | } else if (regno == 14) { | |
1378 | env->banked_r14[0] = T0; | |
1379 | } else if ((env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) { | |
1380 | env->usr_regs[regno - 8] = T0; | |
1381 | } else { | |
1382 | env->regs[regno] = T0; | |
1383 | } | |
1384 | FORCE_RET(); | |
b7bcbe95 | 1385 | } |
191abaa2 | 1386 | |
9ee6e8bb | 1387 | void OPPROTO op_movl_T0_T1(void) |
191abaa2 | 1388 | { |
9ee6e8bb | 1389 | T0 = T1; |
191abaa2 PB |
1390 | } |
1391 | ||
1392 | void OPPROTO op_movl_T0_T2(void) | |
1393 | { | |
1394 | T0 = T2; | |
1395 | } | |
18c9b560 | 1396 | |
9ee6e8bb PB |
1397 | void OPPROTO op_movl_T1_T0(void) |
1398 | { | |
1399 | T1 = T0; | |
1400 | } | |
1401 | ||
1402 | void OPPROTO op_movl_T1_T2(void) | |
1403 | { | |
1404 | T1 = T2; | |
1405 | } | |
1406 | ||
1407 | void OPPROTO op_movl_T2_T0(void) | |
1408 | { | |
1409 | T2 = T0; | |
1410 | } | |
1411 | ||
1412 | /* ARMv6 Media instructions. */ | |
1413 | ||
1414 | /* Note that signed overflow is undefined in C. The following routines are | |
1415 | careful to use unsigned types where modulo arithmetic is required. | |
1416 | Failure to do so _will_ break on newer gcc. */ | |
1417 | ||
1418 | /* Signed saturating arithmetic. */ | |
1419 | ||
1420 | /* Perform 16-bit signed satruating addition. */ | |
1421 | static inline uint16_t add16_sat(uint16_t a, uint16_t b) | |
1422 | { | |
1423 | uint16_t res; | |
1424 | ||
1425 | res = a + b; | |
1426 | if (((res ^ a) & 0x8000) && !((a ^ b) & 0x8000)) { | |
1427 | if (a & 0x8000) | |
1428 | res = 0x8000; | |
1429 | else | |
1430 | res = 0x7fff; | |
1431 | } | |
1432 | return res; | |
1433 | } | |
1434 | ||
1435 | /* Perform 8-bit signed satruating addition. */ | |
1436 | static inline uint8_t add8_sat(uint8_t a, uint8_t b) | |
1437 | { | |
1438 | uint8_t res; | |
1439 | ||
1440 | res = a + b; | |
1441 | if (((res ^ a) & 0x80) && !((a ^ b) & 0x80)) { | |
1442 | if (a & 0x80) | |
1443 | res = 0x80; | |
1444 | else | |
1445 | res = 0x7f; | |
1446 | } | |
1447 | return res; | |
1448 | } | |
1449 | ||
1450 | /* Perform 16-bit signed satruating subtraction. */ | |
1451 | static inline uint16_t sub16_sat(uint16_t a, uint16_t b) | |
1452 | { | |
1453 | uint16_t res; | |
1454 | ||
1455 | res = a - b; | |
1456 | if (((res ^ a) & 0x8000) && ((a ^ b) & 0x8000)) { | |
1457 | if (a & 0x8000) | |
1458 | res = 0x8000; | |
1459 | else | |
1460 | res = 0x7fff; | |
1461 | } | |
1462 | return res; | |
1463 | } | |
1464 | ||
1465 | /* Perform 8-bit signed satruating subtraction. */ | |
1466 | static inline uint8_t sub8_sat(uint8_t a, uint8_t b) | |
1467 | { | |
1468 | uint8_t res; | |
1469 | ||
1470 | res = a - b; | |
1471 | if (((res ^ a) & 0x80) && ((a ^ b) & 0x80)) { | |
1472 | if (a & 0x80) | |
1473 | res = 0x80; | |
1474 | else | |
1475 | res = 0x7f; | |
1476 | } | |
1477 | return res; | |
1478 | } | |
1479 | ||
1480 | #define ADD16(a, b, n) RESULT(add16_sat(a, b), n, 16); | |
1481 | #define SUB16(a, b, n) RESULT(sub16_sat(a, b), n, 16); | |
1482 | #define ADD8(a, b, n) RESULT(add8_sat(a, b), n, 8); | |
1483 | #define SUB8(a, b, n) RESULT(sub8_sat(a, b), n, 8); | |
1484 | #define PFX q | |
1485 | ||
1486 | #include "op_addsub.h" | |
1487 | ||
1488 | /* Unsigned saturating arithmetic. */ | |
1489 | static inline uint16_t add16_usat(uint16_t a, uint8_t b) | |
1490 | { | |
1491 | uint16_t res; | |
1492 | res = a + b; | |
1493 | if (res < a) | |
1494 | res = 0xffff; | |
1495 | return res; | |
1496 | } | |
1497 | ||
1498 | static inline uint16_t sub16_usat(uint16_t a, uint8_t b) | |
1499 | { | |
1500 | if (a < b) | |
1501 | return a - b; | |
1502 | else | |
1503 | return 0; | |
1504 | } | |
1505 | ||
1506 | static inline uint8_t add8_usat(uint8_t a, uint8_t b) | |
1507 | { | |
1508 | uint8_t res; | |
1509 | res = a + b; | |
1510 | if (res < a) | |
1511 | res = 0xff; | |
1512 | return res; | |
1513 | } | |
1514 | ||
1515 | static inline uint8_t sub8_usat(uint8_t a, uint8_t b) | |
1516 | { | |
1517 | if (a < b) | |
1518 | return a - b; | |
1519 | else | |
1520 | return 0; | |
1521 | } | |
1522 | ||
1523 | #define ADD16(a, b, n) RESULT(add16_usat(a, b), n, 16); | |
1524 | #define SUB16(a, b, n) RESULT(sub16_usat(a, b), n, 16); | |
1525 | #define ADD8(a, b, n) RESULT(add8_usat(a, b), n, 8); | |
1526 | #define SUB8(a, b, n) RESULT(sub8_usat(a, b), n, 8); | |
1527 | #define PFX uq | |
1528 | ||
1529 | #include "op_addsub.h" | |
1530 | ||
1531 | /* Signed modulo arithmetic. */ | |
1532 | #define SARITH16(a, b, n, op) do { \ | |
1533 | int32_t sum; \ | |
1534 | sum = (int16_t)((uint16_t)(a) op (uint16_t)(b)); \ | |
1535 | RESULT(sum, n, 16); \ | |
1536 | if (sum >= 0) \ | |
1537 | ge |= 3 << (n * 2); \ | |
1538 | } while(0) | |
1539 | ||
1540 | #define SARITH8(a, b, n, op) do { \ | |
1541 | int32_t sum; \ | |
1542 | sum = (int8_t)((uint8_t)(a) op (uint8_t)(b)); \ | |
1543 | RESULT(sum, n, 8); \ | |
1544 | if (sum >= 0) \ | |
1545 | ge |= 1 << n; \ | |
1546 | } while(0) | |
1547 | ||
1548 | ||
1549 | #define ADD16(a, b, n) SARITH16(a, b, n, +) | |
1550 | #define SUB16(a, b, n) SARITH16(a, b, n, -) | |
1551 | #define ADD8(a, b, n) SARITH8(a, b, n, +) | |
1552 | #define SUB8(a, b, n) SARITH8(a, b, n, -) | |
1553 | #define PFX s | |
1554 | #define ARITH_GE | |
1555 | ||
1556 | #include "op_addsub.h" | |
1557 | ||
1558 | /* Unsigned modulo arithmetic. */ | |
1559 | #define ADD16(a, b, n) do { \ | |
1560 | uint32_t sum; \ | |
1561 | sum = (uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b); \ | |
1562 | RESULT(sum, n, 16); \ | |
1563 | if ((sum >> 16) == 0) \ | |
1564 | ge |= 3 << (n * 2); \ | |
1565 | } while(0) | |
1566 | ||
1567 | #define ADD8(a, b, n) do { \ | |
1568 | uint32_t sum; \ | |
1569 | sum = (uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b); \ | |
1570 | RESULT(sum, n, 8); \ | |
1571 | if ((sum >> 8) == 0) \ | |
1572 | ge |= 3 << (n * 2); \ | |
1573 | } while(0) | |
1574 | ||
1575 | #define SUB16(a, b, n) do { \ | |
1576 | uint32_t sum; \ | |
1577 | sum = (uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b); \ | |
1578 | RESULT(sum, n, 16); \ | |
1579 | if ((sum >> 16) == 0) \ | |
1580 | ge |= 3 << (n * 2); \ | |
1581 | } while(0) | |
1582 | ||
1583 | #define SUB8(a, b, n) do { \ | |
1584 | uint32_t sum; \ | |
1585 | sum = (uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b); \ | |
1586 | RESULT(sum, n, 8); \ | |
1587 | if ((sum >> 8) == 0) \ | |
1588 | ge |= 3 << (n * 2); \ | |
1589 | } while(0) | |
1590 | ||
1591 | #define PFX u | |
1592 | #define ARITH_GE | |
1593 | ||
1594 | #include "op_addsub.h" | |
1595 | ||
1596 | /* Halved signed arithmetic. */ | |
1597 | #define ADD16(a, b, n) \ | |
1598 | RESULT(((int32_t)(int16_t)(a) + (int32_t)(int16_t)(b)) >> 1, n, 16) | |
1599 | #define SUB16(a, b, n) \ | |
1600 | RESULT(((int32_t)(int16_t)(a) - (int32_t)(int16_t)(b)) >> 1, n, 16) | |
1601 | #define ADD8(a, b, n) \ | |
1602 | RESULT(((int32_t)(int8_t)(a) + (int32_t)(int8_t)(b)) >> 1, n, 8) | |
1603 | #define SUB8(a, b, n) \ | |
1604 | RESULT(((int32_t)(int8_t)(a) - (int32_t)(int8_t)(b)) >> 1, n, 8) | |
1605 | #define PFX sh | |
1606 | ||
1607 | #include "op_addsub.h" | |
1608 | ||
1609 | /* Halved unsigned arithmetic. */ | |
1610 | #define ADD16(a, b, n) \ | |
1611 | RESULT(((uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b)) >> 1, n, 16) | |
1612 | #define SUB16(a, b, n) \ | |
1613 | RESULT(((uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b)) >> 1, n, 16) | |
1614 | #define ADD8(a, b, n) \ | |
1615 | RESULT(((uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b)) >> 1, n, 8) | |
1616 | #define SUB8(a, b, n) \ | |
1617 | RESULT(((uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b)) >> 1, n, 8) | |
1618 | #define PFX uh | |
1619 | ||
1620 | #include "op_addsub.h" | |
1621 | ||
1622 | void OPPROTO op_pkhtb_T0_T1(void) | |
1623 | { | |
1624 | T0 = (T0 & 0xffff0000) | (T1 & 0xffff); | |
1625 | } | |
1626 | ||
1627 | void OPPROTO op_pkhbt_T0_T1(void) | |
1628 | { | |
1629 | T0 = (T0 & 0xffff) | (T1 & 0xffff0000); | |
1630 | } | |
1631 | void OPPROTO op_rev_T0(void) | |
1632 | { | |
1633 | T0 = ((T0 & 0xff000000) >> 24) | |
1634 | | ((T0 & 0x00ff0000) >> 8) | |
1635 | | ((T0 & 0x0000ff00) << 8) | |
1636 | | ((T0 & 0x000000ff) << 24); | |
1637 | } | |
1638 | ||
1639 | void OPPROTO op_revh_T0(void) | |
1640 | { | |
1641 | T0 = (T0 >> 16) | (T0 << 16); | |
1642 | } | |
1643 | ||
1644 | void OPPROTO op_rev16_T0(void) | |
1645 | { | |
1646 | T0 = ((T0 & 0xff000000) >> 8) | |
1647 | | ((T0 & 0x00ff0000) << 8) | |
1648 | | ((T0 & 0x0000ff00) >> 8) | |
1649 | | ((T0 & 0x000000ff) << 8); | |
1650 | } | |
1651 | ||
1652 | void OPPROTO op_revsh_T0(void) | |
1653 | { | |
1654 | T0 = (int16_t)( ((T0 & 0x0000ff00) >> 8) | |
1655 | | ((T0 & 0x000000ff) << 8)); | |
1656 | } | |
1657 | ||
1658 | void OPPROTO op_rbit_T0(void) | |
1659 | { | |
1660 | T0 = ((T0 & 0xff000000) >> 24) | |
1661 | | ((T0 & 0x00ff0000) >> 8) | |
1662 | | ((T0 & 0x0000ff00) << 8) | |
1663 | | ((T0 & 0x000000ff) << 24); | |
1664 | T0 = ((T0 & 0xf0f0f0f0) >> 4) | |
1665 | | ((T0 & 0x0f0f0f0f) << 4); | |
1666 | T0 = ((T0 & 0x88888888) >> 3) | |
1667 | | ((T0 & 0x44444444) >> 1) | |
1668 | | ((T0 & 0x22222222) << 1) | |
1669 | | ((T0 & 0x11111111) << 3); | |
1670 | } | |
1671 | ||
1672 | /* Swap low and high halfwords. */ | |
1673 | void OPPROTO op_swap_half_T1(void) | |
1674 | { | |
1675 | T1 = (T1 >> 16) | (T1 << 16); | |
1676 | FORCE_RET(); | |
1677 | } | |
1678 | ||
1679 | /* Dual 16-bit signed multiply. */ | |
1680 | void OPPROTO op_mul_dual_T0_T1(void) | |
1681 | { | |
1682 | int32_t low; | |
1683 | int32_t high; | |
1684 | low = (int32_t)(int16_t)T0 * (int32_t)(int16_t)T1; | |
1685 | high = (((int32_t)T0) >> 16) * (((int32_t)T1) >> 16); | |
1686 | T0 = low; | |
1687 | T1 = high; | |
1688 | } | |
1689 | ||
1690 | void OPPROTO op_sel_T0_T1(void) | |
1691 | { | |
1692 | uint32_t mask; | |
1693 | uint32_t flags; | |
1694 | ||
1695 | flags = env->GE; | |
1696 | mask = 0; | |
1697 | if (flags & 1) | |
1698 | mask |= 0xff; | |
1699 | if (flags & 2) | |
1700 | mask |= 0xff00; | |
1701 | if (flags & 4) | |
1702 | mask |= 0xff0000; | |
1703 | if (flags & 8) | |
1704 | mask |= 0xff000000; | |
1705 | T0 = (T0 & mask) | (T1 & ~mask); | |
1706 | FORCE_RET(); | |
1707 | } | |
1708 | ||
1709 | void OPPROTO op_roundqd_T0_T1(void) | |
1710 | { | |
1711 | T0 = T1 + ((uint32_t)T0 >> 31); | |
1712 | } | |
1713 | ||
1714 | /* Signed saturation. */ | |
1715 | static inline uint32_t do_ssat(int32_t val, int shift) | |
1716 | { | |
1717 | int32_t top; | |
1718 | uint32_t mask; | |
1719 | ||
1720 | shift = PARAM1; | |
1721 | top = val >> shift; | |
1722 | mask = (1u << shift) - 1; | |
1723 | if (top > 0) { | |
1724 | env->QF = 1; | |
1725 | return mask; | |
1726 | } else if (top < -1) { | |
1727 | env->QF = 1; | |
1728 | return ~mask; | |
1729 | } | |
1730 | return val; | |
1731 | } | |
1732 | ||
1733 | /* Unsigned saturation. */ | |
1734 | static inline uint32_t do_usat(int32_t val, int shift) | |
1735 | { | |
1736 | uint32_t max; | |
1737 | ||
1738 | shift = PARAM1; | |
1739 | max = (1u << shift) - 1; | |
1740 | if (val < 0) { | |
1741 | env->QF = 1; | |
1742 | return 0; | |
1743 | } else if (val > max) { | |
1744 | env->QF = 1; | |
1745 | return max; | |
1746 | } | |
1747 | return val; | |
1748 | } | |
1749 | ||
1750 | /* Signed saturate. */ | |
1751 | void OPPROTO op_ssat_T1(void) | |
1752 | { | |
1753 | T0 = do_ssat(T0, PARAM1); | |
1754 | FORCE_RET(); | |
1755 | } | |
1756 | ||
1757 | /* Dual halfword signed saturate. */ | |
1758 | void OPPROTO op_ssat16_T1(void) | |
1759 | { | |
1760 | uint32_t res; | |
1761 | ||
1762 | res = (uint16_t)do_ssat((int16_t)T0, PARAM1); | |
1763 | res |= do_ssat(((int32_t)T0) >> 16, PARAM1) << 16; | |
1764 | T0 = res; | |
1765 | FORCE_RET(); | |
1766 | } | |
1767 | ||
1768 | /* Unsigned saturate. */ | |
1769 | void OPPROTO op_usat_T1(void) | |
1770 | { | |
1771 | T0 = do_usat(T0, PARAM1); | |
1772 | FORCE_RET(); | |
1773 | } | |
1774 | ||
1775 | /* Dual halfword unsigned saturate. */ | |
1776 | void OPPROTO op_usat16_T1(void) | |
1777 | { | |
1778 | uint32_t res; | |
1779 | ||
1780 | res = (uint16_t)do_usat((int16_t)T0, PARAM1); | |
1781 | res |= do_usat(((int32_t)T0) >> 16, PARAM1) << 16; | |
1782 | T0 = res; | |
1783 | FORCE_RET(); | |
1784 | } | |
1785 | ||
1786 | /* Dual 16-bit add. */ | |
1787 | void OPPROTO op_add16_T1_T2(void) | |
1788 | { | |
1789 | uint32_t mask; | |
1790 | mask = (T0 & T1) & 0x8000; | |
1791 | T0 ^= ~0x8000; | |
1792 | T1 ^= ~0x8000; | |
1793 | T0 = (T0 + T1) ^ mask; | |
1794 | } | |
1795 | ||
1796 | static inline uint8_t do_usad(uint8_t a, uint8_t b) | |
1797 | { | |
1798 | if (a > b) | |
1799 | return a - b; | |
1800 | else | |
1801 | return b - a; | |
1802 | } | |
1803 | ||
1804 | /* Unsigned sum of absolute byte differences. */ | |
1805 | void OPPROTO op_usad8_T0_T1(void) | |
1806 | { | |
1807 | uint32_t sum; | |
1808 | sum = do_usad(T0, T1); | |
1809 | sum += do_usad(T0 >> 8, T1 >> 8); | |
1810 | sum += do_usad(T0 >> 16, T1 >>16); | |
1811 | sum += do_usad(T0 >> 24, T1 >> 24); | |
1812 | T0 = sum; | |
1813 | } | |
1814 | ||
1815 | /* Thumb-2 instructions. */ | |
1816 | ||
1817 | /* Insert T1 into T0. Result goes in T1. */ | |
1818 | void OPPROTO op_bfi_T1_T0(void) | |
1819 | { | |
1820 | int shift = PARAM1; | |
1821 | uint32_t mask = PARAM2; | |
1822 | uint32_t bits; | |
1823 | ||
1824 | bits = (T1 << shift) & mask; | |
1825 | T1 = (T0 & ~mask) | bits; | |
1826 | } | |
1827 | ||
1828 | /* Unsigned bitfield extract. */ | |
1829 | void OPPROTO op_ubfx_T1(void) | |
1830 | { | |
1831 | uint32_t shift = PARAM1; | |
1832 | uint32_t mask = PARAM2; | |
1833 | ||
1834 | T1 >>= shift; | |
1835 | T1 &= mask; | |
1836 | } | |
1837 | ||
1838 | /* Signed bitfield extract. */ | |
1839 | void OPPROTO op_sbfx_T1(void) | |
1840 | { | |
1841 | uint32_t shift = PARAM1; | |
1842 | uint32_t width = PARAM2; | |
1843 | int32_t val; | |
1844 | ||
1845 | val = T1 << (32 - (shift + width)); | |
1846 | T1 = val >> (32 - width); | |
1847 | } | |
1848 | ||
1849 | void OPPROTO op_movtop_T0_im(void) | |
1850 | { | |
1851 | T0 = (T0 & 0xffff) | PARAM1; | |
1852 | } | |
1853 | ||
1854 | /* Used by table branch instructions. */ | |
1855 | void OPPROTO op_jmp_T0_im(void) | |
1856 | { | |
1857 | env->regs[15] = PARAM1 + (T0 << 1); | |
1858 | } | |
1859 | ||
1860 | void OPPROTO op_set_condexec(void) | |
1861 | { | |
1862 | env->condexec_bits = PARAM1; | |
1863 | } | |
1864 | ||
1865 | void OPPROTO op_sdivl_T0_T1(void) | |
1866 | { | |
1867 | int32_t num; | |
1868 | int32_t den; | |
1869 | num = T0; | |
1870 | den = T1; | |
1871 | if (den == 0) | |
1872 | T0 = 0; | |
1873 | else | |
1874 | T0 = num / den; | |
1875 | FORCE_RET(); | |
1876 | } | |
1877 | ||
1878 | void OPPROTO op_udivl_T0_T1(void) | |
1879 | { | |
1880 | uint32_t num; | |
1881 | uint32_t den; | |
1882 | num = T0; | |
1883 | den = T1; | |
1884 | if (den == 0) | |
1885 | T0 = 0; | |
1886 | else | |
1887 | T0 = num / den; | |
1888 | FORCE_RET(); | |
1889 | } | |
1890 | ||
1891 | void OPPROTO op_movl_T1_r13_banked(void) | |
1892 | { | |
1893 | T1 = helper_get_r13_banked(env, PARAM1); | |
1894 | } | |
1895 | ||
1896 | void OPPROTO op_movl_r13_T1_banked(void) | |
1897 | { | |
1898 | helper_set_r13_banked(env, PARAM1, T1); | |
1899 | } | |
1900 | ||
1901 | void OPPROTO op_v7m_mrs_T0(void) | |
1902 | { | |
1903 | T0 = helper_v7m_mrs(env, PARAM1); | |
1904 | } | |
1905 | ||
1906 | void OPPROTO op_v7m_msr_T0(void) | |
1907 | { | |
1908 | helper_v7m_msr(env, PARAM1, T0); | |
1909 | } | |
1910 | ||
1911 | void OPPROTO op_movl_T0_sp(void) | |
1912 | { | |
1913 | if (PARAM1 == env->v7m.current_sp) | |
1914 | T0 = env->regs[13]; | |
1915 | else | |
1916 | T0 = env->v7m.other_sp; | |
1917 | FORCE_RET(); | |
1918 | } | |
1919 | ||
1920 | #include "op_neon.h" | |
1921 | ||
18c9b560 AZ |
1922 | /* iwMMXt support */ |
1923 | #include "op_iwmmxt.c" |