3.3 复位和初始化
GTP 收发器必须在 FPGA 器件上电和配置后初始化,然后才能使用。GTP 收发器的发射器 (TX) 和接收器 (RX) 可以独立且并行地初始化,如图 2-11 所示。GTP 收发器的 TX 和 RX 初始化包括两个步骤:
初始化驱动 TX/RX 的相关 PLL 初始化 TX 和 RX 数据路径 (PMA + PCS) GTP 收发器的 TX 和 RX 可以从 PLL0 或 PLL1 接收时钟。TX 和 RX 使用的相关 PLL(PLL0/PLL1)必须先初始化,然后才能初始化 TX 和 RX。TX 和 RX 使用的任何 PLL 都单独复位,其复位操作完全独立于所有 TX 和 RX 复位。TX 和 RX 数据路径必须仅在相关 PLL 锁定后初始化,初始化流程如下:
这一部分有官方的复位逻辑代码,感兴趣的朋友可以仔细阅读一下官方代码。
四、环回模式
环回模式是收发器数据路径的专门配置,其中流量被折回源。通常,会传输特定的流量模式,然后进行比较以检查错误。一共有四种环回模式,如下如所示:
控制接口如下:
. gt0_loopback_in ( gt0_loopback_in) ,
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
环回测试模式分为两大类:
近端环回模式将数据回传到最靠近流量生成器的收发器中
①Near-end PCS Loopback:必须启用 RX 弹性缓冲区,并将 RX_XCLK_SEL 设置为 RXREC,以使近端 PCS 环回正常工作。在近端 PCS 环回中,RX XCLK 域由 TX PMA 并行时钟 (TX XCLK) 提供时钟。如果在正常运行期间使用 RXOUTCLK 为 FPGA 逻辑提供时钟,并将 RXOUTCLKSEL 设置为 RXOUTCLKPMA,则在将 GTP 收发器置于近端 PCS 环回中时,必须更改以下两项之一: 1、Set RXOUTCLKSEL to select RXOUTCLKPCS 2、Set RXCDRHOLD = 1’b1
②Near-end PMA Loopback :进入和退出近端 PMA 环回后需要 GTRXRESET
远端环回模式将接收到的数据环回到链路远端的收发器中
③Far-end PMA Loopback:必须启用 TX 缓冲区,并且必须将 TX_XCLK_SEL 设置为 TXOUT,以使远端 PMA 环回正常工作。 在远端 PMA 环回中,TX 缓冲区的写入侧由 RX PMA 并行时钟 (RX XCLK) 计时。 进入和退出远端 PMA 环回后,需要 GTTXRESET。 ④ Far-end PCS Loopback:如果未使用时钟校正,远端 PCS 环回中的收发器必须使用与作为环回数据源的收发器相同的参考时钟。无论是否使用时钟校正,端口 TXUSRCLK 和 RXUSRCLK 都必须由相同的时钟资源 (BUFG、BUFH) 驱动。 当通道中的两个或一个变速箱均启用时,不支持远端 PCS 环回。
4.1 环回选择端口属性
class="table-box">信号名称 方向 描述 LOOPBACK[2:0] in 000: Normal operation 001: Near-End PCS Loopback 010: Near-End PMA Loopback 011: Reserved 100: Far-End PMA Loopback 101: Reserved 110: Far-End PCS Loopback
class="table-box">
五、发送模块讲解
对于用户来说,发送数据只需使用以下三个信号即可,其它的根据GUI配置后,GTP就会自动将数据发送出去:
. gt0_txdata_in ( gt0_txdata_in) ,
. gt0_txusrclk_in ( gt0_txusrclk_i) ,
. gt0_txusrclk2_in ( gt0_txusrclk2_i) ,
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
5.1 TX 接口介绍
FPGA TX 接口是 FPGA 到 GTP 收发器 TX 数据路径的网关。 用户通过在 TXUSRCLK2 的上升沿将数据写入 TXDATA 端口来通过 GTP 收发器传输数据。端口的宽度可以配置为两个或四个字节宽。端口的实际宽度取决于 TX_DATA_WIDTH 属性和 TX8B10BEN 端口设置。端口宽度可以是 16、20、32 和 40 位。接口处的并行时钟 (TXUSRCLK2) 的速率由 TX 线路速率、TXDATA 端口的宽度以及是否启用 8B/10B 编码决定。必须为发射器中的内部 PCS 逻辑提供第二个并行时钟 (TXUSRCLK)
GTP 收发器包含 2 字节内部数据路径。FPGA 接口宽度可通过设置 TX_DATA_WIDTH 属性进行配置。当启用 8B/10B 编码器时,必须将 TX_DATA_WIDTH 属性配置为 20 位或 40 位,在这种情况下,FPGA TX 接口仅使用 TXDATA 端口。例如,当 FPGA 接口宽度为 16 时,使用 TXDATA[15:0]。当绕过 8B/10B 编码器时,TX_DATA_WIDTH 属性可以配置为任何可用宽度:16、20、32 或 40 位。
当启动8b10b编码后,对于用户来说,发送端口模块的信号就变成了6个,新增三个信号代码如下:
. gt0_txchardispmode_in ( gt0_txchardispmode_in) ,
. gt0_txchardispval_in ( gt0_txchardispval_in) ,
. gt0_txcharisk_in ( gt0_txcharisk_in) ,
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
当禁止8b10b编码时
class="table-box">信号名称 方向 描述 TXCHARDISPMODE[3:0] in 当 8B/10B 编码被禁用时,TXCHARDISPMODE 用于扩展 20 位和 40 位 TX 接口的数据总线。 TXCHARDISPVAL[3:0] in 当 8B/10B 编码被禁用时,TXCHARDISPVAL 用于扩展 20 位和 40 位 TX 接口的数据总线。
class="table-box">
当启动8b10b编码后,有了极性控制的作用
class="table-box">TXCHARDISPMODE TXCHARDISPVAL 描述 0 0 保留 0 1 反转RD极性 1 0 设置RD为负 1 1 设置RD为正
class="table-box">
5.2 发送时钟结构
5.2.1 TXUSRCLK 和 TXUSRCLK2 关系
FPGA TX 接口包括两个并行时钟:TXUSRCLK 和 TXUSRCLK2。 TXUSRCLK 是 GTP 收发器发射器中 PCS 逻辑的内部时钟。TXUSRCLK 所需的速率取决于 GTPE2_CHANNEL 原语的内部数据路径宽度和 GTP 收发器发射器的 TX 线速率。 TXUSRCLK2 频率与 TXUSRCLK 的关系:
class="table-box">FPGA Interface Width TX_DATA_WIDTH TXUSRCLK2 Frequency 2-Byte 16, 20 TXUSRCLK2 = TXUSRCLK 4-Byte 32, 40 TXUSRCLK2 = TXUSRCLK/2
class="table-box">
5.2.2 使用 TXOUTCLK 驱动 TX 接口
上图展示了发送模块的详细时钟结构,其中TXOUTCLK 来自 MGTREFCLK0[P/N] 或 MGTREFCLK1[P/N],还有TXOUTCLKPCS、TXOUTCLKPMA;通过TXOUTCLKSEL端口来选择。TXOUTCLK可以提供TXUSRCLK和TXUSRCLK2,具体如下所示: 上图中TXOUTCLK 用于在一个通道配置中驱动 2 字节模式(TX_DATA_WIDTH = 16 或 20)的 TXUSRCLK 和 TXUSRCLK2。TXUSRCLK2 的频率等于 TXUSRCLK
上图中TXOUTCLK 用于驱动 4 字节模式 (TX_DATA_WIDTH = 32 或 40) 的 TXUSRCLK2。TXUSRCLK2 的频率等于 TXUSRCLK 频率的一半。 MMCM 或 PLL 是位于器件上半部分的时钟管理块 (CMT) 的一部分,只能驱动器件上半部分的 BUFG。同样,位于下半部分的 MMCM 或 PLL 只能驱动下半部分的 BUFG。
&emspTXSYSCLKSEL是一个2bit数据,用来选择TXOUTCLK源和TXPMA时钟源,高位[1]选择TXOUTCLK源来自PLL0或者PLL1的参考时钟,低位[0]选择TXPMA来自PLL0或者PLL1的输出。“/D”分频器为我们提供了每通道实现不一样速率的方式,但只能实现1、2、4、8分频。所以每个发送器PMA模块都有一个D分频器,它将PLL的时钟分频,以降低线路速率,通过TXRATE来控制。
5.3 TX BUFFER
发送缓冲fifo可以选择不使用,但是如果没有特别的速率要求还是打开好一点。
还有一个信号来指示缓冲FIFO的状态,TXBUFSTATUS [1:0]:
class="table-box">端口名 方向 时钟域 说明 TXBUFSTATUS[1:0] out TXUSRCLK2 TX 缓冲区状态。 TXBUFSTATUS[1]:TX 缓冲区溢出或下溢状态。当 TXBUFSTATUS[1] 设置为高电平时,它将保持高电平直到 TX 缓冲区复位。 1:TX FIFO 有溢出或下溢。 0:无 TX FIFO 溢出或下溢错误。 TXBUFSTATUS[0]:TX 缓冲区已满。 1:TX FIFO 至少为半满。 0:TX FIFO 未满半满。
其它的端口设计到具体的通信协议,比如PCIE,SRIO等等,等以后用到了再讲解。
class="table-box">
六、接收模块讲解
6.1 接收器结构框图
每个 GTP 收发器都包含一个独立的接收器,由 PCS 和 PMA 组成。上图显示了 GTP 收发器 RX 的模块。高速串行数据从电路板上的走线流入 GTP 收发器 RX 的 PMA,再流入 PCS,最后流入 FPGA 逻辑。
6.2 模拟前端
模拟信号进入GT收发器后,该部分需要对其进行数字化分析处理。例如信号放大,电压均衡等,也就是上图的RX_EQ模块,具体更详细的内部结构图如下所示:
对于用户来说,需要配置的有两点:
配置接收端电压模式 校准终端电阻
配置终端电阻来选择接收的电压摆幅范围。
6.3 RX_EQ均衡器
GTP 收发器接收器具有节能的自适应连续时间线性均衡器 (CTLE),可补偿物理信道中高频衰减导致的信号失真。CTLE 被称为低功耗模式 (LPM)
6.4 CDR时钟恢复
每个 GTPE2_CHANNEL 收发器中的 RX 时钟数据恢复 (CDR) 电路从传入数据流中提取恢复的时钟和数据。PLL0 或 PLL1 为相位插值器提供基准时钟。相位插值器依次产生精细、均匀间隔的采样相位,以允许 CDR 状态机进行精细相位控制。CDR 状态机可以跟踪可能与本地 PLL 参考时钟存在频率偏移的传入数据流。
6.5 接收时钟结构
接收器的时钟结构和发送器的时钟结构几乎一模一样,因此这里不过多介绍。
6.6 极性控制
如果 PCB 上的 RXP 和 RXN 差分走线意外接反了,GTP 收发器 RX 接收的差分数据将被反转。GTP 收发器 RX 允许在 SIPO 之后对 PCS 中的并行字节进行反转,以抵消差分对上的反转极性。 极性控制功能使用 RXPOLARITY 输入,该输入由结构用户界面驱动为高电平以反转极性。
class="table-box">端口名 方向 时钟域 说明 RXPOLARITY in RXUSRCLK2 RXPOLARITY 端口可以反转输入数据的极性:0:不反转。RXP 为正,RXN 为负。 1:反转。RXP 为负,RXN 为正
class="table-box">
6.7 接收字节对齐
串行数据必须与符号边界对齐,然后才能用作并行数据。为了实现对齐,发送器发送一个可识别的序列,通常称为逗号。接收器在传入数据中搜索逗号。当它找到逗号时,它会将逗号移动到字节边界,以便接收的并行字与发送的并行字匹配。
下图左侧显示TX为并行数据,右侧显示RX接收到逗号对齐后可识别的并行数据。 要启用逗号对齐块,RXCOMMADETEN 端口将被驱动为高电平。 RXCOMMADETEN 将被驱动为低电平,以完全绕过该块,从而实现最短延迟 这些逗号码都是8B10B里面的内容,后续会单独出一篇文章来了解并实现8B10B,这里就先大致了解一下即可。
6.8 接收弹性缓冲区
GTP收发器RX数据通路的PCS部分有两个内部并行时钟域:PMA并行时钟域(XCLK)和RXUSRCLK域。要保证数据的正确接收,不仅要求速率一致,也要解决两个时钟域之间的相位差异,如下图所示:
为解决该问题,Xilinx提供了两种解决方案,一是利用弹性缓冲区,二是用相位对齐。
RX 相位对齐电路用于在绕过 RX 弹性缓冲器时调整 PMA 并行时钟域 (XCLK) 和 RXUSRCLK 域之间的相位差。它还通过调整 RXUSRCLK 来执行 RX 延迟对齐,以补偿温度和电压变化。组合的 RX 相位和延迟对齐可以由 GTP 收发器自动执行,也可以由用户手动控制。 RX 缓冲区是建议尽可能使用的默认缓冲区。它功能强大且更易于操作;可以使用 RX 恢复时钟或本地时钟(带时钟校正);时钟校正和通道绑定所需
6.9 时钟矫正
RX 弹性缓冲器旨在桥接两个不同的时钟域,即 RXUSRCLK 和 XCLK,后者是从 CDR 恢复的时钟。即使 RXUSRCLK 和 XCLK 以相同的时钟频率运行,也总是存在微小的频率差异。由于 XCLK 和 RXUSRCLK 并不完全相同,因此除非纠正,否则差异可能会累积,最终导致 RX 弹性缓冲器溢出或下溢。为了允许纠正,每个 GTP 收发器 TX 都会定期传输一个或多个特殊字符,GTP 收发器 RX 可以根据需要在 RX 弹性缓冲器中移除或复制这些字符。通过在 RX 弹性缓冲器太满时移除字符并在 RX 弹性缓冲器太空时复制字符,接收器可以防止溢出或下溢。
6.10 用户接口
上面介绍的大部分是接收器的功能配置,实际上对于用户来说,需要使用的端口只有几个:
. gt0_rxdata_out ( gt0_rxdata_out) ,
. gt0_rxusrclk_in ( gt0_rxusrclk_i) ,
. gt0_rxusrclk2_in ( gt0_rxusrclk2_i) ,
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
如果启用了8B10B解码,则还增加两个:
. gt0_rxcharisk_out ( gt0_rxcharisk_out) ,
. gt0_rxdisperr_out ( gt0_rxdisperr_out) ,
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
端口信号功能和发送端一样。
七、GTP眼图下板测试
7.1 IBERT核例化
在配置GTP之前,我们可以使用Xilinx提供的IBERT核来测试一下我们的GTP功能是否正常,通过收发器由外部回环进行自收自发而实现。就是将同一组收发器的 TX 和 RX 进行短接,TX 发送端通过发送某种特定序列的数据流,在 RX 接收端接收后,通过比对发送和接收的数据,从而得出误码率和眼图信息,来验证开发板 GTP 部分工作的稳定性和可靠性。
打开IP库搜索IBERT,然后打开。
7.2 连接光纤
配置好后直接打开设计例程,然后分配管脚直接下板; 首先插入一个SFP,然后用光纤把发送和接收端短接在一起,然后下载程序。
7.3 下载程序
下载后会自动弹出响应的收发器链接的通道以及速率。
选择7bit伪随机序列,然后复位后跑一段时间观察误码率一直为0,说明GTP运行没问题,我们更改一下伪随机序列为31bit,然后点击复位。
更换了31bit的伪随机序列误码率依然为0。
更换另一组GTP收发器测试依然误码率一直为0
7.4 创建眼图扫描
点击加号创建一个眼图扫描 中间蓝色部分区域越大,表示GTP 所对应的 PCB 高速电路的信号完整性越好。
八、配置GTP
既然板级上的GTP和连线没有问题,那我们就用官方例程实现GTP通信验证一下,开始例化IP核。
九、分析官方例程
9.1 打开设计例程
GTP的IP核例化成功后,我们打开设计例程:
gtwizard_0_support :实例化GTP的顶层模块 gtwizard_0_GT_USRCLK_SOURCE:产生用户使用时钟和发送时钟 gtwizard_0_cpll_railing:收发器的断电复位和初始化模块 gtwizard_0_common:例化收发器的原语 gtwizard_0_common_reset:产生CPLL复位 GT收发器 发送数据产生模块 接收数据校验模块 接收数据文件 发送数据文件
9.2 gtwizard_0_GT_USRCLK_SOURCE模块分析
源码如下:
`timescale 1 ns / 1 ps
module gtwizard_0_GT_USRCLK_SOURCE
(
output GT0_TXUSRCLK_OUT,
output GT0_TXUSRCLK2_OUT,
input GT0_TXOUTCLK_IN,
output GT0_RXUSRCLK_OUT,
output GT0_RXUSRCLK2_OUT,
input GT0_RXOUTCLK_IN,
input wire Q0_CLK1_GTREFCLK_PAD_N_IN,
input wire Q0_CLK1_GTREFCLK_PAD_P_IN,
output wire Q0_CLK1_GTREFCLK_OUT
) ;
`define DLY #1
wire tied_to_ground_i;
wire tied_to_vcc_i;
wire gt0_txoutclk_i;
wire gt0_rxoutclk_i;
wire q0_clk1_gtrefclk ;
wire gt0_txusrclk_i;
wire gt0_rxusrclk_i;
assign tied_to_ground_i = 1 'b0;
assign tied_to_vcc_i = 1 'b1;
assign gt0_txoutclk_i = GT0_TXOUTCLK_IN;
assign gt0_rxoutclk_i = GT0_RXOUTCLK_IN;
assign Q0_CLK1_GTREFCLK_OUT = q0_clk1_gtrefclk;
IBUFDS_GTE2 ibufds_instQ0_CLK1
(
. O ( q0_clk1_gtrefclk) ,
. ODIV2 ( ) ,
. CEB ( tied_to_ground_i) ,
. I ( Q0_CLK1_GTREFCLK_PAD_P_IN) ,
. IB ( Q0_CLK1_GTREFCLK_PAD_N_IN)
) ;
BUFG txoutclk_bufg0_i
(
. I ( gt0_txoutclk_i) ,
. O ( gt0_txusrclk_i)
) ;
BUFG rxoutclk_bufg1_i
(
. I ( gt0_rxoutclk_i) ,
. O ( gt0_rxusrclk_i)
) ;
assign GT0_TXUSRCLK_OUT = gt0_txusrclk_i;
assign GT0_TXUSRCLK2_OUT = gt0_txusrclk_i;
assign GT0_RXUSRCLK_OUT = gt0_rxusrclk_i;
assign GT0_RXUSRCLK2_OUT = gt0_rxusrclk_i;
endmodule
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
正如前面3.1节所说,外部输入的参考差分时钟进入GT前会先进入一个缓冲器转变成单端时钟后给收发器使用,具体IBUFDS_GTE2原语的使用方法,看本文的第3.1.1节。
除此之外,输入给用户的TX时钟以及RX时钟的来源是自己通过GUI界面选的如下所示:
其中TXUSRCLK 和 TXUSRCLK2 关系以及RXUSRCLK 和 RXUSRCLK2 关系请看本文的第5.2.1节。
9.3 gtwizard_0_cpll_railing 模块分析
源码分析:
`timescale 1 ns / 1 ps
`define DLY #1
module gtwizard_0_cpll_railing #
(
parameter USE_BUFG = 0
)
(
output cpll_reset_out,
output cpll_pd_out,
output refclk_out,
input refclk_in
) ;
( * equivalent_register_removal= "no" * ) reg [ 95 : 0 ] cpllpd_wait = 96 'hFFFFFFFFFFFFFFFFFFFFFFFF;
( * equivalent_register_removal= "no" * ) reg [ 127 : 0 ] cpllreset_wait = 128 'h000000000000000000000000000000FF;
wire refclk_i;
generate
if ( USE_BUFG == 1 )
begin
BUFG refclk_buf
( . O ( refclk_i) ,
. I ( refclk_in) ) ;
end
else
begin
BUFH refclk_buf
( . O ( refclk_i) ,
. I ( refclk_in) ) ;
end
endgenerate
assign refclk_out = refclk_i;
always @( posedge refclk_i)
begin
cpllpd_wait <= { cpllpd_wait[ 94 : 0 ] , 1 'b0} ;
cpllreset_wait <= { cpllreset_wait[ 126 : 0 ] , 1 'b0} ;
end
assign cpll_pd_out = cpllpd_wait[ 95 ] ;
assign cpll_reset_out = cpllreset_wait[ 127 ] ;
endmodule
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
本模块输出的cpll_pd_out信号是对 CPLL进行断电操作,高电平有效 上电后对CPLL进行断电96个周期然后拉低。 cpll_reset_out信号是对CPLL进行高电平复位的信号,上电后,等待120个周期后,拉高8个时钟周期的cpll 复位信号,然后再拉低。 refclk_out:在上面差分参考时钟进入IBUFDS_GTE2后转成单端信号,再进入BUFG或者BUFH,然后输出给收发器。整个模块仿真如下图所示:
9.4 gtwizard_0_common 模块分析
这个模块就是例化出硬核GT收发器,看不到源码,只能看到信号接入端口:
`default_nettype wire
`timescale 1 ns / 1 ps
`define DLY #1
module gtwizard_0_common #
(
parameter WRAPPER_SIM_GTRESET_SPEEDUP = "TRUE" ,
parameter SIM_PLL0REFCLK_SEL = 3 'b001,
parameter SIM_PLL1REFCLK_SEL = 3 'b001
)
(
output PLL0OUTCLK_OUT,
output PLL0OUTREFCLK_OUT,
output PLL0LOCK_OUT,
input PLL0LOCKDETCLK_IN,
output PLL0REFCLKLOST_OUT,
input PLL0RESET_IN,
input [ 2 : 0 ] PLL0REFCLKSEL_IN,
input PLL0PD_IN,
output PLL1OUTCLK_OUT,
output PLL1OUTREFCLK_OUT,
input GTREFCLK1_IN,
input GTREFCLK0_IN
) ;
parameter PLL0_FBDIV_IN = 4 ;
parameter PLL1_FBDIV_IN = 1 ;
parameter PLL0_FBDIV_45_IN = 5 ;
parameter PLL1_FBDIV_45_IN = 4 ;
parameter PLL0_REFCLK_DIV_IN = 1 ;
parameter PLL1_REFCLK_DIV_IN = 1 ;
wire tied_to_ground_i;
wire [ 63 : 0 ] tied_to_ground_vec_i;
wire tied_to_vcc_i;
wire [ 63 : 0 ] tied_to_vcc_vec_i;
assign tied_to_ground_i = 1 'b0;
assign tied_to_ground_vec_i = 64 'h0000000000000000;
assign tied_to_vcc_i = 1 'b1;
assign tied_to_vcc_vec_i = 64 'hffffffffffffffff;
GTPE2_COMMON #
(
. SIM_RESET_SPEEDUP ( WRAPPER_SIM_GTRESET_SPEEDUP) ,
. SIM_PLL0REFCLK_SEL ( SIM_PLL0REFCLK_SEL) ,
. SIM_PLL1REFCLK_SEL ( SIM_PLL1REFCLK_SEL) ,
. SIM_VERSION ( "2.0" ) ,
. PLL0_FBDIV ( PLL0_FBDIV_IN ) ,
. PLL0_FBDIV_45 ( PLL0_FBDIV_45_IN ) ,
. PLL0_REFCLK_DIV ( PLL0_REFCLK_DIV_IN) ,
. PLL1_FBDIV ( PLL1_FBDIV_IN ) ,
. PLL1_FBDIV_45 ( PLL1_FBDIV_45_IN ) ,
. PLL1_REFCLK_DIV ( PLL1_REFCLK_DIV_IN) ,
. BIAS_CFG ( 64 'h0000000000050001) ,
. COMMON_CFG ( 32 'h00000000) ,
. PLL0_CFG ( 27 'h01F03DC) ,
. PLL0_DMON_CFG ( 1 'b0) ,
. PLL0_INIT_CFG ( 24 'h00001E) ,
. PLL0_LOCK_CFG ( 9 'h1E8) ,
. PLL1_CFG ( 27 'h01F03DC) ,
. PLL1_DMON_CFG ( 1 'b0) ,
. PLL1_INIT_CFG ( 24 'h00001E) ,
. PLL1_LOCK_CFG ( 9 'h1E8) ,
. PLL_CLKOUT_CFG ( 8 'h00) ,
. RSVD_ATTR0 ( 16 'h0000) ,
. RSVD_ATTR1 ( 16 'h0000)
)
gtpe2_common_i
(
. DMONITOROUT ( ) ,
. DRPADDR ( tied_to_ground_vec_i[ 7 : 0 ] ) ,
. DRPCLK ( tied_to_ground_i) ,
. DRPDI ( tied_to_ground_vec_i[ 15 : 0 ] ) ,
. DRPDO ( ) ,
. DRPEN ( tied_to_ground_i) ,
. DRPRDY ( ) ,
. DRPWE ( tied_to_ground_i) ,
. GTEASTREFCLK0 ( tied_to_ground_i) ,
. GTEASTREFCLK1 ( tied_to_ground_i) ,
. GTGREFCLK1 ( tied_to_ground_i) ,
. GTREFCLK0 ( GTREFCLK0_IN) ,
. GTREFCLK1 ( GTREFCLK1_IN) ,
. GTWESTREFCLK0 ( tied_to_ground_i) ,
. GTWESTREFCLK1 ( tied_to_ground_i) ,
. PLL0OUTCLK ( PLL0OUTCLK_OUT) ,
. PLL0OUTREFCLK ( PLL0OUTREFCLK_OUT) ,
. PLL1OUTCLK ( PLL1OUTCLK_OUT) ,
. PLL1OUTREFCLK ( PLL1OUTREFCLK_OUT) ,
. PLL0FBCLKLOST ( ) ,
. PLL0LOCK ( PLL0LOCK_OUT) ,
. PLL0LOCKDETCLK ( PLL0LOCKDETCLK_IN) ,
. PLL0LOCKEN ( tied_to_vcc_i) ,
. PLL0PD ( PLL0PD_IN) ,
. PLL0REFCLKLOST ( PLL0REFCLKLOST_OUT) ,
. PLL0REFCLKSEL ( PLL0REFCLKSEL_IN) ,
. PLL0RESET ( PLL0RESET_IN) ,
. PLL1FBCLKLOST ( ) ,
. PLL1LOCK ( ) ,
. PLL1LOCKDETCLK ( tied_to_ground_i) ,
. PLL1LOCKEN ( tied_to_vcc_i) ,
. PLL1PD ( 1 'b1) ,
. PLL1REFCLKLOST ( ) ,
. PLL1REFCLKSEL ( 3 'b001) ,
. PLL1RESET ( tied_to_ground_i) ,
. BGRCALOVRDENB ( tied_to_vcc_i) ,
. GTGREFCLK0 ( tied_to_ground_i) ,
. PLLRSVD1 ( 16 'b0000000000000000) ,
. PLLRSVD2 ( 5 'b00000) ,
. REFCLKOUTMONITOR0 ( ) ,
. REFCLKOUTMONITOR1 ( ) ,
. PMARSVDOUT ( ) ,
. BGBYPASSB ( tied_to_vcc_i) ,
. BGMONITORENB ( tied_to_vcc_i) ,
. BGPDB ( tied_to_vcc_i) ,
. BGRCALOVRD ( 5 'b11111) ,
. PMARSVD ( 8 'b00000000) ,
. RCALENB ( tied_to_vcc_i)
) ;
endmodule
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
9.5 gtwizard_0_common_reset模块分析
这个模块主要是用户给的系统时钟以及用户控制CPLL的复位,复位信号高电平有效,复位信号下降沿时,给CPLL一个周期的高电平复位
`timescale 1 ns / 1 ps
`define DLY #1
module gtwizard_0_common_reset #
(
parameter STABLE_CLOCK_PERIOD = 8
)
(
input wire STABLE_CLOCK,
input wire SOFT_RESET,
output reg COMMON_RESET = 1 'b0
) ;
localparam integer STARTUP_DELAY = 500 ;
localparam integer WAIT_CYCLES = STARTUP_DELAY / STABLE_CLOCK_PERIOD;
localparam integer WAIT_MAX = WAIT_CYCLES + 10 ;
reg [ 7 : 0 ] init_wait_count = 0 ;
reg init_wait_done = 1 'b0;
wire common_reset_i;
reg common_reset_asserted = 1 'b0;
localparam INIT = 1 'b0;
localparam ASSERT_COMMON_RESET = 1 'b1;
reg state = INIT;
always @( posedge STABLE_CLOCK)
begin
if ( init_wait_count == WAIT_MAX)
init_wait_done <= `DLY 1 'b1;
else
init_wait_count <= `DLY init_wait_count + 1 ;
end
always @( posedge STABLE_CLOCK)
begin
if ( SOFT_RESET == 1 'b1)
begin
state <= INIT;
COMMON_RESET <= 1 'b0;
common_reset_asserted <= 1 'b0;
end
else
begin
case ( state)
INIT :
begin
if ( init_wait_done == 1 'b1) state <= ASSERT_COMMON_RESET;
end
ASSERT_COMMON_RESET :
begin
if ( common_reset_asserted == 1 'b0)
begin
COMMON_RESET <= 1 'b1;
common_reset_asserted <= 1 'b1;
end
else
COMMON_RESET <= 1 'b0;
end
default :
state <= INIT;
endcase
end
end
endmodule
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
模块仿真如下所示:
9.6 gtwizard_0_GT_FRAME_GEN 模块分析
这个模块主要是产生发送数据,在tx_user_clk上升沿时从tx_data.dat文件 中读一个数出来。
`timescale 1 ns / 1 ps
`define DLY #1
( * DowngradeIPIdentifiedWarnings= "yes" * )
module gtwizard_0_GT_FRAME_GEN #
(
parameter WORDS_IN_BRAM = 512
)
(
output reg [ 79 : 0 ] TX_DATA_OUT,
output reg [ 7 : 0 ] TXCTRL_OUT,
input wire USER_CLK,
input wire SYSTEM_RESET
) ;
wire tied_to_ground_i;
wire tied_to_vcc_i;
wire [ 31 : 0 ] tied_to_ground_vec_i;
wire [ 63 : 0 ] tx_data_bram_i;
wire [ 7 : 0 ] tx_ctrl_i;
reg [ 8 : 0 ] read_counter_i;
reg [ 79 : 0 ] rom [ 0 : 511 ] ;
reg [ 79 : 0 ] tx_data_ram_r;
( * ASYNC_REG = "TRUE" * ) ( * keep = "true" * ) reg system_reset_r;
( * ASYNC_REG = "TRUE" * ) ( * keep = "true" * ) reg system_reset_r2;
assign tied_to_ground_vec_i = 32 'h00000000;
assign tied_to_ground_i = 1 'b0;
assign tied_to_vcc_i = 1 'b1;
always@( posedge USER_CLK)
begin
system_reset_r <= `DLY SYSTEM_RESET;
system_reset_r2 <= `DLY system_reset_r;
end
always @( posedge USER_CLK)
if ( system_reset_r2 || ( read_counter_i == "111111111" ) )
begin
read_counter_i <= `DLY 9 'd0;
end
else read_counter_i <= `DLY read_counter_i + 9 'd1;
always @( posedge USER_CLK)
if ( system_reset_r2) TX_DATA_OUT <= `DLY 80 'h0000000000;
else TX_DATA_OUT <= `DLY { tx_data_bram_i, tx_data_ram_r[ 15 : 0 ] } ;
always @( posedge USER_CLK)
if ( system_reset_r2) TXCTRL_OUT <= `DLY 8 'h0;
else TXCTRL_OUT <= `DLY tx_ctrl_i;
assign tx_data_bram_i = tx_data_ram_r[ 79 : 16 ] ;
assign tx_ctrl_i = tx_data_ram_r[ 15 : 8 ] ;
initial
begin
$readmemh ( "gt_rom_init_tx.dat" , rom, 0 , 511 ) ;
end
always @( posedge USER_CLK)
tx_data_ram_r <= `DLY rom[ read_counter_i] ;
endmodule
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
打开gt_rom_init_tx.dat文件,我们观察发送的数据如下:
rx_data.dat文件内容和这一模一样。
9.7 gtwizard_0_GT_FRAME_CHECK 模块分析
该模块主要就是检查接受到的数据,然后找到K码对齐从而接收到K码之后的数据与rx_data.dat文件里的数据是否一直,如果不一致然后就累加ERROR_COUNT_OUT
always @( posedge USER_CLK)
begin
if ( ( system_reset_r2 == 1 'b1) | (rxdata_or == 1' b0) ) begin
bit_align_r <= 1 'b0;
end else begin
if ( ( { rx_data_r[ 9 : 0 ] , rx_data_r2[ 19 : 10 ] } == START_OF_PACKET_CHAR) || ( rx_data_r[ 19 : 0 ] == START_OF_PACKET_CHAR) )
begin
bit_align_r <= 1 'b1;
end
end
end
always @( posedge USER_CLK)
begin
if ( system_reset_r2) begin
sel <= 1 'b0;
end else begin
if ( { rx_data_r[ 9 : 0 ] , rx_data_r2[ 19 : 10 ] } == START_OF_PACKET_CHAR)
begin
sel <= 1 'b1;
end
else if ( rx_data_r[ 19 : 0 ] == START_OF_PACKET_CHAR)
begin
sel <= 1 'b0;
end
end
end
always @( posedge USER_CLK)
begin
if ( system_reset_r2) rx_data_r3 <= 'h0;
else
begin
if ( sel == 1 'b1)
begin
rx_data_r3 <= `DLY { rx_data_r[ 9 : 0 ] , rx_data_r2[ 19 : 10 ] } ;
end
else
begin
rx_data_r3 <= `DLY rx_data_r2;
end
end
end
assign rx_data_has_start_char_c = ( rx_data_aligned == START_OF_PACKET_CHAR) ;
assign error_detected_c = track_data_r3 && ( rx_data_r_track != bram_data_r) ;
always @( posedge USER_CLK)
if ( ! track_data_r)
error_detected_r <= `DLY 1 'b0;
else
error_detected_r <= `DLY error_detected_c;
always @( posedge USER_CLK)
if ( system_reset_r2)
error_count_r <= `DLY 9 'd0;
else if ( error_detected_r)
error_count_r <= `DLY error_count_r + 1 ;
assign ERROR_COUNT_OUT = error_count_r[ 7 : 0 ] ;
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
十、仿真验证
然后直接开始仿真,先来观察数据发送模块
复位结束后,就每个时钟上升沿发送ROM里面的数,从00100、0027C、00403等开始,和tx_data.dat文件里的一样。接下来看接收端:
复位结束后,接收对接收到的数据进行打拍处理,这里可以看到,此时接收到的数据并不是我们发送过来的数据,因为此时的数据是未经过字节对齐的数据,因此需要有个模块来进行K码检测,源码如9.7所示,
再找到K码27C后,对齐后的数据就和我们发送数据一模一样了。
再找到K码后,延迟67个周期表示整个接收链路以及建立链接,传输正常。
十一、下板验证
我们配置一个aurora协议,启用8b10b编码,配置如下: 后面的配置同样默认就好,打开例程,添加ila核观察发送和接受数据,以及K码,分配好管脚后直接下板,先观察接收端: 我们找到K码的位置,K码为BC(K28.5),在低位,K码后面的数据为a0 09 08 07 等等。我们打开发送的数据rom看: 从数据文件可以看出,bc后面的数据和ila接受的数据一致,我们再来看发送端:
发送端也一致,至此整个GTP的通信没有问题。
参考
《UG482》
评论记录:
回复评论: