home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / assemblr / library / async / casyn.asm next >
Assembly Source File  |  1988-03-08  |  23KB  |  474 lines

  1.         page    ,132
  2. ;*****************************************************************************
  3. ;
  4. ;                       Asynchronous Support Routines
  5. ; Beispielprogramm zum Linken mit C Version 1.0
  6. ;*****************************************************************************
  7. _TEXT   SEGMENT BYTE PUBLIC 'CODE'       ; Default code segment
  8. _TEXT   ENDS
  9. _DATA   SEGMENT WORD PUBLIC 'DATA'       ; Default data segment
  10. _DATA   ENDS
  11. CONST   SEGMENT WORD PUBLIC 'CONST'      ; Read only constants
  12. CONST   ENDS
  13. _BSS    SEGMENT WORD PUBLIC 'BSS'        ; Uninitialized static data
  14. _BSS    ENDS
  15. STACK   SEGMENT PARA STACK 'STACK'       ; Stack segment
  16. STACK   ENDS
  17.  
  18. DGROUP  GROUP   _DATA,CONST,_BSS,STACK
  19. _TEXT   SEGMENT BYTE PUBLIC 'CODE'
  20.         ASSUME  CS:_TEXT,DS:DGROUP
  21. @AB     EQU     4
  22.  
  23. XMITI   EQU     00000h                  ;set to 0FFFFh for xmit via interrupt
  24.  
  25.         public  _asnget                 ;get char from asynch buffer
  26.         public  _asnput                 ;put char to asynch line
  27.         public  _asnstat                ;get status of asynch port
  28.         public  _asninit                ;initialize asynch port & routines
  29.         public  _asnclr                 ;clear asynch receive buffer
  30.         public  _asnfls                 ;flush asynch transmit buffer
  31.         public  _asnexit                ;remove asynch interrupt routine
  32.         public  _asnbaud                ;set baud rate for asynch port
  33. ;*****************************************************************************
  34. ;
  35. ;       POPF Macro for PC/AT 2/86 hardware bugÜ
  36. ;
  37. ;*****************************************************************************
  38. POPFF   MACRO                   ;this kludge is due to INTEL's idiocyÜ
  39.         local   f1,b1
  40.         jmp     short f1        ;jump over iret
  41. b1:     iret                    ;simulate the POPF in a way that works
  42. f1:     push    cs              ;save cs so that the IRET works correctly
  43.         call    b1              ;save ip and execute the IRET, and continue
  44.         ENDM
  45.         page
  46. ;*****************************************************************************
  47. ;
  48. ;       Miscellaneous Definitions
  49. ;
  50. ;*****************************************************************************
  51. BSIZE   equ     4096                    ;circular receive buffer size
  52. LCRBYTE equ     00010011b               ;LCR default, 8 bits+no parity
  53.  
  54. ;*****************************************************************************
  55. ;
  56. ;       Device address definitions
  57. ;
  58. ;*****************************************************************************
  59. PICCMD  equ     20h                     ;8259 Priority Interrupt Controller
  60. PICMSK  equ     21h                     ;8259 Priority Interrupt Controller
  61.  
  62. ASRBR   equ     008h                    ;8250 Receiver Buffer Register
  63. ASTHR   equ     008h                    ;8250 Transmitter Holding Register
  64. ASDLL   equ     008h                    ;8250 Divisor Latch Low
  65. ASDLH   equ     009h                    ;8250 Divisor Latch High
  66. ASIER   equ     009h                    ;8250 Interrupt Enable Register
  67. ASIIR   equ     00Ah                    ;8250 Interrupt Identification Register
  68. ASLCR   equ     00Bh                    ;8250 Line Control Register
  69. ASMCR   equ     00Ch                    ;8250 Modem Control Register
  70. ASLSR   equ     00Dh                    ;8250 Line Status Register
  71. ASMSR   equ     00Eh                    ;8250 Modem Status Register
  72.  
  73. ;*****************************************************************************
  74. ;
  75. ;       data
  76. ;
  77. ;*****************************************************************************
  78. _DATA   segment
  79. clock   dd      115200                  ;dividend value for asnbaud
  80. rbhead  dw      offset dgroup:rbfbeg    ;recv buffer empty pointer
  81. rbtail  dw      offset dgroup:rbfbeg    ;recv buffer fill  pointer
  82. rbfbeg  db      BSIZE dup (?)           ;recv buffer for receive data
  83. rbfend  equ     this byte               ;recv buffer end address
  84.  
  85.         IF      XMITI
  86. xbhead  dw      offset dgroup:xbfbeg    ;xmit buffer empty pointer
  87. xbtail  dw      offset dgroup:xbfbeg    ;xmit buffer fill  pointer
  88. xbcnt   dw      BSIZE                   ;count of room left in buffer
  89. xbfbeg  db      BSIZE dup (?)           ;xmit buffer for receive data
  90. xbfend  equ     this byte               ;xmit buffer end address
  91.         ENDIF
  92.  
  93. iolist  dw      03f0h,02f0h             ;COM1, COM2 I/O base addresses
  94. ioaddr  dw      ?                       ;selected I/O adapter base address
  95.  
  96. ivlist  dw      0030h,002Ch             ;COM1, COM2 interrupt vector addr list
  97. ivaddr  dw      ?                       ;selected interrupt vector
  98.  
  99. imlist  db      11101111b,11110111b     ;COM1, COM2 interrupt mask list
  100. imbyte  db      ?                       ;selected interrupt mask byte
  101. _DATA   ends
  102.         page
  103. ;*****************************************************************************
  104. ;
  105. ;       asninit is called to initialize the async support routines
  106. ;
  107. ;               it MUST be called before any of the other asynch routines
  108. ;               argument should be 0 for COM1 or 1 for COM2
  109. ;
  110. ;       syntax - asninit(comport)
  111. ;
  112. ;*****************************************************************************
  113. _asninit proc   near
  114.         cli                             ;disable interrupts
  115.         push    bp
  116.         mov     bp,sp
  117.         mov     ax,@AB[bp]              ;get argument
  118.         mov     bx,ax                   ;get adapter selection value into bx
  119.         cmp     bx,1                    ;test for invalid value
  120.         jna     asi2                    ;ok, continue
  121.         mov     bx,0                    ;invalid, assume 0
  122. asi2:   mov     al,imlist[bx]           ;get selected interrupt mask byte
  123.         mov     imbyte,al               ;save it in imbyte
  124.         add     bx,bx                   ;convert to index into iolist
  125.         mov     ax,iolist[bx]           ;get i/o adapter base address
  126.         mov     ioaddr,ax               ;store into ioaddr
  127.         mov     ax,ivlist[bx]           ;get interrupt vector address
  128.         mov     ivaddr,ax               ;store into ivaddr
  129.         mov     cx,cs                   ;get current cs into cx
  130.         mov     dx,offset asnint        ;get offset of interrupt routine
  131.         mov     bx,ivaddr               ;get interrupt vector address
  132.         mov     ax,0
  133.         push    ds
  134.         mov     ds,ax                   ;set ds to 0
  135.         mov     [bx+2],cx               ;set interrupt vector in low mem
  136.         mov     [bx],dx
  137.         pop     ds
  138.         mov     ax,offset dgroup:rbfbeg ;get offset of buffer
  139.         mov     rbhead,ax               ;initialize buffer empty pointer
  140.         mov     rbtail,ax               ;initialize buffer fill  pointer
  141.         IF      XMITI
  142.         mov     ax,offset dgroup:xbfbeg ;get offset of buffer
  143.         mov     xbhead,ax               ;initialize buffer empty pointer
  144.         mov     xbtail,ax               ;initialize buffer fill  pointer
  145.         mov     ax,BSIZE                ;get buffer size
  146.         mov     xbcnt,ax                ;initialize buffer room count
  147.         ENDIF
  148.         in      al,PICMSK               ;read 8259 interrupt mask
  149.         and     al,imbyte               ;enable the async interrupt
  150.         out     PICMSK,al               ;output the new mask
  151.         IF      XMITI
  152.         mov     al,00000011b            ;interrupt mask for 8250 (rx & tx)
  153.         ELSE
  154.         mov     al,00000001b            ;interrupt mask for 8250 (rx only)
  155.         ENDIF
  156.         mov     dx,ASIER                ;interrupt enable register address
  157.         add     dx,ioaddr               ;get adapter address
  158.         out     dx,al                   ;enable interrupts on 8250
  159.         mov     al,00001011b            ;rts,dtr,out2 bits in 8250 mcr
  160.         mov     dx,ASMCR                ;8250 modem control register address
  161.         add     dx,ioaddr               ;get adapter base address
  162.         out     dx,al                   ;set modem control register bits
  163.         mov     al,LCRBYTE              ;set line control register
  164.         mov     dx,ASLCR                ;lcr address
  165.         add     dx,ioaddr               ;get adapter address
  166.         out     dx,al                   ;set lcr
  167.         sti                             ;re-enable interrupts
  168.         pop     bp
  169.         ret
  170. _asninit endp
  171.  
  172. ;*****************************************************************************
  173. ;
  174. ;       asnbaud is called to set the 8250 baud latch
  175. ;
  176. ;       syntax - asynbaud(baudrate)
  177. ;
  178. ;*****************************************************************************
  179. _asnbaud proc   near
  180.         push    bp
  181.         mov     bp,sp
  182.         mov     ax,@AB[bp]              ;get argument to AX
  183.         mov     cx,ax                   ;baud rate (divisor) into cx
  184.         mov     ax,word ptr clock       ;low order of dividend into ax
  185.         mov     dx,word ptr clock+2     ;hi  order of dividend into dx
  186.         div     cx                      ;divide to get 8250 divisor word
  187.         mov     cx,ax                   ;get result into cx temporarily
  188.         mov     dx,ASLCR                ;8250 Line control register address
  189.         add     dx,ioaddr               ;add adapter base address
  190.         in      al,dx                   ;get current LCR
  191.         mov     bl,al                   ;...save in BL
  192.         or      al,10000000b            ;turn Divisor Latch Enable bit on
  193.         out     dx,al                   ;...in LCR
  194.         mov     dx,ASDLL                ;8250 Divisor Latch Low order address
  195.         add     dx,ioaddr               ;add adapter base address
  196.         mov     al,cl                   ;get low order byte of divisor word
  197.         out     dx,al                   ;output to the Divisor Latch register
  198.         mov     dx,ASDLH                ;8250 Divisor Latch Hi order address
  199.         add     dx,ioaddr               ;add adapter base address
  200.         mov     al,ch                   ;get hi order byte of divisor word
  201.         out     dx,al                   ;output to the Divisor Latch register
  202.         mov     dx,ASLCR                ;LCR address
  203.         add     dx,ioaddr               ;add adapter base address
  204.         mov     al,bl                   ;old LCR contents
  205.         out     dx,al                   ;restore old LCR contents
  206.         pop     bp
  207.         ret
  208. _asnbaud endp
  209.  
  210. ;*****************************************************************************
  211. ;
  212. ;       asnget is called to get a character from asynch receive buffer
  213. ;
  214. ;               it returns the character or
  215. ;               -1 if no character is available in the buffer
  216. ;
  217. ;*****************************************************************************
  218. _asnget proc    near
  219.         pushf                           ;save interrupt state
  220.         cli                             ;disable interrupts
  221.         mov     bx,rbhead               ;buffer empty pointer into bx
  222.         mov     ax,rbtail               ;buffer fill pointer into ax
  223.         cmp     ax,bx                   ;see if data in circular buffer
  224.         jz      asngx                   ;no, return -1 to caller
  225.         mov     al,[bx]                 ;get character from buffer into al
  226.         inc     bx                      ;bump buffer empty pointer
  227.         cmp     bx,offset dgroup:rbfend ;test for end of buffer
  228.         jnz     asng1                   ;no, continue
  229.         mov     bx,offset dgroup:rbfbeg ;yes, reset buffer empty pointer
  230. asng1:  mov     rbhead,bx               ;update buffer empty pointer
  231.         mov     ah,0                    ;make sure ax is a character
  232.         POPFF                           ;restore interrupt state
  233.         ret
  234.  
  235. asngx:  mov     ax,0ffffh               ;set ax to -1 to indicate no char
  236.         POPFF                           ;restore interrupt state
  237.         ret
  238. _asnget endp
  239.  
  240.         IF      XMITI
  241. ;*****************************************************************************
  242. ;
  243. ;       asnput is called to output a character to the asynch device
  244. ;
  245. ;       syntax - asnput(char)
  246. ;
  247. ;*****************************************************************************
  248. _asnput proc    near
  249.         push    bp
  250.         mov     bp,sp
  251.         pushf                           ;save interrupt state
  252. asnp00: cli                             ;temporarily disable interrupts
  253.         cmp     xbcnt,BSIZE             ;buffer empty?
  254.         jne     asnp0a                  ;no, continue
  255.         mov     dx,ASLSR                ;8250 line status register address
  256.         add     dx,ioaddr               ;add adapter base address
  257.         in      al,dx                   ;get line status byte
  258.         test    al,01000000b            ;test for Transmit empty
  259.         jz      asnp0a                  ;no, store byte in buffer
  260.         mov     ax,@AB[bp]              ;get argument in ax
  261.         mov     dx,ASTHR                ;address of 8250 xmit hold register
  262.         add     dx,ioaddr               ;add adapter base address
  263.         out     dx,al                   ;xmit the character
  264.         POPFF                           ;restore interrupt state
  265.         pop     bp
  266.         ret
  267. asnp0a: cmp     xbcnt,0                 ;room left in buffer?
  268.         jne     asnp01                  ;yes, continue
  269.         sti                             ;enable interrupts
  270.         nop                             ;waste a little time
  271.         jmp     asnp00                  ;and check again
  272. asnp01: mov     bx,xbtail               ;buffer fill pointer
  273.         mov     ax,@AB[bp]              ;get argument in ax
  274.         mov     [bx],al                 ;store character in buffer
  275.         inc     bx                      ;bump pointer
  276.         dec     xbcnt                   ;and decrement room in buffer
  277.         cmp     bx,offset dgroup:xbfend ;test for end of buffer
  278.         jb      aspn1                   ;no, continue
  279.         mov     bx,offset dgroup:xbfbeg ;offset of buffer start
  280. aspn1:  mov     xbtail,bx               ;update buffer fill pointer
  281.         POPFF                           ;restore interrupt state
  282.         pop     bp
  283.         ret
  284. _asnput endp
  285.         ELSE
  286. ;*****************************************************************************
  287. ;
  288. ;       asnput is called to output a character to the asynch device
  289. ;
  290. ;       syntax - asnput(char)
  291. ;
  292. ;*****************************************************************************
  293. _asnput proc    near
  294.         push    bp
  295.         mov     bp,sp
  296.         mov     dx,ASLSR                ;8250 line status register address
  297.         add     dx,ioaddr               ;add adapter base address
  298. asnp0:  in      al,dx                   ;get line status byte
  299.         test    al,00100000b            ;test for THRE
  300.         jz      asnp0                   ;no, loop
  301.         mov     ax,@AB[bp]              ;get argument in ax
  302.         mov     dx,ASTHR                ;address of 8250 xmit hold register
  303.         add     dx,ioaddr               ;add adapter base address
  304.         out     dx,al                   ;xmit the character
  305.         pop     bp
  306.         ret
  307. _asnput endp
  308.         ENDIF
  309.  
  310. ;*****************************************************************************
  311. ;
  312. ;       asnfls is called to flush the transmit data buffer
  313. ;               (i.e. wait until all characters have been transmitted)
  314. ;
  315. ;*****************************************************************************
  316. _asnfls proc    near
  317.         IF      XMITI
  318. asnf0:  cmp     xbcnt,BSIZE             ;test for xmit buffer empty
  319.         jnz     asnf0                   ;no, keep waiting
  320.         ENDIF
  321.         mov     dx,ASLSR                ;8250 line status register address
  322.         add     dx,ioaddr               ;add adapter base address
  323. asnf1:  in      al,dx                   ;get line status byte
  324.         test    al,01000000b            ;test for TSRE
  325.         jz      asnf1                   ;no, loop
  326.         ret
  327. _asnfls endp
  328.  
  329. ;*****************************************************************************
  330. ;
  331. ;       asnstat is called to obtain the asynch status bits
  332. ;
  333. ;       the modem status bits are returned in high order byte
  334. ;       the line  status bits (error bits only) are returned in low order byte
  335. ;
  336. ;*****************************************************************************
  337. _asnstat proc   near
  338.         mov     dx,ASMSR                ;8250 modem status register address
  339.         add     dx,ioaddr               ;add adapter base address
  340.         in      al,dx                   ;get modem status byte
  341.         mov     ah,al                   ;into ah
  342.         dec     dx                      ;address of 8250 line status register
  343.         in      al,dx                   ;get line status byte
  344.         and     al,00011110b            ;strip everything but error bits
  345.         ret
  346. _asnstat endp
  347.  
  348.  
  349. ;*****************************************************************************
  350. ;
  351. ;       asnclr is called to flush the receive data buffer
  352. ;
  353. ;*****************************************************************************
  354. _asnclr proc    near
  355.         cli                             ;disable interrupts
  356.         mov     ax,offset dgroup:rbfbeg ;offset of buffer beginning
  357.         mov     rbhead,ax               ;reset buffer empty pointer
  358.         mov     rbtail,ax               ;reset buffer fill  pointer
  359.         sti                             ;re-enable interrupts
  360.         ret
  361. _asnclr endp
  362.  
  363. ;*****************************************************************************
  364. ;
  365. ;       asnexit must be called to terminate the asynch support routines
  366. ;               it disables the asynch interrupts which MUST be done
  367. ;               before the calling program exits to DOS
  368. ;
  369. ;               Failure to call this routine prior to returning back to DOS
  370. ;               will leave the asynch interrupt vectors pointing into the
  371. ;               DOS user program area, with probable disasterous results
  372. ;               if a character comes in from the asynch line.
  373. ;
  374. ;*****************************************************************************
  375. _asnexit proc   near
  376.         cli
  377.         in      al,PICMSK               ;get 8259 interrupt mask
  378.         mov     bl,imbyte               ;get interrupt mask byte
  379.         not     bl                      ;invert it
  380.         or      al,bl                   ;turn off async interrupt
  381.         out     PICMSK,al               ;output updated mask to 8259
  382.         mov     al,0                    ;turn off all 8250 interrupts
  383.         mov     dx,ASIER                ;8250 interrupt mask register address
  384.         add     dx,ioaddr               ;add adapter base address
  385.         out     dx,al                   ;output new mask
  386.         mov     dx,ASMCR                ;8250 modem control register address
  387.         add     dx,ioaddr               ;add adapter base address
  388.         out     dx,al                   ;turn off dtr,rts,out2 bits
  389.         sti
  390.         ret
  391. _asnexit endp
  392.         page
  393. ;*****************************************************************************
  394. ;
  395. ;       asnint is the asynch interrupt handler. it is NOT user callable
  396. ;
  397. ;*****************************************************************************
  398.         assume  cs:_TEXT,ds:DGROUP
  399. asnint  proc    far
  400.         push    ds                      ;asynchronous interrupt handler
  401.         push    dx                      ;save all registers
  402.         push    bx
  403.         push    ax
  404.         mov     ax,DGROUP
  405.         mov     ds,ax
  406.         mov     dx,ASIIR                ;address of interrupt id register
  407.         add     dx,ioaddr               ;add adapter base address
  408.         in      al,dx                   ;get interrupt status
  409. asi0:   cmp     al,0000100b             ;test for receiver interrupt
  410.         je      asir                    ;yes, process receiver interrupt
  411.         IF      XMITI
  412.         cmp     al,0000010b             ;test for transmitter empty
  413.         je      asit                    ;yes, process xmitter empty
  414.         ENDIF
  415.         jmp     asix                    ;neither, ignore the interrupt
  416. ;*****************************************************************************
  417. ;
  418. ;       received data available interrupt
  419. ;
  420. ;*****************************************************************************
  421. asir:   mov     dx,ASRBR                ;address of receiver buffer register
  422.         add     dx,ioaddr               ;add adapter base address
  423.         in      al,dx                   ;get data byte from 8250 rbr
  424.         mov     bx,rbtail               ;buffer fill pointer
  425.         mov     [bx],al                 ;store character in buffer
  426.         inc     bx                      ;bump pointer
  427.         cmp     bx,offset dgroup:rbfend ;test for end of buffer
  428.         jb      asin1                   ;no, continue
  429.         mov     bx,offset dgroup:rbfbeg ;offset of buffer start
  430. asin1:  mov     rbtail,bx               ;update buffer fill pointer
  431.         jmp     asix                    ;exit from interrupt
  432.         IF      XMITI
  433. ;*****************************************************************************
  434. ;
  435. ;       transmit buffer empty interrupt
  436. ;
  437. ;*****************************************************************************
  438. asit:   mov     bx,xbcnt                ;get buffer room count
  439.         cmp     bx,BSIZE                ;buffer empty?
  440.         je      asix                    ;yes, exit
  441.         mov     bx,xbhead               ;get buffer head
  442.         mov     al,[bx]                 ;get character from buffer into al
  443.         inc     bx                      ;bump buffer empty pointer
  444.         cmp     bx,offset dgroup:xbfend ;test for end of buffer
  445.         jnz     asitg1                  ;no, continue
  446.         mov     bx,offset dgroup:xbfbeg ;yes, reset buffer empty pointer
  447. asitg1: mov     xbhead,bx               ;update buffer empty pointer
  448.         mov     dx,ASTHR                ;address of 8250 xmit hold register
  449.         add     dx,ioaddr               ;add adapter base address
  450.         out     dx,al                   ;xmit the character
  451.         inc     xbcnt                   ;increment room count
  452.         jmp     asix                    ;exit from interrupt routine
  453.         ENDIF
  454. ;*****************************************************************************
  455. ;
  456. ;       exit interrupt routine
  457. ;
  458. ;*****************************************************************************
  459. asix:   mov     dx,ASIIR                ;address of interrupt id register
  460.         add     dx,ioaddr               ;add adapter base address
  461.         in      al,dx                   ;get interrupt status
  462.         test    al,00000001b            ;test for another interrupt pending
  463.         jz      asi0                    ;yes, process another one
  464.         mov     al,00100000b            ;EOI for 8259
  465.         out     PICCMD,al               ;reset 8259
  466.         pop     ax                      ;restore saved registers
  467.         pop     bx
  468.         pop     dx
  469.         pop     ds
  470.         iret                            ;return from interrupt
  471. asnint  endp
  472. _TEXT   ENDS
  473.         end
  474.