|
@@ -4,6 +4,7 @@ |
|
|
#include <ctype.h> |
|
|
#include <ctype.h> |
|
|
#include <errno.h> |
|
|
#include <errno.h> |
|
|
#include <stdio.h> |
|
|
#include <stdio.h> |
|
|
|
|
|
#include <stdbool.h> |
|
|
#include <stdlib.h> |
|
|
#include <stdlib.h> |
|
|
#include <string.h> |
|
|
#include <string.h> |
|
|
#include <sys/stat.h> |
|
|
#include <sys/stat.h> |
|
@@ -56,12 +57,16 @@ static void print_header(const uint8_t *header) |
|
|
#endif |
|
|
#endif |
|
|
|
|
|
|
|
|
/* |
|
|
/* |
|
|
Determine whether the checksum indicated in the ROM file is valid. |
|
|
|
|
|
|
|
|
Compute the correct ROM data checksum. |
|
|
|
|
|
|
|
|
|
|
|
If the summable region (as specified by the range parameter) is too large, |
|
|
|
|
|
we'll compute the checksum over the default range (0x0000-0x7FF0), or the |
|
|
|
|
|
largest possible range. |
|
|
*/ |
|
|
*/ |
|
|
static bool validate_checksum(const uint8_t *data, uint16_t checksum, uint8_t size) |
|
|
|
|
|
|
|
|
static uint16_t compute_checksum(const uint8_t *data, size_t size, uint8_t range) |
|
|
{ |
|
|
{ |
|
|
size_t low_region, high_region; |
|
|
size_t low_region, high_region; |
|
|
switch (size) { |
|
|
|
|
|
|
|
|
switch (range & 0xF) { |
|
|
case 0xA: low_region = 0x1FEF; high_region = 0; break; |
|
|
case 0xA: low_region = 0x1FEF; high_region = 0; break; |
|
|
case 0xB: low_region = 0x3FEF; high_region = 0; break; |
|
|
case 0xB: low_region = 0x3FEF; high_region = 0; break; |
|
|
case 0xC: low_region = 0x7FEF; high_region = 0; break; |
|
|
case 0xC: low_region = 0x7FEF; high_region = 0; break; |
|
@@ -71,9 +76,14 @@ static bool validate_checksum(const uint8_t *data, uint16_t checksum, uint8_t si |
|
|
case 0x0: low_region = 0x7FEF; high_region = 0x3FFFF; break; |
|
|
case 0x0: low_region = 0x7FEF; high_region = 0x3FFFF; break; |
|
|
case 0x1: low_region = 0x7FEF; high_region = 0x7FFFF; break; |
|
|
case 0x1: low_region = 0x7FEF; high_region = 0x7FFFF; break; |
|
|
case 0x2: low_region = 0x7FEF; high_region = 0xFFFFF; break; |
|
|
case 0x2: low_region = 0x7FEF; high_region = 0xFFFFF; break; |
|
|
default: return false; |
|
|
|
|
|
|
|
|
default: low_region = 0x7FEF; high_region = 0; break; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (low_region >= size) |
|
|
|
|
|
low_region = (size >= 0x4000) ? 0x3FEF : 0x1FEF; |
|
|
|
|
|
if (high_region >= size) |
|
|
|
|
|
high_region = 0; |
|
|
|
|
|
|
|
|
uint16_t sum = 0; |
|
|
uint16_t sum = 0; |
|
|
for (size_t index = 0; index <= low_region; index++) |
|
|
for (size_t index = 0; index <= low_region; index++) |
|
|
sum += data[index]; |
|
|
sum += data[index]; |
|
@@ -81,7 +91,7 @@ static bool validate_checksum(const uint8_t *data, uint16_t checksum, uint8_t si |
|
|
for (size_t index = 0x08000; index <= high_region; index++) |
|
|
for (size_t index = 0x08000; index <= high_region; index++) |
|
|
sum += data[index]; |
|
|
sum += data[index]; |
|
|
} |
|
|
} |
|
|
return sum == checksum; |
|
|
|
|
|
|
|
|
return sum; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#ifdef DEBUG_MODE |
|
|
#ifdef DEBUG_MODE |
|
@@ -136,22 +146,24 @@ static bool parse_header(ROM *rom, const uint8_t *header) |
|
|
print_header(header); |
|
|
print_header(header); |
|
|
#endif |
|
|
#endif |
|
|
|
|
|
|
|
|
uint8_t size = header[0xF] & 0xF; |
|
|
|
|
|
rom->checksum = header[0xA] + (header[0xB] << 8); |
|
|
|
|
|
rom->valid_checksum = validate_checksum(rom->data, rom->checksum, size); |
|
|
|
|
|
|
|
|
rom->reported_checksum = header[0xA] + (header[0xB] << 8); |
|
|
|
|
|
rom->expected_checksum = compute_checksum(rom->data, rom->size, header[0xF]); |
|
|
rom->product_code = bcd_decode(header[0xC]) + |
|
|
rom->product_code = bcd_decode(header[0xC]) + |
|
|
(bcd_decode(header[0xD]) * 100) + ((header[0xE] >> 4) * 10000); |
|
|
(bcd_decode(header[0xD]) * 100) + ((header[0xE] >> 4) * 10000); |
|
|
rom->version = header[0xE] & 0x0F; |
|
|
rom->version = header[0xE] & 0x0F; |
|
|
rom->region_code = header[0xF] >> 4; |
|
|
rom->region_code = header[0xF] >> 4; |
|
|
const char* region = rom_region(rom); |
|
|
|
|
|
|
|
|
|
|
|
DEBUG("- header info:") |
|
|
DEBUG("- header info:") |
|
|
DEBUG(" - checksum: 0x%04X (%s)", rom->checksum, |
|
|
|
|
|
rom->valid_checksum ? "valid" : "invalid") |
|
|
|
|
|
|
|
|
if (rom->reported_checksum == rom->expected_checksum) |
|
|
|
|
|
DEBUG(" - checksum: 0x%04X (valid)", rom->reported_checksum) |
|
|
|
|
|
else |
|
|
|
|
|
DEBUG(" - checksum: 0x%04X (invalid, expected 0x%04X)", |
|
|
|
|
|
rom->reported_checksum, rom->expected_checksum) |
|
|
DEBUG(" - product code: %u", rom->product_code) |
|
|
DEBUG(" - product code: %u", rom->product_code) |
|
|
DEBUG(" - version: %u", rom->version) |
|
|
DEBUG(" - version: %u", rom->version) |
|
|
DEBUG(" - region code: %u (%s)", rom->region_code, region ? region : "unknown") |
|
|
|
|
|
DEBUG(" - reported size: %s", parse_reported_size(size)) |
|
|
|
|
|
|
|
|
DEBUG(" - region code: %u (%s)", rom->region_code, |
|
|
|
|
|
rom_region(rom) ? rom_region(rom) : "unknown") |
|
|
|
|
|
DEBUG(" - reported size: %s", parse_reported_size(header[0xF] & 0xF)) |
|
|
return true; |
|
|
return true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@@ -216,8 +228,8 @@ const char* rom_open(ROM **rom_ptr, const char *path) |
|
|
rom->name = NULL; |
|
|
rom->name = NULL; |
|
|
rom->data = NULL; |
|
|
rom->data = NULL; |
|
|
rom->size = 0; |
|
|
rom->size = 0; |
|
|
rom->checksum = 0; |
|
|
|
|
|
rom->valid_checksum = false; |
|
|
|
|
|
|
|
|
rom->reported_checksum = 0; |
|
|
|
|
|
rom->expected_checksum = 0; |
|
|
rom->product_code = 0; |
|
|
rom->product_code = 0; |
|
|
rom->version = 0; |
|
|
rom->version = 0; |
|
|
rom->region_code = 0; |
|
|
rom->region_code = 0; |
|
|