comparison blastem.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 22e87b739ad6
children 45db303fc705
comparison
equal deleted inserted replaced
1110:d1eed3b1121c 1111:2eb54e24914e
6 #include <stdio.h> 6 #include <stdio.h>
7 #include <stdlib.h> 7 #include <stdlib.h>
8 #include <string.h> 8 #include <string.h>
9 #include <ctype.h> 9 #include <ctype.h>
10 10
11 #include "system.h"
11 #include "68kinst.h" 12 #include "68kinst.h"
12 #include "m68k_core.h" 13 #include "m68k_core.h"
13 #include "z80_to_x86.h" 14 #include "z80_to_x86.h"
14 #include "mem.h" 15 #include "mem.h"
15 #include "vdp.h" 16 #include "vdp.h"
64 filesize -= SMD_BLOCK_SIZE; 65 filesize -= SMD_BLOCK_SIZE;
65 } 66 }
66 return rom_size; 67 return rom_size;
67 } 68 }
68 69
69 int load_rom(char * filename, uint16_t **dst) 70 int load_rom(char * filename, uint16_t **dst, system_type *stype)
70 { 71 {
71 uint8_t header[10]; 72 uint8_t header[10];
72 FILE * f = fopen(filename, "rb"); 73 FILE * f = fopen(filename, "rb");
73 if (!f) { 74 if (!f) {
74 return 0; 75 return 0;
88 } 89 }
89 if (i == 8) { 90 if (i == 8) {
90 if (header[2]) { 91 if (header[2]) {
91 fatal_error("%s is a split SMD ROM which is not currently supported", filename); 92 fatal_error("%s is a split SMD ROM which is not currently supported", filename);
92 } 93 }
94 if (stype) {
95 *stype = SYSTEM_GENESIS;
96 }
93 return load_smd_rom(filesize, f, dst); 97 return load_smd_rom(filesize, f, dst);
94 } 98 }
95 } 99 }
96 *dst = malloc(nearest_pow2(filesize)); 100 *dst = malloc(nearest_pow2(filesize));
97 if (filesize != fread(*dst, 1, filesize, f)) { 101 if (filesize != fread(*dst, 1, filesize, f)) {
98 fatal_error("Error reading from %s\n", filename); 102 fatal_error("Error reading from %s\n", filename);
99 } 103 }
100 fclose(f); 104 fclose(f);
105 if (stype) {
106 *stype = detect_system_type((uint8_t *)*dst, filesize);
107 }
101 return filesize; 108 return filesize;
102 } 109 }
103 110
104 111
105 112
109 116
110 117
111 118
112 119
113 char * save_filename; 120 char * save_filename;
114 genesis_context *genesis; 121 system_header *current_system;
115 genesis_context *menu_context; 122 system_header *menu_context;
116 genesis_context *game_context; 123 system_header *game_context;
117 void persist_save() 124 void persist_save()
118 { 125 {
119 if (!game_context) { 126 if (!game_context) {
120 return; 127 return;
121 } 128 }
122 FILE * f = fopen(save_filename, "wb"); 129 game_context->persist_save(game_context);
123 if (!f) { 130 }
124 fprintf(stderr, "Failed to open %s file %s for writing\n", game_context->save_type == SAVE_I2C ? "EEPROM" : "SRAM", save_filename);
125 return;
126 }
127 fwrite(game_context->save_storage, 1, game_context->save_size, f);
128 fclose(f);
129 printf("Saved %s to %s\n", game_context->save_type == SAVE_I2C ? "EEPROM" : "SRAM", save_filename);
130 }
131
132
133 131
134 char *title; 132 char *title;
135 void update_title(char *rom_name) 133 void update_title(char *rom_name)
136 { 134 {
137 if (title) { 135 if (title) {
140 } 138 }
141 title = alloc_concat(rom_name, " - BlastEm"); 139 title = alloc_concat(rom_name, " - BlastEm");
142 render_update_caption(title); 140 render_update_caption(title);
143 } 141 }
144 142
145 void setup_saves(char *fname, rom_info *info, genesis_context *context) 143 void setup_saves(char *fname, rom_info *info, system_header *context)
146 { 144 {
145 static uint8_t persist_save_registered;
147 char * barename = basename_no_extension(fname); 146 char * barename = basename_no_extension(fname);
148 char const * parts[3] = {get_save_dir(), PATH_SEP, barename}; 147 char const * parts[3] = {get_save_dir(), PATH_SEP, barename};
149 char *save_dir = alloc_concat_m(3, parts); 148 char *save_dir = alloc_concat_m(3, parts);
150 if (!ensure_dir_exists(save_dir)) { 149 if (!ensure_dir_exists(save_dir)) {
151 warning("Failed to create save directory %s\n", save_dir); 150 warning("Failed to create save directory %s\n", save_dir);
152 } 151 }
153 parts[0] = save_dir; 152 parts[0] = save_dir;
154 parts[2] = info->save_type == SAVE_I2C ? "save.eeprom" : "save.sram"; 153 parts[2] = info->save_type == SAVE_I2C ? "save.eeprom" : "save.sram";
155 free(save_filename); 154 free(save_filename);
156 save_filename = alloc_concat_m(3, parts); 155 save_filename = alloc_concat_m(3, parts);
156 //TODO: make quick save filename dependent on system type
157 parts[2] = "quicksave.gst"; 157 parts[2] = "quicksave.gst";
158 free(save_state_path); 158 free(save_state_path);
159 save_state_path = alloc_concat_m(3, parts); 159 save_state_path = alloc_concat_m(3, parts);
160 context->save_dir = save_dir; 160 context->save_dir = save_dir;
161 free(barename); 161 free(barename);
162 if (info->save_type != SAVE_NONE) { 162 if (info->save_type != SAVE_NONE) {
163 FILE * f = fopen(save_filename, "rb"); 163 context->load_save(context);
164 if (f) { 164 if (!persist_save_registered) {
165 uint32_t read = fread(context->save_storage, 1, info->save_size, f); 165 atexit(persist_save);
166 fclose(f); 166 persist_save_registered = 1;
167 if (read > 0) { 167 }
168 printf("Loaded %s from %s\n", info->save_type == SAVE_I2C ? "EEPROM" : "SRAM", save_filename);
169 }
170 }
171 atexit(persist_save);
172 } 168 }
173 } 169 }
174 170
175 int main(int argc, char ** argv) 171 int main(int argc, char ** argv)
176 { 172 {
179 int width = -1; 175 int width = -1;
180 int height = -1; 176 int height = -1;
181 int debug = 0; 177 int debug = 0;
182 int ym_log = 0; 178 int ym_log = 0;
183 int loaded = 0; 179 int loaded = 0;
180 system_type stype;
184 uint8_t force_region = 0; 181 uint8_t force_region = 0;
185 char * romfname = NULL; 182 char * romfname = NULL;
186 FILE *address_log = NULL; 183 FILE *address_log = NULL;
187 char * statefile = NULL; 184 char * statefile = NULL;
188 int rom_size, lock_on_size; 185 int rom_size, lock_on_size;
189 uint16_t *cart = NULL, *lock_on = NULL; 186 uint16_t *cart = NULL, *lock_on = NULL;
190 uint8_t * debuggerfun = NULL; 187 debugger_type dtype = DEBUGGER_NATIVE;
188 uint8_t start_in_debugger = 0;
191 uint8_t fullscreen = FULLSCREEN_DEFAULT, use_gl = 1; 189 uint8_t fullscreen = FULLSCREEN_DEFAULT, use_gl = 1;
192 uint8_t debug_target = 0; 190 uint8_t debug_target = 0;
193 for (int i = 1; i < argc; i++) { 191 for (int i = 1; i < argc; i++) {
194 if (argv[i][0] == '-') { 192 if (argv[i][0] == '-') {
195 switch(argv[i][1]) { 193 switch(argv[i][1]) {
200 } 198 }
201 headless = 1; 199 headless = 1;
202 exit_after = atoi(argv[i]); 200 exit_after = atoi(argv[i]);
203 break; 201 break;
204 case 'd': 202 case 'd':
205 debuggerfun = (uint8_t *)debugger; 203 start_in_debugger = 1;
206 //allow debugging the menu 204 //allow debugging the menu
207 if (argv[i][2] == 'm') { 205 if (argv[i][2] == 'm') {
208 debug_target = 1; 206 debug_target = 1;
209 } 207 }
210 break; 208 break;
211 case 'D': 209 case 'D':
212 gdb_remote_init(); 210 gdb_remote_init();
213 debuggerfun = (uint8_t *)gdb_debug_enter; 211 dtype = DEBUGGER_GDB;
214 break; 212 break;
215 case 'f': 213 case 'f':
216 fullscreen = !fullscreen; 214 fullscreen = !fullscreen;
217 break; 215 break;
218 case 'g': 216 case 'g':
254 case 'o': { 252 case 'o': {
255 i++; 253 i++;
256 if (i >= argc) { 254 if (i >= argc) {
257 fatal_error("-o must be followed by a lock on cartridge filename\n"); 255 fatal_error("-o must be followed by a lock on cartridge filename\n");
258 } 256 }
259 lock_on_size = load_rom(argv[i], &lock_on); 257 lock_on_size = load_rom(argv[i], &lock_on, NULL);
260 if (!lock_on_size) { 258 if (!lock_on_size) {
261 fatal_error("Failed to load lock on cartridge %s\n", argv[i]); 259 fatal_error("Failed to load lock on cartridge %s\n", argv[i]);
262 } 260 }
263 break; 261 break;
264 } 262 }
281 return 0; 279 return 0;
282 default: 280 default:
283 fatal_error("Unrecognized switch %s\n", argv[i]); 281 fatal_error("Unrecognized switch %s\n", argv[i]);
284 } 282 }
285 } else if (!loaded) { 283 } else if (!loaded) {
286 if (!(rom_size = load_rom(argv[i], &cart))) { 284 if (!(rom_size = load_rom(argv[i], &cart, &stype))) {
287 fatal_error("Failed to open %s for reading\n", argv[i]); 285 fatal_error("Failed to open %s for reading\n", argv[i]);
288 } 286 }
289 romfname = argv[i]; 287 romfname = argv[i];
290 loaded = 1; 288 loaded = 1;
291 } else if (width < 0) { 289 } else if (width < 0) {
300 romfname = tern_find_path(config, "ui\0rom\0").ptrval; 298 romfname = tern_find_path(config, "ui\0rom\0").ptrval;
301 if (!romfname) { 299 if (!romfname) {
302 romfname = "menu.bin"; 300 romfname = "menu.bin";
303 } 301 }
304 if (is_absolute_path(romfname)) { 302 if (is_absolute_path(romfname)) {
305 if (!(rom_size = load_rom(romfname, &cart))) { 303 if (!(rom_size = load_rom(romfname, &cart, &stype))) {
306 fatal_error("Failed to open UI ROM %s for reading", romfname); 304 fatal_error("Failed to open UI ROM %s for reading", romfname);
307 } 305 }
308 } else { 306 } else {
309 long fsize; 307 long fsize;
310 cart = (uint16_t *)read_bundled_file(romfname, &fsize); 308 cart = (uint16_t *)read_bundled_file(romfname, &fsize);
311 if (!cart) { 309 if (!cart) {
312 fatal_error("Failed to open UI ROM %s for reading", romfname); 310 fatal_error("Failed to open UI ROM %s for reading", romfname);
313 } 311 }
312 stype = detect_system_type((uint8_t *)cart, fsize);
314 rom_size = nearest_pow2(fsize); 313 rom_size = nearest_pow2(fsize);
315 if (rom_size > fsize) { 314 if (rom_size > fsize) {
316 cart = realloc(cart, rom_size); 315 cart = realloc(cart, rom_size);
317 } 316 }
318 } 317 }
339 render_init(width, height, "BlastEm", fullscreen); 338 render_init(width, height, "BlastEm", fullscreen);
340 } 339 }
341 340
342 rom_info info; 341 rom_info info;
343 uint32_t ym_opts = (ym_log && !menu) ? YM_OPT_WAVE_LOG : 0; 342 uint32_t ym_opts = (ym_log && !menu) ? YM_OPT_WAVE_LOG : 0;
344 genesis = alloc_config_genesis(cart, rom_size, lock_on, lock_on_size, ym_opts, force_region, &info); 343 current_system = alloc_config_system(stype, cart, rom_size, lock_on, lock_on_size, ym_opts, force_region, &info);
345 setup_saves(romfname, &info, genesis); 344 setup_saves(romfname, &info, current_system);
346 update_title(info.name); 345 update_title(info.name);
347 if (menu) { 346 if (menu) {
348 menu_context = genesis; 347 menu_context = current_system;
349 } else { 348 } else {
350 genesis->m68k->options->address_log = address_log; 349 //TODO: make this an option flag
351 game_context = genesis; 350 //genesis->m68k->options->address_log = address_log;
352 } 351 game_context = current_system;
353 352 }
354 set_keybindings(genesis->ports); 353
355 start_genesis(genesis, menu ? NULL : statefile, menu == debug_target ? debuggerfun : NULL); 354 current_system->debugger_type = dtype;
355 current_system->enter_debugger = start_in_debugger && menu == debug_target;
356 current_system->start_context(current_system, menu ? NULL : statefile);
356 for(;;) 357 for(;;)
357 { 358 {
358 if (genesis->should_exit) { 359 if (current_system->should_exit) {
359 break; 360 break;
360 } 361 }
361 if (menu && menu_context->next_rom) { 362 if (menu && menu_context->next_rom) {
362 if (game_context) { 363 if (game_context) {
363 if (game_context->save_type != SAVE_NONE) { 364 game_context->persist_save(game_context);
364 genesis = game_context;
365 persist_save();
366 genesis = menu_context;
367 }
368 //swap to game context arena and mark all allocated pages in it free 365 //swap to game context arena and mark all allocated pages in it free
369 genesis->arena = set_current_arena(game_context->arena); 366 current_system->arena = set_current_arena(game_context->arena);
370 mark_all_free(); 367 mark_all_free();
371 free_genesis(game_context); 368 game_context->free_context(game_context);
372 } else { 369 } else {
373 //start a new arena and save old one in suspended genesis context 370 //start a new arena and save old one in suspended genesis context
374 genesis->arena = start_new_arena(); 371 current_system->arena = start_new_arena();
375 } 372 }
376 if (!(rom_size = load_rom(menu_context->next_rom, &cart))) { 373 if (!(rom_size = load_rom(menu_context->next_rom, &cart, &stype))) {
377 fatal_error("Failed to open %s for reading\n", menu_context->next_rom); 374 fatal_error("Failed to open %s for reading\n", menu_context->next_rom);
378 } 375 }
379 //allocate new genesis context 376 //allocate new genesis context
380 game_context = alloc_config_genesis(cart, rom_size, lock_on, lock_on_size, ym_opts,force_region, &info); 377 game_context = alloc_config_system(stype, cart, rom_size, lock_on, lock_on_size, ym_opts,force_region, &info);
381 menu_context->next_context = game_context; 378 menu_context->next_context = game_context;
382 game_context->next_context = menu_context; 379 game_context->next_context = menu_context;
383 setup_saves(menu_context->next_rom, &info, game_context); 380 setup_saves(menu_context->next_rom, &info, game_context);
384 update_title(info.name); 381 update_title(info.name);
385 free(menu_context->next_rom); 382 free(menu_context->next_rom);
386 menu_context->next_rom = NULL; 383 menu_context->next_rom = NULL;
387 menu = 0; 384 menu = 0;
388 genesis = game_context; 385 current_system = game_context;
389 genesis->m68k->options->address_log = address_log; 386 //TODO: make this an option flag
390 map_all_bindings(genesis->ports); 387 //genesis->m68k->options->address_log = address_log;
391 start_genesis(genesis, statefile, menu == debug_target ? debuggerfun : NULL); 388 current_system->debugger_type = dtype;
389 current_system->enter_debugger = start_in_debugger && menu == debug_target;
390 current_system->start_context(current_system, statefile);
392 } else if (menu && game_context) { 391 } else if (menu && game_context) {
393 genesis->arena = set_current_arena(game_context->arena); 392 current_system->arena = set_current_arena(game_context->arena);
394 genesis = game_context; 393 current_system = game_context;
395 menu = 0; 394 menu = 0;
396 map_all_bindings(genesis->ports); 395 current_system->resume_context(current_system);
397 resume_68k(genesis->m68k);
398 } else if (!menu && menu_context) { 396 } else if (!menu && menu_context) {
399 genesis->arena = set_current_arena(menu_context->arena); 397 current_system->arena = set_current_arena(menu_context->arena);
400 genesis = menu_context; 398 current_system = menu_context;
401 menu = 1; 399 menu = 1;
402 map_all_bindings(genesis->ports); 400 current_system->resume_context(current_system);
403 resume_68k(genesis->m68k);
404 } else { 401 } else {
405 break; 402 break;
406 } 403 }
407 } 404 }
408 405