home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
assemblr
/
library
/
async
/
casyn.asm
next >
Wrap
Assembly Source File
|
1988-03-08
|
23KB
|
474 lines
page ,132
;*****************************************************************************
;
; Asynchronous Support Routines
; Beispielprogramm zum Linken mit C Version 1.0
;*****************************************************************************
_TEXT SEGMENT BYTE PUBLIC 'CODE' ; Default code segment
_TEXT ENDS
_DATA SEGMENT WORD PUBLIC 'DATA' ; Default data segment
_DATA ENDS
CONST SEGMENT WORD PUBLIC 'CONST' ; Read only constants
CONST ENDS
_BSS SEGMENT WORD PUBLIC 'BSS' ; Uninitialized static data
_BSS ENDS
STACK SEGMENT PARA STACK 'STACK' ; Stack segment
STACK ENDS
DGROUP GROUP _DATA,CONST,_BSS,STACK
_TEXT SEGMENT BYTE PUBLIC 'CODE'
ASSUME CS:_TEXT,DS:DGROUP
@AB EQU 4
XMITI EQU 00000h ;set to 0FFFFh for xmit via interrupt
public _asnget ;get char from asynch buffer
public _asnput ;put char to asynch line
public _asnstat ;get status of asynch port
public _asninit ;initialize asynch port & routines
public _asnclr ;clear asynch receive buffer
public _asnfls ;flush asynch transmit buffer
public _asnexit ;remove asynch interrupt routine
public _asnbaud ;set baud rate for asynch port
;*****************************************************************************
;
; POPF Macro for PC/AT 2/86 hardware bugÜ
;
;*****************************************************************************
POPFF MACRO ;this kludge is due to INTEL's idiocyÜ
local f1,b1
jmp short f1 ;jump over iret
b1: iret ;simulate the POPF in a way that works
f1: push cs ;save cs so that the IRET works correctly
call b1 ;save ip and execute the IRET, and continue
ENDM
page
;*****************************************************************************
;
; Miscellaneous Definitions
;
;*****************************************************************************
BSIZE equ 4096 ;circular receive buffer size
LCRBYTE equ 00010011b ;LCR default, 8 bits+no parity
;*****************************************************************************
;
; Device address definitions
;
;*****************************************************************************
PICCMD equ 20h ;8259 Priority Interrupt Controller
PICMSK equ 21h ;8259 Priority Interrupt Controller
ASRBR equ 008h ;8250 Receiver Buffer Register
ASTHR equ 008h ;8250 Transmitter Holding Register
ASDLL equ 008h ;8250 Divisor Latch Low
ASDLH equ 009h ;8250 Divisor Latch High
ASIER equ 009h ;8250 Interrupt Enable Register
ASIIR equ 00Ah ;8250 Interrupt Identification Register
ASLCR equ 00Bh ;8250 Line Control Register
ASMCR equ 00Ch ;8250 Modem Control Register
ASLSR equ 00Dh ;8250 Line Status Register
ASMSR equ 00Eh ;8250 Modem Status Register
;*****************************************************************************
;
; data
;
;*****************************************************************************
_DATA segment
clock dd 115200 ;dividend value for asnbaud
rbhead dw offset dgroup:rbfbeg ;recv buffer empty pointer
rbtail dw offset dgroup:rbfbeg ;recv buffer fill pointer
rbfbeg db BSIZE dup (?) ;recv buffer for receive data
rbfend equ this byte ;recv buffer end address
IF XMITI
xbhead dw offset dgroup:xbfbeg ;xmit buffer empty pointer
xbtail dw offset dgroup:xbfbeg ;xmit buffer fill pointer
xbcnt dw BSIZE ;count of room left in buffer
xbfbeg db BSIZE dup (?) ;xmit buffer for receive data
xbfend equ this byte ;xmit buffer end address
ENDIF
iolist dw 03f0h,02f0h ;COM1, COM2 I/O base addresses
ioaddr dw ? ;selected I/O adapter base address
ivlist dw 0030h,002Ch ;COM1, COM2 interrupt vector addr list
ivaddr dw ? ;selected interrupt vector
imlist db 11101111b,11110111b ;COM1, COM2 interrupt mask list
imbyte db ? ;selected interrupt mask byte
_DATA ends
page
;*****************************************************************************
;
; asninit is called to initialize the async support routines
;
; it MUST be called before any of the other asynch routines
; argument should be 0 for COM1 or 1 for COM2
;
; syntax - asninit(comport)
;
;*****************************************************************************
_asninit proc near
cli ;disable interrupts
push bp
mov bp,sp
mov ax,@AB[bp] ;get argument
mov bx,ax ;get adapter selection value into bx
cmp bx,1 ;test for invalid value
jna asi2 ;ok, continue
mov bx,0 ;invalid, assume 0
asi2: mov al,imlist[bx] ;get selected interrupt mask byte
mov imbyte,al ;save it in imbyte
add bx,bx ;convert to index into iolist
mov ax,iolist[bx] ;get i/o adapter base address
mov ioaddr,ax ;store into ioaddr
mov ax,ivlist[bx] ;get interrupt vector address
mov ivaddr,ax ;store into ivaddr
mov cx,cs ;get current cs into cx
mov dx,offset asnint ;get offset of interrupt routine
mov bx,ivaddr ;get interrupt vector address
mov ax,0
push ds
mov ds,ax ;set ds to 0
mov [bx+2],cx ;set interrupt vector in low mem
mov [bx],dx
pop ds
mov ax,offset dgroup:rbfbeg ;get offset of buffer
mov rbhead,ax ;initialize buffer empty pointer
mov rbtail,ax ;initialize buffer fill pointer
IF XMITI
mov ax,offset dgroup:xbfbeg ;get offset of buffer
mov xbhead,ax ;initialize buffer empty pointer
mov xbtail,ax ;initialize buffer fill pointer
mov ax,BSIZE ;get buffer size
mov xbcnt,ax ;initialize buffer room count
ENDIF
in al,PICMSK ;read 8259 interrupt mask
and al,imbyte ;enable the async interrupt
out PICMSK,al ;output the new mask
IF XMITI
mov al,00000011b ;interrupt mask for 8250 (rx & tx)
ELSE
mov al,00000001b ;interrupt mask for 8250 (rx only)
ENDIF
mov dx,ASIER ;interrupt enable register address
add dx,ioaddr ;get adapter address
out dx,al ;enable interrupts on 8250
mov al,00001011b ;rts,dtr,out2 bits in 8250 mcr
mov dx,ASMCR ;8250 modem control register address
add dx,ioaddr ;get adapter base address
out dx,al ;set modem control register bits
mov al,LCRBYTE ;set line control register
mov dx,ASLCR ;lcr address
add dx,ioaddr ;get adapter address
out dx,al ;set lcr
sti ;re-enable interrupts
pop bp
ret
_asninit endp
;*****************************************************************************
;
; asnbaud is called to set the 8250 baud latch
;
; syntax - asynbaud(baudrate)
;
;*****************************************************************************
_asnbaud proc near
push bp
mov bp,sp
mov ax,@AB[bp] ;get argument to AX
mov cx,ax ;baud rate (divisor) into cx
mov ax,word ptr clock ;low order of dividend into ax
mov dx,word ptr clock+2 ;hi order of dividend into dx
div cx ;divide to get 8250 divisor word
mov cx,ax ;get result into cx temporarily
mov dx,ASLCR ;8250 Line control register address
add dx,ioaddr ;add adapter base address
in al,dx ;get current LCR
mov bl,al ;...save in BL
or al,10000000b ;turn Divisor Latch Enable bit on
out dx,al ;...in LCR
mov dx,ASDLL ;8250 Divisor Latch Low order address
add dx,ioaddr ;add adapter base address
mov al,cl ;get low order byte of divisor word
out dx,al ;output to the Divisor Latch register
mov dx,ASDLH ;8250 Divisor Latch Hi order address
add dx,ioaddr ;add adapter base address
mov al,ch ;get hi order byte of divisor word
out dx,al ;output to the Divisor Latch register
mov dx,ASLCR ;LCR address
add dx,ioaddr ;add adapter base address
mov al,bl ;old LCR contents
out dx,al ;restore old LCR contents
pop bp
ret
_asnbaud endp
;*****************************************************************************
;
; asnget is called to get a character from asynch receive buffer
;
; it returns the character or
; -1 if no character is available in the buffer
;
;*****************************************************************************
_asnget proc near
pushf ;save interrupt state
cli ;disable interrupts
mov bx,rbhead ;buffer empty pointer into bx
mov ax,rbtail ;buffer fill pointer into ax
cmp ax,bx ;see if data in circular buffer
jz asngx ;no, return -1 to caller
mov al,[bx] ;get character from buffer into al
inc bx ;bump buffer empty pointer
cmp bx,offset dgroup:rbfend ;test for end of buffer
jnz asng1 ;no, continue
mov bx,offset dgroup:rbfbeg ;yes, reset buffer empty pointer
asng1: mov rbhead,bx ;update buffer empty pointer
mov ah,0 ;make sure ax is a character
POPFF ;restore interrupt state
ret
asngx: mov ax,0ffffh ;set ax to -1 to indicate no char
POPFF ;restore interrupt state
ret
_asnget endp
IF XMITI
;*****************************************************************************
;
; asnput is called to output a character to the asynch device
;
; syntax - asnput(char)
;
;*****************************************************************************
_asnput proc near
push bp
mov bp,sp
pushf ;save interrupt state
asnp00: cli ;temporarily disable interrupts
cmp xbcnt,BSIZE ;buffer empty?
jne asnp0a ;no, continue
mov dx,ASLSR ;8250 line status register address
add dx,ioaddr ;add adapter base address
in al,dx ;get line status byte
test al,01000000b ;test for Transmit empty
jz asnp0a ;no, store byte in buffer
mov ax,@AB[bp] ;get argument in ax
mov dx,ASTHR ;address of 8250 xmit hold register
add dx,ioaddr ;add adapter base address
out dx,al ;xmit the character
POPFF ;restore interrupt state
pop bp
ret
asnp0a: cmp xbcnt,0 ;room left in buffer?
jne asnp01 ;yes, continue
sti ;enable interrupts
nop ;waste a little time
jmp asnp00 ;and check again
asnp01: mov bx,xbtail ;buffer fill pointer
mov ax,@AB[bp] ;get argument in ax
mov [bx],al ;store character in buffer
inc bx ;bump pointer
dec xbcnt ;and decrement room in buffer
cmp bx,offset dgroup:xbfend ;test for end of buffer
jb aspn1 ;no, continue
mov bx,offset dgroup:xbfbeg ;offset of buffer start
aspn1: mov xbtail,bx ;update buffer fill pointer
POPFF ;restore interrupt state
pop bp
ret
_asnput endp
ELSE
;*****************************************************************************
;
; asnput is called to output a character to the asynch device
;
; syntax - asnput(char)
;
;*****************************************************************************
_asnput proc near
push bp
mov bp,sp
mov dx,ASLSR ;8250 line status register address
add dx,ioaddr ;add adapter base address
asnp0: in al,dx ;get line status byte
test al,00100000b ;test for THRE
jz asnp0 ;no, loop
mov ax,@AB[bp] ;get argument in ax
mov dx,ASTHR ;address of 8250 xmit hold register
add dx,ioaddr ;add adapter base address
out dx,al ;xmit the character
pop bp
ret
_asnput endp
ENDIF
;*****************************************************************************
;
; asnfls is called to flush the transmit data buffer
; (i.e. wait until all characters have been transmitted)
;
;*****************************************************************************
_asnfls proc near
IF XMITI
asnf0: cmp xbcnt,BSIZE ;test for xmit buffer empty
jnz asnf0 ;no, keep waiting
ENDIF
mov dx,ASLSR ;8250 line status register address
add dx,ioaddr ;add adapter base address
asnf1: in al,dx ;get line status byte
test al,01000000b ;test for TSRE
jz asnf1 ;no, loop
ret
_asnfls endp
;*****************************************************************************
;
; asnstat is called to obtain the asynch status bits
;
; the modem status bits are returned in high order byte
; the line status bits (error bits only) are returned in low order byte
;
;*****************************************************************************
_asnstat proc near
mov dx,ASMSR ;8250 modem status register address
add dx,ioaddr ;add adapter base address
in al,dx ;get modem status byte
mov ah,al ;into ah
dec dx ;address of 8250 line status register
in al,dx ;get line status byte
and al,00011110b ;strip everything but error bits
ret
_asnstat endp
;*****************************************************************************
;
; asnclr is called to flush the receive data buffer
;
;*****************************************************************************
_asnclr proc near
cli ;disable interrupts
mov ax,offset dgroup:rbfbeg ;offset of buffer beginning
mov rbhead,ax ;reset buffer empty pointer
mov rbtail,ax ;reset buffer fill pointer
sti ;re-enable interrupts
ret
_asnclr endp
;*****************************************************************************
;
; asnexit must be called to terminate the asynch support routines
; it disables the asynch interrupts which MUST be done
; before the calling program exits to DOS
;
; Failure to call this routine prior to returning back to DOS
; will leave the asynch interrupt vectors pointing into the
; DOS user program area, with probable disasterous results
; if a character comes in from the asynch line.
;
;*****************************************************************************
_asnexit proc near
cli
in al,PICMSK ;get 8259 interrupt mask
mov bl,imbyte ;get interrupt mask byte
not bl ;invert it
or al,bl ;turn off async interrupt
out PICMSK,al ;output updated mask to 8259
mov al,0 ;turn off all 8250 interrupts
mov dx,ASIER ;8250 interrupt mask register address
add dx,ioaddr ;add adapter base address
out dx,al ;output new mask
mov dx,ASMCR ;8250 modem control register address
add dx,ioaddr ;add adapter base address
out dx,al ;turn off dtr,rts,out2 bits
sti
ret
_asnexit endp
page
;*****************************************************************************
;
; asnint is the asynch interrupt handler. it is NOT user callable
;
;*****************************************************************************
assume cs:_TEXT,ds:DGROUP
asnint proc far
push ds ;asynchronous interrupt handler
push dx ;save all registers
push bx
push ax
mov ax,DGROUP
mov ds,ax
mov dx,ASIIR ;address of interrupt id register
add dx,ioaddr ;add adapter base address
in al,dx ;get interrupt status
asi0: cmp al,0000100b ;test for receiver interrupt
je asir ;yes, process receiver interrupt
IF XMITI
cmp al,0000010b ;test for transmitter empty
je asit ;yes, process xmitter empty
ENDIF
jmp asix ;neither, ignore the interrupt
;*****************************************************************************
;
; received data available interrupt
;
;*****************************************************************************
asir: mov dx,ASRBR ;address of receiver buffer register
add dx,ioaddr ;add adapter base address
in al,dx ;get data byte from 8250 rbr
mov bx,rbtail ;buffer fill pointer
mov [bx],al ;store character in buffer
inc bx ;bump pointer
cmp bx,offset dgroup:rbfend ;test for end of buffer
jb asin1 ;no, continue
mov bx,offset dgroup:rbfbeg ;offset of buffer start
asin1: mov rbtail,bx ;update buffer fill pointer
jmp asix ;exit from interrupt
IF XMITI
;*****************************************************************************
;
; transmit buffer empty interrupt
;
;*****************************************************************************
asit: mov bx,xbcnt ;get buffer room count
cmp bx,BSIZE ;buffer empty?
je asix ;yes, exit
mov bx,xbhead ;get buffer head
mov al,[bx] ;get character from buffer into al
inc bx ;bump buffer empty pointer
cmp bx,offset dgroup:xbfend ;test for end of buffer
jnz asitg1 ;no, continue
mov bx,offset dgroup:xbfbeg ;yes, reset buffer empty pointer
asitg1: mov xbhead,bx ;update buffer empty pointer
mov dx,ASTHR ;address of 8250 xmit hold register
add dx,ioaddr ;add adapter base address
out dx,al ;xmit the character
inc xbcnt ;increment room count
jmp asix ;exit from interrupt routine
ENDIF
;*****************************************************************************
;
; exit interrupt routine
;
;*****************************************************************************
asix: mov dx,ASIIR ;address of interrupt id register
add dx,ioaddr ;add adapter base address
in al,dx ;get interrupt status
test al,00000001b ;test for another interrupt pending
jz asi0 ;yes, process another one
mov al,00100000b ;EOI for 8259
out PICCMD,al ;reset 8259
pop ax ;restore saved registers
pop bx
pop dx
pop ds
iret ;return from interrupt
asnint endp
_TEXT ENDS
end