Mercurial > repos > blastem
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 |