文章来源:FPGA入门到精通
AXI(Advanced eXtensible Interface)是Xilinx FPGA中常用的接口协议,Vivado中很多IP都是采用AXI接口,特别是在Block Design模式下,添加AXI接口类的IP,可以发现AXI接口都是合并聚拢在一起的,连接同类型接口,只需连接一根线即可实现接口整体连接,非常方便。
那么对于我们自定义verilog模块,带AXI接口时,如何在导入Block Design后,也一样实现聚合在一起?
一、如何在Block Design模式下添加RTL代码?
打开Block Design,在Diagram界面中,鼠标右击,打开右键菜单下,鼠标点击找到的“Add Module”。
弹出“Add Module”,鼠标单击要选择要导入的RTL代码,再点击OK,或者直接双击要导入的RTL代码。
二、如何将导入的RTL代码接口聚合在一起?
1、创建一个示例模块接口
module axi_test( input s_axi_clk, input s_axi_resetn, input valid_i, input last_i, input [31:0] data_i, output ready_o, output valid_o, output last_o, output [31:0] data_o, input ready_i ); endmodule
导入BD后的效果如下图,所有接口都是分开的。
这里分享两个解决办法。
2、遵循AXI4接口的命名方式
这里需要遵循AXI4接口的命名方式,导入BD中后,会自动聚合在一起,但这个方式的缺点是不可控,可能出现聚合混乱的情况。
(1)AXI4-Stream
module axi4_stream_test( input wire clk, input wire reset, // Slave side input wire [31:0] s_axis_tdata, input wire s_axis_tkeep, input wire s_axis_tlast, input wire [2:0] s_axis_tid, input wire [1:0] s_axis_tqos, input wire s_axis_tvalid, output wire s_axis_tready, // Master side output wire [31:0] m_axis_tdata, output wire m_axis_tkeep, output wire m_axis_tlast, output wire [2:0] m_axis_tid, output wire [1:0] m_axis_tqos, output wire m_axis_tvalid, input wire m_axis_tready ); endmodule
导入效果如下:
(2)AXI4 Memory Mapped(也称为AXI4-MM)
module axi4_mm( input wire clk, input wire reset, // Address and data signals output wire [31:0] awaddr, output wire [2:0] awprot, output wire awvalid, input wire awready, output wire [31:0] wdata, output wire [3:0] wstrb, output wire wvalid, input wire wready, // Response signals input wire [1:0] bresp, input wire bvalid, output wire bready, // Address and data signals for read input wire [31:0] araddr, input wire [2:0] arprot, input wire arvalid, output wire arready, input wire [31:0] rdata, input wire [1:0] rresp, input wire rvalid, output wire rready );endmodule
导入效果:
二、使用IP Integrator HDL语言
1、什么是IP Integrator HDL?
IP Integrator HDL并不是一个特定的硬件描述语言(HDL),而是一个概念或工具,可以让用VHDL或Verilog编写的RTL模块,定义的接口更清晰明确,包括接口的类型和聚合后的名称。
2、如何使用?
在vivado中,点击菜单栏“Tools”-》“Language Templates”,再点开Verilog下的IP Integrator HDL代码示例,如下图:
这里面有详细的示例,这里介绍AXI接口。
(1)AXI Memory Mapped
module my_module (
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> AWID" *)
// Uncomment the following to set interface specific parameter on the bus interface.
// (* X_INTERFACE_PARAMETER = "CLK_DOMAIN <value>,PHASE <value>,MAX_BURST_LENGTH <value>,NUM_WRITE_OUTSTANDING <value>,NUM_READ_OUTSTANDING <value>,SUPPORTS_NARROW_BURST <value>,READ_WRITE_MODE <value>,BUSER_WIDTH <value>,RUSER_WIDTH <value>,WUSER_WIDTH <value>,ARUSER_WIDTH <value>,AWUSER_WIDTH <value>,ADDR_WIDTH <value>,ID_WIDTH <value>,FREQ_HZ <value>,PROTOCOL <value>,DATA_WIDTH <value>,HAS_BURST <value>,HAS_CACHE <value>,HAS_LOCK <value>,HAS_PROT <value>,HAS_QOS <value>,HAS_REGION <value>,HAS_WSTRB <value>,HAS_BRESP <value>,HAS_RRESP <value>" *)
input [<left_bound>:0] <s_awid>, // Write address ID (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> AWADDR" *)
input [<left_bound>:0] <s_awaddr>, // Write address (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> AWLEN" *)
input [<left_bound>:0] <s_awlen>, // Burst length (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> AWSIZE" *)
input [2:0] <s_awsize>, // Burst size (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> AWBURST" *)
input [1:0] <s_awburst>, // Burst type (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> AWLOCK" *)
input [<left_bound>:0] <s_awlock>, // Lock type (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> AWCACHE" *)
input [3:0] <s_awcache>, // Cache type (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> AWPROT" *)
input [2:0] <s_awprot>, // Protection type (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> AWREGION" *)
input [3:0] <s_awregion>, // Write address slave region (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> AWQOS" *)
input [3:0] <s_awqos>, // Transaction Quality of Service token (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> AWUSER" *)
input [<left_bound>:0] <s_awuser>, // Write address user sideband (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> AWVALID" *)
input <s_awvalid>, // Write address valid (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> AWREADY" *)
output <s_awready>, // Write address ready (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> WID" *)
input [<left_bound>:0] <s_wid>, // Write ID tag (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> WDATA" *)
input [<left_bound>:0] <s_wdata>, // Write data (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> WSTRB" *)
input [<left_bound>:0] <s_wstrb>, // Write strobes (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> WLAST" *)
input <s_wlast>, // Write last beat (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> WUSER" *)
input [<left_bound>:0] <s_wuser>, // Write data user sideband (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> WVALID" *)
input <s_wvalid>, // Write valid (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> WREADY" *)
output <s_wready>, // Write ready (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> BID" *)
output [<left_bound>:0] <s_bid>, // Response ID (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> BRESP" *)
output [1:0] <s_bresp>, // Write response (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> BUSER" *)
output [<left_bound>:0] <s_buser>, // Write response user sideband (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> BVALID" *)
output <s_bvalid>, // Write response valid (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> BREADY" *)
input <s_bready>, // Write response ready (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> ARID" *)
input [<left_bound>:0] <s_arid>, // Read address ID (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> ARADDR" *)
input [<left_bound>:0] <s_araddr>, // Read address (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> ARLEN" *)
input [<left_bound>:0] <s_arlen>, // Burst length (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> ARSIZE" *)
input [2:0] <s_arsize>, // Burst size (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> ARBURST" *)
input [1:0] <s_arburst>, // Burst type (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> ARLOCK" *)
input [<left_bound>:0] <s_arlock>, // Lock type (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> ARCACHE" *)
input [3:0] <s_arcache>, // Cache type (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> ARPROT" *)
input [2:0] <s_arprot>, // Protection type (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> ARREGION" *)
input [3:0] <s_arregion>, // Read address slave region (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> ARQOS" *)
input [3:0] <s_arqos>, // Quality of service token (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> ARUSER" *)
input [<left_bound>:0] <s_aruser>, // Read address user sideband (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> ARVALID" *)
input <s_arvalid>, // Read address valid (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> ARREADY" *)
output <s_arready>, // Read address ready (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> RID" *)
output [<left_bound>:0] <s_rid>, // Read ID tag (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> RDATA" *)
output [<left_bound>:0] <s_rdata>, // Read data (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> RRESP" *)
output [1:0] <s_rresp>, // Read response (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> RLAST" *)
output <s_rlast>, // Read last beat (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> RUSER" *)
output [<left_bound>:0] <s_ruser>, // Read user sideband (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> RVALID" *)
output <s_rvalid>, // Read valid (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 <interface_name> RREADY" *)
input <s_rready>, // Read ready (optional)
// additional ports here
);
// user logic here
endmodule
(2)AXI Stream
module my_module (
(* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 <interface_name> TID" *)
// Uncomment the following to set interface specific parameter on the bus interface.
// (* X_INTERFACE_PARAMETER = "CLK_DOMAIN <value>,PHASE <value>,FREQ_HZ <value>,LAYERED_METADATA <value>,HAS_TLAST <value>,HAS_TKEEP <value>,HAS_TSTRB <value>,HAS_TREADY <value>,TUSER_WIDTH <value>,TID_WIDTH <value>,TDEST_WIDTH <value>,TDATA_NUM_BYTES <value>" *)
input [<left_bound>:0] <s_tid>, // Transfer ID tag (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 <interface_name> TDEST" *)
input [<left_bound>:0] <s_tdest>, // Transfer Destination (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 <interface_name> TDATA" *)
input [<left_bound>:0] <s_tdata>, // Transfer Data (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 <interface_name> TSTRB" *)
input [<left_bound>:0] <s_tstrb>, // Transfer Data Byte Strobes (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 <interface_name> TKEEP" *)
input [<left_bound>:0] <s_tkeep>, // Transfer Null Byte Indicators (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 <interface_name> TLAST" *)
input <s_tlast>, // Packet Boundary Indicator (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 <interface_name> TUSER" *)
input [<left_bound>:0] <s_tuser>, // Transfer user sideband (optional)
(* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 <interface_name> TVALID" *)
input <s_tvalid>, // Transfer valid (required)
(* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 <interface_name> TREADY" *)
output <s_tready>, // Transfer ready (optional)
// additional ports here
);
// user logic here
endmodule
其中“<interface_name>”是定义聚合后的接口名称。
只需要在每个参数接口前,添加对应的IP Integrator HDL属性语句。
未加IP Integrator HDL代码示例:
module axi_test( input wire clk, input wire reset, // Slave side input wire [31:0] s_tdata, input wire s_tkeep, input wire s_tlast, input wire s_tvalid, output wire s_tready, // Master side output wire [31:0] m_tdata, output wire m_tkeep, output wire m_tlast, output wire m_tvalid, input wire m_tready ); endmodule
导入效果图:
添加IP Integrator HDL代码示例:
module axi_test( input wire clk, input wire reset, // Slave side (* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 s_axis_test TDATA" *) input wire [31:0] s_tdata, (* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 s_axis_test TKEEP" *) input wire s_tkeep, (* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 s_axis_test TLAST" *) input wire s_tlast, (* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 s_axis_test TVALID" *) input wire s_tvalid, (* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 s_axis_test TREADY" *) output wire s_tready, // Master side (* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 m_axis_test TDATA" *) output wire [31:0] m_tdata, (* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 m_axis_test TKEEP" *) output wire m_tkeep, (* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 m_axis_test TLAST" *) output wire m_tlast, (* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 m_axis_test TVALID" *) output wire m_tvalid, (* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 m_axis_test TREADY" *) input wire m_tready ); endmodule
导入效果图: