view level1/modules/sc6551.asm @ 3036:42861a1dd59e

Low level driver update to CoCoSDC provided by Darren.
author David Ladd <drencor-xeen@users.sf.net>
date Fri, 09 Jan 2015 12:32:56 -0600
parents f91dc5c378f6
children
line wrap: on
line source

********************************************************************
* sc6551 - 6551 Driver
*
* $Id$
*
* Edt/Rev  YYYY/MM/DD  Modified by
* Comment
* ------------------------------------------------------------------
*          ????/??/??
* NitrOS-9 2.00 distribution.
*
*   9r4    2003/01/01  Boisy G. Pitre
* Back-ported to OS-9 Level Two.
*
*  10r1    2003/??/??  Robert Gault
* Added 6809 code where it was lacking.
*
*  10r2    2004/05/03  Boisy G. Pitre
* Fixed numerous issues with 6809 and Level 1 versions.
* Tested 6809 Level 1 and Level 2.

           nam   sc6551
           ttl   6551 Driver

           ifp1
           use   defsfile
;           use   scfdefs
           endc

* conditional assembly switches
TC9        set   false          "true" for TC-9 version, "false" for Coco 3
MPIFlag    set   true           "true" MPI slot selection, "false" no slot

* miscellaneous definitions
DCDStBit   equ   %00100000      DCD status bit for SS.CDSta call
DSRStBit   equ   %01000000      DSR status bit for SS.CDSta call
SlpBreak   set   TkPerSec/2+1   line Break duration
SlpHngUp   set   TkPerSec/2+1   hang up (drop DTR) duration

       ifeq  TC9-true
IRQBit     equ   %00000100      GIME IRQ bit to use for IRQ ($FF92)
       else
IRQBit     equ   %00000001      GIME IRQ bit to use for IRQ ($FF92)
       endc

* 6551 register definitions
           org   0
DataReg    rmb   1              receive/transmit Data (read Rx / write Tx)
StatReg    rmb   1              status (read only)
PRstReg    equ   StatReg        programmed reset (write only)
CmdReg     rmb   1              command (read/write)
CtlReg     rmb   1              control (read/write)

* Status bit definitions
Stat.IRQ   equ   %10000000      IRQ occurred
Stat.DSR   equ   %01000000      DSR level (clear = active)
Stat.DCD   equ   %00100000      DCD level (clear = active)
Stat.TxE   equ   %00010000      Tx data register Empty
Stat.RxF   equ   %00001000      Rx data register Full
Stat.Ovr   equ   %00000100      Rx data Overrun error
Stat.Frm   equ   %00000010      Rx data Framing error
Stat.Par   equ   %00000001      Rx data Parity error

Stat.Err   equ   Stat.Ovr!Stat.Frm!Stat.Par Status error bits
Stat.Flp   equ   $00            all Status bits active when set
Stat.Msk   equ   Stat.IRQ!Stat.RxF active IRQs

* Control bit definitions
Ctl.Stop   equ   %10000000      stop bits (set=two, clear=one)
Ctl.DBit   equ   %01100000      see data bit table below
Ctl.RxCS   equ   %00010000      Rx clock source (set=baud rate, clear=external)
Ctl.Baud   equ   %00001111      see baud rate table below

* data bit table
DB.8       equ   %00000000      eight data bits per character
DB.7       equ   %00100000      seven data bits per character
DB.6       equ   %01000000      six data bits per character
DB.5       equ   %01100000      five data bits per character

* baud rate table
           org   $00
BR.ExClk   rmb   1              16x external clock (not supported)
           org   $11
BR.00050   rmb   1              50 baud (not supported)
BR.00075   rmb   1              75 baud (not supported)
BR.00110   rmb   1              109.92 baud
BR.00135   rmb   1              134.58 baud (not supported)
BR.00150   rmb   1              150 baud (not supported)
BR.00300   rmb   1              300 baud
BR.00600   rmb   1              600 baud
BR.01200   rmb   1              1200 baud
BR.01800   rmb   1              1800 baud (not supported)
BR.02400   rmb   1              2400 baud
BR.03600   rmb   1              3600 baud (not supported)
BR.04800   rmb   1              4800 baud
BR.07200   rmb   1              7200 baud (not supported)
BR.09600   rmb   1              9600 baud
BR.19200   rmb   1              19200 baud

* Command bit definitions
Cmd.Par    equ   %11100000      see parity table below
Cmd.Echo   equ   %00010000      local echo (set=activated)
Cmd.TIRB   equ   %00001100      see Tx IRQ/RTS/Break table below
Cmd.RxI    equ   %00000010      Rx IRQ (set=disabled)
Cmd.DTR    equ   %00000001      DTR output (set=enabled)

* parity table
Par.None   equ   %00000000
Par.Odd    equ   %00100000
Par.Even   equ   %01100000
Par.Mark   equ   %10100000
Par.Spac   equ   %11100000

* Tx IRQ/RTS/Break table
TIRB.Off   equ   %00000000      RTS & Tx IRQs disabled
TIRB.On    equ   %00000100      RTS & Tx IRQs enabled
TIRB.RTS   equ   %00001000      RTS enabled, Tx IRQs disabled
TIRB.Brk   equ   %00001100      RTS enabled, Tx IRQs disabled, Tx line Break

* V.ERR bit definitions
DCDLstEr   equ   %00100000      DCD lost error
OvrFloEr   equ   %00000100      Rx data overrun or Rx buffer overflow error
FrmingEr   equ   %00000010      Rx data framing error
ParityEr   equ   %00000001      Rx data parity error

* FloCtlRx bit definitions
FCRxSend   equ   %10000000      send flow control character
FCRxSent   equ   %00010000      Rx disabled due to XOFF sent
FCRxDTR    equ   %00000010      Rx disabled due to DTR
FCRxRTS    equ   %00000001      Rx disabled due to RTS

* FloCtlTx bit definitions
FCTxXOff   equ   %10000000      due to XOFF received
FCTxBrk    equ   %00000010      due to currently transmitting Break

* Wrk.Type bit definitions
Parity     equ   %11100000      parity bits
MdmKill    equ   %00010000      modem kill option
RxSwFlow   equ   %00001000      Rx data software (XON/XOFF) flow control
TxSwFlow   equ   %00000100      Tx data software (XON/XOFF) flow control
RTSFlow    equ   %00000010      CTS/RTS hardware flow control
DSRFlow    equ   %00000001      DSR/DTR hardware flow control

* Wrk.Baud bit definitions
StopBits   equ   %10000000      number of stop bits code
WordLen    equ   %01100000      word length code
BaudRate   equ   %00001111      baud rate code

* Wrk.XTyp bit definitions
SwpDCDSR   equ   %10000000      swap DCD+DSR bits (valid for 6551 only)
ForceDTR   equ   %01000000      don't drop DTR in term routine
RxBufPag   equ   %00001111      input buffer page count

* static data area definitions
           org   V.SCF          allow for SCF manager data area
Cpy.Stat   rmb   1              Status register copy
CpyDCDSR   rmb   1              DSR+DCD status copy
Mask.DCD   rmb   1              DCD status bit mask (MUST immediately precede Mask.DSR)
Mask.DSR   rmb   1              DSR status bit mask (MUST immediately follow Mask.DCD)
CDSigPID   rmb   1              process ID for CD signal
CDSigSig   rmb   1              CD signal code
FloCtlRx   rmb   1              Rx flow control flags
FloCtlTx   rmb   1              Tx flow control flags
RxBufEnd   rmb   2              end of Rx buffer
RxBufGet   rmb   2              Rx buffer output pointer
RxBufMax   rmb   2              Send XOFF (if enabled) at this point
RxBufMin   rmb   2              Send XON (if XOFF sent) at this point
RxBufPtr   rmb   2              pointer to Rx buffer
RxBufPut   rmb   2              Rx buffer input pointer
RxBufSiz   rmb   2              Rx buffer size
RxDatLen   rmb   2              current length of data in Rx buffer
SigSent    rmb   1              keyboard abort/interrupt signal already sent
SSigPID    rmb   1              SS.SSig process ID
SSigSig    rmb   1              SS.SSig signal code
WritFlag   rmb   1              initial write attempt flag
Wrk.Type   rmb   1              type work byte (MUST immediately precede Wrk.Baud)
Wrk.Baud   rmb   1              baud work byte (MUST immediately follow Wrk.Type)
Wrk.XTyp   rmb   1              extended type work byte
           IFEQ  Level-1
orgDFIRQ   rmb   2
           ENDC
regWbuf    rmb   2              substitute for regW
RxBufDSz   equ   256-.          default Rx buffer gets remainder of page...
RxBuff     rmb   RxBufDSz       default Rx buffer
MemSize    equ   .

rev        set   2
edition    set   10

           mod   ModSize,ModName,Drivr+Objct,ReEnt+rev,ModEntry,MemSize

           fcb   UPDAT.         access mode(s)

ModName    fcs   "sc6551"
           fcb   edition

       ifeq  MPIFlag-true
SlotSlct   fcb   MPI.Slot       selected MPI slot
       else
SlotSlct   fcb   $FF            disable MPI slot selection
       endc

IRQPckt    equ   *
Pkt.Flip   fcb   Stat.Flp       flip byte
Pkt.Mask   fcb   Stat.Msk       mask byte
           fcb   $0A            priority

BaudTabl   equ   *
           fcb   BR.00110,BR.00300,BR.00600
           fcb   BR.01200,BR.02400,BR.04800
           fcb   BR.09600,BR.19200

           IFEQ  Level-1
FIRQRtn    tst   ,s		'Entire' bit of carry set?
           bmi   L003B		branch if so
           leas  -$01,s		make room on stack
           pshs  y,x,dp,b,a	save regs
           lda   $08,s		get original CC on stack
           stu   $07,s		save U
           ora   #$80		set 'Entire' bit
           pshs  a		save CC
L003B      jmp   [>D.SvcIRQ]	jump to IRQ service routine
           ENDC

* NOTE:  SCFMan has already cleared all device memory except for V.PAGE and
*        V.PORT.  Zero-default variables are:  CDSigPID, CDSigSig, Wrk.XTyp.
Init       clrb                 default to no error...
           pshs  cc,dp        save IRQ/Carry status, system DP
           IFNE  H6309
           tfr   u,w
           tfr   e,dp
           tfr   y,w            save descriptor pointer
           ELSE
           tfr   u,d
           tfr   a,dp
           pshs  y
           ENDC
           ldd   <V.PORT        base hardware address
           IFNE  H6309
           incd                 point to 6551 status address
           ELSE
           addd  #$0001
           ENDC
           leax  IRQPckt,pc
           leay  IRQSvc,pc
           os9   F$IRQ
           IFNE  H6309
           tfr   w,y            recover descriptor pointer
           ELSE
           puls  y
           ENDC
           lbcs  ErrExit        go report error...
           IFEQ  Level-1
           ldd   >D.FIRQ
           std   <orgDFIRQ
           leax  >FIRQRtn,pcr
           stx   >D.FIRQ
           ENDC 
           ldb   M$Opt,y        get option size
           cmpb  #IT.XTYP-IT.DTP room for extended type byte?
           bls   DfltInfo       no, go use defaults...
           ldd   #Stat.DCD*256+Stat.DSR default (unswapped) DCD+DSR masks
           tst   IT.XTYP,y      check extended type byte for swapped DCD & DSR bits
           bpl   NoSwap         no, go skip swapping them...
           exg   a,b            swap to DSR+DCD masks
NoSwap     std   <Mask.DCD      save DCD+DSR (or DSR+DCD) masks
           lda   IT.XTYP,y      get extended type byte
           sta   <Wrk.XTyp      save it
           anda  #RxBufPag      clear all but Rx buffer page count bits
           beq   DfltInfo       none, go use defaults...
           clrb                 make data size an even number of pages
           IFNE  H6309
           tfr   u,w            save data pointer
           ELSE
           pshs  u
           ENDC
           os9   F$SRqMem       get extended buffer
           tfr   u,x            copy address
           IFNE  H6309
           tfr   w,u            recover data pointer
           ELSE
           puls  u
           ENDC
           lbcs  TermExit       error, go remove IRQ entry and exit...
           bra   SetRxBuf
DfltInfo   ldd   #RxBufDSz      default Rx buffer size
           leax  RxBuff,u       default Rx buffer address
SetRxBuf   std   <RxBufSiz      save Rx buffer size
           stx   <RxBufPtr      save Rx buffer address
           stx   <RxBufGet      set initial Rx buffer input address
           stx   <RxBufPut      set initial Rx buffer output address
           IFNE  H6309
           addr  d,x            point to end of Rx buffer
           ELSE
           leax  d,x
           ENDC
           stx   <RxBufEnd      save Rx buffer end address
           subd  #80            characters available in Rx buffer
           std   <RxBufMax      set auto-XOFF threshold
           ldd   #10            characters remaining in Rx buffer
           std   <RxBufMin      set auto-XON threshold after auto-XOFF
           ldb   #TIRB.RTS      default command register
           IFNE  H6309
           tim   #ForceDTR,<Wrk.XTyp
           ELSE
           lda   #ForceDTR
           bita  <Wrk.XTyp
           ENDC
           beq   NoDTR          no, don't enable DTR yet
           orb   #Cmd.DTR       set (enable) DTR bit
NoDTR      ldx   <V.PORT        get port address
           stb   CmdReg,x       set new command register
           ldd   IT.PAR,y       [A] = IT.PAR, [B] = IT.BAU from descriptor
           lbsr  SetPort        go save it and set up control/format registers
           orcc  #IntMasks      disable IRQs while setting up hardware
           IFEQ  TC9-true
           ELSE
           IFNE  H6309
           aim   #$FC,>PIA1Base+3
           ELSE
           lda   >PIA1Base+3
           anda  #$FC
           IFEQ  Level-1
           ora   #$01
           ENDC
           sta   >PIA1Base+3
           ENDC
           lda   >PIA1Base+2    clear possible pending PIA CART* FIRQ
           ENDC
           IFGT  Level-1
           lda   #IRQBit        get GIME IRQ bit to use
           ora   >D.IRQER       mask in current GIME IRQ enables
           sta   >D.IRQER       save GIME CART* IRQ enable shadow register
           sta   >IrqEnR        enable GIME CART* IRQs
           ENDC
           lda   StatReg,x      ensure old IRQ flags are clear
           lda   DataReg,x      ensure old error and Rx data IRQ flags are clear
           lda   StatReg,x      ... again
           lda   DataReg,x      ... and again
           lda   StatReg,x      get new Status register contents
           sta   <Cpy.Stat      save Status copy
           tfr   a,b            copy it...
           eora  Pkt.Flip,pc    flip bits per D.Poll
           anda  Pkt.Mask,pc    any IRQ(s) still pending?
           lbne  NRdyErr        yes, go report error... (device not plugged in?)
           andb  #Stat.DSR!Stat.DCD clear all but DSR+DCD status
           stb   <CpyDCDSR      save new DCD+DSR status copy
           IFEQ  MPIFlag-true
           lda   SlotSlct,pc    get MPI slot select value
           bmi   NoSelect       no MPI slot select, go on...
           sta   >MPI.Slct      set MPI slot select register
           ENDC
NoSelect   puls  cc,dp,pc       recover IRQ/Carry status, system DP, return

Term       clrb                 default to no error...
           pshs  cc,dp          save IRQ/Carry status, dummy B, system DP
           IFNE  H6309
           tfr   u,w            setup our DP
           tfr   e,dp
           ELSE
           tfr   u,d
           tfr   a,dp
           ENDC
           IFEQ  Level-1
           ldx   >D.Proc
           lda   P$ID,x
           sta   <V.BUSY
           sta   <V.LPRC
           ENDC
           ldx   <V.PORT
           lda   CmdReg,x       get current Command register contents
           anda  #^(Cmd.TIRB!Cmd.DTR) disable Tx IRQs, RTS, and DTR
           ora   #Cmd.RxI       disable Rx IRQs
           ldb   <Wrk.XTyp      get extended type byte
           andb  #ForceDTR      forced DTR?
           beq   KeepDTR        no, go leave DTR disabled...
           ora   #Cmd.DTR       set (enable) DTR bit
KeepDTR    sta   CmdReg,x       set DTR and RTS enable/disable
           ldd   <RxBufSiz      get Rx buffer size
           tsta                 less than 256 bytes?
           beq   TermExit       yes, no system memory to return...
           pshs  u              save data pointer
           ldu   <RxBufPtr      get address of system memory
           os9   F$SRtMem
           puls  u              recover data pointer
TermExit   
           IFEQ  Level-1
           ldd   <orgDFIRQ
           std   >D.FIRQ
           ENDC
           ldd   <V.PORT        base hardware address is status register
           IFNE  H6309
           incd                 point to 6551 status register
           ELSE
           addd  #$0001
           ENDC
           ldx   #$0000         remove IRQ table entry
           leay  IRQSvc,pc
           puls  cc             recover IRQ/Carry status
           os9   F$IRQ
           puls  dp,pc          restore dummy A, system DP, return

ReadSlp    
           IFEQ  Level-1
           lda   <V.BUSY
           sta   <V.WAKE
           lbsr  Sleep0         go suspend process...
           ELSE
           ldd   >D.Proc        process descriptor address
           sta   <V.WAKE        save MSB for IRQ service routine
           tfr   d,x            copy process descriptor address
           IFNE  H6309
           oim   #Suspend,P$State,x
           ELSE
           ldb   P$State,x
           orb   #Suspend
           stb   P$State,x
           ENDC
           lbsr  Sleep1         go suspend process...
           ENDC
           ldx   >D.Proc        process descriptor address
           ldb   P$Signal,x     pending signal for this process?
           beq   ChkState       no, go check process state...
           cmpb  #S$Intrpt      do we honor signal?
           lbls  ErrExit        yes, go do it...
ChkState   equ   *
           IFNE  H6309
           tim   #Condem,P$State,x
           ELSE
           ldb   P$State,x
           bitb  #Condem
           ENDC
           bne   PrAbtErr       yes, go do it...
           ldb   <V.WAKE        true interrupt?
           beq   ReadChk        yes, go read the char.
           bra   ReadSlp        no, go suspend the process

Read       clrb                 default to no errors...
           pshs  cc,dp          save IRQ/Carry status, system DP
           IFNE  H6309
           tfr   u,w            setup our DP
           tfr   e,dp
           ELSE
           tfr   u,d
           tfr   a,dp
           ENDC
ReadLoop   orcc  #IntMasks      disable IRQs while checking Rx flow control
ReadChk    lda   <FloCtlRx      get Rx flow control flags
           beq   ReadChar       none, go get Rx character...
           ldx   <RxDatLen      get Rx data count again
           cmpx  <RxBufMin      at or below XON level?
           bhi   ReadChar       no, go get Rx character...
           ldx   <V.PORT
           bita  #FCRxSent      Rx disabled due to XOFF sent?
           beq   ChkHWHS        no, go check hardware handshake(s)...
           ldb   <FloCtlTx      get Tx flow control flags
           bitb  #FCTxBrk       currently transmitting line Break?
           beq   NotTxBrk       yes, go skip XON this time...
ReadLp2    andcc #^IntMasks     turn interupts back on
           bra   ReadLoop
NotTxBrk   equ   *
           IFNE  H6309
           tim   #Stat.TxE,StatReg,x
           ELSE
           pshs  a
           lda   StatReg,x
           bita  #Stat.TxE
           puls  a
           ENDC
           beq   ReadLp2        no, go skip XON this time...
           ldb   <V.XON
           stb   DataReg,x      write XON character
ChkHWHS    bita  #FCRxDTR!FCRxRTS Rx disabled due to DTR or RTS?
           beq   RxFloClr       no, go clear Rx flow control flag(s)...
           ldb   CmdReg,x       get current Command register contents
           andb  #^Cmd.TIRB     clear Tx IRQ/RTS/Break control bits
           orb   #TIRB.RTS!Cmd.DTR enable RTS and DTR, disable Tx IRQs
           stb   CmdReg,x       set Command register
RxFloClr   clr   <FloCtlRx      clear Rx flow control flags
ReadChar   ldb   <V.ERR         get accumulated errors, if any
           stb   PD.ERR,y       set/clear error(s) in path descriptor
           bne   ReprtErr       error(s), go report it/them...
           ldd   <RxDatLen      get Rx buffer count
           beq   ReadSlp        none, go sleep while waiting for new Rx data...
           IFNE  H6309
           decd                 less character we're about to grab
           ELSE
           subd  #$0001
           ENDC
           std   <RxDatLen      save new Rx data count
           orcc  #IntMasks  see if this fixes the problem
           ldx   <RxBufGet      current Rx buffer pickup position
           lda   ,x+            get Rx character, set up next pickup position
           cmpx  <RxBufEnd      end of Rx buffer?
           blo   SetPckUp       no, go keep pickup pointer
           ldx   <RxBufPtr      get Rx buffer start address
SetPckUp   stx   <RxBufGet      set new Rx data pickup pointer
           puls  cc,dp,pc       recover IRQ/Carry status, dummy B, system DP, return

ModEntry   lbra  Init
           bra   Read
           nop
           bra   Write
           nop
           IFNE  H6309
           bra   GStt
           nop
           ELSE
           lbra  GStt
           ENDC
           lbra  SStt
           lbra  Term

PrAbtErr   ldb   #E$PrcAbt
           bra   ErrExit

ReprtErr   clr   <V.ERR         clear error status
           bitb  #DCDLstEr      DCD lost error?
           bne   HngUpErr       yes, go report it...
           ldb   #E$Read
ErrExit    equ  *
           IFNE  H6309
           oim   #Carry,,s      set carry
           ELSE
           lda   ,s
           ora   #Carry
           sta   ,s
           ENDC
           puls  cc,dp,pc       restore CC, system DP, return

HngUpErr   ldb   #E$HangUp
           lda   #PST.DCD       DCD lost flag
           sta   PD.PST,y       set path status flag
           bra   ErrExit

NRdyErr    ldb   #E$NotRdy
           bra   ErrExit

UnSvcErr   ldb   #E$UnkSvc
           bra   ErrExit

Write      clrb                 default to no error...
           pshs  cc,dp          save IRQ/Carry status, Tx character, system DP
           IFNE  H6309
           tfr   u,w            setup our DP
           tfr   e,dp
           tfr   a,e
           ELSE
           pshs  a
           tfr   u,d
           tfr   a,dp
           puls  a
           sta   <regWbuf
           ENDC
           orcc  #IntMasks      disable IRQs during error and Tx disable checks
           bra   WritChr
