📄 8390.asm
字号:
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 + -