内容 |
PCI卡有一个特殊的空间叫配置空间.该空间记录卡的中断,输入输出地址,内存映射,总线速度等一些PCI卡的信息.PCI的配置空间最多256字节,而PCI2.1标准规定的空间只有64字节,就是0x00-0x3F.RTL8019AS支持PCI2.1版本.所以空间只有64字节.超过64字节的空间0x40-0xFF为保留的.
PCI配置空间的读出内容如下:
PCI配置空间地址 |
读出内容 |
意义 |
0x00 |
0x802910EC |
DeviceID=8029 VendorID=10EC |
0x04 |
0x02000001 |
|
0x08 |
0x02000000 |
|
0x0C |
0x00000000 |
|
0x10 |
0x00000001 |
|
0x14 |
0x00000000 |
|
0x18 |
0x00000000 |
|
0x1C |
0x00000000 |
|
0x20 |
0x00000000 |
|
0x24 |
0x00000000 |
|
0x28 |
0x00000000 |
|
0x2C |
0x802910EC |
|
0x30 |
0x00000000 |
|
0x34 |
0x00000000 |
|
0x38 |
0x00000000 |
|
0x3C |
0x0000010F |
|
0x40--0xFF |
0x00000000 |
保留 |
PCI卡在复位之后(上电之后),它是处于待机状态的,卡属于禁止状态,就是说它还不能进行I/O或内存地址译码.必须先对它进行配置,才可以开始工作.配置就是对PCI配置空间进行一些读写的操作.
对RTL8029As来说,最重要的有几个配置寄存器,一个是BAR,一个是Command.分别介绍.
BAR:Base Address Register,地址译码寄存器,位于PCI配置空间的10-13H,读出内容如下:
bit 31-5 :BAR31-5,在还没有进行设置之前,读出值是一个不确定的值.
bit 4-2 :IOSIZE只读,为0,表示地址译码的大小为32个地址
bit 1:只读,为0
bit 0:IOIN ,只读,为1 ,表示该地址译码为I/O地址空间的译码.
初始化的时候向该寄存器写入全0就可以了.写入全0之后,网卡的译码地址为:
0x00000000--0x0000001F 译码空间为I/O地址空间.
可以看到网卡的32位的I/O地址译码的高3个字节是0,只有低位字节是需要变化的.
那么在PCI的接口逻辑的设计里,我们可以固定高3个字节的地址为0,然后只变化低位字节的地址.这样可以大大简化接口逻辑.同时也简化单片机对PCI总线的操作.
可以看到网卡的译码地址是I/O空间的地址译码,而没有内存地址的译码.那么对PCI卡进行内存译码的操作和接口是可以省略的.在我的PCI接口逻辑里,为了简化设计,没有进行内存地址寻址的逻辑设计.
我的设计只支持PCI配置空间寻址和I/O地址空间寻址.I/O地址寻址空间也限制在
0x00000000--0x000000FF范围内,最多支持256个I/O地址.而RTL8029AS只用了其中的32个地址.
设置完BAR之后,网卡实际上还没有开始工作. 还需要设置命令寄存器.
命令寄存器中只有最低位是可以写的,其他为只读.需要向该位IOEN写入1, 网卡才开始进行地址译码.
设置完这两个寄存器,网卡就可以开始工作了.开始工作之后,不需要再进行PCI配置空间的读写.
为了简化用户的程序设计,我提供了6个函数用来进行PCI接口的驱动.两个进行PCI配置空间读写的函数:
unsigned long read_config(unsigned char
address)
/*PCI 配置寄存器读,地址address必须是4的倍数0,4,8。。。。地址,一次读出4个字节 */
void write_config(unsigned char addr,unsigned
char value3,unsigned char value2,unsigned char value1,unsigned
char value0)
/*PCI 配置寄存器写,地址addr必须为4的倍数0,4,8。。。。,value3-value0为要写入的值,value3为高位字节,一次要写入4个字节?*/
4个读写网卡寄存器的函数:
unsigned char read_register(unsigned
char addr)//读网卡的寄存器
void write_register(unsigned char address_offset,unsigned
char value)//写网卡的寄存器
void write_dma_port(unsigned char value)//写网卡的Remote
DMA port
unsigned char read_register(unsigned
char addr) //读网卡的Remote DMA port
有了这6个函数,对PCI总线的操作就和ISA总线的操作一样了.通过这6个函数,用户可以方便的进行PCI卡的读写,而不需要太多的了解PCI总线的时序.
|