前文配置生成了GTX IP,本文讲解xilinx官方提供的示例工程,获取IP使用方式,最后在仿真和上板。
1、分析示例工程各模块功能
首先选中生成的IP,然后鼠标右击Open IP Example Design生成该IP的示例工程。
之后选择示例工程存放路径,如下图所示。
生成的示例工程中,顶层模块gtwizard_0_exdes下包含三个模块,如下图所示。其中2号模块是GT IP相关的处理,3号模块用于生成GT IP的测试数据,4号模块将GT IP接收的数据进行校验。
顶层模块的RTL视图如下所示,输入包含接收数据差分对、GT参考时钟差分对、DRP时钟差分对,输出包括输出数据差分对和数据校验指示信号。
由于该模块只使用一个收发器,因此需要使用回环模式,才能进行上板测试。
1.1、数据生成模式
设计思路是从一个深度为512的ROM中循环读出数据,作为GTX IP的发送数据。
下图是该模块的部分截图,相关代码比较简单,就是同步复位信号,生成一个地址计数器,对时钟计数,后续每个时钟从ROM中读取一个数据输出。
剩余代码如下所示,由于ROM存储的数据是80位的,因此这里读出的数据也是80位的,但是最终只使用了16位到47位的32位数据,从后文的RTL视图可以得知。
注意一个问题,此处使用initial和$readmemh函数去初始化ROM是可以的,可能会有人认为这些是Verilog HDL的不可综合语法,但是这里的initial和$readmemh真的变成可综合的电路了?
有这部分理解的人应该是对“可综合”理解有问题,可综合其实是指综合成电路,比如if-else语句可以综合成数据选择器这种真实存在的电路结构。而initial和$readmemh在此处只是完成了对ROM内部数据的初始化,而这部分内容是在综合软件对工程综合时,就已经变成数字常量了,并不会对应具体的电路结构,因此虽然依旧能够完成初始化功能,但是并不是可综合语法。
从下图可知,数据生成模块输出的80位数据,只有中间的32位数据作为GTX IP的发送数据,ROM存储的4到8位数据作为K码指示信号。
由下图可知,ROM初始化数据是一组循环的16进制数据,每16个地址循环一次。红色框中的32位数据作为GTX IP待发送的数据,蓝色框中的8位数据作为GTX IP待发送数据的K码指示信号。
由此可知32’h060504bc的低8位数据是K码,及K28.5对应的十六进制数据。
1.2、数据校验模块
例化接收检测模块如下所示,设定的数据位宽与IP设置的用户位宽保持一致,且规定了一帧数据的开头为32’h060504bc,且逗号为16’h04bc。
GTX IP输出的数据只是完成了字节对齐,但是没有进行字对齐,接收模块在接收数据后,需要判断一帧数据的起始位置,然后进行字对齐,之后才能与发送的数据进行对比,因此该模块的代码还是有点麻烦。
如下所示,发送端是按照字节然后转换成串行数据发送的,先发送低字节数据,接收端会将接收字节进行对齐,比如发送端发送8’hbc,接收端依旧会输出8’bc。
但是接收端可能在任何时间开始接收数据,只能保证接收的每个字节的数据正确性,并不能保证接收的32位数据与发送端是一致的。比如下图接收端可能在8’h00开始接收的数据,那么GTX IP输出给用户的32位数据为32’h0504bc00,用户拿到这个数据后,需要自己将输出的32位数据对齐。
一般通过检测一帧数据的帧头,来调节输出数据的字对齐。由于示例工程的接收模块也考虑了数据位宽为80,64位等等,位宽越大,字对齐越复杂,导致该模块的代码很繁杂。
关于字对齐具体代码就不做讲解了,代码篇幅比较长,核心内容就是检测帧头,然后最后一个数据时需要做处理,可能有些字节是无效数据。
下图是通过对比发送和字对齐后的接收数据是否相同,从而生成错误指示信号。
1.3、GTX IP相关模块
主要关心的其实还是与GTX IP相关的模块,主要包含以下几部分。1号模块内部包含一个MMCM,GTX IP输出的TXOUTCLK通过MMCM生成TXUSRCLK、TXUSRCLK2、RXUSRCLK、RXUSRCLK2等时钟信号。还包含一个IBUFGDS_GTE2将GT差分时钟转换为单端时钟,作为2号模块的输入信号。
2号模块内部通过GT_COMMON原语调用QPLL,为GT IP提供参考时钟信号。3号模块是一个异步复位同步模块,生成的复位信号作为QPLL的复位信号之一。4就是生成的GTX IP。
该模块的RTL视图如下所示,包括几个模块也很明显。
内部模块如下所示,IBUFGDS_GTE2将差分时钟转换为单端时钟,之后再作为QPLL的输入,之后驱动GTX IP时钟管脚。
gtwizard_0_common_reset模块很简单,就是将复位信号同步到当前系统时钟域下,就不再赘述。
gtwizard_0_GT_USRCLK_SOURCE模块用于生成接收和发送通道的用户时钟信号,以及将差分时钟转换为单端时钟信号。
如下所示,直接调用IBUFGDS完成差分转单端功能。
下图是通过MMCM生成发送通道和接收通道的用户时钟信号TXUSRCLK2和RCUSRCLK2,以及PCS并行时钟TXUSRCLK和RXUSRCLK,由于在设置IP时,接收通道和发送通道的原时钟均采用TXOUTCLK,因此此处只使用了一个MMCM。
gtwizard_0_common模块内部只是调用了GTXE2_COMMON原语,达到使用QPLL的目的,关于该原语的具体参数,可以参考UG476手册,此处不再赘述。注意SIM_QPLLREFCLK_SEL和QPLLREFCLKSEL_IN的取值,与时钟信号所接的原语接口直接相关,可用于动态控制QPLL时钟输入。
如下图所示,参考时钟接在GTXE2_COMMON的GTREFCLK1_IN端口,那么SIM_QPLLREFCLK_SEL和QPLLREFCLKSEL_IN的值为1。由于ZYNQ7030只有一个GT bank,不存在南北bank的时钟信号,因此该模块并没有将另外四个参考时钟管脚引出。
关于示例工程的相关模块分析到此结束,GTX IP的信号很多,但是多数信号一般情况下是不会使用的,因此只需要关注少量使用端口即可。
示例工程模块分析到此结束,后续对该工程进行仿真和上板调试。
2、模块仿真
示例工程提供了TestBench,直接运行即可,仿真是将发送的差分信号与接收的差分信号短接。
下面是仿真运行结果,紫色信号是发送通道和接收通道的复位完成指示信号,为高电平表示复位完成,该IP在上电后会复位两个通道,复位完成后才能正常工作。
发送端的仿真结果如下所示,循环发送一帧数据,注意帧头数据为32’h060504bc,最字节是K码,对应的指示信号为高电平。
而接收通道接收的数据如下所示,当复位完成且字节对齐(gt0_rxbyteisaligned_out为高电平)后,接收的数据才是有效的。
如下图所示,逗号所在数据为32’h04bc0302,并不是发送时的32’h060504bc,这是用户自己需要接收数据后进行处理的。
前文所说的检测模块就会接收GTX IP输出的数据,然后检测帧头,进行字对齐处理。如下图所示,rx_data_r_track就是字对齐之后的数据,与发送的数据就保持一致了。
接收和发送的数据保持一致,表示GTX IP收发数据正确,仿真通过。
3、上板测试
这个工程不能直接上板,需要做一些修改,首先就是差分时钟输入问题,我的开发板光纤时钟时从CLK0进入的,因此需要将时钟输入端口进行修改。
如下图所示,QPLL时钟来源选择GTREFCLK0。
由于示例工程只使用了一个高速收发器通道,在上板测试时,需要使用回环功能,才能够正常测试。如下图所示,在顶层模块中将高速收发器设置为近端PMA回环模块。
使用回环模式,信号并不会输出FPGA管脚,因此损耗比较小,加重等参数可以不用修改。
示例工程的DRP时钟使用的差分时钟信号,由于开发板并没有多余的差分时钟,因此改为单端时钟,将IBUFDS注释掉,直接把DRPCLK_IN作为时钟输入引脚。
将上板需要观测的信号加入ILA中,之后综合工程,然后分配管脚。
上板之后,ILA抓取结果如下所示,有可能GTX IP接收的数据本来就与发送数据对齐,也有可能时错开的,下图就是对齐的情况。
当重新烧录程序后发现,GTX IP接收的数据与发送的数据又不是对齐的了,但是经过字对齐处理之后,才将数据对齐,如下图所示。
所以说想要正确使用该IP接收数据,用户必须完成接收数据的字对齐处理,否则无法保证接收数据正确性。
关于GTX IP的官方示例工程讲解到此结束,其实也比较简单,没有用那些复杂的信号,稍微难一点的就是接收端用户需要做字对齐。
可以利用GTX来完成自定义的PHY设置,相比aurora 8b/10b这种IP更加灵活,后续可能会有利用GTX IP完成自定义PHY的设计,到时候就需要自己完成接收部分的字对齐等等功能。
需要获取本文工程的可以在后台回复“GTX IP示例工程”(不包括引号)。
如果对文章内容理解有疑惑或者对代码不理解,可以在评论区或者后台留言,看到后均会回复!
如果本文对您有帮助,还请多多点赞👍、评论💬和收藏⭐!您的支持是我更新的最大动力!将持续更新工程!