当前位置:   article > 正文

AXI总线,AXI_BRAM读写仿真测试_axi bram

axi bram

平台:vivado2017.4

芯片:kintex-7  xc7k325tffg900-2 (active)

准备学习AXI总线。那就从最简单的AXI BRAM学习开始。

新建BLOCK MEMORY GENERATOR,选择接口类型AXI4,这里选择simple

Dual port ram。数据位32位,数据深度1024。模块的例化部分如下

首先需要明白使用AXI封装的RAM的各个接口的作用。AXI总线是一种多通道传输总线,地址,数据,写数据,握手信号。在不同的通道中发送。这是AXI_BRAM的例化模板。

  1. //----------- Begin Cut here for INSTANTIATION Template ---// INST_TAG
  2. blk_mem_gen_0 your_instance_name (
  3. .rsta_busy(rsta_busy), // output wire rsta_busy
  4. .rstb_busy(rstb_busy), // output wire rstb_busy
  5. .s_aclk(s_aclk), // input wire s_aclk
  6. .s_aresetn(s_aresetn), // input wire s_aresetn
  7. .s_axi_awid(s_axi_awid), // input wire [3 : 0] s_axi_awid
  8. .s_axi_awaddr(s_axi_awaddr), // input wire [31 : 0] s_axi_awaddr
  9. .s_axi_awlen(s_axi_awlen), // input wire [7 : 0] s_axi_awlen
  10. .s_axi_awsize(s_axi_awsize), // input wire [2 : 0] s_axi_awsize
  11. .s_axi_awburst(s_axi_awburst), // input wire [1 : 0] s_axi_awburst
  12. .s_axi_awvalid(s_axi_awvalid), // input wire s_axi_awvalid
  13. .s_axi_awready(s_axi_awready), // output wire s_axi_awready
  14. .s_axi_wdata(s_axi_wdata), // input wire [31 : 0] s_axi_wdata
  15. .s_axi_wstrb(s_axi_wstrb), // input wire [3 : 0] s_axi_wstrb
  16. .s_axi_wlast(s_axi_wlast), // input wire s_axi_wlast
  17. .s_axi_wvalid(s_axi_wvalid), // input wire s_axi_wvalid
  18. .s_axi_wready(s_axi_wready), // output wire s_axi_wready
  19. .s_axi_bid(s_axi_bid), // output wire [3 : 0] s_axi_bid
  20. .s_axi_bresp(s_axi_bresp), // output wire [1 : 0] s_axi_bresp
  21. .s_axi_bvalid(s_axi_bvalid), // output wire s_axi_bvalid
  22. .s_axi_bready(s_axi_bready), // input wire s_axi_bready
  23. .s_axi_arid(s_axi_arid), // input wire [3 : 0] s_axi_arid
  24. .s_axi_araddr(s_axi_araddr), // input wire [31 : 0] s_axi_araddr
  25. .s_axi_arlen(s_axi_arlen), // input wire [7 : 0] s_axi_arlen
  26. .s_axi_arsize(s_axi_arsize), // input wire [2 : 0] s_axi_arsize
  27. .s_axi_arburst(s_axi_arburst), // input wire [1 : 0] s_axi_arburst
  28. .s_axi_arvalid(s_axi_arvalid), // input wire s_axi_arvalid
  29. .s_axi_arready(s_axi_arready), // output wire s_axi_arready
  30. .s_axi_rid(s_axi_rid), // output wire [3 : 0] s_axi_rid
  31. .s_axi_rdata(s_axi_rdata), // output wire [31 : 0] s_axi_rdata
  32. .s_axi_rresp(s_axi_rresp), // output wire [1 : 0] s_axi_rresp
  33. .s_axi_rlast(s_axi_rlast), // output wire s_axi_rlast
  34. .s_axi_rvalid(s_axi_rvalid), // output wire s_axi_rvalid
  35. .s_axi_rready(s_axi_rready) // input wire s_axi_rready
  36. );

部分接口说明

  1. //全局信号
  2. wire rsta_busy ;
  3. wire rstb_busy ;
  4. wire s_aclk ;//时钟
  5. wire s_aresetn ;//复位
  6. //写地址通道
  7. reg [3:0] s_axi_awid ;//写地址ID,这个信号是写地址信号组的IDtag
  8. reg [31:0] s_axi_awaddr ;//写地址
  9. reg [7:0] s_axi_awlen ;//突发次数
  10. reg [2:0] s_axi_awsize ;//一次传输字节数。一个时钟节拍传输的数据的最大位。s_axi_awsize = 3'b000,传输1byte。s_axi_awsize = 3'b001,传输2byte。s_axi_awsize = 3'b010,传输4byte。s_axi_awsize = 3'b011,传输8byte。s_axi_awsize = 3'b100,传输16byte。s_axi_awsize = 3'b101,传输32byte。s_axi_awsize = 3'b110,传输64byte。s_axi_awsize = 3'b111,传输128byte。
  11. reg [1:0] s_axi_awburst ;//突发类型
  12. reg s_axi_awvalid ;//握手信号,写地址有效。'1'有效
  13. wire s_axi_awready ;//握手。写地址准备好,'1'设备准备好
  14. //写数据通道
  15. reg [31:0] s_axi_wdata ;//写入数据
  16. reg [3:0] s_axi_wstrb ;//写阀门,WSTRB[n]表示的区间为WDATA[(8*n) + 7:(8*n)];说明:s_axi_wstrb[0]表示s_axi_wdata[7:0]有效。依次类推。
  17. reg s_axi_wlast ;//最后一个数据
  18. reg s_axi_wvalid ;//写数据有效
  19. wire s_axi_wready ;//写数据准备就绪
  20. //写请求通道
  21. wire [3:0] s_axi_bid ;//响应ID,这个数值必须与AWID的数值匹配。
  22. wire [1:0] s_axi_bresp ;//写入响应,这个信号指明写事务的状态。可能有的响应:OKAY,EXOKAY,SLVERR,DECERR
  23. wire s_axi_bvalid ;//写响应有效。'1'有效
  24. reg s_axi_bready ;//接收响应就绪,该信号表示主机已经能够接受响应信息。'1'主机就绪
  25. //读地址通道
  26. reg [3:0] s_axi_arid ;//读地址ID
  27. reg [31:0] s_axi_araddr ;//低地址
  28. reg [7:0] s_axi_arlen ;//读地址突发长度
  29. reg [2:0] s_axi_arsize ;//一次传输字节数
  30. reg [1:0] s_axi_arburst ;//突发类型
  31. reg s_axi_arvalid ;//握手信号,读地址有效。该信号一直保持,直到ARREADY为高。'1'地址和控制信号有效。
  32. wire s_axi_arready ;//握手信号,读地址就绪,指明设备已经准备好接收数据了。'1'设备就绪。
  33. //读数据通道
  34. wire [3:0] s_axi_rid ;//读IDtag。RID的数值必须与ARID的数值匹配
  35. wire [31:0] s_axi_rdata ;//读数据
  36. wire [1:0] s_axi_rresp ;//读响应。这个信号指明读传输状态
  37. wire s_axi_rlast ;//读取最后一个数据
  38. wire s_axi_rvalid ;//读取有效'1'读数据有效
  39. reg s_axi_rready ;//读数据就绪'1'主机就绪

首先分析AXI通道。AXI总线最重要的是握手机制,握手机制。再向RAM里面写数据的时候,通过AXI总线握手机制,握手成功后通过写数据发送数据。

关于AXI的握手机制:AXI全部五个通道使用相同的VALID/READY握手机制传输数据以及控制信息。传输源产生VALID信号来指明何时数据或控制信息有效。而且地源产生READY信号来指明已经准备好接受数据或者控制信息。传输发生在VALID和READY信号同时为高的时候。

注意:

  1. 发送方不能等待接收方先给出AWREADY或者WREADY信号后在给出AWVALID或WVALID。发送方准备发送,置起VALID信号是完全主动与独立的。接收方按照协议可以等待发送方的VALID信号,但是如果发送方也等待接收方的信号。就会造成总线锁死。
  2. 且发送方一旦置起VALID信号就不能置低,直到握手完成。
  3. 接收方的READY信号可以等待发送方的VALID信号有效后在置起。且可以在接收方意识到自己忙碌时可再次置低READY信号。只要发送方VALID没有置起。

AXI突发读写类型和在一次突发读写事务内如何计算地址和byte lanes。

s_axi_awlen和s_axi_arlen每一次突发读写传输的数据的个数。

Len = 4’b0000,一次突发传输1个数据。

Len = 4’b0001,一次突发传输2个数据。

Len = 4’b0010,一次突发传输3个数据。

Len = 4’b0011,一次突发传输4个数据。

Len = 4’b0100,一次突发传输5个数据。

Len = 4’b0101,一次突发传输6个数据。

Len = 4’b0110,一次突发传输7个数据。

Len = 4’b0111,一次突发传输8个数据。

Len = 4’b1000,一次突发传输9个数据。

Len = 4’b1001,一次突发传输10个数据。

Len = 4’b1010,一次突发传输11个数据。

Len = 4’b1011,一次突发传输12个数据。

Len = 4’b1100,一次突发传输13个数据。

