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

📄 8390.asm

📁 RTL8019 Plug-And-Play Packet Driver.
💻 ASM
📖 第 1 页 / 共 4 页
字号:
	dec al
rcv_nwrap4:
	loadport		; Point at the Boundary Reg again
 	setport	EN0_BOUNDARY	; ..
	pause_
	out dx,	al		; Set new boundary
; This is real bizarre. The NIC DP8390 Datasheet Addendum, June 1990, states
; that:
;
;    In heavily loaded networks which cause overflows of the Recieve Buffer
;    Ring, the NIC may disable the local DMA and suspend further receptions
;    even if the Boundary register is advanced beyond the Current register.
;    In the event that the Network Interface Controller (DP8390 NIC) should
;    encounter a receiver buffer overflow, it is necessary to implement the
;    following routine. A receive buffer overflow is indicated by the NIC's
;    assertion of the overflow bit (OVW) in the interrupt status register
;    (ISR).
;
;    If this routine is not adhered to, the NIC may act in an unpredictable
;    manner. It should also be noted that it is not permissible to service
;    an overflow interrupt by continuing to empty packets from the receive
;    buffer without implementing the prescribed overflow routine.
;    ...
;
; The overflow routine is the one implemented at recv_overrun.
;
; The funny thing is that the way this code is written, in a heavily loaded
; network, you could NEVER NOTICE THAT AN OVERRUN OCCURED. If the NIC does
; NOT suspend further receptions even though the Boundary register is advanced
; (like is says the NIC MAY do above), you will simply receive each frame,
; advance the boundary pointer (allowing the NIC to receive another frame),
; and jump from here back to recv_frame to read the next packet, NEVER CHECKING
; ISR for OVW. If the NIC NEVER stops, and the network is heavily loaded
; enough you could go round and round forever.
;
; So what's the problem you ask? If the NIC DOES stop receiving, you will
; process every packet in the ring before you notice that there is an overrun!
; Instead of dropping a few packets here and a few packets there you will drop
; large blocks of packets because you have taken the time to empty the ring
; completely before turning the NIC back on.
;
; The solution is to check here for an OVW after each pass and jump to
; recv_overrun if required.
;
;	setport	EN0_ISR		; Point at interrupt status register
;	pause_
;	in al,	dx		; Get pending interrupts
;ifdef debug
;	mov log_isr,al
;endif
;	test al,ENISR_OVER	; Was there an overrun?
;	jz	recv_frame_loop	; Go if not.
;	jmp	recv_overrun	; Go if so.
;recv_frame_loop:
;
; But that's a performance hit and it may not be necessaary. I have not yet
; been able to tell if the NIC is stopping (like National says it MAY do), or 
; if it keeps on receiving as soon as the boundary pointer is advanced. It 
; SEEMS to keep on working fine.
;
; Therefore I'm not going to put that overrun check in here and I'll
; live with this routine as long as it seems to be working fine.
;
; One more thought, if this code is implemented, it shoud be moved to the
; beginning of recv_frame before the RX interrupts are cleared. Recv_overrun
; only receives ONE packet and jumps back to check_isr, and if you don't move 
; this routine you could exit with packets in the ring and not know it because
; you cleared the interrupt bits.
;
;  - gft - 910606
;
; New thoughts and fixes - gft - 910611
; 
; A compromise fix which also MINIMIZES NIC accesses is to remember the
; contents of the current page register after entry to recv_frame and then
; remove from the ring only those packets received at that point. Then go
; back to check_isr and catch any new packets or receive overruns. See comments
; at the start of recv_frame.
;
	jmp	recv_frame	; See if any more frames

;
; The next bit of code following recv_frame_break: is superfluous. 
;   1. recv_frame_break: is not public, it can't be reached from outside.
;   2. a grep of all the Clarkson packet driver collection reveals only
;      one jump to recv_frame_break.
;   3. Just prior to that jump, the command register was set to 
;      ENC_NODMA+ENC_PAGE0+ENC_START, followed by a setport to EN0_BOUNDARY
;      and a fetch of the boundry register.
; Therefore I am commenting out the following bit of code, and changing the
; jmp recv_frame_break (formerly je recv_frame_break) to a jmp check_isr.
; - gft - 910531
;
;recv_frame_break:
;	loadport		; Point at Command register
; 	setport	EN_CCMD		; ..
;	pause_
;	mov al,	ENC_NODMA+ENC_PAGE0+ENC_START
;	out	dx,al
;	jmp	check_isr	; See if any other interrupts pending
;

recv_no_frame:				; Handle transmit flags.
	test al,ENISR_TX+ENISR_TX_ERR	; Frame transmitted?
	jnz	isr_tx		; Go if so.
	jmp	isr_no_tx	; Go if not.
isr_tx:
	mov ah,	al		; Hold interrupt status bits
	loadport		; Point at Transmit Status Reg
 	setport	EN0_TSR		; ..
	pause_
	in al,	dx		; ..

; New TX interrupt acknowledge code follows:

	mov	ah,al		; save the TSR state

	setport EN0_ISR		; Point at the interrupt status register
	pause_

; Since transmissions happen synchronously to this driver (even if as_send_pkt
; is implemented, their still synchronous to the driver), only one of the two
; possible TX interrupts may occur at any one time. Therefore it is OK to
; zap both TX and TX_ERR bits in the interrupt status register here.

	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
	jz	isr_tx_done	; No usefull errors, skip. See the called
				; routine for explanation of the selection
				; of TSR bits for consideration as errors.
	call	count_tx_err

isr_tx_done:
; If TX queue and/or TX shared memory ring buffer were being
; used, logic to step through them would go here.  However,
; in this version, we just clear the flags for background to notice.

 	jmp	check_isr	; See if any other interrupts on

isr_no_tx:
; Now check to see if any counters are getting full
	test al,ENISR_COUNTERS	; Interrupt to handle counters?
	jnz	isr_stat	; Go if so.
	jmp	isr_no_stat	; Go if not.
isr_stat:
; We have to read the counters to clear them and to clear the interrupt.
; Version 1 of the PC/FTP driver spec doesn't give us
; anything useful to do with the data, though.
; Fix this up for V2 one of these days.
	loadport		; Point at first counter
 	setport	EN0_COUNTER0	; ..
	pause_
	in al,	dx		; Read the count, ignore it.
	setport	EN0_COUNTER1
	pause_
	in al,	dx		; Read the count, ignore it.
	setport	EN0_COUNTER2
	pause_
	in al,	dx		; Read the count, ignore it.
	setport	EN0_ISR		; Clear the statistics completion flag
	pause_
	mov al,	ENISR_COUNTERS	; ..
	out dx,	al		; ..
isr_no_stat:
 	jmp	check_isr	; Anything else to do?

interrupt_done:
	loadport
	setport	EN0_IMR		; Tell card it can cause these interrupts
	pause_
	mov al,	ENISR_ALL
	out dx,	al
	ret

; Do the work of copying out a receive frame.
; Called with bl/ the page number of the frame header in shared memory

	public	rcv_frm
rcv_frm:
	mkle LE_RCVFRM_E, 0, 0, 0

; Set cx to length of this frame.
	mov ch,	rcv_hdr+EN_RBUF_SIZE_HI	; Extract size of frame
	mov cl,	rcv_hdr+EN_RBUF_SIZE_LO	; Extract size of frame
	sub cx,	EN_RBUF_NHDR		; Less the header stuff
; Set es:di to point to Ethernet type field.
	mov di,	offset rcv_hdr+EN_RBUF_NHDR+EADDR_LEN+EADDR_LEN
	push	bx			; save page.
	push	cx			; Save frame size
	push	es
	mov ax,	cs			; Set ds = code
	mov ds,	ax
	mov es,ax
	assume	ds:code

	mov	dl, BLUEBOOK		;assume bluebook Ethernet.
	mov	ax, es:[di]
	xchg	ah, al
	cmp 	ax, 1500
	ja	BlueBookPacket
	inc	di			;set di to 802.2 header
	inc	di
	mov	dl, IEEE8023
BlueBookPacket:

	call	recv_find		; See if type and size are wanted
	pop	ds			; RX page pointer in ds now
	assume	ds:nothing
	pop	cx
	pop	bx
	cld			; Copies below are forward, please
	mov ax,	es		; Did recv_find give us a null pointer?
	or ax,	di		; ..
	je	rcv_no_copy	; If null, don't copy the data

	push	cx		; We will want the count and pointer
	push	es		;  to hand to client after copying,
	push	di		;  so save them at this point
	mov	ah,bl		; set ax to page to start from
	mov	al,EN_RBUF_NHDR	; skip the header stuff
	call	block_input
;
; Added defer upcall code here in support of new ring overrun code.
; If defer_upcall is set, don't call recv_copy, just save si,ds,cx
; and the receive ring overrun code will call recv_copy later.
;  - gft - 910604
;
	cmp	defer_upcall,0	; is deferral required?
	jz	rcv_copy_ok	; No, finish of the copy.
	pop	ax		; Yes, save the parameters for recv_copy
	mov	defer_si,ax	; to use later.
	pop	ax
	mov	defer_ds,ax
	pop	ax
	mov	defer_cx,ax
	jmp	rcv_copy_deferred

rcv_copy_ok:
	pop	si		; Recover pointer to destination
	pop	ds		; Tell client it's his source
	pop	cx		; And it's this long
	assume	ds:nothing
	call	recv_copy	; Give it to him
rcv_no_copy:
	movseg	ds,cs
	assume	ds:code
	mov	defer_upcall,0	; clear the defer upcall flag - gft - 910604
rcv_copy_deferred:
	mkle LE_RCVFRM_X, 0, 0, 0
	ret			; That's it for rcv_frm

	include	multicrc.asm
	include	timeout.asm

	public	timer_isr
