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

📄 8390.asm

📁 RTL8019 Plug-And-Play Packet Driver.
💻 ASM
📖 第 1 页 / 共 4 页
字号:

	dec	bx		; waited more than max collision time?
	jnz	tx_wait_l1	; -no, probably not stuck yet

	SHOW_EVENT	'b'
	add2	hard_tx_errors,1	;count hard errors.
	call	count_out_err	; Should count these error timeouts
				; Maybe need to add recovery logic here
	jmp	short tx_idle_0


	public	send_pkt
send_pkt:
;enter with ds:si -> packet, cx = packet length.
;exit with nc if ok, or else cy if error, dh set to error number.
	assume	ds:nothing
	mkle LE_SP_E, cx, si, ds

	cli

;ne1000 checks the packet size at this point, which is probably more sensible.
	loadport		; Point at chip command register
	setport EN_CCMD		; ..
	pause_
;ne1000 fails to check to see if the transmitter is still busy.
	in al,	dx		; Get chip command state
	test al,ENC_TRANS	; Is transmitter still running?
ifdef debug
	mov log_ccmd,al		; added - gft - 910607
endif
;
; Used to just go to tx_idle here if the transmitter was not running, however
; it is possible to get here with the transmission complete, but since
; interrupts are off when we get here it is also possible that a transmission
; JUST DID complete and has not yet had its interrupt acknowledge and errors
; recorded. Proceding here without checking will work, it just looses the 
; error status from the last transmission if that transmission has not been
; acknowledged by the isr_tx code.
;
; Changed the jz tx_idle below to the following code - gft - 910607
;
; 	jz	tx_idle		; Go if free

	jnz	tx_wait

; Check for recent TX completions in the interrupt status register

	setport EN0_ISR		; Point at isr
	pause_
	in	al,dx		; get state
ifdef debug
	mov	log_isr,al
endif
	test al,ENISR_TX+ENISR_TX_ERR ; pending TX interupts?
	jz	tx_idle		; No, Go on with new TX

tx_idle_0:	; Added to capture TSR if tx not done on entry
		; AND added all the below TX error detection down to tx_idle
		; - gft - 910603

	loadport
 	setport	EN0_TSR		; point to TSR
	pause_
	in al,	dx		; get state from prior TX
ifdef debug
	mov log_tsr,al		; added - gft - 910603
endif

; Acknowledge the TX interrupt and take care of any TX errors from the 
; previous transmission

	mov	ah,al		; save the TSR state

	setport EN0_ISR		; Point at the interrupt status register
	pause_
	mov	al,ENISR_TX+ENISR_TX_ERR ; clear either possible TX int bit
	out	dx,al

	test ah,ENTSR_COLL+ENTSR_COLL16+ENTSR_FU+ENTSR_OWC+ENTSR_CRS
	jz	tx_idle		; No usefull errors, skip. See the called
				; routine for explanation of the selection
				; of TSR bits for consideration as errors.
	call	count_tx_err

tx_idle:
; If IPX + NETX ver 3.26 receives a CANT_SEND it will put a query on the
; screen if one should abort or retry. This is annoying, causes delay and
; destroys formatted screens. Even worse, the current NETX, ver 3.32, will
; hang for any of the replies.

	cmp	word ptr [si+2*EADDR_LEN+2],0ffffh ; Novell packet?
	je	tx_nov_noerr	; -yes, avoid CANT_SEND, causes hang :-(

	mov	ax,soft_tx_errors	;return an error if the previous
	or	ax,hard_tx_errors	;  packet failed.
	jne	send_pkt_err
tx_nov_noerr:

	cmp	cx,GIANT	; Is this packet too large?
	ja	send_pkt_toobig

	cmp cx,	RUNT		; Is the frame long enough?
	jnb	tx_oklen	; Go if OK
	mov cx,	RUNT		; Stretch frame to minimum allowed
tx_oklen:
	push	cx		; Hold count for later
	loadport		; Set up for address
	setport EN0_ISR
	pause_
	mov	al,ENISR_RDC	; clear remote interrupt int.
	out	dx,al
	setport	EN0_TCNTLO	; Low byte of TX count
	pause_
	mov al,	cl		; Get the count
	out dx,	al		; Tell card the count
	setport	EN0_TCNTHI	; High byte of TX count
	pause_
	mov al,	ch		; Get the count
	out dx,	al		; Tell card the count
	xor ax,	ax		; Set up ax at base of tx buffer
	mov ah,	SM_TSTART_PG	; Where to put tx frame
	pop	cx		; Get back count to give to board
	call	block_output
	jc	tx_no_rdc
	loadport
	setport	EN0_TPSR	; Transmit Page Start Register
	pause_
	mov al,	SM_TSTART_PG
	out dx,	al		; Start the transmitter
	setport	EN_CCMD		; Chip command reg
	pause_
	mov al,	ENC_TRANS+ENC_NODMA+ENC_START
	out dx,	al		; Start the transmitter
	mkle LE_SP_X, cx, 1, 0

	mov	ax,soft_tx_errors	;return an error if the previous
	or	ax,hard_tx_errors	;  packet failed.
	jne	send_pkt_err
	clc			; Successfully started
	ret			; End of transmit-start routine
send_pkt_toobig:
	mov	dh,NO_SPACE
	stc
	ret
send_pkt_err:
	SHOW_EVENT	'e'
	mov	soft_tx_errors,0
	mov	soft_tx_collisions,0
	mov	hard_tx_errors,0
	stc
	mov	dh,CANT_SEND
	ret
tx_no_rdc:
	mov	dh,CANT_SEND
	mkle LE_SP_X, cx, 0, 0
	stc
	ret

count_tx_err:
;
; Function to count hard and soft TX completion errors and collisions.
; Entered with ah containing the transmit status register state.
;  - gft - 910607

	test ah,ENTSR_PTX	; 
	jnz	tx_err_02	; NO hard tx errors go look for soft ones

; Handle hard tx errors, fifo underrun and abort

	add2	hard_tx_errors,1	;count hard errors.

	test ah,ENTSR_COLL16	; 16 collision abort?
	jz	tx_err_01 	; no skip
	SHOW_EVENT	'c'	; this almost always occurs in pairs, is this
				; routine called twice WHILE one collision
				; error lasts??? /Jan E LDC
	add2	soft_tx_collisions,16
tx_err_01:
	call	count_out_err  ; only possible other hard error is FU, just
	                       ; count the hard error and skip the soft error
	jmp 	tx_err_done

; Handle the tx soft errors and collisions
;
;  National DP8390 Datasheet Addendum June 1990 says that Carrier Sense Lost 
;  (CRS) and Non Deferred TX (DFR) are useless in some or all 8390s, that
;  leaves only out of window collision (OWC) and CD Heartbeat (CDH) as 
;  soft errors (I would hesitate to call collision an error of any kind).
;  With who knows how may MAUs out there with SQE either disabled or not
;  functional, I don't count CDs as errors either (If your MAU doesn't SQE
;  you would count CD errors on EVERY transmission.) That only leaves OWC
;  as a soft error.

tx_err_02:
	test ah,ENTSR_OWC+ENTSR_COLL ; No soft errors or collisions?
	jz	tx_err_done	     ; return

	test ah,ENTSR_OWC	; Out of window collision?
	jz	tx_err_03	; No, skip
	SHOW_EVENT	'f'	; this is not uncommon on a real net using
                                ; some WD cards, other WD cards on same net
				; don't report any OWC!?? /Jan E LDC
	add2	soft_tx_errors,1

; Collison Counter
	
