KCU105 开发板连接光纤的图片

引言

本指南介绍如何在 AMD(原 Xilinx)Ultrascale FPGA 上配置一个多吉比特收发器(MGT),并将其连接到 Xillyp2p IP 核。本示例中使用的是 GTH,但绝大多数细节同样适用于 GTY 以及后续 FPGA(如 Ultrascale+ 等)上的新型 MGT。

这里展示的示例,是对 IP 核端口与 API 指南 中简化应用框图的实现:

应用逻辑、Xillyp2p IP 核与物理链路(MGT 或 SERDES)之间的连接示意图

如上图详细所示,GTH 与 Xillyp2p 之间的接口非常简单。尽管如此,要正确配置 GTH 并确定其端口连接方式仍有一定难度。本指南给出了一个完整的设计示例,包括屏幕截图、Verilog 代码和时序约束。

本示例以 KCU105 开发板为目标,这是 Kintex Ultrascale 系列中最流行的开发板。该设计利用板上的 SFP0 接口,借助光收发模块和光纤,以 5 Gb/s 的数据速率与另一块板通信(如上图所示)。

此设计可根据其他用途和接口进行修改。由于采用了最简单的 GTH 配置(无编码),如果出现连接问题,相对容易诊断。此外,Xillyp2p IP 核提供了一些诊断输出信号,可以连接到 LED 指示灯上(如下所示),这非常有用,尤其是其中一个 LED 会在物理链路上每出现一个比特错误时闪烁一次。

对于使用 7 系列 FPGA(Kintex-7、Artix-7、Virtex-7 和 Zynq-7000)的用户,另有专门的指南介绍如何配置 Kintex-7 GTX(而不是本例中的 GTH)。

配置 GTH

配置过程通过带简要注释的截图说明。本示例使用 Vivado 2025.1 创建,但其他版本也应适用,可能仅有细微差别。

您也可以下载一个现成的 XCI 文件,其中包含了此处所示的配置。

在 Vivado 中,打开 IP 目录(IP Catalog),选择 UltraScale FPGAs Transceiver Wizard。根据以下截图调整配置。请注意,收发器可以通过向导中的子菜单进行更详细的配置,但这并非必需:所有需要修改的内容均已在下方截图中体现。向导中“Start from scratch”的默认配置在其他方面是合适的。

向导的初始窗口应配置如下:

Vivado 2025.1 UltraScale FPGAs Transceiver Wizard 初始设置截图(Basic 选项卡)
(点击图片放大)

需要注意以下几点:

  • IP 核的名称设为“fibergt”。这将在下面 Verilog 示例的例化中使用。
  • 线速率(Line Rate)在两个方向上都设为 5 Gb/s。您可以根据设备需要使用不同的速率。
  • 为简单起见,PLL 类型选择 CPLL。这是每个收发器独立的 PLL,与 Quad PLL(四个收发器共享,功能更多但配置更复杂)不同。
  • “Actual Reference Clock”是外部参考时钟的频率。KCU105 板上默认在 P6/P5 引脚提供 156.25 MHz 的低抖动时钟,因此使用该时钟。
  • “Encoding”保持默认设置 Raw(无编码),因为 Xillyp2p 期望收发器像普通 SERDES 一样工作,不进行任何数据流操作。
  • 用户数据宽度(User Data Width)和内部数据宽度(Internal Data Width)在发射器和接收器上均已默认正确设置为 32 位。用户数据宽度应与 Xillyp2p IP 核指定的并行字宽度匹配,这里已经一致。
  • 在接收器一侧,端接(Termination)设置为 AVTT。这设定了施加到 GTH 电接收输入端的偏置电压。如果您使用的不是带 SFP+ 模块的光纤链路,则可能需要不同的链路耦合、端接以及可编程端接电压设置。这些设置会显著影响链路质量。即使每个并行字到达时包含大量错误,调整这些设置有时也能使链路完全无误。
  • ppm 频率偏移设为 200 ppm,考虑了每侧 100 ppm 的时钟振荡器容差。这个数值可能偏大。

接下来,转到“Physical Resources”选项卡:

Vivado 2025.1 UltraScale FPGAs Transceiver Wizard, Physical Resources 选项卡截图
(点击图片放大)

这里唯一需要修改的是将自由运行时钟的频率设为 125 MHz。这个额外的时钟提供给收发器用于其内部管理任务。在下面的示例设计中,使用 KCU105 板上的一个时钟来实现此目的,其频率为 125 MHz。

该窗口的下半部分允许选择使用 FPGA 中的哪些 GTH 资源。这些设置会被项目 XDC 文件中的布局约束覆盖,因此本节对最终结果没有影响。也可以删除 XDC 文件中的约束,依赖这些设置。使用哪种方法取决于个人偏好;在本示例中,忽略向导的这些设置。

接下来,转到“Optional Features”选项卡:

Vivado 2025.1 UltraScale FPGAs Transceiver Wizard, Optional Features 选项卡截图
(点击图片放大)

此处显示该选项卡只是为了说明无需更改任何内容。特别是接收端的逗号检测与对齐,以及接收时钟校正等功能均未使用,因为这些功能需要启用编码,而此处并未启用。Xillyp2p 内部实现了自己的同步、对齐和时钟校正方案。

接下来,转到最后一个选项卡“Structural Options”:

Vivado 2025.1 UltraScale FPGAs Transceiver Wizard, Structural Options 选项卡截图
(点击图片放大)

这里,将“Include simple receiver / transmitter user clocking network in the”改为 Core,而不是 Example design。这样,几个 BUFG 会被添加到核内部,而不是在设计例化中。这只是一个小差异。

窗口的下半部分包含许多用于向收发器接口添加端口的选项。本示例都不需要,因此默认设置已足够。

至此,GTH 的配置就完成了。接下来,给出一个示例 Verilog 设计。

收发器的例化

顶层 Verilog 模块的开头如下:

module example
  (
   input  gth_refclk_n,
   input  gth_refclk_p,
   input  gth_rxn,
   input  gth_rxp,
   output gth_txn,
   output gth_txp,

   input  init_clk_p,
   input  init_clk_n,

   output sfp_tx_enable,

   output [7:0] gpio_led
  );

前六个端口属于 GTH 本身:参考时钟、接收和发送引脚。

init_clk_p/n 端口是 KCU105 板上自由运行时钟的差分输入,频率为 125 MHz。sfp_tx_enable 将在下面简要说明。

最后是八个 LED 输出。

在例化 GTH 之前,向设计中添加两个时钟缓冲器:

   wire gt_refclk;
   wire init_clk, init_clk_i;

   IBUFDS_GTE3 #(
     .REFCLK_EN_TX_PATH(1'b0),
     .REFCLK_HROW_CK_SEL(2'd0),
     .REFCLK_ICNTL_RX(2'd0)
    ) ibufds_gt (
      .I(gth_refclk_p),
      .IB(gth_refclk_n),
      .CEB(1'b0),
      .O(gt_refclk),
      .ODIV2()
    );

   IBUFDS ibufds (.O(init_clk_i), .I(init_clk_p), .IB(init_clk_n));
   BUFG bufg (.O(init_clk), .I(init_clk_i));

与 Xillyp2p IP 核接口需要用到以下这些连线:

  wire  rx_clk;
  wire  tx_clk;
  wire  async_reset;

  wire [31:0] in_data;
  wire [31:0] out_data;

  assign async_reset = 0;

本例中将 async_reset 接地。这有点粗糙,但设计仍然可以工作。在实际设计中,建议使用此异步复位在上电后立即复位逻辑。

接下来是一个虽小但可能重要的细节:

  assign sfp_tx_enable = 1; // Enable SFP+ transmitter

sfp_tx_enable 输出端口通过一个 MOSFET 晶体管连接到光收发器的 TX_DISABLE 输入,这会使其极性反转。默认情况下,板子上安装了一个跳线,使收发器的发送器保持使能。但如果该跳线缺失,收发器的发送器将被关闭。将此输出保持为高电平,会强制 TX_DISABLE 为低电平,确保光收发器正常工作。

现在例化收发器:

fibergt fibergt_ins (
  .gtwiz_userclk_tx_reset_in(async_reset),
  .gtwiz_userclk_tx_srcclk_out(),
  .gtwiz_userclk_tx_usrclk_out(),
  .gtwiz_userclk_tx_usrclk2_out(tx_clk),
  .gtwiz_userclk_tx_active_out(),
  .gtwiz_userclk_rx_reset_in(async_reset),
  .gtwiz_userclk_rx_srcclk_out(),
  .gtwiz_userclk_rx_usrclk_out(),
  .gtwiz_userclk_rx_usrclk2_out(rx_clk),
  .gtwiz_userclk_rx_active_out(),
  .gtwiz_reset_clk_freerun_in(init_clk),
  .gtwiz_reset_all_in(async_reset),
  .gtwiz_reset_tx_pll_and_datapath_in(1'b0),
  .gtwiz_reset_tx_datapath_in(1'b0),
  .gtwiz_reset_rx_pll_and_datapath_in(1'b0),
  .gtwiz_reset_rx_datapath_in(1'b0),
  .gtwiz_reset_rx_cdr_stable_out(),
  .gtwiz_reset_tx_done_out(),
  .gtwiz_reset_rx_done_out(),
  .gtwiz_userdata_tx_in(out_data),
  .gtwiz_userdata_rx_out(in_data),
  .drpclk_in(init_clk),
  .gthrxn_in(gth_rxn),
  .gthrxp_in(gth_rxp),
  .gtrefclk0_in(gt_refclk),
  .gthtxn_out(gth_txn),
  .gthtxp_out(gth_txp),
  .gtpowergood_out(),
  .rxpmaresetdone_out(),
  .txpmaresetdone_out()
);

收发器直接连接到物理引脚 gth_rxp、gth_rxn、gth_txp 和 gth_txn。参考时钟 gt_refclk 是 IBUFDS_GTE3 时钟缓冲器的输出。

自由运行时钟 init_clk 连接到 gtwiz_reset_clk_freerun_in 和 drpclk_in。如上所述,该时钟用于收发器的控制逻辑。

注意 tx_clk 和 rx_clk 是收发器的输出。换句话说,收发器通过 gtwiz_userclk_tx_usrclk2_out 和 gtwiz_userclk_rx_usrclk2_out 端口提供这两个时钟。与 in_data 和 out_data 一起,这些是收发器和 Xillyp2p IP 核之间的唯一连接,如下所示。

Xillyp2p IP 核的例化

本示例使用了在 IP Core Factory 生成的 IP 核中的 core A。物理链路的另一端应使用 core B(除非核是对称的,相关主题在 IP Core Factory 指南 末尾有说明)。

IP 核的配置如下面这个网络应用截图所示:

IP Core Factory 网络工具中配置 Xillyp2p IP 核的截图
(点击图片放大)

IP 核的通用参数与 GTH 匹配:32 位并行字宽,时钟频率 156.25 MHz。请注意,这也是 rx_clk 和 tx_clk 的频率,恰好与参考时钟相同。例如,如果改变 GTH 的线速率(不改变参考时钟和并行字宽),rx_clk 和 tx_clk 的频率也会相应改变。此时,需要在 IP Core Factory 中指定更新后的频率。

为此 IP 核定义了三个数据流:demo32_to_b、demo32_to_a 和 demo_256。可以根据应用需要配置不同数量、不同名称和属性的数据流。

在例化 IP 核之前,还需要一些额外的连线。以下代码段直接从 IP 核的例化模板中复制:

  wire  status_link_down;
  wire  status_initializing;
  wire  status_link_partner_mismatch;
  wire  status_bit_error;
  wire  status_rev_polarity;
  wire [31:0] status_debug;

  wire [2:0] error_test_rate;

  // Wires related to data stream "demo32_to_a"
  wire  user_rx_demo32_to_a_wr_en;
  wire [31:0] user_rx_demo32_to_a_wr_data;
  wire  user_rx_demo32_to_a_full;
  wire  user_rx_demo32_to_a_eop;

  // Wires related to data stream "demo32_to_b"
  wire  user_tx_demo32_to_b_rd_en;
  wire [31:0] user_tx_demo32_to_b_rd_data;
  wire  user_tx_demo32_to_b_empty;
  wire  user_tx_demo32_to_b_eop;

  // Wires related to data stream "demo_256"
  wire  user_tx_demo_256_rd_en;
  wire [255:0] user_tx_demo_256_rd_data;
  wire  user_tx_demo_256_empty;
  wire  user_tx_demo_256_eop;

现在进行例化本身。这部分也是从 core A 的例化模板中复制的:

  xillyp2p_core_a xillyp2p_core_a_ins (
    // Ports related to data stream "demo32_to_a"
    // Inbound data stream:
    .user_rx_demo32_to_a_wr_en(user_rx_demo32_to_a_wr_en),
    .user_rx_demo32_to_a_wr_data(user_rx_demo32_to_a_wr_data),
    .user_rx_demo32_to_a_full(user_rx_demo32_to_a_full),
    .user_rx_demo32_to_a_eop(user_rx_demo32_to_a_eop),

    // Ports related to data stream "demo32_to_b"
    // Outbound data stream:
    .user_tx_demo32_to_b_rd_en(user_tx_demo32_to_b_rd_en),
    .user_tx_demo32_to_b_rd_data(user_tx_demo32_to_b_rd_data),
    .user_tx_demo32_to_b_empty(user_tx_demo32_to_b_empty),
    .user_tx_demo32_to_b_eop(user_tx_demo32_to_b_eop),

    // Ports related to data stream "demo_256"
    // Outbound data stream:
    .user_tx_demo_256_rd_en(user_tx_demo_256_rd_en),
    .user_tx_demo_256_rd_data(user_tx_demo_256_rd_data),
    .user_tx_demo_256_empty(user_tx_demo_256_empty),
    .user_tx_demo_256_eop(user_tx_demo_256_eop),

    // General signals
    .rx_clk(rx_clk),
    .tx_clk(tx_clk),
    .async_reset(async_reset),
    .in_data(in_data),
    .out_data(out_data),
    .status_link_down(status_link_down),
    .status_initializing(status_initializing),
    .status_link_partner_mismatch(status_link_partner_mismatch),
    .status_bit_error(status_bit_error),
    .status_rev_polarity(status_rev_polarity),
    .status_debug(status_debug),
    .error_test_rate(error_test_rate)
  );

  // error_test_rate should always be zero unless you want to the test
  // what happens when there are errors on the physical data link.

  assign error_test_rate = 3'd0;

如前所述,IP 核使用四根线与 GTH 连接:rx_clk、tx_clk、in_data 和 out_data。其余连接与应用程序逻辑相关,下面讨论。

与应用程序逻辑交换数据

熟悉 Xillybus 的 PCIe 或 XillyUSB IP 核的用户会发现这部分非常相似。

首先,回顾一下,本示例围绕 core A 展开,而物理链路另一侧的 FPGA 上(通常)应使用 core B。

名为“demo32_to_a”的应用程序数据流允许另一侧(使用 core B)的 FPGA 向使用 core A 的 FPGA 发送数据。

访问这些数据的主流方法是通过 FIFO。例如,fifo_32 是一个标准的双时钟 FIFO,数据字宽为 32 位,在 Vivado 项目中定义并按如下方式例化:

   fifo_32 data_in_fifo
     (
      .rst(async_reset),
      .wr_clk(tx_clk),
      .rd_clk(<连接到应用逻辑>),

      .din(user_rx_demo32_to_a_wr_data),
      .wr_en(user_rx_demo32_to_a_wr_en),
      .full(user_rx_demo32_to_a_full),

      .rd_en(<连接到应用逻辑>),
      .dout(<连接到应用逻辑>),
      .empty(<连接到应用逻辑>)
      );

名为 user_rx_demo32_to_a_* 的三根线连接到 Xillyp2p IP 核。IP 核使用这些信号将来自 core B 的数据填入 FIFO。

请注意,FIFO 的“full”端口也被连接。Xillyp2p IP 核会尊重该信号,并通过其流量控制机制避免溢出。此机制是可选的,但推荐使用(注意在 IP 核配置截图的所有三个数据流的“Flow control”列中均为“Yes”)。

FIFO 的其余端口连接到应用程序逻辑,后者根据需要读取数据。应用程序逻辑不需要以特定速率读取数据;唯一的要求是避免在 FIFO 为空时尝试读取。

另请注意,FIFO 的 wr_clk 端口连接到了 tx_clk,尽管它接收数据。所有与应用程序逻辑的交互都基于 tx_clk。不要被其他信号名称中的“rx”前缀搞混——rx_clk 仅用于与收发器相关的部分,并且只与 in_data 一起使用。

对于相反方向的数据流,“demo32_to_b”允许 core A 向另一侧(使用 core B)的 FPGA 发送数据。用于此目的的 FIFO 例化如下:

   fifo_32 data_out_fifo
     (
      .rst(async_reset),
      .wr_clk(<连接到应用逻辑>),
      .rd_clk(tx_clk),

      .din(<连接到应用逻辑>),
      .wr_en(<连接到应用逻辑>),
      .full(<连接到应用逻辑>),

      .rd_en(user_tx_demo32_to_b_rd_en),
      .dout(user_tx_demo32_to_b_rd_data),
      .empty(user_tx_demo32_to_b_empty)
      );

   assign user_tx_demo32_to_b_eop = 0;

名为 user_tx_demo32_to_b_* 的三根线连接到 Xillyp2p IP 核。IP 核使用这些信号在 FIFO 非空时立即从中取出数据。

FIFO 的其他端口连接到应用程序逻辑,应用程序逻辑以常规方式向 FIFO 写入数据。应用程序逻辑向 FIFO 写入多少数据没有要求,也不需要特殊操作来使数据到达另一端。唯一明显的要求是避免在 FIFO 已满时写入。

由于此数据流启用了流量控制,只有当对端的 FIFO 未满时,才会从此端的 FIFO 中取出数据。因此,core B 侧的应用程序逻辑实际上控制了端到端的数据流:如果对侧(core B)的应用程序逻辑从其 FIFO 读取数据的速度慢于此侧(core A)向 FIFO 写入数据的速度,那么此侧的 FIFO 最终会变满,迫使应用程序逻辑停止写入。换句话说,这种安排等效于一个写端口在一个 FPGA 上、读端口在另一个 FPGA 上的单一 FIFO。

另请注意,本例中未使用 user_rx_demo32_to_a_eop,而 user_tx_demo32_to_b_eop 被接地。这两个端口与随数据字一起发送数据包结束标志(EOP)的能力有关。当需要通过数据流发送数据段或数据包时,此功能非常有用。关于 EOP 的更多信息,请参阅 Xillyp2p 端口与 API 指南

关于数据交换的几点说明

出于测试目的,将来自 core B 的数据环回给它自身可能很有用。换句话说,将“demo32_to_a”接收到的数据直接路由到“demo32_to_b”。这可以通过例化一个 FIFO 而不是两个来实现,如下所示:

   fifo_32 loopbackfifo
     (
      .rst(async_reset),
      .wr_clk(tx_clk),
      .rd_clk(tx_clk),

      .din(user_rx_demo32_to_a_wr_data),
      .wr_en(user_rx_demo32_to_a_wr_en),
      .full(user_rx_demo32_to_a_full),

      .rd_en(user_tx_demo32_to_b_rd_en),
      .dout(user_tx_demo32_to_b_rd_data),
      .empty(user_tx_demo32_to_b_empty)
      );

   assign user_tx_demo32_to_b_eop = 0;

再次注意,FIFO 两侧都使用 tx_clk

与“demo_256”的接口以相同方式处理,使用一个数据字宽为 256 位的 FIFO。请注意,此数据流使用 256 位宽的数据字,这比物理链路的 32 位并行字宽得多。而且,该数据流的最大理论数据速率为 256 * 156.25 MHz / 8 = 5000 MB/s,远高于物理链路约 606 MB/s 的容量。

尽管如此,如果应用程序的自然数据格式由 256 位字组成,那么使用 256 位宽的数据流是合适的,即使它不提供带宽优势。这种选择确保每个字以正确的格式和对齐方式在接收端交付。

LED 指示灯与诊断信号

KCU105 板上有 8 个 GPIO LED。Xillyp2p IP 核有几个输出可以连接到 LED,用于指示链路状态,详见本指南

推荐的设置如下:

   reg [26:0] txclk_cnt, initclk_cnt;

   always @(posedge init_clk)
     initclk_cnt <= initclk_cnt + 1;

   always @(posedge tx_clk)
     txclk_cnt <= txclk_cnt + 1;

   assign gpio_led[1:0] = { txclk_cnt[26], initclk_cnt[26] };

   ledhelper ledhelper_ins[5:0]
     (
      .clk(tx_clk),
      .in( {
	    status_link_down,
	    status_link_partner_mismatch,
	    status_initializing,
	    status_bit_error,
	    status_debug[2],
	    status_debug[0] } ),
      .led(gpio_led[7:2])
      );

对于不太熟悉 Verilog 的用户,ledhelper 的例化重复了六次,每次(分别)对应“in”输入的一位及其相应的“led”输出。

从上可见,GPIO LED 0 和 1 是简单的心跳信号,通过闪烁指示 init_clk 和 tx_clk 处于活动状态。

其余六个 LED 显示来自 Xillyp2p IP 核的六个状态信号。ledhelper 模块确保 LED 保持亮起或熄灭足够长时间,以便人眼感知短至单个时钟周期的事件。例如,如果物理链路上检测到错误,status_bit_error 会在一个时钟周期内为高电平。如果没有 ledhelper,这样短暂的事件将是不可见的。

ledhelper 模块定义如下:

module ledhelper(
  input clk,
  input in,
  output reg led
);

   // 22 bits = 4194304 counts, ~26.8 ms at 156.25 MHz clock
   reg [21:0] count;

   always @(posedge clk)
     if (count != 0)
       count <= count - 1;
     else if (in != led)
       begin
	  led <= in;
	  count <= ~0;
       end
endmodule

该模块在每次变化后的 222 个时钟周期内冻结“led”输出。因此,如果输入在一个时钟周期内为高电平,LED 将保持点亮约 26.8 毫秒,这足以被人眼感知。此外,如果输入快速变化,LED 会剧烈闪烁,人眼会正确将其解释为高活动性。

当有 8 个 LED 可用时,这种方法很合适。如果可用的 LED 较少,status_bit_error 通常是最有用的指示,其次是 status_link_partner_mismatch、status_link_down 和 status_debug[2]。同时也建议至少有一个心跳 LED。

XDC 约束

为了完整性,展示并解释 XDC 文件中的约束。请记住,使用的板卡是 KCU105。

首先,与收发器直接相关的约束:

create_clock -name refclk -period 6.4 [get_ports gth_refclk_n]

set_property PACKAGE_PIN P6 [get_ports gth_refclk_p];
set_property PACKAGE_PIN P5 [get_ports gth_refclk_n];

set_property LOC GTHE3_CHANNEL_X0Y10 \
  [get_cells -hier -filter { ref_name =~ GT*_CHANNEL }]

参考时钟周期设为 6.4 ns,对应 156.25 MHz,与之前的讨论一致。注意,rx_clk 和 tx_clk 也具有相同频率纯属巧合。

然后明确放置参考时钟的引脚,覆盖向导中的定义。

之后,为收发器显式选择 GTH,再次覆盖向导中的选择。注意,用于查找 GTH 的表达式匹配设计中的任何 GTH;这之所以有效,是因为整个设计中只有一个 GTH。因此,如果存在多个 GTH,则需要更具体的约束,但这样的约束可能无法在不同版本的 Vivado 中一致工作。

接下来是自由运行时钟的约束:

create_clock -name initclk -period 8 [get_ports init_clk_n]
set_property -dict { PACKAGE_PIN F10 IOSTANDARD LVDS } \
  [get_ports "init_clk_n"];
set_property -dict { PACKAGE_PIN G10 IOSTANDARD LVDS } \
  [get_ports "init_clk_p"];

自由运行时钟周期设为 8 ns,即 125 MHz。请注意,如果更改此时钟频率,则必须在 Transceiver Wizard 中更新该设置。

一旦两个时钟都被定义和约束,需要告知 Vivado 逻辑设计将 init_clk、rx_clk 和 tx_clk 视为不相关时钟,从而将所有跨越这些时钟域的路径设为伪路径:

set_clock_groups -asynchronous \
    -group [get_clocks -include_generated_clocks -of_objects \
       [get_ports init_clk_n]] \
    -group [get_clocks -of_objects [ get_nets rx_clk ] ] \
    -group [get_clocks -of_objects [ get_nets tx_clk ] ]

如果没有这一步,设计可能无法满足时序约束。

最后是 GPIO LED 和 sfp_tx_enable(琐碎部分):

set_property PACKAGE_PIN AP8 [get_ports "gpio_led[0]"];
set_property PACKAGE_PIN H23 [get_ports "gpio_led[1]"];
set_property PACKAGE_PIN P20 [get_ports "gpio_led[2]"];
set_property PACKAGE_PIN P21 [get_ports "gpio_led[3]"];
set_property PACKAGE_PIN N22 [get_ports "gpio_led[4]"];
set_property PACKAGE_PIN M22 [get_ports "gpio_led[5]"];
set_property PACKAGE_PIN R23 [get_ports "gpio_led[6]"];
set_property PACKAGE_PIN P23 [get_ports "gpio_led[7]"];

set_property IOSTANDARD LVCMOS18 [get_ports "gpio_led[*]"]
set_false_path -to [get_ports "gpio_led[*]"]

set_property -dict {PACKAGE_PIN AL8 IOSTANDARD LVCMOS18} \
  [get_ports sfp_tx_enable];

结论

本指南提供了一个完整的示例,展示了如何在 AMD(原 Xilinx)UltraScale FPGA 上配置多吉比特收发器(GTH)并将其连接到 Xillyp2p IP 核。从 Vivado 中的 Transceiver Wizard 配置开始,经过时钟、FIFO 和应用程序逻辑的例化,到诊断 LED 的连线以及 XDC 约束的定义,每一步都进行了详细说明。

本示例既可作为使用 UltraScale GTH 收发器和 Xillyp2p IP 核的实用参考,也可作为学习工具。

请回顾上文,关于为 7 系列 FPGA(Kintex-7、Artix-7、Virtex-7 和 Zynq-7000)配置收发器的示例,请参阅另一份指南