Files
Digital-Research-Source-Code/CPM OPERATING SYSTEMS/CPM 86/CONCURRENT/CCPM-86 3.1 SOURCE/D5/SERIN.A86
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

335 lines
9.7 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

title 'Serial Input module'
;*****************************************
; *
; SERIAL INPUT MODULE *
; Last change : 2/13/84 *
; *
;*****************************************
include system.lib
include chrcomm.equ
include serdata.equ
cseg
public serial_in
public store_char
extrn supif:near ;; headentr.a86
extrn ocdesctbl:word ;; serdata.a86
extrn usart_on:near
extrn xmit_on:near ;; servar.a86
extrn xmit_off:near ;; servar.a86
extrn set_bit:near ;; servar.a86
extrn clear_bit:near ;; servar.a86
serial_in:
;-----
; ENTRY: bx = addr of the input Q control block
;
; EXIT: al = data from the usart's Q
; ah = the usarts status byte
pushf ! cli
cin2: ;; if char is available, get it
test Q_STATE[bx], CHAR_AVAIL ;; else flagwait until it's available
jnz cin1
or Q_STATE[bx], IPROC_WAITING ;; set a loacal proc waiting flag
push bx ;; save the address of Q control struc
mov dl, SYS_FLAG[bx] ;; do the flag wait
mov cl, F_FLAGWAIT
call supif
cmp ax, 0ffffh ! jne cin3 ;; was there an error ?
mov cl, P_DISPATCH ;; dispatch the process, let it try
call supif ;; again later
cin3:
pop bx ;; get back the Q control structure
jmps cin2 ;; just in case the flagset shouldn't
;; have happened.
cin1:
push bx ;; save the Q control structure
call conin_fc ;; call the console read routine
pop bx ;; restore the Q control addr
mov al, LAST_CHAR[bx] ;; al = char from Q
mov ah, LAST_STAT[bx] ;; ah = status from Q
popf ;; turn the interrupts back on
ret
conin_fc:
;;--------
;; This routine reads a character from the console input Q
;;
;; ENTRY: bx -> the Q control structure
;;
;; EXIT: LAST_CHAR[bx] = the character that was read in
;; LAST_STAT[bx] = the usart's status that corresponded to the
;; char in LAST_CHAR[bx]
push si ;; we need an index register
mov si, PROC_OUT[bx] ;; get the Q's output index
mov al, D_BUFF[bx+si] ;; get the character
mov LAST_CHAR[bx], al
mov al, S_BUFF[bx+si] ;; get the status byte
mov LAST_STAT[bx], al
inc si ;; inc the processes output index
and si, (INMSGS -1) ;; mod the size of the Q
mov PROC_OUT[bx], si ;; restore the index register
pop si ;; restore the extra index register
dec UN_PC[bx] ;; dec un-processed char count
cmp UN_PC[bx], 0 ;; was this the last char in the Q ?
jne cinf2 ;; no ...
cinf1:
and Q_STATE[bx], not CHAR_AVAIL
cinf2: ;; if sender was stopped check the receive buffer
;; for being half empty. When the receive buffer is half
test Q_STATE[bx], SENDER_STOPPED ;; empty restart the sender
jz cinf3
cmp UN_PC[bx], ( INMSGS / 2 )
ja cinf3
call start_sender ;; the Q is half empty
cinf3:
ret
store_char:
;;----------
;;
;; This routine stores the status and data bytes from a usart in their Q's.
;; It also handles the interrupt level Xon Xoff protocol.
;; If an error is detected in the status byte returned from the USART
;; a reset error command is sent to the usart.
;;
;; ENTRY: bx -> receive Q control structure
;; al = the data read from the USART
;; ah = the status read from the USART
;;
;; EXIT: the status and data are put in the status and data Q's.
;;
test Q_STATE[bx], BIT8_MASK ;; are we masking off the 8th bit
jz try_xon
and al, 7FH
try_xon:
test Q_STATE[bx], XX_MODE ;; is this Q in Xon Xoff mode ?
jz store_now
cmp al, XON ! jne try_xoff ;; is the char an Xon
call xmit_on ;; char was an Xon, start transmitter
ret
try_xoff:
cmp al, XOFF ! jne store_now
call xmit_off ;; char was an Xoff, stop transmitter
ret
store_now:
push si ;; use SI as an index register
mov si, INT_IN[bx]
mov D_BUFF[bx+si], al ;; store the data
mov S_BUFF[bx+si], ah ;; store the status
inc si
and si, (INMSGS - 1)
mov INT_IN[bx], si
pop si
or Q_STATE[bx], CHAR_AVAIL ;; set char avail flag
test ah, PARITY_ERR or OVERRUN_ERR or FRAME_ERR;; check for usart errs
jz no_err ;; if err, send error reset to usart
inc ERR_CNT[bx] ;; inc the error reset counter
mov ah, ERROR_RESET ;; set up the error reset bit
call set_bit ;; now set it in the usarts command register
and CMD_REG[bx], not ERROR_RESET ;; this is one time command
;; we have to reset the command
;; register image, so we don't
;; keep doing an error reset
no_err:
inc UN_PC[bx]
cmp UN_PC[bx], UPPER_LIM ;; is # chars in buff >= limit ?
jb check_proc_waiting ;; no
call stop_sender ;; yes, stop transmitter
check_proc_waiting:
test Q_STATE[bx], IPROC_WAITING ;; only do flagset if proc is waiting
jz no_proc_waiting ;; for a character
and Q_STATE[bx], not IPROC_WAITING ;; clear the process waiting flag
push ax ! push bx ! push cx ;; this is an interrupt context
push dx ! push bp ! push si ;; save the environment
push di ! push es ! push ds
sc2:
mov dl, SYS_FLAG[bx] ;; get the flag number
mov cl, F_FLAGSET ;; set the system function
push bx ;; save the Q ptr in case of a retry
call supif
pop bx ;; restore the Q ptr
cmp ax, 0ffffh ;; check for an error
jne sc3
cmp cx, 2aH ;; was it a flag ignore ?
jne sc3 ;; if it was not an ignore just exit
jmps sc2 ;; else, try again
sc3:
pop ds ! pop es ! pop di ;; restore environment
pop si ! pop bp ! pop dx
pop cx ! pop bx ! pop ax
no_proc_waiting:
ret
start_sender:
;;------------
;;
;; This routine tries to restart the sender.
;;
;; ENTRY: bx = addr Q control structure
;;
;; EXIT: none
;;
;; NOTE: I have assumed + 12 volts on the DSR or RTS lines means
;; send data. Conversely - 12 volts means stop
;; sending data.
;; The DTR* pin (#24) on the 2651 is wired
;; to the DSR pin on the DB-25 connector ( pin 6 ),
;; through an inverting driver. This requires setting
;; the DTR bit in the command register to start the sender.
;;
;; For the RTS protocol, the RTS* pin (23) on the 2651
;; is wired to the Ready for Send pin on the DB-25
;; connector ( pin 5 ) through an inverting driver. This
;; requires setting the RTS bit in the command register
;; to start the sender.
test Q_STATE[bx], DTR_MODE ;; check dtr protocol
jz try_rts1
mov ah, DTR ;; force DTR* (dtr not) pin low
call set_bit
and Q_STATE[bx], not SENDER_STOPPED
try_rts1:
test Q_STATE[bx], RTS_MODE ;; check for RTS protocol,
jz try_xx1
mov ah, RTS ;; force the RTS* (rts not) pin low
call set_bit
and Q_STATE[bx], not SENDER_STOPPED
try_xx1:
test Q_STATE[bx], XX_MODE ;; check for Xon/Xoff protocol
jz no_prot
call send_xon
and Q_STATE[bx], not SENDER_STOPPED
no_prot:
ret
stop_sender:
;;-----------
;; This routine tries to stop the transmitter.
;;
;; ENTRY: bx = addr( Q control )
;;
;; EXIT: none
;;
test Q_STATE[bx], DTR_MODE
jz try_rts
mov ah, DTR ;; force DTR* (dtr not) pin high
call clear_bit
or Q_STATE[bx], SENDER_STOPPED
try_rts:
test Q_STATE[bx], RTS_MODE ;; check for RTS protocol,
jz try_xx
mov ah, RTS ;; force the RTS* (rts not) pin high
call clear_bit
or Q_STATE[bx], SENDER_STOPPED
try_xx:
test Q_STATE[bx], XX_MODE ;; check for Xon/Xoff protocol
jz no_protocol
call send_xoff
or Q_STATE[bx], SENDER_STOPPED
no_protocol:
cmp UN_PC[bx], INMSGS ;; If at lim of buffer, adjust char
jb ss_2
ss_0:
dec UN_PC[bx]
cmp INT_IN[bx], 0
je ss_1
dec INT_IN[bx]
jmps ss_2
ss_1:
mov INT_IN[bx], (INMSGS - 1) ;; force index to end of buffer
ss_2:
ret
send_xon:
;;--------
;; This routine sends an Xon to the sender
;;
;; ENTRY: bx = addr of Q control sturcture
;;
;; EXIT: An Xon ( ctl q ) is sent to the sender
;;
test XINT_MASK[bx], SS_U ;; is this the system support board?
je sxn
mov ah, XON ;; it's interfacer 3 board
call send_char
sxn:
ret
send_xoff:
;;---------
;; This routine sends an Xoff to the sender.
;;
;; ENTRY: bx = addr of Q control sturcture
;;
;; EXIT: An Xoff ( ctl s ) is sent to the sender
;;
test XINT_MASK[bx], SS_U ;; is this the system support board?
je sxf
mov ah, XOFF ;; it's the interfacer 3 board
call send_char
sxf:
ret
send_char:
;;---------
;; This routine sends a single character to the USART in the Q ctl struct.
;;
;; ENTRY: bx = addr Q control structure
;; ah = char to send
;;
;; EXIT: none
push bx ;; save the input Q control addr
mov bl, U_NUMB[bx] ;; get the usart's i3 number
xor bh, bh ;; clear the upper byte
inc bx ;; index above the SS usart
shl bx, 1 ;; indexing into a word table
mov bx, ocdesctbl[bx] ;; bx -> Output Q control
push cx
push si
mov cx, OMSGCNT[bx] ;; get the number of chars in Q
mov si, omsgout[bx] ;; get the output index
add si, cx ;; add to it the number of chars
and si,onmsgs-1 ;; in the buffer, mod( buff size )
mov obuffer[bx+si],ah ;; put the char in the Q
inc cx ;; inc the chars in Q count
mov omsgcnt[bx],cx ;; update
dec cx ;; if 1st char in Q, start Xmit int's
jnz sc1 ;; cx = chars in Q - 1
call usart_on ;; start the Xmitter
sc1:
pop si
pop cx
pop bx ;; restore the input Q control addr
ret
end