SOPC Builder利用Avalon总线协议建立外设与NiosII的通信,最直接的好处是,它省去了FPGA开发人员编写NiosII与外设连接的TOP Entity的HDL代码。当然还有其他的好处,例如自动生成裁决器,用于多个主设备Master访问同一个外设时,并且可以时分复用的方式设置Master的优先级;当Avalon-MM位宽与外设位宽不一致时,SOPC自动完成其时序转换。
言归正传,具体Avalon-MM Slave的时序该如何设置呢?尤其是Read Wait?
<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
* Minimum arbitration shares:可以由多少个Master访问;
先看下面这个时序图:
上述时序的Read Wait:1Cycles;
A:读周期开始;
B:输出地址、字节使能、读使能信号;
C:置位片选信号;
D:第一个等待周期结束(当Read Wait: 1Cycles,也即等待周期结束,在下个时钟上升沿读入Readdata),锁存地址、字节使能等信号;
E:外设送出Readdata;
F:锁存Readdata,读周期结束;
再看下面这个时序图:
上述时序的Read Wait:2Cycles;
A:读周期开始;
B:输出地址、字节使能、读使能信号;
C:置位片选信号;
D:第一个等待周期结束(当Read Wait: 2Cycles,还有一个等待周期),锁存地址、字节使能等信号;
E:第二个等待周期结束(等待周期结束,在下个时钟上升沿读入Readdata);
F:外设送出Readdata;
G:锁存Readdata,读周期结束;
经过上述描述,我们应该知道Read Wait如何设置了,但是我们想一想,如果这个值设置错误时,是如何表现的?我说说我现实遇到的问题。
有一个自制外设,完成对一个数据流的特殊段进行过滤并把该段数据放在On-Chip RAM,RAM的数据读出接口是带寄存器输出,NiosII可以通过Avalon总线对RAM读,在读周期中的第三个时钟上升沿可以读入Readdata,也即Read Wait:2Cycles。但是很不幸,我设置为Read Wait:1Cycles。
假设在RAM的零偏移地址开始,放着0x11111111,0x22222222,0x33333333,0x44444444,用Memory Monitor观察得到的却是:0xXXXXXXXX,0x11111111,0x22222222,0x33333333,0x44444444。利用C将上述地址将16Bytes读入时,得不到正确数据。但是我们可以通过下述方法读入正确16Bytes数据:
A) 先读一遍零偏移地址,再从零到三将16Bytes读入;
B) 将零到四偏移地址20Bytes读入,截取后16Bytes读入;
C) 最正确的方法,Read Wait:2Cycles。
为什么会造成上述现象呢?当我们第一个读周期完成时,0x11111111刚刚锁存在RAM的输出寄存器上面,但是没有被NiosII读入;当第二个读周期完成时,0x22222222也刚刚锁存在RAM的输出寄存器上面,而此时NiosII读入的是0x11111111;周而复始,就造成了上述现象的发生。
总结,在读此篇文章之前,相信很多人就知道Read Wait如何设置,在这里长篇叙述,是想给自己的错误一个彻底的交待,避免再次发生。
参考文献:
Altera公司 Avalon Memory-Mapped Interface Specification.pdf
用户1278632 2011-1-28 22:14