home *** CD-ROM | disk | FTP | other *** search
/ ftp.wwiv.com / ftp.wwiv.com.zip / ftp.wwiv.com / pub / DOOR / DDPLUS67.ZIP / SLASYNC.ASM < prev    next >
Assembly Source File  |  1994-11-21  |  25KB  |  819 lines

  1. ;    Status byte definition (C_Status):
  2.  
  3. ;    7   6   5   4   3   2   1   0
  4. ;    |   |   |   |   |   |   |   |____ Input buffer empty
  5. ;    |   |   |   |   |   |   |________ Input buffer full
  6. ;    |   |   |   |   |   |____________ Output buffer empty
  7. ;    |   |   |   |   |________________ Output buffer full
  8. ;    |   |   |   |____________________ Input buffer overflow
  9. ;    |   |   |________________________ Output buffer overflow
  10. ;    |   |____________________________ Hard handshake active (xmit stopped)
  11. ;    |________________________________ Soft handshake active (xmit stopped)
  12.  
  13. ;    Control byte definition (C_Ctrl):
  14.  
  15. ;    7   6   5   4   3   2   1   0
  16. ;    |   |   |   |   |   |   |   |____ Enable RTS handshake
  17. ;    |   |   |   |   |   |   |________ Enable CTS handshake
  18. ;    |   |   |   |   |   |____________ Enable software handshake
  19. ;    |   |   |   |   |________________
  20. ;    |   |   |   |____________________
  21. ;    |   |   |________________________
  22. ;    |   |____________________________
  23. ;    |________________________________
  24.  
  25. ;********************************************************
  26.  
  27. ; Macro:    PutChar
  28. ; Function:    Place character in transmit buffer (transmit a character)
  29. ; Entry:    AL <- Port # (0-3)
  30. ;        AH <- Status register
  31. ;        BX <- Byte array pointer
  32. ;        CH <- Character to put in buffer
  33. ;        DX <- Base address of port
  34. ; Destroyed:    ES,SI,DI,AL
  35.  
  36. ; Note:    Port address passed is NOT checked for validity.
  37. ;    Subroutine ChkPort will create the proper entry environment
  38.  
  39. PUTCHAR MACRO
  40.  
  41.         test    ah, 00001000b           ;Is buffer full?
  42.         JZ      @@putch1                ;No, OK to put character
  43.         or      ah, 00100000b           ;set overflow flag
  44.         JMP     @@putchx                ;and exit
  45.  
  46. @@putch1:
  47.         shl     bl,1                    ;bx <- word array index
  48.         mov     di, [C_outhead+bx]      ;bump the head pointer
  49.         mov     si, [c_outtail+bx]
  50.         inc     di
  51.         cmp     di, [C_outsize+bx]
  52.         jb      @@putch2
  53.         xor     di,di
  54. @@putch2:
  55.         mov     [C_outhead+bx],di       ;save head pointer
  56.         inc     [C_buffull+bx]          ;increment buffer-full word
  57.  
  58.         shl     bl,1                    ;BX <- pointer array index
  59.         LES     BX, [C_outbufptr+bx]    ;Load ES with segment of output buf
  60.         mov     [ES:BX+DI],ch           ;save the byte
  61.  
  62.         cmp     di, si                  ;Is output buffer full?
  63.         jnz     @@putch3                ;no, go enable xmitter
  64.         or      ah, 00001000b           ;Set status to output buffer full
  65. @@putch3:
  66.         xor     bh, bh
  67.         mov     bl, al                  ;Save AL in BL and make BX byte index
  68.  
  69.         test    ah, 11000000b           ;soft/hard handshake on?
  70.         jnz     @@putchx
  71. ;        test    ah, 00000100b
  72. ;        jz      @@putchx
  73.  
  74.         and     ah, 11111011b           ;Buffer is no longer empty
  75.         inc     dl                      ;Change to IER register
  76.         in      al, dx                  ;Read in the IER
  77.         or      al, 00000010b           ;Turn on xmt interrupt
  78.         NOP                             ;Slow down for slow machines
  79.         NOP
  80.         out     dx, al                  ;Write out the IER
  81.         dec     dl                      ;Back to base reg
  82. @@putchx:
  83.         mov     [C_status+bx],ah        ;set status byte
  84. ;        mov     al,bl                   ;get port num back in AL
  85.     ENDM
  86.  
  87. ;******************************************************************
  88. ; MACRO: Test for modem status change
  89. ;
  90. ; Entry: DX - port base
  91. ;        BX - byte array index
  92. ;
  93. ; Destroyed: AX, CX
  94.  
  95. MSCHG   MACRO
  96.  
  97. ;    Get modem status & control/status registers
  98.  
  99. @@Msc0:    ADD    DL,MSR            ;DX <- 8250 MSR port address
  100.     IN    AL,DX            ;AL <- 8250 Modem status
  101.     SUB    DL,MSR            ;Back to base
  102.  
  103.     MOV    CL,[C_Status+BX]    ;CL <- Status register
  104.     MOV    CH,[C_Ctrl+BX]        ;CH <- Control register
  105.  
  106. ;    Control CTS status flag based on CTS status and handshake enable
  107.  
  108.     TEST    CH,00000010b        ;CTS handshake enabled ?
  109.     JZ    @@Msc2            ; No, ignore CTS status
  110.     TEST    AL,00010000b        ;CTS asserted ?
  111.     JNZ    @@Msc1            ; Yes, enable transmit
  112.     OR    CL,01000000b        ;CTS inactive - hard handshake on
  113.     JMP    @@Msc2            ;
  114. @@Msc1:    AND    CL,10111111b        ;CTS active - hard handshake off
  115. @@Msc2:    MOV    [C_Status+BX],CL    ;Save status flags
  116.  
  117. ;    Determine if transmitter should be enabled
  118.  
  119. @@Msc3:    ADD    DL,IER            ;DX <- 8250 IER port address
  120.     IN    AL,DX            ;AL <- Interrupt enable register
  121.     OR    AL,00000010b        ;Enable transmitter by default
  122.     TEST    CL,11000100b        ;Enable transmitter ?
  123.     JZ    @@Msc4            ; Yes
  124.     AND    AL,11111101b        ; No - disable transmitter
  125. @@Msc4:    OUT    DX,AL            ;Update IER
  126.         SUB     DL, IER
  127.  
  128.         ENDM
  129.  
  130.     IDEAL
  131.  
  132.     SEGMENT    DATA     WORD PUBLIC
  133.  
  134. ;    Externally accessed (TP program) variables
  135. ;    Note:     Most of these variables are declared as arrays in the main
  136. ;        program; i.e. C_InSize : Array[1..4] Of Word
  137.  
  138.     EXTRN    C_InBufPtr :DWORD    ;Pointer to input buffers
  139.     EXTRN    C_OutBufPtr:DWORD    ;Pointer to output buffers
  140.     EXTRN    C_InSize   :WORD    ;Size (bytes) of input buffers
  141.     EXTRN    C_OutSize  :WORD    ;Size (bytes) of output buffers
  142.     EXTRN    C_InHead   :WORD    ;Input (receive) head pointers
  143.     EXTRN    C_OutHead  :WORD    ;Output (transmit) head pointers
  144.     EXTRN    C_InTail   :WORD    ;Input (receive) tail pointers
  145.     EXTRN    C_OutTail  :WORD    ;Output (transmit) tail pointers
  146.     EXTRN    C_RTSOn    :WORD    ;Point at which RTS line is asserted
  147.     EXTRN    C_RTSOff   :WORD    ;Point at which RTS line is dropped
  148.     EXTRN    C_StartChar:BYTE    ;Start character for soft handshake
  149.     EXTRN    C_StopChar :BYTE    ;Stop character for soft handshake
  150.     EXTRN    C_Status   :BYTE    ;Status byte (see above)
  151.     EXTRN    C_Ctrl     :BYTE    ;Control byte (see above)
  152.     EXTRN    C_PortOpen :BYTE    ;Port-open flags
  153.     EXTRN    C_PortAddr :WORD    ;Base address of ports
  154.     EXTRN    C_MaxCom   :BYTE    ;Highest port # defined (single byte)
  155.         EXTRN   C_bufFull  :WORD
  156.         EXTRN   C_cascade  :BYTE
  157. ;        EXTRN   C_CharSend  :WORD
  158. ;        EXTRN   C_CharWrite :WORD
  159. ;        EXTRN   C_Temp      :WORD    ;Used for debugging
  160.  
  161. ;    8250 register offsets
  162.  
  163. IER    EQU    1            ;Interrupt enable register
  164. IIR    EQU    2            ;Interrupt identification register
  165. LCR    EQU    3            ;Line control register
  166. MCR    EQU    4            ;Modem control register
  167. LSR    EQU    5            ;Line status register
  168. MSR    EQU    6            ;Modem status register
  169. SCR    EQU    7            ;8250 scratch register
  170.  
  171.     ENDS    DATA
  172.  
  173. ;    Code segment declaration
  174.  
  175.     SEGMENT    CODE    BYTE PUBLIC
  176.  
  177.     ASSUME    CS:CODE,DS:DATA
  178.  
  179. ;    Externally accessable procedures defined here
  180.  
  181.         PUBLIC  INT_Handler
  182.     PUBLIC    ComReadCh
  183.     PUBLIC    ComReadChW
  184.     PUBLIC    ComWriteCh
  185.     PUBLIC    ComWriteChW
  186.  
  187. ;********************************************************
  188. ;*                            *
  189. ;*    Subroutines that are used internally        *
  190. ;*                            *
  191. ;********************************************************
  192.  
  193. ; Subroutine:    ChkPort
  194. ; Function:    Check port parameter(s), ensure that port is OPEN
  195. ; Entry:    AL <- Port # (1 - C_MaxCom)
  196. ; Exit:        AL -> Adjusted port # (0 - 3)
  197. ;        AH -> Status register
  198. ;        BX -> Byte array index
  199. ;        DX -> Base address of port
  200. ;        Carry flag SET if parameters & port are OK
  201. ;
  202. ;    PROC    ChkPort        FAR
  203. ;
  204. ;    Determine if port # is valid
  205. ;
  206. ;    CMP    AL,[C_MaxCom]        ;Port # > Maximum port # ?
  207. ;    JA    ChkErr            ; Yes, exit w/error
  208. ;    CMP    AL,0            ;Port # = 0 (invalid port #)
  209. ;    JZ    ChkErr            ; Yes, exit w/error
  210. ;    DEC    AL            ;AL <- Adjusted port #
  211. ;
  212. ;    Check if port open
  213. ;
  214. ;    XOR    BH,BH            ;
  215. ;    MOV    BL,AL            ;BX <- Byte array index
  216. ;    MOV    AH,[C_PortOpen+BX]    ;AH <- Port-open flag
  217. ;    CMP    AH,0            ;Port open ?
  218. ;    JZ    ChkErr            ; No, exit w/error
  219. ;
  220. ;    Get status register and base port address in DX
  221. ;
  222. ;    MOV    AH,[C_Status+BX]    ;AH <- Status register
  223. ;    SHL    BL,1            ;BX <- Word array index
  224. ;    MOV    DX,[C_PortAddr+BX]    ;DX <- Port address
  225. ;    SHR    BL,1            ;BX <- Byte array index
  226. ;    STC                ;Set carry (valid return)
  227. ;    RET                ;Exit
  228. ;
  229. ;    Here if error
  230. ;
  231. ;ChkErr:    CLC                ;Clear carry (invalid return)
  232. ;    RET                ;Exit
  233. ;
  234. ;    ENDP    ChkPort
  235.  
  236. ;    PROC    PutChar        FAR
  237. ;
  238. ;;    Check for buffer overflow
  239. ;
  240. ;    TEST    AH,00001000b        ;Buffer full ?
  241. ;    JZ    PutCh1            ; No, continue
  242. ;    OR    AH,00100000b        ;Set buffer-overflow flag
  243. ;    JMP    PutChX            ;Exit
  244. ;
  245. ;;    Increment head pointer
  246. ;
  247. ;PutCh1:    SHL    BL,1            ;BX <- Word array index
  248. ;    MOV    DI,[C_OutHead+BX]    ;DI <- Output head pointer
  249. ;    MOV    SI,[C_OutTail+BX]    ;SI <- Output tail pointer
  250. ;    INC    DI            ;Bump head pointer
  251. ;    CMP    DI,[C_OutSize+BX]    ;Head >= Buffer size ?
  252. ;    JB    PutCh2            ; No, continue
  253. ;    XOR    DI,DI            ; Yes, reset pointer
  254. ;PutCh2:    MOV    [C_OutHead+BX],DI    ;Save head pointer
  255. ;        INC     [C_buffull+bx]          ;Increment chars in buffer
  256. ;;        INC     [C_charwrite+bx]
  257. ;
  258. ;;    Place character in buffer
  259. ;
  260. ;    SHL    BL,1            ;BX <- Pointer array index
  261. ;    LES    BX,[C_OutBufPtr+BX]    ;ES:BX <- Pointer to output buffer
  262. ;    MOV    [ES:BX+DI],CH        ;Place character in buffer
  263. ;
  264. ;;    Check for full buffer
  265. ;
  266. ;    CMP    DI,SI            ;Head = Tail (buffer full) ?
  267. ;    JNZ    PutCh3            ; No, buffer not full
  268. ;    OR    AH,00001000b        ;Set buffer-full flag
  269. ;
  270. ;;    Determine if transmitter should be activated
  271. ;
  272. ;PutCh3:    XOR    BH,BH            ;
  273. ;    MOV    BL,AL            ;BX <- Byte array index
  274. ;
  275. ;    TEST    AH,11000000b        ;Any inhibits (soft/hard hshake) ?
  276. ;    JNZ    PutChX            ; Yes, do not activate xmit interrupt
  277. ;;    TEST    AH,00000100b        ;Buffer empty ?
  278. ;;    JZ    PutChX            ; No, xmit interrupt is on already
  279. ;
  280. ;    AND    AH,11111011b        ;Reset buffer-empty flag
  281. ;    ADD    DL,IER            ;Point to interrupt enable register
  282. ;    IN    AL,DX            ;AL <- Interrupt enable register
  283. ;    OR    AL,00000010b        ;Enable transmit interrupt
  284. ;       NOP                             ;Slow down for slow machines
  285. ;       NOP
  286. ;    OUT    DX,AL            ;Update port
  287. ;    SUB    DL,IER            ;Point back to base
  288. ;
  289. ;;    Here to exit
  290. ;
  291. ;PutChX:    MOV    [C_Status+BX],AH    ;Save status byte
  292. ;    MOV    AL,BL            ;
  293. ;    RET                ;Exit
  294. ;
  295. ;    ENDP    PutChar
  296.  
  297.  
  298. ;********************************************************
  299. ;*                            *
  300. ;*    Interrupt service routine for INT3,INT4        *
  301. ;*                            *
  302. ;*        INT3 typically used by COM2, COM4        *
  303. ;*         INT4 typically used by COM1, COM3        *
  304. ;*                            *
  305. ;********************************************************
  306.  
  307.     PROC    INT_Handler     FAR
  308.  
  309.     PUSH    AX            ;Save environment
  310.     PUSH    BX            ;
  311.     PUSH    CX            ;
  312.     PUSH    DX            ;
  313.     PUSH    SI            ;
  314.     PUSH    DI            ;
  315.     PUSH    DS            ;
  316.     PUSH    ES            ;
  317.     PUSH    BP            ;
  318.  
  319.     MASM
  320.     MOV    AX,SEG DATA        ;AX <- Current data segment
  321.     IDEAL
  322.     MOV    DS,AX            ;Set new data segment
  323.  
  324. INT_Id:    XOR    BX,BX            ;BL <- Port # (start at 0)
  325.  
  326. ;    Identify active port
  327.  
  328. IntID1:    MOV    AL,[C_PortOpen+BX]    ;AL <- Port-open flag
  329.     CMP    AL,0            ;Port open ?
  330.     JZ    IntID2            ; No, don't check
  331.     SHL    BL,1            ;BX <- Word array index
  332.     MOV    DX,[C_PortAddr+BX]    ;DX <- Base address of port
  333.     SHR    BL,1            ;BX <- Byte array index
  334.     ADD    DL,IIR            ;Add in offset for IIR
  335.     IN    AL,DX            ;AL <- COMn IIR
  336.     TEST    AL,00000001b        ;Interrupt active on this port ?
  337.     JZ    INT_Active        ; (Bit 0 = 0 if active)
  338. IntID2:    INC    BL            ;Bump port #
  339.     CMP    BL,[C_MaxCom]        ;All ports checked ?
  340.     JB    IntID1            ; No, continue
  341.  
  342. ;    Here to reset 8259 controller
  343.  
  344.     MOV    AL,20h            ;AL <- EOI Acknowledge code
  345.     OUT    20h,AL            ;To 8259 PIC
  346.         MOV     AL,[C_Cascade]          ;Move cascade flag
  347.         CMP     AL,0                    ;No cascade?
  348.         JE      IntID3                  ;Check it no cascaded irq
  349.  
  350. ;    Reset cascade port
  351.  
  352.     MOV    DX,0A0h                 ;DX To 8259 cascade PIC
  353.     MOV    AL,20h            ;AL <- EOI Acknowledge code
  354.     OUT    DX,AL            ;To 8259 cascade PIC
  355.  
  356. ;    Here to leave interrupt handler
  357.  
  358. IntID3:    POP    BP            ;Restore envirionment
  359.     POP    ES            ;
  360.     POP    DS            ;
  361.     POP    DI            ;
  362.     POP    SI            ;
  363.     POP    DX            ;
  364.     POP    CX            ;
  365.     POP    BX            ;
  366.     POP    AX            ;
  367.  
  368.     IRET                ;Interrupt exit
  369.  
  370. ;    Active port (8250) found.
  371. ;    Determine cause of interrupt and execute appropriate handler.
  372. ;    Upon entry into routine, registers are set as follows:
  373. ;    BX <- Byte array index
  374. ;    DX <- Port address
  375.  
  376. INT_Active:
  377.     DEC    DX            ;
  378.     DEC    DX            ;DX <- Base address of COM port
  379.  
  380.     CMP    AL,0            ;IIR = 0 (Modem status change) ?
  381.     JZ    ComMsc            ; Yes
  382.     CMP    AL,2            ;IIR = 2 (Character transmitted) ?
  383.     JZ    ComXmt            ; Yes
  384.     CMP    AL,4            ;IIR = 4 (Character received) ?
  385.     JNZ    Next            ;
  386.     JMP    ComRcv            ; Yes
  387. Next:    CMP    AL,6            ;IIR = 6 (Line status change) ?
  388.     JZ    ComLsc            ; Yes
  389.     JMP    INT_Id            ;Check other ports & exit
  390.  
  391. ;*******************************************************
  392. ;        Line status change
  393. ;        NOTE: Currently unused
  394. ;*******************************************************
  395.  
  396. ComLsc:    ADD    DL,LSR            ;Point to line status register
  397.     IN    AL,DX            ;Get LSR
  398.  
  399. ;    The following code (which disables then enables the transmit
  400. ;    interrupt) is required to compensate for some "buggy" 8250's and
  401. ;    8250-emulating gate arrays.
  402.  
  403.     SUB    DL,LSR            ;Back to base
  404.     ADD    DL,IER            ;Point to interrupt enable register
  405.     IN    AL,DX            ;Get IER
  406.     MOV    AH,AL            ;Save IER
  407.     AND    AL,11111101b        ;Mask transmit interrupt
  408.     OUT    DX,AL            ;Send modified to port
  409.     MOV    AL,AH            ;
  410.         NOP                             ;slow down for slow machines
  411.         NOP
  412.     OUT    DX,AL            ;Send original to port
  413.  
  414.     JMP    INT_Id            ;Exit
  415.  
  416. ;*******************************************************
  417. ;        Modem status change
  418. ;*******************************************************
  419.  
  420. ComMsc:    NOP
  421.  
  422. ;    Get modem status & control/status registers
  423.  
  424. Msc0:    ADD    DL,MSR            ;DX <- 8250 MSR port address
  425.     IN    AL,DX            ;AL <- 8250 Modem status
  426.     SUB    DL,MSR            ;Back to base
  427.  
  428.     MOV    CL,[C_Status+BX]    ;CL <- Status register
  429.     MOV    CH,[C_Ctrl+BX]        ;CH <- Control register
  430.  
  431. ;    Control CTS status flag based on CTS status and handshake enable
  432.  
  433.     TEST    CH,00000010b        ;CTS handshake enabled ?
  434.     JZ    Msc2            ; No, ignore CTS status
  435.     TEST    AL,00010000b        ;CTS asserted ?
  436.     JNZ    Msc1            ; Yes, enable transmit
  437.     OR    CL,01000000b        ;CTS inactive - hard handshake on
  438.     JMP    Msc2            ;
  439. Msc1:    AND    CL,10111111b        ;CTS active - hard handshake off
  440. Msc2:    MOV    [C_Status+BX],CL    ;Save status flags
  441.  
  442. ;    Determine if transmitter should be enabled
  443.  
  444. Msc3:    ADD    DL,IER            ;DX <- 8250 IER port address
  445.     IN    AL,DX            ;AL <- Interrupt enable register
  446.     OR    AL,00000010b        ;Enable transmitter by default
  447.     TEST    CL,11000100b        ;Enable transmitter ?
  448.     JZ    Msc4            ; Yes
  449.     AND    AL,11111101b        ; No - disable transmitter
  450. Msc4:    OUT    DX,AL            ;Update IER
  451.     JMP    INT_Id            ;Exit
  452.  
  453. ;*******************************************************
  454. ;        Character transmitted
  455. ;*******************************************************
  456.  
  457. ; Register usage:
  458. ; AH : Status register
  459. ; BX : Array pointer
  460. ; DX : Port address
  461. ; SI : Output tail pointer
  462. ; DI : Output head pointer
  463.  
  464. ;    Get status and control registers
  465.  
  466. ComXmt:    MOV    AH,[C_Status+BX]    ;AH <- Status register
  467.     TEST    AH,00000100b        ;Buffer empty ?
  468.     JNZ    Xmt2            ; Yes, stop transmitter
  469.  
  470. ;    Bump tail pointer
  471.  
  472.     PUSH    BX            ;Save byte array pointer
  473.     SHL    BL,1            ;BX <- Word array pointer
  474.     MOV    SI,[C_OutTail+BX]    ;SI <- Output tail pointer
  475.     MOV    DI,[C_OutHead+BX]    ;DI <- Output head pointer
  476.  
  477.     INC    SI            ;Bump tail pointer
  478.     CMP    SI,[C_OutSize+BX]    ;Tail < Buffer size ?
  479.     JB    Xmt1            ; Yes, proceed normally
  480.     XOR    SI,SI            ; No, reset to 0
  481. Xmt1:    MOV    [C_OutTail+BX],SI    ;Save tail pointer
  482.  
  483.         DEC     [C_buffull+bx]          ;Decrement chars in buffer
  484. ;        INC     [C_charsend+bx]
  485.  
  486. ;    Send character
  487.  
  488.     SHL    BL,1            ;BX <- Pointer array pointer
  489.     LES    BX,[C_OutBufPtr+BX]    ;ES:BX <- Pointer to output buffer
  490.     MOV    AL,[ES:BX+SI]        ;AL <- Character from buffer
  491.     OUT    DX,AL            ;Send
  492.     POP    BX            ;Recover byte array pointer
  493.  
  494. ;    Determine if buffer is empty
  495. ;    Reset output-buffer-full flag & exit
  496.  
  497.     CMP    DI,SI            ;Head = Tail (buffer empty) ?
  498.     JNZ    Xmt2            ; No, continue normally
  499.     OR    AH,00000100b        ;Set buffer-empty flag
  500. Xmt2:    AND    AH,11010111b        ;Reset FULL and OVERFLOW flags
  501.     MOV    [C_Status+BX],AH    ;Save status flags
  502.     JMP    Msc0            ;Exit (check xmit mask)
  503.  
  504. ;*******************************************************
  505. ;        Character received
  506. ;*******************************************************
  507.  
  508. ; Register usage:
  509. ; AL : Status register
  510. ; AH : Control register
  511. ; BX : Array index
  512. ; CL : Character received
  513. ; CH : Temporary storage
  514. ; DX : Port address
  515. ; SI : Input tail pointer
  516. ; DI : Input head pointer
  517.  
  518. ComRcv:    IN    AL,DX            ;
  519.     MOV    CL,AL            ;CL <- Received character
  520.  
  521. ;    Check for software handshake
  522.  
  523.     MOV    AL,[C_Status+BX]    ;AL <- Status byte
  524.     MOV    AH,[C_Ctrl+BX]        ;AH <- Control byte
  525.     TEST    AH,00000100b        ;Software handshake enabled ?
  526.     JZ    Rcv3            ; No, don't check software handshake
  527.     CMP    CL,[C_StopChar+BX]    ;STOP TRANSMIT character ?
  528.     JZ    Rcv1            ; Yes
  529.     CMP    CL,[C_StartChar+BX]    ;START TRANSMIT character ?
  530.     JNZ    Rcv3            ; No
  531.  
  532. ;    Soft-handshake character received.
  533. ;    Activate or deactive transmitter depending on status
  534.  
  535.     AND    AL,01111111b        ;Reset soft-handshake flag (start)
  536.     JMP    Rcv2            ;Save status & exit
  537. Rcv1:    OR    AL,10000000b        ;Set soft-handshake flag (stop)
  538. Rcv2:    MOV    CL,AL            ;Routines in MSC2 require status in CL
  539.     JMP    Msc2            ;Exit (xmit interrupt controlled here)
  540.  
  541. ;    Clear buffer empty flag / check for buffer overflow
  542.  
  543.  
  544. Rcv3:    AND    AL,11111110b        ;Clear buffer-empty flag
  545.     TEST    AL,00000010b        ;Buffer full ?
  546.     JZ    Rcv4            ; No, continue
  547.     OR    AL,00010000b        ;Set overflow flag
  548.     JMP    Rcv10            ;Exit
  549.  
  550. ;    Bump receive buffer pointer
  551.  
  552. Rcv4:    SHL    BL,1            ;BX <- Word array index
  553.     MOV    DI,[C_InHead+BX]    ;DI <- Input head pointer
  554.     MOV    SI,[C_InTail+BX]    ;SI <- Input tail pointer
  555.  
  556.     INC    DI            ;Bump buffer pointer
  557.     CMP    DI,[C_InSize+BX]    ;Head > buffer size ?
  558.     JB    Rcv5            ; No, continue
  559.     XOR    DI,DI            ; Yes, reset pointer
  560.  
  561. ;    Store character in buffer
  562.  
  563. Rcv5:    PUSH    BX            ;Save word array pointer
  564.     MOV    [C_InHead+BX],DI    ;Save updated input head pointer
  565.     SHL    BL,1            ;BX <- Doubleword array index
  566.     LES    BX,[C_InBufPtr+BX]    ;ES:BX <- Pointer to buffer
  567.     MOV    [ES:BX+DI],CL        ;Save character in buffer
  568.     POP    BX            ;Recover word array pointer
  569.  
  570. ;    Check for full buffer
  571.  
  572.     CMP    SI,DI            ;Tail = Head ?
  573.     JNZ    Rcv6            ;If Tail <> Head, buffer is not full
  574.     OR    AL,00000010b        ;Set buffer-full flag
  575.     JMP    Rcv8            ;Reset RTS and exit
  576.  
  577. ;    Check for near-full buffer (buffer used >= RTSOff)
  578.  
  579. Rcv6:    CMP    SI,DI            ;Tail <= Head ?
  580.     JBE    Rcv7            ; Yes, use standard formula
  581.     SUB    SI,DI            ;SI <- Tail - Head
  582.     MOV    DI,[C_InSize+BX]    ;DI <- Input buffer size
  583. Rcv7:    SUB    DI,SI            ;DI <- Head - Tail (amt used)
  584.     CMP    DI,[C_RTSOff+BX]    ;Used < Limit ?
  585.     JB    Rcv9            ; Yes, leave RTS on
  586.  
  587. ;    Buffer is (near) full, force RTS off & exit
  588.  
  589. Rcv8:    TEST    AH,00000001b        ;RTS handshake enabled ?
  590.     JZ    Rcv9            ; No, exit now
  591.  
  592.     MOV    CH,AL            ;Keep status byte
  593.     ADD    DL,MCR            ;DX <- Address of modem control reg.
  594.     IN    AL,DX            ;AL <- MCR
  595.     AND    AL,11111101b        ;Disable RTS
  596.     OUT    DX,AL            ;Update MCR
  597.     SUB    DL,MCR            ;DX <- Base of port
  598.     MOV    AL,CH            ;Recover status byte
  599.  
  600. ;    Exit - receive
  601.  
  602. Rcv9:    SHR    BL,1            ;BX <- Byte array index
  603. Rcv10:    MOV    [C_Status+BX],AL    ;Save status byte
  604.  
  605. ;    The following code corrects a "bug" present in some 8250's
  606.  
  607.     ADD    DL,IER            ;DX <- Interrupt Enable Register
  608.     IN    AL,DX            ;AL <- IER
  609.     MOV    AH,AL            ;Save IER
  610.     AND    AL,11111101b        ;Mask off transmit interrupt
  611.     OUT    DX,AL            ;Send to IER
  612.     MOV    AL,AH            ;
  613.         NOP                             ;Slow down for slow machines
  614.         NOP
  615.     OUT    DX,AL            ;Restore original IER state
  616.  
  617.     JMP    INT_Id            ;Check for pending INTs and exit
  618.  
  619.     ENDP    INT_Handler
  620.  
  621. ;********************************************************
  622. ;*                            *
  623. ;*    Start of Pascal low-level procedures        *
  624. ;*                            *
  625. ;********************************************************
  626. ;*                            *
  627. ;*    Function ComReadCh(ComPort:Byte) : Char        *
  628. ;*                            *
  629. ;********************************************************
  630.  
  631.     PROC    ComReadCh     FAR
  632.  
  633.     CLI                ;Interrupts disabled
  634.  
  635.     MOV    BX,SP            ;BX <- Stack pointer
  636.     MOV    AL,[SS:BX+4]        ;AL <- Port #
  637.  
  638.         dec     al                      ;Adjust port number (COM1=0)
  639.         xor     bh,bh                   ;Nuke BH
  640.         mov     bl,al                   ;Get byte index into BL
  641.         shl     bl,1                    ;Convert to word index
  642.         mov     dx,[C_Portaddr+BX]      ;Get port base address
  643.         shr     bl,1                    ;Convert back to byte index
  644.  
  645. ;    Check buffer, return null if empty
  646.  
  647.     MOV    AH,[C_Status+BX]    ;AH <- Status byte
  648.     TEST    AH,00000001b        ;Buffer empty ?
  649.     JZ    ComRd2            ; No, continue normally
  650.  
  651. ;    Buffer empty, port not open or port # invalid - exit
  652.  
  653. ComRd1:    MOV    CH,0            ;Return null (port error or empty)
  654. ComRdX:    MOV    AL,CH            ;AL <- Char from buffer
  655.     STI                ;Enable interrupts
  656.     RET    2            ;Exit
  657.  
  658. ;    Increment tail pointer
  659. ;    NOTE: Entry point for ComReadChW
  660.  
  661. ComRd2:    SHL    BL,1            ;BX <- Word array index
  662.     MOV    SI,[C_InTail+BX]    ;SI <- Tail pointer
  663.     MOV    DI,[C_InHead+BX]    ;DI <- Input head pointer
  664.     INC    SI            ;Bump tail pointer
  665.     CMP    SI,[C_InSize+BX]    ;Tail past end of buffer ?
  666.     JB    ComRd3            ; No, continue
  667.     XOR    SI,SI            ; Yes, reset pointer
  668. ComRd3:    MOV    [C_InTail+BX],SI    ;Save updated tail pointer
  669.  
  670. ;    Get character from buffer
  671.  
  672.     SHL    BL,1            ;BX <- Pointer array index
  673.     LES    BX,[C_InBufPtr+BX]    ;ES:BX <- Pointer to input buffer
  674.     MOV    CH,[ES:BX+SI]        ;CH <- Character from buffer
  675.  
  676. ;    Clear FULL and OVERFLOW flags
  677. ;    Check for empty buffer
  678.  
  679.     XOR    BH,BH            ;
  680.     MOV    BL,AL            ;Byte array index
  681.     AND    AH,11101101b        ;Reset FULL and OVERFLOW status flags
  682.     CMP    DI,SI            ;Head = Tail (buffer empty ?)
  683.     JNZ    ComRd4            ; No, continue normally
  684.     OR    AH,00000001b        ; Yes, set empty flag
  685. ComRd4:    MOV    [C_Status+BX],AH    ;Save status byte
  686.  
  687.         MOV     AL,[c_ctrl+bx]          ;get control byte in AL
  688.         TEST    AL,00000001b            ;is RTS handshake enabled?
  689.         JZ      ComRdX                  ;no, exit
  690.  
  691.  
  692. ;    Check for RTS assert (Used <= RTSOn)
  693. ;    Variable USED (# of used bytes in buffer) calculated as :
  694. ;      IF (Head >= Tail) THEN
  695. ;        Used = Head-Tail
  696. ;      ELSE
  697. ;        Used = BufferSize - (Tail-Head)
  698.  
  699.     SHL    BL,1            ;BX <- Word array index
  700.     CMP    DI,SI            ;Head >= Tail ?
  701.     JAE    ComRd5            ; Yes, use alternate formula
  702.     SUB    SI,DI            ;SI <- Tail - Head
  703.     MOV    DI,[C_InSize+BX]    ;DI <- Input buffer size
  704. ComRd5:    SUB    DI,SI            ;DI <- Amount of buffer used
  705.     CMP    DI,[C_RTSOn+BX]        ;Used > Limit ?
  706.     JA    ComRdX            ; Yes, not ready for receive
  707.  
  708. ;    Here to assert RTS
  709.  
  710.     ADD    DL,MCR            ;DX <- 8250 MCR port address
  711.     IN    AL,DX            ;AL <- 8250 MCR
  712.     OR    AL,00000010b        ;Assert RTS
  713.         NOP                             ;Slow down for slow machines
  714.         NOP
  715.     OUT    DX,AL            ;Send to port
  716.     JMP    ComRdX            ;Exit
  717.  
  718.     ENDP    ComReadCh
  719.  
  720. ;********************************************************
  721. ;*                            *
  722. ;*    Function ComReadChW(ComPort:Byte) : Char    *
  723. ;*                            *
  724. ;********************************************************
  725.  
  726.     PROC    ComReadChW    FAR
  727.  
  728.     MOV    BX,SP            ;BX <- Stack pointer
  729.     MOV    AL,[SS:BX+4]        ;AL <- Port #
  730.  
  731.         dec     al                      ;Adjust port number (COM1=0)
  732.         xor     bh,bh                   ;Nuke BH
  733.         mov     bl,al                   ;Get byte index into BL
  734.         shl     bl,1                    ;Convert to word index
  735.         mov     dx,[C_Portaddr+BX]      ;Get port base address
  736.         shr     bl,1                    ;Convert back to byte index
  737.  
  738. ;    Wait for character
  739.  
  740. ComRW1:    MOV    AH,[C_Status+BX]    ;AL <- Status byte
  741.     TEST    AH,00000001b        ;Input buffer empty ?
  742.     JNZ    ComRW1            ; Yes, continue waiting
  743.  
  744.     CLI                ;Disable interrupts
  745.     JMP    ComRd2            ;Proceed with normal read
  746.  
  747.     ENDP    ComReadChW
  748.  
  749. ;********************************************************
  750. ;*                            *
  751. ;*    Procedure ComWriteCh(ComPort:Byte; Var Ch:Char)    *
  752. ;*                            *
  753. ;********************************************************
  754.  
  755.     PROC    ComWriteCh    FAR
  756.  
  757. ;    Check port # for validity
  758.  
  759.     MOV    BX,SP            ;Point BX at parameters
  760.     MOV    AL,[SS:BX+6]        ;AL <- Port #
  761.     MOV    CH,[SS:BX+4]        ;CH <- Character to send
  762.  
  763.         dec     al                      ;Adjust port number (COM1=0)
  764.         xor     bh,bh                   ;Nuke BH
  765.         mov     bl,al                   ;Get byte index into BL
  766.         shl     bl,1                    ;Convert to word index
  767.         mov     dx,[C_Portaddr+BX]      ;Get port base address
  768.         shr     bl,1                    ;Convert back to byte index
  769.  
  770.         mov     ah, [c_status+bx]       ;get status word for PUTCHAR
  771.  
  772.     CLI                ;Disable interrupts
  773.     PutChar                            ;Place character in buffer (AL nuked)
  774.     STI                ;Enable interrupts
  775.  
  776. ComWr1:    RET    4            ;Exit
  777.  
  778.     ENDP    ComWriteCh
  779.  
  780. ;********************************************************
  781. ;*                            *
  782. ;*   Procedure ComWriteChW(ComPort:Byte; Var Ch:Char)    *
  783. ;*                            *
  784. ;********************************************************
  785.  
  786.     PROC    ComWriteChW    FAR
  787.  
  788. ;    Check port # for validity
  789.  
  790.     MOV    BX,SP            ;Point BX at parameters
  791.     MOV    AL,[SS:BX+6]        ;AL <- Port #
  792.     MOV    CH,[SS:BX+4]        ;CH <- Character to send
  793.  
  794.         dec     al                      ;Adjust port number (COM1=0)
  795.         xor     bh,bh                   ;Nuke BH
  796.         mov     bl,al                   ;Get byte index into BL
  797.         shl     bl,1                    ;Convert to word index
  798.         mov     dx,[C_Portaddr+BX]      ;Get port base address
  799.         shr     bl,1                    ;Convert back to byte index
  800.  
  801. ;    Wait for buffer to open up
  802.  
  803. ComWW1:    MOV    AH,[C_Status+BX]    ;AH <- Status byte
  804.     TEST    AH,00101000b        ;Buffer filled ?
  805.     JNZ    ComWW1            ; Yes, loop until open
  806.  
  807.     CLI                ;Turn off interrupts
  808.     PutChar                    ;Place character in buffer (AL nuked)
  809.     STI                ;Enable interrupts
  810.  
  811. ComWW2:    RET    4            ;Exit
  812.  
  813.     ENDP    ComWriteChW
  814.  
  815. ;********************************************************
  816.  
  817.     ENDS    CODE
  818.     END
  819.