
1AXI 握手协议规范以及BUG处理
简介
列举AXI应该遵循的逻辑规范以及一些逻辑BUG,即使是赛林丝官方的代码也要注意。
规则
AXI所需要的信号并不多,比如,TLAST
(packet最后一位数据),TUSER
(帧开始信号)等等。我们先集中于握手信号这个概念,把握手信号分为三类:TVALID
(有效信号,表示主机开始有效传输),TREADY
(就绪信号,表示从机在该时钟周期准备好接收数据),以及TDATA
(数据)。
先大致了解握手信号的基础规则:
xVALID
必须在复位后清除总线不应该变化,除非出现
xVALID && xREADY
逻辑,即数据传输必须在xVALID
和xREADY
同时置位时发生。xVALID
&&xREADY
逻辑期间尽量不要在此处插入其他判断逻辑以免错过握手同一个时钟周期内,
xVALID
和xREADY
可以有先后或者同时置位,若有置位先后,那么另一个信号必须保持置位直到握手完成主机和从机接口间不应该有组合逻辑(标准中有表述)
建议规则:在总线空闲状态
READY
应该保持高逻辑
从机逻辑示例:
always@(posedgeACLK)
// Logic to determine S_AXIS_TREADY
always@(posedgeACLK)
if(S_AXIS_TVALID && S_AXIS_TREADY)// plus nothing!(有效和准备信号下不插入其他逻辑)
// Do something
2.出现BUG的代码(源自赛灵丝官方):
always@(posedgeS_AXI_ACLK)
if(!S_AXI_ARESETN)
// reset the circuit
elseif(S_AXI_AWVALID && S_AXI_AWREADY && something_else)
// design is already buggy
3.下面代码来自Vivado2018.3示例
always@(posedgeS_AXI_ACLK )
begin
if( S_AXI_ARESETN ==1'b0)
begin
// Some reset code
end
else
begin
if(~axi_awready && S_AXI_AWVALID && ~axi_awv_awr_flag)
begin
// Address latching code
end
elseif(axi_wready && S_AXI_WVALID && something_else)
// The design is now broken
虽然上面的代码示例是针对写入地址和数据通道,但它可以在任何通道上找到。这不仅包括读地址通道,还包括写确认和读返回通道。具体来说,在任何使用基本握手协议的设计中都经常会发现此错误。之所以这个错误常常出现,可能是因为 Xilinx的示例代码就是如此。
问题在于协议本身规定总线逻辑仅取决于**VALID
和*READY
*,如果两者都置位,那么不管其他条件是否有效,总线都应该进入下一个状态。而以上代码的逻辑带来的危害就是,当我们用这种逻辑去和其他设备的标准总线交互时,很容易错过事务。
把
always@(posedgeS_AXI_ACLK)
if(!S_AXI_ARESETN)
// reset the circuit
elseif(S_AXI_AWVALID && S_AXI_AWREADY && something_else)
// design is already buggy
改为
always@(posedgeS_AXI_ACLK)
if(!S_AXI_ARESETN)
// reset the circuit
elseif(S_AXI_AWVALID && S_AXI_AWREADY)
// Design continues ...
always@(*)
if(S_AXI_ARESETN && S_AXI_AWREADY)
assert(something_else);
always@(posedgeS_AXI_ACLK)
if(!S_AXI_ARESETN)
// Reset code
elseif(S_AXI_AWVALID && S_AXI_AWREADY)
// Accept a transaction
elseif(S_AXI_BVALID && S_AXI_BREADY)
// Code is now buggy
总体来讲,都是握手协议应该生效进入下一状态的时候,逻辑有可能会出现阻止它进入下状态的情况,国外有个博主详细讨论了这个不规范产生的BUG(这个大家可以见仁见智):
http://zipcpu.com/formal/2019/04/16/axi-mistakes.html
主机示例代码
// OPT_LOWPOWER is a parameter telling me when to force unused signals
// to a known value, to reduce any unnecessary signal toggling within
// an FPGA.
parameter[0:0] OPT_LOWPOWER =1'b0;
always@(posedgeACLK)
if(!ARESETN)
M_AXIS_TVALID <=0;
elseif(!M_AXIS_TVALID || M_AXIS_TREADY)
M_AXIS_TVALID <= next_valid_signal;
always@(posedgeACLK)
if(OPT_LOWPOWER && !ARESETN)
M_AXIS_TDATA <=0;
elseif(!M_AXIS_TVALID || M_AXIS_TREADY)
begin
M_AXIS_TDATA <= next_data;
if(OPT_LOWPOWER && !next_valid)
M_AXIS_TDATA <=0;
end
Xilinx’s AXI stream master 模版
assignaxis_tlast = (read_pointer == NUMBER_OF_ITEMS-1);
always@(posedgeACLK)
if(!ARESETN)
axis_tlast_delay <=1'b0;
else
axis_tlast_delay <= axis_tlast;
assignM_AXIS_TLAST = axis_tlast_delay;
如果M_AXIS_TVALID && !M_AXIS_TREADY
在突发长度结束的倒数第二个节拍上,则M_AXIS_TLAST
将随后被置位,而通道已经因为违反协议而停止。那么数据数量将出错,当然也不仅只会发生在AXI上,很多工程师不太注意这些细节逻辑。
详细的协议本身请参阅官方提供的文件。
暂无评论哦,快来评论一下吧!
