SH4: convert simple compare instructions to TCG
[qemu] / target-sh4 / op.c
1 /*
2  *  SH4 emulation
3  *
4  *  Copyright (c) 2005 Samuel Tardieu
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 static inline void set_t(void)
23 {
24     env->sr |= SR_T;
25 }
26
27 static inline void clr_t(void)
28 {
29     env->sr &= ~SR_T;
30 }
31
32 static inline void cond_t(int cond)
33 {
34     if (cond)
35         set_t();
36     else
37         clr_t();
38 }
39
40 void OPPROTO op_bf_s(void)
41 {
42     env->delayed_pc = PARAM1;
43     if (!(env->sr & SR_T)) {
44         env->flags |= DELAY_SLOT_TRUE;
45     }
46     RETURN();
47 }
48
49 void OPPROTO op_bt_s(void)
50 {
51     env->delayed_pc = PARAM1;
52     if (env->sr & SR_T) {
53         env->flags |= DELAY_SLOT_TRUE;
54     }
55     RETURN();
56 }
57
58 void OPPROTO op_store_flags(void)
59 {
60     env->flags &= DELAY_SLOT_TRUE;
61     env->flags |= PARAM1;
62     RETURN();
63 }
64
65 void OPPROTO op_bra(void)
66 {
67     env->delayed_pc = PARAM1;
68     RETURN();
69 }
70
71 void OPPROTO op_braf_T0(void)
72 {
73     env->delayed_pc = PARAM1 + T0;
74     RETURN();
75 }
76
77 void OPPROTO op_bsr(void)
78 {
79     env->pr = PARAM1;
80     env->delayed_pc = PARAM2;
81     RETURN();
82 }
83
84 void OPPROTO op_bsrf_T0(void)
85 {
86     env->pr = PARAM1;
87     env->delayed_pc = PARAM1 + T0;
88     RETURN();
89 }
90
91 void OPPROTO op_jsr_T0(void)
92 {
93     env->pr = PARAM1;
94     env->delayed_pc = T0;
95     RETURN();
96 }
97
98 void OPPROTO op_rts(void)
99 {
100     env->delayed_pc = env->pr;
101     RETURN();
102 }
103
104 void OPPROTO op_ldtlb(void)
105 {
106     helper_ldtlb();
107     RETURN();
108 }
109
110 void OPPROTO op_frchg(void)
111 {
112     env->fpscr ^= FPSCR_FR;
113     RETURN();
114 }
115
116 void OPPROTO op_fschg(void)
117 {
118     env->fpscr ^= FPSCR_SZ;
119     RETURN();
120 }
121
122 void OPPROTO op_rte(void)
123 {
124     env->sr = env->ssr;
125     env->delayed_pc = env->spc;
126     RETURN();
127 }
128
129 void OPPROTO op_addc_T0_T1(void)
130 {
131     helper_addc_T0_T1();
132     RETURN();
133 }
134
135 void OPPROTO op_addv_T0_T1(void)
136 {
137     helper_addv_T0_T1();
138     RETURN();
139 }
140
141 void OPPROTO op_cmp_str_T0_T1(void)
142 {
143     cond_t((T0 & 0x000000ff) == (T1 & 0x000000ff) ||
144            (T0 & 0x0000ff00) == (T1 & 0x0000ff00) ||
145            (T0 & 0x00ff0000) == (T1 & 0x00ff0000) ||
146            (T0 & 0xff000000) == (T1 & 0xff000000));
147     RETURN();
148 }
149
150 void OPPROTO op_div0s_T0_T1(void)
151 {
152     if (T1 & 0x80000000)
153         env->sr |= SR_Q;
154     else
155         env->sr &= ~SR_Q;
156     if (T0 & 0x80000000)
157         env->sr |= SR_M;
158     else
159         env->sr &= ~SR_M;
160     cond_t((T1 ^ T0) & 0x80000000);
161     RETURN();
162 }
163
164 void OPPROTO op_div1_T0_T1(void)
165 {
166     helper_div1_T0_T1();
167     RETURN();
168 }
169
170 void OPPROTO op_dmulsl_T0_T1(void)
171 {
172     helper_dmulsl_T0_T1();
173     RETURN();
174 }
175
176 void OPPROTO op_dmulul_T0_T1(void)
177 {
178     helper_dmulul_T0_T1();
179     RETURN();
180 }
181
182 void OPPROTO op_macl_T0_T1(void)
183 {
184     helper_macl_T0_T1();
185     RETURN();
186 }
187
188 void OPPROTO op_macw_T0_T1(void)
189 {
190     helper_macw_T0_T1();
191     RETURN();
192 }
193
194 void OPPROTO op_mull_T0_T1(void)
195 {
196     env->macl = (T0 * T1) & 0xffffffff;
197     RETURN();
198 }
199
200 void OPPROTO op_mulsw_T0_T1(void)
201 {
202     env->macl = (int32_t)(int16_t) T0 *(int32_t)(int16_t) T1;
203     RETURN();
204 }
205
206 void OPPROTO op_muluw_T0_T1(void)
207 {
208     env->macl = (uint32_t)(uint16_t) T0 *(uint32_t)(uint16_t) T1;
209     RETURN();
210 }
211
212 void OPPROTO op_negc_T0(void)
213 {
214     helper_negc_T0();
215     RETURN();
216 }
217
218 void OPPROTO op_shad_T0_T1(void)
219 {
220     if ((T0 & 0x80000000) == 0)
221         T1 <<= (T0 & 0x1f);
222     else if ((T0 & 0x1f) == 0)
223         T1 = (T1 & 0x80000000)? 0xffffffff : 0;
224     else
225         T1 = ((int32_t) T1) >> ((~T0 & 0x1f) + 1);
226     RETURN();
227 }
228
229 void OPPROTO op_shld_T0_T1(void)
230 {
231     if ((T0 & 0x80000000) == 0)
232         T1 <<= (T0 & 0x1f);
233     else if ((T0 & 0x1f) == 0)
234         T1 = 0;
235     else
236         T1 = ((uint32_t) T1) >> ((~T0 & 0x1f) + 1);
237     RETURN();
238 }
239
240 void OPPROTO op_subc_T0_T1(void)
241 {
242     helper_subc_T0_T1();
243     RETURN();
244 }
245
246 void OPPROTO op_subv_T0_T1(void)
247 {
248     helper_subv_T0_T1();
249     RETURN();
250 }
251
252 void OPPROTO op_trapa(void)
253 {
254     env->tra = PARAM1 << 2;
255     env->exception_index = 0x160;
256     do_raise_exception();
257     RETURN();
258 }
259
260 void OPPROTO op_jmp_T0(void)
261 {
262     env->delayed_pc = T0;
263     RETURN();
264 }
265
266 void OPPROTO op_ldcl_rMplus_rN_bank(void)
267 {
268     env->gregs[PARAM2] = env->gregs[PARAM1];
269     env->gregs[PARAM1] += 4;
270     RETURN();
271 }
272
273 void OPPROTO op_ldc_T0_sr(void)
274 {
275     env->sr = T0 & 0x700083f3;
276     RETURN();
277 }
278
279 void OPPROTO op_stc_sr_T0(void)
280 {
281     T0 = env->sr;
282     RETURN();
283 }
284
285 #define LDSTOPS(target,load,store) \
286 void OPPROTO op_##load##_T0_##target (void) \
287 { env ->target = T0;   RETURN(); \
288 } \
289 void OPPROTO op_##store##_##target##_T0 (void) \
290 { T0 = env->target;   RETURN(); \
291 } \
292
293     LDSTOPS(gbr, ldc, stc)
294     LDSTOPS(vbr, ldc, stc)
295     LDSTOPS(ssr, ldc, stc)
296     LDSTOPS(spc, ldc, stc)
297     LDSTOPS(sgr, ldc, stc)
298     LDSTOPS(dbr, ldc, stc)
299     LDSTOPS(mach, lds, sts)
300     LDSTOPS(macl, lds, sts)
301     LDSTOPS(pr, lds, sts)
302     LDSTOPS(fpul, lds, sts)
303
304 void OPPROTO op_lds_T0_fpscr(void)
305 {
306     env->fpscr = T0 & 0x003fffff;
307     env->fp_status.float_rounding_mode = T0 & 0x01 ?
308       float_round_to_zero : float_round_nearest_even;
309
310     RETURN();
311 }
312
313 void OPPROTO op_sts_fpscr_T0(void)
314 {
315     T0 = env->fpscr & 0x003fffff;
316     RETURN();
317 }
318
319 void OPPROTO op_rotcl_Rn(void)
320 {
321     helper_rotcl(&env->gregs[PARAM1]);
322     RETURN();
323 }
324
325 void OPPROTO op_rotcr_Rn(void)
326 {
327     helper_rotcr(&env->gregs[PARAM1]);
328     RETURN();
329 }
330
331 void OPPROTO op_rotl_Rn(void)
332 {
333     cond_t(env->gregs[PARAM1] & 0x80000000);
334     env->gregs[PARAM1] = (env->gregs[PARAM1] << 1) | (env->sr & SR_T);
335     RETURN();
336 }
337
338 void OPPROTO op_rotr_Rn(void)
339 {
340     cond_t(env->gregs[PARAM1] & 1);
341     env->gregs[PARAM1] = (env->gregs[PARAM1] >> 1) |
342         ((env->sr & SR_T) ? 0x80000000 : 0);
343     RETURN();
344 }
345
346 void OPPROTO op_shal_Rn(void)
347 {
348     cond_t(env->gregs[PARAM1] & 0x80000000);
349     env->gregs[PARAM1] <<= 1;
350     RETURN();
351 }
352
353 void OPPROTO op_shar_Rn(void)
354 {
355     cond_t(env->gregs[PARAM1] & 1);
356     *(int32_t *)&env->gregs[PARAM1] >>= 1;
357     RETURN();
358 }
359
360 void OPPROTO op_shlr_Rn(void)
361 {
362     cond_t(env->gregs[PARAM1] & 1);
363     env->gregs[PARAM1] >>= 1;
364     RETURN();
365 }
366
367 void OPPROTO op_fmov_frN_FT0(void)
368 {
369     FT0 = env->fregs[PARAM1];
370     RETURN();
371 }
372
373 void OPPROTO op_fmov_drN_DT0(void)
374 {
375     CPU_DoubleU d;
376
377     d.l.upper = *(uint32_t *)&env->fregs[PARAM1];
378     d.l.lower = *(uint32_t *)&env->fregs[PARAM1 + 1];
379     DT0 = d.d;
380     RETURN();
381 }
382
383 void OPPROTO op_fmov_frN_FT1(void)
384 {
385     FT1 = env->fregs[PARAM1];
386     RETURN();
387 }
388
389 void OPPROTO op_fmov_drN_DT1(void)
390 {
391     CPU_DoubleU d;
392
393     d.l.upper = *(uint32_t *)&env->fregs[PARAM1];
394     d.l.lower = *(uint32_t *)&env->fregs[PARAM1 + 1];
395     DT1 = d.d;
396     RETURN();
397 }
398
399 void OPPROTO op_fmov_FT0_frN(void)
400 {
401     env->fregs[PARAM1] = FT0;
402     RETURN();
403 }
404
405 void OPPROTO op_fmov_DT0_drN(void)
406 {
407     CPU_DoubleU d;
408
409     d.d = DT0;
410     *(uint32_t *)&env->fregs[PARAM1] = d.l.upper;
411     *(uint32_t *)&env->fregs[PARAM1 + 1] = d.l.lower;
412     RETURN();
413 }
414
415 void OPPROTO op_fadd_FT(void)
416 {
417     FT0 = float32_add(FT0, FT1, &env->fp_status);
418     RETURN();
419 }
420
421 void OPPROTO op_fadd_DT(void)
422 {
423     DT0 = float64_add(DT0, DT1, &env->fp_status);
424     RETURN();
425 }
426
427 void OPPROTO op_fsub_FT(void)
428 {
429     FT0 = float32_sub(FT0, FT1, &env->fp_status);
430     RETURN();
431 }
432
433 void OPPROTO op_fsub_DT(void)
434 {
435     DT0 = float64_sub(DT0, DT1, &env->fp_status);
436     RETURN();
437 }
438
439 void OPPROTO op_fmul_FT(void)
440 {
441     FT0 = float32_mul(FT0, FT1, &env->fp_status);
442     RETURN();
443 }
444
445 void OPPROTO op_fmul_DT(void)
446 {
447     DT0 = float64_mul(DT0, DT1, &env->fp_status);
448     RETURN();
449 }
450
451 void OPPROTO op_fdiv_FT(void)
452 {
453     FT0 = float32_div(FT0, FT1, &env->fp_status);
454     RETURN();
455 }
456
457 void OPPROTO op_fdiv_DT(void)
458 {
459     DT0 = float64_div(DT0, DT1, &env->fp_status);
460     RETURN();
461 }
462
463 void OPPROTO op_fcmp_eq_FT(void)
464 {
465     cond_t(float32_compare(FT0, FT1, &env->fp_status) == 0);
466     RETURN();
467 }
468
469 void OPPROTO op_fcmp_eq_DT(void)
470 {
471     cond_t(float64_compare(DT0, DT1, &env->fp_status) == 0);
472     RETURN();
473 }
474
475 void OPPROTO op_fcmp_gt_FT(void)
476 {
477     cond_t(float32_compare(FT0, FT1, &env->fp_status) == 1);
478     RETURN();
479 }
480
481 void OPPROTO op_fcmp_gt_DT(void)
482 {
483     cond_t(float64_compare(DT0, DT1, &env->fp_status) == 1);
484     RETURN();
485 }
486
487 void OPPROTO op_float_FT(void)
488 {
489     FT0 = int32_to_float32(env->fpul, &env->fp_status);
490     RETURN();
491 }
492
493 void OPPROTO op_float_DT(void)
494 {
495     DT0 = int32_to_float64(env->fpul, &env->fp_status);
496     RETURN();
497 }
498
499 void OPPROTO op_ftrc_FT(void)
500 {
501     env->fpul = float32_to_int32_round_to_zero(FT0, &env->fp_status);
502     RETURN();
503 }
504
505 void OPPROTO op_ftrc_DT(void)
506 {
507     env->fpul = float64_to_int32_round_to_zero(DT0, &env->fp_status);
508     RETURN();
509 }
510
511 void OPPROTO op_fneg_frN(void)
512 {
513     env->fregs[PARAM1] = float32_chs(env->fregs[PARAM1]);
514     RETURN();
515 }
516
517 void OPPROTO op_fabs_FT(void)
518 {
519     FT0 = float32_abs(FT0);
520     RETURN();
521 }
522
523 void OPPROTO op_fabs_DT(void)
524 {
525     DT0 = float64_abs(DT0);
526     RETURN();
527 }
528
529 void OPPROTO op_fcnvsd_FT_DT(void)
530 {
531     DT0 = float32_to_float64(FT0, &env->fp_status);
532     RETURN();
533 }
534
535 void OPPROTO op_fcnvds_DT_FT(void)
536 {
537     FT0 = float64_to_float32(DT0, &env->fp_status);
538     RETURN();
539 }
540
541 void OPPROTO op_fsqrt_FT(void)
542 {
543     FT0 = float32_sqrt(FT0, &env->fp_status);
544     RETURN();
545 }
546
547 void OPPROTO op_fsqrt_DT(void)
548 {
549     DT0 = float64_sqrt(DT0, &env->fp_status);
550     RETURN();
551 }
552
553 void OPPROTO op_fmov_T0_frN(void)
554 {
555     *(uint32_t *)&env->fregs[PARAM1] = T0;
556     RETURN();
557 }
558
559 void OPPROTO op_movl_fpul_FT0(void)
560 {
561     FT0 = *(float32 *)&env->fpul;
562     RETURN();
563 }
564
565 void OPPROTO op_movl_FT0_fpul(void)
566 {
567     *(float32 *)&env->fpul = FT0;
568     RETURN();
569 }
570
571 void OPPROTO op_jT(void)
572 {
573     if (env->sr & SR_T)
574         GOTO_LABEL_PARAM(1);
575     RETURN();
576 }
577
578 void OPPROTO op_jdelayed(void)
579 {
580     if (env->flags & DELAY_SLOT_TRUE) {
581         env->flags &= ~DELAY_SLOT_TRUE;
582         GOTO_LABEL_PARAM(1);
583     }
584     RETURN();
585 }
586
587 void OPPROTO op_movl_delayed_pc_PC(void)
588 {
589     env->pc = env->delayed_pc;
590     RETURN();
591 }
592
593 void OPPROTO op_raise_illegal_instruction(void)
594 {
595     env->exception_index = 0x180;
596     do_raise_exception();
597     RETURN();
598 }
599
600 void OPPROTO op_raise_slot_illegal_instruction(void)
601 {
602     env->exception_index = 0x1a0;
603     do_raise_exception();
604     RETURN();
605 }
606
607 void OPPROTO op_debug(void)
608 {
609     env->exception_index = EXCP_DEBUG;
610     cpu_loop_exit();
611 }
612
613 void OPPROTO op_sleep(void)
614 {
615     env->halted = 1;
616     env->exception_index = EXCP_HLT;
617     cpu_loop_exit();
618 }
619
620 /* Load and store */
621 #define MEMSUFFIX _raw
622 #include "op_mem.c"
623 #undef MEMSUFFIX
624 #if !defined(CONFIG_USER_ONLY)
625 #define MEMSUFFIX _user
626 #include "op_mem.c"
627 #undef MEMSUFFIX
628
629 #define MEMSUFFIX _kernel
630 #include "op_mem.c"
631 #undef MEMSUFFIX
632 #endif