在Vivado中创建及封装AXI4接口的自定义IP核

在 Vivado 中开发 ZYNQ 系列 SoC 时,AXI4 是使用频次较高的总线,有时候为了使 FPGA 功能模块化,还会将一些特定的模块封装成 AXI4 总线接口的自定义 IP。Xilinx 官方还有针对此项需求发布的官方文档UG1037,可以参阅。本篇博文以 AXI4 总线读写 PL 侧 BRAM 为例,详细讲解如何在 Vivado 中创建及封装自定义 IP 核,以及如何将自定义 IP 移植到其他工程。

一、Vivado 中创建及编写 AXI4 总线 IP

首先创建 IP 核:Tools->Creat and Package New IP,选择创建 AXI4 Peripheral:

在Vivado中创建及封装AXI4接口的自定义IP核

在 Name 一栏的名称改为“ pl_bram_plus1”, IP 核的路径改为工程目录下的 ip_repo 文件夹,即删除路径“ /../”中间的一个“ .”符号,其它的设置直接保持默认即可,点击“NEXT”。

在Vivado中创建及封装AXI4接口的自定义IP核

直到最后,点击“Finish”按钮完成自定义 IP 核的创建。

在Vivado中创建及封装AXI4接口的自定义IP核

到这里 IP 核的框架已经搭建好了,接下来要去进行细节定义。

首先打开 IP Catalog,依次展开 User Repository→AXI Peripheral→“ pl_bram_plus1_v1.0”,右键选择“ Edit in IP Packager”。

打开 pl_bram_plus1_v1_0.v 文件,在 Users to add ports here 和 User port ends 中间行添加如下代码:

output wire ram_clk ,                  //RAM 时钟
input wire [31:0] ram_rd_data,         //RAM 中读出的数据
output wire ram_en ,                   //RAM 使能信号
output wire [31:0] ram_addr ,          //RAM 地址
output wire [3:0] ram_we ,             //RAM 读写控制信号
output wire [31:0] ram_wr_data,        //RAM 写数据
output wire ram_rst ,                  //RAM 复位信号,高电平有

在实例化 pl_ram_plus1_v1_0_S00_AXI 模块的位置,添加以下代码。这里需要注意一下例化时的逗号问题,如果添加在最后,需要在之前的最后一个信号后添加逗号。

.ram_clk (ram_clk ),
.ram_rd_data (ram_rd_data),
.ram_en (ram_en ),
.ram_addr (ram_addr ),
.ram_we (ram_we ),
.ram_wr_data (ram_wr_data),
.ram_rst (ram_rst )

打开 pl_bram_plus1_v1_0_S00_AXI.v 文件,同样在 Users to add ports here 和 User port ends 中间行添加如下代码:

output wire ram_clk ,                //RAM 时钟
input wire [31:0] ram_rd_data,       //RAM 中读出的数据
output wire ram_en ,                 //RAM 使能信号
output wire [31:0] ram_addr ,        //RAM 地址
output wire [3:0] ram_we ,           //RAM 读写控制信号
output wire [31:0] ram_wr_data,      //RAM 写数据
output wire ram_rst ,                //RAM 复位信号,高电平有

在程序最后 Add user logic here 和 User logic ends 的中间行,添加如下代码:

bram_ip_plus1 inst_bram_ip_plus1(
		.clk (S_AXI_ACLK),
		.rst_n (S_AXI_ARESETN),
		.start_rd (slv_reg0[0]),
		.start_addr (slv_reg1),
		.rd_len (slv_reg2),
		//RAM 端口
		.ram_clk (ram_clk ),
		.ram_rd_data (ram_rd_data),
		.ram_en (ram_en ),
		.ram_addr (ram_addr ),
		.ram_we (ram_we ),
		.ram_wr_data (ram_wr_data),
		.ram_rst (ram_rst )
	);

接下来在工程中创建一个新的模块,命名为“bram_ip_plus1”,位于../BRAMIP/ip_repo/pl_bram_plus1_1.0/hdl 路径下, bram_ip_plus1 模块的代码如下:

module bram_ip_plus1(
	input clk , //时钟信号
	input rst_n , //复位信号
	input start_rd , //读开始信号
	input [31:0] start_addr , //读起始地址
	input [31:0] rd_len , //读数据的长度
	//RAM 端口
	output ram_clk , //RAM 时钟
	input [31:0] ram_rd_data, //RAM 中读出的数据
	output reg ram_en , //RAM 使能信号
	output reg [31:0] ram_addr , //RAM 地址
	output reg [3:0] ram_we , //RAM 读写控制信号
	output reg [31:0] ram_wr_data, //RAM 写数据
	output ram_rst //RAM 复位信号,高电平有效
	);
	
	 //reg define
	reg [1:0] flow_cnt;
	reg start_rd_d0;
	reg start_rd_d1;
	
	//wire define
	wire pos_start_rd;
	
	//*****************************************************
	//** main code
	//*****************************************************
	
	assign ram_rst = 1'b0;
	assign ram_clk = clk ;
	assign pos_start_rd = ~start_rd_d1 & start_rd_d0;
	
	//延时两拍,采 start_rd 信号的上升沿
	always @(posedge clk or negedge rst_n) begin
	if(!rst_n) begin
		start_rd_d0 <= 1'b0;
		start_rd_d1 <= 1'b0;
	end
	else begin
		start_rd_d0 <= start_rd;
		start_rd_d1 <= start_rd_d0;
		end
	end
	
	//根据读开始信号,从 RAM 中读出数据
	always @(posedge clk or negedge rst_n) begin
	if(!rst_n) begin
		flow_cnt <= 2'd0;
		ram_en <= 1'b0;
		ram_addr <= 32'd0;
		ram_we <= 4'd0;
		end
	 else begin
	 case(flow_cnt)
	2'd0 : begin
	if(pos_start_rd) begin
		ram_en <= 1'b1;
		ram_addr <= start_addr;
		flow_cnt <= flow_cnt + 2'd1;
 
	end
	end
	2'd1 : begin
	ram_wr_data <= ram_rd_data + 1;
	flow_cnt <= flow_cnt + 2'd1;
	ram_we <= 4'b1111;
	end 
	2'd2:begin
		if(ram_addr - start_addr == rd_len - 4) begin //数据读完
			flow_cnt <= flow_cnt + 2'd1;
		end
		else begin
			ram_addr <= ram_addr + 32'd4; //地址累加 4
			ram_we <= 4'b0000;
			flow_cnt <= flow_cnt - 2'd1;
		end		
	end
	 2'd3 : begin
	 ram_addr <= 32'd0;
	 flow_cnt <= 2'd0;
	 ram_en <= 1'b0;
	 end
	 endcase
	 end
	 end
	
endmodule

代码都添加完毕后,进行 IP 封装。

二、Vivado 中封装自定义 AXI4 总线 IP

双击 IP-XACT 界面下的 component.xml 切换至 Packaging Steps 界面。依次完成下面的操作:

(1)点击“File Groups”一栏,随后点击界面上的“Merge changes from File Groups Wizard”;

(2)点击“Customization Parameters”一栏,随后点击界面上的“Merge changes from Customization Parameters Wizard”;

(3)点击“Ports and Interfaces”一栏,可以看到该 IP 核顶层模块的端口,为了方便在 Block Diagram 界面中对自定义的 IP 核的 BRAM 端口进行连线,我们需要将 BRAM 相关的端口定义成总线接口的形式,方法如下。

a)点击“Add Bus Interfac”图标,如下图所示:

在Vivado中创建及封装AXI4接口的自定义IP核

b)在弹出的页面中,在 Name 一栏,输入 BRAM_PORT,然后点击 Interface Definition(总线定义)右侧的“…”图标,如下图所示:

在Vivado中创建及封装AXI4接口的自定义IP核

c)接下来在弹出页面的搜索框中输入“BRAM”,选中 Advanced 一栏下的“bram_rtl”,即 BRAM 总线接口。然后点击“OK”按钮,如下图所示:

在Vivado中创建及封装AXI4接口的自定义IP核

d)将页面切换至“Port Mapping”选项页,左侧窗口为总线逻辑端口,右侧窗口为 IP 核定义的物理端口,最下面的窗口是映射端口的总结页面,如下图所示:

在Vivado中创建及封装AXI4接口的自定义IP核

e)点击左侧的“EN”端口,然后点击右侧的“ram_en”端口,此时页面上的“Map Ports”变成可以点击的按钮,点击这个按钮,此时在映射端口总结页面可以看到这两个端口映射到了一起,如下图所示:

在Vivado中创建及封装AXI4接口的自定义IP核

f)这个步骤是将顶层模块定义的“ram_en”端口和 BRAM 的“EN”端口映射到一起,我们接下来将其余接口分别一一映射,如下图所示:

在Vivado中创建及封装AXI4接口的自定义IP核

g)接下来将页面切换至“Parameters”选项页,展开 Auto-calculated,选中“MASTER_TYPE”,然后点击单个向右的箭头,如下图所示:

在Vivado中创建及封装AXI4接口的自定义IP核

h)此时,“MASTER_TYPE”参数会出现在右侧 Overridden 目录下,最后点击“OK”按钮完成 BRAM 接口的封装,如下图所示:

在Vivado中创建及封装AXI4接口的自定义IP核

(4)接下来切换至“Review and Package”页面,点击上侧的“IP has been modified”来更新 IP,最后点击“Re-Package IP”完成 IP 核的封装,此时 IP 核的封装界面会自动关闭。

退出后点击右侧的 IP Catalog,在 user repository 下面的 AXI 处右键添加 IP,添加之后就可以在 BD 中调用了,跟 Vivado 自带的 IP 核使用无异。

补充说明

(1)如果不嫌麻烦,可以在进行最后的封装前,进行一下综合,检查电路是否有问题,是否有信号被优化没了。不综合大多数情况下没问题,偶尔会出现问题。我建议可以不要嫌麻烦,综合后再进行封装。下面是将上述 IP 经过综合后的 RTL。

在Vivado中创建及封装AXI4接口的自定义IP核

(2)使用时的注意事项:

在 board diagram 中使用时,需要注意 Address Editor 中是否自动分配了该 IP 的地址和长度,如果没有配置,则点击下图中红框处的图标进行自动分配地址。

在Vivado中创建及封装AXI4接口的自定义IP核

否则,编译时会出现如下所示的警告,且编译不通过。

在Vivado中创建及封装AXI4接口的自定义IP核

三、Vivado 中自定义 AXI4 总线 IP 核移植到其他工程

要想在一个工程中设置好的 IP 核移植到另一个工程中,只需要将 xci 文件添加即可。步骤如下:

1、add source

在Vivado中创建及封装AXI4接口的自定义IP核

2、add file

在Vivado中创建及封装AXI4接口的自定义IP核

注意第一个不能勾选,不然会和第二个冲突。

3、选择文件对应 IP 核的 xci 文件即可。

扫码关注尚为网微信公众号

尚为网微信公众号
每天学习电路设计嵌入式系统的专业知识,关注一波,没准就用上了。

原创文章,作者:sunev,如若转载,请注明出处:https://www.sunev.cn/embedded/1224.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022年6月13日 14:33
下一篇 2022年6月16日 21:51

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注