main
m68k_core.c
1/*
2 Copyright 2014 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 "m68k_core.h"
7#include "m68k_internal.h"
8#include "68kinst.h"
9#include "backend.h"
10#include "gen.h"
11#include "util.h"
12#include "serialize.h"
13#include <stdio.h>
14#include <stddef.h>
15#include <stdlib.h>
16#include <string.h>
17
18char disasm_buf[1024];
19
20int8_t native_reg(m68k_op_info * op, m68k_options * opts)
21{
22 if (op->addr_mode == MODE_REG) {
23 return opts->dregs[op->params.regs.pri];
24 }
25 if (op->addr_mode == MODE_AREG) {
26 return opts->aregs[op->params.regs.pri];
27 }
28 return -1;
29}
30
31size_t dreg_offset(uint8_t reg)
32{
33 return offsetof(m68k_context, dregs) + sizeof(uint32_t) * reg;
34}
35
36size_t areg_offset(uint8_t reg)
37{
38 return offsetof(m68k_context, aregs) + sizeof(uint32_t) * reg;
39}
40
41//must be called with an m68k_op_info that uses a register
42size_t reg_offset(m68k_op_info *op)
43{
44 return op->addr_mode == MODE_REG ? dreg_offset(op->params.regs.pri) : areg_offset(op->params.regs.pri);
45}
46
47void m68k_print_regs(m68k_context * context)
48{
49 printf("XNZVC\n%d%d%d%d%d\n", context->flags[0], context->flags[1], context->flags[2], context->flags[3], context->flags[4]);
50 for (int i = 0; i < 8; i++) {
51 printf("d%d: %X\n", i, context->dregs[i]);
52 }
53 for (int i = 0; i < 8; i++) {
54 printf("a%d: %X\n", i, context->aregs[i]);
55 }
56}
57
58void m68k_read_size(m68k_options *opts, uint8_t size)
59{
60 switch (size)
61 {
62 case OPSIZE_BYTE:
63 call(&opts->gen.code, opts->read_8);
64 break;
65 case OPSIZE_WORD:
66 call(&opts->gen.code, opts->read_16);
67 break;
68 case OPSIZE_LONG:
69 call(&opts->gen.code, opts->read_32);
70 break;
71 }
72}
73
74void m68k_write_size(m68k_options *opts, uint8_t size, uint8_t lowfirst)
75{
76 switch (size)
77 {
78 case OPSIZE_BYTE:
79 call(&opts->gen.code, opts->write_8);
80 break;
81 case OPSIZE_WORD:
82 call(&opts->gen.code, opts->write_16);
83 break;
84 case OPSIZE_LONG:
85 if (lowfirst) {
86 call(&opts->gen.code, opts->write_32_lowfirst);
87 } else {
88 call(&opts->gen.code, opts->write_32_highfirst);
89 }
90 break;
91 }
92}
93
94void m68k_save_result(m68kinst * inst, m68k_options * opts)
95{
96 if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG && inst->dst.addr_mode != MODE_UNUSED) {
97 if (inst->dst.addr_mode == MODE_AREG_PREDEC &&
98 ((inst->src.addr_mode == MODE_AREG_PREDEC && inst->op != M68K_MOVE) || (inst->op == M68K_NBCD))
99 ) {
100 areg_to_native(opts, inst->dst.params.regs.pri, opts->gen.scratch2);
101 }
102 m68k_write_size(opts, inst->extra.size, 1);
103 }
104}
105
106static void translate_m68k_lea_pea(m68k_options * opts, m68kinst * inst)
107{
108 code_info *code = &opts->gen.code;
109 int8_t dst_reg = inst->op == M68K_PEA ? opts->gen.scratch1 : native_reg(&(inst->dst), opts);
110 switch(inst->src.addr_mode)
111 {
112 case MODE_AREG_INDIRECT:
113 cycles(&opts->gen, BUS);
114 if (dst_reg >= 0) {
115 areg_to_native(opts, inst->src.params.regs.pri, dst_reg);
116 } else {
117 if (opts->aregs[inst->src.params.regs.pri] >= 0) {
118 native_to_areg(opts, opts->aregs[inst->src.params.regs.pri], inst->dst.params.regs.pri);
119 } else {
120 areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1);
121 native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
122 }
123 }
124 break;
125 case MODE_AREG_DISPLACE:
126 cycles(&opts->gen, 8);
127 calc_areg_displace(opts, &inst->src, dst_reg >= 0 ? dst_reg : opts->gen.scratch1);
128 if (dst_reg < 0) {
129 native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
130 }
131 break;
132 case MODE_AREG_INDEX_DISP8:
133 cycles(&opts->gen, 12);
134 if (dst_reg < 0 || inst->dst.params.regs.pri == inst->src.params.regs.pri || inst->dst.params.regs.pri == (inst->src.params.regs.sec >> 1 & 0x7)) {
135 dst_reg = opts->gen.scratch1;
136 }
137 calc_areg_index_disp8(opts, &inst->src, dst_reg);
138 if (dst_reg == opts->gen.scratch1 && inst->op != M68K_PEA) {
139 native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
140 }
141 break;
142 case MODE_PC_DISPLACE:
143 cycles(&opts->gen, 8);
144 if (inst->op == M68K_PEA) {
145 ldi_native(opts, inst->src.params.regs.displacement + inst->address+2, dst_reg);
146 } else {
147 ldi_areg(opts, inst->src.params.regs.displacement + inst->address+2, inst->dst.params.regs.pri);
148 }
149 break;
150 case MODE_PC_INDEX_DISP8:
151 cycles(&opts->gen, BUS*3);
152 if (dst_reg < 0 || inst->dst.params.regs.pri == (inst->src.params.regs.sec >> 1 & 0x7)) {
153 dst_reg = opts->gen.scratch1;
154 }
155 ldi_native(opts, inst->address+2, dst_reg);
156 calc_index_disp8(opts, &inst->src, dst_reg);
157 if (dst_reg == opts->gen.scratch1 && inst->op != M68K_PEA) {
158 native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
159 }
160 break;
161 case MODE_ABSOLUTE:
162 case MODE_ABSOLUTE_SHORT:
163 cycles(&opts->gen, (inst->src.addr_mode == MODE_ABSOLUTE) ? BUS * 3 : BUS * 2);
164 if (inst->op == M68K_PEA) {
165 ldi_native(opts, inst->src.params.immed, dst_reg);
166 } else {
167 ldi_areg(opts, inst->src.params.immed, inst->dst.params.regs.pri);
168 }
169 break;
170 default:
171 m68k_disasm(inst, disasm_buf);
172 fatal_error("%X: %s\naddress mode %d not implemented (lea src)\n", inst->address, disasm_buf, inst->src.addr_mode);
173 }
174 if (inst->op == M68K_PEA) {
175 subi_areg(opts, 4, 7);
176 areg_to_native(opts, 7, opts->gen.scratch2);
177 call(code, opts->write_32_lowfirst);
178 }
179}
180
181static void push_const(m68k_options *opts, int32_t value)
182{
183 ldi_native(opts, value, opts->gen.scratch1);
184 subi_areg(opts, 4, 7);
185 areg_to_native(opts, 7, opts->gen.scratch2);
186 call(&opts->gen.code, opts->write_32_highfirst);
187}
188
189void jump_m68k_abs(m68k_options * opts, uint32_t address)
190{
191 code_info *code = &opts->gen.code;
192 code_ptr dest_addr = get_native_address(opts, address);
193 if (!dest_addr) {
194 opts->gen.deferred = defer_address(opts->gen.deferred, address, code->cur + 1);
195 //dummy address to be replaced later, make sure it generates a 4-byte displacement
196 dest_addr = code->cur + 256;
197 }
198 jmp(code, dest_addr);
199 //this used to call opts->native_addr for destinations in RAM, but that shouldn't be needed
200 //since instruction retranslation patches the original native instruction location
201}
202
203static void translate_m68k_bsr(m68k_options * opts, m68kinst * inst)
204{
205 code_info *code = &opts->gen.code;
206 int32_t disp = inst->src.params.immed;
207 uint32_t after = inst->address + (inst->variant == VAR_BYTE ? 2 : 4);
208 //TODO: Add cycles in the right place relative to pushing the return address on the stack
209 cycles(&opts->gen, 10);
210 push_const(opts, after);
211 jump_m68k_abs(opts, inst->address + 2 + disp);
212}
213
214static void translate_m68k_jmp_jsr(m68k_options * opts, m68kinst * inst)
215{
216 uint8_t is_jsr = inst->op == M68K_JSR;
217 code_info *code = &opts->gen.code;
218 code_ptr dest_addr;
219 uint8_t sec_reg;
220 uint32_t after;
221 uint32_t m68k_addr;
222 switch(inst->src.addr_mode)
223 {
224 case MODE_AREG_INDIRECT:
225 cycles(&opts->gen, BUS*2);
226 if (is_jsr) {
227 push_const(opts, inst->address+2);
228 }
229 areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1);
230 call(code, opts->native_addr);
231 jmp_r(code, opts->gen.scratch1);
232 break;
233 case MODE_AREG_DISPLACE:
234 cycles(&opts->gen, BUS*2);
235 if (is_jsr) {
236 push_const(opts, inst->address+4);
237 }
238 calc_areg_displace(opts, &inst->src, opts->gen.scratch1);
239 call(code, opts->native_addr);
240 jmp_r(code, opts->gen.scratch1);
241 break;
242 case MODE_AREG_INDEX_DISP8:
243 cycles(&opts->gen, BUS*3);//TODO: CHeck that this is correct
244 if (is_jsr) {
245 push_const(opts, inst->address+4);
246 }
247 calc_areg_index_disp8(opts, &inst->src, opts->gen.scratch1);
248 call(code, opts->native_addr);
249 jmp_r(code, opts->gen.scratch1);
250 break;
251 case MODE_PC_DISPLACE:
252 //TODO: Add cycles in the right place relative to pushing the return address on the stack
253 cycles(&opts->gen, 10);
254 if (is_jsr) {
255 push_const(opts, inst->address+4);
256 }
257 jump_m68k_abs(opts, inst->src.params.regs.displacement + inst->address + 2);
258 break;
259 case MODE_PC_INDEX_DISP8:
260 cycles(&opts->gen, BUS*3);//TODO: CHeck that this is correct
261 if (is_jsr) {
262 push_const(opts, inst->address+4);
263 }
264 ldi_native(opts, inst->address+2, opts->gen.scratch1);
265 calc_index_disp8(opts, &inst->src, opts->gen.scratch1);
266 call(code, opts->native_addr);
267 jmp_r(code, opts->gen.scratch1);
268 break;
269 case MODE_ABSOLUTE:
270 case MODE_ABSOLUTE_SHORT:
271 //TODO: Add cycles in the right place relative to pushing the return address on the stack
272 cycles(&opts->gen, inst->src.addr_mode == MODE_ABSOLUTE ? 12 : 10);
273 if (is_jsr) {
274 push_const(opts, inst->address + (inst->src.addr_mode == MODE_ABSOLUTE ? 6 : 4));
275 }
276 jump_m68k_abs(opts, inst->src.params.immed);
277 break;
278 default:
279 m68k_disasm(inst, disasm_buf);
280 fatal_error("%s\naddress mode %d not yet supported (%s)\n", disasm_buf, inst->src.addr_mode, is_jsr ? "jsr" : "jmp");
281 }
282}
283
284static void translate_m68k_unlk(m68k_options * opts, m68kinst * inst)
285{
286 cycles(&opts->gen, BUS);
287 if (inst->dst.params.regs.pri != 7) {
288 areg_to_native(opts, inst->dst.params.regs.pri, opts->aregs[7]);
289 }
290 areg_to_native(opts, 7, opts->gen.scratch1);
291 call(&opts->gen.code, opts->read_32);
292 native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
293 if (inst->dst.params.regs.pri != 7) {
294 addi_areg(opts, 4, 7);
295 }
296}
297
298static void translate_m68k_link(m68k_options * opts, m68kinst * inst)
299{
300 //compensate for displacement word
301 cycles(&opts->gen, BUS);
302 subi_areg(opts, 4, 7);
303 areg_to_native(opts, 7, opts->gen.scratch2);
304 areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1);
305 call(&opts->gen.code, opts->write_32_highfirst);
306 native_to_areg(opts, opts->aregs[7], inst->src.params.regs.pri);
307 addi_areg(opts, inst->dst.params.immed, 7);
308 //prefetch
309 cycles(&opts->gen, BUS);
310}
311
312static void translate_m68k_rts(m68k_options * opts, m68kinst * inst)
313{
314 code_info *code = &opts->gen.code;
315 areg_to_native(opts, 7, opts->gen.scratch1);
316 addi_areg(opts, 4, 7);
317 call(code, opts->read_32);
318 cycles(&opts->gen, 2*BUS);
319 call(code, opts->native_addr);
320 jmp_r(code, opts->gen.scratch1);
321}
322
323static void translate_m68k_rtr(m68k_options *opts, m68kinst * inst)
324{
325 code_info *code = &opts->gen.code;
326 //Read saved CCR
327 areg_to_native(opts, 7, opts->gen.scratch1);
328 call(code, opts->read_16);
329 addi_areg(opts, 2, 7);
330 call(code, opts->set_ccr);
331 //Read saved PC
332 areg_to_native(opts, 7, opts->gen.scratch1);
333 call(code, opts->read_32);
334 addi_areg(opts, 4, 7);
335 //Get native address and jump to it
336 call(code, opts->native_addr);
337 jmp_r(code, opts->gen.scratch1);
338}
339
340static void translate_m68k_trap(m68k_options *opts, m68kinst *inst)
341{
342 code_info *code = &opts->gen.code;
343 uint32_t vector, pc = inst->address;
344 switch (inst->op)
345 {
346 case M68K_TRAP:
347 vector = inst->src.params.immed + VECTOR_TRAP_0;
348 pc += 2;
349 break;
350 case M68K_A_LINE_TRAP:
351 vector = VECTOR_LINE_1010;
352 break;
353 case M68K_F_LINE_TRAP:
354 vector = VECTOR_LINE_1111;
355 break;
356 }
357 ldi_native(opts, vector, opts->gen.scratch2);
358 ldi_native(opts, pc, opts->gen.scratch1);
359 jmp(code, opts->trap);
360}
361
362static void translate_m68k_illegal(m68k_options *opts, m68kinst *inst)
363{
364 code_info *code = &opts->gen.code;
365 cycles(&opts->gen, BUS);
366 ldi_native(opts, VECTOR_ILLEGAL_INST, opts->gen.scratch2);
367 ldi_native(opts, inst->address, opts->gen.scratch1);
368 jmp(code, opts->trap);
369}
370
371static void translate_m68k_move_usp(m68k_options *opts, m68kinst *inst)
372{
373 m68k_trap_if_not_supervisor(opts, inst);
374 cycles(&opts->gen, BUS);
375 int8_t reg;
376 if (inst->src.addr_mode == MODE_UNUSED) {
377 reg = native_reg(&inst->dst, opts);
378 if (reg < 0) {
379 reg = opts->gen.scratch1;
380 }
381 areg_to_native(opts, 8, reg);
382 if (reg == opts->gen.scratch1) {
383 native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
384 }
385 } else {
386 reg = native_reg(&inst->src, opts);
387 if (reg < 0) {
388 reg = opts->gen.scratch1;
389 areg_to_native(opts, inst->src.params.regs.pri, reg);
390 }
391 native_to_areg(opts, reg, 8);
392 }
393}
394
395static void translate_movem_regtomem_reglist(m68k_options * opts, m68kinst *inst)
396{
397 code_info *code = &opts->gen.code;
398 int8_t bit,reg,dir;
399 if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
400 reg = 15;
401 dir = -1;
402 } else {
403 reg = 0;
404 dir = 1;
405 }
406 for(bit=0; reg < 16 && reg >= 0; reg += dir, bit++) {
407 if (inst->src.params.immed & (1 << bit)) {
408 if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
409 subi_native(opts, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, opts->gen.scratch2);
410 }
411 push_native(opts, opts->gen.scratch2);
412 if (reg > 7) {
413 areg_to_native(opts, reg-8, opts->gen.scratch1);
414 } else {
415 dreg_to_native(opts, reg, opts->gen.scratch1);
416 }
417 if (inst->extra.size == OPSIZE_LONG) {
418 call(code, opts->write_32_lowfirst);
419 } else {
420 call(code, opts->write_16);
421 }
422 pop_native(opts, opts->gen.scratch2);
423 if (inst->dst.addr_mode != MODE_AREG_PREDEC) {
424 addi_native(opts, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, opts->gen.scratch2);
425 }
426 }
427 }
428}
429
430static void translate_movem_memtoreg_reglist(m68k_options * opts, m68kinst *inst)
431{
432 code_info *code = &opts->gen.code;
433 for(uint8_t reg = 0; reg < 16; reg ++) {
434 if (inst->dst.params.immed & (1 << reg)) {
435 push_native(opts, opts->gen.scratch1);
436 if (inst->extra.size == OPSIZE_LONG) {
437 call(code, opts->read_32);
438 } else {
439 call(code, opts->read_16);
440 }
441 if (inst->extra.size == OPSIZE_WORD) {
442 sign_extend16_native(opts, opts->gen.scratch1);
443 }
444 if (reg > 7) {
445 native_to_areg(opts, opts->gen.scratch1, reg-8);
446 } else {
447 native_to_dreg(opts, opts->gen.scratch1, reg);
448 }
449 pop_native(opts, opts->gen.scratch1);
450 addi_native(opts, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, opts->gen.scratch1);
451 }
452 }
453}
454
455static code_ptr get_movem_impl(m68k_options *opts, m68kinst *inst)
456{
457 uint8_t reg_to_mem = inst->src.addr_mode == MODE_REG;
458 uint8_t size = inst->extra.size;
459 int8_t dir = reg_to_mem && inst->dst.addr_mode == MODE_AREG_PREDEC ? -1 : 1;
460 uint16_t reglist = reg_to_mem ? inst->src.params.immed : inst->dst.params.immed;
461 for (uint32_t i = 0; i < opts->num_movem; i++)
462 {
463 if (
464 opts->big_movem[i].reglist == reglist && opts->big_movem[i].reg_to_mem == reg_to_mem
465 && opts->big_movem[i].size == size && opts->big_movem[i].dir == dir
466 ) {
467 return opts->big_movem[i].impl;
468 }
469 }
470 if (opts->num_movem == opts->movem_storage) {
471 if (!opts->movem_storage) {
472 opts->movem_storage = 4;
473 } else {
474 opts->movem_storage *= 2;
475 }
476 opts->big_movem = realloc(opts->big_movem, sizeof(movem_fun) * opts->movem_storage);
477 }
478 if (!opts->extra_code.cur) {
479 init_code_info(&opts->extra_code);
480 }
481 check_alloc_code(&opts->extra_code, 512);
482 code_ptr impl = opts->extra_code.cur;
483 code_info tmp = opts->gen.code;
484 opts->gen.code = opts->extra_code;
485 if (reg_to_mem) {
486 translate_movem_regtomem_reglist(opts, inst);
487 } else {
488 translate_movem_memtoreg_reglist(opts, inst);
489 }
490 opts->extra_code = opts->gen.code;
491 opts->gen.code = tmp;
492
493 rts(&opts->extra_code);
494 return impl;
495}
496
497static void translate_m68k_movem(m68k_options * opts, m68kinst * inst)
498{
499 code_info *code = &opts->gen.code;
500 uint8_t early_cycles;
501 uint16_t num_regs = inst->src.addr_mode == MODE_REG ? inst->src.params.immed : inst->dst.params.immed;
502 {
503 //TODO: Move this popcount alg to a utility function
504 uint16_t a = (num_regs & 0b1010101010101010) >> 1;
505 uint16_t b = num_regs & 0b0101010101010101;
506 num_regs = a + b;
507 a = (num_regs & 0b1100110011001100) >> 2;
508 b = num_regs & 0b0011001100110011;
509 num_regs = a + b;
510 a = (num_regs & 0b1111000011110000) >> 4;
511 b = num_regs & 0b0000111100001111;
512 num_regs = a + b;
513 a = (num_regs & 0b1111111100000000) >> 8;
514 b = num_regs & 0b0000000011111111;
515 num_regs = a + b;
516 }
517 if(inst->src.addr_mode == MODE_REG) {
518 //reg to mem
519 early_cycles = 8;
520 switch (inst->dst.addr_mode)
521 {
522 case MODE_AREG_INDIRECT:
523 case MODE_AREG_PREDEC:
524 areg_to_native(opts, inst->dst.params.regs.pri, opts->gen.scratch2);
525 break;
526 case MODE_AREG_DISPLACE:
527 early_cycles += BUS;
528 calc_areg_displace(opts, &inst->dst, opts->gen.scratch2);
529 break;
530 case MODE_AREG_INDEX_DISP8:
531 early_cycles += 6;
532 calc_areg_index_disp8(opts, &inst->dst, opts->gen.scratch2);
533 break;
534 case MODE_PC_DISPLACE:
535 early_cycles += BUS;
536 ldi_native(opts, inst->dst.params.regs.displacement + inst->address+2, opts->gen.scratch2);
537 break;
538 case MODE_PC_INDEX_DISP8:
539 early_cycles += 6;
540 ldi_native(opts, inst->address+2, opts->gen.scratch2);
541 calc_index_disp8(opts, &inst->dst, opts->gen.scratch2);
542 case MODE_ABSOLUTE:
543 early_cycles += 4;
544 case MODE_ABSOLUTE_SHORT:
545 early_cycles += 4;
546 ldi_native(opts, inst->dst.params.immed, opts->gen.scratch2);
547 break;
548 default:
549 m68k_disasm(inst, disasm_buf);
550 fatal_error("%X: %s\naddress mode %d not implemented (movem dst)\n", inst->address, disasm_buf, inst->dst.addr_mode);
551 }
552
553 cycles(&opts->gen, early_cycles);
554 if (num_regs <= 9) {
555 translate_movem_regtomem_reglist(opts, inst);
556 } else {
557 call(code, get_movem_impl(opts, inst));
558 }
559 if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
560 native_to_areg(opts, opts->gen.scratch2, inst->dst.params.regs.pri);
561 }
562 } else {
563 //mem to reg
564 early_cycles = 8; //includes prefetch
565 switch (inst->src.addr_mode)
566 {
567 case MODE_AREG_INDIRECT:
568 case MODE_AREG_POSTINC:
569 areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1);
570 break;
571 case MODE_AREG_DISPLACE:
572 early_cycles += BUS;
573 calc_areg_displace(opts, &inst->src, opts->gen.scratch1);
574 break;
575 case MODE_AREG_INDEX_DISP8:
576 early_cycles += 6;
577 calc_areg_index_disp8(opts, &inst->src, opts->gen.scratch1);
578 break;
579 case MODE_PC_DISPLACE:
580 early_cycles += BUS;
581 ldi_native(opts, inst->src.params.regs.displacement + inst->address+2, opts->gen.scratch1);
582 break;
583 case MODE_PC_INDEX_DISP8:
584 early_cycles += 6;
585 ldi_native(opts, inst->address+2, opts->gen.scratch1);
586 calc_index_disp8(opts, &inst->src, opts->gen.scratch1);
587 break;
588 case MODE_ABSOLUTE:
589 early_cycles += 4;
590 case MODE_ABSOLUTE_SHORT:
591 early_cycles += 4;
592 ldi_native(opts, inst->src.params.immed, opts->gen.scratch1);
593 break;
594 default:
595 m68k_disasm(inst, disasm_buf);
596 fatal_error("%X: %s\naddress mode %d not implemented (movem src)\n", inst->address, disasm_buf, inst->src.addr_mode);
597 }
598 cycles(&opts->gen, early_cycles);
599
600 if (num_regs <= 9) {
601 translate_movem_memtoreg_reglist(opts, inst);
602 } else {
603 call(code, get_movem_impl(opts, inst));
604 }
605 if (inst->src.addr_mode == MODE_AREG_POSTINC) {
606 native_to_areg(opts, opts->gen.scratch1, inst->src.params.regs.pri);
607 }
608 //Extra read
609 call(code, opts->read_16);
610 }
611}
612
613static void translate_m68k_nop(m68k_options *opts, m68kinst *inst)
614{
615 cycles(&opts->gen, BUS);
616}
617
618void swap_ssp_usp(m68k_options * opts)
619{
620 areg_to_native(opts, 7, opts->gen.scratch2);
621 areg_to_native(opts, 8, opts->aregs[7]);
622 native_to_areg(opts, opts->gen.scratch2, 8);
623}
624
625static void translate_m68k_rte(m68k_options *opts, m68kinst *inst)
626{
627 m68k_trap_if_not_supervisor(opts, inst);
628
629 code_info *code = &opts->gen.code;
630 //Read saved SR
631 areg_to_native(opts, 7, opts->gen.scratch1);
632 call(code, opts->read_16);
633 addi_areg(opts, 2, 7);
634 call(code, opts->set_sr);
635 //Read saved PC
636 areg_to_native(opts, 7, opts->gen.scratch1);
637 call(code, opts->read_32);
638 addi_areg(opts, 4, 7);
639 check_user_mode_swap_ssp_usp(opts);
640 cycles(&opts->gen, 2*BUS);
641 //Get native address, sync components, recalculate integer points and jump to returned address
642 call(code, opts->native_addr_and_sync);
643 jmp_r(code, opts->gen.scratch1);
644}
645
646code_ptr get_native_address(m68k_options *opts, uint32_t address)
647{
648 native_map_slot * native_code_map = opts->gen.native_code_map;
649
650 memmap_chunk const *mem_chunk = find_map_chunk(address, &opts->gen, 0, NULL);
651 if (mem_chunk) {
652 //calculate the lowest alias for this address
653 address = mem_chunk->start + ((address - mem_chunk->start) & mem_chunk->mask);
654 } else {
655 address &= opts->gen.address_mask;
656 }
657 uint32_t chunk = address / NATIVE_CHUNK_SIZE;
658 if (!native_code_map[chunk].base) {
659 return NULL;
660 }
661 uint32_t offset = address % NATIVE_CHUNK_SIZE;
662 if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET || native_code_map[chunk].offsets[offset] == EXTENSION_WORD) {
663 return NULL;
664 }
665 return native_code_map[chunk].base + native_code_map[chunk].offsets[offset];
666}
667
668code_ptr get_native_from_context(m68k_context * context, uint32_t address)
669{
670 return get_native_address(context->options, address);
671}
672
673uint32_t get_instruction_start(m68k_options *opts, uint32_t address)
674{
675 native_map_slot * native_code_map = opts->gen.native_code_map;
676 memmap_chunk const *mem_chunk = find_map_chunk(address, &opts->gen, 0, NULL);
677 if (mem_chunk) {
678 //calculate the lowest alias for this address
679 address = mem_chunk->start + ((address - mem_chunk->start) & mem_chunk->mask);
680 } else {
681 address &= opts->gen.address_mask;
682 }
683
684 uint32_t chunk = address / NATIVE_CHUNK_SIZE;
685 if (!native_code_map[chunk].base) {
686 return 0;
687 }
688 uint32_t offset = address % NATIVE_CHUNK_SIZE;
689 if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET) {
690 return 0;
691 }
692 while (native_code_map[chunk].offsets[offset] == EXTENSION_WORD)
693 {
694 --address;
695 chunk = address / NATIVE_CHUNK_SIZE;
696 offset = address % NATIVE_CHUNK_SIZE;
697 }
698 return address;
699}
700
701static void map_native_address(m68k_context * context, uint32_t address, code_ptr native_addr, uint8_t size, uint8_t native_size)
702{
703 m68k_options * opts = context->options;
704 native_map_slot * native_code_map = opts->gen.native_code_map;
705 uint32_t meta_off;
706 memmap_chunk const *mem_chunk = find_map_chunk(address, &opts->gen, MMAP_CODE, &meta_off);
707 if (mem_chunk) {
708 if (mem_chunk->flags & MMAP_CODE) {
709 uint32_t masked = (address - mem_chunk->start) & mem_chunk->mask;
710 uint32_t final_off = masked + meta_off;
711 uint32_t ram_flags_off = final_off >> (opts->gen.ram_flags_shift + 3);
712 context->ram_code_flags[ram_flags_off] |= 1 << ((final_off >> opts->gen.ram_flags_shift) & 7);
713
714 uint32_t slot = final_off / 1024;
715 if (!opts->gen.ram_inst_sizes[slot]) {
716 opts->gen.ram_inst_sizes[slot] = malloc(sizeof(uint8_t) * 512);
717 }
718 opts->gen.ram_inst_sizes[slot][(final_off/2) & 511] = native_size;
719
720 //TODO: Deal with case in which end of instruction is in a different memory chunk
721 masked = (address + size - 1) & mem_chunk->mask;
722 final_off = masked + meta_off;
723 ram_flags_off = final_off >> (opts->gen.ram_flags_shift + 3);
724 context->ram_code_flags[ram_flags_off] |= 1 << ((final_off >> opts->gen.ram_flags_shift) & 7);
725 }
726 //calculate the lowest alias for this address
727 address = mem_chunk->start + ((address - mem_chunk->start) & mem_chunk->mask);
728 } else {
729 address &= opts->gen.address_mask;
730 }
731
732 uint32_t chunk = address / NATIVE_CHUNK_SIZE;
733 if (!native_code_map[chunk].base) {
734 native_code_map[chunk].base = native_addr;
735 native_code_map[chunk].offsets = malloc(sizeof(int32_t) * NATIVE_CHUNK_SIZE);
736 memset(native_code_map[chunk].offsets, 0xFF, sizeof(int32_t) * NATIVE_CHUNK_SIZE);
737 }
738 uint32_t offset = address % NATIVE_CHUNK_SIZE;
739 native_code_map[chunk].offsets[offset] = native_addr-native_code_map[chunk].base;
740 for(address++,size-=1; size; address++,size-=1) {
741 address &= opts->gen.address_mask;
742 chunk = address / NATIVE_CHUNK_SIZE;
743 offset = address % NATIVE_CHUNK_SIZE;
744 if (!native_code_map[chunk].base) {
745 native_code_map[chunk].base = native_addr;
746 native_code_map[chunk].offsets = malloc(sizeof(int32_t) * NATIVE_CHUNK_SIZE);
747 memset(native_code_map[chunk].offsets, 0xFF, sizeof(int32_t) * NATIVE_CHUNK_SIZE);
748 }
749 if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET) {
750 //TODO: Better handling of overlapping instructions
751 native_code_map[chunk].offsets[offset] = EXTENSION_WORD;
752 }
753 }
754}
755
756static uint8_t get_native_inst_size(m68k_options * opts, uint32_t address)
757{
758 uint32_t meta_off;
759 memmap_chunk const *chunk = find_map_chunk(address, &opts->gen, MMAP_CODE, &meta_off);
760 if (chunk) {
761 meta_off += (address - chunk->start) & chunk->mask;
762 }
763 uint32_t slot = meta_off/1024;
764 return opts->gen.ram_inst_sizes[slot][(meta_off/2)%512];
765}
766
767uint8_t m68k_is_terminal(m68kinst * inst)
768{
769 return inst->op == M68K_RTS || inst->op == M68K_RTE || inst->op == M68K_RTR || inst->op == M68K_JMP
770 || inst->op == M68K_TRAP || inst->op == M68K_ILLEGAL || inst->op == M68K_INVALID
771 || (inst->op == M68K_BCC && inst->extra.cond == COND_TRUE);
772}
773
774static void m68k_handle_deferred(m68k_context * context)
775{
776 m68k_options * opts = context->options;
777 process_deferred(&opts->gen.deferred, context, (native_addr_func)get_native_from_context);
778 if (opts->gen.deferred) {
779 translate_m68k_stream(opts->gen.deferred->address, context);
780 }
781}
782
783uint16_t m68k_get_ir(m68k_context *context)
784{
785 uint32_t inst_addr = get_instruction_start(context->options, context->last_prefetch_address-2);
786 uint16_t *native_addr = get_native_pointer(inst_addr, (void **)context->mem_pointers, &context->options->gen);
787 if (native_addr) {
788 return *native_addr;
789 }
790 fprintf(stderr, "M68K: Failed to calculate value of IR. Last prefetch address: %X\n", context->last_prefetch_address);
791 return 0xFFFF;
792}
793
794static m68k_debug_handler find_breakpoint(m68k_context *context, uint32_t address)
795{
796 for (uint32_t i = 0; i < context->num_breakpoints; i++)
797 {
798 if (context->breakpoints[i].address == address) {
799 return context->breakpoints[i].handler;
800 }
801 }
802 return NULL;
803}
804
805void insert_breakpoint(m68k_context * context, uint32_t address, m68k_debug_handler bp_handler)
806{
807 if (!find_breakpoint(context, address)) {
808 if (context->bp_storage == context->num_breakpoints) {
809 context->bp_storage *= 2;
810 if (context->bp_storage < 4) {
811 context->bp_storage = 4;
812 }
813 context->breakpoints = realloc(context->breakpoints, context->bp_storage * sizeof(m68k_breakpoint));
814 }
815 context->breakpoints[context->num_breakpoints++] = (m68k_breakpoint){
816 .handler = bp_handler,
817 .address = address
818 };
819 m68k_breakpoint_patch(context, address, bp_handler, NULL);
820 }
821}
822
823m68k_context *m68k_bp_dispatcher(m68k_context *context, uint32_t address)
824{
825 m68k_debug_handler handler = find_breakpoint(context, address);
826 if (handler) {
827 handler(context, address);
828 } else {
829 //spurious breakoint?
830 warning("Spurious breakpoing at %X\n", address);
831 remove_breakpoint(context, address);
832 }
833
834 return context;
835}
836
837typedef enum {
838 RAW_FUNC = 1,
839 BINARY_ARITH,
840 UNARY_ARITH,
841 OP_FUNC
842} impl_type;
843
844typedef void (*raw_fun)(m68k_options * opts, m68kinst *inst);
845typedef void (*op_fun)(m68k_options * opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
846
847typedef struct {
848 union {
849 raw_fun raw;
850 uint32_t flag_mask;
851 op_fun op;
852 } impl;
853 impl_type itype;
854} impl_info;
855
856#define RAW_IMPL(inst, fun) [inst] = { .impl = { .raw = fun }, .itype = RAW_FUNC }
857#define OP_IMPL(inst, fun) [inst] = { .impl = { .op = fun }, .itype = OP_FUNC }
858#define UNARY_IMPL(inst, mask) [inst] = { .impl = { .flag_mask = mask }, .itype = UNARY_ARITH }
859#define BINARY_IMPL(inst, mask) [inst] = { .impl = { .flag_mask = mask}, .itype = BINARY_ARITH }
860
861static impl_info m68k_impls[] = {
862 //math
863 BINARY_IMPL(M68K_ADD, X|N|Z|V|C),
864 BINARY_IMPL(M68K_SUB, X|N|Z|V|C),
865 //z flag is special cased for ADDX/SUBX
866 BINARY_IMPL(M68K_ADDX, X|N|V|C),
867 BINARY_IMPL(M68K_SUBX, X|N|V|C),
868 OP_IMPL(M68K_ABCD, translate_m68k_abcd_sbcd),
869 OP_IMPL(M68K_SBCD, translate_m68k_abcd_sbcd),
870 OP_IMPL(M68K_NBCD, translate_m68k_abcd_sbcd),
871 BINARY_IMPL(M68K_AND, N|Z|V0|C0),
872 BINARY_IMPL(M68K_EOR, N|Z|V0|C0),
873 BINARY_IMPL(M68K_OR, N|Z|V0|C0),
874 RAW_IMPL(M68K_CMP, translate_m68k_cmp),
875 OP_IMPL(M68K_DIVS, translate_m68k_div),
876 OP_IMPL(M68K_DIVU, translate_m68k_div),
877 OP_IMPL(M68K_MULS, translate_m68k_mul),
878 OP_IMPL(M68K_MULU, translate_m68k_mul),
879 RAW_IMPL(M68K_EXT, translate_m68k_ext),
880 UNARY_IMPL(M68K_NEG, X|N|Z|V|C),
881 OP_IMPL(M68K_NEGX, translate_m68k_negx),
882 UNARY_IMPL(M68K_NOT, N|Z|V|C),
883 UNARY_IMPL(M68K_TST, N|Z|V0|C0),
884
885 //shift/rotate
886 OP_IMPL(M68K_ASL, translate_m68k_sl),
887 OP_IMPL(M68K_LSL, translate_m68k_sl),
888 OP_IMPL(M68K_ASR, translate_m68k_asr),
889 OP_IMPL(M68K_LSR, translate_m68k_lsr),
890 OP_IMPL(M68K_ROL, translate_m68k_rot),
891 OP_IMPL(M68K_ROR, translate_m68k_rot),
892 OP_IMPL(M68K_ROXL, translate_m68k_rot),
893 OP_IMPL(M68K_ROXR, translate_m68k_rot),
894 UNARY_IMPL(M68K_SWAP, N|Z|V0|C0),
895
896 //bit
897 OP_IMPL(M68K_BCHG, translate_m68k_bit),
898 OP_IMPL(M68K_BCLR, translate_m68k_bit),
899 OP_IMPL(M68K_BSET, translate_m68k_bit),
900 OP_IMPL(M68K_BTST, translate_m68k_bit),
901
902 //data movement
903 RAW_IMPL(M68K_MOVE, translate_m68k_move),
904 RAW_IMPL(M68K_MOVEM, translate_m68k_movem),
905 RAW_IMPL(M68K_MOVEP, translate_m68k_movep),
906 RAW_IMPL(M68K_MOVE_USP, translate_m68k_move_usp),
907 RAW_IMPL(M68K_LEA, translate_m68k_lea_pea),
908 RAW_IMPL(M68K_PEA, translate_m68k_lea_pea),
909 UNARY_IMPL(M68K_CLR, N0|V0|C0|Z1),
910 OP_IMPL(M68K_EXG, translate_m68k_exg),
911 RAW_IMPL(M68K_SCC, translate_m68k_scc),
912
913 //function calls and branches
914 RAW_IMPL(M68K_BCC, translate_m68k_bcc),
915 RAW_IMPL(M68K_BSR, translate_m68k_bsr),
916 RAW_IMPL(M68K_DBCC, translate_m68k_dbcc),
917 RAW_IMPL(M68K_JMP, translate_m68k_jmp_jsr),
918 RAW_IMPL(M68K_JSR, translate_m68k_jmp_jsr),
919 RAW_IMPL(M68K_RTS, translate_m68k_rts),
920 RAW_IMPL(M68K_RTE, translate_m68k_rte),
921 RAW_IMPL(M68K_RTR, translate_m68k_rtr),
922 RAW_IMPL(M68K_LINK, translate_m68k_link),
923 RAW_IMPL(M68K_UNLK, translate_m68k_unlk),
924
925 //SR/CCR stuff
926 RAW_IMPL(M68K_ANDI_CCR, translate_m68k_andi_ori_ccr_sr),
927 RAW_IMPL(M68K_ANDI_SR, translate_m68k_andi_ori_ccr_sr),
928 RAW_IMPL(M68K_EORI_CCR, translate_m68k_eori_ccr_sr),
929 RAW_IMPL(M68K_EORI_SR, translate_m68k_eori_ccr_sr),
930 RAW_IMPL(M68K_ORI_CCR, translate_m68k_andi_ori_ccr_sr),
931 RAW_IMPL(M68K_ORI_SR, translate_m68k_andi_ori_ccr_sr),
932 OP_IMPL(M68K_MOVE_CCR, translate_m68k_move_ccr_sr),
933 OP_IMPL(M68K_MOVE_SR, translate_m68k_move_ccr_sr),
934 OP_IMPL(M68K_MOVE_FROM_SR, translate_m68k_move_from_sr),
935 RAW_IMPL(M68K_STOP, translate_m68k_stop),
936
937 //traps
938 OP_IMPL(M68K_CHK, translate_m68k_chk),
939 RAW_IMPL(M68K_TRAP, translate_m68k_trap),
940 RAW_IMPL(M68K_A_LINE_TRAP, translate_m68k_trap),
941 RAW_IMPL(M68K_F_LINE_TRAP, translate_m68k_trap),
942 RAW_IMPL(M68K_TRAPV, translate_m68k_trapv),
943 RAW_IMPL(M68K_ILLEGAL, translate_m68k_illegal),
944 RAW_IMPL(M68K_INVALID, translate_m68k_illegal),
945
946 //misc
947 RAW_IMPL(M68K_NOP, translate_m68k_nop),
948 RAW_IMPL(M68K_RESET, translate_m68k_reset),
949 RAW_IMPL(M68K_TAS, translate_m68k_tas),
950};
951
952static void translate_m68k(m68k_context *context, m68kinst * inst)
953{
954 m68k_options * opts = context->options;
955 if (inst->address & 1) {
956 translate_m68k_odd(opts, inst);
957 return;
958 }
959 code_ptr start = opts->gen.code.cur;
960 check_cycles_int(&opts->gen, inst->address);
961
962 m68k_debug_handler bp;
963 if ((bp = find_breakpoint(context, inst->address))) {
964 m68k_breakpoint_patch(context, inst->address, bp, start);
965 }
966
967 //log_address(&opts->gen, inst->address, "M68K: %X @ %d\n");
968 if (
969 (inst->src.addr_mode > MODE_AREG && inst->src.addr_mode < MODE_IMMEDIATE)
970 || (inst->dst.addr_mode > MODE_AREG && inst->dst.addr_mode < MODE_IMMEDIATE)
971 || (inst->op == M68K_BCC && (inst->src.params.immed & 1))
972 ) {
973 //Not accurate for all cases, but probably good enough for now
974 m68k_set_last_prefetch(opts, inst->address + inst->bytes);
975 }
976 impl_info * info = m68k_impls + inst->op;
977 if (info->itype == RAW_FUNC) {
978 info->impl.raw(opts, inst);
979 return;
980 }
981
982 host_ea src_op, dst_op;
983 uint8_t needs_int_latch = 0;
984 if (inst->src.addr_mode != MODE_UNUSED) {
985 needs_int_latch |= translate_m68k_op(inst, &src_op, opts, 0);
986 }
987 if (inst->dst.addr_mode != MODE_UNUSED) {
988 needs_int_latch |= translate_m68k_op(inst, &dst_op, opts, 1);
989 }
990 if (needs_int_latch) {
991 m68k_check_cycles_int_latch(opts);
992 }
993 if (info->itype == OP_FUNC) {
994 info->impl.op(opts, inst, &src_op, &dst_op);
995 } else if (info->itype == BINARY_ARITH) {
996 translate_m68k_arith(opts, inst, info->impl.flag_mask, &src_op, &dst_op);
997 } else if (info->itype == UNARY_ARITH) {
998 translate_m68k_unary(opts, inst, info->impl.flag_mask, inst->dst.addr_mode != MODE_UNUSED ? &dst_op : &src_op);
999 } else {
1000 m68k_disasm(inst, disasm_buf);
1001 fatal_error("%X: %s\ninstruction %d not yet implemented\n", inst->address, disasm_buf, inst->op);
1002 }
1003 if (opts->gen.code.stack_off) {
1004 m68k_disasm(inst, disasm_buf);
1005 fatal_error("Stack offset is %X after %X: %s\n", opts->gen.code.stack_off, inst->address, disasm_buf);
1006 }
1007}
1008
1009void translate_m68k_stream(uint32_t address, m68k_context * context)
1010{
1011 m68kinst instbuf;
1012 m68k_options * opts = context->options;
1013 code_info *code = &opts->gen.code;
1014 if(get_native_address(opts, address)) {
1015 return;
1016 }
1017 uint16_t *encoded, *next;
1018 do {
1019 if (opts->address_log) {
1020 fprintf(opts->address_log, "%X\n", address);
1021 fflush(opts->address_log);
1022 }
1023 do {
1024 encoded = get_native_pointer(address, (void **)context->mem_pointers, &opts->gen);
1025 if (!encoded) {
1026 code_ptr start = code->cur;
1027 translate_out_of_bounds(opts, address);
1028 code_ptr after = code->cur;
1029 map_native_address(context, address, start, 2, after-start);
1030 break;
1031 }
1032 code_ptr existing = get_native_address(opts, address);
1033 if (existing) {
1034 jmp(code, existing);
1035 break;
1036 }
1037 next = m68k_decode(encoded, &instbuf, address);
1038 if (instbuf.op == M68K_INVALID) {
1039 instbuf.src.params.immed = *encoded;
1040 }
1041 uint16_t m68k_size = (next-encoded)*2;
1042 address += m68k_size;
1043 //char disbuf[1024];
1044 //m68k_disasm(&instbuf, disbuf);
1045 //printf("%X: %s\n", instbuf.address, disbuf);
1046
1047 //make sure the beginning of the code for an instruction is contiguous
1048 check_code_prologue(code);
1049 code_ptr start = code->cur;
1050 translate_m68k(context, &instbuf);
1051 code_ptr after = code->cur;
1052 map_native_address(context, instbuf.address, start, m68k_size, after-start);
1053 } while(!m68k_is_terminal(&instbuf) && !(address & 1));
1054 process_deferred(&opts->gen.deferred, context, (native_addr_func)get_native_from_context);
1055 if (opts->gen.deferred) {
1056 address = opts->gen.deferred->address;
1057 }
1058 } while(opts->gen.deferred);
1059}
1060
1061void * m68k_retranslate_inst(uint32_t address, m68k_context * context)
1062{
1063 m68k_options * opts = context->options;
1064 code_info *code = &opts->gen.code;
1065 uint8_t orig_size = get_native_inst_size(opts, address);
1066 code_ptr orig_start = get_native_address(context->options, address);
1067 uint32_t orig = address;
1068 code_info orig_code = {orig_start, orig_start + orig_size + 5, 0};
1069 uint16_t *after, *inst = get_native_pointer(address, (void **)context->mem_pointers, &opts->gen);
1070 m68kinst instbuf;
1071 after = m68k_decode(inst, &instbuf, orig);
1072 if (orig_size != MAX_NATIVE_SIZE) {
1073 deferred_addr * orig_deferred = opts->gen.deferred;
1074
1075 //make sure we have enough code space for the max size instruction
1076 check_alloc_code(code, MAX_NATIVE_SIZE);
1077 code_ptr native_start = code->cur;
1078 translate_m68k(context, &instbuf);
1079 code_ptr native_end = code->cur;
1080 /*uint8_t is_terminal = m68k_is_terminal(&instbuf);
1081 if ((native_end - native_start) <= orig_size) {
1082 code_ptr native_next;
1083 if (!is_terminal) {
1084 native_next = get_native_address(context->native_code_map, orig + (after-inst)*2);
1085 }
1086 if (is_terminal || (native_next && ((native_next == orig_start + orig_size) || (orig_size - (native_end - native_start)) > 5))) {
1087 printf("Using original location: %p\n", orig_code.cur);
1088 remove_deferred_until(&opts->gen.deferred, orig_deferred);
1089 code_info tmp;
1090 tmp.cur = code->cur;
1091 tmp.last = code->last;
1092 code->cur = orig_code.cur;
1093 code->last = orig_code.last;
1094 translate_m68k(context, &instbuf);
1095 native_end = orig_code.cur = code->cur;
1096 code->cur = tmp.cur;
1097 code->last = tmp.last;
1098 if (!is_terminal) {
1099 nop_fill_or_jmp_next(&orig_code, orig_start + orig_size, native_next);
1100 }
1101 m68k_handle_deferred(context);
1102 return orig_start;
1103 }
1104 }*/
1105
1106 map_native_address(context, instbuf.address, native_start, (after-inst)*2, MAX_NATIVE_SIZE);
1107
1108 jmp(&orig_code, native_start);
1109 if (!m68k_is_terminal(&instbuf)) {
1110 code_ptr native_end = code->cur;
1111 code->cur = native_start + MAX_NATIVE_SIZE;
1112 code_ptr rest = get_native_address_trans(context, orig + (after-inst)*2);
1113 code_info tmp_code = {
1114 .cur = native_end,
1115 .last = native_start + MAX_NATIVE_SIZE,
1116 .stack_off = code->stack_off
1117 };
1118 jmp(&tmp_code, rest);
1119 } else {
1120 code->cur = native_start + MAX_NATIVE_SIZE;
1121 }
1122 m68k_handle_deferred(context);
1123 return native_start;
1124 } else {
1125 code_info tmp = *code;
1126 *code = orig_code;
1127 translate_m68k(context, &instbuf);
1128 orig_code = *code;
1129 *code = tmp;
1130 if (!m68k_is_terminal(&instbuf)) {
1131 jmp(&orig_code, get_native_address_trans(context, orig + (after-inst)*2));
1132 }
1133 m68k_handle_deferred(context);
1134 return orig_start;
1135 }
1136}
1137
1138code_ptr get_native_address_trans(m68k_context * context, uint32_t address)
1139{
1140 code_ptr ret = get_native_address(context->options, address);
1141 if (!ret) {
1142 translate_m68k_stream(address, context);
1143 ret = get_native_address(context->options, address);
1144 }
1145 return ret;
1146}
1147
1148void remove_breakpoint(m68k_context * context, uint32_t address)
1149{
1150 for (uint32_t i = 0; i < context->num_breakpoints; i++)
1151 {
1152 if (context->breakpoints[i].address == address) {
1153 if (i != (context->num_breakpoints-1)) {
1154 context->breakpoints[i] = context->breakpoints[context->num_breakpoints-1];
1155 }
1156 context->num_breakpoints--;
1157 break;
1158 }
1159 }
1160 code_ptr native = get_native_address(context->options, address);
1161 if (!native) {
1162 return;
1163 }
1164 code_info tmp = context->options->gen.code;
1165 context->options->gen.code.cur = native;
1166 context->options->gen.code.last = native + MAX_NATIVE_SIZE;
1167 check_cycles_int(&context->options->gen, address);
1168 context->options->gen.code = tmp;
1169}
1170
1171void start_68k_context(m68k_context * context, uint32_t address)
1172{
1173 code_ptr addr = get_native_address_trans(context, address);
1174 m68k_options * options = context->options;
1175 options->start_context(addr, context);
1176}
1177
1178void resume_68k(m68k_context *context)
1179{
1180 code_ptr addr = context->resume_pc;
1181 context->resume_pc = NULL;
1182 m68k_options * options = context->options;
1183 context->should_return = 0;
1184 options->start_context(addr, context);
1185}
1186
1187void m68k_reset(m68k_context * context)
1188{
1189 //TODO: Actually execute the M68K reset vector rather than simulating some of its behavior
1190 uint16_t *reset_vec = get_native_pointer(0, (void **)context->mem_pointers, &context->options->gen);
1191 context->aregs[7] = reset_vec[0] << 16 | reset_vec[1];
1192 uint32_t address = reset_vec[2] << 16 | reset_vec[3];
1193 start_68k_context(context, address);
1194}
1195
1196void m68k_options_free(m68k_options *opts)
1197{
1198 for (uint32_t address = 0; address < opts->gen.address_mask; address += NATIVE_CHUNK_SIZE)
1199 {
1200 uint32_t chunk = address / NATIVE_CHUNK_SIZE;
1201 if (opts->gen.native_code_map[chunk].base) {
1202 free(opts->gen.native_code_map[chunk].offsets);
1203 }
1204 }
1205 free(opts->gen.native_code_map);
1206 uint32_t ram_inst_slots = ram_size(&opts->gen) / 1024;
1207 for (uint32_t i = 0; i < ram_inst_slots; i++)
1208 {
1209 free(opts->gen.ram_inst_sizes[i]);
1210 }
1211 free(opts->gen.ram_inst_sizes);
1212 free(opts->big_movem);
1213 free(opts);
1214}
1215
1216
1217m68k_context * init_68k_context(m68k_options * opts, m68k_reset_handler reset_handler)
1218{
1219 m68k_context * context = calloc(1, sizeof(m68k_context) + ram_size(&opts->gen) / (1 << opts->gen.ram_flags_shift) / 8);
1220 context->options = opts;
1221 context->int_cycle = CYCLE_NEVER;
1222 context->status = 0x27;
1223 context->reset_handler = (code_ptr)reset_handler;
1224 return context;
1225}
1226
1227void m68k_serialize(m68k_context *context, uint32_t pc, serialize_buffer *buf)
1228{
1229 for (int i = 0; i < 8; i++)
1230 {
1231 save_int32(buf, context->dregs[i]);
1232 }
1233 for (int i = 0; i < 9; i++)
1234 {
1235 save_int32(buf, context->aregs[i]);
1236 }
1237 save_int32(buf, pc);
1238 uint16_t sr = context->status << 3;
1239 for (int flag = 4; flag >= 0; flag--) {
1240 sr <<= 1;
1241 sr |= context->flags[flag] != 0;
1242 }
1243 save_int16(buf, sr);
1244 save_int32(buf, context->current_cycle);
1245 save_int32(buf, context->int_cycle);
1246 save_int8(buf, context->int_num);
1247 save_int8(buf, context->int_pending);
1248 save_int8(buf, context->trace_pending);
1249}
1250
1251void m68k_deserialize(deserialize_buffer *buf, void *vcontext)
1252{
1253 m68k_context *context = vcontext;
1254 for (int i = 0; i < 8; i++)
1255 {
1256 context->dregs[i] = load_int32(buf);
1257 }
1258 for (int i = 0; i < 9; i++)
1259 {
1260 context->aregs[i] = load_int32(buf);
1261 }
1262 //hack until both PC and IR registers are represented properly
1263 context->last_prefetch_address = load_int32(buf);
1264 uint16_t sr = load_int16(buf);
1265 context->status = sr >> 8;
1266 for (int flag = 0; flag < 5; flag++)
1267 {
1268 context->flags[flag] = sr & 1;
1269 sr >>= 1;
1270 }
1271 context->current_cycle = load_int32(buf);
1272 context->int_cycle = load_int32(buf);
1273 context->int_num = load_int8(buf);
1274 context->int_pending = load_int8(buf);
1275 context->trace_pending = load_int8(buf);
1276}