home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-01-23 | 39.1 KB | 1,133 lines |
- ;;******************************************************************************
- ;; 3c507.inc 3c507.inc
- ;;******************************************************************************
- ;;
- ;; Copyright (C) 1991 Vance Morrison
- ;;
- ;;
- ;; Permission to view, compile, and modify for LOCAL (intra-organization)
- ;; USE ONLY is hereby granted, provided that this copyright and permission
- ;; notice appear on all copies. Any other use by permission only.
- ;;
- ;; Vance Morrison makes no representations about the suitability
- ;; of this software for any purpose. It is provided "as is" without expressed
- ;; or implied warranty. See the copywrite notice file for complete details.
- ;;
- ;;******************************************************************************
- ;; 3c507.inc holds the interface routines for the 3com etherlink 16 card.
- ;;
- ;; The functions provided by this file are
- ;;
- ;; C507_DECLARE name, io_address, seg, len, promiscuous
- ;; C507_DEFINE_out_AX name, fail
- ;; C507_IF_R_ACCESS_out_BX_CX_ES name, no_packet
- ;; C507_IF_R_CONT_in_BX_CX_ES_const_BX_CX_DX_BP_SI_DI_ES name, ok
- ;; C507_IF_R_FREE_const_BX_CX_BP_SI_DI_ES name
- ;; C507_IF_W_ACCESS_in_CX_out_DI_ES_const_BX_CX_BP name, no_buffer
- ;; C507_IF_W_WRITE_in_CX_const_BX_BP_ES name
- ;; C507_IF_SET_ADDRESS_in_SI_const_BX_CX_BP_DI_ES name
- ;; C507_IF_COPY_in_CX_SI_DI_ES_out_SI_DI_const_BX_BP_ES name
- ;;
- ;; Variables set by this module
- ;;
- ;; c507_&name&_declared ;; one if this interface exists
- ;; if_&name&_address ;; the hardware address
- ;; if_&name&_mtu ;; the maximum trans unit
- ;;
- ;;******************************************************************************
- ;; data storage needed by this module
-
- c507_data STRUC
- ;; these values are set at init only
- c507_base dw 0 ;; the offset value for shared memory
- c507_end_buff dw 0 ;; end of buffer block for packet data
- c507_start_buff dw 0 ;; begining of buffer block for packet data
-
- ;; set at init, and updated at FREE
- c507_last_rbd dw 0 ;; points to buff desc with the EOL marker
- c507_last_rfd dw 0 ;; points to frame desc with the EOL marker
-
- ;; set at R_ACCESS used at FREE
- c507_last_frame_rbd dw 0 ;; last buff descriptor in current frame
- c507_cur_frame dw 0 ;; pointer to current frame
-
- c507_cur_tcb dw 0 ;; current transmit command buffer
- c507_data ENDS
-
-
- ;;******************************************************************************
- ;; C507_DECLARE name, io_address, seg, len, promiscuous
- ;; declares that there is a 3c507 ethernet card at 'io_address'. The
- ;; shared memory starts a the SEGMENT 'seg' and has length 'len'.
- ;; if 'promiscuous' is non-blank and non-zero then every packet on
- ;; the ethernet is returned.
- ;;
- c507_first = 0 ;; the first 3c507 card.
-
- C507_DECLARE MACRO name, io_address, seg, len, promiscuous
- .errb <seg>
- .errb <len>
-
- .DATA
- c507_&name&_declared = 1
- c507_&name&_io = io_address
- c507_&name&_seg = seg
- c507_&name&_len = len
-
- c507_&name&_promiscuous = 0
- ifnb <promiscuous>
- c507_&name&_promiscuous = 0&promiscuous
- endif
-
- if (name le c507_first) or (c507_first eq 0)
- c507_first = name
- endif
-
- if_&name&_mtu = 1514
-
- global c507_&name&_data:c507_data
- global if_&name&_address:word
-
- .CODE
- global c507_&name&_real_define:near
- ENDM
-
-
- ;;******************************************************************************
- ;; IF_DEFINE name
- ;; sets asside memory an name object and initializes it. This
- ;; routine is a no-op if 'name' was not declared
- ;; Note that if multiple 3C507 cards are present, they must be
- ;; the smallest named card must be defined first (since this card
- ;; turns on all the cards). AX holds a failure code if the initialization
- ;; fails.
- ;;
- C507_DEFINE_out_AX MACRO name, fail
- ifdef c507_&name&_declared
- call c507_&name&_real_define
- or AX, AX
- jnz fail
- endif
- ENDM
-
- C507_REAL_DEFINE MACRO name
- local ret_code, rfd_loop, found_rfd, rbd_loop, found_rbd
- .errb <name>
-
- ifdef c507_&name&_declared
- .DATA
- if_&name&_address DW 3 dup (0)
- c507_&name&_data c507_data <>
-
- .CODE
- c507_&name&_real_define:
-
- ;; put all card in run state (only done for first card)
- if name eq c507_first
- xor AX, AX
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES C507_ID_PORT, 0
- C507_SEND_ID_const_BX_BP_SI_DI_ES C507_ID_PORT
- xor AX, AX
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES C507_ID_PORT, 0
- endif
-
- ;; get the ethernet address
- mov SI, offset if_&name&_address
- C507_GET_ADDRESS_in_SI_const_BX_BP_DI_ES c507_&name&_io
-
- C507_INIT_SETUP_out_ES c507_&name&_io, c507_&name&_seg, c507_&name&_len, if_&name&_address, c507_&name&_promiscuous, ret_code
- mov c507_&name&_data.c507_base, ES
-
- ;; initialize my state variables
- mov SI, ES:[SCB+scb_rframes]
- mov c507_&name&_data.c507_cur_frame, SI
-
- mov DI, ES:[SI+rfd_rbd] ;; DI points to the first buffer descriptor, we
- ;; assume that this rbd points to the begining
- ;; of the large block of memory
- mov DX, ES:[DI+rbd_buff.offs]
- mov c507_&name&_data.c507_start_buff, DX
-
- ;; find the last element of the Buffer list
- rbd_loop:
- test ES:[DI+rbd_len], RBD_LEN_EOL
- jnz found_rbd
- mov DI, ES:[DI+rbd_next]
- jmp rbd_loop
- found_rbd:
- mov c507_&name&_data.c507_last_rbd, DI
-
- mov AX, ES:[DI+rbd_len] ;; DI points to the last buffer descriptor. we
- ;; assume that this rbd points to the end of the
- ;; large block of memory.
- and AX, RBD_LEN_MSK
- mov DX, ES:[DI+rbd_buff.offs]
- add DX, AX
- mov c507_&name&_data.c507_end_buff, DX
-
- ;; find the last element of the Frame list
- mov DI, ES:[SCB+scb_rframes]
- rfd_loop:
- test ES:[DI+rfd_cmd], RFD_CMD_EOL
- jnz found_rfd
- mov DI, ES:[DI+rfd_next]
- jmp rfd_loop
- found_rfd:
- mov c507_&name&_data.c507_last_rfd, DI
-
- mov c507_&name&_data.c507_cur_tcb, CU_TCMD1
-
- xor AX, AX
- ret_code:
- ret
-
- endif
- ENDM
-
-
- ;;******************************************************************************
- ;; IF_R_ACCESS_out_BX_ES name, no_packet
- ;; IF_R_ACCESS waits for the next packet to come from the the board
- ;; associated with 'name' and returns a pointer to the begining of
- ;; an ethernet packet in BX:ES. CX holds the length of the packet
- ;; R_ACCESS jumps to 'no_packet' if there are no packets waiting to
- ;; be read in
- ;;
- C507_IF_R_ACCESS_out_BX_CX_ES MACRO name, no_packet
- local look_packet, found_packet, len_loop, last_buff
- .errb <no_packet>
-
- mov ES, c507_&name&_data.c507_base
- mov SI, c507_&name&_data.c507_cur_frame
-
-
- look_packet:
- mov AX, ES:[SI+rfd_status]
- test AX, RFD_STAT_DONE
- jz no_packet
-
- test AX, RFD_STAT_OK
- jnz found_packet
- mov SI, ES:[SI+rfd_next]
- jmp look_packet
- found_packet:
-
- mov c507_&name&_data.c507_cur_frame, SI
- mov SI, ES:[SI+rfd_rbd]
- mov BX, ES:[SI+rbd_buff.offs]
-
- ;; compute the length of the packet, as well as if it wrapped or not
- xor CX, CX
- len_loop:
- mov AX, ES:[SI+rbd_used_len]
- test AX, RBD_USED_LEN_EOF
- jnz last_buff
- and AX, RBD_USED_LEN_MSK
- add CX, AX
- mov SI, ES:[SI+rbd_next]
- jmp len_loop
- last_buff:
- and AX, RBD_USED_LEN_MSK
- add CX, AX
- mov c507_&name&_data.c507_last_frame_rbd, SI
- ENDM
-
-
- ;;******************************************************************************
- ;; IF_R_FREE_const_BX_CX_BP_SI_DI_ES name
- ;; After the client is through processing the packet returned by
- ;; IF_R_ACCESS, IF_R_FREE must be called to inform 'name' that the
- ;; memory that the packet was in can be reused for future packets.
- ;;
- C507_IF_R_FREE_const_BX_CX_BP_SI_DI_ES MACRO name
- local ok_rbd, do_restart, no_restart, look_first_ndone, found_restart
- .errb <name>
-
- mov DX, SI ;; save SI
- mov AX, ES
- xchg AX, c507_&name&_data.c507_base ;; load/save ES
- mov ES, AX
-
- mov SI, c507_&name&_data.c507_last_frame_rbd
- or ES:[SI+rbd_len], RBD_LEN_EOL
-
- mov SI, c507_&name&_data.c507_last_rbd
- and ES:[SI+rbd_len], (NOT RBD_LEN_EOL)
-
- mov SI, c507_&name&_data.c507_last_frame_rbd
- mov c507_&name&_data.c507_last_rbd, SI
-
- mov SI, c507_&name&_data.c507_cur_frame
- mov AX, SI
- mov ES:[SI+rfd_status], 0
- or ES:[SI+rfd_cmd], RFD_CMD_EOL
- mov SI, ES:[SI+rfd_next]
- mov c507_&name&_data.c507_cur_frame, SI
-
- mov SI, c507_&name&_data.c507_last_rfd
- mov ES:[SI+rfd_cmd], 0
-
- mov c507_&name&_data.c507_last_rfd, AX
-
- mov AX, ES:[SCB+scb_status] ;; is the reciever still recieving?
- and AX, SCB_STAT_RUS_MSK
- cmp AX, SCB_STAT_RUS_READY
- jz no_restart
- mov SI, c507_&name&_data.c507_cur_frame
- mov AX, 16 ;; only look forward 16 packets at most
- look_first_ndone:
- test ES:[SI+rfd_status], RFD_STAT_DONE
- jz found_restart
-
- mov SI, ES:[SI+rfd_next]
- dec AX
- jnz look_first_ndone
- found_restart:
- mov ES:[SCB+scb_rframes], SI
- mov ES:[SI+rfd_status], 0
- cmp word ptr ES:[SI+rfd_rbd], 0FFFFH
- jnz ok_rbd
- mov SI, c507_&name&_data.c507_last_rfd
- mov AX, ES:[SI+rfd_rbd]
- mov SI, ES:[SCB+scb_rframes]
- mov ES:[SI+rfd_rbd], AX
- ok_rbd:
-
- mov ES:[SCB+scb_cmd], SCB_RUC_START
- ;; signal the 82586
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES c507_&name&_io, C507_IO_ATTN
- no_restart:
-
- mov SI, DX ;; restore SI
- mov AX, ES
- xchg AX, c507_&name&_data.c507_base ;; restore ES
- mov ES, AX
- ENDM
-
-
- ;;******************************************************************************
- ;; C507_IF_R_CONT_in_BX_CX_ES name, ok
- ;; IF_R_CONT determines if the packet returned by R_READ in BX:ES
- ;; of length CX is continuous. If it is it jumps to 'ok' otherwise
- ;; it just returns
- ;;
- C507_IF_R_CONT_in_BX_CX_ES_const_BX_CX_DX_BP_SI_DI_ES MACRO name, ok
- .errb <ok>
-
- mov AX, BX
- add AX, CX
- cmp AX, c507_&name&_data.c507_end_buff
- jb ok
- ENDM
-
-
- ;;******************************************************************************
- ;; IF_W_ACCESS_in_CX_out_DI_ES name, no_buffer
- ;; IF_W_ACCESS returns a pointer to an output buffer for a packet. The
- ;; pointer is returned in DI:ES. If the ouptut buffer is busy, this
- ;; routine will jump to 'no_buffer'. The output buffer min(CX, 1536)
- ;; bytes long
- ;;
- C507_IF_W_ACCESS_in_CX_out_DI_ES_const_BX_CX_BP MACRO name, no_buffer
- local wait_busy, buffer_free, com_accepted, wait_com_accept, nocarry
- .errb <no_buffer>
-
- ;; we ignore CX and always return a buffer 1536 bytes long
-
- mov ES, c507_&name&_data.c507_base
- mov SI, c507_&name&_data.c507_cur_tcb
-
- cmp ES:[SI+cu_status], 0 ;; has the RU done ANYTHING with stat
- jnz com_accepted
- ;; it may be 0 if the CU hasn't even accepted the command
- ;; check for this and wait if necessary
- xor DX, DX ;; so we don't loop forever
- wait_com_accept:
- test ES:[SCB+scb_cmd], SCB_CMD_CUC_MSK
- jz com_accepted
- dec DX
- jnz wait_com_accept
- com_accepted:
-
- xor DX, DX ;; so we don't loop forever
- wait_busy:
- test ES:[SI+cu_status], CU_STAT_BUSY
- jz buffer_free
- dec DX
- jnz wait_busy
- buffer_free:
-
- mov SI, ES:[SI+cu_params+trans_tbd]
- mov DI, ES:[SI+tbd_buff.offs]
- ENDM
-
-
- ;;******************************************************************************
- ;; IF_W_WRITE_in_CX name
- ;; IF_W_WRITE actually signals the ethernet board to write a packet to
- ;; the ethernet. The packet is assumed to be in the buffer returned by
- ;; IF_W_ACCESS. CX is the length of the packet to send.
- ;;
- C507_IF_W_WRITE_in_CX_const_BX_BP_ES MACRO name
- local not_tcmd1, check_prev_com, no_prev_com, wait_busy, buffer_free
- .errb <name>
-
- mov DX, ES ;; save ES
- mov ES, c507_&name&_data.c507_base
- mov DI, c507_&name&_data.c507_cur_tcb
-
- ;; make any previous command has been recognized before
- ;; sending this next one.
- xor AX, AX
- check_prev_com:
- test ES:[SCB+scb_cmd], SCB_CMD_CUC_MSK
- jz no_prev_com
- dec AX
- jnz check_prev_com
- no_prev_com:
-
- xor AX, AX
- wait_busy:
- test ES:[DI+cu_status], CU_STAT_BUSY
- jz buffer_free
- dec AX
- jnz wait_busy
- buffer_free:
-
- mov ES:[DI+cu_status], 0
- mov ES:[DI+cu_cmd], CU_CMD_EOL+CU_CMD_TRANS ;; probably unnecessary
- mov ES:[DI+cu_params+trans_len], CX ;; probably unnecessary
- mov SI, ES:[DI+cu_params+trans_tbd]
- add CX, TBD_LEN_EOL
- mov ES:[SI+tbd_len], CX
-
- ;; send our transmit command
- mov SI, offset SCB
- mov ES:[SI+scb_status], 0
- mov ES:[SI+scb_cuc], DI
- mov ES:[SI+scb_cmd], SCB_CUC_START
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES c507_&name&_io, C507_IO_ATTN
-
- ;; update the tcb pointer to the 'other' command block
- mov AX, CU_TCMD1
- cmp AX, DI
- jnz not_tcmd1
- mov AX, CU_TCMD2
- not_tcmd1:
- mov c507_&name&_data.c507_cur_tcb, AX
-
- mov ES, DX ;; restore ES
- ENDM
-
-
- ;;******************************************************************************
- ;; IF_SET_ADDRESS_in_SI name
- ;; IF_SET_ADDRESS_in_SI sets the hardware address to be the value
- ;; pointed to by SI. Note this function may be a no-op if the
- ;; hardware address cannot be set (ETHERNET for example)
- ;;
-
- C507_IF_SET_ADDRESS_in_SI_const_BX_CX_BP_DI_ES MACRO name
- .err ;; we don't support setting ethernet addresses (yet)
- ENDM
-
-
- ;;******************************************************************************
- ;; IF_COPY_in_CX_SI_DI_ES_out_SI_DI name
- ;; IF_COPY_in_CX_SI_DI_ES copys a packet from the input buffer (pointed
- ;; to by SI and the segement register given in IF_DECLARE) to an output
- ;; buffer (pointed to by DI and dest_reg) of length CX. It assumes the
- ;; output buffer is contiguous. (and the caller shouln't care if the
- ;; input buffer is contiguous)
- ;;
- C507_IF_COPY_in_CX_SI_DI_ES_out_SI_DI_const_BX_BP_ES MACRO name
- local wrap, done
- .errb <name>
-
- mov DX, DS ;; save DS
- mov AX, c507_&name&_data.c507_end_buff
- sub AX, SI ;; space till end
- cmp AX, CX
- jbe wrap
- inc CX
- shr CX, 1
- mov DS, c507_&name&_data.c507_base
- rep movsw
- jmp done
-
- wrap:
- xchg AX, CX
- sub AX, CX
-
- mov DS, c507_&name&_data.c507_base
- inc CX
- shr CX, 1
- rep movsw
-
- mov CX, AX
- mov DS, DX
- ;; remember this instruction rely on DS
- mov SI, c507_&name&_data.c507_start_buff
- mov DS, c507_&name&_data.c507_base
- inc CX
- shr CX, 1
- rep movsw
-
- done:
- mov DS, DX ;; restore DS
- ENDM
-
-
- ;;******************************************************************************
- ;; These macros and definitions are specific to the 3C507
-
- C507_ID_PORT = 100H
-
- C507_IO_ADDR = 00H
- C507_IO_CTR = 06H
- C507_IO_INT_CLEAR = 0AH
- C507_IO_ATTN = 0BH
- C507_IO_ROM = 0DH
- C507_IO_RAM = 0EH
- C507_IO_INT = 0FH
-
- ;; values for teh IO_CTR reg
- C507_CTR_RUN = 080H ;; 1 = run 0 = reset
- C507_CTR_CA = 040H ;; obsolete way of to a chan attn
- C507_CTR_LOOP = 020H ;; put in loopback
- C507_CTR_LAD = 010H ;; LA address decode disable
- C507_CTR_INT = 008H ;; interupt is pending (read only)
- C507_CTR_IEN = 004H ;; interupt enable
- C507_CTR_PG_MSK = 003H ;; controls first 6 locations
-
- ;; values for the CTR_PG field
- C507_PG_3COM = 00H ;; page that has '*3com*' in it
- C507_PG_ETHER = 01H ;; page ethernet address in it
-
-
- ;;*******************************************************************
- ;; This macro sends the ID sequence that the 3Com 3C507 responds to.
- ;; to the I/O address 'port'.
-
- C507_SEND_ID_const_BX_BP_SI_DI_ES MACRO port
- local id_loop, no_xor
-
- mov CX, 0FFH
- mov AL, 0FFH
- id_loop:
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES port, 0
- shl AL, 1
- jnc no_xor
- xor AL, 0E7H
- no_xor:
- loop id_loop
-
- ENDM
-
- ;;*****************************************************************
- ;; this routine gets the ethernet address from the 3Com I/O registers
- ;; and places it in the buffer pointed to by SI
- C507_GET_ADDRESS_in_SI_const_BX_BP_DI_ES MACRO port
- local eaddr_loop
-
- ;; get the ethernet address
- mov AL, C507_CTR_RUN+C507_PG_ETHER
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES port, C507_IO_CTR
- mov CX, 6
- mov DX, port+C507_IO_ADDR
- eaddr_loop:
- in AL, DX
- mov [SI], AL
- inc DX
- inc SI
- loop eaddr_loop
- ENDM
-
-
- ;;********************************************************************
- ;; These definitions have more to do with the 82586
-
- longptr struc ;; just allows me to get at 8086 long ptrs easily
- offs dw ?
- segm dw ?
- longptr ends
-
- ;;*********************************************************************
-
- ;; This structure is always at a fixed location, and points to
- ;; the system control pointer
- i82586_root struc ;; the root pointer
- root_bus dw 0
- root_zero db 4 dup (0)
- root_scp dd ?
- i82586_root ends
-
- I82586_FIXED_ROOT = 0FFF6H ;; this is the fixed position
-
- ;;*********************************************************************
-
- ;; The system control pointer, in turn, points to the
- ;; system control block
- i82586_scp struc ;; the system control pointer
- scp_busy dw 0 ;; 82586 sets to 0 when reset complete
- scp_scb dw 0 ;; offset to system control block
- scp_base dd 0 ;; base for all 16 bit pointers
- i82586_scp ends ;; the system control block
-
-
- ;;*********************************************************************
-
- ;; The system control block is the heart of the communication
- ;; between the CPU and the 82586. The 82586 has a control
- ;; unit (CU) which you can issue commands to, and a recieve
- ;; unit (RU) that buffers packets. Commands to these units
- ;; are given from this structure.
- i82586_scb struc ;; the system control block
- scb_status dw 0 ;; RU and CU status
- scb_cmd dw 0 ;; RU and/or CU command
- scb_cuc dw 0 ;; CU command (list)
- scb_rframes dw 0 ;; buffers for RU
- scb_crc_errs dw 0 ;; CRC error count
- scb_aln_errs dw 0 ;; Alignment error count
- scb_rcs_errs dw 0 ;; Resource error (queue filled)
- scb_ovrn_errs dw 0 ;; Overruns (memory busy)
- i82586_scb ends
-
- ;; masks for the scb_status field
- SCB_STAT_CX = 08000H ;; command with interupt executed
- SCB_STAT_FR = 04000H ;; Frame recieved
- SCB_STAT_CNR = 02000H ;; command unit left active state
- SCB_STAT_RNR = 01000H ;; receive unit left active state
- SCB_STAT_CUS_MSK = 00700H ;; command status mask
- SCB_STAT_RUS_MSK = 00070H ;; reciever status mask
-
- ;; these are the values for teh RUS_MSK field
- SCB_STAT_RUS_IDLE = 00000H ;; reciever idle
- SCB_STAT_RUS_SUSP = 00010H ;; reciever suspended
- SCB_STAT_RUS_NORES = 00020H ;; reciever no_resources
- SCB_STAT_RUS_READY = 00040H ;; reciever ready
-
- ;; masks for the scb_cmd (set by CPU cleared by 82586)
- SCB_CMD_ACK_CX = 08000H ;; acks command executed
- SCB_CMD_ACK_FR = 04000H ;; acks frame received
- SCB_CMD_ACK_CNA = 02000H ;; acks CU not ready
- SCB_CMD_ACK_RNR = 01000H ;; acks RU not ready
- SCB_CMD_CUC_MSK = 00700H ;; CU command mask
- SCB_CMD_RST = 00080H ;; reset the 82586
- SCB_CMD_RUC_MSK = 00070H ;; RU command mask
-
- ;; values for the CUC_MSK part of the scb_cmd field
- SCB_CUC_START = 00100H ;; start a CU command
- SCB_CUC_RESUME = 00200H
- SCB_CUC_SUSPEND = 00300H
- SCB_CUC_ABORT = 00400H
-
- ;; values for the RUC_MSK part of the scb_cmd field
- SCB_RUC_START = 00010H ;; start RU receiving packets
- SCB_RUC_RESUME = 00020H
- SCB_RUC_SUSPEND = 00030H
- SCB_RUC_ABORT = 00040H
-
-
- ;;*********************************************************************
-
- ;; the scb_cuc points to a list of commands for the CU
- ;; to execute. Each entry in the list has this format
- i82586_cu struc
- cu_status dw 0 ;; status of this command
- cu_cmd dw 0 ;; specifies the op
- cu_next dw 0 ;; next cmd in the list
- cu_params db 58 dup (0) ;; depends on particular cmd
- i82586_cu ends
-
- ;; values for the cu_status field
- CU_STAT_COMPLETE = 08000H ;; command is completed
- CU_STAT_BUSY = 04000H ;; command not complete
- CU_STAT_OK = 02000H ;; finished and OK
-
- ;; values for the cu_cmd field
- CU_CMD_CMD_MSK = 00007H ;; mask for the command
- CU_CMD_EOL = 08000H ;; last command list in list
- CU_CMD_SUSPEND = 04000H ;; suspend after completion
- CU_CMD_INT = 02000H ;; interupt after completion
-
-
- ;; values for the CMD_MSK parat of the cu_cmd field
- CU_CMD_NOOP = 0 ;; noop command
- CU_CMD_ADDRESS_SET = 1 ;; set ethernet address
- CU_CMD_CONFIG = 2 ;; configure ethernet params
- CU_CMD_MULTI_SET = 3 ;; set multicast addresses
- CU_CMD_TRANS = 4 ;; transmit packet
- CU_CMD_TDR = 5 ;; Time domain reflectometer
- CU_CMD_DUMP = 6 ;; dump internal state
- CU_CMD_DIAGNOSE = 7 ;; run diagnostics
-
- ;;*******************************************************************
-
- ;; these are the parameters of the TRAMSMIT command
- i82586_trans struc
- trans_tbd dw 0 ;; points to buffer descriptor
- trans_dst_addr db 6 dup (0) ;; address to send it to (not used)
- trans_len dw 0 ;; 802.3 length field (not used)
- i82586_trans ends
-
- ;; the first parameter of a transmit command points to a list
- ;; of transmit buffer discriptors that characterize the
- ;; packet to send
- i82586_tbd struc
- tbd_len dw 0 ;; length and EOL flag
- tbd_next dw 0 ;; pointer to next descriptor
- tbd_buff dd 0 ;; a long pointer to the buffer
- i82586_tbd ends
-
- ;; the bit fields bit in the tbd_len field
- TBD_LEN_EOL = 08000H ;; Last buff in list
- TBD_LEN_LEN_MSK = 03FFFH ;; this part is the length
-
-
- ;;*******************************************************************
-
- ;; the scb_rfd field points to a list of frame descriptors.
- ;; each of these describe a single packet
- i82586_rfd struc
- rfd_status dw 0 ;; recieve status
- rfd_cmd dw 0 ;; really just specifies EOL
- rfd_next dw 0 ;; next frame descriptor
- rfd_rbd dw 0 ;; pointer to buff descriptor
- rfd_dst_addr db 6 dup (0) ;; ethernet address of destination
- rfd_src_addr db 6 dup (0) ;; ethernet address of source
- rfd_len dw 0 ;; length of packet
- i82586_rfd ends
-
- RFD_STAT_DONE = 08000H
- RFD_STAT_CONSUMED = 04000H
- RFD_STAT_OK = 02000H
- RFD_STAT_CRC = 00800H
- RFD_STAT_ALN = 00400H
- RFD_STAT_RSC = 00200H
- RFD_STAT_OVRN = 00100H
- RFD_STAT_RUNT = 00080H
-
- RFD_CMD_EOL = 08000H ;; End of frame list
-
- ;; the rdb_buff field points to a buffer descriptor, which is
- ;; a unit of memory allocation.
- i82586_rbd struc
- rbd_used_len dw 0 ;; also hold some flag bits
- rbd_next dw 0 ;; next buffer descriptor
- rbd_buff dd 0 ;; pointer to actual memory
- rbd_len dw 0 ;; length of buffer
- i82586_rbd ends
-
- ;; masks for the rdb_used_len field
- RBD_USED_LEN_EOF = 08000H ;; Last buff in a frame list
- RBD_USED_LEN_VALID = 04000H ;; says the used_len field valid
- RBD_USED_LEN_MSK = 03FFFH ;; this part is the used length
-
- RBD_LEN_MSK = 03FFFH ;; this part is the used length
- RBD_LEN_EOL = 08000H ;; End of buffer list
-
-
-
- ;;***********************************************************************
- ;; setup the chain of recieve buffers. SI points to a block
- ;; of memory 'len'*(SIZE i82586_rfd) bytes long. Note 1 < CX < 16K
-
- C507_SETUP_R_FRAMES_in_CX_SI_ES_const_AX_BP_ES MACRO
- local init_loop
-
- ;; create a circular list of receive buffers
- mov DX, SI ;; save original pointer
- mov DI, SI
- add DI, (SIZE i82586_rfd)
- dec CX
- init_loop:
- ;; set up a frame descriptor
- mov ES:[SI+rfd_status], 0
- mov ES:[SI+rfd_cmd], 0 ;; says NOT end of list
- mov ES:[SI+rfd_next], DI
- mov ES:[SI+rfd_rbd], 0FFFFH
-
- add SI, (SIZE i82586_rfd)
- add DI, (SIZE i82586_rfd)
- dec CX
- jnz init_loop
-
- mov ES:[SI+rfd_cmd], RFD_CMD_EOL ;; logical end of list
- mov ES:[SI+rfd_next], DX ;; close the loop
- mov ES:[SI+rfd_rbd], 0FFFFH
- ENDM
-
-
- ;;***********************************************************************
- ;; setup the chain of recieve buffers. BX points to the begining of
- ;; a block of memory 'len'* CX bytes long and SI points to a block
- ;; of memory 'len'*(SIZE i82586_rbd) bytes long. Note 1 < CX < 16K
- ;; it returns in SI the start of the list of buffer descriptors.
-
- C507_SETUP_R_BUFFS_in_BX_CX_SI_ES_out_SI_const_AX_BP_ES MACRO len
- local init_loop
-
- ;; create a circular list of receive buffers
- mov DX, SI ;; save original pointer
- mov DI, SI
- add DI, (SIZE i82586_rbd)
- dec CX
- init_loop:
- ;; set up a buffer descriptor
- mov ES:[SI+rbd_next], DI
- mov ES:[SI+rbd_buff.offs], BX
- mov ES:[SI+rbd_buff.segm], 0
- mov ES:[SI+rbd_len], len
-
- add SI, (SIZE i82586_rbd)
- add DI, (SIZE i82586_rbd)
- add BX, len
- dec CX
- jnz init_loop
-
- mov ES:[SI+rbd_next], DX ;; close the loop
- mov ES:[SI+rbd_buff.offs], BX
- mov ES:[SI+rbd_buff.segm], 0
- mov ES:[SI+rbd_len], len+RBD_LEN_EOL ;; logical end of list
-
- mov SI, DX ;; return the first one
- ENDM
-
-
-
- ;;***********************************************************************
- ;; setup the data structure needed for the receiver. CX, ES:SI is the
- ;; len and begining of shared memory in which to set it up. It returns
- ;; in SI the pointer that belongs in the scb_rframes field of the system
- ;; control block 'len' is the length of a buffer
-
- C507_SETUP_R_MEM_in_CX_SI_ES_out_SI_const_ES MACRO len
-
- ;; since we allocate two buffers for every frame
- TOTAL_BUFF_LEN = len + (SIZE i82586_rbd) + (SIZE i82586_rfd)
-
- mov AX, CX
- sub AX, (SIZE i82586_rfd) ;; Want an extra frame desc
- xor DX, DX
- mov BX, TOTAL_BUFF_LEN
- div BX
-
- mov CX, AX ;; AX holds the number of buffers
- mov BX, SI ;; BX start of buffer space
- mov DX, len
- mul DX
- add SI, AX ;; SI start of buff desc
-
- mov BP, SI
- mov AX, CX
- mov DX, (SIZE i82586_rbd)
- mul DX
- add BP, AX ;; BP points to the start of frame desc
-
- mov AX, CX ;; CX holds the number of buffers
- inc AX ;; AX holds the number of frames
-
- C507_SETUP_R_BUFFS_in_BX_CX_SI_ES_out_SI_const_AX_BP_ES len
-
- mov CX, AX
- mov AX, SI ;; save pointer to start of buffer list
- mov SI, BP
- C507_SETUP_R_FRAMES_in_CX_SI_ES_const_AX_BP_ES
-
- mov SI, BP ;; return final pointer to frames
- mov ES:[SI+rfd_rbd], AX ;; link the frames to the buffs
- ENDM
-
-
- ;;***********************************************************************
- ;; setup the data structures needed to communicate with the 82586.
- ;; SI:ES points to the shared memory window. Note that We only use
- ;; the memory ABOVE SI in the ES segment, thus if SI=C000 there is
- ;; a 4K window. In addition, some data structures are in 'standard'
- ;; positions that can be used directly.
- ;;
-
- SCP = 0FFE0H ;; place for system control ptr
- SCB = (SCP-16) ;; place for system control block
- CU_GCMD = (SCB-32) ;; generic command (32 bytes long)
- CU_TCMD1 = (CU_GCMD-32) ;; first trans command (32 bytes long)
- CU_TCMD2 = (CU_TCMD1-32) ;; second trans command (32 bytes long)
- CU_TBD1 = (CU_TCMD2-8) ;; first Transmit buffer descriptor
- CU_TBD2 = (CU_TBD1-8) ;; second Transmit buffer descriptor
- CU_TB1 = (CU_TBD2-1536);; first Trans buffer (1536 bytes long)
- CU_TB2 = (CU_TB1-1536) ;; second Trans buffer (1536 bytes long)
-
- START_RESERVED = CU_TB2 ;; start of fixed allocated memory
- LEN_R_BUFF = 256 ;; this is a optimization param
-
-
- ;;*************************************************************************
- ;; SETUP_MEM sets up all the shared memory data structures that the 82586
- ;; uses SI:ES points the the begining of the memory. It is assumed that
- ;; the memory ranges is ES:SI to ES:FFFF
- ;;
- C507_SETUP_MEM_in_SI_ES_const_ES MACRO
-
- mov DI, SI ;; zero out memory, it makes reading
- xor AX, AX ;; dumps easier
- mov DX, SI
- shr DX, 1
- mov CX, 8000H
- sub CX, DX
- rep stosw
-
- ;; setup ROOT
- mov BX, offset I82586_FIXED_ROOT
- mov ES:[BX+root_bus], 0
- mov ES:[BX+root_scp.offs], offset SCP
- mov ES:[BX+root_scp.segm], 0
-
- ;; setup SCP
- mov BX, offset SCP
- mov ES:[BX+scp_busy], 1 ;; set the busy bit
- mov ES:[BX+scp_scb], SCB
- mov ES:[BX+scp_base.offs], 0
- mov ES:[BX+scp_base.segm], 0
-
- ;; setup SCB
- mov BX, offset SCB
- mov ES:[BX+scb_cmd], 0
- mov ES:[BX+scb_status], 0
- mov ES:[BX+scb_crc_errs], 0
- mov ES:[BX+scb_aln_errs], 0
- mov ES:[BX+scb_rcs_errs], 0
- mov ES:[BX+scb_ovrn_errs], 0
- mov ES:[BX+scb_cuc], offset CU_GCMD
-
- ;; get the length of the rest of memory
- mov CX, START_RESERVED
- sub CX, SI
- C507_SETUP_R_MEM_in_CX_SI_ES_out_SI_const_ES LEN_R_BUFF
-
- mov BX, offset SCB
- mov ES:[BX+scb_rframes], SI
-
- ;; setup transmit buffers descriptors
- mov BX, CU_TCMD1
- mov ES:[BX+cu_cmd], CU_CMD_EOL+CU_CMD_TRANS
- mov ES:[BX+cu_params+trans_tbd], CU_TBD1
-
- mov BX, CU_TCMD2
- mov ES:[BX+cu_cmd], CU_CMD_EOL+CU_CMD_TRANS
- mov ES:[BX+cu_params+trans_tbd], CU_TBD2
-
- mov BX, CU_TBD1
- mov ES:[BX+tbd_buff.offs], offset CU_TB1
- mov ES:[BX+tbd_buff.segm], 0
-
- mov BX, CU_TBD2
- mov ES:[BX+tbd_buff.offs], offset CU_TB2
- mov ES:[BX+tbd_buff.segm], 0
-
- ENDM
-
-
- ;;***********************************************************************
- ;; DO_CMD simply executes the command 'command'. It assumes that all
- ;; parameters to the command have been set up in the DO_CMD_PARAMS
- ;; structure below. This command waits for completion and jumps to
- ;; 'fail' if unsuccessful. (note that DO_CMD_PARAMS points to the
- ;; command specific part of the command.
- ;; Note also that this command should not be used if it is possible
- ;; that other commands are in progress
-
- DO_CMD_PARAMS = (CU_GCMD+6)
-
- C507_DO_CMD_in_ES_const_BP_SI_DI_ES MACRO command, port, fail
- local waitloop, done
- .errb <fail>
-
- mov BX, offset SCB
- mov ES:[BX+scb_status], 0
- mov ES:[BX+scb_cuc], offset CU_GCMD
- mov ES:[BX+scb_cmd], SCB_CUC_START
-
- mov BX, offset CU_GCMD
- mov ES:[BX+cu_status], 0
- mov ES:[BX+cu_cmd], CU_CMD_EOL+command
- ;; we assume that the rest of the command is set up
-
- ;; signal the 82586
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES port, C507_IO_ATTN
-
- xor CX, CX ;; don't wait forever
- waitloop:
- dec CX
- jz fail
-
- mov AX, ES:[BX+cu_status]
- test AX, CU_STAT_COMPLETE
- jz waitloop ;; wait for completion
- test AX, CU_STAT_OK
- jz fail
-
- ENDM
-
-
- ;;***********************************************************************
- ;; do the intial setup of the 3C507 card
-
- C507_RESET_82586_in_ES MACRO port, fail
- local reset_wait, reset_done, reset_loop
-
- ;; reset the 82586
- mov ES:[SCP+scp_busy], 1 ;; set the busy bit
-
- mov AL, 0
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES port, C507_IO_CTR
- nop ;; wait 10 clock cycles
- nop
-
- ;; just in case there was an interupt pending, clear it
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES port, C507_IO_INT_CLEAR
-
- mov AL, C507_CTR_RUN+C507_PG_ETHER
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES port, C507_IO_CTR
- nop
- nop
-
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES port, C507_IO_ATTN
-
- mov CX, 256
- reset_loop:
- cmp ES:[SCP+scp_busy], 0
- jz reset_done
- loop reset_loop
- jmp fail
-
- reset_done:
- ENDM
-
-
- ;;***********************************************************************
- ;; do the intial setup of the 3C507 card
-
- C507_INIT_SETUP_out_ES MACRO port, segment, len, addr, promiscuous, fail
- local eaddr_loop, done, diag_fail, config_fail, setaddr_fail
- local reset_fail, ru_on_fail, wait_ru_on, done_wait_ru
- .errb <len>
-
- ;; adjust ES so that ES:SI point to begining and ES:FFFF the end
- mov AX, segment
- if ((len/16) ne 0) ;; This is a kludge because the assembler wraps 10000H
- sub AX, (1000H - (len / 16))
- endif
- mov ES, AX
- mov SI, 10000H - len
-
- ;; test the memory just a bit
- mov ES:[SI], 5F75H
- mov DX, ES:[SI]
- mov AX, 0101H ;; signals a memory check error type 1
- cmp DX, 5F75H
- jnz fail
-
- mov ES:[0FFFEH], 57A5H
- mov DX, ES:[0FFFEH]
- mov AX, 0102H ;; signals a memory check error type 2
- cmp DX, 57A5H
- jnz fail
-
- C507_SETUP_MEM_in_SI_ES_const_ES
-
-
- ;; just to test the board is there, get the first char
- ;; of the '*3com*' identifier from the I/O ROM.
- mov AL, C507_CTR_RUN+C507_PG_3COM
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES port, C507_IO_CTR
- READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES port, C507_IO_ADDR
- mov DL, AL
- mov AX, 0201H ;; signals 82586 not there
- cmp DL, '*' ;; should be part of *3com*' string
- jnz fail
-
- C507_RESET_82586_in_ES port reset_fail
-
- ;; check the setup by doing a diag
- C507_DO_CMD_in_ES_const_BP_SI_DI_ES CU_CMD_DIAGNOSE, port, diag_fail
-
- ;; configure ethernet params
- mov BX, offset DO_CMD_PARAMS
- mov word ptr ES:[BX+0], 0080CH ; fifo=8 byte count=12
- mov word ptr ES:[BX+2], 02E00H ; preamble=4, add_len=6, DONT ins headers
- mov word ptr ES:[BX+4], 06000H ; interframe spacing = 60h
- mov word ptr ES:[BX+6], 0F200H ; retry = 15, slot time = 200h
- if promiscuous eq 1
- mov word ptr ES:[BX+8], 1 ; flags bit 1 means promiscuous
- else
- mov word ptr ES:[BX+8], 0 ; flags bit 1 means promiscuous
- endif
- mov word ptr ES:[BX+10], 0003CH ; minimum frame length = 60
- C507_DO_CMD_in_ES_const_BP_SI_DI_ES CU_CMD_CONFIG, port, config_fail
-
- ;; set the ethernet address
- mov DI, offset DO_CMD_PARAMS
- mov SI, offset addr
- mov CX, 3
- rep movsw
- C507_DO_CMD_in_ES_const_BP_SI_DI_ES CU_CMD_ADDRESS_SET, port, setaddr_fail
-
- mov BX, offset SCB
- mov ES:[BX+scb_status], 0
- mov ES:[BX+scb_cmd], SCB_RUC_START
-
- ;; signal the 82586
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES port, C507_IO_ATTN
-
- xor CX, CX
- wait_ru_on:
- dec CX
- mov AX, ES:[BX+scb_status]
- and AX, SCB_STAT_RUS_MSK
- jnz done_wait_ru
- dec CX
- jnz wait_ru_on
- done_wait_ru:
- cmp AX, SCB_STAT_RUS_READY
- jz done
-
- ru_on_fail:
- mov AX, 0206H ;; failed to turn RU on
- jmp fail
-
- reset_fail:
- mov AX, 0202H ;; failed resetting the 82586
- jmp fail
-
- diag_fail:
- mov AX, 0203H ;; signals 82586 failed noop test
- jmp fail
-
- config_fail:
- mov AX, 0204H ;; signals 82586 failed config
- jmp fail
-
- setaddr_fail:
- mov AX, 0205H ;; signals 82586 failed set addr
- jmp fail
-
- done:
- ENDM
-
-
- ;;******************************************************************************
- ;; utility functions needed only within this module
-
- READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES MACRO port, if_io
- mov DX, if_io+port
- in AL, DX ;; AL contains data read from port
- ENDM
-
- ;;******************************************************************************
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES MACRO port, if_io
- mov DX, if_io+port
- out DX, AL ;; AL contains data read from port
- ENDM
-
-