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