PC port: phase 1.5 — ROM dump verification groundwork

No-Intro 'GoldenEye 007 (U) [!].z64' placed in data/ and verified
byte-identical (MD5 70c52588...) to the dev ROM copies
(data/ge007.ntsc-final.z64, baserom.u.z64). Header magic/title/country
check out; embedded CRCs DCBC50D1/09FD1AA3 re-computed and matched via
tools/n64cksum.c's CIC-6102 routine.

Adds tools_pc/romverify.c: one-shot integrity check (size, GE header
magic at 0x00, title, country byte, CRC1/CRC2) so any future ROM swap
is detectable in seconds. Fingerprint + provenance recorded in
docs/HANDOFF.md; gitignore the built romverify.exe.
This commit is contained in:
James Dansereau committed 2026-08-21 20:29:03 -04:00
1 parent 8482ba3ed1
commit bd56cff073
3 files changed
+84

No files matched your search

+1
View File
@@ -70,6 +70,7 @@ notes/*
# PC port (see CMakeLists.txt / port/) # PC port (see CMakeLists.txt / port/)
build-pc/ build-pc/
tools_pc/*.exe
data/ data/
ge007.ini ge007.ini
!build/test.c !build/test.c
+6
View File
@@ -96,6 +96,12 @@ fixup loop's pointer stride on x86-64**; rebuild; confirm boot advances. Log eac
`export PATH="/c/msys64/mingw64/bin:$PATH"`. `export PATH="/c/msys64/mingw64/bin:$PATH"`.
- Build: `./build-pc.sh ntsc-final` (incremental; full rebuild only when `port/shim/` - Build: `./build-pc.sh ntsc-final` (incremental; full rebuild only when `port/shim/`
changes). ROM is at `data/ge007.ntsc-final.z64` (= `baserom.u.z64`, byte-identical). changes). ROM is at `data/ge007.ntsc-final.z64` (= `baserom.u.z64`, byte-identical).
- ROM provenance (verified 2026-08): all three copies are byte-identical to the No-Intro
good dump `GoldenEye 007 (U) [!].z64` (kept in `data/`). MD5
`70c525880240c1e838b8b1be35666c3b`, SHA-256
`2cdcec8a9f0cb6e36337f3ee39d8ad105dc8afa6ba1c02d466e8f5b771f9a162`, 0xC00000 bytes,
country 'E' (US). Header CRCs DCBC50D1/09FD1AA3 re-verify with
`tools_pc/romverify.exe` (build line in its header comment).
- gdb: **launch** mode only (`gdb -batch -ex "handle SIGSEGV stop" -ex run …`). Symbolicate - gdb: **launch** mode only (`gdb -batch -ex "handle SIGSEGV stop" -ex run …`). Symbolicate
offline with `addr2line -e build-pc/ge007.x86_64.exe -f -C <0x140000000+rel>`. Image base offline with `addr2line -e build-pc/ge007.x86_64.exe -f -C <0x140000000+rel>`. Image base
is `0x140000000` (re-verify with `info address` after a rebuild). is `0x140000000` (re-verify with `info address` after a rebuild).
+77
View File
@@ -0,0 +1,77 @@
// romverify.c — one-shot ROM integrity check for the PC port.
//
// Verifies a .z64 against the repo's ground truths without modifying it:
// 1. size (must be >= 0x100000, the n64cksum coverage window)
// 2. GE header magic 80 37 12 40 at 0x00 (src/rom_header.s, port/src/romdata.c)
// 3. title "GOLDENEYE" at 0x20
// 4. country byte at 0x3E (E=US/LANG_US, P=EU, J=JP)
// 5. embedded checksums at 0x10/0x14 vs n64cksum_calc_6102() over [0x1000, 0x100000)
// (tools/n64cksum.c — the exact routine the N64 build pipeline uses)
//
// Build (from tools_pc/): gcc -O2 -I../tools romverify.c ../tools/n64cksum.c
// ../tools/utils.c -o romverify.exe
// Usage: ./romverify.exe <file.z64>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "n64cksum.h"
#include "utils.h"
int main(int argc, char **argv)
{
if (argc != 2) {
fprintf(stderr, "usage: %s <file.z64>\n", argv[0]);
return 2;
}
unsigned char *rom;
long len = read_file(argv[1], &rom);
if (len < 0) {
fprintf(stderr, "FAIL: cannot read %s\n", argv[1]);
return 2;
}
int fail = 0;
#define CHECK(cond, ...) do { \
printf(" [%s] ", (cond) ? "ok " : "FAIL"); \
printf(__VA_ARGS__); \
printf("\n"); \
if (!(cond)) fail = 1; \
} while (0)
printf("ROM: %s (%ld bytes)\n", argv[1], len);
CHECK(len >= 0x100000, "size >= 0x100000 (got 0x%lX)", (unsigned long)len);
if (fail) { free(rom); return 1; }
const uint8_t *h = rom;
static const uint8_t magic[4] = { 0x80, 0x37, 0x12, 0x40 };
CHECK(memcmp(h, magic, 4) == 0,
"magic at 0x00 = %02x%02x%02x%02x (want 80371240)",
h[0], h[1], h[2], h[3]);
CHECK(memcmp(h + 0x20, "GOLDENEYE", 9) == 0, "title at 0x20 starts \"GOLDENEYE\"");
char country = (char)h[0x3E];
const char *cname = (country == 'E') ? "US (LANG_US)" :
(country == 'P') ? "EU (LANG_EU)" :
(country == 'J') ? "JP (LANG_JP)" : "?";
printf(" [info] country byte at 0x3E = '%c' -> %s\n", country, cname);
uint32_t stored1 = ((uint32_t)h[0x10] << 24) | ((uint32_t)h[0x11] << 16) |
((uint32_t)h[0x12] << 8) | (uint32_t)h[0x13];
uint32_t stored2 = ((uint32_t)h[0x14] << 24) | ((uint32_t)h[0x15] << 16) |
((uint32_t)h[0x16] << 8) | (uint32_t)h[0x17];
unsigned int calc[2];
n64cksum_calc_6102(rom, calc);
CHECK(calc[0] == stored1, "CRC1: header 0x%08X vs computed 0x%08X", stored1, calc[0]);
CHECK(calc[1] == stored2, "CRC2: header 0x%08X vs computed 0x%08X", stored2, calc[1]);
free(rom);
printf(fail ? "RESULT: FAIL\n" : "RESULT: PASS\n");
return fail;
}