; C02 module vera.h02 assembly language subroutines
; Requires External Functions NYBCAT, NYBCUT
; and Variables TEMP0

;getadr() - Get Vera Address
;Args: A = Bank + Auto-Increment
;      Y,X = Address
GETADR: LDX $9F20   ;Store Address LSB
        LDY $9F21   ;Store Address MSB
        LDA $9F22   ;Store Bank & Auto-Increment
        RTS

;getvid() - Get Video Output Mode
;Returns: A = Video Mode
;         Y = Chroma Disabled
;         X = Current Field
GETVID: LDA #$00    ;Set Register Offset to Video Output
        JSR GETDCR      ;Read from Display Composer
        LDY #$00        ;Set Chroma Disabled to FALSE
        LDX #$00        ;Set Video Field to EVEN
        BIT GETVIM      ;Test Chroma Disabled Bit
        BEQ GETVIE      ;If Bit 3 is Set
        DEY             ;  Set Chroma Disabled to TRUE
        BIT GETVIM      ;Test Chroma Disabled Bit
GETVIE: BCC GETVIF      ;If Bit 7 is Set
        DEX             ;  Set Video Field to ODD
GETVIF: AND #$03        ;Isolate Bits 0-2 (Video Output Mode)
        RTS 
GETVIM: .DC $04         ;Chroma Disable Bit Mask

;getbdr() - Get Get Border Color
;Returns: A = Border Color Palette Index
GETBDR: LDA #$03    ;Set Register Offset to Border Color

;getdcr() - Get Display Composer Register
;Args: A = Register Offset
;Affects: Y
;Returns: A = Contents of Register
;         X = Current Data Port
GETDCR: LDY #$00    ;Set MSB to Display Composer Page
        TAX         ;Set LSB to Register Offset
                    ;and Execute GETREG
;getreg(&addr);
;Args: Y,X = Address
;Returns: A = Mode
;         X = Current Data Port
GETREG: LDA #$0F    ;Set Bank to Registers
GETBYT: JSR SETADR  ;Set Vera Address
        LDX $9F25   ;Get Current Data Port
        LDA $9F23,X ;Read LSB from Data Port
        RTS

;getmem(count, &addr) - Read Array From Vera Memory
;Args: A = Number of Bytes to Read
;      Y,X = Address of Array to Read Into
;Requires: setadr() 
;Sets: DSTLO,DSTHI = Address of Array
;      TEMP0 = Number of Bytes to Read
;Affects: A
;Returns: Y = Number of Bytes Read
;         X = Current Data Port
GETMEM: JSR SETDST      ;Save Destination Address
GETMEA: STA TEMP0       ;Save Number of Bytes
        LDY #0          ;Initialize Counter
        LDX $9F25       ;Get Current Data Port
GETMEL: LDA $9F23,X     ;Read Byte from Data Port
        STA (DSTLO),Y   ;Store in Memory
        INY             ;Increment Counter
        CPY TEMP0       ;If Limit Not Reached
        BNE GETMEL      ;  Loop

;getmod() - Get Layer 0/1 Mode
;Args: A = Layer (0/1)
;Affects: Y
;Returns: A = Layer Mode
;         X = Current Data Port
GETMOD: JSR GETLRC  ;Read Register
        LSR         ;Shift Left Five Bits
        LSR         
        LSR
        LSR
        RTS

;getenb() - Get Layer 0/1 Enabled
;Args: A = Layer (0/1)
;Affects: Y
;Returns: A = $FF - Layer Enabled
;             $00 - Layer Disabled
;         X = Current Data Port
GETENB: JSR GETLRC  ;Read Register
        AND #$01    ;Isolate Bit 1
        BEQ GETENX  ;If Set 
        LDA #$FF    ;  Return TRUE
GETENX: RTS         ;Else Return FALSE        

;getlrc() - Get Layer 0/1 Control Register
;Args: A = Layer (0/1)
;Affects: Y
;Returns: A = Control Register Contents
;         X = Current Data Port
GETLRC: LDX #0      ;Set Offset to Control Register

;getlrr() - Get Layer 0/1 Register
;Args: A = Layer (0/1)
;      X = Register Offset
;Affects: Y
;Returns: A = Contents of Register
;         X = Current Data Port
GETLRR: JSR GETLRP  ;Get Layer Page in Y
        BNE GETREG  ;and Read Register Contents

