Skip to content
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