NES Programming Tutorial : Background

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.
User avatar
FARID
Posts: 503
Joined: Wed Apr 07, 2010 1:14 am
Location: Iran

NES Programming Tutorial : Background

Post by FARID »

NES graphic :

* Graphic designers used a special sheets to draw the arts :

Image

* There are two kinds of graphic on the screen : 1) Background 2) Sprites

* Anything that moves on the screen is a sprite (for example Mario), other fixed graphics are background

* Background and sprites are made from small tiles

* NES screen resolution is 256x240 pixel. In PAL systems the whole screen is visible but in NTSC systems only 256x224 pixel is visible. More info : Overscan

* Each tile is 8x8 pixel, so the full background is made from 32x30 tiles (256x240 pixel) :

* NES uses a very complex method to compress and store graphic data, why? Maybe because memory was expensive back then

* As you can see some of the tiles on the background picture is similar to each other, so the tiles can be reused.

* Tiles are stored inside of CHR (an EPROM memory inside of the cartridge)

* To see and edit those tiles you can use YY-CHR.NET or Tile Layer Pro :

Image

Image

* Need more info? then read this : PPU pattern tables

* Background and Sprites needs color, right? But you know NES hardware is not very powerful, it can only produce maximum of 64 different colors! Also it is not possible to use all of those 64 colors at the same time!

* You can choose and apply only 13 colors to background, and 12 other colors for sprites.

* Fortunately with some programming methods you can overcome these limitations, well to some extent! For example you can choose different colors for each stage of the game!

* For more info about colors read this : PPU palettes

* Yeah I know, NES has a lot of limitations, it is really disappointing, then again if you are a NES enthusiast then you have to live with its limitations

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

* To design a backgroud we can use GIMP but for learning propose we can skip this step and extract a background picture from other games.

Extracting graphic data from a NES game :

* Run Super Mario Bros. (W) [!].nes with FCEUX emulator

* Start the game and then press Pause on the keyboard

* Go to Debug > PPU Viewer. On the left you can see the tiles for sprites, on the right there are tiles of background

Image

* There are some colors on the button. The first row is the colors of background. The second row is the colors of sprites.

* Go to Debug > Name Table Viewer. You can see the background picture here.

Image

* Go to Debug > Hex Editor > View > PPU Memory

Image

* Do not confuse PPU memory address with CPU memory address, they are completely separated from each other

* PPU has its own address space starting from $0000 to $3FFF

* From $0000 to $0FFF (4KB) is data of Left pattern table (sprites tiles)

* From $1000 to $1FFF (4KB) is data of right pattern table (background tiles)

* From $2000 to $2400 (1KB) is data of first name table (background graphic)

* From $3F00 to $3F0F (16bytes) is data of background colors

* From $3F10 to $3F1F (16Bytes) is data of sprites colors

* Copy those values and by using HxD save them separately : mario_spt.chr, mario_bg.chr, mario_bg.nam, mario_bg.pal, mario_spt.pal

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

Editing a background :

* You can edit the exiting backgrounds

* Download 8name which is a background editor

* Make a new text file and write this inside of it :

Code: Select all

name mario_bg
* Save it with this name : Bg_Editor.bat

* Make sure these files are in the same folder :

Code: Select all

name.exe
Bg_Editor.bat
alleg42.dll
mario_bg.nam
mario_bg.pal
mario_bg.chr
* Run Bg_Editor.bat to start editing the background :

Image

* After editing use ctrl + s to save the name table, then reassemble the game to see the output

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

NES Screen Tool :

* You can edit your extracted graphic files with NES Screen Tool

* Use "Patterns > Open CHR" to load "mario_bg.chr"

* Use "Nametable > Open nametable or map" to load "mario_bg.nam"

* Use "Palettes > Open palettes" to load "mario_bg.pal"

Image

* After editing use "All > Save" to save the files

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

* Now we have all the necessary graphics to make a nes file :
- mario_bg.chr and mario_spt.chr --> 8x8 tiles
- mario_bg.nam --> Background picture generated by using tiles
- mario_bg.pal, mario_spt.pal --> Chosen Colors applied to the background and sprites

* We have to pay attention that tiles are stored inside of CHR ROM, while background picture and its color is actually inside of PRG ROM! In another word background picture is generated while playing the game, also colors applied to it at the same time. Codes inside of PRG writes the tiles value to the PPU memory to make the background (name table), also the same thing happens to the colors! It is damn confusing and difficult to understand at the beginning.

The following code generates a fixed background :

Code: Select all

;NES Programming Tutorial
;Level 5 : Background
;+++++++++++++++++++++++++++++++++++++++++++++++++++++
;Constants
;+++++++++++++++++++++++++++++++++++++++++++++++++++++
;Variables
  .enum $0000
L_byte  .dsb 1
H_byte  .dsb 1
  .ende
;+++++++++++++++++++++++++++++++++++++++++++++++++++++
;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 Bank0 $8000 ~ $BFFF (16KB)
  .base $8000
RESET:
   SEI
   CLD
   LDX #$FF
   TXS
   
;Turn off NMI and rendering
   LDA #%00000000
   STA $2000
   LDA #%00000000
   STA $2001

;PPU warm up
   LDA $2002
vBlank_wait1:
   BIT $2002
   BPL vBlank_wait1
vBlank_wait2:
   BIT $2002
   BPL vBlank_wait2

;Clear RAM
   LDA #$00
   LDX #$00
clear_loop:
   STA $0000, X
   STA $0100, X
   STA $0200, X
   STA $0300, X
   STA $0400, X
   STA $0500, X
   STA $0600, X
   STA $0700, X
   INX
   CPX #$00
   BNE clear_loop

;Name table + Attribute
   LDA $2002
   LDA #$20
   STA $2006
   LDA #$00
   STA $2006
   LDA #<bg_nam
   STA L_byte
   LDA #>bg_nam
   STA H_byte
   LDX #$00
   LDY #$00
nam_loop:
   LDA (L_byte), Y
   STA $2007
   INY
   CPY #$00
   BNE nam_loop
   INC H_byte
   INX
   CPX #$04
   BNE nam_loop

;Background color setup
   LDA $2002
   LDA #$3F
   STA $2006
   LDA #$00
   STA $2006
   LDX #$00
bg_pal_loop:
   LDA bg_pal, X
   STA $2007
   INX
   CPX #$10
   BNE bg_pal_loop

;Reset Scroll
   LDA #$00
   STA $2005
   LDA #$00
   STA $2005
   
;Turn on NMI and rendering
   LDA #%00001000
   STA $2000
   LDA #%00001010
   STA $2001

;Infinite loop
Forever:
   JMP Forever
;---------------------------;
NMI:
   RTI
;---------------------------;
IRQ:
   RTI
;---------------------------;
  .pad $C000,$FF
;+++++++++++++++++++++++++++++++++++++++++++++++++++++
;PRG Bank1 $C000 ~ $FFFF (16KB)
  .base $C000
bg_nam:
  .incbin "mario_bg.nam"

bg_pal:
  .incbin "mario_bg.pal"
;---------------------------;    
;Vectors
  .org $FFFA, $FF
  .dw NMI
  .dw RESET
  .dw IRQ
;+++++++++++++++++++++++++++++++++++++++++++++++++++++
;CHR Bank0 $0000 ~ $1FFF (8KB)
  .base $0000
  .incbin "mario_bg.chr"
  .pad $2000,$AA
Output :

Image


Explanation :

Code: Select all

  .enum $0000
L_byte  .dsb 1
H_byte  .dsb 1
  .ende
* With this code we simply assign a name to an address. L_byte will be $00 and H_byte will be $01. Remembering the names is easier than remembering some bunch of address numbers, right?

Code: Select all

   LDA #%00001010
   STA $2001
* We want to show the background so we have to set 1st and 3rd bits

* To make graphic on screen you have to write graphic data to PPU memory

* But you can't write directly to PPU memory, you have to use PPU ports : $2006 and $2007

* By using $2006 you declare the address of PPU memory then by using $2007 you write the desired value to that address

* PPU Memory addresses are 16bit starting from $0000 ~ $3FFF (4KB)

Code: Select all

   LDA #$20
   STA $2006
   LDA #$00
   STA $2006
* So you need to write twice to $2006 to declare it's address, the first write declares high byte of address, the second write declares the low byte of address

* Each time you write a value to $2007, the PPU address is automatically adjusted to the next address, so you don't need to declare the PPU address with $2006 for sequential PPU memory addresses

Code: Select all

bg_nam:
  .incbin "mario_bg.nam"
* We can add any data file by using .incbin to the source code file

Code: Select all

   LDA #<bg_nam
* bg_nam is a label right? So it is a 16bit address. By using < we take its low byte of address and then store it into A

* We assigned L_byte to $00 already

Code: Select all

   STA L_byte
* Also we take the high byte of the address of bg_nam and then store it into $01

Code: Select all

   LDA #>bg_nam
   STA H_byte
* LDY is similar to LDA. Y is another register like A

* From $0000 to $00FF is ram right? but it is kind of special, because we can show those address with this : $00 to $FF, we call those address Zero Page

* LDA (L_byte), Y : Let's imagine : $0000 = #$00 / $0001 = #$90 / Y = #$44. Then : $9000 is made. Then $9000 + $44 = $9044. Then the value inside of $9044 is loaded into A

* INY stands for INcrement Y, For example if the value of Y is #$44 then it will be #$45

* CPY stands for ComPare Y register. It compares the value of X with its following value

* INC H_byte, increase the value inside of $01 by one

* The codes of ";Name table + Attribute" actually transfers a total of 1KB (= 400 bytes in hex) data of background to PPU memory ($2000 ~ $2400)

* The codes of ";Background color setup" actually transfers a total of 16 bytes (= 10 bytes in hex) data of background color to PPU memory ($3F00 ~ $3F0F)

* $2005 is another PPU port which is used to move the background

* Need more info about PPU ports? then read this : PPU registers

* Need to learn about 6502 opcodes? then read this : Assembly In One Step

* Need a reference for assembly 6502 opcodes? then check this : NMOS 6502 Opcodes

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

Exercise :

Extract graphic data from other games and use them instead of mario_bg.nam, mario_bg.pal, mario_bg.chr.

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

Files :
asm6.exe
Assembler.bat
Game.asm
name.exe
Bg_Editor.bat
alleg42.dll
mario_bg.nam
mario_bg.pal
mario_bg.chr

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

Former Level : NES Programming Tutorial : Init Code
Next Level : NES Programming Tutorial : Move Background
User avatar
FARID
Posts: 503
Joined: Wed Apr 07, 2010 1:14 am
Location: Iran

Re: NES Programming Tutorial : Background

Post by FARID »

I am trying to update my tutorial, well actually my personal notes on how to make a nes game! :mrgreen:
For learning purpose I used readymade graphics extracted from other nes games, but for making a real nes game I have to draw the picture and then convert it to background nametable along with its pattern table and color palette. I am curious about how other people prepare these files? (BG.nam, BG.pal, BG.chr). what tools are the best to use?
User avatar
nesrocks
Posts: 603
Joined: Thu Aug 13, 2015 4:40 pm
Location: Rio de Janeiro - Brazil

Re: NES Programming Tutorial : Background

Post by nesrocks »

I use NAW but I'm biased as I'm the dev (big update incoming soon). Other tools that I use are I-CHR and Overlaypal.
You'll probably want to stop recommending NESST and recommend NEXXT instead as it's the much improved fork.