main
m68k_core_x86.c
1/*
2 Copyright 2013 Michael Pavone
3 This file is part of BlastEm.
4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
5*/
6#include "gen_x86.h"
7#include "m68k_core.h"
8#include "m68k_internal.h"
9#include "68kinst.h"
10#include "mem.h"
11#include "backend.h"
12#include "util.h"
13#include <stdio.h>
14#include <stddef.h>
15#include <stdlib.h>
16#include <string.h>
17
18enum {
19 FLAG_X,
20 FLAG_N,
21 FLAG_Z,
22 FLAG_V,
23 FLAG_C
24};
25
26void set_flag(m68k_options * opts, uint8_t val, uint8_t flag)
27{
28 if (opts->flag_regs[flag] >= 0) {
29 mov_ir(&opts->gen.code, val, opts->flag_regs[flag], SZ_B);
30 } else {
31 int8_t offset = offsetof(m68k_context, flags) + flag;
32 if (offset) {
33 mov_irdisp(&opts->gen.code, val, opts->gen.context_reg, offset, SZ_B);
34 } else {
35 mov_irind(&opts->gen.code, val, opts->gen.context_reg, SZ_B);
36 }
37 }
38}
39
40void set_flag_cond(m68k_options *opts, uint8_t cond, uint8_t flag)
41{
42 if (opts->flag_regs[flag] >= 0) {
43 setcc_r(&opts->gen.code, cond, opts->flag_regs[flag]);
44 } else {
45 int8_t offset = offsetof(m68k_context, flags) + flag;
46 if (offset) {
47 setcc_rdisp(&opts->gen.code, cond, opts->gen.context_reg, offset);
48 } else {
49 setcc_rind(&opts->gen.code, cond, opts->gen.context_reg);
50 }
51 }
52}
53
54void check_flag(m68k_options *opts, uint8_t flag)
55{
56 if (opts->flag_regs[flag] >= 0) {
57 cmp_ir(&opts->gen.code, 0, opts->flag_regs[flag], SZ_B);
58 } else {
59 cmp_irdisp(&opts->gen.code, 0, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, SZ_B);
60 }
61}
62
63void flag_to_reg(m68k_options *opts, uint8_t flag, uint8_t reg)
64{
65 if (opts->flag_regs[flag] >= 0) {
66 mov_rr(&opts->gen.code, opts->flag_regs[flag], reg, SZ_B);
67 } else {
68 int8_t offset = offsetof(m68k_context, flags) + flag;
69 if (offset) {
70 mov_rdispr(&opts->gen.code, opts->gen.context_reg, offset, reg, SZ_B);
71 } else {
72 mov_rindr(&opts->gen.code, opts->gen.context_reg, reg, SZ_B);
73 }
74 }
75}
76
77void reg_to_flag(m68k_options *opts, uint8_t reg, uint8_t flag)
78{
79 if (opts->flag_regs[flag] >= 0) {
80 mov_rr(&opts->gen.code, reg, opts->flag_regs[flag], SZ_B);
81 } else {
82 int8_t offset = offsetof(m68k_context, flags) + flag;
83 if (offset) {
84 mov_rrdisp(&opts->gen.code, reg, opts->gen.context_reg, offset, SZ_B);
85 } else {
86 mov_rrind(&opts->gen.code, reg, opts->gen.context_reg, SZ_B);
87 }
88 }
89}
90
91void flag_to_flag(m68k_options *opts, uint8_t flag1, uint8_t flag2)
92{
93 code_info *code = &opts->gen.code;
94 if (opts->flag_regs[flag1] >= 0 && opts->flag_regs[flag2] >= 0) {
95 mov_rr(code, opts->flag_regs[flag1], opts->flag_regs[flag2], SZ_B);
96 } else if(opts->flag_regs[flag1] >= 0) {
97 mov_rrdisp(code, opts->flag_regs[flag1], opts->gen.context_reg, offsetof(m68k_context, flags) + flag2, SZ_B);
98 } else if (opts->flag_regs[flag2] >= 0) {
99 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag1, opts->flag_regs[flag2], SZ_B);
100 } else {
101 push_r(code, opts->gen.scratch1);
102 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag1, opts->gen.scratch1, SZ_B);
103 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, flags) + flag2, SZ_B);
104 pop_r(code, opts->gen.scratch1);
105 }
106}
107
108void update_flags(m68k_options *opts, uint32_t update_mask)
109{
110 uint8_t native_flags[] = {0, CC_S, CC_Z, CC_O, CC_C};
111 for (int8_t flag = FLAG_C; flag >= FLAG_X; --flag)
112 {
113 if (update_mask & X0 << (flag*3)) {
114 set_flag(opts, 0, flag);
115 } else if(update_mask & X1 << (flag*3)) {
116 set_flag(opts, 1, flag);
117 } else if(update_mask & X << (flag*3)) {
118 if (flag == FLAG_X) {
119 if (opts->flag_regs[FLAG_C] >= 0 || !(update_mask & (C0|C1|C))) {
120 flag_to_flag(opts, FLAG_C, FLAG_X);
121 } else if(update_mask & C0) {
122 set_flag(opts, 0, flag);
123 } else if(update_mask & C1) {
124 set_flag(opts, 1, flag);
125 } else {
126 set_flag_cond(opts, CC_C, flag);
127 }
128 } else {
129 set_flag_cond(opts, native_flags[flag], flag);
130 }
131 }
132 }
133}
134
135void flag_to_carry(m68k_options * opts, uint8_t flag)
136{
137 if (opts->flag_regs[flag] >= 0) {
138 bt_ir(&opts->gen.code, 0, opts->flag_regs[flag], SZ_B);
139 } else {
140 bt_irdisp(&opts->gen.code, 0, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, SZ_B);
141 }
142}
143
144void or_flag_to_reg(m68k_options *opts, uint8_t flag, uint8_t reg)
145{
146 if (opts->flag_regs[flag] >= 0) {
147 or_rr(&opts->gen.code, opts->flag_regs[flag], reg, SZ_B);
148 } else {
149 or_rdispr(&opts->gen.code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, reg, SZ_B);
150 }
151}
152
153void xor_flag_to_reg(m68k_options *opts, uint8_t flag, uint8_t reg)
154{
155 if (opts->flag_regs[flag] >= 0) {
156 xor_rr(&opts->gen.code, opts->flag_regs[flag], reg, SZ_B);
157 } else {
158 xor_rdispr(&opts->gen.code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, reg, SZ_B);
159 }
160}
161
162void xor_flag(m68k_options *opts, uint8_t val, uint8_t flag)
163{
164 if (opts->flag_regs[flag] >= 0) {
165 xor_ir(&opts->gen.code, val, opts->flag_regs[flag], SZ_B);
166 } else {
167 xor_irdisp(&opts->gen.code, val, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, SZ_B);
168 }
169}
170
171void cmp_flags(m68k_options *opts, uint8_t flag1, uint8_t flag2)
172{
173 code_info *code = &opts->gen.code;
174 if (opts->flag_regs[flag1] >= 0 && opts->flag_regs[flag2] >= 0) {
175 cmp_rr(code, opts->flag_regs[flag1], opts->flag_regs[flag2], SZ_B);
176 } else if(opts->flag_regs[flag1] >= 0 || opts->flag_regs[flag2] >= 0) {
177 if (opts->flag_regs[flag2] >= 0) {
178 uint8_t tmp = flag1;
179 flag1 = flag2;
180 flag2 = tmp;
181 }
182 cmp_rrdisp(code, opts->flag_regs[flag1], opts->gen.context_reg, offsetof(m68k_context, flags) + flag2, SZ_B);
183 } else {
184 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag1, opts->gen.scratch1, SZ_B);
185 cmp_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, flags) + flag2, SZ_B);
186 }
187}
188
189void areg_to_native(m68k_options *opts, uint8_t reg, uint8_t native_reg)
190{
191 if (opts->aregs[reg] >= 0) {
192 mov_rr(&opts->gen.code, opts->aregs[reg], native_reg, SZ_D);
193 } else {
194 mov_rdispr(&opts->gen.code, opts->gen.context_reg, areg_offset(reg), native_reg, SZ_D);
195 }
196}
197
198void dreg_to_native(m68k_options *opts, uint8_t reg, uint8_t native_reg)
199{
200 if (opts->dregs[reg] >= 0) {
201 mov_rr(&opts->gen.code, opts->dregs[reg], native_reg, SZ_D);
202 } else {
203 mov_rdispr(&opts->gen.code, opts->gen.context_reg, dreg_offset(reg), native_reg, SZ_D);
204 }
205}
206
207void areg_to_native_sx(m68k_options *opts, uint8_t reg, uint8_t native_reg)
208{
209 if (opts->aregs[reg] >= 0) {
210 movsx_rr(&opts->gen.code, opts->aregs[reg], native_reg, SZ_W, SZ_D);
211 } else {
212 movsx_rdispr(&opts->gen.code, opts->gen.context_reg, areg_offset(reg), native_reg, SZ_W, SZ_D);
213 }
214}
215
216void dreg_to_native_sx(m68k_options *opts, uint8_t reg, uint8_t native_reg)
217{
218 if (opts->dregs[reg] >= 0) {
219 movsx_rr(&opts->gen.code, opts->dregs[reg], native_reg, SZ_W, SZ_D);
220 } else {
221 movsx_rdispr(&opts->gen.code, opts->gen.context_reg, dreg_offset(reg), native_reg, SZ_W, SZ_D);
222 }
223}
224
225void native_to_areg(m68k_options *opts, uint8_t native_reg, uint8_t reg)
226 {
227 if (opts->aregs[reg] >= 0) {
228 mov_rr(&opts->gen.code, native_reg, opts->aregs[reg], SZ_D);
229 } else {
230 mov_rrdisp(&opts->gen.code, native_reg, opts->gen.context_reg, areg_offset(reg), SZ_D);
231 }
232}
233
234void native_to_dreg(m68k_options *opts, uint8_t native_reg, uint8_t reg)
235{
236 if (opts->dregs[reg] >= 0) {
237 mov_rr(&opts->gen.code, native_reg, opts->dregs[reg], SZ_D);
238 } else {
239 mov_rrdisp(&opts->gen.code, native_reg, opts->gen.context_reg, dreg_offset(reg), SZ_D);
240 }
241}
242
243void ldi_areg(m68k_options *opts, int32_t value, uint8_t reg)
244{
245 if (opts->aregs[reg] >= 0) {
246 mov_ir(&opts->gen.code, value, opts->aregs[reg], SZ_D);
247 } else {
248 mov_irdisp(&opts->gen.code, value, opts->gen.context_reg, areg_offset(reg), SZ_D);
249 }
250}
251
252void ldi_native(m68k_options *opts, int32_t value, uint8_t reg)
253{
254 mov_ir(&opts->gen.code, value, reg, SZ_D);
255}
256
257void addi_native(m68k_options *opts, int32_t value, uint8_t reg)
258{
259 add_ir(&opts->gen.code, value, reg, SZ_D);
260 }
261
262void subi_native(m68k_options *opts, int32_t value, uint8_t reg)
263{
264 sub_ir(&opts->gen.code, value, reg, SZ_D);
265}
266
267void push_native(m68k_options *opts, uint8_t reg)
268{
269 push_r(&opts->gen.code, reg);
270}
271
272void pop_native(m68k_options *opts, uint8_t reg)
273{
274 pop_r(&opts->gen.code, reg);
275}
276
277void sign_extend16_native(m68k_options *opts, uint8_t reg)
278{
279 movsx_rr(&opts->gen.code, reg, reg, SZ_W, SZ_D);
280}
281
282void addi_areg(m68k_options *opts, int32_t val, uint8_t reg)
283{
284 if (opts->aregs[reg] >= 0) {
285 add_ir(&opts->gen.code, val, opts->aregs[reg], SZ_D);
286 } else {
287 add_irdisp(&opts->gen.code, val, opts->gen.context_reg, areg_offset(reg), SZ_D);
288 }
289}
290
291void subi_areg(m68k_options *opts, int32_t val, uint8_t reg)
292{
293 if (opts->aregs[reg] >= 0) {
294 sub_ir(&opts->gen.code, val, opts->aregs[reg], SZ_D);
295 } else {
296 sub_irdisp(&opts->gen.code, val, opts->gen.context_reg, areg_offset(reg), SZ_D);
297 }
298}
299
300void add_areg_native(m68k_options *opts, uint8_t reg, uint8_t native_reg)
301{
302 if (opts->aregs[reg] >= 0) {
303 add_rr(&opts->gen.code, opts->aregs[reg], native_reg, SZ_D);
304 } else {
305 add_rdispr(&opts->gen.code, opts->gen.context_reg, areg_offset(reg), native_reg, SZ_D);
306 }
307}
308
309void add_dreg_native(m68k_options *opts, uint8_t reg, uint8_t native_reg)
310{
311 if (opts->dregs[reg] >= 0) {
312 add_rr(&opts->gen.code, opts->dregs[reg], native_reg, SZ_D);
313 } else {
314 add_rdispr(&opts->gen.code, opts->gen.context_reg, dreg_offset(reg), native_reg, SZ_D);
315 }
316}
317
318void calc_areg_displace(m68k_options *opts, m68k_op_info *op, uint8_t native_reg)
319{
320 areg_to_native(opts, op->params.regs.pri, native_reg);
321 add_ir(&opts->gen.code, op->params.regs.displacement & 0x8000 ? op->params.regs.displacement | 0xFFFF0000 : op->params.regs.displacement, native_reg, SZ_D);
322}
323
324void calc_index_disp8(m68k_options *opts, m68k_op_info *op, uint8_t native_reg)
325{
326 uint8_t sec_reg = (op->params.regs.sec >> 1) & 0x7;
327 if (op->params.regs.sec & 1) {
328 if (op->params.regs.sec & 0x10) {
329 add_areg_native(opts, sec_reg, native_reg);
330 } else {
331 add_dreg_native(opts, sec_reg, native_reg);
332 }
333 } else {
334 uint8_t other_reg = native_reg == opts->gen.scratch1 ? opts->gen.scratch2 : opts->gen.scratch1;
335 if (op->params.regs.sec & 0x10) {
336 areg_to_native_sx(opts, sec_reg, other_reg);
337 } else {
338 dreg_to_native_sx(opts, sec_reg, other_reg);
339 }
340 add_rr(&opts->gen.code, other_reg, native_reg, SZ_D);
341 }
342 if (op->params.regs.displacement) {
343 add_ir(&opts->gen.code, op->params.regs.displacement, native_reg, SZ_D);
344 }
345}
346
347void calc_areg_index_disp8(m68k_options *opts, m68k_op_info *op, uint8_t native_reg)
348{
349 areg_to_native(opts, op->params.regs.pri, native_reg);
350 calc_index_disp8(opts, op, native_reg);
351}
352
353void m68k_check_cycles_int_latch(m68k_options *opts)
354{
355 code_info *code = &opts->gen.code;
356 check_alloc_code(code, 3*MAX_INST_LEN);
357 uint8_t cc;
358 if (opts->gen.limit < 0) {
359 cmp_ir(code, 1, opts->gen.cycles, SZ_D);
360 cc = CC_NS;
361 } else {
362 cmp_rr(code, opts->gen.cycles, opts->gen.limit, SZ_D);
363 cc = CC_A;
364 }
365 code_ptr jmp_off = code->cur+1;
366 jcc(code, cc, jmp_off+1);
367 call(code, opts->handle_int_latch);
368 *jmp_off = code->cur - (jmp_off+1);
369}
370
371uint8_t translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8_t dst)
372{
373 code_info *code = &opts->gen.code;
374 m68k_op_info *op = dst ? &inst->dst : &inst->src;
375 int8_t reg = native_reg(op, opts);
376 uint8_t sec_reg;
377 uint8_t ret = 1;
378 int32_t dec_amount, inc_amount;
379 if (reg >= 0) {
380 ea->mode = MODE_REG_DIRECT;
381 if (!dst && inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) {
382 movsx_rr(code, reg, opts->gen.scratch1, SZ_W, SZ_D);
383 ea->base = opts->gen.scratch1;
384#ifdef X86_32
385 } else if (reg > RBX && inst->extra.size == OPSIZE_BYTE) {
386 mov_rr(code, reg, opts->gen.scratch1, SZ_D);
387 ea->base = opts->gen.scratch1;
388#endif
389 } else {
390 ea->base = reg;
391 }
392 return 0;
393 }
394 switch (op->addr_mode)
395 {
396 case MODE_REG:
397 case MODE_AREG:
398 //We only get one memory parameter, so if the dst operand is a register in memory,
399 //we need to copy this to a temp register first if we're translating the src operand
400 if (dst || native_reg(&(inst->dst), opts) >= 0 || inst->dst.addr_mode == MODE_UNUSED || !(inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG)
401 || inst->op == M68K_EXG) {
402
403 ea->mode = MODE_REG_DISPLACE8;
404 ea->base = opts->gen.context_reg;
405 ea->disp = reg_offset(op);
406 } else {
407 if (inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) {
408 movsx_rdispr(code, opts->gen.context_reg, reg_offset(op), opts->gen.scratch1, SZ_W, SZ_D);
409 } else {
410 mov_rdispr(code, opts->gen.context_reg, reg_offset(op), opts->gen.scratch1, inst->extra.size);
411 }
412 ea->mode = MODE_REG_DIRECT;
413 ea->base = opts->gen.scratch1;
414 //we're explicitly handling the areg dest here, so we exit immediately
415 return 0;
416 }
417 ret = 0;
418 break;
419 case MODE_AREG_PREDEC:
420 if (dst && inst->src.addr_mode == MODE_AREG_PREDEC) {
421 push_r(code, opts->gen.scratch1);
422 }
423 dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (op->params.regs.pri == 7 ? 2 :1));
424 if (!dst) {
425 cycles(&opts->gen, PREDEC_PENALTY);
426 }
427 subi_areg(opts, dec_amount, op->params.regs.pri);
428 case MODE_AREG_INDIRECT:
429 case MODE_AREG_POSTINC:
430 areg_to_native(opts, op->params.regs.pri, opts->gen.scratch1);
431 m68k_read_size(opts, inst->extra.size);
432
433 if (dst) {
434 if (inst->src.addr_mode == MODE_AREG_PREDEC) {
435 //restore src operand to opts->gen.scratch2
436 pop_r(code, opts->gen.scratch2);
437 } else {
438 //save reg value in opts->gen.scratch2 so we can use it to save the result in memory later
439 areg_to_native(opts, op->params.regs.pri, opts->gen.scratch2);
440 }
441 }
442
443 if (op->addr_mode == MODE_AREG_POSTINC) {
444 inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (op->params.regs.pri == 7 ? 2 : 1));
445 addi_areg(opts, inc_amount, op->params.regs.pri);
446 }
447 ea->mode = MODE_REG_DIRECT;
448 ea->base = (!dst && inst->dst.addr_mode == MODE_AREG_PREDEC && inst->op != M68K_MOVE) ? opts->gen.scratch2 : opts->gen.scratch1;
449 break;
450 case MODE_AREG_DISPLACE:
451 cycles(&opts->gen, BUS);
452 calc_areg_displace(opts, op, opts->gen.scratch1);
453 if (dst) {
454 push_r(code, opts->gen.scratch1);
455 }
456 m68k_read_size(opts, inst->extra.size);
457 if (dst) {
458 pop_r(code, opts->gen.scratch2);
459 }
460
461 ea->mode = MODE_REG_DIRECT;
462 ea->base = opts->gen.scratch1;
463 break;
464 case MODE_AREG_INDEX_DISP8:
465 cycles(&opts->gen, 6);
466 calc_areg_index_disp8(opts, op, opts->gen.scratch1);
467 if (dst) {
468 push_r(code, opts->gen.scratch1);
469 }
470 m68k_read_size(opts, inst->extra.size);
471 if (dst) {
472 pop_r(code, opts->gen.scratch2);
473 }
474
475 ea->mode = MODE_REG_DIRECT;
476 ea->base = opts->gen.scratch1;
477 break;
478 case MODE_PC_DISPLACE:
479 cycles(&opts->gen, BUS);
480 mov_ir(code, op->params.regs.displacement + inst->address+2, opts->gen.scratch1, SZ_D);
481 if (dst) {
482 push_r(code, opts->gen.scratch1);
483 }
484 m68k_read_size(opts, inst->extra.size);
485 if (dst) {
486 pop_r(code, opts->gen.scratch2);
487 }
488
489 ea->mode = MODE_REG_DIRECT;
490 ea->base = opts->gen.scratch1;
491 break;
492 case MODE_PC_INDEX_DISP8:
493 cycles(&opts->gen, 6);
494 mov_ir(code, inst->address+2, opts->gen.scratch1, SZ_D);
495 calc_index_disp8(opts, op, opts->gen.scratch1);
496 if (dst) {
497 push_r(code, opts->gen.scratch1);
498 }
499 m68k_read_size(opts, inst->extra.size);
500 if (dst) {
501 pop_r(code, opts->gen.scratch2);
502 }
503
504 ea->mode = MODE_REG_DIRECT;
505 ea->base = opts->gen.scratch1;
506 break;
507 case MODE_ABSOLUTE:
508 case MODE_ABSOLUTE_SHORT:
509 cycles(&opts->gen, op->addr_mode == MODE_ABSOLUTE ? BUS*2 : BUS);
510 mov_ir(code, op->params.immed, opts->gen.scratch1, SZ_D);
511 if (dst) {
512 push_r(code, opts->gen.scratch1);
513 }
514 m68k_read_size(opts, inst->extra.size);
515 if (dst) {
516 pop_r(code, opts->gen.scratch2);
517 }
518
519 ea->mode = MODE_REG_DIRECT;
520 ea->base = opts->gen.scratch1;
521 break;
522 case MODE_IMMEDIATE:
523 case MODE_IMMEDIATE_WORD:
524 if (inst->variant != VAR_QUICK) {
525 cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG && op->addr_mode == MODE_IMMEDIATE) ? BUS*2 : BUS);
526 }
527 ea->mode = MODE_IMMED;
528 ea->disp = op->params.immed;
529 //sign extend value when the destination is an address register
530 if (inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD && ea->disp & 0x8000) {
531 ea->disp |= 0xFFFF0000;
532 }
533 return inst->variant != VAR_QUICK;
534 default:
535 m68k_disasm(inst, disasm_buf);
536 fatal_error("%X: %s\naddress mode %d not implemented (%s)\n", inst->address, disasm_buf, op->addr_mode, dst ? "dst" : "src");
537 }
538 if (!dst && inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) {
539 if (ea->mode == MODE_REG_DIRECT) {
540 movsx_rr(code, ea->base, opts->gen.scratch1, SZ_W, SZ_D);
541 } else {
542 movsx_rdispr(code, ea->base, ea->disp, opts->gen.scratch1, SZ_W, SZ_D);
543 ea->mode = MODE_REG_DIRECT;
544 }
545 ea->base = opts->gen.scratch1;
546 }
547 return ret;
548}
549
550void check_user_mode_swap_ssp_usp(m68k_options *opts)
551{
552 code_info * code = &opts->gen.code;
553 //Check if we've switched to user mode and swap stack pointers if needed
554 bt_irdisp(code, 5, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
555 code_ptr end_off = code->cur + 1;
556 jcc(code, CC_C, code->cur + 2);
557 swap_ssp_usp(opts);
558 *end_off = code->cur - (end_off + 1);
559}
560
561void translate_m68k_move(m68k_options * opts, m68kinst * inst)
562{
563 code_info *code = &opts->gen.code;
564 int8_t reg, flags_reg, sec_reg;
565 uint8_t dir = 0;
566 int32_t offset;
567 int32_t inc_amount, dec_amount;
568 host_ea src;
569 uint8_t needs_int_latch = translate_m68k_op(inst, &src, opts, 0);
570 reg = native_reg(&(inst->dst), opts);
571
572 if (inst->dst.addr_mode != MODE_AREG) {
573 if (src.mode == MODE_REG_DIRECT) {
574 flags_reg = src.base;
575 } else {
576 if (reg >= 0) {
577 flags_reg = reg;
578 } else {
579 if(src.mode == MODE_REG_DISPLACE8) {
580 mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size);
581 } else {
582 mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
583 }
584 src.mode = MODE_REG_DIRECT;
585 flags_reg = src.base = opts->gen.scratch1;
586 }
587 }
588 }
589 uint8_t size = inst->extra.size;
590 switch(inst->dst.addr_mode)
591 {
592 case MODE_AREG:
593 size = OPSIZE_LONG;
594 case MODE_REG:
595 if (reg >= 0) {
596 if (src.mode == MODE_REG_DIRECT) {
597 mov_rr(code, src.base, reg, size);
598 } else if (src.mode == MODE_REG_DISPLACE8) {
599 mov_rdispr(code, src.base, src.disp, reg, size);
600 } else {
601 mov_ir(code, src.disp, reg, size);
602 }
603 } else if(src.mode == MODE_REG_DIRECT) {
604 mov_rrdisp(code, src.base, opts->gen.context_reg, reg_offset(&(inst->dst)), size);
605 } else {
606 mov_irdisp(code, src.disp, opts->gen.context_reg, reg_offset(&(inst->dst)), size);
607 }
608 break;
609 case MODE_AREG_PREDEC:
610 dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->dst.params.regs.pri == 7 ? 2 : 1));
611 case MODE_AREG_INDIRECT:
612 case MODE_AREG_POSTINC:
613 if (src.mode == MODE_REG_DIRECT) {
614 if (src.base != opts->gen.scratch1) {
615 mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size);
616 }
617 } else if (src.mode == MODE_REG_DISPLACE8) {
618 mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size);
619 } else {
620 mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
621 }
622 if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
623 subi_areg(opts, dec_amount, inst->dst.params.regs.pri);
624 }
625 areg_to_native(opts, inst->dst.params.regs.pri, opts->gen.scratch2);
626 break;
627 case MODE_AREG_DISPLACE:
628 cycles(&opts->gen, BUS);
629 calc_areg_displace(opts, &inst->dst, opts->gen.scratch2);
630 if (src.mode == MODE_REG_DIRECT) {
631 if (src.base != opts->gen.scratch1) {
632 mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size);
633 }
634 } else if (src.mode == MODE_REG_DISPLACE8) {
635 mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size);
636 } else {
637 mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
638 }
639 break;
640 case MODE_AREG_INDEX_DISP8:
641 cycles(&opts->gen, 6);//TODO: Check to make sure this is correct
642 //calc_areg_index_disp8 will clober scratch1 when a 16-bit index is used
643 if (src.base == opts->gen.scratch1 && !(inst->dst.params.regs.sec & 1)) {
644 push_r(code, opts->gen.scratch1);
645 }
646 calc_areg_index_disp8(opts, &inst->dst, opts->gen.scratch2);
647 if (src.base == opts->gen.scratch1 && !(inst->dst.params.regs.sec & 1)) {
648 pop_r(code, opts->gen.scratch1);
649 }
650 if (src.mode == MODE_REG_DIRECT) {
651 if (src.base != opts->gen.scratch1) {
652 mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size);
653 }
654 } else if (src.mode == MODE_REG_DISPLACE8) {
655 mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size);
656 } else {
657 mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
658 }
659 break;
660 case MODE_PC_DISPLACE:
661 cycles(&opts->gen, BUS);
662 mov_ir(code, inst->dst.params.regs.displacement + inst->address+2, opts->gen.scratch2, SZ_D);
663 if (src.mode == MODE_REG_DIRECT) {
664 if (src.base != opts->gen.scratch1) {
665 mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size);
666 }
667 } else if (src.mode == MODE_REG_DISPLACE8) {
668 mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size);
669 } else {
670 mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
671 }
672 break;
673 case MODE_PC_INDEX_DISP8:
674 cycles(&opts->gen, 6);//TODO: Check to make sure this is correct
675 mov_ir(code, inst->address, opts->gen.scratch2, SZ_D);
676 if (src.base == opts->gen.scratch1 && !(inst->dst.params.regs.sec & 1)) {
677 push_r(code, opts->gen.scratch1);
678 }
679 calc_index_disp8(opts, &inst->dst, opts->gen.scratch2);
680 if (src.base == opts->gen.scratch1 && !(inst->dst.params.regs.sec & 1)) {
681 pop_r(code, opts->gen.scratch1);
682 }
683 if (src.mode == MODE_REG_DIRECT) {
684 if (src.base != opts->gen.scratch1) {
685 mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size);
686 }
687 } else if (src.mode == MODE_REG_DISPLACE8) {
688 mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size);
689 } else {
690 mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
691 }
692 break;
693 case MODE_ABSOLUTE:
694 case MODE_ABSOLUTE_SHORT:
695 if (src.mode == MODE_REG_DIRECT) {
696 if (src.base != opts->gen.scratch1) {
697 mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size);
698 }
699 } else if (src.mode == MODE_REG_DISPLACE8) {
700 mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size);
701 } else {
702 mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
703 }
704 if (inst->dst.addr_mode == MODE_ABSOLUTE) {
705 cycles(&opts->gen, BUS*2);
706 } else {
707 cycles(&opts->gen, BUS);
708 }
709 mov_ir(code, inst->dst.params.immed, opts->gen.scratch2, SZ_D);
710 break;
711 default:
712 m68k_disasm(inst, disasm_buf);
713 fatal_error("%X: %s\naddress mode %d not implemented (move dst)\n", inst->address, disasm_buf, inst->dst.addr_mode);
714 }
715
716 if (inst->dst.addr_mode != MODE_AREG) {
717 cmp_ir(code, 0, flags_reg, inst->extra.size);
718 update_flags(opts, N|Z|V0|C0);
719 }
720 if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG) {
721 if (inst->extra.size == OPSIZE_LONG) {
722 //We want the int latch to occur between the two writes,
723 //but that's a pain to do without refactoring how 32-bit writes work
724 //workaround it by temporarily increasing the cycle count before the check
725 cycles(&opts->gen, BUS);
726 }
727 m68k_check_cycles_int_latch(opts);
728 if (inst->extra.size == OPSIZE_LONG) {
729 //and then backing out that extra increment here before the write happens
730 cycles(&opts->gen, -BUS);
731 }
732 m68k_write_size(opts, inst->extra.size, inst->dst.addr_mode == MODE_AREG_PREDEC);
733 if (inst->dst.addr_mode == MODE_AREG_POSTINC) {
734 inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->dst.params.regs.pri == 7 ? 2 : 1));
735 addi_areg(opts, inc_amount, inst->dst.params.regs.pri);
736 }
737 } else if (needs_int_latch) {
738 m68k_check_cycles_int_latch(opts);
739 }
740
741 //add cycles for prefetch
742 cycles(&opts->gen, BUS);
743}
744
745void translate_m68k_ext(m68k_options * opts, m68kinst * inst)
746{
747 code_info *code = &opts->gen.code;
748 host_ea dst_op;
749 uint8_t dst_size = inst->extra.size;
750 inst->extra.size--;
751 translate_m68k_op(inst, &dst_op, opts, 1);
752 if (dst_op.mode == MODE_REG_DIRECT) {
753 movsx_rr(code, dst_op.base, dst_op.base, inst->extra.size, dst_size);
754 cmp_ir(code, 0, dst_op.base, dst_size);
755 } else {
756 movsx_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch1, inst->extra.size, dst_size);
757 cmp_ir(code, 0, opts->gen.scratch1, dst_size);
758 mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, dst_size);
759 }
760 inst->extra.size = dst_size;
761 update_flags(opts, N|V0|C0|Z);
762 cycles(&opts->gen, BUS);
763 //M68K EXT only operates on registers so no need for a call to save result here
764}
765
766uint8_t m68k_eval_cond(m68k_options * opts, uint8_t cc)
767{
768 uint8_t cond = CC_NZ;
769 switch (cc)
770 {
771 case COND_HIGH:
772 cond = CC_Z;
773 case COND_LOW_SAME:
774 flag_to_reg(opts, FLAG_Z, opts->gen.scratch1);
775 or_flag_to_reg(opts, FLAG_C, opts->gen.scratch1);
776 break;
777 case COND_CARRY_CLR:
778 cond = CC_Z;
779 case COND_CARRY_SET:
780 check_flag(opts, FLAG_C);
781 break;
782 case COND_NOT_EQ:
783 cond = CC_Z;
784 case COND_EQ:
785 check_flag(opts, FLAG_Z);
786 break;
787 case COND_OVERF_CLR:
788 cond = CC_Z;
789 case COND_OVERF_SET:
790 check_flag(opts, FLAG_V);
791 break;
792 case COND_PLUS:
793 cond = CC_Z;
794 case COND_MINUS:
795 check_flag(opts, FLAG_N);
796 break;
797 case COND_GREATER_EQ:
798 cond = CC_Z;
799 case COND_LESS:
800 cmp_flags(opts, FLAG_N, FLAG_V);
801 break;
802 case COND_GREATER:
803 cond = CC_Z;
804 case COND_LESS_EQ:
805 flag_to_reg(opts, FLAG_V, opts->gen.scratch1);
806 xor_flag_to_reg(opts, FLAG_N, opts->gen.scratch1);
807 or_flag_to_reg(opts, FLAG_Z, opts->gen.scratch1);
808 break;
809 }
810 return cond;
811}
812
813void translate_m68k_bcc(m68k_options * opts, m68kinst * inst)
814{
815 code_info *code = &opts->gen.code;
816
817 int32_t disp = inst->src.params.immed;
818 uint32_t after = inst->address + 2;
819 if (inst->extra.cond == COND_TRUE) {
820 cycles(&opts->gen, 10);
821 jump_m68k_abs(opts, after + disp);
822 } else {
823 uint8_t cond = m68k_eval_cond(opts, inst->extra.cond);
824 code_ptr do_branch = code->cur + 1;
825 jcc(code, cond, do_branch);
826
827 cycles(&opts->gen, inst->variant == VAR_BYTE ? 8 : 12);
828 code_ptr done = code->cur + 1;
829 jmp(code, done);
830
831 *do_branch = code->cur - (do_branch + 1);
832 cycles(&opts->gen, 10);
833 code_ptr dest_addr = get_native_address(opts, after + disp);
834 if (!dest_addr) {
835 opts->gen.deferred = defer_address(opts->gen.deferred, after + disp, code->cur + 1);
836 //dummy address to be replaced later, make sure it generates a 4-byte displacement
837 dest_addr = code->cur + 256;
838 }
839 jmp(code, dest_addr);
840
841 *done = code->cur - (done + 1);
842 }
843}
844
845void translate_m68k_scc(m68k_options * opts, m68kinst * inst)
846{
847 code_info *code = &opts->gen.code;
848 uint8_t cond = inst->extra.cond;
849 host_ea dst_op;
850 inst->extra.size = OPSIZE_BYTE;
851 translate_m68k_op(inst, &dst_op, opts, 1);
852 if (cond == COND_TRUE || cond == COND_FALSE) {
853 if ((inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG) && inst->extra.cond == COND_TRUE) {
854 cycles(&opts->gen, 6);
855 } else {
856 cycles(&opts->gen, BUS);
857 }
858 if (dst_op.mode == MODE_REG_DIRECT) {
859 mov_ir(code, cond == COND_TRUE ? 0xFF : 0, dst_op.base, SZ_B);
860 } else {
861 mov_irdisp(code, cond == COND_TRUE ? 0xFF : 0, dst_op.base, dst_op.disp, SZ_B);
862 }
863 } else {
864 uint8_t cc = m68k_eval_cond(opts, cond);
865 check_alloc_code(code, 6*MAX_INST_LEN);
866 code_ptr true_off = code->cur + 1;
867 jcc(code, cc, code->cur+2);
868 cycles(&opts->gen, BUS);
869 if (dst_op.mode == MODE_REG_DIRECT) {
870 mov_ir(code, 0, dst_op.base, SZ_B);
871 } else {
872 mov_irdisp(code, 0, dst_op.base, dst_op.disp, SZ_B);
873 }
874 code_ptr end_off = code->cur+1;
875 jmp(code, code->cur+2);
876 *true_off = code->cur - (true_off+1);
877 cycles(&opts->gen, 6);
878 if (dst_op.mode == MODE_REG_DIRECT) {
879 mov_ir(code, 0xFF, dst_op.base, SZ_B);
880 } else {
881 mov_irdisp(code, 0xFF, dst_op.base, dst_op.disp, SZ_B);
882 }
883 *end_off = code->cur - (end_off+1);
884 }
885 m68k_save_result(inst, opts);
886}
887
888void translate_m68k_dbcc(m68k_options * opts, m68kinst * inst)
889{
890 code_info *code = &opts->gen.code;
891 //best case duration
892 cycles(&opts->gen, 10);
893 code_ptr skip_loc = NULL;
894 //TODO: Check if COND_TRUE technically valid here even though
895 //it's basically a slow NOP
896 if (inst->extra.cond != COND_FALSE) {
897 uint8_t cond = m68k_eval_cond(opts, inst->extra.cond);
898 check_alloc_code(code, 6*MAX_INST_LEN);
899 skip_loc = code->cur + 1;
900 jcc(code, cond, code->cur + 2);
901 }
902 if (opts->dregs[inst->dst.params.regs.pri] >= 0) {
903 sub_ir(code, 1, opts->dregs[inst->dst.params.regs.pri], SZ_W);
904 cmp_ir(code, -1, opts->dregs[inst->dst.params.regs.pri], SZ_W);
905 } else {
906 sub_irdisp(code, 1, opts->gen.context_reg, offsetof(m68k_context, dregs) + 4 * inst->dst.params.regs.pri, SZ_W);
907 cmp_irdisp(code, -1, opts->gen.context_reg, offsetof(m68k_context, dregs) + 4 * inst->dst.params.regs.pri, SZ_W);
908 }
909 code_ptr loop_end_loc = code->cur + 1;
910 jcc(code, CC_Z, code->cur + 2);
911 uint32_t after = inst->address + 2;
912 jump_m68k_abs(opts, after + inst->src.params.immed);
913 *loop_end_loc = code->cur - (loop_end_loc+1);
914 if (skip_loc) {
915 cycles(&opts->gen, 2);
916 *skip_loc = code->cur - (skip_loc+1);
917 cycles(&opts->gen, 2);
918 } else {
919 cycles(&opts->gen, 4);
920 }
921}
922
923void translate_m68k_movep(m68k_options * opts, m68kinst * inst)
924{
925 code_info *code = &opts->gen.code;
926 int8_t reg;
927 cycles(&opts->gen, BUS*2);
928 if (inst->src.addr_mode == MODE_REG) {
929 calc_areg_displace(opts, &inst->dst, opts->gen.scratch2);
930 reg = native_reg(&(inst->src), opts);
931 if (inst->extra.size == OPSIZE_LONG) {
932 if (reg >= 0) {
933 mov_rr(code, reg, opts->gen.scratch1, SZ_D);
934 shr_ir(code, 24, opts->gen.scratch1, SZ_D);
935 push_r(code, opts->gen.scratch2);
936 call(code, opts->write_8);
937 pop_r(code, opts->gen.scratch2);
938 mov_rr(code, reg, opts->gen.scratch1, SZ_D);
939 shr_ir(code, 16, opts->gen.scratch1, SZ_D);
940
941 } else {
942 mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src))+3, opts->gen.scratch1, SZ_B);
943 push_r(code, opts->gen.scratch2);
944 call(code, opts->write_8);
945 pop_r(code, opts->gen.scratch2);
946 mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src))+2, opts->gen.scratch1, SZ_B);
947 }
948 add_ir(code, 2, opts->gen.scratch2, SZ_D);
949 push_r(code, opts->gen.scratch2);
950 call(code, opts->write_8);
951 pop_r(code, opts->gen.scratch2);
952 add_ir(code, 2, opts->gen.scratch2, SZ_D);
953 }
954 if (reg >= 0) {
955 mov_rr(code, reg, opts->gen.scratch1, SZ_W);
956 shr_ir(code, 8, opts->gen.scratch1, SZ_W);
957 push_r(code, opts->gen.scratch2);
958 call(code, opts->write_8);
959 pop_r(code, opts->gen.scratch2);
960 mov_rr(code, reg, opts->gen.scratch1, SZ_W);
961 } else {
962 mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src))+1, opts->gen.scratch1, SZ_B);
963 push_r(code, opts->gen.scratch2);
964 call(code, opts->write_8);
965 pop_r(code, opts->gen.scratch2);
966 mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src)), opts->gen.scratch1, SZ_B);
967 }
968 add_ir(code, 2, opts->gen.scratch2, SZ_D);
969 call(code, opts->write_8);
970 } else {
971 calc_areg_displace(opts, &inst->src, opts->gen.scratch1);
972 reg = native_reg(&(inst->dst), opts);
973 if (inst->extra.size == OPSIZE_LONG) {
974 if (reg >= 0) {
975 push_r(code, opts->gen.scratch1);
976 call(code, opts->read_8);
977 shl_ir(code, 24, opts->gen.scratch1, SZ_D);
978 mov_rr(code, opts->gen.scratch1, reg, SZ_D);
979 pop_r(code, opts->gen.scratch1);
980 add_ir(code, 2, opts->gen.scratch1, SZ_D);
981 push_r(code, opts->gen.scratch1);
982 call(code, opts->read_8);
983 movzx_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_B, SZ_W);
984 shl_ir(code, 16, opts->gen.scratch1, SZ_D);
985 or_rr(code, opts->gen.scratch1, reg, SZ_D);
986 } else {
987 push_r(code, opts->gen.scratch1);
988 call(code, opts->read_8);
989 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, reg_offset(&(inst->dst))+3, SZ_B);
990 pop_r(code, opts->gen.scratch1);
991 add_ir(code, 2, opts->gen.scratch1, SZ_D);
992 push_r(code, opts->gen.scratch1);
993 call(code, opts->read_8);
994 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, reg_offset(&(inst->dst))+2, SZ_B);
995 }
996 pop_r(code, opts->gen.scratch1);
997 add_ir(code, 2, opts->gen.scratch1, SZ_D);
998 }
999 push_r(code, opts->gen.scratch1);
1000 call(code, opts->read_8);
1001 if (reg >= 0) {
1002
1003 shl_ir(code, 8, opts->gen.scratch1, SZ_W);
1004 mov_rr(code, opts->gen.scratch1, reg, SZ_W);
1005 pop_r(code, opts->gen.scratch1);
1006 add_ir(code, 2, opts->gen.scratch1, SZ_D);
1007 call(code, opts->read_8);
1008 mov_rr(code, opts->gen.scratch1, reg, SZ_B);
1009 } else {
1010 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, reg_offset(&(inst->dst))+1, SZ_B);
1011 pop_r(code, opts->gen.scratch1);
1012 add_ir(code, 2, opts->gen.scratch1, SZ_D);
1013 call(code, opts->read_8);
1014 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, reg_offset(&(inst->dst)), SZ_B);
1015 }
1016 }
1017}
1018
1019typedef void (*shift_ir_t)(code_info *code, uint8_t val, uint8_t dst, uint8_t size);
1020typedef void (*shift_irdisp_t)(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size);
1021typedef void (*shift_clr_t)(code_info *code, uint8_t dst, uint8_t size);
1022typedef void (*shift_clrdisp_t)(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
1023
1024void translate_shift(m68k_options * opts, m68kinst * inst, host_ea *src_op, host_ea * dst_op, shift_ir_t shift_ir, shift_irdisp_t shift_irdisp, shift_clr_t shift_clr, shift_clrdisp_t shift_clrdisp, shift_ir_t special, shift_irdisp_t special_disp)
1025{
1026 code_info *code = &opts->gen.code;
1027 code_ptr end_off = NULL;
1028 code_ptr nz_off = NULL;
1029 code_ptr z_off = NULL;
1030 if (inst->src.addr_mode == MODE_UNUSED) {
1031 cycles(&opts->gen, BUS);
1032 //Memory shift
1033 shift_ir(code, 1, dst_op->base, SZ_W);
1034 } else {
1035 if (src_op->mode == MODE_IMMED) {
1036 cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG ? 8 : 6) + 2 * src_op->disp);
1037 if (src_op->disp != 1 && inst->op == M68K_ASL) {
1038 set_flag(opts, 0, FLAG_V);
1039 for (int i = 0; i < src_op->disp; i++) {
1040 if (dst_op->mode == MODE_REG_DIRECT) {
1041 shift_ir(code, 1, dst_op->base, inst->extra.size);
1042 } else {
1043 shift_irdisp(code, 1, dst_op->base, dst_op->disp, inst->extra.size);
1044 }
1045 check_alloc_code(code, 2*MAX_INST_LEN);
1046 code_ptr after_flag_set = code->cur + 1;
1047 jcc(code, CC_NO, code->cur + 2);
1048 set_flag(opts, 1, FLAG_V);
1049 *after_flag_set = code->cur - (after_flag_set+1);
1050 }
1051 } else {
1052 if (dst_op->mode == MODE_REG_DIRECT) {
1053 shift_ir(code, src_op->disp, dst_op->base, inst->extra.size);
1054 } else {
1055 shift_irdisp(code, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size);
1056 }
1057 set_flag_cond(opts, CC_O, FLAG_V);
1058 }
1059 } else {
1060 cycles(&opts->gen, inst->extra.size == OPSIZE_LONG ? 8 : 6);
1061 if (src_op->base != RCX) {
1062 if (src_op->mode == MODE_REG_DIRECT) {
1063 mov_rr(code, src_op->base, RCX, SZ_B);
1064 } else {
1065 mov_rdispr(code, src_op->base, src_op->disp, RCX, SZ_B);
1066 }
1067
1068 }
1069 and_ir(code, 63, RCX, SZ_D);
1070 check_alloc_code(code, 7*MAX_INST_LEN);
1071 nz_off = code->cur + 1;
1072 jcc(code, CC_NZ, code->cur + 2);
1073 //Flag behavior for shift count of 0 is different for x86 than 68K
1074 if (dst_op->mode == MODE_REG_DIRECT) {
1075 cmp_ir(code, 0, dst_op->base, inst->extra.size);
1076 } else {
1077 cmp_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size);
1078 }
1079 set_flag_cond(opts, CC_Z, FLAG_Z);
1080 set_flag_cond(opts, CC_S, FLAG_N);
1081 set_flag(opts, 0, FLAG_C);
1082 //For other instructions, this flag will be set below
1083 if (inst->op == M68K_ASL) {
1084 set_flag(opts, 0, FLAG_V);
1085 }
1086 z_off = code->cur + 1;
1087 jmp(code, code->cur + 2);
1088 *nz_off = code->cur - (nz_off + 1);
1089 //add 2 cycles for every bit shifted
1090 mov_ir(code, 2 * opts->gen.clock_divider, opts->gen.scratch2, SZ_D);
1091 imul_rr(code, RCX, opts->gen.scratch2, SZ_D);
1092 add_rr(code, opts->gen.scratch2, opts->gen.cycles, SZ_D);
1093 if (inst->op == M68K_ASL) {
1094 //ASL has Overflow flag behavior that depends on all of the bits shifted through the MSB
1095 //Easiest way to deal with this is to shift one bit at a time
1096 set_flag(opts, 0, FLAG_V);
1097 check_alloc_code(code, 5*MAX_INST_LEN);
1098 code_ptr loop_start = code->cur;
1099 if (dst_op->mode == MODE_REG_DIRECT) {
1100 shift_ir(code, 1, dst_op->base, inst->extra.size);
1101 } else {
1102 shift_irdisp(code, 1, dst_op->base, dst_op->disp, inst->extra.size);
1103 }
1104 code_ptr after_flag_set = code->cur + 1;
1105 jcc(code, CC_NO, code->cur + 2);
1106 set_flag(opts, 1, FLAG_V);
1107 *after_flag_set = code->cur - (after_flag_set+1);
1108 loop(code, loop_start);
1109 } else {
1110 //x86 shifts modulo 32 for operand sizes less than 64-bits
1111 //but M68K shifts modulo 64, so we need to check for large shifts here
1112 cmp_ir(code, 32, RCX, SZ_B);
1113 check_alloc_code(code, 14*MAX_INST_LEN);
1114 code_ptr norm_shift_off = code->cur + 1;
1115 jcc(code, CC_L, code->cur + 2);
1116 if (special) {
1117 code_ptr after_flag_set = NULL;
1118 if (inst->extra.size == OPSIZE_LONG) {
1119 code_ptr neq_32_off = code->cur + 1;
1120 jcc(code, CC_NZ, code->cur + 2);
1121
1122 //set the carry bit to the lsb
1123 if (dst_op->mode == MODE_REG_DIRECT) {
1124 special(code, 1, dst_op->base, SZ_D);
1125 } else {
1126 special_disp(code, 1, dst_op->base, dst_op->disp, SZ_D);
1127 }
1128 set_flag_cond(opts, CC_C, FLAG_C);
1129 after_flag_set = code->cur + 1;
1130 jmp(code, code->cur + 2);
1131 *neq_32_off = code->cur - (neq_32_off+1);
1132 }
1133 set_flag(opts, 0, FLAG_C);
1134 if (after_flag_set) {
1135 *after_flag_set = code->cur - (after_flag_set+1);
1136 }
1137 set_flag(opts, 1, FLAG_Z);
1138 set_flag(opts, 0, FLAG_N);
1139 if (dst_op->mode == MODE_REG_DIRECT) {
1140 xor_rr(code, dst_op->base, dst_op->base, inst->extra.size);
1141 } else {
1142 mov_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size);
1143 }
1144 } else {
1145 if (dst_op->mode == MODE_REG_DIRECT) {
1146 shift_ir(code, 31, dst_op->base, inst->extra.size);
1147 shift_ir(code, 1, dst_op->base, inst->extra.size);
1148 } else {
1149 shift_irdisp(code, 31, dst_op->base, dst_op->disp, inst->extra.size);
1150 shift_irdisp(code, 1, dst_op->base, dst_op->disp, inst->extra.size);
1151 }
1152
1153 }
1154 end_off = code->cur + 1;
1155 jmp(code, code->cur + 2);
1156 *norm_shift_off = code->cur - (norm_shift_off+1);
1157 if (dst_op->mode == MODE_REG_DIRECT) {
1158 shift_clr(code, dst_op->base, inst->extra.size);
1159 } else {
1160 shift_clrdisp(code, dst_op->base, dst_op->disp, inst->extra.size);
1161 }
1162 }
1163 }
1164
1165 }
1166 if (!special && end_off) {
1167 *end_off = code->cur - (end_off + 1);
1168 }
1169 update_flags(opts, C|Z|N);
1170 if (special && end_off) {
1171 *end_off = code->cur - (end_off + 1);
1172 }
1173 //set X flag to same as C flag
1174 if (opts->flag_regs[FLAG_C] >= 0) {
1175 flag_to_flag(opts, FLAG_C, FLAG_X);
1176 } else {
1177 set_flag_cond(opts, CC_C, FLAG_X);
1178 }
1179 if (z_off) {
1180 *z_off = code->cur - (z_off + 1);
1181 }
1182 if (inst->op != M68K_ASL) {
1183 set_flag(opts, 0, FLAG_V);
1184 }
1185 if (inst->src.addr_mode == MODE_UNUSED) {
1186 m68k_save_result(inst, opts);
1187 }
1188}
1189
1190void translate_m68k_reset(m68k_options *opts, m68kinst *inst)
1191{
1192 code_info *code = &opts->gen.code;
1193 //RESET instructions take a long time to give peripherals time to reset themselves
1194 cycles(&opts->gen, 132);
1195 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, reset_handler), opts->gen.scratch1, SZ_PTR);
1196 cmp_ir(code, 0, opts->gen.scratch1, SZ_PTR);
1197 code_ptr no_reset_handler = code->cur + 1;
1198 jcc(code, CC_Z, code->cur+2);
1199 call(code, opts->gen.save_context);
1200 call_args_r(code, opts->gen.scratch1, 1, opts->gen.context_reg);
1201 mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR);
1202 call(code, opts->gen.load_context);
1203 *no_reset_handler = code->cur - (no_reset_handler + 1);
1204}
1205
1206void op_ir(code_info *code, m68kinst *inst, int32_t val, uint8_t dst, uint8_t size)
1207{
1208 switch (inst->op)
1209 {
1210 case M68K_ADD: add_ir(code, val, dst, size); break;
1211 case M68K_ADDX: adc_ir(code, val, dst, size); break;
1212 case M68K_AND: and_ir(code, val, dst, size); break;
1213 case M68K_BTST: bt_ir(code, val, dst, size); break;
1214 case M68K_BSET: bts_ir(code, val, dst, size); break;
1215 case M68K_BCLR: btr_ir(code, val, dst, size); break;
1216 case M68K_BCHG: btc_ir(code, val, dst, size); break;
1217 case M68K_CMP: cmp_ir(code, val, dst, size); break;
1218 case M68K_EOR: xor_ir(code, val, dst, size); break;
1219 case M68K_OR: or_ir(code, val, dst, size); break;
1220 case M68K_ROL: rol_ir(code, val, dst, size); break;
1221 case M68K_ROR: ror_ir(code, val, dst, size); break;
1222 case M68K_ROXL: rcl_ir(code, val, dst, size); break;
1223 case M68K_ROXR: rcr_ir(code, val, dst, size); break;
1224 case M68K_SUB: sub_ir(code, val, dst, size); break;
1225 case M68K_SUBX: sbb_ir(code, val, dst, size); break;
1226 }
1227}
1228
1229void op_irdisp(code_info *code, m68kinst *inst, int32_t val, uint8_t dst, int32_t disp, uint8_t size)
1230{
1231 switch (inst->op)
1232 {
1233 case M68K_ADD: add_irdisp(code, val, dst, disp, size); break;
1234 case M68K_ADDX: adc_irdisp(code, val, dst, disp, size); break;
1235 case M68K_AND: and_irdisp(code, val, dst, disp, size); break;
1236 case M68K_BTST: bt_irdisp(code, val, dst, disp, size); break;
1237 case M68K_BSET: bts_irdisp(code, val, dst, disp, size); break;
1238 case M68K_BCLR: btr_irdisp(code, val, dst, disp, size); break;
1239 case M68K_BCHG: btc_irdisp(code, val, dst, disp, size); break;
1240 case M68K_CMP: cmp_irdisp(code, val, dst, disp, size); break;
1241 case M68K_EOR: xor_irdisp(code, val, dst, disp, size); break;
1242 case M68K_OR: or_irdisp(code, val, dst, disp, size); break;
1243 case M68K_ROL: rol_irdisp(code, val, dst, disp, size); break;
1244 case M68K_ROR: ror_irdisp(code, val, dst, disp, size); break;
1245 case M68K_ROXL: rcl_irdisp(code, val, dst, disp, size); break;
1246 case M68K_ROXR: rcr_irdisp(code, val, dst, disp, size); break;
1247 case M68K_SUB: sub_irdisp(code, val, dst, disp, size); break;
1248 case M68K_SUBX: sbb_irdisp(code, val, dst, disp, size); break;
1249 }
1250}
1251
1252void op_rr(code_info *code, m68kinst *inst, uint8_t src, uint8_t dst, uint8_t size)
1253{
1254 switch (inst->op)
1255 {
1256 case M68K_ADD: add_rr(code, src, dst, size); break;
1257 case M68K_ADDX: adc_rr(code, src, dst, size); break;
1258 case M68K_AND: and_rr(code, src, dst, size); break;
1259 case M68K_BTST: bt_rr(code, src, dst, size); break;
1260 case M68K_BSET: bts_rr(code, src, dst, size); break;
1261 case M68K_BCLR: btr_rr(code, src, dst, size); break;
1262 case M68K_BCHG: btc_rr(code, src, dst, size); break;
1263 case M68K_CMP: cmp_rr(code, src, dst, size); break;
1264 case M68K_EOR: xor_rr(code, src, dst, size); break;
1265 case M68K_OR: or_rr(code, src, dst, size); break;
1266 case M68K_SUB: sub_rr(code, src, dst, size); break;
1267 case M68K_SUBX: sbb_rr(code, src, dst, size); break;
1268 }
1269}
1270
1271void op_rrdisp(code_info *code, m68kinst *inst, uint8_t src, uint8_t dst, int32_t disp, uint8_t size)
1272{
1273 switch(inst->op)
1274 {
1275 case M68K_ADD: add_rrdisp(code, src, dst, disp, size); break;
1276 case M68K_ADDX: adc_rrdisp(code, src, dst, disp, size); break;
1277 case M68K_AND: and_rrdisp(code, src, dst, disp, size); break;
1278 case M68K_BTST: bt_rrdisp(code, src, dst, disp, size); break;
1279 case M68K_BSET: bts_rrdisp(code, src, dst, disp, size); break;
1280 case M68K_BCLR: btr_rrdisp(code, src, dst, disp, size); break;
1281 case M68K_BCHG: btc_rrdisp(code, src, dst, disp, size); break;
1282 case M68K_CMP: cmp_rrdisp(code, src, dst, disp, size); break;
1283 case M68K_EOR: xor_rrdisp(code, src, dst, disp, size); break;
1284 case M68K_OR: or_rrdisp(code, src, dst, disp, size); break;
1285 case M68K_SUB: sub_rrdisp(code, src, dst, disp, size); break;
1286 case M68K_SUBX: sbb_rrdisp(code, src, dst, disp, size); break;
1287 }
1288}
1289
1290void op_rdispr(code_info *code, m68kinst *inst, uint8_t src, int32_t disp, uint8_t dst, uint8_t size)
1291{
1292 switch (inst->op)
1293 {
1294 case M68K_ADD: add_rdispr(code, src, disp, dst, size); break;
1295 case M68K_ADDX: adc_rdispr(code, src, disp, dst, size); break;
1296 case M68K_AND: and_rdispr(code, src, disp, dst, size); break;
1297 case M68K_CMP: cmp_rdispr(code, src, disp, dst, size); break;
1298 case M68K_EOR: xor_rdispr(code, src, disp, dst, size); break;
1299 case M68K_OR: or_rdispr(code, src, disp, dst, size); break;
1300 case M68K_SUB: sub_rdispr(code, src, disp, dst, size); break;
1301 case M68K_SUBX: sbb_rdispr(code, src, disp, dst, size); break;
1302 }
1303}
1304
1305void translate_m68k_arith(m68k_options *opts, m68kinst * inst, uint32_t flag_mask, host_ea *src_op, host_ea *dst_op)
1306{
1307 code_info *code = &opts->gen.code;
1308 uint8_t size = inst->dst.addr_mode == MODE_AREG ? OPSIZE_LONG : inst->extra.size;
1309
1310 uint32_t numcycles;
1311 if ((inst->op == M68K_ADDX || inst->op == M68K_SUBX) && inst->src.addr_mode != MODE_REG) {
1312 numcycles = 6;
1313 } else if (size == OPSIZE_LONG) {
1314 if (inst->op == M68K_CMP) {
1315 numcycles = 6;
1316 } else if (inst->op == M68K_AND && inst->variant == VAR_IMMEDIATE) {
1317 numcycles = 6;
1318 } else if (inst->op == M68K_ADD && inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD && inst->variant == VAR_QUICK) {
1319 numcycles = 4;
1320 } else if (inst->dst.addr_mode <= MODE_AREG) {
1321 numcycles = inst->src.addr_mode <= MODE_AREG || inst->src.addr_mode == MODE_IMMEDIATE ? 8 : 6;
1322 } else {
1323 numcycles = 4;
1324 }
1325 } else {
1326 numcycles = 4;
1327 }
1328 cycles(&opts->gen, numcycles);
1329
1330 if (inst->op == M68K_ADDX || inst->op == M68K_SUBX) {
1331 flag_to_carry(opts, FLAG_X);
1332 }
1333
1334 if (src_op->mode == MODE_REG_DIRECT) {
1335 if (dst_op->mode == MODE_REG_DIRECT) {
1336 op_rr(code, inst, src_op->base, dst_op->base, size);
1337 } else {
1338 op_rrdisp(code, inst, src_op->base, dst_op->base, dst_op->disp, size);
1339 }
1340 } else if (src_op->mode == MODE_REG_DISPLACE8) {
1341 op_rdispr(code, inst, src_op->base, src_op->disp, dst_op->base, size);
1342 } else {
1343 if (dst_op->mode == MODE_REG_DIRECT) {
1344 op_ir(code, inst, src_op->disp, dst_op->base, size);
1345 } else {
1346 op_irdisp(code, inst, src_op->disp, dst_op->base, dst_op->disp, size);
1347 }
1348 }
1349 if (inst->dst.addr_mode != MODE_AREG || inst->op == M68K_CMP) {
1350 update_flags(opts, flag_mask);
1351 if (inst->op == M68K_ADDX || inst->op == M68K_SUBX) {
1352 check_alloc_code(code, 2*MAX_INST_LEN);
1353 code_ptr after_flag_set = code->cur + 1;
1354 jcc(code, CC_Z, code->cur + 2);
1355 set_flag(opts, 0, FLAG_Z);
1356 *after_flag_set = code->cur - (after_flag_set+1);
1357 }
1358 }
1359 if (inst->op != M68K_CMP) {
1360 m68k_save_result(inst, opts);
1361 }
1362}
1363
1364void translate_m68k_cmp(m68k_options * opts, m68kinst * inst)
1365{
1366 code_info *code = &opts->gen.code;
1367 uint8_t size = inst->extra.size;
1368 host_ea src_op, dst_op;
1369 translate_m68k_op(inst, &src_op, opts, 0);
1370 if (inst->dst.addr_mode == MODE_AREG_POSTINC) {
1371 push_r(code, opts->gen.scratch1);
1372 translate_m68k_op(inst, &dst_op, opts, 1);
1373 pop_r(code, opts->gen.scratch2);
1374 src_op.base = opts->gen.scratch2;
1375 } else {
1376 translate_m68k_op(inst, &dst_op, opts, 1);
1377 if (inst->dst.addr_mode == MODE_AREG && size == OPSIZE_WORD) {
1378 size = OPSIZE_LONG;
1379 }
1380 }
1381 translate_m68k_arith(opts, inst, N|Z|V|C, &src_op, &dst_op);
1382}
1383
1384void translate_m68k_tas(m68k_options *opts, m68kinst *inst)
1385{
1386 code_info *code = &opts->gen.code;
1387 host_ea op;
1388 translate_m68k_op(inst, &op, opts, 1);
1389 if (op.mode == MODE_REG_DIRECT) {
1390 cmp_ir(code, 0, op.base, SZ_B);
1391 } else {
1392 cmp_irdisp(code, 0, op.base, op.disp, SZ_B);
1393 }
1394 update_flags(opts, N|Z|V0|C0);
1395 if (inst->dst.addr_mode == MODE_REG) {
1396 cycles(&opts->gen, BUS);
1397 if (op.mode == MODE_REG_DIRECT) {
1398 bts_ir(code, 7, op.base, SZ_B);
1399 } else {
1400 bts_irdisp(code, 7, op.base, op.disp, SZ_B);
1401 }
1402 } else {
1403 if (opts->gen.flags & M68K_OPT_BROKEN_READ_MODIFY) {
1404 //2 cycles for processing
1405 //4 for failed writeback
1406 //4 for prefetch
1407 cycles(&opts->gen, BUS * 2 + 2);
1408 } else {
1409 cycles(&opts->gen, 2);
1410 bts_ir(code, 7, op.base, SZ_B);
1411 m68k_save_result(inst, opts);
1412 cycles(&opts->gen, BUS);
1413 }
1414 }
1415}
1416
1417void op_r(code_info *code, m68kinst *inst, uint8_t dst, uint8_t size)
1418{
1419 switch(inst->op)
1420 {
1421 case M68K_CLR: xor_rr(code, dst, dst, size); break;
1422 case M68K_NEG: neg_r(code, dst, size); break;
1423 case M68K_NOT: not_r(code, dst, size); cmp_ir(code, 0, dst, size); break;
1424 case M68K_ROL: rol_clr(code, dst, size); break;
1425 case M68K_ROR: ror_clr(code, dst, size); break;
1426 case M68K_ROXL: rcl_clr(code, dst, size); break;
1427 case M68K_ROXR: rcr_clr(code, dst, size); break;
1428 case M68K_SWAP: rol_ir(code, 16, dst, SZ_D); cmp_ir(code, 0, dst, SZ_D); break;
1429 case M68K_TST: cmp_ir(code, 0, dst, size); break;
1430 }
1431}
1432
1433void op_rdisp(code_info *code, m68kinst *inst, uint8_t dst, int32_t disp, uint8_t size)
1434{
1435 switch(inst->op)
1436 {
1437 case M68K_CLR: mov_irdisp(code, 0, dst, disp, size); break;
1438 case M68K_NEG: neg_rdisp(code, dst, disp, size); break;
1439 case M68K_NOT: not_rdisp(code, dst, disp, size); cmp_irdisp(code, 0, dst, disp, size); break;
1440 case M68K_ROL: rol_clrdisp(code, dst, disp, size); break;
1441 case M68K_ROR: ror_clrdisp(code, dst, disp, size); break;
1442 case M68K_ROXL: rcl_clrdisp(code, dst, disp, size); break;
1443 case M68K_ROXR: rcr_clrdisp(code, dst, disp, size); break;
1444 case M68K_SWAP: rol_irdisp(code, 16, dst, disp, SZ_D); cmp_irdisp(code, 0, dst, disp, SZ_D); break;
1445 case M68K_TST: cmp_irdisp(code, 0, dst, disp, size); break;
1446 }
1447}
1448
1449void translate_m68k_unary(m68k_options *opts, m68kinst *inst, uint32_t flag_mask, host_ea *dst_op)
1450{
1451 code_info *code = &opts->gen.code;
1452 uint32_t num_cycles = BUS;
1453 if (inst->extra.size == OPSIZE_LONG && (inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG)) {
1454 num_cycles += 2;
1455 }
1456 cycles(&opts->gen, num_cycles);
1457 if (dst_op->mode == MODE_REG_DIRECT) {
1458 op_r(code, inst, dst_op->base, inst->extra.size);
1459 } else {
1460 op_rdisp(code, inst, dst_op->base, dst_op->disp, inst->extra.size);
1461 }
1462 update_flags(opts, flag_mask);
1463 m68k_save_result(inst, opts);
1464}
1465
1466void translate_m68k_abcd_sbcd(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
1467{
1468 code_info *code = &opts->gen.code;
1469 if (inst->op == M68K_NBCD) {
1470 if (dst_op->base != opts->gen.scratch2) {
1471 if (dst_op->mode == MODE_REG_DIRECT) {
1472 mov_rr(code, dst_op->base, opts->gen.scratch2, SZ_B);
1473 } else {
1474 mov_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_B);
1475 }
1476 }
1477 xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_B);
1478 } else {
1479 if (src_op->base != opts->gen.scratch2) {
1480 if (src_op->mode == MODE_REG_DIRECT) {
1481 mov_rr(code, src_op->base, opts->gen.scratch2, SZ_B);
1482 } else {
1483 mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_B);
1484 }
1485 }
1486 if (dst_op->base != opts->gen.scratch1) {
1487 if (dst_op->mode == MODE_REG_DIRECT) {
1488 mov_rr(code, dst_op->base, opts->gen.scratch1, SZ_B);
1489 } else {
1490 mov_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch1, SZ_B);
1491 }
1492 }
1493 }
1494 if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG && inst->dst.addr_mode != MODE_AREG_PREDEC) {
1495 //destination is in memory so we need to preserve scratch2 for the write at the end
1496 push_r(code, opts->gen.scratch2);
1497 }
1498 //MC68000 User's Manual suggests NBCD hides the 2 cycle penalty during the write cycle somehow
1499 cycles(&opts->gen, inst->op == M68K_NBCD && inst->dst.addr_mode != MODE_REG_DIRECT ? BUS : BUS + 2);
1500 uint8_t other_reg;
1501 //WARNING: This may need adjustment if register assignments change
1502 if (opts->gen.scratch2 > RBX) {
1503 other_reg = RAX;
1504 xchg_rr(code, opts->gen.scratch2, RAX, SZ_D);
1505 } else {
1506 other_reg = opts->gen.scratch2;
1507 }
1508 mov_rr(code, opts->gen.scratch1, opts->gen.scratch1 + (AH-RAX), SZ_B);
1509 mov_rr(code, other_reg, other_reg + (AH-RAX), SZ_B);
1510 and_ir(code, 0xF, opts->gen.scratch1 + (AH-RAX), SZ_B);
1511 and_ir(code, 0xF, other_reg + (AH-RAX), SZ_B);
1512 //do op on low nibble so we can determine if an adjustment is necessary
1513 flag_to_carry(opts, FLAG_X);
1514 if (inst->op == M68K_ABCD) {
1515 adc_rr(code, other_reg + (AH-RAX), opts->gen.scratch1 + (AH-RAX), SZ_B);
1516 } else {
1517 sbb_rr(code, other_reg + (AH-RAX), opts->gen.scratch1 + (AH-RAX), SZ_B);
1518 }
1519 cmp_ir(code, inst->op == M68K_SBCD ? 0x10 : 0xA, opts->gen.scratch1 + (AH-RAX), SZ_B);
1520 mov_ir(code, 0xA0, other_reg + (AH-RAX), SZ_B);
1521 code_ptr no_adjust = code->cur+1;
1522 //add correction factor if necessary
1523 jcc(code, CC_B, no_adjust);
1524 mov_ir(code, 6, opts->gen.scratch1 + (AH-RAX), SZ_B);
1525 mov_ir(code, inst->op == M68K_ABCD ? 0x9A : 0xA6, other_reg + (AH-RAX), SZ_B);
1526 code_ptr after_adjust = code->cur+1;
1527 jmp(code, after_adjust);
1528
1529 *no_adjust = code->cur - (no_adjust+1);
1530 xor_rr(code, opts->gen.scratch1 + (AH-RAX), opts->gen.scratch1 + (AH-RAX), SZ_B);
1531 *after_adjust = code->cur - (after_adjust+1);
1532
1533 //do op on full byte
1534 flag_to_carry(opts, FLAG_X);
1535 if (inst->op == M68K_ABCD) {
1536 adc_rr(code, other_reg, opts->gen.scratch1, SZ_B);
1537 } else {
1538 sbb_rr(code, other_reg, opts->gen.scratch1, SZ_B);
1539 }
1540 set_flag(opts, 0, FLAG_C);
1541 //determine if we need a correction on the upper nibble
1542 code_ptr def_adjust = code->cur+1;
1543 jcc(code, CC_C, def_adjust);
1544 if (inst->op == M68K_SBCD) {
1545 no_adjust = code->cur+1;
1546 jmp(code, no_adjust);
1547 } else {
1548 cmp_rr(code, other_reg + (AH-RAX), opts->gen.scratch1, SZ_B);
1549 no_adjust = code->cur+1;
1550 jcc(code, CC_B, no_adjust);
1551 }
1552 *def_adjust = code->cur - (def_adjust + 1);
1553 set_flag(opts, 1, FLAG_C);
1554 or_ir(code, 0x60, opts->gen.scratch1 + (AH-RAX), SZ_B);
1555 *no_adjust = code->cur - (no_adjust+1);
1556 if (inst->op == M68K_ABCD) {
1557 add_rr(code, opts->gen.scratch1 + (AH-RAX), opts->gen.scratch1, SZ_B);
1558 } else {
1559 sub_rr(code, opts->gen.scratch1 + (AH-RAX), opts->gen.scratch1, SZ_B);
1560 }
1561 code_ptr no_ensure_carry = code->cur+1;
1562 jcc(code, CC_NC, no_ensure_carry);
1563 set_flag(opts, 1, FLAG_C);
1564 *no_ensure_carry = code->cur - (no_ensure_carry+1);
1565 //restore RAX if necessary
1566 if (opts->gen.scratch2 > RBX) {
1567 mov_rr(code, opts->gen.scratch2, RAX, SZ_D);
1568 }
1569 //V flag is set based on the result of the addition/subtraction of the
1570 //result and the correction factor
1571 set_flag_cond(opts, CC_O, FLAG_V);
1572
1573 flag_to_flag(opts, FLAG_C, FLAG_X);
1574
1575 cmp_ir(code, 0, opts->gen.scratch1, SZ_B);
1576 set_flag_cond(opts, CC_S, FLAG_N);
1577 code_ptr no_setz = code->cur+1;
1578 jcc(code, CC_Z, no_setz);
1579 set_flag(opts, 0, FLAG_Z);
1580 *no_setz = code->cur - (no_setz + 1);
1581 if (dst_op->base != opts->gen.scratch1) {
1582 if (dst_op->mode == MODE_REG_DIRECT) {
1583 mov_rr(code, opts->gen.scratch1, dst_op->base, SZ_B);
1584 } else {
1585 mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_B);
1586 }
1587 }
1588 if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG && inst->dst.addr_mode != MODE_AREG_PREDEC) {
1589 //destination is in memory so we need to restore scratch2 for the write at the end
1590 pop_r(code, opts->gen.scratch2);
1591 }
1592 m68k_save_result(inst, opts);
1593}
1594
1595void translate_m68k_sl(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
1596{
1597 translate_shift(opts, inst, src_op, dst_op, shl_ir, shl_irdisp, shl_clr, shl_clrdisp, shr_ir, shr_irdisp);
1598}
1599
1600void translate_m68k_asr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
1601{
1602 translate_shift(opts, inst, src_op, dst_op, sar_ir, sar_irdisp, sar_clr, sar_clrdisp, NULL, NULL);
1603}
1604
1605void translate_m68k_lsr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
1606{
1607 translate_shift(opts, inst, src_op, dst_op, shr_ir, shr_irdisp, shr_clr, shr_clrdisp, shl_ir, shl_irdisp);
1608}
1609
1610void translate_m68k_bit(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
1611{
1612 code_info *code = &opts->gen.code;
1613 cycles(&opts->gen, inst->extra.size == OPSIZE_BYTE ? 4 : (
1614 inst->op == M68K_BTST ? 6 : (inst->op == M68K_BCLR ? 10 : 8))
1615 );
1616 if (src_op->mode == MODE_IMMED) {
1617 if (inst->extra.size == OPSIZE_BYTE) {
1618 src_op->disp &= 0x7;
1619 }
1620 if (dst_op->mode == MODE_REG_DIRECT) {
1621 op_ir(code, inst, src_op->disp, dst_op->base, inst->extra.size);
1622 } else {
1623 op_irdisp(code, inst, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size);
1624 }
1625 } else {
1626 if (src_op->mode == MODE_REG_DISPLACE8 || (inst->dst.addr_mode != MODE_REG && src_op->base != opts->gen.scratch1 && src_op->base != opts->gen.scratch2)) {
1627 if (dst_op->base == opts->gen.scratch1) {
1628 push_r(code, opts->gen.scratch2);
1629 if (src_op->mode == MODE_REG_DIRECT) {
1630 mov_rr(code, src_op->base, opts->gen.scratch2, SZ_B);
1631 } else {
1632 mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_B);
1633 }
1634 src_op->base = opts->gen.scratch2;
1635 } else {
1636 if (src_op->mode == MODE_REG_DIRECT) {
1637 mov_rr(code, src_op->base, opts->gen.scratch1, SZ_B);
1638 } else {
1639 mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_B);
1640 }
1641 src_op->base = opts->gen.scratch1;
1642 }
1643 }
1644 uint8_t size = inst->extra.size;
1645 if (dst_op->mode == MODE_REG_DISPLACE8) {
1646 if (src_op->base != opts->gen.scratch1 && src_op->base != opts->gen.scratch2) {
1647 if (src_op->mode == MODE_REG_DIRECT) {
1648 mov_rr(code, src_op->base, opts->gen.scratch1, SZ_D);
1649 } else {
1650 mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_D);
1651 src_op->mode = MODE_REG_DIRECT;
1652 }
1653 src_op->base = opts->gen.scratch1;
1654 }
1655 //b### with register destination is modulo 32
1656 //x86 with a memory destination isn't modulo anything
1657 //so use an and here to force the value to be modulo 32
1658 and_ir(code, 31, opts->gen.scratch1, SZ_D);
1659 } else if(inst->dst.addr_mode != MODE_REG) {
1660 //b### with memory destination is modulo 8
1661 //x86-64 doesn't support 8-bit bit operations
1662 //so we fake it by forcing the bit number to be modulo 8
1663 and_ir(code, 7, src_op->base, SZ_D);
1664 size = SZ_D;
1665 }
1666 if (dst_op->mode == MODE_IMMED) {
1667 dst_op->base = src_op->base == opts->gen.scratch1 ? opts->gen.scratch2 : opts->gen.scratch1;
1668 mov_ir(code, dst_op->disp, dst_op->base, SZ_B);
1669 dst_op->mode = MODE_REG_DIRECT;
1670 }
1671 if (dst_op->mode == MODE_REG_DIRECT) {
1672 op_rr(code, inst, src_op->base, dst_op->base, size);
1673 } else {
1674 op_rrdisp(code, inst, src_op->base, dst_op->base, dst_op->disp, size);
1675 }
1676 if (src_op->base == opts->gen.scratch2) {
1677 pop_r(code, opts->gen.scratch2);
1678 }
1679 }
1680 //x86 sets the carry flag to the value of the bit tested
1681 //68K sets the zero flag to the complement of the bit tested
1682 set_flag_cond(opts, CC_NC, FLAG_Z);
1683 if (inst->op != M68K_BTST) {
1684 m68k_save_result(inst, opts);
1685 }
1686}
1687
1688void translate_m68k_chk(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
1689 {
1690 code_info *code = &opts->gen.code;
1691 cycles(&opts->gen, 6);
1692 if (dst_op->mode == MODE_REG_DIRECT) {
1693 cmp_ir(code, 0, dst_op->base, inst->extra.size);
1694 } else {
1695 cmp_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size);
1696 }
1697 uint32_t isize;
1698 switch(inst->src.addr_mode)
1699 {
1700 case MODE_AREG_DISPLACE:
1701 case MODE_AREG_INDEX_DISP8:
1702 case MODE_ABSOLUTE_SHORT:
1703 case MODE_PC_INDEX_DISP8:
1704 case MODE_PC_DISPLACE:
1705 case MODE_IMMEDIATE:
1706 isize = 4;
1707 break;
1708 case MODE_ABSOLUTE:
1709 isize = 6;
1710 break;
1711 default:
1712 isize = 2;
1713 }
1714 //make sure we won't start a new chunk in the middle of these branches
1715 check_alloc_code(code, MAX_INST_LEN * 11);
1716 code_ptr passed = code->cur + 1;
1717 jcc(code, CC_GE, code->cur + 2);
1718 set_flag(opts, 1, FLAG_N);
1719 mov_ir(code, VECTOR_CHK, opts->gen.scratch2, SZ_D);
1720 mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D);
1721 jmp(code, opts->trap);
1722 *passed = code->cur - (passed+1);
1723 if (dst_op->mode == MODE_REG_DIRECT) {
1724 if (src_op->mode == MODE_REG_DIRECT) {
1725 cmp_rr(code, src_op->base, dst_op->base, inst->extra.size);
1726 } else if(src_op->mode == MODE_REG_DISPLACE8) {
1727 cmp_rdispr(code, src_op->base, src_op->disp, dst_op->base, inst->extra.size);
1728 } else {
1729 cmp_ir(code, src_op->disp, dst_op->base, inst->extra.size);
1730 }
1731 } else if(dst_op->mode == MODE_REG_DISPLACE8) {
1732 if (src_op->mode == MODE_REG_DIRECT) {
1733 cmp_rrdisp(code, src_op->base, dst_op->base, dst_op->disp, inst->extra.size);
1734 } else {
1735 cmp_irdisp(code, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size);
1736 }
1737 }
1738 passed = code->cur + 1;
1739 jcc(code, CC_LE, code->cur + 2);
1740 set_flag(opts, 0, FLAG_N);
1741 mov_ir(code, VECTOR_CHK, opts->gen.scratch2, SZ_D);
1742 mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D);
1743 jmp(code, opts->trap);
1744 *passed = code->cur - (passed+1);
1745 cycles(&opts->gen, 4);
1746}
1747
1748static uint32_t divu(uint32_t dividend, m68k_context *context, uint32_t divisor_shift)
1749{
1750 uint16_t quotient = 0;
1751 uint8_t force = 0;
1752 uint16_t bit = 0;
1753 uint32_t cycles = 6;
1754 for (int i = 0; i < 16; i++)
1755 {
1756 force = dividend >> 31;
1757 quotient = quotient << 1 | bit;
1758 dividend = dividend << 1;
1759
1760 if (force || dividend >= divisor_shift) {
1761 dividend -= divisor_shift;
1762 cycles += force ? 4 : 6;
1763 bit = 1;
1764 } else {
1765 bit = 0;
1766 cycles += 8;
1767 }
1768 }
1769 cycles += force ? 6 : bit ? 4 : 2;
1770 context->current_cycle += cycles * context->options->gen.clock_divider;
1771 quotient = quotient << 1 | bit;
1772 return dividend | quotient;
1773}
1774
1775static uint32_t divs(uint32_t dividend, m68k_context *context, uint32_t divisor_shift)
1776{
1777 uint32_t orig_divisor = divisor_shift, orig_dividend = dividend;
1778 if (divisor_shift & 0x80000000) {
1779 divisor_shift = 0 - divisor_shift;
1780 }
1781
1782 uint32_t cycles = 12;
1783 if (dividend & 0x80000000) {
1784 //dvs10
1785 dividend = 0 - dividend;
1786 cycles += 2;
1787 }
1788 if (divisor_shift <= dividend) {
1789 context->flags[FLAG_V] = 1;
1790 context->flags[FLAG_N] = 1;
1791 context->flags[FLAG_Z] = 0;
1792 cycles += 2;
1793 context->current_cycle += cycles * context->options->gen.clock_divider;
1794 return orig_dividend;
1795 }
1796 uint16_t quotient = 0;
1797 uint16_t bit = 0;
1798 for (int i = 0; i < 15; i++)
1799 {
1800 quotient = quotient << 1 | bit;
1801 dividend = dividend << 1;
1802
1803 if (dividend >= divisor_shift) {
1804 dividend -= divisor_shift;
1805 cycles += 6;
1806 bit = 1;
1807 } else {
1808 bit = 0;
1809 cycles += 8;
1810 }
1811 }
1812 quotient = quotient << 1 | bit;
1813 dividend = dividend << 1;
1814 if (dividend >= divisor_shift) {
1815 dividend -= divisor_shift;
1816 quotient = quotient << 1 | 1;
1817 } else {
1818 quotient = quotient << 1;
1819 }
1820 cycles += 4;
1821
1822 context->flags[FLAG_V] = 0;
1823 if (orig_divisor & 0x80000000) {
1824 cycles += 16; //was 10
1825 if (orig_dividend & 0x80000000) {
1826 if (quotient & 0x8000) {
1827 context->flags[FLAG_V] = 1;
1828 context->flags[FLAG_N] = 1;
1829 context->flags[FLAG_Z] = 0;
1830 context->current_cycle += cycles * context->options->gen.clock_divider;
1831 return orig_dividend;
1832 } else {
1833 dividend = -dividend;
1834 }
1835 } else {
1836 quotient = -quotient;
1837 if (quotient && !(quotient & 0x8000)) {
1838 context->flags[FLAG_V] = 1;
1839 }
1840 }
1841 } else if (orig_dividend & 0x80000000) {
1842 cycles += 18; // was 12
1843 quotient = -quotient;
1844 if (quotient && !(quotient & 0x8000)) {
1845 context->flags[FLAG_V] = 1;
1846 } else {
1847 dividend = -dividend;
1848 }
1849 } else {
1850 cycles += 14; //was 10
1851 if (quotient & 0x8000) {
1852 context->flags[FLAG_V] = 1;
1853 }
1854 }
1855 if (context->flags[FLAG_V]) {
1856 context->flags[FLAG_N] = 1;
1857 context->flags[FLAG_Z] = 0;
1858 context->current_cycle += cycles * context->options->gen.clock_divider;
1859 return orig_dividend;
1860 }
1861 context->flags[FLAG_N] = (quotient & 0x8000) ? 1 : 0;
1862 context->flags[FLAG_Z] = quotient == 0;
1863 //V was cleared above, C is cleared by the generated machine code
1864 context->current_cycle += cycles * context->options->gen.clock_divider;
1865 return dividend | quotient;
1866}
1867
1868void translate_m68k_div(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
1869{
1870 code_info *code = &opts->gen.code;
1871 check_alloc_code(code, MAX_NATIVE_SIZE);
1872 set_flag(opts, 0, FLAG_C);
1873 if (dst_op->mode == MODE_REG_DIRECT) {
1874 mov_rr(code, dst_op->base, opts->gen.scratch2, SZ_D);
1875 } else {
1876 mov_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_D);
1877 }
1878 if (src_op->mode == MODE_IMMED) {
1879 mov_ir(code, src_op->disp << 16, opts->gen.scratch1, SZ_D);
1880 } else {
1881 if (src_op->mode == MODE_REG_DISPLACE8) {
1882 movzx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W, SZ_D);
1883 } else if (src_op->base != opts->gen.scratch1) {
1884 movzx_rr(code, src_op->base, opts->gen.scratch1, SZ_W, SZ_D);
1885 }
1886 shl_ir(code, 16, opts->gen.scratch1, SZ_D);
1887 }
1888 cmp_ir(code, 0, opts->gen.scratch1, SZ_D);
1889 code_ptr not_zero = code->cur+1;
1890 jcc(code, CC_NZ, not_zero);
1891
1892 //TODO: Check that opts->trap includes the cycles conumed by the first trap0 microinstruction
1893 cycles(&opts->gen, 4);
1894 uint32_t isize = 2;
1895 switch(inst->src.addr_mode)
1896 {
1897 case MODE_AREG_DISPLACE:
1898 case MODE_AREG_INDEX_DISP8:
1899 case MODE_ABSOLUTE_SHORT:
1900 case MODE_PC_DISPLACE:
1901 case MODE_PC_INDEX_DISP8:
1902 case MODE_IMMEDIATE:
1903 isize = 4;
1904 break;
1905 case MODE_ABSOLUTE:
1906 isize = 6;
1907 break;
1908 }
1909 //zero seems to clear all flags
1910 update_flags(opts, N0|Z0|V0);
1911 mov_ir(code, VECTOR_INT_DIV_ZERO, opts->gen.scratch2, SZ_D);
1912 mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D);
1913 jmp(code, opts->trap);
1914
1915 *not_zero = code->cur - (not_zero + 1);
1916 code_ptr end = NULL;
1917 if (inst->op == M68K_DIVU) {
1918 //initial overflow check needs to be done in the C code for divs
1919 //but can be done before dumping state to mem in divu as an optimization
1920 cmp_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_D);
1921 code_ptr not_overflow = code->cur+1;
1922 jcc(code, CC_C, not_overflow);
1923
1924 //overflow seems to always set the N and clear Z
1925 update_flags(opts, N1|Z0|V1);
1926 cycles(&opts->gen, 10);
1927 end = code->cur+1;
1928 jmp(code, end);
1929
1930 *not_overflow = code->cur - (not_overflow + 1);
1931 }
1932 call(code, opts->gen.save_context);
1933 push_r(code, opts->gen.context_reg);
1934 //TODO: inline the functionality of divudivs/ so we don't need to dump context to memory
1935 call_args(code, (code_ptr)(inst->op == M68K_DIVU ? divu : divs), 3, opts->gen.scratch2, opts->gen.context_reg, opts->gen.scratch1);
1936 pop_r(code, opts->gen.context_reg);
1937 mov_rr(code, RAX, opts->gen.scratch1, SZ_D);
1938
1939 call(code, opts->gen.load_context);
1940
1941 if (inst->op == M68K_DIVU) {
1942 cmp_ir(code, 0, opts->gen.scratch1, SZ_W);
1943 update_flags(opts, V0|Z|N);
1944 }
1945
1946 if (dst_op->mode == MODE_REG_DIRECT) {
1947 mov_rr(code, opts->gen.scratch1, dst_op->base, SZ_D);
1948 } else {
1949 mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_D);
1950 }
1951 if (end) {
1952 *end = code->cur - (end + 1);
1953 }
1954}
1955
1956void translate_m68k_exg(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
1957{
1958 code_info *code = &opts->gen.code;
1959 cycles(&opts->gen, 6);
1960 if (dst_op->mode == MODE_REG_DIRECT) {
1961 mov_rr(code, dst_op->base, opts->gen.scratch2, SZ_D);
1962 if (src_op->mode == MODE_REG_DIRECT) {
1963 mov_rr(code, src_op->base, dst_op->base, SZ_D);
1964 mov_rr(code, opts->gen.scratch2, src_op->base, SZ_D);
1965 } else {
1966 mov_rdispr(code, src_op->base, src_op->disp, dst_op->base, SZ_D);
1967 mov_rrdisp(code, opts->gen.scratch2, src_op->base, src_op->disp, SZ_D);
1968 }
1969 } else {
1970 mov_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_D);
1971 if (src_op->mode == MODE_REG_DIRECT) {
1972 mov_rrdisp(code, src_op->base, dst_op->base, dst_op->disp, SZ_D);
1973 mov_rr(code, opts->gen.scratch2, src_op->base, SZ_D);
1974 } else {
1975 mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_D);
1976 mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_D);
1977 mov_rrdisp(code, opts->gen.scratch2, src_op->base, src_op->disp, SZ_D);
1978 }
1979 }
1980}
1981
1982
1983
1984static uint32_t mulu_cycles(uint16_t value)
1985{
1986 //4 for prefetch, 2-cycles per bit x 16, 2 for cleanup
1987 uint32_t cycles = 38;
1988 uint16_t a = (value & 0b1010101010101010) >> 1;
1989 uint16_t b = value & 0b0101010101010101;
1990 value = a + b;
1991 a = (value & 0b1100110011001100) >> 2;
1992 b = value & 0b0011001100110011;
1993 value = a + b;
1994 a = (value & 0b1111000011110000) >> 4;
1995 b = value & 0b0000111100001111;
1996 value = a + b;
1997 a = (value & 0b1111111100000000) >> 8;
1998 b = value & 0b0000000011111111;
1999 value = a + b;
2000 return cycles + 2*value;
2001}
2002
2003static uint32_t muls_cycles(uint16_t value)
2004{
2005 //muls timing is essentially the same as muls, but it's based on the number of 0/1
2006 //transitions rather than the number of 1 bits. xoring the value with itself shifted
2007 //by one effectively sets one bit for every transition
2008 return mulu_cycles((value << 1) ^ value);
2009}
2010
2011void translate_m68k_mul(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
2012{
2013 code_info *code = &opts->gen.code;
2014 if (src_op->mode == MODE_IMMED) {
2015 cycles(&opts->gen, inst->op == M68K_MULU ? mulu_cycles(src_op->disp) : muls_cycles(src_op->disp));
2016 mov_ir(code, inst->op == M68K_MULU ? (src_op->disp & 0xFFFF) : ((src_op->disp & 0x8000) ? src_op->disp | 0xFFFF0000 : src_op->disp), opts->gen.scratch1, SZ_D);
2017 } else if (src_op->mode == MODE_REG_DIRECT) {
2018 if (inst->op == M68K_MULS) {
2019 movsx_rr(code, src_op->base, opts->gen.scratch1, SZ_W, SZ_D);
2020 } else {
2021 movzx_rr(code, src_op->base, opts->gen.scratch1, SZ_W, SZ_D);
2022 }
2023 } else {
2024 if (inst->op == M68K_MULS) {
2025 movsx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W, SZ_D);
2026 } else {
2027 movzx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W, SZ_D);
2028 }
2029 }
2030 if (src_op->mode != MODE_IMMED) {
2031 //TODO: Inline cycle calculation so we don't need to save/restore a bunch of registers
2032 //save context to memory and call the relevant C function for calculating the cycle count
2033 call(code, opts->gen.save_context);
2034 push_r(code, opts->gen.scratch1);
2035 push_r(code, opts->gen.context_reg);
2036 call_args(code, (code_ptr)(inst->op == M68K_MULS ? muls_cycles : mulu_cycles), 1, opts->gen.scratch1);
2037 pop_r(code, opts->gen.context_reg);
2038 //turn 68K cycles into master clock cycles and add to the current cycle count
2039 imul_irr(code, opts->gen.clock_divider, RAX, RAX, SZ_D);
2040 add_rrdisp(code, RAX, opts->gen.context_reg, offsetof(m68k_context, current_cycle), SZ_D);
2041 //restore context and scratch1
2042 call(code, opts->gen.load_context);
2043 pop_r(code, opts->gen.scratch1);
2044 }
2045
2046 uint8_t dst_reg;
2047 if (dst_op->mode == MODE_REG_DIRECT) {
2048 dst_reg = dst_op->base;
2049 if (inst->op == M68K_MULS) {
2050 movsx_rr(code, dst_reg, dst_reg, SZ_W, SZ_D);
2051 } else {
2052 movzx_rr(code, dst_reg, dst_reg, SZ_W, SZ_D);
2053 }
2054 } else {
2055 dst_reg = opts->gen.scratch2;
2056 if (inst->op == M68K_MULS) {
2057 movsx_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_W, SZ_D);
2058 } else {
2059 movzx_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_W, SZ_D);
2060 }
2061 }
2062 imul_rr(code, opts->gen.scratch1, dst_reg, SZ_D);
2063 if (dst_op->mode == MODE_REG_DISPLACE8) {
2064 mov_rrdisp(code, dst_reg, dst_op->base, dst_op->disp, SZ_D);
2065 }
2066 cmp_ir(code, 0, dst_reg, SZ_D);
2067 update_flags(opts, N|Z|V0|C0);
2068}
2069
2070void translate_m68k_negx(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
2071{
2072 code_info *code = &opts->gen.code;
2073 cycles(&opts->gen, BUS);
2074 if (dst_op->mode == MODE_REG_DIRECT) {
2075 if (dst_op->base == opts->gen.scratch1) {
2076 push_r(code, opts->gen.scratch2);
2077 xor_rr(code, opts->gen.scratch2, opts->gen.scratch2, inst->extra.size);
2078 flag_to_carry(opts, FLAG_X);
2079 sbb_rr(code, dst_op->base, opts->gen.scratch2, inst->extra.size);
2080 mov_rr(code, opts->gen.scratch2, dst_op->base, inst->extra.size);
2081 pop_r(code, opts->gen.scratch2);
2082 } else {
2083 xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, inst->extra.size);
2084 flag_to_carry(opts, FLAG_X);
2085 sbb_rr(code, dst_op->base, opts->gen.scratch1, inst->extra.size);
2086 mov_rr(code, opts->gen.scratch1, dst_op->base, inst->extra.size);
2087 }
2088 } else {
2089 xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, inst->extra.size);
2090 flag_to_carry(opts, FLAG_X);
2091 sbb_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch1, inst->extra.size);
2092 mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, inst->extra.size);
2093 }
2094 set_flag_cond(opts, CC_C, FLAG_C);
2095 code_ptr after_flag_set = code->cur + 1;
2096 jcc(code, CC_Z, code->cur + 2);
2097 set_flag(opts, 0, FLAG_Z);
2098 *after_flag_set = code->cur - (after_flag_set+1);
2099 set_flag_cond(opts, CC_S, FLAG_N);
2100 set_flag_cond(opts, CC_O, FLAG_V);
2101 if (opts->flag_regs[FLAG_C] >= 0) {
2102 flag_to_flag(opts, FLAG_C, FLAG_X);
2103 } else {
2104 set_flag_cond(opts, CC_C, FLAG_X);
2105 }
2106 m68k_save_result(inst, opts);
2107}
2108
2109void translate_m68k_rot(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
2110{
2111 code_info *code = &opts->gen.code;
2112 int32_t init_flags = C|V0;
2113 if (inst->src.addr_mode == MODE_UNUSED) {
2114 cycles(&opts->gen, BUS);
2115 //Memory rotate
2116 if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) {
2117 flag_to_carry(opts, FLAG_X);
2118 init_flags |= X;
2119 }
2120 op_ir(code, inst, 1, dst_op->base, inst->extra.size);
2121 update_flags(opts, init_flags);
2122 cmp_ir(code, 0, dst_op->base, inst->extra.size);
2123 update_flags(opts, Z|N);
2124 m68k_save_result(inst, opts);
2125 } else {
2126 if (src_op->mode == MODE_IMMED) {
2127 cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG ? 8 : 6) + src_op->disp*2);
2128 if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) {
2129 flag_to_carry(opts, FLAG_X);
2130 init_flags |= X;
2131 }
2132 if (dst_op->mode == MODE_REG_DIRECT) {
2133 op_ir(code, inst, src_op->disp, dst_op->base, inst->extra.size);
2134 } else {
2135 op_irdisp(code, inst, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size);
2136 }
2137 update_flags(opts, init_flags);
2138 } else {
2139 if (src_op->mode == MODE_REG_DIRECT) {
2140 if (src_op->base != opts->gen.scratch1) {
2141 mov_rr(code, src_op->base, opts->gen.scratch1, SZ_B);
2142 }
2143 } else {
2144 mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_B);
2145 }
2146 and_ir(code, 63, opts->gen.scratch1, SZ_D);
2147 code_ptr zero_off = code->cur + 1;
2148 jcc(code, CC_Z, code->cur + 2);
2149 //add 2 cycles for every bit shifted
2150 mov_ir(code, 2 * opts->gen.clock_divider, opts->gen.scratch2, SZ_D);
2151 imul_rr(code, RCX, opts->gen.scratch2, SZ_D);
2152 add_rr(code, opts->gen.scratch2, opts->gen.cycles, SZ_D);
2153 cmp_ir(code, 32, opts->gen.scratch1, SZ_B);
2154 code_ptr norm_off = code->cur + 1;
2155 jcc(code, CC_L, code->cur + 2);
2156 if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) {
2157 flag_to_carry(opts, FLAG_X);
2158 init_flags |= X;
2159 } else {
2160 sub_ir(code, 32, opts->gen.scratch1, SZ_B);
2161 }
2162 if (dst_op->mode == MODE_REG_DIRECT) {
2163 op_ir(code, inst, 31, dst_op->base, inst->extra.size);
2164 op_ir(code, inst, 1, dst_op->base, inst->extra.size);
2165 } else {
2166 op_irdisp(code, inst, 31, dst_op->base, dst_op->disp, inst->extra.size);
2167 op_irdisp(code, inst, 1, dst_op->base, dst_op->disp, inst->extra.size);
2168 }
2169
2170 if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) {
2171 set_flag_cond(opts, CC_C, FLAG_X);
2172 sub_ir(code, 32, opts->gen.scratch1, SZ_B);
2173 *norm_off = code->cur - (norm_off+1);
2174 flag_to_carry(opts, FLAG_X);
2175 } else {
2176 *norm_off = code->cur - (norm_off+1);
2177 }
2178 if (dst_op->mode == MODE_REG_DIRECT) {
2179 op_r(code, inst, dst_op->base, inst->extra.size);
2180 } else {
2181 op_rdisp(code, inst, dst_op->base, dst_op->disp, inst->extra.size);
2182 }
2183 update_flags(opts, init_flags);
2184 code_ptr end_off = code->cur + 1;
2185 jmp(code, code->cur + 2);
2186 *zero_off = code->cur - (zero_off+1);
2187 if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) {
2188 //Carry flag is set to X flag when count is 0, this is different from ROR/ROL
2189 flag_to_flag(opts, FLAG_X, FLAG_C);
2190 } else {
2191 set_flag(opts, 0, FLAG_C);
2192 }
2193 *end_off = code->cur - (end_off+1);
2194 }
2195 if (dst_op->mode == MODE_REG_DIRECT) {
2196 cmp_ir(code, 0, dst_op->base, inst->extra.size);
2197 } else {
2198 cmp_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size);
2199 }
2200 update_flags(opts, Z|N);
2201 }
2202}
2203
2204#define BIT_SUPERVISOR 5
2205
2206void m68k_trap_if_not_supervisor(m68k_options *opts, m68kinst *inst)
2207{
2208 code_info *code = &opts->gen.code;
2209 //check supervisor bit in SR and trap if not in supervisor mode
2210 bt_irdisp(code, BIT_SUPERVISOR, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
2211 code_ptr in_sup_mode = code->cur + 1;
2212 jcc(code, CC_C, code->cur + 2);
2213
2214 ldi_native(opts, VECTOR_PRIV_VIOLATION, opts->gen.scratch2);
2215 ldi_native(opts, inst->address, opts->gen.scratch1);
2216 jmp(code, opts->trap);
2217
2218 *in_sup_mode = code->cur - (in_sup_mode + 1);
2219}
2220
2221void translate_m68k_andi_ori_ccr_sr(m68k_options *opts, m68kinst *inst)
2222{
2223 code_info *code = &opts->gen.code;
2224 if (inst->op == M68K_ANDI_SR || inst->op == M68K_ORI_SR) {
2225 m68k_trap_if_not_supervisor(opts, inst);
2226 }
2227 cycles(&opts->gen, 20);
2228 uint32_t flag_mask = 0;
2229 uint32_t base_flag = inst->op == M68K_ANDI_SR || inst->op == M68K_ANDI_CCR ? X0 : X1;
2230 for (int i = 0; i < 5; i++)
2231 {
2232 if ((base_flag == X0) ^ ((inst->src.params.immed & 1 << i) > 0))
2233 {
2234 flag_mask |= base_flag << ((4 - i) * 3);
2235 }
2236 }
2237 update_flags(opts, flag_mask);
2238 if (inst->op == M68K_ANDI_SR || inst->op == M68K_ORI_SR) {
2239 if (inst->op == M68K_ANDI_SR) {
2240 and_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
2241 } else {
2242 or_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
2243 }
2244 if (inst->op == M68K_ANDI_SR && !(inst->src.params.immed & (1 << (BIT_SUPERVISOR + 8)))) {
2245 //leave supervisor mode
2246 swap_ssp_usp(opts);
2247 }
2248 if ((inst->op == M68K_ANDI_SR && (inst->src.params.immed & 0x700) != 0x700)
2249 || (inst->op == M68K_ORI_SR && inst->src.params.immed & 0x8700)) {
2250 if (inst->op == M68K_ANDI_SR) {
2251 //set int pending flag in case we trigger an interrupt as a result of the mask change
2252 mov_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
2253 }
2254 call(code, opts->do_sync);
2255 }
2256 }
2257}
2258
2259void translate_m68k_eori_ccr_sr(m68k_options *opts, m68kinst *inst)
2260{
2261 code_info *code = &opts->gen.code;
2262 if (inst->op == M68K_EORI_SR) {
2263 m68k_trap_if_not_supervisor(opts, inst);
2264 }
2265 cycles(&opts->gen, 20);
2266 if (inst->src.params.immed & 0x1) {
2267 xor_flag(opts, 1, FLAG_C);
2268 }
2269 if (inst->src.params.immed & 0x2) {
2270 xor_flag(opts, 1, FLAG_V);
2271 }
2272 if (inst->src.params.immed & 0x4) {
2273 xor_flag(opts, 1, FLAG_Z);
2274 }
2275 if (inst->src.params.immed & 0x8) {
2276 xor_flag(opts, 1, FLAG_N);
2277 }
2278 if (inst->src.params.immed & 0x10) {
2279 xor_flag(opts, 1, FLAG_X);
2280 }
2281 if (inst->op == M68K_EORI_SR) {
2282 xor_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
2283 if (inst->src.params.immed & 0x8700) {
2284 //set int pending flag in case we trigger an interrupt as a result of the mask change
2285 mov_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
2286 call(code, opts->do_sync);
2287 }
2288 }
2289}
2290
2291void set_all_flags(m68k_options *opts, uint8_t flags)
2292{
2293 uint32_t flag_mask = flags & 0x10 ? X1 : X0;
2294 flag_mask |= flags & 0x8 ? N1 : N0;
2295 flag_mask |= flags & 0x4 ? Z1 : Z0;
2296 flag_mask |= flags & 0x2 ? V1 : V0;
2297 flag_mask |= flags & 0x1 ? C1 : C0;
2298 update_flags(opts, flag_mask);
2299}
2300
2301void translate_m68k_move_ccr_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
2302{
2303 code_info *code = &opts->gen.code;
2304 if (inst->op == M68K_MOVE_SR) {
2305 m68k_trap_if_not_supervisor(opts, inst);
2306 }
2307 if (src_op->mode == MODE_IMMED) {
2308 set_all_flags(opts, src_op->disp);
2309 if (inst->op == M68K_MOVE_SR) {
2310 mov_irdisp(code, (src_op->disp >> 8), opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
2311 if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) {
2312 //leave supervisor mode
2313 swap_ssp_usp(opts);
2314 }
2315 if (((src_op->disp >> 8) & 7) < 7) {
2316 //set int pending flag in case we trigger an interrupt as a result of the mask change
2317 mov_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
2318 }
2319 call(code, opts->do_sync);
2320 }
2321 cycles(&opts->gen, 12);
2322 } else {
2323 if (src_op->base != opts->gen.scratch1) {
2324 if (src_op->mode == MODE_REG_DIRECT) {
2325 mov_rr(code, src_op->base, opts->gen.scratch1, SZ_W);
2326 } else {
2327 mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W);
2328 }
2329 }
2330 if (inst->op == M68K_MOVE_SR) {
2331 call(code, opts->set_sr);
2332 call(code, opts->do_sync);
2333 } else {
2334 call(code, opts->set_ccr);
2335 }
2336 cycles(&opts->gen, 12);
2337 }
2338}
2339
2340void translate_m68k_stop(m68k_options *opts, m68kinst *inst)
2341{
2342 m68k_trap_if_not_supervisor(opts, inst);
2343 //manual says 4 cycles, but it has to be at least 8 since it's a 2-word instruction
2344 //possibly even 12 since that's how long MOVE to SR takes
2345 //On further thought prefetch + the fact that this stops the CPU may make
2346 //Motorola's accounting make sense here
2347 code_info *code = &opts->gen.code;
2348 cycles(&opts->gen, BUS*2);
2349 set_all_flags(opts, inst->src.params.immed);
2350 mov_irdisp(code, (inst->src.params.immed >> 8), opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
2351 if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) {
2352 //leave supervisor mode
2353 swap_ssp_usp(opts);
2354 }
2355 code_ptr loop_top = code->cur;
2356 call(code, opts->do_sync);
2357 cmp_rr(code, opts->gen.cycles, opts->gen.limit, SZ_D);
2358 code_ptr normal_cycle_up = code->cur + 1;
2359 jcc(code, CC_A, code->cur + 2);
2360 cycles(&opts->gen, BUS);
2361 code_ptr after_cycle_up = code->cur + 1;
2362 jmp(code, code->cur + 2);
2363 *normal_cycle_up = code->cur - (normal_cycle_up + 1);
2364 mov_rr(code, opts->gen.limit, opts->gen.cycles, SZ_D);
2365 *after_cycle_up = code->cur - (after_cycle_up+1);
2366 cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_cycle), opts->gen.cycles, SZ_D);
2367 jcc(code, CC_C, loop_top);
2368 //set int pending flag so interrupt fires immediately after stop is done
2369 mov_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
2370}
2371
2372void translate_m68k_trapv(m68k_options *opts, m68kinst *inst)
2373{
2374 code_info *code = &opts->gen.code;
2375 cycles(&opts->gen, BUS);
2376 flag_to_carry(opts, FLAG_V);
2377 code_ptr no_trap = code->cur + 1;
2378 jcc(code, CC_NC, no_trap);
2379 ldi_native(opts, VECTOR_TRAPV, opts->gen.scratch2);
2380 ldi_native(opts, inst->address+2, opts->gen.scratch1);
2381 jmp(code, opts->trap);
2382 *no_trap = code->cur - (no_trap + 1);
2383}
2384
2385void translate_m68k_odd(m68k_options *opts, m68kinst *inst)
2386{
2387 code_info *code = &opts->gen.code;
2388 //swap USP and SSP if not already in supervisor mode
2389 check_user_mode_swap_ssp_usp(opts);
2390 //save PC
2391 subi_areg(opts, 4, 7);
2392 areg_to_native(opts, 7, opts->gen.scratch2);
2393 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, last_prefetch_address), opts->gen.scratch1, SZ_D);
2394 call(code, opts->write_32_lowfirst);
2395 //save status register
2396 subi_areg(opts, 2, 7);
2397 call(code, opts->get_sr);
2398 areg_to_native(opts, 7, opts->gen.scratch2);
2399 call(code, opts->write_16);
2400 //save instruction register
2401 subi_areg(opts, 2, 7);
2402 //calculate IR
2403 push_r(code, opts->gen.context_reg);
2404 call(code, opts->gen.save_context);
2405 call_args_abi(code, (code_ptr)m68k_get_ir, 1, opts->gen.context_reg);
2406 mov_rr(code, RAX, opts->gen.scratch1, SZ_W);
2407 pop_r(code, opts->gen.context_reg);
2408 push_r(code, RAX); //save it for use in the "info" word
2409 call(code, opts->gen.load_context);
2410 //write it to the stack
2411 areg_to_native(opts, 7, opts->gen.scratch2);
2412 call(code, opts->write_16);
2413 //save access address
2414 subi_areg(opts, 4, 7);
2415 mov_ir(code, inst->address, opts->gen.scratch1, SZ_D);
2416 areg_to_native(opts, 7, opts->gen.scratch2);
2417 call(code, opts->write_32_lowfirst);
2418 //save FC, I/N and R/W word'
2419 xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_W);
2420 //FC3 is basically the same as the supervisor bit
2421 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, status), opts->gen.scratch1, SZ_B);
2422 shr_ir(code, 3, opts->gen.scratch1, SZ_B);
2423 and_ir(code, 4, opts->gen.scratch1, SZ_B);
2424 //set FC1 to one to indicate instruction fetch, and R/W to indicate read
2425 or_ir(code, 0x12, opts->gen.scratch1, SZ_B);
2426 //set undefined bits to IR value
2427 pop_r(code, opts->gen.scratch2);
2428 and_ir(code, 0xFFE0, opts->gen.scratch2, SZ_W);
2429 or_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_W);
2430 subi_areg(opts, 2, 7);
2431 areg_to_native(opts, 7, opts->gen.scratch2);
2432 call(code, opts->write_16);
2433 //set supervisor bit
2434 or_irdisp(code, 0x20, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
2435 //load vector address
2436 mov_ir(code, 4 * VECTOR_ADDRESS_ERROR, opts->gen.scratch1, SZ_D);
2437 call(code, opts->read_32);
2438 call(code, opts->native_addr_and_sync);
2439 cycles(&opts->gen, 18);
2440 jmp_r(code, opts->gen.scratch1);
2441}
2442
2443void translate_m68k_move_from_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
2444{
2445 code_info *code = &opts->gen.code;
2446 cycles(&opts->gen, inst->dst.addr_mode == MODE_REG_DIRECT ? BUS+2 : BUS);
2447 call(code, opts->get_sr);
2448 if (dst_op->mode == MODE_REG_DIRECT) {
2449 mov_rr(code, opts->gen.scratch1, dst_op->base, SZ_W);
2450 } else {
2451 mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_W);
2452 }
2453 m68k_save_result(inst, opts);
2454}
2455
2456void m68k_out_of_bounds_execution(uint32_t address)
2457{
2458 fatal_error("M68K attempted to execute code at unmapped or I/O address %X\n", address);
2459}
2460
2461void translate_out_of_bounds(m68k_options *opts, uint32_t address)
2462{
2463 code_info *code = &opts->gen.code;
2464 check_cycles_int(&opts->gen, address);
2465 mov_ir(code, address, opts->gen.scratch1, SZ_D);
2466 call_args(code, (code_ptr)m68k_out_of_bounds_execution, 1, opts->gen.scratch1);
2467}
2468
2469void m68k_set_last_prefetch(m68k_options *opts, uint32_t address)
2470{
2471 mov_irdisp(&opts->gen.code, address, opts->gen.context_reg, offsetof(m68k_context, last_prefetch_address), SZ_D);
2472}
2473
2474void nop_fill_or_jmp_next(code_info *code, code_ptr old_end, code_ptr next_inst)
2475{
2476 if (next_inst == old_end && next_inst - code->cur < 2) {
2477 while (code->cur < old_end) {
2478 *(code->cur++) = 0x90; //NOP
2479 }
2480 } else {
2481 jmp(code, next_inst);
2482 }
2483}
2484
2485#define M68K_MAX_INST_SIZE (2*(1+2+2))
2486
2487m68k_context * m68k_handle_code_write(uint32_t address, m68k_context * context)
2488{
2489 m68k_options * options = context->options;
2490 uint32_t inst_start = get_instruction_start(options, address);
2491 while (inst_start && (address - inst_start) < M68K_MAX_INST_SIZE) {
2492 code_ptr dst = get_native_address(context->options, inst_start);
2493 patch_for_retranslate(&options->gen, dst, options->retrans_stub);
2494 inst_start = get_instruction_start(options, inst_start - 2);
2495 }
2496 return context;
2497}
2498
2499void m68k_invalidate_code_range(m68k_context *context, uint32_t start, uint32_t end)
2500{
2501 m68k_options *opts = context->options;
2502 native_map_slot *native_code_map = opts->gen.native_code_map;
2503 memmap_chunk const *mem_chunk = find_map_chunk(start, &opts->gen, 0, NULL);
2504 if (mem_chunk) {
2505 //calculate the lowest alias for this address
2506 start = mem_chunk->start + ((start - mem_chunk->start) & mem_chunk->mask);
2507 }
2508 mem_chunk = find_map_chunk(end, &opts->gen, 0, NULL);
2509 if (mem_chunk) {
2510 //calculate the lowest alias for this address
2511 end = mem_chunk->start + ((end - mem_chunk->start) & mem_chunk->mask);
2512 }
2513 uint32_t start_chunk = start / NATIVE_CHUNK_SIZE, end_chunk = end / NATIVE_CHUNK_SIZE;
2514 for (uint32_t chunk = start_chunk; chunk <= end_chunk; chunk++)
2515 {
2516 if (native_code_map[chunk].base) {
2517 uint32_t start_offset = chunk == start_chunk ? start % NATIVE_CHUNK_SIZE : 0;
2518 uint32_t end_offset = chunk == end_chunk ? end % NATIVE_CHUNK_SIZE : NATIVE_CHUNK_SIZE;
2519 for (uint32_t offset = start_offset; offset < end_offset; offset++)
2520 {
2521 if (native_code_map[chunk].offsets[offset] != INVALID_OFFSET && native_code_map[chunk].offsets[offset] != EXTENSION_WORD) {
2522 patch_for_retranslate(&opts->gen, native_code_map[chunk].base + native_code_map[chunk].offsets[offset], opts->retrans_stub);
2523 /*code_info code;
2524 code.cur = native_code_map[chunk].base + native_code_map[chunk].offsets[offset];
2525 code.last = code.cur + 32;
2526 code.stack_off = 0;
2527 mov_ir(&code, chunk * NATIVE_CHUNK_SIZE + offset, opts->gen.scratch2, SZ_D);
2528 jmp(&code, opts->retrans_stub);*/
2529 }
2530 }
2531 }
2532 }
2533}
2534
2535void m68k_breakpoint_patch(m68k_context *context, uint32_t address, m68k_debug_handler bp_handler, code_ptr native_addr)
2536{
2537 m68k_options * opts = context->options;
2538 code_info native;
2539 native.cur = native_addr ? native_addr : get_native_address(context->options, address);
2540
2541 if (!native.cur) {
2542 return;
2543 }
2544
2545 if (*native.cur != opts->prologue_start) {
2546 //instruction has already been patched, probably for retranslation
2547 return;
2548 }
2549 native.last = native.cur + 128;
2550 native.stack_off = 0;
2551 code_ptr start_native = native.cur;
2552 mov_ir(&native, address, opts->gen.scratch1, SZ_D);
2553
2554
2555 call(&native, opts->bp_stub);
2556}
2557
2558void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chunks, uint32_t clock_divider)
2559{
2560 memset(opts, 0, sizeof(*opts));
2561 opts->gen.memmap = memmap;
2562 opts->gen.memmap_chunks = num_chunks;
2563 opts->gen.address_size = SZ_D;
2564 opts->gen.address_mask = 0xFFFFFF;
2565 opts->gen.byte_swap = 1;
2566 opts->gen.max_address = 0x1000000;
2567 opts->gen.bus_cycles = BUS;
2568 opts->gen.clock_divider = clock_divider;
2569 opts->gen.mem_ptr_off = offsetof(m68k_context, mem_pointers);
2570 opts->gen.ram_flags_off = offsetof(m68k_context, ram_code_flags);
2571 opts->gen.ram_flags_shift = 11;
2572 for (int i = 0; i < 8; i++)
2573 {
2574 opts->dregs[i] = opts->aregs[i] = -1;
2575 }
2576#ifdef X86_64
2577 opts->dregs[0] = R10;
2578 opts->dregs[1] = R11;
2579 opts->dregs[2] = R12;
2580 opts->dregs[3] = R8;
2581 opts->aregs[0] = R13;
2582 opts->aregs[1] = R14;
2583 opts->aregs[2] = R9;
2584 opts->aregs[7] = R15;
2585
2586 opts->flag_regs[0] = -1;
2587 opts->flag_regs[1] = RBX;
2588 opts->flag_regs[2] = RDX;
2589 opts->flag_regs[3] = BH;
2590 opts->flag_regs[4] = DH;
2591
2592 opts->gen.scratch2 = RDI;
2593#else
2594 opts->dregs[0] = RDX;
2595 opts->aregs[7] = RDI;
2596
2597 for (int i = 0; i < 5; i++)
2598 {
2599 opts->flag_regs[i] = -1;
2600 }
2601 opts->gen.scratch2 = RBX;
2602#endif
2603 opts->gen.context_reg = RSI;
2604 opts->gen.cycles = RAX;
2605 opts->gen.limit = RBP;
2606 opts->gen.scratch1 = RCX;
2607 opts->gen.align_error_mask = 1;
2608
2609
2610 opts->gen.native_code_map = malloc(sizeof(native_map_slot) * NATIVE_MAP_CHUNKS);
2611 memset(opts->gen.native_code_map, 0, sizeof(native_map_slot) * NATIVE_MAP_CHUNKS);
2612 opts->gen.deferred = NULL;
2613
2614 uint32_t inst_size_size = sizeof(uint8_t *) * ram_size(&opts->gen) / 1024;
2615 opts->gen.ram_inst_sizes = malloc(inst_size_size);
2616 memset(opts->gen.ram_inst_sizes, 0, inst_size_size);
2617
2618 code_info *code = &opts->gen.code;
2619 init_code_info(code);
2620
2621 opts->gen.save_context = code->cur;
2622 for (int i = 0; i < 5; i++)
2623 if (opts->flag_regs[i] >= 0) {
2624 mov_rrdisp(code, opts->flag_regs[i], opts->gen.context_reg, offsetof(m68k_context, flags) + i, SZ_B);
2625 }
2626 for (int i = 0; i < 8; i++)
2627 {
2628 if (opts->dregs[i] >= 0) {
2629 mov_rrdisp(code, opts->dregs[i], opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t) * i, SZ_D);
2630 }
2631 if (opts->aregs[i] >= 0) {
2632 mov_rrdisp(code, opts->aregs[i], opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * i, SZ_D);
2633 }
2634 }
2635 mov_rrdisp(code, opts->gen.cycles, opts->gen.context_reg, offsetof(m68k_context, current_cycle), SZ_D);
2636 retn(code);
2637
2638 opts->gen.load_context = code->cur;
2639 for (int i = 0; i < 5; i++)
2640 {
2641 if (opts->flag_regs[i] >= 0) {
2642 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + i, opts->flag_regs[i], SZ_B);
2643 }
2644 }
2645 for (int i = 0; i < 8; i++)
2646 {
2647 if (opts->dregs[i] >= 0) {
2648 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t) * i, opts->dregs[i], SZ_D);
2649 }
2650 if (opts->aregs[i] >= 0) {
2651 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * i, opts->aregs[i], SZ_D);
2652 }
2653 }
2654 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, current_cycle), opts->gen.cycles, SZ_D);
2655 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, target_cycle), opts->gen.limit, SZ_D);
2656 retn(code);
2657
2658 opts->start_context = (start_fun)code->cur;
2659 save_callee_save_regs(code);
2660#ifdef X86_64
2661 if (opts->gen.scratch2 != RDI) {
2662 mov_rr(code, RDI, opts->gen.scratch2, SZ_PTR);
2663 }
2664#else
2665 mov_rdispr(code, RSP, 20, opts->gen.scratch2, SZ_D);
2666 mov_rdispr(code, RSP, 24, opts->gen.context_reg, SZ_D);
2667#endif
2668 call(code, opts->gen.load_context);
2669 call_r(code, opts->gen.scratch2);
2670 call(code, opts->gen.save_context);
2671 restore_callee_save_regs(code);
2672 retn(code);
2673
2674 opts->native_addr = code->cur;
2675 call(code, opts->gen.save_context);
2676 push_r(code, opts->gen.context_reg);
2677 call_args(code, (code_ptr)get_native_address_trans, 2, opts->gen.context_reg, opts->gen.scratch1);
2678 mov_rr(code, RAX, opts->gen.scratch1, SZ_PTR); //move result to scratch reg
2679 pop_r(code, opts->gen.context_reg);
2680 call(code, opts->gen.load_context);
2681 retn(code);
2682
2683 opts->native_addr_and_sync = code->cur;
2684 call(code, opts->gen.save_context);
2685 push_r(code, opts->gen.scratch1);
2686
2687 xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_D);
2688 call_args_abi(code, (code_ptr)sync_components, 2, opts->gen.context_reg, opts->gen.scratch1);
2689 pop_r(code, RSI); //restore saved address from opts->gen.scratch1
2690 push_r(code, RAX); //save context pointer for later
2691 call_args(code, (code_ptr)get_native_address_trans, 2, RAX, RSI);
2692 mov_rr(code, RAX, opts->gen.scratch1, SZ_PTR); //move result to scratch reg
2693 pop_r(code, opts->gen.context_reg);
2694 call(code, opts->gen.load_context);
2695 retn(code);
2696
2697 opts->gen.handle_cycle_limit = code->cur;
2698 cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, sync_cycle), opts->gen.cycles, SZ_D);
2699 code_ptr skip_sync = code->cur + 1;
2700 jcc(code, CC_C, code->cur + 2);
2701 opts->do_sync = code->cur;
2702 push_r(code, opts->gen.scratch1);
2703 push_r(code, opts->gen.scratch2);
2704 call(code, opts->gen.save_context);
2705 xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_D);
2706 call_args_abi(code, (code_ptr)sync_components, 2, opts->gen.context_reg, opts->gen.scratch1);
2707 mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR);
2708 call(code, opts->gen.load_context);
2709 pop_r(code, opts->gen.scratch2);
2710 pop_r(code, opts->gen.scratch1);
2711 *skip_sync = code->cur - (skip_sync+1);
2712 retn(code);
2713
2714 opts->gen.handle_code_write = (code_ptr)m68k_handle_code_write;
2715
2716 check_alloc_code(code, 256);
2717 opts->gen.handle_align_error_write = code->cur;
2718 code->cur += 256;
2719 check_alloc_code(code, 256);
2720 opts->gen.handle_align_error_read = code->cur;
2721 code->cur += 256;
2722
2723 opts->read_16 = gen_mem_fun(&opts->gen, memmap, num_chunks, READ_16, NULL);
2724 opts->read_8 = gen_mem_fun(&opts->gen, memmap, num_chunks, READ_8, NULL);
2725 opts->write_16 = gen_mem_fun(&opts->gen, memmap, num_chunks, WRITE_16, NULL);
2726 opts->write_8 = gen_mem_fun(&opts->gen, memmap, num_chunks, WRITE_8, NULL);
2727
2728 opts->read_32 = code->cur;
2729 push_r(code, opts->gen.scratch1);
2730 call(code, opts->read_16);
2731 mov_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_W);
2732 pop_r(code, opts->gen.scratch1);
2733 push_r(code, opts->gen.scratch2);
2734 add_ir(code, 2, opts->gen.scratch1, SZ_D);
2735 call(code, opts->read_16);
2736 pop_r(code, opts->gen.scratch2);
2737 movzx_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_W, SZ_D);
2738 shl_ir(code, 16, opts->gen.scratch2, SZ_D);
2739 or_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_D);
2740 retn(code);
2741
2742 opts->write_32_lowfirst = code->cur;
2743 push_r(code, opts->gen.scratch2);
2744 push_r(code, opts->gen.scratch1);
2745 add_ir(code, 2, opts->gen.scratch2, SZ_D);
2746 call(code, opts->write_16);
2747 pop_r(code, opts->gen.scratch1);
2748 pop_r(code, opts->gen.scratch2);
2749 shr_ir(code, 16, opts->gen.scratch1, SZ_D);
2750 jmp(code, opts->write_16);
2751
2752 opts->write_32_highfirst = code->cur;
2753 push_r(code, opts->gen.scratch1);
2754 push_r(code, opts->gen.scratch2);
2755 shr_ir(code, 16, opts->gen.scratch1, SZ_D);
2756 call(code, opts->write_16);
2757 pop_r(code, opts->gen.scratch2);
2758 pop_r(code, opts->gen.scratch1);
2759 add_ir(code, 2, opts->gen.scratch2, SZ_D);
2760 jmp(code, opts->write_16);
2761
2762 opts->get_sr = code->cur;
2763 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, status), opts->gen.scratch1, SZ_B);
2764 shl_ir(code, 8, opts->gen.scratch1, SZ_W);
2765 if (opts->flag_regs[FLAG_X] >= 0) {
2766 mov_rr(code, opts->flag_regs[FLAG_X], opts->gen.scratch1, SZ_B);
2767 } else {
2768 int8_t offset = offsetof(m68k_context, flags);
2769 if (offset) {
2770 mov_rdispr(code, opts->gen.context_reg, offset, opts->gen.scratch1, SZ_B);
2771 } else {
2772 mov_rindr(code, opts->gen.context_reg, opts->gen.scratch1, SZ_B);
2773 }
2774 }
2775 for (int flag = FLAG_N; flag <= FLAG_C; flag++)
2776 {
2777 shl_ir(code, 1, opts->gen.scratch1, SZ_B);
2778 if (opts->flag_regs[flag] >= 0) {
2779 or_rr(code, opts->flag_regs[flag], opts->gen.scratch1, SZ_B);
2780 } else {
2781 or_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, opts->gen.scratch1, SZ_B);
2782 }
2783 }
2784 retn(code);
2785
2786 opts->set_sr = code->cur;
2787 for (int flag = FLAG_C; flag >= FLAG_X; flag--)
2788 {
2789 rcr_ir(code, 1, opts->gen.scratch1, SZ_B);
2790 if (opts->flag_regs[flag] >= 0) {
2791 setcc_r(code, CC_C, opts->flag_regs[flag]);
2792 } else {
2793 int8_t offset = offsetof(m68k_context, flags) + flag;
2794 if (offset) {
2795 setcc_rdisp(code, CC_C, opts->gen.context_reg, offset);
2796 } else {
2797 setcc_rind(code, CC_C, opts->gen.context_reg);
2798 }
2799 }
2800 }
2801 shr_ir(code, 8, opts->gen.scratch1, SZ_W);
2802 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
2803 //set int pending flag in case we trigger an interrupt as a result of the mask change
2804 mov_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
2805 retn(code);
2806
2807 opts->set_ccr = code->cur;
2808 for (int flag = FLAG_C; flag >= FLAG_X; flag--)
2809 {
2810 rcr_ir(code, 1, opts->gen.scratch1, SZ_B);
2811 if (opts->flag_regs[flag] >= 0) {
2812 setcc_r(code, CC_C, opts->flag_regs[flag]);
2813 } else {
2814 int8_t offset = offsetof(m68k_context, flags) + flag;
2815 if (offset) {
2816 setcc_rdisp(code, CC_C, opts->gen.context_reg, offset);
2817 } else {
2818 setcc_rind(code, CC_C, opts->gen.context_reg);
2819 }
2820 }
2821 }
2822 retn(code);
2823
2824 code_info tmp_code = *code;
2825 code->cur = opts->gen.handle_align_error_write;
2826 code->last = code->cur + 256;
2827 //unwind the stack one functinon call
2828 add_ir(code, 16, RSP, SZ_PTR);
2829 //save address that triggered error so we can write it to the 68K stack at the appropriate place
2830 push_r(code, opts->gen.scratch2);
2831 //swap USP and SSP if not already in supervisor mode
2832 check_user_mode_swap_ssp_usp(opts);
2833 //save PC
2834 subi_areg(opts, 4, 7);
2835 areg_to_native(opts, 7, opts->gen.scratch2);
2836 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, last_prefetch_address), opts->gen.scratch1, SZ_D);
2837 call(code, opts->write_32_lowfirst);
2838 //save status register
2839 subi_areg(opts, 2, 7);
2840 call(code, opts->get_sr);
2841 areg_to_native(opts, 7, opts->gen.scratch2);
2842 call(code, opts->write_16);
2843 //save instruction register
2844 subi_areg(opts, 2, 7);
2845 //calculate IR
2846 push_r(code, opts->gen.context_reg);
2847 call(code, opts->gen.save_context);
2848 call_args_abi(code, (code_ptr)m68k_get_ir, 1, opts->gen.context_reg);
2849 mov_rr(code, RAX, opts->gen.scratch1, SZ_W);
2850 pop_r(code, opts->gen.context_reg);
2851 pop_r(code, opts->gen.scratch2); //access address
2852 push_r(code, RAX); //save it for use in the "info" word
2853 push_r(code, opts->gen.scratch2); //access address
2854 call(code, opts->gen.load_context);
2855 //write it to the stack
2856 areg_to_native(opts, 7, opts->gen.scratch2);
2857 call(code, opts->write_16);
2858 //save access address
2859 subi_areg(opts, 4, 7);
2860 pop_r(code, opts->gen.scratch1);
2861 areg_to_native(opts, 7, opts->gen.scratch2);
2862 call(code, opts->write_32_lowfirst);
2863 //save FC, I/N and R/W word'
2864 xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_W);
2865 //FC3 is basically the same as the supervisor bit
2866 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, status), opts->gen.scratch1, SZ_B);
2867 shr_ir(code, 3, opts->gen.scratch1, SZ_B);
2868 and_ir(code, 4, opts->gen.scratch1, SZ_B);
2869 //set FC0 to one to indicate data access
2870 or_ir(code, 1, opts->gen.scratch1, SZ_B);
2871 //set undefined bits to IR value
2872 pop_r(code, opts->gen.scratch2);
2873 and_ir(code, 0xFFE0, opts->gen.scratch2, SZ_W);
2874 or_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_W);
2875 subi_areg(opts, 2, 7);
2876 areg_to_native(opts, 7, opts->gen.scratch2);
2877 call(code, opts->write_16);
2878 //set supervisor bit
2879 or_irdisp(code, 0x20, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
2880 //load vector address
2881 mov_ir(code, 4 * VECTOR_ADDRESS_ERROR, opts->gen.scratch1, SZ_D);
2882 call(code, opts->read_32);
2883 call(code, opts->native_addr_and_sync);
2884 cycles(&opts->gen, 18);
2885 jmp_r(code, opts->gen.scratch1);
2886
2887 code->cur = opts->gen.handle_align_error_read;
2888 code->last = code->cur + 256;
2889 //unwind the stack one functinon call
2890 add_ir(code, 16, RSP, SZ_PTR);
2891 //save address that triggered error so we can write it to the 68K stack at the appropriate place
2892 push_r(code, opts->gen.scratch1);
2893 //swap USP and SSP if not already in supervisor mode
2894 check_user_mode_swap_ssp_usp(opts);
2895 //save PC
2896 subi_areg(opts, 4, 7);
2897 areg_to_native(opts, 7, opts->gen.scratch2);
2898 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, last_prefetch_address), opts->gen.scratch1, SZ_D);
2899 call(code, opts->write_32_lowfirst);
2900 //save status register
2901 subi_areg(opts, 2, 7);
2902 call(code, opts->get_sr);
2903 areg_to_native(opts, 7, opts->gen.scratch2);
2904 call(code, opts->write_16);
2905 //save instruction register
2906 subi_areg(opts, 2, 7);
2907 //calculate IR
2908 push_r(code, opts->gen.context_reg);
2909 call(code, opts->gen.save_context);
2910 call_args_abi(code, (code_ptr)m68k_get_ir, 1, opts->gen.context_reg);
2911 mov_rr(code, RAX, opts->gen.scratch1, SZ_W);
2912 pop_r(code, opts->gen.context_reg);
2913 pop_r(code, opts->gen.scratch2); //access address
2914 push_r(code, RAX); //save it for use in the "info" word
2915 push_r(code, opts->gen.scratch2); //access address
2916 call(code, opts->gen.load_context);
2917 //write it to the stack
2918 areg_to_native(opts, 7, opts->gen.scratch2);
2919 call(code, opts->write_16);
2920 //save access address
2921 subi_areg(opts, 4, 7);
2922 pop_r(code, opts->gen.scratch1);
2923 areg_to_native(opts, 7, opts->gen.scratch2);
2924 call(code, opts->write_32_lowfirst);
2925 //save FC, I/N and R/W word'
2926 xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_W);
2927 //FC3 is basically the same as the supervisor bit
2928 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, status), opts->gen.scratch1, SZ_B);
2929 shr_ir(code, 3, opts->gen.scratch1, SZ_B);
2930 and_ir(code, 4, opts->gen.scratch1, SZ_B);
2931 //set FC0 to one to indicate data access, and R/W to indicate read
2932 or_ir(code, 0x11, opts->gen.scratch1, SZ_B);
2933 //set undefined bits to IR value
2934 pop_r(code, opts->gen.scratch2);
2935 and_ir(code, 0xFFE0, opts->gen.scratch2, SZ_W);
2936 or_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_W);
2937 subi_areg(opts, 2, 7);
2938 areg_to_native(opts, 7, opts->gen.scratch2);
2939 call(code, opts->write_16);
2940 //set supervisor bit
2941 or_irdisp(code, 0x20, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
2942 //load vector address
2943 mov_ir(code, 4 * VECTOR_ADDRESS_ERROR, opts->gen.scratch1, SZ_D);
2944 call(code, opts->read_32);
2945 call(code, opts->native_addr_and_sync);
2946 cycles(&opts->gen, 18);
2947 jmp_r(code, opts->gen.scratch1);
2948
2949 *code = tmp_code;
2950
2951 opts->gen.handle_cycle_limit_int = code->cur;
2952 //calculate stack adjust size
2953 add_ir(code, 16-sizeof(void*), RSP, SZ_PTR);
2954 uint32_t adjust_size = code->cur - opts->gen.handle_cycle_limit_int;
2955 code->cur = opts->gen.handle_cycle_limit_int;
2956 //handle trace mode
2957 cmp_irdisp(code, 0, opts->gen.context_reg, offsetof(m68k_context, trace_pending), SZ_B);
2958 code_ptr do_trace = code->cur + 1;
2959 jcc(code, CC_NZ, do_trace);
2960 bt_irdisp(code, 7, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
2961 code_ptr no_trace = code->cur + 1;
2962 jcc(code, CC_NC, no_trace);
2963 mov_irdisp(code, 1, opts->gen.context_reg, offsetof(m68k_context, trace_pending), SZ_B);
2964 *no_trace = code->cur - (no_trace + 1);
2965 //handle interrupts
2966 cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_cycle), opts->gen.cycles, SZ_D);
2967 code_ptr do_int = code->cur + 2;
2968 jcc(code, CC_NC, do_int+512);//force 32-bit displacement
2969 //handle component synchronization
2970 cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, sync_cycle), opts->gen.cycles, SZ_D);
2971 skip_sync = code->cur + 1;
2972 jcc(code, CC_C, code->cur + 2);
2973 call(code, opts->gen.save_context);
2974 call_args_abi(code, (code_ptr)sync_components, 2, opts->gen.context_reg, opts->gen.scratch1);
2975 mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR);
2976 jmp(code, opts->gen.load_context);
2977 *skip_sync = code->cur - (skip_sync+1);
2978 cmp_irdisp(code, 0, opts->gen.context_reg, offsetof(m68k_context, should_return), SZ_B);
2979 code_ptr do_ret = code->cur + 1;
2980 jcc(code, CC_NZ, do_ret);
2981 retn(code);
2982 *do_ret = code->cur - (do_ret+1);
2983 uint32_t tmp_stack_off = code->stack_off;
2984 //fetch return address and adjust RSP
2985 pop_r(code, opts->gen.scratch1);
2986 add_ir(code, 16-sizeof(void *), RSP, SZ_PTR);
2987 add_ir(code, adjust_size, opts->gen.scratch1, SZ_PTR);
2988 //save return address for restoring later
2989 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, resume_pc), SZ_PTR);
2990 retn(code);
2991 code->stack_off = tmp_stack_off;
2992 *do_trace = code->cur - (do_trace + 1);
2993 //clear out trace pending flag
2994 mov_irdisp(code, 0, opts->gen.context_reg, offsetof(m68k_context, trace_pending), SZ_B);
2995 //save PC as stored in scratch1 for later
2996 push_r(code, opts->gen.scratch1);
2997 //swap USP and SSP if not already in supervisor mode
2998 check_user_mode_swap_ssp_usp(opts);
2999 //save status register
3000 subi_areg(opts, 6, 7);
3001 call(code, opts->get_sr);
3002 cycles(&opts->gen, 6);
3003 //save SR to stack
3004 areg_to_native(opts, 7, opts->gen.scratch2);
3005 call(code, opts->write_16);
3006 //update the status register
3007 and_irdisp(code, 0x7F, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
3008 or_irdisp(code, 0x20, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
3009 //save PC
3010 areg_to_native(opts, 7, opts->gen.scratch2);
3011 add_ir(code, 2, opts->gen.scratch2, SZ_D);
3012 pop_r(code, opts->gen.scratch1);
3013 call(code, opts->write_32_lowfirst);
3014 //read vector
3015 mov_ir(code, 0x24, opts->gen.scratch1, SZ_D);
3016 call(code, opts->read_32);
3017 call(code, opts->native_addr_and_sync);
3018 //2 prefetch bus operations + 2 idle bus cycles
3019 cycles(&opts->gen, 10);
3020 //discard function return address
3021 pop_r(code, opts->gen.scratch2);
3022 add_ir(code, 16-sizeof(void *), RSP, SZ_PTR);
3023 jmp_r(code, opts->gen.scratch1);
3024
3025 code->stack_off = tmp_stack_off;
3026
3027 *((uint32_t *)do_int) = code->cur - (do_int+4);
3028 //implement 1 instruction latency
3029 cmp_irdisp(code, INT_PENDING_NONE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
3030 do_int = code->cur + 1;
3031 jcc(code, CC_NZ, do_int);
3032 //store current interrupt number so it doesn't change before we start processing the vector
3033 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_num), opts->gen.scratch1, SZ_B);
3034 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
3035 retn(code);
3036 *do_int = code->cur - (do_int + 1);
3037 //Check if int_pending has an actual interrupt priority in it
3038 cmp_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
3039 code_ptr already_int_num = code->cur + 1;
3040 jcc(code, CC_NZ, already_int_num);
3041
3042 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_num), opts->gen.scratch2, SZ_B);
3043 mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
3044
3045 *already_int_num = code->cur - (already_int_num + 1);
3046 //save PC as stored in scratch1 for later
3047 push_r(code, opts->gen.scratch1);
3048 //set target cycle to sync cycle
3049 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, sync_cycle), opts->gen.limit, SZ_D);
3050 //swap USP and SSP if not already in supervisor mode
3051 check_user_mode_swap_ssp_usp(opts);
3052 //save status register
3053 subi_areg(opts, 6, 7);
3054 call(code, opts->get_sr);
3055 //6 cycles before SR gets saved
3056 cycles(&opts->gen, 6);
3057 //save SR to stack
3058 areg_to_native(opts, 7, opts->gen.scratch2);
3059 call(code, opts->write_16);
3060 //interrupt ack cycle
3061 //the Genesis responds to these exclusively with !VPA which means its a slow
3062 //6800 operation. documentation says these can take between 10 and 19 cycles.
3063 //actual results measurements seem to suggest it's actually between 9 and 18
3064 //WARNING: this code might break with register assignment changes
3065 //save RDX
3066 push_r(code, RDX);
3067 //save cycle count
3068 mov_rr(code, RAX, opts->gen.scratch1, SZ_D);
3069 //clear top doubleword of dividend
3070 xor_rr(code, RDX, RDX, SZ_D);
3071 //set divisor to clock divider
3072 mov_ir(code, opts->gen.clock_divider, opts->gen.scratch2, SZ_D);
3073 div_r(code, opts->gen.scratch2, SZ_D);
3074 //discard remainder
3075 xor_rr(code, RDX, RDX, SZ_D);
3076 //set divisor to 10, the period of E
3077 mov_ir(code, 10, opts->gen.scratch2, SZ_D);
3078 div_r(code, opts->gen.scratch2, SZ_D);
3079 //delay will be (9 + 4 + the remainder) * clock_divider
3080 //the extra 4 is to cover the idle bus period after the ack
3081 add_ir(code, 9 + 4, RDX, SZ_D);
3082 mov_ir(code, opts->gen.clock_divider, RAX, SZ_D);
3083 mul_r(code, RDX, SZ_D);
3084 pop_r(code, RDX);
3085 //add saved cycle count to result
3086 add_rr(code, opts->gen.scratch1, RAX, SZ_D);
3087
3088 //update status register
3089 and_irdisp(code, 0x78, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
3090 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_num), opts->gen.scratch1, SZ_B);
3091 //clear trace pending flag
3092 mov_irdisp(code, 0, opts->gen.context_reg, offsetof(m68k_context, trace_pending), SZ_B);
3093 //need to separate int priority and interrupt vector, but for now mask out large interrupt numbers
3094 and_ir(code, 0x7, opts->gen.scratch1, SZ_B);
3095 or_ir(code, 0x20, opts->gen.scratch1, SZ_B);
3096 or_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
3097
3098 pop_r(code, opts->gen.scratch1);
3099
3100 //save PC
3101 areg_to_native(opts, 7, opts->gen.scratch2);
3102 add_ir(code, 2, opts->gen.scratch2, SZ_D);
3103 call(code, opts->write_32_lowfirst);
3104
3105 //grab saved interrupt number
3106 xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_D);
3107 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_pending), opts->gen.scratch1, SZ_B);
3108 //ack the interrupt (happens earlier on hardware, but shouldn't be an observable difference)
3109 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, int_ack), SZ_W);
3110 //calculate the vector address
3111 shl_ir(code, 2, opts->gen.scratch1, SZ_D);
3112 add_ir(code, 0x60, opts->gen.scratch1, SZ_D);
3113 //clear out pending flag
3114 mov_irdisp(code, INT_PENDING_NONE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
3115 //read vector
3116 call(code, opts->read_32);
3117 call(code, opts->native_addr_and_sync);
3118 //2 prefetch bus operations + 2 idle bus cycles
3119 cycles(&opts->gen, 10);
3120 tmp_stack_off = code->stack_off;
3121 //discard function return address
3122 pop_r(code, opts->gen.scratch2);
3123 add_ir(code, 16-sizeof(void *), RSP, SZ_PTR);
3124 jmp_r(code, opts->gen.scratch1);
3125 code->stack_off = tmp_stack_off;
3126
3127 opts->handle_int_latch = code->cur;
3128 cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_cycle), opts->gen.cycles, SZ_D);
3129 code_ptr do_latch = code->cur + 1;
3130 jcc(code, CC_NC, do_latch);
3131 retn(code);
3132 *do_latch = code->cur - (do_latch + 1);
3133 cmp_irdisp(code, INT_PENDING_NONE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
3134 do_latch = code->cur + 1;
3135 jcc(code, CC_Z, do_latch);
3136 retn(code);
3137 *do_latch = code->cur - (do_latch + 1);
3138 //store current interrupt number so it doesn't change before we start processing the vector
3139 push_r(code, opts->gen.scratch1);
3140 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_num), opts->gen.scratch1, SZ_B);
3141 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
3142 pop_r(code, opts->gen.scratch1);
3143 retn(code);
3144
3145 opts->trap = code->cur;
3146 push_r(code, opts->gen.scratch2);
3147 //swap USP and SSP if not already in supervisor mode
3148 check_user_mode_swap_ssp_usp(opts);
3149 //save PC
3150 subi_areg(opts, 4, 7);
3151 areg_to_native(opts, 7, opts->gen.scratch2);
3152 call(code, opts->write_32_lowfirst);
3153 //save status register
3154 subi_areg(opts, 2, 7);
3155 call(code, opts->get_sr);
3156 areg_to_native(opts, 7, opts->gen.scratch2);
3157 call(code, opts->write_16);
3158 //set supervisor bit
3159 or_irdisp(code, 0x20, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
3160 //clear trace bit
3161 and_irdisp(code, 0x7F, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
3162 mov_irdisp(code, 0, opts->gen.context_reg, offsetof(m68k_context, trace_pending), SZ_B);
3163 //calculate vector address
3164 pop_r(code, opts->gen.scratch1);
3165 shl_ir(code, 2, opts->gen.scratch1, SZ_D);
3166 call(code, opts->read_32);
3167 call(code, opts->native_addr_and_sync);
3168 cycles(&opts->gen, 18);
3169 jmp_r(code, opts->gen.scratch1);
3170
3171 opts->retrans_stub = code->cur;
3172 call(code, opts->gen.save_context);
3173 push_r(code, opts->gen.context_reg);
3174 call_args(code,(code_ptr)m68k_retranslate_inst, 2, opts->gen.scratch1, opts->gen.context_reg);
3175 pop_r(code, opts->gen.context_reg);
3176 mov_rr(code, RAX, opts->gen.scratch1, SZ_PTR);
3177 call(code, opts->gen.load_context);
3178 jmp_r(code, opts->gen.scratch1);
3179
3180
3181 check_code_prologue(code);
3182 opts->bp_stub = code->cur;
3183
3184 tmp_stack_off = code->stack_off;
3185 //Calculate length of prologue
3186 check_cycles_int(&opts->gen, 0x1234);
3187 int check_int_size = code->cur-opts->bp_stub;
3188 code->cur = opts->bp_stub;
3189 code->stack_off = tmp_stack_off;
3190 opts->prologue_start = *opts->bp_stub;
3191 //Calculate length of patch
3192 mov_ir(code, 0x1234, opts->gen.scratch1, SZ_D);
3193 call(code, opts->bp_stub);
3194 int patch_size = code->cur - opts->bp_stub;
3195 code->cur = opts->bp_stub;
3196 code->stack_off = tmp_stack_off;
3197
3198 //Save context and call breakpoint handler
3199 call(code, opts->gen.save_context);
3200 push_r(code, opts->gen.scratch1);
3201 call_args_abi(code, (code_ptr)m68k_bp_dispatcher, 2, opts->gen.context_reg, opts->gen.scratch1);
3202 mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR);
3203 //Restore context
3204 call(code, opts->gen.load_context);
3205 pop_r(code, opts->gen.scratch1);
3206 //do prologue stuff
3207 cmp_rr(code, opts->gen.cycles, opts->gen.limit, SZ_D);
3208 code_ptr jmp_off = code->cur + 1;
3209 jcc(code, CC_NC, code->cur + 7);
3210 call(code, opts->gen.handle_cycle_limit_int);
3211 *jmp_off = code->cur - (jmp_off+1);
3212 //jump back to body of translated instruction
3213 pop_r(code, opts->gen.scratch1);
3214 add_ir(code, check_int_size - patch_size, opts->gen.scratch1, SZ_PTR);
3215 jmp_r(code, opts->gen.scratch1);
3216 code->stack_off = tmp_stack_off;
3217
3218 retranslate_calc(&opts->gen);
3219}