;getlrp() - Get Layer 0/1 Register Page
;Args: A = Layer (0/1)
;Returns: A,Y = Layer Register Page
GETLRP: AND #$01    ;Isolate Bit 1
        ASL         ;Move to Left Nybble
        ASL
        ASL
        ASL
        ORA #$20    ;And Add to 2
        TAY         ;Return Page in Y
        RTS

;getchd(index, &array) - Read Character Data into Array
;Args: A = Character Index
;      Y,X = Address of Array to Read into
;Destroys: TEMP0,TEMP1,TEMP2
;Returns: A = Number of Bytes Read
GETCHD: JSR SETDST      ;Store Address in Destination Pointer
        STA TEMP1       ;Set Offset LSB to Index
        LDA #0          ;Set Offset MSB to Zero
        ASL TEMP1       ;Multiple Offset by 2
        ROL             
        STA TEMP2       ;and Store MSB
        JSR GETLRI      ;Get Tile Base
        TXA             ;Add Offset To Tile Base
        CLC
        ADC TEMP0
        STA TEMP0
        TYA
        ADC TEMP1
        STA TEMP1
        LDA #0
        ADC #0
        JSR GETMBX      ;Multiply by 4
        ORA #$10        ;Set Auto-Increment to 1
        JSR SETADR      ;and Set Vera Address
        LDA #8          ;Set Byte Count to 8
        BNE GETMEA      ;and Read Bytes into Array

;gettba() - Get Layer 0/1 Tile Base Address
;Args: A = Layer (0/1)
;Destroys: TEMP1,TEMP2
;Returns: A = Tile Base Bank
;         Y,X = Tile Base Address
GETTBA: LDX #4      ;Set Register Offset
        .DC $2C     ;Read Register Pair and Rotate

;getmba() - Get Layer 0/1 Map Base Address
;Args: A = Layer (0/1)
;Destroys: TEMP1,TEMP2
;Returns: A = Map Base Bank
;         Y,X = Map Base Address
GETMBA: LDX #2      ;Set Register Offset
        JSR GETLRI  ;Read Register Pair as Integer
        LDA #0      ;Initialize Page to 0
        JSR SAVRXY  ;Save Integer in TEMP1,TEMP2
GETMBX: LDX #2      ;Do Twice
GETMBL: ASL TEMP1   ;  Rotate LSB
        ROL TEMP2   ;  MSB and
        ROL         ;  Bank Left
        DEX
        BNE GETMBL
        JMP RESRXY  ;Load LSB, MSB and Return

;getvsc() - Get Layer 0/1 Vertical Scroll
;Args: A = Layer (0/1)
;Returns: A,X = Vertical Scroll LSB
;         Y = Vertical Scroll MSB
GETVSC: LDX #8      ;Set Register Offset
        .DC $2C     ;Skip to GETLRI (BIT Absolute)

;gethsc() - Get Layer 0/1 Horizontal Scroll
;Args: A = Layer (0/1)
;Returns: A,X = Horizontal Scroll LSB
;         Y = Horizontal Scroll MSB
GETHSC: LDX #6      ;Set Register Offset
        .DC $2C     ;Skip to GETLRI (BIT Absolute)

;gettbs() - Get Layer 0/1 Tile Base
;Args: A = Layer (0/1)
;Returns: A,X = Tile Base LSB
;         Y = Tile Base MSB
GETTBS: LDX #4      ;Set Register Offset
        .DC $2C     ;Skip to GETLRI (BIT Absolute)

;getmbs() - Get Layer 0/1 Map Base
;Args: A = Layer (0/1)
;Returns: A,X = Map Base LSB
;         Y = Map Base MSB
GETMBS: LDX #2      ;Set Register Offset

;getlri() - Get Layer 0/1 Register Pair as Integer
;Args: A = Layer (0/1)
;      X = Register Offset
;Returns: A,X = Integer LSB
;         Y = Integer LSB
GETLRI: JSR GETLRP  ;Get Layer Page in Y
        BNE GETREI  ;and Read Register Contents


;mapsiz() - Convert Map Size Specifier to Pixels
;Args: A = Map Size Specifier
;Affects: A
;Returns: Y,X Map Size in Pixels
MAPSIZ: TAX             ;Copy Map Size Specifier to X
        LDA MAPSIH,X    ;Load Pixels MSB from Table
        TAY             ;and Return in Y
        LDA MAPSIL,X    ;Load Pixels LSB from Table
        TAX             ;and Return in X
MAPSIL: .DC $20,$40,$80,$00
MAPSIH: .DC $00,$00,$00,$01
        
;tilsiz() - Convert Tile Size Specifier to Pixels
;Args: A = Tile Size Specifier
;Affects: A
;Returns: A Tile Size in Pixels
TILSIZ: TAX             ;Copy Map Size Specifier to X
        LDA TILSIT,X    ;Load Pixels MSB from Table
        RTS
TILSIT: .DC $08,$10

;gettsz() - Get Layer 0/1 Tile Size

;getmsz() - Get Layer 0/1 Map Size
;Args: A = Layer (0/1)
;Affects: X
;Returns: A = Map Width Specifier
;         Y = Map Height Specifier

;getvsp() - Get Vertical Stop
;Affects: A
;Returns: Y,X = Vertical Stop
GETVSP: LDA #7          ;Set Reg Offset to Vertical Stop
        JSR GETHVS      ;Read Registers
        LSR             ;Shift Left One Bit
        JMP GETVSS      ;Then Four More Bits and Mask

;getvsr() - Get Vertical Start
;Affects: A
;Returns: Y,X = Vertical Start
GETVSR: LDA #6          ;Set Reg Offset to Vertical Start
        JSR GETHVS      ;Read Registers
GETVSS: LSR             ;Shift Left Four Bit
        LSR
        LSR
        LSR
        AND #$01        ;Isolate Bit 0
        TAY             ;and Copy MSB to Y
        RTS
        
;gethsp() - Get Horizontal Stop
;Affects: A
;Returns: Y,X = Horizontal Stop
GETHSP: LDA #5          ;Set Lookup Index to Horizontal Start
        JSR GETHVS      ;Read Registers
        LSR             ;Shift Left Two Bits
        LSR
        JMP GETHSS      ;then Mask and Return

;gethsr() - Get Horizontal Start
;Affects: A
;Returns: Y,X = Horizontal Start
GETHSR: LDA #4          ;Set Lookup Index to Horizontal Start
        JSR GETHVS      ;Read Registers
        ;.dc $ff ;debug
GETHSS: AND #$03        ;Isolate Bit 0
        TAY             ;and Copy MSB to Y
        RTS

;gethvs() - Get Start/Stop Low Byte and High Bits
;Args: X = Low Register 
;Affects: Y
;Returns: A = High Bits
;         X = Low Byte
GETHVS: JSR GETDCR      ;Read LSB from Register
        ;.dc $ff ;debug
        PHA             ;and Save It
        LDA #8          ;Load Register Offset for High Bits
        STA $9F20	    ;Set As Address LSB
        LDA $9F23,X     ;and Read High Bits into A
        .DC $FA ;PLX    ;Restore LSB into X
        RTS

;getiql() - Get Interrupt Line
;Affects: A
;Returns: Y,X = Interrupt Line#
GETIQL: LDA #9      ;Set Register Offset to Interrupt Line
        .DC $2C     ;Skip to SETDCX (BIT Absolute)
        
;getscl() - Get Horizontal and Vertical Scale
;Returns: A,X = Horizontal Scale
;         Y = Vertical Scale
GETSCL: LDA #1      ;Set Register Offset to HSCALE,VSCALE
        .DC $2C     ;Skip SETDCI (BIT Absolute)
        
;getdci() - Get Display Composer Register Pair
;Args: A = Register Offset
;Affects: Y
;Returns: A,X = Integer LSB
;         Y = Integer LSB
GETDCI: LDY #$00    ;Set MSB to Display Composer Page
        TAX         ;Set LSB to Register Offset
                    ;and Execute GETREI

;getrei(addr); Read Vera Register Pair
;Args: Y,X = Address
;Returns: A,X = Integer LSB
;         Y = Integer LSB
GETREI: LDA #$0F    ;Set Bank to Registers