tx_err_03:
	test ah,ENTSR_COLL	; Enumerated Collisions?
	jz	tx_err_done		; No, return

	setport EN0_NCR		; point at the collision counter
	pause_
	in	al,dx		; get the count
	and	al,0fh		; clear the unused bits
	xor	ah,ah		; clear the high byte
	add2	soft_tx_collisions,ax

tx_err_done:
	mkle LE_TX_ERR, ax, 0, 0
  	ret


	public	set_address
set_address:
	assume	ds:code
;enter with my_address,si -> Ethernet address, CX = length of address.
;exit with nc if okay, or cy, dh=error if any errors.
	loadport
	setport	EN_CCMD		; Chip command register
	pushf
	cli			; Protect from irq changing page bits
	mov al,	ENC_NODMA+ENC_PAGE1	;+ENC_STOP
	out dx,	al		; Switch to page one for writing eaddr
	pause_
	setport	EN1_PHYS	; Where it goes in 8390
set_8390_1:
	lodsb
	out	dx,al
	pause_
	inc	dx
	loop	set_8390_1
	loadport
	setport	EN_CCMD		; Chip command register
	mov al,	ENC_NODMA+ENC_PAGE0	;+ENC_STOP
	out dx,	al		; Restore to page zero
	pause_
	popf
	clc
	ret

; Routines to set address filtering modes in the DS8390
rcv_mode_1:     ; Turn off receiver
	mov al,	ENRXCR_MON      ; Set to monitor for counts but accept none
	jmp short rcv_mode_set
rcv_mode_2:     ; Receive only packets to this interface
	mov al, 0               ; Set for only our packets
	jmp short rcv_mode_set
rcv_mode_3:     ; Mode 2 plus broadcast packets (This is the default)
	mov al,	ENRXCR_BCST     ; Set four ours plus broadcasts
	jmp short rcv_mode_set
rcv_mode_4:     ; Mode 3 plus selected multicast packets
	mov al,	ENRXCR_BCST+ENRXCR_MULTI ; Ours, bcst, and filtered multicasts
	mov     mcast_all_flag,0	; need to do sw filter.
	jmp short rcv_mode_set
rcv_mode_5:     ; Mode 3 plus ALL multicast packets
	mov al,	ENRXCR_BCST+ENRXCR_MULTI ; Ours, bcst, and filtered multicasts
	mov     mcast_all_flag,1
	jmp short rcv_mode_set
rcv_mode_6:     ; Receive all packets (Promiscuous physical plus all multi)
	mov al,	ENRXCR_BCST+ENRXCR_MULTI+ENRXCR_PROMP
	mov     mcast_all_flag,1
rcv_mode_set:
	push    ax			; Hold mode until masks are right
	call    set_hw_multi		; Set the multicast mask bits in chip
	pop     ax
	loadport
	setport	EN0_RXCR		; Set receiver to selected mode
	pause_
	out dx,	al
	mov     rxcr_bits,al		; Save a copy of what we set it to
	ret


; Set the multicast filter mask bits in case promiscuous rcv wanted
set_hw_multi:
	push    cs
	pop     ds
	assume	ds:code
	loadport
	setport	EN_CCMD		; Chip command register
	pause_
	mov cx,	8		; Eight bytes of multicast filter
	mov si, offset mcast_list_bits  ; Where bits are, if not all ones
	cli			; Protect from irq changing page bits
	mov al,	ENC_NODMA+ENC_PAGE1+ENC_STOP
	out dx,	al		; Switch to page one for writing eaddr
	setport	EN1_MULT	; Where it goes in 8390
	pause_
	mov al, mcast_all_flag  ; Want all ones or just selected bits?
	or al,  al
	je      set_mcast_2     ; Just selected ones
	mov al,	0ffh		; Ones for filter
set_mcast_all:
	out dx,	al		; Write a mask byte
	inc	dl		; Step to next one
	loop	set_mcast_all	; ..
	jmp short set_mcast_x

set_mcast_2:
	lodsb                   ; Get a byte of mask bits
	out dx,	al		; Write a mask byte
	inc	dl		; Step to next I/O register
	loop	set_mcast_2 	; ..
set_mcast_x:
	loadport
	setport	EN_CCMD		; Chip command register
	pause_
	mov al,	ENC_NODMA+ENC_PAGE0+ENC_START
	out dx,	al		; Restore to page zero
	ret


	public	reset_board
reset_board:
	assume ds:nothing
	reset_8390
	setport	EN_CCMD		; Chip command reg
	pause_
	mov al,	ENC_STOP+ENC_NODMA
	out dx,	al		; Stop the DS8390

; Wait 1.6ms for the NIC to stop transmitting or receiving a packet. National
; says monitoring the ISR RST bit is not reliable, so a wait of the maximum
; packet time (1.2ms) plus some padding is required.

	longpause
	ret

	public	terminate
terminate:
	terminate_board
	ret

	public	reset_interface
reset_interface:
	assume ds:code
	call	reset_board
	loadport		; Base of I/O regs
	setport	EN0_ISR		; Interrupt status reg
	pause_
	mov al,	0ffh		; Clear all pending interrupts
	out dx,	al		; ..
	setport	EN0_IMR		; Interrupt mask reg
	pause_
	xor al,	al		; Turn off all enables
	out dx,	al		; ..
	ret

; Linkages to non-device-specific routines
;called when we want to determine what to do with a received packet.
;enter with cx = packet length, es:di -> packet type, dl = packet class.
;It returns with es:di = 0 if don't want this type or if no buffer available.
	extrn	recv_find: near

;called after we have copied the packet into the buffer.
;enter with ds:si ->the packet, cx = length of the packet.
	extrn	recv_copy: near

;call this routine to schedule a subroutine that gets run after the
;recv_isr.  This is done by stuffing routine's address in place
;of the recv_isr iret's address.  This routine should push the flags when it
;is entered, and should jump to recv_exiting_exit to leave.
;enter with ax = address of routine to run.
	extrn	schedule_exiting: near

;recv_exiting jumps here to exit, after pushing the flags.
	extrn	recv_exiting_exit: near

	extrn	count_in_err: near
	extrn	count_out_err: near

	public	recv
recv:
;called from the recv isr.  All registers have been saved, and ds=cs.
;Actually, not just receive, but all interrupts come here.
;Upon exit, the interrupt will be acknowledged.
;ne1000 and ne2000 routines are identical to this point (except that ne2000
;  masks off interrupts).
	assume	ds:code
	mkle LE_RECV_E, 0, 0, 0

check_isr:			; Was there an interrupt from this card?
	loadport		; Point at card's I/O port base
	setport EN0_IMR		; point at interrupt masks
	pause_			; switch off, this way we can
	mov	al,0		; leave the chip running.
	out	dx,al		; no interrupts please.
	setport	EN0_ISR		; Point at interrupt status register
	pause_
	in al,	dx		; Get pending interrupts
	and al,	ENISR_ALL	; Any?
	jnz	isr_test_overrun
	mkle LE_RECV_X, 0, 0, 0
	jmp	interrupt_done	; Go if none

;
; Revised receive overrun code which corresponds to the National DP8390
; Datasheet Addendum, June 1990.
;
; - gft - 910604
;

; Test for receive overrun in value from NIC ISR register

isr_test_overrun:
	test al,ENISR_OVER	; Was there an overrun?
	jnz	recv_overrun	; Go if so.
	jmp	recv_no_overrun	; Go if not.

recv_overrun:
  ifdef board_features
	test	board_features, BF_NIC_690
	jz	recv_overrun_2
	mov	is_overrun_690, 1
	jmp	recv_no_overrun

recv_overrun_2:
  endif

; Count these things

	add2	soft_rx_overruns,1

; and log them
	SHOW_EVENT	'd'
	mkle LE_RX_OVR_E, 0, 0, 0

⌨️ 快捷键说明

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