Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- @include
- ;===============================================================================
- ; LazyHDMA by ExoticMatter
- ;
- ; This library is a simple way to manage multiple HDMA effects without having
- ; to copy/paste a lot of code.
- ;
- ; To use LazyHDMA, incsrc lazyhdma.asm once from uberASM or levelASM. Then, use
- ; code such as the following:
- ;
- ; level105init:
- ; %LazyInitEffect(MyGradient)
- ; RTS
- ;
- ; MyGradient:
- ; %LazyBGDouble(3, .RedGreen)
- ; %LazyBGSingle(4, .Blue)
- ; %LazyEnd()
- ;
- ; .RedGreen and .Blue are HDMA tables. Using sublabels is not required.
- ; To use a table that is in a different bank, use the _Long suffix. Otherwise,
- ; the table must be in the same bank as the descriptor.
- ;
- ; Make sure to apply IceMan's HDMA patch to prevent common HDMA problems
- ; including disappearing HDMA, flickering, and gradients that briefly appear
- ; when going through a pipe or door.
- ; http://www.smwcentral.net/?p=section&a=details&id=4176
- ;===============================================================================
- ; Main macros:
- ;
- ; %LazyInitEffect[_Tail](effect) - Initializes an HDMA effect.
- ; This macro will set A, X, and Y to 8-bit and overwrite scratch RAM.
- ; The _Tail suffix causes the subroutine to not return. This can only be
- ; used where RTS can be used. (Or RTL, if !LongCall is nonzero.)
- ; %LazyInitEffect only needs to be called once. Initializing an effect
- ; that contains a scrolling gradient every frame will induce slowdown.
- ;
- ; %LazyRunEffect[_Tail](effect) - Runs an HDMA effect.
- ; Like %LazyInitEffect, this macro sets A, X, and Y to 8-bit and overwrite
- ; scratch RAM.
- ; Only scrolling gradients need to be run every frame.
- ; LazyHDMA does not update parallax effects at this point in time.
- ;===============================================================================
- ; Definition macros:
- ;
- ; %LazyBaseBG(color) - Defines the background color in BGR15 format.
- ; Use rgb(r, g, b) to create a BGR15 color:
- ; %LazyBaseBG(rgb(31,31,31))
- ;
- ; %LazyHDMA[_Long](channel, parameters, register, address) - Defines an HDMA
- ; channel with the specified properties.
- ; <register> must be between $2100-$21FF, although $00-$FF are also
- ; allowed.
- ;
- ; %LazyBGSingle[_Long](channel, address) - Defines a background HDMA channel
- ; that writes once per scanline, i.e. transfer mode 0.
- ;
- ; %LazyBGDouble[_Long](channel, address) - Defines a background HDMA channel
- ; that writes twice per scanline, i.e. transfer mode 2.
- ;
- ; %LazyCGRAM[_Long](channel, address) - Defines a palette HDMA channel that
- ; writes to two registers twice per scanline, i.e. transfer mode 3.
- ;
- ; %LazyBrightness[_Long](channel, address) - Defines a brightness HDMA channel
- ; that writes to one register once per scanline, i.e. transfer mode 0.
- ;
- ; %LazyScroll[_Long](channelAB, channelC, address) - Defines a scrolling
- ; background HDMA gradient that is decompressed into memory.
- ; For the scrolling to occur, you must call %Lazy
- ;
- ; %LazyEnd() - Marks the end of the effect.
- ;===============================================================================
- ; Configuration:
- ;
- ; !LongCall: If set to a nonzero value, LazyHDMA will use JSL/JSR, allowing
- ; LazyHDMA to be called from a different bank. Off by default.
- ;
- ; !IncludeScrollingGradientCode: If set to a nonzero value, the scrolling
- ; gradient routines will be included. Off by default.
- ;
- ; !ScrollingFreeRAM_(AB|C): The location to put decompressed scrolling gradient
- ; tables. By default, $7F:B260 and $7F:B830 are used, respectively.
- ;
- ; To configure LazyHDMA, set one or more of these defines before incsrc.
- ;===============================================================================
- !LongCall ?= 0
- !IncludeScrollingGradientCode ?= 0
- !ScrollingFreeRAM_AB ?= $7FB260
- !ScrollingFreeRAM_C ?= $7FB830
- if !LongCall
- !LazyHDMA_Call = JSL : !LazyHDMA_CallS = "JSL "
- !LazyHDMA_Tail = JML : !LazyHDMA_TailS = "JML "
- !LazyHDMA_Return = RTL : !LazyHDMA_ReturnS = "RTL "
- else
- !LazyHDMA_Call = JSR.w : !LazyHDMA_CallS = "JSR.w "
- !LazyHDMA_Tail = JMP.w : !LazyHDMA_TailS = "JMP.w "
- !LazyHDMA_Return = RTS : !LazyHDMA_ReturnS = "RTS "
- endif
- macro _LazyHDMA_LoadLong(effect)
- SEP #$30
- LDA.b #<effect>
- LDY.b #<effect>>>8
- LDX.b #<effect>>>16
- endmacro
- _LazyHDMA:
- macro LazyInitEffect(effect)
- %_LazyHDMA_LoadLong(<effect>)
- !LazyHDMA_Call _LazyHDMA_InitializeEffect
- endmacro
- macro LazyInitEffect_Tail(effect)
- %_LazyHDMA_LoadLong(<effect>)
- !LazyHDMA_Tail _LazyHDMA_InitializeEffect
- endmacro
- if !IncludeScrollingGradientCode
- macro LazyRunEffect(effect)
- %_LazyHDMA_LoadLong(<effect>)
- !LazyHDMA_Call _LazyHDMA_RunEffect
- endmacro
- macro LazyRunEffect_Tail(effect)
- %_LazyHDMA_LoadLong(<effect>)
- !LazyHDMA_Tail _LazyHDMA_RunEffect
- endmacro
- else
- macro LazyRunEffect(effect)
- endmacro
- macro LazyRunEffect_Tail(effect)
- endmacro
- endif
- ; These registers can be written to by HDMA:
- !INIDISP = $2100 ; Display Control 1
- !OBSEL = $2101 ; Object Size and Object Base
- !OAMADDL = $2102 ; OAM Address (lower 8bit)
- !OAMADDH = $2103 ; OAM Address (upper 1bit) and Priority Rotation
- !OAMDATA = $2104 ; OAM Data Write (write-twice)
- !BGMODE = $2105 ; BG Mode and BG Character Size
- !MOSAIC = $2106 ; Mosaic Size and Mosaic Enable
- !BG1SC = $2107 ; BG1 Screen Base and Screen Size
- !BG2SC = $2108 ; BG2 Screen Base and Screen Size
- !BG3SC = $2109 ; BG3 Screen Base and Screen Size
- !BG4SC = $210A ; BG4 Screen Base and Screen Size
- !BG12NBA = $210B ; BG Character Data Area Designation
- !BG34NBA = $210C ; BG Character Data Area Designation
- !BG1HOFS = $210D ; BG1 Horizontal Scroll (X) (write-twice) / M7HOFS
- !BG1VOFS = $210E ; BG1 Vertical Scroll (Y) (write-twice) / M7VOFS
- !BG2HOFS = $210F ; BG2 Horizontal Scroll (X) (write-twice)
- !BG2VOFS = $2110 ; BG2 Vertical Scroll (Y) (write-twice)
- !BG3HOFS = $2111 ; BG3 Horizontal Scroll (X) (write-twice)
- !BG3VOFS = $2112 ; BG3 Vertical Scroll (Y) (write-twice)
- !BG4HOFS = $2113 ; BG4 Horizontal Scroll (X) (write-twice)
- !BG4VOFS = $2114 ; BG4 Vertical Scroll (Y) (write-twice)
- !VMAIN = $2115 ; VRAM Address Increment Mode
- !VMADDL = $2116 ; VRAM Address (lower 8bit)
- !VMADDH = $2117 ; VRAM Address (upper 8bit)
- !VMDATAL = $2118 ; VRAM Data Write (lower 8bit)
- !VMDATAH = $2119 ; VRAM Data Write (upper 8bit)
- !M7SEL = $211A ; Rotation/Scaling Mode Settings
- !M7A = $211B ; Rotation/Scaling Parameter A & Maths 16bit operand
- !M7B = $211C ; Rotation/Scaling Parameter B & Maths 8bit operand
- !M7C = $211D ; Rotation/Scaling Parameter C (write-twice)
- !M7D = $211E ; Rotation/Scaling Parameter D (write-twice)
- !M7X = $211F ; Rotation/Scaling Center Coordinate X (write-twice)
- !M7Y = $2120 ; Rotation/Scaling Center Coordinate Y (write-twice)
- !CGADD = $2121 ; Palette CGRAM Address
- !CGDATA = $2122 ; Palette CGRAM Data Write (write-twice)
- !W12SEL = $2123 ; Window BG1/BG2 Mask Settings
- !W34SEL = $2124 ; Window BG3/BG4 Mask Settings
- !WOBJSEL = $2125 ; Window OBJ/MATH Mask Settings
- !WH0 = $2126 ; Window 1 Left Position (X1)
- !WH1 = $2127 ; Window 1 Right Position (X2)
- !WH2 = $2128 ; Window 2 Left Position (X1)
- !WH3 = $2129 ; Window 2 Right Position (X2)
- !WBGLOG = $212A ; Window 1/2 Mask Logic (BG1-BG4)
- !WOBJLOG = $212B ; Window 1/2 Mask Logic (OBJ/MATH)
- !TM = $212C ; Main Screen Designation
- !TS = $212D ; Sub Screen Designation
- !TMW = $212E ; Window Area Main Screen Disable
- !TSW = $212F ; Window Area Sub Screen Disable
- !CGWSEL = $2130 ; Color Math Control Register A
- !CGADSUB = $2131 ; Color Math Control Register B
- !COLDATA = $2132 ; Color Math Sub Screen Backdrop Color
- !SETINI = $2133 ; Display Control 2
- ; These can be used as transfer modes:
- !OneRegisterWriteOnce = 0 ; 1 byte: p
- !TwoRegistersWriteOnce = 1 ; 2 bytes: p, p+1
- !OneRegisterWriteTwice = 2 ; 2 bytes: p, p
- !TwoRegistersWriteTwice = 3 ; 4 bytes: p, p, p+1, p+1
- !FourRegistersWriteOnce = 4 ; 4 bytes: p, p+1, p+2, p+3
- !TwoRegistersWriteTwiceAlt = 5 ; 4 bytes: p, p+1, p, p+1
- !HDMA_FixedPtr = 8 ; Use a fixed CPU memory pointer
- !HDMA_DecrementPtr = 16 ; CPU memory pointer decreases
- !HDMA_IndirectHDMA = 64 ; The table uses pointers instead of data
- !LazyHDMA_CommandMask = $1F
- !LazyHDMA_ChannelMask = $E0
- macro _LazyHDMA_LoadArgs()
- STA $00 ; Descriptor pointer, LSB
- STY $01 ; Descriptor pointer, MSB
- STX $02 ; Descriptor pointer, Bank
- ; STX $03 ; Other address bank (initialization only)
- ; $04 ; HDMA index (channel << 4)
- ; $05 ; second HDMA index (scrolling gradients only)
- endmacro
- .InitializeEffect
- %_LazyHDMA_LoadArgs()
- STX $03
- - SEP #$30 ; 8-bit A, X, Y
- LDA [$00]
- AND #!LazyHDMA_CommandMask
- BEQ +
- ASL
- TAX
- LDA [$00]
- AND #!LazyHDMA_ChannelMask
- LSR
- STA $04
- REP #$20 ; 16-bit A
- INC $00
- JSR (.Subroutines-2, X)
- BRA -
- + !LazyHDMA_Return
- !_LazySubroutine = 1
- !_LazySubroutineSizes = 1
- macro _LazySubroutine(name, size)
- assert !_LazySubroutine <= !LazyHDMA_CommandMask
- !LazyHDMA_<name> #= !_LazySubroutine
- !_LazySubroutine #= !_LazySubroutine+1
- !_LazySubroutineSizes += ,<size>
- dw .Set<name>
- endmacro
- macro _LazySkip()
- dw $0000
- !_LazySubroutine #= !_LazySubroutine+1
- !_LazySubroutineSizes += ,<size>
- endmacro
- .Subroutines
- %_LazySubroutine(LongPtr, 2)
- %_LazySubroutine(BG, 3)
- %_LazySubroutine(BGDouble, 3)
- %_LazySubroutine(CGRAM, 3)
- %_LazySubroutine(Brightness, 3)
- if !IncludeScrollingGradientCode
- %_LazySubroutine(ScrollGradient, 4)
- else
- %_LazySkip(4)
- endif
- %_LazySubroutine(HDMA, 5)
- %_LazySubroutine(BGFill, 3)
- if !IncludeScrollingGradientCode
- .SubroutineSizes db !_LazySubroutineSizes
- endif
- !LazyHDMA_Invalid = !_LazySubroutine
- .SetLongPtr
- SEP #$20 ; \ 8-bit A
- LDA [$00] ; | \ Set the source bank number
- STA $03 ; | /
- REP #$20 ; / 16-bit A
- INC $00 ; Next
- RTS
- .SetBGFill
- LDA [$00]
- STA $0701
- INC $00
- INC $00
- RTS
- .SetBG
- LDA.w #!COLDATA<<8
- .SimpleCommon
- LDX $04
- STA $4300,X
- LDA [$00]
- STA $4302,X
- SEP #$20 ; 8-bit A
- LDA $03
- STA $4304,X
- TXA
- LSR #4
- TAX
- LDA .Bits,X
- TSB $0D9F
- REP #$20 ; 16-bit A
- INC $00
- INC $00
- LDX $02 ; \ Restore the data table bank
- STX $03 ; / to the same bank as the descriptor
- RTS
- .SetBGDouble
- LDA.w #(!COLDATA<<8)|!OneRegisterWriteTwice
- BRA .SimpleCommon
- .SetCGRAM
- LDA.w #(!CGADD<<8)|!TwoRegistersWriteTwice
- BRA .SimpleCommon
- .SetBrightness
- LDA.w #!INIDISP<<8
- BRA .SimpleCommon
- .SetHDMA
- LDA [$00]
- INC $00
- INC $00
- BRA .SimpleCommon
- .Bits db %00000001,%00000010,%00000100,%00001000,%00010000,%00100000,%01000000,%10000000
- if !IncludeScrollingGradientCode
- .SetScrollGradient
- LDY #$02 ; \
- LDA [$00],Y ; | Load the second HDMA channel
- TAX ; | number and store it to scratch RAM
- STX $05 ; /
- PEI ($04) ; \
- LDX $02 ; | Preserve scratch RAM
- PHX ; |
- PEI ($00) ; /
- LDA [$00] ; Load table pointer
- PHB ; Preserve data bank
- LDX $03 ; \
- PHX ; | Set data bank
- PLB ; /
- REP #$30 ; 16-bit A, X, Y
- STA $02
- INC
- STA $04
- INC
- STA $06
- INC
- STA $08
- LDA.w #!ScrollingFreeRAM_AB
- STA $0A
- LDA.w #!ScrollingFreeRAM_C
- STA $0D
- SEP #$20 ; 8-bit A
- LDA #!ScrollingFreeRAM_AB>>16
- STA $0C
- if !ScrollingFreeRAM_AB>>16 != !ScrollingFreeRAM_C>>16
- LDA #!ScrollingFreeRAM_C>>16
- endif
- STA $0F
- - LDA ($02)
- BEQ +
- STA $00
- -- LDA #$01
- STA [$0A]
- STA [$0D]
- LDY #$0001
- LDA ($04)
- STA [$0A],y
- LDA ($08)
- STA [$0D],y
- INY
- LDA ($06)
- STA [$0A],y
- REP #$20
- INC $0A
- INC $0A
- INC $0A
- INC $0D
- INC $0D
- SEP #$20
- DEC $00
- BPL --
- REP #$20
- LDA $02
- CLC
- ADC #$0004
- STA $02
- INC
- STA $04
- INC
- STA $06
- INC
- STA $08
- SEP #$20
- BRA -
- + PLB ; Restore previous data bank number
- SEP #$10 ; Restore 8-bit X, Y
- REP #$20 ; Restore 16-bit A
- PLA ; \
- INC A ; | \
- INC A ; | | Advance the command pointer
- INC A ; | /
- STA $00 ; |
- PLX ; | Restore scratch RAM
- STX $02 ; |
- STX $03 ; | | Restore the data source bank
- PLA ; |
- STA $04 ; /
- TAX ; \ Load the HDMA indexes
- LDY $05 ; /
- LDA.w #(!COLDATA<<8)|2 ; \
- STA $4300,X ; | Set HDMA channel types
- LDA.w #!COLDATA<<8 ; |
- STA $4300,Y ; /
- SEP #$20 ; 8-bit A
- TXA ; \
- LSR #4 ; |
- TAX ; | Enable gradient A
- LDA .Bits,X ; |
- TSB $0D9F ; /
- TYA ; \
- LSR #4 ; |
- TAX ; | Enable gradient B
- LDA .Bits,X ; |
- TSB $0D9F ; /
- REP #$20 ; 16-bit A
- .ScrollGradient:
- LDA $20 ; \ Load the Y-position of BG2
- LDX $1414 ; | \ Check how much the gradient should be shifted upward
- CPX #$01 ; | | \
- BEQ .Const ; | | / #$01: Constant
- CPX #$02 ; | | \
- BEQ .Var ; | | / #$02: Variable
- CPX #$03 ; | | \
- BEQ .Slow ; | | / #$03: Slow
- ; | |
- .None ; | | \ No scrolling (consider using fixed HDMA)
- SEC ; | | |
- SBC #$00C0 ; | | | shift 192 pixels downward
- BRA .Const ; | | / Continue
- ; | |
- .Slow ; | | \ Slow scrolling (consider using fixed HDMA)
- SEC ; | | |
- SBC #$00A8 ; | | | shift 168 pixels downward
- BRA .Const ; | | /
- ; | |
- .Var ; | | \ Variable scrolling
- SEC ; | | |
- SBC #$0060 ; | | / shift 96 pixels downward
- ; | |
- .Const ; | / < Constant scrolling (BG2:Camera = 1:1)
- ; |
- ; | \ Put an LSR/ASL or two here to change the rate at which
- ; | / the gradient scrolls.
- ; |
- STA $06 ; / and store it to scratch RAM.
- LDX $04 ; \ Load the HDMA indexes
- LDY $05 ; /
- LDA $06
- ASL ; \
- CLC ; | This transforms the Y-pos of BG2
- ADC $06 ; | into the address at which the HDMA
- CLC ; | gradient should start
- ADC.w #!ScrollingFreeRAM_AB
- STA $4302,X ; HDMA Channel A table starting address.
- LDA $06 ; \
- ASL ; | Y-pos of BG2 to
- CLC ; | HDMA table offset
- ADC.w #!ScrollingFreeRAM_C
- STA $4302,Y ; HDMA Channel B table starting address.
- SEP #$20 ; 8-bit A
- LDA.b #!ScrollingFreeRAM_AB>>16
- STA $4304,X
- if !ScrollingFreeRAM_AB>>16 != !ScrollingFreeRAM_C>>16
- LDA.b #!ScrollingFreeRAM_C>>16
- endif
- STA $4304,Y
- RTS
- .RunEffect:
- %_LazyHDMA_LoadArgs()
- - SEP #$30 ; 8-bit A, X, Y
- LDA [$00]
- AND #!LazyHDMA_CommandMask
- BEQ +
- CMP.b #!LazyHDMA_ScrollGradient
- BEQ ++
- TAX
- LDA .SubroutineSizes,X
- CLC
- REP #$20 ; 16-bit A
- AND #$00FF
- ADC $00
- STA $00
- BRA - ; Repeat
- ++ LDA [$00]
- AND #!LazyHDMA_ChannelMask
- LSR
- STA $04
- LDY #$04 ; \
- LDA [$00],Y ; | Load the second channel number
- STA $05 ; /
- REP #$20 ; 16-bit A
- INC $00
- JSR .ScrollGradient
- REP #$20 ; 16-bit A
- INC $00
- INC $00
- INC $00
- BRA -
- + !LazyHDMA_Return
- endif
- macro LazyBaseBG(color)
- assert <color> >= 0 && <color> < $8000, "Invalid color"
- db !LazyHDMA_BGFill
- dw <color>
- endmacro
- function rgb(r, g, b) = r|(g<<5)|(b<<10)
- macro LazyHDMA(channel, params, register, address)
- assert <channel> >= 0 && <channel> < 8, "Invalid HDMA channel"
- assert <params> >= 0 && <params> < $80, "Invalid HDMA parameters"
- if <register> >= $00 && <register> < $100
- elseif <register> >= $2100 && <register> < $2200
- else
- error "Invalid HDMA target register"
- endif
- db !LazyHDMA_HDMA|(<channel><<5)
- db <params>, <register>
- dw <address>
- endmacro
- macro LazyHDMA_Long(channel, params, register, address)
- db !LazyHDMA_LongPtr, (<address>>>16)
- %LazyHDMA(channel, params, register, address)
- endmacro
- macro LazySimple(type, channel, address)
- assert <type> > 0 && <type> < !LazyHDMA_Invalid, "Invalid channel type"
- assert <channel> >= 0 && <channel> < 8, "Invalid HDMA channel"
- db <type>|(<channel><<5)
- dw <address>
- endmacro
- macro LazyBGSingle(channel, address)
- %LazySimple(!LazyHDMA_BG, <channel>, <address>)
- endmacro
- macro LazyBGDouble(channel, address)
- %LazySimple(!LazyHDMA_BGDouble, <channel>, <address>)
- endmacro
- macro LazyCGRAM(channel, address)
- %LazySimple(!LazyHDMA_CGRAM, <channel>, <address>)
- endmacro
- macro LazyBrightness(channel, address)
- %LazySimple(!LazyHDMA_Brightness, <channel>, <address>)
- endmacro
- macro LazySimple_Long(type, channel, address)
- db !LazyHDMA_LongPtr, (<address>>>16)
- %LazySimple(<type>, <channel>, <address>)
- endmacro
- macro LazyBGSingle_Long(channel, address)
- %LazySimple_Long(!LazyHDMA_BG, <channel>, <address>)
- endmacro
- macro LazyBGDouble_Long(channel, address)
- %LazySimple_Long(!LazyHDMA_BGDouble, <channel>, <address>)
- endmacro
- macro LazyCGRAM_Long(channel, address)
- %LazySimple_Long(!LazyHDMA_CGRAM, <channel>, <address>)
- endmacro
- macro LazyBrightness_Long(channel, address)
- %LazySimple_Long(!LazyHDMA_Brightness, <channel>, <address>)
- endmacro
- if !IncludeScrollingGradientCode
- macro LazyScroll(channel, secondchannel, address)
- %LazySimple(!LazyHDMA_ScrollGradient, <channel>, <address>)
- db <secondchannel><<4
- endmacro
- macro LazyScroll_Long(channel, secondchannel, address)
- %LazySimple_Long(!LazyHDMA_ScrollGradient, <channel>, <address>)
- db <secondchannel><<4
- endmacro
- endif
- macro LazyEnd()
- db $00
- endmacro
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement