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

📄 com_pkg.asm

📁 汇编源代码大全2
💻 ASM
📖 第 1 页 / 共 2 页
字号:
; char *tbuf;		/* Transmit buffer address. */
; int tbuflen;		/* Transmit buffer length. */
; char *rbuf;		/* Receive buffer address. */
; int rbuflen;		/* Receive buffer length. */

;	Initialize the Intel 8250 and set up interrupt vector to int_hndlr.

IF LDATA
	BENTRY	COM_INI	<UNIT,DIVISOR,TBOFF,TBSEG,TBLEN,RBOFF,RBSEG,RBLEN>
ELSE
	BENTRY	COM_INI	<UNIT,DIVISOR,TBOFF,TBLEN,RBOFF,RBLEN>
ENDIF
	AUTO	<HANDLR>

	MOV	AX,UNIT		; Get the unit number.
	CALL	SET_SI		; Point to proper control area.
				; (Leaves AX unchanged)
	CMP	AX,2		; Initializing unit #2?
	 JE	INIT2		;   (yes)

				; Select constants for unit #1:
	MOV	AX,COM1_INT	; Interrupt number.
	MOV	BX,COM1_BASE	; I/O base address.
        MOV	CX,OFFSET INT_HNDLR1	; Start of interrupt handler.

	JMP SHORT INITCOM	; Go join common code.

INIT2:				; Select constants for unit #2:
	MOV	AX,COM2_INT	; Interrupt number.
	MOV	BX,COM2_BASE	; I/O base address.
        MOV	CX,OFFSET INT_HNDLR2	; Start of interrupt handler.
				; Fall into INITCOM:

INITCOM:
	MOV	[SI].COMX_INT,AX	; Save the interrupt number.
	MOV	[SI].COMX_BASE,BX	; Save the I/O base address.
	MOV	HANDLR,CX	; Save the interrupt handler starting address.

        MOV     AX,DS		; Copy our data segment number.
IFE LDATA
	MOV	ES,AX		; Save for buffer addresses.
ENDIF
        MOV     CS:DATASEG,AX	; Store segment # in code space (gulp!).

IF LDATA
	MOV	AX,TBSEG	; Get the transmit buffer segment number.
ENDIF
	MOV	[SI].TBUF_SEG,AX	; Save it.
	MOV	BX,TBOFF	; Copy the transmit buffer offset.
	MOV	[SI].TBUF_OFF,BX	;
	MOV	BX,TBLEN	; Copy the transmit buffer length.
	MOV	[SI].TBUF_SIZE,BX	;

IF LDATA
	MOV	AX,RBSEG	; Get the receive buffer segment number.
