BBC Micro Elite

# Drawing lines: LOIN (Part 6 of 7) (6502SP version)

```       Name: LOIN (Part 6 of 7)                                [View in context]
Type: Subroutine
Category: Drawing lines
Summary: Draw a steep line going up and left or down and right

This routine draws a line from (X1, Y1) to (X2, Y2). It has multiple stages.
If we get here, then:

* The line is going up and left (no swap) or down and right (swap)

* X1 < X2 and Y1 >= Y2

* Draw from (X1, Y1) at top left to (X2, Y2) at bottom right

This routine looks complex, but that's because the loop that's used in the
cassette and disc versions has been unrolled to speed it up. The algorithm is
unchanged, it's just a lot longer.

LDA SWAP               \ If SWAP = 0 then we didn't swap the coordinates above,
BEQ LI290              \ so jump down to LI290 to plot the first pixel

TYA                    \ Fetch bits 0-2 of the y-coordinate, so Y contains the
AND #7                 \ y-coordinate mod 8
TAY

BNE P%+5               \ If Y = 0, jump to LI307+8 to start plotting from the
JMP LI307+8            \ pixel above the top row of this character block
\ (LI307+8 points to the DEX instruction after the
\ EOR/STA instructions, so the pixel at row 0 doesn't
\ get plotted but we join at the right point to
\ decrement X and Y correctly to continue plotting from
\ the character row above)

CPY #2                 \ If Y < 2 (i.e. Y = 1), jump to LI306+8 to start
BCS P%+5               \ plotting from row 0 of this character block, missing
JMP LI306+8            \ out row 1

CLC                    \ Clear the C flag so it doesn't affect the arithmetic
\ below

BNE P%+5               \ If Y = 2, jump to LI305+8 to start plotting from row
JMP LI305+8            \ 1 of this character block, missing out row 2

CPY #4                 \ If Y < 4 (i.e. Y = 3), jump to LI304+8 to start
BCS P%+5               \ plotting from row 2 of this character block, missing
JMP LI304+8            \ out row 3

CLC                    \ Clear the C flag so it doesn't affect the arithmetic
\ below

BNE P%+5               \ If Y = 4, jump to LI303+8 to start plotting from row
JMP LI303+8            \ 3 of this character block, missing out row 4

CPY #6                 \ If Y < 6 (i.e. Y = 5), jump to LI302+8 to start
BCS P%+5               \ plotting from row 4 of this character block, missing
JMP LI302+8            \ out row 5

CLC                    \ Clear the C flag so it doesn't affect the arithmetic
\ below

BEQ P%+5               \ If Y <> 6 (i.e. Y = 7), jump to LI300+8 to start
JMP LI300+8            \ plotting from row 6 of this character block, missing
\ out row 7

JMP LI301+8            \ Otherwise Y = 6, so jump to LI301+8 to start plotting
\ from row 5 of this character block, missing out row 6

.LI290

DEX                    \ Decrement the counter in X because we're about to plot
\ the first pixel

TYA                    \ Fetch bits 0-2 of the y-coordinate, so Y contains the
AND #7                 \ y-coordinate mod 8
TAY

BNE P%+5               \ If Y = 0, jump to LI307 to start plotting from row 0
JMP LI307              \ of this character block

CPY #2                 \ If Y < 2 (i.e. Y = 1), jump to LI306 to start plotting
BCS P%+5               \ from row 1 of this character block
JMP LI306

CLC                    \ Clear the C flag so it doesn't affect the arithmetic
\ below

BNE P%+5               \ If Y = 2, jump to LI305 to start plotting from row 2
JMP LI305              \ of this character block

CPY #4                 \ If Y < 4 (i.e. Y = 3), jump to LI304 (via LI304S) to
BCC LI304S             \ start plotting from row 3 of this character block

CLC                    \ Clear the C flag so it doesn't affect the arithmetic
\ below

BEQ LI303S             \ If Y = 4, jump to LI303 (via LI303S) to start plotting
\ from row 4 of this character block

CPY #6                 \ If Y < 6 (i.e. Y = 5), jump to LI302 (via LI302S) to
BCC LI302S             \ start plotting from row 5 of this character block

CLC                    \ Clear the C flag so it doesn't affect the arithmetic
\ below

BEQ LI301S             \ If Y = 6, jump to LI301 (via LI301S) to start plotting
\ from row 6 of this character block

JMP LI300              \ Otherwise Y = 7, so jump to LI300 to start plotting
\ from row 7 of this character block

.LI310

LSR R                  \ If we get here then the slope error just overflowed
\ after plotting the pixel in LI300, so shift the single
\ pixel in R to the right, so the next pixel we plot
\ will be at the next x-coordinate along

BCC LI301              \ If the pixel didn't fall out of the right end of R
\ into the C flag, then jump to LI301 to plot the pixel
\ on the next character row up

LDA #%10001000         \ Set a mask in R to the first pixel in the 4-pixel byte
STA R

LDA SC                 \ Add 8 to SC, so SC(1 0) now points to the next
ADC #7                 \ character along to the right (the C flag is set as we
STA SC                 \ didn't take the above BCC, so the ADC adds 8)

\ the pixel on the next character row up

INC SC+1               \ The addition overflowed, so increment the high byte in
\ SC(1 0) to move to the next page in screen memory

CLC                    \ Clear the C flag so it doesn't affect the arithmetic
\ below

.LI301S

BCC LI301              \ Jump to LI301 to rejoin the pixel plotting routine
\ (this BCC is effectively a JMP as the C flag is clear)

.LI311

LSR R                  \ If we get here then the slope error just overflowed
\ after plotting the pixel in LI301, so shift the single
\ pixel in R to the right, so the next pixel we plot
\ will be at the next x-coordinate along

BCC LI302              \ If the pixel didn't fall out of the right end of R
\ into the C flag, then jump to LI302 to plot the pixel
\ on the next character row up

LDA #%10001000         \ Set a mask in R to the first pixel in the 4-pixel byte
STA R

LDA SC                 \ Add 8 to SC, so SC(1 0) now points to the next
ADC #7                 \ character along to the right (the C flag is set as we
STA SC                 \ didn't take the above BCC, so the ADC adds 8)

\ the pixel on the next character row up

INC SC+1               \ The addition overflowed, so increment the high byte in
\ SC(1 0) to move to the next page in screen memory

CLC                    \ Clear the C flag so it doesn't affect the arithmetic
\ below

.LI302S

BCC LI302              \ Jump to LI302 to rejoin the pixel plotting routine
\ (this BCC is effectively a JMP as the C flag is clear)

.LI312

LSR R                  \ If we get here then the slope error just overflowed
\ after plotting the pixel in LI302, so shift the single
\ pixel in R to the right, so the next pixel we plot
\ will be at the next x-coordinate along

BCC LI303              \ If the pixel didn't fall out of the right end of R
\ into the C flag, then jump to LI303 to plot the pixel
\ on the next character row up

LDA #%10001000         \ Set a mask in R to the first pixel in the 4-pixel byte
STA R

LDA SC                 \ Add 8 to SC, so SC(1 0) now points to the next
ADC #7                 \ character along to the right (the C flag is set as we
STA SC                 \ didn't take the above BCC, so the ADC adds 8)

\ the pixel on the next character row up

INC SC+1               \ The addition overflowed, so increment the high byte in
\ SC(1 0) to move to the next page in screen memory

CLC                    \ Clear the C flag so it doesn't affect the arithmetic
\ below

.LI303S

BCC LI303              \ Jump to LI303 to rejoin the pixel plotting routine
\ (this BCC is effectively a JMP as the C flag is clear)

.LI313

LSR R                  \ If we get here then the slope error just overflowed
\ after plotting the pixel in LI303, so shift the single
\ pixel in R to the right, so the next pixel we plot
\ will be at the next x-coordinate along

BCC LI304              \ If the pixel didn't fall out of the right end of R
\ into the C flag, then jump to LI304 to plot the pixel
\ on the next character row up

LDA #%10001000         \ Set a mask in R to the first pixel in the 4-pixel byte
STA R

LDA SC                 \ Add 8 to SC, so SC(1 0) now points to the next
ADC #7                 \ character along to the right (the C flag is set as we
STA SC                 \ didn't take the above BCC, so the ADC adds 8)

\ the pixel on the next character row up

INC SC+1               \ The addition overflowed, so increment the high byte in
\ SC(1 0) to move to the next page in screen memory

CLC                    \ Clear the C flag so it doesn't affect the arithmetic
\ below

.LI304S

BCC LI304              \ Jump to LI304 to rejoin the pixel plotting routine
\ (this BCC is effectively a JMP as the C flag is clear)

.LIEX3

RTS                    \ Return from the subroutine

.LI300

\ Plot a pixel on row 7 of this character block

LDA R                  \ Fetch the pixel byte from R and apply the colour in
AND COL                \ COL to it

EOR (SC),Y             \ Store A into screen memory at SC(1 0), using EOR
STA (SC),Y             \ logic so it merges with whatever is already on-screen

DEX                    \ Decrement the counter in X

BEQ LIEX3              \ If we have just reached the right end of the line,

DEY                    \ Decrement Y to step up along the y-axis

LDA S                  \ Set S = S + P to update the slope error
STA S

\ the pixel in the next character block along, which
\ returns us to LI301 below

.LI301

\ Plot a pixel on row 6 of this character block

LDA R                  \ Fetch the pixel byte from R and apply the colour in
AND COL                \ COL to it

EOR (SC),Y             \ Store A into screen memory at SC(1 0), using EOR
STA (SC),Y             \ logic so it merges with whatever is already on-screen

DEX                    \ Decrement the counter in X

BEQ LIEX3              \ If we have just reached the right end of the line,

DEY                    \ Decrement Y to step up along the y-axis

LDA S                  \ Set S = S + P to update the slope error
STA S

\ the pixel in the next character block along, which
\ returns us to LI302 below

.LI302

\ Plot a pixel on row 5 of this character block

LDA R                  \ Fetch the pixel byte from R and apply the colour in
AND COL                \ COL to it

EOR (SC),Y             \ Store A into screen memory at SC(1 0), using EOR
STA (SC),Y             \ logic so it merges with whatever is already on-screen

DEX                    \ Decrement the counter in X

BEQ LIEX3              \ If we have just reached the right end of the line,

DEY                    \ Decrement Y to step up along the y-axis

LDA S                  \ Set S = S + P to update the slope error
STA S

\ the pixel in the next character block along, which
\ returns us to LI303 below

.LI303

\ Plot a pixel on row 4 of this character block

LDA R                  \ Fetch the pixel byte from R and apply the colour in
AND COL                \ COL to it

EOR (SC),Y             \ Store A into screen memory at SC(1 0), using EOR
STA (SC),Y             \ logic so it merges with whatever is already on-screen

DEX                    \ Decrement the counter in X

BEQ LIEX3              \ If we have just reached the right end of the line,

DEY                    \ Decrement Y to step up along the y-axis

LDA S                  \ Set S = S + P to update the slope error
STA S

\ the pixel in the next character block along, which
\ returns us to LI304 below

.LI304

\ Plot a pixel on row 3 of this character block

LDA R                  \ Fetch the pixel byte from R and apply the colour in
AND COL                \ COL to it

EOR (SC),Y             \ Store A into screen memory at SC(1 0), using EOR
STA (SC),Y             \ logic so it merges with whatever is already on-screen

DEX                    \ Decrement the counter in X

BEQ LIEX4              \ If we have just reached the right end of the line,

DEY                    \ Decrement Y to step up along the y-axis

LDA S                  \ Set S = S + P to update the slope error
STA S

\ the pixel in the next character block along, which
\ returns us to LI305 below

.LI305

\ Plot a pixel on row 2 of this character block

LDA R                  \ Fetch the pixel byte from R and apply the colour in
AND COL                \ COL to it

EOR (SC),Y             \ Store A into screen memory at SC(1 0), using EOR
STA (SC),Y             \ logic so it merges with whatever is already on-screen

DEX                    \ Decrement the counter in X

BEQ LIEX4              \ If we have just reached the right end of the line,

DEY                    \ Decrement Y to step up along the y-axis

LDA S                  \ Set S = S + P to update the slope error
STA S

\ the pixel in the next character block along, which
\ returns us to LI306 below

.LI306

\ Plot a pixel on row 1 of this character block

LDA R                  \ Fetch the pixel byte from R and apply the colour in
AND COL                \ COL to it

EOR (SC),Y             \ Store A into screen memory at SC(1 0), using EOR
STA (SC),Y             \ logic so it merges with whatever is already on-screen

DEX                    \ Decrement the counter in X

BEQ LIEX4              \ If we have just reached the right end of the line,

DEY                    \ Decrement Y to step up along the y-axis

LDA S                  \ Set S = S + P to update the slope error
STA S

\ the pixel in the next character block along, which
\ returns us to LI307 below

.LI307

\ Plot a pixel on row 0 of this character block

LDA R                  \ Fetch the pixel byte from R and apply the colour in
AND COL                \ COL to it

EOR (SC),Y             \ Store A into screen memory at SC(1 0), using EOR
STA (SC),Y             \ logic so it merges with whatever is already on-screen

DEX                    \ Decrement the counter in X

BEQ LIEX4              \ If we have just reached the right end of the line,

DEC SC+1               \ We just reached the top of the character block, so
DEC SC+1               \ decrement the high byte in SC(1 0) twice to point to
LDY #7                 \ the screen row above (as there are two pages per
\ screen row) and set Y to point to the last row in the
\ new character block

LDA S                  \ Set S = S + P to update the slope error
STA S

JMP LI300              \ continue plotting in the next character block along

LSR R                  \ If we get here then the slope error just overflowed
\ after plotting the pixel in LI307 above, so shift the
\ single pixel in R to the right, so the next pixel we
\ plot will be at the next x-coordinate

BCS P%+5               \ If the pixel didn't fall out of the right end of R
JMP LI300              \ into the C flag, then jump to LI400 to continue
\ plotting in the next character block along

LDA #%10001000         \ Otherwise we need to move over to the next character
STA R                  \ along, so set a mask in R to the first pixel in the
\ 4-pixel byte

LDA SC                 \ Add 8 to SC, so SC(1 0) now points to the next
ADC #7                 \ character along to the right (the C flag is set as we
STA SC                 \ took the above BCS, so the ADC adds 8)

BCS P%+5               \ If the addition didn't overflow, ump to LI300 to
JMP LI300              \ continue plotting in the next character block along

INC SC+1               \ The addition overflowed, so increment the high byte in
\ SC(1 0) to move to the next page in screen memory

CLC                    \ Clear the C flag so it doesn't affect the arithmetic
\ below

JMP LI300              \ Jump to LI300 to continue plotting in the next
\ character block along

.LIEX4

RTS                    \ Return from the subroutine

.LI314

LSR R                  \ If we get here then the slope error just overflowed
\ after plotting the pixel in LI304, so shift the single
\ pixel in R to the right, so the next pixel we plot
\ will be at the next x-coordinate along

BCC LI305              \ If the pixel didn't fall out of the right end of R
\ into the C flag, then jump to LI305 to plot the pixel
\ on the next character row up

LDA #%10001000         \ Set a mask in R to the first pixel in the 4-pixel byte
STA R

LDA SC                 \ Add 8 to SC, so SC(1 0) now points to the next
ADC #7                 \ character along to the right (the C flag is set as we
STA SC                 \ didn't take the above BCC, so the ADC adds 8)

\ the pixel on the next character row up

INC SC+1               \ The addition overflowed, so increment the high byte in
\ SC(1 0) to move to the next page in screen memory

CLC                    \ Clear the C flag so it doesn't affect the arithmetic
\ below

BCC LI305              \ Jump to LI305 to rejoin the pixel plotting routine
\ (this BCC is effectively a JMP as the C flag is clear)

.LI315

LSR R                  \ If we get here then the slope error just overflowed
\ after plotting the pixel in LI305, so shift the single
\ pixel in R to the right, so the next pixel we plot
\ will be at the next x-coordinate along

BCC LI306              \ If the pixel didn't fall out of the right end of R
\ into the C flag, then jump to LI306 to plot the pixel
\ on the next character row up

LDA #%10001000         \ Set a mask in R to the first pixel in the 4-pixel byte
STA R

LDA SC                 \ Add 8 to SC, so SC(1 0) now points to the next
ADC #7                 \ character along to the right (the C flag is set as we
STA SC                 \ didn't take the above BCC, so the ADC adds 8)

\ the pixel on the next character row up

INC SC+1               \ The addition overflowed, so increment the high byte in
\ SC(1 0) to move to the next page in screen memory

CLC                    \ Clear the C flag so it doesn't affect the arithmetic
\ below

BCC LI306              \ Jump to LI306 to rejoin the pixel plotting routine
\ (this BCC is effectively a JMP as the C flag is clear)

.LI316

LSR R                  \ If we get here then the slope error just overflowed
\ after plotting the pixel in LI306, so shift the single
\ pixel in R to the right, so the next pixel we plot
\ will be at the next x-coordinate along

BCC LI307              \ If the pixel didn't fall out of the right end of R
\ into the C flag, then jump to LI307 to plot the pixel
\ on the next character row up

LDA #%10001000         \ Set a mask in R to the first pixel in the 4-pixel byte
STA R

LDA SC                 \ Add 8 to SC, so SC(1 0) now points to the next
ADC #7                 \ character along to the right (the C flag is set as we
STA SC                 \ didn't take the above BCC, so the ADC adds 8)