Mercurial > repos > blastem
comparison blastem.c @ 874:b6842dfb8edf
ROM is now run after being selected in menu. Initial path for menu is read from config file.
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 08 Nov 2015 18:38:33 -0800 |
parents | 7022ba865cfd |
children | 54ffba3768d6 |
comparison
equal
deleted
inserted
replaced
873:91bf4d905eba | 874:b6842dfb8edf |
---|---|
302 fatal_error("machine freeze due to write to address %X\n", 0xC00000 | vdp_port); | 302 fatal_error("machine freeze due to write to address %X\n", 0xC00000 | vdp_port); |
303 } | 303 } |
304 vdp_port &= 0x1F; | 304 vdp_port &= 0x1F; |
305 //printf("vdp_port write: %X, value: %X, cycle: %d\n", vdp_port, value, context->current_cycle); | 305 //printf("vdp_port write: %X, value: %X, cycle: %d\n", vdp_port, value, context->current_cycle); |
306 sync_components(context, 0); | 306 sync_components(context, 0); |
307 vdp_context * v_context = context->video_context; | |
308 genesis_context * gen = context->system; | 307 genesis_context * gen = context->system; |
308 vdp_context *v_context = gen->vdp; | |
309 if (vdp_port < 0x10) { | 309 if (vdp_port < 0x10) { |
310 int blocked; | 310 int blocked; |
311 uint32_t before_cycle = v_context->cycles; | 311 uint32_t before_cycle = v_context->cycles; |
312 if (vdp_port < 4) { | 312 if (vdp_port < 4) { |
313 | 313 |
404 fatal_error("machine freeze due to read from address %X\n", 0xC00000 | vdp_port); | 404 fatal_error("machine freeze due to read from address %X\n", 0xC00000 | vdp_port); |
405 } | 405 } |
406 vdp_port &= 0x1F; | 406 vdp_port &= 0x1F; |
407 uint16_t value; | 407 uint16_t value; |
408 sync_components(context, 0); | 408 sync_components(context, 0); |
409 vdp_context * v_context = context->video_context; | 409 genesis_context *gen = context->system; |
410 vdp_context * v_context = gen->vdp; | |
410 uint32_t before_cycle = v_context->cycles; | 411 uint32_t before_cycle = v_context->cycles; |
411 if (vdp_port < 0x10) { | 412 if (vdp_port < 0x10) { |
412 if (vdp_port < 4) { | 413 if (vdp_port < 4) { |
413 value = vdp_data_port_read(v_context); | 414 value = vdp_data_port_read(v_context); |
414 } else if(vdp_port < 8) { | 415 } else if(vdp_port < 8) { |
793 (read_16_fun)io_read_w, (write_16_fun)io_write_w, | 794 (read_16_fun)io_read_w, (write_16_fun)io_write_w, |
794 (read_8_fun)io_read, (write_8_fun)io_write} | 795 (read_8_fun)io_read, (write_8_fun)io_write} |
795 }; | 796 }; |
796 | 797 |
797 char * save_filename; | 798 char * save_filename; |
798 genesis_context * genesis; | 799 genesis_context *genesis; |
800 genesis_context *menu_context; | |
801 genesis_context *game_context; | |
799 void persist_save() | 802 void persist_save() |
800 { | 803 { |
801 FILE * f = fopen(save_filename, "wb"); | 804 FILE * f = fopen(save_filename, "wb"); |
802 if (!f) { | 805 if (!f) { |
803 fprintf(stderr, "Failed to open %s file %s for writing\n", genesis->save_type == SAVE_I2C ? "EEPROM" : "SRAM", save_filename); | 806 fprintf(stderr, "Failed to open %s file %s for writing\n", genesis->save_type == SAVE_I2C ? "EEPROM" : "SRAM", save_filename); |
806 fwrite(genesis->save_storage, 1, genesis->save_size, f); | 809 fwrite(genesis->save_storage, 1, genesis->save_size, f); |
807 fclose(f); | 810 fclose(f); |
808 printf("Saved %s to %s\n", genesis->save_type == SAVE_I2C ? "EEPROM" : "SRAM", save_filename); | 811 printf("Saved %s to %s\n", genesis->save_type == SAVE_I2C ? "EEPROM" : "SRAM", save_filename); |
809 } | 812 } |
810 | 813 |
811 void init_run_cpu(genesis_context * gen, rom_info *rom, FILE * address_log, char * statefile, uint8_t * debugger) | 814 #ifndef NO_Z80 |
812 { | 815 const memmap_chunk z80_map[] = { |
813 m68k_options opts; | 816 { 0x0000, 0x4000, 0x1FFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, z80_ram, NULL, NULL, NULL, NULL }, |
814 | 817 { 0x8000, 0x10000, 0x7FFF, 0, 0, NULL, NULL, NULL, z80_read_bank, z80_write_bank}, |
818 { 0x4000, 0x6000, 0x0003, 0, 0, NULL, NULL, NULL, z80_read_ym, z80_write_ym}, | |
819 { 0x6000, 0x6100, 0xFFFF, 0, 0, NULL, NULL, NULL, NULL, z80_write_bank_reg}, | |
820 { 0x7F00, 0x8000, 0x00FF, 0, 0, NULL, NULL, NULL, z80_vdp_port_read, z80_vdp_port_write} | |
821 }; | |
822 #endif | |
823 | |
824 genesis_context *alloc_init_genesis(rom_info *rom, int fps, uint32_t ym_opts) | |
825 { | |
826 genesis_context *gen = calloc(1, sizeof(genesis_context)); | |
827 gen->master_clock = gen->normal_clock = fps == 60 ? MCLKS_NTSC : MCLKS_PAL; | |
828 | |
829 gen->vdp = malloc(sizeof(vdp_context)); | |
830 init_vdp_context(gen->vdp, version_reg & 0x40); | |
831 gen->frame_end = vdp_cycles_to_frame_end(gen->vdp); | |
832 char * config_cycles = tern_find_path(config, "clocks\0max_cycles\0").ptrval; | |
833 gen->max_cycles = config_cycles ? atoi(config_cycles) : DEFAULT_SYNC_INTERVAL; | |
834 | |
835 gen->ym = malloc(sizeof(ym2612_context)); | |
836 ym_init(gen->ym, render_sample_rate(), gen->master_clock, MCLKS_PER_YM, render_audio_buffer(), ym_opts); | |
837 | |
838 gen->psg = malloc(sizeof(psg_context)); | |
839 psg_init(gen->psg, render_sample_rate(), gen->master_clock, MCLKS_PER_PSG, render_audio_buffer()); | |
840 | |
841 gen->z80 = calloc(1, sizeof(z80_context)); | |
842 #ifndef NO_Z80 | |
843 z80_options *z_opts = malloc(sizeof(z80_options)); | |
844 init_z80_opts(z_opts, z80_map, 5, NULL, 0, MCLKS_PER_Z80); | |
845 init_z80_context(gen->z80, z_opts); | |
846 z80_assert_reset(gen->z80, 0); | |
847 #endif | |
848 | |
849 gen->z80->system = gen; | |
850 gen->z80->mem_pointers[0] = z80_ram; | |
851 gen->z80->mem_pointers[1] = gen->z80->mem_pointers[2] = (uint8_t *)cart; | |
852 | |
853 gen->work_ram = ram; | |
854 gen->zram = z80_ram; | |
855 setup_io_devices(config, gen->ports); | |
856 | |
857 gen->save_type = rom->save_type; | |
815 gen->save_type = rom->save_type; | 858 gen->save_type = rom->save_type; |
816 if (gen->save_type != SAVE_NONE) { | 859 if (gen->save_type != SAVE_NONE) { |
817 gen->save_ram_mask = rom->save_mask; | 860 gen->save_ram_mask = rom->save_mask; |
818 gen->save_size = rom->save_size; | 861 gen->save_size = rom->save_size; |
819 gen->save_storage = rom->save_buffer; | 862 gen->save_storage = rom->save_buffer; |
833 } | 876 } |
834 } else { | 877 } else { |
835 gen->save_storage = NULL; | 878 gen->save_storage = NULL; |
836 } | 879 } |
837 | 880 |
838 init_m68k_opts(&opts, rom->map, rom->map_chunks, MCLKS_PER_68K); | 881 m68k_options *opts = malloc(sizeof(m68k_options)); |
839 opts.address_log = address_log; | 882 init_m68k_opts(opts, rom->map, rom->map_chunks, MCLKS_PER_68K); |
840 opts.gen.flags |= M68K_OPT_BROKEN_READ_MODIFY; | 883 //TODO: make this configurable |
841 m68k_context *context = init_68k_context(&opts); | 884 opts->gen.flags |= M68K_OPT_BROKEN_READ_MODIFY; |
842 gen->m68k = context; | 885 gen->m68k = init_68k_context(opts); |
843 | 886 gen->m68k->system = gen; |
844 context->video_context = gen->vdp; | 887 |
845 context->system = gen; | |
846 for (int i = 0; i < rom->map_chunks; i++) | 888 for (int i = 0; i < rom->map_chunks; i++) |
847 { | 889 { |
848 if (rom->map[i].flags & MMAP_PTR_IDX) { | 890 if (rom->map[i].flags & MMAP_PTR_IDX) { |
849 context->mem_pointers[rom->map[i].ptr_index] = rom->map[i].buffer; | 891 gen->m68k->mem_pointers[rom->map[i].ptr_index] = rom->map[i].buffer; |
850 } | 892 } |
851 } | 893 } |
894 | |
895 return gen; | |
896 } | |
897 | |
898 void start_genesis(genesis_context *gen, char *statefile, uint8_t *debugger) | |
899 { | |
900 set_keybindings(gen->ports); | |
852 | 901 |
853 if (statefile) { | 902 if (statefile) { |
854 uint32_t pc = load_gst(gen, statefile); | 903 uint32_t pc = load_gst(gen, statefile); |
855 if (!pc) { | 904 if (!pc) { |
856 fatal_error("Failed to load save state %s\n", statefile); | 905 fatal_error("Failed to load save state %s\n", statefile); |
857 } | 906 } |
858 printf("Loaded %s\n", statefile); | 907 printf("Loaded %s\n", statefile); |
859 if (debugger) { | 908 if (debugger) { |
860 insert_breakpoint(context, pc, debugger); | 909 insert_breakpoint(gen->m68k, pc, debugger); |
861 } | 910 } |
862 adjust_int_cycle(gen->m68k, gen->vdp); | 911 adjust_int_cycle(gen->m68k, gen->vdp); |
863 start_68k_context(context, pc); | 912 start_68k_context(gen->m68k, pc); |
864 } else { | 913 } else { |
865 if (debugger) { | 914 if (debugger) { |
866 uint32_t address = cart[2] << 16 | cart[3]; | 915 uint32_t address = cart[2] << 16 | cart[3]; |
867 insert_breakpoint(context, address, debugger); | 916 insert_breakpoint(gen->m68k, address, debugger); |
868 } | 917 } |
869 m68k_reset(context); | 918 m68k_reset(gen->m68k); |
870 } | 919 } |
871 } | 920 } |
872 | 921 |
873 char *title; | 922 char *title; |
874 | 923 |
877 if (title) { | 926 if (title) { |
878 free(title); | 927 free(title); |
879 title = NULL; | 928 title = NULL; |
880 } | 929 } |
881 title = alloc_concat(rom_name, " - BlastEm"); | 930 title = alloc_concat(rom_name, " - BlastEm"); |
931 render_update_caption(title); | |
882 } | 932 } |
883 | 933 |
884 void set_region(rom_info *info, uint8_t region) | 934 void set_region(rom_info *info, uint8_t region) |
885 { | 935 { |
886 if (!region) { | 936 if (!region) { |
897 version_reg = NO_DISK | JAP; | 947 version_reg = NO_DISK | JAP; |
898 } else { | 948 } else { |
899 version_reg = NO_DISK | USA; | 949 version_reg = NO_DISK | USA; |
900 } | 950 } |
901 } | 951 } |
902 | |
903 #ifndef NO_Z80 | |
904 const memmap_chunk z80_map[] = { | |
905 { 0x0000, 0x4000, 0x1FFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, z80_ram, NULL, NULL, NULL, NULL }, | |
906 { 0x8000, 0x10000, 0x7FFF, 0, 0, NULL, NULL, NULL, z80_read_bank, z80_write_bank}, | |
907 { 0x4000, 0x6000, 0x0003, 0, 0, NULL, NULL, NULL, z80_read_ym, z80_write_ym}, | |
908 { 0x6000, 0x6100, 0xFFFF, 0, 0, NULL, NULL, NULL, NULL, z80_write_bank_reg}, | |
909 { 0x7F00, 0x8000, 0x00FF, 0, 0, NULL, NULL, NULL, z80_vdp_port_read, z80_vdp_port_write} | |
910 }; | |
911 #endif | |
912 | 952 |
913 int main(int argc, char ** argv) | 953 int main(int argc, char ** argv) |
914 { | 954 { |
915 set_exe_str(argv[0]); | 955 set_exe_str(argv[0]); |
916 config = load_config(); | 956 config = load_config(); |
1012 width = atoi(argv[i]); | 1052 width = atoi(argv[i]); |
1013 } else if (height < 0) { | 1053 } else if (height < 0) { |
1014 height = atoi(argv[i]); | 1054 height = atoi(argv[i]); |
1015 } | 1055 } |
1016 } | 1056 } |
1057 uint8_t menu = !loaded; | |
1017 if (!loaded) { | 1058 if (!loaded) { |
1018 #ifdef __ANDROID__ | 1059 //load menu |
1019 //Temporary hack until UI is in place | 1060 romfname = tern_find_path(config, "ui\rom\0").ptrval; |
1020 if (!(rom_size = load_rom("/mnt/sdcard/rom.bin"))) { | 1061 if (!romfname) { |
1021 fatal_error("Failed to open /mnt/sdcard/rom.bin for reading"); | 1062 romfname = "menu.bin"; |
1022 | 1063 } |
1023 } | 1064 //TODO: load relative to executable or from assets depending on platform |
1024 romfname = "/mnt/sdcard/rom.bin"; | 1065 if (!(rom_size = load_rom(romfname))) { |
1066 fatal_error("Failed to open UI ROM %s for reading", romfname); | |
1067 | |
1068 } | |
1025 loaded = 1; | 1069 loaded = 1; |
1026 #else | |
1027 fatal_error("Usage: blastem [OPTIONS] ROMFILE [WIDTH] [HEIGHT]\n"); | |
1028 #endif | |
1029 } | 1070 } |
1030 tern_node *rom_db = load_rom_db(); | 1071 tern_node *rom_db = load_rom_db(); |
1031 rom_info info = configure_rom(rom_db, cart, rom_size, base_map, sizeof(base_map)/sizeof(base_map[0])); | 1072 rom_info info = configure_rom(rom_db, cart, rom_size, base_map, sizeof(base_map)/sizeof(base_map[0])); |
1032 byteswap_rom(rom_size); | 1073 byteswap_rom(rom_size); |
1033 set_region(&info, force_version); | 1074 set_region(&info, force_version); |
1047 fps = 50; | 1088 fps = 50; |
1048 } | 1089 } |
1049 if (!headless) { | 1090 if (!headless) { |
1050 render_init(width, height, title, fps, fullscreen); | 1091 render_init(width, height, title, fps, fullscreen); |
1051 } | 1092 } |
1052 vdp_context v_context; | |
1053 genesis_context gen; | |
1054 memset(&gen, 0, sizeof(gen)); | |
1055 gen.master_clock = gen.normal_clock = fps == 60 ? MCLKS_NTSC : MCLKS_PAL; | |
1056 | |
1057 init_vdp_context(&v_context, version_reg & 0x40); | |
1058 gen.frame_end = vdp_cycles_to_frame_end(&v_context); | |
1059 char * config_cycles = tern_find_path(config, "clocks\0max_cycles\0").ptrval; | |
1060 gen.max_cycles = config_cycles ? atoi(config_cycles) : DEFAULT_SYNC_INTERVAL; | |
1061 | |
1062 ym2612_context y_context; | |
1063 ym_init(&y_context, render_sample_rate(), gen.master_clock, MCLKS_PER_YM, render_audio_buffer(), ym_log ? YM_OPT_WAVE_LOG : 0); | |
1064 | |
1065 psg_context p_context; | |
1066 psg_init(&p_context, render_sample_rate(), gen.master_clock, MCLKS_PER_PSG, render_audio_buffer()); | |
1067 | |
1068 z80_context z_context; | |
1069 #ifndef NO_Z80 | |
1070 z80_options z_opts; | |
1071 init_z80_opts(&z_opts, z80_map, 5, NULL, 0, MCLKS_PER_Z80); | |
1072 init_z80_context(&z_context, &z_opts); | |
1073 z80_assert_reset(&z_context, 0); | |
1074 #endif | |
1075 | |
1076 z_context.system = &gen; | |
1077 z_context.mem_pointers[0] = z80_ram; | |
1078 z_context.mem_pointers[1] = z_context.mem_pointers[2] = (uint8_t *)cart; | |
1079 | |
1080 gen.z80 = &z_context; | |
1081 gen.vdp = &v_context; | |
1082 gen.ym = &y_context; | |
1083 gen.psg = &p_context; | |
1084 gen.work_ram = ram; | |
1085 gen.zram = z80_ram; | |
1086 genesis = &gen; | |
1087 setup_io_devices(config, gen.ports); | |
1088 | |
1089 int fname_size = strlen(romfname); | 1093 int fname_size = strlen(romfname); |
1090 char * ext = info.save_type == SAVE_I2C ? "eeprom" : "sram"; | 1094 char * ext = info.save_type == SAVE_I2C ? "eeprom" : "sram"; |
1091 save_filename = malloc(fname_size+strlen(ext) + 2); | 1095 save_filename = malloc(fname_size+strlen(ext) + 2); |
1092 memcpy(save_filename, romfname, fname_size); | 1096 memcpy(save_filename, romfname, fname_size); |
1093 int i; | 1097 int i; |
1099 } | 1103 } |
1100 if (i < 0) { | 1104 if (i < 0) { |
1101 save_filename[fname_size] = '.'; | 1105 save_filename[fname_size] = '.'; |
1102 strcpy(save_filename + fname_size + 1, ext); | 1106 strcpy(save_filename + fname_size + 1, ext); |
1103 } | 1107 } |
1104 set_keybindings(gen.ports); | 1108 |
1105 | 1109 genesis = alloc_init_genesis(&info, fps, (ym_log && !menu) ? YM_OPT_WAVE_LOG : 0); |
1106 init_run_cpu(&gen, &info, address_log, statefile, debuggerfun); | 1110 if (menu) { |
1111 menu_context = genesis; | |
1112 } else { | |
1113 genesis->m68k->options->address_log = address_log; | |
1114 game_context = genesis; | |
1115 } | |
1116 | |
1117 start_genesis(genesis, menu ? NULL : statefile, menu ? NULL : debuggerfun); | |
1118 if (menu && menu_context->next_rom) { | |
1119 //TODO: Allow returning to menu | |
1120 if (!(rom_size = load_rom(menu_context->next_rom))) { | |
1121 fatal_error("Failed to open %s for reading\n", menu_context->next_rom); | |
1122 } | |
1123 info = configure_rom(rom_db, cart, rom_size, base_map, sizeof(base_map)/sizeof(base_map[0])); | |
1124 byteswap_rom(rom_size); | |
1125 set_region(&info, force_version); | |
1126 update_title(info.name); | |
1127 fname_size = strlen(romfname); | |
1128 ext = info.save_type == SAVE_I2C ? "eeprom" : "sram"; | |
1129 save_filename = malloc(fname_size+strlen(ext) + 2); | |
1130 memcpy(save_filename, romfname, fname_size); | |
1131 for (i = fname_size-1; fname_size >= 0; --i) { | |
1132 if (save_filename[i] == '.') { | |
1133 strcpy(save_filename + i + 1, ext); | |
1134 break; | |
1135 } | |
1136 } | |
1137 if (i < 0) { | |
1138 save_filename[fname_size] = '.'; | |
1139 strcpy(save_filename + fname_size + 1, ext); | |
1140 } | |
1141 game_context = alloc_init_genesis(&info, fps, ym_log ? YM_OPT_WAVE_LOG : 0); | |
1142 genesis->m68k->options->address_log = address_log; | |
1143 genesis = game_context; | |
1144 start_genesis(genesis, statefile, debuggerfun); | |
1145 } | |
1146 | |
1107 return 0; | 1147 return 0; |
1108 } | 1148 } |