本文将xilinx的axi读写代码进行修改,实现吞吐量达到50%
写入
原本的逻辑是在S_AXI_AWVALID 和 S_AXI_WVALID均有效后,axi_awready 有效,维持一个时钟周期
并且若S_AXI_BREADY&&axi_bvalid一直无效,aw_en将保持无效,从而使axi_awready无效再次有效来接收下一次写入
axi_awready 在一个 S_AXI_ACLK 时钟周期内被置位
always @( posedge S_AXI_ACLK )
begin
if ( S_AXI_ARESETN == 1'b0 )
begin
axi_awready <= 1'b0;
aw_en <= 1'b1;
end
else
begin
if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID && aw_en)
begin
axi_awready <= 1'b1;
aw_en <= 1'b0;
end
else if (S_AXI_BREADY && axi_bvalid)
begin
aw_en <= 1'b1;
axi_awready <= 1'b0;
end
else
begin
axi_awready <= 1'b0;
end
end
end
———————————————————————————————————————————————————————————————————————————————————————
修改为这种逻辑,表示从机准备好了【S_AXI_BVALID拉高】但是主机一直未准备好【S_AXI_BREADY为低】
always @(posedge S_AXI_ACLK)
axil_awready <= (S_AXI_AWVALID && S_AXI_WVALID)
&& (!S_AXI_BVALID || S_AXI_BREADY);
但是这样不够,因为若axil_awready 保留超过一个时钟周期,还是有可能在BVALID && !BREADY有效时,
axil_awready有效,那这样子主机【此时上一个数据还未被正确接收响应】将会误以为可以发送下一个
所以修改为
initial axil_awready = 1'b0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN)
axil_awready <= 1'b0;
else
axil_awready <= !axil_awready
&& (S_AXI_AWVALID && S_AXI_WVALID)
&& (!S_AXI_BVALID || S_AXI_BREADY);
—————————————————————————— **axil_bvalid 的定义** ————————————————————————————————————
**axil_bvalid 在收到**axil_awready写准备信号之后,开始有效,直到得到主机发出的S_AXI_BREADY
initial axil_bvalid = 0;
always @(posedge S_AXI_ACLK)
if (i_reset)
axil_bvalid <= 0;
else if (axil_awready)
axil_bvalid <= 1;
else if (S_AXI_BREADY)
axil_bvalid <= 0;
assign S_AXI_BVALID = axil_bvalid;
修改逻辑后可以实现50%的吞吐量
读取
always @( posedge S_AXI_ACLK )
begin
if ( S_AXI_ARESETN == 1'b0 )
begin
axi_rvalid <= 0;
axi_rresp <= 0;
end
else
begin
if (axi_arready && S_AXI_ARVALID && ~axi_rvalid)//在slv_reg_rden 读使能有效时
begin//告知完读取的地址,axi_rvalid 有效,一直保持到主机发出S_AXI_RREADY
// Valid read data is available at the read data bus
axi_rvalid <= 1'b1;
axi_rresp <= 2'b0; // 'OKAY' response
end
else if (axi_rvalid && S_AXI_RREADY)
begin
// Read data is accepted by the master
axi_rvalid <= 1'b0;
end
end
end
// 在接收到了S_AXI_ARVALID有效信号后,axi_arready维持一周期的有效,
// 直接读取地址【告知从机要读取的寄存器是哪一个】
always @( posedge S_AXI_ACLK )
begin
if ( S_AXI_ARESETN == 1'b0 )
begin
axi_arready <= 1'b0;
axi_araddr <= 32'b0;
end
else
begin
if (~axi_arready && S_AXI_ARVALID)
begin
// indicates that the slave has acceped the valid read address
axi_arready <= 1'b1;
// Read address latching
axi_araddr <= S_AXI_ARADDR;
end
else
begin
axi_arready <= 1'b0;
end
end
end
assign slv_reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid;
// 这个逻辑表示在接收到了地址之后的下一个周期,读数据使能有效
—————————————————————————— **修改之后的逻辑** ————————————————————————————————————
当S_AXI_ARVALID && S_AXI_ARREADY有效后【也就是地址读完之后】
S_AXI_RVALID 有效 ,axil_arready 无效
接收到S_AXI_RREADY,S_AXI_RVALID 无效,axil_arready 再次有效,可以读取下一次的数据
always @(*)
axil_arready = !S_AXI_RVALID;
// 这允许我们将 S_AXI_ARREADY 保持在高电平,直到读请求到来,然后立即将其丢弃,直到读响应发出。
assign S_AXI_ARREADY = axil_arready;
assign S_AXI_RVALID = axil_read_valid;
assign axil_read_ready = (S_AXI_ARVALID && S_AXI_ARREADY);
initial axil_read_valid = 1'b0;
always @(posedge S_AXI_ACLK)
if (i_reset)
axil_read_valid <= 1'b0;
else if (S_AXI_ARVALID && S_AXI_ARREADY)
axil_read_valid <= 1'b1;
else if (S_AXI_RREADY)
axil_read_valid <= 1'b0;
在!S_AXI_RVALID || S_AXI_RREADY以及
S_AXI_ARVALID && S_AXI_ARREADY有效时,读取数据
当使用缓冲机制,RVALID一直有效,只要上级发出RREADY,就可以迅速读取![](https://img-blog.csdnimg.cn/direct/5f87e655753b46179264854683aadb38.png)
assign axil_read_ready = arskd_valid
&& (!axil_read_valid || S_AXI_RREADY);
二者的区别在于有缓冲器下,S_AXI_RREADY有效axil_read_ready 就有效
assign axil_read_ready = (S_AXI_ARVALID && S_AXI_ARREADY);