---- 完成上面的过程之后,网卡还不能正确的接收数据包,因为我们还没有对网卡的物理地址(网卡地址,48位的地址)进行设置。网卡还不知道它应该什么地址的数据包。要对网卡的物理地址进行设置,就必须知道网卡的物理地址是多少。
读取网卡的物理地址的子程序:
union u {uint word; struct{uchar high;uchar low;}bytes;}; //我定义的数据结构,为两个字节的结构 //,可以按照uint(unsigned int)来读取,也可以按照高低字节high和low来读取。
union u mynodeid[3];//存储网卡的物理地址
union u protocal; //临时变量
void readmynodeid()
{uchar data i,temp;
page(0);
reg09=0;//寄存器RSAR1 dma read highaddress=0
reg08=0;//RSAR0 dma read lowaddress=0;
reg0b=0; //RBCR1 read count high
reg0a=12;//RBCR0 count low
reg00=0x0a;//dma read and start
for (i=0;i<6;i++)
{ temp=reg10;//读取一个字节
if (i % 2==0)
{protocal.bytes.high=temp;}
else {protocal.bytes.low=temp;mynodeid[i/2].word=protocal.word;}
rtl8019as有3种工作方式:
第一种为跳线方式,网卡的i/o和中断由跳线决定
第二种为即插即用方式,由软件进行自动配置plug and play
第三种为免跳线方式,网卡的i/o和中断由外接的93c46里的内容决定。
我们买到的网卡一般只支持第2和第3种。在嵌入式应用的 场合,如果可以不使用93c46的话,可以降低成本,同时又减少连线。那么我们如何使用第1种方式跳线方式呢?网卡使用哪种方式由rtl8019as的第65脚JP决定。我们来看引脚图:
;函数 set_hw_multi ; Set the multicast mask bits in chip是将mcast_list_bits[8]写入到MAR0--MAR7
;的一个函数调用,这里没有写。
public set_multicast_list
set_multicast_list:
;enter with ds:si ->list of multicast addresses, ax = number of addresses,
; cx = number of bytes.
;入口调用: 将list of multicast addresses 组播地址列表(可以有多个组播地址)的地址放在
;ds:si 指针里。ax为多播地址的个数。cx为字节数
;return nc if we set all of them, or cy,dh=error if we didn't.
;设置成功返回c=0,失败c=1(c就是cy,cpu标志位)
assume ds:code
mov cx,ax ;keep a count of addresses in cx.
;cx=多播地址的个数
mov di,offset mcast_list_bits ;di=64位的多播地址crc
xor ax,ax
mov [di+0],ax
mov [di+2],ax
mov [di+4],ax
mov [di+6],ax ;将多播地址8个字节的crc全部设置为0
jcxz set_mcl_2 ;cx=0 跳到set_mc1_2,将多播地址crc设置为全部0
set_mcl_1:
call add_mc_bits ;调用crc计算
loop set_mcl_1
set_mcl_2:
call set_hw_multi ; Set the multicast mask bits in chip
;将mcast_list_bits[8] 8个字节分别写入到MAR0--MAR7
;mcast_list_bits[0]对应于MAR0 .
clc
ret
;=================
add_mc_bits: 开始计算
;entry: ds:si -> multicast address, di-> sixty-four bit multicast filter.
;preserve cx, di, increment si by EADDR_LEN
push cx ;保存cx,就是保存多播地址的个数
mov cx,EADDR_LEN ;EADDR_LEN就是以太网地址的长度=6
mov dx,0ffffh ; this is msw.
mov bx,0ffffh ; set 32 bit number
add_mcb_1:
lodsb ;将一个字节的数(地址为si指向的数)装到AL里,同时使si地址+1
call upd_crc ; update crc
loop add_mcb_1 ; and loop.
;=============
ifdef MULTICRC_REVERSE ;ifdef 到endif这段函数是产生CRC过滤的反顺序码的,
;例如 0000001 反顺序就是 1000000
;就是高位和低位反过来。
;程序的执行将dh里的数反顺序排列
;这段程序应该是没有使用,也就是说我们用的是正顺序码。而不是反顺序码。
mov cl,8
add_mcb_2:
shl dh,1 ;逻辑左移1位,高位进c,地位补0
rcr dl,1 ;带进位的循环右移,c进高位,低位进c
loop add_mcb_2
mov dh,dl
endif
;====================
mov al,dh ; get ms 8 bits,
rol al,1 ;循环左移,高位进c和低位,
rol al,1
rol al,1 ; put 3 bits at bottom
and al,7
mov bl,al ; save in bl
xor bh,bh ; make bx into an index to the byte.
mov al,dh ; get ms 8 bits,
ror al,1 ;循环右移,低位进c和高位
ror al,1 ; but at bottom
and al,7
mov cl,al ; save in cl
mov al,1
shl al,cl ; set the correct bit,
;逻辑左移1位,高位进c,地位补0
or [bx+di],al
pop cx
ret
;
; dx is high,
; bx is low.
; al is data
;======================
upd_crc:
push cx
mov cx,8 ; do 8 bits;cx=次数
mov ah,0
upd_crc1:
shl bx,1 ; shift bx ;bx在最开始时被设置为0xffff
;逻辑左移1位,高位进c,地位补0
rcl dx,1 ; through dx;dx最开始被设置为0xffff
;带进位循环左移,高位进c,c进低位
rcl ah,1 ; carry is at bottom of ah
;带进位循环左移,高位进c,c进低位
xor ah,al ; xor with lsb of data
;逻辑异或,结果放在左边的ah里,相同为0,不同为1
rcr ah,1 ; and put in carry bit
;带进位的循环右移,c进高位,低位进c
jnc upd_crc2
;
; autodin is x^32+x^26+x^23x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1
;
xor dx,0000010011000001b
xor bx,0001110110110110b + 1 ;plus one for end-around carry.
upd_crc2:
shr al,1 ; shift the data
; 循环右移,高位补0,低位进c
loop upd_crc1
pop cx
ret