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