终于找到关于RTL8019AS里的 MAR0-MAR7的计算的程序,源程序是80x86的汇编,我把它转换成了在keil c51里的程序,以便可以在51单片机里使用。
跟组播地址有关的寄存器:
为8个寄存器,提供对组播地址的过滤。跟crc的逻辑有关。MAR0-7 全部设置为0xff时,将接收所有的组播数据包,将MAR0-7 全部设置为0x00时,将不接收所有组播地址的数据包。在windows98里,该值被设置为:
MAR0=0x00;
MAR1=0x41;
MAR2=0x00;
MAR3=0x80;
MAR4=0x00;
MAR5=0x00;
MAR6=0x00;
MAR7=0x00;
用户在嵌入式的应用当中,可以设置为全部0xff,也可以对特定的组播地址(比如你用在网络电台广播)进行计算,生成一个你需要的过滤参数。建议该过滤的算法不写在单片机里,最好是先算好,存储在单片机里,用的时候直接调用,以节省单片机的程序空间。
这8个寄存器的值是根据组播地址数组的值生成的,提供对组播地址的过滤,过滤掉一些不属于自己接收组播数据包。
以下是在80x86 里的汇编程序:
点击这里打开。
;注解: laogu http://www.laogu.com
;这是一段在80x86里的汇编源程序,用来生成多播地址过滤的 MAR0-MAR7(以太网卡里的多播地址过滤寄存器)
;多播也叫组播。程序调用的时候 将组播地址列表的地址传递到ds:si ,
;列表相当于c语言里的二维数组 unsigned char multicast_addresses[ax][6];
; 因为每个地址的长度为6,总共有ax个组播地址。
; ds:si 相当于c语言里的指针 unsigned char *multicast_addresses ;
;将地址总数传递到ax,字节数(=地址总数*6)传递到 cx里(在这个程序里,没有用到cx传递的值)
;程序运算的结果放在mcast_list_bits里,相当于c语言里的unsigned char mcast_list_bits[8];
;程序里的di相当于c语言里的指针 unsigned char *mcast_list_bits;
;mcast_list_bits[8]对应于地址过滤寄存器MAR[8],即MAR0---MAR7
;函数 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
以下是在keil c51里的c语言程序,为斑竹所写
点击这里打开。
//作者laogu http://www.laogu.com
//程序的功能是根据多播地址multicast_address[6]的值,计算出MAR0-MAR7,就是multicast_filter[8];
//本程序指计算一个多播地址。如果有多个多播地址,将每个多播地址生成的multicast_filter[8]相或就可以了,
//例如根据多播地址 01:00:5e:00:00:01生成的 value1=multicast_filter[8];
//根据多播地址 01:00:5e:00:00:02生成的 value2=multicast_filter[8];
//那么对这两个多播地址生成的multicast_filter[8]=value1 | value2 ;将两个值相或
//很容易从这里得到如果要接收所有多播地址的数据包,MAR0--MAR7必须设置为0xff,就是说
//multicast_filter[8]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
#define al ax_value.bytes.low
#define bl bx_value.bytes.low
#define cl cx_value.bytes.low
#define ah ax_value.bytes.high
#define bh bx_value.bytes.high
#define dh dx_value.bytes.high
#define ax ax_value.word
#define bx bx_value.word
#define cx cx_value.word
#define dx dx_value.word
#define shl_bx if((bx&0x8000)!=0){cf=1;}else{cf=0;};bx=bx<<1;
#define shl_al if((al&0x80)!=0){cf=1;}else{cf=0;};al=al<<1;
#define shr_al if((al&0x01)!=0){cf=1;}else{cf=0;};al=al>>1;
#define rcl_dx if((dx&0x8000)!=0){cf_temp=1;}else{cf_temp=0;};dx=dx<<1;if(cf){dx=dx+1;};cf=cf_temp;
#define rcl_ah if((ah&0x80)!=0){cf_temp=1;}else{cf_temp=0;};ah=ah<<1;if(cf){ah=ah+1;};cf=cf_temp;
#define rcr_ah if((ah&0x01)!=0){cf_temp=1;}else{cf_temp=0;};ah=ah>>1;if(cf){ah=ah+0x80;};cf=cf_temp;
#define rol_al if((al&0x80)!=0){cf=1;}else{cf=0;};al=al<<1;if(cf){al=al+1;};
#define ror_al if((al&0x01)!=0){cf=1;}else{cf=0;};al=al>>1;if(cf){al=al+0x80;};
union u {unsigned int word;
struct{unsigned char high;unsigned char low;}bytes;//字节顺序为高位在前的2byte结构
};
union u ax_value;
union u bx_value;
union u cx_value;
union u dx_value;
bit cf;
bit cf_temp;
unsigned char multicast_address[6]={0x01,0x00,0x5e,0x00,0x00,0x00};
//unsigned char multicast_address[6]={0x00,0x00,0x00,0x5e,0x00,0x01}; //只计算一个多播地址
//unsigned char multicast_address[6]={0x01,0x80,0xc2,0x00,0x00,0x00};
unsigned char multicast_filter[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
//结果放在这里,就是MAR0--MAR7的值
//;;0x41,0x00,0x00,0x80,0x00,0x00,0x00,0x00;
void up_crc(unsigned char al_byte)
{
al=al_byte;
ah=0;
for (cx=0;cx<8;cx++)
{
shl_bx;
rcl_dx;
rcl_ah;
ah=ah^al;
rcr_ah;
if(cf){
dx=dx^0x04c1;// 0000,0100,1100,0001b
bx=bx^0x1db7; //0001,1101,1011,0110b + 1 ;plus one for end-around carry.
}
shr_al;
}
}
void add_mc_bits()
{
unsigned char i;
bx=0xffff;
dx=0xffff;
for(i=0;i<6;i++)
{
up_crc(multicast_address);
}
cl=8;
al=dh;
rol_al;
rol_al;
rol_al;
al=al&0x07;
bl=al;
bh=bh^bh;
al=dh;
ror_al;
ror_al;
al=al&0x07;
cl=al;
al=1;
for(i=0;i<cl;i++)
{
shl_al;
}
multicast_filter[bx]=multicast_filter[bx] | al;
}
main()
{
add_mc_bits(); //计算多播地址的MAR0-MAR7.
while(1);
}
|