 ttl exdrive : example input, output, keyboard
exdrive idnt 1,6 example input,output,keyboard
*
 include /dd/xrun/xpasequ
*
* misc
*
break equ $5 used for break function
qsize equ 128 queue size
reset equ $10 reset 2661
mode1a equ $4e eight bits, no parity
mode1b equ $7e baud rate
mode2 equ $26 receive interrupt enabled
mode3 equ $27 same with receive and xmit interrupt enabled
readerr equ 100 I/O error on 2661 input
back equ 8
del equ $7f
delline equ $18
*
* descriptor offset for input device only
*
 abs 7
*
p$break rmb 1 break enable if true
p$pntr rmb 2 buffer pointer
p$buf rmb 128 buffer
*
 abs $bf40 terminal port 2661 address
epcidata rmb 1 epci data register
epcistat rmb 1 epci status register
epcimode rmb 1 epci mode register
epcicom rmb 1 epci control register
*
* queues for input and output of 2661
*
 varib
inq_err rmb 1 error flag for input from 2661
roff rmb 1 receive buffer full
toff rmb 1 transmit buffer hold
special rmb 1 xon/xoff flag
inq_mode rmb 2 pointer to input descriptor
inq_in rmb 2 input from 2661 input pointer
inq_out rmb 2 input from 2661 output pointer
inq_max rmb 2 end of input queue
inq_cnt rmb 1 number of characters in input queue
outq_in rmb 2 output to 2661 input pointer
outq_out rmb 2 output to 2661 output pointer
outq_max rmb 2 end of output queue
outq_cnt rmb 1 number of characters in output queue
inq rmb qsize input from 2661 queue
outq rmb qsize output to 2661 queue
*
 code
*
 xref global
 xdef .input,.output,.keyboar,int2661
*
* each entry point has room for 4 sub-entries
*
* + 0 - initialization
* + 3 - output
* + 6 - input
* + 9 - setup
*
* table for input
*
.input lbra inp_init
 rts cannot due output function
 rmb 2
 lbra data_in
 lbra key_set
*
inp_init pshs y,x
 ora #m$in open for input
 leay <.input,pcr driver address
 lbsr ddset setup descriptor
 leay p$buf,x
 sty p$pntr,x
 ldb #cr
 stb 0,y
 ldy global
 stx inq_mode,y save address of desc.
 clr p$break,x assume break not enabled
 lda p$mode,x
 bita #m$bk
 beq inp_1
 anda #$ff-m$bk
 sta p$mode,x
 lda #1
 sta p$break,x set flag true
inp_1 equ *
 leax inq,y
 stx inq_in,y
 stx inq_out,y input queue is empty
 leax qsize,x
 stx inq_max,y limit of input queue
 clr inq_cnt,y
 clr inq_err,y no error yet
 clr roff,y
 puls y,x,pc
*
* table for output
*
.output lbra out_init
 lbra dat_out
 rts can't do input function
 rmb 2
 lbra out_set
*
out_init pshs y,x
 ora #m$out open for output
 leay <.output,pcr driver address
 bsr ddset
 ldy global
 leax outq,y
 stx outq_in,y
 stx outq_out,y queue is empty
 leax qsize,x
 stx outq_max,y
 clr outq_cnt,y
 clr toff,y
 clr special,y
 lda #reset
 sta epcicom clear epci
 lda #mode1a
 sta epcimode mode register 1
 lda #mode1b
 sta epcimode mode register 2
 lda epcidata make sure receive empty
 lda #mode2
 sta epcicom enable receive interrupt
out_2 puls y,x,pc
*
* table for keyboard
*
.keyboar lbra key_init
 rts can't do output function
 rmb 2
 lbra data_in
 lbra key_set
key_init pshs y,x
 ora #m$in open for input
 leay <.keyboar,pcr driver address
 bsr ddset
 puls y,x,pc
*
ddset sta p$mode,x
 clr p$err,x
 sty p$drv,x
 ldy #1
 sty p$elnt,x
 rts
*
* transfer data to device
*
dat_out pshs y,x,d
 ldy global
 tsta see if writeln
 bmi txto3 if string write
 beq txto1 nope
 lda #cr
 bsr outch
 lda #lf
 bra txto5
txto1 equ *
 lda p$elmt,x
txto5 bsr outch
txto4 puls y,x,d,pc
txto3 equ *
 leax 1,u
 bra txto3a
txto3b lda 0,x+
 bsr outch
txto3a decb
 bpl txto3b
 bra txto4
*
* put one character in output queue
*
outch pshs x,b
outch0 ldb outq_cnt,y
 cmpb #110
 bhi outch0 too full
 pshs cc
 orcc #$10 disable interrupts
 ldx outq_in,y
 leax 1,x
 cmpx outq_max,y
 blo outch1
 leax outq,y past buffer, back to beginning
outch1 pshs x
 ldx outq_in,y
 sta 0,x
 puls x
 stx outq_in,y update pointer
 inc outq_cnt,y
 ldb #mode3
 stb epcicom
 puls cc restore interrupts
outch2 puls x,b,pc
*
* transfer data from device
*
data_in pshs y,x,d
 ldy global
 ldb p$mode,x
 andb #$ff-m$eof-m$eoln clear flags
 orb #m$val set to valid
 stb p$mode,x
 bitb #m$text
 bne txti use text input
 lbsr inch get character
 lbcs inerr
 sta p$elmt,x
 bra txti7
txti ldy p$pntr,x get buffer pointer
 lda 0,y+
 cmpa #cr
 beq txti4 need new buffer
txti5 lda 0,y get new character
 sta p$elmt,x
 sty p$pntr,x update registers
 cmpa #cr
 beq txti6 set eoln flag
txti7 clr p$err,x
 puls y,x,d,pc
txti6 orb #m$eoln
 stb p$mode,x
 lda #space
 sta p$elmt,x return space to user
 bra txti7
txti4 leay p$buf,x
 sty p$pntr,x reset pointers
 clrb character counter
 leax 0,y
 ldy global
txti10 bsr inch
 bcs inerr
 cmpa #back
 beq txti10a
 cmpa #del
 bne txti11
txti10a lda #1
txti12 tstb
 beq txti10 nothing to back out
 tsta
 beq txti10 count
 pshs a
 lda #back
 lbsr outch
 lda #space
 lbsr outch
 lda #back
 lbsr outch
 puls a
 leax -1,x move pointer back
 decb decrement character count
 deca backup counter
 bra txti12
txti11 cmpa #delline
 bne txti13
 tfr b,a remove all characters
 bra txti12
txti13 cmpa #cr see if end of line
 beq txti14 yes
 cmpb #127
 bhs txti10 cannot accept more characters
 sta 0,x+ put in buffer
 incb bump counter
 lbsr outch echo
 bra txti10
txti14 sta 0,x+
 lbsr outch send cr
 lda #lf
 lbsr outch send lf
 ldx 2,s get descriptor back
 ldy p$pntr,x start of buffer
 ldb p$mode,x
 bra txti5 go for more
inerr lda inq_err,y
 ldx 2,s
 sta p$err,x put in error
 clr inq_err,y acknowledge error
 puls y,x,d,pc
*
* get one character from queue
*
inch pshs x,b
inch0 ldb inq_err,y
 bne inch2
 tst inq_cnt,y
 beq inch0
 pshs cc
 orcc #$10 disable interrupts
 tst roff,y
 beq inch3
 ldb inq_cnt,y
 cmpb #50 see if empty enough
 bhi inch3
 clr roff,y
 ldb #$11
 stb special,y tell other end to go ahead
inch3 ldx inq_out,y
 lda 0,x+ get character
 cmpx inq_max,y
 blo inch1
 leax inq,y move to start of queue
inch1 stx inq_out,y update pointer
 dec inq_cnt,y
 puls cc
 andcc #$fe no error
 puls x,b,pc
inch2 orcc #1 error 
 puls x,b,pc
*
* output status handler
* return true if output queue empty
*
out_set pshs y
 ldy global
 cmpa #st$stat
 bne outs2
 clrb
 tst outq_cnt,y
 bne key1
 ldb #1
 bra key1
outs2 puls y,pc
*
* keyboard status handler
* return true if a character in queue
*
key_set pshs y
 ldy global
 cmpa #st$stat
 bne key2
 clrb
 tst inq_cnt,y
 beq key1
 ldb #1
key1 stb [0,s]
key2 puls y,pc
*
* interrupt handler for 2661
*
int2661 ldy global
int0 ldb epcistat
 bitb #2
 bne int1 receive data register full
*
* transmit register empty
*
 tst special,y
 bne int6a put in special ahead of other stuff
 tst toff,y
 bne int6
 tst outq_cnt,y
 beq int6 empty
 ldx outq_out,y
 lda 0,x+
 sta epcidata get character
 cmpx outq_max,y
 blo int7
 leax outq,y move to start of queue
int7 stx outq_out,y update pointer
 dec outq_cnt,y
 lbra intexit
int6 ldb #mode2
 stb epcicom disable xmit interrupt
 lbra intexit
int6a lda special,y
 sta epcidata
 clr special,y
 bra intexit
*
* receive register full
*
int1 lda epcidata clear interrupt
 anda #$7f clear msb
 andb #%00110000
 bne int2 error
 cmpa #break see if break
 beq int4
 cmpa #lf
 beq intexit ignore line feeds
 cmpa #$13
 beq int15 disable xmitter
 cmpa #$11
 beq int16 enable xmitter
 ldb inq_cnt,y
 cmpb #110
 blo int14
 tst roff,y
 bne int14 already off
 inc roff,y is stopped
 ldb #$13
 stb special,y
 ldb #mode3
 stb epcicom
int14 ldx inq_in,y
 leax 1,x
 cmpx inq_max,y
 blo int3
 leax inq,y past buffer, back to beginning
int3 pshs x
 ldx inq_in,y
 sta 0,x put into queue
 puls x
 stx inq_in,y update pointer
 inc inq_cnt,y
 bra intexit
int2 ldb #readerr
 stb inq_err,y flag error
 bra intexit
int4 ldx inq_mode,y get descriptor
 ldb p$mode,x
 orb #m$bk
 stb p$mode,x
intexit rti
int15 ldb #1
 stb toff,y disable output
 bra intexit
int16 clr toff,y
 ldb #mode3
 stb epcicom re-enable interrupts
 bra intexit
 end
