Mercurial > repos > blastem
comparison m68k_to_x86.c @ 193:c66e4636f991
Implement support for self-modifying code
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Tue, 15 Jan 2013 00:14:36 -0800 |
parents | 1db07e112bf7 |
children | 811163790e6c |
comparison
equal
deleted
inserted
replaced
192:1db07e112bf7 | 193:c66e4636f991 |
---|---|
42 void m68k_modified_ret_addr(); | 42 void m68k_modified_ret_addr(); |
43 void m68k_native_addr(); | 43 void m68k_native_addr(); |
44 void m68k_native_addr_and_sync(); | 44 void m68k_native_addr_and_sync(); |
45 void m68k_trap(); | 45 void m68k_trap(); |
46 void m68k_invalid(); | 46 void m68k_invalid(); |
47 void m68k_retrans_stub(); | |
47 void set_sr(); | 48 void set_sr(); |
48 void set_ccr(); | 49 void set_ccr(); |
49 void get_sr(); | 50 void get_sr(); |
50 void do_sync(); | 51 void do_sync(); |
51 void m68k_start_context(uint8_t * addr, m68k_context * context); | 52 void m68k_start_context(uint8_t * addr, m68k_context * context); |
677 } | 678 } |
678 | 679 |
679 uint8_t * get_native_address(native_map_slot * native_code_map, uint32_t address) | 680 uint8_t * get_native_address(native_map_slot * native_code_map, uint32_t address) |
680 { | 681 { |
681 address &= 0xFFFFFF; | 682 address &= 0xFFFFFF; |
682 if (address > 0x400000) { | |
683 printf("get_native_address: %X\n", address); | |
684 } | |
685 address /= 2; | 683 address /= 2; |
686 uint32_t chunk = address / NATIVE_CHUNK_SIZE; | 684 uint32_t chunk = address / NATIVE_CHUNK_SIZE; |
687 if (!native_code_map[chunk].base) { | 685 if (!native_code_map[chunk].base) { |
688 return NULL; | 686 return NULL; |
689 } | 687 } |
690 uint32_t offset = address % NATIVE_CHUNK_SIZE; | 688 uint32_t offset = address % NATIVE_CHUNK_SIZE; |
689 if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET || native_code_map[chunk].offsets[offset] == EXTENSION_WORD) { | |
690 return NULL; | |
691 } | |
692 return native_code_map[chunk].base + native_code_map[chunk].offsets[offset]; | |
693 } | |
694 | |
695 uint32_t get_instruction_start(native_map_slot * native_code_map, uint32_t address) | |
696 { | |
697 address &= 0xFFFFFF; | |
698 address /= 2; | |
699 uint32_t chunk = address / NATIVE_CHUNK_SIZE; | |
700 if (!native_code_map[chunk].base) { | |
701 return 0; | |
702 } | |
703 uint32_t offset = address % NATIVE_CHUNK_SIZE; | |
691 if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET) { | 704 if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET) { |
692 return NULL; | 705 return 0; |
693 } | 706 } |
694 return native_code_map[chunk].base + native_code_map[chunk].offsets[offset]; | 707 while (native_code_map[chunk].offsets[offset] == EXTENSION_WORD) { |
708 --address; | |
709 chunk = address / NATIVE_CHUNK_SIZE; | |
710 offset = address % NATIVE_CHUNK_SIZE; | |
711 } | |
712 return address*2; | |
695 } | 713 } |
696 | 714 |
697 deferred_addr * defer_address(deferred_addr * old_head, uint32_t address, uint8_t *dest) | 715 deferred_addr * defer_address(deferred_addr * old_head, uint32_t address, uint8_t *dest) |
698 { | 716 { |
699 deferred_addr * new_head = malloc(sizeof(deferred_addr)); | 717 deferred_addr * new_head = malloc(sizeof(deferred_addr)); |
753 native_code_map[chunk].offsets = malloc(sizeof(int32_t) * NATIVE_CHUNK_SIZE); | 771 native_code_map[chunk].offsets = malloc(sizeof(int32_t) * NATIVE_CHUNK_SIZE); |
754 memset(native_code_map[chunk].offsets, 0xFF, sizeof(int32_t) * NATIVE_CHUNK_SIZE); | 772 memset(native_code_map[chunk].offsets, 0xFF, sizeof(int32_t) * NATIVE_CHUNK_SIZE); |
755 } | 773 } |
756 uint32_t offset = address % NATIVE_CHUNK_SIZE; | 774 uint32_t offset = address % NATIVE_CHUNK_SIZE; |
757 native_code_map[chunk].offsets[offset] = native_addr-native_code_map[chunk].base; | 775 native_code_map[chunk].offsets[offset] = native_addr-native_code_map[chunk].base; |
776 for(address++,size-=2; size; address++,size-=2) { | |
777 chunk = address / NATIVE_CHUNK_SIZE; | |
778 offset = address % NATIVE_CHUNK_SIZE; | |
779 if (!native_code_map[chunk].base) { | |
780 native_code_map[chunk].base = native_addr; | |
781 native_code_map[chunk].offsets = malloc(sizeof(int32_t) * NATIVE_CHUNK_SIZE); | |
782 memset(native_code_map[chunk].offsets, 0xFF, sizeof(int32_t) * NATIVE_CHUNK_SIZE); | |
783 } | |
784 native_code_map[chunk].offsets[offset] = EXTENSION_WORD; | |
785 } | |
786 } | |
787 | |
788 uint8_t get_native_inst_size(x86_68k_options * opts, uint32_t address) | |
789 { | |
790 if (address < 0xE00000) { | |
791 return 0; | |
792 } | |
793 uint32_t slot = (address & 0xFFFF)/1024; | |
794 return opts->ram_inst_sizes[slot][((address & 0xFFFF)/2)%512]; | |
758 } | 795 } |
759 | 796 |
760 uint8_t * translate_m68k_move(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) | 797 uint8_t * translate_m68k_move(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) |
761 { | 798 { |
762 int8_t reg, flags_reg, sec_reg; | 799 int8_t reg, flags_reg, sec_reg; |
3609 printf("attempt to translate non-memory address: %X\n", address); | 3646 printf("attempt to translate non-memory address: %X\n", address); |
3610 exit(1); | 3647 exit(1); |
3611 } | 3648 } |
3612 do { | 3649 do { |
3613 do { | 3650 do { |
3614 if (dst_end-dst < 128) { | 3651 if (dst_end-dst < MAX_NATIVE_SIZE) { |
3615 if (dst_end-dst < 5) { | 3652 if (dst_end-dst < 5) { |
3616 puts("out of code memory, not enough space for jmp to next chunk"); | 3653 puts("out of code memory, not enough space for jmp to next chunk"); |
3617 exit(1); | 3654 exit(1); |
3618 } | 3655 } |
3619 size_t size = 1024*1024; | 3656 size_t size = 1024*1024; |
3669 if (!ret) { | 3706 if (!ret) { |
3670 translate_m68k_stream(address, context); | 3707 translate_m68k_stream(address, context); |
3671 ret = get_native_address(context->native_code_map, address); | 3708 ret = get_native_address(context->native_code_map, address); |
3672 } | 3709 } |
3673 return ret; | 3710 return ret; |
3711 } | |
3712 | |
3713 void * m68k_retranslate_inst(uint32_t address, m68k_context * context) | |
3714 { | |
3715 x86_68k_options * opts = context->options; | |
3716 uint8_t orig_size = get_native_inst_size(opts, address); | |
3717 uint8_t * orig_start = get_native_address(context->native_code_map, address); | |
3718 uint32_t orig = address; | |
3719 address &= 0xFFFF; | |
3720 uint8_t * dst = opts->cur_code; | |
3721 uint8_t * dst_end = opts->code_end; | |
3722 uint16_t *after, *inst = context->mem_pointers[1] + address/2; | |
3723 m68kinst instbuf; | |
3724 after = m68k_decode(inst, &instbuf, orig); | |
3725 if (orig_size != MAX_NATIVE_SIZE) { | |
3726 if (dst_end - dst < 128) { | |
3727 size_t size = 1024*1024; | |
3728 dst = alloc_code(&size); | |
3729 opts->code_end = dst_end = dst + size; | |
3730 opts->cur_code = dst; | |
3731 } | |
3732 uint8_t * native_end = translate_m68k(dst, &instbuf, opts); | |
3733 if ((native_end - dst) <= orig_size) { | |
3734 native_end = translate_m68k(orig_start, &instbuf, opts); | |
3735 while (native_end < orig_start + orig_size) { | |
3736 *(native_end++) = 0x90; //NOP | |
3737 } | |
3738 return orig_start; | |
3739 } else { | |
3740 map_native_address(context, instbuf.address, dst, (after-inst)*2, MAX_NATIVE_SIZE); | |
3741 opts->code_end = dst+MAX_NATIVE_SIZE; | |
3742 if (instbuf.op != M68K_RTS && instbuf.op != M68K_RTE && instbuf.op != M68K_RTR && instbuf.op != M68K_JMP && (instbuf.op != M68K_BCC || instbuf.extra.cond != COND_TRUE)) { | |
3743 jmp(native_end, get_native_address(context->native_code_map, address + (after-inst)*2)); | |
3744 } | |
3745 return dst; | |
3746 } | |
3747 } else { | |
3748 dst = translate_m68k(orig_start, &instbuf, opts); | |
3749 if (instbuf.op != M68K_RTS && instbuf.op != M68K_RTE && instbuf.op != M68K_RTR && instbuf.op != M68K_JMP && (instbuf.op != M68K_BCC || instbuf.extra.cond != COND_TRUE)) { | |
3750 dst = jmp(dst, get_native_address(context->native_code_map, address + (after-inst)*2)); | |
3751 } | |
3752 return orig_start; | |
3753 } | |
3754 } | |
3755 | |
3756 m68k_context * m68k_handle_code_write(uint32_t address, m68k_context * context) | |
3757 { | |
3758 uint32_t inst_start = get_instruction_start(context->native_code_map, address | 0xFF0000); | |
3759 if (inst_start) { | |
3760 uint8_t * dst = get_native_address(context->native_code_map, inst_start); | |
3761 dst = mov_ir(dst, inst_start, SCRATCH2, SZ_D); | |
3762 dst = jmp(dst, (uint8_t *)m68k_retrans_stub); | |
3763 } | |
3764 return context; | |
3674 } | 3765 } |
3675 | 3766 |
3676 void insert_breakpoint(m68k_context * context, uint32_t address, uint8_t * bp_handler) | 3767 void insert_breakpoint(m68k_context * context, uint32_t address, uint8_t * bp_handler) |
3677 { | 3768 { |
3678 static uint8_t * bp_stub = NULL; | 3769 static uint8_t * bp_stub = NULL; |
3758 opts->deferred = NULL; | 3849 opts->deferred = NULL; |
3759 size_t size = 1024 * 1024; | 3850 size_t size = 1024 * 1024; |
3760 opts->cur_code = alloc_code(&size); | 3851 opts->cur_code = alloc_code(&size); |
3761 opts->code_end = opts->cur_code + size; | 3852 opts->code_end = opts->cur_code + size; |
3762 opts->ram_inst_sizes = malloc(sizeof(uint8_t *) * 64); | 3853 opts->ram_inst_sizes = malloc(sizeof(uint8_t *) * 64); |
3854 memset(opts->ram_inst_sizes, 0, sizeof(uint8_t *) * 64); | |
3763 } | 3855 } |
3764 | 3856 |
3765 void init_68k_context(m68k_context * context, native_map_slot * native_code_map, void * opts) | 3857 void init_68k_context(m68k_context * context, native_map_slot * native_code_map, void * opts) |
3766 { | 3858 { |
3767 memset(context, 0, sizeof(m68k_context)); | 3859 memset(context, 0, sizeof(m68k_context)); |