简介
在 FPGA 中,每个 I/O 端口在逻辑结构中都拥有自己的一小块专属区域。这个区域称为 IOB(Input / Output Block,输入/输出块),它包含支持该 I/O 端口特性所需的全部内容:确保 I/O 引脚上电压和电流正确的模拟电路,以及少量特殊逻辑元件。
需要指出的是,术语“IOB”属于 AMD(原 Xilinx)使用的术语体系。每家 FPGA 厂商都有自己的叫法。
IOB 内部几乎总是有 IOB 寄存器。这些寄存器是直接连接到 I/O 端口引脚的触发器。
其中一些触发器用于引脚作为输入端口的场合:这些触发器的 D 输入连接到 I/O 端口的引脚。因此,这类触发器会对来自外部世界的信号进行采样(sampling)。
另一些触发器则用于引脚作为输出端口的场合。这些触发器的 Q 输出连接到引脚。
不同 FPGA 的 IOB 结构各不相同。有些 IOB 功能复杂、特性丰富,另一些则结构更简单。很多时候,IOB 寄存器是一个更大的逻辑单元(例如 SERDES)的一部分。因此,即使描述 IOB 的文档示意图中没有明确画出触发器,该 FPGA 的 I/O 引脚仍可能拥有 IOB 寄存器。
为什么要使用 IOB 寄存器
使用 IOB 寄存器的主要动因是时序:由于这些寄存器紧邻 I/O 端口引脚,由此获得的 clock-to-output(时钟到输出)延迟无可匹敌。对于输入端口,IOB 寄存器也最有希望满足所需的时序。
不过,即使时序要求很容易满足,坚持使用 IOB 寄存器也有一个充分理由:可重复性。否则,I/O 端口引脚与触发器之间的延迟在 FPGA 工程的每次实现中都会不同。这是因为工具每次都可以把触发器放在不同的位置。只要满足时序约束(timing constraints),工具也可以改变布线延迟。只要 PCB 设计正确,并且与外部组件的接口规划得当,这就不是问题。然而,当问题确实存在时,不同实现之间延迟的差异可能会造成困惑:某个功能不工作了,你修改了设计中的某个地方,问题似乎就解决了。但真正起作用的,其实是某处 I/O 时序发生的微小变化。
使用 IOB 寄存器可以确保在 FPGA 逻辑的开发过程中,与外部组件之间的电气接口不会意外改变。这样,当问题出现时也更容易隔离定位。
请求使用 IOB 寄存器
有时需要明确告诉 FPGA 工具使用 IOB 寄存器。这一任务通常由综合器(synthesizer)负责,因此可以在 Vivado 中使用下面这样的综合属性(synthesis attribute):
(* IOB = "TRUE" *) input the_input,
也可以在 XDC 文件中进行相同的设置:
set_property IOB true [get_ports the_input]
另一种方法是,给连接到输入的寄存器添加综合属性:
(* IOB = "TRUE" *) reg the_input_samp;
需要注意,仅在 XDC 文件中添加属性也许不够:为了把触发器放进 IOB,往往需要综合器复制寄存器。当触发器的输出还要被 FPGA 内的普通逻辑使用时,这一点就很重要。原因是,位于 IOB 内部的触发器的输出只能用于对应端口,因此还需要另一个触发器产生同样的输出,供逻辑结构中的普通逻辑使用。在这种情况下,通常需要综合属性(如上所示)。
对于 Quartus,可以把类似的命令加到 QSF 文件中:
set_instance_assignment -name FAST_INPUT_REGISTER ON -to the_input set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to the_output
每种工具实现这一目的的方式都略有不同。
时序约束
对于使用了 IOB 寄存器的端口,还有必要编写 时序约束(timing constraints) 吗?毕竟 IOB 寄存器只有一个可能的位置。那么是否可以放心地认为,无论有没有时序约束,时序结果都会始终相同?
因此,即使使用了 IOB 寄存器,编写时序约束也主要有两个充分理由。
第一个理由是确保确实使用了 IOB 寄存器:有时,逻辑设计中的改动会无意中让全部或部分端口无法使用 IOB。出现这种情况时,工具很少会抱怨。相反,它会悄无声息地使用一个不在 IOB 内的触发器。时序约束可以阻止这种情况:如果只有所有相关触发器都位于各自的 IOB 内时,时序约束才能满足,那么这些触发器一旦被移出 IOB,就不会再是无声无息的——时序约束会因此无法满足。
第二个原因是,工具可能会在 I/O 端口引脚与 IOB 寄存器之间有意插入一段延迟(尽管并非所有 FPGA 都支持这一特性)。该延迟的目的是改善与 thold(保持时间)相关的时序(参见 这个 Quartus 示例)。通过设定一个只有不包含这段额外延迟才能满足的时序约束,可以阻止这种我们不希望的改动。
set_max_delay 通常是用来保证 IOB 寄存器使用保持一致性的合适时序约束。如果 FPGA 工具支持该命令的 "datapath_only" 选项(或类似功能),那就更方便了。
结论
只要有可能,就应该使用 IOB 寄存器。FPGA 工具不一定会主动这样做,因此实现这一目标可能需要付出一点努力。这份努力的回报不仅是获得最佳时序,还能让 I/O 端口的行为具有可重复性。