Mercurial > repos > blastem
comparison m68k_to_x86.c @ 92:c3d034e076ee
Fix some bugs in emulation of CLR
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Thu, 27 Dec 2012 10:40:03 -0800 |
parents | 60b5c9e2f4e0 |
children | f63b0e58e2d5 |
comparison
equal
deleted
inserted
replaced
91:8c446fc19cc0 | 92:c3d034e076ee |
---|---|
316 exit(1); | 316 exit(1); |
317 } | 317 } |
318 return out; | 318 return out; |
319 } | 319 } |
320 | 320 |
321 uint8_t * translate_m68k_dst(m68kinst * inst, x86_ea * ea, uint8_t * out, x86_68k_options * opts) | 321 uint8_t * translate_m68k_dst(m68kinst * inst, x86_ea * ea, uint8_t * out, x86_68k_options * opts, uint8_t fake_read) |
322 { | 322 { |
323 int8_t reg = native_reg(&(inst->dst), opts); | 323 int8_t reg = native_reg(&(inst->dst), opts); |
324 int32_t dec_amount, inc_amount; | 324 int32_t dec_amount, inc_amount; |
325 if (reg >= 0) { | 325 if (reg >= 0) { |
326 ea->mode = MODE_REG_DIRECT; | 326 ea->mode = MODE_REG_DIRECT; |
342 } else { | 342 } else { |
343 out = sub_irdisp8(out, dec_amount, CONTEXT, reg_offset(&(inst->dst)), SZ_D); | 343 out = sub_irdisp8(out, dec_amount, CONTEXT, reg_offset(&(inst->dst)), SZ_D); |
344 } | 344 } |
345 case MODE_AREG_INDIRECT: | 345 case MODE_AREG_INDIRECT: |
346 case MODE_AREG_POSTINC: | 346 case MODE_AREG_POSTINC: |
347 if (opts->aregs[inst->dst.params.regs.pri] >= 0) { | 347 if (fake_read) { |
348 out = mov_rr(out, opts->aregs[inst->dst.params.regs.pri], SCRATCH1, SZ_D); | 348 out = cycles(out, inst->extra.size == OPSIZE_LONG ? 8 : 4); |
349 } else { | 349 } else { |
350 out = mov_rdisp8r(out, CONTEXT, reg_offset(&(inst->dst)), SCRATCH1, SZ_D); | 350 if (opts->aregs[inst->dst.params.regs.pri] >= 0) { |
351 } | 351 out = mov_rr(out, opts->aregs[inst->dst.params.regs.pri], SCRATCH1, SZ_D); |
352 switch (inst->extra.size) | 352 } else { |
353 { | 353 out = mov_rdisp8r(out, CONTEXT, reg_offset(&(inst->dst)), SCRATCH1, SZ_D); |
354 case OPSIZE_BYTE: | 354 } |
355 out = call(out, (char *)m68k_read_byte_scratch1); | 355 switch (inst->extra.size) |
356 break; | 356 { |
357 case OPSIZE_WORD: | 357 case OPSIZE_BYTE: |
358 out = call(out, (char *)m68k_read_word_scratch1); | 358 out = call(out, (char *)m68k_read_byte_scratch1); |
359 break; | 359 break; |
360 case OPSIZE_LONG: | 360 case OPSIZE_WORD: |
361 out = call(out, (char *)m68k_read_long_scratch1); | 361 out = call(out, (char *)m68k_read_word_scratch1); |
362 break; | 362 break; |
363 case OPSIZE_LONG: | |
364 out = call(out, (char *)m68k_read_long_scratch1); | |
365 break; | |
366 } | |
363 } | 367 } |
364 //save reg value in SCRATCH2 so we can use it to save the result in memory later | 368 //save reg value in SCRATCH2 so we can use it to save the result in memory later |
365 if (opts->aregs[inst->dst.params.regs.pri] >= 0) { | 369 if (opts->aregs[inst->dst.params.regs.pri] >= 0) { |
366 out = mov_rr(out, opts->aregs[inst->dst.params.regs.pri], SCRATCH2, SZ_D); | 370 out = mov_rr(out, opts->aregs[inst->dst.params.regs.pri], SCRATCH2, SZ_D); |
367 } else { | 371 } else { |
378 } | 382 } |
379 ea->mode = MODE_REG_DIRECT; | 383 ea->mode = MODE_REG_DIRECT; |
380 ea->base = SCRATCH1; | 384 ea->base = SCRATCH1; |
381 break; | 385 break; |
382 case MODE_AREG_DISPLACE: | 386 case MODE_AREG_DISPLACE: |
383 out = cycles(out, BUS); | 387 out = cycles(out, fake_read ? BUS+(inst->extra.size == OPSIZE_LONG ? BUS*2 : BUS) : BUS); |
388 reg = fake_read ? SCRATCH2 : SCRATCH1; | |
384 if (opts->aregs[inst->dst.params.regs.pri] >= 0) { | 389 if (opts->aregs[inst->dst.params.regs.pri] >= 0) { |
385 out = mov_rr(out, opts->aregs[inst->dst.params.regs.pri], SCRATCH1, SZ_D); | 390 out = mov_rr(out, opts->aregs[inst->dst.params.regs.pri], reg, SZ_D); |
386 } else { | 391 } else { |
387 out = mov_rdisp8r(out, CONTEXT, reg_offset(&(inst->dst)), SCRATCH1, SZ_D); | 392 out = mov_rdisp8r(out, CONTEXT, reg_offset(&(inst->dst)), reg, SZ_D); |
388 } | 393 } |
389 out = add_ir(out, inst->dst.params.regs.displacement, SCRATCH1, SZ_D); | 394 out = add_ir(out, inst->dst.params.regs.displacement, reg, SZ_D); |
390 out = push_r(out, SCRATCH1); | 395 if (!fake_read) { |
391 switch (inst->extra.size) | 396 out = push_r(out, SCRATCH1); |
392 { | 397 switch (inst->extra.size) |
393 case OPSIZE_BYTE: | 398 { |
394 out = call(out, (char *)m68k_read_byte_scratch1); | 399 case OPSIZE_BYTE: |
395 break; | 400 out = call(out, (char *)m68k_read_byte_scratch1); |
396 case OPSIZE_WORD: | 401 break; |
397 out = call(out, (char *)m68k_read_word_scratch1); | 402 case OPSIZE_WORD: |
398 break; | 403 out = call(out, (char *)m68k_read_word_scratch1); |
399 case OPSIZE_LONG: | 404 break; |
400 out = call(out, (char *)m68k_read_long_scratch1); | 405 case OPSIZE_LONG: |
401 break; | 406 out = call(out, (char *)m68k_read_long_scratch1); |
402 } | 407 break; |
403 out = pop_r(out, SCRATCH2); | 408 } |
409 out = pop_r(out, SCRATCH2); | |
410 } | |
404 ea->mode = MODE_REG_DIRECT; | 411 ea->mode = MODE_REG_DIRECT; |
405 ea->base = SCRATCH1; | 412 ea->base = SCRATCH1; |
406 break; | 413 break; |
407 case MODE_PC_DISPLACE: | 414 case MODE_PC_DISPLACE: |
408 out = cycles(out, BUS); | 415 out = cycles(out, fake_read ? BUS+(inst->extra.size == OPSIZE_LONG ? BUS*2 : BUS) : BUS); |
409 out = mov_ir(out, inst->dst.params.regs.displacement + inst->address+2, SCRATCH1, SZ_D); | 416 out = mov_ir(out, inst->dst.params.regs.displacement + inst->address+2, fake_read ? SCRATCH2 : SCRATCH1, SZ_D); |
410 out = push_r(out, SCRATCH1); | 417 if (!fake_read) { |
411 switch (inst->extra.size) | 418 out = push_r(out, SCRATCH1); |
412 { | 419 switch (inst->extra.size) |
413 case OPSIZE_BYTE: | 420 { |
414 out = call(out, (char *)m68k_read_byte_scratch1); | 421 case OPSIZE_BYTE: |
415 break; | 422 out = call(out, (char *)m68k_read_byte_scratch1); |
416 case OPSIZE_WORD: | 423 break; |
417 out = call(out, (char *)m68k_read_word_scratch1); | 424 case OPSIZE_WORD: |
418 break; | 425 out = call(out, (char *)m68k_read_word_scratch1); |
419 case OPSIZE_LONG: | 426 break; |
420 out = call(out, (char *)m68k_read_long_scratch1); | 427 case OPSIZE_LONG: |
421 break; | 428 out = call(out, (char *)m68k_read_long_scratch1); |
422 } | 429 break; |
423 out = pop_r(out, SCRATCH2); | 430 } |
431 out = pop_r(out, SCRATCH2); | |
432 } | |
424 ea->mode = MODE_REG_DIRECT; | 433 ea->mode = MODE_REG_DIRECT; |
425 ea->base = SCRATCH1; | 434 ea->base = SCRATCH1; |
426 break; | 435 break; |
427 case MODE_ABSOLUTE: | 436 case MODE_ABSOLUTE: |
428 case MODE_ABSOLUTE_SHORT: | 437 case MODE_ABSOLUTE_SHORT: |
429 //Add cycles for reading address from instruction stream | 438 //Add cycles for reading address from instruction stream |
430 if (inst->dst.addr_mode == MODE_ABSOLUTE) { | 439 out = cycles(out, (inst->dst.addr_mode == MODE_ABSOLUTE ? BUS*2 : BUS) + (fake_read ? (inst->extra.size == OPSIZE_LONG ? BUS*2 : BUS) : 0)); |
431 out = cycles(out, BUS*2); | 440 out = mov_ir(out, inst->dst.params.immed, fake_read ? SCRATCH2 : SCRATCH1, SZ_D); |
432 } else { | 441 if (!fake_read) { |
433 out = cycles(out, BUS); | 442 out = push_r(out, SCRATCH1); |
434 } | 443 switch (inst->extra.size) |
435 out = mov_ir(out, inst->dst.params.immed, SCRATCH1, SZ_D); | 444 { |
436 out = push_r(out, SCRATCH1); | 445 case OPSIZE_BYTE: |
437 switch (inst->extra.size) | 446 out = call(out, (char *)m68k_read_byte_scratch1); |
438 { | 447 break; |
439 case OPSIZE_BYTE: | 448 case OPSIZE_WORD: |
440 out = call(out, (char *)m68k_read_byte_scratch1); | 449 out = call(out, (char *)m68k_read_word_scratch1); |
441 break; | 450 break; |
442 case OPSIZE_WORD: | 451 case OPSIZE_LONG: |
443 out = call(out, (char *)m68k_read_word_scratch1); | 452 out = call(out, (char *)m68k_read_long_scratch1); |
444 break; | 453 break; |
445 case OPSIZE_LONG: | 454 } |
446 out = call(out, (char *)m68k_read_long_scratch1); | 455 out = pop_r(out, SCRATCH2); |
447 break; | 456 } |
448 } | |
449 out = pop_r(out, SCRATCH2); | |
450 ea->mode = MODE_REG_DIRECT; | 457 ea->mode = MODE_REG_DIRECT; |
451 ea->base = SCRATCH1; | 458 ea->base = SCRATCH1; |
452 break; | 459 break; |
453 default: | 460 default: |
454 printf("address mode %d not implemented (dst)\n", inst->dst.addr_mode); | 461 printf("address mode %d not implemented (dst)\n", inst->dst.addr_mode); |
876 { | 883 { |
877 dst = mov_ir(dst, 0, FLAG_N, SZ_B); | 884 dst = mov_ir(dst, 0, FLAG_N, SZ_B); |
878 dst = mov_ir(dst, 0, FLAG_V, SZ_B); | 885 dst = mov_ir(dst, 0, FLAG_V, SZ_B); |
879 dst = mov_ir(dst, 0, FLAG_C, SZ_B); | 886 dst = mov_ir(dst, 0, FLAG_C, SZ_B); |
880 dst = mov_ir(dst, 1, FLAG_Z, SZ_B); | 887 dst = mov_ir(dst, 1, FLAG_Z, SZ_B); |
881 uint8_t reg = native_reg(&(inst->dst), opts); | 888 int8_t reg = native_reg(&(inst->dst), opts); |
882 if (reg >= 0) { | 889 if (reg >= 0) { |
883 dst = cycles(dst, (inst->extra.size == OPSIZE_LONG ? 6 : 4)); | 890 dst = cycles(dst, (inst->extra.size == OPSIZE_LONG ? 6 : 4)); |
884 return xor_rr(dst, reg, reg, inst->extra.size); | 891 return xor_rr(dst, reg, reg, inst->extra.size); |
885 } | 892 } |
886 int32_t dec_amount,inc_amount; | 893 x86_ea dst_op; |
887 switch (inst->dst.addr_mode) | 894 dst = translate_m68k_dst(inst, &dst_op, dst, opts, 1); |
888 { | 895 if (dst_op.mode == MODE_REG_DIRECT) { |
889 case MODE_REG: | 896 dst = xor_rr(dst, dst_op.base, dst_op.base, inst->extra.size); |
890 case MODE_AREG: | 897 } else { |
891 dst = cycles(dst, (inst->extra.size == OPSIZE_LONG ? 6 : 4)); | 898 dst = mov_irdisp8(dst, 0, dst_op.base, dst_op.disp, inst->extra.size); |
892 dst = mov_irdisp8(dst, 0, CONTEXT, reg_offset(&(inst->dst)), inst->extra.size); | 899 } |
893 break; | 900 dst = m68k_save_result(inst, dst, opts); |
894 case MODE_AREG_PREDEC: | |
895 dst = cycles(dst, PREDEC_PENALTY); | |
896 dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : 1); | |
897 if (opts->aregs[inst->dst.params.regs.pri] >= 0) { | |
898 dst = sub_ir(dst, dec_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D); | |
899 } else { | |
900 dst = sub_irdisp8(dst, dec_amount, CONTEXT, reg_offset(&(inst->dst)), SZ_D); | |
901 } | |
902 case MODE_AREG_INDIRECT: | |
903 case MODE_AREG_POSTINC: | |
904 //add cycles for prefetch and wasted read | |
905 dst = cycles(dst, (inst->extra.size == OPSIZE_LONG ? 12 : 8)); | |
906 if (opts->aregs[inst->dst.params.regs.pri] >= 0) { | |
907 dst = mov_rr(dst, opts->aregs[inst->dst.params.regs.pri], SCRATCH2, SZ_D); | |
908 } else { | |
909 dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->dst)), SCRATCH2, SZ_D); | |
910 } | |
911 dst = xor_rr(dst, SCRATCH1, SCRATCH1, SZ_D); | |
912 switch (inst->extra.size) | |
913 { | |
914 case OPSIZE_BYTE: | |
915 dst = call(dst, (char *)m68k_write_byte); | |
916 break; | |
917 case OPSIZE_WORD: | |
918 dst = call(dst, (char *)m68k_write_word); | |
919 break; | |
920 case OPSIZE_LONG: | |
921 dst = call(dst, (char *)m68k_write_long_highfirst); | |
922 break; | |
923 } | |
924 if (inst->dst.addr_mode == MODE_AREG_POSTINC) { | |
925 inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : 1); | |
926 if (opts->aregs[inst->dst.params.regs.pri] >= 0) { | |
927 dst = add_ir(dst, inc_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D); | |
928 } else { | |
929 dst = add_irdisp8(dst, inc_amount, CONTEXT, reg_offset(&(inst->dst)), SZ_D); | |
930 } | |
931 } | |
932 break; | |
933 default: | |
934 printf("address mode %d not implemented (clr dst)\n", inst->dst.addr_mode); | |
935 exit(1); | |
936 } | |
937 return dst; | 901 return dst; |
938 } | 902 } |
939 | 903 |
940 uint8_t * translate_m68k_lea(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) | 904 uint8_t * translate_m68k_lea(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) |
941 { | 905 { |
1450 x86_ea src_op, dst_op; | 1414 x86_ea src_op, dst_op; |
1451 if (inst->src.addr_mode != MODE_UNUSED) { | 1415 if (inst->src.addr_mode != MODE_UNUSED) { |
1452 dst = translate_m68k_src(inst, &src_op, dst, opts); | 1416 dst = translate_m68k_src(inst, &src_op, dst, opts); |
1453 } | 1417 } |
1454 if (inst->dst.addr_mode != MODE_UNUSED) { | 1418 if (inst->dst.addr_mode != MODE_UNUSED) { |
1455 dst = translate_m68k_dst(inst, &dst_op, dst, opts); | 1419 dst = translate_m68k_dst(inst, &dst_op, dst, opts, 0); |
1456 } | 1420 } |
1457 switch(inst->op) | 1421 switch(inst->op) |
1458 { | 1422 { |
1459 //case M68K_ABCD: | 1423 //case M68K_ABCD: |
1460 // break; | 1424 // break; |