Copy Link
Add to Bookmark
Report

Programming that 8-bit beast of power, the NES

Nintendo's profile picture
Published in 
Famicom
 · 19 Jun 2020

-==============================================- 
+Programming that 8-bit beast of power, the NES+
+By joker21@earthlink.net v.75.420.69.666 +
-==============================================-

Don't Panic
------------
This document should help you learn how to program the nes. It better.
Didn't waste all this time for nothing. You really should use this
in conjunction with the docs that I have included. Some information
is omitted or only touched on because it is mentioned in
more detail somewhere else. The only thing about coding using
emulators is that some times your code will work for one emulator but
not for another. I don't know why that happens. Nesticle runs just
about anything you throw at it but some of the more realistic
emulators won't run your code if it's not proper code.

The formatting should also allow you to print this document with
a minimal amount of hassle. You may have to adjust margins though.


Tools
--------

1. Nes Assembler(Compiles 6502 assembly into NES roms)
-Required. If you don't have this, then you're pretty much screwed.
Well, no not really. NES programs can be compiled using TASM(Not the
Borland one) but it's a pain in the ass.

2. NES Screen Arranger(Name Table editor)
-Not required but it makes making editing title screens and such ALOT
easier.

3. Tile Layer(Edit graphics)
-Pretty much required. You can use Nesticle but it's a lot more complex.

4. Nes Emulator
-Required. How else are you gonna play your ROM? You'll be wanting one
that has code trace, pattern table viewer, palette viewer, stuff like
that. Nesticle works okay but there are better emulators out there.

I've included most of these tools. And a bunch of docs about the nes.
Good luck!


Need to Know
----------------
You need to know 6502 assembly. Also, you need Y0SHi's NES doc. This
thing is VERY useful. Print it out, a hard copy is a must. You might
also want Marat Fayzullin's NES document. And Chris Covell's NES Tech
FAQ is good too. So much information!


Stuff to do before B.C.(Before Coding. Witty, huh?)
----------------------------------------------------
Some things just gotta be done before you can start coding. Now, since
we're use NESASM, the first thing you need is INES header setup table.
This should go at the front of you're program. This pretty much tells
NESASM how to setup the INES header in your NES ROM.

; INES header setup
.inesprg 1
.ineschr 1
.inesmir 1
.inesmap 0

Right from the NESASM usage.txt is what each '.ines' thing means.

.INESPRG - Specifies the number of 16k prg banks.
.INESCHR - Specifies the number of 8k chr banks.
.INESMAP - Specifies the NES mapper used.
.INESMIR - Specifies VRAM mirroring of the banks.

The example header shown is for a program with (1)16k code bank,
(1)8k character bank, Vertical mirroring, and no mapper(0) used. This
setup will work...for now(creepy music, evil laugh)!!

The Vector table are a set of three addresses that are stored in a
certain memory location in the NES ROM($FFFA to be exact). Here's an example:

.bank 1 ;needed or NESASM gets cranky
.org $FFFA ;ditto
.dw ;NMI_Routine($FFFA)
.dw ;Reset_Routine($FFFC)
.dw ;IRQ_Routine($FFFE)

NMI_Routine means Non-Maskable Interrupt. This address is called
different times on different systems(PAL/NSTC). It's called every
VBlank(screen refresh). Nesticle does not trace this when using it's
code trace(I don't think so anyway...)

The Reset_Routine is jumped to when the game is powered up and when it
is reset. When the game is reset, the NES _does not_ clear the memory
nor the registers. I guess so programmers can count how many times the
game has been reset. On a more serious note, this can could cause
problems if you're not careful with how you store and read data.

Finally, the IRQ_Routine is the address that is jumped to when a BRK
instruction is hit. I have no idea how you could use this. Maybe for
error checking or something(shrug).

You don't need to have actual values for these addresses. Well, you do
for address $FFFC since it does tell the NES were your code is. If you
don't use it, turn NMI($FFFA) off(more on that later) and put a 0 as
the address. You don't even need to put a value in $FFFE, just make
sure there are no BRK instructions.

So far for our ROM we have:
-------------------------------------------------------------------
!The Header!

.inesprg 1
.ineschr 1
.inesmir 1
.inesmap 0


!The Vector Table!
.bank 1
.org $FFFA
.dw NMI (NMI_Routine)
.dw Start (Reset_Routine)
.dw IRQ (IRQ_Routine)
-------------------------------------------------------------------


Coding!
---------
Okay, one little thing before coding. The code must '.org' at $8000
or $C000 and it must be in bank 0. I'm pretty sure this is right. All
my stuff is going to use bank 0 and $8000 but that's just me.


Here's what the program should look like now:
-------------------------------------------------------------------
;This will compile! Try it!

;!The Header!

.inesprg 1
.ineschr 0 ;this is 0 b/c we have no chr data...yet
.inesmir 1
.inesmap 0

.org $8000
.bank 0


Start:
;!Code Goes Here!

jmp Start


;!The Vector Table!
.bank 1
.org $FFFA
.dw 0 ;(NMI_Routine)
.dw Start ;(Reset_Routine)
.dw 0 ;(IRQ_Routine)
-------------------------------------------------------------------


Wow! This program does two things well; nothing and not a damn thing.
What it really does is simply go into an infinite loop. We need that
infinite loop because the nes will keep going and end up trying to
execute garbage instructions. It's a start though! Now, let's show some
pretty pictures!


Graphics
----------
Showing graphics on the nes is composed of; CHR-ROM, PPU control, the
palette(the colors! THE COLORS!!!!), and some other fun things.


The PPU
--------
Before we can really do anything graphic wise, we need to write to the
PPU control registers. It's not as hard as it sounds. Basically you just
write a byte to both memory locations $2000 and $2001. Here's an
example:

lda #%00001000
sta $2000
lda #%00011110
sta $2001

Now, looking at our NES doc, we see that each bit writen to $2000 and
$2001 does something special. Let's let our nestech.doc explain.

#%00001000
D-76543210

+---------+----------------------------------------------------------+
| $2000 | PPU Control Register #1 (W) |
| | |
| | D7: Execute NMI on VBlank |
| | 0 = Disabled |
| | 1 = Enabled |
| | D6: PPU Master/Slave Selection --+ |
| | 0 = Master +-- UNUSED |
| | 1 = Slave --+ |
| | D5: Sprite Size |
| | 0 = 8x8 |
| | 1 = 8x16 |
| | D4: Background Pattern Table Address |
| | 0 = $0000 (VRAM) |
| | 1 = $1000 (VRAM) |
| | D3: Sprite Pattern Table Address |
| | 0 = $0000 (VRAM) |
| | 1 = $1000 (VRAM) |
| | D2: PPU Address Increment |
| | 0 = Increment by 1 |
| | 1 = Increment by 32 |
| | D1-D0: Name Table Address |
| | 00 = $2000 (VRAM) |
| | 01 = $2400 (VRAM) |
| | 10 = $2800 (VRAM) |
| | 11 = $2C00 (VRAM) |
+---------+----------------------------------------------------------+
Let's go into a little more detail:

D5 sets the sprite size. 0 is 8 pixels by 8 pixels. 1 is 8 pixels by 16
pixels. If it's set to 0, sprites are just one 8x8 entry on the
pattern table. Setting it to 1 uses two entries(8x16) on the pattern table.
_ _
i.e. 8x8 =[_] 8x16 =[ ]
[_]

D4 sets the address that is used for the screen(background). Writing 0
sets the address to $0000. This means that the NES is using the data in
pattern table 1 for background graphics. Writing 1 sets the address to
$1000. Address $1000 is the 2nd pattern table.

D3 sets the sprite address. Writing 0 sets the address to $0000. This
means that the NES uses the data in pattern table 1 for sprites. Setting
it to 1 means that the NES uses $1000 for sprites. Address $1000 is
pattern table 2.

-Start Note-
You usually don't want the sprite data to be the background data too.
This means that the NES uses that same pattern table for both sprites
and backgrounds. This could get confusing.
-End Note-

D2 sets how much to increment PPU writes/reads. If it's 0 then the PPU
point is increased by 1 each write/read. If it's 1 then it's increase
by 32. I can't remember why you would want to increase it by 32. Sure
there's a reason...

D1-D0 sets which name table you want to use. Now, it may seem like you
have 4 choices for name tables but you don't. Name table 1 is mirrored
to name table 3 and name table 2 is mirrored to name table 4. Name
tables are the backgrounds to games and such.

What about $2001? Well, again nestech.doc comes to the rescue. With
help from the NES Tech FAQ by Chris Covell.

#%00011110
D-76543210

+---------+----------------------------------------------------------+
| $2001 | PPU Control Register #2 (W) |
| | |
| | D7-D5: Full Background Colour (when D0 == 1) |
| | 000 = None +------------+ |
| | 001 = Green | NOTE: Do not use more |
| | 010 = Blue | than one type |
| | 100 = Red +------------+ |
| | D7-D5: Colour Intensity (when D0 == 0) |
| | 000 = None +--+ |
| | 001 = Intensify green | NOTE: Do not use more |
| | 010 = Intensify blue | than one type |
| | 100 = Intensify red +--+ |
| | D4: Sprite Visibility |
| | 0 = Sprites not displayed |
| | 1 = Sprites visible |
| | D3: Background Visibility |
| | 0 = Background not displayed |
| | 1 = Background visible |
| | D2: Sprite Clipping |
| | 0 = Sprites invisible in left 8-pixel column |
| | 1 = No clipping |
| | D1: Background Clipping |
| | 0 = BG invisible in left 8-pixel column |
| | 1 = No clipping |
| | D0: Display Type |
| | 0 = Colour display |
| | 1 = Monochrome display |
+---------+----------------------------------------------------------+
Most of this is pretty easy to understand. But here's some more detailed
info on some of the registers from The NES Tech FAQ:

-What are the colour emphasis bits?

This is almost the final frontier of NES emulation, as not many
emulators handle these bits properly. The top 3 bits of $2001 are known
as the "Colour Emphasis Bits" because each bit modifies the R, G, or B
colour component of the NES' display. The bits look like this in $2001:
BGRxxxx. If you set one of these bits, the entire palette changes
dynamically towards the colour component selected in the bits. If you
set the Red bit, the entire palette seems much more "red". However, since
the NES does not work in RGB, what seems to be happening is that the hue
of all the colours in the display are more influenced towards the hue
that is being emphasized. Another thing to note is that if the Red bit
is set, for example, the palette entries that have a large amount of
cyan (red's negative) in them are darkened considerably.

You can combine each of the emphasis bits as well. Setting both
the R and G bits emphasizes the yellow in the palette, and so on.
However, when any two bits are set, the entire palette is dimmer than
normally. Thus, the emphasis seems more like "de-emphasis". I really
believe that when you set the R bit, for example, to emphasize red,
what is really occurring is a widespread de-emphasis of cyan. My
suspicions are confirmed further because when you set all three of
the colour emphasis bits, the entire palette dims to 75% of its
original brightness. The game Super Spy Hunter does this very thing
with the emphasis bits when you pause the game.

-What is the monochrome mode in the NES?

Bit 0 of $2001 is funny. When it is set, the entire palette goes
greyscale. However, it is not a simple greyscale mode. For one, there
is no black value when the monochrome bit is set. In fact, what
technically occurs is that when the monochrome bit is set, the 64-value
palette in the NES is reduced to simply a 4-value palette. All palette
entries from $01 to $0F are mirrored to entry $00; all entries from $11
to $1F are mirrored to $10; all entries from $21 to $2F are mirrored to
$20; and finally, all entries from $31 to $3F are mirrored to $30. This
is also shown to be true because if you set the monochrome bit and some
of the colour emphasis bits, the display still gets skewed to the colour
being emphasized.


Adding CHR-ROM
----------------
Okay, now that you know about using the PPU, it's time to learn how to
add CHR-ROM so you have something to look at. Looking at the header,
we see:

.inesprg 1
.ineschr 0
.inesmir 1
.inesmap 0

Now, that 0 is telling NESASM that we have 0 banks of CHR-ROM. Every time
you add a bank of CHR-ROM, you need to increase that value by one. Since
we're only going to have 1 bank of data just change that 0 to a 1.

.inesprg 1
.ineschr 1
.inesmir 1
.inesmap 0

We're not done yet. Now we have to add the actual CHR-ROM to the rom
and load it into the pattern table. Which is easily added like this:

.bank 2
.org $0000
.incbin "test.chr" ;gotta be 8192 bytes long

Since there is only one chunk of CHR-ROM, we place it at address $0000.
Address $0000 is where the nes starts to look for character data.
CHR-ROM goes from $0000 to $2000 in the nes ram and is called the
pattern table. Hence the 8192 byte length of test.chr. I'm not sure how
to switch CHR-ROM from different banks though. I did come up with a
workaround though. It will be discussed later. But let's look at the
code we got going so far:
----------------------------------------------------------------
.inesprg 1
.ineschr 1
.inesmir 1
.inesmap 0

.org $8000
.bank 0

Start:
;this setups the PPU
lda #%00001000
sta $2000
lda #%00011110
sta $2001

Loop:
jmp Loop

.bank 1
.org $FFFA
.dw 0 ;(NMI_Routine)
.dw Start ;(Reset_Routine)
.dw 0 ;(IRQ_Routine)

.bank 2
.org $0000
.incbin "test.chr" ;gotta be 8192 bytes long
---------------------------------------------------------------


We're not done yet though. If you run this code, you'll get nothing but
a blank screen. That's because we haven't told the nes about the
palette. Which brings us to our next section!


The Palette
------------
The palette starts at $3F00 and goes to $3F1F in the VRAM. From $3F00
to $3F0F is the image(background) palette. From $3F10 to $3F1F is the
sprite palette. This gives you 2 palettes that are 16 bytes each. The
most important address in the palette is $3F00. The value that is
written here defines background colour, transparency for both background
and sprites, and is mirrored every 4 bytes. This means that $3F04,$3F08,
$3F0C, $3F14, $3F18, are just mirrors of $3F00. Writing to these places
does nothing. Ready to learn how to write to the palette? Let's go!

Writing to the palette involves the use of registers $2006 and $2007.
You can't write/read directly to the VRAM. Instead, you write the VRAM
address of where you want to write/read to register $2006 and use
register $2007 to write/read data. First you would write the high byte
to $2006 then the low byte. To point the register at the palette($3F00),
you would first write #$3F then #$00. Like this:

lda #$3F ;set to start of palette
sta $2006
lda #$00
sta $2006

Now you can write to the palette by writing to register $2007. Just
write 32 bytes to register $2007 and you got your palette. Let's look
at the code we got so far:
--------------------------------------------------------------
.inesprg 1
.ineschr 1
.inesmir 1
.inesmap 0

.org $8000
.bank 0

Start:

;this sets up the PPU
lda #%00001000
sta $2000
lda #%00011110
sta $2001

;set to start of palette
lda #$3F
sta $2006
lda #$00
sta $2006

;these are the writes that setup the palette
lda #$01
sta $2007
lda #$02
sta $2007
lda #$03
sta $2007
lda #$04
sta $2007
lda #$05
sta $2007
lda #$06
sta $2007
lda #$07
sta $2007
lda #$08
sta $2007
lda #$01 ;stop here
sta $2007
lda #$08
sta $2007
lda #$09
sta $2007
lda #$0A
sta $2007
lda #$01
sta $2007
lda #$0B
sta $2007
lda #$0C
sta $2007
lda #$0D
sta $2007
lda #$01 ;Start sprite colors
sta $2007
lda #$0D
sta $2007
lda #$08
sta $2007
lda #$2B
sta $2007
lda #$01
sta $2007
lda #$05
sta $2007
lda #$06
sta $2007
lda #$07
sta $2007
lda #$01
sta $2007
lda #$08
sta $2007
lda #$09
sta $2007
lda #$0A
sta $2007
lda #$01
sta $2007
lda #$0B
sta $2007
lda #$0C
sta $2007
lda #$0D
sta $2007

Loop:
jmp Loop

.bank 1
.org $FFFA
.dw 0 ;(NMI_Routine)
.dw Start ;(Reset_Routine)
.dw 0 ;(IRQ_Routine)

.bank 2
.org $0000
.incbin "test.chr" ;gotta be 8192 bytes long
-----------------------------------------------------------------


Damn. That code is so ugly it hurts my feelings. Let's make it a little
less nasty, shall we?
Like this:
----------------------------------------------------------------
.inesprg 1
.ineschr 1
.inesmir 1
.inesmap 0

.org $8000
.bank 0

Start:


;this sets up the PPU
lda #%00001000
sta $2000
lda #%00011110
sta $2001

lda #$3F ;set ppu to start of palette
sta $2006
lda #$00
sta $2006
ldx #$00

loadpal:
lda titlepal, x ;loads a 32 byte palette
sta $2007
inx
cpx #$21 ;gotta be one extra b/c of inx
bne loadpal

Loop:
jmp Loop


titlepal: .incbin "test.pal" ;palette data


.bank 1
.org $FFFA
.dw 0 ;(NMI_Routine)
.dw Start ;(Reset_Routine)
.dw 0 ;(IRQ_Routine)

.bank 2
.org $0000
.incbin "test.chr" ;gotta be 8192 bytes long
------------------------------------------------------------------


What I did was get rid of that ugly mess and use a loop. The loop loads
the data that is included in test.pal and then writes it to $2007. It
does this until the counter(x) gets to 21 and then continues the
program. Test.pal is an external file that is 32 bytes of palette data.
Makes it easier to edit colors and stuff. We got the palette down, the
PPU under control, that nasty CHR-ROM in there. Ready to start putting
shit on the screen? Of course you are!


Name Tables!
-------------
Y0SHi says it best:
The NES displays graphics using a matrix of "tiles"; this grid is called
a Name Table. Tiles themselves are 8x8 pixels. The entire Name Table
itself is 32x30 tiles (256x240 pixels). Keep in mind that the displayed
resolution differs between NTSC and PAL units. The Name Tables holds
the tile number of the data kept in the Pattern Table.

+---------+-------+-------+--------------------+
| Address | Size | Flags | Description |
+---------+-------+-------+--------------------+
| $2000 | $3C0 | | Name Table #0 |
| $23C0 | $40 | N | Attribute Table #0 |
| $2400 | $3C0 | N | Name Table #1 |
| $27C0 | $40 | N | Attribute Table #1 |
| $2800 | $3C0 | N | Name Table #2 |
| $2BC0 | $40 | N | Attribute Table #2 |
| $2C00 | $3C0 | N | Name Table #3 |
| $2FC0 | $40 | N | Attribute Table #3 |
+---------+-------+-------+--------------------+
N = Mirrored

In addition to name tables, there are also attribute tables. Again, I'll
let Y0SHi talk about it:

Each byte in an Attribute Table represents a 4x4 group of tiles on the
screen. There's multiple ways to describe what the function of one (1)
byte in the Attribute Table is:

* Holds the upper two (2) bits of a 32x32 pixel grid, per 16x16 pixels.
* Holds the upper two (2) bits of sixteen (16) 8x8 tiles.
* Holds the upper two (2) bits of four (4) 4x4 tile grids.

It's quite confusing; two graphical diagrams may help:

+------------+------------+
| Square 0 | Square 1 | #0-F represents an 8x8 tile
| #0 #1 | #4 #5 |
| #2 #3 | #6 #7 | Square [x] represents four (4) 8x8 tiles
+------------+------------+ (i.e. a 16x16 pixel grid)
| Square 2 | Square 3 |
| #8 #9 | #C #D |
| #A #B | #E #F |
+------------+------------+

The actual format of the attribute byte is the following (and
corresponds to the above example):

Attribute Byte
(Square #)
----------------
33221100
||||||+--- Upper two (2) colour bits for Square 0 (Tiles #0,1,2,3)
||||+----- Upper two (2) colour bits for Square 1 (Tiles #4,5,6,7)
||+------- Upper two (2) colour bits for Square 2 (Tiles #8,9,A,B)
+--------- Upper two (2) colour bits for Square 3 (Tiles #C,D,E,F)

Writing to the name table is rather simple. Simply set register $2006 to
point to $2000 and then write your name table using register $2007.
However, you can't just write to it like that. You have to wait for
the VBlank to get done before you write to the PPU or you'll have
problems. If you're only writing a little to the PPU, like the palette,
then you're okay. But if you're writing a lot of data, you'll have
problems. Here's how to wait for the VBlank to get done:

vwait:
lda $2002 ;wait
bpl vwait

That's it. What it does is read $2002 and see if the VBlank flag is set.
If it is then it loops until the VBlank is done. If you have to write a
lot of data to the VRAM then just turn the display off, write your data,
then turn the display back on. Here's it in action(it may not even be
needed in this instance because not much data is being written):


vwait:
lda $2002 ;wait
bpl vwait

lda #$20 ;set ppu to start of VRAM
sta $2006
lda #$20
sta $2006

lda #$48 ;write pattern table tile numbers to the name table
sta $2007
lda #$65
sta $2007
lda #$6C
sta $2007
lda #$6C
sta $2007
lda #$6F
sta $2007

If you'll look at the code, you'll notice that the address written to
$2006 is $2020 and not $2000. That's because the first line(the first
32 bytes) is not displayed due to the difference between NSTC and PAL.
I think. I can't find the information I had on it. Now that we gots a
background, it's time for some sprites to start dancing. Dance little
sprites! Dance!


Sprites
---------
Sprites are well....sprites. You know what they are. The actual pixels
for sprites are stored in the pattern tables. Which pattern table
depends on which flag you wrote to the PPU. To control the sprites,
you have to write data to the SPR-RAM. This ram is 256 bytes long.
Each sprite has 4 bytes in which to be described. This gives you a limit
of 64 sprites. Y0SHi's nestech.doc has some information:

+------+----------+--------------------------------------+
+ Byte | Bits | Description |
+------+----------+--------------------------------------+
| 0 | YYYYYYYY | Y Coordinate - 1. Consider the coor- |
| | | dinate the upper-left corner of the |
| | | sprite itself. |
| 1 | IIIIIIII | Tile Index # |
| 2 | vhp000cc | Attributes |
| | | v = Vertical Flip (1=Flip) |
| | | h = Horizontal Flip (1=Flip) |
| | | p = Background Priority |
| | | 0 = In front |
| | | 1 = Behind |
| | | c = Upper two (2) bits of colour |
| 3 | XXXXXXXX | X Coordinate (upper-left corner) |
+------+----------+--------------------------------------+

The Tile Index # is what number from the pattern table is being used
for the sprite. To access this SPR-RAM, you have to set the register
$2003 to the address that you want to write to and write the sprite data
to register $2004. Check it out:

ldx #$00 ;set $2004 to the start of SPR-RAM
stx $2003
stx $2003

lda #$7F ;y-1
sta $2004
lda #$00 ;sprite pattern number
sta $2004
lda #%00000001 ;color bit
sta $2004
lda #$08 ;x
sta $2004

That's only one way of writing to the SPR-RAM. You can also use the
Sprite DMA register $4014. This register writes 256 bytes of data to
SPR-RAM. The address read from is $100*N, where N is the value written
to the register. Okay. We got backgrounds. We got sprites. What's next?
Input! Yes! Make them sprites move!


Reading Input
--------------
Reading input from the joypad is sort of simple. All you have to do is
read register $4016 for joypad 1 and $4017 for joypad 2. Before you can
read them though, you have to reset the joypads by strobing them. You
have to do this. Just write 1 then 0 to register $4016 then read the
register. Here's what each read means according to Y0SHi:

1 = A 9 = Ignored 17 = +--+
2 = B 10 = Ignored 18 = +-- Signature
3 = SELECT 11 = Ignored 19 = |
4 = START 12 = Ignored 20 = +--+
5 = UP 13 = Ignored 21 = 0
6 = DOWN 14 = Ignored 22 = 0
7 = LEFT 15 = Ignored 23 = 0
8 = RIGHT 16 = Ignored 24 = 0

How you handle the input from the joypad is up to you. There's a
bunch of ways to do it. It really depends on the program. Here's an
example that waits for the start button to be pressed:

loopkey:
lda #$01 ;strobe the joypad before read
sta $4016
lda #$00
sta $4016

lda $4016
lda $4016
lda $4016
lda $4016 ;this read gives you the status of the start button
cpa #$01
bne loopkey ;loop if no start pressed

Handling the key presses can be kinda hard though. Check the examples
included for some different ways.


Sound
------
I'm not touching sound. I'm sorry if you were all excited to learn about
it. The most recent of Y0SHi's nestech.doc(v2.00) doesn't have anything
about sound in it because some of the information is wrong. However, his
earlier doc did include it so just look at that. Pretty easy to figure
out. Just same old writing to registers bullshit.


The End???
-----------
Nope. You should now have an idea on how to make the nes do what you
want. I hope so anyway. I'm now going to give some code snippets and
talk about how to do some things. Save you some time trying to figure
this shit out.


Pausing Your Program
---------------------
This is a nice little routine I got from a 6502 newsgroup a long time
ago:

killtime:

LDY #$10
LDX #$10
.1 JSR .2
DEX
BNE .1
DEY
BNE .1
.2 RTS

What you do is simply call this routine when you want to kill some
time. Maybe show a title screen for a couple of seconds before allowing
input. To change the time killed just change the values that are loaded
into Y and X.


Writing To CHR-ROM
-------------------
Normally you can't write to the CHR-ROM. However, if you set .ineschr
to 0 and tell the nes that you have no chr data, it will let you write
to the CHR-RAM. It's CHR-RAM now because you can write to it. Here's a
way to do it. Have a bank in your PRG-ROM that is really chr data:

.bank 2
.org $C000
.incbin "title.chr" ;8192 bytes long

Now, since we can't write to the PPU will VBlank is going on, we have to
turn the display off like this:

lda #%00010110
sta $2001

This stops the VBlank and we can write all we want without worrying about
fucking shit up. Just write from the address were you chr data is at, in
this case $C000, and then just turn the display back on when you're done:

lda #%00011110
sta $2001

But since your chr data is going to be more than 256 bytes, you can't
just use a simple loop. The 6502 has some special ways of dealing with
this. Look at the docs that I've included for the best way for you to
do it. Try asm1step.html. This is a nice way to refresh something in the
pattern table without switching CHR-ROM. Or modify graphics on the fly.


Moving A Sprite
-----------------
Moving a sprite is pretty simple. Just get joypad input, decide which
buttons were pressed. Then just set register $2003 to the X, Y bytes
in the SPR-RAM, read from $2004 and increase or decrease that value
depending on which button was pressed.


That's It Folks
---------------
That's it. I hope this is a help to somebody out there. If you got
issues or want me to add some sort of information or something just
mail me. All this information in this document is stuff I've
discovered just playing around with emulators. It maybe wrong or
incorrect. But it works. Most of the time.


Places To Go
-------------
http://nesdev.parodius.com/
http://www.zophar.net/index.phtml
http://www.komkon.org/fms/EMUL8/
http://www.sfu.ca/~ccovell/NESTechFAQ.html


Thanks And Biography
---------------------
(No Order)
RTK, Assembly In One Step
Tony Young, JunkDemo
Charles Doty, Converted JunkDemo, NESASM, other things
Bloodlust Software, Nesticle
Marat Fayzullin, Nintendo Entertainment System Architecture v2.1
David Michel, NESASM
Y0SHi, Nintendo Entertainment System Documentation v.53, v2.00
Chris Covell, NES Technical/Emulation/Development FAQ v1.2
SnowBro, NSA, Tlayer, misc info
HeAvEn/Taquart, 6502 Opcodes

And all the random people who write shit about the nes and put it
on the web.

All these people, though they don't know it, have contributed to
this document in some way.


bob
joker21@earthlink.net
July 26

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT