; 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.
;
; > $.Source.VduDecl

; ARTHUR OPERATING SYSTEM - Vdu Drivers
; =======================
;
; Vdu driver workspace and macro declarations
;
; Author R C Manby
; Date   5.9.86
;

        GBLL ForceMark                  ; whether we force start of mark state
ForceMark    SETL   {FALSE}             ; of cursor on exit from WRCH

        GBLL RePlot                     ; Re-plot cursor after wrch
RePlot  SETL {TRUE}

        GBLL UseVLineOnSolidLines       ; When TRUE VLine is assembled and used
UseVLineOnSolidLines  SETL {TRUE}       ; to plot vertical solid lines

        GBLL AvoidScreenReads           ; When TRUE, use extra code to avoid
AvoidScreenReads      SETL {TRUE}       ; reading the screen when we can avoid it

        GBLL DefaultSupremacy           ; When TRUE, 16bpp and 32bpp modes' default
DefaultSupremacy      SETL {FALSE}      ; palettes use top bits for supremacy

;
; Register usage
; ==============
;
StkPtr  RN 13    ;Restore on exit to keep BASIC happy!!
Link    RN 14

;
; Manifest constants
; ==================
;


; Reason codes for generalised DAG interface



; Layout of palette space
PalEntries              *       256+1+3
                        ^       0
Pal_Blank               #       PalEntries*4    ; Blank palette (for screen saver)
Pal_LogFirst            #       PalEntries*4    ; Logical palette (as read/written by user)
Pal_LogSecond           #       PalEntries*4
Pal_PhysFirst           #       PalEntries*4    ; Physical palette (post transfer function)
Pal_PhysSecond          #       PalEntries*4
Pal_RTable              #       256             ; Logical->physical lookup tables for R,G,B,S
Pal_GTable              #       256
Pal_BTable              #       256
Pal_STable              #       256
Pal_Blocksize           #       0

; GraphicsV driver state
; For each allocated driver number, the corresponding word of GraphicsVDrivers
; points to an instance of the following structure:

                            ^   0
GVDriver_RegisterFlags      #   4        ; Flags on registration
GVDriver_Name               #   4        ; Name on registration
GVDriver_StateFlags         #   4        ; Current state flags
GVDriver_Size               #   0

GVDriverState_Started       *   1:SHL:0  ; ScreenMode_StartDriver called

;
; Macro Definitions
; =================
;

;
; Macro Sort - Sort two values into increasing order
;
        MACRO
        Sort    $lo, $hi
        CMP     $hi, $lo
        EORLT   $lo, $lo, $hi
        EORLT   $hi, $lo, $hi
        EORLT   $lo, $lo, $hi
        MEND

;
; Macro SortT - Sort two values into increasing order using a temporary reg
;
        MACRO
        SortT   $lo, $hi, $temp
        SUBS    $temp, $hi, $lo
        MOVLT   $hi, $lo
        ADDLT   $lo, $lo, $temp
        MEND

;
; Macro CompSwap - Compare and sort a pair of coordinates into
;                    order of increasing Y
;                  If Y values equal, sort in order of decreasing X
;
        MACRO
        CompSwap $xl,$yl, $xh,$yh
        CMP     $yh, $yl
        EORLT   $yl, $yl, $yh
        EORLT   $yh, $yl, $yh
        EORLT   $yl, $yl, $yh
        CMPEQ   $xl, $xh
        EORLT   $xl, $xl, $xh
        EORLT   $xh, $xl, $xh
        EORLT   $xl, $xl, $xh
        MEND

;
; Macro CompSwapT - Compare and sort a pair of coordinates into
;                    order of increasing Y
;                   If Y values equal, sort in order of decreasing X
;                   Uses a temporary register
;
        MACRO
        CompSwapT $xl,$yl, $xh,$yh, $temp
        SortT   $yl, $yh, $temp
        CMPEQ   $xl, $xh
        EORLT   $xl, $xl, $xh
        EORLT   $xh, $xl, $xh
        EORLT   $xl, $xl, $xh
        MEND

;
; Macro Difference - rc := ABS(ra-rb)
;
;                    Test GE/LT for ra>=rb / ra<rb
;
        MACRO
        Difference $rc,$ra,$rb
        SUBS $rc,$ra,$rb
        RSBLT $rc,$rc,#0
        MEND

;
; Macro Least - Select the smallest value (signed)
;
        MACRO
        Least $rc,$ra,$rb
        CMP $ra,$rb
       [ $rc = $ra
       |
        MOVLE $rc,$ra
       ]
       [ $rc = $rb
       |
        MOVGT $rc,$rb
       ]
        MEND

