OSBYTE 132, 133, 135; Cursor editing mode routines - 382 bytes (2.3%)


§1. OSBYTE 135 - Read character at text cursor position.

.osbyte135EntryPoint = $d7c2
    LDY .vduNumberOfLogicalColoursMinusOne              get number of logical colours for
                                                        current MODE
    BNE .nonMODE7ReadCharacter                          if (MODE is not 7) then branch
    LDA (.vduWriteCursorScreenAddressLow),Y             read MODE 7 character from screen
    LDY #2                                              Y=2
-
    CMP .teletextCharacterConversionTable + 1,Y         compare with conversion table
    BNE +                                               if (not equal) then branch
    LDA .teletextCharacterConversionTable,Y             get previous byte from table
    DEY                                                 Y=Y-1
+
    DEY                                                 Y=Y-1
    BPL -                                               if (+ve) then branch (loop back and
                                                        do it again)
.finishUpFX135 = $d7d7
    LDY .vduCurrentScreenMODE                           Y = current screen MODE
    TAX                                                 X = character
    RTS                                                 

§2. nonMODE7ReadCharacter.

.nonMODE7ReadCharacter = $d7dc
    JSR .readCharacterDefinitionMaskFromScreen          read from screen, making a one bit
                                                        mask of 8 bytes to match against
                                                        each character, in workspaceA-H
    LDX #.charSPACE                                     Start with the space character (loop
                                                        counter)
.readCharLoop = $d7e1
    TXA                                                 Loop through each character in turn
                                                        looking to see if it matches
                                                        workspaceA-H
    PHA                                                 Save character
    JSR .getCharacterDefinitionAddress                  get character definition address for
                                                        character A
    PLA                                                 recall character
    TAX                                                 move to X
-
    LDY #7                                              Y=7
--
    LDA .vduWorkspaceA,Y                                get byte in workspaceA-H copy
    CMP (.vduTempStoreDE),Y                             check against character definition
    BNE +                                               if (not the same) then branch (to
                                                        skip to next character)
    DEY                                                 Y--
    BPL --                                              if (still non-negative) then branch
                                                        (back to loop eight times, to check
                                                        each row of the character)
    TXA                                                 At this point the character matches
    CPX #.charDELETE                                    but if it's the DELETE character
                                                        then pretend we didn't match and
                                                        carry on
    BNE .finishUpFX135                                  if (we are NOT the DELETE character)
                                                        then branch (to finish up)
+
    INX                                                 no match on this character so
                                                        increment to next character
    LDA .vduTempStoreDE                                 }
    CLC                                                 } Add 8 to address of character
                                                        } definition to move on to the next
                                                        } character
    ADC #8                                              } Affects low byte only as we check
                                                        } one page of characters at a time
    STA .vduTempStoreDE                                 }
    BNE -                                               if (we have not reached the end of
                                                        the page) then branch (back to check
                                                        the character)

    TXA                                                 A=X
    BNE .readCharLoop                                   if (character number not zero) then
                                                        branch (loop back)
    BEQ .finishUpFX135                                  ALWAYS branch (finish up)

§3. Read character from screen pixels.

 Reads 8x8 cell of pixels from the screen. This will be compared against each of the
 character definitions to determine which character is on screen. This is for the
 cursor editing mode feature.
.readCharacterDefinitionMaskFromScreen = $d808
    LDY #7                                              Y=7
.setupPatternLoop = $d80a
    STY .vduTempStoreDA                                 .vduTempStoreDA=Y (loop counter)
    LDA #1                                              A=1
    STA .vduTempStoreDB                                 .vduTempStoreDB=A
--
    LDA .vduColourMaskLeft                              A=left colour mask
    STA .vduTempStoreDC                                 store in .vduTempStoreDC
    LDA (.vduWriteCursorScreenAddressLow),Y             get a byte from current text
                                                        character
    EOR .vduBackgroundTextColour                        EOR with text background colour
    CLC                                                 clear carry
-
    BIT .vduTempStoreDC                                 and check bits of colour mask
    BEQ +                                               if (result = 0) then branch (this
                                                        becomes a zero bit in our mask)
    SEC                                                 set carry. This becomes a one bit in
                                                        our mask
+
    ROL .vduTempStoreDB                                 Rotate left and add the carry in the
                                                        low bit
    BCS +                                               if (carry now set; bit 7 originally
                                                        set) then branch (because we are
                                                        done:
                                                                      the initial value of 1
                                                        has rotated through the 8 bits and
                                                        into the carry)
    LSR .vduTempStoreDC                                 shift mask right one place for the
                                                        next pixel
    BCC -                                               if (carry clear; nothing shifted off
                                                        the left) then branch (loop back)
    TYA                                                 }
    ADC #7                                              } Y = Y + 8 (Carry is set, so adding
                                                        } 7 + carry = 8)
    TAY                                                 }
    BCC --                                              if (no overflow from the add) then
                                                        branch (loop back, move on to the
                                                        next cell to read from)
+
    LDY .vduTempStoreDA                                 read modified values into Y and A
    LDA .vduTempStoreDB                                 
    STA .vduWorkspaceA,Y                                store copy
    DEY                                                 and do it again
    BPL .setupPatternLoop                               until 8 bytes copied
    RTS                                                 

§4. Read pixel.

 On Entry:
       A = VDU variable offset for the graphics coordinates to use.

 On Exit:
       A = current colour at the coordinate specified OR
       A = $FF if coordinate is out of bounds
.readPixel = $d839
    PHA                                                 store A
    TAX                                                 X=A
    JSR .plotConvertExternalAbsoluteCoordinatesToPixels set up positional data
    PLA                                                 get back A
    TAX                                                 X=A
    JSR .checkPointXInBoundsAndSetScreenAddresses       set a screen address after checking
                                                        for window bounds
    BNE ++                                              if (out of bounds) then branch (exit
                                                        with A=$FF)
    LDA (.vduScreenAddressOfGraphicsCursorCellLow),Y    get row of current graphics cell
-
    ASL                                                 A=A*2, Carry=bit 7
    ROL .vduTempStoreDA                                 .vduTempStoreDA=.vduTempStoreDA+2
                                                        +Carry,
                                                        Carry=bit 7 of .vduTempStoreDA
    ASL .vduCurrentPlotByteMask                         byte mask=byte mask*2 + Carry
    PHP                                                 save flags
    BCS +                                               if (carry set) then branch
    LSR .vduTempStoreDA                                 restore .vduTempStoreDA with bit 7=0
+
    PLP                                                 pull flags
    BNE -                                               if (Z set) then branch
    LDA .vduTempStoreDA                                 A=.vduTempStoreDA AND number of
                                                        colours in current MODE -1
    AND .vduNumberOfLogicalColoursMinusOne              
    RTS                                                 

++
    LDA #$FF                                            A=$FF
-
    RTS                                                 

§5. Check the graphics point on the VDU queue is within the graphics window.

.checkParameterInBoundsAndSetScreenAddresses = $d85d
    LDX #.vdu25ParameterXLow - .vduVariablesStart       X is the offset to the desired
                                                        parameter for the point in graphics
                                                        coordinates
    fall through...

§6. Check the given point is within the graphics window.

 Takes the graphics coordinates pointed to by X, checks whether they are in the bounds of
 the graphics window, and if so sets up screen addresses.

 On Entry:
       X is the vdu variables offset to the graphics point to check
 On Exit:
       .vduScreenAddressOfGraphicsCursorCellLow/High is the screen address
       Y is the vertical offset within the character cell (0-7)
       Z is clear (i.e. BNE will branch) if coordinates are outside the graphics area
.checkPointXInBoundsAndSetScreenAddresses = $d85f
    JSR .checkPointXIsWithinGraphicsWindow              
    BNE -                                               if (point is not in graphics window)
                                                        then branch (exit)
.setScreenAddress = $d864
    LDA .vduGraphicsWindowPixelsBottomLow,X             read low byte of Y coordinate
    EOR #$FF                                            Flip the coordinates to be from the
                                                        top of the screen
    TAY                                                 Remember in Y
    AND #7                                              A = row within a character cell
    STA .vduGraphicsCursorVerticalOffsetInCell          store row (0-7)
    TYA                                                 A=Y
    LSR                                                 }
    LSR                                                 }
    LSR                                                 } divide by 8
    ASL                                                 Multiply by two to give the offset
                                                        in the multiplication table
    TAY                                                 Y = offset into multiplication table
    LDA (.vduMultiplicationTableLow),Y                  Get high byte of offset from screen
                                                        RAM start
    STA .vduTempStoreDA                                 store it
    INY                                                 Y=Y+1
    LDA (.vduMultiplicationTableLow),Y                  get low byte
    LDY .vduCurrentScreenMODEGroup                      check MODE group
    BEQ +                                               if (zero, i.e. MODEs 0,1,2) then
                                                        branch (skip this next bit)
    LSR .vduTempStoreDA                                 } divide the offset by two
    ROR                                                 }
+
    ADC .vduScreenTopLeftAddressLow                     add the screen top left address (low)
    STA .vduScreenAddressOfGraphicsCursorCellLow        store it
    LDA .vduTempStoreDA                                 get high byte
    ADC .vduScreenTopLeftAddressHigh                    add with carry the screen top left
                                                        address (high)
    STA .vduScreenAddressOfGraphicsCursorCellHigh       store it
    LDA .vduGraphicsWindowPixelsLeftHigh,X              
    STA .vduTempStoreDA                                 store x coordinate of point (high)
    LDA .vduGraphicsWindowPixelsLeftLow,X               get x coordinate of point (low)
    PHA                                                 remember it
    AND .vduPixelsPerByteMinusOne                       get the horizontal X offset within
                                                        the range of pixelsPerByte
    ADC .vduPixelsPerByteMinusOne                       add the pixels per byte minus one,
                                                        which offsets to (one more than) the
                                                        start of the MODE mask table for the
                                                        current MODE
    TAY                                                 Y=A
    LDA .sixteenColourMODEMaskTable - 1,Y               read byte mask
    STA .vduCurrentPlotByteMask                         store it
    PLA                                                 get back A
    LDY .vduPixelsPerByteMinusOne                       Y=number of pixels per byte minus one
    CPY #3                                              compare with 3
    BEQ +                                               if (MODE 1 or 5) then branch forward
    BCS ++                                              if (MODE 0 or 4) then branch forward
    ASL                                                 }
    ROL .vduTempStoreDA                                 } (A,.vduTempStoreDA) *= 2
+
    ASL                                                 }
    ROL .vduTempStoreDA                                 } (A,.vduTempStoreDA) *= 2
++
    AND #$F8                                            clear bits 0-2
    CLC                                                 clear carry
    ADC .vduScreenAddressOfGraphicsCursorCellLow        add A/.vduTempStoreDA to screen
                                                        address
    STA .vduScreenAddressOfGraphicsCursorCellLow        
    LDA .vduTempStoreDA                                 
    ADC .vduScreenAddressOfGraphicsCursorCellHigh       
    BPL +                                               if (result +ve) then branch
    SEC                                                 set carry
    SBC .vduScreenSizeHighByte                          and subtract screen memory size
                                                        making it wrap round
+
    STA .vduScreenAddressOfGraphicsCursorCellHigh       store it
    LDY .vduGraphicsCursorVerticalOffsetInCell          get line in graphics cell containing
                                                        current graphics
.zeroAReturn = $d8cb
    LDA #0                                              A=0 to set Z flag (valid result)
    RTS                                                 

§7. splitIntoTwoCursors.

.splitIntoTwoCursors = $d8ce
    PHA                                                 Push A
    LDA #$A0                                            A=$A0
    LDX .twosComplimentOfNumberOfBytesInVDUQueue        X=number of items in VDU queue
    BNE .pullAndReturn2                                 if (not 0) then branch
    BIT .vduStatusByte                                  check VDU status byte
    BNE .pullAndReturn2                                 if (either VDU is disabled, or plot
                                                        to graphics cursor enabled) then
                                                        branch (exit)
    BVS +                                               if (cursor editing mode enabled)
                                                        then branch
    LDA .vduLastCursorStartRegisterValue                get CRTC register start setting
    AND #%10011111                                      clear bits 5 and 6
    ORA #%01000000                                      set bit 6 to modify last cursor size
                                                        setting
    JSR .setCursorOnOrOff                               change cursor format
    LDX #.vduTextCursorXPosition - .vduVariablesStart          source = text cursor
    LDY #.vduTextInputCursorXCoordinate - .vduVariablesStart   destination = text input
                                                               cursor
    JSR .copyTwoBytesWithinVDUVariables                 set text input cursor from text
                                                        output cursor
    JSR .restoreWriteCursor                             modify character at cursor position
    LDA #2                                              
    JSR .setVDUStatusByteFlags                          bit 1 of VDU status is set to bar
                                                        scrolling
+
    LDA #%10111111                                      
    JSR .clearVDUStatusByteFlags                        bit 6 of VDU status (separated
                                                        cursors) is set to zero
    PLA                                                 Pull A
    AND #%01111111                                      clear high bit (7)
    JSR .vduChrEntryPoint                               call VDU routine
    LDA #%01000000                                      set bit six (separate cursors)
    JMP .setVDUStatusByteFlags                          set separated cursors and return

§8. readCharacterFromScreenAndCursorRight.

.readCharacterFromScreenAndCursorRight = $d905
    LDA #%00100000                                      A=$20
    BIT .vduStatusByte                                  
    BVC .zeroAReturn                                    if (bit 6 clear; not in cursor
                                                        editing mode) then branch (exit)
    BNE .zeroAReturn                                    if (bit 5 set; graphics cursor
                                                        enabled) then branch (exit)
    JSR .osbyte135EntryPoint                            read a character from the screen
    BEQ .exit12                                         if (A = 0, i.e. failed to read) then
                                                        branch (exit)
    PHA                                                 store A
    JSR .vdu9EntryPoint                                 perform cursor right
.pullAndReturn2 = $d916
    PLA                                                 restore A
.exit12 = $d917
    RTS                                                 

§9. terminateEdit.

 When editing a line with two cursors, pressing return terminates the edit.
 This clears the VDU status flags and restores the text cursor to normal.
.terminateEdit = $d918
    LDA #%10111101                                      }
    JSR .clearVDUStatusByteFlags                        } clear bits 2 and 6 of VDU status
                                                        } (page scrolling; separated cursors)
    JSR .setTextCursor                                  set text cursor (CRTC hardware)
    LDA #.charRETURN                                    continue processing as a RETURN
                                                        character
    RTS                                                 

§10. OSBYTE 132 - Read HIMEM (start of screen memory).

.osbyte132EntryPoint = $d923
    LDX .vduCurrentScreenMODE                           get current screen MODE
    fall through...

§11. OSBYTE 133 - Read start of screen memory for given MODE.

.osbyte133EntryPoint = $d926
    TXA                                                 X=MODE number
    AND #7                                              keep it in range 0-7
    TAY                                                 Y=MODE number
    LDX .screenDisplayMemoryIndexTable,Y                X = get screen RAM size index
    LDA .screenMemoryStartHigh,X                        A = high byte of start address
    LDX #0                                              X = 0 (low byte of result)
    BIT .systemAvailableRAM                             get available RAM
    BMI .returnTheScreenAddress                         if (32k available) then branch
    AND #$3F                                            AND A with $3F to bring into memory
                                                        range for a 16K BBC Micro
    CPY #4                                              
    BCS .returnTheScreenAddress                         if (MODE number >= 4) then branch
                                                        (to return the value)
    TXA                                                 return zero (Model A can't display
                                                        MODEs 0-3)
.returnTheScreenAddress = $d93e
    TAY                                                 Y = high byte of screen address
    RTS