引言
Xillyp2p IP核由两个网表构成,分别称为 Core A 和 Core B。这两个网表各自实例化于建立数据链路所涉及的两个 FPGA 工程中。
Core A 和 Core B 的端口通常并不相同,因为物理链路不一定是对称的,多数情况下应用数据流也不是对称的。尽管如此,两个核的端口结构是相同的。
端口可分为四组:
- 连接到 MGT、SERDES 或其他物理链路的端口。这些端口包括并行数据字及其相关时钟。还可以包含一个可选输入端口,用于对物理链路的数据流进行节流控制。
- 用于传输应用数据的端口。这些端口连接到由用户实例化的标准 FIFO。
- 复位端口。
- 用于状态、测试和调试的端口。
下图是一个稍微简化的示意图,展示了 Xillyp2p IP 核在包含 MGT 或 SERDES 的设计中的连接方式:

为清晰起见,图中省略了 Xillyp2p IP 核的几个端口。这些端口将在下文描述,并注明“图中未示出”。
连接物理链路的端口
以下两个端口用于承载将要通过物理链路发送到对端的并行数据字流。若 IP 核为双向,则两个网表都包含这两个端口;若为单向,则仅 Core A 包含。
- out_data(输出):此位向量输出包含物理链路要向对端发送的并行数据。比特从位 0 开始发送,直至该字的最高有效位。该输出字的宽度可在 IP Core Factory 中配置为 1 到 128 之间的任意数值。
- tx_clk(输入):与 out_data 配合使用的时钟。事实上,除 in_data 和 in_valid(当这两个端口存在时)外,所有其他端口都使用该时钟进行时钟同步。
如果物理链路是单向的,则 Core B 上不存在上述两个端口,所有端口都使用下文将提到的 rx_clk 进行时钟同步。
以下两个端口用于承载从对端通过物理链路接收到的并行数据字流。若 IP 核为双向,则两个网表都包含这两个端口;若为单向,则仅 Core B 包含。
- in_data(输入):此向量输入包含从物理链路到达的并行数据。比特顺序从位 0 开始,至该字的最高有效位结束(与 out_data 的方式相同)。该输入字的宽度可在 IP Core Factory 中配置为 1 到 128 之间的任意数值。
- rx_clk(输入):与 in_data 配合使用的时钟。当 tx_clk 不存在时(例如在单向物理链路配置下的 Core B,此时只有数据到达,没有发送时钟),该时钟也用于所有其他端口。当使用 MGT 作为物理链路时,rx_clk 是 MGT 通过时钟恢复从数据流中提取出的时钟。
当链路为双向时,tx_clk 和 rx_clk 的频率必须大致相同,误差需在 IP Core Factory 配置 IP 核时设定的容差范围内。在某些场景下,这两个时钟也可能是同一个时钟信号,或者相位不同的同一时钟信号。
请注意,对于双向物理链路,应用逻辑与 Xillyp2p IP 核之间的所有应用数据交换都仅使用发送时钟进行时钟同步。这适用于两个方向的应用数据。换言之,所有应用 FIFO 都连接到 tx_clk(在它们与 Xillyp2p 连接的那一侧),即使是那些从对端接收数据的 FIFO 也是如此。
并行数据字的节流控制
在 IP Core Factory 中配置 Xillyp2p IP 核时,有一个选项叫做“A parallel word is transmitted / received on every clock cycle”。默认情况下该选项是启用的,这在绝大多数情况下是正确的选择:MGT 和 SERDES 都是每个时钟周期发送和接收一个并行字。
然而,如果在 Xillyp2p IP 核与物理链路之间插入了额外的逻辑(例如变速齿轮箱),则可能需要对进出 IP 核的并行字流进行节流控制。此时应禁用上述选项。禁用后,网表中会增加两个端口:
- out_ready(输入,由 tx_clk 时钟同步):若 out_data 端口存在,则该输入端口存在,其功能相当于该端口的时钟使能。当物理链路的发送器准备好接收一个数据字时,该信号应为高电平。换言之,当同一时钟周期内 out_ready 为高电平时,IP 核认为 out_data 中的数据字已被发送。
- in_valid(输入,由 rx_clk 时钟同步):若 in_data 端口存在,则该输入端口存在,其功能相当于 in_data 的时钟使能。当 in_data 包含有效字时,该信号应为高电平。换言之,当同一时钟周期内 in_valid 为高电平时,IP 核会消费 in_data 中的数据字。
总而言之,当使用 MGT 或 SERDES 时,几乎从不需要节流控制,因为每个时钟周期都会发送和接收一个并行字。这就是上图中没有出现 out_ready 和 in_valid 的原因。但在需要时,可以添加这两个端口。
复位
Xillyp2p IP 核有一个异步复位输入:async_reset。
该输入应保持高电平,直到时钟输入(tx_clk 和/或 rx_clk)稳定在正确的频率上。尽管复位输入是异步的,但建议将该信号生成为一个寄存器的输出,以避免毛刺。复位脉冲的长度应足以让目标 FPGA 上的触发器响应异步复位。例如,一个 tx_clk 或 rx_clk 时钟周期就足够长了。
复位信号传播到 IP 核内部逻辑可能需要很短的时间。因此,在复位生效后,数据活动可能还会持续最多 10 个时钟周期。特别是,在这段短时间内,IP 核可能仍在向应用逻辑发送数据或从应用逻辑读取数据。
输入时钟稳定后,就无需再使用 async_reset。特别地,Xillyp2p 支持热插拔,因此如果物理数据链路断开后重新连接,只要时钟输入一直保持在允许的频率范围内,就无需重复复位。
状态、测试与调试
Xillyp2p IP 核具有多个输出端口,用于监视物理链路的状态和质量,以及 Xillyp2p 自身协议的状态。这些输出端口的详细说明,以及解决物理链路设置问题的建议,请参阅另一份指南。
Xillyp2p IP 核还具备在物理链路上有意插入位错误以进行测试的能力。这使得用户可以评估其逻辑如何应对物理链路错误带来的影响(例如,如果链路是双向的,则由于重传导致数据速率暂时降低;对于单向链路,则是暂停/恢复机制)。
错误注入机制由 error_test_rate 输入端口控制(上图中未示出),这是一个 3 位向量。正常操作时,该输入应接 0。
当该输入非零时,Xillyp2p 的发送器前端会故意随机翻转某个输出位的值,从而产生一个有意为之的位错误。
错误率的估算方式如下:将 error_test_rate 上的数值记为 r,则模拟的比特误码率(BER)大约为 10r-10,其中 r 取 1 到 7。当 r=0 时,该功能被禁用,不会故意引入错误。
与用户应用逻辑的数据交换
与 Xillybus 和 XillyUSB IP 核类似,Xillyp2p 与应用数据流的交换也是通过每个数据流对应的标准 FIFO 来完成的。
对于待发送的应用数据,这意味着应用逻辑将数据写入一个实例化在 Xillyp2p IP 核旁边的 FIFO,而 Xillyp2p IP 核则连接在该 FIFO 的另一侧。IP 核从该 FIFO 读取数据并发送到对端。
请注意,无需累积到一定数量的数据字,也无需执行任何其他操作来启动向对端的传输。对于 Xillyp2p IP 核而言,只要 FIFO 非空,就会被视为尽快发送数据的请求。
对于接收应用数据,同样是通过一个中间 FIFO 工作:Xillyp2p IP 核将数据写入与其相连的 FIFO,应用逻辑则从该 FIFO 中读取数据。IP 核内部的流控机制通过检测 FIFO 的“full”输出来防止该 FIFO 溢出,该输出也连接到了 IP 核。
但是,有两种情况无法使用这种流控机制,即没有机会将“full”输出连接到 IP 核:
- 当链路为单向时,接收方无法请求发送方暂停数据流。
- 在 IP Core Factory 中配置数据流时,选择退出流控(即取消勾选“Enable flow control with "full" input at receiver”旁的复选框)。
在这两种情况下,应用逻辑必须足够快地读取数据,以防止 FIFO 溢出。
因此,建议使用双向物理链路,并启用基于 FIFO 的“full”端口的流控机制。这会营造出一种将一个 FIFO 分割在两个 FPGA 上的真实幻觉,更重要的是,它允许接收方控制数据流:接收方的应用逻辑按照自己期望的速度从 FIFO 中读取数据,而 Xillyp2p 的流控机制则确保当接收端的 FIFO 变满时,特定数据流上的数据传输被暂时暂停。
应用数据端口的命名约定
如前所述,用户需要在使用 Xillyp2p IP 核的同时实例化标准 FIFO,用于应用数据的发送和接收。
对于每个向对端发送数据的应用数据流,有三个端口连接到标准 FIFO。IP 核使用这些端口从 FIFO 读取数据以供发送。这些端口的名称是:
- user_tx_{名称}_rd_en,连接到 FIFO 的 rd_en 端口。
- user_tx_{名称}_rd_data,连接到 FIFO 的数据输出端口。
- user_tx_{名称}_empty,连接到 FIFO 的 empty 端口。
占位符“{名称}”替换为数据流的名称,该名称由用户在 IP Core Factory 中指定。
类似地,对于每个从对端接收数据的应用数据流,IP 核使用以下端口写入其从对端接收到的数据:
- user_rx_{名称}_wr_en,连接到 FIFO 的 wr_en 端口。
- user_rx_{名称}_wr_data,连接到 FIFO 的数据输入端口。
- user_rx_{名称}_full,连接到 FIFO 的 full 端口。如上所述,如果物理链路是单向的,或者在 IP Core Factory 中选择退出流控,则此端口不存在。
当物理链路为单向时,每个接收数据的流还会多出两个端口:user_rx_{名称}_halt(输出)和 user_rx_{名称}_resume(输入)。下文(参见“单向物理链路下的错误处理”)将详细解释这两个端口。
重要:所有应用数据端口(发送和接收相关的端口)都与 tx_clk 同步(当该时钟存在时)。唯一的例外是在单向物理链路配置下的 Core B,此时使用 rx_clk,因为它是唯一可用的时钟源。
包结束标志(EOP)
作为一个附加特性,Xillyp2p IP 核允许在每个应用数据字旁边附带一个包结束(EOP)标志。请注意,触发向对端发送应用数据并不需要这个标志;用户应用逻辑写入 FIFO 的任何数据都会尽快发送到对端。
包结束标志的唯一目的是作为一个标记,使用户应用能够将数据划分为段、数据包或视频帧等。如果物理链路是单向的,EOP 标志会特别有用(参见下文“单向物理链路下的错误处理”)。
如果不需要此功能,请将 user_tx_{名称}_eop 接 0,并在接收端忽略 user_rx_{名称}_eop。虽然上图中没有显示 EOP 端口,但它们始终包含在 IP 核的接口中。
对于 EOP 标志的置位频率没有限制,因此数据段或数据包没有长度限制。但是,置位 EOP 会在物理链路上产生最多 16 个字节的带宽开销。使用 EOP 创建短数据包可能会降低带宽性能。
EOP 的使用方式如下:对于通过 user_tx_{名称}_rd_data 取出的每个数据字,应用逻辑通过输入端口 user_tx_{名称}_eop 提供相应的 EOP 标志。如果该输入与该数据字同时为高电平,则该字被标记上 EOP 标志。
在接收端,当 user_rx_{名称}_wr_data 包含的是被置位了 EOP 标志发送过来的字时,输出端口 user_rx_{名称}_eop 为高电平。
从概念上讲,EOP 可以被视为应用数据字的一个扩展,使其宽了一位。当在应用中使用 EOP 时,很自然地将两侧 FIFO 的字宽都增加一位,并将额外的那一位用于 EOP 标志。在大多数情况下,这甚至不会增加 FIFO 的内存资源消耗。
但再次强调,EOP 信号不仅仅是一个被传输的比特位:只要该位为 '0',它在物理数据链路上就不会消耗带宽。相反,当该位为 '1' 时,如前所述,会对物理数据链路的使用造成轻微的效率损失。
不可能在没有伴随数据字的情况下发送 EOP。如果需要这种功能,可以将接收端的应用逻辑设计为当 EOP 标志置位时忽略该数据字。
FIFO 深度考量
通常希望保持应用逻辑与其关联 FIFO 之间的连续数据流。在数据流分配的数据速率允许的前提下,设计问题在于 FIFO 需要多深(即其存储器阵列需要能够存储多少个数据字)。
当向对端 IP 核发送数据时,应用逻辑将数据写入 FIFO,而 Xillyp2p IP 核从中读取数据。原则上,一旦 FIFO 的“empty”端口为低电平,IP 核就会开始从中读取数据,但可能会因以下两个原因而延迟:
- 对端的 FIFO 已满。这种可能性仅适用于双向物理链路且启用流控的情况下(推荐)。
- IP 核正在代表另一个应用数据流发送数据。
对于第一种情况,这与接收端消耗数据的速度有关。如果这是主要因素,那么两侧 FIFO 的深度规划原则应与应用两侧位于同一 FPGA 上并通过单个 FIFO 连接时的原则相同。
第二种情况与 Xillyp2p 的数据传输模式有关:IP 核以轮询方式检查其所有 user_tx_{名称}_empty 输入端口,并为每个该信号未置位的应用数据流发起一次数据传输。每次连续传输略少于 1024 字节的数据,或者一直传输到相关 FIFO 变空为止。然后 IP 核会转向下一个“empty”端口未置位的流(如果其他 FIFO 都为空,则可能停留在同一个流上)。
鉴于这种行为,FIFO 应该足够深,以吸收在 IP 核忙于传输其他数据流期间由应用逻辑写入的数据。一个合理的估计是假设在每个轮询周期中,IP 核为每个活跃的发送流传输最多 1024 字节。因此,FIFO 深度应能容纳在传输其他每个活跃的发送流的 1024 字节数据所需时间内所产生的数据量。
就这一点而言,已知处于空闲状态(在所讨论数据流的使用场景中)的发送流不应被考虑在内,因为它们不会造成任何延迟。
对于接收侧的 FIFO,只要“full”变为低电平(如果存在该端口),数据就会立即被送入。在缺乏流控的情况下(即链路为单向或选择退出流控时),数据一旦到达就会被送入。
自然地,接收数据的可用性取决于对端是否发送了数据以及发送了多少数据。因此,讨论又回到了上面已经解释过的轮询机制。换句话说,接收侧 FIFO 的深度应该能够补偿由于服务其他应用数据流而出现的数据流间隙,每个其他数据流占用物理链路大约 1024 字节的时间。
请注意,实际的数据交付模式可能与传输模式看起来不同,因为 Xillyp2p 维护着内部数据缓冲区。然而,只要 IP 核在 IP Core Factory 中配置了正确的参数,这种差异只会更有利于维持连续的数据流。
单向物理链路下的错误处理
本节讨论单向链路从错误状态中恢复的问题,因此当物理链路为双向时,本节内容不适用。关于一般性的调试问题,请参阅另一份指南。
当物理链路为单向时,发送方无法知道其发送的数据是否被正确接收。如果由于位错误或物理介质暂时断开而导致数据丢失,通过对应用数据进行 CRC32 校验,以及检测到达数据段之间间隙的机制,可以保证检测到这种丢失。然而,由于没有返回通道,发送方无法得知错误,也无法重传受影响的数据。
Xillyp2p 可确保交付给应用逻辑的所有数据都是无差错且连续的,与发送时完全相同。如果物理链路上发生了某种错误,Xillyp2p 会尽可能多地将数据写入 FIFO,直到错误可能影响数据的那一点之前。此后,数据流暂停,并且 user_rx_{名称}_halt 输出端口变为 '1' 以指示此状态。
当错误原因被消除且 user_rx_{名称}_resume 输入端口为 '1' 时,数据流恢复正常运行。位错误被认为会立即消除,但其他类型的错误可能会持续一段时间,例如物理链路断开。因此,可能需要将“resume”信号保持高电平超过一个时钟周期。如果错误尚未消除,user_rx_{名称}_halt 将保持高电平,无论“resume”输入如何。只有当问题被解决后,在“resume”为 '1' 的下一个时钟周期,“halt”才会变为 '0'。
如果希望在物理链路再次可用时立即继续数据流,那么将任何 user_rx_{名称}_resume 端口永久保持高电平也是完全有效的。
还需要注意以下几点:
- 数据流在从对端发送的数据流中一个不可预测的位置恢复,且恢复点位于应用数据流字宽的边界上。可能会丢失任意数量的字。因此,恢复之后,从发送方 FIFO 中取出的任何字都会正确且不变地到达,但恢复后的第一个字是哪个是不可预测的。
- 如果基于单向链路的应用需要某种帧或数据包(例如传输视频帧)的同步,可以使用前面提到的 EOP 功能:在暂停/恢复握手之后,接收方应忽略所有数据,直到 user_rx_{名称}_eop 端口被置位,然后恢复正常操作。在发送方一侧,必须偶尔置位 EOP,以标记合适起始点之前的那个字。
- 链路上发生的任何类型的错误都会导致所有数据流进入暂停状态,即使它是一个位错误(因此只直接影响一个应用数据流)。然而,每个数据流的“halt”输出是独立的。这些输出通常不会同时变为 '1',因为每个数据流将数据写入其 FIFO 的完成时间不同。尽管如此,在物理链路上发生错误之后的某个时刻,所有数据流都会进入暂停状态。如果一个数据流没有被恢复,而链路上又发生了另一个错误(或多个错误),该数据流将保持暂停状态,其行为就好像只发生了第一次错误一样。
