; 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

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

;
; Manifest constants
; ==================
;
 [ VIDC_Type = "VIDC20"

; Registers

VIDCPalAddress          *       &10000000       ; used in palette programming

LCDOffsetRegister0      *       &30000000
LCDOffsetRegister1      *       &31000000

HorizCycle              *       &80000000
HorizSyncWidth          *       &81000000
HorizBorderStart        *       &82000000
HorizDisplayStart       *       &83000000
HorizDisplayEnd         *       &84000000
HorizBorderEnd          *       &85000000
HorizCursorStart        *       &86000000       ; used in pointer programming
HorizInterlace          *       &87000000

VertiCycle              *       &90000000
VertiSyncWidth          *       &91000000       ; Needed to set up FSIZE register in IOMD
VertiBorderStart        *       &92000000       ; First register affected by *TV
VertiDisplayStart       *       &93000000
VertiDisplayEnd         *       &94000000
VertiBorderEnd          *       &95000000
VertiCursorStart        *       &96000000
VertiCursorEnd          *       &97000000       ; Last register affected by *TV

VIDCExternal            *       &C0000000
VIDCFSyn                *       &D0000000
VIDCControl             *       &E0000000
VIDCDataControl         *       &F0000000

; Pseudo-registers used to return additional information to kernel

PseudoRegister_ClockSpeed *     &FC000000       ; used to indicate real VIDC rclock speed
PseudoRegister_DPMSState *      &FD000000       ; used to return desired DPMS state


; Bits in external register

Ext_HSYNCbits   *       3 :SHL: 16
Ext_InvertHSYNC *       1 :SHL: 16
Ext_CompHSYNC   *       2 :SHL: 16
Ext_InvertCompHSYNC *   3 :SHL: 16
Ext_VSYNCbits   *       3 :SHL: 18
Ext_InvertVSYNC *       1 :SHL: 18
Ext_CompVSYNC   *       2 :SHL: 18
Ext_InvertCompVSYNC *   3 :SHL: 18
Ext_HiResMono   *       1 :SHL: 14
Ext_LCDGrey     *       1 :SHL: 13
Ext_DACsOn      *       1 :SHL: 12
Ext_PedsOn      *       7 :SHL: 8
Ext_PedsShift   *       8
Ext_ERegShift   *       4
Ext_ECKOn       *       1 :SHL: 2
Ext_ERegBits    *       3 :SHL: 0
Ext_ERegRed     *       0 :SHL: 0
Ext_ERegGreen   *       1 :SHL: 0
Ext_ERegBlue    *       2 :SHL: 0
Ext_ERegExt     *       3 :SHL: 0       ; use this for lowest power

; Bits in Frequency Synthesizer Register

FSyn_VShift     *       8
FSyn_RShift     *       0
FSyn_ClearV     *       1 :SHL: 15
FSyn_ForceLow   *       1 :SHL: 14
FSyn_ClearR     *       1 :SHL: 7
FSyn_ForceHigh  *       1 :SHL: 6

FSyn_ResetValue *       FSyn_ClearV :OR: FSyn_ClearR :OR: FSyn_ForceLow :OR: (63 :SHL: FSyn_RShift) :OR: (0 :SHL: FSyn_VShift)           ; value to get PLL working properly

; Bits in Control Register

CR_DualPanel    *       1 :SHL: 13
CR_Interlace    *       1 :SHL: 12
CR_FIFOLoadShift *      8
CR_LBPP0        *       0 :SHL: 5
CR_LBPP1        *       1 :SHL: 5
CR_LBPP2        *       2 :SHL: 5
CR_LBPP3        *       3 :SHL: 5
CR_LBPP4        *       4 :SHL: 5
CR_LBPP5        *       6 :SHL: 5 ; spot the gap!
CR_PixelDivShift *      2
CR_VCLK         *       0 :SHL: 0
CR_HCLK         *       1 :SHL: 0
CR_RCLK         *       2 :SHL: 0

; Bits in Data Control Register

DCR_VRAMOff     *       0 :SHL: 18
DCR_VRAMDiv1    *       1 :SHL: 18
DCR_VRAMDiv2    *       2 :SHL: 18
DCR_VRAMDiv4    *       3 :SHL: 18
DCR_BusBits     *       3 :SHL: 16
DCR_Bus31_0     *       1 :SHL: 16
DCR_Bus63_32    *       2 :SHL: 16
DCR_Bus63_0     *       3 :SHL: 16
DCR_HDis        *       1 :SHL: 13
DCR_Sync        *       1 :SHL: 12
DCR_HDWRShift   *       0

 |

; Registers
                                                                                                                                          �����������������������������������������������������������
HorizDisplayStart       *       &8C000000       ; used in mode change code
HorizCursorStart        *       &98000000       ; used in pointer programming

VertiBorderStart        *       &A8000000       ; First register affected by *TV
VertiDisplayStart       *       &AC000000
VertiCursorStart        *       &B8000000
VertiCursorEnd          *       &BC000000       ; Last register affected by *TV

SoundFrequency          *       &C0000000
VIDCControl             *       &E0000000

; Bits in control register

CR_Interlace            *       &40             ; 0 - no interlace, 64 - interlace
CompSync        *       &80     ; Controls sync signal on CS/VS pin
                                ; 0 - output vertical sync, 128 - composite sync.
; Other bits

SupBit          *       &1000   ; Supremacy bit in palette
 ]

PhysCursorStartAdr * CursorSoundPhysRAM

; Reason codes for generalised DAG interface - independent of MEMC type

MEMCDAG_VInit   *       0
MEMCDAG_VStart  *       1
MEMCDAG_VEnd    *       2
MEMCDAG_CInit   *       3

MEMCDAG_MaxReason *     3

 [ ModeSelectors

; OS_ScreenMode reason codes

ScreenModeReason_SelectMode             *       0
ScreenModeReason_ReturnMode             *       1
ScreenModeReason_EnumerateModes         *       2
ScreenModeReason_SelectMonitorType      *       3
ScreenModeReason_Limit                  *       4

; Mode selector format

                        ^       0
ModeSelector_Flags      #       4       ; flags word
ModeSelector_XRes       #       4       ; x-resolution in pixels
ModeSelector_YRes       #       4       ; y-resolution in pixels
ModeSelector_PixelDepth #       4       ; pixel depth (=Log2BPP)
ModeSelector_FrameRate  #       4       ; nominal frame rate (in Hz)
ModeSelector_ModeVars   #       0       ; start of pairs of (mode var index, value)

ModeSelectorFlags_FormatMask    *       &FF
ModeSelectorFlags_ValidFormat   *       1

ModeSelector_MaxSize    *       ModeSelector_ModeVars+(NumModeVars * 8)+4
                                        ; maximum size of a mode selector, with each mode variable overridden
                                        ; plus terminator on end

 ]



;
; 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
        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)
          MOV   $y, $y, LSL #16             ;               (Yh,Yl, 0, 0)
          MOV   $y, $y, ASR #16             ;               (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)
          MOV   $x, $x, LSL #16             ; (Xh,Xl, 0, 0)
          MOV   $x, $x, ASR #16             ; (Xs,Xs,Xh,Xl)
        ]
        MEND

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

;
; Macro Return - Pull from stack into PC
;
        MACRO
        Return $cond
        LDM$cond.FD StkPtr!, {PC}
        MEND

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

;
; Macro UserMode - Return to user mode
;
        MACRO
        UserMode
        TEQP PC,#0        ; Return to user mode
        MOV R0,R0         ; Force a NOP so it works
        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, #Flag_NonGraphic                ;NE then non-graphic mode!
        MEND

        END