NES Hello World Aug 7, 2011

The program below is written for xa65, a 6502/R65C02/65816 cross-assembler. It should be portable to other 6502 assemblers with minor tweaks. (The xa65 website is down as of the time of writing, but the program can be found in many places on the web, or from your friendly neighborhood Linux distro's package system.)

Some Notes

The $200X addresses used below are magic registers which control the NES's video memory. See NES PPU for details on their function, and for some brief info on how images are stored in the NES. (It's complicated.)

This program eschews the normal method of storing graphics in ROM (called CHR-ROMs) in favor of copying the graphics from PRG-ROM into CHR-RAM. There is not really a good reason for this, except you have to deal with fewer bank files.



; load this at $8000
* = $8000

; Graphics data.
; Each line is a character:
; space H E L O , W R D !
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,102,102,126,102,102,102,0,0,0,0,0,0,0,0,0
.byte 0,126,96,120,96,96,126,0,0,0,0,0,0,0,0,0
.byte 0,96,96,96,96,96,126,0,0,0,0,0,0,0,0,0
.byte 0,60,102,102,102,102,60,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,24,24,48,0,0,0,0,0,0,0,0
.byte 0,102,102,102,102,126,102,0,0,0,0,0,0,0,0,0
.byte 0,124,102,124,120,108,102,0,0,0,0,0,0,0,0,0
.byte 0,124,102,102,102,102,124,0,0,0,0,0,0,0,0,0
.byte 0,24,24,24,24,0,24,0,0,0,0,0,0,0,0,0
.byte $ff

; The message "Hello, World!",
; chosen from the characters above.
.byte 1,2,3,3,4,5,0,6,4,7,3,8,9,$ff

; Colors
.byte 13,32,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0

; the beginning
	; load graphics data into CHR-RAM
	lda #0
	sta $2006
	sta $2006
	ldx #0
ldc:	lda chrdata,x
	cmp #$ff
	beq cdone
	sta $2007
	jmp ldc
	; write the message to the name table
	lda #$20
	sta $2006
	sta $2006
	ldx #0
ldm:	lda message,x
	cmp #$ff
	beq mdone
	sta $2007
	jmp ldm
	; load the palette
	lda #$3f
	sta $2006
	lda #$00
	sta $2006
	ldx #0
ldp:	lda palette,x
	sta $2007
	cpx #$10
	bne ldp
	; reset PPU pointer
	; (otherwise everything is offset)
	lda #0
	sta $2006
	sta $2006
	; enable PPU
	lda #%10001000
	sta $2000
	lda #%00011110
	sta $2001
	; done, just wait around
main:	jmp main

; these interrupts aren't needed for this program

; fill the rest of this bank with zeroes
.dsb $bffa-*, 0

; except for the interrupt vectors
.word int_vblank, int_reset, int_irqbrk


To get the above code to work in an emulator, just assembling it isn't quite enough. You need to wrap it with a header that gives the emulator a little more information about your program. This is beyond the scope of this writeup.

Here is the assembled ROM, gzipped and base64 encoded. Save this into hello.b64 and run base64 -d hello.b64 | gunzip > hello.nes, then use your favorite NES emulator.


Pseudo_Intellectual says re NES Hello World (how-to): this could be done much more easily using the NES' Family BASIC 8)

raincomplex says haha, indeed. although, going that route, you may as well use the C64

Pseudo_Intellectual says Fair enough, though the C64 won't come pre-loaded with Donkey Kong sprites to dance while you greet the world 8)