home *** CD-ROM | disk | FTP | other *** search
- ;;******************************************************************************
- ;; wd8003e.inc wd8003e.inc
- ;;******************************************************************************
- ;;
- ;; Copyright (C) 1989 Northwestern University, 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.
- ;;
- ;; Northwestern University 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.
- ;;
- ;;******************************************************************************
- ;; wd8003 holds the interface routines for the western digital ethernet card
- ;; WD8003E or the starlan card WD8003S. Althougth this routine will work
- ;; for any of the above cards, it has been optimized for the Ethernet card.
- ;;
- ;; The functions provided by this file are
- ;;
- ;; WDE_DECLARE name,io_address,shr_seg,shr_off,promiscuous,total_pgs,bits16
- ;; WDE_DEFINE name
- ;; WDE_IF_R_ACCESS_out_BX_CX_ES name, no_packet
- ;; WDE_IF_R_CONT_in_BX_CX_ES_const_BX_CX_DX_BP_SI_DI_ES name, ok
- ;; WDE_IF_R_FREE_const_BX_CX_BP_SI_DI_ES name
- ;; WDE_IF_W_ACCESS_in_CX_out_DI_ES_const_BX_CX_BP name, no_buffer
- ;; WDE_IF_W_WRITE_in_CX_const_BX_BP_ES name
- ;; WDE_IF_SET_ADDRESS_in_SI_const_BX_CX_BP_DI_ES name
- ;; WDE_IF_COPY_in_CX_SI_DI_ES_out_SI_DI_const_BX_BP_ES name
- ;;
- ;; Variables set by this module
- ;;
- ;; wde_&name&_declared ;; one if this interface exists
- ;; if_&name&_address ;; the hardware address
- ;; if_&name&_mtu ;; the maximum trans unit
- ;;
- ;;******************************************************************************
-
- include wd.inc
-
- ;;******************************************************************************
- ;; data storage needed by this module
-
- wde_data STRUC
- wde_new_bndry DB 0
- wde_data ENDS
-
-
- ;;******************************************************************************
- ;; IF_DECLARE name, io_address, shr_seg, shr_off
- ;; declares an interface object. 'io_address' is the address of the
- ;; start of the 8003E control registers. 'shr_seg' and
- ;; 'shr_off' is the address of the WD8003 card buffer
- ;; This address must be a multiple of 512. If 'promiscuous' is not
- ;; zero (or blank),the interface is configured so that every packet on
- ;; the ethernet is received. 'total_pg' if not blank, is the total
- ;; amount of pages of shared memory. (default = 32 pages = 8K)
- ;; if 'bits16' is non-blank and equal to 1, then the card is assumed
- ;; to be a WD8013EBT card. It it is 2, then it is a WD8013 card but
- ;; we have disabled 16bit transfers (some hardware doesn't like it)
- ;;
- WDE_DECLARE MACRO name, io_address, shr_seg, shr_off, promiscuous, total_pg, bits16
- .errb <name>
- .errb <io_address>
- .errb <shr_seg>
- .errb <shr_off>
-
- .DATA
- wde_&name&_declared = 1
- wde_&name&_io = io_address ;; set compile time values
- wde_&name&_shared_off = shr_off
- wde_&name&_shared_seg = shr_seg
- if shr_seg lt 8000h
- .err Shared memory MUST be above 80000H
- endif
-
- wde_&name&_stop_pg = STOP_PG
- ifnb <total_pg>
- wde_&name&_stop_pg = 0&total_pg
- endif
-
- wde_&name&_promiscuous = 0
- ifnb <promiscuous>
- wde_&name&_promiscuous = 0&promiscuous
- endif
-
- wde_&name&_bits16 = 0
- ifnb <bits16>
- wde_&name&_bits16 = 0&bits16
- endif
-
- ;; note these can only touch registers AX and DX
- WDE_&name&_16BIT_ON MACRO
- mov AL,LAN16ENB or LA19 or MEM16ENB
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES LAAR, wde_&name&_io
- ENDM
-
- WDE_&name&_16BIT_OFF MACRO
- mov AL,LAN16ENB or LA19
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES LAAR, wde_&name&_io
- ENDM
-
- if wde_&name&_bits16 eq 1
- MEM_DECLARE_16BIT WDE_&name&_16BIT_ON WDE_&name&_16BIT_OFF
- else
- MEM_DECLARE_8BIT
- endif
-
- if_&name&_mtu = 1514
- global wde_&name&_data:wde_data
- global if_&name&_address:word
- .CODE
- global wde_&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
- ;;
- WDE_DEFINE MACRO name
- ifdef wde_&name&_declared
- call wde_&name&_real_define
- endif
- ENDM
-
- WDE_REAL_DEFINE MACRO name
- LOCAL loop1, loop2, loop3, around, resetwait
- .errb <name>
-
- ifdef wde_&name&_declared
- .DATA
- if_&name&_address DW 3 DUP (0)
- wde_&name&_data wde_data <> ;; create storage needed
-
- .CODE
- wde_&name&_real_define:
- mov cx, 6 ;; get the ethernet address
- mov bx, OFFSET if_&name&_address
- mov dx, wde_&name&_io+ADDROM ;; point to the Ethernet address ROM
- loop1:
- in AL, DX
- mov [BX], AL
- inc DX
- inc BX
- loop loop1
-
- mov AL, 80h ;; reset the card
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES 0, wde_&name&_io
- mov AL, 00h
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES 0, wde_&name&_io
-
- ;; this sets bit 6 (0 justified) of register offset 0x05, it will enable
- ;; the lan controller to access shared RAM 16 bits at a time
- ;; In addition, this routine maintains address bit 19
- ;; (previous cards assumed this bit high...we must do it manually)
-
- ;; note: this is a write only register and only exists on the WD8013
- mov AL, LAN16ENB + LA19 ; set bit19 of address and 16 bit mode for card
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES LAAR, wde_&name&_io
-
- ;; register 0 is the MSR (Memory base reg)
- ;; this will enable the on board ram
- mov AL, (wde_&name&_shared_seg+(wde_&name&_shared_off/16))/512
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES 0, wde_&name&_io
-
- mov AL, MSK_STP + MSK_PG0 + MSK_RD2 ;; RESET, goto page 0
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES CMDR, wde_&name&_io
-
- xor AL, AL ;; clear RBCR0,1
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES RBCR0, wde_&name&_io
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES RBCR1, wde_&name&_io
-
- resetwait: ;; make sure reset is complete
- READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES ISR, wde_&name&_io
- test AL, MSK_RST
- jz resetwait
-
- mov AL, MSK_BMS + MSK_FT10 ;; select FIFO threshold = 8 bytes
- if wde_&name&_bits16 eq 1
- or AL, MSK_WTS ;; FOR 16 BIT OPERATION
- endif
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES DCR, wde_&name&_io
-
- xor AL, AL ;; turn off receiving
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES RCVR, wde_&name&_io
- mov AL, MSK_LBm1 ;; enter loopback operation mode 1
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES TCR, wde_&name&_io
-
- mov AL, STRT_PG ;; start of input buffer (in 256b pages)
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES PSTART, wde_&name&_io
- mov AL, wde_&name&_stop_pg ;; end of input buffer (in 256b pages)
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES PSTOP, wde_&name&_io
- mov AL, STRT_PG
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES BNRY, wde_&name&_io
-
- mov AL, -1 ;; clear all status bits
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES ISR, wde_&name&_io
- mov AL, 0 ;; no interupts
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES IMR, wde_&name&_io
-
- mov AL, MSK_STP + MSK_PG1 + MSK_RD2 ;; make sure we are on page 1
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES CMDR, wde_&name&_io
-
- mov CX, 6 ;; set the ethernet address
- mov BX, OFFSET if_&name&_address
-
- mov DX, wde_&name&_io+PAR0
- loop2:
- mov AL, [BX] ;; get 1 byte into AL
- out DX, AL ;; write to PAR
- inc BX
- inc DX
- loop loop2
-
- if wde_&name&_promiscuous ne 0
- mov AL, 0FFH
- else
- xor AL, AL
- endif
- mov CX, 8 ;; set the multicast address to all 0's
- mov DX, wde_&name&_io+MAR0
- loop3:
- out DX, AL
- inc DX
- loop loop3
-
- mov AL, STRT_PG+1 ;; Set input pointer for queue
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES CURR, wde_&name&_io
-
- mov AL, MSK_STA + MSK_PG0 + MSK_RD2 ;; make sure we are on page 0
- ;; and start the NIC 8390
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES CMDR, wde_&name&_io
-
- xor AL, AL ;; loopback off
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES TCR, wde_&name&_io
-
- ;; set receiver mode
- if wde_&name&_promiscuous ne 0
- mov AL, MSK_AB+MSK_AM+MSK_PRO ;; promiscuous
- else
- mov AL, MSK_AB ;; just broadcasts + to me
- endif
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES RCVR, wde_&name&_io
-
- 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
- ;;
- WDE_IF_R_ACCESS_out_BX_CX_ES MACRO name, no_packet
- local inside, good_packet, wrapped, new_wrapped, bad_packet, ok_status
- local good_length, truncate
- .errb <no_packet>
-
- mov AL, MSK_PG0 + MSK_RD2 ;; read the BNRY register into AL
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES CMDR, wde_&name&_io
- READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES BNRY, wde_&name&_io
-
- inc AL ;; increment with wrap around
- cmp AL, wde_&name&_stop_pg
- jb inside
- mov AL, STRT_PG
- inside:
- mov BH, AL ;; save it in BH
-
- mov AL, MSK_PG1 + MSK_RD2 ;; read CURR register into AL
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES CMDR, wde_&name&_io
- READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES CURR, wde_&name&_io
-
- cmp AL, BH
- je no_packet
- xor BL, BL ;; BX now holds pointer to packet
-
- mov DX, wde_&name&_shared_seg ;; ES = segment address
- mov ES, DX
- mov AH, ES:[BX+wde_&name&_shared_off] ;; get the status
- cmp AH, SMK_PRX ;; is it good
- jz ok_status
- cmp AH, SMK_PRX+SMK_PHY
- jnz bad_packet
-
- ok_status:
- mov AH, ES:[BX+1+wde_&name&_shared_off] ;; pointer to the next packet
- ;; sanity check on next packet pointer AH
- cmp BH, AL ;; is BNDRY+1 <= CURR?
- ja wrapped
- cmp AH, BH
- jb bad_packet
- cmp AH, AL
- jbe good_packet
- jmp bad_packet
- wrapped:
- cmp AH, BH
- jb new_wrapped
- cmp AH, wde_&name&_stop_pg
- jnb bad_packet
- jmp good_packet
- new_wrapped:
- cmp AH, STRT_PG
- jb bad_packet
- cmp AH, AL
- jbe good_packet
- bad_packet:
- ;; set BNDRY = BNDRY+1 and try again
- mov AL, MSK_PG0 + MSK_RD2 ;; make sure we are on page 0
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES CMDR, wde_&name&_io
-
- mov AL, BH ;; write the new BNRY register
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES BNRY, wde_&name&_io
- jmp no_packet ;; return bad status
- good_packet:
-
- mov wde_&name&_data.wde_new_bndry, AH ;; save it for R_FREE
- mov CX, ES:[BX+wde_&name&_shared_off+2] ;; load the length
- add BX, wde_&name&_shared_off+4 ;; BX point to begining of the packet
- sub CX, 4
-
- cmp CX, 1536 ;; sanity check
- jle good_length
- cmp CH, CL
- jne truncate
- xor CH, CH ;; fix western digital bug
- jmp good_length
- truncate:
- mov CX, 1536
- good_length:
- 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.
- ;;
- WDE_IF_R_FREE_const_BX_CX_BP_SI_DI_ES MACRO name
- local inside
- .errb <name>
-
- mov AL, MSK_PG0 + MSK_RD2 ;; make sure we are on page 0
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES CMDR, wde_&name&_io
-
- mov AL, wde_&name&_data.wde_new_bndry ;; Retreive NEW_BOUNDRY
- dec AL
- cmp AL, STRT_PG
- jge inside
- mov AL, wde_&name&_stop_pg-1
- inside: ;; write the new BNRY register
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES BNRY, wde_&name&_io
- ENDM
-
-
- ;;******************************************************************************
- ;; WDE_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
- ;;
- WDE_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, OFFSET wde_&name&_shared_off+wde_&name&_stop_pg*256
- 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
- ;;
- WDE_IF_W_ACCESS_in_CX_out_DI_ES_const_BX_CX_BP MACRO name, no_buffer
- local wait_loop
- .errb <no_buffer>
-
- mov DI, 65000 ;; so we don't wait forever
- wait_loop:
- dec DI
- jz no_buffer
-
- READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES CMDR, wde_&name&_io
- test AL, MSK_TXP
- jnz wait_loop
-
- mov DI, wde_&name&_shared_off ;; return DI:ES pointer
- mov DX, wde_&name&_shared_seg
- mov ES, DX
- 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.
- ;;
- WDE_IF_W_WRITE_in_CX_const_BX_BP_ES MACRO name
- .errb <name>
-
- mov AL, MSK_PG0 + MSK_RD2 ;; make sure we are in register page 0
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES CMDR, wde_&name&_io
- mov AL, CL ;; set length
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES TBCR0, wde_&name&_io
- mov AL, CH
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES TBCR1, wde_&name&_io
-
- xor AL, AL ;; tell card packet begins at page 0
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES TPSR, wde_&name&_io
- mov AL, MSK_TXP + MSK_RD2 ;; send the packet
- WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES CMDR, wde_&name&_io
- 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)
- ;;
-
- WDE_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)
- ;;
-
- WDE_IF_COPY_in_CX_SI_DI_ES_out_SI_DI_const_BX_BP_ES MACRO name
- local wrap, done, no_time1, no_time2
- .errb <name>
-
- mov DX, DS ;; save DS
- mov AX, wde_&name&_shared_seg
- mov DS, AX
-
- mov AX, OFFSET wde_&name&_shared_off+wde_&name&_stop_pg*256
- sub AX, SI ;; AX holds length to wrap line
- cmp AX, CX
- jl wrap ;; wrap if AX less than packet lenght
- MEM_COPY_in_CX_SI_DI_ES_out_SI_DI_const_AX_BX_DX_BP_ES
- jmp done
- wrap:
- xchg AX, CX ;; length is now length to wrap line
- sub AX, CX ;; AX holds remainder
- MEM_COPY_in_CX_SI_DI_ES_out_SI_DI_const_AX_BX_DX_BP_ES
-
- mov SI, OFFSET wde_&name&_shared_off+STRT_PG*256
- mov CX, AX
-
- MEM_COPY_in_CX_SI_DI_ES_out_SI_DI_const_AX_BX_DX_BP_ES
- done:
-
- mov DS, DX ;; restore DS
- 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
-
-