timer_isr:
;if the first instruction is an iret, then the timer is not hooked
	iret

;any code after this will not be kept after initialization. Buffers
;used by the program, if any, are allocated from the memory between
;end_resident and end_free_mem.
	public end_resident,end_free_mem
end_resident	label	byte
end_free_mem	label	byte

;standard EN0_DCFG contents:
endcfg	db	048h			; Set burst mode, 8 deep FIFO

; Called once to initialize the card

	public	etopen
etopen:				; Initialize interface

;Step 1. Reset and stop the 8390.

	call	reset_board

;Step 2. Init the Data Config Reg.

	loadport
	mov	al,endcfg
	setport	EN0_DCFG
	pause_
	out	dx,al

;Step 2a.  Config the Command register to page 0.
	loadport
	mov	al, ENC_PAGE0 + ENC_NODMA + ENC_STOP
	setport	EN_CCMD
	pause_
	out	dx,al

;Step 3. Clear Remote Byte Count Regs.

	mov	al, 0
	setport	EN0_RCNTLO
	pause_
	out	dx,al
	setport	EN0_RCNTHI
	pause_
	out	dx,al

;Step 4. Set receiver to monitor mode

	mov	al, ENRXCR_MON
	setport	EN0_RXCR
	pause_
	out	dx,al

;Step 5. Place NIC into Loopback Mode 1.

	mov	al,ENTXCR_LOOP
	setport	EN0_TXCR
	pause_
	out	dx,al

;Step 6. Do anything special that the card needs.  Read the Ethernet address
;into rom_address.

	call	init_card		;init the card as needed.
	jnc	etopen_1		;go if it worked.
	ret
etopen_1:

;Step 7. Re-init endcfg in case they put it into word mode.

	loadport
	mov	al,endcfg
	setport	EN0_DCFG
	pause_
	out	dx,al

;Step 8. Init EN0_STARTPG to same value as EN0_BOUNDARY

	mov	al,SM_RSTART_PG
	setport	EN0_STARTPG
	pause_
	out	dx,al
  if 1	;Paul Kranenburg suggests that this should be set to zero.
	mov	al,SM_RSTART_PG
  else
	mov	al,sm_rstop_ptr
	dec	al
  endif
	setport	EN0_BOUNDARY
	pause_
	out	dx,al
	mov	al,sm_rstop_ptr
	setport	EN0_STOPPG
	pause_
	out	dx,al

;Step 9. Write 1's to all bits of EN0_ISR to clear pending interrupts.

	mov	al, 0ffh
	setport	EN0_ISR
	pause_
	out	dx,al

;Step 10. Init EN0_IMR as desired.

	mov	al, ENISR_ALL
	setport	EN0_IMR
	pause_
	out	dx,al

;Step 11. Init the Ethernet address and multicast filters.

	mov	si,offset rom_address
	mov	cx,EADDR_LEN
	call	set_address	; Now set the address in the 8390 chip
	call	set_hw_multi  ; Put the right stuff into 8390's multicast masks

;Step 12. Program EN_CCMD for page 1.

	loadport
	mov	al, ENC_PAGE1 + ENC_NODMA + ENC_STOP
	setport	EN_CCMD
	pause_
	out	dx,al

;Step 13. Program the Current Page Register to same value as Boundary Pointer.

; THIS IS WRONG WRONG WRONG inspite of some self-contradicting National
; documentation. If the Current Page Register is initialized to the same
; value as the Boundary Pointer, the first ever packet received will be lost or
; trashed because the driver always expects packets to be received at Boundrary
; pointer PLUS ONE! 

	mov	al,SM_RSTART_PG
	inc	al		; To fix the bug! - gft - 910523
	setport	EN1_CURPAG
	pause_
	out	dx,al
	mov	save_curr,al	; added in conjunction with fixes above
				; - gft - 910611
	mov	next_packet, al ; initialize next_packet to the value in
				; current - gft - 910603

;Step 14. Program EN_CCMD back to page 0, and start it.

	mov	al, ENC_NODMA + ENC_START + ENC_PAGE0
	setport	EN_CCMD
	pause_
	out	dx,al

	mov	al, 0			;set transmitter mode to normal.
	setport	EN0_TXCR
	pause_
	out	dx,al

  if 0
	mov	al, ENRXCR_BCST
	setport	EN0_RXCR
	pause_
	out	dx,al
  endif

	call	set_recv_isr	; Put ourselves in interrupt chain

	mov	al, int_no		; Get board's interrupt vector
	add	al, 8
	cmp	al, 8+8			; Is it a slave 8259 interrupt?
	jb	set_int_num		; No.
	add	al, 70h - 8 - 8		; Map it to the real interrupt.
set_int_num:
	xor	ah, ah			; Clear high byte
	mov	int_num, ax		; Set parameter_list int num.

	clc				; Say no error
	ret				; Back to common code

⌨️ 快捷键说明

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