跳至正文

编写AXI4-Lite协议读写BRAM并仿真验证

前面已经详细介绍了AXI4和AXI4-Lite协议,光说不练假把式,要用起来才能知道理解对不对,今天就用AXI4-Lite协议来读写BRAM,看一下协议的读写过程与时序关系。


一. 建立工程

使用Vivado 2018.3,Create Project -> 一路next -> 选择芯片型号xc7z020clg484-2 -> next -> finish,等待工程创建完成。



二. 创建块设计

Flow/Flow Navigator -> Create Block Design -> Design name: bram -> OK

2.1 搭建原理图

2.1.1 添加BRAM并设置

在Diagram中,点击加号+来添加IP,在搜索框输入block,双击选择Block Memory Generator 。


双击Block Menory Generator块设置此IP,在Other Options选项卡最下方取消Enable Safety Circuit的勾选,OK,如下图:发现rsta_busy信号消失了,此信号是用来指示BRAM的工作状态的,我们这个试验不需要关注它。

2.1.2 添加BRAM控制器并设置

添加AXI BRAM Controller,如下图:

双击此IP块进行设置,将AXI Protocol设置为AXILITE,Number of BRAM interfaces设置为1,OK,如下图:

2.1.3 连接IP,引出端口

连线并Make External,如下图所示:

2.1.4 映射存储地址 Assign Address

在Address Editor窗口点击Auto Assign Address按钮,如下图:

2.1.5 生成输出产品 Generate Output Products

在Sources窗口,选中bram后右击选择Generate Output Products,如下图:

2.1.6 添加AXI SmartConnect并设置

添加AXI SmartConnect,将Number of Slave Interfaces设为1,如下图:

2.1.7 连线并验证原理图

全部设置完后连线,最终的原理框图如下图所示:

再映射一遍地址,按F6来验证设计(Validate Design),无报错,按Ctrl+S保存设计,此时一个AXI4-Lite的从机就搭建完成了。后续我们需要对它进行封装以便于测试程序的调用。

2.3 封装原理图

封装需要进行两个步骤:

第一步:生成输出文件 Generate Output Products

在Sources选项卡下,选择bram后右击选择Generate Output Products

综合选项Synthesis Options选择Out of context per IP,点击Generate,等待生成输出文件完成。

第二步: 创建HDL封装

在Sources选项卡下,选择bram后右击选择Create HDL Wrapper。

选择Let Vivado manage wrapper and auto-update,让Vivado管理封装并自动更新,OK,等待封装完成。

细心的朋友应该发现了,我们生成输出产品操作了两次,原因是如果先直接把三个IP添加进去连线的话,生成了M_AXI端口协议是AXI4而非AXI4-Lite,所以我们先将添加了BARM和BRAM控制器生成了输出,来确保M_AXI端口是AXI4-LITE协议,然后再添加AXI SmartConnect,最终封装。不添加AXI SmartConnect时从机不能输出rwready,即无法对BRAM进行写入。


三. 编写testbench

在Sources选项卡中选中sim_1 -> 点击+ -> 选择Add or Create Simulation Sources -> Create File -> File type选择SystemVerilog,File name为bram_tb,OK -> finish -> Yes。

完成后,会在sim_1下生成vivado的仿真文件bram_tb.sv,此文件只是一个框架,内容需要自行编辑。

testbench代码如下:

/*
 * @Author: Xu XiaoKang
 * @Email: xuxiaokang_up@qq.com
 * @Date: 2020-08-01 17:24:27
 * @LastEditors: xu XiaoKang
 * @LastEditTime: 2020-08-03 10:52:08
 * @Filename:
 * @Description: bram AXI Master仿真
 */



module bram_tb ();

timeunit 1ns;
timeprecision 1ps;


logic [12:0] M_AXI_awaddr;
logic [2 :0] M_AXI_awprot;
logic        M_AXI_awvalid;
logic        M_AXI_awready;

logic [31:0] M_AXI_wdata;
logic [3 :0] M_AXI_wstrb;
logic        M_AXI_wvalid;
logic        M_AXI_wready;

logic [1:0]  M_AXI_bresp;
logic        M_AXI_bvalid;
logic        M_AXI_bready;

logic [12:0] M_AXI_araddr;
logic [2 :0] M_AXI_arprot;
logic        M_AXI_arvalid;
logic        M_AXI_arready;


logic [31:0] M_AXI_rdata;
logic [1 :0] M_AXI_rresp;
logic        M_AXI_rvalid;
logic        M_AXI_rready;

logic clk;
logic rstn;


// 生成时钟
localparam CLKT = 2;
initial begin
  clk = 0;
  forever #(CLKT / 2) clk = ~clk;
end

initial begin
  rstn = 0;
  #(CLKT * 5)
  rstn = 1;

  M_AXI_awaddr = 13'b0_0000_0000_1000;
  M_AXI_awprot = '0;
  M_AXI_awvalid = 1'b1;
  wait(M_AXI_awready == 1'b1#(CLKT * 1) M_AXI_awvalid = 1'b0;

  M_AXI_wdata = 32'h0104_15bc;
  M_AXI_wstrb = 4'b1001;
  M_AXI_wvalid = 1'b1;
  wait(M_AXI_wready == 1'b1#(CLKT * 1) M_AXI_wvalid = 1'b0;

  M_AXI_bready = 1'b1;
  wait(M_AXI_bvalid == 1'b1#(CLKT * 1) M_AXI_bready = 1'b0;

  M_AXI_araddr = 13'b0_0000_0000_1000;
  M_AXI_arprot = '0;
  M_AXI_arvalid = 1'b1;
  wait(M_AXI_arready == 1'b1#(CLKT * 1) M_AXI_arvalid = 1'b0;

  M_AXI_rready = 1'b1;
  wait(M_AXI_rvalid == 1'b1#(CLKT * 1) M_AXI_rready = 1'b0;

  #(CLKT * 10) $stop;
end

bram_wrapper  bram_wrapper_inst_0 (.*);

endmodule


四. 运行仿真

使用vivado 2018.3 和 modelsim 10.6e SE-64 联合仿真,关于如何在vivado中使用modelsim仿真我后续会更新相关博客。

可以看到,写入的数据为32’h0104_15bc,此时写选通wstrb = 4‘b1001,表示最高字节位和最低字节位的数据有效,从同一地址读出的数据为32’h0100_00bc,可见写入与读出是一致的。


五. 总结与分享

实验表明AXI4-Lite如前文介绍的一样工作。AXI4-Lite每次只能写入一个数据,且必须按照先地址后数据的方式,它不支持乱序传输,唯一需要注意的是写选通信号wstrb,通过此信号可控制数据总线上的哪些字节会被写入到指定地址。

完整工程文件:axiLiteRwRam.7z

欢迎大家关注我的公众号:徐晓康的博客,回复以下四位数字获取。

4569

建议复制过去不会码错字!


如果本文对你有所帮助,欢迎点赞、转发、收藏、评论让更多人看到,赞赏支持就更好了。

如果对文章内容有疑问,请务必清楚描述问题,留言评论或私信告知我,我看到会回复。


徐晓康的博客持续分享高质量硬件、FPGA与嵌入式知识,软件,工具等内容,欢迎大家关注。

0 0 投票数
文章评分
订阅评论
提醒
0 评论
内联反馈
查看所有评论
0
希望看到您的想法,请您发表评论x
目录