bfirsh / bfirsh/jsnes

ROM loader: header zeroing heuristic breaks NES 2.0 ROMs

Open
#593 0 comments 0 reactions 0 assignees View on GitHub
bug component: rom difficulty: medium priority: high
Dominant language
JavaScript
Stars
6.4k
Forks
857
PR merge metrics
No merged PRs in 30d

Description

## Summary

If any byte from 8-15 in the iNES header is non-zero, the code masks the mapper number to 4 bits (0-15 only), ignoring the high nibble from byte 7. This was a reasonable heuristic for early iNES dumps with garbage in the unused header bytes (like "DiskDude!"), but it breaks NES 2.0 ROMs which legitimately use bytes 8-15.

## Current behavior

```javascript
// rom.js:61-70
let foundError = false;
for (i = 8; i < 16; i++) {
if (this.header[i] !== 0) { foundError = true; break; }
}
if (foundError) {
this.mapperType &= 0xf; // Ignore byte 7
}
```

NES 2.0 ROMs use bytes 8-15 for:
- Submapper numbers (critical for distinguishing MMC3 variants, bus-conflict boards)
- Extended mapper numbers (>255)
- PRG-RAM/CHR-RAM size
- NTSC/PAL timing mode

## Expected behavior

Detect NES 2.0 first and only apply the heuristic for iNES 1.0:

```javascript
if ((this.header[7] & 0x0C) === 0x08) {
// NES 2.0: parse extended fields, don't apply zeroing heuristic
} else {
// iNES 1.0: apply the header zeroing heuristic
}
```

## References

- [NES 2.0 format](https://www.nesdev.org/wiki/NES_2.0)
- [NES 2.0 submappers](https://www.nesdev.org/wiki/NES_2.0_submappers)

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.