]> git.proxmox.com Git - mirror_qemu.git/blame - target-m68k/op.c
Avoid redundant TLB flushes (Daniel Jacobowitz).
[mirror_qemu.git] / target-m68k / op.c
CommitLineData
e6e5906b
PB
1/*
2 * m68k micro operations
3 *
4 * Copyright (c) 2006 CodeSourcery
5 * Written by Paul Brook
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 * 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
22#include "exec.h"
23#include "m68k-qreg.h"
24
25#ifndef offsetof
26#define offsetof(type, field) ((size_t) &((type *)0)->field)
27#endif
28
29static 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),
33 0,
34#include "qregs.def"
35};
36
37#define CPU_FP_STATUS env->fp_status
38
39#define RAISE_EXCEPTION(n) do { \
40 env->exception_index = n; \
41 cpu_loop_exit(); \
42 } while(0)
43
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
48uint32_t
49get_op(int qreg)
50{
51 if (qreg == QREG_T0) {
52 return T0;
53 } else if (qreg < TARGET_NUM_QREGS) {
54 return *(uint32_t *)(((long)env) + qreg_offsets[qreg]);
55 } else {
56 return env->qregs[qreg - TARGET_NUM_QREGS];
57 }
58}
59
60void set_op(int qreg, uint32_t val)
61{
62 if (qreg == QREG_T0) {
63 T0 = val;
64 } else if (qreg < TARGET_NUM_QREGS) {
65 *(uint32_t *)(((long)env) + qreg_offsets[qreg]) = val;
66 } else {
67 env->qregs[qreg - TARGET_NUM_QREGS] = val;
68 }
69}
70
71float64 get_opf64(int qreg)
72{
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];
77 }
78}
79
80void set_opf64(int qreg, float64 val)
81{
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;
86 }
87}
88
89#define OP(name) void OPPROTO op_##name (void)
90
91OP(mov32)
92{
93 set_op(PARAM1, get_op(PARAM2));
94 FORCE_RET();
95}
96
97OP(mov32_im)
98{
99 set_op(PARAM1, PARAM2);
100 FORCE_RET();
101}
102
103OP(movf64)
104{
105 set_opf64(PARAM1, get_opf64(PARAM2));
106 FORCE_RET();
107}
108
109OP(zerof64)
110{
111 set_opf64(PARAM1, 0);
112 FORCE_RET();
113}
114
115OP(add32)
116{
117 uint32_t op2 = get_op(PARAM2);
118 uint32_t op3 = get_op(PARAM3);
119 set_op(PARAM1, op2 + op3);
120 FORCE_RET();
121}
122
123OP(sub32)
124{
125 uint32_t op2 = get_op(PARAM2);
126 uint32_t op3 = get_op(PARAM3);
127 set_op(PARAM1, op2 - op3);
128 FORCE_RET();
129}
130
131OP(mul32)
132{
133 uint32_t op2 = get_op(PARAM2);
134 uint32_t op3 = get_op(PARAM3);
135 set_op(PARAM1, op2 * op3);
136 FORCE_RET();
137}
138
139OP(not32)
140{
141 uint32_t arg = get_op(PARAM2);
142 set_op(PARAM1, ~arg);
143 FORCE_RET();
144}
145
146OP(neg32)
147{
148 uint32_t arg = get_op(PARAM2);
149 set_op(PARAM1, -arg);
150 FORCE_RET();
151}
152
153OP(bswap32)
154{
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();
160}
161
162OP(btest)
163{
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();
171}
172
173OP(addx_cc)
174{
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;
186 }
187 set_op(PARAM1, res);
188 FORCE_RET();
189}
190
191OP(subx_cc)
192{
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;
204 }
205 set_op(PARAM1, res);
206 FORCE_RET();
207}
208
209/* Logic ops. */
210
211OP(and32)
212{
213 uint32_t op2 = get_op(PARAM2);
214 uint32_t op3 = get_op(PARAM3);
215 set_op(PARAM1, op2 & op3);
216 FORCE_RET();
217}
218
219OP(or32)
220{
221 uint32_t op2 = get_op(PARAM2);
222 uint32_t op3 = get_op(PARAM3);
223 set_op(PARAM1, op2 | op3);
224 FORCE_RET();
225}
226
227OP(xor32)
228{
229 uint32_t op2 = get_op(PARAM2);
230 uint32_t op3 = get_op(PARAM3);
231 set_op(PARAM1, op2 ^ op3);
232 FORCE_RET();
233}
234
235/* Shifts. */
236OP(shl32)
237{
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();
244}
245
246OP(shl_cc)
247{
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();
255}
256
257OP(shr32)
258{
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();
265}
266
267OP(shr_cc)
268{
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();
276}
277
278OP(sar_cc)
279{
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();
287}
288
289/* Value extend. */
290
291OP(ext8u32)
292{
293 uint32_t op2 = get_op(PARAM2);
294 set_op(PARAM1, (uint8_t)op2);
295 FORCE_RET();
296}
297
298OP(ext8s32)
299{
300 uint32_t op2 = get_op(PARAM2);
301 set_op(PARAM1, (int8_t)op2);
302 FORCE_RET();
303}
304
305OP(ext16u32)
306{
307 uint32_t op2 = get_op(PARAM2);
308 set_op(PARAM1, (uint16_t)op2);
309 FORCE_RET();
310}
311
312OP(ext16s32)
313{
314 uint32_t op2 = get_op(PARAM2);
315 set_op(PARAM1, (int16_t)op2);
316 FORCE_RET();
317}
318
319/* Load/store ops. */
320OP(ld8u32)
321{
322 uint32_t addr = get_op(PARAM2);
323 set_op(PARAM1, ldub(addr));
324 FORCE_RET();
325}
326
327OP(ld8s32)
328{
329 uint32_t addr = get_op(PARAM2);
330 set_op(PARAM1, ldsb(addr));
331 FORCE_RET();
332}
333
334OP(ld16u32)
335{
336 uint32_t addr = get_op(PARAM2);
337 set_op(PARAM1, lduw(addr));
338 FORCE_RET();
339}
340
341OP(ld16s32)
342{
343 uint32_t addr = get_op(PARAM2);
344 set_op(PARAM1, ldsw(addr));
345 FORCE_RET();
346}
347
348OP(ld32)
349{
350 uint32_t addr = get_op(PARAM2);
351 set_op(PARAM1, ldl(addr));
352 FORCE_RET();
353}
354
355OP(st8)
356{
357 uint32_t addr = get_op(PARAM1);
358 stb(addr, get_op(PARAM2));
359 FORCE_RET();
360}
361
362OP(st16)
363{
364 uint32_t addr = get_op(PARAM1);
365 stw(addr, get_op(PARAM2));
366 FORCE_RET();
367}
368
369OP(st32)
370{
371 uint32_t addr = get_op(PARAM1);
372 stl(addr, get_op(PARAM2));
373 FORCE_RET();
374}
375
376OP(ldf64)
377{
378 uint32_t addr = get_op(PARAM2);
379 set_opf64(PARAM1, ldfq(addr));
380 FORCE_RET();
381}
382
383OP(stf64)
384{
385 uint32_t addr = get_op(PARAM1);
386 stfq(addr, get_opf64(PARAM2));
387 FORCE_RET();
388}
389
390OP(flush_flags)
391{
392 int cc_op = PARAM1;
393 if (cc_op == CC_OP_DYNAMIC)
394 cc_op = env->cc_op;
395 cpu_m68k_flush_flags(env, cc_op);
396 FORCE_RET();
397}
398
399OP(divu)
400{
401 uint32_t num;
402 uint32_t den;
403 uint32_t quot;
404 uint32_t rem;
405 uint32_t flags;
406
407 num = env->div1;
408 den = env->div2;
409 /* ??? This needs to make sure the throwing location is accurate. */
410 if (den == 0)
411 RAISE_EXCEPTION(EXCP_DIV0);
412 quot = num / den;
413 rem = num % den;
414 flags = 0;
415 if (PARAM1 && quot > 0xffff)
416 flags |= CCF_V;
417 if (quot == 0)
418 flags |= CCF_Z;
419 else if ((int32_t)quot < 0)
420 flags |= CCF_N;
421 env->div1 = quot;
422 env->div2 = rem;
423 env->cc_dest = flags;
424 FORCE_RET();
425}
426
427OP(divs)
428{
429 int32_t num;
430 int32_t den;
431 int32_t quot;
432 int32_t rem;
433 int32_t flags;
434
435 num = env->div1;
436 den = env->div2;
437 if (den == 0)
438 RAISE_EXCEPTION(EXCP_DIV0);
439 quot = num / den;
440 rem = num % den;
441 flags = 0;
442 if (PARAM1 && quot != (int16_t)quot)
443 flags |= CCF_V;
444 if (quot == 0)
445 flags |= CCF_Z;
446 else if (quot < 0)
447 flags |= CCF_N;
448 env->div1 = quot;
449 env->div2 = rem;
450 env->cc_dest = flags;
451 FORCE_RET();
452}
453
454OP(raise_exception)
455{
456 RAISE_EXCEPTION(PARAM1);
457 FORCE_RET();
458}
459
460/* Floating point comparison sets flags differently to other instructions. */
461
462OP(sub_cmpf64)
463{
464 float64 src0;
465 float64 src1;
466 src0 = get_opf64(PARAM2);
467 src1 = get_opf64(PARAM3);
468 set_opf64(PARAM1, helper_sub_cmpf64(env, src0, src1));
469 FORCE_RET();
470}
471
472OP(update_xflag_tst)
473{
474 uint32_t op1 = get_op(PARAM1);
475 env->cc_x = op1;
476 FORCE_RET();
477}
478
479OP(update_xflag_lt)
480{
481 uint32_t op1 = get_op(PARAM1);
482 uint32_t op2 = get_op(PARAM2);
483 env->cc_x = (op1 < op2);
484 FORCE_RET();
485}
486
487OP(get_xflag)
488{
489 set_op(PARAM1, env->cc_x);
490 FORCE_RET();
491}
492
493OP(logic_cc)
494{
495 uint32_t op1 = get_op(PARAM1);
496 env->cc_dest = op1;
497 FORCE_RET();
498}
499
500OP(update_cc_add)
501{
502 uint32_t op1 = get_op(PARAM1);
503 uint32_t op2 = get_op(PARAM2);
504 env->cc_dest = op1;
505 env->cc_src = op2;
506 FORCE_RET();
507}
508
509OP(fp_result)
510{
511 env->fp_result = get_opf64(PARAM1);
512 FORCE_RET();
513}
514
515OP(jmp)
516{
517 GOTO_LABEL_PARAM(1);
518}
519
520/* These ops involve a function call, which probably requires a stack frame
521 and breaks things on some hosts. */
522OP(jmp_z32)
523{
524 uint32_t arg = get_op(PARAM1);
525 if (arg == 0)
526 GOTO_LABEL_PARAM(2);
527 FORCE_RET();
528}
529
530OP(jmp_nz32)
531{
532 uint32_t arg = get_op(PARAM1);
533 if (arg != 0)
534 GOTO_LABEL_PARAM(2);
535 FORCE_RET();
536}
537
538OP(jmp_s32)
539{
540 int32_t arg = get_op(PARAM1);
541 if (arg < 0)
542 GOTO_LABEL_PARAM(2);
543 FORCE_RET();
544}
545
546OP(jmp_ns32)
547{
548 int32_t arg = get_op(PARAM1);
549 if (arg >= 0)
550 GOTO_LABEL_PARAM(2);
551 FORCE_RET();
552}
553
554void OPPROTO op_goto_tb0(void)
555{
556 GOTO_TB(op_goto_tb0, PARAM1, 0);
557}
558
559void OPPROTO op_goto_tb1(void)
560{
561 GOTO_TB(op_goto_tb1, PARAM1, 1);
562}
563
564OP(exit_tb)
565{
566 EXIT_TB();
567}
568
569
570/* Floating point. */
571OP(f64_to_i32)
572{
573 set_op(PARAM1, float64_to_int32(get_opf64(PARAM2), &CPU_FP_STATUS));
574 FORCE_RET();
575}
576
577OP(f64_to_f32)
578{
579 union {
580 float32 f;
581 uint32_t i;
582 } u;
583 u.f = float64_to_float32(get_opf64(PARAM2), &CPU_FP_STATUS);
584 set_op(PARAM1, u.i);
585 FORCE_RET();
586}
587
588OP(i32_to_f64)
589{
590 set_opf64(PARAM1, int32_to_float64(get_op(PARAM2), &CPU_FP_STATUS));
591 FORCE_RET();
592}
593
594OP(f32_to_f64)
595{
596 union {
597 float32 f;
598 uint32_t i;
599 } u;
600 u.i = get_op(PARAM2);
601 set_opf64(PARAM1, float32_to_float64(u.f, &CPU_FP_STATUS));
602 FORCE_RET();
603}
604
605OP(absf64)
606{
607 float64 op0 = get_opf64(PARAM2);
608 set_opf64(PARAM1, float64_abs(op0));
609 FORCE_RET();
610}
611
612OP(chsf64)
613{
614 float64 op0 = get_opf64(PARAM2);
615 set_opf64(PARAM1, float64_chs(op0));
616 FORCE_RET();
617}
618
619OP(sqrtf64)
620{
621 float64 op0 = get_opf64(PARAM2);
622 set_opf64(PARAM1, float64_sqrt(op0, &CPU_FP_STATUS));
623 FORCE_RET();
624}
625
626OP(addf64)
627{
628 float64 op0 = get_opf64(PARAM2);
629 float64 op1 = get_opf64(PARAM3);
630 set_opf64(PARAM1, float64_add(op0, op1, &CPU_FP_STATUS));
631 FORCE_RET();
632}
633
634OP(subf64)
635{
636 float64 op0 = get_opf64(PARAM2);
637 float64 op1 = get_opf64(PARAM3);
638 set_opf64(PARAM1, float64_sub(op0, op1, &CPU_FP_STATUS));
639 FORCE_RET();
640}
641
642OP(mulf64)
643{
644 float64 op0 = get_opf64(PARAM2);
645 float64 op1 = get_opf64(PARAM3);
646 set_opf64(PARAM1, float64_mul(op0, op1, &CPU_FP_STATUS));
647 FORCE_RET();
648}
649
650OP(divf64)
651{
652 float64 op0 = get_opf64(PARAM2);
653 float64 op1 = get_opf64(PARAM3);
654 set_opf64(PARAM1, float64_div(op0, op1, &CPU_FP_STATUS));
655 FORCE_RET();
656}
657
658OP(iround_f64)
659{
660 float64 op0 = get_opf64(PARAM2);
661 set_opf64(PARAM1, float64_round_to_int(op0, &CPU_FP_STATUS));
662 FORCE_RET();
663}
664
665OP(itrunc_f64)
666{
667 float64 op0 = get_opf64(PARAM2);
668 set_opf64(PARAM1, float64_trunc_to_int(op0, &CPU_FP_STATUS));
669 FORCE_RET();
670}
671
672OP(compare_quietf64)
673{
674 float64 op0 = get_opf64(PARAM2);
675 float64 op1 = get_opf64(PARAM3);
676 set_op(PARAM1, float64_compare_quiet(op0, op1, &CPU_FP_STATUS));
677 FORCE_RET();
678}