Mercurial > repos > blastem
comparison blastem.c @ 792:724bbec47f86
Use a new fatal_error function instead of calling fprintf and exit for fatal errors. This new function more gracefully handles the case in which BlastEm was not started from a terminal or disconnected from ther terminal (Windows).
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 25 Jul 2015 18:22:07 -0700 |
parents | 283bdcd5bdb8 |
children | 092524bb2e8f |
comparison
equal
deleted
inserted
replaced
791:60686f8d5e48 | 792:724bbec47f86 |
---|---|
89 FILE * f = fopen(filename, "rb"); | 89 FILE * f = fopen(filename, "rb"); |
90 if (!f) { | 90 if (!f) { |
91 return 0; | 91 return 0; |
92 } | 92 } |
93 if (sizeof(header) != fread(header, 1, sizeof(header), f)) { | 93 if (sizeof(header) != fread(header, 1, sizeof(header), f)) { |
94 fprintf(stderr, "Error reading from %s\n", filename); | 94 fatal_error("Error reading from %s\n", filename); |
95 exit(1); | |
96 } | 95 } |
97 fseek(f, 0, SEEK_END); | 96 fseek(f, 0, SEEK_END); |
98 long filesize = ftell(f); | 97 long filesize = ftell(f); |
99 fseek(f, 0, SEEK_SET); | 98 fseek(f, 0, SEEK_SET); |
100 if (header[1] == SMD_MAGIC1 && header[8] == SMD_MAGIC2 && header[9] == SMD_MAGIC3) { | 99 if (header[1] == SMD_MAGIC1 && header[8] == SMD_MAGIC2 && header[9] == SMD_MAGIC3) { |
104 break; | 103 break; |
105 } | 104 } |
106 } | 105 } |
107 if (i == 8) { | 106 if (i == 8) { |
108 if (header[2]) { | 107 if (header[2]) { |
109 fprintf(stderr, "%s is a split SMD ROM which is not currently supported", filename); | 108 fatal_error("%s is a split SMD ROM which is not currently supported", filename); |
110 exit(1); | |
111 } | 109 } |
112 return load_smd_rom(filesize, f); | 110 return load_smd_rom(filesize, f); |
113 } | 111 } |
114 } | 112 } |
115 cart = malloc(nearest_pow2(filesize)); | 113 cart = malloc(nearest_pow2(filesize)); |
116 if (filesize != fread(cart, 1, filesize, f)) { | 114 if (filesize != fread(cart, 1, filesize, f)) { |
117 fprintf(stderr, "Error reading from %s\n", filename); | 115 fatal_error("Error reading from %s\n", filename); |
118 exit(1); | |
119 } | 116 } |
120 fclose(f); | 117 fclose(f); |
121 return filesize; | 118 return filesize; |
122 } | 119 } |
123 | 120 |
287 } | 284 } |
288 | 285 |
289 m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_t value) | 286 m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_t value) |
290 { | 287 { |
291 if (vdp_port & 0x2700E0) { | 288 if (vdp_port & 0x2700E0) { |
292 printf("machine freeze due to write to address %X\n", 0xC00000 | vdp_port); | 289 fatal_error("machine freeze due to write to address %X\n", 0xC00000 | vdp_port); |
293 exit(1); | |
294 } | 290 } |
295 vdp_port &= 0x1F; | 291 vdp_port &= 0x1F; |
296 //printf("vdp_port write: %X, value: %X, cycle: %d\n", vdp_port, value, context->current_cycle); | 292 //printf("vdp_port write: %X, value: %X, cycle: %d\n", vdp_port, value, context->current_cycle); |
297 sync_components(context, 0); | 293 sync_components(context, 0); |
298 vdp_context * v_context = context->video_context; | 294 vdp_context * v_context = context->video_context; |
337 context->sync_cycle = gen->frame_end = vdp_cycles_to_frame_end(v_context); | 333 context->sync_cycle = gen->frame_end = vdp_cycles_to_frame_end(v_context); |
338 //printf("Set sync cycle to: %d @ %d, vcounter: %d, hslot: %d\n", context->sync_cycle, context->current_cycle, v_context->vcounter, v_context->hslot); | 334 //printf("Set sync cycle to: %d @ %d, vcounter: %d, hslot: %d\n", context->sync_cycle, context->current_cycle, v_context->vcounter, v_context->hslot); |
339 adjust_int_cycle(context, v_context); | 335 adjust_int_cycle(context, v_context); |
340 } | 336 } |
341 } else { | 337 } else { |
342 printf("Illegal write to HV Counter port %X\n", vdp_port); | 338 fatal_error("Illegal write to HV Counter port %X\n", vdp_port); |
343 exit(1); | |
344 } | 339 } |
345 if (v_context->cycles != before_cycle) { | 340 if (v_context->cycles != before_cycle) { |
346 //printf("68K paused for %d (%d) cycles at cycle %d (%d) for write\n", v_context->cycles - context->current_cycle, v_context->cycles - before_cycle, context->current_cycle, before_cycle); | 341 //printf("68K paused for %d (%d) cycles at cycle %d (%d) for write\n", v_context->cycles - context->current_cycle, v_context->cycles - before_cycle, context->current_cycle, before_cycle); |
347 context->current_cycle = v_context->cycles; | 342 context->current_cycle = v_context->cycles; |
348 //Lock the Z80 out of the bus until the VDP access is complete | 343 //Lock the Z80 out of the bus until the VDP access is complete |
367 { | 362 { |
368 z80_context * context = vcontext; | 363 z80_context * context = vcontext; |
369 genesis_context * gen = context->system; | 364 genesis_context * gen = context->system; |
370 vdp_port &= 0xFF; | 365 vdp_port &= 0xFF; |
371 if (vdp_port & 0xE0) { | 366 if (vdp_port & 0xE0) { |
372 printf("machine freeze due to write to Z80 address %X\n", 0x7F00 | vdp_port); | 367 fatal_error("machine freeze due to write to Z80 address %X\n", 0x7F00 | vdp_port); |
373 exit(1); | |
374 } | 368 } |
375 if (vdp_port < 0x10) { | 369 if (vdp_port < 0x10) { |
376 //These probably won't currently interact well with the 68K accessing the VDP | 370 //These probably won't currently interact well with the 68K accessing the VDP |
377 vdp_run_context(gen->vdp, context->current_cycle); | 371 vdp_run_context(gen->vdp, context->current_cycle); |
378 if (vdp_port < 4) { | 372 if (vdp_port < 4) { |
379 vdp_data_port_write(gen->vdp, value << 8 | value); | 373 vdp_data_port_write(gen->vdp, value << 8 | value); |
380 } else if (vdp_port < 8) { | 374 } else if (vdp_port < 8) { |
381 vdp_control_port_write(gen->vdp, value << 8 | value); | 375 vdp_control_port_write(gen->vdp, value << 8 | value); |
382 } else { | 376 } else { |
383 printf("Illegal write to HV Counter port %X\n", vdp_port); | 377 fatal_error("Illegal write to HV Counter port %X\n", vdp_port); |
384 exit(1); | |
385 } | 378 } |
386 } else if (vdp_port < 0x18) { | 379 } else if (vdp_port < 0x18) { |
387 sync_sound(gen, context->current_cycle); | 380 sync_sound(gen, context->current_cycle); |
388 psg_write(gen->psg, value); | 381 psg_write(gen->psg, value); |
389 } else { | 382 } else { |
393 } | 386 } |
394 | 387 |
395 uint16_t vdp_port_read(uint32_t vdp_port, m68k_context * context) | 388 uint16_t vdp_port_read(uint32_t vdp_port, m68k_context * context) |
396 { | 389 { |
397 if (vdp_port & 0x2700E0) { | 390 if (vdp_port & 0x2700E0) { |
398 printf("machine freeze due to read from address %X\n", 0xC00000 | vdp_port); | 391 fatal_error("machine freeze due to read from address %X\n", 0xC00000 | vdp_port); |
399 exit(1); | |
400 } | 392 } |
401 vdp_port &= 0x1F; | 393 vdp_port &= 0x1F; |
402 uint16_t value; | 394 uint16_t value; |
403 sync_components(context, 0); | 395 sync_components(context, 0); |
404 vdp_context * v_context = context->video_context; | 396 vdp_context * v_context = context->video_context; |
411 } else { | 403 } else { |
412 value = vdp_hv_counter_read(v_context); | 404 value = vdp_hv_counter_read(v_context); |
413 //printf("HV Counter: %X at cycle %d\n", value, v_context->cycles); | 405 //printf("HV Counter: %X at cycle %d\n", value, v_context->cycles); |
414 } | 406 } |
415 } else if (vdp_port < 0x18){ | 407 } else if (vdp_port < 0x18){ |
416 printf("Illegal read from PSG port %X\n", vdp_port); | 408 fatal_error("Illegal read from PSG port %X\n", vdp_port); |
417 exit(1); | |
418 } else { | 409 } else { |
419 value = vdp_test_port_read(v_context); | 410 value = vdp_test_port_read(v_context); |
420 } | 411 } |
421 if (v_context->cycles != before_cycle) { | 412 if (v_context->cycles != before_cycle) { |
422 //printf("68K paused for %d (%d) cycles at cycle %d (%d) for read\n", v_context->cycles - context->current_cycle, v_context->cycles - before_cycle, context->current_cycle, before_cycle); | 413 //printf("68K paused for %d (%d) cycles at cycle %d (%d) for read\n", v_context->cycles - context->current_cycle, v_context->cycles - before_cycle, context->current_cycle, before_cycle); |
442 | 433 |
443 uint8_t z80_vdp_port_read(uint32_t vdp_port, void * vcontext) | 434 uint8_t z80_vdp_port_read(uint32_t vdp_port, void * vcontext) |
444 { | 435 { |
445 z80_context * context = vcontext; | 436 z80_context * context = vcontext; |
446 if (vdp_port & 0xE0) { | 437 if (vdp_port & 0xE0) { |
447 printf("machine freeze due to read from Z80 address %X\n", 0x7F00 | vdp_port); | 438 fatal_error("machine freeze due to read from Z80 address %X\n", 0x7F00 | vdp_port); |
448 exit(1); | |
449 } | 439 } |
450 genesis_context * gen = context->system; | 440 genesis_context * gen = context->system; |
451 //VDP access goes over the 68K bus like a bank area access | 441 //VDP access goes over the 68K bus like a bank area access |
452 //typical delay from bus arbitration | 442 //typical delay from bus arbitration |
453 context->current_cycle += 3 * MCLKS_PER_Z80; | 443 context->current_cycle += 3 * MCLKS_PER_Z80; |
465 if (vdp_port < 4) { | 455 if (vdp_port < 4) { |
466 ret = vdp_data_port_read(gen->vdp); | 456 ret = vdp_data_port_read(gen->vdp); |
467 } else if (vdp_port < 8) { | 457 } else if (vdp_port < 8) { |
468 ret = vdp_control_port_read(gen->vdp); | 458 ret = vdp_control_port_read(gen->vdp); |
469 } else { | 459 } else { |
470 printf("Illegal write to HV Counter port %X\n", vdp_port); | 460 fatal_error("Illegal write to HV Counter port %X\n", vdp_port); |
471 exit(1); | |
472 } | 461 } |
473 } else { | 462 } else { |
474 //TODO: Figure out the correct value today | 463 //TODO: Figure out the correct value today |
475 ret = 0xFFFF; | 464 ret = 0xFFFF; |
476 } | 465 } |
505 gen->z80->mem_pointers[1] = (gen->z80->bank_reg << 15) + ((char *)gen->z80->mem_pointers[2]); | 494 gen->z80->mem_pointers[1] = (gen->z80->bank_reg << 15) + ((char *)gen->z80->mem_pointers[2]); |
506 } else { | 495 } else { |
507 gen->z80->mem_pointers[1] = NULL; | 496 gen->z80->mem_pointers[1] = NULL; |
508 } | 497 } |
509 } else { | 498 } else { |
510 printf("68K write to unhandled Z80 address %X\n", location); | 499 fatal_error("68K write to unhandled Z80 address %X\n", location); |
511 exit(1); | |
512 } | 500 } |
513 } | 501 } |
514 } else { | 502 } else { |
515 location &= 0x1FFF; | 503 location &= 0x1FFF; |
516 if (location < 0x100) { | 504 if (location < 0x100) { |
845 } | 833 } |
846 | 834 |
847 if (statefile) { | 835 if (statefile) { |
848 uint32_t pc = load_gst(gen, statefile); | 836 uint32_t pc = load_gst(gen, statefile); |
849 if (!pc) { | 837 if (!pc) { |
850 fprintf(stderr, "Failed to load save state %s\n", statefile); | 838 fatal_error("Failed to load save state %s\n", statefile); |
851 exit(1); | |
852 } | 839 } |
853 printf("Loaded %s\n", statefile); | 840 printf("Loaded %s\n", statefile); |
854 if (debugger) { | 841 if (debugger) { |
855 insert_breakpoint(context, pc, debugger); | 842 insert_breakpoint(context, pc, debugger); |
856 } | 843 } |
905 }; | 892 }; |
906 #endif | 893 #endif |
907 | 894 |
908 int main(int argc, char ** argv) | 895 int main(int argc, char ** argv) |
909 { | 896 { |
910 if (argc < 2) { | |
911 fputs("Usage: blastem [OPTIONS] ROMFILE [WIDTH] [HEIGHT]\n", stderr); | |
912 return 1; | |
913 } | |
914 set_exe_str(argv[0]); | 897 set_exe_str(argv[0]); |
915 config = load_config(); | 898 config = load_config(); |
916 int width = -1; | 899 int width = -1; |
917 int height = -1; | 900 int height = -1; |
918 int debug = 0; | 901 int debug = 0; |
929 if (argv[i][0] == '-') { | 912 if (argv[i][0] == '-') { |
930 switch(argv[i][1]) { | 913 switch(argv[i][1]) { |
931 case 'b': | 914 case 'b': |
932 i++; | 915 i++; |
933 if (i >= argc) { | 916 if (i >= argc) { |
934 fputs("-b must be followed by a frame count\n", stderr); | 917 fatal_error("-b must be followed by a frame count\n"); |
935 return 1; | |
936 } | 918 } |
937 headless = 1; | 919 headless = 1; |
938 exit_after = atoi(argv[i]); | 920 exit_after = atoi(argv[i]); |
939 break; | 921 break; |
940 case 'd': | 922 case 'd': |
952 break; | 934 break; |
953 case 'l': | 935 case 'l': |
954 address_log = fopen("address.log", "w"); | 936 address_log = fopen("address.log", "w"); |
955 break; | 937 break; |
956 case 'v': | 938 case 'v': |
957 printf("blastem %s\n", BLASTEM_VERSION); | 939 info_message("blastem %s\n", BLASTEM_VERSION); |
958 return 0; | 940 return 0; |
959 break; | 941 break; |
960 case 'n': | 942 case 'n': |
961 z80_enabled = 0; | 943 z80_enabled = 0; |
962 break; | 944 break; |
963 case 'r': | 945 case 'r': |
964 i++; | 946 i++; |
965 if (i >= argc) { | 947 if (i >= argc) { |
966 fputs("-r must be followed by region (J, U or E)\n", stderr); | 948 fatal_error("-r must be followed by region (J, U or E)\n"); |
967 return 1; | |
968 } | 949 } |
969 force_version = translate_region_char(toupper(argv[i][0])); | 950 force_version = translate_region_char(toupper(argv[i][0])); |
970 if (!force_version) { | 951 if (!force_version) { |
971 fprintf(stderr, "'%c' is not a valid region character for the -r option\n", argv[i][0]); | 952 fatal_error("'%c' is not a valid region character for the -r option\n", argv[i][0]); |
972 return 1; | |
973 } | 953 } |
974 break; | 954 break; |
975 case 's': | 955 case 's': |
976 i++; | 956 i++; |
977 if (i >= argc) { | 957 if (i >= argc) { |
978 fputs("-s must be followed by a savestate filename\n", stderr); | 958 fatal_error("-s must be followed by a savestate filename\n"); |
979 return 1; | |
980 } | 959 } |
981 statefile = argv[i]; | 960 statefile = argv[i]; |
982 break; | 961 break; |
983 case 'y': | 962 case 'y': |
984 ym_log = 1; | 963 ym_log = 1; |
985 break; | 964 break; |
986 case 'h': | 965 case 'h': |
987 puts( | 966 info_message( |
988 "Usage: blastem [OPTIONS] ROMFILE [WIDTH] [HEIGHT]\n" | 967 "Usage: blastem [OPTIONS] ROMFILE [WIDTH] [HEIGHT]\n" |
989 "Options:\n" | 968 "Options:\n" |
990 " -h Print this help text\n" | 969 " -h Print this help text\n" |
991 " -r (J|U|E) Force region to Japan, US or Europe respectively\n" | 970 " -r (J|U|E) Force region to Japan, US or Europe respectively\n" |
992 " -f Start in fullscreen mode\n" | 971 " -f Start in fullscreen mode\n" |
998 " -l Log 68K code addresses (useful for assemblers)\n" | 977 " -l Log 68K code addresses (useful for assemblers)\n" |
999 " -y Log individual YM-2612 channels to WAVE files\n" | 978 " -y Log individual YM-2612 channels to WAVE files\n" |
1000 ); | 979 ); |
1001 return 0; | 980 return 0; |
1002 default: | 981 default: |
1003 fprintf(stderr, "Unrecognized switch %s\n", argv[i]); | 982 fatal_error("Unrecognized switch %s\n", argv[i]); |
1004 return 1; | |
1005 } | 983 } |
1006 } else if (!loaded) { | 984 } else if (!loaded) { |
1007 if (!(rom_size = load_rom(argv[i]))) { | 985 if (!(rom_size = load_rom(argv[i]))) { |
1008 fprintf(stderr, "Failed to open %s for reading\n", argv[i]); | 986 fatal_error("Failed to open %s for reading\n", argv[i]); |
1009 return 1; | |
1010 } | 987 } |
1011 romfname = argv[i]; | 988 romfname = argv[i]; |
1012 loaded = 1; | 989 loaded = 1; |
1013 } else if (width < 0) { | 990 } else if (width < 0) { |
1014 width = atoi(argv[i]); | 991 width = atoi(argv[i]); |
1015 } else if (height < 0) { | 992 } else if (height < 0) { |
1016 height = atoi(argv[i]); | 993 height = atoi(argv[i]); |
1017 } | 994 } |
1018 } | 995 } |
1019 if (!loaded) { | 996 if (!loaded) { |
1020 fputs("You must specify a ROM filename!\n", stderr); | 997 fatal_error("Usage: blastem [OPTIONS] ROMFILE [WIDTH] [HEIGHT]\n"); |
1021 return 1; | |
1022 } | 998 } |
1023 tern_node *rom_db = load_rom_db(); | 999 tern_node *rom_db = load_rom_db(); |
1024 rom_info info = configure_rom(rom_db, cart, rom_size, base_map, sizeof(base_map)/sizeof(base_map[0])); | 1000 rom_info info = configure_rom(rom_db, cart, rom_size, base_map, sizeof(base_map)/sizeof(base_map[0])); |
1025 byteswap_rom(rom_size); | 1001 byteswap_rom(rom_size); |
1026 set_region(&info, force_version); | 1002 set_region(&info, force_version); |