Vivado 为我的模块推断出不正确的 FREQ_HZ AXI 总线
Vivado infers incorrect FREQ_HZ for AXI busses to my module
我正在使用 Vivado 进行设计。我的顶层设计是一个框图。框图包含 IP 块和我的 Verilog RTL 模块。每当我更改我的主模块并且 Verilog 更新框图时,它总是错误地推断出我的模块的时钟频率。 我该如何解决这个问题?
这个问题真气人,问它打破了我的设计。设计中的所有其他 AXI 总线都正确使用 10MHz,但每当我更改 main
并更新框图时,Vivado 决定 main
的 AXI 总线处于 100MHz。只要时钟不匹配,我就无法构建。我可以手动更新框图中块的属性中的频率,但每次更新 main
时都会擦除这些更改(这很频繁,因为它是我的 main模块)。
我已经尝试为每个 AXI 总线添加专用时钟和重置(即使它们都连接到同一个网络)。我搞砸了 X_INTERFACE_PARAMETER
(这在任何地方都有记录吗?)。都无济于事。
此外,M_AXIS_CMD
是一个主 AXI 接口,应该位于 main
模块的输出端。不知道这是怎么回事。但与时钟相比,这是一个非常小的问题。
来源:https://gitlab.com/tessera/pcd8544-tests
模块接口:
module main #(
CLK_FREQ = 50000000// : CLK_FREQ > 0 // clock frequency
)(
(* X_INTERFACE_PARAMETER = "XIL_INTERFACENAME core_clk, ASSOCIATED_RESET core_rst, FREQ_HZ 10000000" *)
(* X_INTERFACE_INFO = "xilinx.com:signal:clock:1.0 core_clk CLK" *)
input clk,
(* X_INTERFACE_PARAMETER = "XIL_INTERFACENAME core_rst, POLARITY ACTIVE_HIGH" *)
(* X_INTERFACE_INFO = "xilinx.com:signal:reset:1.0 core_rst RST" *)
input rst,
(* X_INTERFACE_PARAMETER = "XIL_INTERFACENAME axi_rst, POLARITY ACTIVE_LOW" *)
(* X_INTERFACE_INFO = "xilinx.com:signal:reset:1.0 axi_rst RST" *)
input axi_rst,
(* X_INTERFACE_INFO = "xilinx.com:interface:fifo_write:1.0 DOUT FULL" *)
input wr_full,
(* X_INTERFACE_INFO = "xilinx.com:interface:fifo_write:1.0 DOUT WR_DATA" *)
output reg [8:0] wr_data,
(* X_INTERFACE_INFO = "xilinx.com:interface:fifo_write:1.0 DOUT WR_EN" *)
output reg wr_valid,
// slave AXI-Lite write channel FROM PS
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG AWADDR" *) input wire [4:0] s_axi_reg_awaddr, // address
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG AWPROT" *) input wire [2:0] s_axi_reg_awprot, // channel protection type
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG AWVALID" *) input wire s_axi_reg_awvalid, // address valid
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG AWREADY" *) output wire s_axi_reg_awready, // address ready
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG WDATA" *) input wire [31:0] s_axi_reg_wdata, // data
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG WSTRB" *) input wire [3:0] s_axi_reg_wstrb, // strobes - one bit per byte of data
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG WVALID" *) input wire s_axi_reg_wvalid, // data/strobes valid
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG WREADY" *) output wire s_axi_reg_wready, // data/strobes ready
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG BRESP" *) output wire [1:0] s_axi_reg_bresp, // response
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG BVALID" *) output wire s_axi_reg_bvalid, // response valid
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG BREADY" *) input wire s_axi_reg_bready, // response ready
// slave AXI-Lite read channel FROM PS
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG ARADDR" *) input wire [4:0] s_axi_reg_araddr, // address
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG ARPROT" *) input wire [2:0] s_axi_reg_arprot, // channel protection type
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG ARVALID" *) input wire s_axi_reg_arvalid, // address valid
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG ARREADY" *) output wire s_axi_reg_arready, // address ready
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG RDATA" *) output wire [31:0] s_axi_reg_rdata, // data
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG RRESP" *) output wire [1:0] s_axi_reg_rresp, // response
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG RVALID" *) output wire s_axi_reg_rvalid, // data/response valid
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG RREADY" *) input wire s_axi_reg_rready, // data/response ready
// master AXI-Stream command channel TO DataMover
(* X_INTERFACE_INFO = "xilinx.com:interface:axis_rtl:1.0 M_AXIS_CMD TDATA" *) output reg [71:0] m_axis_cmd_data,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis_rtl:1.0 M_AXIS_CMD TREADY" *) output reg m_axis_cmd_valid,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis_rtl:1.0 M_AXIS_CMD TVALID" *) input wire m_axis_cmd_ready,
// slave AXI-Stream status channel FROM DataMover
(* X_INTERFACE_INFO = "xilinx.com:interface:axis_rtl:1.0 S_AXIS_STS TDATA" *) input wire [7:0] s_axis_status_data,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis_rtl:1.0 S_AXIS_STS TKEEP" *) input wire [0:0] s_axis_status_keep,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis_rtl:1.0 S_AXIS_STS TLAST" *) input wire s_axis_status_last,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis_rtl:1.0 S_AXIS_STS TREADY" *) input wire s_axis_status_valid,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis_rtl:1.0 S_AXIS_STS TVALID" *) output reg s_axis_status_ready,
// slave AXI-Stream data channel FROM DataMover
(* X_INTERFACE_INFO = "xilinx.com:interface:axis_rtl:1.0 S_AXIS_DATA TDATA" *) input wire [31:0] s_axis_stream_data,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis_rtl:1.0 S_AXIS_DATA TKEEP" *) input wire [3:0] s_axis_stream_keep,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis_rtl:1.0 S_AXIS_DATA TLAST" *) input wire s_axis_stream_last,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis_rtl:1.0 S_AXIS_DATA TREADY" *) input wire s_axis_stream_valid,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis_rtl:1.0 S_AXIS_DATA TVALID" *) output reg s_axis_stream_ready,
// DataMover memory-mapped to stream error
input wire datamover_mm2s_err
);
it always incorrectly infers the clock frequency for my module. How
can I fix this?
我从你的 git 回购中提取出来,它在 Vivado 2017.4 中运行良好。您可能将几件不同的事情混为一谈,并且可能期待一些不应该发生的事情发生。鉴于缺乏有关专有(但有用)Vivado IP 封装器和方框图工具的文档,这完全可以理解。
2017.4 在功能上与 2017.3 相同,只是增加了部分,所以这不应该造成任何差异
我从时钟的 (* X_INTERFACE_PARAMETER ... *)
中删除了 FREQ_HZ
。这 可能 导致了你提到的时钟不匹配,但即使我把它放回去,现在对我来说也能正常工作。但是,FREQ_HZ
只能用于输出(生成的)时钟;见下文。
当我第一次打开图表或更新 main.v 并单击输入引脚时,属性显示 100MHz,正如您所提到的。但在执行 F6 "Validate" 命令后,引脚会正确报告 10MHz。这都是预料之中的。
您不应期望 CLK_FREQ
Verilog 参数会根据引脚神奇地更新。每当模块是新的时,GUI 中的参数将采用默认值。它们可以被编辑并且应该在一个更新周期内保持不变,但是由于重大编辑它们可能必须被重置。 由您来设置这些参数以匹配。
一些 Xilinx 内核,如 AXI Uartlite,使用一些花哨的未记录的 TCL 脚本在验证时自动将引脚频率传输到 Verilog 参数。例如,您可以在 /opt/Xilinx/Vivado/2017.4/data/ip/xilinx/axi_uartlite_v2_0/bd/bd.tcl
文件中看到这是如何完成的。
is this documented anywhere?
在UG994、"Inferring Control Signals in a RTL Module"中有一些关于使用HDL模块的文档,但不是很完整。 最好的 文档在 "Lite Bulb" 家伙(Clippy 的远亲)中,您可以通过按编辑器工具栏中的 lite 灯泡找到它。
主动提供的建议 #1 - 使用 RTL 模块听起来是个好主意。比完成打包您自己的 IP 的工作要容易得多。直到你发现:a)它只是在后台打包模块并在每次编辑时自动 re-runs,b)它甚至比打包器更脆弱,c)你无法控制接口推断等在。学习使用打包器创建真正的 IP 包。
主动提供的建议 #2 - 将框图和项目文件保存在 TCL 脚本中。不要将整个项目或框图 .xci 和 .xml 文件放在 Git 中。请参阅以下命令:write_bd_tcl
和 write_project_tcl
。如果您(经常)需要在项目损坏时重新生成项目,这可以得到完全一致的结果。
最后,这里是 header 我设置 (* X_INTERFACE... *)
东西的方式的片段。如果时钟运行 AXI 总线,也添加 ASSOCIATED_BUSIF
标志:
(* X_INTERFACE_INFO = "xilinx.com:signal:clock:1.0 core_clk CLK" *)
(* X_INTERFACE_PARAMETER = "ASSOCIATED_RESET reset" *)
input clk,
(* X_INTERFACE_INFO = "xilinx.com:signal:reset:1.0 core_rst RST" *)
(* X_INTERFACE_PARAMETER = "POLARITY ACTIVE_HIGH" *)
input rst,
我正在使用 Vivado 进行设计。我的顶层设计是一个框图。框图包含 IP 块和我的 Verilog RTL 模块。每当我更改我的主模块并且 Verilog 更新框图时,它总是错误地推断出我的模块的时钟频率。 我该如何解决这个问题?
这个问题真气人,问它打破了我的设计。设计中的所有其他 AXI 总线都正确使用 10MHz,但每当我更改 main
并更新框图时,Vivado 决定 main
的 AXI 总线处于 100MHz。只要时钟不匹配,我就无法构建。我可以手动更新框图中块的属性中的频率,但每次更新 main
时都会擦除这些更改(这很频繁,因为它是我的 main模块)。
我已经尝试为每个 AXI 总线添加专用时钟和重置(即使它们都连接到同一个网络)。我搞砸了 X_INTERFACE_PARAMETER
(这在任何地方都有记录吗?)。都无济于事。
此外,M_AXIS_CMD
是一个主 AXI 接口,应该位于 main
模块的输出端。不知道这是怎么回事。但与时钟相比,这是一个非常小的问题。
来源:https://gitlab.com/tessera/pcd8544-tests
模块接口:
module main #(
CLK_FREQ = 50000000// : CLK_FREQ > 0 // clock frequency
)(
(* X_INTERFACE_PARAMETER = "XIL_INTERFACENAME core_clk, ASSOCIATED_RESET core_rst, FREQ_HZ 10000000" *)
(* X_INTERFACE_INFO = "xilinx.com:signal:clock:1.0 core_clk CLK" *)
input clk,
(* X_INTERFACE_PARAMETER = "XIL_INTERFACENAME core_rst, POLARITY ACTIVE_HIGH" *)
(* X_INTERFACE_INFO = "xilinx.com:signal:reset:1.0 core_rst RST" *)
input rst,
(* X_INTERFACE_PARAMETER = "XIL_INTERFACENAME axi_rst, POLARITY ACTIVE_LOW" *)
(* X_INTERFACE_INFO = "xilinx.com:signal:reset:1.0 axi_rst RST" *)
input axi_rst,
(* X_INTERFACE_INFO = "xilinx.com:interface:fifo_write:1.0 DOUT FULL" *)
input wr_full,
(* X_INTERFACE_INFO = "xilinx.com:interface:fifo_write:1.0 DOUT WR_DATA" *)
output reg [8:0] wr_data,
(* X_INTERFACE_INFO = "xilinx.com:interface:fifo_write:1.0 DOUT WR_EN" *)
output reg wr_valid,
// slave AXI-Lite write channel FROM PS
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG AWADDR" *) input wire [4:0] s_axi_reg_awaddr, // address
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG AWPROT" *) input wire [2:0] s_axi_reg_awprot, // channel protection type
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG AWVALID" *) input wire s_axi_reg_awvalid, // address valid
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG AWREADY" *) output wire s_axi_reg_awready, // address ready
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG WDATA" *) input wire [31:0] s_axi_reg_wdata, // data
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG WSTRB" *) input wire [3:0] s_axi_reg_wstrb, // strobes - one bit per byte of data
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG WVALID" *) input wire s_axi_reg_wvalid, // data/strobes valid
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG WREADY" *) output wire s_axi_reg_wready, // data/strobes ready
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG BRESP" *) output wire [1:0] s_axi_reg_bresp, // response
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG BVALID" *) output wire s_axi_reg_bvalid, // response valid
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG BREADY" *) input wire s_axi_reg_bready, // response ready
// slave AXI-Lite read channel FROM PS
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG ARADDR" *) input wire [4:0] s_axi_reg_araddr, // address
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG ARPROT" *) input wire [2:0] s_axi_reg_arprot, // channel protection type
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG ARVALID" *) input wire s_axi_reg_arvalid, // address valid
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG ARREADY" *) output wire s_axi_reg_arready, // address ready
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG RDATA" *) output wire [31:0] s_axi_reg_rdata, // data
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG RRESP" *) output wire [1:0] s_axi_reg_rresp, // response
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG RVALID" *) output wire s_axi_reg_rvalid, // data/response valid
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm_rtl:1.0 S_AXI_REG RREADY" *) input wire s_axi_reg_rready, // data/response ready
// master AXI-Stream command channel TO DataMover
(* X_INTERFACE_INFO = "xilinx.com:interface:axis_rtl:1.0 M_AXIS_CMD TDATA" *) output reg [71:0] m_axis_cmd_data,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis_rtl:1.0 M_AXIS_CMD TREADY" *) output reg m_axis_cmd_valid,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis_rtl:1.0 M_AXIS_CMD TVALID" *) input wire m_axis_cmd_ready,
// slave AXI-Stream status channel FROM DataMover
(* X_INTERFACE_INFO = "xilinx.com:interface:axis_rtl:1.0 S_AXIS_STS TDATA" *) input wire [7:0] s_axis_status_data,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis_rtl:1.0 S_AXIS_STS TKEEP" *) input wire [0:0] s_axis_status_keep,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis_rtl:1.0 S_AXIS_STS TLAST" *) input wire s_axis_status_last,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis_rtl:1.0 S_AXIS_STS TREADY" *) input wire s_axis_status_valid,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis_rtl:1.0 S_AXIS_STS TVALID" *) output reg s_axis_status_ready,
// slave AXI-Stream data channel FROM DataMover
(* X_INTERFACE_INFO = "xilinx.com:interface:axis_rtl:1.0 S_AXIS_DATA TDATA" *) input wire [31:0] s_axis_stream_data,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis_rtl:1.0 S_AXIS_DATA TKEEP" *) input wire [3:0] s_axis_stream_keep,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis_rtl:1.0 S_AXIS_DATA TLAST" *) input wire s_axis_stream_last,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis_rtl:1.0 S_AXIS_DATA TREADY" *) input wire s_axis_stream_valid,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis_rtl:1.0 S_AXIS_DATA TVALID" *) output reg s_axis_stream_ready,
// DataMover memory-mapped to stream error
input wire datamover_mm2s_err
);
it always incorrectly infers the clock frequency for my module. How can I fix this?
我从你的 git 回购中提取出来,它在 Vivado 2017.4 中运行良好。您可能将几件不同的事情混为一谈,并且可能期待一些不应该发生的事情发生。鉴于缺乏有关专有(但有用)Vivado IP 封装器和方框图工具的文档,这完全可以理解。
2017.4 在功能上与 2017.3 相同,只是增加了部分,所以这不应该造成任何差异
我从时钟的
(* X_INTERFACE_PARAMETER ... *)
中删除了FREQ_HZ
。这 可能 导致了你提到的时钟不匹配,但即使我把它放回去,现在对我来说也能正常工作。但是,FREQ_HZ
只能用于输出(生成的)时钟;见下文。当我第一次打开图表或更新 main.v 并单击输入引脚时,属性显示 100MHz,正如您所提到的。但在执行 F6 "Validate" 命令后,引脚会正确报告 10MHz。这都是预料之中的。
您不应期望
CLK_FREQ
Verilog 参数会根据引脚神奇地更新。每当模块是新的时,GUI 中的参数将采用默认值。它们可以被编辑并且应该在一个更新周期内保持不变,但是由于重大编辑它们可能必须被重置。 由您来设置这些参数以匹配。一些 Xilinx 内核,如 AXI Uartlite,使用一些花哨的未记录的 TCL 脚本在验证时自动将引脚频率传输到 Verilog 参数。例如,您可以在
/opt/Xilinx/Vivado/2017.4/data/ip/xilinx/axi_uartlite_v2_0/bd/bd.tcl
文件中看到这是如何完成的。
is this documented anywhere?
在UG994、"Inferring Control Signals in a RTL Module"中有一些关于使用HDL模块的文档,但不是很完整。 最好的 文档在 "Lite Bulb" 家伙(Clippy 的远亲)中,您可以通过按编辑器工具栏中的 lite 灯泡找到它。
主动提供的建议 #1 - 使用 RTL 模块听起来是个好主意。比完成打包您自己的 IP 的工作要容易得多。直到你发现:a)它只是在后台打包模块并在每次编辑时自动 re-runs,b)它甚至比打包器更脆弱,c)你无法控制接口推断等在。学习使用打包器创建真正的 IP 包。
主动提供的建议 #2 - 将框图和项目文件保存在 TCL 脚本中。不要将整个项目或框图 .xci 和 .xml 文件放在 Git 中。请参阅以下命令:
write_bd_tcl
和write_project_tcl
。如果您(经常)需要在项目损坏时重新生成项目,这可以得到完全一致的结果。最后,这里是 header 我设置
(* X_INTERFACE... *)
东西的方式的片段。如果时钟运行 AXI 总线,也添加ASSOCIATED_BUSIF
标志:(* X_INTERFACE_INFO = "xilinx.com:signal:clock:1.0 core_clk CLK" *) (* X_INTERFACE_PARAMETER = "ASSOCIATED_RESET reset" *) input clk, (* X_INTERFACE_INFO = "xilinx.com:signal:reset:1.0 core_rst RST" *) (* X_INTERFACE_PARAMETER = "POLARITY ACTIVE_HIGH" *) input rst,