ENDIF
	MOV	[SI].RBUF_SEG,AX	; Save it.
	MOV	AX,RBOFF	; Copy the receive buffer offset.
	MOV	[SI].RBUF_OFF,AX	;
	MOV	AX,RBLEN	; Copy the receive buffer length.
	MOV	[SI].RBUF_SIZE,AX	;

	XOR	AX,AX		; Clear the accumulator.
	MOV	[SI].START_TDATA,AX	; Reset start of transmitted data.
	MOV	[SI].END_TDATA,AX	; Reset end of transmitted data.
	MOV	[SI].SIZE_TDATA,AX	; Reset number of transmitted chars.

	MOV	[SI].START_RDATA,AX	; Reset start of received data.
	MOV	[SI].END_RDATA,AX	; Reset end of received data.
	MOV	[SI].SIZE_RDATA,AX	; Reset number of received chars.

        CLI			; ******* Disable Interrupts *******

	MOV	DX,[SI].COMX_BASE	;;;
        ADD	DX,MCR		;;; Reset the UART (AX is still zero).
        OUT     DX,AL		;;;

        ADD	DX,(LSR-MCR)    ;;; Reset line status condition.
        IN      AL,DX		;;;
        ADD	DX,(DATREG-LSR)	;;; Reset receive data condition.
        IN      AL,DX		;;;
        ADD	DX,(MSR-DATREG)	;;; Reset modem deltas and conditions.
        IN      AL,DX		;;;

        ADD     DX,(LCR-MSR)	;;; Set baud rate with the passed argument.
        MOV     AL,DLA+MODE	;;;
        OUT     DX,AL		;;;
        ADD	DX,(DLL-LCR)	;;;
        MOV     AX,DIVISOR	;;;
        OUT     DX,AL		;;; Low byte of passed argument.
        ADD	DX,(DLH-DLL)	;;;
	MOV	AL,AH		;;;
        OUT     DX,AL	        ;;; High byte of passed argument.

        ADD	DX,(LCR-DLH)	;;; Set 8250 to 8 bits, no parity.
        MOV     AL,MODE		;;;
        OUT     DX,AL		;;;

	PUSH	SI			;;; Save pointer to COM block.
	MOV	AX,[SI].COMX_INT	;;; Get the 8259 interrupt number.
	ADD	AX,INT_OFF		;;; Convert to 8086 interrupt number.
	BCALL	INT_SETU <AX HANDLR CS>	;;; Call int_setup(vec, newip, newcs).
	POP	SI			;;; Restore data block pointer.

				;;; Enable interrupts on 8259 and 8250:
        IN      AL,IMR          ;;; Get current enable bits on 8259.
	MOV	CL,BYTE PTR [SI].COMX_INT	;;; Get interrupt number.
	MOV	BL,1		;;; Convert to
	SHL	BL,CL		;;;   bit position.
	NOT	BL		;;; Clear current
        AND     AL,BL		;;;   interrupt bit.
        OUT     IMR,AL		;;; Set enable on 8259.
	MOV	DX,[SI].COMX_BASE	;;;
        ADD	DX,IER          ;;; Enable interrupts on 8250.
        MOV     AL,RXINT	;;;
        OUT     DX,AL		;;;
        ADD	DX,(MCR-IER)	;;; Set dtr and enable int driver.
        MOV     AL,DTR		;;;
        OUT     DX,AL		;;;

        STI			;;; ******* Enable Interrupts *******
				;;; (Next instruction still disabled)
	BEND	COM_INI

	.SBHED	<COM_TRM -- Turn Off Interrupts and Shutdown>

; void
; com_trm(unit)		/* Turns off interrupts from the COM1: port. */
; int unit;		/* 1 ==> COM1:, 2 ==> COM2:. */

	BENTRY	COM_TRM <UNIT>

	MOV	AX,UNIT		; Point to COM1: or COM2: save area.
	CALL	SET_SI		;

	MOV	DX,[SI].COMX_BASE
	ADD	DX,IER		; Turn off 8250.
        MOV     AL,0
        OUT     DX,AL

        IN      AL,IMR		; Turn off 8259.
	MOV	CL,BYTE PTR [SI].COMX_INT	; Get interrupt number.
	MOV	BL,1		; Convert to
	SHL	BL,CL		;   bit position.
        OR      AL,BL		; Disable this interrupt.
        OUT     IMR,AL

				; Reset interrupt vector:
	MOV	AX,[SI].COMX_INT	; Get the 8259 interrupt number.
	ADD	AX,INT_OFF		; Convert to 8086 interrupt number.
	BCALL	INT_REST <AX>		; Call int_restore(vec).

	BEND	COM_TRM

	.SBHED	<COM_DOFF -- Turn off DTR>

; void
; com_doff(unit)	/* Turns off DTR. */
; int unit;		/* 1 ==> COM1:, 2 ==> COM2:. */

; 	Turns off DTR to tell modems that the terminal has gone away
; and to hang up the phone.

	BENTRY	COM_DOFF <UNIT>

	MOV	AX,UNIT		; Point to COM1: or COM2: save area.
	CALL	SET_SI		;

	MOV	DX,[SI].COMX_BASE
        ADD	DX,MCR
        MOV     AL,DTR_OF
        OUT     DX,AL

	BEND	COM_DOFF

	.SBHED	<COM_DON -- Turn On DTR>

; void
; com_don(unit)		/* Turns on DTR. */
; int unit;		/* 1 ==> COM1:, 2 ==> COM2:. */

	BENTRY	COM_DON <UNIT>

	MOV	AX,UNIT		; Point to COM1: or COM2: save area.
	CALL	SET_SI		;

	MOV	DX,[SI].COMX_BASE
        ADD	DX,MCR
        MOV     AL,DTR
        OUT     DX,AL

	BEND	COM_DON

	.SBHED	<COM_ICNT -- Return Number of Input Bytes>

; int			/* Number of characters in input buffer. */
; com_icnt(unit)	/* Returns number of characters in input buffer. */
; int unit;		/* 1 ==> COM1:, 2 ==> COM2:. */

	BENTRY	COM_ICNT <UNIT>

	MOV	AX,UNIT		; Point to COM1: or COM2: save area.
	CALL	SET_SI		;

        MOV     AX,[SI].SIZE_RDATA   ; Get number of bytes used.

	BEND	COM_ICNT

	.SBHED	<COM_GETC -- Get the Next Received Character>

; int			/* Next character in input buffer or EOF. */
; com_getc(unit)	/* Reads next character in input buffer. */
; int unit;		/* 1 ==> COM1:, 2 ==> COM2:. */
;
;	Returns the next character from the receive buffer and
; removes it from the buffer.

	BENTRY	COM_GETC <UNIT>

	MOV	AX,UNIT		; Point to COM1: or COM2: save area.
	CALL	SET_SI		;

	CMP	[SI].SIZE_RDATA,0	; Is there anything in the buffer?
	 JE	L12		;   (nothing)

	MOV	ES,[SI].RBUF_SEG	; Get receive buffer segment number.
	MOV	DI,[SI].RBUF_OFF	; Get receive buffer offset.
        MOV     BX,[SI].START_RDATA	; Fetch next data byte.
        MOV     AL,ES:[BX+DI]   ; Get data from buffer.
        XOR     AH,AH

        INC     BX              ; Bump START_RDATA so it points at next char.
        CMP     BX,[SI].RBUF_SIZE	; See if past end.
         JB	L10             ; If not then skip.
        XOR     BX,BX		; Adjust to beginning.
L10:    MOV     [SI].START_RDATA,BX  ; Save the new START_RDATA value.

        DEC     [SI].SIZE_RDATA      ; One less character.
	JMP SHORT L14		; Skip to common return code.

L12:	MOV	AX,-1		; Indicate no characters available.

L14:	BEND	COM_GETC

	.SBHED	<COM_OCNT -- Returns Number of Free Bytes>

; int			/* Number of free bytes in output buffer. */
; com_ocnt(unit)	/* Returns number of free bytes in output buffer. */
; int unit;		/* 1 ==> COM1:, 2 ==> COM2:. */

	BENTRY	COM_OCNT <UNIT>

	MOV	AX,UNIT		; Point to COM1: or COM2: save area.
	CALL	SET_SI		;

        MOV     AX,[SI].TBUF_SIZE	; Get the size of the x-mit buffer.
        SUB     AX,[SI].SIZE_TDATA   ; Subtract the number of bytes used.

	BEND	COM_OCNT

	.SBHED	<COM_PUTC -- Queue a Character for Output>

; bool			/* Returns FALSE if no more room. */
; com_putc(unit, ch)	/* Writes a character to the output buffer. */
; int unit;		/* 1 ==> COM1:, 2 ==> COM2:. */
; char ch;		/* The character to write. */

;	Note that there is an implicit interlock with the interrupt
; level.  It is OK for an interrupt to occur between incrementing
; SIZE_TDATA and the end of the code that monkeys with the interrupt
; enable bits.  The worst that can happen is that there will be an
; extra interrupt, which will be ignored (because SIZE_TDATA will be
; zero again by then).

	BENTRY	COM_PUTC <UNIT,OCHAR>

	MOV	AX,UNIT		; Point to COM1: or COM2: save area.
	CALL	SET_SI		;

        MOV     AX,[SI].TBUF_SIZE	; Get the size of the x-mit buffer.
        SUB     AX,[SI].SIZE_TDATA   ; Subtract the number of bytes used.
	 JE	L24		; No more free space.

	MOV	ES,[SI].TBUF_SEG	; Get transmit buffer segment number.
	MOV	DI,[SI].TBUF_OFF	; Get transmit buffer offset.
        MOV     BX,[SI].END_TDATA    ; BX points to free space.
        MOV     AL,OCHAR        ; Move data from stack to x-mit buffer.
        MOV     ES:[BX+DI],AL
        INC     BX              ; Increment END_TDATA to point to free space.
        CMP     BX,[SI].TBUF_SIZE	; See if past end.
         JB      L20		; If not then skip.
        XOR     BX,BX		; Adjust to beginning.
L20:	MOV     [SI].END_TDATA,BX    ; Save new END_TDATA.

				; (Implicit interlock with interrupt level):
        INC     [SI].SIZE_TDATA      ; One more character in x-mit buffer.

	MOV	DX,[SI].COMX_BASE
        ADD	DX,IER          ; See if tx interrupts are enabled.
        IN      AL,DX
        AND     AL,TXINT
        OR      AL,AL
         JNZ     L22
        MOV     AL,RXINT+TXINT  ; If not then set them.
        OUT     DX,AL
