免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2225 | 回复: 0
打印 上一主题 下一主题

十.RTL8019AS,RTL8029AS如何读写网卡的RAM [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-03-18 20:44 |只看该作者 |倒序浏览

               
转自zcx3000的专栏~~~~http://blog.csdn.net/zcx3000/
最近把AX88796的datasheet看了一下,又看到了zcx3000关于RTL8019的一系列文章,转过来参考一下~~~~~~
要接收和发送数据包都必须读写网卡的内部的16k的ram,必须通过DMA进行读和写.网卡的内部ram是一块双端口的16k字节的ram.所谓双端口就
是说有两套总线连结到该ram,一套总线A是网卡控制器读/写网卡上的ram,另一套总线B是单片机读/写网卡上的ram.总线A又叫Local
DMA,总线B又叫Remote DMA.


  上图中虚线框住的部分为Remote DMA,也就是单片机对网卡ram进行读写的总线,对8019来说就是ISA总线.没有框住的部分(左边的部分),就是Local DMA,网卡控制器对网卡ram进行读写的总线.
其中的地址总线没有画出来,只画了数据总线.实际在ram的内部还有一些总线仲裁的逻辑,这里也没有画出来.所谓总线仲裁的逻辑就是为了实现两套总线都能进行对ram的读写,而不互相冲突.
网卡控制器读写网卡ram(Local DMA)的优先级比单片机读写网卡ram的优先级要高.优先级要高的意思是:
1.当两者都要请求控制总线时.Local DMA优先获得控制权.
2.高优先级的Local DMA可以中断Remote DMA,而Remote DMA不能中断Local DMA
3.
在Remote DMA,也就是单片机对网卡ram读写的过程进行中可以被Local DMA中断,Local DMA中断Remote
DMA,然后进行Local DMA的数据传输,Local DMA传输完毕之后继续刚才被中断的Remote DMA,以完成Remote
DMA的传输.

 
 上图中的Remote就是Remote DMA的传输,Local burst就是Local DMA的传输.图的左边是一个Remote
DMA被Local DMA中断的示意图.Remote DMA是等到Local
Burst完成之后才结束该次的传输.被打断多久的时间取决于FT1,FT0(是DCR配置寄存器的位)


  单片机的总线要比网卡的DMA总线慢很多.网卡的DMA总线大概在10Mhz,而单片机的总线大概1Mhz.所以在Remote DMA的过程中不需要特别的等待时序.
  但是如果使用较快的CPU,比如DSP,ARM等,可能要考虑时序问题.也就是说IOCHRDY(ISA总线的一个信号,RTL8019AS),或者TRDY(PCI总线的信号 RTL8029AS) ,是需要考虑连到CPU上,或者做一定的处理.
  那么对于不快也不慢的AVR单片机来说,要不要接IOCHRDY?估计是要的.因为我不提供avr的上网方案,所以也没有做太多的研究.对于77E58来说可以不接IOCHRDY,因为77E58可以内部设置外部ram的存取的速度.
  DMA有8位和16位两种.网卡支持这两种DMA,一般我们使用8位的DMA,8位的DMA的接线比较少,同时适合单片机处理.电脑里一般使用16位DMA.
  有人问到在电脑里如何使用8位的DMA的问题.有些卡自动检测总线上的IOCS16B来选择总线,比如RTL8019as,我试过
RTL8019as使用8位DMA在电脑里是失败的.如果真的要在电脑里使用8位的DMA,要把该引脚IOCS16B断开(可以割断),而不连到ISA总
线上,这样这些网卡会自动的进行8位的操作(地址译码为10位).
对于使用DM9008芯片的网卡,16位DMA传输是由SLOT引脚决定的。我试过把DM9008的IOCS16B
引脚与ISA槽断开(通过贴“透明胶”的方法),配套的设置程序检查时死机。如果想DM9008
使用8位DMA操作,应该把SLOT引脚割断,而不是IOCS16B。
在DSP里可以使用16位的DMA.
  因为不同的单片机(CPU),代码可能不同,我在下面将用几种表示法来论述:
  假设用到的I/O地址为0xC000,读出到temp变量或写temp到寄存器,temp为8位变量:
   
        
            通用的
            RTL8019 C程序(mcs51)
            RTL8019 汇编的程序(mcs51)
        
        
            temp=read_register(address)
读寄存器函数
            temp=reg00;
            MOV DPTR,#address
MOVX A,@DPTR
MOV temp,A
        
        
            write_register(address,temp)
写寄存器函数
            reg00=temp;
            MOV temp,A
MOV DPTR,#address
MOVX @DPTR,A
        
        
            
            注:
#define reg00 XBYTE[0xc000]
            注:address equ 0C000H
        
   
通用的表达式:
void write_register(unsigned char address,unsigned char value)或
void write_register(unsigned int address,unsigned char value)
unsigned char read_register(unsigned char address)或
unsigned char read_register(unsigned int address)
上面的表达式中,根据你的地址或寻址方法而选择unsigned int address或unsigned char address.
上表给出了用c语言或汇编语言或其他语言的表达的等价的程序.
下面给出用51单片机的c语言程序:
#define reg00 XBYTE[0xc000] //reg00- 10为isa网卡接口的寄存器地址240-250;
#define reg01 XBYTE[0xc100]
#define reg02 XBYTE[0xc200]
#define reg03 XBYTE[0xc300]
#define reg04 XBYTE[0xc400]
#define reg05 XBYTE[0xc500]
#define reg06 XBYTE[0xc600]
#define reg07 XBYTE[0xc700]
#define reg08 XBYTE[0xc800]
#define reg09 XBYTE[0xc900]
#define reg0a XBYTE[0xca00]
#define reg0b XBYTE[0xcb00]
#define reg0c XBYTE[0xcc00]
#define reg0d XBYTE[0xcd00]
#define reg0e XBYTE[0xce00]
#define reg0f XBYTE[0xcf00]
#define reg10 XBYTE[0xd000]
xdata unsigned char buffer[1536];//缓冲区,放在外部ram.
unsigned int count;//需要读或写的字节数
unsigned int i;
//DCR=0xc8;要配置DCR为8位的dma
void write_dma(unsigned int address,unsigned int count)//写网卡的ram
{//address为要写入到网卡里的ram的起始地址,count为要连续写入的字节数
page(0);
reg09=address>>8;//address high
reg08=address&0xff;//address low
reg0b=count>>8; //write count high
reg0a=count&0xff;//write count low
reg00=0x12 ;//dma write
for(i=0;i>8;//address high
reg08=address&0xff;//address low
reg0b=count>>8; //write count high
reg0a=count&0xff;//write count low
reg00=0x0a ;//dma read
for(i=0;i>8;//address high
reg08=address&0xff;//address low
reg0b=count>>8; //write count high
reg0a=count&0xff;//write count low
reg00=0x12 ;//dma write
[color="#3333ff"]count=(count+1) /2;
for(i=0;i>8;//address high
reg08=address&0xff;//address low
reg0b=count>>8; //write count high
reg0a=count&0xff;//write count low
reg00=0x0a ;//dma read
[color="#0000ff"]count=(count+1) /2;
for(i=0;i<count;i++)
{
buffer=reg10;
}

[color="#ff3333"]reg0b=0; // count high 中止DMA操作
reg0a=0;// count low
reg00=0x22;//abort/complete dma page 0

}
上面的count=(ount+1) /2,为什么要加一,是因为读取字节数为单数的时候就要.
               
               
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/84137/showart_1867718.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP