📄 async.asm
字号:
; Async Module.
% MODEL MEMMOD
IDEAL
P8086
EOIX equ 020h ; 8259 end-of-interupt
EOIX2 equ 0a0h ; 8259 #2 end-of-interrupt
Ctrl8259_0 equ 020h ; 8259 port
Ctrl8259_1 equ 021h ; 8259 port (Masks)
Ctrl8259_2 equ 0a0h ; 8259 port #2
Ctrl8259_3 equ 0a1h ; 8259 port (Masks) #2
BufSize equ 512 ; Buffer Size
IIRx equ 002h ; Interrupt Ident Reg
IIR_FIFO_ENABLED equ 0c0h ; FIFO enabled (FCR0,1=1)-16550A only
FCR equ 002h ; FIFO control register (16550A only)
FIFO_ENABLE equ 001h ; enable TX & RX fifo
BufBytes equ 4 ; FIFO Trigger point
; DATASEG
FARDATA
ends
;
; I can't take the time to figure out how to handle all the addressing for the data in the
; far segments in the tchuge model so I'll just put all of the data in the code seg
; and make ds=cs. crh Sept 25, 1998
;
CODESEG
assume cs:ASYNC_TEXT,ds:ASYNC_TEXT
; Various things to be set upon AsyncInit()
VectorNum db ? ; Vector Number
EnableIRQ db ? ; Mask to enable 8259 IRQ
DisableIRQ db ? ; Mask to disable 8259 IRQ
VectorSeg dw ? ; Old Vector Segment
VectorOfs dw ? ; Old Vector Offset
IRQgen dw 0 ; 0 until tx int received
_TXints dd 0 ; Transmitter interrupts
_RXints dd 0 ; Receiver interrupts
_TXhw dw 0 ; Transmitter software hi water
_RXhw dw 0 ; Receiver software hi water
_TXoverrun dw 0 ; Transmitter software overrun
_RXoverrun dw 0 ; Receiver software overrun
_Is_16550a dw 0 ; 1 if UART is 16550a with FIFO
; Register Addresses for the 8250 UART
Port dw ? ; Port Base Address
LABEL RegStart word
THR dw ? ; Transmitter Holding Register
RDR dw ? ; Reciever Data Register
BRDL dw ? ; Baud Rate Divisor, Low byte
BRDH dw ? ; Baud Rate Divisor, High Byte
IER dw ? ; Interupt Enable Register
IIR dw ? ; Interupt Identification Register
LCR dw ? ; Line Control Register
MCR dw ? ; Modem Control Register
LSR dw ? ; Line Status Register
MSR dw ? ; Modem Status Register
; Buffer Data
RecBuffer db BufSize DUP (?) ; Recieve Buffer
RecHead dw ? ; Buffer Head Pointer
RecTail dw ? ; Buffer Tail Pointer
TransBuffer db BufSize DUP (?) ; Transmit Buffer
TransHead dw ? ; Buffer Head Pointer
TransTail dw ? ; Buffer Tail Pointer
Isat dw 0 ; 1 if irq > 7
; Register Offsets for the UART
RegOffsets dw 0, 0, 0, 1, 1, 2, 3, 4, 5, 6
PUBLIC _AsyncInit, _AsyncClear, _AsyncStop
PUBLIC _AsyncIn, _AsyncOut, _AsyncSet, _TXoverrun
PUBLIC _AsyncHand, _AsyncStat, _AsyncInStat, _RXoverrun
PUBLIC _AsyncOutStat, _kbraw, _TXints, _RXints, _RXhw, _TXhw
PUBLIC _Is_16550a
PROC _kbraw
mov ah,06h ; Direct Console I/O
mov dl,0ffh ; Read keyboard
int 21h ; DOS
jz @@1 ; zero flag set implies no character ready
mov ah,0 ;
ret
@@1: mov ax,-1 ; no char, return -1
ret
endp _kbraw
;-----------------------------------------------------------------------------
; Re-arm 8259 interrupt controller(s)
; Should be called just after taking an interrupt, instead of just
; before returning. This is because the 8259 inputs are edge triggered, and
; new interrupts arriving during an interrupt service routine might be missed.
PROC eoi
push ds
push cs
pop ds
cmp [Isat],1
jnz @@1 ; Only one 8259?
mov al,0bh ; read in-service register from
out Ctrl8259_2,al ; secondary 8259
nop ; settling delay
nop
nop
in al,Ctrl8259_2 ; get it
or al,al ; Any bits set?
jz @@1 ; nope, not a secondary interrupt
mov al,EOIX ; Get EOI instruction
out Ctrl8259_2,al ; Secondary 8259 (PC/AT only)
@@1: mov al,EOIX ; 8259 end-of-interrupt command
out Ctrl8259_0,al ; Primary 8259
pop ds
ret
endp eoi
;-----------------------------------------------------------------------------
; AsyncClear Empty the receive buffer
;-----------------------------------------------------------------------------
; void AsyncClear( void);
;
;
;-----------------------------------------------------------------------------
PROC _AsyncClear
cli
push ds
push cs
pop ds
push ax
mov ax, offset RecBuffer
mov [RecHead], ax
mov [RecTail], ax
mov ax, offset TransBuffer
mov [TransHead], ax
mov [TransTail], ax
pop ax
pop ds
sti
ret
ENDP _AsyncClear
;-----------------------------------------------------------------------------
; AsyncInit Initalize Serial Port and install ISR
;-----------------------------------------------------------------------------
; void AsyncInit( int IOAddress, IRQnum)
;
; Where IOAddress is normally
;
; COM1 = 03f8
; COM2 = 02f8
; COM3 = 03e8
; COM2 = 02e8
;
;-----------------------------------------------------------------------------
PROC _AsyncInit
ARG IOAddress:word,IRQnum:word
push bp
mov bp, sp
push ds
push cs
pop ds
;----- COM Setup
mov ax,[IOAddress]
mov [Port], ax
mov ax,[IRQnum]
cmp al,8
jge @@1 ; must be an AT
add al,8
mov [VectorNum],al
mov [Isat],0
jmp @@3
;
; IRQ >7 indicates an AT
;
@@1:
mov [Isat],1
sub al,8
add al,070h
@@3:
mov cx,[IRQnum]
mov ax,1
sal ax,cl
mov [DisableIRQ],al
not ax
mov [EnableIRQ], al
;---- Check for 16550a with FIFO
;
; set enable bit and check reg. If bits 6&7 (0xC0) are not set then
; the UART is not a 16550a or is defective. This routine always
; returns 'not an 16550a' under WinNT.
;
mov ax,[IOAddress]
add ax,FCR
mov dx,ax
push dx ; save address for later use
mov ax,[IOAddress] ; setup base address
add ax,IIRx ; add FIFO control reg offset
mov dx,ax
mov al,FIFO_ENABLE ; setup enable check
out dx,al
in al,dx
and al,IIR_FIFO_ENABLED
cmp al,IIR_FIFO_ENABLED ; do we have a valid FIFO?
jne @@x ; No, jump
mov [_Is_16550a],1 ; Yes, we do
pop dx ; restore FIFO cntl reg address
mov al,BufBytes
jmp @@y
@@x:
mov [_Is_16550a],0 ; No FIFO or a defective FIFO
pop dx ; restore FIFO cntl reg address
mov al,0
@@y:
out dx,al
;---- Compute Register locations
mov cx, 10
mov bx, offset RegOffsets
push di
mov di, offset RegStart
@@4:
mov ax, [bx]
add ax, [Port]
mov [di], ax
add bx, 2
add di, 2
loop @@4
pop di
;----- Initalize Buffer
call _AsyncClear
;--- Save and reassign interrupt vector
push ds ; Save Old Vector
mov al,[VectorNum]
mov ah,35h
int 21h
mov [VectorSeg], es
mov [VectorOfs], bx
mov al, [VectorNum]
push cs ; Set New Vector
pop ds
mov dx, offset AsyncISR
mov ah, 25h
int 21h
pop ds
;----- Enable 8259 interrupt (IRQ) line for this async adapter
cmp [Isat],1
je @@33
in al, Ctrl8259_1
and al, [EnableIRQ]
out Ctrl8259_1, al
jmp @@34
@@33:
in al, Ctrl8259_3
and al, [EnableIRQ]
out Ctrl8259_3, al
@@34:
;----- Enable 8250 Interrupt-on-data-ready
mov dx, [LCR] ; Read Line control register and clear
in al, dx ; bit 7, the Divisor Latch Address
and al, 07Fh
out dx, al
mov dx, [IER]
mov al, 0 ;we're gonna test the UART first
out dx, al
in al, dx ;if this isn't 0, there's no UART
cmp al, 0
jnz @@222
mov al, 3
out dx, al
;----- Clear 8250 Status and data registers
@@10:
mov dx, [RDR] ; Clear RDR by reading port
in al, dx
mov dx, [LSR] ; Clear LSR
in al, dx
mov dx, [MSR] ; Clear MSR
in al, dx
mov dx, [IIR] ; Clear IIR
in al, dx
test al, 1
jz @@10
;----- Set Bit 3 of MCR -- Enable interupts
mov dx, [MCR]
in al, dx
or al, 08h
out dx, al
;----- Clear Buffer Just in case
call _AsyncClear
;----- Return
xor ax, ax
@@222:
pop ds
pop bp
ret
ENDP _AsyncInit
;-----------------------------------------------------------------------------
; AsyncStop Uninstall ISR
;-----------------------------------------------------------------------------
; void AsyncStop( void)
;-----------------------------------------------------------------------------
PROC _AsyncStop
push bp
mov bp, sp
push ds
push cs
pop ds
;----- Mask (disable) 8259 IRQ Interrupt
cmp [Isat],1
je @@1
in al, Ctrl8259_1
or al, [DisableIRQ]
out Ctrl8259_1, al
jmp @@2
@@1:
in al, Ctrl8259_3
or al, [DisableIRQ]
out Ctrl8259_3, al
@@2:
;----- Disable 8250 interrupt
mov dx, [LCR]
in al, dx
and al, 07Fh
out dx, al
mov dx, [IER]
xor al, al
out dx, al
;----- Set bit 3 in MCR to 0
mov dx, [MCR]
in al, dx
and al, 0F7h
out dx, al
;----- Interrupts are disabled. Restore saved interrupt vector.
push ds
mov al, [VectorNum]
mov ah, 25h
mov dx, [VectorOfs]
mov ds, [VectorSeg]
int 21h
pop ds
;----- Clear UART buffer
mov ax,[_Is_16550a]
cmp ax,1
jne @@z
mov ax,[IOAddress]
add ax,FCR
mov dx,ax
mov al,BufBytes
jmp @@x
@@z:
mov al,0
@@x:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -