Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ; reference: https://www.kibrit.tech/en/blog/nes-game-development-part-1
- ; -----------------------------------------------------
- ; Header
- ; -----------------------------------------------------
- ; These 16 bytes let nes know how banks are organised
- ; and how to run code
- .segment "HEADER"
- .byte "NES" ; Name of Game (Maybe?)
- .byte $1a ; Indicates to nes that this is a game file that can be loaded
- .byte $02 ; 2 * 16KB PRG ROM for code
- .byte $01 ; 1 * 8KB CHR ROM for sprites
- .byte %00000001 ; mapper and mirroring
- .byte $00
- .byte $00
- .byte $00
- .byte $00
- .byte $00, $00, $00, $00, $00 ; filler bytes
- .segment "ZEROPAGE" ; $0 - $FF
- ; -----------------------------------------------------
- ; Startup
- ; -----------------------------------------------------
- .segment "STARTUP"
- ; Interrupts
- ; some things must be disabled or initalised for reset
- ; process
- Reset:
- sei ; disable interrupts
- cld ; disable decimal mode
- ldx #$40
- stx $4017 ;disable APU interrupts
- ldx #$FF
- txs ; (copy x to s) Initialise stack
- inx ; set x to $00
- ; Zero out PPU
- stx $2000
- stx $2001
- stx $4010 ; disable APU DMC channel
- ; We need to wait for VBlank before doing anything
- ; Waits until VBlank period
- ; bit $2002 sets negative flag to match the 7th(last) bit
- ; this is the bit that indicates we are in a VBlank
- ; if vblank = 0, negative = 0
- ; bpl will brach if posotive, aka if negative flag = 0
- VBlankWait1:
- bit $2002
- bpl VBlankWait1
- ; Clearing Memory
- ; When console starts RAM is initalised with random/garbage values
- ; NES RAM = 2KB or $0000 to $0800
- ; We need to init these all to #$00
- ; First, set a to zero, then store in registers seen below
- ; with offset of x. Then increment x every cycle
- ; if x = 0, branch out
- ClearMem:
- lda #$00
- sta $0000, x ; 0 - 255
- sta $0100, x ; 256 - 511
- ; $0200 - $02FF designated for sprite storage
- sta $0300, x ; etc
- sta $0400, x
- sta $0500, x
- sta $0600, x
- sta $0700, x
- ; put all sprites off-screen. PPU will ignore them
- lda #$FE
- sta $0200, x
- inx
- cpx #$00
- bne ClearMem
- ; wait for another VBlank to make sure NES is totally ready
- VBlankWait2:
- bit $2002
- bpl VBlankWait2
- ; PPU Palettes and init
- ; PPU needs to know where sprites are located($0200 - $02FF)
- lda #$02 ; load most significant byte of $0200 into A
- sta $4014 ; tells PPU where sprites start will assume next 256 bytes are sprites too
- nop ; (no operation) Give time for the PPU to load
- ; Palette Init
- ; Total of 8 palettes. 4 for background and 4 for sprites
- ; 32 bytes all together
- ; Each palette consists of 4 colors, where the first one
- ; is always the same
- ; PPU has own internal RAM.
- ; Palettes are stored in range $3F00 -$3F1F
- ; PPU first needs to know what we want ot write
- ; to this range of memory
- ; We do this by giving the address to $2006 which will send that
- ; to the PPU RAM, since the CPU and PPU are on different buses
- lda #$3F ; load most significant bit to A
- sta $2006 ; sends to PPU
- lda #$00 ; load least significant bit to A
- sta $2006 ; sends to PPU
- ; Next we need to load the palettes by iterating
- ; through PaletteData(which stores each palette in groups of 4 bytes)
- ; and adding each to $2007
- ; PPU will then read the color from that port and write to $3F00,
- ; then increment by itself and write the next color to $3F01, etc.
- ldx #$00 ; init x for indexing PaletteData
- LoadPalettes:
- lda PaletteData, x ; load color from PaletteData at index X
- sta $2007 ; $3F00 - $3F1F
- inx
- cpx #$20
- bne LoadPalettes ; if x != 32, loop
- ; Now, all of the palettes are loaded into the PPU
- ; Loading Sprites
- ; Memory Range $0200 - $02FF
- ; Sprites are stored in a different file, in this case, "hellomario.chr"
- ; We iterate through the sprites and store them in $0200 - $02FF
- ldx #$00
- LoadSprites:
- lda SpriteData, x
- sta $0200, x
- inx
- cpx #$20
- bne LoadSprites
- ; NMI(Non-Maskable Interrupts)
- ; NMIs happen every frame. This is a good place to do
- ; graphical updates
- ; The PPUs RAM is dynamic(values will degrade over time) so we will
- ; use the NMI to update that memory every frame
- ; We also need to re-enable all the interrupts from earlier in the HEADER
- cli ; re-enable interrupts
- ; Re-enables PPU drawing
- lda #%10010000
- sta $2000
- lda #%00011110
- sta $2001
- ; AAAAAALLLLLL of that was part of the reset process
- ; Now, we define the behaviour of the NMI interrupt, which is much simpler
- ; Here we tell the PPU from where to take the spprites for
- ; an update by providing the most significant bit of $0200
- NMI:
- lda #$02
- sta $4014 ; send to PPU memory for display
- rti ; return form interrupt
- ; Palette Data and Sprite Data
- ; Each palette starts with the same number
- PaletteData:
- .byte $22,$29,$1A,$0F,$22,$36,$17,$0f,$22,$30,$21,$0f,$22,$27,$17,$0F ;background palette data
- .byte $22,$16,$27,$18,$22,$1A,$30,$27,$22,$16,$30,$27,$22,$0F,$36,$17 ;sprite palette data
- ; Byte 0 = Y position
- ; Byte 1 = Tile Index
- ; Byte 2 = Attributes - sprite flipping, z depth and palette
- ; Byte 3 = X position of sprite
- SpriteData:
- .byte $08, $00, $00, $08
- .byte $08, $01, $00, $10
- .byte $10, $02, $00, $08
- .byte $10, $03, $00, $10
- .byte $18, $04, $00, $08
- .byte $18, $05, $00, $10
- .byte $20, $06, $00, $08
- .byte $20, $07, $00, $10
- ; -----------------------------------------------------
- ; Vectors
- ; -----------------------------------------------------
- ; Sometimes interrupts are called vectors, these will just
- ; connect the labels to the actual interrupts
- .segment "VECTORS"
- .word NMI
- .word Reset
- ; -----------------------------------------------------
- ; Chars
- ; -----------------------------------------------------
- ; Lastly, we need to include a tile map where the
- ; actual sprites are stored
- ; I'm using a mario .chr with marios sprites in it
- .segment "CHARS"
- .incbin "hellomario.chr"
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement