⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 comm.asm

📁 由3926个源代码
💻 ASM
📖 第 1 页 / 共 4 页
字号:
	CMP	SIZE_TDATA[SI],S_SIZE	; BUFFER FULL?
	 JB	SENDII2 		; JUMP IF NOT
	INC	WORD PTR EOVFLOW[SI]	; BUMP ERROR COUNT (Can this happen?)
	ADD BX,START_TDATA[SI]		; ES:BX point to 1st chr in buffer
	MOV ES:[BX],AL			; Overwrite 1st character
	JMP SHORT SENDII4

SENDII2:MOV DX,START_TDATA[SI]		; DX is index of 1st char
	DEC DX				; Back it up
	AND DX,S_SIZE-1 		; Ring it
	MOV START_TDATA[SI],DX		; Save new value
	ADD BX,DX			; Address within buffer
	MOV ES:[BX],AL			; Move character to buffer
	INC	SIZE_TDATA[SI]		; ONE MORE CHARACTER IN X-MIT BUFFER
	MOV URGENT_SEND[SI],1		; Flag high priority message
	; No check for PC_OFF here.  Flow control ALWAYS gets sent!
SENDII4:CALL CHROUT			; Output a chr if possible
SENDIIX:POP ES
	POP DX
	POP BX
	RET
SENDII	ENDP

;*---------------------------------------------------------------------*
;*	s p i n l o o p 					       *
;*								       *
;*	Waste time to allow slow UART chips to catch up 	       *
;*---------------------------------------------------------------------*

SPINLOOP PROC NEAR
	PUSH CX
	MOV CX,100
WASTERS:
	CALL CRET		; Better time waster than a 1-byte NOP
	LOOP WASTERS
	POP  CX
CRET:	RET
SPINLOOP ENDP

; CHROUT()	Process level routine to remove a chr from the buffer,
;		give it to the UART and adjust the pointer and count.
;		If interrupts are disabled at entry, nothing is done.
;		If a character is successfully output, Tx ints are enabled.
;	Requires: SI pointing at the appropriate data area
;	Clobbers: AX, BX, DX, ES
;	Must preserve: CX in case there is a count there

CHROUT	PROC NEAR
	MOV DX,IER[SI]			; Interrupt Enable Register
	IN AL,DX
	TEST AL,2			; Tx interrupts enabled?
	 JNZ CHROUX			; Jump if not
	CMP SEND_OK[SI],1		; See if Data Set Ready & CTS are on
	 JNE CHROUX			; No. Still can't enable TX ints
	CALL TX_CHR			; Actually transmit the chr
	MOV DX,IER[SI]			; Interrupt Enable Register
	MOV AL,0FH			; Rx, Tx, Line & Modem enable bits
	OUT DX,AL			; Enable those interrupts
CHROUX: RET
CHROUT	ENDP
	PAGE;

IFNDEF UUPC
;
; void far send_local(char);
;	Simulate a loopback by placing characters sent in recv buffer
;
_send_local PROC FAR
	push bp
	mov bp,sp
	PUSHF
	PUSH SI
	PUSH ES
	MOV	SI,CURRENT_AREA 	; SI POINTS TO DATA AREA
	TEST	INSTALLED[SI],1 	; PORT INSTALLED?
	 JZ	SLX			; ABORT IF NOT

	CLI				; INTERRUPTS OFF
	CMP	SIZE_RDATA[SI],R_SIZE	; SEE IF ANY ROOM
	 JB SL3 			; SKIP IF ROOM
	INC	WORD PTR EOVFLOW[SI]	; BUMP OVERFLOW COUNT
	JMP SHORT SLX			; PUNT

SL3:	LES BX,RBuff[SI]		; Receive buffer location
	ADD BX,END_RDATA[SI]		; ES:BX POINTS TO FREE SPACE
	MOV AL,[BP+6]			; Get the byte to send
	MOV ES:[BX],AL			; Put into buffer
	MOV BX,END_RDATA[SI]		; Get the end pointer
	INC	BX			; INCREMENT END_RDATA POINTER
	AND BX,R_SIZE-1 		; Ring the pointer
	MOV	END_RDATA[SI],BX	; SAVE VALUE
	INC	SIZE_RDATA[SI]		; GOT ONE MORE CHARACTER

SLX:	POP ES
	POP SI
	POPF				; Restore interrupt state
	mov sp,bp
	pop bp
	RET				; DONE
_send_local	ENDP
ENDIF
	PAGE;
;
; void far break_com(void)	Send a BREAK out to alert the remote end
;
_break_com PROC FAR
	push bp
	mov bp,sp
	PUSH SI

	MOV	SI,CURRENT_AREA 	; SI POINTS TO DATA AREA
	TEST	INSTALLED[SI],1 	; PORT INSTALLED?
	 JZ	BREAKX			; ABORT IF NOT

	MOV	DX,LCR[SI]		; LINE CONTROL REGISTER
	IN	AL,DX			; GET CURRENT SETTING
	OR	AL,40H			; TURN ON BREAK BIT
	OUT	DX,AL			; SET IT ON THE UART
	MOV AX,25			; 25/100 of a second
	CALL WaitN
	MOV	DX,LCR[SI]		; LINE CONTROL REGISTER
	IN	AL,DX			; GET CURRENT SETTING
	AND	AL,0BFH 		; TURN OFF BREAK BIT
	OUT	DX,AL			; RESTORE LINE CONTROL REGISTER
BREAKX: POP SI
	mov sp,bp
	pop bp
	RET
_break_com ENDP
	PAGE;
;
; ERROR_STRUCT far *com_errors(void)
;	Returns a pointer to the table of error counters
;
_com_errors PROC FAR
	push bp
	mov bp,sp
	PUSH SI
	MOV SI,CURRENT_AREA		; Point to block for selected port
	LEA AX,ERROR_BLOCK[SI]		; Offset to error counters
	MOV DX,DS			; Value is in DX:AX
	POP SI
	mov sp,bp
	pop bp
	RET
_com_errors ENDP






;
; char far modem_status(void)
;	Returns the modem status register in AL
;
; Bits are:	0x80:	Carrier Detect
;		0x40:	Ring Indicator
;		0x20:	Data Set Ready
;		0x10:	Clear To Send
;		0x08:	Delta Carrier Detect	(CD changed)
;		0x04:	Trailing edge of RI	(RI went OFF)
;		0x02:	Delta DSR		(DSR changed)
;		0x01:	Delta CTS		(CTS changed)

_modem_status PROC FAR
	push bp
	mov bp,sp
	PUSH SI
	MOV SI,CURRENT_AREA		; Point to block for selected port
	MOV DX,MSR[SI]			; IO Addr of Modem Status Register
	IN AL,DX			; Get the live value
	XOR AH,AH			; Flush unwanted bits
	POP SI
	mov sp,bp
	pop bp
	RET
_modem_status ENDP
	PAGE;
;
; INT_HNDLR1 - HANDLES INTERRUPTS GENERATED BY COM1:
;
INT_HNDLR1 PROC FAR
	PUSH SI
	MOV	SI,OFFSET DGROUP:AREA1	; DATA AREA FOR COM1:
	JMP	SHORT INT_COMMON	; CONTINUE
;
; INT_HNDLR2 - HANDLES INTERRUPTS GENERATED BY COM2:
;
INT_HNDLR2 PROC FAR
	PUSH SI
	MOV	SI,OFFSET DGROUP:AREA2	; DATA AREA FOR COM2:
	JMP	SHORT INT_COMMON	; CONTINUE
;
; INT_HNDLR3 - HANDLES INTERRUPTS GENERATED BY COM3:
;
INT_HNDLR3 PROC FAR
	PUSH SI
	MOV	SI,OFFSET DGROUP:AREA3	; DATA AREA FOR COM3:
	JMP	SHORT INT_COMMON	; CONTINUE
;
; INT_HNDLR4 - HANDLES INTERRUPTS GENERATED BY COM4:
;
INT_HNDLR4 PROC FAR
	PUSH SI
	MOV	SI,OFFSET DGROUP:AREA4	; DATA AREA FOR COM4:
	; Fall into INT_COMMON
	PAGE;
;
; BODY OF INTERRUPT HANDLER
;
INT_COMMON: ; SI has been pushed and loaded
	PUSH AX
	PUSH BX
	PUSH CX
	PUSH DX
	PUSH DS
	PUSH ES

	MOV AX,DGROUP			; Offsets are relative to DGROUP [WWP]
	MOV	DS,AX


; FIND OUT WHERE INTERRUPT CAME FROM AND JUMP TO ROUTINE TO HANDLE IT
REPOLL: MOV DX,IIR[SI]			; Interrupt Identification Register
	IN AL,DX
	TEST AL,1			; Check the "no interrupt present" bit
	 JNZ INT_END			; ON means we are done
	MOV BL,AL			; Put where we can index by it
	AND BX,000EH			; Ignore FIFO_ENABLED bits, etc.

	JMP WORD PTR CS:INT_DISPATCH[BX]; Go to appropriate routine

INT_DISPATCH:
	DW MSI				; 0: Modem status interrupt
	DW TXI				; 2: Transmitter interrupt
	DW RXI				; 4: Receiver interrupt
	DW LSI				; 6: Line status interrupt
	DW REPOLL			; 8: (Future use by UART makers)
	DW REPOLL			; A: (Future use by UART makers)
	DW RXI				; C: FIFO Timeout
	DW REPOLL			; E: (Future use by UART makers)

INT_END: ; Now tell 8259 we handled that IRQ

	MOV DX,IER[SI]			; Gordon Lee's cure for dropped ints
	IN AL,DX			; Get enabled interrupts
	MOV AH,AL
	XOR AL,AL
	OUT DX,AL			; Disable UART interrupts
	MOV AL,EOI[SI]			; End of Interrupt. With input gone,
	OUT INTA00,AL			; Give EOI to 8259 Interrupt ctlr
	MOV AL,AH			; Get save interrupt enable bits
	OUT DX,AL			; Restore them, maybe causing a
					; transition into the 8259!!!
	POP ES
	POP DS
	POP DX
	POP CX
	POP BX
	POP AX
	POP SI
	IRET
	PAGE;
;
; Line status interrupt
;
LSI:	MOV DX,LSR[SI]			; Line status register
	IN AL,DX			; Read line status & bump error counts
	TEST	AL,2			; OVERRUN ERROR?
	 JZ	LSI1			; JUMP IF NOT
	INC	WORD PTR EOVRUN[SI]	; ELSE BUMP ERROR COUNT
LSI1:	TEST	AL,4			; PARITY ERROR?
	 JZ	LSI2			; JUMP IF NOT
	INC	WORD PTR EPARITY[SI]	; ELSE BUMP ERROR COUNT
LSI2:	TEST	AL,8			; FRAMING ERROR?
	 JZ	LSI3			; JUMP IF NOT
	INC	WORD PTR EFRAME[SI]	; ELSE BUMP ERROR COUNT
LSI3:	TEST	AL,16			; BREAK RECEIVED?
	 JZ	LSI4			; JUMP IF NOT
	INC	WORD PTR EBREAK[SI]	; ELSE BUMP ERROR COUNT
LSI4:	JMP	REPOLL			; SEE IF ANY MORE INTERRUPTS

;
; Modem status interrupt
;
MSI:	MOV DX,MSR[SI]			; Modem Status Register
	IN AL,DX			; Read status & clear interrupt
	CMP CONNECTION[SI],'D'          ; Direct connection - ignore int
	 JE MSI0			; Just noise on DSR,CTS pins
	AND AL,30H			; Expose CTS and Data Set Ready
	CMP AL,30H			; Both on?
	 JE MSI0			; Yes.	Enable output at TXI
	XOR AL,AL
	JMP SHORT MSI1

MSI0:	MOV AL,1
MSI1:	MOV SEND_OK[SI],AL		; Put where TXI and send_com can see
	MOV DX,IER[SI]			; Let a TX int happen for thoro chks
	MOV AL,0FH			; Line & modem sts, recv, send.
	OUT DX,AL
	JMP REPOLL			; Check for other interrupts
	PAGE;
;
; Transmit interrupt
;
TXI:	CMP SEND_OK[SI],1		; Harware (CTS & DSR on) OK?
	 JNE TXI9			; No.  Must wait 'til cable right!
	MOV CX,1			; Transfer count for flow ctl
	CMP URGENT_SEND[SI],1		; Flow control character to send?
	 JE TXI3			; Yes.	Always send flow control.
	CMP PC_OFF[SI],1		; Flow control (XON/XOFF) OK?
	 JE TXI9			; Stifled & not urgent. Forget it.

TXI1:	MOV CL,UART_SILO_LEN[SI]	; MAX size chunk (1 for simple 8250)
	; Too bad there is no "Tranmitter FIFO Full" indication!
	CMP SIZE_TDATA[SI],CX		; SEE IF ANY MORE DATA TO SEND
	 JG TXI2			; UART is the limit
	MOV CX,SIZE_TDATA[SI]		; Buffer space limited.  Use that.
TXI2:	 JCXZ TXI9			; No data, disable TX ints

TXI3:	CALL TX_CHR			; Transmit a character
	 LOOP TXI3			; Keep going 'til silo is full
	MOV URGENT_SEND[SI],0		; Tell process level we sent flow ctl
	JMP	REPOLL

; IF NO DATA TO SEND, or can't send, RESET TX INTERRUPT AND RETURN
TXI9:	MOV DX,IER[SI]
	MOV AL,0DH			; Line & modem sts, recv, no send.
	OUT DX,AL
	JMP REPOLL


; TX_CHR	Internal routine used to actually move a character from
;		the transmit buffer to the UART and adjust pointers.
;		Called from process and interrupt levels with interrutps
;		enabled or disabled.
;	Requires: SI pointing at data area for this UART
;	Clobbers: AX, BX, DX, ES
;	Must preserve: CX  (Caller has count here).

TX_CHR	PROC NEAR
	LES BX,TBuff[SI]		; Pointer to buffer
	ADD BX,START_TDATA[SI]		; ES:BX points to next char to send
	MOV AL,ES:[BX]			; Get character from buffer
	MOV DX,DATREG[SI]		; I/O address of data register
	OUT DX,AL			; Output the character
	INC BX				; Bump the head pointer
	AND BX,S_SIZE-1 		; Ring it
	MOV START_TDATA[SI],BX		; Store back in private block
	DEC SIZE_TDATA[SI]		; One fewer in buffer now
	RET
TX_CHR	ENDP
	PAGE;
;
; Receive interrupt
;
RXI:
RXI0:	MOV DX,LSR[SI]			; Line Status Register
	IN AL,DX			; Read it
	TEST AL,1			; Check the RECV DATA READY bit
	 JE RXIX			; No more data available
	MOV	DX,DATREG[SI]		; UART DATA REGISTER
	IN AL,DX			; Get data, clear status
	CMP	XON_XOFF[SI],'E'        ; FLOW CONTROL ENABLED?
	 JNE RXI2			; No.  Don't check for XON/XOFF

; Check each character for possible flow control (XON/XOFF)
	AND	AL,7FH			; STRIP PARITY
	CMP	AL,CONTROL_S		; STOP COMMAND RECEIVED?
	 JNE RXI1			; Jump if not. Might be ^Q though.
	MOV PC_OFF[SI],1		; Stop output
	JMP SHORT RXI0			; Don't store character

RXI1:	CMP	AL,CONTROL_Q		; GO COMMAND RECEIVED?
	 JNE RXI2			; No.  Not a flow control character
	MOV PC_OFF[SI],0		; Enable output
	JMP SHORT RXI0			; Don't store character

; Have a real data byte.  Store if possible.
RXI2:	CMP	SIZE_RDATA[SI],R_SIZE	; SEE IF ANY ROOM
	 JL RXI6			; CONTINUE IF SO
	INC	WORD PTR EOVFLOW[SI]	; BUMP OVERFLOW ERROR COUNT
	JMP SHORT RXIX

RXI6:	LES BX,RBuff[SI]		; Receive buffer location
	ADD BX,END_RDATA[SI]		; ES:BX points to free space
	MOV ES:[BX],AL			; Put character in buffer
	INC	SIZE_RDATA[SI]		; GOT ONE MORE CHARACTER
	MOV BX,END_RDATA[SI]		; Get the end index
	INC BX				; Bump it passed location just used
	AND BX,R_SIZE-1 		; Ring the pointer
	MOV	END_RDATA[SI],BX	; SAVE VALUE

; See if we must tell remote host to stop outputting.
	CMP	XON_XOFF[SI],'E'        ; FLOW CONTROL ENABLED?
	 JNE RXI0			; No
	CMP HOST_OFF[SI],1		; Already told remote to shut up?
	 JE RXI0			; Yes.	Don't flood him with ^Ss
	CMP	SIZE_RDATA[SI],R_SIZE/2 ; RECEIVE BUFFER NEARLY FULL?
	 JLE RXIX			; No.  No need to stifle remote end
	; Would like to wait here for URGENT_SEND to go off if it is on.
	; But we need to take a TX interrupt for that to happen.
	MOV	AL,CONTROL_S		; TURN OFF HOST IF SO
	CALL	SENDII			; SEND IMMEDIATELY INTERNAL
	MOV	HOST_OFF[SI],1		; HOST IS NOW OFF
RXIX:	JMP REPOLL

INT_HNDLR4 ENDP
INT_HNDLR3 ENDP
INT_HNDLR2 ENDP
INT_HNDLR1 ENDP
COM_TEXT   ENDS
	   END

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -