;***************************************************************
;*
;* Serial Port Interrupt Vector
;*
;***************************************************************

        CSEG    AT 0023H        ; 2~ for H/W's LCALL
        LJMP    SIO_ISR         ; 2~

        CSEG    AT 002BH
        LJMP    TBD_ISR

        ; ...

;***************************************************************
;*
;* Serial Port Interrupt Service Routine
;*
;***************************************************************

SIO_ISR:                        ; 4~ to get here
        PUSH    PSW             ; 2~ Save context
        MOV     PSW,#00001000B  ; 2~ Select register bank 1
        JBC     RI,RX_HDLR      ; 2~ If not RI, assume TI.
                                ;10~ For ISR entry and Rx/Tx dispatch

; TI_HDLR ---------------------- 10~ to get here
        CLR     TI              ; 1~ Relieve the interrupt
        CJNE    R1,#0,TX_EXIT   ; 2~ If done transmitting,
                                ;     ..TI clear prevents more interrupts.
        MOV     SBUF,@R0        ; 2~ Transmit a byte
        INC     R0              ; 1~ Advance buffer pointer
        DEC     R1              ; 1~ Count off one byte
TX_EXIT:
        POP     PSW             ; 2~ Restore context (and register bank)
        RETI                    ; 2~ *** 21 cycles/byte

RX_HDLR: ;---------------------- 10~ to get here
        MOV     @R0,SBUF        ; 2~ Buffer received byte
        INC     R0              ; 1~ Advance buffer pointer
        DJNZ    R1,RX_EXIT      ; 2~ If done receiving,
        CLR     REN             ;     ..REN clear prevents more interrupts.
RX_EXIT:
        POP     PSW             ; 2~ Restore context
        RETI                    ; 2~ *** 19 cycles/byte

;***************************************************************
;*
;* Concurrent "Work" and I/O
;*
;***************************************************************

; Receive a 16-byte packet.

        USING   1
        MOV     AR0,#RX_BUFFER  ; Point to the receive buffer
        MOV     AR1,#16         ; Number of bytes to receive
        CLR     RI              ; Enable the receiver, allowing the
        SETB    REN             ;  ..ISR to buffer the received bytes.
RX_WAIT:
        LCALL   DO_SOMETHING    ; Do something useful
        MOV     A,AR1           ;  ..until the ISR decrements the
        JNZ     RX_WAIT         ;  ..byte counter down to zero.

; Process the received packet.
;       ...
;       ...
;       ...

; Transmit a 16-byte packet.

        MOV     AR0,#TX_BUFFER  ; Point to the transmit buffer
        MOV     AR1,#16         ; Number of bytes to transmit
        SETB    TI              ; Enable the transmitter, allowing the
                                ;  ..ISR to transmit bytes from the buffer.
TX_WAIT:
        LCALL   DO_SOMETHING    ; Do something useful
        MOV     A,AR1           ;  ..until the ISR decrements the
        JNZ     TX_WAIT         ;  ..byte counter down to zero.