Mercurial > repos > blastem
comparison genesis.c @ 1111:2eb54e24914e
Mostly working changes to allow support for multiple emulated system types in main blastem program
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Mon, 19 Dec 2016 13:28:18 -0800 |
parents | 87114df913ec |
children | 45db303fc705 |
comparison
equal
deleted
inserted
replaced
1110:d1eed3b1121c | 1111:2eb54e24914e |
---|---|
7 #include "blastem.h" | 7 #include "blastem.h" |
8 #include <stdlib.h> | 8 #include <stdlib.h> |
9 #include "render.h" | 9 #include "render.h" |
10 #include "gst.h" | 10 #include "gst.h" |
11 #include "util.h" | 11 #include "util.h" |
12 #include "debug.h" | |
13 #include "gdb_remote.h" | |
12 #define MCLKS_NTSC 53693175 | 14 #define MCLKS_NTSC 53693175 |
13 #define MCLKS_PAL 53203395 | 15 #define MCLKS_PAL 53203395 |
14 | 16 |
15 uint32_t MCLKS_PER_68K; | 17 uint32_t MCLKS_PER_68K; |
16 #define MCLKS_PER_YM 7 | 18 #define MCLKS_PER_YM 7 |
25 | 27 |
26 #define MAX_SOUND_CYCLES 100000 | 28 #define MAX_SOUND_CYCLES 100000 |
27 | 29 |
28 uint16_t read_dma_value(uint32_t address) | 30 uint16_t read_dma_value(uint32_t address) |
29 { | 31 { |
32 genesis_context *genesis = (genesis_context *)current_system; | |
30 //addresses here are word addresses (i.e. bit 0 corresponds to A1), so no need to do multiply by 2 | 33 //addresses here are word addresses (i.e. bit 0 corresponds to A1), so no need to do multiply by 2 |
31 uint16_t *ptr = get_native_pointer(address*2, (void **)genesis->m68k->mem_pointers, &genesis->m68k->options->gen); | 34 uint16_t *ptr = get_native_pointer(address*2, (void **)genesis->m68k->mem_pointers, &genesis->m68k->options->gen); |
32 if (ptr) { | 35 if (ptr) { |
33 return *ptr; | 36 return *ptr; |
34 } | 37 } |
36 return 0; | 39 return 0; |
37 } | 40 } |
38 | 41 |
39 uint16_t get_open_bus_value() | 42 uint16_t get_open_bus_value() |
40 { | 43 { |
44 genesis_context *genesis = (genesis_context *)current_system; | |
41 return read_dma_value(genesis->m68k->last_prefetch_address/2); | 45 return read_dma_value(genesis->m68k->last_prefetch_address/2); |
42 } | 46 } |
43 | 47 |
44 void adjust_int_cycle(m68k_context * context, vdp_context * v_context) | 48 void adjust_int_cycle(m68k_context * context, vdp_context * v_context) |
45 { | 49 { |
171 exit(0); | 175 exit(0); |
172 } | 176 } |
173 } | 177 } |
174 | 178 |
175 vdp_adjust_cycles(v_context, mclks); | 179 vdp_adjust_cycles(v_context, mclks); |
176 io_adjust_cycles(gen->ports, context->current_cycle, mclks); | 180 io_adjust_cycles(gen->io.ports, context->current_cycle, mclks); |
177 io_adjust_cycles(gen->ports+1, context->current_cycle, mclks); | 181 io_adjust_cycles(gen->io.ports+1, context->current_cycle, mclks); |
178 io_adjust_cycles(gen->ports+2, context->current_cycle, mclks); | 182 io_adjust_cycles(gen->io.ports+2, context->current_cycle, mclks); |
179 context->current_cycle -= mclks; | 183 context->current_cycle -= mclks; |
180 z80_adjust_cycles(z_context, mclks); | 184 z80_adjust_cycles(z_context, mclks); |
181 gen->ym->current_cycle -= mclks; | 185 gen->ym->current_cycle -= mclks; |
182 gen->psg->cycles -= mclks; | 186 gen->psg->cycles -= mclks; |
183 if (gen->ym->write_cycle != CYCLE_NEVER) { | 187 if (gen->ym->write_cycle != CYCLE_NEVER) { |
190 if (context->int_ack) { | 194 if (context->int_ack) { |
191 //printf("acknowledging %d @ %d:%d, vcounter: %d, hslot: %d\n", context->int_ack, context->current_cycle, v_context->cycles, v_context->vcounter, v_context->hslot); | 195 //printf("acknowledging %d @ %d:%d, vcounter: %d, hslot: %d\n", context->int_ack, context->current_cycle, v_context->cycles, v_context->vcounter, v_context->hslot); |
192 vdp_int_ack(v_context); | 196 vdp_int_ack(v_context); |
193 context->int_ack = 0; | 197 context->int_ack = 0; |
194 } | 198 } |
195 if (!address && (break_on_sync || gen->save_state)) { | 199 if (!address && (gen->header.enter_debugger || gen->header.save_state)) { |
196 context->sync_cycle = context->current_cycle + 1; | 200 context->sync_cycle = context->current_cycle + 1; |
197 } | 201 } |
198 adjust_int_cycle(context, v_context); | 202 adjust_int_cycle(context, v_context); |
199 if (address) { | 203 if (address) { |
200 if (break_on_sync) { | 204 if (gen->header.enter_debugger) { |
201 break_on_sync = 0; | 205 gen->header.enter_debugger = 0; |
202 debugger(context, address); | 206 debugger(context, address); |
203 } | 207 } |
204 if (gen->save_state && (z_context->pc || (!z_context->reset && !z_context->busreq))) { | 208 if (gen->header.save_state && (z_context->pc || (!z_context->reset && !z_context->busreq))) { |
205 uint8_t slot = gen->save_state - 1; | 209 uint8_t slot = gen->header.save_state - 1; |
206 gen->save_state = 0; | 210 gen->header.save_state = 0; |
207 //advance Z80 core to the start of an instruction | 211 //advance Z80 core to the start of an instruction |
208 while (!z_context->pc) | 212 while (!z_context->pc) |
209 { | 213 { |
210 sync_z80(z_context, z_context->current_cycle + MCLKS_PER_Z80); | 214 sync_z80(z_context, z_context->current_cycle + MCLKS_PER_Z80); |
211 } | 215 } |
213 if (slot == QUICK_SAVE_SLOT) { | 217 if (slot == QUICK_SAVE_SLOT) { |
214 save_path = save_state_path; | 218 save_path = save_state_path; |
215 } else { | 219 } else { |
216 char slotname[] = "slot_0.gst"; | 220 char slotname[] = "slot_0.gst"; |
217 slotname[5] = '0' + slot; | 221 slotname[5] = '0' + slot; |
218 char const *parts[] = {gen->save_dir, PATH_SEP, slotname}; | 222 char const *parts[] = {gen->header.save_dir, PATH_SEP, slotname}; |
219 save_path = alloc_concat_m(3, parts); | 223 save_path = alloc_concat_m(3, parts); |
220 } | 224 } |
221 save_gst(gen, save_path, address); | 225 save_gst(gen, save_path, address); |
222 printf("Saved state to %s\n", save_path); | 226 printf("Saved state to %s\n", save_path); |
223 if (slot != QUICK_SAVE_SLOT) { | 227 if (slot != QUICK_SAVE_SLOT) { |
224 free(save_path); | 228 free(save_path); |
225 } | 229 } |
226 } else if(gen->save_state) { | 230 } else if(gen->header.save_state) { |
227 context->sync_cycle = context->current_cycle + 1; | 231 context->sync_cycle = context->current_cycle + 1; |
228 } | 232 } |
229 } | 233 } |
230 #ifdef REFRESH_EMULATION | 234 #ifdef REFRESH_EMULATION |
231 last_sync_cycle = context->current_cycle; | 235 last_sync_cycle = context->current_cycle; |
484 location &= 0x1FFF; | 488 location &= 0x1FFF; |
485 if (location < 0x100) { | 489 if (location < 0x100) { |
486 switch(location/2) | 490 switch(location/2) |
487 { | 491 { |
488 case 0x1: | 492 case 0x1: |
489 io_data_write(gen->ports, value, context->current_cycle); | 493 io_data_write(gen->io.ports, value, context->current_cycle); |
490 break; | 494 break; |
491 case 0x2: | 495 case 0x2: |
492 io_data_write(gen->ports+1, value, context->current_cycle); | 496 io_data_write(gen->io.ports+1, value, context->current_cycle); |
493 break; | 497 break; |
494 case 0x3: | 498 case 0x3: |
495 io_data_write(gen->ports+2, value, context->current_cycle); | 499 io_data_write(gen->io.ports+2, value, context->current_cycle); |
496 break; | 500 break; |
497 case 0x4: | 501 case 0x4: |
498 gen->ports[0].control = value; | 502 gen->io.ports[0].control = value; |
499 break; | 503 break; |
500 case 0x5: | 504 case 0x5: |
501 gen->ports[1].control = value; | 505 gen->io.ports[1].control = value; |
502 break; | 506 break; |
503 case 0x6: | 507 case 0x6: |
504 gen->ports[2].control = value; | 508 gen->io.ports[2].control = value; |
505 break; | 509 break; |
506 } | 510 } |
507 } else { | 511 } else { |
508 if (location == 0x1100) { | 512 if (location == 0x1100) { |
509 if (value & 1) { | 513 if (value & 1) { |
595 case 0x0: | 599 case 0x0: |
596 //version bits should be 0 for now since we're not emulating TMSS | 600 //version bits should be 0 for now since we're not emulating TMSS |
597 value = gen->version_reg; | 601 value = gen->version_reg; |
598 break; | 602 break; |
599 case 0x1: | 603 case 0x1: |
600 value = io_data_read(gen->ports, context->current_cycle); | 604 value = io_data_read(gen->io.ports, context->current_cycle); |
601 break; | 605 break; |
602 case 0x2: | 606 case 0x2: |
603 value = io_data_read(gen->ports+1, context->current_cycle); | 607 value = io_data_read(gen->io.ports+1, context->current_cycle); |
604 break; | 608 break; |
605 case 0x3: | 609 case 0x3: |
606 value = io_data_read(gen->ports+2, context->current_cycle); | 610 value = io_data_read(gen->io.ports+2, context->current_cycle); |
607 break; | 611 break; |
608 case 0x4: | 612 case 0x4: |
609 value = gen->ports[0].control; | 613 value = gen->io.ports[0].control; |
610 break; | 614 break; |
611 case 0x5: | 615 case 0x5: |
612 value = gen->ports[1].control; | 616 value = gen->io.ports[1].control; |
613 break; | 617 break; |
614 case 0x6: | 618 case 0x6: |
615 value = gen->ports[2].control; | 619 value = gen->io.ports[2].control; |
616 break; | 620 break; |
617 default: | 621 default: |
618 value = 0xFF; | 622 value = 0xFF; |
619 } | 623 } |
620 } else { | 624 } else { |
735 } | 739 } |
736 | 740 |
737 return context; | 741 return context; |
738 } | 742 } |
739 | 743 |
740 void set_speed_percent(genesis_context * context, uint32_t percent) | 744 static void set_speed_percent(system_header * system, uint32_t percent) |
741 { | 745 { |
746 genesis_context *context = (genesis_context *)system; | |
742 uint32_t old_clock = context->master_clock; | 747 uint32_t old_clock = context->master_clock; |
743 context->master_clock = ((uint64_t)context->normal_clock * (uint64_t)percent) / 100; | 748 context->master_clock = ((uint64_t)context->normal_clock * (uint64_t)percent) / 100; |
744 while (context->ym->current_cycle != context->psg->cycles) { | 749 while (context->ym->current_cycle != context->psg->cycles) { |
745 sync_sound(context, context->psg->cycles + MCLKS_PER_PSG); | 750 sync_sound(context, context->psg->cycles + MCLKS_PER_PSG); |
746 } | 751 } |
770 gen->normal_clock = MCLKS_PAL; | 775 gen->normal_clock = MCLKS_PAL; |
771 } else { | 776 } else { |
772 gen->normal_clock = MCLKS_NTSC; | 777 gen->normal_clock = MCLKS_NTSC; |
773 } | 778 } |
774 gen->master_clock = gen->normal_clock; | 779 gen->master_clock = gen->normal_clock; |
780 } | |
781 | |
782 static void start_genesis(system_header *system, char *statefile) | |
783 { | |
784 genesis_context *gen = (genesis_context *)system; | |
785 set_keybindings(&gen->io); | |
786 if (statefile) { | |
787 uint32_t pc = load_gst(gen, statefile); | |
788 if (!pc) { | |
789 fatal_error("Failed to load save state %s\n", statefile); | |
790 } | |
791 printf("Loaded %s\n", statefile); | |
792 if (gen->header.enter_debugger) { | |
793 gen->header.enter_debugger = 0; | |
794 insert_breakpoint(gen->m68k, pc, gen->header.debugger_type == DEBUGGER_NATIVE ? debugger : gdb_debug_enter); | |
795 } | |
796 adjust_int_cycle(gen->m68k, gen->vdp); | |
797 start_68k_context(gen->m68k, pc); | |
798 } else { | |
799 if (gen->header.enter_debugger) { | |
800 gen->header.enter_debugger = 0; | |
801 uint32_t address = gen->cart[2] << 16 | gen->cart[3]; | |
802 insert_breakpoint(gen->m68k, address, gen->header.debugger_type == DEBUGGER_NATIVE ? debugger : gdb_debug_enter); | |
803 } | |
804 m68k_reset(gen->m68k); | |
805 } | |
806 } | |
807 | |
808 static void resume_genesis(system_header *system) | |
809 { | |
810 genesis_context *gen = (genesis_context *)system; | |
811 map_all_bindings(&gen->io); | |
812 resume_68k(gen->m68k); | |
813 } | |
814 | |
815 static void inc_debug_mode(system_header *system) | |
816 { | |
817 genesis_context *gen = (genesis_context *)system; | |
818 gen->vdp->debug++; | |
819 if (gen->vdp->debug == 7) { | |
820 gen->vdp->debug = 0; | |
821 } | |
822 } | |
823 | |
824 static void inc_debug_pal(system_header *system) | |
825 { | |
826 genesis_context *gen = (genesis_context *)system; | |
827 gen->vdp->debug_pal++; | |
828 if (gen->vdp->debug_pal == 4) { | |
829 gen->vdp->debug_pal = 0; | |
830 } | |
831 } | |
832 | |
833 static void request_exit(system_header *system) | |
834 { | |
835 genesis_context *gen = (genesis_context *)system; | |
836 gen->m68k->should_return = 1; | |
837 } | |
838 | |
839 static void persist_save(system_header *system) | |
840 { | |
841 genesis_context *gen = (genesis_context *)system; | |
842 if (gen->save_type == SAVE_NONE) { | |
843 return; | |
844 } | |
845 FILE * f = fopen(save_filename, "wb"); | |
846 if (!f) { | |
847 fprintf(stderr, "Failed to open %s file %s for writing\n", gen->save_type == SAVE_I2C ? "EEPROM" : "SRAM", save_filename); | |
848 return; | |
849 } | |
850 fwrite(gen->save_storage, 1, gen->save_size, f); | |
851 fclose(f); | |
852 printf("Saved %s to %s\n", gen->save_type == SAVE_I2C ? "EEPROM" : "SRAM", save_filename); | |
853 } | |
854 | |
855 static void load_save(system_header *system) | |
856 { | |
857 genesis_context *gen = (genesis_context *)system; | |
858 FILE * f = fopen(save_filename, "rb"); | |
859 if (f) { | |
860 uint32_t read = fread(gen->save_storage, 1, gen->save_size, f); | |
861 fclose(f); | |
862 if (read > 0) { | |
863 printf("Loaded %s from %s\n", gen->save_type == SAVE_I2C ? "EEPROM" : "SRAM", save_filename); | |
864 } | |
865 } | |
866 } | |
867 | |
868 static void free_genesis(system_header *system) | |
869 { | |
870 genesis_context *gen = (genesis_context *)system; | |
871 vdp_free(gen->vdp); | |
872 m68k_options_free(gen->m68k->options); | |
873 free(gen->m68k); | |
874 free(gen->work_ram); | |
875 z80_options_free(gen->z80->options); | |
876 free(gen->z80); | |
877 free(gen->zram); | |
878 ym_free(gen->ym); | |
879 psg_free(gen->psg); | |
880 free(gen->save_storage); | |
881 free(gen->header.save_dir); | |
882 free(gen->lock_on); | |
775 } | 883 } |
776 | 884 |
777 genesis_context *alloc_init_genesis(rom_info *rom, void *main_rom, void *lock_on, uint32_t ym_opts, uint8_t force_region) | 885 genesis_context *alloc_init_genesis(rom_info *rom, void *main_rom, void *lock_on, uint32_t ym_opts, uint8_t force_region) |
778 { | 886 { |
779 static memmap_chunk z80_map[] = { | 887 static memmap_chunk z80_map[] = { |
782 { 0x4000, 0x6000, 0x0003, 0, 0, 0, NULL, NULL, NULL, z80_read_ym, z80_write_ym}, | 890 { 0x4000, 0x6000, 0x0003, 0, 0, 0, NULL, NULL, NULL, z80_read_ym, z80_write_ym}, |
783 { 0x6000, 0x6100, 0xFFFF, 0, 0, 0, NULL, NULL, NULL, NULL, z80_write_bank_reg}, | 891 { 0x6000, 0x6100, 0xFFFF, 0, 0, 0, NULL, NULL, NULL, NULL, z80_write_bank_reg}, |
784 { 0x7F00, 0x8000, 0x00FF, 0, 0, 0, NULL, NULL, NULL, z80_vdp_port_read, z80_vdp_port_write} | 892 { 0x7F00, 0x8000, 0x00FF, 0, 0, 0, NULL, NULL, NULL, z80_vdp_port_read, z80_vdp_port_write} |
785 }; | 893 }; |
786 genesis_context *gen = calloc(1, sizeof(genesis_context)); | 894 genesis_context *gen = calloc(1, sizeof(genesis_context)); |
895 gen->header.set_speed_percent = set_speed_percent; | |
896 gen->header.start_context = start_genesis; | |
897 gen->header.resume_context = resume_genesis; | |
898 gen->header.load_save = load_save; | |
899 gen->header.persist_save = persist_save; | |
900 gen->header.free_context = free_genesis; | |
901 gen->header.request_exit = request_exit; | |
902 gen->header.inc_debug_mode = inc_debug_mode; | |
903 gen->header.inc_debug_pal = inc_debug_pal; | |
787 set_region(gen, rom, force_region); | 904 set_region(gen, rom, force_region); |
788 | 905 |
789 gen->vdp = malloc(sizeof(vdp_context)); | 906 gen->vdp = malloc(sizeof(vdp_context)); |
790 init_vdp_context(gen->vdp, gen->version_reg & 0x40); | 907 init_vdp_context(gen->vdp, gen->version_reg & 0x40); |
791 gen->frame_end = vdp_cycles_to_frame_end(gen->vdp); | 908 gen->frame_end = vdp_cycles_to_frame_end(gen->vdp); |
851 opts->gen.flags |= M68K_OPT_BROKEN_READ_MODIFY; | 968 opts->gen.flags |= M68K_OPT_BROKEN_READ_MODIFY; |
852 gen->m68k = init_68k_context(opts, NULL); | 969 gen->m68k = init_68k_context(opts, NULL); |
853 gen->m68k->system = gen; | 970 gen->m68k->system = gen; |
854 | 971 |
855 return gen; | 972 return gen; |
856 } | |
857 | |
858 | |
859 | |
860 void free_genesis(genesis_context *gen) | |
861 { | |
862 vdp_free(gen->vdp); | |
863 m68k_options_free(gen->m68k->options); | |
864 free(gen->m68k); | |
865 free(gen->work_ram); | |
866 z80_options_free(gen->z80->options); | |
867 free(gen->z80); | |
868 free(gen->zram); | |
869 ym_free(gen->ym); | |
870 psg_free(gen->psg); | |
871 free(gen->save_storage); | |
872 free(gen->save_dir); | |
873 free(gen->lock_on); | |
874 } | |
875 | |
876 void start_genesis(genesis_context *gen, char *statefile, uint8_t *debugger) | |
877 { | |
878 | |
879 if (statefile) { | |
880 uint32_t pc = load_gst(gen, statefile); | |
881 if (!pc) { | |
882 fatal_error("Failed to load save state %s\n", statefile); | |
883 } | |
884 printf("Loaded %s\n", statefile); | |
885 if (debugger) { | |
886 insert_breakpoint(gen->m68k, pc, debugger); | |
887 } | |
888 adjust_int_cycle(gen->m68k, gen->vdp); | |
889 start_68k_context(gen->m68k, pc); | |
890 } else { | |
891 if (debugger) { | |
892 uint32_t address = gen->cart[2] << 16 | gen->cart[3]; | |
893 insert_breakpoint(gen->m68k, address, debugger); | |
894 } | |
895 m68k_reset(gen->m68k); | |
896 } | |
897 } | 973 } |
898 | 974 |
899 genesis_context *alloc_config_genesis(void *rom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, uint32_t ym_opts, uint8_t force_region, rom_info *info_out) | 975 genesis_context *alloc_config_genesis(void *rom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, uint32_t ym_opts, uint8_t force_region, rom_info *info_out) |
900 { | 976 { |
901 static memmap_chunk base_map[] = { | 977 static memmap_chunk base_map[] = { |