📄 comm.asm
字号:
*
* Low level ASYNC serial I/O driver for
* use with DDS MICRO-C compiler on IBM/PC.
*
* Copyright 1990-2000 Dave Dunfield
* All rights reserved.
*
* Misc constants.
?BUFMSK EQU $00FF Buffer size mask
?WINDOW EQU 256-30 Flow control assertion window
?RXRDY EQU %00000001 Uart Receiver ready flag
?TXRDY EQU %00100000 Uart Transmitter ready flag
?8259 EQU $0020 8259 interrupt controller
* Bits in driver control flags
?RFLOW EQU %10000000 Received flow control
?TFLOW EQU %01000000 Transmit flow control
?TXOFF EQU %00100000 Transmit XOFF pending
?TXON EQU %00010000 Transmit XON pending
?XPAREN EQU %00001000 Transparency enabled
*
$SE:1
*
* Initialized variables & tables
*
Cflags DB 0 Control flags
?comvec DW 0 Comm interrupt vector
*
$DD:?rdptr 2 Buffer read pointer
$DD:?wrptr 2 Buffer write pointer
$DD:?comadr 2 Com port address
$DD:?oldoff 2 Saved old interrupt offset
$DD:?oldseg 2 Saved old interrupt segment
$DD:?buffer 256 Receive buffer
*
$SE:0
*
* Open the com port: Copen(int port, int speed, char mode, char modem)
*
Copen PUSH BP Save callers stack
MOV BP,SP Address parameters
CALL Cclose Insure its closed
MOV AX,10[BP] Get com port
MOV DX,#$03FD Comm 1 address
MOV BX,#$0030 Comm 1 interrupt vector
MOV CL,#$0EF Comm 1 interrupt mask
DEC AX Is it com1?
JZ ?2 Yes, it is
MOV DX,#$02FD Comm 2 address
MOV BX,#$002C Comm 2 interrupt vector
MOV CL,#$0F7 Comm 2 interrupt mask
DEC AX Is it com2?
JZ ?2 Yes it is
* Report failure to open port
?1 STI Insure interrupts enabled
MOV AX,#-1 Indicate failure
POP BP Restore caller
RET
* Proceed with opening the comm port
?2 MOV ?comadr,DX Save address
CLI Inhibit interrupts
* Setup the uart
DEC DX Backup ...
DEC DX to line control register (FB)
IN AL,DX Read current value
OR AL,#$80 Enable baud rate register
OUT DX,AL Write it
MOV AX,8[BP] Get baud rate
SUB DX,#3 Point to baud rate LSB (F8)
OUT DX,AL Write it
INC DX Advance to MSB (F9)
MOV AL,AH Get MSB
OUT DX,AL Write it
DEC DX Backup to LSB (F8)
IN AL,DX Re-read LSB
MOV AH,AL Copy for later
INC DX Back to MSB (F9)
IN AL,DX Re-read MSB
XCHG AH,AL Swap for multi
CMP AX,8[BP] Does it match
JNZ ?1 No, its dosn't
MOV AL,6[BP] Get mode
AND AL,#$7F Insure no baud rate
INC DX Advance...
INC DX to line control register (FB)
OUT DX,AL Write it
MOV AL,#$01 Receive interrupt only
DEC DX Backup ...
DEC DX to Interrupt enable register (F9)
OUT DX,AL Write it
MOV AL,4[BP] Get modem control
ADD DX,#3 Point to modem control register (FC)
OUT DX,AL Write it
* Setup the interrupt vector
MOV ?comvec,BX Save interrupt vector
MOV CS:?dsval,DS Save data segment for int handler
XOR AX,AX Get a zero
MOV ?rdptr,AX Zero read pointer
MOV ?wrptr,AX Zero write pointer
MOV AX,ES:[BX] Get old offset
MOV ?oldoff,AX Save old offset
MOV AX,ES:2[BX] Get old segmemt
MOV ?oldseg,AX Save segment
MOV AX,#?COMINT Point to routine
MOV ES:[BX],AX Write new offset
MOV ES:2[BX],CS Write new segment
* Clear out any pending characters
SUB DX,#4 Point to data register (F8)
IN AL,DX Read to clear interrupt
IN AL,DX Read to clear interrupt
* Setup the interrupt controller
IN AL,?8259+1 Read interrupt mask
AND AL,CL Enable serial port
OUT ?8259+1,AL Write interrupt controller
STI Re-enable interrupts
XOR AX,AX Indicate success
POP BP Restore caller
RET
*
* Close the comm port: Cclose()
*
Cclose XOR AX,AX Get zero
MOV ES,AX Point to interrupt vectors
MOV BX,?comvec Get old vector
AND BX,BX Is it set?
JZ ?3 No, its not
MOV ?comvec,AX Indicate not set
CLI Disable interrupts
* Restore the old comm interrupt vector
MOV DX,?oldoff Get old offset
MOV ES:[BX],DX Restore old offset
MOV DX,?oldseg Get old segment
MOV ES:2[BX],DX Restore old segment
* Disable interrupts on the uart
MOV DX,?comadr Get uart address
SUB DX,#4 Point to interrupt enable register
OUT DX,AL Write zero
IN AL,?8259+1 Read interrupt mask
OR AL,#$18 Disable comm interrupts
OUT ?8259+1,AL Write interrupt mask
STI Re-enable interrupts
?3 RET
*
* Test for char from com port: int Ctestc()
*
Ctestc MOV BX,?rdptr Get read pointer
CMP BX,?wrptr Test for data in buffer
JNZ ?4 Yes, we have some
MOV AX,#-1 Report no data available
RET
*
* Read a character from the comport: int Cgetc()
*
Cgetc MOV BX,?rdptr Get read pointer
CMP BX,?wrptr Test for data in buffer
JZ Cgetc No characters, wait for them
* Read character from com port
?4 MOV DI,#?buffer Get I/O buffer address
MOV AL,[BX+DI] Get character from buffer
XOR AH,AH Zero high
INC BX Advance read pointer
AND BX,#?BUFMSK Mask for buffer wrap
MOV ?rdptr,BX Resave read pointer
CMP BX,?wrptr Did we just empty buffer?
JNZ ?3 No, its ok
PUSH AX Save for later
* Buffer is empty, send XON if necessary
MOV DX,?comadr Point to com port
CLI No interrupts
MOV AH,Cflags Get control flags
TEST AH,#?TFLOW Flow controlled?
JZ ?7 No, its not
AND AH,#~(?TFLOW|?TXOFF|?TXON) Clear flags
IN AL,DX Get status
TEST AL,#?TXRDY Ok to send?
JZ ?5 No, set pending
SUB DX,#5 Backup to data port
MOV AL,#'Q'-$40 Get XON character
OUT DX,AL Send the XON
JMP <?6 And continue
* Cannot send not, set pending flag
?5 OR AH,#?TXON Set XON pending flag
?6 MOV Cflags,AH Resave the flags
?7 STI Re-enable interrupts
POP AX Restore character
RET
*
* Write a character to the com port: Cputc(char c)
*
Cputc PUSH BP Save callers stack frame
MOV BP,SP Address parameters
?8 MOV DX,?comadr Get address of uart
IN AL,DX Read uart status
TEST AL,#?TXRDY Ok to transmit
JZ ?8 No, wait for it
SUB DX,#5 Position to data address
CLI Disallow interrupts
MOV AH,Cflags Get control flags
* Test for pending XOFF to send
TEST AH,#?TXOFF Transmit XOFF?
JZ ?9 No, try next
MOV AL,#'S'-$40 Get XOFF
AND AH,#~?TXOFF Clear the bit
JMP <?10 Write to comm port
* Test for pending XON to send
?9 TEST AH,#?TXON Transmit XON?
JZ ?11 No, output character
MOV AL,#'Q'-$40 Get XON
AND AH,#~?TXON Clear the bit
* Resave the control flags & proceed
?10 MOV Cflags,AH Re-save control flags
STI Re-enable interrupts
OUT DX,AL Write character
JMP <?8 And proceed
* No pending flow control, output data
?11 STI Re-enable interrupts
TEST AH,#?RFLOW Output inhibited?
JNZ ?8 Yes, wait for it
MOV AL,4[BP] Get character
OUT DX,AL Write to comm port
POP BP Restore caller
RET
*
* Read the com port signals: int Csignals()
*
Csignals MOV DX,?comadr Get the com port address
INC DX Advance to modem status register
IN AL,DX Read modem status
XOR AH,AH Zero high bits
RET
*
* Comms Interrupt handler
*
?COMINT PUSH AX Save AX
PUSH BX Save BX
PUSH DX Save DX
PUSH DI Save DI
PUSH DS Save DS
MOV DS,CS:?dsval Get data segment
MOV DX,?comadr Get com port I/O address
IN AL,DX Read uart status register
TEST AL,#?RXRDY Receiver ready?
JZ ?15 No, Spurious interrupt
SUB DX,#5 Backup to data port
MOV AH,Cflags Get comm flags
IN AL,DX Read data character
TEST AH,#?XPAREN Are we transparent?
JNZ ?13 Yes, do not interpret flow control
* Test for XOFF, inhibit output
CMP AL,#'S'-$40 Is it XOFF?
JNZ ?12 No, try next
OR AH,#?RFLOW Set flow control bit
JMP <?14 and continue
* Test for XON, enable output
?12 CMP AL,#'Q'-$40 Is it XON
JNZ ?13 No, its not
AND AH,#~?RFLOW Reset flow control bit
JMP <?14 and continue
* Normal character, stuff in buffer
?13 MOV DI,#?buffer Get I/O buffer address
MOV BX,?wrptr Get write pointer
MOV [BX+DI],AL Write into buffer
INC BX Advance
AND BX,#?BUFMSK Mask for buffer wrap
MOV ?wrptr,BX Resave pointer
* Test for nearing end of buffer
SUB BX,?rdptr Calculate size of buffer
AND BX,#?BUFMSK Mask for buffer wrap
CMP BX,#?WINDOW Are we nearing end
JB ?15 No, its ok
TEST AH,#?XPAREN Are we transparent?
JNZ ?15 Don't send flow ctrl
* Send XOFF, flow control dest
OR AH,(?TFLOW|?TXOFF) Indicate flow control asserted
AND AH,#~?TXON Insure no XON pending
ADD DX,#5 Offset to status register
IN AL,DX Read status
TEST AL,#?TXRDY Test for transmitter ready
JZ ?14 Not ready
SUB DX,#5 Backup to data port
MOV AL,#'S'-$40 Get XOFF character
OUT DX,AL Write to port
AND AH,#~?TXOFF No pending XOFF needed
* Resave status flags to record changes
?14 MOV Cflags,AH Resave flags
* Reset 8259, Restore registers & return from interrupt
?15 MOV AL,#$20 End of Interrupt command
OUT ?8259,AL Write to interrupt controller
POP DS Restore DS
POP DI Restore DI
POP DX Restore DX
POP BX Restore BX
POP AX Restore AX
IRET
* Saved data segment incase we are running in small model
?dsval DW 0 Stored code segment value
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -