From 1abeed9abb637cac2adc9964801af343b9beb1ff Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Tue, 23 Apr 2024 00:53:06 -0400 Subject: rom2cart: warn on bad checksum, add -H option for testing. --- rom2cart.c | 43 ++++++++++++++++++++++++++++++++++--------- rom2cart.rst | 29 +++++++++++++++++++++-------- 2 files changed, 55 insertions(+), 17 deletions(-) diff --git a/rom2cart.c b/rom2cart.c index 7eaaa06..4126c81 100644 --- a/rom2cart.c +++ b/rom2cart.c @@ -70,6 +70,7 @@ char *usage = " -T type Like -t, but forces the type. Numeric type only.\n" " -C sum Force the checksum to sum. Not very useful.\n" " -U data Set 'unused' bytes in CART header to data.\n" + " -H Test code heuristics (developer option).\n" "\n" "infile may be either a raw dump or a CART image, and may be '-' to read\n" "from standard input. outfile may be omitted, in which case output will\n" @@ -77,7 +78,7 @@ char *usage = ".car (or .rom, if -r given). outfile may be '-' to write to standard\n" "output.\n"; -#define OPTIONS "vchlm:nT:t:C:rU:" +#define OPTIONS "vchlm:nT:t:C:rU:H" void print_type_table(int *set) { /* print a nicely-formatted type table. If set is NULL, print all types, @@ -87,7 +88,7 @@ void print_type_table(int *set) { "Type", "Machine", "SizeKB", "Name"); fprintf(stderr, "------|----------|--------|------------------------\n"); for(i=1; i<=MAX_CART_TYPE; i++) { - if(set == NULL || set[i]) + if(cart_types[i].machine != M_INVALID && (set == NULL || set[i])) fprintf(stderr, "%5d | %8s | %6d | %s\n", i, (cart_types[i].machine == M_5200 ? "5200" : "8-bit"), @@ -184,10 +185,15 @@ machine_t code_heuristics(unsigned char *rom, int size, int verbose) { SELF ": found %d probable 5200 POKEY writes\n", a52); } - if(a8 >= 3 && a52 <= 1) + if(a8 >= 3 && a52 <= 1) { machine = M_ATARI8; - else if(a52 >= 3 && a8 <= 1) + fprintf(stderr, SELF ": code_heuristics() returning M_ATARI8\n"); + } else if(a52 >= 3 && a8 <= 1) { machine = M_5200; + fprintf(stderr, SELF ": code_heuristics() returning M_5200\n"); + } else { + fprintf(stderr, SELF ": code_heuristics() returning M_INVALID\n"); + } return machine; } @@ -277,7 +283,7 @@ int determine_type( else return 0; /* bogus -T */ } else { - if(!type || type > MAX_CART_TYPE) { + if(!type || type > MAX_CART_TYPE || cart_types[type].machine == M_INVALID) { fprintf(stderr, "Invalid numeric type '%d' for -t (valid types " "are 1 to %d; use -l for list)\n", type, MAX_CART_TYPE); return 0; @@ -307,7 +313,7 @@ int determine_type( fprintf(stderr, SELF ": trying to match '%s'\n", type_param); for(i=1; i<=MAX_CART_TYPE; i++) { - if(string_match(cart_types[i].name, type_param)) { + if(cart_types[i].machine != M_INVALID && string_match(cart_types[i].name, type_param)) { if(verbose > 1) fprintf(stderr, SELF ": matched type %d (%s)\n", i, cart_types[i].name); @@ -439,7 +445,7 @@ int main(int argc, char **argv) { int check_only = 0, type = 0, type_override = 0, allow_guess = 1, verbose = 0, raw_output = 0; machine_t machine = M_INVALID; - int c, size; + int c, size, test_heuristics = 0, raw_input = 0; unsigned int cksum = 0, cksum_override = 0, unused_data = 0; unsigned char *buffer; unsigned char **bufp = &buffer; @@ -508,6 +514,11 @@ int main(int argc, char **argv) { raw_output++; break; + case 'H': + test_heuristics++; + verbose = 2; + break; + default: fputs(BANNER, stderr); fprintf(stderr, usage); @@ -555,6 +566,7 @@ int main(int argc, char **argv) { } else { rom = buffer; if(verbose) fprintf(stderr, SELF ": input is raw dump, %d bytes\n", size); + raw_input++; } if(size <= 0) { @@ -587,12 +599,25 @@ int main(int argc, char **argv) { when there's only 8K of actual ROM. */ memcpy(cart, CART_SIGNATURE, 4); set_cart_type(cart, type); - if(!cksum_override) + if(!cksum_override) { cksum = calc_rom_checksum(buffer, size); + if(!raw_input) { + int oldsum = get_cart_checksum(buffer); + if(oldsum != cksum) { + fprintf(stderr, SELF ": stored checksum %08x doesn't match calculated %08x, fixing.\n", oldsum, cksum); + } + } + } set_cart_checksum(cart, cksum); set_cart_unused(cart, unused_data); - if(verbose > 1) cart_dump_header(cart, 0); + if(verbose > 1 && !(check_only && raw_input)) cart_dump_header(cart, 0); + + if(test_heuristics) { + fprintf(stderr, SELF ": testing code_heuristics() and exiting.\n"); + (void)code_heuristics(buffer, size, verbose); + exit(0); + } if(!check_only) { if(optind < argc) { diff --git a/rom2cart.rst b/rom2cart.rst index 0edc57d..580d77b 100644 --- a/rom2cart.rst +++ b/rom2cart.rst @@ -22,7 +22,7 @@ SYNOPSIS DESCRIPTION =========== -**rom2cart** converts between raw ROM dumps and Atari800 **.CAR** +**rom2cart** converts between raw ROM dumps and Atari800 **.CAR** images. Despite the name, conversion can be done in either direction. **cart2rom** is equivalent to **rom2cart -r**. @@ -36,7 +36,7 @@ content), and (optional) user-supplied type number or name (**-t**). If **rom2cart** is unable to narrow the selection down to one image type, it will "guess" by choosing the lowest-numbered type that matches the given parameters (unless **-n** is given to prevent -this behavior). +this behavior, in which case it will exit with an error message). When writing a **.CAR** file, **rom2cart** will calculate the checksum automatically and store it in the **CART** header (unless **-C** is @@ -121,6 +121,13 @@ useful for debugging **rom2cart** or Atari800 itself. (prefixed with $ or 0x) or decimal (no prefix). This option has no effect if the output is a raw dump (**-r** option). +-H + Test the code-detection heuristics: examine the first 8K of the ROM and + look for writes to $D2xx (8-bit computer) or $E8xx (5200) to guess the + machine type for the ROM. This option exists only for testing: normally, + the machine type gets guessed by the cartridge option bytes, and the + code-detection is only done if the option byte tests are inconclusive. + NOTES ===== @@ -134,7 +141,7 @@ be constructed from *infile* by replacing the filename extension with is no extension. **rom2cart** contains an internal database of image types. The current -version uses the list from Atari800 v2.0.3 (types 1-43). If you +version uses the list from Atari800 v5.2.0 (types 1-103 and 160). If you need to create a **.CAR** image of a type not supported in this version of **rom2cart**, you can use the **-T** option. Alternatively, look for a newer version of **rom2cart**. If no new version exists, bug the @@ -158,15 +165,21 @@ A **.CAR** image consists of a 16-byte header followed by the ROM data. The first 4 bytes contain 'C' 'A' 'R' 'T' in ASCII. -The next 4 bytes contain the cartridge type in MSB (aka -*big-endian*) format. +The next 4 bytes contain the cartridge type in MSB (aka *big-endian*) +32-bit integer format. -The next 4 bytes contain cartridge checksum in MSB format (ROM only). +The next 4 bytes contain cartridge checksum in MSB format (ROM only; +the header is not checksummed). The next 4 bytes are currently unused (zero). -The rest of the file contains the ROM data: 4, 8, 16, 32, 40, 64, 128, -256, 512 or 1024 kilobytes. +The rest of the file contains the ROM data, up to 32Mbytes as of +Atari800 5.2.0. The cartridge type determines the amount of data; see +*cart.txt* or the output of **rom2cart -l**. + +The latest version of *cart.txt* can be found at: + + https://raw.githubusercontent.com/atari800/atari800/master/DOC/cart.txt HEURISTICS ========== -- cgit v1.2.3