vdugrafe 34.5 KB
Newer Older
Neil Turton's avatar
Neil Turton committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
; 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.VduGrafE
;
; ARTHUR OPERATING SYSTEM - Vdu Drivers
; =======================
;
; Vdu driver code - Line Fill L & R and Flood Fill
;
; Author R C Manby
; Date   17.10.86
;

; *****************************************************************************
;
; FillLRnonBg
; ===========
;
; On entry, R0 (X), R1 (Y) hold point to fill from
;
; On exit, R0..R11 corrupt
;

FillLRtoFg
        ADD     R2, WsPtr, #FgEcf
        MOV     R3, #0
        B       FillLRnonBg10           ; Fill L <-> R

FillLRnonBg
        ADD     R2, WsPtr, #BgEcf
        MOV     R3, #&80000000
FillLRnonBg10
        SaveRetAdr
        BL      FillAlong2
        SUBCS   R1, R1, #1              ; indicate nothing filled by Y-=1
        STR     R0, [WsPtr, #GCsIX]     ; left X
        STR     R1, [WsPtr, #GCsIY]     ; Y
        Return  CS                      ; external new pt hasn't changed
        STR     R2, [WsPtr, #NewPtX]    ; right X
        MOV     R0, R2
        BL      IEGB                    ; update external version of new NewPt
        Return                          ; then things get shuffled

; *****************************************************************************
;
; FillLRtoBg    (Really only fill right!)
; ==========
;
; On entry, R0 (X), R1 (Y) hold point to fill from
;
; On exit, R0..R11 corrupt
;

FillLRnonFg
        ADD     R2, WsPtr, #FgEcf
        MOV     R3, #&80000000
        B       FillLRtoBg10            ; Fill -> R

FillLRtoBg
        ADD     R2, WsPtr, #BgEcf
        MOV     R3, #&0
FillLRtoBg10
        SaveRetAdr
        STR     R0, [WsPtr, #GCsIX]     ; "left hand point" = given point
        STR     R1, [WsPtr, #GCsIY]
        BL      GenLineFillParm         ; if C=1 (nothing can be plotted)
        SUBCS   R0, R0, #1              ; then NewPtX-=1 ie NewPtX < GCsIX
        BLCC    FillLineRightRegs       ; else fill right
        STR     R0, [WsPtr, #NewPtX]    ; Convert NewPt(X,Y) (internal) into
        LDR     R1, [WsPtr, #NewPtY]    ; GCs(X,Y) (external)
        BL      IEGB
        Return                          ; On returning, cursors are shuffled
                                        ; which updates GCsI(X,Y)

; *****************************************************************************
;
; GenLineFillParm
; ===============
;
; On entry, R0 (X), R1 (Y) hold point to fill from
;           R2 points to delimiting colour (FgEcf/BgEcf)
;           R3 fill flag, 0/&80000000 for fill to/to-non
;
; On exit, Carry=0, valid parameter setup, R0-R10 contain copy of control block
;          Carry=1, point outside window, R0 preserved, R1-R10 undefined
;
;  Format of control block
;
;  R0  - StartX
;  R1  - DelimitColour
;  R2  - FillFlag
;  R3  - ScreenAdr
;  R4  - PixelMsk
;  R5  - zgora
;  R6  - zgeor
;  R7  - GWLCol
;  R8  - GWRCol
;  R9  - BytesPerChar
;  R10 - NPix
;
GenLineFillParm
        WINDow  R0,R1, R7,R8,R9,R10     ; Window(R0,R1) using R7-R10
                                        ;  gives GE if in window
Kevin Bracey's avatar
Kevin Bracey committed
116 117 118 119
        BGE     %FT01
        SEC                             ; If point outside window
        MOV     PC, Link                ;  then quit with carry set
01
Neil Turton's avatar
Neil Turton committed
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
        Push    "R2,R3,R7,R9,Link"      ; Save colourptr, fillflag
                                        ; GWLCol, GWRCol
        BL      ScreenAddr              ; Returns R2 = Addr, R3 = Mask

        LDR     R9, [WsPtr, #YWindLimit]
        SUB     R9, R9, R1              ; Flip Ycoord
        AND     R9, R9, #7              ; Line within ecf
        LDR     R5, [WsPtr, #GColAdr]   ; Base address of ecf pattern
        ADD     R5, R5, R9, LSL #3
        LDMIA   R5, {R5, R6}            ; Get zgora,zgeor

        MOV     R4, R3
        MOV     R3, R2

        Pull    "R1,R2,R7,R8,Link"      ; restore other registers
        LDR     R1, [R1, R9, LSL #2]    ; load delimiting colour
        LDR     R9, [WsPtr, #BytesPerChar]
        LDR     R10, [WsPtr, #NPix]

        ADD     R11, WsPtr, #LineFillBlk ; now save completed control block
        STMIA   R11, {R0-R10}

        LDR     R11, [R3]               ; load screen
        EOR     R11, R11, R1            ; screen EOR boundary
        TST     R11, R4                 ; just look at this pixel
Kevin Bracey's avatar
Kevin Bracey committed
145
        ; Blimey.
146
        MRS     R7, CPSR
Kevin Bracey's avatar
Kevin Bracey committed
147 148 149 150
        TEQ     R2, R7, LSL #1          ; N := (Z EOR R2) ie invert test if
                                        ; stopping on non-colour
        BICPL   R7, R7, #C_bit          ; point can be filled, exit CC
        ORRMI   R7, R7, #C_bit          ; point cannot be filled, exit CS
151
        MSR     CPSR_f, R7
Kevin Bracey's avatar
Kevin Bracey committed
152
        MOV     PC, Link
Neil Turton's avatar
Neil Turton committed
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179

; *****************************************************************************
;
; FillLineRight - Fill right from point upto delimiting colour
; =============    or graphics window
;
;
;  R0  - RightLimitX
;  R1  - LimitColour
;  R2  - FillFlag
;  R3  - ScreenAdr
;  R4  - PixelMsk
;  R5  - zgora
;  R6  - zgeor
;  R7  - GWLCol /BPC/NPIX
;  R8  - GWRCol
;  R9  -          ScreenWord
;  R10 - NPix
;  R11 -          MultPixMsk     / temp
;
; out:  PSR must be preserved
;
FillLineRight ROUT
        ADD     R11, WsPtr, #LineFillBlk
        LDMIA   R11, {R0-R10}
FillLineRightRegs
        Push    R14
180
        MRS     R14, CPSR
Kevin Bracey's avatar
Kevin Bracey committed
181
        Push    "WsPtr, R14"            ; we also need R12 for a temp
Neil Turton's avatar
Neil Turton committed
182 183 184 185 186 187 188 189
        RSB     R7, R9, #32             ; shift factor for next pixel position
        SUB     R0, R8, R0
10
        MOV     R11, #0                 ; clear partial word mask
        LDR     R9, [R3]                ; screen word EOR delimit colour
        EOR     R14, R9, R1
30
        TST     R14, R4                 ; test pixel position for delimiting
190
        MRS     WsPtr, CPSR
Kevin Bracey's avatar
Kevin Bracey committed
191
        TEQ     R2, WsPtr, LSL #1       ; invert condition if necessary
Neil Turton's avatar
Neil Turton committed
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237

        ORRPL   R11, R11, R4            ; add pixel to partial word mask
        SUBPLS  R0, R0, #1              ; "increment" X; if on edge of window
        BMI     %FT40                   ; then give up and plot partial word

        TEQ     R4, #0                  ; test for end of word
        MOV     R4, R4, ROR R7          ; shift pixel mask left
        BPL     %BT30

        AND     R14, R5, R11            ; fill partial word, using pixel mask
        AND     R11, R6, R11            ; in R11
        ORR     R9, R9, R14
        EOR     R9, R9, R11
        STR     R9, [R3], #4

        CMP     R2, #2                  ; CC => filling until pixel=target
        BCC     %BT10                   ; so do it slowly (goto next word)

        RSB     R0, R0, #0              ; make X in range GWLCol-GWRCol .. 0
        ADDS    R0, R0, R10             ; move R0 to end of word
        BGT     %FT36                   ; outside window, continue slowly

        ORR     R14, R1, R5             ; word to store if going fast
        EOR     R14, R14, R6

32
        LDR     R9, [R3]                ; screen word
        CMP     R9, R1                  ; EOR target colour (CS if EQ)
        BNE     %FT36
        STR     R14, [R3], #4
        ADCS    R0, R0, R10             ; C=1, so add NPix+1
        BLE     %BT32
36
        SUBS    R0, R10, R0             ; R0 back to start of word and negate
        BGE     %BT10                   ; if still inside, continue slowly
        B       %FT50

40
        AND     R14, R5, R11            ; fill partial word, using pixel mask
        AND     R11, R6, R11            ; in R11
        ORR     R9, R9, R14
        EOR     R9, R9, R11
        STR     R9, [R3]
50
        SUB     R0, R8, R0              ; make back into normal coord again
        SUB     R0, R0, #1              ; correct end point
Kevin Bracey's avatar
Kevin Bracey committed
238
        Pull    "WsPtr, R14"
239
        MSR     CPSR_f, R14
Kevin Bracey's avatar
Kevin Bracey committed
240
        Pull    PC
Neil Turton's avatar
Neil Turton committed
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269

; *****************************************************************************
;
; FillLineLeft - Fill left from point upto delimiting colour
; ============    or graphics window
;
;                N.B. Starts one pixel left of point given, since
;                      FillLineRight will have already plotted it.
;
;  R0  - LeftLimitX
;  R1  - LimitColour
;  R2  - FillFlag
;  R3  - ScreenAdr
;  R4  - PixelMsk
;  R5  - zgora
;  R6  - zgeor
;  R7  - GWLCol                 } Slightly different from FillLineRight
;  R8  - GWRCol /BPC/NPIX       }
;  R9  -          ScreenWord
;  R10 -          LimitEorScreen / temp
;  R11 -          MultPixMsk     / temp
;
;
;
FillLineLeft ROUT
        ADD     R11, WsPtr, #LineFillBlk
        LDMIA   R11, {R0-R10}
FillLineLeftRegs
        Push    R14
270
        MRS     R14, CPSR
Kevin Bracey's avatar
Kevin Bracey committed
271
        Push    "WsPtr, R14"            ; also need WsPtr for a temp
Neil Turton's avatar
Neil Turton committed
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
        MOV     R8, R9                  ; shift factor for next pixel position

        SUB     R0, R0, R7
        LDR     R9, [R3]                ; screen word EOR delimit colour
        EOR     R14, R9, R1
        MOVS    R11, #0                 ; clear partial word mask (and set PL)
        B       %FT31

10
        MOV     R11, #0                 ; clear partial word mask
        LDR     R9, [R3]                ; screen word EOR delimit colour
        EOR     R14, R9, R1

30
        TST     R14, R4                 ; test pixel position for delimiting
287
        MRS     WsPtr, CPSR
Kevin Bracey's avatar
Kevin Bracey committed
288
        TEQ     R2, WsPtr, LSL #1       ; invert condition if appropriate
Neil Turton's avatar
Neil Turton committed
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
        ORRPL   R11, R11, R4            ; add pixel to partial word mask
31
        SUBPLS  R0, R0, #1              ; decrement X; if on edge of window
        BMI     %FT40                   ; then give up and plot partial word

        MOVS    R4, R4, ROR R8          ; test for end of word
        BPL     %BT30                   ; loop until mask exhausted

        AND     R14, R5, R11            ; fill partial word, using pixel mask
        AND     R11, R6, R11            ; in R11
        ORR     R9, R9, R14
        EOR     R9, R9, R11
        STR     R9, [R3], #-4

        CMP     R2, #2                  ; CC => filling until pixel=target
        BCC     %BT10                   ; so do it slowly (goto next word)

        SUBS    R0, R0, R10             ; move R0 to beginning of word
        BCC     %FT36                   ; if outside window continue slowly
        ADD     R10, R10, #1
        ORR     R14, R1, R5             ; compute target word
        EOR     R14, R14, R6
32
        LDR     R9, [R3]                ; screen word
        CMP     R9, R1
        BNE     %FT35                   ; NZ => terminate
        STR     R14, [R3], #-4
        SUBS    R0, R0, R10
        BCS     %BT32
35
        SUB     R10, R10, #1
36
        ADDS    R0, R0, R10             ; point R0 back to end of word
        BGE     %BT10                   ; if still inside, continue but slowly
        B       %FT50

40
        AND     R14, R5, R11            ; fill partial word, using pixel mask
        AND     R11, R6, R11            ; in R11
        ORR     R9, R9, R14
        EOR     R9, R9, R11
        STR     R9, [R3]
50
        ADD     R0, R0, R7              ; add GWLCol back on
        ADD     R0, R0, #1              ; Correct endpoint value
Kevin Bracey's avatar
Kevin Bracey committed
334
        Pull    "WsPtr, R14"
335
        MSR     CPSR_f, R14
Kevin Bracey's avatar
Kevin Bracey committed
336
        Pull    PC
Neil Turton's avatar
Neil Turton committed
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597

; *****************************************************************************
;
; FillAlong - Fill left and right from point given
; =========
;
; On entry, R0 (X), R1(Y) hold point to fill from
;
; On exit,  R0 (X) End of scan left
;           R1 (Y) Preserved
;           R2 (X) End of scan right
;
;           Carry set = no fill performed ie outside window or already filled
;           Carry clear = fill occured
;
        ASSERT  FldBoundaryFlag = FldBoundaryCol +4

FillAlong
        ADD     R2, WsPtr, #FldBoundaryCol
        LDMIA   R2, {R2,R3}             ; R2 = colour, R3 = flag
FillAlong2                              ; entry point when R2, R3 loaded
        Push    "R1, R14"
        BL      GenLineFillParm         ; On exit C=1 if nothing can be plotted
        BLCC    FillLineRightRegs
        Push    R0                      ; New RightX
        BLCC    FillLineLeft
        Pull    R2                      ; Recover RightX
        Pull    "R1, PC"                ; Recover Y, C=1 <=> fill occured

; *****************************************************************************
;
; FloodFill
; =========
;
; On entry, R0 (X), R1 (Y) hold point to flood from
;           R2 Delimit colour, pointer to FgEcf/BgEcf
;           R3 0/&80000000 for flood until/over
;
        ASSERT  FldBoundaryFlag = FldBoundaryCol +4
        ASSERT  FldY = FldLeftXLimit +4
        ASSERT  FldRightXLimit = FldLeftXLimit +8

FloodToFg
        ADD     R2, WsPtr, #FgEcf       ; delimit colour
        MOV     R3, #0                  ; flood until
        B       FloodFill

FloodNonBg
        ADD     R2, WsPtr, #BgEcf       ; delimit colour
        MOV     R3, #&80000000          ; flood over
FloodFill ROUT
        Push    R14
        STR     R13, [WsPtr, #FldStackLevel]    ; save stack level !

        ADD     R14, WsPtr, #FldBoundaryCol
        LDR     R4, [WsPtr, #YWindLimit]
        STMIA   R14, {R2-R4}            ; store colour, flag, YWindLimit

        [ med_00001_userma

        ; the idea here is to try to use between 48k and 128k of rma instead of 16k of
        ; scratchspace. if there's less than 48k of rma in the first place we go back to
        ; scratchspace. if there's 128k or more we claim the 128k and proceed. For values
        ; between 48k and 128k we first grow the rma by 128k-largest_free_space. If this
        ; results in a lump of 128k now being free we claim it and proceed. If the largest
        ; free space hasn't grown to 128k we then claim the additional balance needed to
        ; have 128k available. Should either grow fail, we just use whatever (over 48k)
        ; was available

        ;R3-R7 spare at presenet
        Push    "R0-R2"
        MOV     R0, #0
        STR     R0, [WsPtr, #flood_cda_rma]                     ; set amount to change dyn. area by
        MOV     R0, #ModHandReason_RMADesc
        SWI     XOS_Module                                      ; get the largest free space in rma
        BVC     %FT91                                           ; if that failed, use scratchspace

use_scratchspace
        LDR     R3, =FldQueueStart                              ; head ptr (== scratchspace)
        MOV     R4, R3                                          ; tail ptr
        ADD     R5, R3, #FldQueueSize                           ; end ptr (== scratchspace size)
        MOV     R6, R3                                          ; start ptr
        B       %FT92
91
        CMP     R2, #smallest_rma_size                          ; compare against small threshold
        BLT     use_scratchspace                                ; not enough free - use scratchspace
        CMP     R2, #largest_rma_size                           ; compare against high threshold
        BHS     %FT96                                           ; lots free - use largest ceiling value

        RSB     R1, R2, #largest_rma_size                       ; work out how much more to claim
        MOV     R0, #1                                          ; rma
        SWI     XOS_ChangeDynamicArea
        STRVC   R1, [WsPtr, #flood_cda_rma]                     ; save the amount we grew the rma
        BVS     %FT94                                           ; if it failed, use the minimum<size<maximum lump

        MOV     R0, #ModHandReason_RMADesc                      ; reread the largest free space to see if
        SWI     XOS_Module                                      ; it has risen to maximum
        BVS     use_scratchspace
        CMP     R2, #largest_rma_size
        BHS     %FT96                                           ; it has, so claim the maximum

        LDR     R1, [WsPtr, #flood_cda_rma]                     ; the free space didn't grow to maximum, so the
        RSB     R1, R1, #largest_rma_size                       ; largest space wasn't at the end. Do a second
        MOV     R0, #1                                          ; grow of the rma to make the maximum
        SWI     XOS_ChangeDynamicArea
        LDRVC   R0, [WsPtr, #flood_cda_rma]                     ; if it succeeded, update the amount that we
        ADDVC   R0, R0, R1                                      ; need to shrink the rma by
        STRVC   R0, [WsPtr, #flood_cda_rma]
                                                                ; and fall into the claim largest space routine
94
        MOV     R0, #ModHandReason_RMADesc
        SWI     XOS_Module
        BVS     use_scratchspace                                ; find the largest lump now available
        CMP     R2, #largest_rma_size
96
        MOVGT   R3, #largest_rma_size
        MOVLE   R3, R2                                          ; cap it at the maximum size we want
        MOV     R0, #ModHandReason_Claim                        ; try to claim it
        SWI     XOS_Module
        BVS     use_scratchspace

        ADD     R5, R2, R3                                      ; do it in a slightly different order so
        MOV     R3, R2                                          ; we can use the R2 and R3 back from the claim
        MOV     R4, R3                                          ; (R2=where, R3=size)
        MOV     R6, R3

92
        ADD     R7, WsPtr, #QueuePtrs
        STMIA   R7, {R3, R4, R5, R6}    ; initialise queue
        Pull    "R0-R2"
        |
        LDR     R3, =FldQueueStart      ; head ptr
        MOV     R4, R3                  ; tail ptr
        ADD     R5, R3, #FldQueueSize   ; end ptr
        MOV     R6, R3                  ; start ptr
        ADD     R7, WsPtr, #QueuePtrs
        STMIA   R7, {R3, R4, R5, R6}    ; initialise queue
        ]

        BL      FillAlong               ; try filling L&R from given point
        Pull    PC, CS                  ; quit if can't be filled

        MOV     R3, #3                  ; bit0 => fill up, bit1 => fill down
10
        ADD     R14, WsPtr, #FldLeftXLimit
        STMIA   R14, {R0-R2}            ; store leftX, Y, rightX

        TST     R3, #1
        BEQ     %FT20

        LDR     R10, [WsPtr, #GWTRow]   ; if below Top of window
        CMP     R10, R1
        BLE     %FT20

        ADD     R4, WsPtr, #FldBoundaryCol      ; R4=target colour ptr,R5=flag,
        LDMIA   R4, {R4,R5,R6}                  ; R6=YWindLimit

        ORR     R5, R5, #FillingUpBit   ; fill line above
        Push    R3
        BL      CheckAlong              ; (will bomb out if queue explodes)
        Pull    R3

        ADD     R14, WsPtr, #FldLeftXLimit
        LDMIA   R14, {R0,R1}            ; reload leftX, Y
20
        TST     R3, #2
        BEQ     %FT30

        LDR     R10, [WsPtr, #GWBRow]   ; if above bottom of window
        CMP     R1, R10
        BLE     %FT30

        ADD     R4, WsPtr, #FldBoundaryCol      ; R4=target colour ptr,R5=flag,
        LDMIA   R4, {R4,R5,R6}                  ; R6=YWindLimit

;        BIC     R5, R5, #FillingUpBit  ; fill line below
        BL      CheckAlong              ; (will bomb out if queue explodes)
30
        ADD     R11, WsPtr, #QueuePtrs  ; unqueue one item
        LDMIA   R11, {R3,R4,R5}         ; head,tail,limit
        TEQ     R3, R4                  ; if queue empty
        [ med_00001_userma
        BLEQ    release_memory
        ]
        Pull    PC, EQ                  ; then exit

        [ med_00001_twowords
        LDR     R1, [R3], #4
        MOV     R0, R1, LSR #16         ; LeftX
        MOV     R2, R1
        EOR     R2, R2, R0, LSL #16     ; RightX (with LeftX EORed out)
        LDR     R1, [R3], #4            ; Recover Y
        |
        LDR     R1, [R3], #4            ; then load word
        MOV     R2, R1, LSR #21         ; Recover RightX
        EOR     R1, R1, R2, LSL #21     ; clear those bits out
        MOV     R0, R1, LSR #10         ; Recover LeftX
        EOR     R1, R1, R0, LSL #10     ; Recover Y
        ]
        TEQ     R3, R5                  ; if at limit
        LDREQ   R3, [R11, #12]          ; then reload with start
        STR     R3, [R11, #0]           ; store head ptr back

        MOV     R3, #2                  ; indicate fill down
        CMP     R2, R0                  ; if right < left then subtract 1 off
                                        ; larger and swap
        SBCCC   R0, R0, R2              ; R0 := large-small-1
        ADDCC   R2, R0, R2              ; R2 := (large-small-1)+small = large-1
        SUBCC   R0, R2, R0              ; R0 := (large-1)-(large-small-1)=small
        MOVCC   R3, #1                  ; and indicate fill up
        B       %BT10

; *****************************************************************************
;
; CheckAlong - Fill and skip background between LeftXLimit & RightXLimit
; ==========
;
; On entry, R0 LeftXLimit
;           R1 Y
;           R4 target colour
;           R5 fill flag
;           R6 YWindLimit
;
; Exits using R14 if normal termination
; Exits using FldStackLevel if queue full
;

FillingUpBit * 1

        ASSERT  FldBoundaryFlag = FldBoundaryCol +4
        ASSERT  FldYWindLimit = FldBoundaryCol +8

        ASSERT  FldY = FldLeftXLimit +4
        ASSERT  FldRightXLimit = FldLeftXLimit +8

CheckAlong ROUT
        Push    R14

        TST     R5, #FillingUpBit               ; if going up
        ADDNE   R1, R1, #1                      ; then increment Y
        SUBEQ   R1, R1, #1                      ; else decrement Y

        BL      ScreenAddr                      ; R2=screen addr, R3=mask

        SUB     R6, R6, R1                      ; flip Y
        AND     R6, R6, #7                      ; ecf offset
        LDR     R4, [R4, R6, LSL #2]            ; R4=target colour
        LDR     R7, [WsPtr, #GColAdr]           ; base address of plot ecf
        ADD     R7, R7, R6, LSL #3              ; R7 -> zgora, zgeor
        LDMIA   R7, {R10,R11}                   ; R10=zgora, R11=zgeor
        LDR     R6, [WsPtr, #BytesPerChar]      ; R6=pixel shift
        LDR     R9, [WsPtr, #NPix]              ; R9=no. of pixels per word-1

        ADD     R7, WsPtr, #FldSaveArea         ; save Y, target colour,
        STMIA   R7, {R1, R4, R9, R10, R11}      ; NPix, zgora, zgeor

; test first pixel, to see if we can go left

        LDR     R7, [R2]
        EOR     R1, R7, R4
        TST     R1, R3
598
        MRS     R8, CPSR
Kevin Bracey's avatar
Kevin Bracey committed
599
        TEQ     R5, R8, LSL #1          ; PL => it's fillable
Neil Turton's avatar
Neil Turton committed
600 601 602 603 604 605 606
        RSBMI   R6, R6, #32             ; not fillable, reverse pixel shift
        LDRMI   R8, [WsPtr, #GWRCol]    ; load right window limit
        BMI     %FT37                   ; and skip left+right filling bit

        Push    "R0, R2, R3"            ; save X, screen address, mask
        LDR     R8, [WsPtr, #GWLCol]
        SUB     R0, R0, R8              ; make X in range 0..GWRCol-GWLCol
Kevin Bracey's avatar
Kevin Bracey committed
607 608 609 610
        MOV     R14, #0                 ; clear partial word mask
        TEQ     R5, #0                  ; get into correct loop
        BMI     %FT84
        BPL     %FT64
Neil Turton's avatar
Neil Turton committed
611 612 613 614 615

10
        MOV     R14, #0                 ; clear partial word mask
        LDR     R7, [R2]                ; R7 = screen
        EOR     R1, R7, R4
Jeffrey Lee's avatar
Jeffrey Lee committed
616

Kevin Bracey's avatar
Kevin Bracey committed
617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639
 ; ***KJB - very cumbersome. Surely a temporary reg somewhere?
        TEQ     R5, #0                  ; check "not" flag
        BMI     %FT80

61      TST     R1, R3                  ; test pixel position for delimiter
        BEQ     %FT22                   ; NE => it's fillable
        ORR     R14, R14, R3            ; add pixel to partial word mask
64      SUBS    R0, R0, #1              ; decrement X; if on edge of window
        BMI     %FT22                   ; then give up and plot partial word

        MOVS    R3, R3, ROR R6          ; test for end of word
        BPL     %BT61                   ; loop until mask wraps
        B       %FT89

80      TST     R1, R3                  ; test pixel position for delimiter
        BNE     %FT22                   ; EQ => it's fillable
        ORR     R14, R14, R3            ; add pixel to partial word mask
84      SUBS    R0, R0, #1              ; decrement X; if on edge of window
        BMI     %FT22                   ; then give up and plot partial word

        MOVS    R3, R3, ROR R6          ; test for end of word
        BPL     %BT80                   ; loop until mask wraps
89
Neil Turton's avatar
Neil Turton committed
640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694

        AND     R1, R10, R14            ; R1 := zgora AND pixmask
        ORR     R7, R7, R1              ; screen := screen OR R1
        AND     R1, R11, R14            ; R1 := zgeor AND pixmask
        EOR     R7, R7, R1              ; screen := screen EOR R1
        STR     R7, [R2], #-4

        CMP     R5, #2                  ; CC => filling until target
        BCC     %BT10                   ; so do it slowly (do next word)

        SUBS    R0, R0, R9              ; move R0 to start of word
        BCC     %FT20                   ; if outside window continue slowly

        ADD     R9, R9, #1              ; R9 := pixels per word
        ORR     R1, R4, R10             ; compute word to plonk on screen
        EOR     R1, R1, R11
16
        LDR     R7, [R2]                ; screen word
        CMP     R7, R4
        BNE     %FT18                   ; NZ => terminate
        STR     R1, [R2], #-4
        SUBS    R0, R0, R9              ; back another word
        BCS     %BT16
18
        SUB     R9, R9, #1              ; R9 := pixels per word -1
20
        ADDS    R0, R0, R9              ; point R0 back to end of word
        BGE     %BT10                   ; if still inside, continue but slowly
        B       %FT24                   ; else exit
22
        AND     R1, R10, R14            ; R1 := zgora AND pixmask
        ORR     R7, R7, R1              ; screen := screen OR R1
        AND     R1, R11, R14            ; R1 := zgeor AND pixmask
        EOR     R7, R7, R1              ; screen := screen EOR R1
        STR     R7, [R2]
24
        ADD     R0, R0, R8              ; add GWLCol back on
        ADD     R0, R0, #1
        Pull    "R1, R2, R3"            ; restore X, screen addr, mask
        Push    R0                      ; save left-of-line coordinate
        MOV     R0, R1                  ; R0 = start X
        RSB     R6, R6, #32             ; reverse pixel shift
        LDR     R8, [WsPtr, #GWRCol]    ; load right window limit

; now the filling right part

26
        SUB     R0, R8, R0              ; make X in range GWRCol-GWLCol .. 0

; start of each word

27
        MOV     R14, #0
        LDR     R7, [R2]                ; screen word
        EOR     R1, R7, R4
Kevin Bracey's avatar
Kevin Bracey committed
695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721

; ***KJB - very cumbersome. Surely a temporary reg somewhere?
        TEQ     R5, #0
        BMI     %FT75
72
        TST     R1, R3                  ; test pixel position for delimiter
        BEQ     %FT34                   ; NE => it's fillable
        ORR     R14, R14, R3            ; add pixel to partial word mask
        SUBS    R0, R0, #1              ; "increment" X; if on edge of window
        BMI     %FT34                   ; then give up and plot partial word

        TEQ     R3, #0                  ; test for end of word
        MOV     R3, R3, ROR R6          ; shift pixel mask
        BPL     %BT72                   ; loop until mask wraps
        B       %FT79

75
        TST     R1, R3                  ; test pixel position for delimiter
        BNE     %FT34                   ; EQ => it's fillable
        ORR     R14, R14, R3            ; add pixel to partial word mask
        SUBS    R0, R0, #1              ; "increment" X; if on edge of window
        BMI     %FT34                   ; then give up and plot partial word

        TEQ     R3, #0                  ; test for end of word
        MOV     R3, R3, ROR R6          ; shift pixel mask
        BPL     %BT75                   ; loop until mask wraps
79
Neil Turton's avatar
Neil Turton committed
722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797

        AND     R1, R10, R14            ; R1 := zgora AND pixmask
        ORR     R7, R7, R1              ; screen := screen OR R1
        AND     R1, R11, R14            ; R1 := zgeor AND pixmask
        EOR     R7, R7, R1              ; screen := screen EOR R1
        STR     R7, [R2], #4

        CMP     R5, #2                  ; CC => filling until target
        BCC     %BT27                   ; so do it slowly (do next word)

        RSB     R0, R0, #0              ; make X in range GWLCol-GWRCol .. 0
        ADDS    R0, R0, R9              ; move R0 to end of word
        BGT     %FT32                   ; outside window, continue slowly

        ORR     R1, R4, R10             ; word to store if going fast
        EOR     R1, R1, R11
30
        LDR     R7, [R2]                ; screen word
        CMP     R7, R4                  ; EOR target colour (CS if EQ)
        BNE     %FT32                   ; NZ => terminate
        STR     R1, [R2], #4
        ADCS    R0, R0, R9              ; C=1, so add NPix +1
        BLE     %BT30
32
        SUBS    R0, R9, R0              ; R0 back to start of word and negate
        BGE     %BT27                   ; if still inside, continue slowly
        B       %FT36                   ; else exit

34
        AND     R1, R10, R14            ; R1 := zgora AND pixmask
        ORR     R7, R7, R1              ; screen := screen OR R1
        AND     R1, R11, R14            ; R1 := zgeor AND pixmask
        EOR     R7, R7, R1              ; screen := screen EOR R1
        STR     R7, [R2]
36
        SUB     R0, R8, R0              ; make back into normal coord again

; now queue this segment

        Pull    R4                      ; R4 := LH end point
        SUB     R7, R0, #1              ; R7 := corrected RH end point
        LDR     R1, [WsPtr, #FldSaveY]  ; reload Y coordinate of THIS segment
        BL      Queue

        ADD     R14, WsPtr, #FldLeftXLimit      ; load lxlim, (Y+?), rxlim
        LDMIA   R14, {R7,R10,R11}

        EOR     R5, R5, #FillingUpBit   ; invert direction

        SUB     R7, R7, #2              ; lxlim -2
        CMP     R4, R7                  ; if leftX <= lxlim-2
        BLLE    Queue                   ; then Q LH end bit in opposite dir

        ADD     R4, R11, #2             ; rxlim +2
        SUB     R7, R0, #1              ; R7 = RH end point
        CMP     R7, R4                  ; if rightX >= rxlim+2
        BLGE    Queue                   ; then Q RH end bit in opposite dir

        EOR     R5, R5, #FillingUpBit   ; invert direction back again

        SUB     R4, R4, #3              ; rxlim -1
        CMP     R7, R4                  ; if rightX >= rxlim-1
        Pull    PC, GE                  ; no point in skipping any more

; now do the skipping
; R0 points to first non-fillable pixel; R3=correct mask for this pixel

        ADD     R7, WsPtr, #FldSaveArea         ; reload target colour, NPix,
        LDMIB   R7, {R4, R9, R10, R11}          ; zgora, zgeor
37
        LDR     R1, [WsPtr, #FldRightXLimit]
38
        LDR     R7, [R2], #4
        EOR     R7, R7, R4                      ; screen EOR target
40
        TST     R7, R3                          ; if pixel is fillable
798
        MRS     R14, CPSR
Kevin Bracey's avatar
Kevin Bracey committed
799
        TEQ     R5, R14, LSL #1
Neil Turton's avatar
Neil Turton committed
800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907
        SUBPL   R2, R2, #4                      ; then correct address
        Push    R0, PL                          ; and push new X coord
        BPL     %BT26                           ; and go to fill right bit
50
        CMP     R0, R1                          ; on limit of segment ?
        Pull    PC, CS                          ; yes, so give up
        ADD     R0, R0, #1                      ; step coord
        TEQ     R3, #0                          ; test for mask wrap
        MOV     R3, R3, ROR R6                  ; rotate mask to next pixel
        BPL     %BT40                           ; continue within this word
        B       %BT38                           ; continue with next word

; *****************************************************************************
;
;       Queue - Queue a line segment
;
; in:   R1 = Y coordinate of segment
;       R4 = left X coordinate
;       R5 = fill flag (Bit0=0/1 => look downwards/upwards)
;       R7 = right X coordinate
;
; out:  R0-R8, R11, R12 preserved
;       R9,R10 corrupted
;       exits by pulling stacked R14 if queue was full
;

Queue   ROUT
        Push    "R0,R11,R14"
        TEQ     R5, R5, LSR #1          ; CS => mangle coords

        MOVCC   R9, R4
        MOVCC   R10, R7

        SUBCS   R9, R7, R4              ; R9 = R-L
        SUBCS   R10, R7, R9             ; R10 = R-(R-L) = L
        ADCCS   R9, R9, R10             ; R9 = (R-L)+L+1 = R+1

        [ med_00001_twowords
        ; revised packing, expanded to two words, LeftX in 31..16 of word 1,
        ; RightX in 15..0 of word 1, and Y in 15..0 of word 2

        MOV     R9, R9, LSL #16         ; shift LeftX up
        ORR     R9, R9, R10             ; combine in RightX

        ADD     R0, WsPtr, #QueuePtrs
        LDMIA   R0, {R10, R11, R14}     ; head,tail,limit

        STR     R9, [R11], #4           ; store word at tail and move on
        STR     R1, [R11], #4           ; store second word
        |
        ; pack Y into bits 0..9, L into bits 10..20, R into bits 21..31

        ORR     R9, R1, R9, LSL #10     ; R9 = Y + (L << 10)
        ORR     R9, R9, R10, LSL #21    ; R9 = Y + (L << 10) + (R <<21)

        ADD     R0, WsPtr, #QueuePtrs
        LDMIA   R0, {R10, R11, R14}     ; head,tail,limit

        STR     R9, [R11], #4           ; store word at tail and move on
        ]

        TEQ     R11, R14                ; if at limit
        LDREQ   R11, [R0, #12]          ; then reload with start ptr
        CMP     R11, R10                ; EQ and CS if queue full
        STRNE   R11, [R0, #4]           ; store tail ptr back if OK

        Pull    "R0,R11,PC", NE         ; queue not full, terminate normally

        [ med_00001_userma
        BL      release_memory
        ]
        LDR     R13, [WsPtr, #FldStackLevel]
        Pull    PC                      ; else bomb out

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

        [ med_00001_userma
release_memory
        ROUT
        Push   "R0-R5,lr"

        ADD    R0, WsPtr, #QueuePtrs
        LDMIA  R0, {R0-R3}

        LDR    R5, =FldQueueStart

        CMP    R3, R5                   ; did we use scratchspace ?
        BEQ    %FT20

        MOV    R2, R3
        MOV    R0, #ModHandReason_Free
        SWI    XOS_Module
20
        LDR    R0, [WsPtr, #flood_cda_rma]
        CMP    R0, #0
        BEQ    %FT30                    ; no need to shrink rma

        RSB    R1, R0, #0               ; get the signed negative value
        MOV    R0, #1                   ; rma
        SWI    XOS_ChangeDynamicArea
30
        CMP    r0, r0                   ; ensure we return EQ set
        Pull   "r0-r5,pc"
        ]

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

        END