;
; Macro Greatest - Select the largest (signed) value
;
        MACRO
        Greatest $rc,$ra,$rb
        CMP $ra,$rb
       [ $rc = $ra
       |
        MOVGE $rc,$ra
       ]
       [ $rc = $rb
       |
        MOVLT $rc,$rb
       ]
        MEND

;
; Macro PackXtnd - pack 2 bytes into 1 word and sign extend
;

        MACRO
        PackXtnd $result,$hi,$lo
        [ $lo = $result
          ADD $result,$lo,$hi,LSL #8
          MOV $result,$result,LSL #16
          MOV $result,$result,ASR #16
        |
          MOV $result,$hi,LSL #24
          ORR $result,$lo,$result,ASR #16
        ]
        MEND

        MACRO
        LoadCoordPair   $x, $y, $basereg, $offset
    [ NoARMv4 :LOR: (($offset :AND: 1)=1)
      [ NoARMv6 :LOR: NoUnaligned
        ASSERT  $x < $y
        [ ($offset) :AND: 3 = 2
          ADD   $x, $basereg, #($offset)-2
          LDMIA $x, {$x, $y}                ; (Xh,Xl,??,??) (??,??,Yh,Yl)
          MOV   $x, $x, ASR #16             ; (Xs,Xs,Xh,Xl)
          [ NoARMv6
            MOV   $y, $y, LSL #16           ;               (Yh,Yl, 0, 0)
            MOV   $y, $y, ASR #16           ;               (Ys,Ys,Yh,Yl)
          |
            SXTH  $y, $y                    ;               (Ys,Ys,Yh,Yl)
          ]
        |
          [ ($offset) :AND: 3 = 0
            LDR   $x, [$basereg, #$offset]  ; (Yh,Yl,Xh,Xl)
          |
          [ ($offset) :AND: 3 = 1
            ADD   $x, $basereg, #($offset)-1
            LDMIA $x, {$x, $y}              ; (Yl,Xh,Xl,??) (??,??,??,Yh)
            MOV   $x, $x, LSR #8            ; ( 0,Yl,Xh,Xl)
            ORR   $x, $x, $y, LSL #24       ; (Yh,Yl,Xh,Xl)
          |
            ADD   $x, $basereg, #($offset)-3
            LDMIA $x, {$x, $y}              ; (Xl,??,??,??) (??,Yh,Yl,Xh)
            MOV   $x, $x, LSR #24           ; ( 0, 0, 0,Xl)
            ORR   $x, $x, $y, LSL #8        ; (Yh,Yl,Xh,Xl)
          ]
          ]
          MOV   $y, $x, ASR #16             ;               (Ys,Ys,Yh,Yl)
          [ NoARMv6
            MOV   $x, $x, LSL #16           ; (Xh,Xl, 0, 0)
            MOV   $x, $x, ASR #16           ; (Xs,Xs,Xh,Xl)
          |
            SXTH  $x, $x                    ; (Xs,Xs,Xh,Xl)
          ]
        ]
      |
        ; Use unaligned loads from ARMv6
        LDRSH   $x, [$basereg, #$offset]
        LDRSH   $y, [$basereg, #($offset)+2]
      ]
    |
        ; Aligned halfwords
        LDRSH   $x, [$basereg, #$offset]
        LDRSH   $y, [$basereg, #($offset)+2]
    ]
        MEND

;
; Macro SaveRetAdr - Push R14 to our pseudo stack
;
        MACRO
        SaveRetAdr
        Push    R14
        MEND

;
; Macro Return - Pull from stack into PC
;
        MACRO
        Return $cond
        LDR$cond PC, [StkPtr], #4
        MEND

;
; Macro SuperMode - Set supervisor mode
;
        MACRO
        SuperMode
        SWI &16
        MEND

;
; Macro WINDow - Compare coordinate against graphics window
;
;                Test GE/LT for within/outside window
;
        MACRO
        WINDow $rx,$ry, $rl,$rb,$rr,$rt
; ASSERT ($rl < $rb) AND ($rb < $rr) AND ($rr < $rt)
        ADD $rt,WsPtr,#GWLCol
        LDMIA $rt,{$rl,$rb,$rr,$rt}
        CMP $rx,$rl
        CMPGE $rr,$rx
        CMPGE $ry,$rb
        CMPGE $rt,$ry
        MEND

;
; Macro WindowRes - Window a coordinate, giving status word
;
;           Result word is as follows:
;
;                |      |
;           1001 | 1000 | 1010
;                |      |
;           -----+------+----- GWTRow
;                |      |
;           0001 | 0000 | 0010
;                |      |
;           -----+------+----- GWBRow
;                |      |
;           0101 | 0100 | 0110
;                |      |
;
;              GWLCol GWRCol
;
;
        MACRO
        WindowRes $result, $rx,$ry, $rl,$rb,$rr,$rt
; ASSERT ($rl < $rb) AND ($rb < $rr) AND ($rr < $rt)
        MOV $result,#0
        ADD $rt,WsPtr,#GWLCol
        LDMIA $rt,{$rl,$rb,$rr,$rt}
        CMP $rx,$rl
        ORRLT $result,$result,#1        ;Set bit 0 if X < window
        CMP $rr,$rx
        ORRLT $result,$result,#2        ;Set bit 1 if X > window
        CMP $ry,$rb
        ORRLT $result,$result,#4        ;Set bit 2 if Y < window
        CMP $rt,$ry
        ORRLT $result,$result,#8        ;Set bit 3 if Y > window
        MEND

        MACRO
$lab    EQUB    $var
        ASSERT  $var >= &00
        ASSERT  $var <= &FF
$lab    =       $var
        MEND

        MACRO
        OrrEor $d,$s, $or,$eor
        ORR $d,$s,$or
        EOR $d,$d,$eor
        MEND


        MACRO                           ;Scr:=ScrOR(oraANDmsk)EOR(eorANDmsk)
        OrrEorMASK $scr,$msk, $ora,$eor, $tmp
        AND $tmp,$msk,$ora
        ORR $scr,$scr,$tmp
        AND $tmp,$msk,$eor
        EOR $scr,$scr,$tmp
        MEND


        MACRO
        ORoreorEORoreor  $d,$s, $oo,$eo,$oe,$ee, $tmp
        OrrEor $tmp,$s, $oo,$eo
        ORR $d,$d,$tmp
        OrrEor $tmp,$s, $oe,$ee
        EOR $d,$d,$tmp
        MEND


        MACRO
        ORoreorEORoreorMASK  $d,$s,$m, $oo,$eo,$oe,$ee, $tmp
        OrrEor $tmp,$s, $oo,$eo
        AND $tmp,$tmp,$m
        ORR $d,$d,$tmp
        OrrEor $tmp,$s, $oe,$ee
        AND $tmp,$tmp,$m
        EOR $d,$d,$tmp
        MEND


        MACRO
        ShiftR $d,$e, $r,$rcomp
        MOV $d,$d,LSR $r
        ORR $d,$d,$e,LSL $rcomp
        MEND

        MACRO
        ShiftL $d,$e, $r,$rcomp
        MOV $e,$e,LSL $rcomp
        ORR $e,$e,$d,LSR $r
        MEND


        MACRO
        BitLOffset $b,$x, $xshftfactor,$npix,$log2bpc
        AND $b,$x,$npix
        MOV $b,$b,LSL $log2bpc
        MEND


        MACRO
        BitROffset $b,$x, $xshftfactor,$npix,$log2bpc
        AND $b,$x,$npix
        ADD $b,$b,#1
        MOV $b,$b,LSL $log2bpc
        SUB $b,$b,#1
        MEND


        MACRO
        WordOffset $w,$x, $xshftfactor,$npix,$log2bpc
        MOV $w,$x,ASR $xshftfactor
        MEND


        MACRO
        OffsetWordAndBit $o,$b,$x,$tmp
        LDR $tmp,[WsPtr,#XShftFactor]
        MOV $o,$x,ASR $tmp                      ;Word offset into scanline
        LDR $tmp,[WsPtr,#NPix]
        AND $b,$x,$tmp                          ;Pixel offset into word
        LDR $tmp,[WsPtr,#Log2BPC]
        MOV $b,$b,LSL $tmp                      ;Bit offset into word
        MEND


        MACRO
$label  ErrorMsg $num,$string
$label  DCD $num
        DCB "$string", 0
        ALIGN
        MEND

;
; Macro when given a register will return the state to indicate
; if we are in a graphics mode.  Originally lots of code used to simply
; load NPix and look for a null parameter (fair enough in 1-8 bit per pixel)
; but now we look at the mode flags, the choice of a new generation!
;
        MACRO
$label  GraphicsMode $scrap
$label  LDR     $scrap, [WsPtr, #ModeFlags]
        TST     $scrap, #ModeFlag_NonGraphic            ;NE then non-graphic mode!
        MEND

        END