        PSR     1
        LIST    0
        IF      IODRIVERBODY
        LIST    1
        PAGE    *** CONSOLE: (TTY) DRIVER ***
        IF      PSITECH
TTY:KCTL        EQU     $FAF5   ; KEYBOARD PIA CONTROL REGISTER
TTY:KDAT        EQU     $FAF4   ; KEYBOARD PIA DATA REGISTER
TTYDEPTH        EQU     25
TTYWIDTH        EQU     80
IOROM:PUTC      EQU     $E006   ; PUT CHARACTER THRU I/O ROM
IOROM:GETC      EQU     $E003   ; GET A CHARACTER FROM KEYBOARD THRU ROM
IOROM:INITS     EQU     $E018   ; INITZ SCREEN VIA ROM
SCREEN  EQU     $C000   ; WHERE SCREEN STORAGE IS
CURSORPOSITION  EQU     $FE80   ; TAKEN FROM BOOT/ I/O ROM CODE
GETCDBL0FLAG    EQU     $FE87   ; "DOUBLE 00" KEY HIT FLAG FOR ROM (KLUGE, KLUGE!)
TTY:SCRNCNT     EQU     $FE80
TTY:ROWC        EQU     $FE82
TTY:COLC        EQU     $FE83
TTY:MODE        EQU     $FE84
TTY:RESTTO      EQU     $FEB8
TTY:CHARF       EQU     $FEBA
TTY:RAM EQU     $FEC0
        FIN     PSITECH
        IFUND   TTYINTINBUFSIZE
        IF      MEMSIZE<=32
TTYINTINBUFSIZE EQU     40
        ELSE
TTYINTINBUFSIZE EQU     80
        FIN     MEMSIZE<=32
        FIN     TTYINTINBUFSIZE
        IFUND   TTYLINEBUFSIZE
TTYLINEBUFSIZE  EQU     100
        FIN     TTYLINEBUFSIZE
        IFUND   TTYINTOUTBUFSIZE
        IF      MEMSIZE<=32
TTYINTOUTBUFSIZE        EQU     40
        ELSE
TTYINTOUTBUFSIZE        EQU     100
        FIN     MEMSIZE<=32
        FIN     TTYINTOUTBUFSIZE
        IFUND   TTYININTERRUPT
TTYININTERRUPT  EQU     1
        FIN     TTYININTERRUPT
        IFUND   TTYOUTINTERRUPT
TTYOUTINTERRUPT EQU     1
        FIN     TTYOUTINTERRUPT
        IFUND   TTYWIDTH
TTYWIDTH        EQU     80
        FIN     TTYWIDTH
        IFUND   TTYDEPTH
TTYDEPTH        EQU     24
        FIN     TTYDEPTH
        IFUND   LSIADM1
LSIADM1 EQU     0
        FIN     LSIADM1
        IFUND   USECONSOLEACIAASCLOCK
USECONSOLEACIAASCLOCK   EQU     0
        FIN     USECONSOLEACIAASCLOCK
        IFUND   CONSOLEACIABAUDRATE
CONSOLEACIABAUDRATE     EQU     9600    "BAUD"
        FIN

LINEFLAGS       EQU     $F0     HOLDS LINEFLAGS FOR BASIC

::      SET     *
        ORG     DCB:SIZE
*
*       TTY DCB DISPLACEMENTS
*
TTYSAVEX        RMB     2       TEMPX FOR TTY ROUTINES
TTYOLDCOLCNT    RMB     1       OLD COLUMN COUNT
TTYREADAFLAG    RMB     1       ON --> LINE INPUT, OFF --> FILL BUFFER
TTYECHO RMB     1
TTYPAGE RMB     1
TTYLINECOUNT    RMB     1
TTYIDLES        RMB     1
TTYEOF  RMB     1       END OF FILE FLAG
TTYCOLCNT       RMB     1       COLUMN COUNT ORIGIN 0
TTYBINREADMODE  RMB     1       <> 0 IS BINARY READ MODE
        IF      TTYININTERRUPT
TTYFOLDMASK     RMB     1       $FF --> DON'T FOLD; $BF --> FOLD LOWER CASE TO UPPER
TTYINLASTCHAR   RMB     1       CONTAINS LAST KEYSTROKE READ IN ASCII MODE
TTYINPUTWAIT    RMB     1       <> 0, TASK IS ASLEEP, WAITING FOR INPUT
TTYINPUTWAITPTR RMB     2
        FIN     TTYINTERRUPT
TTYPAGINGWAITPTR        RMB     2
TTYXONWAITP     EQU     *
TTYXONWAITPTR   RMB     2
TTYTABSPTR      EQU     *
TTYTABSP        RMB     2
TTYXONWAIT      RMB     1       <> 0 --> XON ARRIVED
TTYPAGINGWAIT   RMB     1       <> 0 IS IN ^P WAIT
NTTYTABS        EQU     10
        RMB     1       MUST PRECEED TTYTABS
TTYTABS RMB     NTTYTABS        DEFAULTTABS
        RMB     1       MUST FOLLOW TTYTABS
TTYBUFFERPOINTER        RMB     2       TASK LEVEL BUFFER
TTYBUFFERSTART  RMB     2
TTYBUFFEREND    RMB     2
*
*       TTY INTERRUPT BUFFERS
*
        IF      TTYOUTINTERRUPT
TTYINTOUTMPT    RMB     2       EMPTY POINTER
TTYINTOUTFILL   RMB     2       FILL POINTER
TTYINTOUTBUFP   RMB     2       POINTER TO OUTPUT BUFFER
TTYINTOUTBUFE   RMB     2       POINTER TO LAST CHAR+1
TTYINTOUTEXPECTED       RMB     1       <> 0 --> I'M EXPECTING (NO, AN INTERRUPT!)
TTYINTOUTFORCECHAR      RMB     1       <> 0 --> PRIORITY CHAR!
        FIN     TTYOUTINTERRUPT
        IF      TTYININTERRUPT
TTYINTINMPT     RMB     2       EMPTY POINTER
TTYINTINFILL    RMB     2       FILL POINTER
TTYINTINBUFP    RMB     2       POINTER TO INPUT BUFFER
TTYINTINBUFE    RMB     2       LAST CHAR+1
        FIN     TTYININTERRUPT
TTYSCREENBUSY   RMB     1       1-->TASK IS MANIPULATING SCREEN
TTYSCREENFORCE  RMB     2       POINTS TO PRIORITY START IO PLACE IN TTYININT HANDLER
        IF      TTYININTERRUPT
TTYINTINUSED    RMB     1
TTYINTINBUF     RMB     TTYINTINBUFSIZE
        FIN     TTYININTERRUPT
TTYBUFFER       RMB     TTYLINEBUFSIZE
        IF      TTYOUTINTERRUPT
TTYINTOUTFREE   RMB     1
TTYINTOUTBUF    RMB     TTYINTOUTBUFSIZE
        FIN     TTYOUTINTERRUPT
TTYDCBSIZE      EQU     *
        ORG     ::
        LIST    0
        FIN     IODRIVERBODY
***
        IF      IODRIVERRAM
        LIST    1
        PAGE    TTY DCB
*
*       THE TTY DCB MUST BE THE FIRST DEVICE DCB IN THE LIST
*
TTYDCB  FCB     1       DONE
        FDB     0
        FDB     CONSOLESTR
        FDB     DEVICEDCBS      THIS POINTS TO THE REST OF THE DCB'S
        FDB     TTYDRIVER
        RPT     TTYDCB+TTYTABS-*
        FCB     0
        RPT     NTTYTABS
        FCB     (*-TTYDCB-TTYTABS+1)*8
        RPT     TTYDCB+TTYBUFFER-*
        FCB     0
        RPT     TTYDCBSIZE-(*-TTYDCB)
        FCB     0
CONSOLESTR      FCC     'CONSOLE:'
        FCB     0
*
*NEXTDEVICEDCB  SET     TTYDCB  (WE DON'T WANT TO INCLUDE THE TTYDCB HERE)
        LIST    0
        FIN
***
        IF      IODRIVERBODY
        LIST    1
        PAGE    TTYDRIVER
TTYDRIVER       FDB     TTYOPEN
        FDB     TTYCLOSE
        FDB     TTYREADA
        FDB     TTYWRITEA
        FDB     TTYREADB
        FDB     TTYWRITEB
        FDB     TTYCREATE
        FDB     ILLDEVICEOP     RENAME
        FDB     ILLDEVICEOP     DELETE
        FDB     TTYCONTROL
        FDB     TTYSTATUS
        FDB     TTYRESET
        FDB     TTYPFRESTART
*
TTYCREATE       EQU     *
TTYOPEN LDX     DCBPOINTER
        CLR     TTYBINREADMODE,X        'ASCII READS'
        CLR     TTYEOF,X        FLAG "NO EOF"
TTYPFRESTART    EQU     *
TTYCLOSE        OKRTS
        PAGE
TTYCONTROL      LDX     SDOS+SDOS:IOBLOCKPTR
        CMPA    #CC:IDLES
        BEQ     SETTTYIDLES
        IF      MEMSIZE>32
        CMPA    #CC:ECHO
        BEQ     SETTTYECHO
        CMPA    #CC:NOECHO
        BEQ     SETTTYNOECHO
        CMPA    #CC:TABS
        BEQ     SETTTYTABS
        CMPA    #CC:POSITION
        BEQ     SETTTYPOS
        FIN     MEMSIZE>32
        JMP     ILLDEVICEOP
*
SETTTYIDLES     JSR     SDOS+SDOS:CHECKWRLEN    CHECK AT LEAST ONE BYTE
        FDB     1
        LDX     SCBLK:WRBUF,X   GET THE POINTER TO THE DATA
        LDAA    CONTROL:DATA,X
        STAA    TTYIDLES+TTYDCB
        OKRTS
*
        IF      MEMSIZE>32
SETTTYECHO      LDAA    #1
        SK1
SETTTYNOECHO    CLRA
        LDX     DCBPOINTER
        STAA    TTYECHO,X
        OKRTS
*
SETTTYTABS      JSR     SDOS+SDOS:CHECKWRLEN    THERE HAS TO BE AT LEAST 2 BYTES
        FDB     0       (COUNT, TAB)
        LDAA    SCBLK:WRLEN,X
        BNE     SETTTYPOS2      ; B/ >255 TABS!
        CLR     TTYTABS+TTYDCB  MARK END OF LIST FOR THE NO-TABS CASE
        LDAB    SCBLK:WRLEN+1,X GET NUMBER OF TAB STOPS
        BEQ     SETTTYTABS4     B/ I'M DONE (NO-TABS CASE)
        CMPB    #NTTYTABS
        BLS     SETTTYTABS1     TAKE THE MINIMUM OF THE TWO VALUES
        LDAB    #NTTYTABS
SETTTYTABS1     STAB    TEMPB
        LDX     SDOS+SDOS:IOBLOCKPTR
        LDX     SCBLK:WRBUF,X
SETTTYTABS2     LDAA    CONTROL:DATA,X
        INX
        PSHA
        DECB
        BNE     SETTTYTABS2     B/ MORE TO DO
        LDX     DCBPOINTER
        CLR     TTYTABS+NTTYTABS,X
SETTTYTABS3     PULA
        STAA    TTYTABS+NTTYTABS-1,X
        DEX
        DEC     TEMPB
        BNE     SETTTYTABS3     B/ MORE TO DO
SETTTYTABS4     OKRTS
*
SETTTYPOS       JSR     SDOS+SDOS:CHECKWRLEN
        FDB     4
        LDX     SCBLK:WRBUF,X
        LDAA    CONTROL:DATA,X  CHECK THE PARAMETERS
        ORAA    CONTROL:DATA+1,X
        BNE     SETTTYPOS2      B/ UPPER TWO BYTES ARE NEVER NON-ZERO
*
*       CURSOR POSITIONING
*       0,0,ROW,COLUMN
*
        LDAA    CONTROL:DATA+2,X        GET THE ROW
        LDAB    CONTROL:DATA+3,X        GET THE COLUMN
        ADDA    #ASCII:SPACE    CONVERT ROW, COL TO PRINTING CHARACTERS
        ADDB    #ASCII:SPACE
        PSHB            AND SAVE A MOMENT
        PSHA
        LDAA    #ASCII:DLE      DO CURSOR POSITION
        JSR     TTYOUT
        PULA
        JSR     TTYOUT
        PULA
        JSR     TTYOUT
        OKRTS
SETTTYPOS1      OKRTS
SETTTYPOS2      JMP     ILLDEVICEOP
        FIN     MEMSIZE>32
        PAGE
TTYSTATUS       LDX     SDOS+SDOS:IOBLOCKPTR
        CMPA    #SC:GETEOF
        BEQ     TTYGETEOF
        CMPA    #SC:GETCOL
        BEQ     TTYGETCOL
        CMPA    #SC:GETTYPE
        BEQ     TTYGETTYPE
        CMPA    #SC:GETPARAMS
        BEQ     TTYGETPARAMS
        IF      MEMSIZE>32
        CMPA    #SC:GETPOS
        BEQ     TTYGETPOS
        FIN     MEMSIZE>32
        JMP     ILLDEVICEOP
*
TTYGETCOL       JSR     SDOS+SDOS:CHECKRDLEN    MAKE SURE ENOUGH ROOM FOR COL CNT
        FDB     1
        LDX     SCBLK:RDBUF,X   GET BUFFER POINTER
        IF      PSITECH
        LDAA    CURSORPOSITION+1
        ELSE
        LDAA    TTYCOLCNT+TTYDCB
        FIN
        STAA    STATUS:COLUMN,X
        OKRTS
*
TTYGETEOF       JSR     SDOS+SDOS:CHECKRDLEN    MAKE SURE ENOUGH ROOM FOR EOF
        FDB     1
        LDX     SCBLK:RDBUF,X   GET POINTER TO BUFFER
        LDAA    TTYEOF+TTYDCB
        STAA    STATUS:EOFFLAG,X
        OKRTS
        IF      MEMSIZE>32
*
*       CURSOR POSITION SENSE
*       RETURN 0,0,ROW,COLUMN
*
TTYGETPOS       EQU     *
        JSR     SDOS+SDOS:CHECKRDLEN
        FDB     4
        LDX     SCBLK:RDBUF,X
        CLR     STATUS:DATA,X
        CLR     STATUS:DATA+1,X
        IF      PSITECH
        LDAA    CURSORPOSITION
        SUBA    #SCREEN/256     SUBTRACT OF BASE OF SCREEN BIAS
        STAA    STATUS:DATA+2,X
        LDAA    CURSORPOSITION+1
        STAA    STATUS:DATA+3,X
        ELSE
        LDAA    TTYCOLCNT+TTYDCB
        STAA    STATUS:DATA+3,X
        LDAA    TTYLINECOUNT+TTYDCB
        STAA    STATUS:DATA+2,X
        FIN
        OKRTS
        FIN     MEMSIZE
*
TTYGETTYPE      JSR     SDOS+SDOS:CHECKRDLEN    MAKE SURE ENOUGH ROOM FOR TTY INFO
        FDB     1
        LDX     SCBLK:RDBUF,X   GO GET THE BUFFER
        LDAA    #DVTYP.CONSOLE
        STAA    DVTYP:TYPE,X
        OKRTS

TTYGETPARAMS    EQU     *
        JSR     SDOS+SDOS:CHECKRDLEN
        FDB     2
        LDX     SCBLK:RDBUF,X
        LDAA    #TTYWIDTH
        LDAB    #TTYDEPTH
        STAA    DVDAT:WIDTH,X
        STAB    DVDAT:DEPTH,X
        OKRTS
        PAGE
TTYREADA        LDX     DCBPOINTER
        CLR     TTYBINREADMODE,X        "WE'RE NOT DOING BINARY READS"
        TST     TTYEOF,X        HIT EOF ?
        BNE     TTYREADA6       B/ YES, GIVE UP QUICK
        LDX     SDOS+SDOS:IOBLOCKPTR
        LDX     READA:BUFFERP,X
        STX     BUFFERPOINTER
        LDX     DCBPOINTER
        LDAA    TTYCOLCNT,X
        STAA    TTYOLDCOLCNT,X
        LDX     SDOS+SDOS:IOBLOCKPTR
        LDAA    READA:LMFLAG,X
        STAA    TTYREADAFLAG+TTYDCB
        LDX     READA:MAXCOUNT,X
        STX     COUNT
        BEQ     TTYREADA5       B/ NOTHING TO DO
TTYREADA1       BSR     TTYENDOFBUF
        BNE     TTYREADA0
        JMP     TTYREADA7       B/ YES, GO FILL IT AGAIN
TTYREADA0       LDAA    0,X
        INX
        CMPA    #ASCII:CR
        BEQ     TTYREADA2       B/ IT'S A CR
        CMPA    #ASCII:SUB       EOF HIT?
        BNE     TTYREADA3       B/ NOT A CONTROLZ
        STAA    TTYEOF+TTYDCB   IS ^Z, FORCE EVENTUAL EOF ERROR
TTYREADA2       LDX     TEMPX   NEXT TIME, I WILL FIND THE BUFFER EMPTY
TTYREADA3       STX     TTYBUFFERPOINTER+TTYDCB
        CMPA    #ASCII:SUB
        BEQ     TTYREADA6       B/ TIME TO QUIT
        LDX     BUFFERPOINTER
        STAA    0,X
        INX
        STX     BUFFERPOINTER
        LDX     COUNT
        DEX
        STX     COUNT
        BEQ     TTYREADA4       B/ ALL BYTES READ IN
        CMPA    #ASCII:CR     WAS IT A CR ?
        BNE     TTYREADA1       B/ NO
        LDAA    TTYREADAFLAG+TTYDCB     LINE INPUT MODE?
        BEQ     TTYREADA1       B/ NO
TTYREADA4       LDX     SDOS+SDOS:IOBLOCKPTR
        LDAA    READA:MAXCOUNT,X
        LDAB    READA:MAXCOUNT+1,X
        SUBB    COUNT+1
        SBCA    COUNT
        STAA    READA:ACTUALCOUNT,X
        STAB    READA:ACTUALCOUNT+1,X
TTYREADA5       OKRTS
*
TTYREADA6       JSR     SDOS+SDOS:ERROR
        FDB     ERR:EOFHIT
*
*       FILL THE BUFFER (USING INPUT EDITING)
*
TTYENDOFBUF     LDX     TTYBUFFEREND+TTYDCB
        STX     TEMPX
        LDX     TTYBUFFERPOINTER+TTYDCB
        CPX     TEMPX
        RTS
*
*       STX     TTYBUFFERPOINTER,DCBPOINTER
*
TTYSTXBUFPTR    EQU     *
        STX     TTYBUFFERPOINTER+TTYDCB
        RTS
*
*       STX     TTYSAVEX,DCBPOINTER
*
TTYSTXSAVX      STX     TTYSAVEX+TTYDCB
        RTS
*
*       THIS IS A CPX TTYBUFFERSTART,DCBPOINTER ROUTINE
*       THUS, IT MUST PRESERVE X
*       TEMPX, HOWEVER, IS NOT SO LUCKY
TTYCPXBUFST     CPX     TTYBUFFERSTART+TTYDCB
        RTS
*
*       CPX     TTYBUFFEREND,DCBPOINTER
*
TTYCPXBUFEND    CPX     TTYBUFFEREND+TTYDCB
        RTS
*
*       CPX     TTYBUFFERPOINTER,DCBPOINTER
*
TTYCPXBUFPTR    CPX     TTYBUFFERPOINTER+TTYDCB
        RTS
*
*       DEX
*       PSHA
*       CPX     TTYBUFFEREND,DCBPOINTER
*       TPA
*       INX
*       TAP
*       PULA
TTYCPXBUFENDM1  INX
        PSHA
        CPX     TTYBUFFEREND+TTYDCB
        TPA
        DEX
        TAP
        PULA
        RTS
*
*
*       CPX     TTYINTINBUFFEREND,DCBPOINTER
*
TTYCPXINBUFE    EQU     *
        CPX     TTYINTINBUFE+TTYDCB
        RTS
*
*       STX     TTYINTINMPT,DCBPOINTER
*
TTYSTXINMPT     STX     TTYINTINMPT+TTYDCB
        RTS
*
*
*
*
*       CPX     TTYINTOUTBUFE,DCBPOINTER
*
        IF      TTYOUTINTERRUPT
TTYCPXOUTBUFE   CPX     TTYINTOUTBUFE+TTYDCB
        RTS
*
*       STX     TTYINTOUTFILL,DCBPOINTER
*
TTYSTXOUTFILL   STX     TTYINTOUTFILL+TTYDCB
        RTS
        FIN     TTYOUTINTERRUPT
*
TTYRESETBUFP    LDX     TTYBUFFERSTART+TTYDCB
        STX     TTYBUFFERPOINTER+TTYDCB
        RTS
TTYREADA7       BSR     TTYRESETBUFP
*
*       NOW GET THE STUFF
*
TTYREADA8       JSR     TTYIN
        BCS     TTYREADA80      B/ ATTENTION REQUEST
        ANDA    #$7F
        BEQ     TTYREADA8       B/ IGNORE NULLS
        CMPA    #ASCII:LF
        BEQ     TTYREADA8       B/ IGNORE LINEFEEDS
        CMPA    #ASCII:ETX
        BEQ     TTYREADA4J      GIVE HIM WHAT WE HAVE SO FAR
*                       SDOS WILL BLOW HIM AWAY BECAUSE OF KILL
*                       USER PROGRAM CALL BY INTERRUPT ROUTINE
*
*       HERE WE GO...
*
TTYREADA81      CMPA    #ASCII:SUB       CHECK FOR END OF FILE ON CONSOLE
        BNE     TTYREADA10      B/ NOT A CONTROL-Z
        JSR     TTYSTUFFINBUFF
        JSR     TTYPUTECHO      SHOW IT TO HIM
TTYREADA9       BSR     TTYRESETBUFP
        JMP     TTYREADA1
*
TTYREADA80      LDX     TTYBUFFEREND+TTYDCB
        STX     TTYBUFFERPOINTER+TTYDCB
        JSR     SDOS+SDOS:ERROR
        FDB     ERR:ATTENTION
*
TTYREADA91      BSR     TTYRESETBUFP
TTYREADA4J      JMP     TTYREADA4
*
TTYREADA10      CMPA    #ASCII:CR
        BNE     TTYREADA11
        JSR     TTYSTUFFINBUFF
        JSR     TTYPUTECHO
        JSR     TTYENDOFBUF
        BEQ     TTYREADA9       B/ YES, QUIT REGARDLESS OF LINE MODE
        TST     TTYREADAFLAG+TTYDCB     LINE INPUT MODE?
        BEQ     TTYREADA8       B/ NO, DON'T QUIT NOW
        BRA     TTYREADA9
*
TTYREADA11      CMPA    #ASCII:CAN       IS IT A LINE DELETE?
        BNE     TTYREADA15      B/ NOPE
        JSR     TTYPUTECHO      ECHO IT AS ^X
        JSR     TTYCRLF PRINT A NEW LINE & CLEAR THE COLUMN COUNT
        LDX     DCBPOINTER
        LDX     TTYBUFFERPOINTER,X
TTYREADA12      JSR     TTYCPXBUFST     AT BEGINNING OF BUFFER?
        BEQ     TTYREADA13      B/ YES, I WON'T TOUCH THE COUNT OR THE POINTER
        DEX
        LDAA    0,X
        CMPA    #ASCII:CR     ARE WE AT THE BEGINNING OF A LINE?
        BNE     TTYREADA12      B/ NO
        INX
TTYREADA13      JSR     TTYSTXBUFPTR
TTYREADA14      BRA     TTYREADA8
*
TTYREADA15      CMPA    #ASCII:RUBOUT
        BNE     TTYREADA16      B/ NOPE
        LDX     DCBPOINTER
        LDX     TTYBUFFERPOINTER,X
        JSR     TTYCPXBUFST     BEGINNING OF THE BUFFER?
        BEQ     TTYREADA14      B/ YES
        DEX
        LDAA    0,X
        CMPA    #ASCII:CR     BEGINNING OF LINE?
        BEQ     TTYREADA14      B/ YES
        JSR     TTYSTXBUFPTR
        LDAA    0,X
        JSR     TTYPUTECHO
        BRA     TTYREADA14
*
TTYREADA16      CMPA    #ASCII:BS       IS IT A CONTROL-H?
        BNE     TTYREADA25      B/ NOPE
        LDX     DCBPOINTER
        LDX     TTYBUFFERPOINTER,X
        JSR     TTYCPXBUFST
        BEQ     TTYREADA17      B/ YES
        DEX             EAT ONE CHAR
        LDAA    0,X
        CMPA    #ASCII:CR     BEGINNING OF LINE?
        BNE     TTYREADA17      B/ NO
        INX
TTYREADA17      JSR     TTYSTXBUFPTR
*
*       FIND THE LEFT MARGIN
*
        INX
        LDAB    TTYOLDCOLCNT+TTYDCB
TTYREADA18      DEX
        JSR     TTYCPXBUFST     BEGINNING OF BUFFER?
        BEQ     TTYREADA19      B/ YES
        LDAA    0,X
        CMPA    #ASCII:CR     BEGINNING OF LINE?
        BNE     TTYREADA18      B/ NO
        INX
        CLRB
TTYREADA19      LDAA    TTYCOLCNT+TTYDCB
        STAB    TTYCOLCNT+TTYDCB
*       THIS IS WHERE WE MEASURE FROM
        PSHA
*
*       SCAN THE BUFFER COMPUTING THE COLUMN COUNT
*
TTYREADA20      JSR     TTYCPXBUFPTR    END OF BUFFER?
        BEQ     TTYREADA23      B/ YES, I'VE COUNTED ALL THE CHARACTERS
        LDAB    0,X
        INX
        LDAA    #1
        CMPB    #ASCII:SPACE-1
        BHI     TTYREADA21
        INCA
TTYREADA21      CMPB    #ASCII:HT
        BNE     TTYREADA22
        JSR     EXPANDTABSWECHO
TTYREADA22      ADDA    TTYCOLCNT+TTYDCB
        STAA    TTYCOLCNT+TTYDCB
        BRA     TTYREADA20      B/ MORE TO DO
*
*       COMPUTE THE DIFFERENCE BETWEEN CALCULATED
*       COLCNT AND ACTUAL POSITION
*
TTYREADA23      LDX     DCBPOINTER
        LDAA    TTYCOLCNT,X
        PULB
        SBA
        JSR     SPACE
TTYREADA24      JMP     TTYREADA8
*
TTYREADA25      CMPA    #ASCII:DC2       RETYPE REQUEST?
        BNE     TTYREADA29      B/ NO
        JSR     TTYPUTECHO      ECHO IT AS ^R
        JSR     TTYCRLF PRINT A NEW LINE & CLEAR THE COLUMN COUNT
        LDX     DCBPOINTER
        LDX     TTYBUFFERPOINTER,X
        JSR     TTYCPXBUFST
        BEQ     TTYREADA27
TTYREADA26      DEX
        JSR     TTYCPXBUFST
        BEQ     TTYREADA27      B/ BEGINNING OF BUFFER
        LDAA    0,X
        CMPA    #ASCII:CR
        BNE     TTYREADA26
        INX
TTYREADA27      JSR     TTYCPXBUFPTR
        BEQ     TTYREADA24      B/ DONE
        LDAA    0,X
        INX
        CMPA    #ASCII:HT
        BNE     TTYREADA28      B/ NOT A TAB
        JSR     EXPANDTABSWECHO
        TAB
        ADDB    TTYCOLCNT+TTYDCB
        STAB    TTYCOLCNT+TTYDCB
        JSR     SPACE
        BRA     TTYREADA27
TTYREADA28      JSR     TTYPUTECHO
        BRA     TTYREADA27
*
TTYREADA29      LDX     DCBPOINTER
        LDX     TTYBUFFERPOINTER,X
        JSR     TTYCPXBUFENDM1  IS IT THE LAST HOLE?
        BNE     TTYREADA30      B/ NO, ANY CHAR IS OK
        LDAA    #ASCII:BEL
        JSR     TTYOUT  SOUND OFF, THEN GO GET ANOTHER CHAR
        BRA     TTYREADA24
*
TTYREADA30      CMPA    #ASCII:HT
        BNE     TTYREADA31
        BSR     TTYSTUFFINBUFF
        JSR     EXPANDTABSWECHO
        TAB
        LDX     DCBPOINTER
        ADDB    TTYCOLCNT,X
        STAB    TTYCOLCNT,X
        JSR     SPACE
        BRA     TTYREADA24
*
TTYREADA31      BSR     TTYSTUFFINBUFF
        JSR     TTYPUTECHO
        BRA     TTYREADA24
*
TTYSTUFFINBUFF  LDX     TTYBUFFERPOINTER+TTYDCB
        STAA    0,X
        INX
        STX     TTYBUFFERPOINTER+TTYDCB
        RTS
        PAGE
TTYWRITEA       BSR     TTYSTARTIO
        BEQ     TTYWRITEA7      B/ NOTHING TO DO!
TTYWRITEA1      LDX     DCBPOINTER      XOFF SEEN?
        LDAA    TTYXONWAIT,X
        BNE     TTYWRITEA2      B/ NOPE
        LDX     TTYXONWAITPTR,X
        JSR     SDOS+SDOS:WAITEVENT     YES, WAIT FOR XON
TTYWRITEA2      LDX     BUFFERPOINTER
        LDAA    0,X
        INX
        STX     BUFFERPOINTER
        ANDA    #$7F
        CMPA    #ASCII:BEL
        BNE     TTYWRITEA3
        JSR     TTYOUT
        BRA     TTYWRITEA5
TTYWRITEA3      CMPA    #ASCII:HT
        BNE     TTYWRITEA8
        JSR     EXPANDTABS
        TAB
        LDX     DCBPOINTER
        ADDB    TTYCOLCNT,X
        STAB    TTYCOLCNT,X
        JSR     SPACE
        BRA     TTYWRITEA5

TTYWRITEA8      CMPA    #ASCII:BS       BACKSPACE?
        BNE     TTYWRITEA4      B/ NO
        LDX     DCBPOINTER
        LDAB    TTYCOLCNT,X
        DEC     TTYCOLCNT,X
        JSR     TTYOUT
        BRA     TTYWRITEA6

TTYWRITEA4      JSR     TTYPUTCHAR
*
*       CHECK PAGING
*
TTYWRITEA5      LDX     DCBPOINTER
        LDAB    TTYPAGE,X
        BITB    #1      ODD? (PAGING ON?)
        BEQ     TTYWRITEA6      B/ NOPE
        CMPA    #ASCII:CR     YES, NOW CHECK IF END OF LINE
        BNE     TTYWRITEA6      B/ NOT END OF LINE
        LDAA    TTYLINECOUNT,X
        CMPA    #TTYDEPTH-1     ARE WE READY TO WAIT?
        BMI     TTYWRITEA6      B/ NOT YET
        CLR     TTYLINECOUNT,X
        LDX     TTYPAGINGWAITPTR,X
        CLR     0,X
        JSR     SDOS+SDOS:WAITEVENT
*
TTYWRITEA6      LDX     COUNT
        DEX
        STX     COUNT
        BNE     TTYWRITEA1      B/ MORE TO DO
TTYWRITEA7      OKRTS
*
TTYSTARTIO      LDX     SDOS+SDOS:IOBLOCKPTR
        LDX     WRITEA:BUFFERP,X
        STX     BUFFERPOINTER
        LDX     SDOS+SDOS:IOBLOCKPTR
        LDX     WRITEA:COUNT,X
        STX     COUNT
        RTS
        PAGE
TTYWRITEB       EQU     *
        LDX     DCBPOINTER
        CLR     TTYCOLCNT,X
        BSR     TTYSTARTIO
        BEQ     TTYWRITEB4
TTYWRITEB1      LDX     BUFFERPOINTER
        LDAA    0,X
        INX
        STX     BUFFERPOINTER
        JSR     TTYOUT
        LDX     COUNT
        DEX
        STX     COUNT
        BNE     TTYWRITEB1      B/ MORE TO DO
TTYWRITEB3      EQU     *
TTYWRITEB4      OKRTS
        PAGE
TTYREADB        EQU     *
        LDAA    #1      SELECT "BINARY MODE"
        LDX     DCBPOINTER
        STAA    TTYBINREADMODE,X
        JSR     ATTNCHECK       FORGET ANY RECENT ATTENTIONS
        LDX     DCBPOINTER
        TST     TTYEOF,X
        BNE     TTYREADB3       B/ EOF HIT, ERROR HIM
        LDX     SDOS+SDOS:IOBLOCKPTR
        LDX     READB:BUFFERP,X
        STX     BUFFERPOINTER
        LDX     SDOS+SDOS:IOBLOCKPTR
        LDX     READB:MAXCOUNT,X
        STX     COUNT
        BEQ     TTYREADB2       B/ NOTHING TO DO (HOW STUPID!)
TTYREADB1       BSR     TTYIN
        LDX     BUFFERPOINTER
        STAA    0,X
        INX
        STX     BUFFERPOINTER
        LDX     COUNT
        DEX
        STX     COUNT
        BNE     TTYREADB1
        JMP     TTYREADA4
TTYREADB2       OKRTS
*
TTYREADB3       JSR     SDOS+SDOS:ERROR
        FDB     ERR:EOFHIT
        PAGE
LINE    JSR     INTDISABLE
        LDAA    LINEFLAGS
        JMP     INTENABLE       MUST PRESERVE (A)
*
ATTNCHECK       LDAA    LINEFLAGS
        BPL     ATTNCHECK1
        JSR     INTDISABLE
        LDAA    LINEFLAGS
        ANDA    #$7F    MASK OFF ESC BIT
        STAA    LINEFLAGS
        JSR     INTENABLE
        JSR     SDOS+SDOS:ERROR
        FDB     ERR:ATTENTION
ATTNCHECK1      OKRTS
        PAGE    PHYSICAL TTY I/O
TTYIN   PSHB
        JSR     TTYSTXSAVX
        IF      TTYININTERRUPT
        LDX     DCBPOINTER      INPUT AVAILABLE ?
        LDX     TTYINTINBUFP,X
        LDAA    0,X
        BNE     TTYIN1  B/ YES
        INC     TTYINPUTWAIT+TTYDCB
        LDAA    #TTYINWAIT/256  WAIT FOR CHARACTER OR ATTENTION REQUEST
        LDAB    #TTYINWAIT&$FF
        JSR     SDOS+SDOS:WAITCOND      ...
        LDX     DCBPOINTER
        CLR     TTYINPUTWAIT,X
TTYIN1  EQU     *
        JSR     ATTNCHECK       ATTENTION OCCUR ?
        BCS     TTYINXIT        B/ YES, GIVE UP NOW!
        LDX     DCBPOINTER
        LDX     TTYINTINMPT,X
        LDAA    1,X
        DEC     TTYINTINUSED+TTYDCB     HEY WE GOT ONE!
        INX
        JSR     TTYCPXINBUFE
        BNE     TTYIN2  B/ NO, SAVE ADJUSTED POINTER
        LDX     DCBPOINTER
        LDX     TTYINTINBUFP,X
TTYIN2  JSR     TTYSTXINMPT
        ELSE
        JSR     IOROM:GETC
        FIN     TTYININTERRUPT
        LDX     DCBPOINTER
        LDX     TTYSAVEX,X
TTYINXIT        PULB
        RTS
        IF      TTYININTERRUPT
TTYINWAIT       EQU     *
        LDAA    LINEFLAGS       WAIT FOR ATTENTION OR INPUT
        ANDA    #$80
        ORAA    TTYDCB+TTYINTINUSED
        RTS
        FIN     TTYININTERRUPT
        PAGE
TTYOUT  PSHB
        PSHA
        JSR     TTYSTXSAVX
        LDX     DCBPOINTER
        IF      PSITECH
        INC     TTYSCREENBUSY,X
        JSR     IOROM:PUTC
        LDX     DCBPOINTER
        DEC     TTYSCREENBUSY,X
        LDX     TTYSCREENFORCE,X        DID INTERRUPT WANT TO FORCE OUT A CHAR?
        BEQ     TTYOUT0 B/NO
        JSR     SDOS+SDOS:STARTIO       YES, WAKE UP INTERRUPT ROUTINE
        FIN     PSITECH
TTYOUT0 EQU     *
        IF      TTYOUTINTERRUPT
        LDX     DCBPOINTER
        LDX     TTYINTOUTBUFP,X
        LDAB    0,X     ... ?
        BNE     TTYOUT1 B/ YES, GO STUFF CHARACTER INTO BUFFER
        JSR     SDOS+SDOS:WAITEVENT     NO, WAIT FOR BUFFER SPACE
        TSX             GET CHARACTER BACK
        LDAA    0,X
TTYOUT1 LDX     DCBPOINTER      STUFF CHAR INTO OUTPUT BUFFER
        LDX     TTYINTOUTFILL,X
        STAA    1,X
        DEC     TTYINTOUTFREE+TTYDCB    HEY BOY, FETCH!
        INX             BUMP BUFFER FILL POINTER
        JSR     TTYCPXOUTBUFE   AT END OF BUFFER?
        BNE     TTYOUT2 B/ NO, SAVE ADJUSTED POINTER
        LDX     DCBPOINTER
        LDX     TTYINTOUTBUFP,X
TTYOUT2 JSR     TTYSTXOUTFILL   SAVE POINTER
        IF      REALTIMECLOCK
        LDX     DCBPOINTER
        LDAA    TTYINTOUTEXPECTED,X     WILL TTY INT SERVICE HANDLE CHARACTER ?
        BNE     TTYOUT3 B/ YES, JUST GET OUT!
        LDX     #TTYINTOUTSERVICE       NO, FAKE AN INTERRUPT
        JSR     SDOS+SDOS:STARTIO
TTYOUT3 EQU     *
        FIN     REALTIMECLOCK
        FIN     TTYOUTINTERRUPT
        LDX     DCBPOINTER
        LDX     TTYSAVEX,X
        PULA
        PULB
        RTS
        PAGE
SPACE   TAB
        BEQ     SPACE3  B/ NOTHING TO DO
        BMI     SPACE2  B/ BACKSPACE
*
*       FORWARD SPACE
*
SPACE1  LDAA    #ASCII:SPACE
        JSR     TTYOUT
        DECB
        BNE     SPACE1
        RTS
*
*       BACKSPACE
*
SPACE2  LDAA    #ASCII:BS
        JSR     TTYOUT
        LDAA    #ASCII:SPACE
        JSR     TTYOUT
        LDAA    #ASCII:BS
        JSR     TTYOUT
        INCB
        BNE     SPACE2
SPACE3  RTS
        PAGE
EXPANDTABSWECHO TST     TTYECHO+TTYDCB
        BNE     EXPANDTABS
        CLRA
        RTS
EXPANDTABS      STX     TEMPX
        LDX     DCBPOINTER
        LDAB    TTYCOLCNT,X
        LDX     TTYTABSPTR,X
EXPANDTABS0     INCB            MAKE IT ORIGIN 1
EXPAND1 LDAA    0,X     GET A TAB STOP FROM THE LIST
        BEQ     EXPAND2 B/ END OF LIST
        INX
        SBA
        BLS     EXPAND1 B/ HAVEN'T FOUND IT YET, KEEP LOOKING
        DECA
EXPAND2 INCA
        LDX     TEMPX
        RTS
        PAGE
TTYPUTECHO      EQU     *
        TST     TTYECHO+TTYDCB  ECHO ON?
        BNE     TTYPUTCHAR      B/ YES
        RTS             DON'T PRINT ANYTHING
TTYCRLF LDAA    #ASCII:CR
TTYPUTCHAR      PSHA
        TAB
        ANDB    #$7F    IN CASE HE'S USING PARITY
        CMPB    #ASCII:RUBOUT
        BEQ     TTYPUTCHAR4
        CMPB    #ASCII:CR
        BNE     TTYPUTCHAR6
        INC     TTYLINECOUNT+TTYDCB
        JSR     TTYOUT
        LDAA    #ASCII:LF
        JSR     TTYOUT
        IF      &PSITECH
        LDAB    TTYIDLES+TTYDCB
        BEQ     TTYPUTCHAR5     B/ I'M DONE
TTYPUTCHAR1     LDAA    #ASCII:NULL
        JSR     TTYOUT
        DECB
        BNE     TTYPUTCHAR1
TTYPUTCHAR5     EQU     *
        FIN     &PSITECH
        CLR     TTYCOLCNT+TTYDCB        CLEARED ON A CR
        CLR     TTYOLDCOLCNT+TTYDCB
        PULA
        RTS
TTYPUTCHAR6     CMPB    #ASCII:FF       IS IT FORM FEED
        BNE     TTYPUTCHAR2
        JSR     TTYOUT
        CLR     TTYCOLCNT+TTYDCB
        CLR     TTYLINECOUNT+TTYDCB
        PULA
        RTS
TTYPUTCHAR2     CMPB    #ASCII:SPACE-1        IS IT A CONTROL CHAR?
        BHI     TTYPUTCHAR3     B/ NO
        LDAA    #'^
        JSR     TTYOUT
        INC     TTYCOLCNT+TTYDCB
        TBA
        ADDA    #$40    MAKE IT PRINTABLE
TTYPUTCHAR3     INC     TTYCOLCNT+TTYDCB
TTYPUTCHAR4     JSR     TTYOUT
        PULA
        RTS
        PAGE    TTY INTERRUPT DRIVERS
        IF      TTYININTERRUPT
TTYINTINSERVICE EQU     *
        IF      PSITECH
        LDAA    TTY:KDAT        GET KEYSTROKE AND ACK THE INTERRUPT
        CMPA    #$7F    IS IT A FUNCTION KEY?
        BLS     TTYINITINCON5   B IF SMALLER THEN F KEYS
        CMPA    #$8F    IS IT TO BIG TO BE F KEY?
        BHI     TTYINITINCON5   B IF NOT F KEY
        ANDA    #$0F    ONLY LOWER 4 BITS COUNT
        PSHA
        LDAA    #PACETBL2/256   THIS IS A TRICK FROM IRA
        PSHA
        TSX
        LDX     0,X
        INS
        INS
        LDAA    PACETBL2&$FF,X
TTYINITINCON5   TST     TTYBINREADMODE+TTYDCB   BINARY READ MODE ?
        BNE     TTYINTINCON4    B/ YES, LEAVE KEYSTROKE ALONE!
        IF      MEMSIZE>32
        CMPA    #$8B    PRINT PAGE KEY ?
        BEQ     TTYINTINCONP    B/ YES
        FIN     MEMSIZE>32
        CMPA    #$C3    CLEAR SCREEN ?
        BEQ     TTYINTINCON3    B/ YES, GO DO IT!
        CMPA    #$CD    DOUBLE 00 KEY ?
        BEQ     TTYINTINCON00   B/ YES, GO HANDLE IT
        CMPA    #$C0-1  KEY FROM RIGHT HAND KEYPAD ?
        BLS     TTYINTINCON2    B/ NO, LEAVE IT ALONE!
        CMPA    #$CF    ... ?
        BHI     TTYINTINCON2    B/ NO
        PSHA            TRANSLATE FROM FUNNY CODE GIVEN BY KEYBOARD
        LDAA    #(PACETABLE-$C0)/256    TO CODE APPROPRIATE FOR PRINTING ON KEY
        PSHA            NOW STACK HAS POINTER TO TRANSLATED CHARACTER
        TSX             TRANSLATE THE CHARACTER
        LDX     0,X
        INS
        INS
        LDAA    (PACETABLE-$C0)&$FF,X
        BRA     TTYINTINCON2    GO TREAT LIKE REGULAR CHARACTER

        IF      MEMSIZE>32
TTYINTINCONP    EQU     *       PRINT PAGE KEY HIT
        STAA    PPREQUEST       TELL PRINT TASK
        JMP     SDOS+SDOS:RTI   AND GO AWAY...
        FIN     MEMSIZE>32

PACETABLE       EQU     *       TRANSLATE TABLE FOR KEYCODES $C0-$CF
        FCC     "789X456123"
        FCB     $0D     (RETURN KEY)
        FCC     "0X.    "       "X" MEANS SPECIAL CASE
PACETBL2        EQU     *       TRANSLATE TABLE FOR FUNCTION KEYS(AND ARROWS)
        FCB     $B1,$B2,$B3,$B4,$B5,$B6,$B7,$B8
        FCB     $B9,$E1,$E2,$8B,$08,$0C,$0B,$0A


TTYINTINCON3    EQU     *       CLEAR THE SCREEN
        JSR     IOROM:INITS
        JMP     SDOS+SDOS:RTI   AND EXIT

TTYINTINCON4    EQU     *
        JMP     TTYINTINSERV4

TTYINTINCON00   EQU     *       DOUBLE ZERO KEY HIT
        LDAA    #'0     GET THE FIRST ZERO CHARACTER
        STAA    GETCDBL0FLAG    REMEMBER THERE'S ANOTHER 0 COMING!
        ELSE
        LDAA    TTYACIA+1
        FIN     PSITECH
TTYINTINCON2    EQU     *
        IF   IDBTRAP
        LDX     IDBBASE+1       SEE IF IDB IS AROUND
        CPX     #$01BD  THIS TRICK IS CALLED "CARNAL KNOWLEDGE" (SHUDDER!)
        BNE     TTYINTSERV0     B/ CAN'T BE DEBUG REQUEST
        CMPA    #ASCII:EOT       IS IT A DEBUG REQUEST?
        BNE     TTYINTSERV0     B/ NO
        LDAA    SDOS+SDOS:KILLPROOF     IS HE KILL PROOF?
        BEQ     TTYINTCTLDA
        JMP     TTYINTINEXIT    B/ YES, IGNORE ^D
TTYINTCTLDA     EQU     *
        NOP
        SEI
        LDAA    TTYSCREENBUSY+TTYDCB
        BEQ     TTYINTCTLD0
        LDX     #TTYINTCTLD0
        STX     TTYSCREENFORCE+TTYDCB
        BRA     TTYINTINEXITJ
TTYINTCTLD0     EQU     *
        LDX     #0
        STX     TTYSCREENFORCE+TTYDCB
        LDAA    SDOS+SDOS:STACKSWITCHED =0 IF WE INTERRUPTED TASK LEVEL ROUTINE
        BNE     TTYINTCTLD1     B/ WE INTERRUPTED INTERRUPT LEVEL ROUTINE
        LDX     SDOS+SDOS:CURRENTASK
        LDS     TCB:STACK,X
TTYINTCTLD1     DEC     SDOS+SDOS:STACKSWITCHED
        JMP     IDBBASE+$8      = NMI ENTRY POINT FOR "IDB"
        FIN     IDBTRAP
****    USE PARITY MASK HERE FOR EPA TTYBUG ??? ****
TTYINTSERV0     CMPA    #ASCII:ETX       IS IT A CONTROL-C?
        BNE     TTYINTINSERV2   B/ NO
        IF      PSITECH
        LDAA    TTYSCREENBUSY+TTYDCB
        BEQ     TTYINTSERVCC1
        LDX     #TTYINTSERVCC
        STX     TTYSCREENFORCE+TTYDCB
        ELSE
        BRA     TTYINTSERVCC
        FIN     PSITECH
TTYINTINEXITJ   JMP     TTYINTINEXIT


TTYINTSERVCC    EQU     *
TTYINTSERVCC1   EQU     *
        IF      PSITECH
        LDX     #0
        STX     TTYSCREENFORCE+TTYDCB
        LDAA    #'^
        JSR     IOROM:PUTC
        LDAA    #'C
        JSR     IOROM:PUTC
        ELSE
        JSR     TTYINTOUTFORCE
        FIN     PSITECH
        LDAB    #ASCII:ETX
        CMPB    TTYINLASTCHAR+TTYDCB    HAVE WE SEEN ONE BEFORE?
        BNE     TTYINTINSERV1   B/ NO
        CLR     TTYINLASTCHAR+TTYDCB    ^C^C, NEW BALL GAME IS NEXT
        JSR     SDOS+SDOS:KILLUSERPROGRAM       TWO IN A ROW, THAT'S DEADLY
        BCS     TTYINTINEXITJ1  B/ THIS GUY'S KILL PROOF
        LDAA    #ASCII:ETX
******* TIMING SPLINTERS OCCUR HERE! ******
        CLRB
        STAB    LINEFLAGS
        STAB    TTYINTINUSED+TTYDCB     REAM THE INPUT BUFFERS
        LDX     TTYINTINMPT+TTYDCB
        STX     TTYINTINFILL+TTYDCB
        LDX     #TTYBUFFER+TTYLINEBUFSIZE+TTYDCB
        STX     TTYBUFFERPOINTER+TTYDCB
        STAB    TTYPAGE+TTYDCB  TURN OFF PAGING COUNT
        STAA    TTYXONWAIT+TTYDCB       CLEAR ANY XOFF'S
        STAA    TTYPAGINGWAIT+TTYDCB
TTYINTINSERV1   STAB    TTYINLASTCHAR+TTYDCB
        BNE     TTYINTINEXITJ1  B/ FIRST ^C
        LDAB    TTYINPUTWAIT+TTYDCB     SEE IF TASK IS WAITING FOR INPUT
        BNE     TTYINTINSERV4J  B/ YES
TTYINTINEXITJ1  JMP     TTYINTINEXIT
TTYINTINSERV4J  JMP     TTYINTINSERV4
*
TTYINTINSERV2   STAA    TTYINLASTCHAR+TTYDCB
        LDAB    #$80
        CMPA    #ASCII:DLE
        BEQ     TTY:CONTROLP
        CMPA    #ASCII:DC1
        BEQ     TTY:XON
        CMPA    #ASCII:DC3
        BEQ     TTY:XOFF
        CMPA    #ASCII:BEL
        BEQ     TTY:CONTROLG
        CMPA    #ASCII:STX
        BEQ     TTY:CONTROLB
        CMPA    #ASCII:DC4
        BEQ     TTY:CONTROLT
        CMPA    #ASCII:SYN          SINGLE STEP  ???
        BEQ     TTY:SINGLESTEP
        CMPA    #ASCII:SOH      CONTROL A ?
        BEQ     TTY:CONTROLA    B/ YES
        CMPA    #ASCII:ESC
        BNE     TTYINTINFOLD
        BRA     TTY:ESCAPE
*
TTY:CONTROLG    LSRB
TTY:SINGLESTEP  LSRB
TTY:CONTROLB    LSRB
TTY:CONTROLT    LSRB
TTY:ESCAPE      ORAB    LINEFLAGS
        STAB    LINEFLAGS
        BRA     TTYINTINEXIT
*
TTY:XON STAA    TTYPAGINGWAIT+TTYDCB
        STAA    TTYXONWAIT+TTYDCB
        BRA     TTYINTINEXIT
*
TTY:XOFF        LDAA    TTYPAGINGWAIT+TTYDCB    ARE WE IN PAGING WAIT?
        BEQ     TTY:XOFF1       B/ YES, IGNORE XOFF
        CLR     TTYXONWAIT+TTYDCB       FORCE WAIT FOR XON ARRIVAL
TTY:XOFF1       BRA     TTYINTINEXIT
*
TTY:CONTROLP    INC     TTYPAGE+TTYDCB  TOGGLE PAGING. IF WE'RE IN
        CLR     TTYLINECOUNT+TTYDCB
        STAA    TTYPAGINGWAIT+TTYDCB    PAGEWAIT, THIS WILL GET US OUT.
        BRA     TTYINTINEXIT    IF NOT, IT WON'T HURT
*
TTY:CONTROLA    EQU     *       TOGGLE "FOLD" MODE
        LDAA    #$20
        EORA    TTYDCB+TTYFOLDMASK
        STAA    TTYDCB+TTYFOLDMASK
        BRA     TTYINTINEXIT    ALL DONE!

TTYINTINFOLD    EQU     *
        CMPA    #'a-1   lower case letter ?
        BLS     TTYINTINSERV4   B/ NO, STUFF INTO BUFFER
        CMPA    #'z     ... ?
        BHI     TTYINTINSERV4   B/ NO
        ANDA    TTYDCB+TTYFOLDMASK      YES, FOLD IT IF FOLD MODE SET
TTYINTINSERV4   LDAB    TTYINTINUSED+TTYDCB     IS THERE ROOM?
        CMPB    #TTYINTINBUFSIZE
        BEQ     TTYINTINEXIT    B/ NO ROOM, JUST IGNORE
*
TTYINTINSERV5   LDX     TTYINTINFILL+TTYDCB
        STAA    1,X
        INC     TTYINTINUSED+TTYDCB
        INX
        CPX     #TTYINTINBUF+TTYINTINBUFSIZE+TTYDCB-1
        BNE     TTYINTINSERV6
        LDX     #TTYINTINBUF+TTYDCB-1
TTYINTINSERV6   STX     TTYINTINFILL+TTYDCB
TTYINTINEXIT    EQU     *
        IF      PSITECH
        LDAA    GETCDBL0FLAG
        BEQ     TTYINTINSERV7
        CLR     GETCDBL0FLAG    MAKE THE "00" KEY HIT FLAG GO AWAY
        JMP     TTYINTINCON2
        FIN     PSITECH
TTYINTINSERV7   EQU     *
        JMP     SDOS+SDOS:RTI   ALL DONE
        FIN     TTYININTERRUPT
        PAGE
        IF      TTYININTERRUPT&TTYOUTINTERRUPT
*       TTYINTOUTFORCE -- FORCE CHARACTER IN (A) TO GO TO TTY AS NEXT OUTPUT CHARACTER
*       EITHER STUFFS CHARACTER OUT DIRECTLY OR LEAVES IT FOR TTYINTOUTSERVICE TO HANDLE
*
TTYINTOUTFORCE  EQU     *
        JSR     INTDISABLE      SHUT OFF THE WORLD
        LDAB    TTYACIA TTY OUTPUT BUSY ?
        BITB    #2      ...?
        BNE     TTYINTOUTFORCE1 B/ NO
        STAA    TTYINTOUTFORCECHAR+TTYDCB       YES, SET UP TIME BOMB
        JMP     INTENABLE       AND RETURN
*
TTYINTOUTFORCE1 EQU     *       TTY OUTPUT IS NOT BUSY
        CMPA    #ASCII:ETX       WANT TO DISPLAY ^C?
        BNE     TTYINTOUTFORCE2 B/ NO, (A) IS THE CHARACTER TO DISPLAY
        LDAA    #'C     YES, SET TIME BOMB
        STAA    TTYINTOUTFORCECHAR+TTYDCB
        LDAA    #'^     GET UP ARROW PART
TTYINTOUTFORCE2 EQU     *       STUFF CHARACTER OUT THE DOOR
        STAA    TTYACIA+1
        INC     TTYINTOUTEXPECTED+TTYDCB        FLAG "OUTPUT INTERRUPT EXPECTED"
        LDAA    #%10110101      WAIT FOR OUTPUT INTERRUPT
        STAA    TTYACIA
        JMP     INTENABLE       AND RETURN
        FIN     TTYININTERRUPT&TTYOUTINTERRUPT

        IF      &PSITECH
*       IS THIS 'IF' RIGHT ???
        IF      TTYININTERRUPT!TTYOUTINTERRUPT
TTYINTSERVICE   EQU     *
        LDAA    TTYACIA NOW FIGURE WHO KICKED US...
        RORA
        BCS     TTYINTSERVJ
        RORA
        BCS     TTYINTOUTSERVICE
        JMP     BADINTERRUPT    WARN'T NOBUDDY AH KNOWS?
TTYINTSERVJ     JMP     TTYINTINSERVICE
        IF      TTYOUTINTERRUPT
*
*       TTYINTOUTSERVICE -- PROCESSES TTY OUTPUT INTERRUPTS
*
TTYINTOUTSERVICE        EQU     *
        LDAA    TTYINTOUTFORCECHAR+TTYDCB       IS THERE A CHARACTER TO FORCE OUT?
        BEQ     TTYINTOUTSERV0A B/ NOPE
        CLR     TTYINTOUTFORCECHAR+TTYDCB       YES, ZAP IT SO THIS ONE DOESN'T BOTHER US AGAIN
        CMPA    #ASCII:ETX       SPOSD TO PRINT "^C"?
        BNE     TTYINTOUTSERV0  B/ NO, JUST THE CHARACTER IN (A)
        LDAA    #'C     YES, SET UP SO NEXT TIME THE "C" GOES OUT
        STAA    TTYINTOUTFORCECHAR+TTYDCB
        LDAA    #'^     AND THIS TIME WE PRINT THE UP ARROW
TTYINTOUTSERV0  EQU     *
        STAA    TTYACIA+1
        BRA     TTYINTOUTSERV3  GO DIDDLE THE CLOCK IF NEEDED
*
TTYINTOUTSERV0A EQU     *       NO CHARACTER TO STUFF OUT THE DOOR
        LDAA    TTYINTOUTFREE+TTYDCB    BUFFER EMPTY?
        SUBA    #TTYINTOUTBUFSIZE       ... ?
        BEQ     TTYINTOUTSERV2  B/ YES
        IF   REALTIMECLOCK
        STAA    TTYINTOUTEXPECTED+TTYDCB        'WE EXPECT ANOTHER INTERRUPT'
        FIN     REALTIMECLOCK
        LDX     TTYINTOUTMPT+TTYDCB     NO, GET A CHAR & DUMP IT OUT
        LDAA    1,X
        STAA    TTYACIA+1
        INC     TTYINTOUTFREE+TTYDCB    SAY "WE GOT A CHAR"
        INX
        CPX     #TTYINTOUTBUF+TTYINTOUTBUFSIZE+TTYDCB-1
        BNE     TTYINTOUTSERV1
        LDX     #TTYINTOUTBUF+TTYDCB-1
TTYINTOUTSERV1  STX     TTYINTOUTMPT+TTYDCB
        IF   &REALTIMECLOCK
        BRA     TTYINTOUTSERV3  B/ GO BUMP THE CLOCK
TTYINTOUTSERV2  EQU     *       USE CONSOLE OUTPUT AS A CLOCK
        STAA    TTYACIA+1       ALSO, LEAVE INTERRUPT EXPECTED FLAG SET
TTYINTOUTSERV3  INC     CLOCKFRACTION
        BMI     TTYINTOUTSERV4  B/ 1/60 SEC NOT REACHED YET
        LDAA    CLOCKFRACTION   SUBTRACT 1/60 SECOND FROM FRACTION TOTAL
        SUBA    #16
        STAA    CLOCKFRACTION
        LDAA    #1      TELL SDOS THAT 1 CLOCK TICK WENT BY
        JMP     SDOS+SDOS:CLOCKTICKED
        ELSE
TTYINTOUTSERV3  EQU     *
        LDAA    #%10110101      "INT OUTPUT"
        STAA    TTYACIA
        JMP     SDOS+SDOS:RTI
*
TTYINTOUTSERV2  EQU     *
        CLR     TTYINTOUTEXPECTED+TTYDCB
        LDAA    #%10010101      DISABLE OUTPUT READY INTERRUPTS
        STAA    TTYACIA
        FIN     &REALTIMECLOCK
TTYINTOUTSERV4  JMP     SDOS+SDOS:RTI
        FIN
        FIN             TTYINTERRUPT
        FIN     &PSITECH
        EQU     *-TTYDRIVER     SIZE OF TTY DRIVER
        PAGE


        EQU     *-TTYDRIVER     SIZE OF TTY DRIVER
        LIST    0
        FIN     IODRIVERBODY
****
        IF      IODRIVERINIT
        LIST    1
TTYRESET        LDX     #$4000
TTYRESET1       DEX             DELAY AWHILE...
        BNE     TTYRESET1       TO LET THINGS SETTLE DOWN
        IF      PSITECH
        LDAA    #$2D
        STAA    TTY:KCTL        LET KEYBOARD INTERRUPT
        ELSE
        LDX     #TTYACIA
        LDAA    #3
        STAA    0,X
        IF      TTYININTERRUPT&TTYOUTINTERRUPT
        LDAA    #%10110101      IN INT, OUT INT, 8 DATA 1 STOP, /16
        STAA    0,X
        ELSE
        LDAA    #$15
        STAA    0,X
        FIN     TTYININTERRUPT&TTYOUTINTERRUPT
        LDAA    TTYACIA+1       CLEAR ANY SPURIOUS INPUT INTERRUPT
        FIN     PSITECH
        LDX     #TTYDCB
        STX     DCBPOINTER
        PAGE
TTYINITDCB      EQU     *       PLACE ALL VALID POINTERS INTO DCB
        CLR     TTYBINREADMODE,X
        CLR     TTYEOF,X
        LDAA    DCBPOINTER
        LDAB    DCBPOINTER+1
        ADDB    #TTYXONWAIT
        ADCA    #0
        STAA    TTYXONWAITP,X
        STAB    TTYXONWAITP+1,X
        LDAA    DCBPOINTER
        LDAB    DCBPOINTER+1
        ADDB    #TTYPAGINGWAIT
        ADCA    #0
        STAA    TTYPAGINGWAITPTR,X
        STAB    TTYPAGINGWAITPTR+1,X
        LDAA    DCBPOINTER
        LDAB    DCBPOINTER+1
        ADDB    #TTYTABS
        ADCA    #0
        STAA    TTYTABSP,X
        STAB    TTYTABSP+1,X
        LDAA    DCBPOINTER
        LDAB    DCBPOINTER+1
        ADDB    #TTYBUFFER&$FF
        ADCA    #TTYBUFFER/256
        STAA    TTYBUFFERSTART,X
        STAB    TTYBUFFERSTART+1,X
        ADDB    #TTYLINEBUFSIZE
        ADCA    #0
        STAA    TTYBUFFERPOINTER,X
        STAB    TTYBUFFERPOINTER+1,X
        STAA    TTYBUFFEREND,X
        STAB    TTYBUFFEREND+1,X
        IF      TTYININTERRUPT
        LDAA    #$FF    "DON'T FOLD"
        STAA    TTYFOLDMASK,X
        LDAA    DCBPOINTER
        LDAB    DCBPOINTER+1
        ADDB    #TTYINTINUSED&$FF
        ADCA    #TTYINTINUSED/256
        STAA    TTYINTINMPT,X
        STAB    TTYINTINMPT+1,X
        STAA    TTYINTINFILL,X
        STAB    TTYINTINFILL+1,X
        STAA    TTYINTINBUFP,X
        STAB    TTYINTINBUFP+1,X
        ADDB    #TTYINTINBUFSIZE
        ADCA    #0
        STAA    TTYINTINBUFE,X
        STAB    TTYINTINBUFE+1,X
        FIN     TTYININTERRUPT
        IF      TTYOUTINTERRUPT
        LDAA    DCBPOINTER
        LDAB    DCBPOINTER+1
        ADDB    #TTYINTOUTFREE&$FF
        ADCA    #TTYINTOUTFREE/256
        STAA    TTYINTOUTMPT,X
        STAB    TTYINTOUTMPT+1,X
        STAA    TTYINTOUTFILL,X
        STAB    TTYINTOUTFILL+1,X
        STAA    TTYINTOUTBUFP,X
        STAB    TTYINTOUTBUFP+1,X
        ADDB    #TTYINTOUTBUFSIZE
        ADCA    #0
        STAA    TTYINTOUTBUFE,X
        STAB    TTYINTOUTBUFE+1,X
        LDAA    #TTYINTOUTBUFSIZE
        STAA    TTYINTOUTFREE,X
        FIN     TTYOUTINTERRUPT
        DEC     TTYXONWAIT,X
        INC     TTYECHO,X
        DEC     TTYPAGINGWAIT,X
        OKRTS
        LIST    0
        FIN     IODRIVERINIT
****
        IF      IODRIVERPOLL
        LIST    1
        IF      PSITECH
        LDAA    TTY:KCTL
        BPL     NOTTTYINT   B/NOT KEYBOARD    ???????
        JMP     TTYINTINSERVICE
        ELSE
        LDAA    TTYACIA
        BPL     NOTTTYINT
        JMP     TTYINTSERVICE
        FIN     PSITECH
NOTTTYINT       EQU     *
        LIST    0
        FIN     IODRIVERPOLL
        LIST    1
        PSR     0
****
        END

