M68k system mode semihosting.
[qemu/mini2440.git] / target-m68k / op.c
blob69d1fde9a76c3178b93eb08f06231034e390c630
1 /*
2 * m68k micro operations
3 *
4 * Copyright (c) 2006-2007 CodeSourcery
5 * Written by Paul Brook
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.
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 * General Public License for more details.
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
22 #include "exec.h"
23 #include "m68k-qreg.h"
25 #ifndef offsetof
26 #define offsetof(type, field) ((size_t) &((type *)0)->field)
27 #endif
29 static long qreg_offsets[] = {
30 #define DEFO32(name, offset) offsetof(CPUState, offset),
31 #define DEFR(name, reg, mode) -1,
32 #define DEFF64(name, offset) offsetof(CPUState, offset),
34 #include "qregs.def"
37 #define CPU_FP_STATUS env->fp_status
39 #define RAISE_EXCEPTION(n) do { \
40 env->exception_index = n; \
41 cpu_loop_exit(); \
42 } while(0)
44 #define get_op helper_get_op
45 #define set_op helper_set_op
46 #define get_opf64 helper_get_opf64
47 #define set_opf64 helper_set_opf64
48 uint32_t
49 get_op(int qreg)
51 if (qreg >= TARGET_NUM_QREGS) {
52 return env->qregs[qreg - TARGET_NUM_QREGS];
53 } else if (qreg == QREG_T0) {
54 return T0;
55 } else {
56 return *(uint32_t *)(((long)env) + qreg_offsets[qreg]);
60 void set_op(int qreg, uint32_t val)
62 if (qreg >= TARGET_NUM_QREGS) {
63 env->qregs[qreg - TARGET_NUM_QREGS] = val;
64 } else if (qreg == QREG_T0) {
65 T0 = val;
66 } else {
67 *(uint32_t *)(((long)env) + qreg_offsets[qreg]) = val;
71 float64 get_opf64(int qreg)
73 if (qreg < TARGET_NUM_QREGS) {
74 return *(float64 *)(((long)env) + qreg_offsets[qreg]);
75 } else {
76 return *(float64 *)&env->qregs[qreg - TARGET_NUM_QREGS];
80 void set_opf64(int qreg, float64 val)
82 if (qreg < TARGET_NUM_QREGS) {
83 *(float64 *)(((long)env) + qreg_offsets[qreg]) = val;
84 } else {
85 *(float64 *)&env->qregs[qreg - TARGET_NUM_QREGS] = val;
89 #define OP(name) void OPPROTO glue(op_,name) (void)
91 OP(mov32)
93 set_op(PARAM1, get_op(PARAM2));
94 FORCE_RET();
97 OP(mov32_im)
99 set_op(PARAM1, PARAM2);
100 FORCE_RET();
103 OP(movf64)
105 set_opf64(PARAM1, get_opf64(PARAM2));
106 FORCE_RET();
109 OP(zerof64)
111 set_opf64(PARAM1, 0);
112 FORCE_RET();
115 OP(add32)
117 uint32_t op2 = get_op(PARAM2);
118 uint32_t op3 = get_op(PARAM3);
119 set_op(PARAM1, op2 + op3);
120 FORCE_RET();
123 OP(sub32)
125 uint32_t op2 = get_op(PARAM2);
126 uint32_t op3 = get_op(PARAM3);
127 set_op(PARAM1, op2 - op3);
128 FORCE_RET();
131 OP(mul32)
133 uint32_t op2 = get_op(PARAM2);
134 uint32_t op3 = get_op(PARAM3);
135 set_op(PARAM1, op2 * op3);
136 FORCE_RET();
139 OP(not32)
141 uint32_t arg = get_op(PARAM2);
142 set_op(PARAM1, ~arg);
143 FORCE_RET();
146 OP(neg32)
148 uint32_t arg = get_op(PARAM2);
149 set_op(PARAM1, -arg);
150 FORCE_RET();
153 OP(bswap32)
155 uint32_t arg = get_op(PARAM2);
156 arg = (arg >> 24) | (arg << 24)
157 | ((arg >> 16) & 0xff00) | ((arg << 16) & 0xff0000);
158 set_op(PARAM1, arg);
159 FORCE_RET();
162 OP(btest)
164 uint32_t op1 = get_op(PARAM1);
165 uint32_t op2 = get_op(PARAM2);
166 if (op1 & op2)
167 env->cc_dest &= ~CCF_Z;
168 else
169 env->cc_dest |= CCF_Z;
170 FORCE_RET();
173 OP(subx_cc)
175 uint32_t op1 = get_op(PARAM1);
176 uint32_t op2 = get_op(PARAM2);
177 uint32_t res;
178 if (env->cc_x) {
179 env->cc_x = (op1 <= op2);
180 env->cc_op = CC_OP_SUBX;
181 res = op1 - (op2 + 1);
182 } else {
183 env->cc_x = (op1 < op2);
184 env->cc_op = CC_OP_SUB;
185 res = op1 - op2;
187 set_op(PARAM1, res);
188 FORCE_RET();
191 OP(addx_cc)
193 uint32_t op1 = get_op(PARAM1);
194 uint32_t op2 = get_op(PARAM2);
195 uint32_t res;
196 if (env->cc_x) {
197 res = op1 + op2 + 1;
198 env->cc_x = (res <= op2);
199 env->cc_op = CC_OP_ADDX;
200 } else {
201 res = op1 + op2;
202 env->cc_x = (res < op2);
203 env->cc_op = CC_OP_ADD;
205 set_op(PARAM1, res);
206 FORCE_RET();
209 /* Logic ops. */
211 OP(and32)
213 uint32_t op2 = get_op(PARAM2);
214 uint32_t op3 = get_op(PARAM3);
215 set_op(PARAM1, op2 & op3);
216 FORCE_RET();
219 OP(or32)
221 uint32_t op2 = get_op(PARAM2);
222 uint32_t op3 = get_op(PARAM3);
223 set_op(PARAM1, op2 | op3);
224 FORCE_RET();
227 OP(xor32)
229 uint32_t op2 = get_op(PARAM2);
230 uint32_t op3 = get_op(PARAM3);
231 set_op(PARAM1, op2 ^ op3);
232 FORCE_RET();
235 /* Shifts. */
236 OP(shl32)
238 uint32_t op2 = get_op(PARAM2);
239 uint32_t op3 = get_op(PARAM3);
240 uint32_t result;
241 result = op2 << op3;
242 set_op(PARAM1, result);
243 FORCE_RET();
246 OP(shl_cc)
248 uint32_t op1 = get_op(PARAM1);
249 uint32_t op2 = get_op(PARAM2);
250 uint32_t result;
251 result = op1 << op2;
252 set_op(PARAM1, result);
253 env->cc_x = (op1 << (op2 - 1)) & 1;
254 FORCE_RET();
257 OP(shr32)
259 uint32_t op2 = get_op(PARAM2);
260 uint32_t op3 = get_op(PARAM3);
261 uint32_t result;
262 result = op2 >> op3;
263 set_op(PARAM1, result);
264 FORCE_RET();
267 OP(shr_cc)
269 uint32_t op1 = get_op(PARAM1);
270 uint32_t op2 = get_op(PARAM2);
271 uint32_t result;
272 result = op1 >> op2;
273 set_op(PARAM1, result);
274 env->cc_x = (op1 >> (op2 - 1)) & 1;
275 FORCE_RET();
278 OP(sar_cc)
280 int32_t op1 = get_op(PARAM1);
281 uint32_t op2 = get_op(PARAM2);
282 uint32_t result;
283 result = op1 >> op2;
284 set_op(PARAM1, result);
285 env->cc_x = (op1 >> (op2 - 1)) & 1;
286 FORCE_RET();
289 /* Value extend. */
291 OP(ext8u32)
293 uint32_t op2 = get_op(PARAM2);
294 set_op(PARAM1, (uint8_t)op2);
295 FORCE_RET();
298 OP(ext8s32)
300 uint32_t op2 = get_op(PARAM2);
301 set_op(PARAM1, (int8_t)op2);
302 FORCE_RET();
305 OP(ext16u32)
307 uint32_t op2 = get_op(PARAM2);
308 set_op(PARAM1, (uint16_t)op2);
309 FORCE_RET();
312 OP(ext16s32)
314 uint32_t op2 = get_op(PARAM2);
315 set_op(PARAM1, (int16_t)op2);
316 FORCE_RET();
319 OP(flush_flags)
321 int cc_op = PARAM1;
322 if (cc_op == CC_OP_DYNAMIC)
323 cc_op = env->cc_op;
324 cpu_m68k_flush_flags(env, cc_op);
325 FORCE_RET();
328 OP(divu)
330 uint32_t num;
331 uint32_t den;
332 uint32_t quot;
333 uint32_t rem;
334 uint32_t flags;
336 num = env->div1;
337 den = env->div2;
338 /* ??? This needs to make sure the throwing location is accurate. */
339 if (den == 0)
340 RAISE_EXCEPTION(EXCP_DIV0);
341 quot = num / den;
342 rem = num % den;
343 flags = 0;
344 /* Avoid using a PARAM1 of zero. This breaks dyngen because it uses
345 the address of a symbol, and gcc knows symbols can't have address
346 zero. */
347 if (PARAM1 == 2 && quot > 0xffff)
348 flags |= CCF_V;
349 if (quot == 0)
350 flags |= CCF_Z;
351 else if ((int32_t)quot < 0)
352 flags |= CCF_N;
353 env->div1 = quot;
354 env->div2 = rem;
355 env->cc_dest = flags;
356 FORCE_RET();
359 OP(divs)
361 int32_t num;
362 int32_t den;
363 int32_t quot;
364 int32_t rem;
365 int32_t flags;
367 num = env->div1;
368 den = env->div2;
369 if (den == 0)
370 RAISE_EXCEPTION(EXCP_DIV0);
371 quot = num / den;
372 rem = num % den;
373 flags = 0;
374 if (PARAM1 == 2 && quot != (int16_t)quot)
375 flags |= CCF_V;
376 if (quot == 0)
377 flags |= CCF_Z;
378 else if (quot < 0)
379 flags |= CCF_N;
380 env->div1 = quot;
381 env->div2 = rem;
382 env->cc_dest = flags;
383 FORCE_RET();
386 /* Halt is special because it may be a semihosting call. */
387 OP(halt)
389 RAISE_EXCEPTION(EXCP_HALT_INSN);
390 FORCE_RET();
393 OP(stop)
395 env->halted = 1;
396 RAISE_EXCEPTION(EXCP_HLT);
397 FORCE_RET();
400 OP(raise_exception)
402 RAISE_EXCEPTION(PARAM1);
403 FORCE_RET();
406 /* Floating point comparison sets flags differently to other instructions. */
408 OP(sub_cmpf64)
410 float64 src0;
411 float64 src1;
412 src0 = get_opf64(PARAM2);
413 src1 = get_opf64(PARAM3);
414 set_opf64(PARAM1, helper_sub_cmpf64(env, src0, src1));
415 FORCE_RET();
418 OP(update_xflag_tst)
420 uint32_t op1 = get_op(PARAM1);
421 env->cc_x = op1;
422 FORCE_RET();
425 OP(update_xflag_lt)
427 uint32_t op1 = get_op(PARAM1);
428 uint32_t op2 = get_op(PARAM2);
429 env->cc_x = (op1 < op2);
430 FORCE_RET();
433 OP(get_xflag)
435 set_op(PARAM1, env->cc_x);
436 FORCE_RET();
439 OP(logic_cc)
441 uint32_t op1 = get_op(PARAM1);
442 env->cc_dest = op1;
443 FORCE_RET();
446 OP(update_cc_add)
448 uint32_t op1 = get_op(PARAM1);
449 uint32_t op2 = get_op(PARAM2);
450 env->cc_dest = op1;
451 env->cc_src = op2;
452 FORCE_RET();
455 OP(fp_result)
457 env->fp_result = get_opf64(PARAM1);
458 FORCE_RET();
461 OP(jmp)
463 GOTO_LABEL_PARAM(1);
466 /* These ops involve a function call, which probably requires a stack frame
467 and breaks things on some hosts. */
468 OP(jmp_z32)
470 uint32_t arg = get_op(PARAM1);
471 if (arg == 0)
472 GOTO_LABEL_PARAM(2);
473 FORCE_RET();
476 OP(jmp_nz32)
478 uint32_t arg = get_op(PARAM1);
479 if (arg != 0)
480 GOTO_LABEL_PARAM(2);
481 FORCE_RET();
484 OP(jmp_s32)
486 int32_t arg = get_op(PARAM1);
487 if (arg < 0)
488 GOTO_LABEL_PARAM(2);
489 FORCE_RET();
492 OP(jmp_ns32)
494 int32_t arg = get_op(PARAM1);
495 if (arg >= 0)
496 GOTO_LABEL_PARAM(2);
497 FORCE_RET();
500 void OPPROTO op_goto_tb0(void)
502 GOTO_TB(op_goto_tb0, PARAM1, 0);
505 void OPPROTO op_goto_tb1(void)
507 GOTO_TB(op_goto_tb1, PARAM1, 1);
510 OP(exit_tb)
512 EXIT_TB();
516 /* Floating point. */
517 OP(f64_to_i32)
519 set_op(PARAM1, float64_to_int32(get_opf64(PARAM2), &CPU_FP_STATUS));
520 FORCE_RET();
523 OP(f64_to_f32)
525 union {
526 float32 f;
527 uint32_t i;
528 } u;
529 u.f = float64_to_float32(get_opf64(PARAM2), &CPU_FP_STATUS);
530 set_op(PARAM1, u.i);
531 FORCE_RET();
534 OP(i32_to_f64)
536 set_opf64(PARAM1, int32_to_float64(get_op(PARAM2), &CPU_FP_STATUS));
537 FORCE_RET();
540 OP(f32_to_f64)
542 union {
543 float32 f;
544 uint32_t i;
545 } u;
546 u.i = get_op(PARAM2);
547 set_opf64(PARAM1, float32_to_float64(u.f, &CPU_FP_STATUS));
548 FORCE_RET();
551 OP(absf64)
553 float64 op0 = get_opf64(PARAM2);
554 set_opf64(PARAM1, float64_abs(op0));
555 FORCE_RET();
558 OP(chsf64)
560 float64 op0 = get_opf64(PARAM2);
561 set_opf64(PARAM1, float64_chs(op0));
562 FORCE_RET();
565 OP(sqrtf64)
567 float64 op0 = get_opf64(PARAM2);
568 set_opf64(PARAM1, float64_sqrt(op0, &CPU_FP_STATUS));
569 FORCE_RET();
572 OP(addf64)
574 float64 op0 = get_opf64(PARAM2);
575 float64 op1 = get_opf64(PARAM3);
576 set_opf64(PARAM1, float64_add(op0, op1, &CPU_FP_STATUS));
577 FORCE_RET();
580 OP(subf64)
582 float64 op0 = get_opf64(PARAM2);
583 float64 op1 = get_opf64(PARAM3);
584 set_opf64(PARAM1, float64_sub(op0, op1, &CPU_FP_STATUS));
585 FORCE_RET();
588 OP(mulf64)
590 float64 op0 = get_opf64(PARAM2);
591 float64 op1 = get_opf64(PARAM3);
592 set_opf64(PARAM1, float64_mul(op0, op1, &CPU_FP_STATUS));
593 FORCE_RET();
596 OP(divf64)
598 float64 op0 = get_opf64(PARAM2);
599 float64 op1 = get_opf64(PARAM3);
600 set_opf64(PARAM1, float64_div(op0, op1, &CPU_FP_STATUS));
601 FORCE_RET();
604 OP(iround_f64)
606 float64 op0 = get_opf64(PARAM2);
607 set_opf64(PARAM1, float64_round_to_int(op0, &CPU_FP_STATUS));
608 FORCE_RET();
611 OP(itrunc_f64)
613 float64 op0 = get_opf64(PARAM2);
614 set_opf64(PARAM1, float64_trunc_to_int(op0, &CPU_FP_STATUS));
615 FORCE_RET();
618 OP(compare_quietf64)
620 float64 op0 = get_opf64(PARAM2);
621 float64 op1 = get_opf64(PARAM3);
622 set_op(PARAM1, float64_compare_quiet(op0, op1, &CPU_FP_STATUS));
623 FORCE_RET();
626 OP(movec)
628 int op1 = get_op(PARAM1);
629 uint32_t op2 = get_op(PARAM2);
630 helper_movec(env, op1, op2);
633 /* Memory access. */
635 #define MEMSUFFIX _raw
636 #include "op_mem.h"
638 #if !defined(CONFIG_USER_ONLY)
639 #define MEMSUFFIX _user
640 #include "op_mem.h"
641 #define MEMSUFFIX _kernel
642 #include "op_mem.h"
643 #endif