📄 ir.asm
字号:
get_status_again:
if CHIP EQ INTEL_82596
mov ax, scb_buff.scb_status
else
LOAD_PORT SCB_STATUS
in ax, dx
endif
and ax, SCB_STATUS_MASK
jz short check_receiver_status
mov temp_ru_status, ax ; Save for later
if CHIP EQ INTEL_82596
mov scb_buff.scb_command, ax ; ACK the interrupts
STALL
C_ATTENTION
STALL
else
out dx, ax ; ACK the interrupts
endif
test temp_ru_status, FR_ST_BIT ; A receive interrupt ?
jz short try_no_resources_int
to_scrn 2,0,'R'
if CHIP EQ INTEL_82557
mov timer_count, 0 ; Receever is not dead - clear watchdog
endif
call receive_int
cmp rbd_counter, GIANT / SIZE_ONE_DATA_BUFF ; Gone too far ?
ja short check_receiver_status ; Yes - restart
try_no_resources_int:
test temp_ru_status, RNR_ST_BIT ; An out of resources interrupt ?
jz short get_status_again
check_receiver_status:
call start_receive_unit ; This also handles out of resources
if CHIP EQ INTEL_82596
STALL
call clear_interrupt_latch
STALL
endif
to_scrn 2,0,'i'
ret
receive_int PROC NEAR
to_scrn 2,0,'{'
another_frame:
mov ax, cs
mov es, ax
mov bx, first_rfd ; bx => first RFD
test [bx].rfd_status, RFD_DONE_BIT ; Has RFD been used
jnz short rfd_used ; Yes - read frame data
to_scrn 2,0,'}'
ret ; No - exit
rfd_used: ; First find length of the frame
test [bx].rfd_status, RESOURCES_BIT
jz short enough_resources
call count_in_err
to_scrn 2,0,'B'
ret
enough_resources:
mov si, first_rbd ; si => buffer descriptor
xor dx, dx ; dx holds byte count
mov di, [si].rbd_voffset ; Save pointer to data
mov rbd_counter, 0 ; Guard against no EOF set
continue_count:
mov ax, [si].rbd_status ; Status and count word for RBD
test ax, EOF_BIT ; Last RBD for this frame
jne short got_count
valid_count:
add dx, SIZE_ONE_DATA_BUFF ; Add full buffer to count
mov si, WORD PTR [si].rbd_link ; Advance to next RBD
inc rbd_counter ; Should eventually find an EOF
cmp rbd_counter, GIANT / SIZE_ONE_DATA_BUFF ; Gone too far
jle continue_count ; Continue if not
call count_in_err
to_scrn 2,0,'*'
ret
got_count:
test ax, COUNT_VALID ; Is the count valid
jz ptrupdate ; No - exit with cleanup
and ax, 3FFFh ; Clear status bits in the count
add dx, ax ; Add partial buffer to count
; Did we receive our own broadcast?
add di, EADDR_LEN ; Point to the source address
mov ax, di ; Save pointer to received data
mov si, offset cgroup:my_address
mov cx, EADDR_LEN/2
repe cmpsw
jne short not_our_own ; Jump if not
to_scrn 23,79,'O'
inc received_ours ; Remember that we received it.
jmp ptrupdate ; Exit with cleanup
not_our_own:
mov di, ax ; Recover pointer to received data
add di, EADDR_LEN ; Now point to the type/length bytes
; Check to make sure that frame has been received with no errors.
; If errors are found then only return frame if in promiscuous mode.
; In promiscuous mode the frame status is assembled and placed in save_err.
mov save_err, 1 ; Set default value of no error
mov ax, [bx].rfd_status ; Get status of frame
test ax, RX_OK ; Check if received without errors
jnz short no_frame_errs ; Jump if ok
call count_in_err
to_scrn 23,72,'E'
cmp curr_rcv_mode, MATCH_EVERYTHING ; Currently in promiscuous mode ?
jne short cleanup_exit ; No - discard bad frame
; Find the error bits in the status of the current frame and save in save_err
mov ch, 0
test ax, SHORT_FRAME_BIT
je short RX_not_short
or ch, 02h
RX_not_short:
test ax, CRC_BIT
je short RX_crc_ok
or ch, 04h
RX_crc_ok:
test ax, ALIGN_BIT
je short RX_align_ok
or ch, 08h
RX_align_ok:
test ax, OVER_RUN_BIT
je short RX_no_over_run
or ch, 10h
RX_no_over_run:
mov save_err, ch
cleanup_exit:
jmp short ptrupdate ; Exit with cleanup
no_frame_errs:
to_scrn 2,0,'R'
mov cx, dx ; Get length of packet in cx
push bx
push cx
mov dl, BLUEBOOK ;assume bluebook Ethernet.
mov ax, [di] ; Get the packet type
xchg ah, al
cmp ax, 1500
ja short BlueBookPacket
inc di ;set di to 802.2 header
inc di
mov dl, IEEE8023
BlueBookPacket:
mov dh, save_err ; Get the error status into dh for Intel
call recv_find ; See if type and size are wanted
pop cx
pop bx
mov ax, es ; Did recv_find give us a null pointer?
or ax, di ; ..
je short ptrupdate ; 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 si, first_rbd ; si => buffer descriptor
copybuf:
mov dx, si ; Save a copy of the RBD
mov cx, [si].rbd_status ; Get count word for RBD
test cx, EOF_BIT ; Last RBD for this frame
jne short use_actual_count
mov cx, SIZE_ONE_DATA_BUFF ; Add full buffer to count
use_actual_count:
and ch, 3Fh ; Clear any status bits in count
mov si, [si].rbd_voffset ; Get a pointer to data buffer
; Memory copy routine
mov ax, cx ; Save byte count
sar cx, 1 ; Convert to a DWORD count
sar cx, 1 ; Convert to a DWORD count
rep movsd ; Copy DWORDS
mov cx, ax ; Recover byte count
and cx, 0003h ; Obtain count mod 4
jz short no_more_1
rep movsb ; Copy remaining bytes
no_more_1:
mov si, dx ; Recover copy of the RBD
test [si].rbd_status, EOF_BIT ; Check EOF bit
mov si, WORD PTR [si].rbd_link ; Advance to the next RBD
jz copybuf ; If not EOF the contine the copy
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
assume ds:cgroup
mov ax, cs ; Recover our DS
mov ds, ax
ptrupdate:
to_scrn 2,0,'-'
; First update the RBD list
mov si, first_rbd ; si => buffer descriptor
do_next_rbd:
test [si].rbd_status, EOF_BIT ; Check EOF bit
mov [si].rbd_status, 0 ; Clear status word
jnz short do_last_rbd
cmp si, last_rbd ; At the end of list ?
jz short do_last_rbd ; Jump if so
mov si, WORD PTR [si].rbd_link ; Get to the next rbd
jmp do_next_rbd
do_last_rbd:
mov di, last_rbd ; Current end of RBD list
mov last_rbd, si ; Update with the new end of RBD list
mov [si].rbd_size, EL_BIT+SIZE_ONE_DATA_BUFF ; Mark end of the list
mov [di].rbd_size, SIZE_ONE_DATA_BUFF ; Remove old end-of-list
mov ax, WORD PTR [si].rbd_link ; Get to the next rbd
mov first_rbd, ax ; Store as the first rbd for next time
; Now update the RFD list
mov di, last_rfd ; Current end of RFD list
mov bx, first_rfd ; bx => first RFD
mov last_rfd, bx ; Update with the new end of RFD list
mov [bx].rfd_eol, EL_BIT+FLEXIBLE_MODE ; Set new end of RFD list
mov [bx].rfd_status, 0 ; Clear status word for frame
mov [di].rfd_eol, FLEXIBLE_MODE ; Remove old end of RFD list
mov si, WORD PTR [bx].rfd_link ; Get address of next RFD
mov first_rfd, si ; Store first RFD for next time
jmp another_frame
receive_int ENDP
if CHIP EQ INTEL_82596
do_tdr PROC NEAR
; enter with es:di pointing to time int
push es
push di
mov ax, cs ; Get correct segment into es
mov es, ax
mov cx, 8 ; Get buffer will wait for 27ms each call
try_for_tdr_buffer:
call get_buffer
jnc short got_tdr_buffer
loop try_for_tdr_buffer
tdr_problem_exit:
stc
pop di
pop es
ret
got_tdr_buffer:
mov bx, di ; Save the start of the buffer
mov eax, (EL_BIT + S_BIT + TDR_CMD)*10000h
stosd ; Store the action command word + status word
mov ax, -1
stosw ; Write the address of the next command
xor ax, ax
stosw ; Clear the tdr result
mov di, bx ; Recover the start of the buffer
call issue_cmd
mov ax, 40h
call set_timeout
wait_tdr_to_complete:
test cs:[di], word ptr C_DONE_BIT
jnz short tdr_done
call do_timeout ; Any more time left ?
jnz short wait_tdr_to_complete
jmp short tdr_problem_exit
tdr_done:
pop di
pop es
test ax, LNK_OK
jz short tdr_bad_cable
clc
ret
tdr_bad_cable:
push ax
and ax, TDR_TIME
stosw ; store time
pop ax
mov cl, 12
shr ax, cl
and ax, 7
mov dh, al
stc
ret
do_tdr ENDP
endif
public timer_isr
timer_isr:
;if the first instruction is an iret, then the timer is not hooked
if CHIP EQ INTEL_82596
iret
else
; 82557 has a receiver lockup problem
; requires a multicast setup command to 'unlock' it
; issued every 2 seconds if necessary
inc cs:timer_count
cmp cs:timer_count, 25h
jb short no_receiver_wakeup
PUSH_16_32 ax ; save lots of registers
PUSH_16_32 bx
PUSH_16_32 cx
PUSH_16_32 dx
PUSH_16_32 si
PUSH_16_32 di
PUSH_16_32 bp
push ds
push es
cld
assume ds:cgroup, es:cgroup
mov ax, cs
mov ds, ax
mov es, ax
mov timer_count, 0
mov si, offset cgroup:our_multicast_list
mov ax, MAX_MULTICAST ; Max addresses in multicast data
mov cx, MAX_MULTICAST * EADDR_LEN ; Max size of multicast data
call set_multicast_list
to_scrn 2,0,'!'
assume ds:nothing, es:nothing
pop es ; restore lots of registers
pop ds
POP_16_32 bp
POP_16_32 di
POP_16_32 si
POP_16_32 dx
POP_16_32 cx
POP_16_32 bx
POP_16_32 ax
no_receiver_wakeup:
jmp cs:their_timer
endif
public enable_board_int
enable_board_int PROC NEAR
if CHIP EQ INTEL_82596
LOAD_PORT PLXP_INTERRUPT_CONTROL
mov al, LATCHED_INTWRITE_BIT
out dx, al
else
LOAD_PORT SCB_CMD_INT
xor al, al
out dx, al
endif
ret
enable_board_int ENDP
if CHIP EQ INTEL_82557
public disable_board_int
disable_board_int PROC NEAR
LOAD_PORT SCB_CMD_INT
mov al, MASK_INT_BIT
out dx, al
ret
disable_board_int ENDP
endif
if CHIP EQ INTEL_82596
public clear_interrupt_latch
clear_interrupt_latch PROC NEAR
LOAD_PORT PLXP_INTERRUPT_CONTROL ; Clear int latch
in al, dx
or al, BIT_4
out dx, al
ret
clear_interrupt_latch ENDP
endif
if CHIP EQ INTEL_82557
our_multicast_list db (MAX_MULTICAST * EADDR_LEN) dup (81h)
endif
if CHIP EQ INTEL_82596
ALIGN 16
public scb_buff
scb_buff db size SCB_STRUC dup (0)
endif
public first_rfd, last_rfd, first_rbd, last_rbd
first_rfd dw ?
last_rfd dw ?
first_rbd dw ?
last_rbd dw ?
public start_rfd, start_rbd, start_rx_buff
align 4
start_rfd db RFD_COUNT * (size RFD_STRUCT) dup (?)
align 4
start_rbd db RBD_COUNT * (size RBD_STRUCT) dup (?)
align 4
start_rx_buff db RBD_COUNT * SIZE_ONE_DATA_BUFF dup (?)
code ends
_text segment para public 'code'
_text ends
init segment para public 'code'
init ends
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -