AXI4协议-Narrow Transfer总结


最近因开发需要在学习AXI4协议,这里对其中的Narrow transfer机制做一点总结,如有疏漏敬请批评指正!

1-基本规定

Narrow transfer适用于传输位宽小于总线位宽的情况。这种情况下只有部分总线被占用,因此需要通过wstrb信号来控制我们需要写入的字节。
AXI4规定如果burst type为INCR或WRAP,则必须使用不同的通道来传输字节。以总线宽度32bit、transfer宽度16bit为例,如果第一次传输使用了总线的0-15位,那么下一次传输必须使用16-31位;
注意地址都是按照4KB对齐的!

2-仿真测试分析

我使用Vivado的Block Memory Generator v8.4生成AXI4接口的SDP RAM,然后编写测试文件进行仿真时序分析。
详细参数:SDP的AB端口均为32*1024,协议采用AXI4,初始化RAM的内容为:
0x0000-AA0000AA,0x0001-BB0000BB,
0x0010-CC0000CC,0x0011-DD0000DD,
0x0100-EE0000EE,0x0101-FF0000FF;
上述地址为字地址,字节地址需要换算。
编写tb文件,awsize设为1,即1次transfer只能传2个byte,然后进行写操作,写完之后读数据判断写入是否正确;

module axi4_full_test();
 
 wire rsta_busy;
 wire rstb_busy;
 reg s_aclk;
 reg s_aresetn;
 reg [3:0] s_axi_awid;
 reg [31:0] s_axi_awaddr;
 reg [7:0] s_axi_awlen;
 reg [2:0] s_axi_awsize;
 reg [1:0] s_axi_awburst;
 reg s_axi_awvalid;
 wire s_axi_awready;
 
 reg [31:0] s_axi_wdata;
 reg [3:0] s_axi_wstrb;
 reg s_axi_wlast;
 reg s_axi_wvalid;
 wire s_axi_wready;
 
 wire [3:0] s_axi_bid;
 wire [1:0] s_axi_bresp;
 wire s_axi_bvalid;
 reg s_axi_bready;
 
 reg [3:0] s_axi_arid;
 reg [31:0] s_axi_araddr;
 reg [7:0] s_axi_arlen;
 reg [2:0] s_axi_arsize;
 reg [1:0] s_axi_arburst;
 reg s_axi_arvalid;
 wire s_axi_arready;
 
 wire [3:0] s_axi_rid;
 wire [31:0] s_axi_rdata;
 wire [1:0] s_axi_rresp;
 wire s_axi_rlast;
 wire s_axi_rvalid;
 reg s_axi_rready;

 blk_mem_gen_0 my_interface_full(
  .rsta_busy(rsta_busy),          // output wire rsta_busy
  .rstb_busy(rstb_busy),          // output wire rstb_busy
  .s_aclk(s_aclk),                // input wire s_aclk
  .s_aresetn(s_aresetn),          // input wire s_aresetn
  .s_axi_awid(s_axi_awid),        // input wire [3 : 0] s_axi_awid
  .s_axi_awaddr(s_axi_awaddr),    // input wire [31 : 0] s_axi_awaddr
  .s_axi_awlen(s_axi_awlen),      // input wire [7 : 0] s_axi_awlen
  .s_axi_awsize(s_axi_awsize),    // input wire [2 : 0] s_axi_awsize
  .s_axi_awburst(s_axi_awburst),  // input wire [1 : 0] s_axi_awburst
  .s_axi_awvalid(s_axi_awvalid),  // input wire s_axi_awvalid
  .s_axi_awready(s_axi_awready),  // output wire s_axi_awready
  .s_axi_wdata(s_axi_wdata),      // input wire [31 : 0] s_axi_wdata
  .s_axi_wstrb(s_axi_wstrb),      // input wire [3 : 0] s_axi_wstrb
  .s_axi_wlast(s_axi_wlast),      // input wire s_axi_wlast
  .s_axi_wvalid(s_axi_wvalid),    // input wire s_axi_wvalid
  .s_axi_wready(s_axi_wready),    // output wire s_axi_wready
  .s_axi_bid(s_axi_bid),          // output wire [3 : 0] s_axi_bid
  .s_axi_bresp(s_axi_bresp),      // output wire [1 : 0] s_axi_bresp
  .s_axi_bvalid(s_axi_bvalid),    // output wire s_axi_bvalid
  .s_axi_bready(s_axi_bready),    // input wire s_axi_bready
  .s_axi_arid(s_axi_arid),        // input wire [3 : 0] s_axi_arid
  .s_axi_araddr(s_axi_araddr),    // input wire [31 : 0] s_axi_araddr
  .s_axi_arlen(s_axi_arlen),      // input wire [7 : 0] s_axi_arlen
  .s_axi_arsize(s_axi_arsize),    // input wire [2 : 0] s_axi_arsize
  .s_axi_arburst(s_axi_arburst),  // input wire [1 : 0] s_axi_arburst
  .s_axi_arvalid(s_axi_arvalid),  // input wire s_axi_arvalid
  .s_axi_arready(s_axi_arready),  // output wire s_axi_arready
  .s_axi_rid(s_axi_rid),          // output wire [3 : 0] s_axi_rid
  .s_axi_rdata(s_axi_rdata),      // output wire [31 : 0] s_axi_rdata
  .s_axi_rresp(s_axi_rresp),      // output wire [1 : 0] s_axi_rresp
  .s_axi_rlast(s_axi_rlast),      // output wire s_axi_rlast
  .s_axi_rvalid(s_axi_rvalid),    // output wire s_axi_rvalid
  .s_axi_rready(s_axi_rready)    // input wire s_axi_rready
);

 //test
 initial begin
  //initializing
  s_aclk = 1'b0;
  s_aresetn = 1'b0;
  s_axi_awid = 4'b1010;//compare with the output s_axi_bid to see the relations
  s_axi_awaddr  =32'hFFFFFF00;
  s_axi_awlen = 8'b0;
  s_axi_awsize = 3'b0;
  s_axi_awburst = 2'b01;
  s_axi_awvalid = 1'b0;
  s_axi_wstrb = 4'b1111;
  s_axi_wvalid = 1'b0;
  s_axi_bready = 1'b1;
  s_axi_arid = 4'b0101;//compare with the output s_axi_rid to see the relations
  s_axi_araddr = 32'hFFFFFF00;
  s_axi_arlen = 8'b0;
  s_axi_arsize = 3'b0;
  s_axi_arburst = 2'b01;
  s_axi_arvalid = 1'b0;
  s_axi_rready = 1'b1;
  s_axi_wlast = 1'b0;
  
 end
 always #5 s_aclk = ~s_aclk;//generate global clk
 
 initial begin
  #22 s_aresetn  =1'b1;//reset before everything
  
  //burst write, 
  #10;
  s_axi_wstrb = 4'b0011;
  s_axi_awaddr = 32'd4;
  s_axi_awlen = 8'd4;
  s_axi_awsize = 3'd1;
  s_axi_awvalid = 1'b1;
  s_axi_wdata = 32'hAAAA0001;
  wait(s_axi_awready == 1'b1 && s_aclk == 1'b1);
  #1 s_axi_awvalid = 1'b0;
     s_axi_wvalid = 1'b1;
  repeat(3) begin
   #10 s_axi_wdata = s_axi_wdata + 32'h11110001;
       s_axi_wstrb = ~s_axi_wstrb;
  end
   #10 s_axi_wlast = 1'b1;
       s_axi_wdata = s_axi_wdata + 32'd1;
       s_axi_wstrb = ~s_axi_wstrb;
   #10 s_axi_wlast = 1'b0;
  
  //read to check if we've written the correct data
  #5;
  s_axi_araddr = 32'd0;
  s_axi_arlen = 8'd4;
  s_axi_arsize = 3'd2;
  s_axi_arvalid = 1'b1;
  wait(s_axi_arready == 1'b1 && s_aclk == 1'b1);
  #1 s_axi_arvalid = 1'b0;
     s_axi_arid = 4'bx;
  #5 s_axi_rready = 1'b1;
     s_axi_araddr = 32'bx;
     
  #5 s_axi_araddr = 32'd8;
     s_axi_arvalid = 1'b1;
     s_axi_arid = 4'd15;
  #45 s_axi_arvalid = 1'b0;
  
 end
 
endmodule

测试得到的的结果如下图:这里主机做的是把32位的数据和控制信号wstrb放到总线上,进而实现只传输2个字节的功能。
蓝线为写入,黄线开始读
4条蓝线为写数据,而黄线开始是连续的读数据。根据wstrb信号的值,可以看到, 第一次写入的是0xaaaa0001的低2字节,即0001,第二次写入的是0xbbbb0001的高2字节,即bbbb,以此类推。因而原先字节地址0x0004位置储存的0xbb0000bb,就变成了0xbbbb0001;注意,传输中总线上对应字节写入也是在对应字节的位置,我画了一个并不准确的传输机制图:
传输机制猜想
那如果只想要写入1个16位数据怎么办呢?很简单,让wstrb信号保持2个时钟周期不变就可以了,正如我们最后读出的数据0xdd000005一样,就是只把低16位写入了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值