pikuma_6502_nes/loadbackground/loadbackground.asm

307 lines
12 KiB
NASM
Raw Normal View History

2022-12-05 04:13:27 +00:00
; 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