]>
Commit | Line | Data |
---|---|---|
2c0262af FB |
1 | /* |
2 | * ARM micro operations | |
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 REGNAME r0 | |
23 | #define REG (env->regs[0]) | |
24 | #include "op_template.h" | |
25 | ||
26 | #define REGNAME r1 | |
27 | #define REG (env->regs[1]) | |
28 | #include "op_template.h" | |
29 | ||
30 | #define REGNAME r2 | |
31 | #define REG (env->regs[2]) | |
32 | #include "op_template.h" | |
33 | ||
34 | #define REGNAME r3 | |
35 | #define REG (env->regs[3]) | |
36 | #include "op_template.h" | |
37 | ||
38 | #define REGNAME r4 | |
39 | #define REG (env->regs[4]) | |
40 | #include "op_template.h" | |
41 | ||
42 | #define REGNAME r5 | |
43 | #define REG (env->regs[5]) | |
44 | #include "op_template.h" | |
45 | ||
46 | #define REGNAME r6 | |
47 | #define REG (env->regs[6]) | |
48 | #include "op_template.h" | |
49 | ||
50 | #define REGNAME r7 | |
51 | #define REG (env->regs[7]) | |
52 | #include "op_template.h" | |
53 | ||
54 | #define REGNAME r8 | |
55 | #define REG (env->regs[8]) | |
56 | #include "op_template.h" | |
57 | ||
58 | #define REGNAME r9 | |
59 | #define REG (env->regs[9]) | |
60 | #include "op_template.h" | |
61 | ||
62 | #define REGNAME r10 | |
63 | #define REG (env->regs[10]) | |
64 | #include "op_template.h" | |
65 | ||
66 | #define REGNAME r11 | |
67 | #define REG (env->regs[11]) | |
68 | #include "op_template.h" | |
69 | ||
70 | #define REGNAME r12 | |
71 | #define REG (env->regs[12]) | |
72 | #include "op_template.h" | |
73 | ||
74 | #define REGNAME r13 | |
75 | #define REG (env->regs[13]) | |
76 | #include "op_template.h" | |
77 | ||
78 | #define REGNAME r14 | |
79 | #define REG (env->regs[14]) | |
80 | #include "op_template.h" | |
81 | ||
82 | #define REGNAME r15 | |
83 | #define REG (env->regs[15]) | |
99c475ab | 84 | #define SET_REG(x) REG = x & ~(uint32_t)1 |
2c0262af FB |
85 | #include "op_template.h" |
86 | ||
99c475ab FB |
87 | void OPPROTO op_bx_T0(void) |
88 | { | |
89 | env->regs[15] = T0 & ~(uint32_t)1; | |
90 | env->thumb = (T0 & 1) != 0; | |
91 | } | |
92 | ||
2c0262af FB |
93 | void OPPROTO op_movl_T0_0(void) |
94 | { | |
95 | T0 = 0; | |
96 | } | |
97 | ||
98 | void OPPROTO op_movl_T0_im(void) | |
99 | { | |
100 | T0 = PARAM1; | |
101 | } | |
102 | ||
103 | void OPPROTO op_movl_T1_im(void) | |
104 | { | |
105 | T1 = PARAM1; | |
106 | } | |
107 | ||
108 | void OPPROTO op_movl_T2_im(void) | |
109 | { | |
110 | T2 = PARAM1; | |
111 | } | |
112 | ||
113 | void OPPROTO op_addl_T1_im(void) | |
114 | { | |
115 | T1 += PARAM1; | |
116 | } | |
117 | ||
118 | void OPPROTO op_addl_T1_T2(void) | |
119 | { | |
120 | T1 += T2; | |
121 | } | |
122 | ||
123 | void OPPROTO op_subl_T1_T2(void) | |
124 | { | |
125 | T1 -= T2; | |
126 | } | |
127 | ||
128 | void OPPROTO op_addl_T0_T1(void) | |
129 | { | |
130 | T0 += T1; | |
131 | } | |
132 | ||
133 | void OPPROTO op_addl_T0_T1_cc(void) | |
134 | { | |
135 | unsigned int src1; | |
136 | src1 = T0; | |
137 | T0 += T1; | |
138 | env->NZF = T0; | |
139 | env->CF = T0 < src1; | |
140 | env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0); | |
141 | } | |
142 | ||
143 | void OPPROTO op_adcl_T0_T1(void) | |
144 | { | |
145 | T0 += T1 + env->CF; | |
146 | } | |
147 | ||
148 | void OPPROTO op_adcl_T0_T1_cc(void) | |
149 | { | |
150 | unsigned int src1; | |
151 | src1 = T0; | |
152 | if (!env->CF) { | |
153 | T0 += T1; | |
154 | env->CF = T0 < src1; | |
155 | } else { | |
156 | T0 += T1 + 1; | |
157 | env->CF = T0 <= src1; | |
158 | } | |
159 | env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0); | |
160 | env->NZF = T0; | |
161 | FORCE_RET(); | |
162 | } | |
163 | ||
164 | #define OPSUB(sub, sbc, res, T0, T1) \ | |
165 | \ | |
166 | void OPPROTO op_ ## sub ## l_T0_T1(void) \ | |
167 | { \ | |
168 | res = T0 - T1; \ | |
169 | } \ | |
170 | \ | |
171 | void OPPROTO op_ ## sub ## l_T0_T1_cc(void) \ | |
172 | { \ | |
173 | unsigned int src1; \ | |
174 | src1 = T0; \ | |
175 | T0 -= T1; \ | |
176 | env->NZF = T0; \ | |
177 | env->CF = src1 >= T1; \ | |
178 | env->VF = (src1 ^ T1) & (src1 ^ T0); \ | |
179 | res = T0; \ | |
180 | } \ | |
181 | \ | |
182 | void OPPROTO op_ ## sbc ## l_T0_T1(void) \ | |
183 | { \ | |
184 | res = T0 - T1 + env->CF - 1; \ | |
185 | } \ | |
186 | \ | |
187 | void OPPROTO op_ ## sbc ## l_T0_T1_cc(void) \ | |
188 | { \ | |
189 | unsigned int src1; \ | |
190 | src1 = T0; \ | |
191 | if (!env->CF) { \ | |
192 | T0 = T0 - T1 - 1; \ | |
193 | env->CF = src1 >= T1; \ | |
194 | } else { \ | |
195 | T0 = T0 - T1; \ | |
196 | env->CF = src1 > T1; \ | |
197 | } \ | |
198 | env->VF = (src1 ^ T1) & (src1 ^ T0); \ | |
199 | env->NZF = T0; \ | |
200 | res = T0; \ | |
201 | FORCE_RET(); \ | |
202 | } | |
203 | ||
204 | OPSUB(sub, sbc, T0, T0, T1) | |
205 | ||
206 | OPSUB(rsb, rsc, T0, T1, T0) | |
207 | ||
208 | void OPPROTO op_andl_T0_T1(void) | |
209 | { | |
210 | T0 &= T1; | |
211 | } | |
212 | ||
213 | void OPPROTO op_xorl_T0_T1(void) | |
214 | { | |
215 | T0 ^= T1; | |
216 | } | |
217 | ||
218 | void OPPROTO op_orl_T0_T1(void) | |
219 | { | |
220 | T0 |= T1; | |
221 | } | |
222 | ||
223 | void OPPROTO op_bicl_T0_T1(void) | |
224 | { | |
225 | T0 &= ~T1; | |
226 | } | |
227 | ||
228 | void OPPROTO op_notl_T1(void) | |
229 | { | |
230 | T1 = ~T1; | |
231 | } | |
232 | ||
233 | void OPPROTO op_logic_T0_cc(void) | |
234 | { | |
235 | env->NZF = T0; | |
236 | } | |
237 | ||
238 | void OPPROTO op_logic_T1_cc(void) | |
239 | { | |
240 | env->NZF = T1; | |
241 | } | |
242 | ||
243 | #define EIP (env->regs[15]) | |
244 | ||
245 | void OPPROTO op_test_eq(void) | |
246 | { | |
247 | if (env->NZF == 0) | |
248 | JUMP_TB(op_test_eq, PARAM1, 0, PARAM2); | |
249 | FORCE_RET(); | |
250 | } | |
251 | ||
252 | void OPPROTO op_test_ne(void) | |
253 | { | |
254 | if (env->NZF != 0) | |
255 | JUMP_TB(op_test_ne, PARAM1, 0, PARAM2); | |
256 | FORCE_RET(); | |
257 | } | |
258 | ||
259 | void OPPROTO op_test_cs(void) | |
260 | { | |
261 | if (env->CF != 0) | |
262 | JUMP_TB(op_test_cs, PARAM1, 0, PARAM2); | |
263 | FORCE_RET(); | |
264 | } | |
265 | ||
266 | void OPPROTO op_test_cc(void) | |
267 | { | |
268 | if (env->CF == 0) | |
269 | JUMP_TB(op_test_cc, PARAM1, 0, PARAM2); | |
270 | FORCE_RET(); | |
271 | } | |
272 | ||
273 | void OPPROTO op_test_mi(void) | |
274 | { | |
275 | if ((env->NZF & 0x80000000) != 0) | |
276 | JUMP_TB(op_test_mi, PARAM1, 0, PARAM2); | |
277 | FORCE_RET(); | |
278 | } | |
279 | ||
280 | void OPPROTO op_test_pl(void) | |
281 | { | |
282 | if ((env->NZF & 0x80000000) == 0) | |
283 | JUMP_TB(op_test_pl, PARAM1, 0, PARAM2); | |
284 | FORCE_RET(); | |
285 | } | |
286 | ||
287 | void OPPROTO op_test_vs(void) | |
288 | { | |
289 | if ((env->VF & 0x80000000) != 0) | |
290 | JUMP_TB(op_test_vs, PARAM1, 0, PARAM2); | |
291 | FORCE_RET(); | |
292 | } | |
293 | ||
294 | void OPPROTO op_test_vc(void) | |
295 | { | |
296 | if ((env->VF & 0x80000000) == 0) | |
297 | JUMP_TB(op_test_vc, PARAM1, 0, PARAM2); | |
298 | FORCE_RET(); | |
299 | } | |
300 | ||
301 | void OPPROTO op_test_hi(void) | |
302 | { | |
303 | if (env->CF != 0 && env->NZF != 0) | |
304 | JUMP_TB(op_test_hi, PARAM1, 0, PARAM2); | |
305 | FORCE_RET(); | |
306 | } | |
307 | ||
308 | void OPPROTO op_test_ls(void) | |
309 | { | |
310 | if (env->CF == 0 || env->NZF == 0) | |
311 | JUMP_TB(op_test_ls, PARAM1, 0, PARAM2); | |
312 | FORCE_RET(); | |
313 | } | |
314 | ||
315 | void OPPROTO op_test_ge(void) | |
316 | { | |
317 | if (((env->VF ^ env->NZF) & 0x80000000) == 0) | |
318 | JUMP_TB(op_test_ge, PARAM1, 0, PARAM2); | |
319 | FORCE_RET(); | |
320 | } | |
321 | ||
322 | void OPPROTO op_test_lt(void) | |
323 | { | |
324 | if (((env->VF ^ env->NZF) & 0x80000000) != 0) | |
325 | JUMP_TB(op_test_lt, PARAM1, 0, PARAM2); | |
326 | FORCE_RET(); | |
327 | } | |
328 | ||
329 | void OPPROTO op_test_gt(void) | |
330 | { | |
331 | if (env->NZF != 0 && ((env->VF ^ env->NZF) & 0x80000000) == 0) | |
332 | JUMP_TB(op_test_gt, PARAM1, 0, PARAM2); | |
333 | FORCE_RET(); | |
334 | } | |
335 | ||
336 | void OPPROTO op_test_le(void) | |
337 | { | |
338 | if (env->NZF == 0 || ((env->VF ^ env->NZF) & 0x80000000) != 0) | |
339 | JUMP_TB(op_test_le, PARAM1, 0, PARAM2); | |
340 | FORCE_RET(); | |
341 | } | |
342 | ||
343 | void OPPROTO op_jmp(void) | |
344 | { | |
345 | JUMP_TB(op_jmp, PARAM1, 1, PARAM2); | |
346 | } | |
347 | ||
348 | void OPPROTO op_exit_tb(void) | |
349 | { | |
350 | EXIT_TB(); | |
351 | } | |
352 | ||
353 | void OPPROTO op_movl_T0_psr(void) | |
354 | { | |
355 | T0 = compute_cpsr(); | |
356 | } | |
357 | ||
358 | /* NOTE: N = 1 and Z = 1 cannot be stored currently */ | |
359 | void OPPROTO op_movl_psr_T0(void) | |
360 | { | |
361 | unsigned int psr; | |
362 | psr = T0; | |
363 | env->CF = (psr >> 29) & 1; | |
364 | env->NZF = (psr & 0xc0000000) ^ 0x40000000; | |
365 | env->VF = (psr << 3) & 0x80000000; | |
366 | /* for user mode we do not update other state info */ | |
367 | } | |
368 | ||
369 | void OPPROTO op_mul_T0_T1(void) | |
370 | { | |
371 | T0 = T0 * T1; | |
372 | } | |
373 | ||
374 | /* 64 bit unsigned mul */ | |
375 | void OPPROTO op_mull_T0_T1(void) | |
376 | { | |
377 | uint64_t res; | |
2e134c9c | 378 | res = (uint64_t)T0 * (uint64_t)T1; |
2c0262af FB |
379 | T1 = res >> 32; |
380 | T0 = res; | |
381 | } | |
382 | ||
383 | /* 64 bit signed mul */ | |
384 | void OPPROTO op_imull_T0_T1(void) | |
385 | { | |
386 | uint64_t res; | |
163a7cb6 | 387 | res = (int64_t)((int32_t)T0) * (int64_t)((int32_t)T1); |
2c0262af FB |
388 | T1 = res >> 32; |
389 | T0 = res; | |
390 | } | |
391 | ||
99c475ab FB |
392 | /* 48 bit signed mul, top 32 bits */ |
393 | void OPPROTO op_imulw_T0_T1(void) | |
394 | { | |
395 | uint64_t res; | |
396 | res = (int64_t)((int32_t)T0) * (int64_t)((int32_t)T1); | |
397 | T0 = res >> 16; | |
398 | } | |
399 | ||
2c0262af FB |
400 | void OPPROTO op_addq_T0_T1(void) |
401 | { | |
402 | uint64_t res; | |
403 | res = ((uint64_t)T1 << 32) | T0; | |
404 | res += ((uint64_t)(env->regs[PARAM2]) << 32) | (env->regs[PARAM1]); | |
405 | T1 = res >> 32; | |
406 | T0 = res; | |
407 | } | |
408 | ||
99c475ab FB |
409 | void OPPROTO op_addq_lo_T0_T1(void) |
410 | { | |
411 | uint64_t res; | |
412 | res = ((uint64_t)T1 << 32) | T0; | |
413 | res += (uint64_t)(env->regs[PARAM1]); | |
414 | T1 = res >> 32; | |
415 | T0 = res; | |
416 | } | |
417 | ||
2c0262af FB |
418 | void OPPROTO op_logicq_cc(void) |
419 | { | |
420 | env->NZF = (T1 & 0x80000000) | ((T0 | T1) != 0); | |
421 | } | |
422 | ||
423 | /* memory access */ | |
424 | ||
425 | void OPPROTO op_ldub_T0_T1(void) | |
426 | { | |
427 | T0 = ldub((void *)T1); | |
428 | } | |
429 | ||
430 | void OPPROTO op_ldsb_T0_T1(void) | |
431 | { | |
432 | T0 = ldsb((void *)T1); | |
433 | } | |
434 | ||
435 | void OPPROTO op_lduw_T0_T1(void) | |
436 | { | |
437 | T0 = lduw((void *)T1); | |
438 | } | |
439 | ||
440 | void OPPROTO op_ldsw_T0_T1(void) | |
441 | { | |
442 | T0 = ldsw((void *)T1); | |
443 | } | |
444 | ||
445 | void OPPROTO op_ldl_T0_T1(void) | |
446 | { | |
447 | T0 = ldl((void *)T1); | |
448 | } | |
449 | ||
450 | void OPPROTO op_stb_T0_T1(void) | |
451 | { | |
452 | stb((void *)T1, T0); | |
453 | } | |
454 | ||
455 | void OPPROTO op_stw_T0_T1(void) | |
456 | { | |
457 | stw((void *)T1, T0); | |
458 | } | |
459 | ||
460 | void OPPROTO op_stl_T0_T1(void) | |
461 | { | |
462 | stl((void *)T1, T0); | |
463 | } | |
464 | ||
465 | void OPPROTO op_swpb_T0_T1(void) | |
466 | { | |
467 | int tmp; | |
468 | ||
469 | cpu_lock(); | |
470 | tmp = ldub((void *)T1); | |
471 | stb((void *)T1, T0); | |
472 | T0 = tmp; | |
473 | cpu_unlock(); | |
474 | } | |
475 | ||
476 | void OPPROTO op_swpl_T0_T1(void) | |
477 | { | |
478 | int tmp; | |
479 | ||
480 | cpu_lock(); | |
481 | tmp = ldl((void *)T1); | |
482 | stl((void *)T1, T0); | |
483 | T0 = tmp; | |
484 | cpu_unlock(); | |
485 | } | |
486 | ||
487 | /* shifts */ | |
488 | ||
489 | /* T1 based */ | |
1e8d4eec | 490 | |
2c0262af FB |
491 | void OPPROTO op_shll_T1_im(void) |
492 | { | |
493 | T1 = T1 << PARAM1; | |
494 | } | |
495 | ||
496 | void OPPROTO op_shrl_T1_im(void) | |
497 | { | |
498 | T1 = (uint32_t)T1 >> PARAM1; | |
499 | } | |
500 | ||
1e8d4eec FB |
501 | void OPPROTO op_shrl_T1_0(void) |
502 | { | |
503 | T1 = 0; | |
504 | } | |
505 | ||
2c0262af FB |
506 | void OPPROTO op_sarl_T1_im(void) |
507 | { | |
508 | T1 = (int32_t)T1 >> PARAM1; | |
509 | } | |
510 | ||
1e8d4eec FB |
511 | void OPPROTO op_sarl_T1_0(void) |
512 | { | |
513 | T1 = (int32_t)T1 >> 31; | |
514 | } | |
515 | ||
2c0262af FB |
516 | void OPPROTO op_rorl_T1_im(void) |
517 | { | |
518 | int shift; | |
519 | shift = PARAM1; | |
520 | T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); | |
521 | } | |
522 | ||
88920f34 FB |
523 | void OPPROTO op_rrxl_T1(void) |
524 | { | |
525 | T1 = ((uint32_t)T1 >> 1) | ((uint32_t)env->CF << 31); | |
526 | } | |
527 | ||
2c0262af FB |
528 | /* T1 based, set C flag */ |
529 | void OPPROTO op_shll_T1_im_cc(void) | |
530 | { | |
531 | env->CF = (T1 >> (32 - PARAM1)) & 1; | |
532 | T1 = T1 << PARAM1; | |
533 | } | |
534 | ||
535 | void OPPROTO op_shrl_T1_im_cc(void) | |
536 | { | |
537 | env->CF = (T1 >> (PARAM1 - 1)) & 1; | |
538 | T1 = (uint32_t)T1 >> PARAM1; | |
539 | } | |
540 | ||
1e8d4eec FB |
541 | void OPPROTO op_shrl_T1_0_cc(void) |
542 | { | |
543 | env->CF = (T1 >> 31) & 1; | |
544 | T1 = 0; | |
545 | } | |
546 | ||
2c0262af FB |
547 | void OPPROTO op_sarl_T1_im_cc(void) |
548 | { | |
549 | env->CF = (T1 >> (PARAM1 - 1)) & 1; | |
550 | T1 = (int32_t)T1 >> PARAM1; | |
551 | } | |
552 | ||
1e8d4eec FB |
553 | void OPPROTO op_sarl_T1_0_cc(void) |
554 | { | |
555 | env->CF = (T1 >> 31) & 1; | |
556 | T1 = (int32_t)T1 >> 31; | |
557 | } | |
558 | ||
2c0262af FB |
559 | void OPPROTO op_rorl_T1_im_cc(void) |
560 | { | |
561 | int shift; | |
562 | shift = PARAM1; | |
563 | env->CF = (T1 >> (shift - 1)) & 1; | |
564 | T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); | |
565 | } | |
566 | ||
88920f34 FB |
567 | void OPPROTO op_rrxl_T1_cc(void) |
568 | { | |
569 | uint32_t c; | |
570 | c = T1 & 1; | |
571 | T1 = ((uint32_t)T1 >> 1) | ((uint32_t)env->CF << 31); | |
572 | env->CF = c; | |
573 | } | |
574 | ||
2c0262af FB |
575 | /* T2 based */ |
576 | void OPPROTO op_shll_T2_im(void) | |
577 | { | |
578 | T2 = T2 << PARAM1; | |
579 | } | |
580 | ||
581 | void OPPROTO op_shrl_T2_im(void) | |
582 | { | |
583 | T2 = (uint32_t)T2 >> PARAM1; | |
584 | } | |
585 | ||
1e8d4eec FB |
586 | void OPPROTO op_shrl_T2_0(void) |
587 | { | |
588 | T2 = 0; | |
589 | } | |
590 | ||
2c0262af FB |
591 | void OPPROTO op_sarl_T2_im(void) |
592 | { | |
593 | T2 = (int32_t)T2 >> PARAM1; | |
594 | } | |
595 | ||
1e8d4eec FB |
596 | void OPPROTO op_sarl_T2_0(void) |
597 | { | |
598 | T2 = (int32_t)T2 >> 31; | |
599 | } | |
600 | ||
2c0262af FB |
601 | void OPPROTO op_rorl_T2_im(void) |
602 | { | |
603 | int shift; | |
604 | shift = PARAM1; | |
605 | T2 = ((uint32_t)T2 >> shift) | (T2 << (32 - shift)); | |
606 | } | |
607 | ||
1e8d4eec FB |
608 | void OPPROTO op_rrxl_T2(void) |
609 | { | |
610 | T2 = ((uint32_t)T2 >> 1) | ((uint32_t)env->CF << 31); | |
611 | } | |
612 | ||
2c0262af FB |
613 | /* T1 based, use T0 as shift count */ |
614 | ||
615 | void OPPROTO op_shll_T1_T0(void) | |
616 | { | |
617 | int shift; | |
618 | shift = T0 & 0xff; | |
619 | if (shift >= 32) | |
620 | T1 = 0; | |
621 | else | |
622 | T1 = T1 << shift; | |
623 | FORCE_RET(); | |
624 | } | |
625 | ||
626 | void OPPROTO op_shrl_T1_T0(void) | |
627 | { | |
628 | int shift; | |
629 | shift = T0 & 0xff; | |
630 | if (shift >= 32) | |
631 | T1 = 0; | |
632 | else | |
633 | T1 = (uint32_t)T1 >> shift; | |
634 | FORCE_RET(); | |
635 | } | |
636 | ||
637 | void OPPROTO op_sarl_T1_T0(void) | |
638 | { | |
639 | int shift; | |
640 | shift = T0 & 0xff; | |
641 | if (shift >= 32) | |
642 | shift = 31; | |
643 | T1 = (int32_t)T1 >> shift; | |
644 | } | |
645 | ||
646 | void OPPROTO op_rorl_T1_T0(void) | |
647 | { | |
648 | int shift; | |
649 | shift = T0 & 0x1f; | |
650 | if (shift) { | |
651 | T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); | |
652 | } | |
653 | FORCE_RET(); | |
654 | } | |
655 | ||
656 | /* T1 based, use T0 as shift count and compute CF */ | |
657 | ||
658 | void OPPROTO op_shll_T1_T0_cc(void) | |
659 | { | |
660 | int shift; | |
661 | shift = T0 & 0xff; | |
662 | if (shift >= 32) { | |
663 | if (shift == 32) | |
664 | env->CF = T1 & 1; | |
665 | else | |
666 | env->CF = 0; | |
667 | T1 = 0; | |
668 | } else if (shift != 0) { | |
669 | env->CF = (T1 >> (32 - shift)) & 1; | |
670 | T1 = T1 << shift; | |
671 | } | |
672 | FORCE_RET(); | |
673 | } | |
674 | ||
675 | void OPPROTO op_shrl_T1_T0_cc(void) | |
676 | { | |
677 | int shift; | |
678 | shift = T0 & 0xff; | |
679 | if (shift >= 32) { | |
680 | if (shift == 32) | |
681 | env->CF = (T1 >> 31) & 1; | |
682 | else | |
683 | env->CF = 0; | |
684 | T1 = 0; | |
685 | } else if (shift != 0) { | |
686 | env->CF = (T1 >> (shift - 1)) & 1; | |
687 | T1 = (uint32_t)T1 >> shift; | |
688 | } | |
689 | FORCE_RET(); | |
690 | } | |
691 | ||
692 | void OPPROTO op_sarl_T1_T0_cc(void) | |
693 | { | |
694 | int shift; | |
695 | shift = T0 & 0xff; | |
696 | if (shift >= 32) { | |
697 | env->CF = (T1 >> 31) & 1; | |
698 | T1 = (int32_t)T1 >> 31; | |
699 | } else { | |
700 | env->CF = (T1 >> (shift - 1)) & 1; | |
701 | T1 = (int32_t)T1 >> shift; | |
702 | } | |
703 | FORCE_RET(); | |
704 | } | |
705 | ||
706 | void OPPROTO op_rorl_T1_T0_cc(void) | |
707 | { | |
708 | int shift1, shift; | |
709 | shift1 = T0 & 0xff; | |
710 | shift = shift1 & 0x1f; | |
711 | if (shift == 0) { | |
712 | if (shift1 != 0) | |
713 | env->CF = (T1 >> 31) & 1; | |
714 | } else { | |
715 | env->CF = (T1 >> (shift - 1)) & 1; | |
716 | T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); | |
717 | } | |
718 | FORCE_RET(); | |
719 | } | |
720 | ||
99c475ab FB |
721 | /* misc */ |
722 | void OPPROTO op_clz_T0(void) | |
723 | { | |
724 | int count; | |
725 | for (count = 32; T0 > 0; count--) | |
726 | T0 = T0 >> 1; | |
727 | T0 = count; | |
728 | FORCE_RET(); | |
729 | } | |
730 | ||
731 | void OPPROTO op_sarl_T0_im(void) | |
732 | { | |
733 | T0 = (int32_t)T0 >> PARAM1; | |
734 | } | |
735 | ||
736 | /* 16->32 Sign extend */ | |
737 | void OPPROTO op_sxl_T0(void) | |
738 | { | |
739 | T0 = (int16_t)T0; | |
740 | } | |
741 | ||
742 | void OPPROTO op_sxl_T1(void) | |
743 | { | |
744 | T1 = (int16_t)T1; | |
745 | } | |
746 | ||
747 | #define SIGNBIT (uint32_t)0x80000000 | |
748 | /* saturating arithmetic */ | |
749 | void OPPROTO op_addl_T0_T1_setq(void) | |
750 | { | |
751 | uint32_t res; | |
752 | ||
753 | res = T0 + T1; | |
754 | if (((res ^ T0) & SIGNBIT) && !((T0 ^ T1) & SIGNBIT)) | |
755 | env->QF = 1; | |
756 | ||
757 | T0 = res; | |
758 | FORCE_RET(); | |
759 | } | |
760 | ||
761 | void OPPROTO op_addl_T0_T1_saturate(void) | |
762 | { | |
763 | uint32_t res; | |
764 | ||
765 | res = T0 + T1; | |
766 | if (((res ^ T0) & SIGNBIT) && !((T0 ^ T1) & SIGNBIT)) { | |
767 | env->QF = 1; | |
768 | if (T0 & SIGNBIT) | |
769 | T0 = 0x80000000; | |
770 | else | |
771 | T0 = 0x7fffffff; | |
772 | } | |
773 | else | |
774 | T0 = res; | |
775 | ||
776 | FORCE_RET(); | |
777 | } | |
778 | ||
779 | void OPPROTO op_subl_T0_T1_saturate(void) | |
780 | { | |
781 | uint32_t res; | |
782 | ||
783 | res = T0 - T1; | |
784 | if (((res ^ T0) & SIGNBIT) && ((T0 ^ T1) & SIGNBIT)) { | |
785 | env->QF = 1; | |
786 | if (T0 & SIGNBIT) | |
787 | T0 = 0x8000000; | |
788 | else | |
789 | T0 = 0x7fffffff; | |
790 | } | |
791 | else | |
792 | T0 = res; | |
793 | ||
794 | FORCE_RET(); | |
795 | } | |
796 | ||
797 | /* thumb shift by immediate */ | |
798 | void OPPROTO op_shll_T0_im_thumb(void) | |
799 | { | |
800 | int shift; | |
801 | shift = PARAM1; | |
802 | if (shift != 0) { | |
803 | env->CF = (T1 >> (32 - shift)) & 1; | |
804 | T0 = T0 << shift; | |
805 | } | |
806 | env->NZF = T0; | |
807 | FORCE_RET(); | |
808 | } | |
809 | ||
810 | void OPPROTO op_shrl_T0_im_thumb(void) | |
811 | { | |
812 | int shift; | |
813 | ||
814 | shift = PARAM1; | |
815 | if (shift == 0) { | |
816 | env->CF = 0; | |
817 | T0 = 0; | |
818 | } else { | |
819 | env->CF = (T0 >> (shift - 1)) & 1; | |
820 | T0 = T0 >> shift; | |
821 | } | |
822 | FORCE_RET(); | |
823 | } | |
824 | ||
825 | void OPPROTO op_sarl_T0_im_thumb(void) | |
826 | { | |
827 | int shift; | |
828 | ||
829 | shift = PARAM1; | |
830 | if (shift == 0) { | |
831 | T0 = ((int32_t)T0) >> 31; | |
832 | env->CF = T0 & 1; | |
833 | } else { | |
834 | env->CF = (T0 >> (shift - 1)) & 1; | |
835 | T0 = ((int32_t)T0) >> shift; | |
836 | } | |
837 | env->NZF = T0; | |
838 | FORCE_RET(); | |
839 | } | |
840 | ||
2c0262af FB |
841 | /* exceptions */ |
842 | ||
843 | void OPPROTO op_swi(void) | |
844 | { | |
845 | env->exception_index = EXCP_SWI; | |
846 | cpu_loop_exit(); | |
847 | } | |
848 | ||
849 | void OPPROTO op_undef_insn(void) | |
850 | { | |
851 | env->exception_index = EXCP_UDEF; | |
852 | cpu_loop_exit(); | |
853 | } | |
854 | ||
855 | /* thread support */ | |
856 | ||
857 | spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; | |
858 | ||
859 | void cpu_lock(void) | |
860 | { | |
861 | spin_lock(&global_cpu_lock); | |
862 | } | |
863 | ||
864 | void cpu_unlock(void) | |
865 | { | |
866 | spin_unlock(&global_cpu_lock); | |
867 | } | |
868 |