COMMENT $
Copyright (C) Magna Carta Software, Inc. 1989, 1990. All Rights Reserved
COMMINT.ASM -- Assembly language versions of of routines to handle
communications interrupts for C Communications Toolkit.
NOTE: These are not the ISRs. They are "interrupt processing routines".
Each is declared void far xxx(struct comm_port far *)
These are the routines called from the default assembly language ISRs.
They may be called from C. Registers DS and SS are preserved. SI and DI are
not. The code to permit these routines to be called from C adds some overhead,
which could be stripped out.
$
INCLUDE CMACROS.MAC
;Public IIR, XONXOFF, RTS_CTS, DTR_DSR, RX_BUF, RX_HEAD, RX_TAIL, RX_END
;Public TX_BUF, TX_HEAD, TX_TAIL, TX_END, INTTABLE, F_TXHOLD, F_RXHOLD, F_FLOW
;Public F_HIGH, XON_CHAR, XOFF_CHAR, HIGHWATER, LOWWATER, COM, encore
;Public no_int, com_rls_int, com_rx_int, nooflow1, head_lt_tail, store_byte
;Public bump1, stop_flow, test_rts1, test_dtr1
;Public com_tx_int, t1, com_ms_int, com_lstx_int, com_rxtx_int
;Public nooflow1, bump1, no_others, com_dummy
DEFSEG COMMISR _DATA
IIR EQU 2 ; offset of Interrupt ID reg. from base
LSR EQU 5 ; offset of line status reg. from base
MSR EQU 6 ; offset of Modem Status Register
LS_OFF EQU 18 ; offset in UART of Line Status reg.
TX_BUSY EQU 1 ; TX interrupts held by RX flow control
;==========================================================================
;THE FORMAT OF THE BIT-ENCODED FLOW CONTROL FLAG "p->flowctl"
RX EQU 00001111b ; accept flow control
TX EQU 11110000b ; assert flow control
RXONXOFF EQU 00000001b ; accept XON-XOFF 1
RRTS_CTS EQU 00000010b ; accept RTS/CTS 2
RDTR_DSR EQU 00000100b ; accept DTR/DSR 4
TXONXOFF EQU 00010000b ; assert XON-XOFF 16
TRTS_CTS EQU 00100000b ; assert RTS/CTS 32
TDTR_DSR EQU 01000000b ; assert DTR/DSR 64
DICTATE EQU 10000000b ; do not accept rx chars. in rx hold
;==========================================================================
;DEFINITION OF FLOW CONTROL FLAG
;The above values are used in the bit-encoded flag F_FLOW as follows:
;Bit 0=1 Accept XON-XOFF flow control
;Bit 1=1 Accept RTS/CTS flow control
;Bit 2=1 Accept DTR/DSR flow control
;Bit 3 RESERVED
;Bit 4=1 Assert XON-XOFF flow control
;Bit 5=1 Assert RTS/CTS flow control
;Bit 6=1 Assert DTR/DSR flow control
;Bit 7=1 Assert flow control with DICTATE
;==========================================================================
RX_BUF EQU 0
RX_HEAD EQU RX_BUF+4
RX_TAIL EQU RX_BUF+8
RX_END EQU RX_BUF+12
TX_BUF EQU RX_BUF+16
TX_HEAD EQU RX_BUF+20
TX_TAIL EQU RX_BUF+24
TX_END EQU RX_BUF+28
INTTABLE EQU RX_BUF+32 ;offset of int. table inreg. from base
INHOLD EQU RX_BUF+48 ; in HOLD
FLOWCTL EQU RX_BUF+50 ; flow control in use f->flowctl
F_HIGH EQU RX_BUF+52 ; flow control in use f->flowhigh
XON_CHAR EQU RX_BUF+54 ; XON character
XOFF_CHAR EQU RX_BUF+56 ; XOFF character
HIGHWATER EQU RX_BUF+58 ; highwater mark
LOWWATER EQU RX_BUF+60 ; lowwater mark
COM EQU RX_BUF+62 ;offset in COM_PORT of base addr.
RS232IN EQU RX_BUF+64 ;storage for RS-232 inputs states
LSIN EQU RX_BUF+65 ;line status register input states
F_TXBUSY EQU RX_BUF+66 ;flag for TX int. busy
F_TX_START EQU RX_BUF+68 ;flag for TX int. restart
DSEG SEGMENT WORD PUBLIC 'DATA'
EXTERN FAR_DPTR mcport ;MUST be defined at assembly
DSEG ENDS
CSEG SEGMENT WORD PUBLIC 'CODE'
ASSUME CS:CSEG, DS:DGROUP
;-------------------------------------------------------------------------------
;COM_RX_IPR_ -- Receive interrupt routine for the 8250 family.
;On entry:
; DS points to DGROUP
; Parameter port_addr contains the address of the COMM_PORT structure.
;On exit:
; Received byte stored in COM_PORT rxbuf
;Registers destroyed: All but DS
;General rules within handler:
; DS:BX points to the address of the COMM_PORT
; SI points to RX buffer head
; CX points to next received character slot
;Operations:
; Checks for XONXOFF accepted and:
; a) sets hold flag if XOFF received.
; b) clears hold flag if XON received.
; Checks if we assert FLOW CONTROL. Compares buffer with highwater mark
; a) sends XOFF if XON-XOFF in use
; b) Checks for RTS/CTS and DTR/DSR and changes line state if at
; highwater mark (receive flow control).
;-------------------------------------------------------------------------------
START_PROC <_FAR com_rx_ipr_> <FAR_DPTR comm_port>
push ds
les bx, comm_port
mov cx, es ; set DS to addr. of COMM_PORT
mov ds, cx
re_entry: ;NS16550 re-entry point.
mov dx, [bx+COM]
in al, dx ;get the character
les si, DWORD PTR [bx+RX_HEAD] ;rxbufhead
;IS FLOW CTL. ACCEPTED?
test WORD PTR [bx+FLOWCTL], RX
jz not_xonxoff
;is XONXOFF flow ctl. accepted
test WORD PTR [bx+FLOWCTL], RXONXOFF
jz not_xonxoff
cmp al, BYTE PTR [bx+XOFF_CHAR] ; is this an XOFF
jne not_an_xoff
or WORD PTR [bx+INHOLD], RXONXOFF ; turn off transmission
jmp SHORT bump1 ; and exit
not_an_xoff: ; IS THIS AN XON?
cmp BYTE PTR [bx+XON_CHAR], 0 ; is any character an XON?
jne not_xany ;no
and WORD PTR [bx+INHOLD], NOT RXONXOFF ; turn on transmission
or WORD PTR [bx+F_TX_START], 1 ; set flag to prime TX
jmp SHORT bump1
not_xany:
cmp al, BYTE PTR [bx+XON_CHAR] ; is this an XON?
jne not_xonxoff
and WORD PTR [bx+INHOLD], NOT RXONXOFF ; turn on transmission
or WORD PTR [bx+F_TX_START], 1 ; set flag to prime TX
jmp SHORT bump1 ; and exit
not_xonxoff:
mov cx, si
inc cx ;advance CX (head) to "next slot"
cmp cx, WORD PTR [bx+RX_END] ;is next slot > rxbufend?
jbe nooflow1 ;no
mov cx, WORD PTR [bx+RX_BUF] ;yes <=> go to jail...p_rxbuf
nooflow1:
test WORD PTR [bx+FLOWCTL], TX ;is flow ctl. to be asserted?
jz store_byte ;no - just store byte
test WORD PTR [bx+INHOLD], TX ;are we already asserting HOLD?
jz error_skip ;jump if not already asserting
test WORD PTR [bx+FLOWCTL], DICTATE ; we have asserted flow ctl.
jz store_byte ;if permissive, store byte.
jmp SHORT bump1
error_skip: ; come here to test highwater
mov di, WORD PTR [bx+RX_TAIL]
cmp si, di
jl head_lt_tail
sub si, di
cmp si, [bx+HIGHWATER] ;head > tail. SI = difference
ja stop_flow ;buffer nearly full!
jmp SHORT store_byte
head_lt_tail:
sub di, si
cmp di, [bx+LOWWATER] ;tail > head. DI = difference
jb stop_flow ;buffer nearly full!
store_byte:
mov si, WORD PTR [bx+RX_HEAD] ;rxbufhead
mov BYTE PTR es:[si], al ;store the byte
cmp cx, WORD PTR [bx+RX_TAIL] ;has head caught tail?
je bump1 ;yes
mov WORD PTR [bx+RX_HEAD],cx ;update rxbufhead
bump1:
add dx, 5
in al, dx ;see if data ready
test al, 1
jz no_more0
sub dx, 3
jmp re_entry
no_more0: ;we always come here to return
pop ds
mov sp,bp
pop bp
ret
;ASSERT FLOW CONTROL
stop_flow: ;TEST FOR TYPE OF FLOW CTL.
push ax ;save the received byte
mov di, WORD PTR [bx+FLOWCTL] ;is flow ctl. to be asserted?
test di, TXONXOFF ;flow ctl flag in AX
jz test_rts1
mov ax, WORD PTR [bx+XOFF_CHAR] ;send XOFF
out dx, al
or WORD PTR [bx+INHOLD], TXONXOFF ;set flag indicating RX_HOLD
test_rts1:
test di, TRTS_CTS
jz test_dtr1
add dx, 4 ;move to modem ctl. register
in al, dx ;turn off RTS
and al, 11111101b
out dx, al
or WORD PTR [bx+INHOLD], TRTS_CTS ;set flag indicating RX_HOLD
sub dx, 4
test_dtr1:
test di, TDTR_DSR
jz do_store
add dx, 4 ;move to modem ctl. register
in al, dx ;turn off DTR
and al, 11111110b
out dx, al
or WORD PTR [bx+INHOLD], TDTR_DSR ;set flag indicating RX_HOLD
sub dx, 4
do_store:
pop ax
jmp SHORT store_byte
END_PROC com_rx_ipr_
;-------------------------------------------------------------------------------
;COM_TX_IPR_ -- Transmitter holding register empty interrupt.
;On entry:
; ES:BX set to COM_PORT segment
; DX points to IID
;On exit:
;Registers destroyed: AX, CX, DX, SI, ES
;General rules within handler:
; BX points to COMM_PORT
; SI points to TX buffer tail
;Operations:
; Check for TX hold flag
; Check for head-tail collision
; Transmit byte
; Update tail pointer
;-------------------------------------------------------------------------------
START_PROC <_FAR com_tx_ipr_>, <FAR_DPTR port_addr>
push ds
les bx, port_addr
mov cx, es ;set DS to addr. of COMM_PORT
mov ds, cx
les si, DWORD PTR [bx+TX_TAIL] ; does the head = tail (SI)?
cmp si, WORD PTR [bx+TX_HEAD]
jne t0 ; yes
and WORD PTR [bx + F_TXBUSY], 0FEh; reset busy flag
jmp SHORT t_end
t0:
test WORD PTR [bx+INHOLD], RX ; in HOLD state?
jz no_hold
jmp SHORT t_end ; exit for later restart
no_hold:
mov dx, WORD PTR [bx+COM] ;point to the THR
mov al, es:[si] ;get next byte
out dx, al ;transmit it
inc si ;increment the tail
cmp si, WORD PTR [bx+TX_END]
jbe tn
mov si, WORD PTR [bx+TX_BUF]
tn:
mov WORD PTR [bx+TX_TAIL], si
t_end:
pop ds
END_PROC com_tx_ipr_
;-------------------------------------------------------------------------------
;COM_RLS_IPR_ -- Receiver line status interrupt handler.
;Reads the line status register and stores the info. in p->uart->u8250.status[5]
;Nukes the character received in error.
;-------------------------------------------------------------------------------
START_PROC <_FAR com_rls_ipr_>, <FAR_DPTR port_addr>
push ds
les bx, port_addr
mov cx, es ;set DS to addr. of COMM_PORT
mov ds, cx
mov dx, [bx+COM]
add dx, LSR ;point to the LS register
in al, dx ;read to clear and store
mov BYTE PTR [bx+LSIN], al
test al, 1 ;test for received char.
jz end_ls
sub dx, LSR ; read the character
in al, dx ; ...to nuke it.
end_ls:
pop ds
END_PROC com_rls_ipr_
;-------------------------------------------------------------------------------
;COM_MS_IPR_ -- Modem status interrupt handler.
;-------------------------------------------------------------------------------
START_PROC <_FAR com_ms_ipr_>, <FAR_DPTR port_addr>
push ds
les bx, port_addr
mov cx, es ;set DS to addr. of COMM_PORT
mov ds, cx
mov dx, [bx+COM]
add dx, MSR ;point to the MS register
in al, dx ;read to clear and store
mov BYTE PTR [bx+RS232IN], al ;store the status
;is RTS_CTS flow ctl. accepted
test WORD PTR [bx+FLOWCTL], RRTS_CTS
jz testDTR
test al, 010h ;test the CTS bit
jz tx_off1 ;if LOW, turn off TX
and WORD PTR [bx+INHOLD], NOT RRTS_CTS ;else clear RTS_CTS hold
or WORD PTR [bx+F_TX_START], 1 ; set flag to prime TX
jmp SHORT testDTR
tx_off1:
or WORD PTR [bx+INHOLD], RRTS_CTS;set flag indicating RX_HOLD
testDTR:
;is DTR_DSR flow ctl. accepted
test WORD PTR [bx+FLOWCTL], RDTR_DSR
jz end_ms_int
test al, 020h ;test the DSR bit
jz tx_off2 ;if LOW, turn off TX
and WORD PTR [bx+INHOLD], NOT RDTR_DSR ;else clear DTR/DSR hold
or WORD PTR [bx+F_TX_START], 1 ; set flag to prime TX
jmp SHORT end_ms_int
tx_off2:
or WORD PTR [bx+INHOLD], RDTR_DSR ;set flag indicating RX_HOLD
end_ms_int:
pop ds
END_PROC com_ms_ipr_
COMMENT $
;-------------------------------------------------------------------------------
;COM_LSTX_INT_ -- Line status AND TX data interrupt handler.
;-------------------------------------------------------------------------------
START_PROC <_FAR com_lstx_int_>, <FAR_DPTR port_addr>
push ds
les bx, port_addr
push es
push bx
call com_ls_int ;call the receive data available int
add sp, 4
mov dx, [bx+COM] ;point DX at RBR again
add dx, 5 ;examine THRE bit in LSR
in al, dx
test al, 020h
jz lstx ;THRE bit not set, so skip
or WORD PTR [bx+F_TX_START], 1 ; set flag to prime TX
lstx:
pop ds
END_PROC com_lstx_int_
;-------------------------------------------------------------------------------
;COM_RXTX_INT_ -- Received data AND TX data interrupt handler.
;-------------------------------------------------------------------------------
START_PROC <_FAR com_rxtx_int_>, <FAR_DPTR port_addr>
push ds
les bx, port_addr
push es
push bx
call com_rx_int ;call the receive data available int
add sp, 4
mov dx, [bx+COM] ;point DX at RBR again
add dx, 5 ;examine THRE bit in LSR
in al, dx
test al, 020h
jz no_others ;THRE bit not set, so skip
or WORD PTR [bx+F_TX_START], 1 ; set flag to prime TX
no_others:
pop ds
END_PROC com_rxtx_int_
$
;-------------------------------------------------------------------------------
;COM_DUMMY_ -- Dummy handler that does nothing.
;-------------------------------------------------------------------------------
START_PROC <_FAR com_dummy_>
END_PROC com_dummy_
CSEG ENDS
END