Len = 4’b1101,一次突发传输14个数据。

Len = 4’b1110,一次突发传输15个数据。

Len = 4’b1111,一次突发传输16个数据。

s_axi_awsize和s_axi_arsize一个时钟节拍所传输的数据的最大位数。

//一次传输字节数。一个时钟节拍传输的数据的最大位。

s_axi_awsize = 3'b000,传输1byte。

s_axi_awsize = 3'b001,传输2byte。

s_axi_awsize = 3'b010,传输4byte。

s_axi_awsize = 3'b011,传输8byte。

s_axi_awsize = 3'b100,传输16byte。

s_axi_awsize = 3'b101,传输32byte。

s_axi_awsize = 3'b110,传输64byte。

s_axi_awsize = 3'b111,传输128byte。

s_axi_awburst和s_axi_arburst指示AXI协议的三种突发读写类型。固定式突发读写,增值式突发读写,包装式突发读写。

  1. Burst = 2’b00 ,FIXED固定式突发读写是指地址是固定的,每一次传输的地址都不变。这样的突发读写式重复的对一个相同的位置进行存取。如FIFO。
  2. Burst = 2’b01,INCR增值式突发读写是指每一次读写的地址都比上一次的地址增加一个固定的值。
  3. Burst = 2’b10,WRAP包装式突发读写跟增值式突发读写类似。包装式突发读写的地址是包数据的低地址当到达一个包边界。

包装式突发读写有两个限制:

起始地址必须以传输的size对齐。

突发式读写的长度必须是2,4,6,8,或者16。

设计代码...实现对AXI_BRAM的单个数据的读写。

根据AXI总线读写的分析。分别设置空闲,写地址,写数据,读地址以及停止状态。

状态机分三步写。

设计两个接口,分别为AXI写使能,和AXI读使能。默认在空闲状态下,等待读写使能。当写使能来到的时候,先进入写地址状态。在写地址状态里面判断是否握手,valid和ready同时为1,退出写地址状态(这里我准备只使用AXI总线的单个读写功能)之后进入写状态,同样在写状态判断是否握手,结束写状态,进入停止状态。当AXI读使能来到的时候,进入读状态,读状态只需要发送读地址即可读出数据,这里同样只握手后退出。

在写通道,首先写入一个地址。

  1. //写地址
  2. s_axi_awaddr <= #U_DLY s_axi_awaddr + 32'b1;//地址0
  3. s_axi_awlen <= #U_DLY 8'b0;//1个数据
  4. s_axi_awsize <= #U_DLY 3'b010;//4bytes
  5. s_axi_awburst<= #U_DLY 2'b0;//突发地址固定模式
  6. s_axi_awvalid<= #U_DLY 1'b1;//地址有效

结束写通道后地址不清零,保留原值。

在写入数据。

  1. s_axi_araddr <= #U_DLY s_axi_araddr + 32'b1;
  2. s_axi_arlen <= #U_DLY 8'b0;
  3. s_axi_arsize <= #U_DLY 3'b010;
  4. s_axi_arburst<= #U_DLY 2'b0;
  5. s_axi_arvalid<= #U_DLY 1'b1;

同时。需要拉高s_axi_rready,表示主机接收读数据就绪。

但是在仿真过程中却发现了问题,写地址在一个写期间地址递增。通过观察发现使我们的写地址状态持续了两个时钟周期。这样做导致地址增加了一个。所以上述的写地址赋值方式错误。

 同理写数据也递增。

同理读地址也递增。读数据不对。

修改代码。

经过分析,我在testbench里面写的过程是:首先向地址0写入32位的数据1。之后立马将地址0的数据读出来。之后在写地址1写32位的数据2,再读出来。

我的逻辑代码里面,首先向地址0写32位数据1,在向地址1写32位数据32位2。一直重复十次。

仿真的结果是:我经过AXI总线读取地址0的数据是我写入的地址3的数据。这里就有了问题。说明我向AXI_RAM里面写入的地址和数据不匹配。

思考:AXI_RAM的写地址是否和DDR等地址线类似。而不与传统的RAM地址递增一致。修改代码,设置AXI_RAM的s_axi_awaddr地址累加32'd4。

  1. //地址累加
  2. always@(posedge lb_clk , negedge lb_rst_n)
  3. begin
  4. if(!lb_rst_n)
  5. reg_wr_addr <= #U_DLY 32'b0;
  6. else if(c_state == wr_addr_valid && s_axi_awvalid == 1'b1 && s_axi_awready == 1'b1 )
  7. reg_wr_addr <= #U_DLY reg_wr_addr + 32'd4;
  8. else
  9. reg_wr_addr <= #U_DLY reg_wr_addr;
  10. end

结果仿真正确。

写数据。

读数据。

数据正常。

这样就对了。接下来试试突发写入。Burst = 2’b01,INCR增值式突发读写是指每一次读写的地址都比上一次的地址增加一个固定的值。

首先要明白AXI_BRAM的突发读写,

关于突发读第一种情况。当地址出现在地址总线上后,传输的数据将出现在读数据通道上。从设备将保持VALID为低直到读数据有效。为了表示一次突发式读写完成,设备用RLAST信号来表示最后一个被传输的数据。

第二种情况,突发读可以一次发送两个读地址。设备会在第一次突发读完成后处理第二次突发读。主机一开始传输了两个地址给设备。设备在完全处理完第一个地址的数据后开始处理第二个地址的数据

关于AXI_BRAM的突发写。

突发写的过程一开始,主机先将地址和控制信息写到写地址通道中,然后主机发送每一个写数据到写数据通道中。当主机发送最后一个数据是,拉高WLAST信号就变为高。当设备接收完所有数据之后他将一个写响应发送回主机来表明写事务完成。

好接下来根据上面的时序来实现对AXI_BRAM的突发读写。向地址0突发写16个数据,再读出。

写代码中。

更新状态机。

在写数据状态增加了

reg     [31:0]       write_cnt           ;

用于计数写数据的传输个数。作为主机我们向AXI_BRAM里面写数据首先需要设置写入首地址,设置突发传输次数,设置传输的字节数(小于或等于AXI总线位宽),这里我们突发模式为地址递增模式。主机需要提供最后一个数据信息s_axi_wlast,所以我采样计数器对当前突发传输个数进行计数。等待写通道响应作为写结束信号。

  1. write:
  2. begin
  3. if(s_axi_bvalid == 1'b1)
  4. n_state = stop;
  5. else
  6. n_state = write;
  7. end

仿真结果如下:

可以看到写结束后并没有结束写状态,写响应也没有更新,这和我们预期的不一致。

更改写状态的结束标志。经过分析代码,更改部分为。

  1. write:
  2. begin
  3. if(s_axi_wlast == 1'b1 && s_axi_wvalid == 1'b1 && s_axi_wready == 1'b1 )//只有在写数据的最后一个数据和最后一个数据握手成功后退出写状态
  4. n_state = stop;
  5. else
  6. n_state = write;
  7. end

写状态用最后一个数据标志握手成功后退出。

更改写通道部分数据和计数器。

  1. //写数据通道
  2. always@(posedge lb_clk , negedge lb_rst_n)
  3. begin
  4. if(!lb_rst_n)
  5. begin
  6. //写数据通道
  7. s_axi_wdata <= #U_DLY 32'b0;
  8. s_axi_wstrb <= #U_DLY 4'b0;
  9. s_axi_wvalid <= #U_DLY 1'b0;
  10. s_axi_bready <= #U_DLY 1'b0;
  11. write_cnt <= #U_DLY 32'd1;
  12. end
  13. else if(c_state == write )
  14. begin
  15. s_axi_wstrb <= #U_DLY 4'b1111;//wdata都有效
  16. s_axi_wvalid <= #U_DLY 1'b1;
  17. s_axi_bready <= #U_DLY 1'b1;
  18. //写数据
  19. if(s_axi_wvalid == 1'b1 && s_axi_wready == 1'b1)
  20. begin
  21. write_cnt <= #U_DLY write_cnt + 32'd1;
  22. s_axi_wdata <= #U_DLY s_axi_wdata + 32'b1;
  23. end
  24. else
  25. begin
  26. write_cnt <= #U_DLY write_cnt;
  27. s_axi_wdata <= #U_DLY s_axi_wdata;
  28. end
  29. end
  30. else
  31. begin
  32. //写数据通道
  33. s_axi_wdata <= #U_DLY 32'b0;
  34. s_axi_wstrb <= #U_DLY 4'b0;
  35. s_axi_wvalid <= #U_DLY 1'b0;
  36. s_axi_bready <= #U_DLY 1'b1;
  37. write_cnt <= #U_DLY 32'd1;
  38. end
  39. end

计数器默认值为1。数据累加。仿真效果如下图。写数据虽然跟新到了16,但是我们设置了数据长度为16个,所以最后一个数据是没有握手成功的。

下面看读部分。

同样读地址从0开始。突发读取16个数据,采用地址递增的突发读模式。比较简单就不放代码了。

下面是读的截图。

多测试几次。

从地址5读取6个数。

 地址3读取6个数。

 

地址4读取6个数。

综合上述的仿真结果,AXI突发读取的数据地址位是按4递增的。

0-3地址存储的数据0,4-7地址存储的数据1,依次类推。这点在使用时需要注意一下。

下面附上控制程序和测试文件。

  1. // *********************************************************************************/
  2. // Project Name :
  3. // Author : i_huyi
  4. // Email : i_huyi@qq.com
  5. // Creat Time : 2021/8/2 14:06:24
  6. // File Name : .v
  7. // Module Name :
  8. // Called By :
  9. // Abstract :
  10. // v1.0对AXI_BRAM单独读写模块。
  11. // v1.1更新对AXI_BRAM的突发读写。设置突发长度。
  12. //
  13. // CopyRight(c) 2020, xxx xxx xxx Co., Ltd..
  14. // All Rights Reserved
  15. //
  16. // *********************************************************************************/
  17. // Modification History:
  18. // 1. initial
  19. // *********************************************************************************/
  20. // *************************
  21. // MODULE DEFINITION
  22. // *************************
  23. `timescale 1 ps / 1 ps
  24. module bram_control_burst#(
  25. parameter U_DLY = 1
  26. )
  27. (
  28. input wire lb_clk ,
  29. input wire lb_rst ,
  30. input wire reg_axi_write ,
  31. input wire reg_axi_read
  32. );
  33. //--------------------------------------
  34. // localparam
  35. //--------------------------------------
  36. //配置突发个数
  37. localparam len = 8'h0f;//突发16个数据
  38. //状态空间
  39. localparam idle = 4'b0000;
  40. localparam wr_addr = 4'b0001;
  41. localparam wr_addr_valid = 4'b0010;
  42. localparam write = 4'b0011;
  43. localparam write_valid = 4'b0100;
  44. localparam read = 4'b0101;
  45. localparam read_valid = 4'b0110;
  46. localparam read_data = 4'b0111;
  47. localparam stop = 4'b1000;
  48. //--------------------------------------
  49. // register
  50. //--------------------------------------
  51. reg [3:0] c_state ;
  52. reg [3:0] n_state ;
  53. reg [31:0] reg_wr_addr ;
  54. //reg [31:0] reg_wr_data ;
  55. reg [31:0] reg_rd_addr ;
  56. reg [31:0] write_cnt ;
  57. //--------------------------------------
  58. // wire
  59. //--------------------------------------
  60. //全局信号
  61. wire rsta_busy ;
  62. wire rstb_busy ;
  63. wire s_aclk ;//时钟
  64. wire s_aresetn ;//复位
  65. //写地址通道
  66. reg [3:0] s_axi_awid ;//写地址ID,这个信号是写地址信号组的IDtag
  67. reg [31:0] s_axi_awaddr ;//写地址
  68. reg [7:0] s_axi_awlen ;//突发次数
  69. reg [2:0] s_axi_awsize ;//一次传输字节数。一个时钟节拍传输的数据的最大位。s_axi_awsize = 3'b000,传输1byte。s_axi_awsize = 3'b001,传输2byte。s_axi_awsize = 3'b010,传输4byte。s_axi_awsize = 3'b011,传输8byte。s_axi_awsize = 3'b100,传输16byte。s_axi_awsize = 3'b101,传输32byte。s_axi_awsize = 3'b110,传输64byte。s_axi_awsize = 3'b111,传输128byte。
  70. reg [1:0] s_axi_awburst ;//突发类型
  71. reg s_axi_awvalid ;//握手信号,写地址有效。'1'有效
  72. wire s_axi_awready ;//握手。写地址准备好,'1'设备准备好
  73. //写数据通道
  74. reg [31:0] s_axi_wdata ;//写入数据
  75. reg [3:0] s_axi_wstrb ;//写阀门,WSTRB[n]表示的区间为WDATA[(8*n) + 7:(8*n)];说明:s_axi_wstrb[0]表示s_axi_wdata[7:0]有效。依次类推。
  76. reg s_axi_wlast ;//最后一个数据
  77. reg s_axi_wvalid ;//写数据有效
  78. wire s_axi_wready ;//写数据准备就绪
  79. //写请求通道
  80. wire [3:0] s_axi_bid ;//响应ID,这个数值必须与AWID的数值匹配。
  81. wire [1:0] s_axi_bresp ;//写入响应,这个信号指明写事务的状态。可能有的响应:OKAY,EXOKAY,SLVERR,DECERR
  82. wire s_axi_bvalid ;//写响应有效。'1'有效
  83. reg s_axi_bready ;//接收响应就绪,该信号表示主机已经能够接受响应信息。'1'主机就绪
  84. //读地址通道
  85. reg [3:0] s_axi_arid ;//读地址ID
  86. reg [31:0] s_axi_araddr ;//低地址
  87. reg [7:0] s_axi_arlen ;//读地址突发长度
  88. reg [2:0] s_axi_arsize ;//一次传输字节数
  89. reg [1:0] s_axi_arburst ;//突发类型
  90. reg s_axi_arvalid ;//握手信号,读地址有效。该信号一直保持,直到ARREADY为高。'1'地址和控制信号有效。
  91. wire s_axi_arready ;//握手信号,读地址就绪,指明设备已经准备好接收数据了。'1'设备就绪。
  92. //读数据通道
  93. wire [3:0] s_axi_rid ;//读IDtag。RID的数值必须与ARID的数值匹配
  94. wire [31:0] s_axi_rdata ;//读数据
  95. wire [1:0] s_axi_rresp ;//读响应。这个信号指明读传输状态
  96. wire s_axi_rlast ;//读取最后一个数据
  97. wire s_axi_rvalid ;//读取有效'1'读数据有效
  98. reg s_axi_rready ;//读数据就绪'1'主机就绪
  99. //system signal
  100. wire lb_rst_n ;
  101. //--------------------------------------
  102. // assign
  103. //--------------------------------------
  104. //system signal
  105. assign lb_rst_n = ~lb_rst;
  106. assign s_aclk = lb_clk;
  107. assign s_aresetn = ~lb_rst;
  108. //------------------------------------------------------------
  109. //------------------------------------------------------------
  110. always@(posedge lb_clk ,negedge lb_rst_n)
  111. begin
  112. if(!lb_rst_n)
  113. c_state <= #U_DLY idle;
  114. else
  115. c_state <= #U_DLY n_state;
  116. end
  117. always @(*)
  118. begin
  119. case(c_state)
  120. idle:
  121. begin
  122. if(reg_axi_write == 1'b1)
  123. n_state = wr_addr;
  124. else if(reg_axi_read == 1'b1)
  125. n_state = read;
  126. else
  127. n_state = idle;
  128. end
  129. wr_addr:
  130. begin
  131. n_state = wr_addr_valid;
  132. end
  133. wr_addr_valid:
  134. begin
  135. if(s_axi_awvalid == 1'b1 && s_axi_awready == 1'b1)
  136. n_state = write;
  137. else
  138. n_state = wr_addr_valid;
  139. end
  140. write:
  141. begin
  142. if(s_axi_wlast == 1'b1 && s_axi_wvalid == 1'b1 && s_axi_wready == 1'b1 )//只有在写数据的最后一个数据和最后一个数据握手成功后退出写状态
  143. n_state = stop;
  144. else
  145. n_state = write;
  146. end
  147. read:
  148. n_state = read_valid;
  149. read_valid:
  150. begin
  151. if(s_axi_arvalid == 1'b1 && s_axi_arready == 1'b1)
  152. n_state = read_data;
  153. else
  154. n_state = read_valid;
  155. end
  156. read_data:
  157. begin
  158. if(s_axi_rvalid == 1'b1 && s_axi_rready == 1'b1)
  159. n_state = stop;
  160. else
  161. n_state = read_data;
  162. end
  163. stop:
  164. n_state = idle;
  165. default:
  166. n_state = idle;
  167. endcase
  168. end
  169. //写地址通道
  170. always@(posedge lb_clk , negedge lb_rst_n)
  171. begin
  172. if(!lb_rst_n)
  173. begin
  174. //写地址通道
  175. s_axi_awid <= #U_DLY 4'b0000;
  176. s_axi_awaddr <= #U_DLY 32'b0;
  177. s_axi_awlen <= #U_DLY 8'b0;
  178. s_axi_awsize <= #U_DLY 3'b0;
  179. s_axi_awburst<= #U_DLY 2'b0;
  180. reg_wr_addr <= #U_DLY 32'd0;
  181. end
  182. else if(c_state == wr_addr || c_state == wr_addr_valid)
  183. begin
  184. //写地址
  185. s_axi_awaddr <= #U_DLY reg_wr_addr;//地址0
  186. s_axi_awlen <= #U_DLY len;//16个数据
  187. s_axi_awsize <= #U_DLY 3'b010;//一次传输4bytes
  188. s_axi_awburst<= #U_DLY 2'b01;//突发地址递增模式
  189. end
  190. else
  191. begin
  192. //写地址通道
  193. s_axi_awid <= #U_DLY 4'b0000;
  194. s_axi_awaddr <= #U_DLY s_axi_awaddr;
  195. s_axi_awlen <= #U_DLY s_axi_awlen;
  196. s_axi_awsize <= #U_DLY s_axi_awsize;
  197. s_axi_awburst<= #U_DLY s_axi_awburst;
  198. end
  199. end
  200. //写地址有效
  201. always@(posedge lb_clk , negedge lb_rst_n)
  202. begin
  203. if(!lb_rst_n)
  204. begin
  205. s_axi_awvalid <= #U_DLY 1'b0;
  206. end
  207. else if(c_state == wr_addr_valid)
  208. s_axi_awvalid <= #U_DLY 1'b1;
  209. else
  210. s_axi_awvalid <= #U_DLY 1'b0;
  211. end
  212. //写数据通道
  213. always@(posedge lb_clk , negedge lb_rst_n)
  214. begin
  215. if(!lb_rst_n)
  216. begin
  217. //写数据通道
  218. s_axi_wdata <= #U_DLY 32'b0;
  219. s_axi_wstrb <= #U_DLY 4'b0;
  220. s_axi_wvalid <= #U_DLY 1'b0;
  221. s_axi_bready <= #U_DLY 1'b0;
  222. write_cnt <= #U_DLY 32'd1;
  223. end
  224. else if(c_state == write )
  225. begin
  226. s_axi_wstrb <= #U_DLY 4'b1111;//wdata都有效
  227. s_axi_wvalid <= #U_DLY 1'b1;
  228. s_axi_bready <= #U_DLY 1'b1;
  229. //写数据
  230. if(s_axi_wvalid == 1'b1 && s_axi_wready == 1'b1)
  231. begin
  232. write_cnt <= #U_DLY write_cnt + 32'd1;
  233. s_axi_wdata <= #U_DLY s_axi_wdata + 32'b1;
  234. end
  235. else
  236. begin
  237. write_cnt <= #U_DLY write_cnt;
  238. s_axi_wdata <= #U_DLY s_axi_wdata;
  239. end
  240. end
  241. else
  242. begin
  243. //写数据通道
  244. s_axi_wdata <= #U_DLY 32'b0;
  245. s_axi_wstrb <= #U_DLY 4'b0;
  246. s_axi_wvalid <= #U_DLY 1'b0;
  247. s_axi_bready <= #U_DLY 1'b1;
  248. write_cnt <= #U_DLY 32'd1;
  249. end
  250. end
  251. //产生最后一位标志
  252. always@(posedge lb_clk , negedge lb_rst_n)
  253. begin
  254. if(!lb_rst_n)
  255. s_axi_wlast <= #U_DLY 1'b0;
  256. else if(c_state == write && write_cnt == {24'h00_0000,len})
  257. s_axi_wlast <= #U_DLY 1'b1;
  258. else
  259. s_axi_wlast <= #U_DLY 1'b0;
  260. end
  261. //读数据通道
  262. always@(posedge lb_clk , negedge lb_rst_n)
  263. begin
  264. if(!lb_rst_n)
  265. begin
  266. //读地址通道
  267. s_axi_arid <= #U_DLY 4'b0;
  268. s_axi_araddr <= #U_DLY 32'b0;
  269. s_axi_arlen <= #U_DLY 8'b0;
  270. s_axi_arsize <= #U_DLY 3'b0;
  271. s_axi_arburst<= #U_DLY 2'b0;
  272. reg_rd_addr <= #U_DLY 32'd28;
  273. //读数据通道
  274. s_axi_rready <= #U_DLY 1'b1;
  275. end
  276. else if(c_state == read || c_state == read_valid)
  277. begin
  278. s_axi_araddr <= #U_DLY reg_rd_addr;
  279. s_axi_arlen <= #U_DLY len - 8'd10;
  280. s_axi_arsize <= #U_DLY 3'b010;
  281. s_axi_arburst<= #U_DLY 2'b01;
  282. end
  283. else
  284. begin
  285. //读地址通道
  286. s_axi_arid <= #U_DLY 4'b0;
  287. s_axi_araddr <= #U_DLY s_axi_araddr;
  288. s_axi_arlen <= #U_DLY s_axi_arlen;
  289. s_axi_arsize <= #U_DLY s_axi_arsize;
  290. s_axi_arburst<= #U_DLY s_axi_arburst;
  291. //读数据通道
  292. s_axi_rready <= #U_DLY 1'b1;
  293. end
  294. end
  295. //读地址有效
  296. always@(posedge lb_clk , negedge lb_rst_n)
  297. begin
  298. if(!lb_rst_n)
  299. s_axi_arvalid<= #U_DLY 1'b0;
  300. else if(c_state == read_valid)
  301. s_axi_arvalid<= #U_DLY 1'b1;
  302. else
  303. s_axi_arvalid<= #U_DLY 1'b0;
  304. end
  305. //------------------------------------------------------------
  306. //------------------------------------------------------------
  307. //------------------------------------------------------------
  308. //------------------------------------------------------------
  309. blk_mem_gen_0 u_double_ram (
  310. //全局信号
  311. .rsta_busy (rsta_busy ),
  312. .rstb_busy (rstb_busy ),
  313. .s_aclk (s_aclk ),
  314. .s_aresetn (s_aresetn ),
  315. //写地址通道
  316. .s_axi_awid (s_axi_awid ),//写地址ID
  317. .s_axi_awaddr (s_axi_awaddr ),//写地址
  318. .s_axi_awlen (s_axi_awlen ),//突发次数
  319. .s_axi_awsize (s_axi_awsize ),//一次传输字节数
  320. .s_axi_awburst (s_axi_awburst ),//突发类型
  321. .s_axi_awvalid (s_axi_awvalid ),//握手有效
  322. .s_axi_awready (s_axi_awready ),//握手准备好
  323. //写数据通道
  324. .s_axi_wdata (s_axi_wdata ),//写入数据
  325. .s_axi_wstrb (s_axi_wstrb ),//表示写字节通道保存有效,在每8位的写数据总线上有1位被选通。
  326. .s_axi_wlast (s_axi_wlast ),//最后一个数据
  327. .s_axi_wvalid (s_axi_wvalid ),//写数据有效
  328. .s_axi_wready (s_axi_wready ),//写数据准备就绪
  329. //写请求通道
  330. .s_axi_bid (s_axi_bid ),//
  331. .s_axi_bresp (s_axi_bresp ),//写入响应
  332. .s_axi_bvalid (s_axi_bvalid ),//写响应有效
  333. .s_axi_bready (s_axi_bready ),//已准备好写入响应
  334. //读地址通道
  335. .s_axi_arid (s_axi_arid ),//读地址ID
  336. .s_axi_araddr (s_axi_araddr ),//低地址
  337. .s_axi_arlen (s_axi_arlen ),//读地址突发长度
  338. .s_axi_arsize (s_axi_arsize ),//一次传输字节数
  339. .s_axi_arburst (s_axi_arburst ),
  340. .s_axi_arvalid (s_axi_arvalid ),
  341. .s_axi_arready (s_axi_arready ),
  342. //读数据通道
  343. .s_axi_rid (s_axi_rid ),
  344. .s_axi_rdata (s_axi_rdata ),
  345. .s_axi_rresp (s_axi_rresp ),
  346. .s_axi_rlast (s_axi_rlast ),
  347. .s_axi_rvalid (s_axi_rvalid ),
  348. .s_axi_rready (s_axi_rready )
  349. );
  350. //------------------------------------------------------------
  351. //------------------------------------------------------------
  352. //------------------------------------------------------------
  353. //------------------------------------------------------------
  354. endmodule

测试文件

  1. `timescale 1ns / 1ps
  2. //
  3. // Company:
  4. // Engineer:
  5. //
  6. // Create Date: 2021/08/04 09:23:17
  7. // Design Name:
  8. // Module Name: vtf_bram_control
  9. // Project Name:
  10. // Target Devices:
  11. // Tool Versions:
  12. // Description:
  13. //
  14. // Dependencies:
  15. //
  16. // Revision:
  17. // Revision 0.01 - File Created
  18. // Additional Comments:
  19. //
  20. //
  21. module vtf_bram_control_burst;
  22. reg lb_clk ;
  23. reg lb_rst ;
  24. reg reg_axi_write ;
  25. reg reg_axi_read ;
  26. localparam size = 1;
  27. bram_control_burst u_bram_control_burst(
  28. .lb_clk (lb_clk ),
  29. .lb_rst (lb_rst ),
  30. .reg_axi_write (reg_axi_write ),
  31. .reg_axi_read (reg_axi_read )
  32. );
  33. initial
  34. begin
  35. lb_clk = 0;
  36. lb_rst = 1;
  37. reg_axi_write = 0;
  38. reg_axi_read = 0;
  39. #100;
  40. lb_rst = 0;
  41. #5;
  42. repeat(size)
  43. begin
  44. #100;
  45. #10;
  46. reg_axi_write = 1;
  47. #10;
  48. reg_axi_write = 0;
  49. end
  50. #1000;
  51. repeat(size)
  52. begin
  53. #120;
  54. #10;
  55. reg_axi_read = 1;
  56. #10;
  57. reg_axi_read = 0;
  58. end
  59. end
  60. always #5 lb_clk = ~lb_clk;
  61. endmodule

下面准备实现AXI接口之间的互相通信,能更加方便的控制AXI_BRAM。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/493579
推荐阅读
相关标签
  

闽ICP备14008679号