SHARE
TWEET

MyScrollingASM




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
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy.