 lib ../environment
 lib hardware
 data
 sttl 8274 interface routines
 pag
 name tty_8274
 global ttconf,ttputc,ttgetc,ttenxr,ttdisx,ttenr,ttenx,ttenno
 global ttxbsy,tttstx,tttstr,tttstb,tttstc,tttste,ttend,ttsbrg
 global ttiscts,ttwcts,ttwdcd,tttsts
 global waiters,nowtty,fndng,waitlst

* The routines in this file are specific to an 8274.
* They are called from the "ttyhan" and "ttydrv" files.

* constants

cont equ 2 control reg
data equ 0 data reg
CTSBIT equ $20 Clear To Send bit in status reg.
DCDBIT equ $08 Data Carrier Detect bit in status reg.

nowtty fcb 0 tty now in use
waiters fcb 0 count waiting to transmit
nxtguy fcb 0 next tty in waitlst to transmit
waitlst fdb 0,0,0,0,0 devices waiting to transmit

baudbyte fcb INITBR initial baud rate

*
* ttconf
*
* Configure the port pointed at by the Y register.  The X
* register is pointing to the terminal table.  All registers
* except D should be preserved.
*

ttconf
 cmpy #IFR08
 beq ttconf_p
 bhi ttconx
 lbsr clstat reset status
 ldb #$ee load configuration byte
 lbsr setupx do auto enable and DTR/RTS
 lbsr clstat reset status
 lda cont,y read status
 bita #CTSBIT is CTS on?
 bne ttcnf2 skip if on
 clc Zero bit already set, no Carry->no CTS
 rts
ttcnf2 pshs d
 ldd usarg1 get open type
 cmpd #3 is it special open?
 puls d
 beq ttcnf3 skip if special open
 bita #DCDBIT is DCD on?
 bne ttcnf4 skip if on
 sec Zero bit already set, Carry->no DCD
 rts
ttcnf3 lda #3 select control reg. 3
 sta cont,y
 lda #$C1 turn off auto enables
 sta cont,y
 lda tstat2,x get open status
 ora #TOPWOC show special open
 sta tstat2,x
ttcnf4 lbsr reset reset pending interrupts
 ldb #1 select interrupt cntrl reg
 stb cont,y
 ldb #$1F turn on interrupts
 stb cont,y
 lbra true return true
*
*parallel configure
*
ttconf_p
 clr outstat
 clr incomp
 lda #i_via+CA1
 sta IER08
 clr INIT_TTY -- must re-initialize terminal for RAW output
ttconx clz
 clc
 rts

*
* ttputc
*
* Send the character in the B register to the ACIA.  All
* registers should be preserved.  Y points to the device.
*

ttputc
 cmpy #IFR08
 bhs ttputc_p
 stb data,y send character
 rts return
ttputc_p
 pshs d,cc
 seti
 tfr b,a
 andb #%00111111
 stb out2
 clrb
 asla
 rolb
 asla
 rolb
 orb #$80
 lda #0
 cmpy #IFRPPR
 bne ttpspr
 orb #$01<<2 point at PPR
 lda #8
 bra ttpout
ttpspr cmpy #IFRSPR spr?
 bne ttpcom
 orb #$02<<2 point at SPR
 lda #9
 bra ttpout
ttpcom cmpy #IFRCOM comm line?
 bne ttpout
 orb #$03<<2 point at comm
 lda #3
ttpout stb out1 save in first output pos.
 sta nowtty save which tty is in use
 lda outstat
 anda #$3F
 ora #$80      say sending first half
 sta outstat
 stb ORB08     stuff byte on via B side
 ldb #20
 stb TIMCNT    timeout
 ldd #0
 std T1CNTR
 lda #$C0+CB1  timer and txmit irq enable
 sta IER08
 puls cc,d,pc back out out



*
* ttgetc
*
* Get the character from the device and return in the B
* register.  Y points to the device and all registers
* should be preserved.
*

ttgetc
 cmpy #IFR08
 bhs ttgetc_p
 ldb data,y get the character
 rts
ttgetc_p pshs a
 lda in1
 ldb in2
 lslb
 lslb
 asra
 rorb
 asra
 rorb
 sez
 puls a,pc

*
* ttenxr
*
* Enable the transmit interrupts and leave the receive
* interrupt enabled (it is enabled upon routine entry).
* Y points to the device and X points to to the terminal
* table entry.  Preserve all registers but D.
*
*

ttenxr
 pshs cc
 seti
 lda outstat
 bita #$C0
 bne ttenxout
 lda #1
 cmpy #IFR08
 beq ttenxr_p
 lsla
 cmpy #IFRPPR
 beq ttenxr_p
 lsla
 cmpy #IFRSPR
 beq ttenxr_p
 lsla
 cmpy #IFRCOM
 bne ttenxout
ttenxr_p coma
 anda outstat
 anda #$3F
 sta outstat
 lda #CB1+i_via
 sta IER08
 lda tflags,x
 bita #RAW
 beq ttenxout
 jsr ttyst
ttenxout puls cc
 rts

*
* ttenr
*
* Enable the receive interrupts only.  The transmit
* interrupts should be turned off.  Y points to the device
* and X point to the terminal table entry.  Preserve all
* but the D register.
*

ttenr
 cmpy #IFR08
 beq ttenr_p
 rts
ttenr_p
 lda #CA1+i_via
 sta IER08
 lda #CB1
 sta IER08
 sta IFR08
 rts


*
* ttenx
*
* Enable the transmit interrupts only.  The receive
* interrupts should be left disabled.  Y points to the
* device and X points to the terminal table entry.
* All registers but D shoud be preserved.
*

ttenx
 rts


*
* ttdisx
*
* Disable the transmit interrupt and leave the receive
* interrupt enabled.  Y points to the device and X points
* to the terminal table entry.  Preserve all but D.
*

ttdisx lda #1
 ldb #0 tty00 device
 cmpy #IFR08
 beq ttdisx_p
 lsla
 ldb #8 ppr device
 cmpy #IFRPPR
 beq ttdisx_p
 lsla
 ldb #9 spr device
 cmpy #IFRSPR
 beq ttdisx_p
 lsla
 ldb #3 tty03 device
 cmpy #IFRCOM
 bne ttdisx74
ttdisx_p
 ora outstat
 sta outstat
 cmpb nowtty are we disabling current?
 bne ttdisx6
 bita #$C0 currently busy?
 bne ttdisx6
 anda #$3F
ttdisx5 sta outstat
 tst waiters
 beq ttdisx6
 pshs x,y,u
 bsr fndng find next guy waiting
 clr b,x clear guy out of waitlst
 dec waiters
 lbsr figpoint
 jsr ttyst
 puls x,y,u
ttdisx6 rts
ttdisx74 lda #$28 reset transmit interrupt command
 sta cont,y
 rts

* find next guy wanting to do output

fndng pshs a
 lda #10 only try 10 slots
 ldx #waitlst
 ldb nxtguy
fndng0 decb
 bpl fndng1
 ldb #9 wrap back to SPR
fndng1 tst b,x is this guy waiting?
 bne fndng2 branch if waiting
 deca
 bne fndng0 if not all, try another
fndng2 stb nxtguy
 puls a
 rts


*
* ttenno
*
* Disable all interrupts from device and drop the RTS
* line.  Y points to the device and X points to the
* terminal table entry.  Preserve all but D register.
*

ttenno cmpy #IFR08
 bhs tenno_p
 lda #1 select interrupt cntrl reg
 sta cont,y select reg 1
 clr cont,y reset all bits
 ldb #$6c turn off DTR and RTS
setupx lda #3 select register 3
 sta cont,y
 lda #$E1 restore to auto enables
 sta cont,y
 lda #5 select xmit control reg
 sta cont,y
 stb cont,y store pre-loaded configuration
tenno_p
 rts return

*
* ttxbsy
*
* Test if the transmit buffer is empty.  Return TRUE if
* it is empty (N.E. status). Y points to the device and
* all but A needs preserved.
*

ttxbsy cmpy #IFR08
 bhs ttxbsy_p
 lda cont,y
 bita #4
 rts
* parallel busy test
ttxbsy_p lda incomp
 cmpy #IFR08
 bne ttxbsy0
 ldb #0 device number
 bita #$01
 bne isbsy
 bra ttxbs1
ttxbsy0 cmpy #IFRPPR
 bne ttxbsy1
 ldb #8 device number
 bita #$04
 bne isbsy
 bra ttxbs1
ttxbsy1 cmpy #IFRSPR
 bne ttxbsy2
 ldb #9 device number
 bita #$08
 bne isbsy
 bra ttxbs1
ttxbsy2 cmpy #IFRCOM
 bne ttxbsy3
 ldb #3 device number
 bita #$10
 bne isbsy
ttxbs1 lda outstat
 bita #$C0
 bne isbsy
ttxbsy3
isempty
 clz
 rts
isbsy
 cmpb nowtty busy on device being tested?
 beq isbsy9 exit if same device
 pshs d,x,y,u
 pshs cc
 seti
 ldx #waitlst
 tst b,x
 bne isbsy8
 inc b,x
 inc waiters
isbsy8 puls cc
 puls d,x,y,u
isbsy9 sez show busy
 rts

*
* tttstx
*
* Test device pointed at by Y for a transmit interrupt.
* Return TRUE if interrupt present.  Preserve all but
* the A register.
*

tttstx ldd 6,s get status
 cmpa #0
 bne false is it xmit int?
 bra true

*
* ttiscts
*
* Test device pointed at by X for "Clear to Send"
* -- Return TRUE (not equal) if yes
*
ttiscts
 cmpx #IFR08 from X12 or 7201?
 bhs true always true if X12
 lda cont,x check for CTS
 bita #%00100000 is CTS down?
 beq false
true clz no - return TRUE
 rts


*
* tttstr
*
* Test device pointed at by Y for a receive interrupt.
* Return TRUE if interrupt present.  Preserve all
* registers.
*

tttstr cmpa #2 is it rcv int?
 bne false
 bra true


*
* tttstb
*
* Test device pointed at by Y for a "break" condition.
* Return TRUE if found.  Preserve all registers
* and return NULL in B (for break character).
*

tttstb cmpa #1 is it break condition?
 bne false
 bitb #$80
 bne clsint clear int. & show true
false sez yes - return FALSE
 rts


* Test device pointed at by Y for a "CTS" interrupt.
*

tttsts cmpa #1 is it special interrupt?
 bne false
 lda #CTSBIT use CTS bit position
 bsr hilo see if bit went hi
 beq clsint if lo, go clear int.
 bsr chkopn was terminal open?
 bne clsint clear int & exit if so
 bsr wake wakeup blocked open

*
* clear interrupt and return true status
*

clsint lda #1 select int. control reg.
 sta cont,y
 lda cont,y clear interrupt
clstat lda #$10 reset port
 sta cont,y
 rts return true



*
* check for device open
*
chkopn pshs a
 lda tstate,x
 bita #TOPEN
 puls a,pc


*
* tttstc
*
* Test device pointed at by Y for drop "Carrier Detect"
* type interrupt.  Return TRUE if so.  Preserve all registers
* but A.
*

tttstc cmpa #1 special interrupt type?
 bne false exit if not
 lda #DCDBIT setup DCD bit position
 bsr hilo see if bit went hi or lo
 bne 3f branch if high
 bsr chkopn was terminal open?
 beq flsclr if not, clear int. & show false
 bra clsint clr int & show true (HANGUP)
3 bsr chkopn was terminal open?
 bne flsclr if so, clr int & show false
 bsr wake waken blocked open

flsclr pshs a
 bsr clsint clear interrupt
 puls a
 lbra false show false response

*
* See if bit in position supplied in a went high or low
*

hilo pshs a save bit position
 tfr b,a
 eora tstat2,x see if bit has changed
 anda 0,s look at only the desired bit
 bne 1f branch if changed
 leas 3,s remove return address
 lda #1 restore interrupt type
 bra false go straight to false
1 lda tstat2,x preload saved bits
 bitb 0,s did bit go high?
 bne 2f branch if went high
 com 0,s prepare to clear bit
 anda 0,s+ clear saved bit
 bsr 3f put back
 bra false show bit went low
2 ora 0,s+ set saved bit
3 sta tstat2,x
 lda #1 restore interrupt type
 rts (returning true (NE))


*
* wakeup routine for CTS and DCD
*
wake pshs d,x,y,u
 ldy tqout,x get address for wakeup
 jsr wakeup
 puls d,x,y,u,pc


*
* tttste
*
* Test device pointed at by Y for error conditions.
* Handle all errors local to this routine - no status
* returned.  Preserve all but A.
*

tttste cmpa #1 special condition?
 beq flsclr yes - jump
 lda #1 reset error condition
 sta cont,y
 lda cont,y
 lda #$30
 sta cont,y
 lda data,y read data register - just to be sure
 bra clstat clear status


*
* reset impending interrupts and determine current
* status of CTS and DCD
*

reset bsr clsint clear interrupts
 lda cont,y get status
 anda #CTSBIT|DCDBIT just CTS and DCD
 ldb tstat2,x
 andb #!(CTSBIT|DCDBIT) turn off
 stb tstat2,x
 ora tstat2,x add in new bits
 sta tstat2,x
 rts


*
* ttend
*
* Terminate i/o operation for device pointed at by Y.
* Preserve all but D.
*

ttend cmpy #IFR08 is it from VIA or 7201?
 lbhs true return if VIA
 pshs d,y save port address
 ldd 2,s compute base address for chip
 andb #$FE
 tfr d,y
 lda #$38 reset port
 sta cont,y
 puls d,y,pc return


*
* ttsbrg
*
* Set up the baud rate generators - if any.  On entry,
* Y points to xmit BRG and U points to rcvr BRG.  X is
* pointing to the terminal table entry (tbaud2,x has
* byte for baud rate generator).
*

ttsbrg ldd tdevic,x get device no. in b
 lda tbaud2,x get speed byte
 cmpb #1 is it tty01?
 beq ttsbr1
 cmpb #2 is it tty02?
 bne ret
 ldb baudbyte get previous
 andb #$f0 mask off proper half
 anda #$0f ensure tbaud2 is OK
 bra ttsbr7
ttsbr1 ldb baudbyte get previous
 andb #$0f mask off proper half
 lsla move tbaud2
 lsla
 lsla
 lsla
ttsbr7 pshs b
 ora 0,s+ "or" in baud rate
 sta baudbyte save it
 sta 0,y set baud rate generator
ret rts




*
* ttwcts
*
* Wait for CTS to go high.  (Sleep on it).
*

* Same as ttwdcd, so fall through

*
* ttwdcd
*
* Wait for DCD to go high.  (Sleep on it).
*

ttwcts lda #CTSBIT
 bra ttw2
ttwdcd lda #DCDBIT
ttw2 pshs a
 bsr reset reset impending interrupts
 lda #1  select interrupt control reg.
 sta cont,y
 lda #$05 enable only ext/status interrupts
 sta cont,y
 lbsr clstat
 lda cont,y get status
 anda 0,s+
 bne ret
 ldb #TTYOPR set priority
 ldy tqout,x point to something
 jmp sleep sleep on DCD
