OSBYTE 123, 156; OSWRCH entry point; Econet / User printer routines; Flush buffers; Count or purge buffer (CNPV); Append to buffer - 362 bytes (2.2%)


§1. OSWRCH - write character.

 This is the main entry point for writing characters to the display and/or to other devices
 such as ECONET, a printer, RS-423 or to a file.

 Note: the .characterDestinationsAvailableFlags has the following bits:

   bit 0 - enable RS-423 driver
   bit 1 - disable VDU driver
   bit 2 - disable printer driver
   bit 3 - enable printer, independent of VDU 2/3 (=CTRL B/C)
   bit 4 - disable SPOOLed output
   bit 5 - not used, zero
   bit 6 - disable printer driver (unless preceded by VDU 1)
   bit 7 - not used, zero

 On Entry:
       A = character to write
 On Exit:
       A, X, Y are preserved
.oswrchEntryPoint = $e0a4
    PHA                                                 }
    TXA                                                 }
    PHA                                                 } store A,X,Y registers
    TYA                                                 }
    PHA                                                 }
    TSX                                                 X = stack pointer
    LDA .stackPage + 3,X                                peek into stack to get A value back
    PHA                                                 push A again
    BIT .econetWriteCharacterInterceptionFlag           check OSWRCH interception flag
    BPL .skipEconetProcessing                           if (not set) then branch (skip
                                                        Econet)
    TAY                                                 pass character to Y
    LDA #4                                              A=4 for OSWRCH service call
    JSR .netvJumper                                     call NETV code
    BCS .oswrchFinishUp                                 if (claimed) then branch (finish up
                                                        and exit)

.skipEconetProcessing = $e0bb
    CLC                                                 prepare to not send this to printer
    LDA #2                                              check output destination
    BIT .characterDestinationsAvailableFlags            is VDU driver disabled?
    BNE .skipVDUOutput                                  yes, skip past VDU driver
    PLA                                                 pull character
    PHA                                                 push character
    JSR .vduChrEntryPoint                               call VDU driver
                                                        on exit, C=1 if character to be sent
                                                        to printer
.skipVDUOutput = $e0c8
    LDA #8                                              check output destination
    BIT .characterDestinationsAvailableFlags            is printer separately enabled?
    BNE .printerEnabled                                 yes, jump to call printer driver
    BCC .printerDisabled                                carry clear, don't sent to printer

.printerEnabled = $e0d1
    PLA                                                 pull character
    PHA                                                 push character
    JSR .sendCharacterToPrinter                         call printer driver

.printerDisabled = $e0d6
    LDA .characterDestinationsAvailableFlags            check output destination
    ROR                                                 check RS-423 output bit
    BCC .skipRS423Output                                if (RS-423 output is disabled) then
                                                        branch (skip past serial output)

    Check for timeout
    LDY .rs423TimeoutCounter                            get RS-423 timout counter
    DEY                                                 decrease counter
    BPL .skipRS423Output                                if (timed out) then branch (skip
                                                        past serial code)

    RS-423 output
    PLA                                                 pull character
    PHA                                                 push character
    PHP                                                 save IRQs
    SEI                                                 disable IRQs
    LDX #.bufferNumberRS423Output                       X=RS-423 output buffer
    PHA                                                 save character
    JSR .osbyte152EntryPoint                            examine RS-423 output buffer to see
                                                        if it's empty
    BCC +                                               buffer is not empty, jump to send
                                                        character
    JSR .clearBusyFlagAndSetRS423Active                 set RS-423 Active
+
    PLA                                                 get character
    LDX #.bufferNumberRS423Output                       X=RS-423 output buffer
    JSR .addByteToBuffer                                send character to RS-423 output
                                                        buffer
    PLP                                                 restore IRQs

.skipRS423Output = $e0f7
    LDA #$10                                            check output destination
    BIT .characterDestinationsAvailableFlags            check SPOOL output
    BNE .oswrchFinishUp                                 if (SPOOL output disabled) then
                                                        branch (skip past SPOOL output)
    LDY .spoolFileHandle                                get SPOOL file handle
    BEQ .oswrchFinishUp                                 if (not open) then branch (skip past
                                                        SPOOL output)
    PLA                                                 pull character
    PHA                                                 push character
    SEC                                                 }
    ROR .tapeCritical                                   } Set tape critical flag
    JSR .OSBPUT                                         write character to SPOOL channel
                                                        (A=character to write, Y=file handle)
    LSR .tapeCritical                                   clear tape critical flag

.oswrchFinishUp = $e10d
    PLA                                                 
    PLA                                                 }
    TAY                                                 }
    PLA                                                 } restore A,X,Y registers
    TAX                                                 }
    PLA                                                 }
    RTS                                                 

§2. On Entry:.

       A=character to print
.sendCharacterToPrinter = $e114
    BIT .characterDestinationsAvailableFlags            check for bit 6 set
    BVS .exit16                                         if (printer is disabled) then branch
                                                        (exit)
    CMP .printerIgnoreCharacter                         compare character against printer
                                                        ignore character
    BEQ .exit16                                         if (the same) then branch (exit)

.sendValidByteToPrinter = $e11e
    PHP                                                 save flags (including IRQ flag)
    SEI                                                 disable interrupts
    TAX                                                 store byte to send in X
    LDA #%00000100                                      }
    BIT .characterDestinationsAvailableFlags            } check bit 2 'disable printer
                                                        } driver'
    BNE .pullAndExit14                                  if (printer is disabled) then branch
                                                        (pull flags and exit)
    TXA                                                 restore byte to send to A
    LDX #.bufferNumberPrinter                           X=printer buffer number
    JSR .addByteToBuffer                                put character in printer buffer
    BCS .pullAndExit14                                  if (carry set, i.e. unsuccessful)
                                                        then branch (pull flags and exit)

    BIT .printerBufferEmptyFlag                         check buffer empty flag
    BPL .pullAndExit14                                  if (printer buffer is not empty)
                                                        then branch (pull flags and exit)
    JSR .openPrinterChannel                             open printer channel
.pullAndExit14 = $e138
    PLP                                                 restore flags (including IRQ flag)
.exit16 = $e139
    RTS                                                 

§3. openPrinterChannel.

.openPrinterChannel = $e13a
    LDA .printerDestination                             check printer destination
    BEQ .flushBufferX                                   if (zero) then branch (clear printer
                                                        buffer and exit)
    CMP #1                                              }
    BNE .checkForSerialPrinter                          } if (parallel printer not selected)
                                                        } then branch (check for serial
                                                        } printer)

    deal with parallel printer
    JSR .osbyte145EntryPoint                            read a byte from the printer buffer
    ROR .printerBufferEmptyFlag                         rotate carry into bit 7 of the
                                                        printer buffer empty flag
    BMI .exit17                                         if (printer buffer empty) then
                                                        branch (return)

    To send data to the parallel printer:
    
    1. Enable the User VIA interrupt '1'. The printer will trigger an IRQ when it is ready
       for another character.
    2. Write the byte to send to .userVIARegisterA
    3. Set bits 1-3 of the userVIAPeripheralControlRegister to %110
    4. Set bits 1-3 of the userVIAPeripheralControlRegister to %111
    This sends a 'STROBE' signal to advise the printer that valid data is waiting.

    LDY #%10000010                                      enable interrupt 1 of the user VIA
    STY .userVIAInterruptEnableRegister                 this is triggered by the printer
                                                        when it is ready to receive a new
                                                        character
    STA .userVIARegisterA                               pass byte to the Centronics port
    LDA .userVIAPeripheralControlRegister               }
    AND #%11110001                                      }
    ORA #%00001100                                      } pulse CA2 line to generate
    STA .userVIAPeripheralControlRegister               } STROBE signal to advise printer
    ORA #%00001110                                      } that valid data is waiting
    STA .userVIAPeripheralControlRegister               }
    BNE .exit17                                         ALWAYS branch (return)
                                                        [this could just be an RTS, saving
                                                        one byte]

§4. checkForSerialPrinter.

.checkForSerialPrinter = $e164
    CMP #2                                              }
    BNE .userPrinter                                    } if (serial printer is NOT
                                                        } selected) then branch (check for
                                                        } user printer)

    deal with serial printer
    LDY .rs423TimeoutCounter                            }
    DEY                                                 }
    BPL .flushBufferX                                   } if (timeout counter is timed out)
                                                        } then branch (to flush the buffer)
    LSR .printerBufferEmptyFlag                         clear printer buffer empty flag

.clearBusyFlagAndSetRS423Active = $e170
    LSR .rs423ReadyFlag                                 clear RS-423 busy flag
.setRS423Active = $e173
    JSR .getRS423InputBufferFreeBytes                   }
    BCC .exit17                                         } if (free space in buffer is low)
                                                        } then branch (return)
    LDX #%00100000                                      set bit 5 on ACIA control register
                                                        set 'Request To Send' low (meaning
                                                        Active)

.writeToACIARequestToSend = $e17a
    LDY #%10011111                                      Mask for setting bits 5 and 6
                                                        This writes the 'Request To Send'
                                                        value.
    fall through...

§5. OSBYTE 156 - Update ACIA Control Register and OS Copy.

 write (current value AND Y) EOR X
 Preserves Y and flags
.osbyte156EntryPoint = $e17c
    PHP                                                 push flags
    SEI                                                 disable interrupts
    TYA                                                 A=Y
    STX .tempStoreFA                                    .tempStoreFA=X
    AND .rs423ControlRegisterCopy                       A=old value AND Y EOR X
    EOR .tempStoreFA                                    
    LDX .rs423ControlRegisterCopy                       get old value in X
.storeACIAAndPull = $e189
    STA .rs423ControlRegisterCopy                       put new value in
    STA .acia6850ControlRegister                        and store to ACIA control register
    PLP                                                 get back flags
.exit17 = $e190
    RTS                                                 

§6. userPrinter.

.userPrinter = $e191
    CLC                                                 clear carry
    LDA #1                                              A = 1
    JSR .printerServiceCall                             
    fall through...

§7. OSBYTE 123 - Warn OS about printer going dormant.

 This call is used by the User Print Routine to indicate to the MOS that it has finished
 its task (The User Print Routine is selected by *FX 5,3).
.osbyte123EntryPoint = $e197
    ROR .printerBufferEmptyFlag                         mark printer buffer empty (clear top
                                                        bit)
-
    RTS                                                 

§8. printerServiceCallIfNotEmpty.

 Signal to the printer that there's at least one character in the printer buffer, at a
 rate of 100Hz until the printer driver deals with it.
.printerServiceCallIfNotEmpty = $e19b
    BIT .printerBufferEmptyFlag                         check printer buffer empty flag
    BMI -                                               if (buffer is empty) then branch
                                                        (exit)
    LDA #0                                              A=0 (100Hz update when printer is
                                                        active and buffer is not empty)
    fall through...

§9. printerServiceCall.

 Econet / User printer routines

 See NAUG Section 24.2.4, Page 424 for more detail on reason codes

 On Entry:
       A = reason code
           0 means 100Hz update
           1 means become active, since printer buffer is no longer empty
           2 means VDU 2 happened (disable printer output)
           3 means VDU 3 happened (enable printer output)
           5 means select new printer driver (entry via OSBYTE 5 to .selectPrinterType)
.printerServiceCall = $e1a2
    LDX #.bufferNumberPrinter                           X=printer buffer number
.selectPrinterType = $e1a4
    LDY .printerDestination                             Y=printer destination (*FX 5 value)
    JSR .netvJumper                                     let network have a look (should
                                                        respond if Y=4 for net printer)
    JMP (.vectorUPTV)                                   let user printer routine have a look
                                                        (can respond if Y=3, or 5-255 for
                                                        user printer)

§10. Flushes the given buffer.

 For buffer numbers, see .bufferNumberKeyboard.

 On Entry:
       X=buffer number
.flushBufferX = $e1ad
    CLC                                                 clear carry

.flushSoundBufferX = $e1ae
    PHA                                                 save A
    PHP                                                 save flags
    SEI                                                 disable interrupts
    BCS .flushNonSoundBufferX                           if (carry set on entry) then branch
    LDA .bufferTypeAndSerialBaudRatesTable,X            carry clear so get byte from table
    BPL .flushNonSoundBufferX                           if (not sound buffer) then branch
    JSR .clearSoundChannelBuffer                        clear sound buffer

.flushNonSoundBufferX = $e1bb
    SEC                                                 set carry
    ROR .bufferEmptyFlags,X                             rotate buffer flag to show buffer
                                                        empty
    CPX #2                                              
    BCS .skipInputBufferHandling                        if (X > 1) then branch (it's not an
                                                        input buffer)

    LDA #0                                              this is an input buffer
    STA .softKeyStringLength                            reset length of the *KEY string
                                                        currently being decoded (to stop
                                                        decoding a soft key, which would
                                                        otherwise add more characters into
                                                        the input buffer)
    STA .twosComplimentOfNumberOfBytesInVDUQueue        reset length of VDU queue

.skipInputBufferHandling = $e1cb
    JSR .purgeBuffer                                    purge buffer
    PLP                                                 restore flags
    PLA                                                 restore A
    RTS                                                 

§11. Count or Purge Buffer (CNPV) - Default Entry Point.

 On Entry:
       X = buffer to access
       if V set then purge buffer (else count buffer)
       for count buffer: if C set then get bytes free
                                  else get bytes used
.cnpEntryPoint = $e1d1
    BVC .countBuffer                                    if (V clear) then branch (count
                                                        buffer)
    LDA .bufferStartIndices,X                           purge buffer by setting
    STA .bufferEndIndices,X                             end of buffer = start of buffer
    RTS                                                 

.countBuffer = $e1da
    PHP                                                 push flags
    SEI                                                 disable interrupts
    PHP                                                 push flags
    SEC                                                 set carry
    LDA .bufferEndIndices,X                             get end of buffer
    SBC .bufferStartIndices,X                           subtract start of buffer
    BCS +                                               if (carry set) then branch
    SEC                                                 set carry
    SBC .emptyBufferStartOffset,X                       subtract buffer start offset (i.e.
                                                        add buffer length)
+
    PLP                                                 pull flags
    BCC +                                               if (carry clear) then branch (to
                                                        tidy up and exit)
    CLC                                                 clear carry
    ADC .emptyBufferStartOffset,X                       adc to get bytes used
    EOR #$FF                                            and invert to get space left
+
    LDY #0                                              Y=0
    TAX                                                 X=A
    PLP                                                 get back flags
    RTS                                                 

§12. Adds a byte to a buffer..

 On failure (e.g. the buffer is full), flash the keyboard lights and keep trying

 On Entry:
       A = byte to write
       X = buffer to write into

 On Exit:
       Carry clear if successful
.addByteToBuffer = $e1f8
    SEI                                                 prevent interrupts
    JSR .insJumper                                      enter a byte in buffer X
    BCC .exit18                                         if (successful) then branch (exit)
    JSR .turnOnKeyboardLightsAndTestEscape              switch on both keyboard lights

    PHP                                                 push flags
    PHA                                                 push A
    JSR .keyboardIndicators                             switch off unselected LEDs
    PLA                                                 recall A
    PLP                                                 recall flags

    BMI .exit18                                         if (return is -ve, i.e. Escape
                                                        pressed) then branch (exit)
    CLI                                                 allow interrupts
    BCS .addByteToBuffer                                if (byte didn't enter buffer) then
                                                        branch (go back and try again)
.exit18 = $e20d
    RTS