mirror of
https://github.com/jkdansereau/goldeneye-pc-port.git
synced 2026-10-23 15:52:42 +02:00
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:
1 parent
8482ba3ed1
commit
bd56cff073
3 files changed
+84
No files matched your search
@@ -70,6 +70,7 @@ notes/*
|
||||
|
||||
# PC port (see CMakeLists.txt / port/)
|
||||
build-pc/
|
||||
tools_pc/*.exe
|
||||
data/
|
||||
ge007.ini
|
||||
!build/test.c
|
||||
|
||||
@@ -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"`.
|
||||
- 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).
|
||||
- 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
|
||||
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).
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in new issue
Block a user