; Copyright 1996 Acorn Computers Ltd
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
;     http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;
; > VduPal10

; mjs - not used any more (it's pre-Medusa, for goodness sake)

; Palette programming for VIDC10 (ie VIDC1 or VIDC1a)

; *****************************************************************************

; PaletteV handler
; ----------------

; *****************************************************************************
;
;       MOSPaletteV - Default owner of PaletteV
;

        ASSERT  paletteV_Complete = 0
        ASSERT  paletteV_Read = 1
        ASSERT  paletteV_Set = 2
        ASSERT  paletteV_1stFlashState = 3
        ASSERT  paletteV_2ndFlashState = 4
        ASSERT  paletteV_SetDefaultPalette = 5
        ASSERT  paletteV_BlankScreen = 6

MOSPaletteV ROUT
        CMP     r4, #1
        MOVCC   pc, lr
        BEQ     PV_ReadPalette
        CMP     r4, #3
        BCC     PV_SetPalette
        BEQ     PV_1stFlashState
        CMP     r4, #5
        BCC     PV_2ndFlashState
        BEQ     PV_SetDefaultPalette
        CMP     r4, #7
        BCC     PV_BlankScreen
        MOV     pc, lr                  ; reason code not known, so pass it on

; *****************************************************************************

PV_SetDefaultPalette ROUT
        Push    "r0-r3,r5-r9"
        LDR     r0, [WsPtr, #PalIndex]  ; the new index 0-5
        ADR     r1, paldptab
        LDR     r2, [r1, r0, LSL #2]    ; offset from r1 to start of table
        ADD     r0, r0, #1              ; point to next item
        LDR     r5, [r1, r0, LSL #2]    ; offset from r1 to end of table +1
        ADD     r2, r2, r1              ; r2 -> start of table
        ADD     r5, r5, r1              ; r5 -> end of table
        MOV     r0, #0                  ; start at palette index 0
        MOV     r1, #3                  ; set both halves
10
        LDR     r6, [r2], #4
        MOVS    r3, r6, LSL #17         ; get 1st half word and set carry if flashing
        MOV     r3, r3, LSR #17
        MOVCC   r4, #0
        LDRCS   r4, =&FFF               ; flashing so invert 2nd half RGB
        BL      UpdateSettingStraightRGB
        ADD     r0, r0, #1
        MOVS    r3, r6, LSL #1          ; get 2nd half word and set carry if flashing
        MOV     r3, r3, LSR #17
        MOVCC   r4, #0
        LDRCS   r4, =&FFF
        BL      UpdateSettingStraightRGB
        ADD     r0, r0, #1
        TEQ     r2, r5
        BNE     %BT10

; now ensure all palette entries from 0..15 are initialised

        MOV     r3, #0                  ; set unused (and border) to black
        MOV     r4, #0                  ; no flashing
20
        CMP     r0, #16
        BHS     %FT25
        BL      UpdateSettingStraightRGB
        ADD     r0, r0, #1
        B       %BT20

25      MOV     r2, #0                  ; Set border to black (sup 0)
        BL      BorderInitEntry

        MOV     r4, #0                  ; indicate PaletteV operation complete
        Pull    "r0-r3,r5-r9,pc"        ; restore registers and claim vector

        LTORG

; *****************************************************************************

; Table of offsets from paldata_pointer to palette data

paldptab
        &       paldat1-paldptab        ; 2  Colour Modes
        &       paldat2-paldptab        ; 4
        &       paldat4-paldptab        ; 16
        &       paldat8-paldptab        ; 256
        &       paldatT-paldptab        ; teletext mode
        &       paldatHR-paldptab       ; Hi-res mono mode
        &       paldatend-paldptab      ; end of table marker

paldat1 ; Data for 1 bit modes - only necessary to program registers 0 and 1

;               FSBGR

        DCW     &0000           ; 0  Black
        DCW     &0FFF           ; 1  White

paldat2 ; Data for 2 bit modes - only necessary to program registers 0..3

;               FSBGR

        DCW     &0000           ; 0  Black
        DCW     &000F           ; 1  Red
        DCW     &00FF           ; 2  Yellow
        DCW     &0FFF           ; 3  White

paldat4 ; Data for 4 bit modes - program all registers
        ; Flashing Colours will be needed here

;               FSBGR

        DCW     &0000           ; 0  Black
        DCW     &000F           ; 1  Red
        DCW     &00F0           ; 2  Green
        DCW     &00FF           ; 3  Yellow
        DCW     &0F00           ; 4  Blue
        DCW     &0F0F           ; 5  Magenta
        DCW     &0FF0           ; 6  Cyan
        DCW     &0FFF           ; 7  White
        DCW     &8000           ; 8  Flashing Black
        DCW     &800F           ; 9  Flashing Red
        DCW     &80F0           ; 10 Flashing Green
        DCW     &80FF           ; 11 Flashing Yellow
        DCW     &8F00           ; 12 Flashing Blue
        DCW     &8F0F           ; 13 Flashing Magenta
        DCW     &8FF0           ; 14 Flashing Cyan
        DCW     &8FFF           ; 15 Flashing White

paldat8 ; Data for 8 bit modes - Program all registers
        ; PP field is 16 for all these, cos not true BBC colours

;               FSBGR

        DCW     &0000           ; 0
        DCW     &0111           ; 1
        DCW     &0222           ; 2
        DCW     &0333           ; 3
        DCW     &0004           ; 4
        DCW     &0115           ; 5
        DCW     &0226           ; 6
        DCW     &0337           ; 7
        DCW     &0400           ; 8
        DCW     &0511           ; 9
        DCW     &0622           ; A
        DCW     &0733           ; B
        DCW     &0404           ; C
        DCW     &0515           ; D
        DCW     &0626           ; E
        DCW     &0737           ; F

paldatT ; Data for teletext mode

        DCW     &0000           ; 0 Black
        DCW     &000F           ; 1 Red
        DCW     &00F0           ; 2 Green
        DCW     &00FF           ; 3 Yellow
        DCW     &0F00           ; 4 Blue
        DCW     &0F0F           ; 5 Magenta
        DCW     &0FF0           ; 6 Cyan
        DCW     &0FFF           ; 7 White

; Colours 8 to 15 have supremacy bit set

        DCW     &1000           ; 8 Supremacy+ Black
        DCW     &100F           ; 9            Red
        DCW     &10F0           ; 10           Green
        DCW     &10FF           ; 11           Yellow
        DCW     &1F00           ; 12           Blue
        DCW     &1F0F           ; 13           Magenta
        DCW     &1FF0           ; 14           Cyan
        DCW     &1FFF           ; 15           White

paldatHR  ; data for Hi-res mono mode
        DCW     &0000           ; Only red gun necessary
        DCW     &0111           ; but setting all three makes
        DCW     &0222           ; reading it more natural
        DCW     &0333
        DCW     &0444
        DCW     &0555
        DCW     &0666
        DCW     &0777
        DCW     &0888
        DCW     &0999
        DCW     &0AAA
        DCW     &0BBB
        DCW     &0CCC
        DCW     &0DDD
        DCW     &0EEE
        DCW     &0FFF

        DCW     &0000           ; border black
        DCW     &0010           ; fixed pointer colours
        DCW     &0020
        DCW     &0030
paldatend


; *****************************************************************************

; PaletteV call to set palette
; in:   R0 = logical colour
;       R1 = colour type (16,17,18,24,25)
;       R2 = BBGGRRS0
;       R4 = PaletteV reason code
;
; out:  R4 = 0, claim vector if recognised
;       otherwise preserve R4 and pass on
;

PV_SetPalette ROUT
        Push    "r0-r3"
        TEQ     r1, #16                 ; if 16 then set both colours
        MOVEQ   r1, #3
        BEQ     UpdateNormalColour

        TEQ     r1, #17                 ; elif 17 then set 1st colour
        MOVEQ   r1, #1
        BEQ     UpdateNormalColour

        TEQ     r1, #18                 ; elif 18 then set 2nd colour
        MOVEQ   r1, #2
        BEQ     UpdateNormalColour

        TEQ     r1, #24                 ; elif 24 then border colour
        BEQ     BorderColour

        TEQ     r1, #25                 ; elif 25 then pointer colour
        BEQ     PointerColour

        Pull    "r0-r3"
        MOV     pc, lr                  ; else not defined

; *****************************************************************************

UpdateNormalColour ROUT
        LDR     lr, [WsPtr, #DisplayNColour] ; get the mask
        AND     r0, r0, lr              ; and mask it off
        AND     r0, r0, #15             ; maximum 15
        BL      UpdateSettingAndVIDC
        MOV     r4, #0                  ; indicate successful PaletteV op
        Pull    "r0-r3, pc"

BorderInitEntry ENTRY "r0-r3"           ; entry used in default palette setting
BorderColour ROUT
        LDR     r0, [WsPtr, #PalIndex]  ; if hi res mono
        TEQ     r0, #5
        BICEQ   r2, r2, #&00300000      ; then knock out bits 0,1 of green palette

        MOV     r0, #16                 ; palette index for border colour
        MOV     r1, #3                  ; both colours
        BL      UpdateSettingAndVIDC

; Now test for BBC gap mode (ie 3 or 6)
; if so then set colour 2 to same as border, and colour 3 to inverse

        LDR     lr, [WsPtr, #DisplayModeFlags]
        TST     lr, #ModeFlag_BBCGapMode
        BEQ     %FT10

        MOV     r0, #2                  ; make colour 2 (gap) same as border
        BL      UpdateSettingAndVIDC

        MOV     r0, #3                  ; make colour 3 inverse gap
        MVN     r2, r2                  ; invert R, G and B
        EOR     r2, r2, #&FF            ; but use same supremacy
        BL      UpdateSettingAndVIDC
10
        MOV     r4, #0                  ; indicate successful PaletteV op
        Pull    "r0-r3, pc"


PointerColour ROUT
        LDR     r1, [WsPtr, #PalIndex]  ; if hi res mono, then don't allow
        TEQ     r1, #5                  ; pointer palette changes
        ANDNES  r0, r0, #3              ; force pointer colour number in range 1..3
        BEQ     %FT10                   ; zero is invalid
        ADD     r0, r0, #16             ; form palette index 17..19
        MOV     r1, #3
        BL      UpdateSettingAndVIDC
10
        MOV     r4, #0                  ; indicate successful PaletteV op
        Pull    "r0-r3,pc"

UpdateSettingAndVIDC ROUT
        AND     r4, r2, #&F0000000
        MOV     r3, r4, LSR #(28-8)     ; move blue to bits 8..11
        AND     r4, r2, #&00F00000
        ORR     r3, r3, r4, LSR #(20-4) ; move green to bits 4..7
        AND     r4, r2, #&0000F000
        ORR     r3, r3, r4, LSR #(12-0) ; move red to bits 0..3
        AND     r4, r2, #&00000080
        ORR     r3, r3, r4, LSL #(12-7) ; move sup to bit 12

        CMP     r0, #16                 ; if not normal colour
        BCS     %FT10                   ; then OK for hi-res-mono
        LDR     r4, [WsPtr, #PalIndex]
        TEQ     r4, #5
        BEQ     UpdateHiResRGB
10
        MOV     r4, #0                  ; indicate no EORing between parts

; and drop thru to ...

UpdateSettingStraightRGB ENTRY "r2,r5,r6"
        PHPSEI                          ; protect against IRQs
        ORR     r3, r3, r0, LSL #26     ; form VIDC register number at top
        LDRB    r5, [WsPtr, #ScreenBlankFlag]
        TEQ     r5, #0
        MOVNE   r5, #&00FFFFFF          ; bits to knock out if blanked

        LDROSB  r2, FlashState          ; 0 => second, 1 => first
        CMP     r2, #1                  ; C=0 => second, C=1 => first

        TST     r1, #1
        BEQ     %FT10                   ; skip if not setting 1st colour
        ADD     r2, WsPtr, #FirPalSetting
        STR     r3, [r2, r0, LSL #2]
        MOVCS   r2, #VIDC
        BICCS   r6, r3, r5              ; knock out bits for blanking
        STRCS   r6, [r2]                ; poke VIDC if setting 1st colour and in 1st state
10
        TST     r1, #2
        BEQ     %FT20                   ; skip if not setting 2nd colour
        ADD     r2, WsPtr, #SecPalSetting
        EOR     r3, r3, r4              ; toggle requested bits for 2nd half
        STR     r3, [r2, r0, LSL #2]
        MOVCC   r2, #VIDC
        BICCC   r6, r3, r5              ; knock out bits for blanking
        STRCC   r6, [r2]                ; poke VIDC if setting 2nd colour and in 2nd state
20
        PLP
        EXIT                            ; restore registers, claim vector

; *****************************************************************************
;
;       UpdateHiResRGB - Routine to program normal palette for Hi-Res-Mono display
;
; in:   r0 = logical colour
;       r1 = mask of which states to update (bit 0 = 1st flash state, bit 1 = 2nd)
;       r3 = &0000SBGR
;
; out:  r3, r4 may be corrupted
;

UpdateHiResRGB ENTRY "r5"
        PHPSEI
        Push    "lr"
        LDROSB  r5, FlashState
        TEQ     r5, #0                  ; 0 => 2nd state, 1 => 1st state
        MOVNE   r5, #VIDC               ; 1st state => r5 = VIDC, else = 0

        TST     r1, #1
        ADDNE   r4, WsPtr, #FirPalSetting
        BLNE    UpdateOneHiResSetting

        EOR     r5, r5, #VIDC           ; 2nd state => r5 = VIDC, else = 0
        TST     r1, #2
        ADDNE   r4, WsPtr, #SecPalSetting
        BLNE    UpdateOneHiResSetting
        Pull    "lr"
        PLP
        EXIT

UpdateOneHiResSetting ENTRY "r1,r2,r6-r9"
        LDRB    lr, [WsPtr, #ScreenBlankFlag]
        TEQ     lr, #0
        MOVNE   lr, #&00FFFFFF          ; if blanked, mask off these bits

        LDR     r2, =&FFF
        TEQ     r0, #0
        MOVEQ   r1, r3                  ; if programming colour 0 then 1st colour is r3
        LDREQ   r6, [r4, #15*4]         ; and 2nd colour is what's in colour 15
        LDRNE   r1, [r4, #0*4]          ; else 1st colour is what's in colour 0
        MOVNE   r6, r3                  ; and 2nd colour is r3

        EOR     r6, r6, #&008           ; invert bit R3 of colour 15
        EOR     r6, r6, r1              ; inverted EOR of colours 0 and 15
        ANDS    r6, r6, #&008           ; just use R3 for black/white
        MOVNE   r6, r2                  ; if non-zero make BIC mask full RGB else 0
        ANDS    r1, r1, #&008           ; if colour 0 = white then make EOR mask full RGB else 0
        MOVNE   r1, r2

        ADD     r7, r4, #16*4           ; end of table
        MOV     r8, #0                  ; start
        LDR     r2, =&04000111          ; amount to add on each time round

10
        BIC     r9, r8, r6              ; take value and knock out BIC mask
        EOR     r9, r9, r1              ; then toggle EOR mask
        STR     r9, [r4], #4            ; store in soft copy
        TEQ     r5, #0                  ; if updating VIDC
        BICNE   r9, r9, lr              ; knock out bits (for blanking)
        STRNE   r9, [r5]                ; then do it
        ADD     r8, r8, r2              ; move on to next value
        TEQ     r4, r7                  ; if not done all 16 entries
        BNE     %BT10                   ; then loop

        EXIT

        LTORG

; *****************************************************************************
;
;       PV_ReadPalette - PaletteV read palette handler
;
; in:   R0 = logical colour
;       R1 = 16 (read normal colour)
;            24 (read border colour)
;            25 (read cursor colour)
;
; out:  R2 = first flash setting   (BBGGRRS0), supremacy bit 7
;       R3 = second flash setting  (BBGGRRS0), supremacy bit 7
;

PV_ReadPalette ROUT
        Push    "r10,r11"
        LDR     r10, [WsPtr, #DisplayNColour] ; logical colours in this mode -1
        TEQ     r1, #24                 ; is it reading border palette
        MOVEQ   r11, #16                ; then set up border index
        BEQ     %FT10                   ; and go

        TEQ     r1, #25                 ; is it reading pointer palette
        BEQ     %FT05
        AND     r11, r0, r10            ; no, then force into suitable range
        AND     r11, r11, #15           ; only allow 0..15
        LDR     r2, [WsPtr, #PalIndex]
        TEQ     r2, #5                  ; if hi res mono
        TEQEQ   r11, #1                 ; and reading colour 1
        MOVEQ   r11, #15                ; then read colour 15 instead
        B       %FT10                   ; always skip
05
        ANDS    r11, r0, #3             ; else force logical colour 0..3
        BEQ     %FT99                   ; and 0 is illegal, so do nothing
        ADD     r11, r11, #16           ; set up correct index
10
        CMP     r11, #16                ; is it normal one (not border/cursor)
        MOVCSS  r3, #0                  ; no, then don't fudge colours; Z=1
                                        ; (carry preserved from CMP)
        ANDCCS  r3, r10, #&F0           ; yes, then fudge if 256 colour mode

        ADD     r10, WsPtr, #FirPalSetting

        LDR     r11, [r10, r11, LSL #2]! ; r11 := 1st XX00SBGR
        BLNE    FudgeRGB

        AND     lr, r11, #&F00          ; lr  := 1st 00000B00
        MOV     r2, lr, LSL #20         ; r2  := 1st B0000000
        AND     lr, r11, #&0F0          ; lr  := 1st 000000G0
        ORR     r2, r2, lr, LSL #16     ; r2  := 1st B0G00000
        AND     lr, r11, #&00F          ; lr  := 1st 0000000R
        ORR     r2, r2, lr, LSL #12     ; r2  := 1st B0G0R000
        ORR     r2, r2, r2, LSR #4      ; r2  := 1st BBGGRR00
        AND     lr, r11, #&1000
        ORR     r2, r2, lr, LSR #5      ; r2  := 1st BBGGRRS0

        LDR     r11, [r10, #SecPalSetting-FirPalSetting]
        BLNE    FudgeRGB

        AND     lr, r11, #&F00          ; lr  := 2nd 00000B00
        MOV     r3, lr, LSL #20         ; r3  := 2nd B0000000
        AND     lr, r11, #&0F0          ; lr  := 2nd 000000G0
        ORR     r3, r3, lr, LSL #16     ; r3  := 2nd B0G00000
        AND     lr, r11, #&00F          ; lr  := 2nd 0000000R
        ORR     r3, r3, lr, LSL #12     ; r3  := 2nd B0G0R000
        ORR     r3, r3, r3, LSR #4      ; r3  := 2nd BBGGRR00
        AND     lr, r11, #&1000
        ORR     r3, r3, lr, LSR #5      ; r3  := 2nd BBGGRRS0
99
        MOV     r4, #0
        Pull    "r10, r11, pc"

FudgeRGB ROUT
 [ No26bitCode
        mrs    ,r4, CPSR
 ]
        BIC     r11, r11, #&C8          ; knock out top bit R, top 2 bits G
        BIC     r11, r11, #&800         ; knock out top bit B

        TST     r0, #&10                ; override top bit of red
        ORRNE   r11, r11, #&8
        TST     r0, #&20                ; override next to top bit of green
        ORRNE   r11, r11, #&40
        TST     r0, #&40                ; override top bit of green
        ORRNE   r11, r11, #&80
        TST     r0, #&80                ; override top bit of blue
        ORRNE   r11, r11, #&800
 [ No26bitCode
        msr    ,CPSR_f, r4
 |
        MOVS    pc, lr
 ]

; *****************************************************************************
;
;       PV_1stFlashState - PaletteV routine to set first flash state
;

PV_1stFlashState ROUT
        Push    "r0-r3"
        ADD     r0, WsPtr, #FirPalSetting
DoR0Flash
        MOV     r1, #15                 ; logical colour
DoAllUpdate
        LDRB    lr, [WsPtr, #ScreenBlankFlag]
        TEQ     lr, #0
        MOVEQ   lr, #&FF000000          ; unblanked, just knock off top 8 bits
        MOVNE   lr, #&FFFFFFFF          ; blanked, knock off all bits!
        MOV     r2, #VIDC
10
        LDR     r3, [r0, r1, LSL #2]
        BIC     r3, r3, lr              ; get rid of top bits, or all if blanked
        ORR     r3, r3, r1, LSL #26     ; OR in register number
        STR     r3, [r2]                ; program VidC
        SUBS    r1, r1, #1
        BPL     %BT10

        MOV     r4, #0
        Pull    "r0-r3, pc"

; *****************************************************************************
;
;       PV_2ndFlashState - PaletteV routine to set second flash state
;

PV_2ndFlashState ROUT
        Push    "r0-r3"
        ADD     r0, WsPtr, #SecPalSetting
        B       DoR0Flash

; *****************************************************************************
;
;       UpdateAllPalette - Update all VIDC palette entries
;

UpdateAllPalette ENTRY "r0-r3"          ; "r0-r3,lr" stacked ready to branch to code
        LDROSB  r0, FlashState
        CMP     r0, #1
        ADDCS   r0, WsPtr, #FirPalSetting ; FlashState = 1 => 1st state, 0 => 2nd state
        ADDCC   r0, WsPtr, #SecPalSetting
        MOV     r1, #19                 ; do 0-15 and border + 3 pointer
        B       DoAllUpdate

; *****************************************************************************
;
;       PV_BlankScreen - Blank/unblank screen
;
; in:   R0 = -1 => read blank state
;       R0 = 0 => unblank screen
;       R0 = 1 => blank screen
;
; out:  R0 = old state (0=unblanked, 1=blanked)
;       R4 = 0

PV_BlankScreen ROUT
        Push    "r1-r3"
        LDRB    r3, [WsPtr, #ScreenBlankFlag]
        CMP     r0, #1
        BHI     %FT99

        TEQ     r0, r3                  ; changing to same state? (carry preserved)
        BEQ     %FT99                   ; if so, do nothing

        STRB    r0, [WsPtr, #ScreenBlankFlag] ; update new state

        MOVCC   r0, #(1 :SHL: 10) :OR: (0 :SHL: 8) ; unblank: video DMA on, no refresh
        MOVCS   r0, #(0 :SHL: 10) :OR: (3 :SHL: 8) ; blank:   video DMA off, continuous refresh
        MOV     r1, #(1 :SHL: 10) :OR: (3 :SHL: 8) ; bits to modify
        SWI     XOS_UpdateMEMC

        PHPSEI  r0, lr                  ; disable IRQs so we don't get a flash in the middle
        BL      UpdateAllPalette        ; update all palette, including border + pointer
        PLP     r0                      ; restore old IRQ state
99
        MOV     r0, r3
        MOV     r4, #0
        Pull    "r1-r3, pc"


        END