CPU & PPU Memory Map :
* CPU Memory address starts from $0000 to $FFFF :
* Need more info about CPU memory map? then check this : CPU memory map
* PPU Memory address starts from $0000 to $3FFF :
* Need more info about PPU memory map? then check this : PPU memory map
* Here is the structure of a NES file (NROM-256 Mapper 0) :
* When the game runs PRG of the game ($0010 to $8010) is loaded into CPU memory ($8000 to $10000)
* CHR of the game ($$8010 to $A010) is loaded into PPU memory ($0000 to $2000)
/////////////////////////////////////////////////////////////////////////////////////////////////
How to separate PRG and CHR of a nes game :
* PRG and CHR are stored inside of two separated EPROM memories :
* To make the cartridge we have to remove the iNES header and binary files of PRG and CHR separately
* We can use HxD to do it but a better way is to use famiROM :
* Just load the desired game and click on split
* PRG.bin and CHR.bin of the game are generated and ready to use
* These files must be trasfered to EPROM memories by using programmer
* Need more info about making a nes cartridge? then check ROM Laboratory : Link1 Link2
/////////////////////////////////////////////////////////////////////////////////////////////////
Explanation :
* .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
* RESET: is just a label. Name a label anything you want. After assembling the code, labels are translated to an address
* JMP is a 6502 opcode. It tells the CPU to jump to a label and continue the execution from there. In the example I made an infinite loop by using JMP and a label to prevent CPU from executing other irrelevant opcodes
* RTI tells the CPU to go back to the normal routine after finishing an interrupt
* .org $FFFA puts its following code exactly in the mentioned address
* A Label's address is 16bit, .dw breaks the address of the Label into two bytes and put them in two offset. NES CPU is little endian, it means the Low byte of the address must be stored first and then the High byte of the address must be stored, so that NES CPU can read and use that address correctly
* There are three interrupts in NES :
1) Reset : when the console turns on, the cpu execute the codes from this address
2) NMI : Before showing a new frame of picture on TV there is a period called vBlank or vertical blank to clean the screen, when vBlank starts NMI interrupt happens. During vBlank we can change the graphic of the new frame
3) Some advanced games use this interrupt. I don't know how to use it yet so let's ignore it for now!
* Need More info about interrupts? then read this : CPU interrupts
/////////////////////////////////////////////////////////////////////////////////////////////////
Exercise :
Put NMI label in the address of $9000.
/////////////////////////////////////////////////////////////////////////////////////////////////
Files :
asm6.exe
Assembler.bat
Game.asm
/////////////////////////////////////////////////////////////////////////////////////////////////
Former Level : NES Programming Tutorial : iNES Header
Next Level : NES Programming Tutorial : Init Code
* CPU Memory address starts from $0000 to $FFFF :
* Need more info about CPU memory map? then check this : CPU memory map
* PPU Memory address starts from $0000 to $3FFF :
* Need more info about PPU memory map? then check this : PPU memory map
* Here is the structure of a NES file (NROM-256 Mapper 0) :
* When the game runs PRG of the game ($0010 to $8010) is loaded into CPU memory ($8000 to $10000)
* CHR of the game ($$8010 to $A010) is loaded into PPU memory ($0000 to $2000)
/////////////////////////////////////////////////////////////////////////////////////////////////
How to separate PRG and CHR of a nes game :
* PRG and CHR are stored inside of two separated EPROM memories :
* To make the cartridge we have to remove the iNES header and binary files of PRG and CHR separately
* We can use HxD to do it but a better way is to use famiROM :
* Just load the desired game and click on split
* PRG.bin and CHR.bin of the game are generated and ready to use
* These files must be trasfered to EPROM memories by using programmer
* Need more info about making a nes cartridge? then check ROM Laboratory : Link1 Link2
/////////////////////////////////////////////////////////////////////////////////////////////////
Code:
;NES Programming Tutorial
;Level 3 : Interrupts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;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
RESET:
;Infinite loop
Forever:
JMP Forever
;---------------------------;
NMI:
RTI
;---------------------------;
IRQ:
RTI
;---------------------------;
.pad $FFFA,$FF
;Vectors
.org $FFFA
.dw NMI
.dw RESET
.dw IRQ
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;CHR data $0000 ~ $1FFF (8KB)
.base $0000
;graphic data
.pad $2000,$FF
;Level 3 : Interrupts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;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
RESET:
;Infinite loop
Forever:
JMP Forever
;---------------------------;
NMI:
RTI
;---------------------------;
IRQ:
RTI
;---------------------------;
.pad $FFFA,$FF
;Vectors
.org $FFFA
.dw NMI
.dw RESET
.dw IRQ
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;CHR data $0000 ~ $1FFF (8KB)
.base $0000
;graphic data
.pad $2000,$FF
Explanation :
* .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
* RESET: is just a label. Name a label anything you want. After assembling the code, labels are translated to an address
* JMP is a 6502 opcode. It tells the CPU to jump to a label and continue the execution from there. In the example I made an infinite loop by using JMP and a label to prevent CPU from executing other irrelevant opcodes
* RTI tells the CPU to go back to the normal routine after finishing an interrupt
* .org $FFFA puts its following code exactly in the mentioned address
* A Label's address is 16bit, .dw breaks the address of the Label into two bytes and put them in two offset. NES CPU is little endian, it means the Low byte of the address must be stored first and then the High byte of the address must be stored, so that NES CPU can read and use that address correctly
* There are three interrupts in NES :
1) Reset : when the console turns on, the cpu execute the codes from this address
2) NMI : Before showing a new frame of picture on TV there is a period called vBlank or vertical blank to clean the screen, when vBlank starts NMI interrupt happens. During vBlank we can change the graphic of the new frame
3) Some advanced games use this interrupt. I don't know how to use it yet so let's ignore it for now!
* Need More info about interrupts? then read this : CPU interrupts
/////////////////////////////////////////////////////////////////////////////////////////////////
Exercise :
Put NMI label in the address of $9000.
/////////////////////////////////////////////////////////////////////////////////////////////////
Files :
asm6.exe
Assembler.bat
Game.asm
/////////////////////////////////////////////////////////////////////////////////////////////////
Former Level : NES Programming Tutorial : iNES Header
Next Level : NES Programming Tutorial : Init Code