📄 casyncms.asm
字号:
;CASYNCMS.ASM - for Microsoft C
;Based on CASYNC.ASM by Curt Klinsing
;A set of C callable functions to support
;interrupt driven character I/O on the IBM PC. Input
;is buffered, output is polled.
;910609 rr minor cleanup
;930811 rr conversion for microsoft C
;931213 rr fix various bugs (I hope)
;940529 rr move to 9600
.286p
.seq
; ----- Equates -----------------------------------------------------
BASE equ 03F8H ;BASE FOR SERIAL BOARD (COM1)
IER equ BASE+1 ;Interrup Enable Register
LCR equ BASE+3 ;Line control register
MCR equ BASE+4 ;modem control register
LSR equ BASE+5 ;line status register
MSR equ BASE+6 ;modem status register
; Bits in IER
ERBFI equ 01H ;enable 'data-ready' interrupt bit
; Bits in LSR
THRE equ 20H ;8250 tbe flag
IntCtlr equ 21H ;OCW 1 FOR 8259 CONTROLLER
EnblIRQ4 equ 0EFH ;Enable COMMUNICATIONS (IRQ4)
MaskIRQ4 equ 10H ;BIT TO DISABLE COMM INTERRUPT (IRQ4)
RS8259 equ 20H ;OCW 3 FOR 8259
RSTINT equ 64H ;SPECIFIC EOI FOR COMM INTERRUPT
DosCall equ 21h ;INTERRUPT NUMBER FOR DOS CALL
BUFSIZ equ 512 ;Max NUMBER OF CHARS (was 512)
SetIntVect equ 25H ;SET INTERRUPT VECTOR FUNCTION NUMBER
;divisor is 48 for 2400 baud, 12 for 9600 baud,
; 96 for 1200 baud
BAUDRATEDIVISOR equ 12
; ----- Data segment ------------------------------------------------
_DATA SEGMENT PARA PUBLIC 'DATA'
circ_buf db BUFSIZ DUP(?) ;ALLOW MaxIMUM BUFFERED CHARACTERS
buf_top equ $ - 1 ;KEEP TRACK OF THE TOP OF THE BUFFER
circ_in dw offset circ_buf ;POINTER TO LAST CHAR. PLACED
;IN BUFFER
circ_cur dw offset circ_buf ;POINTER TO NEXT CHAR. TO BE
;RETRIEVED FROM BUFFER
circ_cnt dw 0 ;COUNT OF CHARACTERS USED IN BUFFER
_DATA ENDS
; ----- Code segment ------------------------------------------------
_TEXT SEGMENT PARA PUBLIC 'CODE'
ASSUME CS: _TEXT, DS: _DATA
;int far inp_status( void )
;Returns the number of characters available in the input buffer.
PUBLIC _inp_status
_inp_status PROC FAR
push ds
mov ax,_DATA
mov ds,ax
mov ax,word ptr circ_cnt
pop ds
ret
_inp_status ENDP
;void far inp_flush( void )
;Flush the input buffer.
PUBLIC _inp_flush
_inp_flush PROC FAR
push ds
mov ax,_DATA
mov ds,ax
mov bx,offset circ_buf
mov word ptr circ_in,bx
mov word ptr circ_cur,bx
xor ax,ax
mov word ptr circ_cnt,ax
pop ds
ret
_inp_flush ENDP
;--------- Init -----------------------------------
;Program initialization:
;-- Set up vector for RS232 interrupt (0CH)
;-- Enbl IRQ4
;-- Enbl RS232 interrupt on data ready
;---------------------------------------------------
;void far init_comm( void )
PUBLIC _init_comm
_init_comm PROC FAR
push bp ;in case damaged by dos call
cli ;disable interrupts
;---- Set up INT x'0C' for IRQ4 (COM1)
push ds ;save DS
mov ax,cs
mov ds,ax ;put CS into DS
mov dx,offset IntHdlr ;relative address of interrupt handler
mov al,0CH ;interrupt number for comm.
mov ah,SetIntVect ;function number for setting int vector
int DosCall ;set interrupt in 8086 table
pop ds ;restore DS
;---- Enbl IRQ4 on 8259 interrupt controller
cli ;disable interrupts - again
in al,IntCtlr ;get current masks
and al,EnblIRQ4 ;Reset IRQ4 mask
out IntCtlr,al ;And restore to IMR
;--- Set up 8250 port
;divisor is 48 for 2400 baud, 12 for 9600 baud,
; 96 for 1200 baud
mov dx,LCR
mov al,083h ;DLAB = 1
out dx,al ;to access baud rate divisors
mov dx,BASE
mov ax,BAUDRATEDIVISOR ;set baud rate divisor lsb
out dx,al
inc dx ;set baud rate divisor msb
mov al,ah
out dx,al
mov dx,LCR
mov al,03h ;8 bits, no parity, 1 stop
out dx,al
;--- Enbl 8250 data ready interrupt
mov dx,IER ;Interrupt Enbl Register
mov al,ERBFI ;Enable 'data-ready' interrupt
out dx,al
;--- Enbl OUT2 on 8250
mov dx,MCR ;modem control register
mov al,0BH ;Enable OUT2, DCD and DTR
out dx,al
pop bp
sti ;enable interrupts
ret
_init_comm ENDP
;void far uninit_comm( void )
;Removes the interrupt structure
;installed by init_comm(). Must be
;done before passing control to the DOS, else chars received
;will be stored into the next program loaded!
PUBLIC _uninit_comm
_uninit_comm PROC FAR
push bp
;--- Disable IRQ4 on 8259
cli
in al,IntCtlr ;GET OCW1 FROM 8259
or al,MaskIRQ4 ;DISABLE COMMUNICATIONS INTERRUPT
out IntCtlr,al
;--- Disable 8250 data ready interrupt
mov dx,LCR ;DX ==> LCR
in al,dx ;Reset DLAB for IER access
and al,7FH
out dx,al
mov dx,IER ;Interrupt Enbl Register
mov al,0 ;Disable all 8250 interrupts
out dx,al
;--- Disable OUT2 on 8250
mov dx,MCR ;modem control register
mov al,0 ;Disable OUT2
out dx,al
sti ;reenable interrupts
pop bp
ret
_uninit_comm ENDP
;int far inp_char( void )
;Return a character from the input
;buffer. Assumes you have called
;inp_status() to see if theres any characters to get.
PUBLIC _inp_char
_inp_char PROC FAR
push ds
mov ax,_DATA
mov ds,ax ;put _DATA in DS
mov bx,word ptr circ_cur
xor ax,ax
mov al,[bx] ;get next char from circ_buf
dec word ptr circ_cnt ;decrement circ_buf COUNT
cmp bx,offset buf_top
jz reset_cur ;JUMP IF SO
inc bx ;ELSE, BUMP PTR
jmp upd_cur
reset_cur:
mov bx,offset circ_buf ;RESET circ_cur TO BOTTOM OF BUF.
upd_cur:
mov word ptr circ_cur,bx ;SAVE NEW PTR
pop ds
ret
_inp_char ENDP
;void far outp_char( int c )
;Output the character to the
;char c;serial port. This is not buffered
;or interrupt driven.
PUBLIC _outp_char
_outp_char PROC FAR
push bp
mov bp,sp
comout:
mov dx,LSR
in al,dx ;get 8250 status
and al,THRE ;check for transmitter ready
jz comout ;jump if not to wait
mov al,[bp+6] ;get char to al
mov dx,BASE ;data port
out dx,al ;output char to 8250
pop bp
ret
_outp_char ENDP
; ----- RECEIVE INTERRUPT HANDLER -----------------------------------
PUBLIC IntHdlr
IntHdlr PROC FAR
cli ;disable interrupts
push dx
push bx
push ax
push ds
mov ax,_DATA
mov ds,ax
mov bx,word ptr circ_in ;GET circ_buf IN PTR
mov dx,BASE ;GET DATA PORT NUMBER
in al,dx ;GET RECEIVED CHARACTER
cmp word ptr circ_cnt,BUFSIZ ;SEE IF circ_buf ALREADY FULL
jz clnup ;jump if so, discard char
savch:
mov [bx],al ;SAVE NEW CHARACTER IN circ_buf
inc word ptr circ_cnt ;BUMP circ_buf COUNT
cmp bx,offset buf_top ;ARE WE AT THE TOP OF THE circ_buf?
jz reset_in ;JUMP IF SO
inc bx ;ELSE, BUMP PTR
jmp into_buf
reset_in:
mov bx,offset circ_buf ;RESET circ_in TO BOTTOM OF BUF.
into_buf:
mov word ptr circ_in,bx ;SAVE NEW PTR
clnup:
mov al,RSTINT
out RS8259,al ;ISSUE SPECIFIC EOI FOR 8259
pop ds ;GET BACK ENTERING DS
pop ax
pop bx
pop dx
sti
iret
IntHdlr ENDP
_TEXT ENDS
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -