194 lines
12 KiB
NASM
194 lines
12 KiB
NASM
|
.include "consts.inc"
|
||
|
.include "header.inc"
|
||
|
.include "reset.inc"
|
||
|
.include "utils.inc"
|
||
|
|
||
|
.segment "ZEROPAGE"
|
||
|
Frame: .res 1 ; Reserve 1 byte to store the number of frames
|
||
|
Clock60: .res 1 ; Reserve 1 byte to store a counter that increments every second (60 frames)
|
||
|
BgPtr: .res 2 ; Reserve 2 bytes (16 bits) to store a pointer to the background address
|
||
|
; (we store first the lo-byte, and immediately after, the hi-byte) - little endian
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;; PRG-ROM code located at $8000
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
.segment "CODE"
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;; Subroutine to load all 32 color palette values from ROM
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
.proc LoadPalette
|
||
|
PPU_SETADDR $3F00
|
||
|
ldy #0 ; Y = 0
|
||
|
: lda PaletteData,y ; Lookup byte in ROM
|
||
|
sta PPU_DATA ; Set value to send to PPU_DATA
|
||
|
iny ; Y++
|
||
|
cpy #32 ; Is Y equal to 32?
|
||
|
bne :- ; Not yet, keep looping
|
||
|
rts ; Return from subroutine
|
||
|
.endproc
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;; Subroutine to load tiles and attributes into the first nametable
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
.proc LoadBackground
|
||
|
lda #<BackgroundData ; Fetch the lo-byte of BackgroundData address
|
||
|
sta BgPtr
|
||
|
lda #>BackgroundData ; Fetch the hi-byte of BackgroundData address
|
||
|
sta BgPtr+1
|
||
|
|
||
|
PPU_SETADDR $2000
|
||
|
|
||
|
ldx #$00 ; X = 0 --> x is the outer loop index (hi-byte) from $0 to $4
|
||
|
ldy #$00 ; Y = 0 --> y is the inner loop index (lo-byte) from $0 to $FF
|
||
|
OuterLoop:
|
||
|
InnerLoop:
|
||
|
lda (BgPtr),y ; Fetch the value *pointed* by BgPtr + Y
|
||
|
sta PPU_DATA ; Store in the PPU data
|
||
|
iny ; Y++
|
||
|
cpy #0 ; If Y == 0 (wrapped around 256 times)?
|
||
|
beq IncreaseHiByte ; Then: we need to increase the hi-byte
|
||
|
jmp InnerLoop ; Else: Continue with the inner loop
|
||
|
IncreaseHiByte:
|
||
|
inc BgPtr+1 ; We increment the hi-byte pointer to point to the next background section (next 255-chunk)
|
||
|
inx ; X++
|
||
|
cpx #4 ; Compare X with #4
|
||
|
bne OuterLoop ; If X is still not 4, then we keep looping back to the outer loop
|
||
|
rts ; Return from subroutine
|
||
|
.endproc
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;; Subroutine to load text in the nametable until it finds a 0-terminator
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
.proc LoadText
|
||
|
|
||
|
;; TODO:
|
||
|
;; Loop all characters from ROM and load/display the text in the nametable.
|
||
|
;; Bonus points if you code manages to display an empty tile for [space].
|
||
|
|
||
|
rts ; Return from subroutine
|
||
|
.endproc
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;; Reset handler (called when the NES resets or powers on)
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
Reset:
|
||
|
INIT_NES ; Macro to initialize the NES to a known state
|
||
|
|
||
|
lda #0
|
||
|
sta Frame ; Frame = 0
|
||
|
sta Clock60 ; Clock60 = 0
|
||
|
|
||
|
Main:
|
||
|
jsr LoadPalette ; Call LoadPalette subroutine to load 32 colors into our palette
|
||
|
jsr LoadBackground ; Call LoadBackground subroutine to load a full nametable of tiles and attributes
|
||
|
jsr LoadText ; Call LoadText subroutine to draw the text message on the nametable
|
||
|
|
||
|
EnablePPURendering:
|
||
|
lda #%10010000 ; Enable NMI and set background to use the 2nd pattern table (at $1000)
|
||
|
sta PPU_CTRL
|
||
|
lda #0
|
||
|
sta PPU_SCROLL ; Disable scroll in X
|
||
|
sta PPU_SCROLL ; Disable scroll in Y
|
||
|
lda #%00011110
|
||
|
sta PPU_MASK ; Set PPU_MASK bits to render the background
|
||
|
|
||
|
LoopForever:
|
||
|
jmp LoopForever ; Force an infinite execution loop
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;; NMI interrupt handler
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
NMI:
|
||
|
inc Frame ; Frame++
|
||
|
|
||
|
lda Frame ; Increment Clock60 every time we reach 60 frames (NTSC = 60Hz)
|
||
|
cmp #60 ; Is Frame equal to #60?
|
||
|
bne :+ ; If not, bypass Clock60 increment
|
||
|
inc Clock60 ; But if it is 60, then increment Clock60 and zero Frame counter
|
||
|
lda #0
|
||
|
sta Frame
|
||
|
:
|
||
|
rti ; Return from interrupt
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;; IRQ interrupt handler
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
IRQ:
|
||
|
rti ; Return from interrupt
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;; Hardcoded list of color values in ROM to be loaded by the PPU
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
PaletteData:
|
||
|
.byte $22,$29,$1A,$0F, $22,$36,$17,$0F, $22,$30,$21,$0F, $22,$27,$17,$0F ; Background palette
|
||
|
.byte $22,$16,$27,$18, $22,$1A,$30,$27, $22,$16,$30,$27, $22,$0F,$36,$17 ; Sprite palette
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;; Background data with tile numbers that must be copied to the nametable
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
BackgroundData:
|
||
|
.byte $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
|
||
|
.byte $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
|
||
|
.byte $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
|
||
|
.byte $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
|
||
|
.byte $24,$24,$24,$24,$24,$36,$37,$36,$37,$36,$37,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
|
||
|
.byte $24,$24,$24,$24,$35,$25,$25,$25,$25,$25,$25,$38,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$36,$37,$24,$24,$24,$24,$24
|
||
|
.byte $24,$24,$24,$24,$39,$3A,$3B,$3A,$3B,$3A,$3B,$3C,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$35,$25,$25,$38,$24,$24,$24,$24
|
||
|
.byte $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$39,$3A,$3B,$3C,$24,$24,$24,$24
|
||
|
.byte $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
|
||
|
.byte $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
|
||
|
.byte $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$53,$54,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
|
||
|
.byte $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$55,$56,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
|
||
|
.byte $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
|
||
|
.byte $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
|
||
|
.byte $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
|
||
|
.byte $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
|
||
|
.byte $24,$24,$53,$54,$24,$24,$24,$24,$24,$24,$24,$24,$45,$45,$53,$54,$45,$45,$53,$54,$45,$45,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
|
||
|
.byte $24,$24,$55,$56,$24,$24,$24,$24,$24,$24,$24,$24,$47,$47,$55,$56,$47,$47,$55,$56,$47,$47,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
|
||
|
.byte $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
|
||
|
.byte $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
|
||
|
.byte $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$60,$61,$62,$63,$24,$24,$24,$24
|
||
|
.byte $24,$24,$24,$24,$24,$24,$31,$32,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$64,$65,$66,$67,$24,$24,$24,$24
|
||
|
.byte $24,$24,$24,$24,$24,$30,$26,$34,$33,$24,$24,$24,$24,$36,$37,$36,$37,$24,$24,$24,$24,$24,$24,$24,$68,$69,$26,$6A,$24,$24,$24,$24
|
||
|
.byte $24,$24,$24,$24,$30,$26,$26,$26,$26,$33,$24,$24,$35,$25,$25,$25,$25,$38,$24,$24,$24,$24,$24,$24,$68,$69,$26,$6A,$24,$24,$24,$24
|
||
|
.byte $B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5
|
||
|
.byte $B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7
|
||
|
.byte $B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B6
|
||
|
.byte $B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7
|
||
|
.byte $B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5,$B4,$B5
|
||
|
.byte $B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7,$B6,$B7
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;; Attributes tell which palette is used by a group of tiles in the nametable
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
AttributeData:
|
||
|
.byte %00000000, %00000000, %00000000, %00000000, %00000000, %00000000, %00000000, %00000000
|
||
|
.byte %00000000, %10101010, %10101010, %00000000, %00000000, %00000000, %10101010, %00000000
|
||
|
.byte %00000000, %00000000, %00000000, %00000000, %11111111, %00000000, %00000000, %00000000
|
||
|
.byte %00000000, %00000000, %10101010, %10101010, %10101010, %10101010, %00000000, %00000000
|
||
|
.byte %11111111, %00000000, %00000000, %00001111, %00001111, %00000011, %00000000, %00000000
|
||
|
.byte %00000000, %00000000, %00000000, %00000000, %00000000, %00000000, %00000000, %00000000
|
||
|
.byte %11111111, %11111111, %11111111, %11111111, %11111111, %11111111, %11111111, %11111111
|
||
|
.byte %11111111, %11111111, %11111111, %11111111, %11111111, %11111111, %11111111, %11111111
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;; Hardcoded ASCII message stored in ROM with 0-terminator
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
TextMessage:
|
||
|
.byte "HELLO WORLD",$0
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;; Here we add the CHR-ROM data, included from an external .CHR file
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
.segment "CHARS"
|
||
|
.incbin "mario.chr"
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;; Vectors with the addresses of the handlers that we always add at $FFFA
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
.segment "VECTORS"
|
||
|
.word NMI ; Address (2 bytes) of the NMI handler
|
||
|
.word Reset ; Address (2 bytes) of the Reset handler
|
||
|
.word IRQ ; Address (2 bytes) of the IRQ handler
|