; 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.VduGrafL
;
; ARTHUR OPERATING SYSTEM - Vdu Drivers
; =======================
;
; Vdu driver code - Sprite stuff
;
; Author T M Dobson
; Date   22-Sep-87
;

; *****************************************************************************
;
;       ReadSaveAreaSize - Read size of a VDU context save area
;
; in:   R0 = SpriteReason_ReadSaveAreaSize
;       R1 -> sprite area
;       R2 -> sprite (0 => screen (possibly))
;
; out:  R3 = size of an area suitable for this sprite
;

ReadSaveAreaSize ROUT
        MOV     R3, #MainSize           ; I was kidding about it depending
        STR     R3, [WsPtr, #RetnReg3]  ; on the sprite!
        MOV     PC, R14

; *****************************************************************************
;
;       SwitchOutputToSprite - Make VDU(graphics) output go to a sprite
;
;       External routine
;
; in:   R0 = SpriteReason_SwitchOutputTo <Sprite or Mask>
;       R1 -> sprite area
;       R2 -> sprite (0 => screen)
;       R3 -> save area for VDU variables relating to sprite
;        0 => no save area, initialise variables from mode number of sprite
;             or display mode number
;        1 => use MOS's save area
;
;       First word of save area = 0      => uninitialised save area
;                                 "VOTS" => initialised save area
;                                 else error
;

; From Medusa onwards, things are further complicated here by the fact that
; the sprite may have a new sprite mode word rather than a mode number. When
; the former case occurs calling pushmodeinfoanymonitor doesn't really help
; very much. Instead, when a sprite mode word is given, it will derive or
; fudge all the variables that it is really interested from the sprite mode
; word directly.

SwitchOutputToSprite ROUT
SwitchOutputToMask ROUT
        CMP     R3, #1                  ; check for values 0 and 1
        MOVCC   R4, #0                  ; R3=0 => no save area, so not inited

        ADDEQ   R5, WsPtr, #VduSaveArea ; R3=1 => MOS's area
        MOVHI   R5, R3                  ; else user area
        LDRCS   R4, [R5, #InitFlag]     ; if is an area, load R4 with init flag
        LDR     R5, VOTS                ; compare with initialised identifier
        TEQ     R4, R5                  ; if not initialised
        TEQNE   R4, #0                  ; and not uninitialised
        BNE     InvalidSaveArea

; no more errors can be generated, so update returned registers

        ADD     R5, WsPtr, #VduOutputCurrentState
        LDMIA   R5, {R6-R9}
        ADD     R5, WsPtr, #RetnReg0
        STMIA   R5, {R6-R9}

        Push    "R0-R4,R14"

        ASSERT  SpriteMaskSelect = VduOutputCurrentState +0
        ASSERT  VduSpriteArea    = VduOutputCurrentState + 4
        ASSERT  VduSprite        = VduOutputCurrentState + 8

        ORR     R0, R0, #RangeC         ; make R0 into &2nn

        ADD     R5, WsPtr, #VduOutputCurrentState
        STMIA   R5, {R0-R2}

        BL      PreWrchCursor           ; remove cursor
        BL      PackVars                ; save away current vars into save area
                                        ; (if any)
        Pull    "R0-R4"
        STR     R3, [WsPtr, #VduSaveAreaPtr] ; save new save area ptr

        TEQ     R2, #0                  ; if switching to screen
        LDREQ   R9, [WsPtr, #DisplayScreenStart] ; then load up new ScreenStart
        LDREQ   R11, [WsPtr, #DisplayModeNo] ; and mode number
        BEQ     %FT20                   ; and skip sprite stuff

; do stuff for switching to sprite

        Push    R0
        BL      RemoveLeftHandWastage   ; then remove LH wastage from sprite
        Pull    R0                      ; (spLBit := 0)

        ASSERT  spHeight = spWidth +4
        ASSERT  spLBit   = spWidth +8
        ASSERT  spRBit   = spWidth +12
        ASSERT  spImage  = spWidth +16
        ASSERT  spTrans  = spWidth +20
        ASSERT  spMode   = spWidth +24

        ADD     R5, R2, #spWidth        ; R5=width:R6=height:R7=LBit(=0)
        LDMIA   R5, {R5-R11}            ; R8=RBit:R9=Image:R10=Trans:R11=Mode

        TEQ     R0, #SpriteReason_SwitchOutputToMask
        BNE     %FT23

        MOV     R9, R10                 ; point at mask instead of image
        MOVS    R0, R11, LSR #27
        BEQ     %FT23                   ; check for old format masks

        BL      GetMaskspWidth          ; adjust R5 and R8 to mask dimensions
        BIC     R11, R11, #&F8000000
        ORR     R11, R11, #&08000000    ; force it to a type 1 (1bpp) sprite
23
        ADD     R9, R9, R2              ; R9 -> sprite data or mask
20
        STR     R9, [WsPtr, #ScreenStart]
        STR     R11, [WsPtr, #ModeNo]           ; new mode number

        MOV     R10, R11
        BL      PushModeInfoAnyMonitor
        MOV     R11, R13

        TEQ     R2, #0                          ; if outputting to screen
        LDREQ   R5, [R11, #wkLineLength]        ; then load up values
        LDREQ   R6, [R11, #wkYWindLimit]        ; from mode table
        LDREQ   R7, [R11, #wkXWindLimit]
        LDREQ   R8, [R11, #wkScrRCol]
        LDREQ   R10, [R11, #wkScrBRow]
        BEQ     %FT30                           ; and skip more sprite stuff

        ADD     R5, R5, #1
        MOV     R5, R5, LSL #2                  ; R5 = width in bytes

        ADD     R7, R8, R5, LSL #3              ; R7 = LineLength*8 + spRBit
        SUB     R7, R7, #31                     ; R7=active area width in bits

        LDR     R8, [R11, #wkLog2BPC]
        MOV     R7, R7, LSR R8                  ; R7 = width in pixels
        MOV     R8, R7, LSR #3                  ; R8 = width in text columns
        SUB     R7, R7, #1                      ; R7 = max value of GWRCol

        SUB     R8, R8, #1                      ; R8 = max column number

        ADD     R10, R6, #1                     ; R10 = no. of pixel rows
        MOV     R10, R10, LSR #3                ; R10 = number of char rows
        SUB     R10, R10, #1                    ; R4 = maximum row number

30
        STR     R5, [WsPtr, #LineLength]
        STR     R6, [WsPtr, #YWindLimit]
        STR     R7, [WsPtr, #XWindLimit]
        STR     R8, [WsPtr, #ScrRCol]
        STR     R10, [WsPtr, #ScrBRow]

        LDR     R0,[R11, #wkNColour]
        STR     R0,[WsPtr, #NColour]            ; copy number of colours -1

        ADD     R11, R11, #wkmiddle
        MOV     R0, #wkmidend-wkmiddle  ; number of bytes to do
        ADD     R1, WsPtr, #YShftFactor ; first mode variable that we do

40
        LDR     R5, [R11], #4           ; copy byte from mode table
        STR     R5, [R1], #4            ; into word variable
        SUBS    R0, R0, #4              ; decrement count
        BNE     %BT40                   ; loop until finished

        ADD     R13, R13, #PushedInfoSize       ; junked stacked info

; now create other variables from simple ones

        LDR     R0, [WsPtr, #Log2BPP]
        LDR     R1, [WsPtr, #Log2BPC]
        LDR     R5, [WsPtr, #XEigFactor]
        LDR     R6, [WsPtr, #ModeFlags]
        TEQ     R2, #0
        ORRNE   R6, R6, #Flag_HardScrollDisabled ; if sprite then disable hard
        STR     R6, [WsPtr, #ModeFlags]

        ;if switching to a sprite, check for full palette 8bpp, and set modeflags and
        ;NColour to suit.

        TEQ     R2, #0
        BEQ     %FT65                   ; switching to a sprite ?

        CMP     R0, #3
        BNE     %FT65                   ; which is 8bpp ?

        ADD     R7, R2, #spImage        ; point R7 at the image/mask start pair
        LDMIA   R7, {R7, LR}            ; fetch them
        CMP     R7, LR                  ; which is lower
        MOVGT   R7, LR                  ; use the lowest
        SUB     R7, R7, #spPalette      ; get the size of the palette
        CMP     R7, #&800               ; full 8bpp palette ?
        BNE     %FT65

        ORR     R6, R6, #Flag_FullPalette
        STR     R6, [WsPtr, #ModeFlags] ; set the full palette flag

        MOV     R7, #255
        STR     R7, [WsPtr, #NColour]   ; and set the number of colours

65
        TST     R6, #Flag_DoubleVertical
        ADREQL  R7, WrchNbitTab         ; point to correct table
        ADRNEL  R7, WrchNbitDoubleTab
        LDR     R8, [R7, R1, LSL #2]    ; get offset to correct code
        ADD     R8, R8, R7              ; convert to absolute address
        STR     R8, [WsPtr, #WrchNbit]

        ADRL    R7, CursorNbitTab
        LDR     R8, [R7, R1, LSL #2]
        ADD     R8, R8, R7
        TST     R6, #Flag_Teletext
        ADRNEL  R8, CursorTeletext
        STR     R8, [WsPtr, #CursorNbit]

        TST     R6, #Flag_NonGraphic
        MOVEQ   R7, #32                 ; if graphic mode
        MOVEQ   R7, R7, LSR R1          ; then = (32 >> lbpc)-1
        SUBEQ   R7, R7, #1
        MOVNE   R7, #0                  ; else = 0 ;;; NOT REALLY SAFE BET ANYMORE!!!
        STR     R7, [WsPtr, #NPix]

        RSB     R7, R1, #5              ; XShftFactor = 5-log2bpc
        STR     R7, [WsPtr, #XShftFactor]

        LDR     R7, [WsPtr, #YEigFactor]
        SUBS    R7, R5, R7              ; XEigFactor-YEigFactor
        MOVLT   R7, #2                  ; X<Y => 2 (vert rect)
        MOVGT   R7, #1                  ; X>Y => 1 (horz rect)
                                        ; else X=Y => 0 (square)
        STR     R7, [WsPtr, #AspectRatio]

        MOV     R8, #1
        MOV     R7, R8, LSL R0          ; bpp = 1 << lbpp
        STR     R7, [WsPtr, #BitsPerPix]

        MOV     R7, R8, LSL R1          ; bpc = 1 << lbpc
        STR     R7, [WsPtr, #BytesPerChar]

      [ HiResTTX
        TST     R6, #Flag_Teletext      ; in teletext mode
        MOVNE   R7, R7, LSL #1          ; characters are 16 pixels
        STR     R7, [WsPtr, #CharWidth]
      ]

        TST     R6, #Flag_BBCGapMode    ; is it a BBC gap mode ?
        MOVNE   R7, #&55                ; yes, then use colour 1
        BNE     %FT70
        TEQ     R0, #2                  ; if (1<<2=4) bits per pixel
        MOVEQ   R7, #&77                ; then use colour 7 for cursor
        MOVNE   R7, #&FF                ; else use colour 15
      [ TTX256
        TST     R6, #Flag_Teletext      ; unless it's teletext
        MOVNE   R7, #&07                ; in which case still use colour 7
      ]
70
        ORR     R7, R7, R7, LSL #8      ; fill out to whole word
        ORR     R7, R7, R7, LSL #16
        STR     R7, [WsPtr, #CursorFill]

        TST     R6, #Flag_DoubleVertical
        MOVEQ   R7, #8                  ; if single vertical then 8 pixels
        MOVNE   R7, #16                 ; if double vertical then 16 pixels
        STR     R7, [WsPtr, #TCharSizeY]
        TST     R6, #Flag_GapMode
        ADDNE   R7, R7, R7, LSR #2      ; make 10 or 20 if gap mode
        STR     R7, [WsPtr, #RowMult]
        STR     R7, [WsPtr, #TCharSpaceY]
        MOV     R8, #8
      [ HiResTTX
        TST     R6, #Flag_Teletext
        MOVNE   R8, #16
      ]
        STR     R8, [WsPtr, #TCharSizeX]
        STR     R8, [WsPtr, #TCharSpaceX]

        LDR     R8, [WsPtr, #LineLength]
        MUL     R7, R8, R7
        STR     R7, [WsPtr, #RowLength]

; finished doing other variables

        SWI     XColourTrans_InvalidateCache    ; let ColourTrans know we've changed mode
                                                ; so that colours get set up correctly

        TEQ     R4, #0                  ; initialising from a save area ?
        BEQ     %FT80                   ; no, then set to defaults

        BL      UnpackVars
        BL      AddressCursors
        BL      ValidateVars
        BL      PlainBit
        BL      SetColour
        LDR     R6, [WsPtr, #CursorFlags]
        ORR     R6, R6, #TEUpdate       ; TextExpand needs updating
        STR     R6, [WsPtr, #CursorFlags]
        B       %FT90
80

; *****Change made by DJS
; Original code was:
;        MOV     R0, #0
;        STR     R0, [WsPtr, #ECFShift]
;        STR     R0, [WsPtr, #ECFYOffset]
; This needed to be changed to make the bottom left of the screen (rather
; than the top left) be the default ECF origin.
        LDR     R0, [WsPtr, #YWindLimit]
        ADD     R0, R0, #1
        AND     R0, R0, #7
        STR     R0, [WsPtr, #ECFYOffset]
        MOV     R0, #0
        STR     R0, [WsPtr, #ECFShift]
; *****End of change made by DJS

        STR     R0, [WsPtr, #ClipBoxEnable]
        STRB    R0, [R0, #OsbyteVars + :INDEX: VDUqueueItems]

        MOV     R0, #8
        STR     R0, [WsPtr, #GCharSizeX]        ; chars are 8x8 by default
        STR     R0, [WsPtr, #GCharSizeY]
        STR     R0, [WsPtr, #GCharSpaceX]       ; and with 8x8 spacing
        STR     R0, [WsPtr, #GCharSpaceY]

        LDR     R1, [WsPtr, #ModeFlags]

        LDR     R0, [WsPtr, #CursorFlags]
        BIC     R0, R0, #(ActualState :OR: Vdu5Bit)
        BIC     R0, R0, #(CursorsSplit :OR: PageMode :OR: TeletextMode :OR: ClipBoxEnableBit)
        TST     R1, #Flag_Teletext              ; is it teletext ?
        ORRNE   R0, R0, #TeletextMode           ; yes, then set bit
        STR     R0, [WsPtr, #CursorFlags]
        BLNE    TeletextInit                    ; initialise TTX if appropriate

        BL      InitCursor                      ; initialise cursor after
                                                ; cursorflags
        BL      PlainBit                ; also sets up RAMMaskTb
        BL      DefaultColours          ; N.B. SetColour is called by both
        BL      DefaultEcfPattern       ; of these.
        BL      DefaultLineStyle
        BL      DefaultWindows
        BL      Home
90
 [ STB		; Change made by TMD 29-May-96, to stop cursor flashing before interlace module has
		; fixed up LineLength on Service_SwitchingOutputToSprite
        MOV     R1, #Service_SwitchingOutputToSprite    ; issue the service *first*
        ADD     R2, WsPtr, #VduOutputCurrentState
        LDMIA   R2, {R2-R5}                             ; load the registers that were in R0-R3 on entry
        IssueService
        BL      PostWrchCursor				; it should now be safe to restore the cursor
 |
        BL      PostWrchCursor

        MOV     R1, #Service_SwitchingOutputToSprite    ; call Ran's service
        ADD     R2, WsPtr, #VduOutputCurrentState
        LDMIA   R2, {R2-R5}                             ; load the registers that were in R0-R3 on entry
        IssueService
 ]

        Pull    R14
        RETURNVC

InvalidSaveArea
        ADRL    R0, SpriteErr_InvalidSaveArea
      [ International
        Push    "lr"
        BL      TranslateError
        Pull    "lr"
      ]
        STR     R0, [WsPtr, #RetnReg0]
        RETURNVS

VOTS    =       "VOTS"


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

; Specially saved items

                        ^       0
InitFlag                #       4       ; 0 => uninit, "VOTS" => init
SavedSpoolFileH         #       1       ; an OSBYTE variable
SavedWrchDest           #       1       ; --------""--------
SavedVDUqueueItems      #       1       ; --------""--------
                        #       1       ; padding to word align it
SavedDataOffset         #       0       ; start of compressed data

        GBLA    FirstOffset
        GBLA    NextOffset
        GBLA    CompressedSize

        MACRO
        CompStart
FirstOffset SETA -1
NextOffset SETA -1
CompressedSize SETA 0
        MEND

        MACRO
        Compress $v0, $v1, $v2, $v3, $v4, $v5, $v6, $v7
        [ "$v0"<>""
        Compo $v0
        ]
        [ "$v1"<>""
        Compo $v1
        ]
        [ "$v2"<>""
        Compo $v2
        ]
        [ "$v3"<>""
        Compo $v3
        ]
        [ "$v4"<>""
        Compo $v4
        ]
        [ "$v5"<>""
        Compo $v5
        ]
        [ "$v6"<>""
        Compo $v6
        ]
        [ "$v7"<>""
        Compo $v7
        ]
        MEND

        MACRO
        Compo   $var
        [ FirstOffset <> -1
         [ $var = NextOffset
NextOffset SETA ($var)+4
         |
         DCW FirstOffset
         DCW NextOffset
CompressedSize SETA CompressedSize + (NextOffset-FirstOffset)
FirstOffset SETA $var
NextOffset SETA ($var)+4
         ]
        |
FirstOffset SETA $var
NextOffset SETA ($var)+4
        ]
        MEND

        MACRO
        CompMult $start, $size
        [ FirstOffset <> -1
         [ $start = NextOffset
NextOffset SETA $start + $size
         |
         DCW FirstOffset
         DCW NextOffset
CompressedSize SETA CompressedSize + (NextOffset-FirstOffset)
FirstOffset SETA $start
NextOffset SETA $start + $size
         ]
        |
FirstOffset SETA $start
NextOffset SETA $start + $size
        ]
        MEND

        MACRO
        CompRange $start, $end
        CompMult $start, ($end+4-$start)
        MEND

        MACRO
        CompEnd
        [ FirstOffset <> -1
        DCW FirstOffset
        DCW NextOffset
CompressedSize SETA CompressedSize + (NextOffset-FirstOffset)
        ]
        &       -1
        MEND

CompressionTable
        CompStart

;        CompMult  FgEcf, 8*4        ; recreated from GCOLs + ecfs by
;        CompMult  BgEcf, 8*4        ; call to SetColour

        Compress  GPLFMD, GPLBMD, GFCOL, GBCOL, GWLCol, GWBRow, GWRCol, GWTRow
        CompRange qqqPad, JVec

;        Compress  ScreenStart ; worked out from sprite address each time

        Compress  TWLCol, TWBRow, TWRCol, TWTRow
        CompRange OrgX, NewPtY
        Compress  TForeCol, TBackCol, CursorX, CursorY

;       Compress  CursorAddr, InputCursorAddr - computed from (Input)CursorX,Y

        Compress  InputCursorX, InputCursorY

        Compress  VduStatus
        Compress  CursorDesiredState, CursorStartOffset, CursorEndOffset
        Compress  CursorCounter, CursorSpeed, Reg10Copy

;       Compress  CursorFill, CursorNbit - computed from mode variables

;       Compress  DriverBankAddr - refers to screen always

        CompRange Ecf1, Ecf4+4
        CompMult  DotLineStyle, 8

;       Compress  ModeNo - stored in sprite itself

        Compress  TFTint, TBTint, GFTint, GBTint

;       Compress  TotalScreenSize, MaxMode, ScreenEndAddr - refer to screen always

        Compress  CursorFlags, CursorStack
        Compress  ECFShift, ECFYOffset

        Compress  GCharSizeX, GCharSizeY, GCharSpaceX, GCharSpaceY
;       Compress  TCharSizeX, TCharSizeY        ; recomputed from mode number
;       Compress  TCharSpaceX, TCharSpaceY      ; each time

;       CompMult  FgEcfOraEor, 64      ; recreated from GCOLs and ecfs
;       CompMult  BgEcfOraEor, 64      ; by call to SetColour
;       CompMult  BgEcfStore, 64       ;

        Compress  LineDotCnt, LineDotPatLSW, LineDotPatMSW, DotLineLength
        Compress  BBCcompatibleECFs

;       Compress  WrchNbit - computed from mode number

        CompRange ClipBoxEnable, ClipBoxTRow

        CompMult  FgPattern, 4*8
        CompMult  BgPattern, 4*8

        Compress  TextFgColour
        Compress  TextBgColour

        CompEnd
CompressionTableEnd
MainSize * CompressedSize + SavedDataOffset

        ASSERT  MainSize <= SaveAreaSize
        ! 0, "Space free in VDU save area = ":CC::STR:(SaveAreaSize-MainSize)

        [ {FALSE}                       ; don't allow teletext mode for now
TTXCompressionTable
        CompStart
        CompMult  TTXDoubleCounts, 28   ; (25 rounded up to a word)
        CompMult  TTXMap, 41*25*4
        CompEnd
TTXCompressionTableEnd
TTXSize * CompressedSize
        ]


; *****************************************************************************
;
;       PackVars - Pack variables into save area
;

PackVars ROUT
        CLC                             ; clear carry - indicate packing
PackOrUnpack
        Push    "R0-R4,R14"
        LDR     R0, [WsPtr, #VduSaveAreaPtr]
        TEQ     R0, #0
        Pull    "R0-R4,PC", EQ          ; ptr=0 => no area

        TEQ     R0, #1
        ADDEQ   R0, WsPtr, #VduSaveArea ; ptr=1 => use MOS's save area

        BL      DoSpecialVars                   ; process special vars

        ADD     R0, R0, #SavedDataOffset        ; move on to compressed data
        ADR     R1, CompressionTable
10
        LDR     R2, [R1], #4
        MVNS    R3, R2                  ; set Z if it was -1 (end of table)
        Pull    "R0-R4,PC", EQ          ; (preserves C)

        ADD     R3, WsPtr, R2, LSR #16          ; R3 = end pointer
        MOV     R2, R2, LSL #16
        ADD     R2, WsPtr, R2, LSR #16          ; R2 = start pointer
20
        LDRCC   R4, [R2], #4                    ; load a word from vars
        LDRCS   R4, [R0], #4                    ; or from save area
        STRCC   R4, [R0], #4                    ; store into save area
        STRCS   R4, [R2], #4                    ; or into vars
        TEQ     R2, R3                          ; end of this block ?
        BNE     %BT20                           ; [no, so loop]
        B       %BT10                           ; go back for another block

; *****************************************************************************
;
;       UnpackVars - Unpack variables from save area
;

UnpackVars ROUT
        SEC                             ; set carry - indicate unpacking
        B       PackOrUnpack

; *****************************************************************************
;
;       DoSpecialVars - Pack/unpack special vars: CursorAddr, InputCursorAddr,
;        (stored relative to ScreenStart); SpoolFileH, WrchDest, VDUqueueItems
;
; in:   R0 -> save area
;
; out:  R0 preserved
;       R1-R2 corrupted
;       Flags preserved
;

DoSpecialVars ROUT
        BYTEWS  R1
        BCS     %FT10
        LDRB    R2, [R1, #:INDEX: SpoolFileH]
        STRB    R2, [R0, #SavedSpoolFileH]
        LDRB    R2, [R1, #:INDEX: WrchDest]
        STRB    R2, [R0, #SavedWrchDest]
        LDRB    R2, [R1, #:INDEX: VDUqueueItems]
        STRB    R2, [R0, #SavedVDUqueueItems]
        LDR     R1, VOTS                ; initialised save area identifier
        STR     R1, [R0, #InitFlag]
        MOV     PC, R14

; unpack special vars (R1 -> ByteWS)

10
        LDRB    R2, [R0, #SavedSpoolFileH]
        STRB    R2, [R1, #:INDEX: SpoolFileH]
        LDRB    R2, [R0, #SavedWrchDest]
        STRB    R2, [R1, #:INDEX: WrchDest]
        LDRB    R2, [R0, #SavedVDUqueueItems]
        STRB    R2, [R1, #:INDEX: VDUqueueItems]
        MOV     PC, R14

; *****************************************************************************
;
;       ValidateVars - Validate unpacked variables (windows, cursor posns)
;

ValidateVars ROUT
        Push    R14
        ASSERT  ScrBRow = ScrRCol + 4
        ADD     R4, WsPtr, #ScrRCol
        LDMIA   R4, {R4, R5}            ; R4 = ScrRCol; R5 = ScrBRow

        ADD     R6, WsPtr, #TWLCol      ; R0 = TWLCol; R1 = TWBRow
        LDMIA   R6, {R0-R3}             ; R2 = TWRCol; R3 = TWTRow

        MOV     R7, #0
        MOV     R8, R5
        MOV     R9, R4
        MOV     R10, #0
        STMIA   R6, {R7-R10}            ; set up default window

        BL      FSRegs                  ; and attempt to define text window

        ASSERT  YWindLimit = XWindLimit + 4
        ADD     R0, WsPtr, #XWindLimit
        LDMIA   R0, {R2, R3}            ; R2 = XWindLimit; R3 = YWindLimit

        ADD     R8, WsPtr, #GWLCol      ; R4 = GWLCol; R5 = GWBRow
        LDMIA   R8, {R4-R7}             ; R6 = GWRCol; R7 = GWTRow

        CMP     R6, R2                  ; if GWRCol > XWindLimit
        CMPLS   R7, R3                  ; or GWTRow > YWindLimit

        MOVHI   R0, #0
        MOVHI   R1, #0
        STMHIIA R8, {R0-R3}             ; then set default graphics window

        Pull    PC

        END