NES Programming Tutorial : iNES Header

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
NES Programming Tutorial : iNES Header
by on (#190908)
Code:
;NES Programming Tutorial
;Level 2 : iNES Header
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Constants
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Variables
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;iNES header data (16bytes)
;32KB PRG + 8KB CHR + NROM-256 + Vertical Mirroring
  .db $4E,$45,$53,$1A,$02,$01,$01,$00
  .db $00,$00,$00,$00,$00,$00,$00,$00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;PRG codes $8000 ~ $FFFF (32KB)
  .base $8000
  ;user codes
  .pad $10000,$FF
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;CHR data $0000 ~ $1FFF (8KB)
  .base $0000
  ;graphic data
  .pad $2000,$FF


Explanation :

* The first 16KB of a nes game is header info which is used just by emulators to run the game. It gives information about PRG size, CHR size, Mapper number, Mirroring, etc.

* I setup the header to : 32KB PRG + 8KB CHR + NROM-256 + Vertical Mirroring.

* Need more info about iNES header? then read this : INES

* lines starting with . are directive commands of assembler

* .db puts a value in the file directly.

* .base $8000 is another directive command. It tells the assembler that the following commands will be loaded into $8000 of CPU. So labels addresses are adjusted according to $8000

* .pad $10000,$FF is another directive command. It fills the remaining empty space of memory up to $10000 with the value of #$FF

* We need an assembler (ASM6) to convert the source code of assembly language (Game.asm) to object code of machine language (Game.nes) so that you can run it on Emulator

/////////////////////////////////////////////////////////////////////////////////////////////////

How to use ASM6 :

* Download ASM6

* Make a new text file

* Write this inside of it :

Code:
ASM6 Game.asm Game.nes
pause


* Save it with this name : Assembler.bat

* Make sure these files are in the same folder :

Code:
asm6.exe
Assembler.bat
Game.asm


* Run Assembler.bat to make your FIRST NES GAME!

Image

/////////////////////////////////////////////////////////////////////////////////////////////////

How to use Hex Editor :

* Sometimes we need to see the exact values of 0 and 1 inside of a file (object code of machine language), so we use a Hex Editor program like HxD

* Download HxD

* Open Game.NES with HxD

* You can see the header data on the first line, they should match to the values which you used inside of the Game.asm

Image

* Note that values are in Hexadecimal system

* Each value is one byte

* Each byte has it's own address

* Their address starts from zero, so first byte is in the $0 address second byte is in the $01 address, and so on

/////////////////////////////////////////////////////////////////////////////////////////////////

Exercise :

Find out which byte of iNES data controls Mirroring and then set it to Horizontal (Vertical Arrangement).

/////////////////////////////////////////////////////////////////////////////////////////////////

Files :
asm6.exe
Assembler.bat
Game.asm

/////////////////////////////////////////////////////////////////////////////////////////////////

Former Level : NES Programming Tutorial : Source Code Structure
Next Level : NES Programming Tutorial : Interrupts
Re: NES Programming Tutorial : iNES Header
by on (#191000)
I might suggest writing it out in a way that makes it easier to change and see where the bits are going and what they mean, instead of just making it a block of mysterious hex numbers. In my example program I did it like this:
Code:
INES_MAPPER = 0 ; 0 = NROM
INES_MIRROR = 1 ; 0 = horizontal mirroring, 1 = vertical mirroring
INES_SRAM   = 0 ; 1 = battery backed SRAM at $6000-7FFF

.byte 'N', 'E', 'S', $1A ; ID
.byte $02 ; 16k PRG bank count
.byte $01 ; 8k CHR bank 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
Re: NES Programming Tutorial : iNES Header
by on (#191002)
You forgot byte 8 and 9: PRG-RAM size and PAL flag respectively.
Re: NES Programming Tutorial : iNES Header
by on (#191003)
I didn't forget those. Those two bytes are late extensions by Marat, never really adopted by anyone else, and were also both reclaimed by iNES 2.

Most emulators ignore both of those bytes. Most ROMs that require PRG-RAM have 0 in byte 8, and most PAL ROMs have 0 in byte 9 as well, so emulators have to expect this anyway.

Implementing these in my example header would give the user an unrealistic expectation that either of these bytes is supposed to do something (which they won't, in most emulators), and set them up for a future incompatibility if they ever switch to iNES 2. The safest and most compatible thing is to leave them both as 0.
Re: NES Programming Tutorial : iNES Header
by on (#191041)
I see, I thought they where in the official specifications. I guess it's better to use NES 2.0 for the NTSC/PAL setting.
Re: NES Programming Tutorial : iNES Header
by on (#191045)
Pokun wrote:
I see, I thought they where in the official specifications.

They are, if Marat's spec is the "official" one. He invented the format, and he's the one that made those additions.

If you want the "de facto" standard, though, those bytes aren't really used, probably because it was easier to support the handful of games that needed them through other means (hash, filename, heuristics, etc.), and/or trying to cope with ROMs with garbage in the header's padding area?
Re: NES Programming Tutorial : iNES Header
by on (#191121)
Yeah I guess it's what the ROMs use that is the real standard.