for this question I have the content of 2 asm files. The first one is from Nerdy Nights, the second one is from Joe Granato.
My questions are as following:
1. Is the order within a LABEL important or is it just, that you have to have all parts in it?
2. What registers (X,Y and A) should be used in what label? (e.g. one used ldx and one lda in RESET label)
3. The second code by Joe Granato uses PHA, TXA, PHA and TYA in the NMI label, is there an equivalent in Nerdy Nights code?
4. What should exactly happen in RESET, NMI, Clearmemory? (especially if comparing both codes)
5. Where in the code from Joe Granato is said that the green $0a is used? How would I change it (not the color palette itself)?
I look forward for your answers.
Thank you in advance.
Here is the code:
Nerdy Nights:
Code: Select all
;; 1. The iNES Header
.db "NES", $1a ;INES identifier
.db $01 ;number of PRG-Rom blocks the game will have
.db $01 ;number of CHR-Rom blocks the game will have
.db $00, $01 ;control bytes
.db $00, $00, $00, $00, $00, $00, $00, $00 ;filler
;; 2. Constants and Variables
.enum $0000
;variables will eventually go here
.ende
;;;;;;;;;;;;;;;
.org $C000
RESET:
SEI ; disable IRQs
CLD ; disable decimal mode
LDX #$40
STX $4017 ; disable APU frame IRQ
LDX #$FF
TXS ; Set up stack
INX ; now X = 0
STX $2000 ; disable NMI
STX $2001 ; disable rendering
STX $4010 ; disable DMC IRQs
vblankwait1: ; First wait for vblank to make sure PPU is ready
BIT $2002
BPL vblankwait1
clrmem:
LDA #$00
STA $0000, x
STA $0100, x
STA $0300, x
STA $0400, x
STA $0500, x
STA $0600, x
STA $0700, x
LDA #$FE
STA $0200, x
INX
BNE clrmem
vblankwait2: ; Second wait for vblank, PPU is ready after this
BIT $2002
BPL vblankwait2
LoadPalettes:
LDA $2002 ; read PPU status to reset the high/low latch
LDA #$3F
STA $2006 ; write the high byte of $3F00 address
LDA #$00
STA $2006 ; write the low byte of $3F00 address
LDX #$00 ; start out at 0
LoadPalettesLoop:
LDA palette, x ; load data from address (palette + the value in x)
; 1st time through loop it will load palette+0
; 2nd time through loop it will load palette+1
; 3rd time through loop it will load palette+2
; etc
STA $2007 ; write to PPU
INX ; X = X + 1
CPX #$20 ; Compare X to hex $10, decimal 16 - copying 16 bytes = 4 sprites
BNE LoadPalettesLoop ; Branch to LoadPalettesLoop if compare was Not Equal to zero
; if compare was equal to 32, keep going down
LoadSprites:
LDX #$00 ; start at 0
LoadSpritesLoop:
LDA sprites, x ; load data from address (sprites + x)
STA $0200, x ; store into RAM address ($0200 + x)
INX ; X = X + 1
CPX #$10 ; Compare X to hex $10, decimal 16
BNE LoadSpritesLoop ; Branch to LoadSpritesLoop if compare was Not Equal to zero
; if compare was equal to 16, keep going down
LoadBackground:
LDA $2002 ; read PPU status to reset the high/low latch
LDA #$20
STA $2006 ; write the high byte of $2000 address
LDA #$00
STA $2006 ; write the low byte of $2000 address
LDX #$00 ; start out at 0
LoadBackgroundLoop:
LDA background, x ; load data from address (background + the value in x)
STA $2007 ; write to PPU
INX ; X = X + 1
CPX #$80 ; Compare X to hex $80, decimal 128 - copying 128 bytes
BNE LoadBackgroundLoop ; Branch to LoadBackgroundLoop if compare was Not Equal to zero
; if compare was equal to 128, keep going down
LoadAttribute:
LDA $2002 ; read PPU status to reset the high/low latch
LDA #$23
STA $2006 ; write the high byte of $23C0 address
LDA #$C0
STA $2006 ; write the low byte of $23C0 address
LDX #$00 ; start out at 0
LoadAttributeLoop:
LDA attribute, x ; load data from address (attribute + the value in x)
STA $2007 ; write to PPU
INX ; X = X + 1
CPX #$08 ; Compare X to hex $08, decimal 8 - copying 8 bytes
BNE LoadAttributeLoop ; Branch to LoadAttributeLoop if compare was Not Equal to zero
; if compare was equal to 128, keep going down
LDA #%10010000 ; enable NMI, sprites from Pattern Table 0, background from Pattern Table 1
STA $2000
LDA #%00011110 ; enable sprites, enable background, no clipping on left side
STA $2001
Forever:
JMP Forever ;jump back to Forever, infinite loop
NMI:
LDA #$00
STA $2003 ; set the low byte (00) of the RAM address
LDA #$02
STA $4014 ; set the high byte (02) of the RAM address, start the transfer
LatchController:
LDA #$01
STA $4016
LDA #$00
STA $4016 ; tell both the controllers to latch buttons
ReadA:
LDA $4016 ; player 1 - A
AND #%00000001 ; only look at bit 0
BEQ ReadADone ; branch to ReadADone if button is NOT pressed (0)
; add instructions here to do something when button IS pressed (1)
LDA $0203 ; load sprite X position
CLC ; make sure the carry flag is clear
ADC #$01 ; A = A + 1
STA $0203 ; save sprite X position
ReadADone: ; handling this button is done
ReadB:
LDA $4016 ; player 1 - B
AND #%00000001 ; only look at bit 0
BEQ ReadBDone ; branch to ReadBDone if button is NOT pressed (0)
; add instructions here to do something when button IS pressed (1)
LDA $0203 ; load sprite X position
SEC ; make sure carry flag is set
SBC #$01 ; A = A - 1
STA $0203 ; save sprite X position
ReadBDone: ; handling this button is done
;;This is the PPU clean up section, so rendering the next frame starts properly.
LDA #%10010000 ; enable NMI, sprites from Pattern Table 0, background from Pattern Table 1
STA $2000
LDA #%00011110 ; enable sprites, enable background, no clipping on left side
STA $2001
LDA #$00 ;;tell the ppu there is no background scrolling
STA $2005
STA $2005
RTI ; return from interrupt
;;;;;;;;;;;;;;
.org $E000
palette:
.db $22,$29,$1A,$0F, $22,$36,$17,$0F, $22,$30,$21,$0F, $22,$27,$17,$0F ;;background palette
.db $22,$1C,$15,$14, $22,$02,$38,$3C, $22,$1C,$15,$14, $22,$02,$38,$3C ;;sprite palette
sprites:
;vert tile attr horiz
.db $80, $32, $00, $80 ;sprite 0
.db $80, $33, $00, $88 ;sprite 1
.db $88, $34, $00, $80 ;sprite 2
.db $88, $35, $00, $88 ;sprite 3
background:
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24 ;;row 1
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24 ;;all sky
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24 ;;row 2
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24 ;;all sky
.db $24,$24,$24,$24,$45,$45,$24,$24,$45,$45,$45,$45,$45,$45,$24,$24 ;;row 3
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$53,$54,$24,$24 ;;some brick tops
.db $24,$24,$24,$24,$47,$47,$24,$24,$47,$47,$47,$47,$47,$47,$24,$24 ;;row 4
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$55,$56,$24,$24 ;;brick bottoms
attribute:
.db %00000000, %00010000, %01010000, %00010000, %00000000, %00000000, %00000000, %00110000
.db $24,$24,$24,$24, $47,$47,$24,$24 ,$47,$47,$47,$47, $47,$47,$24,$24 ,$24,$24,$24,$24 ,$24,$24,$24,$24, $24,$24,$24,$24, $55,$56,$24,$24 ;;brick bottoms
.org $FFFA ;first of the three vectors starts here
.dw NMI ;when an NMI happens (once per frame if enabled) the
;processor will jump to the label NMI:
.dw RESET ;when the processor first turns on or is reset, it will jump
;to the label RESET:
.dw 0 ;external interrupt IRQ is not used in this tutorial
;;;;;;;;;;;;;;
.incbin "mario.chr" ;includes 8KB graphics file from SMB1
Joe Granato:
Code: Select all
.inesprg 1 ; 1x 16KB PRG code
.ineschr 1 ; 1x 8KB CHR data
.inesmap 0 ; mapper 0 = NROM, no bank swapping
.inesmir 1 ; background mirroring
.bank 0
;; 3. Set the code starting point
.org $C000 ;this starts the code at the address $C000
;; 4. The RESET routine
;;turn things off and initialize
RESET:
SEI ;SEI tells the code to ignore interrupts for the routine
LDA #$00 ;load 0 into the accumulator
STA $2000 ;disable the NMI
STA $2001 ;disable rendering
STA $4010
STA $4015
LDA #$40 ;loads HEX value 40 which is dec value 64
STA $4017
CLD ;disable decimal mode
LDX #$FF ;loads value 255
TXS ;initialize the stack
bit $2002
vBlankWait1:
bit $2002
BPL vBlankWait1
;;clear out memory etc.
LDA #$00 ;loads zero into the accumulator
LDX #$00 ;loads zero into x
;;ready to start loop
ClearMemomryLoop:
STA $0000,x ;store accumulator 0 into address $0000+x
STA $0100,x ;store accumulator 0 into address $0100+x
STA $0200,x ;store accumulator 0 into address $0200+x
STA $0300,x ;store accumulator 0 into address $0300+x
STA $0400,x ;store accumulator 0 into address $0400+x
STA $0500,x ;store accumulator 0 into address $0500+x
STA $0600,x ;store accumulator 0 into address $0600+x
STA $0700,x ;store accumulator 0 into address $0700+x
INX ;x goes up by one, so all of those + x's at the end that were zero the first time through are increased
BNE ClearMemomryLoop ;loop again until all adresses + x (#$FF = 255) become 0
vBlankWait2:
bit $2002
BPL vBlankWait2
;;turn things back on now that we're set up
LDA #%10010000 ;loads this binary number to accumulator = 144 decimal
STA $2000 ;storing it here, turns NMI back on
LDA #%00011110 ;loads this binary number to accumulator = 30 decimal
STA $2001 ;enables rendering
JMP MainGameLoop
;; 5. The NMI
NMI:
;PUSH registers to the stack to preserve them
PHA ;this pushes the accumulator to the stack, it is the first thing there.
TXA ;this loads whatever is in X into the accumulator
PHA ;and pushes it into the accumulator, now the old 'A' is on the bottom and X is on top of it
TYA ;this loads whatever is in Y into the accumulator
PHA ;and pushes the accumulator to the stack, now Y is on top, X is in the middle and A is in the bottom
;;do NMI things here
;;transfer sprites to PPU
LDA #$00 ;puts 0 into the accumulator (low byte)
STA $2003 ;sets the low byte of the sprite RAM address
LDA #$02 ;puts 02 into the accumulator (high byte)
STA $4014 ;sets high byte of the RAM address and starts transfer
;read backwards: RAM address we loaded 00
;then loaded 02 (this has loaded low byte of 00, high byte 02 = it is a 16-bit address)
;high+low (02+00 or $0200), this the address for our sprite data
;load the palettes
LDA $2002
LDA #$3F
STA $2006
LDA #$00
STA $2006
LDX #$00
;ready to start loop
LoadPaletteLoop:
LDA MyPalettes,x ;load value from the table that x equals to
STA $2007 ;store it to the address that handles palettes
INX ;increase x
CPX #$20 ;compare it to hex 20 = 32 decimal (8 banks of 4 colors), so 32-times the loop
BNE LoadPaletteLoop ;if 32-x is not 0, then start loop again
LDA #%10010000 ;turns on NMI, like in RESET = 144 decimal
STA $2000
LDA #%00011110 ;turns on rendering, like in RESET = 30 decimal
STA $2001
;PULL registers from the stack and restore them
;first thing to pull is the top, then go down
PLA ;pulls the top stack and put it in the accumulator
TAY ;puts that value into Y, now Y is restored to what it was before NMI
PLA ;pulls second stack value and puts it in accumulator
TAX ;puts that value into X, now X is restored to what it was before NMI
PLA ;pulls third stack value and puts it in accumulator, now Y, X and A are all restored
RTI ;at the end of NMI, return from the interrupt
;; 6. The Main Game Loop
MainGameLoop:
;game logic will go here
JMP MainGameLoop ;jumps back to MainGameLoop, create an infinite loop
;; 7. Sub Routines
.bank 1
.org $E000
;; 8. Includes and data tables
MyPalettes:
;backgroud
.db $0F,$11,$17,$0a, $28,$31,$01,$1c, $05,$3c,$01,$14, $08,$21,$39,$03
;sprites
.db $0F,$31,$28,$1b, $13,$06,$05,$31, $39,$2a,$2c,$16, $17,$13,$14,$00
;; 9. The Vectors
.org $fffa ;sets up at the very end of the code
.dw NMI ;now the NMI points to our label NMI
.dw RESET ;now the RESET points to our label RESET
.dw 00