Mercurial > repos > blastem
comparison blastem.c @ 1140:4490c9c12272
Detect system type from filename if header based methods fail. Allow overriding system type from command line.
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Mon, 02 Jan 2017 21:46:26 -0800 |
parents | 093c19f34dfd |
children | 21df13266e6a |
comparison
equal
deleted
inserted
replaced
1139:160e3f597cec | 1140:4490c9c12272 |
---|---|
47 #define SMD_MAGIC1 0x03 | 47 #define SMD_MAGIC1 0x03 |
48 #define SMD_MAGIC2 0xAA | 48 #define SMD_MAGIC2 0xAA |
49 #define SMD_MAGIC3 0xBB | 49 #define SMD_MAGIC3 0xBB |
50 #define SMD_BLOCK_SIZE 0x4000 | 50 #define SMD_BLOCK_SIZE 0x4000 |
51 | 51 |
52 int load_smd_rom(long filesize, FILE * f, uint16_t **buffer) | 52 int load_smd_rom(long filesize, FILE * f, void **buffer) |
53 { | 53 { |
54 uint8_t block[SMD_BLOCK_SIZE]; | 54 uint8_t block[SMD_BLOCK_SIZE]; |
55 filesize -= SMD_HEADER_SIZE; | 55 filesize -= SMD_HEADER_SIZE; |
56 fseek(f, SMD_HEADER_SIZE, SEEK_SET); | 56 fseek(f, SMD_HEADER_SIZE, SEEK_SET); |
57 | 57 |
65 filesize -= SMD_BLOCK_SIZE; | 65 filesize -= SMD_BLOCK_SIZE; |
66 } | 66 } |
67 return rom_size; | 67 return rom_size; |
68 } | 68 } |
69 | 69 |
70 int load_rom(char * filename, uint16_t **dst, system_type *stype) | 70 uint32_t load_rom(char * filename, void **dst, system_type *stype) |
71 { | 71 { |
72 uint8_t header[10]; | 72 uint8_t header[10]; |
73 FILE * f = fopen(filename, "rb"); | 73 FILE * f = fopen(filename, "rb"); |
74 if (!f) { | 74 if (!f) { |
75 return 0; | 75 return 0; |
100 *dst = malloc(nearest_pow2(filesize)); | 100 *dst = malloc(nearest_pow2(filesize)); |
101 if (filesize != fread(*dst, 1, filesize, f)) { | 101 if (filesize != fread(*dst, 1, filesize, f)) { |
102 fatal_error("Error reading from %s\n", filename); | 102 fatal_error("Error reading from %s\n", filename); |
103 } | 103 } |
104 fclose(f); | 104 fclose(f); |
105 if (stype) { | |
106 *stype = detect_system_type((uint8_t *)*dst, filesize); | |
107 } | |
108 return filesize; | 105 return filesize; |
109 } | 106 } |
110 | 107 |
111 | 108 |
112 | 109 |
175 int width = -1; | 172 int width = -1; |
176 int height = -1; | 173 int height = -1; |
177 int debug = 0; | 174 int debug = 0; |
178 uint32_t opts = 0; | 175 uint32_t opts = 0; |
179 int loaded = 0; | 176 int loaded = 0; |
180 system_type stype; | 177 system_type stype = SYSTEM_UNKNOWN, force_stype = SYSTEM_UNKNOWN; |
181 uint8_t force_region = 0; | 178 uint8_t force_region = 0; |
182 char * romfname = NULL; | 179 char * romfname = NULL; |
183 char * statefile = NULL; | 180 char * statefile = NULL; |
184 int rom_size, lock_on_size; | 181 system_media cart = {.chain = NULL}, lock_on; |
185 uint16_t *cart = NULL, *lock_on = NULL; | |
186 debugger_type dtype = DEBUGGER_NATIVE; | 182 debugger_type dtype = DEBUGGER_NATIVE; |
187 uint8_t start_in_debugger = 0; | 183 uint8_t start_in_debugger = 0; |
188 uint8_t fullscreen = FULLSCREEN_DEFAULT, use_gl = 1; | 184 uint8_t fullscreen = FULLSCREEN_DEFAULT, use_gl = 1; |
189 uint8_t debug_target = 0; | 185 uint8_t debug_target = 0; |
190 for (int i = 1; i < argc; i++) { | 186 for (int i = 1; i < argc; i++) { |
233 force_region = translate_region_char(toupper(argv[i][0])); | 229 force_region = translate_region_char(toupper(argv[i][0])); |
234 if (!force_region) { | 230 if (!force_region) { |
235 fatal_error("'%c' is not a valid region character for the -r option\n", argv[i][0]); | 231 fatal_error("'%c' is not a valid region character for the -r option\n", argv[i][0]); |
236 } | 232 } |
237 break; | 233 break; |
234 case 'm': | |
235 i++; | |
236 if (i >= argc) { | |
237 fatal_error("-r must be followed by a machine type (sms, gen or jag)\n"); | |
238 } | |
239 if (!strcmp("sms", argv[i])) { | |
240 stype = force_stype = SYSTEM_SMS; | |
241 } else if (!strcmp("gen", argv[i])) { | |
242 stype = force_stype = SYSTEM_GENESIS; | |
243 } else if (!strcmp("jag", argv[i])) { | |
244 stype = force_stype = SYSTEM_JAGUAR; | |
245 } else { | |
246 fatal_error("Unrecognized machine type %s\n", argv[i]); | |
247 } | |
248 break; | |
238 case 's': | 249 case 's': |
239 i++; | 250 i++; |
240 if (i >= argc) { | 251 if (i >= argc) { |
241 fatal_error("-s must be followed by a savestate filename\n"); | 252 fatal_error("-s must be followed by a savestate filename\n"); |
242 } | 253 } |
251 case 'o': { | 262 case 'o': { |
252 i++; | 263 i++; |
253 if (i >= argc) { | 264 if (i >= argc) { |
254 fatal_error("-o must be followed by a lock on cartridge filename\n"); | 265 fatal_error("-o must be followed by a lock on cartridge filename\n"); |
255 } | 266 } |
256 lock_on_size = load_rom(argv[i], &lock_on, NULL); | 267 lock_on.size = load_rom(argv[i], &lock_on.buffer, NULL); |
257 if (!lock_on_size) { | 268 if (!lock_on.size) { |
258 fatal_error("Failed to load lock on cartridge %s\n", argv[i]); | 269 fatal_error("Failed to load lock on cartridge %s\n", argv[i]); |
259 } | 270 } |
271 lock_on.extension = path_extension(argv[i]); | |
272 cart.chain = &lock_on; | |
260 break; | 273 break; |
261 } | 274 } |
262 case 'h': | 275 case 'h': |
263 info_message( | 276 info_message( |
264 "Usage: blastem [OPTIONS] ROMFILE [WIDTH] [HEIGHT]\n" | 277 "Usage: blastem [OPTIONS] ROMFILE [WIDTH] [HEIGHT]\n" |
265 "Options:\n" | 278 "Options:\n" |
266 " -h Print this help text\n" | 279 " -h Print this help text\n" |
267 " -r (J|U|E) Force region to Japan, US or Europe respectively\n" | 280 " -r (J|U|E) Force region to Japan, US or Europe respectively\n" |
281 " -m MACHINE Force emulated machine type to MACHINE. Valid values are:\n" | |
282 " sms - Sega Master System/Mark III\n" | |
283 " gen - Sega Genesis/Megadrive\n" | |
284 " jag - Atari Jaguar\n" | |
268 " -f Toggles fullscreen mode\n" | 285 " -f Toggles fullscreen mode\n" |
269 " -g Disable OpenGL rendering\n" | 286 " -g Disable OpenGL rendering\n" |
270 " -s FILE Load a GST format savestate from FILE\n" | 287 " -s FILE Load a GST format savestate from FILE\n" |
271 " -o FILE Load FILE as a lock-on cartridge\n" | 288 " -o FILE Load FILE as a lock-on cartridge\n" |
272 " -d Enter debugger on startup\n" | 289 " -d Enter debugger on startup\n" |
278 return 0; | 295 return 0; |
279 default: | 296 default: |
280 fatal_error("Unrecognized switch %s\n", argv[i]); | 297 fatal_error("Unrecognized switch %s\n", argv[i]); |
281 } | 298 } |
282 } else if (!loaded) { | 299 } else if (!loaded) { |
283 if (!(rom_size = load_rom(argv[i], &cart, &stype))) { | 300 if (!(cart.size = load_rom(argv[i], &cart.buffer, stype == SYSTEM_UNKNOWN ? &stype : NULL))) { |
284 fatal_error("Failed to open %s for reading\n", argv[i]); | 301 fatal_error("Failed to open %s for reading\n", argv[i]); |
285 } | 302 } |
303 cart.extension = path_extension(argv[i]); | |
286 romfname = argv[i]; | 304 romfname = argv[i]; |
287 loaded = 1; | 305 loaded = 1; |
288 } else if (width < 0) { | 306 } else if (width < 0) { |
289 width = atoi(argv[i]); | 307 width = atoi(argv[i]); |
290 } else if (height < 0) { | 308 } else if (height < 0) { |
297 romfname = tern_find_path(config, "ui\0rom\0").ptrval; | 315 romfname = tern_find_path(config, "ui\0rom\0").ptrval; |
298 if (!romfname) { | 316 if (!romfname) { |
299 romfname = "menu.bin"; | 317 romfname = "menu.bin"; |
300 } | 318 } |
301 if (is_absolute_path(romfname)) { | 319 if (is_absolute_path(romfname)) { |
302 if (!(rom_size = load_rom(romfname, &cart, &stype))) { | 320 if (!(cart.size = load_rom(romfname, &cart.buffer, &stype))) { |
303 fatal_error("Failed to open UI ROM %s for reading", romfname); | 321 fatal_error("Failed to open UI ROM %s for reading", romfname); |
304 } | 322 } |
305 } else { | 323 } else { |
306 long fsize; | 324 cart.buffer = (uint16_t *)read_bundled_file(romfname, &cart.size); |
307 cart = (uint16_t *)read_bundled_file(romfname, &fsize); | 325 if (!cart.buffer) { |
308 if (!cart) { | |
309 fatal_error("Failed to open UI ROM %s for reading", romfname); | 326 fatal_error("Failed to open UI ROM %s for reading", romfname); |
310 } | 327 } |
311 stype = detect_system_type((uint8_t *)cart, fsize); | 328 uint32_t rom_size = nearest_pow2(cart.size); |
312 rom_size = nearest_pow2(fsize); | 329 if (rom_size > cart.size) { |
313 if (rom_size > fsize) { | 330 cart.buffer = realloc(cart.buffer, rom_size); |
314 cart = realloc(cart, rom_size); | 331 cart.size = rom_size; |
315 } | 332 } |
316 } | 333 } |
334 //force system detection, value on command line is only for games not the menu | |
335 stype = detect_system_type(&cart); | |
336 cart.extension = path_extension(romfname); | |
317 | 337 |
318 loaded = 1; | 338 loaded = 1; |
319 } | 339 } |
320 | 340 |
321 int def_width = 0; | 341 int def_width = 0; |
335 } | 355 } |
336 if (!headless) { | 356 if (!headless) { |
337 render_init(width, height, "BlastEm", fullscreen); | 357 render_init(width, height, "BlastEm", fullscreen); |
338 } | 358 } |
339 | 359 |
360 if (stype == SYSTEM_UNKNOWN) { | |
361 stype = detect_system_type(&cart); | |
362 } | |
363 if (stype == SYSTEM_UNKNOWN) { | |
364 fatal_error("Failed to detect system type for %s\n", romfname); | |
365 } | |
340 rom_info info; | 366 rom_info info; |
341 current_system = alloc_config_system(stype, cart, rom_size, lock_on, lock_on_size, menu ? 0 : opts, force_region, &info); | 367 current_system = alloc_config_system(stype, &cart, menu ? 0 : opts, force_region, &info); |
342 if (!current_system) { | 368 if (!current_system) { |
343 fatal_error("Failed to detect system type for %s\n", romfname); | 369 fatal_error("Failed to configure emulated machine for %s\n", romfname); |
344 } | 370 } |
345 setup_saves(romfname, &info, current_system); | 371 setup_saves(romfname, &info, current_system); |
346 update_title(info.name); | 372 update_title(info.name); |
347 if (menu) { | 373 if (menu) { |
348 menu_context = current_system; | 374 menu_context = current_system; |
367 game_context->free_context(game_context); | 393 game_context->free_context(game_context); |
368 } else { | 394 } else { |
369 //start a new arena and save old one in suspended genesis context | 395 //start a new arena and save old one in suspended genesis context |
370 current_system->arena = start_new_arena(); | 396 current_system->arena = start_new_arena(); |
371 } | 397 } |
372 if (!(rom_size = load_rom(menu_context->next_rom, &cart, &stype))) { | 398 if (!(cart.size = load_rom(menu_context->next_rom, &cart.buffer, &stype))) { |
373 fatal_error("Failed to open %s for reading\n", menu_context->next_rom); | 399 fatal_error("Failed to open %s for reading\n", menu_context->next_rom); |
374 } | 400 } |
401 cart.extension = path_extension(menu_context->next_rom); | |
402 stype = force_stype; | |
403 if (stype == SYSTEM_UNKNOWN) { | |
404 stype = detect_system_type(&cart); | |
405 } | |
406 if (stype == SYSTEM_UNKNOWN) { | |
407 fatal_error("Failed to detect system type for %s\n", menu_context->next_rom); | |
408 } | |
375 //allocate new genesis context | 409 //allocate new genesis context |
376 game_context = alloc_config_system(stype, cart, rom_size, lock_on, lock_on_size, opts,force_region, &info); | 410 game_context = alloc_config_system(stype, &cart, opts,force_region, &info); |
377 if (!game_context) { | 411 if (!game_context) { |
378 fatal_error("Failed to detect system type for %s\n", menu_context->next_rom); | 412 fatal_error("Failed to configure emulated machine for %s\n", menu_context->next_rom); |
379 } | 413 } |
380 menu_context->next_context = game_context; | 414 menu_context->next_context = game_context; |
381 game_context->next_context = menu_context; | 415 game_context->next_context = menu_context; |
382 setup_saves(menu_context->next_rom, &info, game_context); | 416 setup_saves(menu_context->next_rom, &info, game_context); |
383 update_title(info.name); | 417 update_title(info.name); |