;getint(addr); Read Integer from Vera Memory
;Args: A = Bank
;      Y,X = Address
;Returns: A,X = Integer LSB
;         Y = Integer LSB
GETINT: ORA #$10    ;Set Auto-Increment to 1
        JSR SETADR  ;Set Vera Address
        LDX $9F25   ;Get Current Data Port
        LDA $9F23,X ;Read LSB from Data Port
        LDY $9F23,X ;Read MSB Data Port
        TAX         ;Copy LSB to X
        RTS

;setvsp() - Set Horizontal Stop
;Args: Y,X = Horizontal Stop
;Affects: A,X,Y
SETVSP: TYA             ;Convert MSB to High Bit
        AND #$01
        ASL
        ASL
        ASL
        ASL
        ASL
        STA TEMP1       ;and Save
        TXA             ;Copy LSB to Accumlator
        LDX #7          ;Set Register Offset to Horizontal Start
        LDY #$DF        ;Set High Bits Mask 
        JMP SETHST      ;OR in High Bits and Write Back

;setvsr() - Set Horizontal Start
;Args: Y,X = Horizontal Start
;Affects: A,X,Y
SETVSR: TYA             ;Convert MSB to High Bit
        AND #$01
        ASL
        ASL
        ASL
        ASL
        STA TEMP1       ;and Save
        TXA             ;Copy LSB to Accumlator
        LDX #6          ;Set Register Offset to Horizontal Start
        LDY #$EF        ;Set High Bits Mask 
        JMP SETHST      ;OR in High Bits and Write Back

;sethsp() - Set Horizontal Stop
;Args: Y,X = Horizontal Stop
;Affects: A,X,Y
SETHSP: TYA             ;Convert MSB to High Bits
        AND #$03
        ASL
        ASL
        STA TEMP1       ;and Save
        TXA             ;Copy LSB to Accumlator
        LDX #5          ;Set Register Offset to Horizontal Start
        LDY #$F3        ;Set High Bits Mask 
        JMP SETHST      ;OR in High Bits and Write Back

;sethsr() - Set Horizontal St7art
;Args: Y,X = Horizontal Start
;Destroys TEMP0,TEMP1,TEMP2
;Affects: A,X,Y
SETHSR: TYA             ;Convert MSB to High Bits
        AND #$03
        STA TEMP1       ;and Save
        TXA             ;Copy LSB to Accumlator
        LDX #4          ;Set Register Offset to Horizontal Start
        LDY #$FC        ;Set High Bits Mask 
SETHST: STY TEMP2       ;Save
        JSR SETHVS      ;Write LSB and Get High Bits
        AND TEMP2       ;Mask Start Stop High
        ORA TEMP1       ;OR in High Bits
        STA $9F23,X     ;and Write back to Register
        RTS
        
        
SETHVS: JSR SETDCX      ;Write LSB
        LDA #8          ;Load Register Offset for High Bits
        STA $9F20	    ;Set As Address LSB
        LDA $9F23,X     ;and Read High Bits into A
        RTS

;setvid() - Set Video Output Mode
;Args: A = Video Mode
;      Y = Chroma Disabled
;Destroys: TEMP0
SETVID: AND #3      ;Isolate Video Mode Bits
        CPY #0      ;Set Chroma Mask to
        BEQ SETVIF  ;  0 if Y is Zero or
        LDY #4      ;  4 if it is not
SETVIF: STY TEMP0   ;Save Chroma Bit
        ORA TEMP0   ;Combine with Video Mode Bits
        LDX #0      ;Set Register Offset to Video Mode
        BEQ SETDCX  ;Write to Register

;setbdr() - Set Border Color
;Args: A = Border Color Palette Index
SETBDR:  LDX #3     ;Set Register Offset to Border Color
        .DC $2C     ;Skip to SETDCX (BIT Absolute)

;setdcr() - Set Display Composer Register
;Args: A = Register Offset
;      Y = Value to Write
;Affects: Y
;Returns: A = Value Written
;         X = Current Data Port
SETDCR: TAX         ;Set LSB to Register Offset
        TYA         ;Move Write Value to Accumulator
SETDCX: LDY #$00    ;Set MSB to Display Composer Page

;setreg(addr) - Set Register 
;Args: A = Value to Write
;      Y,X = Address
;Sets: TEMP0 = Value to Write
;Affects: Y
;Returns: A = Value Written
;         X = Current Data Port
SETREG: STA TEMP0   ;Save Value to Write
SETREH: LDA #$0F    ;Set Bank, Auto-Increment

;setbyt(addr) - Write Byte to Vera Memory
;Args: A = Bank
;      Y,X = Address
;Uses: TEMP0 = Value to Write
;Affects: Y
;Returns: A = Value Written
;         X = Current Data Port
SETBYT: JSR SETADR  ;Set Vera Address
        LDA TEMP0   ;Retrieve Value to Write
        LDX $9F25   ;Get Current Data Port
        STA $9F23,X ;Write Value to Data Port
        RTS

;settbs() - Set Layer 0/1 Map Base
;Args: A = Layer (0/1)
;      Y,X = Map Base
;Sets: TEMP1,TEMP2 = Map Base
;Affecta: A,Y,X
SETTBS: JSR SAVRXY  ;Store Map Base in TEMP1,TEMP2
        LDX #4      ;Set Register Offset
        BNE SETLRI  ;Write to Layer Register
        
;setmbs() - Set Layer 0/1 Map Base
;Args: A = Layer (0/1)
;      Y,X = Map Base
;Sets: TEMP1,TEMP2 = Map Base
;Affecta: A,Y,X
SETMBS: JSR SAVRXY  ;Store Map Base in TEMP1,TEMP2
        LDX #2      ;Set Register Offset
        BNE SETLRI  ;Write to Layer Register

;setvsc() - Set Layer 0/1 Vertical Scroll
;Args: A = Layer (0/1)
;      Y,X = Map Base
;Sets: TEMP1,TEMP2 = Vertical Scroll
;Affecta: A,Y,X
SETVSC: JSR SAVRXY  ;Store Vertical Scroll in TEMP1,TEMP2
        LDX #8      ;Set Register Offset
        BNE SETLRI  ;Write to Layer Register

;sethsc() - Set Layer 0/1 Horizontal Scroll
;Args: A = Layer (0/1)
;      Y,X = Map Base
;Sets: TEMP1,TEMP2 = Horizontal Scroll
;Affecta: A,Y,X
SETHSC: JSR SAVRXY  ;Store Horizontal Scroll in TEMP1,TEMP2
        LDX #6      ;Set Register Offset

;setlri() - Write Integer to Get Layer 0/1 Register
;Args: A = Layer (0/1)
;      X = Register Offset
;Uses: TEMP1,TEMP2 = Integer Value
;Affecta: A,Y,X
SETLRI: JSR GETLRP  ;Get Layer Page in Y
        BNE SETREI  ;and Write Integer to Register

;setiql() - Set IRQ Line
;Args: Y,X = IRQ Line Number`
;Sets: TEMP1,TEMP2 = IRQ Line Number
;Affecta: A,Y,X
SETIQL: TXA         ;Copy LSB to Accumulator
        LDX #9      ;Set Register Offset to HSCALE,VSCALE
        .DC $2C     ;Skip to SETDCP (BIT Absolute)

;setscl() - Set Horizontal and Vertical Scale
;Args: A = Horizontal Scale
;      Y = Vertical Scale
SETSCL: LDX #1      ;Set Register Offset to HSCALE,VSCALE

;setdcp() - Set Display Composer Register Pair
;Args: A = First Register Value
;      Y = Second Register Value
;      X = Register Offset
;Affects: A,Y
;Returns: X = Current Data Port
SETDCP: STA TEMP1   ;Store First Value as LSB
        STY TEMP2   ;Store Second Value as MSB
        LDY #$00   ;Set MSB to Display Composer Page

;setrei(addr); Set Vera Register to Integer
;Args: Y,X = Address
;Uses: TEMP1,TEMP2 = Integer Value
;Affects: A,Y
;Returns: X = Current Data Port
SETREI: LDA #$0F    ;Set Bank to Registers

;setint(addr); Write Integer to Vera Memory
;Args: A = Bank
;      Y,X = Address
;Uses: TEMP1,TEMP2 = Integer Value
;Affects: A,Y
;Returns: X = Current Data Port
SETINT: ORA #$10    ;Set Auto-Increment to 1
        JSR SETADR  ;Set Vera Address
        LDX $9F25   ;Get Current Data Port
        LDA TEMP1   ;Get LSB
        STA $9F23,X ;Write to Data Port
        LDA TEMP2   ;Get MSB
        STA $9F23,X ;Write to Data Port
        RTS

;setmem(count, &addr) - Write Array to Vera Memory
;Args: A = Number of Bytes to Write
;      Y,X = Address of Array to Write From
;Requires: setadr() 
;Sets: SRCLO,SRCHI = Address of Array
;      TEMP0 = Number of Bytes to Write
;Affects: A
;Returns: Y = Number of Bytes Written
;         X = Current Data Port
SETMEM: STA TEMP0       ;Save Number of Bytes
        JSR SETSRC      ;Save Destination Address
        LDX $9F25       ;Get Current Data Port
        LDY #0          ;Initialize Counter
SETMEL: LDA (SRCLO),Y   ;Read Byte from Array
        STA $9F23,X     ;Write Byte to Data Port
        INY             ;Increment Counter
        CPY TEMP0       ;If Limit Not Reached
        BNE SETMEL      ;  Loop
        RTS

;rgbclr(r,g,b) - Convert RGB Values to Palette Color
;Args: A = Red Value (0-15)
;      Y = Green Value (0-15)
;      X = Blue Value (0-15)
;Affects: A
;Returns: Y = Color MSB (0000RRRR)
;         X = Color LSB (GGGGBBBB)
RGBCLR: PHA         ;Save Red Value
        TYA         ;Copy Green Value to Left Nybble
        .DC $DA ;PHX Copy Blue Value
        .DC $7A ;PLY to Right Nybble
        JSR NYBCAT  ;Concatanate Green and Blue
        TAX         ;and Return as LSB
        .DC $7A ;PLY Return Red as MSB
        RTS
        
;clrrgb(c) - Convert Palette Color to RGB Values 
;Args: Y = Color MSB (0000RRRR)
;      X = Color LSB (GGGGBBBB)
;Returns: A = Red Value (0-15)
;         Y = Green Value (0-15)
;         X = Blue Value (0-15)
CLRRGB: .DC $5A ;PHY Save MSB
        TXA         ;Copy LSB into Accumulator
        JSR NYBCUT  ;and Split into Nybbles
        .DC $5A ;PHY Return Blue Value
        .DC $FA ;PLX in X Register
        TAY         ;Green Value in Y Register
        PLA         ;and Red Value in Accumulator
        RTS

;getclr(idx) - Get Color Entry idx from Palette
;Args: A = Color Entry Index
;Affects: A
;Returns: Y = Color MSB (0000RRRR)
;         X = Color LSB (GGGGBBBB)
GETCLR: JSR SETIDX  ;Set Vera Address to Palette Index
        LDX $9F25   ;Get Current Data Port
        LDA $9F23,X ;Read LSB from Data Port
        LDY $9F23,X ;Read MSB from Data Port
        TAX         ;Copy LSB to X Register
        RTS

;setclr(idx) - Set Color Entry idx in Palette
;Args: A = Color Entry Index
;      Y = Color MSB (0000RRRR)
;      X = Color LSB (GGGGBBBB)
;Affects: A
;Returns: Y,X = Color Entry Address
SETCLR: JSR SAVRXY  ;Save Color Value
        JSR SETIDX  ;Set Vera Address to Palette Index
        LDX $9F25   ;Get Current Data Port
        LDA TEMP1   ;Retrieve Color Value LSB
        STA $9F23,X ;and Write to Data Port
        LDA TEMP2   ;Retrieve Color Value MSB
        STA $9F23,X ;Read MSB from Data Port
        RTS

;setidx(idx) - Set Vera Address to Palette Index
;Args: A = Index
;Returns: A = Bank + Auto-Increment
;         Y,X = Address
SETIDX: ASL         ;Multiply Index by 2
        TAX         ;and Set as LSB
        LDA #$10    ;Get Palette Page
        ADC #$00    ;Add Carry from Multiply
        TAY         ;and Set as MSB


;regadr(opts,addr) - Set Vera Address to Internal Register
;Args: Y,X = Register Address
;Returns: A= Bank + Auto-Increment
REGADR: LDA #$1F    ;Set Bank and Auto-Increment

;setadr(opts,addr) - Set Vera Address
;Args: A = Bank + Auto-Increment
;      Y,X = Address
SETADR: STX $9F20   ;Store Address LSB
        STY $9F21   ;Store Address MSB
        STA $9F22   ;Store Bank & Auto-Increment
        RTS