WritLoop   lda   <WritFlag
           beq   WritFast
           lbsr  Sleep1
WritFast   inc   <WritFlag
WritChr    ldx   <V.PORT
           ldb   <V.ERR         get accumulated errors, if any
           andb  #DCDLstEr      DCD lost error? (ignore other errors, if any)
           stb   PD.ERR,y       set/clear error(s) in path descriptor
           bne   ReprtErr       DCD lost error, go report it...
ChkTxFlo   ldb   <FloCtlTx      get Tx flow control flags
           bitb  #FCTxBrk       currently transmitting line Break?
           bne   WritLoop       yes, go sleep a while...
           lda   <Wrk.Type      get software/hardware handshake enables
           bita  #DSRFlow       DSR/DTR handshake enabled?
* Changed below - BGP
*           beq   ChkTxFlo       no, go check Tx flow control
           beq   ChkRxFlo       no, go check Rx flow control
           ldb   <Cpy.Stat      get copy of status register
           bitb  <Mask.DSR      Tx disabled due to DSR?
           bne   WritLoop       yes, go sleep a while...
           bita  #TxSwFlow      Tx software flow control enabled?
           beq   ChkRxFlo       no, go check pending Rx flow control
           bitb  #FCTxXOff      Tx disabled due to received XOFF?
           bne   WritLoop       yes, go sleep a while...
ChkRxFlo   bita  #RxSwFlow      Rx software flow control enabled?
           beq   ChkTxE         no, go check Tx register empty
           ldb   <FloCtlRx      get Rx flow control flags
           bitb  #FCRxSend      XON/XOFF Rx flow control pending?
           bne   WritLoop       yes, go sleep a while...
ChkTxE     equ   *
           IFNE  H6309
           tim   #Stat.TxE,StatReg,x
           ELSE
           pshs  a
           lda   StatReg,x
           bita  #Stat.TxE
           puls  a 
           ENDC
           beq   WritLoop       no, go sleep a while...
           IFNE  H6309
           ste   DataReg,x      write Tx character
           ELSE
           ldb   <regWbuf
           stb   DataReg,x
           ENDC
           clr   <WritFlag      clear "initial write attempt" flag
           puls  cc,dp,pc       recover IRQ/Carry status, Tx character, system DP, return

GStt       clrb                 default to no error...
           pshs  cc,dp          save IRQ/Carry status, dummy B, system DP
           IFNE  H6309
           tfr   u,w            setup our DP
           tfr   e,dp
           ELSE
           pshs  a
           tfr   u,d
           tfr   a,dp
           puls  a
           ENDC
           ldx   PD.RGS,y       caller's register stack pointer
           cmpa  #SS.EOF
           beq   GSExitOK       yes, SCF devices never return EOF
           cmpa  #SS.Ready
           bne   GetScSiz
           ldd   <RxDatLen      get Rx data length
           beq   NRdyErr        none, go report error
           tsta                 more than 255 bytes?
           beq   SaveLen        no, keep Rx data available
           ldb   #255           yes, just use 255
SaveLen    stb   R$B,x          set Rx data available in caller's [B]
GSExitOK   puls  cc,dp,pc       restore Carry status, dummy B, system DP, return

GetScSiz   cmpa  #SS.ScSiz
           bne   GetComSt
           ldu   PD.DEV,y
           ldu   V$DESC,u
           clra
           ldb   IT.COL,u
           std   R$X,x
           ldb   IT.ROW,u
           std   R$Y,x
           puls  cc,dp,pc       restore Carry status, dummy B, system DP, return

GetComSt   cmpa  #SS.ComSt
           lbne  UnSvcErr       no, go report error
           ldd   <Wrk.Type
           std   R$Y,x
           clra                 default to DCD and DSR enabled
           ldb   <CpyDCDSR
           bitb  #Mask.DCD
           beq   CheckDSR       no, go check DSR status
           ora   #DCDStBit
CheckDSR   bitb  <Mask.DSR      DSR bit set (disabled)?
           beq   SaveCDSt       no, go set DCD/DSR status
           ora   #DSRStBit
SaveCDSt   sta   R$B,x          set 6551 ACIA style DCD/DSR status in caller's [B]
           puls  cc,dp,pc       restore Carry status, dummy B, system DP, return

BreakSlp   ldx   #SlpBreak      SS.Break duration
           bra   TimedSlp

HngUpSlp   ldx   #SlpHngUp      SS.HngUp duration
           bra   TimedSlp

           IFEQ  Level-1
Sleep0     ldx   #$0000
           bra   TimedSlp
           ENDC
Sleep1     ldx   #1             give up balance of tick
TimedSlp   pshs  cc             save IRQ enable status
           andcc #^Intmasks     enable IRQs
           os9   F$Sleep
           puls  cc,pc          restore IRQ enable status, return

SStt       clrb                 default to no error...
           pshs  cc,dp          save IRQ/Carry status, dummy B, system DP
           IFNE  H6309
           tfr   u,w            setup our DP
           tfr   e,dp
           ELSE
           pshs  a
           tfr   u,d
           tfr   a,dp
           puls  a
           ENDC
           ldx   PD.RGS,y
           cmpa  #SS.HngUp
           bne   SetBreak
           lda   #^Cmd.DTR      cleared (disabled) DTR bit
           ldx   <V.PORT
           orcc  #IntMasks      disable IRQs while setting Command register
           anda  CmdReg,x       mask in current Command register contents
           sta   CmdReg,x       set new Command register
           bsr   HngUpSlp       go sleep for a while...
BreakClr   lda   #^(Cmd.TIRB!Cmd.DTR) clear (disable) DTR and RTS control bits
FRegClr    ldx   <V.PORT
           anda  CmdReg,x       mask in current Command register
           ldb   <FloCtlRx      get Rx flow control flags
           bitb  #FCRxDTR       Rx disabled due to DTR?
           bne   LeaveDTR       yes, go leave DTR disabled
           ora   #Cmd.DTR       set (enable) DTR bit
LeaveDTR   bitb  #FCRxRTS       Rx disabled due to RTS?
           bne   LeaveRTS       yes, go leave RTS disabled
           ora   #TIRB.RTS      enable RTS output
LeaveRTS   ldb   <FloCtlTx      get Tx flow control flags
           bitb  #FCTxBrk       currently transmitting line Break?
           beq   NoTxBrk        no, go leave RTS alone...
           ora   #TIRB.Brk      set Tx Break bits
NoTxBrk    sta   CmdReg,x       set new Command register
           puls  cc,dp,pc       restore IRQ/Carry status, dummy B, system DP, return

SetBreak   cmpa  #SS.Break      Tx line break?
           bne   SetSSig
           ldy   <V.PORT
           ldd   #FCTxBrk*256+TIRB.Brk [A]=flow control flag, [B]=Tx break enable
           orcc  #Intmasks      disable IRQs while messing with flow control flags
           ora   <FloCtlTx      set Tx break flag bit
           sta   <FloCtlTx      save Tx flow control flags
           orb   CmdReg,y       set Tx line break bits
           stb   CmdReg,y       start Tx line break
           bsr   BreakSlp       go sleep for a while...
           anda  #^FCTxBrk      clear Tx break flag bit
           sta   <FloCtlTx      save Tx flow control flags
           clr   CmdReg,y       clear Tx line break
           bra   BreakClr       go restore RTS output to previous...

SetSSig    cmpa  #SS.SSig
           bne   SetRelea
           lda   PD.CPR,y       current process ID
           ldb   R$X+1,x        LSB of [X] is signal code
           orcc  #IntMasks      disable IRQs while checking Rx data length
           ldx   <RxDatLen
           bne   RSendSig
           std   <SSigPID
           puls  cc,dp,pc       restore IRQ/Carry status, dummy B, system DP, return
RSendSig   puls  cc             restore IRQ/Carry status
           os9   F$Send
           puls  dp,pc          restore system DP, return

SetRelea   cmpa  #SS.Relea
           bne   SetCDSig
           leax  SSigPID,u      point to Rx data signal process ID
           bsr   ReleaSig       go release signal...
           puls  cc,dp,pc       restore Carry status, dummy B, system DP, return

SetCDSig   cmpa  #SS.CDSig      set DCD signal?
           bne   SetCDRel
           lda   PD.CPR,y       current process ID
           ldb   R$X+1,x        LSB of [X] is signal code
           std   <CDSigPID
           puls  cc,dp,pc       restore Carry status, dummy B, system DP, return

SetCDRel   cmpa  #SS.CDRel      release DCD signal?
           bne   SetComSt
CDRelSig   leax  CDSigPID,u     point to DCD signal process ID
           bsr   ReleaSig       go release signal...
           puls  cc,dp,pc       restore Carry status, dummy B, system DP, return

SetComSt   cmpa  #SS.ComSt
           bne   SetOpen
           ldd   R$Y,x          caller's [Y] contains ACIAPAK format type/baud info
           bsr   SetPort        go save it and set up control/format registers
ReturnOK   puls  cc,dp,pc       restore Carry status, dummy B, system DP, return

SetOpen    cmpa  #SS.Open
           bne   SetClose
           lda   R$Y+1,x        get LSB of caller's [Y]
           deca                 real SS.Open from SCF? (SCF sets LSB of [Y] = 1)
           bne   ReturnOK       no, go do nothing but return OK...
           lda   #TIRB.RTS      enabled DTR and RTS outputs
           orcc  #IntMasks      disable IRQs while setting Format register
           lbra  FRegClr        go enable DTR and RTS (if not disabled due to Rx flow control)

SetClose   cmpa  #SS.Close
           lbne  UnSvcErr       no, go report error...
           lda   R$Y+1,x        real SS.Close from SCF? (SCF sets LSB of [Y] = 0)
           bne   ReturnOK       no, go do nothing but return OK...
           leax  SSigPID,u      point to Rx data signal process ID
           bsr   ReleaSig       go release signal...
           bra   CDRelSig       go release DCD signal, return from there...

ReleaSig   pshs  cc             save IRQ enable status
           orcc  #IntMasks      disable IRQs while releasing signal
           lda   PD.CPR,y       get current process ID
           suba  ,x             same as signal process ID?
           bne   NoReleas       no, go return...
           sta   ,x             clear this signal's process ID
NoReleas   puls  cc,pc          restore IRQ enable status, return

SetPort    pshs  cc             save IRQ enable and Carry status
           orcc  #IntMasks      disable IRQs while setting up ACIA registers
           std   <Wrk.Type      save type/baud in data area
           leax  BaudTabl,pc
           andb  #BaudRate      clear all but baud rate bits
           ldb   b,x            get baud rate setting
           IFNE  H6309
           tfr   b,e            save it temporarily
           ELSE
           stb   <regWbuf
           ENDC
           ldb   <Wrk.Baud      get baud info again
           andb  #^(Ctl.RxCS!Ctl.Baud) clear clock source + baud rate code bits
           IFNE  H6309
           orr   e,b            mask in clock source + baud rate and clean up stack
           ELSE
           orb   <regWbuf
           ENDC
           ldx   <V.PORT        get port address
           anda  #Cmd.Par       clear all except parity bits
           IFNE  H6309
           tfr   a,e            save new command register contents temporarily
           ELSE
           sta   <regWbuf
           ENDC
           lda   CmdReg,x       get current command register contents
           anda  #^Cmd.Par      clear parity control bits
           IFNE  H6309
           orr   e,a            mask in new parity
           ELSE
           ora   <regWbuf
           ENDC
           std   CmdReg,x       set command+control registers
           puls  cc,pc          recover IRQ enable and Carry status, return...

IRQSvc
           IFEQ  Level-1
           lda   >PIA1Base+2	clear FIRQ
           ENDC
           pshs  dp             save system DP
           IFNE  H6309
           tfr   u,w            setup our DP
           tfr   e,dp
           ELSE
           tfr   u,d            setup our DP
           tfr   a,dp
           ENDC
           ldx   <V.PORT
           ldb   StatReg,x      get current Status register contents
           stb   <Cpy.Stat      save Status register copy
           bitb  #Stat.Err      error(s)?
           beq   ChkRDRF        no, go check Rx data
           tst   DataReg,x      read Rx data register to clear ACIA error flags
           bitb  #Stat.Frm      framing error (assume Rx line Break)?
           beq   ChkParty       no, go check if parity error...
           lda   <V.QUIT        default to keyboard quit ("Break") code
           bra   RxBreak        go pretend we've received V.QUIT character...

ChkParty   bitb  #Stat.Par      parity error?
           beq   ChkOvRun       no, go check overrun error...
           lda   #ParityEr      mark parity error
ChkOvRun   bita  #Stat.Ovr      overrun error?
           beq   SaveErrs       no, go save errors...
           ora   #OvrFloEr      mark overrun error
SaveErrs   ora   <V.ERR
           sta   <V.ERR
           lbra  ChkTrDCD       go check if DCD transition...

ChkRDRF    bitb  #Stat.RxF      Rx data?
           lbeq  ChkTrDCD       no, go check DCD transition
           lda   DataReg,x      get Rx data
RxBreak    beq   SavRxDat       its a null, go save it...
*           IFNE  H6309
*           stf   <SigSent       clear signal sent flag
*           ELSE
*           pshs  b
*           ldb   <regWbuf+1
*           stb   <SigSent
*           puls  b
*           ENDC
           clr   <SigSent
           cmpa  <V.INTR        interrupt?
           bne   Chk.Quit       no, go on...
           ldb   #S$Intrpt
           bra   SendSig

Chk.Quit   cmpa  <V.QUIT        abort?
           bne   Chk.PChr       no, go on...
           ldb   #S$Abort
SendSig    pshs  a              save Rx data
           lda   <V.LPRC        get last process' ID
           os9   F$Send
           puls  a              recover Rx data
           stb   <SigSent       set signal sent flag
           bra   SavRxDat       go save Rx data...

Chk.PChr   cmpa  <V.PCHR        pause?
           bne   Chk.Flow       no, go on...
           ldx   <V.DEV2        attached device defined?
           beq   SavRxDat       no, go save Rx data...
           sta   V.PAUS,x       yes, pause attached device
           bra   SavRxDat       go save Rx data...

Chk.Flow   equ   *
           IFNE  H6309
           tim   #TxSwFlow,<Wrk.Type Tx data software flow control enabled?
           ELSE
           pshs  a
           lda   #TxSwFlow
           bita  <Wrk.Type
           puls  a
           ENDC
           beq   SavRxDat       no, go save Rx data...
           cmpa  <V.XON         XON?
           bne   Chk.XOff       no, go on...
           IFNE  H6309
           aim   #^FCTxXOff,<FloCtlTx clear XOFF received bit
           ELSE
           pshs  a
           lda   #^FCTxXOff
           anda  <FloCtlTx
           sta   <FloCtlTx
           puls  a
           ENDC
           bra   SetTxFlo       go save new Tx flow control flags...

Chk.XOff   cmpa  <V.XOFF        XOFF?
           bne   SavRxDat       no, go save Rx data...
           ldb   #FCTxXOff      set XOFF received bit
           orb   <FloCtlTx      set software Tx flow control flag
SetTxFlo   stb   <FloCtlTx      save new Tx flow control flags
           lbra  ChkTrDCD       go check DCD transition...
SavRxDat   equ   *
           IFNE  H6309
           aim   #^FCRxSend,<FloCtlRx clear possible pending XOFF flag
           ELSE
           pshs  a
           lda   #^FCRxSend
           anda  <FloCtlRx
           sta   <FloCtlRx
           puls  a 
           ENDC
           ldx   <RxBufPut      get Rx buffer input pointer
           IFNE  H6309
           ldw   <RxDatLen      Rx get Rx buffer data length
           cmpw  <RxBufSiz      Rx buffer already full?
           ELSE
           pshs  d
           ldd   <RxDatLen
           std   <regWbuf
           cmpd  <RxBufSiz
           puls  d
           ENDC
           blo   NotOvFlo       no, go skip overflow error...
           IFNE  H6309
           oim   #OvrFloEr,<V.ERR mark RX buffer overflow error
           ELSE
           ldb   #OvrFloEr
           orb   <V.ERR
           stb   <V.ERR
           ENDC
           bra   DisRxFlo       go ensure Rx is disabled (if possible)

NotOvFlo   sta   ,x+            save Rx data
           cmpx  <RxBufEnd      end of Rx buffer?
           blo   SetLayDn       no, go keep laydown pointer
           ldx   <RxBufPtr      get Rx buffer start address
SetLayDn   stx   <RxBufPut      set new Rx data laydown pointer
           IFNE  H6309
           incw                 one more byte in Rx buffer
           stw   <RxDatLen      save new Rx data length
           cmpw  <RxBufMax      at or past maximum fill point?
           ELSE
           pshs  d
           ldd   <regWbuf
           addd  #1
           std   <regWbuf
           std   <RxDatLen
           cmpd  <RxBufMax
           puls  d
           ENDC
           blo   SgnlRxD        no, go check Rx data signal...
DisRxFlo   ldx   <V.PORT
           ldb   CmdReg,x       get current Command register contents
           IFNE  H6309
           tim   #ForceDTR,<Wrk.XTyp forced DTR?
           ELSE
           lda   #ForceDTR
           bita  <Wrk.XTyp
           ENDC
           bne   DisRxRTS       yes, go check RTS disable...
           IFNE  H6309
           tim   #DSRFlow,<Wrk.Type DSR/DTR Flow control?
           ELSE
           lda   #DSRFlow
           bita  <Wrk.Type
           ENDC
           beq   DisRxRTS       no, go check RTS disable
           IFNE  H6309
           oim   #FCRxDTR,<Wrk.Type mark RX disabled due to DTR
           ELSE
           lda   #FCRxDTR
           ora   <Wrk.Type
           sta   <Wrk.Type
           ENDC
           andb  #^Cmd.DTR      clear (disable) DTR bit
DisRxRTS   equ   *
           IFNE  H6309
           tim   #RTSFlow,<Wrk.Type
           ELSE
           lda   #RTSFlow
           bita  <Wrk.Type
           ENDC
           beq   NewRxFlo       no, go set new Rx flow control...
           IFNE  H6309
           tim   #DSRFlow,<Wrk.Type line break?
           ELSE
           lda   #DSRFlow
           bita  <Wrk.Type
           ENDC
           bne   NewRxFlo       yes, go set new Rx flow control...
           IFNE  H6309
           oim   #FCRxRTS,<FloCtlRx
           ELSE
           lda   #FCRxRTS
           ora   <FloCtlRx
           sta   <FloCtlRx
           ENDC
           andb  #^Cmd.TIRB     clear Tx IRQ/RTS/Break control bits (disable RTS)
NewRxFlo   stb   CmdReg,x       set/clear DTR and RTS in Command register
           IFNE  H6309
           tim   #RxSwFlow,<Wrk.Type Rx software flow control?
           ELSE
           ldb   <Wrk.Type
           bitb  #RxSwFlow
           ENDC
           beq   SgnlRxD        no, go check Rx data signal...
           lda   <V.XOFF        XOFF character defined?
           beq   SgnlRxD        no, go check Rx data signal...
           ldb   <FloCtlRx      get Rx flow control flags
           bitb  #FCRxSent      XOFF already sent?
           bne   SgnlRxD        yes, go check Rx data signal...
           orb   #FCRxSend      set send XOFF flag
           stb   <FloCtlRx      set new Rx flow control flags
           IFNE  H6309
           tim   #Stat.TxE,StatReg,x
           ELSE
           ldb   StatReg,x
           bitb  #Stat.TxE
           ENDC
           beq   SgnlRxD        no, go skip XOFF this time...
           sta   DataReg,x      write XOFF character
           ldb   #FCRxSent      set XOFF sent flag
           orb   <FloCtlRx      mask in current Rx flow control flags
           andb  #^FCRxSend     clear send XOFF flag
           stb   <FloCtlRx      save new flow control flags
SgnlRxD    ldb   <SigSent       already sent abort/interrupt signal?
           bne   ChkTrDCD       yes, go check DCD transition...
           lda   <SSigPID       Rx data signal process ID?
           beq   ChkTrDCD       none, go check DCD transition...
           stb   <SSigPID       clear Rx data signal
           ldb   <SSigSig       Rx data signal code
           os9   F$Send
ChkTrDCD   ldx   <V.PORT
           lda   <Cpy.Stat      get Status register copy
           tfr   a,b            copy it...
           eora  <CpyDCDSR      mark changes from old DSR+DCD status copy
           andb  #Stat.DSR!Stat.DCD clear all but DSR+DCD status
           stb   <CpyDCDSR      save new DSR+DCD status copy
           bita  <Mask.DCD      DCD transition?
           beq   CkSuspnd       no, go check for suspended process...
           bitb  <Mask.DCD      DCD disabled now?
           beq   SgnlDCD        no, go check DCD signal...
           lda   <Wrk.Type
           bita  #MdmKill       modem kill enabled?
           beq   SgnlDCD        no, go on...
           ldx   <V.PDLHd       path descriptor list header
           beq   StCDLost       no list, go set DCD lost error...
           lda   #PST.DCD       DCD lost flag
PDListLp   sta   PD.PST,x       set path status flag
           ldx   PD.PLP,x       get next path descriptor in list
           bne   PDListLp       not end of list, go do another...
StCDLost   lda   #DCDLstEr      DCD lost error flag
           ora   <V.ERR
           sta   <V.ERR
SgnlDCD    lda   <CDSigPID      get process ID, send a DCD signal?
           beq   CkSuspnd       no, go check for suspended process...
           ldb   <CDSigSig      get DCD signal code
           clr   <CDSigPID      clear DCD signal
           os9   F$Send

CkSuspnd   clrb                 clear Carry (for exit) and LSB of process descriptor address
           lda   <V.WAKE        anybody waiting? ([D]=process descriptor address)
           beq   IRQExit        no, go return...
           IFEQ  Level-1
           clr   <V.WAKE
           ldb   #S$Wake
           os9   F$Send
           ELSE
           stb   <V.WAKE        mark I/O done
           tfr   d,x            copy process descriptor pointer
           lda   P$State,x      get state flags
           anda  #^Suspend      clear suspend state
           sta   P$State,x      save state flags
           ENDC
IRQExit    puls  dp,pc          recover system DP, return...

           emod
ModSize    equ   *
           end