307 lines
12 KiB
NASM
Executable File
307 lines
12 KiB
NASM
Executable File
; HEADER
|
|
.include "consts.inc"
|
|
.include "header.inc"
|
|
.include "reset.inc"
|
|
.include "utils.inc"
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
.segment "ZEROPAGE"
|
|
Buttons: .res 1 ; Button bytes
|
|
XPos: .res 1 ; Char X position
|
|
YPos: .res 1 ; Char Y Position
|
|
Frame: .res 1 ; Reserve 1 byte to store the number of frames
|
|
Clock60: .res 1 ; Store a counter that increments every second (60 frames)
|
|
BgPtr: .res 2 ; Reserve 2 bytes store a ptr to bg address
|
|
; Store low then high bytes (little endian)
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; PRG-ROM code located at $8000
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
.segment "CODE"
|
|
|
|
; LoadPalette
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; 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
|
|
; LoadBackground
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Subroutine to load the background 255 tiles in first nametable
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
.proc LoadBackground
|
|
lda #<BackgroundData
|
|
sta BgPtr
|
|
lda #>BackgroundData
|
|
sta BgPtr+1
|
|
|
|
PPU_SETADDR $2000 ; nametable 0
|
|
|
|
ldx #$00 ; high byte (0-3)
|
|
ldy #$00 ; low byte (0-FF)
|
|
|
|
OuterLoop:
|
|
InnerLoop:
|
|
lda (BgPtr),y ; fetch the value pointed by bgptr+y
|
|
sta PPU_DATA ; store value in ppu data
|
|
iny ; y++
|
|
cpy #0 ; if y == 0 then wrapped
|
|
beq IncreaseHiByte ; then: increase hi byte
|
|
jmp InnerLoop ; else: continue inner loop
|
|
IncreaseHiByte:
|
|
inc BgPtr+1 ; we increment the hi byte pointer to point to the next bg section
|
|
inx ; X++
|
|
cpx #4 ; break condition (4 sections bg)
|
|
bne OuterLoop ; if x is stil not 4, loop back to outer loop
|
|
|
|
rts ; Return from subroutine
|
|
.endproc
|
|
; LoadText
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Subroutine to load text in the nametable until it finds a 0-terminator
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
.proc LoadText
|
|
PPU_SETADDR $21CB
|
|
|
|
ldy #0 ;y=0
|
|
Loop:
|
|
lda TextMessage,y ; Fetch character byte from ROM
|
|
beq EndLoop ; If the character is 0, end loop
|
|
|
|
cmp #32 ; Compare to ASCII 32
|
|
bne DrawLetter ; if its not, draw the letter
|
|
DrawSpace:
|
|
lda #$24 ; tile $24 is a space
|
|
sta PPU_DATA ; Store PPU_DATA with the empty tile
|
|
jmp NextChar ; go to next character
|
|
DrawLetter:
|
|
sec ; set carry
|
|
sbc #55 ; subtract 55 from the ASCII value, to get the character tile as chars start at 10
|
|
sta PPU_DATA ; store the data and advance the PPU_ADDR
|
|
NextChar:
|
|
iny ; y++, next character from the string
|
|
jmp Loop ; go back to top of loop
|
|
|
|
EndLoop:
|
|
rts ; Return from subroutine
|
|
.endproc
|
|
; LoadSprites
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Subroutine to load all 16 sprites into OAM-RAM starting at $0200
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
.proc LoadSprites
|
|
ldx #0 ;
|
|
LoadSprites: ;
|
|
lda SpriteData,x ; fetch bytes from SpriteData lookup table
|
|
sta $0200,x ; store bytes starting at OAM $0200
|
|
inx ; X++
|
|
cpx #32;
|
|
bne LoadSprites ; Loop 16 times (4 hardware sprites, 4 bytes each)
|
|
rts ; Return from subroutine
|
|
.endproc
|
|
;ReadControllers
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Reset handler (called when the NES resets or powers on)
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
.proc ReadControllers
|
|
lda #1 ; A=1
|
|
sta Buttons ; Buttons=1 (This will carry to the bcc, not an input value)
|
|
|
|
sta JOYPAD1 ; Set latch to 1 to begin input
|
|
lsr ; A=0 by shifting right, quicker maybe
|
|
sta JOYPAD1 ; Set latch to 0 to begin output
|
|
LoopButtons:
|
|
lda JOYPAD1 ; 1. reads a bit from the controller line and inverts its value
|
|
; 2. sends a signal to the clock line to shift the bits inside the controller
|
|
|
|
lsr ; we shift right to place that 1bit
|
|
rol Buttons ; rolls bits to the left, placing the carry inside the first bit of `Buttons` in ram
|
|
bcc LoopButtons ; loop until carry is set (from that initial 1 we had inside buttons
|
|
rts
|
|
.endproc
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Reset handler (called when the NES resets or powers on)
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
Reset:
|
|
INIT_NES ; Macro to initialize the NES to a known state
|
|
|
|
InitVariables:
|
|
lda #0
|
|
sta Frame
|
|
sta Clock60
|
|
|
|
|
|
ldx #0
|
|
lda SpriteData,x
|
|
sta YPos
|
|
inx
|
|
inx
|
|
inx
|
|
lda SpriteData,x
|
|
sta XPos
|
|
|
|
|
|
Main:
|
|
jsr LoadPalette ; Jump to subroutine LoadPalette
|
|
jsr LoadBackground ; Jump to subroutine LoadBackground
|
|
jsr LoadSprites
|
|
|
|
EnablePPURendering:
|
|
lda #%10010000 ; enable NMI and set bg to use second pattern table
|
|
sta PPU_CTRL
|
|
lda #0 ; disable ppu scrolling
|
|
sta PPU_SCROLL ; latch (in X)
|
|
sta PPU_SCROLL ; latch (in y)
|
|
lda #%00011110
|
|
sta PPU_MASK
|
|
|
|
LoopForever:
|
|
jmp LoopForever ; Force an infinite execution loop
|
|
|
|
; NMI
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; NMI interrupt handler
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
NMI:
|
|
inc Frame ; Frame ++
|
|
; -------------------------------------
|
|
; As soon as we enter the NMI handler, start OAM copy
|
|
lda #$02 ; every frame we copy sprite data starting at $02**
|
|
sta PPU_OAM_DMA ; The OAM DMA Copy starts when we write to PPU_OAM_DMA
|
|
; -------------------------------------
|
|
|
|
jsr ReadControllers ; Jump to the subroutine that checks the controllers
|
|
|
|
CheckRightButton:
|
|
lda Buttons
|
|
and #BUTTON_RIGHT
|
|
beq CheckLeftButton
|
|
inc XPos ; X++
|
|
CheckLeftButton:
|
|
lda Buttons
|
|
and #BUTTON_LEFT
|
|
beq CheckDownButton
|
|
dec XPos ; X--
|
|
CheckDownButton:
|
|
lda Buttons
|
|
and #BUTTON_DOWN
|
|
beq CheckUpButton
|
|
inc YPos ; Y++
|
|
CheckUpButton:
|
|
lda Buttons
|
|
and #BUTTON_UP
|
|
beq :+
|
|
dec YPos ; Y--
|
|
:
|
|
|
|
UpdateSpritePosition:
|
|
lda XPos
|
|
sta $0203
|
|
sta $020B
|
|
clc
|
|
adc #8
|
|
sta $0207
|
|
sta $020F
|
|
|
|
lda YPos
|
|
sta $0200
|
|
sta $0204
|
|
clc
|
|
adc #8
|
|
sta $0208
|
|
sta $020C
|
|
|
|
;;;;
|
|
lda Frame ; increment clock60 every time the frame reaches 60
|
|
cmp #60 ; frame equal to 60?
|
|
bne :+ ; branch to end if not 60, carry on!
|
|
inc Clock60
|
|
lda #0
|
|
sta Frame ; Zero Frame Counter
|
|
:
|
|
|
|
rti ; Return from interrupt
|
|
|
|
; IRQ
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; 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 CP 00 01 10 11
|
|
.byte $22,$16,$27,$18, $22,$1a,$30,$27, $22,$16,$30,$27, $22,$0f,$36,$17 ; sprite CP 00 01 10 11
|
|
|
|
;BackgroundData
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Background data with tile numbers that must be copied to the nametable
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
BackgroundData:
|
|
.incbin "background.nam"
|
|
|
|
|
|
;SpriteData
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; This is the OAM sprite attribute data data we will use in our game
|
|
;; We have only one big metasprite that is composed of 4 hardware sprites
|
|
;; the OAM is organized in sets of 4 bytes per tile
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
; Sprite Attribute Byte:
|
|
; ----------------------
|
|
; 76543210
|
|
; ||| ||
|
|
; ||| ++- Color Palette of Sprite: Choose which set of 4 from the 16 colors to use
|
|
; |||
|
|
; ||+------ Priority (0: in front of BG, 1: Behind BG)
|
|
; |+------- Flip Horizontally
|
|
; +-------- Flip Vertically
|
|
SpriteData:
|
|
;--------------------------------
|
|
; Mario:
|
|
; Y tile# attributes X
|
|
.byte $AE, $3A, %00000000, $98
|
|
.byte $AE, $37, %00000000, $A0
|
|
.byte $B6, $4F, %00000000, $98
|
|
.byte $B6, $4F, %01000000, $A0
|
|
;--------------------------------
|
|
; Goomba:
|
|
; Y tile# attributes X
|
|
.byte $93, $70, %00100011, $C7
|
|
.byte $93, $71, %00100011, $CF
|
|
.byte $9B, $72, %00100011, $C7
|
|
.byte $9B, $73, %00100011, $CF
|
|
;--------------------------------
|
|
;End Sprites
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Hardcoded ASCII message stored in ROM with 0-terminator
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
TextMessage:
|
|
.byte "TYREL SOUZA",$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
|