Skip to content

Upgrade to NES2.0 header #101

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ ROM CRC32: 1394F57E

A link to the BPS can be found on the [releases page](https://github.com/kirjavascript/TetrisGYM/releases).

The BPS produces a file with an MMC1 header, but it also works when treated as CNROM.
The BPS produces a file with its header specifying MMC1 with fixed PRG (mapper 1:5), but it also works when specified as CNROM with bus conflicts (mapper 3:2).

If you are using a PowerPak, you will need to install an [alternate N.MAP loader](https://forums.nesdev.org/viewtopic.php?p=283943#p283943) so its header check passes.

## Trainers

Expand Down
6 changes: 6 additions & 0 deletions build.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ if (args.includes('-h')) {
-k Famicom Keyboard support
-w force WASM compiler
-c force PNG to CHR conversion
-i use iNES header instead of NES2.0
-o override autodetect mmc1 header with cnrom
-t run tests (requires cargo)
-h you are here
Expand Down Expand Up @@ -82,6 +83,11 @@ if (args.includes('-s')) {
console.log('highscore saving disabled');
}

if (args.includes('-i')) {
compileFlags.push('-D', 'INES_OVERRIDE=1');
console.log('iNES header override');
}

if (args.includes('-o')) {
compileFlags.push('-D', 'CNROM_OVERRIDE=1');
console.log('cnrom override for autodetect');
Expand Down
4 changes: 4 additions & 0 deletions src/constants.asm
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ AUTO_WIN := 0
KEYBOARD := 0
.endif

.ifndef INES_OVERRIDE
INES_OVERRIDE := 0
.endif

.ifndef CNROM_OVERRIDE
CNROM_OVERRIDE := 0
.endif
Expand Down
41 changes: 35 additions & 6 deletions src/header.asm
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
;
; iNES header
; NES2.0 header
; https://www.nesdev.org/wiki/NES_2.0
;

; This iNES header is from Brad Smith (rainwarrior)
; iNES header adapted from Brad Smith (rainwarrior)
; https://github.com/bbbradsmith/NES-ca65-example

.segment "HEADER"

.include "constants.asm" ; for INES_HEADER

INES_MIRROR = 0 ; 0 = horizontal mirroring, 1 = vertical mirroring (ignored in MMC1)
INES_SRAM = 1 ; 1 = battery backed SRAM at $6000-7FFF
INES_SRAM = SAVE_HIGHSCORES ; 1 = battery backed SRAM at $6000-7FFF
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should probably add a HAS_SRAM flag for clarity

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should that flag be a new addition, or should it replace an existing flag? I think replacing SAVE_HIGHSCORES would make the most sense here. The header should ideally be a set-and-forget kind of thing in my opinion.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be an additional flag so the saving highscores can be disabled separately if needed.

In a newer version we might decide to remove or replace it and leaving the name makes it easier to remove.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the HAS_SRAM flag but disabling it is currently lumped with the -s build flag.

NES2_SRAM_SHIFT = INES_SRAM * 7 ; if SRAM present, set shift to 7 for (64 << 7) = 8KiB size
NES2_REGION = 2 ; 0 = NTSC, 1 = PAL, 2 = multi-region, 3 = UA6538 ("Dendy")

; Pick default expansion device
.if KEYBOARD = 1
NES2_INPUT = $23 ; Family BASIC Keyboard
.else
NES2_INPUT = 1 ; standard NES/FC controllers
.endif

; Override INES_MAPPER for mode 1000 (auto detect)
.if INES_MAPPER = 1000
Expand All @@ -20,12 +30,31 @@ INES_SRAM = 1 ; 1 = battery backed SRAM at $6000-7FFF
_INES_MAPPER = 1 ; MMC1 for Emulator/Flashcart
.endif
.else
_INES_MAPPER = INES_MAPPER ; use actual INES_MAPPER otherwise
_INES_MAPPER = INES_MAPPER ; use actual INES_MAPPER otherwise
.endif

; Pick the appropriate NES2_SUBMAPPER
.if _INES_MAPPER = 1
NES2_SUBMAPPER = 5 ; MMC1 fixed PRG
.elseif _INES_MAPPER = 3
NES2_SUBMAPPER = 2 ; CNROM bus conflicts
.else
NES2_SUBMAPPER = 0 ; otherwise don't specify submapper
.endif

; Construct header
.byte 'N', 'E', 'S', $1A ; ID
.byte $02 ; 16k PRG chunk count
.byte $02 ; 8k CHR chunk count
.byte INES_MIRROR | (INES_SRAM << 1) | ((_INES_MAPPER & $f) << 4)
.byte (_INES_MAPPER & %11110000)
.byte $0, $0, $0, $0, $0, $0, $0, $0 ; padding

.if INES_OVERRIDE = 0
.byte (_INES_MAPPER & %11110000) | %00001000 ; NES2.0 header identifier
.byte ((NES2_SUBMAPPER & $f) << 4) | ((_INES_MAPPER & $f00) >> 8) ; submapper/mapper MSB
.byte $0, (NES2_SRAM_SHIFT << 4) ; PRG MSB, SRAM shift count
.byte $0, NES2_REGION, $0, $0, NES2_INPUT ; misc. fields, region, input device
.else
.byte (_INES_MAPPER & %11110000)
.byte $0, $0, $0, $0, $0, $0, $0, $0 ; padding
.endif