Metropoli BBS
VIEWER: commipr.asm MODE: TEXT (ASCII)
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
[ RETURN TO DIRECTORY ]