comparison m68k_to_x86.c @ 18:3e7bfde7606e

M68K to x86 translation works for a limited subset of instructions and addressing modes
author Mike Pavone <pavone@retrodev.com>
date Tue, 04 Dec 2012 19:13:12 -0800
parents 2bdad0f52f42
children 4717146a7606
comparison
equal deleted inserted replaced
17:de0085d4ea40 18:3e7bfde7606e
1 #include "gen_x86.h" 1 #include "gen_x86.h"
2 #include "m68k_to_x86.h" 2 #include "m68k_to_x86.h"
3 3 #include <stdio.h>
4 #include <stddef.h>
5 #include <stdlib.h>
6 #include <string.h>
4 7
5 #define BUS 4 8 #define BUS 4
9 #define PREDEC_PENALTY 2
6 #define CYCLES RAX 10 #define CYCLES RAX
7 #define LIMIT RBP 11 #define LIMIT RBP
8 #define SCRATCH RCX 12 #define SCRATCH1 RCX
13 #define SCRATCH2 RDI
9 #define CONTEXT RSI 14 #define CONTEXT RSI
10 15
11 #define FLAG_N RBX 16 #define FLAG_N RBX
12 #define FLAG_V BH 17 #define FLAG_V BH
13 #define FLAG_Z RDX 18 #define FLAG_Z RDX
20 uint8_t index; 25 uint8_t index;
21 uint8_t cycles; 26 uint8_t cycles;
22 } x86_ea; 27 } x86_ea;
23 28
24 void handle_cycle_limit(); 29 void handle_cycle_limit();
30 void m68k_read_word_scratch1();
31 void m68k_read_long_scratch1();
32 void m68k_read_byte_scratch1();
33 void m68k_write_word();
34 void m68k_write_long_lowfirst();
35 void m68k_write_long_highfirst();
36 void m68k_write_byte();
37 void m68k_save_context();
38 void m68k_modified_ret_addr();
39 void m68k_start_context(uint8_t * addr, m68k_context * context);
25 40
26 uint8_t * cycles(uint8_t * dst, uint32_t num) 41 uint8_t * cycles(uint8_t * dst, uint32_t num)
27 { 42 {
28 dst = add_i32r(dst, num, CYCLES); 43 dst = add_ir(dst, num, CYCLES, SZ_D);
29 } 44 }
30 45
31 uint8_t * check_cycles(uint8_t * dst) Ivds 46 uint8_t * check_cycles(uint8_t * dst)
32 { 47 {
33 dst = cmp_rr(dst, CYCLES, LIMIT, SZ_D); 48 dst = cmp_rr(dst, CYCLES, LIMIT, SZ_D);
34 dst = jcc(dst, CC_G, 5); 49 dst = jcc(dst, CC_G, dst+7);
35 dst = call(dst, (char *)handle_cycle_limit); 50 dst = call(dst, (char *)handle_cycle_limit);
36 } 51 }
37 52
38 int8_t native_reg(m68k_op_info * op, x86_68k_options * opts) 53 int8_t native_reg(m68k_op_info * op, x86_68k_options * opts)
39 { 54 {
44 return opts->aregs[op->params.regs.pri]; 59 return opts->aregs[op->params.regs.pri];
45 } 60 }
46 return -1; 61 return -1;
47 } 62 }
48 63
49 uint8_t * translate_m68k_ea(m68k_op_info * op, x86_ea * dst, uint8_t * out, x86_68k_options * opts) 64 void print_regs_exit(m68k_context * context)
50 { 65 {
51 int8_t reg = native_reg(op, opts); 66 for (int i = 0; i < 8; i++) {
67 printf("d%d: %X\n", i, context->dregs[i]);
68 }
69 for (int i = 0; i < 8; i++) {
70 printf("a%d: %X\n", i, context->aregs[i]);
71 }
72 exit(0);
73 }
74
75 uint8_t * translate_m68k_src(m68kinst * inst, x86_ea * ea, uint8_t * out, x86_68k_options * opts)
76 {
77 int8_t reg = native_reg(&(inst->src), opts);
78 int32_t dec_amount,inc_amount;
52 if (reg >= 0) { 79 if (reg >= 0) {
53 dst->mode = MODE_REG_DIRECT; 80 ea->mode = MODE_REG_DIRECT;
54 dst->base = reg; 81 ea->base = reg;
55 return; 82 return out;
56 } 83 }
57 switch (op->addr_mode) 84 switch (inst->src.addr_mode)
58 { 85 {
59 case MODE_REG: 86 case MODE_REG:
60 case MODE_AREG: 87 case MODE_AREG:
61 dst->mode = MODE_DISPLACE8; 88 //We only get one memory parameter, so if the dst operand is a register in memory,
62 dst->base = CONTEXT; 89 //we need to copy this to a temp register first
63 dst->disp = (op->addr_mode = MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs)) + 4 * op->params.regs.pri; 90 reg = native_reg(&(inst->dst), opts);
64 break; 91 if (reg >= 0 || inst->dst.addr_mode == MODE_UNUSED || (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode == MODE_AREG)
92 || inst->op == M68K_EXG) {
93
94 ea->mode = MODE_REG_DISPLACE8;
95 ea->base = CONTEXT;
96 ea->disp = (inst->src.addr_mode == MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs)) + 4 * inst->src.params.regs.pri;
97 } else {
98 out = mov_rdisp8r(out, CONTEXT, (inst->src.addr_mode == MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs)) + 4 * inst->src.params.regs.pri, SCRATCH1, inst->extra.size);
99 ea->mode = MODE_REG_DIRECT;
100 ea->base = SCRATCH1;
101 }
102 break;
103 case MODE_AREG_PREDEC:
104 dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : 1);
105 out = cycles(out, PREDEC_PENALTY);
106 if (opts->aregs[inst->src.params.regs.pri] >= 0) {
107 out = sub_ir(out, inc_amount, opts->aregs[inst->src.params.regs.pri], SZ_D);
108 } else {
109 out = sub_irdisp8(out, inc_amount, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, SZ_D);
110 }
111 out = check_cycles(out);
65 case MODE_AREG_INDIRECT: 112 case MODE_AREG_INDIRECT:
113 case MODE_AREG_POSTINC:
114 if (opts->aregs[inst->src.params.regs.pri] >= 0) {
115 out = mov_rr(out, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D);
116 } else {
117 out = mov_rdisp8r(out, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, SCRATCH1, SZ_D);
118 }
119 switch (inst->extra.size)
120 {
121 case OPSIZE_BYTE:
122 out = call(out, (char *)m68k_read_byte_scratch1);
123 break;
124 case OPSIZE_WORD:
125 out = call(out, (char *)m68k_read_word_scratch1);
126 break;
127 case OPSIZE_LONG:
128 out = call(out, (char *)m68k_read_long_scratch1);
129 break;
130 }
66 131
67 break; 132 if (inst->src.addr_mode == MODE_AREG_POSTINC) {
68 } 133 inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : 1);
69 } 134 if (opts->aregs[inst->src.params.regs.pri] >= 0) {
70 135 out = add_ir(out, inc_amount, opts->aregs[inst->src.params.regs.pri], SZ_D);
71 uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) 136 } else {
72 { 137 out = add_irdisp8(out, inc_amount, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, SZ_D);
73 int8_t reg_a, reg_b, flags_reg; 138 }
139 }
140 ea->mode = MODE_REG_DIRECT;
141 ea->base = SCRATCH1;
142 break;
143 case MODE_IMMEDIATE:
144 if (inst->variant != VAR_QUICK) {
145 if (inst->extra.size == OPSIZE_LONG) {
146 out = cycles(out, BUS);
147 out = check_cycles(out);
148 }
149 out = cycles(out, BUS);
150 out = check_cycles(out);
151 }
152 ea->mode = MODE_IMMED;
153 ea->disp = inst->src.params.immed;
154 break;
155 default:
156 printf("address mode %d not implemented (src)\n", inst->src.addr_mode);
157 exit(1);
158 }
159 return out;
160 }
161
162 uint8_t * translate_m68k_dst(m68kinst * inst, x86_ea * ea, uint8_t * out, x86_68k_options * opts)
163 {
164 int8_t reg = native_reg(&(inst->dst), opts);
165 int32_t dec_amount, inc_amount;
166 if (reg >= 0) {
167 ea->mode = MODE_REG_DIRECT;
168 ea->base = reg;
169 return out;
170 }
171 switch (inst->dst.addr_mode)
172 {
173 case MODE_REG:
174 case MODE_AREG:
175 ea->mode = MODE_REG_DISPLACE8;
176 ea->base = CONTEXT;
177 ea->disp = (inst->dst.addr_mode == MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs)) + 4 * inst->dst.params.regs.pri;
178 break;
179 case MODE_AREG_PREDEC:
180 dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : 1);
181 if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
182 out = sub_ir(out, dec_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D);
183 } else {
184 out = sub_irdisp8(out, dec_amount, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D);
185 }
186 case MODE_AREG_INDIRECT:
187 case MODE_AREG_POSTINC:
188 if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
189 out = mov_rr(out, opts->aregs[inst->dst.params.regs.pri], SCRATCH1, SZ_D);
190 } else {
191 out = mov_rdisp8r(out, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SCRATCH1, SZ_D);
192 }
193 switch (inst->extra.size)
194 {
195 case OPSIZE_BYTE:
196 out = call(out, (char *)m68k_read_byte_scratch1);
197 break;
198 case OPSIZE_WORD:
199 out = call(out, (char *)m68k_read_word_scratch1);
200 break;
201 case OPSIZE_LONG:
202 out = call(out, (char *)m68k_read_long_scratch1);
203 break;
204 }
205 //save reg value in SCRATCH2 so we can use it to save the result in memory later
206 if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
207 out = mov_rr(out, opts->aregs[inst->dst.params.regs.pri], SCRATCH2, SZ_D);
208 } else {
209 out = mov_rdisp8r(out, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SCRATCH2, SZ_D);
210 }
211
212 if (inst->src.addr_mode == MODE_AREG_POSTINC) {
213 inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : 1);
214 if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
215 out = add_ir(out, inc_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D);
216 } else {
217 out = add_irdisp8(out, inc_amount, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D);
218 }
219 }
220 ea->mode = MODE_REG_DIRECT;
221 ea->base = SCRATCH1;
222 break;
223 default:
224 printf("address mode %d not implemented (dst)\n", inst->dst.addr_mode);
225 exit(1);
226 }
227 return out;
228 }
229
230 uint8_t * m68k_save_result(m68kinst * inst, uint8_t * out, x86_68k_options * opts)
231 {
232 if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG) {
233 switch (inst->extra.size)
234 {
235 case OPSIZE_BYTE:
236 out = call(out, (char *)m68k_write_byte);
237 break;
238 case OPSIZE_WORD:
239 out = call(out, (char *)m68k_write_word);
240 break;
241 case OPSIZE_LONG:
242 out = call(out, (char *)m68k_write_long_lowfirst);
243 break;
244 }
245 }
246 return out;
247 }
248
249 uint8_t * get_native_address(native_map_slot * native_code_map, uint32_t address)
250 {
251 address &= 0xFFFFFF;
252 uint32_t chunk = address / NATIVE_CHUNK_SIZE;
253 if (!native_code_map[chunk].base) {
254 return NULL;
255 }
256 uint32_t offset = address % NATIVE_CHUNK_SIZE;
257 if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET) {
258 return NULL;
259 }
260 return native_code_map[chunk].base + native_code_map[chunk].offsets[offset];
261 }
262
263 deferred_addr * defer_address(deferred_addr * old_head, uint32_t address, uint8_t *dest)
264 {
265 deferred_addr * new_head = malloc(sizeof(deferred_addr));
266 new_head->next = old_head;
267 new_head->address = address & 0xFFFFFF;
268 new_head->dest = dest;
269 return new_head;
270 }
271
272 void process_deferred(x86_68k_options * opts)
273 {
274 deferred_addr * cur = opts->deferred;
275 deferred_addr **last_next = &(opts->deferred);
276 while(cur)
277 {
278 uint8_t * native = get_native_address(opts->native_code_map, cur->address);
279 if (native) {
280 int32_t disp = native - (cur->dest + 4);
281 printf("Native dest: %p, Offset address: %p, displacement: %X\n", native, cur->dest, disp);
282 uint8_t * out = cur->dest;
283 *(out++) = disp;
284 disp >>= 8;
285 *(out++) = disp;
286 disp >>= 8;
287 *(out++) = disp;
288 disp >>= 8;
289 *out = disp;
290 *last_next = cur->next;
291 free(cur);
292 cur = *last_next;
293 } else {
294 last_next = &(cur->next);
295 cur = cur->next;
296 }
297 }
298 }
299
300 void map_native_address(native_map_slot * native_code_map, uint32_t address, uint8_t * native_addr)
301 {
302 //FIXME: This probably isn't going to work with real code in a lot of cases, no guarantee that
303 //all the code in 1KB block is going to be translated at the same time
304 address &= 0xFFFFFF;
305 uint32_t chunk = address / NATIVE_CHUNK_SIZE;
306 if (!native_code_map[chunk].base) {
307 native_code_map[chunk].base = native_addr;
308 native_code_map[chunk].offsets = malloc(sizeof(uint16_t) * NATIVE_CHUNK_SIZE);
309 memset(native_code_map[chunk].offsets, 0xFF, sizeof(uint16_t) * NATIVE_CHUNK_SIZE);
310 }
311 uint32_t offset = address % NATIVE_CHUNK_SIZE;
312 native_code_map[chunk].offsets[offset] = native_addr-native_code_map[chunk].base;
313 }
314
315 uint8_t * translate_m68k_move(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
316 {
317 int8_t reg, flags_reg;
74 uint8_t dir = 0; 318 uint8_t dir = 0;
75 int32_t offset; 319 int32_t offset;
320 int32_t inc_amount, dec_amount;
321 x86_ea src;
322 dst = translate_m68k_src(inst, &src, dst, opts);
323 reg = native_reg(&(inst->dst), opts);
324 if (src.mode == MODE_REG_DIRECT) {
325 flags_reg = src.base;
326 } else {
327 if (reg >= 0) {
328 flags_reg = reg;
329 } else {
330 printf("moving %d to temp register %d\n", src.disp, SCRATCH1);
331 dst = mov_ir(dst, src.disp, SCRATCH1, SZ_D);
332 src.mode = MODE_REG_DIRECT;
333 flags_reg = src.base = SCRATCH1;
334 }
335 }
336 switch(inst->dst.addr_mode)
337 {
338 case MODE_REG:
339 case MODE_AREG:
340 if (reg >= 0) {
341 if (src.mode == MODE_REG_DIRECT) {
342 dst = mov_rr(dst, src.base, reg, inst->extra.size);
343 } else if (src.mode == MODE_REG_DISPLACE8) {
344 dst = mov_rdisp8r(dst, src.base, src.disp, reg, inst->extra.size);
345 } else {
346 dst = mov_ir(dst, src.disp, reg, inst->extra.size);
347 }
348 } else if(src.mode == MODE_REG_DIRECT) {
349 printf("mov_rrdisp8 from reg %d to offset %d from reg %d (%d)\n", src.base, (inst->dst.addr_mode == MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs)) + 4 * inst->dst.params.regs.pri, CONTEXT, inst->dst.params.regs.pri);
350 dst = mov_rrdisp8(dst, src.base, CONTEXT, (inst->dst.addr_mode == MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs)) + 4 * inst->dst.params.regs.pri, inst->extra.size);
351 } else {
352 dst = mov_irdisp8(dst, src.disp, CONTEXT, (inst->dst.addr_mode == MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs)) + 4 * inst->dst.params.regs.pri, inst->extra.size);
353 }
354 break;
355 case MODE_AREG_PREDEC:
356 dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : 1);
357 if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
358 dst = sub_ir(dst, dec_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D);
359 } else {
360 dst = sub_irdisp8(dst, dec_amount, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D);
361 }
362 case MODE_AREG_INDIRECT:
363 case MODE_AREG_POSTINC:
364 if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
365 dst = mov_rr(dst, opts->aregs[inst->dst.params.regs.pri], SCRATCH2, SZ_D);
366 } else {
367 dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SCRATCH2, SZ_D);
368 }
369 if (src.mode == MODE_REG_DIRECT) {
370 if (src.base != SCRATCH1) {
371 dst = mov_rr(dst, src.base, SCRATCH1, inst->extra.size);
372 }
373 } else if (src.mode == MODE_REG_DISPLACE8) {
374 dst = mov_rdisp8r(dst, src.base, src.disp, SCRATCH1, inst->extra.size);
375 } else {
376 dst = mov_ir(dst, src.disp, SCRATCH1, inst->extra.size);
377 }
378 switch (inst->extra.size)
379 {
380 case OPSIZE_BYTE:
381 dst = call(dst, (char *)m68k_write_byte);
382 break;
383 case OPSIZE_WORD:
384 dst = call(dst, (char *)m68k_write_word);
385 break;
386 case OPSIZE_LONG:
387 dst = call(dst, (char *)m68k_write_long_highfirst);
388 break;
389 }
390 if (inst->dst.addr_mode == MODE_AREG_POSTINC) {
391 inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : 1);
392 if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
393 dst = add_ir(dst, inc_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D);
394 } else {
395 dst = add_irdisp8(dst, inc_amount, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D);
396 }
397 }
398 break;
399 default:
400 printf("address mode %d not implemented (move dst)\n", inst->dst.addr_mode);
401 exit(1);
402 }
403
404 //add cycles for prefetch
405 dst = cycles(dst, BUS);
406 //update flags
407 dst = mov_ir(dst, 0, FLAG_V, SZ_B);
408 dst = mov_ir(dst, 0, FLAG_C, SZ_B);
409 dst = cmp_ir(dst, 0, flags_reg, inst->extra.size);
410 dst = setcc_r(dst, CC_Z, FLAG_Z);
411 dst = setcc_r(dst, CC_S, FLAG_N);
412 dst = check_cycles(dst);
413 return dst;
414 }
415
416 uint8_t * translate_m68k_lea(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
417 {
418 int8_t dst_reg = native_reg(&(inst->dst), opts);
419 switch(inst->src.addr_mode)
420 {
421 case MODE_AREG_INDIRECT:
422 dst = cycles(dst, BUS);
423 if (opts->aregs[inst->src.params.regs.pri] >= 0) {
424 if (dst_reg >= 0) {
425 dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], dst_reg, SZ_D);
426 } else {
427 dst = mov_rrdisp8(dst, opts->aregs[inst->src.params.regs.pri], CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D);
428 }
429 } else {
430 if (dst_reg >= 0) {
431 dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, dst_reg, SZ_D);
432 } else {
433 dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, SCRATCH1, SZ_D);
434 dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D);
435 }
436 }
437 dst = check_cycles(dst);
438 break;
439 case MODE_ABSOLUTE:
440 dst = cycles(dst, BUS);
441 dst = check_cycles(dst);
442 case MODE_ABSOLUTE_SHORT:
443 dst = cycles(dst, BUS);
444 dst = check_cycles(dst);
445 dst = cycles(dst, BUS);
446 if (dst_reg >= 0) {
447 dst = mov_ir(dst, inst->src.params.immed, dst_reg, SZ_D);
448 } else {
449 dst = mov_irdisp8(dst, inst->src.params.immed, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D);
450 }
451 dst = check_cycles(dst);
452 break;
453 }
454 return dst;
455 }
456
457 uint8_t * translate_m68k_bsr(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
458 {
459 //TODO: Add cycles
460 int32_t disp = inst->src.params.immed;
461 uint32_t after = inst->address + (inst->variant == VAR_BYTE ? 2 : (inst->variant == VAR_WORD ? 4 : 6));
462 dst = mov_ir(dst, after, SCRATCH1, SZ_D);
463 dst = push_r(dst, SCRATCH1);
464 dst = sub_ir(dst, 4, opts->aregs[7], SZ_D);
465 dst = mov_rr(dst, opts->aregs[7], SCRATCH2, SZ_D);
466 dst = call(dst, (char *)m68k_write_long_highfirst);
467 printf("bsr@%X: after=%X, disp=%X, dest=%X\n", inst->address, after, disp, after+disp);
468 uint8_t * dest_addr = get_native_address(opts->native_code_map, after + disp);
469 if (!dest_addr) {
470 opts->deferred = defer_address(opts->deferred, after + disp, dst + 1);
471 //dummy address to be replaced later
472 dest_addr = dst + 5;
473 }
474 dst = call(dst, (char *)dest_addr);
475 //would add_ir(dst, 8, RSP, SZ_Q) be faster here?
476 dst = pop_r(dst, SCRATCH1);
477 return dst;
478 }
479
480 uint8_t * translate_m68k_bcc(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
481 {
482 //TODO: Add cycles
483 int32_t disp = inst->src.params.immed;
484 uint32_t after = inst->address + (inst->variant == VAR_BYTE ? 2 : (inst->variant == VAR_WORD ? 4 : 6));
485 printf("bcc@%X: after=%X, disp=%X, dest=%X\n", inst->address, after, disp, after+disp);
486 uint8_t * dest_addr = get_native_address(opts->native_code_map, after + disp);
487 if (inst->extra.cond == COND_TRUE) {
488 if (!dest_addr) {
489 opts->deferred = defer_address(opts->deferred, after + disp, dst + 1);
490 //dummy address to be replaced later, make sure it generates a 4-byte displacement
491 dest_addr = dst + 256;
492 }
493 dst = jmp(dst, dest_addr);
494 } else {
495 uint8_t cond = CC_NZ;
496 switch (inst->extra.cond)
497 {
498 case COND_HIGH:
499 cond = CC_Z;
500 case COND_LOW_SAME:
501 dst = mov_rr(dst, FLAG_Z, SCRATCH1, SZ_B);
502 dst = or_rr(dst, FLAG_C, SCRATCH1, SZ_B);
503 break;
504 case COND_CARRY_CLR:
505 cond = CC_Z;
506 case COND_CARRY_SET:
507 dst = cmp_ir(dst, 0, FLAG_C, SZ_B);
508 break;
509 case COND_NOT_EQ:
510 cond = CC_Z;
511 case COND_EQ:
512 dst = cmp_ir(dst, 0, FLAG_Z, SZ_B);
513 break;
514 case COND_OVERF_CLR:
515 cond = CC_Z;
516 case COND_OVERF_SET:
517 dst = cmp_ir(dst, 0, FLAG_V, SZ_B);
518 break;
519 case COND_PLUS:
520 cond = CC_Z;
521 case COND_MINUS:
522 dst = cmp_ir(dst, 0, FLAG_N, SZ_B);
523 break;
524 case COND_GREATER_EQ:
525 cond = CC_Z;
526 case COND_LESS:
527 dst = cmp_rr(dst, FLAG_N, FLAG_V, SZ_B);
528 break;
529 case COND_GREATER:
530 cond = CC_Z;
531 case COND_LESS_EQ:
532 dst = mov_rr(dst, FLAG_V, SCRATCH1, SZ_B);
533 dst = xor_rr(dst, FLAG_N, SCRATCH1, SZ_B);
534 dst = or_rr(dst, FLAG_Z, SCRATCH1, SZ_B);
535 break;
536 }
537 if (!dest_addr) {
538 opts->deferred = defer_address(opts->deferred, after + disp, dst + 2);
539 //dummy address to be replaced later, make sure it generates a 4-byte displacement
540 dest_addr = dst + 256;
541 }
542 dst = jcc(dst, cond, dest_addr);
543 }
544 return dst;
545 }
546
547 uint8_t * translate_m68k_rts(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
548 {
549 //TODO: Add cycles
550 dst = mov_rr(dst, opts->aregs[7], SCRATCH1, SZ_D);
551 dst = add_ir(dst, 4, opts->aregs[7], SZ_D);
552 dst = call(dst, (char *)m68k_read_long_scratch1);
553 dst = cmp_rdisp8r(dst, RSP, 8, SCRATCH1, SZ_D);
554 dst = jcc(dst, CC_NZ, dst+3);
555 dst = retn(dst);
556 dst = jmp(dst, (char *)m68k_modified_ret_addr);
557 return dst;
558 }
559
560 uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
561 {
562 map_native_address(opts->native_code_map, inst->address, dst);
563 if (inst->op == M68K_MOVE) {
564 return translate_m68k_move(dst, inst, opts);
565 } else if(inst->op == M68K_LEA) {
566 return translate_m68k_lea(dst, inst, opts);
567 } else if(inst->op == M68K_BSR) {
568 return translate_m68k_bsr(dst, inst, opts);
569 } else if(inst->op == M68K_BCC) {
570 return translate_m68k_bcc(dst, inst, opts);
571 } else if(inst->op == M68K_RTS) {
572 return translate_m68k_rts(dst, inst, opts);
573 }
574 x86_ea src_op, dst_op;
575 if (inst->src.addr_mode != MODE_UNUSED) {
576 dst = translate_m68k_src(inst, &src_op, dst, opts);
577 }
578 if (inst->dst.addr_mode != MODE_UNUSED) {
579 dst = translate_m68k_dst(inst, &dst_op, dst, opts);
580 }
76 switch(inst->op) 581 switch(inst->op)
77 { 582 {
78 case M68K_ABCD: 583 case M68K_ABCD:
584 break;
79 case M68K_ADD: 585 case M68K_ADD:
586 dst = cycles(dst, BUS);
587 if (src_op.mode == MODE_REG_DIRECT) {
588 if (dst_op.mode == MODE_REG_DIRECT) {
589 dst = add_rr(dst, src_op.base, dst_op.base, inst->extra.size);
590 } else {
591 dst = add_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, inst->extra.size);
592 }
593 } else if (src_op.mode == MODE_REG_DISPLACE8) {
594 dst = add_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, inst->extra.size);
595 } else {
596 if (dst_op.mode == MODE_REG_DIRECT) {
597 dst = add_ir(dst, src_op.disp, dst_op.base, inst->extra.size);
598 } else {
599 dst = add_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size);
600 }
601 }
602 dst = setcc_r(dst, CC_C, FLAG_C);
603 dst = setcc_r(dst, CC_Z, FLAG_Z);
604 dst = setcc_r(dst, CC_S, FLAG_N);
605 dst = setcc_r(dst, CC_O, FLAG_V);
606 dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B);
607 dst = check_cycles(dst);
608 break;
80 case M68K_ADDX: 609 case M68K_ADDX:
81 case M68K_AND: 610 case M68K_AND:
82 case M68K_ANDI_CCR: 611 case M68K_ANDI_CCR:
83 case M68K_ANDI_SR: 612 case M68K_ANDI_SR:
84 case M68K_ASL: 613 case M68K_ASL:
90 case M68K_BSR: 619 case M68K_BSR:
91 case M68K_BTST: 620 case M68K_BTST:
92 case M68K_CHK: 621 case M68K_CHK:
93 case M68K_CLR: 622 case M68K_CLR:
94 case M68K_CMP: 623 case M68K_CMP:
624 dst = cycles(dst, BUS);
625 if (src_op.mode == MODE_REG_DIRECT) {
626 if (dst_op.mode == MODE_REG_DIRECT) {
627 dst = cmp_rr(dst, src_op.base, dst_op.base, inst->extra.size);
628 } else {
629 dst = cmp_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, inst->extra.size);
630 }
631 } else if (src_op.mode == MODE_REG_DISPLACE8) {
632 dst = cmp_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, inst->extra.size);
633 } else {
634 if (dst_op.mode == MODE_REG_DIRECT) {
635 dst = cmp_ir(dst, src_op.disp, dst_op.base, inst->extra.size);
636 } else {
637 dst = cmp_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size);
638 }
639 }
640 dst = setcc_r(dst, CC_C, FLAG_C);
641 dst = setcc_r(dst, CC_Z, FLAG_Z);
642 dst = setcc_r(dst, CC_S, FLAG_N);
643 dst = setcc_r(dst, CC_O, FLAG_V);
644 dst = check_cycles(dst);
645 break;
95 case M68K_DBCC: 646 case M68K_DBCC:
96 case M68K_DIVS: 647 case M68K_DIVS:
97 case M68K_DIVU: 648 case M68K_DIVU:
98 case M68K_EOR: 649 case M68K_EOR:
99 case M68K_EORI_CCR: 650 case M68K_EORI_CCR:
100 case M68K_EORI_SR: 651 case M68K_EORI_SR:
101 case M68K_EXG: 652 case M68K_EXG:
653 dst = cycles(dst, 6);
654 if (dst_op.mode == MODE_REG_DIRECT) {
655 dst = mov_rr(dst, dst_op.base, SCRATCH2, SZ_D);
656 if (src_op.mode == MODE_REG_DIRECT) {
657 dst = mov_rr(dst, src_op.base, dst_op.base, SZ_D);
658 dst = mov_rr(dst, SCRATCH2, src_op.base, SZ_D);
659 } else {
660 dst = mov_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, SZ_D);
661 dst = mov_rrdisp8(dst, SCRATCH2, src_op.base, src_op.disp, SZ_D);
662 }
663 } else {
664 dst = mov_rdisp8r(dst, dst_op.base, dst_op.disp, SCRATCH2, SZ_D);
665 if (src_op.mode == MODE_REG_DIRECT) {
666 dst = mov_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, SZ_D);
667 dst = mov_rr(dst, SCRATCH2, src_op.base, SZ_D);
668 } else {
669 dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH1, SZ_D);
670 dst = mov_rrdisp8(dst, SCRATCH1, dst_op.base, dst_op.disp, SZ_D);
671 dst = mov_rrdisp8(dst, SCRATCH2, src_op.base, src_op.disp, SZ_D);
672 }
673 }
674 dst = check_cycles(dst);
675 break;
102 case M68K_EXT: 676 case M68K_EXT:
103 case M68K_ILLEGAL: 677 case M68K_ILLEGAL:
678 dst = call(dst, (uint8_t *)m68k_save_context);
679 dst = mov_rr(dst, CONTEXT, RDI, SZ_Q);
680 dst = call(dst, (uint8_t *)print_regs_exit);
681 break;
104 case M68K_JMP: 682 case M68K_JMP:
105 case M68K_JSR: 683 case M68K_JSR:
106 case M68K_LEA: 684 case M68K_LEA:
107 case M68K_LINK: 685 case M68K_LINK:
108 case M68K_LSL: 686 case M68K_LSL:
109 case M68K_LSR: 687 case M68K_LSR:
110 case M68K_MOVE:
111
112 if ((inst->src.addr_mode == MODE_REG || inst->src.addr_mode == MODE_AREG || (inst->src.addr_mode == MODE_IMMEDIATE && inst->src.variant == VAR_QUICK)) && (inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG)) {
113 dst = cycles(dst, BUS);
114 reg_a = native_reg(&(inst->src), opts);
115 reg_b = native_reg(&(inst->dst), opts);
116 dst = cycles(dst, BUS);
117 if (reg_a >= 0 && reg_b >= 0) {
118 dst = mov_rr(dst, reg_a, reg_b, inst->extra.size);
119 flags_reg = reg_b;
120 } else if(reg_a >= 0) {
121 offset = inst->dst.addr_mode == MODE_REG ? offsetof(m68k_context, dregs) : offsetof(m68k_context, aregs);
122 dst = mov_rrdisp8(dst, reg_a, CONTEXT, offset + 4 * inst->dst.params.regs.pri, inst->extra.size);
123 flags_reg = reg_a;
124 } else if(reg_b >= 0) {
125 if (inst->src.addr_mode == MODE_REG) {
126 dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + 4 * inst->src.params.regs.pri, reg_b, inst->extra.size);
127 } else if(inst->src.addr_mode == MODE_AREG) {
128 dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, reg_b, inst->extra.size);
129 } else {
130 dst = mov_i32r(dst, inst->src.params.u32, reg_b);
131 }
132 flags_reg = reg_b;
133 } else {
134
135 }
136 dst = mov_i8r(dst, 0, FLAG_V);
137 dst = mov_i8r(dst, 0, FLAG_C);
138 switch (inst->extra.size)
139 {
140 case OPSIZE_BYTE:
141 dst = cmp_i8r(dst, 0, reg_b, SZ_B);
142 break;
143 case OPSIZE_WORD:
144 dst = cmp_i8r(dst, 0, reg_b, SZ_W);
145 break;
146 case OPSIZE_LONG:
147 dst = cmp_i8r(dst, 0, reg_b, SZ_D);
148 break;
149 }
150 dst = setcc_r(dst, CC_Z, FLAG_Z);
151 dst = setcc_r(dst, CC_S, FLAG_N);
152 dst = check_cycles(dst);
153 }
154
155 if (reg_a >= 0 && reg_b >= 0) {
156 dst = cycles(dst, BUS);
157 dst = mov_rr(dst, reg_a, reg_b, inst->extra.size);
158 dst = mov_i8r(dst, 0, FLAG_V);
159 dst = mov_i8r(dst, 0, FLAG_C);
160 switch (inst->extra.size)
161 {
162 case OPSIZE_BYTE:
163 dst = cmp_i8r(dst, 0, reg_b, SZ_B);
164 break;
165 case OPSIZE_WORD:
166 dst = cmp_i8r(dst, 0, reg_b, SZ_W);
167 break;
168 case OPSIZE_LONG:
169 dst = cmp_i8r(dst, 0, reg_b, SZ_D);
170 break;
171 }
172 dst = setcc_r(dst, CC_Z, FLAG_Z);
173 dst = setcc_r(dst, CC_S, FLAG_N);
174 dst = check_cycles(dst);
175 } else if(reg_a >= 0 || reg_b >= 0) {
176 if (reg_a >= 0) {
177 switch (inst->dst.addr_mode)
178 {
179 case MODE_REG:
180 dst = cycles(dst, BUS);
181 dst = mov_rr(dst, reg_a, reg_b, inst->extra.size);
182 dst = check_cycles(dst);
183 break;
184 case MODE_AREG:
185 break;
186 }
187 } else {
188 }
189 }
190 break;
191 case M68K_MOVE_CCR: 688 case M68K_MOVE_CCR:
192 case M68K_MOVE_FROM_SR: 689 case M68K_MOVE_FROM_SR:
193 case M68K_MOVE_SR: 690 case M68K_MOVE_SR:
194 case M68K_MOVE_USP: 691 case M68K_MOVE_USP:
195 case M68K_MOVEM: 692 case M68K_MOVEM:
215 case M68K_RTS: 712 case M68K_RTS:
216 case M68K_SBCD: 713 case M68K_SBCD:
217 case M68K_SCC: 714 case M68K_SCC:
218 case M68K_STOP: 715 case M68K_STOP:
219 case M68K_SUB: 716 case M68K_SUB:
717 dst = cycles(dst, BUS);
718 if (src_op.mode == MODE_REG_DIRECT) {
719 if (dst_op.mode == MODE_REG_DIRECT) {
720 dst = sub_rr(dst, src_op.base, dst_op.base, inst->extra.size);
721 } else {
722 dst = sub_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, inst->extra.size);
723 }
724 } else if (src_op.mode == MODE_REG_DISPLACE8) {
725 dst = sub_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, inst->extra.size);
726 } else {
727 if (dst_op.mode == MODE_REG_DIRECT) {
728 dst = sub_ir(dst, src_op.disp, dst_op.base, inst->extra.size);
729 } else {
730 dst = sub_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size);
731 }
732 }
733 dst = setcc_r(dst, CC_C, FLAG_C);
734 dst = setcc_r(dst, CC_Z, FLAG_Z);
735 dst = setcc_r(dst, CC_S, FLAG_N);
736 dst = setcc_r(dst, CC_O, FLAG_V);
737 dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B);
738 dst = check_cycles(dst);
739 break;
220 case M68K_SUBX: 740 case M68K_SUBX:
221 case M68K_SWAP: 741 case M68K_SWAP:
222 case M68K_TAS: 742 case M68K_TAS:
223 case M68K_TRAP: 743 case M68K_TRAP:
224 case M68K_TRAPV: 744 case M68K_TRAPV:
225 case M68K_TST: 745 case M68K_TST:
226 case M68K_UNLK: 746 case M68K_UNLK:
227 case M68K_INVALID: 747 case M68K_INVALID:
228 break; 748 break;
229 } 749 }
230 } 750 return dst;
231 751 }
752
753 uint8_t * translate_m68k_stream(uint8_t * dst, uint8_t * dst_end, uint32_t address, m68k_context * context)
754 {
755 m68kinst instbuf;
756 x86_68k_options * opts = context->options;
757 char disbuf[1024];
758 uint16_t *encoded = context->mem_pointers[0] + address/2, *next;
759 do {
760 do {
761 if (dst_end-dst < 128) {
762 puts("out of code memory");
763 exit(1);
764 }
765 next = m68k_decode(encoded, &instbuf, address);
766 address += (next-encoded)*2;
767 encoded = next;
768 m68k_disasm(&instbuf, disbuf);
769 printf("%X: %s\n", instbuf.address, disbuf);
770 dst = translate_m68k(dst, &instbuf, opts);
771 } while(instbuf.op != M68K_ILLEGAL && instbuf.op != M68K_RTS && instbuf.op != M68K_RTE && !(instbuf.op == M68K_BCC && instbuf.extra.cond == COND_TRUE) && instbuf.op != M68K_JMP);
772 process_deferred(opts);
773 if (opts->deferred) {
774 address = opts->deferred->address;
775 encoded = context->mem_pointers[0] + address/2;
776 } else {
777 encoded = NULL;
778 }
779 } while(encoded != NULL);
780 return dst;
781 }
782
783 void start_68k_context(m68k_context * context, uint32_t address)
784 {
785 uint8_t * addr = get_native_address(context->native_code_map, address);
786 m68k_start_context(addr, context);
787 }
788
789 void init_x86_68k_opts(x86_68k_options * opts)
790 {
791 opts->flags = 0;
792 for (int i = 0; i < 8; i++)
793 opts->dregs[i] = opts->aregs[i] = -1;
794 opts->dregs[0] = R10;
795 opts->dregs[1] = R11;
796 opts->dregs[2] = R12;
797 opts->aregs[0] = R13;
798 opts->aregs[1] = R14;
799 opts->aregs[7] = R15;
800 opts->native_code_map = malloc(sizeof(native_map_slot) * NATIVE_MAP_CHUNKS);
801 memset(opts->native_code_map, 0, sizeof(native_map_slot) * NATIVE_MAP_CHUNKS);
802 opts->deferred = NULL;
803 }
804
805 void init_68k_context(m68k_context * context, native_map_slot * native_code_map, void * opts)
806 {
807 memset(context, 0, sizeof(m68k_context));
808 context->native_code_map = native_code_map;
809 context->options = opts;
810 }
811