L22:				; (End of implicit interlock)

	MOV	AX,TRUE		; Indicate all's OK.
	JMP SHORT L26		; Go join common return code.

L24:	MOV	AX,FALSE	; No more space in buffer.

L26:	BEND	COM_PUTC

	.SBHED	<COM_LOOPC -- Write to the Input Buffer>

; bool			/* Returns FALSE if no more room. */
; com_loopc(unit, ch)	/* Writes a character to the input buffer. */
; int unit;		/* 1 ==> COM1:, 2 ==> COM2:. */
; char ch;		/* The character to write. */

	BENTRY	COM_LOOPC <UNIT,OCHAR>

	MOV	AX,UNIT		; Point to COM1: or COM2: save area.
	CALL	SET_SI		;

        CLI			; ******* Disable Interrupts *******
	MOV	DX,[SI].RBUF_SIZE ;;; Get the size of the receive buffer.
        CMP     [SI].SIZE_RDATA,DX	;;; See if any room for more data.
         JAE	L32             ;;; If no room then quit.

	MOV	ES,[SI].RBUF_SEG	;;; Get receive buffer segment number.
	MOV	DI,[SI].RBUF_OFF	;;; Get receive buffer offset.
        MOV     BX,[SI].END_RDATA    ;;; BX points to free space.
        MOV     AL,OCHAR	;;; Get data.
        MOV     ES:[BX+DI],AL	;;; Send data to buffer.
        INC     [SI].SIZE_RDATA      ;;; Got one more character.
        INC     BX              ;;; Increment END_RDATA pointer.
        CMP     BX,DX		;;; See if gone past end.
         JL	L30             ;;; If not then skip,
        XOR     BX,BX		;;;   else adjust to beginning.
L30:    MOV     [SI].END_RDATA,BX    ;;; Save value.

        STI			;;; ******* Enable Interrupts *******
	MOV	AX,TRUE		;;; Indicate success.
	JMP SHORT L34		; Go join common return code.

L32:	STI			;;; ******* Enable Interrupts *******
	MOV	AX,FALSE	;;; Indicate no more room.

L34:	BEND	COM_LOOPC

	.SBHED	<COM_BON -- Turn On BREAK Condition>

; void
; com_bon(unit)		/* Turns on BREAK. */
; int unit;		/* 1 ==> COM1:, 2 ==> COM2:. */
;
;	Causes the UART to send the BREAK condition.

	BENTRY	COM_BON <UNIT>

	MOV	AX,UNIT		; Point to COM1: or COM2: save area.
	CALL	SET_SI		;

	MOV	DX,[SI].COMX_BASE
	ADD	DX,LCR
        MOV     AL,BREAK        ; Set break condition.
        OUT     DX,AL

	BEND	COM_BON

	.SBHED	<COM_BOFF -- Turn Off BREAK Condition>

; void
; com_boff(unit)	/* Turns off BREAK. */
; int unit;		/* 1 ==> COM1:, 2 ==> COM2:. */
;
;	Returns the transmit line to the normal state.

	BENTRY	COM_BOFF <UNIT>

	MOV	AX,UNIT		; Point to COM1: or COM2: save area.
	CALL	SET_SI		;

	MOV	DX,[SI].COMX_BASE
	ADD	DX,LCR
        MOV     AL,MODE		; Restore the line control register.
        OUT     DX,AL

	BEND	COM_BOFF

	.SBHED	<COM_BREAK -- Complete BREAK Sequence>

; void
; com_break(unit)	/* Sends complete BREAK sequence. */
; int unit;		/* 1 ==> COM1:, 2 ==> COM2:. */

	BENTRY	COM_BREA <UNIT>

	MOV	AX,UNIT		; Point to COM1: or COM2: save area.
	CALL	SET_SI		;

	MOV	DX,[SI].COMX_BASE
	ADD	DX,LCR
        MOV     AL,BREAK        ; Set break condition.
        OUT     DX,AL

	MOV	CX,0		; Wait a while.
WAIT:	LOOP	WAIT

        MOV     AL,MODE		; Restore the line control register.
        OUT     DX,AL

	BEND	COM_BREA

	ENDPS
        END

⌨️ 快捷键说明

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