]> git.proxmox.com Git - qemu.git/blame - target-m68k/translate.c
Split DMA controller in two
[qemu.git] / target-m68k / translate.c
CommitLineData
e6e5906b
PB
1/*
2 * m68k translation
3 *
0633879f 4 * Copyright (c) 2005-2007 CodeSourcery
e6e5906b
PB
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#include <stdarg.h>
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25#include <inttypes.h>
26
27#include "config.h"
28#include "cpu.h"
29#include "exec-all.h"
30#include "disas.h"
31#include "m68k-qreg.h"
32
0633879f
PB
33//#define DEBUG_DISPATCH 1
34
e6e5906b
PB
35static inline void qemu_assert(int cond, const char *msg)
36{
37 if (!cond) {
38 fprintf (stderr, "badness: %s\n", msg);
39 abort();
40 }
41}
42
43/* internal defines */
44typedef struct DisasContext {
45 target_ulong pc;
46 int is_jmp;
47 int cc_op;
0633879f 48 int user;
e6e5906b
PB
49 uint32_t fpcr;
50 struct TranslationBlock *tb;
51 int singlestep_enabled;
52} DisasContext;
53
54#define DISAS_JUMP_NEXT 4
55
0633879f
PB
56#if defined(CONFIG_USER_ONLY)
57#define IS_USER(s) 1
58#else
59#define IS_USER(s) s->user
60#endif
61
e6e5906b
PB
62/* XXX: move that elsewhere */
63/* ??? Fix exceptions. */
64static void *gen_throws_exception;
65#define gen_last_qop NULL
66
67static uint16_t *gen_opc_ptr;
68static uint32_t *gen_opparam_ptr;
69extern FILE *logfile;
70extern int loglevel;
71
72enum {
73#define DEF(s, n, copy_size) INDEX_op_ ## s,
74#include "opc.h"
75#undef DEF
76 NB_OPS,
77};
78
79#include "gen-op.h"
0633879f
PB
80
81#if defined(CONFIG_USER_ONLY)
82#define gen_st(s, name, addr, val) gen_op_st##name##_raw(addr, val)
83#define gen_ld(s, name, val, addr) gen_op_ld##name##_raw(val, addr)
84#else
85#define gen_st(s, name, addr, val) do { \
86 if (IS_USER(s)) \
87 gen_op_st##name##_user(addr, val); \
88 else \
89 gen_op_st##name##_kernel(addr, val); \
90 } while (0)
91#define gen_ld(s, name, val, addr) do { \
92 if (IS_USER(s)) \
93 gen_op_ld##name##_user(val, addr); \
94 else \
95 gen_op_ld##name##_kernel(val, addr); \
96 } while (0)
97#endif
98
e6e5906b
PB
99#include "op-hacks.h"
100
101#define OS_BYTE 0
102#define OS_WORD 1
103#define OS_LONG 2
104#define OS_SINGLE 4
105#define OS_DOUBLE 5
106
107#define DREG(insn, pos) (((insn >> pos) & 7) + QREG_D0)
108#define AREG(insn, pos) (((insn >> pos) & 7) + QREG_A0)
109#define FREG(insn, pos) (((insn >> pos) & 7) + QREG_F0)
110
e6e5906b
PB
111typedef void (*disas_proc)(DisasContext *, uint16_t);
112
0633879f
PB
113#ifdef DEBUG_DISPATCH
114#define DISAS_INSN(name) \
115 static void real_disas_##name (DisasContext *s, uint16_t insn); \
116 static void disas_##name (DisasContext *s, uint16_t insn) { \
117 if (logfile) fprintf(logfile, "Dispatch " #name "\n"); \
118 real_disas_##name(s, insn); } \
119 static void real_disas_##name (DisasContext *s, uint16_t insn)
120#else
e6e5906b
PB
121#define DISAS_INSN(name) \
122 static void disas_##name (DisasContext *s, uint16_t insn)
0633879f 123#endif
e6e5906b
PB
124
125/* Generate a load from the specified address. Narrow values are
126 sign extended to full register width. */
0633879f 127static inline int gen_load(DisasContext * s, int opsize, int addr, int sign)
e6e5906b
PB
128{
129 int tmp;
130 switch(opsize) {
131 case OS_BYTE:
132 tmp = gen_new_qreg(QMODE_I32);
133 if (sign)
0633879f 134 gen_ld(s, 8s32, tmp, addr);
e6e5906b 135 else
0633879f 136 gen_ld(s, 8u32, tmp, addr);
e6e5906b
PB
137 break;
138 case OS_WORD:
139 tmp = gen_new_qreg(QMODE_I32);
140 if (sign)
0633879f 141 gen_ld(s, 16s32, tmp, addr);
e6e5906b 142 else
0633879f 143 gen_ld(s, 16u32, tmp, addr);
e6e5906b
PB
144 break;
145 case OS_LONG:
146 tmp = gen_new_qreg(QMODE_I32);
0633879f 147 gen_ld(s, 32, tmp, addr);
e6e5906b
PB
148 break;
149 case OS_SINGLE:
150 tmp = gen_new_qreg(QMODE_F32);
0633879f 151 gen_ld(s, f32, tmp, addr);
e6e5906b
PB
152 break;
153 case OS_DOUBLE:
154 tmp = gen_new_qreg(QMODE_F64);
0633879f 155 gen_ld(s, f64, tmp, addr);
e6e5906b
PB
156 break;
157 default:
158 qemu_assert(0, "bad load size");
159 }
160 gen_throws_exception = gen_last_qop;
161 return tmp;
162}
163
164/* Generate a store. */
0633879f 165static inline void gen_store(DisasContext *s, int opsize, int addr, int val)
e6e5906b
PB
166{
167 switch(opsize) {
168 case OS_BYTE:
0633879f 169 gen_st(s, 8, addr, val);
e6e5906b
PB
170 break;
171 case OS_WORD:
0633879f 172 gen_st(s, 16, addr, val);
e6e5906b
PB
173 break;
174 case OS_LONG:
0633879f 175 gen_st(s, 32, addr, val);
e6e5906b
PB
176 break;
177 case OS_SINGLE:
0633879f 178 gen_st(s, f32, addr, val);
e6e5906b
PB
179 break;
180 case OS_DOUBLE:
0633879f 181 gen_st(s, f64, addr, val);
e6e5906b
PB
182 break;
183 default:
184 qemu_assert(0, "bad store size");
185 }
186 gen_throws_exception = gen_last_qop;
187}
188
189/* Generate an unsigned load if VAL is 0 a signed load if val is -1,
190 otherwise generate a store. */
0633879f 191static int gen_ldst(DisasContext *s, int opsize, int addr, int val)
e6e5906b
PB
192{
193 if (val > 0) {
0633879f 194 gen_store(s, opsize, addr, val);
e6e5906b
PB
195 return 0;
196 } else {
0633879f 197 return gen_load(s, opsize, addr, val != 0);
e6e5906b
PB
198 }
199}
200
201/* Handle a base + index + displacement effective addresss. A base of
202 -1 means pc-relative. */
203static int gen_lea_indexed(DisasContext *s, int opsize, int base)
204{
205 int scale;
206 uint32_t offset;
207 uint16_t ext;
208 int add;
209 int tmp;
210
211 offset = s->pc;
0633879f 212 ext = lduw_code(s->pc);
e6e5906b
PB
213 s->pc += 2;
214 tmp = ((ext >> 12) & 7) + ((ext & 0x8000) ? QREG_A0 : QREG_D0);
215 /* ??? Check W/L bit. */
216 scale = (ext >> 9) & 3;
217 if (scale == 0) {
218 add = tmp;
219 } else {
220 add = gen_new_qreg(QMODE_I32);
221 gen_op_shl32(add, tmp, gen_im32(scale));
222 }
223 tmp = gen_new_qreg(QMODE_I32);
224 if (base != -1) {
225 gen_op_add32(tmp, base, gen_im32((int8_t)ext));
226 gen_op_add32(tmp, tmp, add);
227 } else {
228 gen_op_add32(tmp, add, gen_im32(offset + (int8_t)ext));
229 }
230 return tmp;
231}
232
233/* Read a 32-bit immediate constant. */
234static inline uint32_t read_im32(DisasContext *s)
235{
236 uint32_t im;
0633879f 237 im = ((uint32_t)lduw_code(s->pc)) << 16;
e6e5906b 238 s->pc += 2;
0633879f 239 im |= lduw_code(s->pc);
e6e5906b
PB
240 s->pc += 2;
241 return im;
242}
243
244
245/* Update the CPU env CC_OP state. */
246static inline void gen_flush_cc_op(DisasContext *s)
247{
248 if (s->cc_op != CC_OP_DYNAMIC)
249 gen_op_mov32(QREG_CC_OP, gen_im32(s->cc_op));
250}
251
252/* Evaluate all the CC flags. */
253static inline void gen_flush_flags(DisasContext *s)
254{
255 if (s->cc_op == CC_OP_FLAGS)
256 return;
257 gen_op_flush_flags(s->cc_op);
258 s->cc_op = CC_OP_FLAGS;
259}
260
261static inline int opsize_bytes(int opsize)
262{
263 switch (opsize) {
264 case OS_BYTE: return 1;
265 case OS_WORD: return 2;
266 case OS_LONG: return 4;
267 case OS_SINGLE: return 4;
268 case OS_DOUBLE: return 8;
269 default:
270 qemu_assert(0, "bad operand size");
271 }
272}
273
274/* Assign value to a register. If the width is less than the register width
275 only the low part of the register is set. */
276static void gen_partset_reg(int opsize, int reg, int val)
277{
278 int tmp;
279 switch (opsize) {
280 case OS_BYTE:
281 gen_op_and32(reg, reg, gen_im32(0xffffff00));
282 tmp = gen_new_qreg(QMODE_I32);
283 gen_op_and32(tmp, val, gen_im32(0xff));
284 gen_op_or32(reg, reg, tmp);
285 break;
286 case OS_WORD:
287 gen_op_and32(reg, reg, gen_im32(0xffff0000));
288 tmp = gen_new_qreg(QMODE_I32);
289 gen_op_and32(tmp, val, gen_im32(0xffff));
290 gen_op_or32(reg, reg, tmp);
291 break;
292 case OS_LONG:
293 gen_op_mov32(reg, val);
294 break;
295 case OS_SINGLE:
296 gen_op_pack_32_f32(reg, val);
297 break;
298 default:
299 qemu_assert(0, "Bad operand size");
300 break;
301 }
302}
303
304/* Sign or zero extend a value. */
305static inline int gen_extend(int val, int opsize, int sign)
306{
307 int tmp;
308
309 switch (opsize) {
310 case OS_BYTE:
311 tmp = gen_new_qreg(QMODE_I32);
312 if (sign)
313 gen_op_ext8s32(tmp, val);
314 else
315 gen_op_ext8u32(tmp, val);
316 break;
317 case OS_WORD:
318 tmp = gen_new_qreg(QMODE_I32);
319 if (sign)
320 gen_op_ext16s32(tmp, val);
321 else
322 gen_op_ext16u32(tmp, val);
323 break;
324 case OS_LONG:
325 tmp = val;
326 break;
327 case OS_SINGLE:
328 tmp = gen_new_qreg(QMODE_F32);
329 gen_op_pack_f32_32(tmp, val);
330 break;
331 default:
332 qemu_assert(0, "Bad operand size");
333 }
334 return tmp;
335}
336
337/* Generate code for an "effective address". Does not adjust the base
338 register for autoincrememnt addressing modes. */
339static int gen_lea(DisasContext *s, uint16_t insn, int opsize)
340{
341 int reg;
342 int tmp;
343 uint16_t ext;
344 uint32_t offset;
345
346 reg = insn & 7;
347 switch ((insn >> 3) & 7) {
348 case 0: /* Data register direct. */
349 case 1: /* Address register direct. */
350 /* ??? generate bad addressing mode fault. */
351 qemu_assert(0, "invalid addressing mode");
352 case 2: /* Indirect register */
353 case 3: /* Indirect postincrement. */
354 reg += QREG_A0;
355 return reg;
356 case 4: /* Indirect predecrememnt. */
357 reg += QREG_A0;
358 tmp = gen_new_qreg(QMODE_I32);
359 gen_op_sub32(tmp, reg, gen_im32(opsize_bytes(opsize)));
360 return tmp;
361 case 5: /* Indirect displacement. */
362 reg += QREG_A0;
363 tmp = gen_new_qreg(QMODE_I32);
0633879f 364 ext = lduw_code(s->pc);
e6e5906b
PB
365 s->pc += 2;
366 gen_op_add32(tmp, reg, gen_im32((int16_t)ext));
367 return tmp;
368 case 6: /* Indirect index + displacement. */
369 reg += QREG_A0;
370 return gen_lea_indexed(s, opsize, reg);
371 case 7: /* Other */
372 switch (reg) {
373 case 0: /* Absolute short. */
0633879f 374 offset = ldsw_code(s->pc);
e6e5906b
PB
375 s->pc += 2;
376 return gen_im32(offset);
377 case 1: /* Absolute long. */
378 offset = read_im32(s);
379 return gen_im32(offset);
380 case 2: /* pc displacement */
381 tmp = gen_new_qreg(QMODE_I32);
382 offset = s->pc;
0633879f 383 offset += ldsw_code(s->pc);
e6e5906b
PB
384 s->pc += 2;
385 return gen_im32(offset);
386 case 3: /* pc index+displacement. */
387 return gen_lea_indexed(s, opsize, -1);
388 case 4: /* Immediate. */
389 default:
390 /* ??? generate bad addressing mode fault. */
391 qemu_assert(0, "invalid addressing mode");
392 }
393 }
394 /* Should never happen. */
395 return -1;
396}
397
398/* Helper function for gen_ea. Reuse the computed address between the
399 for read/write operands. */
400static inline int gen_ea_once(DisasContext *s, uint16_t insn, int opsize,
401 int val, int *addrp)
402{
403 int tmp;
404
405 if (addrp && val > 0) {
406 tmp = *addrp;
407 } else {
408 tmp = gen_lea(s, insn, opsize);
409 if (addrp)
410 *addrp = tmp;
411 }
0633879f 412 return gen_ldst(s, opsize, tmp, val);
e6e5906b
PB
413}
414
415/* Generate code to load/store a value ito/from an EA. If VAL > 0 this is
416 a write otherwise it is a read (0 == sign extend, -1 == zero extend).
417 ADDRP is non-null for readwrite operands. */
418static int gen_ea(DisasContext *s, uint16_t insn, int opsize, int val,
419 int *addrp)
420{
421 int reg;
422 int result;
423 uint32_t offset;
424
425 reg = insn & 7;
426 switch ((insn >> 3) & 7) {
427 case 0: /* Data register direct. */
428 reg += QREG_D0;
429 if (val > 0) {
430 gen_partset_reg(opsize, reg, val);
431 return 0;
432 } else {
433 return gen_extend(reg, opsize, val);
434 }
435 case 1: /* Address register direct. */
436 reg += QREG_A0;
437 if (val > 0) {
438 gen_op_mov32(reg, val);
439 return 0;
440 } else {
441 return gen_extend(reg, opsize, val);
442 }
443 case 2: /* Indirect register */
444 reg += QREG_A0;
0633879f 445 return gen_ldst(s, opsize, reg, val);
e6e5906b
PB
446 case 3: /* Indirect postincrement. */
447 reg += QREG_A0;
0633879f 448 result = gen_ldst(s, opsize, reg, val);
e6e5906b
PB
449 /* ??? This is not exception safe. The instruction may still
450 fault after this point. */
451 if (val > 0 || !addrp)
452 gen_op_add32(reg, reg, gen_im32(opsize_bytes(opsize)));
453 return result;
454 case 4: /* Indirect predecrememnt. */
455 {
456 int tmp;
457 if (addrp && val > 0) {
458 tmp = *addrp;
459 } else {
460 tmp = gen_lea(s, insn, opsize);
461 if (addrp)
462 *addrp = tmp;
463 }
0633879f 464 result = gen_ldst(s, opsize, tmp, val);
e6e5906b
PB
465 /* ??? This is not exception safe. The instruction may still
466 fault after this point. */
467 if (val > 0 || !addrp) {
468 reg += QREG_A0;
469 gen_op_mov32(reg, tmp);
470 }
471 }
472 return result;
473 case 5: /* Indirect displacement. */
474 case 6: /* Indirect index + displacement. */
475 return gen_ea_once(s, insn, opsize, val, addrp);
476 case 7: /* Other */
477 switch (reg) {
478 case 0: /* Absolute short. */
479 case 1: /* Absolute long. */
480 case 2: /* pc displacement */
481 case 3: /* pc index+displacement. */
482 return gen_ea_once(s, insn, opsize, val, addrp);
483 case 4: /* Immediate. */
484 /* Sign extend values for consistency. */
485 switch (opsize) {
486 case OS_BYTE:
487 if (val)
0633879f 488 offset = ldsb_code(s->pc + 1);
e6e5906b 489 else
0633879f 490 offset = ldub_code(s->pc + 1);
e6e5906b
PB
491 s->pc += 2;
492 break;
493 case OS_WORD:
494 if (val)
0633879f 495 offset = ldsw_code(s->pc);
e6e5906b 496 else
0633879f 497 offset = lduw_code(s->pc);
e6e5906b
PB
498 s->pc += 2;
499 break;
500 case OS_LONG:
501 offset = read_im32(s);
502 break;
503 default:
504 qemu_assert(0, "Bad immediate operand");
505 }
506 return gen_im32(offset);
507 default:
508 qemu_assert(0, "invalid addressing mode");
509 }
510 }
511 /* Should never happen. */
512 return -1;
513}
514
515static void gen_logic_cc(DisasContext *s, int val)
516{
517 gen_op_logic_cc(val);
518 s->cc_op = CC_OP_LOGIC;
519}
520
521static void gen_jmpcc(DisasContext *s, int cond, int l1)
522{
523 int tmp;
524
525 gen_flush_flags(s);
526 switch (cond) {
527 case 0: /* T */
528 gen_op_jmp(l1);
529 break;
530 case 1: /* F */
531 break;
532 case 2: /* HI (!C && !Z) */
533 tmp = gen_new_qreg(QMODE_I32);
534 gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_C | CCF_Z));
535 gen_op_jmp_z32(tmp, l1);
536 break;
537 case 3: /* LS (C || Z) */
538 tmp = gen_new_qreg(QMODE_I32);
539 gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_C | CCF_Z));
540 gen_op_jmp_nz32(tmp, l1);
541 break;
542 case 4: /* CC (!C) */
543 tmp = gen_new_qreg(QMODE_I32);
544 gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_C));
545 gen_op_jmp_z32(tmp, l1);
546 break;
547 case 5: /* CS (C) */
548 tmp = gen_new_qreg(QMODE_I32);
549 gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_C));
550 gen_op_jmp_nz32(tmp, l1);
551 break;
552 case 6: /* NE (!Z) */
553 tmp = gen_new_qreg(QMODE_I32);
554 gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_Z));
555 gen_op_jmp_z32(tmp, l1);
556 break;
557 case 7: /* EQ (Z) */
558 tmp = gen_new_qreg(QMODE_I32);
559 gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_Z));
560 gen_op_jmp_nz32(tmp, l1);
561 break;
562 case 8: /* VC (!V) */
563 tmp = gen_new_qreg(QMODE_I32);
564 gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_V));
565 gen_op_jmp_z32(tmp, l1);
566 break;
567 case 9: /* VS (V) */
568 tmp = gen_new_qreg(QMODE_I32);
569 gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_V));
570 gen_op_jmp_nz32(tmp, l1);
571 break;
572 case 10: /* PL (!N) */
573 tmp = gen_new_qreg(QMODE_I32);
574 gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_N));
575 gen_op_jmp_z32(tmp, l1);
576 break;
577 case 11: /* MI (N) */
578 tmp = gen_new_qreg(QMODE_I32);
579 gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_N));
580 gen_op_jmp_nz32(tmp, l1);
581 break;
582 case 12: /* GE (!(N ^ V)) */
583 tmp = gen_new_qreg(QMODE_I32);
584 gen_op_shr32(tmp, QREG_CC_DEST, gen_im32(2));
585 gen_op_xor32(tmp, tmp, QREG_CC_DEST);
586 gen_op_and32(tmp, tmp, gen_im32(CCF_V));
587 gen_op_jmp_z32(tmp, l1);
588 break;
589 case 13: /* LT (N ^ V) */
590 tmp = gen_new_qreg(QMODE_I32);
591 gen_op_shr32(tmp, QREG_CC_DEST, gen_im32(2));
592 gen_op_xor32(tmp, tmp, QREG_CC_DEST);
593 gen_op_and32(tmp, tmp, gen_im32(CCF_V));
594 gen_op_jmp_nz32(tmp, l1);
595 break;
596 case 14: /* GT (!(Z || (N ^ V))) */
597 {
598 int l2;
599 l2 = gen_new_label();
600 tmp = gen_new_qreg(QMODE_I32);
601 gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_Z));
602 gen_op_jmp_nz32(tmp, l2);
603 tmp = gen_new_qreg(QMODE_I32);
604 gen_op_shr32(tmp, QREG_CC_DEST, gen_im32(2));
605 gen_op_xor32(tmp, tmp, QREG_CC_DEST);
606 gen_op_and32(tmp, tmp, gen_im32(CCF_V));
607 gen_op_jmp_nz32(tmp, l2);
608 gen_op_jmp(l1);
609 gen_set_label(l2);
610 }
611 break;
612 case 15: /* LE (Z || (N ^ V)) */
613 tmp = gen_new_qreg(QMODE_I32);
614 gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_Z));
615 gen_op_jmp_nz32(tmp, l1);
616 tmp = gen_new_qreg(QMODE_I32);
617 gen_op_shr32(tmp, QREG_CC_DEST, gen_im32(2));
618 gen_op_xor32(tmp, tmp, QREG_CC_DEST);
619 gen_op_and32(tmp, tmp, gen_im32(CCF_V));
620 gen_op_jmp_nz32(tmp, l1);
621 break;
622 default:
623 /* Should ever happen. */
624 abort();
625 }
626}
627
628DISAS_INSN(scc)
629{
630 int l1;
631 int cond;
632 int reg;
633
634 l1 = gen_new_label();
635 cond = (insn >> 8) & 0xf;
636 reg = DREG(insn, 0);
637 gen_op_and32(reg, reg, gen_im32(0xffffff00));
638 gen_jmpcc(s, cond ^ 1, l1);
639 gen_op_or32(reg, reg, gen_im32(0xff));
640 gen_set_label(l1);
641}
642
0633879f
PB
643/* Force a TB lookup after an instruction that changes the CPU state. */
644static void gen_lookup_tb(DisasContext *s)
645{
646 gen_flush_cc_op(s);
647 gen_op_mov32(QREG_PC, gen_im32(s->pc));
648 s->is_jmp = DISAS_UPDATE;
649}
650
e6e5906b
PB
651/* Generate a jump to to the address in qreg DEST. */
652static void gen_jmp(DisasContext *s, int dest)
653{
654 gen_flush_cc_op(s);
655 gen_op_mov32(QREG_PC, dest);
656 s->is_jmp = DISAS_JUMP;
657}
658
659static void gen_exception(DisasContext *s, uint32_t where, int nr)
660{
661 gen_flush_cc_op(s);
662 gen_jmp(s, gen_im32(where));
663 gen_op_raise_exception(nr);
664}
665
666/* Generate a jump to an immediate address. */
667static void gen_jmp_tb(DisasContext *s, int n, uint32_t dest)
668{
669 TranslationBlock *tb;
670
671 tb = s->tb;
672 if (__builtin_expect (s->singlestep_enabled, 0)) {
673 gen_exception(s, dest, EXCP_DEBUG);
674 } else if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) ||
675 (s->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
676 gen_op_goto_tb(0, n, (long)tb);
677 gen_op_mov32(QREG_PC, gen_im32(dest));
678 gen_op_mov32(QREG_T0, gen_im32((long)tb + n));
679 gen_op_exit_tb();
680 } else {
681 gen_jmp(s, gen_im32(dest));
682 gen_op_mov32(QREG_T0, gen_im32(0));
683 gen_op_exit_tb();
684 }
685 s->is_jmp = DISAS_TB_JUMP;
686}
687
688DISAS_INSN(undef_mac)
689{
690 gen_exception(s, s->pc - 2, EXCP_LINEA);
691}
692
693DISAS_INSN(undef_fpu)
694{
695 gen_exception(s, s->pc - 2, EXCP_LINEF);
696}
697
698DISAS_INSN(undef)
699{
700 gen_exception(s, s->pc - 2, EXCP_UNSUPPORTED);
701 cpu_abort(cpu_single_env, "Illegal instruction: %04x @ %08x",
702 insn, s->pc - 2);
703}
704
705DISAS_INSN(mulw)
706{
707 int reg;
708 int tmp;
709 int src;
710 int sign;
711
712 sign = (insn & 0x100) != 0;
713 reg = DREG(insn, 9);
714 tmp = gen_new_qreg(QMODE_I32);
715 if (sign)
716 gen_op_ext16s32(tmp, reg);
717 else
718 gen_op_ext16u32(tmp, reg);
719 src = gen_ea(s, insn, OS_WORD, sign ? -1 : 0, NULL);
720 gen_op_mul32(tmp, tmp, src);
721 gen_op_mov32(reg, tmp);
722 /* Unlike m68k, coldfire always clears the overflow bit. */
723 gen_logic_cc(s, tmp);
724}
725
726DISAS_INSN(divw)
727{
728 int reg;
729 int tmp;
730 int src;
731 int sign;
732
733 sign = (insn & 0x100) != 0;
734 reg = DREG(insn, 9);
735 if (sign) {
736 gen_op_ext16s32(QREG_DIV1, reg);
737 } else {
738 gen_op_ext16u32(QREG_DIV1, reg);
739 }
740 src = gen_ea(s, insn, OS_WORD, sign ? -1 : 0, NULL);
741 gen_op_mov32(QREG_DIV2, src);
742 if (sign) {
743 gen_op_divs(1);
744 } else {
745 gen_op_divu(1);
746 }
747
748 tmp = gen_new_qreg(QMODE_I32);
749 src = gen_new_qreg(QMODE_I32);
750 gen_op_ext16u32(tmp, QREG_DIV1);
751 gen_op_shl32(src, QREG_DIV2, gen_im32(16));
752 gen_op_or32(reg, tmp, src);
753 gen_op_flags_set();
754 s->cc_op = CC_OP_FLAGS;
755}
756
757DISAS_INSN(divl)
758{
759 int num;
760 int den;
761 int reg;
762 uint16_t ext;
763
0633879f 764 ext = lduw_code(s->pc);
e6e5906b
PB
765 s->pc += 2;
766 if (ext & 0x87f8) {
767 gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED);
768 return;
769 }
770 num = DREG(ext, 12);
771 reg = DREG(ext, 0);
772 gen_op_mov32(QREG_DIV1, num);
773 den = gen_ea(s, insn, OS_LONG, 0, NULL);
774 gen_op_mov32(QREG_DIV2, den);
775 if (ext & 0x0800) {
2d37be61 776 gen_op_divs(2);
e6e5906b 777 } else {
2d37be61 778 gen_op_divu(2);
e6e5906b
PB
779 }
780 if (num == reg) {
781 /* div */
782 gen_op_mov32 (reg, QREG_DIV1);
783 } else {
784 /* rem */
785 gen_op_mov32 (reg, QREG_DIV2);
786 }
787 gen_op_flags_set();
788 s->cc_op = CC_OP_FLAGS;
789}
790
791DISAS_INSN(addsub)
792{
793 int reg;
794 int dest;
795 int src;
796 int tmp;
797 int addr;
798 int add;
799
800 add = (insn & 0x4000) != 0;
801 reg = DREG(insn, 9);
802 dest = gen_new_qreg(QMODE_I32);
803 if (insn & 0x100) {
804 tmp = gen_ea(s, insn, OS_LONG, 0, &addr);
805 src = reg;
806 } else {
807 tmp = reg;
808 src = gen_ea(s, insn, OS_LONG, 0, NULL);
809 }
810 if (add) {
811 gen_op_add32(dest, tmp, src);
812 gen_op_update_xflag_lt(dest, src);
813 s->cc_op = CC_OP_ADD;
814 } else {
815 gen_op_update_xflag_lt(tmp, src);
816 gen_op_sub32(dest, tmp, src);
817 s->cc_op = CC_OP_SUB;
818 }
819 gen_op_update_cc_add(dest, src);
820 if (insn & 0x100) {
821 gen_ea(s, insn, OS_LONG, dest, &addr);
822 } else {
823 gen_op_mov32(reg, dest);
824 }
825}
826
827
828/* Reverse the order of the bits in REG. */
829DISAS_INSN(bitrev)
830{
831 int val;
832 int tmp1;
833 int tmp2;
834 int reg;
835
836 val = gen_new_qreg(QMODE_I32);
837 tmp1 = gen_new_qreg(QMODE_I32);
838 tmp2 = gen_new_qreg(QMODE_I32);
839 reg = DREG(insn, 0);
840 gen_op_mov32(val, reg);
841 /* Reverse bits within each nibble. */
842 gen_op_shl32(tmp1, val, gen_im32(3));
843 gen_op_and32(tmp1, tmp1, gen_im32(0x88888888));
844 gen_op_shl32(tmp2, val, gen_im32(1));
845 gen_op_and32(tmp2, tmp2, gen_im32(0x44444444));
846 gen_op_or32(tmp1, tmp1, tmp2);
847 gen_op_shr32(tmp2, val, gen_im32(1));
848 gen_op_and32(tmp2, tmp2, gen_im32(0x22222222));
849 gen_op_or32(tmp1, tmp1, tmp2);
850 gen_op_shr32(tmp2, val, gen_im32(3));
851 gen_op_and32(tmp2, tmp2, gen_im32(0x11111111));
852 gen_op_or32(tmp1, tmp1, tmp2);
853 /* Reverse nibbles withing bytes. */
854 gen_op_shl32(val, tmp1, gen_im32(4));
855 gen_op_and32(val, val, gen_im32(0xf0f0f0f0));
856 gen_op_shr32(tmp2, tmp1, gen_im32(4));
857 gen_op_and32(tmp2, tmp2, gen_im32(0x0f0f0f0f));
858 gen_op_or32(val, val, tmp2);
859 /* Reverse bytes. */
860 gen_op_bswap32(reg, val);
861 gen_op_mov32(reg, val);
862}
863
864DISAS_INSN(bitop_reg)
865{
866 int opsize;
867 int op;
868 int src1;
869 int src2;
870 int tmp;
871 int addr;
872 int dest;
873
874 if ((insn & 0x38) != 0)
875 opsize = OS_BYTE;
876 else
877 opsize = OS_LONG;
878 op = (insn >> 6) & 3;
879 src1 = gen_ea(s, insn, opsize, 0, op ? &addr: NULL);
880 src2 = DREG(insn, 9);
881 dest = gen_new_qreg(QMODE_I32);
882
883 gen_flush_flags(s);
884 tmp = gen_new_qreg(QMODE_I32);
885 if (opsize == OS_BYTE)
886 gen_op_and32(tmp, src2, gen_im32(7));
887 else
888 gen_op_and32(tmp, src2, gen_im32(31));
889 src2 = tmp;
890 tmp = gen_new_qreg(QMODE_I32);
891 gen_op_shl32(tmp, gen_im32(1), src2);
892
893 gen_op_btest(src1, tmp);
894 switch (op) {
895 case 1: /* bchg */
896 gen_op_xor32(dest, src1, tmp);
897 break;
898 case 2: /* bclr */
899 gen_op_not32(tmp, tmp);
900 gen_op_and32(dest, src1, tmp);
901 break;
902 case 3: /* bset */
903 gen_op_or32(dest, src1, tmp);
904 break;
905 default: /* btst */
906 break;
907 }
908 if (op)
909 gen_ea(s, insn, opsize, dest, &addr);
910}
911
912DISAS_INSN(sats)
913{
914 int reg;
915 int tmp;
916 int l1;
917
918 reg = DREG(insn, 0);
919 tmp = gen_new_qreg(QMODE_I32);
920 gen_flush_flags(s);
921 gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_V));
922 l1 = gen_new_label();
923 gen_op_jmp_z32(tmp, l1);
924 tmp = gen_new_qreg(QMODE_I32);
925 gen_op_shr32(tmp, reg, gen_im32(31));
926 gen_op_xor32(tmp, tmp, gen_im32(0x80000000));
927 gen_op_mov32(reg, tmp);
928 gen_set_label(l1);
929 gen_logic_cc(s, tmp);
930}
931
0633879f 932static void gen_push(DisasContext *s, int val)
e6e5906b
PB
933{
934 int tmp;
935
936 tmp = gen_new_qreg(QMODE_I32);
937 gen_op_sub32(tmp, QREG_SP, gen_im32(4));
0633879f 938 gen_store(s, OS_LONG, tmp, val);
e6e5906b
PB
939 gen_op_mov32(QREG_SP, tmp);
940}
941
942DISAS_INSN(movem)
943{
944 int addr;
945 int i;
946 uint16_t mask;
947 int reg;
948 int tmp;
949 int is_load;
950
0633879f 951 mask = lduw_code(s->pc);
e6e5906b
PB
952 s->pc += 2;
953 tmp = gen_lea(s, insn, OS_LONG);
954 addr = gen_new_qreg(QMODE_I32);
955 gen_op_mov32(addr, tmp);
956 is_load = ((insn & 0x0400) != 0);
957 for (i = 0; i < 16; i++, mask >>= 1) {
958 if (mask & 1) {
959 if (i < 8)
960 reg = DREG(i, 0);
961 else
962 reg = AREG(i, 0);
963 if (is_load) {
0633879f 964 tmp = gen_load(s, OS_LONG, addr, 0);
e6e5906b
PB
965 gen_op_mov32(reg, tmp);
966 } else {
0633879f 967 gen_store(s, OS_LONG, addr, reg);
e6e5906b
PB
968 }
969 if (mask != 1)
970 gen_op_add32(addr, addr, gen_im32(4));
971 }
972 }
973}
974
975DISAS_INSN(bitop_im)
976{
977 int opsize;
978 int op;
979 int src1;
980 uint32_t mask;
981 int bitnum;
982 int tmp;
983 int addr;
984 int dest;
985
986 if ((insn & 0x38) != 0)
987 opsize = OS_BYTE;
988 else
989 opsize = OS_LONG;
990 op = (insn >> 6) & 3;
991
0633879f 992 bitnum = lduw_code(s->pc);
e6e5906b
PB
993 s->pc += 2;
994 if (bitnum & 0xff00) {
995 disas_undef(s, insn);
996 return;
997 }
998
999 src1 = gen_ea(s, insn, opsize, 0, op ? &addr: NULL);
1000
1001 gen_flush_flags(s);
1002 tmp = gen_new_qreg(QMODE_I32);
1003 if (opsize == OS_BYTE)
1004 bitnum &= 7;
1005 else
1006 bitnum &= 31;
1007 mask = 1 << bitnum;
1008
1009 gen_op_btest(src1, gen_im32(mask));
1010 if (op)
1011 dest = gen_new_qreg(QMODE_I32);
1012 else
1013 dest = -1;
1014
1015 switch (op) {
1016 case 1: /* bchg */
1017 gen_op_xor32(dest, src1, gen_im32(mask));
1018 break;
1019 case 2: /* bclr */
1020 gen_op_and32(dest, src1, gen_im32(~mask));
1021 break;
1022 case 3: /* bset */
1023 gen_op_or32(dest, src1, gen_im32(mask));
1024 break;
1025 default: /* btst */
1026 break;
1027 }
1028 if (op)
1029 gen_ea(s, insn, opsize, dest, &addr);
1030}
1031
1032DISAS_INSN(arith_im)
1033{
1034 int op;
1035 int src1;
1036 int dest;
1037 int src2;
1038 int addr;
1039
1040 op = (insn >> 9) & 7;
1041 src1 = gen_ea(s, insn, OS_LONG, 0, (op == 6) ? NULL : &addr);
1042 src2 = gen_im32(read_im32(s));
1043 dest = gen_new_qreg(QMODE_I32);
1044 switch (op) {
1045 case 0: /* ori */
1046 gen_op_or32(dest, src1, src2);
1047 gen_logic_cc(s, dest);
1048 break;
1049 case 1: /* andi */
1050 gen_op_and32(dest, src1, src2);
1051 gen_logic_cc(s, dest);
1052 break;
1053 case 2: /* subi */
1054 gen_op_mov32(dest, src1);
1055 gen_op_update_xflag_lt(dest, src2);
1056 gen_op_sub32(dest, dest, src2);
1057 gen_op_update_cc_add(dest, src2);
1058 s->cc_op = CC_OP_SUB;
1059 break;
1060 case 3: /* addi */
1061 gen_op_mov32(dest, src1);
1062 gen_op_add32(dest, dest, src2);
1063 gen_op_update_cc_add(dest, src2);
1064 gen_op_update_xflag_lt(dest, src2);
1065 s->cc_op = CC_OP_ADD;
1066 break;
1067 case 5: /* eori */
1068 gen_op_xor32(dest, src1, src2);
1069 gen_logic_cc(s, dest);
1070 break;
1071 case 6: /* cmpi */
1072 gen_op_mov32(dest, src1);
1073 gen_op_sub32(dest, dest, src2);
1074 gen_op_update_cc_add(dest, src2);
1075 s->cc_op = CC_OP_SUB;
1076 break;
1077 default:
1078 abort();
1079 }
1080 if (op != 6) {
1081 gen_ea(s, insn, OS_LONG, dest, &addr);
1082 }
1083}
1084
1085DISAS_INSN(byterev)
1086{
1087 int reg;
1088
1089 reg = DREG(insn, 0);
1090 gen_op_bswap32(reg, reg);
1091}
1092
1093DISAS_INSN(move)
1094{
1095 int src;
1096 int dest;
1097 int op;
1098 int opsize;
1099
1100 switch (insn >> 12) {
1101 case 1: /* move.b */
1102 opsize = OS_BYTE;
1103 break;
1104 case 2: /* move.l */
1105 opsize = OS_LONG;
1106 break;
1107 case 3: /* move.w */
1108 opsize = OS_WORD;
1109 break;
1110 default:
1111 abort();
1112 }
1113 src = gen_ea(s, insn, opsize, -1, NULL);
1114 op = (insn >> 6) & 7;
1115 if (op == 1) {
1116 /* movea */
1117 /* The value will already have been sign extended. */
1118 dest = AREG(insn, 9);
1119 gen_op_mov32(dest, src);
1120 } else {
1121 /* normal move */
1122 uint16_t dest_ea;
1123 dest_ea = ((insn >> 9) & 7) | (op << 3);
1124 gen_ea(s, dest_ea, opsize, src, NULL);
1125 /* This will be correct because loads sign extend. */
1126 gen_logic_cc(s, src);
1127 }
1128}
1129
1130DISAS_INSN(negx)
1131{
1132 int reg;
1133 int dest;
1134 int tmp;
1135
1136 gen_flush_flags(s);
1137 reg = DREG(insn, 0);
1138 dest = gen_new_qreg(QMODE_I32);
1139 gen_op_mov32 (dest, gen_im32(0));
1140 gen_op_subx_cc(dest, reg);
1141 /* !Z is sticky. */
1142 tmp = gen_new_qreg(QMODE_I32);
1143 gen_op_mov32 (tmp, QREG_CC_DEST);
1144 gen_op_update_cc_add(dest, reg);
1145 gen_op_mov32(reg, dest);
1146 s->cc_op = CC_OP_DYNAMIC;
1147 gen_flush_flags(s);
1148 gen_op_or32(tmp, tmp, gen_im32(~CCF_Z));
1149 gen_op_and32(QREG_CC_DEST, QREG_CC_DEST, tmp);
1150 s->cc_op = CC_OP_FLAGS;
1151}
1152
1153DISAS_INSN(lea)
1154{
1155 int reg;
1156 int tmp;
1157
1158 reg = AREG(insn, 9);
1159 tmp = gen_lea(s, insn, OS_LONG);
1160 gen_op_mov32(reg, tmp);
1161}
1162
1163DISAS_INSN(clr)
1164{
1165 int opsize;
1166
1167 switch ((insn >> 6) & 3) {
1168 case 0: /* clr.b */
1169 opsize = OS_BYTE;
1170 break;
1171 case 1: /* clr.w */
1172 opsize = OS_WORD;
1173 break;
1174 case 2: /* clr.l */
1175 opsize = OS_LONG;
1176 break;
1177 default:
1178 abort();
1179 }
1180 gen_ea (s, insn, opsize, gen_im32(0), NULL);
1181 gen_logic_cc(s, gen_im32(0));
1182}
1183
0633879f 1184static int gen_get_ccr(DisasContext *s)
e6e5906b 1185{
e6e5906b
PB
1186 int dest;
1187
1188 gen_flush_flags(s);
1189 dest = gen_new_qreg(QMODE_I32);
1190 gen_op_get_xflag(dest);
1191 gen_op_shl32(dest, dest, gen_im32(4));
1192 gen_op_or32(dest, dest, QREG_CC_DEST);
0633879f
PB
1193 return dest;
1194}
1195
1196DISAS_INSN(move_from_ccr)
1197{
1198 int reg;
1199 int ccr;
1200
1201 ccr = gen_get_ccr(s);
e6e5906b 1202 reg = DREG(insn, 0);
0633879f 1203 gen_partset_reg(OS_WORD, reg, ccr);
e6e5906b
PB
1204}
1205
1206DISAS_INSN(neg)
1207{
1208 int reg;
1209 int src1;
1210
1211 reg = DREG(insn, 0);
1212 src1 = gen_new_qreg(QMODE_I32);
1213 gen_op_mov32(src1, reg);
1214 gen_op_neg32(reg, src1);
1215 s->cc_op = CC_OP_SUB;
1216 gen_op_update_cc_add(reg, src1);
1217 gen_op_update_xflag_lt(gen_im32(0), src1);
1218 s->cc_op = CC_OP_SUB;
1219}
1220
0633879f
PB
1221static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only)
1222{
1223 gen_op_logic_cc(gen_im32(val & 0xf));
1224 gen_op_update_xflag_tst(gen_im32((val & 0x10) >> 4));
1225 if (!ccr_only) {
1226 gen_op_mov32(QREG_SR, gen_im32(val & 0xff00));
1227 }
1228}
1229
1230static void gen_set_sr(DisasContext *s, uint16_t insn, int ccr_only)
e6e5906b
PB
1231{
1232 int src1;
1233 int reg;
1234
1235 s->cc_op = CC_OP_FLAGS;
1236 if ((insn & 0x38) == 0)
1237 {
1238 src1 = gen_new_qreg(QMODE_I32);
1239 reg = DREG(insn, 0);
1240 gen_op_and32(src1, reg, gen_im32(0xf));
1241 gen_op_logic_cc(src1);
1242 gen_op_shr32(src1, reg, gen_im32(4));
1243 gen_op_and32(src1, src1, gen_im32(1));
1244 gen_op_update_xflag_tst(src1);
0633879f
PB
1245 if (!ccr_only) {
1246 gen_op_and32(QREG_SR, reg, gen_im32(0xff00));
1247 }
e6e5906b 1248 }
0633879f 1249 else if ((insn & 0x3f) == 0x3c)
e6e5906b 1250 {
0633879f
PB
1251 uint16_t val;
1252 val = lduw_code(s->pc);
e6e5906b 1253 s->pc += 2;
0633879f 1254 gen_set_sr_im(s, val, ccr_only);
e6e5906b
PB
1255 }
1256 else
1257 disas_undef(s, insn);
1258}
1259
0633879f
PB
1260DISAS_INSN(move_to_ccr)
1261{
1262 gen_set_sr(s, insn, 1);
1263}
1264
e6e5906b
PB
1265DISAS_INSN(not)
1266{
1267 int reg;
1268
1269 reg = DREG(insn, 0);
1270 gen_op_not32(reg, reg);
1271 gen_logic_cc(s, reg);
1272}
1273
1274DISAS_INSN(swap)
1275{
1276 int dest;
1277 int src1;
1278 int src2;
1279 int reg;
1280
1281 dest = gen_new_qreg(QMODE_I32);
1282 src1 = gen_new_qreg(QMODE_I32);
1283 src2 = gen_new_qreg(QMODE_I32);
1284 reg = DREG(insn, 0);
1285 gen_op_shl32(src1, reg, gen_im32(16));
1286 gen_op_shr32(src2, reg, gen_im32(16));
1287 gen_op_or32(dest, src1, src2);
1288 gen_op_mov32(reg, dest);
1289 gen_logic_cc(s, dest);
1290}
1291
1292DISAS_INSN(pea)
1293{
1294 int tmp;
1295
1296 tmp = gen_lea(s, insn, OS_LONG);
0633879f 1297 gen_push(s, tmp);
e6e5906b
PB
1298}
1299
1300DISAS_INSN(ext)
1301{
1302 int reg;
1303 int op;
1304 int tmp;
1305
1306 reg = DREG(insn, 0);
1307 op = (insn >> 6) & 7;
1308 tmp = gen_new_qreg(QMODE_I32);
1309 if (op == 3)
1310 gen_op_ext16s32(tmp, reg);
1311 else
1312 gen_op_ext8s32(tmp, reg);
1313 if (op == 2)
1314 gen_partset_reg(OS_WORD, reg, tmp);
1315 else
1316 gen_op_mov32(reg, tmp);
1317 gen_logic_cc(s, tmp);
1318}
1319
1320DISAS_INSN(tst)
1321{
1322 int opsize;
1323 int tmp;
1324
1325 switch ((insn >> 6) & 3) {
1326 case 0: /* tst.b */
1327 opsize = OS_BYTE;
1328 break;
1329 case 1: /* tst.w */
1330 opsize = OS_WORD;
1331 break;
1332 case 2: /* tst.l */
1333 opsize = OS_LONG;
1334 break;
1335 default:
1336 abort();
1337 }
1338 tmp = gen_ea(s, insn, opsize, -1, NULL);
1339 gen_logic_cc(s, tmp);
1340}
1341
1342DISAS_INSN(pulse)
1343{
1344 /* Implemented as a NOP. */
1345}
1346
1347DISAS_INSN(illegal)
1348{
1349 gen_exception(s, s->pc - 2, EXCP_ILLEGAL);
1350}
1351
1352/* ??? This should be atomic. */
1353DISAS_INSN(tas)
1354{
1355 int dest;
1356 int src1;
1357 int addr;
1358
1359 dest = gen_new_qreg(QMODE_I32);
1360 src1 = gen_ea(s, insn, OS_BYTE, -1, &addr);
1361 gen_logic_cc(s, src1);
1362 gen_op_or32(dest, src1, gen_im32(0x80));
1363 gen_ea(s, insn, OS_BYTE, dest, &addr);
1364}
1365
1366DISAS_INSN(mull)
1367{
1368 uint16_t ext;
1369 int reg;
1370 int src1;
1371 int dest;
1372
1373 /* The upper 32 bits of the product are discarded, so
1374 muls.l and mulu.l are functionally equivalent. */
0633879f 1375 ext = lduw_code(s->pc);
e6e5906b
PB
1376 s->pc += 2;
1377 if (ext & 0x87ff) {
1378 gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED);
1379 return;
1380 }
1381 reg = DREG(ext, 12);
1382 src1 = gen_ea(s, insn, OS_LONG, 0, NULL);
1383 dest = gen_new_qreg(QMODE_I32);
1384 gen_op_mul32(dest, src1, reg);
1385 gen_op_mov32(reg, dest);
1386 /* Unlike m68k, coldfire always clears the overflow bit. */
1387 gen_logic_cc(s, dest);
1388}
1389
1390DISAS_INSN(link)
1391{
1392 int16_t offset;
1393 int reg;
1394 int tmp;
1395
0633879f 1396 offset = ldsw_code(s->pc);
e6e5906b
PB
1397 s->pc += 2;
1398 reg = AREG(insn, 0);
1399 tmp = gen_new_qreg(QMODE_I32);
1400 gen_op_sub32(tmp, QREG_SP, gen_im32(4));
0633879f 1401 gen_store(s, OS_LONG, tmp, reg);
e6e5906b
PB
1402 if (reg != QREG_SP)
1403 gen_op_mov32(reg, tmp);
1404 gen_op_add32(QREG_SP, tmp, gen_im32(offset));
1405}
1406
1407DISAS_INSN(unlk)
1408{
1409 int src;
1410 int reg;
1411 int tmp;
1412
1413 src = gen_new_qreg(QMODE_I32);
1414 reg = AREG(insn, 0);
1415 gen_op_mov32(src, reg);
0633879f 1416 tmp = gen_load(s, OS_LONG, src, 0);
e6e5906b
PB
1417 gen_op_mov32(reg, tmp);
1418 gen_op_add32(QREG_SP, src, gen_im32(4));
1419}
1420
1421DISAS_INSN(nop)
1422{
1423}
1424
1425DISAS_INSN(rts)
1426{
1427 int tmp;
1428
0633879f 1429 tmp = gen_load(s, OS_LONG, QREG_SP, 0);
e6e5906b
PB
1430 gen_op_add32(QREG_SP, QREG_SP, gen_im32(4));
1431 gen_jmp(s, tmp);
1432}
1433
1434DISAS_INSN(jump)
1435{
1436 int tmp;
1437
1438 /* Load the target address first to ensure correct exception
1439 behavior. */
1440 tmp = gen_lea(s, insn, OS_LONG);
1441 if ((insn & 0x40) == 0) {
1442 /* jsr */
0633879f 1443 gen_push(s, gen_im32(s->pc));
e6e5906b
PB
1444 }
1445 gen_jmp(s, tmp);
1446}
1447
1448DISAS_INSN(addsubq)
1449{
1450 int src1;
1451 int src2;
1452 int dest;
1453 int val;
1454 int addr;
1455
1456 src1 = gen_ea(s, insn, OS_LONG, 0, &addr);
1457 val = (insn >> 9) & 7;
1458 if (val == 0)
1459 val = 8;
1460 src2 = gen_im32(val);
1461 dest = gen_new_qreg(QMODE_I32);
1462 gen_op_mov32(dest, src1);
1463 if ((insn & 0x38) == 0x08) {
1464 /* Don't update condition codes if the destination is an
1465 address register. */
1466 if (insn & 0x0100) {
1467 gen_op_sub32(dest, dest, src2);
1468 } else {
1469 gen_op_add32(dest, dest, src2);
1470 }
1471 } else {
1472 if (insn & 0x0100) {
1473 gen_op_update_xflag_lt(dest, src2);
1474 gen_op_sub32(dest, dest, src2);
1475 s->cc_op = CC_OP_SUB;
1476 } else {
1477 gen_op_add32(dest, dest, src2);
1478 gen_op_update_xflag_lt(dest, src2);
1479 s->cc_op = CC_OP_ADD;
1480 }
1481 gen_op_update_cc_add(dest, src2);
1482 }
1483 gen_ea(s, insn, OS_LONG, dest, &addr);
1484}
1485
1486DISAS_INSN(tpf)
1487{
1488 switch (insn & 7) {
1489 case 2: /* One extension word. */
1490 s->pc += 2;
1491 break;
1492 case 3: /* Two extension words. */
1493 s->pc += 4;
1494 break;
1495 case 4: /* No extension words. */
1496 break;
1497 default:
1498 disas_undef(s, insn);
1499 }
1500}
1501
1502DISAS_INSN(branch)
1503{
1504 int32_t offset;
1505 uint32_t base;
1506 int op;
1507 int l1;
1508
1509 base = s->pc;
1510 op = (insn >> 8) & 0xf;
1511 offset = (int8_t)insn;
1512 if (offset == 0) {
0633879f 1513 offset = ldsw_code(s->pc);
e6e5906b
PB
1514 s->pc += 2;
1515 } else if (offset == -1) {
1516 offset = read_im32(s);
1517 }
1518 if (op == 1) {
1519 /* bsr */
0633879f 1520 gen_push(s, gen_im32(s->pc));
e6e5906b
PB
1521 }
1522 gen_flush_cc_op(s);
1523 if (op > 1) {
1524 /* Bcc */
1525 l1 = gen_new_label();
1526 gen_jmpcc(s, ((insn >> 8) & 0xf) ^ 1, l1);
1527 gen_jmp_tb(s, 1, base + offset);
1528 gen_set_label(l1);
1529 gen_jmp_tb(s, 0, s->pc);
1530 } else {
1531 /* Unconditional branch. */
1532 gen_jmp_tb(s, 0, base + offset);
1533 }
1534}
1535
1536DISAS_INSN(moveq)
1537{
1538 int tmp;
1539
1540 tmp = gen_im32((int8_t)insn);
1541 gen_op_mov32(DREG(insn, 9), tmp);
1542 gen_logic_cc(s, tmp);
1543}
1544
1545DISAS_INSN(mvzs)
1546{
1547 int opsize;
1548 int src;
1549 int reg;
1550
1551 if (insn & 0x40)
1552 opsize = OS_WORD;
1553 else
1554 opsize = OS_BYTE;
1555 src = gen_ea(s, insn, opsize, (insn & 0x80) ? 0 : -1, NULL);
1556 reg = DREG(insn, 9);
1557 gen_op_mov32(reg, src);
1558 gen_logic_cc(s, src);
1559}
1560
1561DISAS_INSN(or)
1562{
1563 int reg;
1564 int dest;
1565 int src;
1566 int addr;
1567
1568 reg = DREG(insn, 9);
1569 dest = gen_new_qreg(QMODE_I32);
1570 if (insn & 0x100) {
1571 src = gen_ea(s, insn, OS_LONG, 0, &addr);
1572 gen_op_or32(dest, src, reg);
1573 gen_ea(s, insn, OS_LONG, dest, &addr);
1574 } else {
1575 src = gen_ea(s, insn, OS_LONG, 0, NULL);
1576 gen_op_or32(dest, src, reg);
1577 gen_op_mov32(reg, dest);
1578 }
1579 gen_logic_cc(s, dest);
1580}
1581
1582DISAS_INSN(suba)
1583{
1584 int src;
1585 int reg;
1586
1587 src = gen_ea(s, insn, OS_LONG, 0, NULL);
1588 reg = AREG(insn, 9);
1589 gen_op_sub32(reg, reg, src);
1590}
1591
1592DISAS_INSN(subx)
1593{
1594 int reg;
1595 int src;
1596 int dest;
1597 int tmp;
1598
1599 gen_flush_flags(s);
1600 reg = DREG(insn, 9);
1601 src = DREG(insn, 0);
1602 dest = gen_new_qreg(QMODE_I32);
1603 gen_op_mov32 (dest, reg);
1604 gen_op_subx_cc(dest, src);
1605 /* !Z is sticky. */
1606 tmp = gen_new_qreg(QMODE_I32);
1607 gen_op_mov32 (tmp, QREG_CC_DEST);
1608 gen_op_update_cc_add(dest, src);
1609 gen_op_mov32(reg, dest);
1610 s->cc_op = CC_OP_DYNAMIC;
1611 gen_flush_flags(s);
1612 gen_op_or32(tmp, tmp, gen_im32(~CCF_Z));
1613 gen_op_and32(QREG_CC_DEST, QREG_CC_DEST, tmp);
1614 s->cc_op = CC_OP_FLAGS;
1615}
1616
1617DISAS_INSN(mov3q)
1618{
1619 int src;
1620 int val;
1621
1622 val = (insn >> 9) & 7;
1623 if (val == 0)
1624 val = -1;
1625 src = gen_im32(val);
1626 gen_logic_cc(s, src);
1627 gen_ea(s, insn, OS_LONG, src, NULL);
1628}
1629
1630DISAS_INSN(cmp)
1631{
1632 int op;
1633 int src;
1634 int reg;
1635 int dest;
1636 int opsize;
1637
1638 op = (insn >> 6) & 3;
1639 switch (op) {
1640 case 0: /* cmp.b */
1641 opsize = OS_BYTE;
1642 s->cc_op = CC_OP_CMPB;
1643 break;
1644 case 1: /* cmp.w */
1645 opsize = OS_WORD;
1646 s->cc_op = CC_OP_CMPW;
1647 break;
1648 case 2: /* cmp.l */
1649 opsize = OS_LONG;
1650 s->cc_op = CC_OP_SUB;
1651 break;
1652 default:
1653 abort();
1654 }
1655 src = gen_ea(s, insn, opsize, -1, NULL);
1656 reg = DREG(insn, 9);
1657 dest = gen_new_qreg(QMODE_I32);
1658 gen_op_sub32(dest, reg, src);
1659 gen_op_update_cc_add(dest, src);
1660}
1661
1662DISAS_INSN(cmpa)
1663{
1664 int opsize;
1665 int src;
1666 int reg;
1667 int dest;
1668
1669 if (insn & 0x100) {
1670 opsize = OS_LONG;
1671 } else {
1672 opsize = OS_WORD;
1673 }
1674 src = gen_ea(s, insn, opsize, -1, NULL);
1675 reg = AREG(insn, 9);
1676 dest = gen_new_qreg(QMODE_I32);
1677 gen_op_sub32(dest, reg, src);
1678 gen_op_update_cc_add(dest, src);
1679 s->cc_op = CC_OP_SUB;
1680}
1681
1682DISAS_INSN(eor)
1683{
1684 int src;
1685 int reg;
1686 int dest;
1687 int addr;
1688
1689 src = gen_ea(s, insn, OS_LONG, 0, &addr);
1690 reg = DREG(insn, 9);
1691 dest = gen_new_qreg(QMODE_I32);
1692 gen_op_xor32(dest, src, reg);
1693 gen_logic_cc(s, dest);
1694 gen_ea(s, insn, OS_LONG, dest, &addr);
1695}
1696
1697DISAS_INSN(and)
1698{
1699 int src;
1700 int reg;
1701 int dest;
1702 int addr;
1703
1704 reg = DREG(insn, 9);
1705 dest = gen_new_qreg(QMODE_I32);
1706 if (insn & 0x100) {
1707 src = gen_ea(s, insn, OS_LONG, 0, &addr);
1708 gen_op_and32(dest, src, reg);
1709 gen_ea(s, insn, OS_LONG, dest, &addr);
1710 } else {
1711 src = gen_ea(s, insn, OS_LONG, 0, NULL);
1712 gen_op_and32(dest, src, reg);
1713 gen_op_mov32(reg, dest);
1714 }
1715 gen_logic_cc(s, dest);
1716}
1717
1718DISAS_INSN(adda)
1719{
1720 int src;
1721 int reg;
1722
1723 src = gen_ea(s, insn, OS_LONG, 0, NULL);
1724 reg = AREG(insn, 9);
1725 gen_op_add32(reg, reg, src);
1726}
1727
1728DISAS_INSN(addx)
1729{
1730 int reg;
1731 int src;
1732 int dest;
1733 int tmp;
1734
1735 gen_flush_flags(s);
1736 reg = DREG(insn, 9);
1737 src = DREG(insn, 0);
1738 dest = gen_new_qreg(QMODE_I32);
1739 gen_op_mov32 (dest, reg);
1740 gen_op_addx_cc(dest, src);
1741 /* !Z is sticky. */
1742 tmp = gen_new_qreg(QMODE_I32);
1743 gen_op_mov32 (tmp, QREG_CC_DEST);
1744 gen_op_update_cc_add(dest, src);
1745 gen_op_mov32(reg, dest);
1746 s->cc_op = CC_OP_DYNAMIC;
1747 gen_flush_flags(s);
1748 gen_op_or32(tmp, tmp, gen_im32(~CCF_Z));
1749 gen_op_and32(QREG_CC_DEST, QREG_CC_DEST, tmp);
1750 s->cc_op = CC_OP_FLAGS;
1751}
1752
1753DISAS_INSN(shift_im)
1754{
1755 int reg;
1756 int tmp;
1757
1758 reg = DREG(insn, 0);
1759 tmp = (insn >> 9) & 7;
1760 if (tmp == 0)
1761 tmp = 8;
1762 if (insn & 0x100) {
1763 gen_op_shl_im_cc(reg, tmp);
1764 s->cc_op = CC_OP_SHL;
1765 } else {
1766 if (insn & 8) {
1767 gen_op_shr_im_cc(reg, tmp);
1768 s->cc_op = CC_OP_SHR;
1769 } else {
1770 gen_op_sar_im_cc(reg, tmp);
1771 s->cc_op = CC_OP_SAR;
1772 }
1773 }
1774}
1775
1776DISAS_INSN(shift_reg)
1777{
1778 int reg;
1779 int src;
1780 int tmp;
1781
1782 reg = DREG(insn, 0);
1783 src = DREG(insn, 9);
1784 tmp = gen_new_qreg(QMODE_I32);
1785 gen_op_and32(tmp, src, gen_im32(63));
1786 if (insn & 0x100) {
1787 gen_op_shl_cc(reg, tmp);
1788 s->cc_op = CC_OP_SHL;
1789 } else {
1790 if (insn & 8) {
1791 gen_op_shr_cc(reg, tmp);
1792 s->cc_op = CC_OP_SHR;
1793 } else {
1794 gen_op_sar_cc(reg, tmp);
1795 s->cc_op = CC_OP_SAR;
1796 }
1797 }
1798}
1799
1800DISAS_INSN(ff1)
1801{
1802 cpu_abort(NULL, "Unimplemented insn: ff1");
1803}
1804
0633879f
PB
1805static int gen_get_sr(DisasContext *s)
1806{
1807 int ccr;
1808 int sr;
1809
1810 ccr = gen_get_ccr(s);
1811 sr = gen_new_qreg(QMODE_I32);
1812 gen_op_and32(sr, QREG_SR, gen_im32(0xffe0));
1813 gen_op_or32(sr, sr, ccr);
1814 return sr;
1815}
1816
e6e5906b
PB
1817DISAS_INSN(strldsr)
1818{
1819 uint16_t ext;
1820 uint32_t addr;
1821
1822 addr = s->pc - 2;
0633879f 1823 ext = lduw_code(s->pc);
e6e5906b 1824 s->pc += 2;
0633879f 1825 if (ext != 0x46FC) {
e6e5906b 1826 gen_exception(s, addr, EXCP_UNSUPPORTED);
0633879f
PB
1827 return;
1828 }
1829 ext = lduw_code(s->pc);
1830 s->pc += 2;
1831 if (IS_USER(s) || (ext & SR_S) == 0) {
e6e5906b 1832 gen_exception(s, addr, EXCP_PRIVILEGE);
0633879f
PB
1833 return;
1834 }
1835 gen_push(s, gen_get_sr(s));
1836 gen_set_sr_im(s, ext, 0);
e6e5906b
PB
1837}
1838
1839DISAS_INSN(move_from_sr)
1840{
0633879f
PB
1841 int reg;
1842 int sr;
1843
1844 if (IS_USER(s)) {
1845 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
1846 return;
1847 }
1848 sr = gen_get_sr(s);
1849 reg = DREG(insn, 0);
1850 gen_partset_reg(OS_WORD, reg, sr);
e6e5906b
PB
1851}
1852
1853DISAS_INSN(move_to_sr)
1854{
0633879f
PB
1855 if (IS_USER(s)) {
1856 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
1857 return;
1858 }
1859 gen_set_sr(s, insn, 0);
1860 gen_lookup_tb(s);
e6e5906b
PB
1861}
1862
1863DISAS_INSN(move_from_usp)
1864{
0633879f
PB
1865 if (IS_USER(s)) {
1866 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
1867 return;
1868 }
1869 /* TODO: Implement USP. */
1870 gen_exception(s, s->pc - 2, EXCP_ILLEGAL);
e6e5906b
PB
1871}
1872
1873DISAS_INSN(move_to_usp)
1874{
0633879f
PB
1875 if (IS_USER(s)) {
1876 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
1877 return;
1878 }
1879 /* TODO: Implement USP. */
1880 gen_exception(s, s->pc - 2, EXCP_ILLEGAL);
e6e5906b
PB
1881}
1882
1883DISAS_INSN(halt)
1884{
0633879f
PB
1885 gen_jmp(s, gen_im32(s->pc));
1886 gen_op_halt();
e6e5906b
PB
1887}
1888
1889DISAS_INSN(stop)
1890{
0633879f
PB
1891 uint16_t ext;
1892
1893 if (IS_USER(s)) {
1894 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
1895 return;
1896 }
1897
1898 ext = lduw_code(s->pc);
1899 s->pc += 2;
1900
1901 gen_set_sr_im(s, ext, 0);
a87295e8
PB
1902 gen_jmp(s, gen_im32(s->pc));
1903 gen_op_stop();
e6e5906b
PB
1904}
1905
1906DISAS_INSN(rte)
1907{
0633879f
PB
1908 if (IS_USER(s)) {
1909 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
1910 return;
1911 }
1912 gen_exception(s, s->pc - 2, EXCP_RTE);
e6e5906b
PB
1913}
1914
1915DISAS_INSN(movec)
1916{
0633879f
PB
1917 uint16_t ext;
1918 int reg;
1919
1920 if (IS_USER(s)) {
1921 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
1922 return;
1923 }
1924
1925 ext = lduw_code(s->pc);
1926 s->pc += 2;
1927
1928 if (ext & 0x8000) {
1929 reg = AREG(ext, 12);
1930 } else {
1931 reg = DREG(ext, 12);
1932 }
1933 gen_op_movec(gen_im32(ext & 0xfff), reg);
1934 gen_lookup_tb(s);
e6e5906b
PB
1935}
1936
1937DISAS_INSN(intouch)
1938{
0633879f
PB
1939 if (IS_USER(s)) {
1940 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
1941 return;
1942 }
1943 /* ICache fetch. Implement as no-op. */
e6e5906b
PB
1944}
1945
1946DISAS_INSN(cpushl)
1947{
0633879f
PB
1948 if (IS_USER(s)) {
1949 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
1950 return;
1951 }
1952 /* Cache push/invalidate. Implement as no-op. */
e6e5906b
PB
1953}
1954
1955DISAS_INSN(wddata)
1956{
1957 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
1958}
1959
1960DISAS_INSN(wdebug)
1961{
0633879f
PB
1962 if (IS_USER(s)) {
1963 gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
1964 return;
1965 }
1966 /* TODO: Implement wdebug. */
1967 qemu_assert(0, "WDEBUG not implemented");
e6e5906b
PB
1968}
1969
1970DISAS_INSN(trap)
1971{
1972 gen_exception(s, s->pc - 2, EXCP_TRAP0 + (insn & 0xf));
1973}
1974
1975/* ??? FP exceptions are not implemented. Most exceptions are deferred until
1976 immediately before the next FP instruction is executed. */
1977DISAS_INSN(fpu)
1978{
1979 uint16_t ext;
1980 int opmode;
1981 int src;
1982 int dest;
1983 int res;
1984 int round;
1985 int opsize;
1986
0633879f 1987 ext = lduw_code(s->pc);
e6e5906b
PB
1988 s->pc += 2;
1989 opmode = ext & 0x7f;
1990 switch ((ext >> 13) & 7) {
1991 case 0: case 2:
1992 break;
1993 case 1:
1994 goto undef;
1995 case 3: /* fmove out */
1996 src = FREG(ext, 7);
1997 /* fmove */
1998 /* ??? TODO: Proper behavior on overflow. */
1999 switch ((ext >> 10) & 7) {
2000 case 0:
2001 opsize = OS_LONG;
2002 res = gen_new_qreg(QMODE_I32);
2003 gen_op_f64_to_i32(res, src);
2004 break;
2005 case 1:
2006 opsize = OS_SINGLE;
2007 res = gen_new_qreg(QMODE_F32);
2008 gen_op_f64_to_f32(res, src);
2009 break;
2010 case 4:
2011 opsize = OS_WORD;
2012 res = gen_new_qreg(QMODE_I32);
2013 gen_op_f64_to_i32(res, src);
2014 break;
2015 case 5:
2016 opsize = OS_DOUBLE;
2017 res = src;
2018 break;
2019 case 6:
2020 opsize = OS_BYTE;
2021 res = gen_new_qreg(QMODE_I32);
2022 gen_op_f64_to_i32(res, src);
2023 break;
2024 default:
2025 goto undef;
2026 }
2027 gen_ea(s, insn, opsize, res, NULL);
2028 return;
2029 case 4: /* fmove to control register. */
2030 switch ((ext >> 10) & 7) {
2031 case 4: /* FPCR */
2032 /* Not implemented. Ignore writes. */
2033 break;
2034 case 1: /* FPIAR */
2035 case 2: /* FPSR */
2036 default:
2037 cpu_abort(NULL, "Unimplemented: fmove to control %d",
2038 (ext >> 10) & 7);
2039 }
2040 break;
2041 case 5: /* fmove from control register. */
2042 switch ((ext >> 10) & 7) {
2043 case 4: /* FPCR */
2044 /* Not implemented. Always return zero. */
2045 res = gen_im32(0);
2046 break;
2047 case 1: /* FPIAR */
2048 case 2: /* FPSR */
2049 default:
2050 cpu_abort(NULL, "Unimplemented: fmove from control %d",
2051 (ext >> 10) & 7);
2052 goto undef;
2053 }
2054 gen_ea(s, insn, OS_LONG, res, NULL);
2055 break;
2056 case 6: /* fmovem */
2057 case 7:
2058 {
2059 int addr;
2060 uint16_t mask;
2061 if ((ext & 0x1f00) != 0x1000 || (ext & 0xff) == 0)
2062 goto undef;
2063 src = gen_lea(s, insn, OS_LONG);
2064 addr = gen_new_qreg(QMODE_I32);
2065 gen_op_mov32(addr, src);
2066 mask = 0x80;
2067 dest = QREG_F0;
2068 while (mask) {
2069 if (ext & mask) {
2070 if (ext & (1 << 13)) {
2071 /* store */
0633879f 2072 gen_st(s, f64, addr, dest);
e6e5906b
PB
2073 } else {
2074 /* load */
0633879f 2075 gen_ld(s, f64, dest, addr);
e6e5906b
PB
2076 }
2077 if (ext & (mask - 1))
2078 gen_op_add32(addr, addr, gen_im32(8));
2079 }
2080 mask >>= 1;
2081 dest++;
2082 }
2083 }
2084 return;
2085 }
2086 if (ext & (1 << 14)) {
2087 int tmp;
2088
2089 /* Source effective address. */
2090 switch ((ext >> 10) & 7) {
2091 case 0: opsize = OS_LONG; break;
2092 case 1: opsize = OS_SINGLE; break;
2093 case 4: opsize = OS_WORD; break;
2094 case 5: opsize = OS_DOUBLE; break;
2095 case 6: opsize = OS_BYTE; break;
2096 default:
2097 goto undef;
2098 }
2099 tmp = gen_ea(s, insn, opsize, -1, NULL);
2100 if (opsize == OS_DOUBLE) {
2101 src = tmp;
2102 } else {
2103 src = gen_new_qreg(QMODE_F64);
2104 switch (opsize) {
2105 case OS_LONG:
2106 case OS_WORD:
2107 case OS_BYTE:
2108 gen_op_i32_to_f64(src, tmp);
2109 break;
2110 case OS_SINGLE:
2111 gen_op_f32_to_f64(src, tmp);
2112 break;
2113 }
2114 }
2115 } else {
2116 /* Source register. */
2117 src = FREG(ext, 10);
2118 }
2119 dest = FREG(ext, 7);
2120 res = gen_new_qreg(QMODE_F64);
2121 if (opmode != 0x3a)
2122 gen_op_movf64(res, dest);
2123 round = 1;
2124 switch (opmode) {
2125 case 0: case 0x40: case 0x44: /* fmove */
2126 gen_op_movf64(res, src);
2127 break;
2128 case 1: /* fint */
2129 gen_op_iround_f64(res, src);
2130 round = 0;
2131 break;
2132 case 3: /* fintrz */
2133 gen_op_itrunc_f64(res, src);
2134 round = 0;
2135 break;
2136 case 4: case 0x41: case 0x45: /* fsqrt */
2137 gen_op_sqrtf64(res, src);
2138 break;
2139 case 0x18: case 0x58: case 0x5c: /* fabs */
2140 gen_op_absf64(res, src);
2141 break;
2142 case 0x1a: case 0x5a: case 0x5e: /* fneg */
2143 gen_op_chsf64(res, src);
2144 break;
2145 case 0x20: case 0x60: case 0x64: /* fdiv */
2146 gen_op_divf64(res, res, src);
2147 break;
2148 case 0x22: case 0x62: case 0x66: /* fadd */
2149 gen_op_addf64(res, res, src);
2150 break;
2151 case 0x23: case 0x63: case 0x67: /* fmul */
2152 gen_op_mulf64(res, res, src);
2153 break;
2154 case 0x28: case 0x68: case 0x6c: /* fsub */
2155 gen_op_subf64(res, res, src);
2156 break;
2157 case 0x38: /* fcmp */
2158 gen_op_sub_cmpf64(res, res, src);
2159 dest = 0;
2160 round = 0;
2161 break;
2162 case 0x3a: /* ftst */
2163 gen_op_movf64(res, src);
2164 dest = 0;
2165 round = 0;
2166 break;
2167 default:
2168 goto undef;
2169 }
2170 if (round) {
2171 if (opmode & 0x40) {
2172 if ((opmode & 0x4) != 0)
2173 round = 0;
2174 } else if ((s->fpcr & M68K_FPCR_PREC) == 0) {
2175 round = 0;
2176 }
2177 }
2178 if (round) {
2179 int tmp;
2180
2181 tmp = gen_new_qreg(QMODE_F32);
2182 gen_op_f64_to_f32(tmp, res);
2183 gen_op_f32_to_f64(res, tmp);
2184 }
2185 gen_op_fp_result(res);
2186 if (dest) {
2187 gen_op_movf64(dest, res);
2188 }
2189 return;
2190undef:
2191 s->pc -= 2;
2192 disas_undef_fpu(s, insn);
2193}
2194
2195DISAS_INSN(fbcc)
2196{
2197 uint32_t offset;
2198 uint32_t addr;
2199 int flag;
2200 int zero;
2201 int l1;
2202
2203 addr = s->pc;
0633879f 2204 offset = ldsw_code(s->pc);
e6e5906b
PB
2205 s->pc += 2;
2206 if (insn & (1 << 6)) {
0633879f 2207 offset = (offset << 16) | lduw_code(s->pc);
e6e5906b
PB
2208 s->pc += 2;
2209 }
2210
2211 l1 = gen_new_label();
2212 /* TODO: Raise BSUN exception. */
2213 flag = gen_new_qreg(QMODE_I32);
2214 zero = gen_new_qreg(QMODE_F64);
2215 gen_op_zerof64(zero);
2216 gen_op_compare_quietf64(flag, QREG_FP_RESULT, zero);
2217 /* Jump to l1 if condition is true. */
2218 switch (insn & 0xf) {
2219 case 0: /* f */
2220 break;
2221 case 1: /* eq (=0) */
2222 gen_op_jmp_z32(flag, l1);
2223 break;
2224 case 2: /* ogt (=1) */
2225 gen_op_sub32(flag, flag, gen_im32(1));
2226 gen_op_jmp_z32(flag, l1);
2227 break;
2228 case 3: /* oge (=0 or =1) */
2229 gen_op_jmp_z32(flag, l1);
2230 gen_op_sub32(flag, flag, gen_im32(1));
2231 gen_op_jmp_z32(flag, l1);
2232 break;
2233 case 4: /* olt (=-1) */
2234 gen_op_jmp_s32(flag, l1);
2235 break;
2236 case 5: /* ole (=-1 or =0) */
2237 gen_op_jmp_s32(flag, l1);
2238 gen_op_jmp_z32(flag, l1);
2239 break;
2240 case 6: /* ogl (=-1 or =1) */
2241 gen_op_jmp_s32(flag, l1);
2242 gen_op_sub32(flag, flag, gen_im32(1));
2243 gen_op_jmp_z32(flag, l1);
2244 break;
2245 case 7: /* or (=2) */
2246 gen_op_sub32(flag, flag, gen_im32(2));
2247 gen_op_jmp_z32(flag, l1);
2248 break;
2249 case 8: /* un (<2) */
2250 gen_op_sub32(flag, flag, gen_im32(2));
2251 gen_op_jmp_s32(flag, l1);
2252 break;
2253 case 9: /* ueq (=0 or =2) */
2254 gen_op_jmp_z32(flag, l1);
2255 gen_op_sub32(flag, flag, gen_im32(2));
2256 gen_op_jmp_z32(flag, l1);
2257 break;
2258 case 10: /* ugt (>0) */
2259 /* ??? Add jmp_gtu. */
2260 gen_op_sub32(flag, flag, gen_im32(1));
2261 gen_op_jmp_ns32(flag, l1);
2262 break;
2263 case 11: /* uge (>=0) */
2264 gen_op_jmp_ns32(flag, l1);
2265 break;
2266 case 12: /* ult (=-1 or =2) */
2267 gen_op_jmp_s32(flag, l1);
2268 gen_op_sub32(flag, flag, gen_im32(2));
2269 gen_op_jmp_z32(flag, l1);
2270 break;
2271 case 13: /* ule (!=1) */
2272 gen_op_sub32(flag, flag, gen_im32(1));
2273 gen_op_jmp_nz32(flag, l1);
2274 break;
2275 case 14: /* ne (!=0) */
2276 gen_op_jmp_nz32(flag, l1);
2277 break;
2278 case 15: /* t */
2279 gen_op_mov32(flag, gen_im32(1));
2280 break;
2281 }
2282 gen_jmp_tb(s, 0, s->pc);
2283 gen_set_label(l1);
2284 gen_jmp_tb(s, 1, addr + offset);
2285}
2286
0633879f
PB
2287DISAS_INSN(frestore)
2288{
2289 /* TODO: Implement frestore. */
2290 qemu_assert(0, "FRESTORE not implemented");
2291}
2292
2293DISAS_INSN(fsave)
2294{
2295 /* TODO: Implement fsave. */
2296 qemu_assert(0, "FSAVE not implemented");
2297}
2298
e6e5906b
PB
2299static disas_proc opcode_table[65536];
2300
2301static void
2302register_opcode (disas_proc proc, uint16_t opcode, uint16_t mask)
2303{
2304 int i;
2305 int from;
2306 int to;
2307
2308 /* Sanity check. All set bits must be included in the mask. */
2309 if (opcode & ~mask)
2310 abort();
2311 /* This could probably be cleverer. For now just optimize the case where
2312 the top bits are known. */
2313 /* Find the first zero bit in the mask. */
2314 i = 0x8000;
2315 while ((i & mask) != 0)
2316 i >>= 1;
2317 /* Iterate over all combinations of this and lower bits. */
2318 if (i == 0)
2319 i = 1;
2320 else
2321 i <<= 1;
2322 from = opcode & ~(i - 1);
2323 to = from + i;
0633879f 2324 for (i = from; i < to; i++) {
e6e5906b
PB
2325 if ((i & mask) == opcode)
2326 opcode_table[i] = proc;
0633879f 2327 }
e6e5906b
PB
2328}
2329
2330/* Register m68k opcode handlers. Order is important.
2331 Later insn override earlier ones. */
0402f767 2332void register_m68k_insns (CPUM68KState *env)
e6e5906b 2333{
0402f767
PB
2334#define INSN(name, opcode, mask, feature) \
2335 if (m68k_feature(env, M68K_FEATURE_##feature)) \
e6e5906b 2336 register_opcode(disas_##name, 0x##opcode, 0x##mask)
0402f767
PB
2337 INSN(undef, 0000, 0000, CF_ISA_A);
2338 INSN(arith_im, 0080, fff8, CF_ISA_A);
2339 INSN(bitrev, 00c0, fff8, CF_ISA_C);
2340 INSN(bitop_reg, 0100, f1c0, CF_ISA_A);
2341 INSN(bitop_reg, 0140, f1c0, CF_ISA_A);
2342 INSN(bitop_reg, 0180, f1c0, CF_ISA_A);
2343 INSN(bitop_reg, 01c0, f1c0, CF_ISA_A);
2344 INSN(arith_im, 0280, fff8, CF_ISA_A);
2345 INSN(byterev, 02c0, fff8, CF_ISA_A);
2346 INSN(arith_im, 0480, fff8, CF_ISA_A);
2347 INSN(ff1, 04c0, fff8, CF_ISA_C);
2348 INSN(arith_im, 0680, fff8, CF_ISA_A);
2349 INSN(bitop_im, 0800, ffc0, CF_ISA_A);
2350 INSN(bitop_im, 0840, ffc0, CF_ISA_A);
2351 INSN(bitop_im, 0880, ffc0, CF_ISA_A);
2352 INSN(bitop_im, 08c0, ffc0, CF_ISA_A);
2353 INSN(arith_im, 0a80, fff8, CF_ISA_A);
2354 INSN(arith_im, 0c00, ff38, CF_ISA_A);
2355 INSN(move, 1000, f000, CF_ISA_A);
2356 INSN(move, 2000, f000, CF_ISA_A);
2357 INSN(move, 3000, f000, CF_ISA_A);
2358 INSN(strldsr, 40e7, ffff, CF_ISA_A);
2359 INSN(negx, 4080, fff8, CF_ISA_A);
2360 INSN(move_from_sr, 40c0, fff8, CF_ISA_A);
2361 INSN(lea, 41c0, f1c0, CF_ISA_A);
2362 INSN(clr, 4200, ff00, CF_ISA_A);
2363 INSN(undef, 42c0, ffc0, CF_ISA_A);
2364 INSN(move_from_ccr, 42c0, fff8, CF_ISA_A);
2365 INSN(neg, 4480, fff8, CF_ISA_A);
2366 INSN(move_to_ccr, 44c0, ffc0, CF_ISA_A);
2367 INSN(not, 4680, fff8, CF_ISA_A);
2368 INSN(move_to_sr, 46c0, ffc0, CF_ISA_A);
2369 INSN(pea, 4840, ffc0, CF_ISA_A);
2370 INSN(swap, 4840, fff8, CF_ISA_A);
2371 INSN(movem, 48c0, fbc0, CF_ISA_A);
2372 INSN(ext, 4880, fff8, CF_ISA_A);
2373 INSN(ext, 48c0, fff8, CF_ISA_A);
2374 INSN(ext, 49c0, fff8, CF_ISA_A);
2375 INSN(tst, 4a00, ff00, CF_ISA_A);
2376 INSN(tas, 4ac0, ffc0, CF_ISA_B);
2377 INSN(halt, 4ac8, ffff, CF_ISA_A);
2378 INSN(pulse, 4acc, ffff, CF_ISA_A);
2379 INSN(illegal, 4afc, ffff, CF_ISA_A);
2380 INSN(mull, 4c00, ffc0, CF_ISA_A);
2381 INSN(divl, 4c40, ffc0, CF_ISA_A);
2382 INSN(sats, 4c80, fff8, CF_ISA_B);
2383 INSN(trap, 4e40, fff0, CF_ISA_A);
2384 INSN(link, 4e50, fff8, CF_ISA_A);
2385 INSN(unlk, 4e58, fff8, CF_ISA_A);
2386 INSN(move_to_usp, 4e60, fff8, CF_ISA_B);
2387 INSN(move_from_usp, 4e68, fff8, CF_ISA_B);
2388 INSN(nop, 4e71, ffff, CF_ISA_A);
2389 INSN(stop, 4e72, ffff, CF_ISA_A);
2390 INSN(rte, 4e73, ffff, CF_ISA_A);
2391 INSN(rts, 4e75, ffff, CF_ISA_A);
2392 INSN(movec, 4e7b, ffff, CF_ISA_A);
2393 INSN(jump, 4e80, ffc0, CF_ISA_A);
2394 INSN(jump, 4ec0, ffc0, CF_ISA_A);
2395 INSN(addsubq, 5180, f1c0, CF_ISA_A);
2396 INSN(scc, 50c0, f0f8, CF_ISA_A);
2397 INSN(addsubq, 5080, f1c0, CF_ISA_A);
2398 INSN(tpf, 51f8, fff8, CF_ISA_A);
2399 INSN(branch, 6000, f000, CF_ISA_A);
2400 INSN(moveq, 7000, f100, CF_ISA_A);
2401 INSN(mvzs, 7100, f100, CF_ISA_B);
2402 INSN(or, 8000, f000, CF_ISA_A);
2403 INSN(divw, 80c0, f0c0, CF_ISA_A);
2404 INSN(addsub, 9000, f000, CF_ISA_A);
2405 INSN(subx, 9180, f1f8, CF_ISA_A);
2406 INSN(suba, 91c0, f1c0, CF_ISA_A);
2407 INSN(undef_mac, a000, f000, CF_ISA_A);
2408 INSN(mov3q, a140, f1c0, CF_ISA_B);
2409 INSN(cmp, b000, f1c0, CF_ISA_B); /* cmp.b */
2410 INSN(cmp, b040, f1c0, CF_ISA_B); /* cmp.w */
2411 INSN(cmpa, b0c0, f1c0, CF_ISA_B); /* cmpa.w */
2412 INSN(cmp, b080, f1c0, CF_ISA_A);
2413 INSN(cmpa, b1c0, f1c0, CF_ISA_A);
2414 INSN(eor, b180, f1c0, CF_ISA_A);
2415 INSN(and, c000, f000, CF_ISA_A);
2416 INSN(mulw, c0c0, f0c0, CF_ISA_A);
2417 INSN(addsub, d000, f000, CF_ISA_A);
2418 INSN(addx, d180, f1f8, CF_ISA_A);
2419 INSN(adda, d1c0, f1c0, CF_ISA_A);
2420 INSN(shift_im, e080, f0f0, CF_ISA_A);
2421 INSN(shift_reg, e0a0, f0f0, CF_ISA_A);
2422 INSN(undef_fpu, f000, f000, CF_ISA_A);
e6e5906b
PB
2423 INSN(fpu, f200, ffc0, CF_FPU);
2424 INSN(fbcc, f280, ffc0, CF_FPU);
0633879f
PB
2425 INSN(frestore, f340, ffc0, CF_FPU);
2426 INSN(fsave, f340, ffc0, CF_FPU);
0402f767
PB
2427 INSN(intouch, f340, ffc0, CF_ISA_A);
2428 INSN(cpushl, f428, ff38, CF_ISA_A);
2429 INSN(wddata, fb00, ff00, CF_ISA_A);
2430 INSN(wdebug, fbc0, ffc0, CF_ISA_A);
e6e5906b
PB
2431#undef INSN
2432}
2433
2434/* ??? Some of this implementation is not exception safe. We should always
2435 write back the result to memory before setting the condition codes. */
2436static void disas_m68k_insn(CPUState * env, DisasContext *s)
2437{
2438 uint16_t insn;
2439
0633879f 2440 insn = lduw_code(s->pc);
e6e5906b
PB
2441 s->pc += 2;
2442
2443 opcode_table[insn](s, insn);
2444}
2445
2446#if 0
2447/* Save the result of a floating point operation. */
2448static void expand_op_fp_result(qOP *qop)
2449{
2450 gen_op_movf64(QREG_FP_RESULT, qop->args[0]);
2451}
2452
2453/* Dummy op to indicate that the flags have been set. */
2454static void expand_op_flags_set(qOP *qop)
2455{
2456}
2457
2458/* Convert the confition codes into CC_OP_FLAGS format. */
2459static void expand_op_flush_flags(qOP *qop)
2460{
2461 int cc_opreg;
2462
2463 if (qop->args[0] == CC_OP_DYNAMIC)
2464 cc_opreg = QREG_CC_OP;
2465 else
2466 cc_opreg = gen_im32(qop->args[0]);
2467 gen_op_helper32(QREG_NULL, cc_opreg, HELPER_flush_flags);
2468}
2469
2470/* Set CC_DEST after a logical or direct flag setting operation. */
2471static void expand_op_logic_cc(qOP *qop)
2472{
2473 gen_op_mov32(QREG_CC_DEST, qop->args[0]);
2474}
2475
2476/* Set CC_SRC and CC_DEST after an arithmetic operation. */
2477static void expand_op_update_cc_add(qOP *qop)
2478{
2479 gen_op_mov32(QREG_CC_DEST, qop->args[0]);
2480 gen_op_mov32(QREG_CC_SRC, qop->args[1]);
2481}
2482
2483/* Update the X flag. */
2484static void expand_op_update_xflag(qOP *qop)
2485{
2486 int arg0;
2487 int arg1;
2488
2489 arg0 = qop->args[0];
2490 arg1 = qop->args[1];
2491 if (arg1 == QREG_NULL) {
2492 /* CC_X = arg0. */
2493 gen_op_mov32(QREG_CC_X, arg0);
2494 } else {
2495 /* CC_X = arg0 < (unsigned)arg1. */
2496 gen_op_set_ltu32(QREG_CC_X, arg0, arg1);
2497 }
2498}
2499
2500/* Set arg0 to the contents of the X flag. */
2501static void expand_op_get_xflag(qOP *qop)
2502{
2503 gen_op_mov32(qop->args[0], QREG_CC_X);
2504}
2505
2506/* Expand a shift by immediate. The ISA only allows shifts by 1-8, so we
2507 already know the shift is within range. */
2508static inline void expand_shift_im(qOP *qop, int right, int arith)
2509{
2510 int val;
2511 int reg;
2512 int tmp;
2513 int im;
2514
2515 reg = qop->args[0];
2516 im = qop->args[1];
2517 tmp = gen_im32(im);
2518 val = gen_new_qreg(QMODE_I32);
2519 gen_op_mov32(val, reg);
2520 gen_op_mov32(QREG_CC_DEST, val);
2521 gen_op_mov32(QREG_CC_SRC, tmp);
2522 if (right) {
2523 if (arith) {
2524 gen_op_sar32(reg, val, tmp);
2525 } else {
2526 gen_op_shr32(reg, val, tmp);
2527 }
2528 if (im == 1)
2529 tmp = QREG_NULL;
2530 else
2531 tmp = gen_im32(im - 1);
2532 } else {
2533 gen_op_shl32(reg, val, tmp);
2534 tmp = gen_im32(32 - im);
2535 }
2536 if (tmp != QREG_NULL)
2537 gen_op_shr32(val, val, tmp);
2538 gen_op_and32(QREG_CC_X, val, gen_im32(1));
2539}
2540
2541static void expand_op_shl_im_cc(qOP *qop)
2542{
2543 expand_shift_im(qop, 0, 0);
2544}
2545
2546static void expand_op_shr_im_cc(qOP *qop)
2547{
2548 expand_shift_im(qop, 1, 0);
2549}
2550
2551static void expand_op_sar_im_cc(qOP *qop)
2552{
2553 expand_shift_im(qop, 1, 1);
2554}
2555
2556/* Expand a shift by register. */
2557/* ??? This gives incorrect answers for shifts by 0 or >= 32 */
2558static inline void expand_shift_reg(qOP *qop, int right, int arith)
2559{
2560 int val;
2561 int reg;
2562 int shift;
2563 int tmp;
2564
2565 reg = qop->args[0];
2566 shift = qop->args[1];
2567 val = gen_new_qreg(QMODE_I32);
2568 gen_op_mov32(val, reg);
2569 gen_op_mov32(QREG_CC_DEST, val);
2570 gen_op_mov32(QREG_CC_SRC, shift);
2571 tmp = gen_new_qreg(QMODE_I32);
2572 if (right) {
2573 if (arith) {
2574 gen_op_sar32(reg, val, shift);
2575 } else {
2576 gen_op_shr32(reg, val, shift);
2577 }
2578 gen_op_sub32(tmp, shift, gen_im32(1));
2579 } else {
2580 gen_op_shl32(reg, val, shift);
2581 gen_op_sub32(tmp, gen_im32(31), shift);
2582 }
2583 gen_op_shl32(val, val, tmp);
2584 gen_op_and32(QREG_CC_X, val, gen_im32(1));
2585}
2586
2587static void expand_op_shl_cc(qOP *qop)
2588{
2589 expand_shift_reg(qop, 0, 0);
2590}
2591
2592static void expand_op_shr_cc(qOP *qop)
2593{
2594 expand_shift_reg(qop, 1, 0);
2595}
2596
2597static void expand_op_sar_cc(qOP *qop)
2598{
2599 expand_shift_reg(qop, 1, 1);
2600}
2601
2602/* Set the Z flag to (arg0 & arg1) == 0. */
2603static void expand_op_btest(qOP *qop)
2604{
2605 int tmp;
2606 int l1;
2607
2608 l1 = gen_new_label();
2609 tmp = gen_new_qreg(QMODE_I32);
2610 gen_op_and32(tmp, qop->args[0], qop->args[1]);
2611 gen_op_and32(QREG_CC_DEST, QREG_CC_DEST, gen_im32(~(uint32_t)CCF_Z));
2612 gen_op_jmp_nz32(tmp, l1);
2613 gen_op_or32(QREG_CC_DEST, QREG_CC_DEST, gen_im32(CCF_Z));
2614 gen_op_label(l1);
2615}
2616
2617/* arg0 += arg1 + CC_X */
2618static void expand_op_addx_cc(qOP *qop)
2619{
2620 int arg0 = qop->args[0];
2621 int arg1 = qop->args[1];
2622 int l1, l2;
2623
2624 gen_op_add32 (arg0, arg0, arg1);
2625 l1 = gen_new_label();
2626 l2 = gen_new_label();
2627 gen_op_jmp_z32(QREG_CC_X, l1);
2628 gen_op_add32(arg0, arg0, gen_im32(1));
2629 gen_op_mov32(QREG_CC_OP, gen_im32(CC_OP_ADDX));
2630 gen_op_set_leu32(QREG_CC_X, arg0, arg1);
2631 gen_op_jmp(l2);
2632 gen_set_label(l1);
2633 gen_op_mov32(QREG_CC_OP, gen_im32(CC_OP_ADD));
2634 gen_op_set_ltu32(QREG_CC_X, arg0, arg1);
2635 gen_set_label(l2);
2636}
2637
2638/* arg0 -= arg1 + CC_X */
2639static void expand_op_subx_cc(qOP *qop)
2640{
2641 int arg0 = qop->args[0];
2642 int arg1 = qop->args[1];
2643 int l1, l2;
2644
2645 l1 = gen_new_label();
2646 l2 = gen_new_label();
2647 gen_op_jmp_z32(QREG_CC_X, l1);
2648 gen_op_set_leu32(QREG_CC_X, arg0, arg1);
2649 gen_op_sub32(arg0, arg0, gen_im32(1));
2650 gen_op_mov32(QREG_CC_OP, gen_im32(CC_OP_SUBX));
2651 gen_op_jmp(l2);
2652 gen_set_label(l1);
2653 gen_op_set_ltu32(QREG_CC_X, arg0, arg1);
2654 gen_op_mov32(QREG_CC_OP, gen_im32(CC_OP_SUB));
2655 gen_set_label(l2);
2656 gen_op_sub32 (arg0, arg0, arg1);
2657}
2658
2659/* Expand target specific ops to generic qops. */
2660static void expand_target_qops(void)
2661{
2662 qOP *qop;
2663 qOP *next;
2664 int c;
2665
2666 /* Copy the list of qops, expanding target specific ops as we go. */
2667 qop = gen_first_qop;
2668 gen_first_qop = NULL;
2669 gen_last_qop = NULL;
2670 for (; qop; qop = next) {
2671 c = qop->opcode;
2672 next = qop->next;
2673 if (c < FIRST_TARGET_OP) {
2674 qop->prev = gen_last_qop;
2675 qop->next = NULL;
2676 if (gen_last_qop)
2677 gen_last_qop->next = qop;
2678 else
2679 gen_first_qop = qop;
2680 gen_last_qop = qop;
2681 continue;
2682 }
2683 switch (c) {
2684#define DEF(name, nargs, barrier) \
2685 case INDEX_op_##name: \
2686 expand_op_##name(qop); \
2687 break;
2688#include "qop-target.def"
2689#undef DEF
2690 default:
2691 cpu_abort(NULL, "Unexpanded target qop");
2692 }
2693 }
2694}
2695
2696/* ??? Implement this. */
2697static void
2698optimize_flags(void)
2699{
2700}
2701#endif
2702
2703/* generate intermediate code for basic block 'tb'. */
820e00f2
TS
2704static inline int
2705gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
2706 int search_pc)
e6e5906b
PB
2707{
2708 DisasContext dc1, *dc = &dc1;
2709 uint16_t *gen_opc_end;
2710 int j, lj;
2711 target_ulong pc_start;
2712 int pc_offset;
2713 int last_cc_op;
2714
2715 /* generate intermediate code */
2716 pc_start = tb->pc;
2717
2718 dc->tb = tb;
2719
2720 gen_opc_ptr = gen_opc_buf;
2721 gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
2722 gen_opparam_ptr = gen_opparam_buf;
2723
2724 dc->is_jmp = DISAS_NEXT;
2725 dc->pc = pc_start;
2726 dc->cc_op = CC_OP_DYNAMIC;
2727 dc->singlestep_enabled = env->singlestep_enabled;
2728 dc->fpcr = env->fpcr;
0633879f 2729 dc->user = (env->sr & SR_S) == 0;
e6e5906b
PB
2730 nb_gen_labels = 0;
2731 lj = -1;
2732 do {
2733 free_qreg = 0;
2734 pc_offset = dc->pc - pc_start;
2735 gen_throws_exception = NULL;
2736 if (env->nb_breakpoints > 0) {
2737 for(j = 0; j < env->nb_breakpoints; j++) {
2738 if (env->breakpoints[j] == dc->pc) {
2739 gen_exception(dc, dc->pc, EXCP_DEBUG);
2740 dc->is_jmp = DISAS_JUMP;
2741 break;
2742 }
2743 }
2744 if (dc->is_jmp)
2745 break;
2746 }
2747 if (search_pc) {
2748 j = gen_opc_ptr - gen_opc_buf;
2749 if (lj < j) {
2750 lj++;
2751 while (lj < j)
2752 gen_opc_instr_start[lj++] = 0;
2753 }
2754 gen_opc_pc[lj] = dc->pc;
2755 gen_opc_instr_start[lj] = 1;
2756 }
2757 last_cc_op = dc->cc_op;
2758 disas_m68k_insn(env, dc);
2759 } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
2760 !env->singlestep_enabled &&
2761 (pc_offset) < (TARGET_PAGE_SIZE - 32));
2762
2763 if (__builtin_expect(env->singlestep_enabled, 0)) {
2764 /* Make sure the pc is updated, and raise a debug exception. */
2765 if (!dc->is_jmp) {
2766 gen_flush_cc_op(dc);
2767 gen_op_mov32(QREG_PC, gen_im32((long)dc->pc));
2768 }
2769 gen_op_raise_exception(EXCP_DEBUG);
2770 } else {
2771 switch(dc->is_jmp) {
2772 case DISAS_NEXT:
2773 gen_flush_cc_op(dc);
2774 gen_jmp_tb(dc, 0, dc->pc);
2775 break;
2776 default:
2777 case DISAS_JUMP:
2778 case DISAS_UPDATE:
2779 gen_flush_cc_op(dc);
2780 /* indicate that the hash table must be used to find the next TB */
2781 gen_op_mov32(QREG_T0, gen_im32(0));
2782 gen_op_exit_tb();
2783 break;
2784 case DISAS_TB_JUMP:
2785 /* nothing more to generate */
2786 break;
2787 }
2788 }
2789 *gen_opc_ptr = INDEX_op_end;
2790
2791#ifdef DEBUG_DISAS
2792 if (loglevel & CPU_LOG_TB_IN_ASM) {
2793 fprintf(logfile, "----------------\n");
2794 fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
2795 target_disas(logfile, pc_start, dc->pc - pc_start, 0);
2796 fprintf(logfile, "\n");
2797 if (loglevel & (CPU_LOG_TB_OP)) {
2798 fprintf(logfile, "OP:\n");
2799 dump_ops(gen_opc_buf, gen_opparam_buf);
2800 fprintf(logfile, "\n");
2801 }
2802 }
2803#endif
2804 if (search_pc) {
2805 j = gen_opc_ptr - gen_opc_buf;
2806 lj++;
2807 while (lj <= j)
2808 gen_opc_instr_start[lj++] = 0;
2809 tb->size = 0;
2810 } else {
2811 tb->size = dc->pc - pc_start;
2812 }
2813
2814 //optimize_flags();
2815 //expand_target_qops();
2816 return 0;
2817}
2818
2819int gen_intermediate_code(CPUState *env, TranslationBlock *tb)
2820{
2821 return gen_intermediate_code_internal(env, tb, 0);
2822}
2823
2824int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
2825{
2826 return gen_intermediate_code_internal(env, tb, 1);
2827}
2828
0633879f
PB
2829void cpu_reset(CPUM68KState *env)
2830{
2831 memset(env, 0, offsetof(CPUM68KState, breakpoints));
2832#if !defined (CONFIG_USER_ONLY)
2833 env->sr = 0x2700;
2834#endif
2835 /* ??? FP regs should be initialized to NaN. */
2836 env->cc_op = CC_OP_FLAGS;
2837 /* TODO: We should set PC from the interrupt vector. */
2838 env->pc = 0;
2839 tlb_flush(env, 1);
2840}
2841
e6e5906b
PB
2842CPUM68KState *cpu_m68k_init(void)
2843{
2844 CPUM68KState *env;
2845
2846 env = malloc(sizeof(CPUM68KState));
2847 if (!env)
2848 return NULL;
2849 cpu_exec_init(env);
2850
0633879f 2851 cpu_reset(env);
e6e5906b
PB
2852 return env;
2853}
2854
2855void cpu_m68k_close(CPUM68KState *env)
2856{
2857 free(env);
2858}
2859
e6e5906b
PB
2860void cpu_dump_state(CPUState *env, FILE *f,
2861 int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
2862 int flags)
2863{
2864 int i;
2865 uint16_t sr;
2866 CPU_DoubleU u;
2867 for (i = 0; i < 8; i++)
2868 {
2869 u.d = env->fregs[i];
2870 cpu_fprintf (f, "D%d = %08x A%d = %08x F%d = %08x%08x (%12g)\n",
2871 i, env->dregs[i], i, env->aregs[i],
2872 i, u.l.upper, u.l.lower, u.d);
2873 }
2874 cpu_fprintf (f, "PC = %08x ", env->pc);
2875 sr = env->sr;
2876 cpu_fprintf (f, "SR = %04x %c%c%c%c%c ", sr, (sr & 0x10) ? 'X' : '-',
2877 (sr & CCF_N) ? 'N' : '-', (sr & CCF_Z) ? 'Z' : '-',
2878 (sr & CCF_V) ? 'V' : '-', (sr & CCF_C) ? 'C' : '-');
2879 cpu_fprintf (f, "FPRESULT = %12g\n", env->fp_result);
2880}
2881