📄 llcom3.asm
字号:
cCALL B$INIQUE ; initialize queue
MOV [BX].QUETOP,CX ;Store Out buffer Top addr
MOV [BX].QUELEN,CX ;Store Out Queue length
MOV BX,OFFSET DGROUP:Q_IN ;BX points to COM1 input QCB
CMP [SI].DEVID,0 ;test if COM1
JZ BUFF4 ;branch if so
MOV BX,OFFSET DGROUP:Q_IN2 ;[BX] points to in_QCB
BUFF4:
XOR AX,AX ;each buffer starts at zero
MOV [BX].QUEBOT,AX ;Store In buffer Bottom addr
cCALL B$INIQUE ; initialize queue
MOV [BX].QUETOP,DX ;store in_buf1 top addr
MOV [BX].QUELEN,DX ;store in_queue length
POP AX
POP BX
POP SI
RET
;***
; GETDIV
;
; Purpose:
; gets baud rate divisor from table.
; Entry:
; [CX] = requested baud rate
; Exit:
; [CX] = baud rate divisor
; 0 means invalid baud request
; Modifies:
; None.
;***************************************************************************
GETDIV:
PUSH BX
PUSH DX
MOV BX,OFFSET CODE:BAUD_TBL-2 ;get address of baud table - 2
MOV DX,CX ;copy baud rate for compare
GETRA1:
INC BX
INC BX
MOV CX,CS:[BX] ; Get rate from Table
INC BX
INC BX ; (Baud value)
JCXZ GETEXT ;EOT, Bad Value given
CMP DX,CX
JNZ GETRA1 ; No match, look next
GETEXT:
MOV CX,CS:[BX] ; [CX] = Baud Divisor
POP DX
POP BX
RET
BAUD MACRO RATE,RATDIV
DW RATE
DW RATDIV
ENDM
BAUD_TBL:
BAUD 75,1536 ; 75
BAUD 110,1047 ; 110
BAUD 150,768 ; 150
BAUD 300,384 ; 300
BAUD 600,192 ; 600
BAUD 1200,96 ; 1200
BAUD 1800,64 ; 1800
BAUD 2400,48 ; 2400
BAUD 4800,24 ; 4800
BAUD 9600,12 ; 9600
BAUD 19200,6 ; 19200
BAUD 0,0 ; End
;***
;SETEM
;
; Purpose:
; Place the RS232 card in a deterministic initial state. This
; routine initializes the baud rate, parity, word size, and
; INS 8250 interrupt enable register for the card.
; Entry:
; CX = baud rate divisor
; SI = pointer to deb for this device
; DI = word index to COM device
; Exit:
; AH = 0 means no errors occurred
; 4 means time out occurred while waiting for DSR
; 5 means time out occurred while waiting for RLSD
; Modifies:
; AX,CX,DX
;**************************************************************************
SETEM:
MOV DX,b$ComPort[DI] ;Get I/O Base Addr.
DbAssertRel DX,NE,0,DV_TEXT,<LLCOM3.ASM: Com I/O address = 0 in SETEM>
ADD DX,3 ;Line Ctrl Reg.
MOV AL,80H ;Set DLAB=1
OUT DX,AL ;Enable Baud Latch
SUB DX,2 ;MSB of Baud Latch
MOV AL,CH
PAUSE ;make sure instruction fetch has occurred
OUT DX,AL ;Set MSB of Div
DEC DX
MOV AL,CL
PAUSE ;make sure instruction fetch has occurred
OUT DX,AL ;Set LSB of Div
MOV CH,[SI].PARTYP ;Get Parity
MOV CL,3
SHL CH,CL ;Shift Parity to D4-D3.
MOV AL,[SI].BYTSIZ ;Get Byte size (5,6,7,8)
OR AL,CH ;[AL] = Parity+Word size.
ADD DX,3 ;Line Ctrl Reg.
PAUSE ;make sure instruction fetch has occurred
OUT DX,AL ;Set Line Control Reg.
SUB DX,3 ;Data reg.
XOR CX,CX ;Lots of time
DATDLY:
PAUSE ;make sure instruction fetch has occurred
IN AL,DX ;Trash data
LOOP DATDLY ; waiting for 8250 to settle
ADD DX,5 ;line status register (port xFDH)
PAUSE ;wait for bus settle
IN AL,DX ;read to clear DR,OE,PE,FE,BI,THRE,TEMT
INC DX ;modem status register (port xFEH)
; ADD DX,6 ;Modem Status reg
PAUSE ;make sure instruction fetch has occurred
IN AL,DX ;Throw away 1st status read
PAUSE ;make sure instruction fetch has occurred
IN AL,DX ;Save 2nd
MOV [SI].MSREG,AL ; so MSRWAT works right
DEC DX ;Subtract 2 to get
DEC DX ;Modem Contrl Register
MOV AL,[SI].COMRTS ;Get RTS mask
XOR AL,2 ;toggle rts bit
OR AL,9 ; or in DTR/INT enable
PAUSE ;make sure instruction fetch has occurred
OUT DX,AL ;Enable the Card..
SUB DX,3 ;Interrupt Enable Reg.
MOV AL,MSRIE+RDAIE+TBEIE ;MSR/RDA/THRE Enable
PAUSE ;make sure instruction fetch has occurred
OUT DX,AL ;Enable Tx/Rx Interrupts.
INC DX ;Interrupt I.D. reg.
PAUSE ;make sure instruction fetch has occurred
IN AL,DX ; so interrupt line goes low
; ----------------
CALL MSRWAT ;Check MSR (On ret, [DH] = ERROR CODE).
; ----------------
MOV AH,DH ;copy error code
RET
;***
;MSRWAT:
;
;PURPOSE:
; Checks the modem status register for CTS,DSR, and/or RLSD
; signals. If a timeout occurred while checking then this
; routine will return the appropriate error code in DH.
; This routine will not check for any signal with a corresponding
; time out value of 0.
;ENTRY:
; [SI] = Pointer to deb for this device
; time out values in COMCTS,COMDSR, and COMRLS
;EXIT:
; [DH] = 0 indicates no time out errors occurred.
; 3 CTS timeout occurred
; 4 DSR timeout occurred
; 5 RLSD timeout occurred
; FC CTRL-BREAK found but not handled (COM OPEN ONLY)
;MODIFIED:
; AX,CX
;****
PUBLIC MSRWAT
MSRWAT:
PUSH BX ;save registers
PUSH CX
PUSH DI
XOR BX,BX ;initialize CX:BX to zero...
MOV CX,BX ;...for first time in
MSRWA0:
XOR DI,DI ;initialize millisecond timeout value
MSRWA1:
CMP [b$COFlag],0 ; Is this a COM OPEN?
JNZ MSRComOpen ; brif so -- special case
CALL B$BREAK_CHK
MSRWA2:
XOR AH,AH ;[AH] will be 0 if status is Ok.
MOV AL,[SI].MSREG ;Read Modem Status
TEST AL,CTS
JNZ MSRWA3 ;Brif got CTS
CMP [SI].COMCTS,0 ;Checking CTS?
JZ MSRWA3 ;Brif not
MOV DH,3 ;assume CTS timeout
CMP DI,[SI].COMCTS ;CTS timeout yet?
JAE MSRWAX ;jump if so
INC AH ;Status retry
MSRWA3:
TEST AL,DSR
JNZ MSRWA4 ;Brif got DSR
CMP [SI].COMDSR,0 ;Checking DSR?
JZ MSRWA4 ;Brif not
MOV DH,4 ;assume DSR timeout
CMP DI,[SI].COMDSR ;DSR timeout yet?
JAE MSRWAX ;jump if so
INC AH ;Status retry
MSRWA4:
TEST AL,RLSD
JNZ MSRWA5 ;Brif got RLSD
CMP [SI].COMRLS,0 ;Checking RLSD?
JZ MSRWA5 ;Brif not
MOV DH,5 ;assume MSR timeout
CMP DI,[SI].COMRLS ;RLDS timeout yet?
JAE MSRWAX ;jump if so
INC AH ;Status retry
MSRWA5:
OR AH,AH ;Check final status
JZ MSRWA8 ;Brif Status is Ok!
; CX:BX has entry tick value if nonzero.
; If zero, the entry tick value is set.
MOV DI,CX ;DI:BX has entry tick value
XOR AH,AH ;clear AH to get time-of-day...
INT 1AH ;...tick value in CX:DX
XCHG DI,CX ;CX:BX has entry - DI:DX has t-o-d value
MOV AX,CX ;get low-order t-o-d value...
OR AX,BX ;...and OR with high-order to test if zero
JNZ MSRNotFirst ;if nonzero, then not first time in
MOV CX,DI ;CX:BX zero, set to value...
MOV BX,DX ;...in DI:DX
JMP SHORT MSRWA0 ;jump to init DI to 0
MSRNotFirst:
SUB DX,BX ;subtract CX:BX from DI:DX...
SBB DI,CX ;...to get elapsed tick value
JNC MSRNoWrap ;if no wraparound, then jump
ADD DX,00B0H ;add 0018:00B0H to DI:DX...
ADC DI,0018H ;...to wrap for the next day
MSRNoWrap:
OR DI,DI ;test if over 64K ticks
MOV DI,0FFFFH ;assume maximum millisecond value
JNZ MSRWA1 ;if over 64K ticks, use maximum value
MOV AX,55D ;convert ticks to milliseconds...
MUL DX ;...where 1 tick is 55 milliseconds
JC MSRWA1 ;if over 64K milliseconds, use maximum value
MOV DI,AX ;move computed millisecond value
JMP SHORT MSRWA1 ;jump to retry the test
MSRComOpen: ; special handling for COM OPEN
CALL [b$IPOLKEY] ; check keyboard buffer (if /D or QB)
TEST [b$EventFlags],CNTLC ; test for CTRL-BREAK
JZ MSRWA2 ; brif no CTRL-BREAK
MOV DH,0FCh ; set error flag to indicate CTRL_BREAK
SKIP 2 ; and exit via MSRWAX
MSRWA8:
XOR DH,DH ;indicate no errors occurred
MSRWAX:
POP DI
POP CX
POP BX
RET
SUBTTL Comm read/write/status
page
;***
;B$RECCOM
;[OEM documentation in LLCOM5]
;
;PURPOSE:
; Read Byte From RS232 Input Queue If Data Is Ready
;
;ALGORITHM:
; If COM interrupt handler detected error for this device,
; set PSW.C and return error code in [AH]
; Else if interrupt handler has queued data for this device,
; move 1 byte from queue into [AL] and
; return with [AH]=0 and PSW.Z reset
; Else if cntrl z (eof) then
; return with [AH]=26 and PSW.Z reset
; Else
; return with [AH]=0 and PSW.Z set.
;ENTRY:
; [AH] = RS232 device ID (0..255)
;
;EXIT:
; [AH] = 0 if no I/O errors have occured
; = 1 if receive data queue overflow
; = 2 if receive parity error
; = 3 if CTS timeout
; = 4 if DSR timeout
; = 5 if RLSD timeout
; = 6 if receive Overrun error
; = 7 if receive Framing error
; = FF for all other I/O errors
; If data is available, PSW.Z is reset & [AL] = input byte
; else PSW.Z is set.
;
;MODIFIED:
; none
;****
cProc B$RECCOM,<PUBLIC,NEAR>
cBegin
PUSH SI
PUSH BX
MOV SI,OFFSET DGROUP:COMM1 ;get comm1 deb
OR AH,AH ;is it com1?
JZ RECC2 ;br. if so
MOV SI,OFFSET DGROUP:COMM2 ;get com2 deb
RECC2:
CALL CHKERR ;get any errors in [AH]
CMP AH,0 ;have any errors occurred?
JNZ RECERR ;br. if so
MOV BX,OFFSET DGROUP:Q_IN ;get address of queue control block
CMP [SI].DEVID,0 ; is this COM1?
JZ RECC3 ;br. if so
MOV BX,OFFSET DGROUP:Q_IN2 ; must be COM2 - get its queue
RECC3:
CMP [BX].QUENUM,0 ;are there elements in the queue
JNZ NOZYET ;br. if so
CMP [SI].CTRLZ,0 ;has control z been struck?
JZ RECERR ;br. if not
MOV AL,26D ;else return control z
JMP SHORT RETOK ;avoid deque
NOZYET:
PUSH ES
MOV ES,[SI].RCVSEG ;get buffer segment from DCB
cCALL B$DQUE ; get char from queue in [AL]
POP ES
RETOK:
OR SP,SP ;reset PSW.Z
JMP SHORT RECEXIT
RECERR:
XOR AL,AL ;set PSW.Z
RECEXIT: ; get back registers and exit
POP BX
POP SI
cEnd ; return to caller
;***
;CHKERR
;
;PURPOSE:
; checks to see if framing, overrun, parity, or data queue overflow
; errors have taken place.
;
;ENTRY:
; [SI] = Pointer to deb for this device
;
;EXIT:
; [AH] = 0 if no errors have occurred
; 1 if receive data queue overflow
; 2 if receive parity error
; 6 if ovrrun error
; 7 if framing error
; FF if other errors occurred
;
;MODIFIED:
; AH
;****
CHKERR:
CMP [SI].COMERR,0 ;did line status register return errors?
JZ NOCMER ;br. if not
MOV AL,[SI].COMERR ;get error
MOV AH,6 ;assume overrun error
TEST AL,2 ;was this overrun error?
JNZ CHKRET ;br. if so
MOV AH,2 ;assume parity error
TEST AL,4 ;was it parity error?
JNZ CHKRET ;br. if so
MOV AH,7 ;assume framing error
TEST AL,8 ;was it a framing error?
JNZ CHKRET ;br. if so
MOV AH,0FFH ;assume break error
TEST AL,10H ;was it a break error
JNZ CHKRET ;br. if so
NOCMER:
MOV AH,1 ;assume overflow
CMP [SI].COMOVF,0 ;was there overflow
JNZ CHKRET ;br. if so
XOR AH,AH ;must have been no errors
CHKRET:
MOV [SI].COMOVF,0 ;reset for next time
MOV [SI].COMERR,0 ;reset for next time
RET
;***
; B$SNDCOM
;[OEM documentation in LLCOM5]
;
; Purpose:
; Transmit one character over the specified serial port.
; Algorithm:
; if COM interrupt handler detected error for this device,
; reset error-flag and return error code in [AH]
; else if [DCB].CD_CTSTO > 0 then begin
; wait [DCB].CD_CTSTO milliseconds for CTS signal to become true.
; If TIMEOUT, return CTS timeout indication.
; if [DCB].CD_DSRTO > 0 then begin
; wait [DCB].CD_DSRTO milliseconds for DSR signal to become true.
; If TIMEOUT, return DSR timeout indication.
; if [DCB].CD_RSLTO > 0 then begin
; wait [DCB].CD_RSLTO milliseconds for RSLD signal to become true.
; If TIMEOUT, return RSLD timeout indication.
; if queue is full wait until there is room in queue
; queue Data and return with [AH] = 0.
; Entry:
; [AH] = RS232 device ID (0..255)
; [AL] = byte to be output
;
; Exit:
; [AH] = 0 if no I/O errors have occured
; = 1 if receive data queue overflow
; = 2 if receive parity error
; = 3 if CTS timeout
; = 4 if DSR timeout
; = 5 if RLSD timeout
; = 6 if receive Overrun error
; = 7 if receive Framing error
; = FF for all other I/O errors
; Modifies:
; None.
;******************************************************************************
cProc B$SNDCOM,<PUBLIC,NEAR>
cBegin
PUSH DI
PUSH SI
PUSH DX
PUSH CX
PUSH BX
MOV SI,OFFSET DGROUP:COMM1 ;get com1 deb
MOV BX,OFFSET DGROUP:Q_OUT ; get com1 queue
OR AH,AH ;is it comm1?
JZ SND2 ;br. if so
MOV SI,OFFSET DGROUP:COMM2 ;get com2 deb
MOV BX,OFFSET DGROUP:Q_OUT2 ; get com2 queue
SND2:
PUSH AX
CALL MSRWAT ;Check MSR, return or "timeout"
POP AX ;restore char
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -