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[] = {