Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- .inesprg 1 ; 1x 16KB PRG code
- .ineschr 1 ; 1x 8KB CHR data
- .inesmap 0 ; mapper 0 = NROM, no bank swapping
- .inesmir 1 ; VERT mirroring for HORIZ scrolling
- ;;;;;;;;;;;;;;;
- ;; DECLARE SOME VARIABLES HERE
- .rsset $0000 ;;start variables at ram location 0
- scroll .rs 1 ; horizontal scroll count
- nametable .rs 1 ; which nametable to use, 0 or 1
- columnLow .rs 1 ; low byte of new column address
- columnHigh .rs 1 ; high byte of new column address
- sourceLow .rs 1 ; source for column data
- sourceHigh .rs 1
- columnNumber .rs 1 ; which column of level data to draw
- partialVariable .rs 1 ; fractional walking speed
- isLeft .rs 1 ; set if facing left
- isDescending .rs 1 ; set if descending
- isOnGround: .rs 1 ; set if on ground
- ;; DECLARE SOME CONSTANTS HERE
- GROUND = $C8
- SEMIGROUND = $C0
- TOP_JUMP = $80
- MARIO = $0200
- ;;;;;;;;;;;;
- .bank 0
- .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)
- 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 $20, decimal 16
- BNE LoadSpritesLoop ; Branch to LoadSpritesLoop if compare was Not Equal to zero
- ; if compare was equal to 16, keep going down
- InitializeNametables:
- LDA #$01
- STA nametable
- LDA #$00
- STA scroll
- STA columnNumber
- InitializeNametablesLoop:
- JSR DrawNewColumn ; draw bg column
- LDA scroll ; go to next column
- CLC
- ADC #$08
- STA scroll
- INC columnNumber
- LDA columnNumber ; repeat for first nametable
- CMP #$20
- BNE InitializeNametablesLoop
- LDA #$00
- STA nametable
- LDA #$00
- STA scroll
- JSR DrawNewColumn ; draw first column of second nametable
- INC columnNumber
- LDA #$00 ; set back to increment +1 mode
- STA $2000
- InitializeNametablesDone:
- InitializeAttributes:
- LDA #$01
- STA nametable
- LDA #$00
- STA scroll
- STA columnNumber
- InitializeAttributesLoop:
- JSR DrawNewAttributes ; draw attribs
- LDA scroll ; go to next column
- CLC
- ADC #$20
- STA scroll
- LDA columnNumber ; repeat for first nametable
- CLC
- ADC #$04
- STA columnNumber
- CMP #$20
- BNE InitializeAttributesLoop
- LDA #$00
- STA nametable
- LDA #$00
- STA scroll
- JSR DrawNewAttributes ; draw first column of second nametable
- InitializeAttributesDone:
- LDA #$21
- STA columnNumber
- 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
- ;; ----- Initialize variables -----
- LDA #$00
- STA partialVariable
- LDA #%00000000
- STA isLeft
- LDA #%00000000
- STA isDescending
- LDA #%00000001
- STA isOnGround
- Forever:
- JMP Forever ; jump back to Forever, infinite loop
- ;; ----- NMI -----
- NMI:
- LDA #$00
- STA $2003
- LDA #$02
- STA $4014 ; sprite DMA from $0200
- ; run other game graphics updating code here
- LDA #$00
- STA $2006 ; clean up PPU address registers
- STA $2006
- LDA scroll
- STA $2005 ; write the horizontal scroll count register
- LDA #$00 ; no vertical scrolling
- STA $2005
- ;; ------------------------------------------------------------------------------
- ;; 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
- ORA nametable ; select correct nametable for bit 0
- STA $2000
- LDA #%00011110 ; enable sprites, enable background, no clipping on left side
- STA $2001
- ; run normal game engine code here
- ; reading from controllers, etc
- ;; --------------------------------
- ;; ---------- CONTROLLER ----------
- ;; --------------------------------
- LatchController:
- LDA #$01
- STA $4016
- LDA #$00
- STA $4016 ; tell both the controllers to latch buttons
- ReadA: ; ----- BUTTON A (JUMP) -----
- LDA $4016 ; player 1 - A
- AND #%00000001 ; only look at bit 0
- BEQ DescendNow ; branch to DescendNow if button is NOT pressed (0)
- ; add instructions here to do something when button IS pressed (1)
- LDA MARIO
- CMP #TOP_JUMP
- BEQ DescendNow
- LDA isDescending
- CMP #%00000001
- BEQ DescendNow
- JSR Jump
- LDA #$00
- CMP #$00
- BEQ ReadADone ; branch always
- DescendNow:
- LDA MARIO
- CMP #SEMIGROUND
- BEQ JumpDescend
- LDA #%00000001
- STA isDescending
- JumpDescend:
- JSR Descend
- 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)
- ReadBDone: ; handling this button is done
- ReadSelect:
- LDA $4016
- AND #%00000001
- BEQ ReadSelectDone
- ReadSelectDone:
- ReadStart:
- LDA $4016
- AND #$00000001
- BEQ ReadStartDone
- ReadStartDone:
- ReadUp:
- LDA $4016
- AND #$00000001
- BEQ ReadUpDone
- ReadUpDone:
- ReadDown:
- LDA $4016
- AND #%00000001
- BEQ ReadDownDone
- ReadDownDone:
- ReadLeft: ; ----- LEFT BUTTON -----
- LDA $4016
- AND #%00000001
- BEQ NotWalkingLeft
- LDA #%00000001
- STA isLeft ; left
- LDA #$33 ; load walking sprites
- STA $0201
- LDA #$32
- STA $0205
- LDA #$43
- STA $0209
- LDA #$42
- STA $020D
- LDA #%01000000 ; unflip
- STA $0202
- STA $0206
- STA $020A
- STA $020E
- LDA isOnGround
- CMP #%00000001
- BEQ OnGroundLeft
- LDA #$41 ; load jumping sprites
- STA $0201
- LDA #$32
- STA $0205
- LDA #$43
- STA $0209
- LDA #$42
- STA $020D
- LDA #%01000000
- STA $0202
- STA $0206
- STA $020A
- STA $020E
- OnGroundLeft:
- LDX #$03
- LDY partialVariable
- ButtonLeftLoop:
- TYA
- SEC
- SBC #$20 ; fractionary speed
- STA partialVariable
- LDA MARIO, X ; load sprite X position
- SBC #$01 ; integer speed
- STA MARIO, X ; save sprite X position
- INX
- INX
- INX
- INX
- CPX #$13
- BNE ButtonLeftLoop
- LDA #$00
- CMP #$00
- BEQ ReadLeftDone ; branch always
- NotWalkingLeft: ; only when on ground and left
- LDA isOnGround
- CMP #%00000001
- BNE ReadLeftDone
- LDA isLeft
- CMP #%00000001
- BNE ReadLeftDone
- LDA #$33 ; load static left sprites
- STA $0201
- LDA #$32
- STA $0205
- LDA #$4F
- STA $0209
- STA $020D
- LDA #%0000000 ; flip
- STA $020A
- LDA #%01000000
- STA $0202
- STA $0206
- STA $020E
- ReadLeftDone:
- ReadRight: ; ----- RIGHT BUTTON -----
- LDA $4016
- AND #$00000001
- BEQ NotWalkingRight
- ; background scrolling
- JSR Scrolling
- ; MARIO ACTIONS
- LDA #%00000000
- STA isLeft ; not left
- LDA #$32 ; load walking sprites
- STA $0201
- LDA #$33
- STA $0205
- LDA #$42
- STA $0209
- LDA #$43
- STA $020D
- LDA #%00000000 ; unflip
- STA $0202
- STA $0206
- STA $020A
- STA $020E
- LDA isOnGround
- CMP #%00000001
- BEQ OnGroundRight
- LDA #$32 ; load jumping sprites
- STA $0201
- LDA #$41
- STA $0205
- LDA #$42
- STA $0209
- LDA #$43
- STA $020D
- LDA #%00000000
- STA $0202
- STA $0206
- STA $020A
- STA $020E
- OnGroundRight:
- LDX #$03
- LDY partialVariable
- ButtonRightLoop:
- TYA
- CLC
- ADC #$20 ; fractionary speed
- STA partialVariable
- LDA MARIO, X ; load sprite X position
- ADC #$01 ; integer speed
- STA MARIO, X ; save sprite X position
- INX
- INX
- INX
- INX
- CPX #$13
- BNE ButtonRightLoop
- LDA #$00
- CMP #$00
- BEQ ReadRightDone ; branch always
- NotWalkingRight: ; only when on ground and not left
- LDA isOnGround
- CMP #%00000001
- BNE ReadRightDone
- LDA isLeft
- CMP #%00000001
- BEQ ReadRightDone
- LDA #$32 ; load static sprites
- STA $0201
- LDA #$33
- STA $0205
- LDA #$4F
- STA $0209
- STA $020D
- LDA #%00000000 ; unflip
- STA $0202
- STA $0206
- STA $020A
- LDA #%01000000
- STA $020E
- ReadRightDone:
- RTI ; return from interrupt
- ;; ---------------------------------
- ;; ---------- SUBROUTINES ----------
- ;; ---------------------------------
- ;; ----- SCROLLING -----
- Scrolling:
- INC scroll
- NTSwapCheck:
- LDA scroll ; check if the scroll just wrapped from 255 to 0
- BNE NTSwapCheckDone
- NTSwap:
- LDA nametable ; load current nametable number (0 or 1)
- EOR #$01 ; exclusive OR of bit 0 will flip that bit
- STA nametable ; so if nametable was 0, now 1
- ; if nametable was 1, now 0
- NTSwapCheckDone:
- NewAttribCheck:
- LDA scroll
- AND #%00011111 ; check for multiple of 32
- BNE NewAttribCheckDone ; if low 5 bits = 0, time to write new attribute bytes
- jsr DrawNewAttributes
- NewAttribCheckDone:
- NewColumnCheck:
- LDA scroll
- AND #%00000111 ; throw away higher bits to check for multiple of 8
- BNE NewColumnCheckDone ; done if lower bits != 0
- JSR DrawNewColumn ; if lower bits = 0, time for new column
- lda columnNumber
- clc
- adc #$01 ; go to next column
- and #%01111111 ; only 128 columns of data, throw away top bit to wrap
- sta columnNumber
- NewColumnCheckDone:
- RTS
- DrawNewColumn:
- LDA scroll ; calculate new column address using scroll register
- LSR A
- LSR A
- LSR A ; shift right 3 times = divide by 8
- STA columnLow ; $00 to $1F, screen is 32 tiles wide
- LDA nametable ; calculate new column address using current nametable
- EOR #$01 ; invert low bit, A = $00 or $01
- ASL A ; shift up, A = $00 or $02
- ASL A ; $00 or $04
- CLC
- ADC #$20 ; add high byte of nametable base address ($2000)
- STA columnHigh ; now address = $20 or $24 for nametable 0 or 1
- LDA columnNumber ; column number * 32 = column data offset
- ASL A
- ASL A
- ASL A
- ASL A
- ASL A
- STA sourceLow
- LDA columnNumber
- LSR A
- LSR A
- LSR A
- STA sourceHigh
- LDA sourceLow ; column data start + offset = address to load column data from
- CLC
- ADC #LOW(columnData)
- STA sourceLow
- LDA sourceHigh
- ADC #HIGH(columnData)
- STA sourceHigh
- DrawColumn:
- LDA #%00000100 ; set to increment +32 mode
- STA $2000
- LDA $2002 ; read PPU status to reset the high/low latch
- LDA columnHigh
- STA $2006 ; write the high byte of column address
- LDA columnLow
- STA $2006 ; write the low byte of column address
- LDX #$1E ; copy 30 bytes
- LDY #$00
- DrawColumnLoop:
- LDA [sourceLow], y
- STA $2007
- INY
- DEX
- BNE DrawColumnLoop
- RTS
- DrawNewAttributes:
- LDA nametable
- EOR #$01 ; invert low bit, A = $00 or $01
- ASL A ; shift up, A = $00 or $02
- ASL A ; $00 or $04
- CLC
- ADC #$23 ; add high byte of attribute base address ($23C0)
- STA columnHigh ; now address = $23 or $27 for nametable 0 or 1
- LDA scroll
- LSR A
- LSR A
- LSR A
- LSR A
- LSR A
- CLC
- ADC #$C0
- STA columnLow ; attribute base + scroll / 32
- LDA columnNumber ; (column number / 4) * 8 = column data offset
- AND #%11111100
- ASL A
- STA sourceLow
- LDA columnNumber
- LSR A
- LSR A
- LSR A
- LSR A
- LSR A
- LSR A
- LSR A
- STA sourceHigh
- LDA sourceLow ; column data start + offset = address to load column data from
- CLC
- ADC #LOW(attribData)
- STA sourceLow
- LDA sourceHigh
- ADC #HIGH(attribData)
- STA sourceHigh
- LDY #$00
- LDA $2002 ; read PPU status to reset the high/low latch
- DrawNewAttributesLoop
- LDA columnHigh
- STA $2006 ; write the high byte of column address
- LDA columnLow
- STA $2006 ; write the low byte of column address
- LDA [sourceLow], y ; copy new attribute byte
- STA $2007
- INY
- CPY #$08 ; copy 8 attribute bytes
- BEQ DrawNewAttributesLoopDone
- LDA columnLow ; next attribute byte is at address + 8
- CLC
- ADC #$08
- STA columnLow
- JMP DrawNewAttributesLoop
- DrawNewAttributesLoopDone:
- RTS
- ;; ----- MARIO ACTIONS -----
- Jump:
- LDA #%00000000
- STA isOnGround ; false
- LDA #$32 ; load right sprites
- STA $0201
- LDA #$41
- STA $0205
- LDA #$42
- STA $0209
- LDA #$43
- STA $020D
- LDA #%00000000
- STA $0202
- STA $0206
- STA $020A
- STA $020E
- LDA isLeft
- CMP #%00000001
- BNE NotLeft
- LDA #$41 ; load left sprites
- STA $0201
- LDA #$32
- STA $0205
- LDA #$43
- STA $0209
- LDA #$42
- STA $020D
- LDA #%01000000
- STA $0202
- STA $0206
- STA $020A
- STA $020E
- NotLeft:
- LDA MARIO
- CMP #TOP_JUMP
- BEQ Return
- LDX #$00
- SpriteUpLoop:
- LDA MARIO, x ; load sprite Y position
- SEC ; make sure carry flag is set
- SBC #$02 ; jump speed
- STA MARIO, x ; save sprite Y position
- INX
- INX
- INX
- INX
- CPX #$10
- BNE SpriteUpLoop
- Return:
- RTS
- Descend:
- LDA isOnGround
- CMP #%00000001
- BEQ DescendReturn
- StepDown:
- LDX #$00
- SpriteDownLoop:
- LDA MARIO, x ; load sprite Y position
- CLC ; make sure carry flag is clear
- ADC #$02 ; descend speed
- STA MARIO, x ; save sprite Y position
- INX
- INX
- INX
- INX
- CPX #$10
- BNE SpriteDownLoop
- ;JSR vblankwait
- LDA MARIO
- CMP #SEMIGROUND
- BNE DescendReturn
- JSR OnGround
- DescendReturn
- RTS
- OnGround:
- LDA #%00000001
- STA isOnGround ; true
- LDA #%00000000
- STA isDescending ;false
- LDA #$32 ; restore right sprites
- STA $0201
- LDA #$33
- STA $0205
- LDA #$4F
- STA $0209
- STA $020D
- LDA #%00000000
- STA $0202
- STA $0206
- STA $020A
- LDA #%01000000
- STA $020E
- LDA isLeft
- CMP #%00000001
- BNE NotDescending
- LDA #$33 ; restore left sprites
- STA $0201
- LDA #$32
- STA $0205
- LDA #$4F
- STA $0209
- STA $020D
- LDA #%01000000
- STA $0202
- STA $0206
- STA $020E
- LDA #%00000000
- STA $020A
- NotDescending:
- LDA #%00000000
- STA isDescending
- RTS
- ;;;;;;;;;;;;;;
- .bank 1
- .org $E000
- palette:
- .db $22,$29,$1A,$0F, $22,$36,$17,$0F, $22,$30,$21,$0F, $22,$27,$17,$0F ;;background palette
- .db $22,$16,$27,$18, $22,$1A,$30,$27, $22,$16,$30,$27, $22,$0F,$36,$17 ;;sprite palette
- sprites:
- ;vert tile attr horiz
- .db SEMIGROUND, $32, $00, $40 ;sprite 0
- .db SEMIGROUND, $33, $00, $48 ;sprite 1
- .db GROUND, $4F, $00, $40 ;sprite 2
- .db GROUND, $4F, $40, $48 ;sprite 3
- columnData:
- .incbin "SMBlevel.bin"
- attribData:
- .incbin "SMBattrib.bin"
- .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
- ;;;;;;;;;;;;;;
- .bank 2
- .org $0000
- .incbin "mario.chr" ;includes 8KB graphics file from SMB1
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement