I've been dreaming of assembly for the last two nights…
In his blog, Cyrus non-seriously challenged me to create a raycaster for the NES.I'm not 100% sure whether I'll be able to pull that off or not, but I did start tinkering with some of the tools again, and decided to challenge myself incrementally. There's still a lot I have to learn about the NES hardware, and the tricks I can pull off with it.So what I'm going to do is post blogs like this each time I complete a challenge I've set. The first one was to create a "text writer", something like the printf() function, for the NES.I'm using pure assembly code, and a simple bitmap font. Strings are written to the nametable at runtime (A considerable amount of my time was spent last night trying to safely modify the nametables without glitching).The result is this:It's also scrolling, but you can't see that.If you have an NES emulator, you can take a look at the ROM:CH01.NESAnd here's the assembly listing for those of you who can read it :Pasm
;;;;;;;;;;;;;;;;;;;;;;;
;; CH01
;; Text Writer
;;;;;;;;;;;;;;;;;;;;;;;
;; By 64Mega
;;;;;;;;;;;;;;;;;;;;;;;
; Set up iNES header
.inesprg 1
.ineschr 1
.inesmap 0
.inesmir 1
;;;;;;;;;;;
;; CHR BANK
;;;;;;;;;;;
.bank 0
.org $C000
chr_palette:
.db $1D, $0C, $1C, $27, $1D, $0C, $1C, $26, $1D, $1D, $1D, $1D, $1D, $1D, $1D, $1D
.db $1D, $0C, $1C, $27, $1D, $0C, $1C, $26, $1D, $1D, $1D, $1D, $1D, $1D, $1D, $1D
;;;;;;;;;;;;;;;
;; VECTOR SETUP
;;;;;;;;;;;;;;;
RESET:
sei ;; Disable interrupts
cld
lda #$40
stx $4017
ldx #$FF
txs
inx
stx $2000
stx $2001
stx $4010
_vblank1:
bit $2002
bpl _vblank1
; Clear working memory
clearmem:
lda #$00
sta $0000, x
sta $0100, x
sta $0200, x
sta $0400, x
sta $0500, x
sta $0600, x
sta $0700, x
lda #$FE
sta $0300, x
inx
bne clearmem
_vblank2:
bit $2002
bpl _vblank2
;;;;;;;;;;;;;;;;;;
;; MACROS
;;;;;;;;;;;;;;;;;;
ppu_addr .macro
lda \1
sta $2006
lda \2
sta $2006
.endm
write_nt_char .macro
lda \1
sta $2007
.endm
write_nt_str .macro ;; Doesn't work
ldx #$00
.xloop\@:
lda \1, x
beq .xloopend\@
sbc #$41
sta $2007
.xloopend\@:
.endm
;;;;;;;;;;;;;;;;;
;; Initialize PPU
;;;;;;;;;;;;;;;;;
lda #%00011111
sta $2001
loadPalettes:
lda $2002
lda #$3F
sta $2006
lda #$10
sta $2006
ldx #$00
loop_paletteLoop:
lda chr_palette, x
sta $2007
inx
cpx #$20
bne loop_paletteLoop
ldx #$00
finalizePPU:
lda #%10000000
sta $2000
setupVars:
; YScroll
lda #$00
sta $0100
gameLoop:
gameLoopVBlank:
bit $2002
bpl gameLoopVBlank ;; I should probably write a macro for this...
bit $2002
lda #$20
sta $2006
lda #$00
sta $2006
lda #$00
ldx #$40
zeroWrite:
sta $2007
dex
bne zeroWrite
ldx #$00
bit $2002
bit $2002
ldx #$00
loopwc_begin:
lda str_test2, x
cmp #$00
beq loopwc_end
sbc #64
sta $2007
inx
jmp loopwc_begin
loopwc_end:
;; Scroll screen for kicks
bit $2002
ldx #00
stx $2005
ldx $0100
dex
txa
cmp #$00
beq reset_yscroll
jmp or_not
reset_yscroll:
ldx #$E0
or_not:
stx $2005
stx $0100
jmp gameLoop
;; Non-Maskable Interrupt
;; Do any DMA stuff here.
NMI:
rti
str_test2:
.db "HELLO SIXTY FOUR DIGITS"
.db 0
;;;;;;;;;;;;;;;
;; BANK 1 SETUP
;;;;;;;;;;;;;;;
.bank 1
.org $FFFA
.dw NMI
.dw RESET
.dw 0
.bank 2
.org $0000
.incbin "./res/simplefont.chr"
asm
;; I should do this
lda $<somelocation>
bne a_label
;; Instead of
lda $<somelocation>
cmp #$00
bne a_label
i've been playing NES games exclusively lately, lol. this does indeed work in an emulator. it's white text on grey though, not orange and black.
if you managed to make something with this, that would be pretty neat.Could be an emulator specific problem, though it could also be that I'm accidentally clobbering the palette values in certain situations.
If I get into this enough, I'll probably at least try making a shmup or platformer for the NES. :P