目录
01 axi4_lite_slave写事务代码分析
AWREADY时序控制代码分析
WREADY时序控制代码分析
AWADDR寄存时序代码分析
WDATA寄存时序代码分析
BVALID、BRESP时序控制代码分析
axi4_lite_slave 写事务时序总结
02 axi4_lite_slave读事务代码分析
ARREADY时序、ARADDR寄存控制代码分析
RDATA时序控制代码分析
RVALID、RRESP时序控制代码分析
03 文章总结
大家好,这里是程序员杰克。一名平平无奇的嵌入式软件工程师。
上篇主要是对AXI4-Lite总线协议的特性以及master、slave接口进行了总结分享。本篇内容主要是对AXI4-Lite_slave接口信号的时序代码进行分析。
下面正式进入本章推送的内容。
01 axi4_lite_slave写事务代码分析
对于AXI4-Lite总线写事务而言,Xilinx提供的slave模板中写地址通道、写数据通道同时握手成功才执行写事务传输。而axi4-lite_slave接口主要是实现如下时序:
- 写地址通道握手信号AWREADY的时序控制
- 写数据通道握手信号WREADY的时序控制
- AWADDR以及WDATA的寄存(latch)时序控制
- 写响应通道BVALID、BRESP信号的时序控制
AXI4-Lite 写事务仿真逻辑时序如下图所示:
AWREADY时序控制代码分析
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
在该段代码中,需要关注的信号为aw_en以及axi_awready.
信号 | 条件 | 描述 |
aw_en (默认为1) | 置高 | 辅助信号,用于控制单次写事务的传输;S_AXI_BREADY与axi_bvalid同时为高时(写响应通道握手成功),aw_en置高(写事务传输完成) |
置低 | 当写地址通道、写数据通道握手成功,aw_en置低(写事务开始),直到本次写事务传输结束 | |
axi_awready (默认为0) | 置高 | axi_awready == 1‘b0 && aw_en == 1‘b1, 即写事务传输未开始, 并且S_AXI_AWVALID跟S_AXI_WVALID 同时为高,说明控制逻辑为写地址通道、写数据通道同时满足握手条件,写事务传输才开始. |
置低 | axi_awready 置高的任一条件不满足都置低,即说明axi_awready是一个脉冲信号 |
WREADY时序控制代码分析
always @( posedge S_AXI_ACLK )
begin
if ( S_AXI_ARESETN == 1'b0 )
begin
axi_wready <= 1'b0;
end
else
begin
if (~axi_wready && S_AXI_WVALID && S_AXI_AWVALID && aw_en )
begin
axi_wready <= 1'b1;
end
else
begin
axi_wready <= 1'b0;
end
end
end
信号 | 条件 | 描述 |
axi_wready (默认为0) | 置高 | 置高条件与axi_awready条件一致,写地址通道、写数据通道同时满足握手条件,写事务传输才开始. |
置低 | axi_wready置高的任一条件不满足都置低,即说明axi_wready也是一个脉冲信号 |
AWADDR寄存时序代码分析
always @( posedge S_AXI_ACLK )
begin
if ( S_AXI_ARESETN == 1'b0 )
begin
axi_awaddr <= 0;
end
else
begin
if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID && aw_en)
begin
axi_awaddr <= S_AXI_AWADDR; // Write Address latching
end
end
end
信号 | 描述 |
axi_awaddr (默认为0) | 地址锁存条件与axi_awready/axi_wready一致,即写地址通道、写数据通道VALID同时为高,地址才被锁存. |
WDATA寄存时序代码分析
assign slv_reg_wren = axi_wready && S_AXI_WVALID && axi_awready && S_AXI_AWVALID;
always @( posedge S_AXI_ACLK )
begin
if ( S_AXI_ARESETN == 1'b0 )
begin
slv_reg0 <= 0;
slv_reg1 <= 0;
slv_reg2 <= 0;
slv_reg3 <= 0;
end
else begin
if (slv_reg_wren)
begin
case ( axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
2'h0:
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
if ( S_AXI_WSTRB[byte_index] == 1 ) begin
slv_reg0[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
end
2'h1:
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
if ( S_AXI_WSTRB[byte_index] == 1 ) begin
slv_reg1[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
end
2'h2:
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
if ( S_AXI_WSTRB[byte_index] == 1 ) begin
slv_reg2[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
end
2'h3:
for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
if ( S_AXI_WSTRB[byte_index] == 1 ) begin
slv_reg3[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
end
default : begin
slv_reg0 <= slv_reg0;
slv_reg1 <= slv_reg1;
slv_reg2 <= slv_reg2;
slv_reg3 <= slv_reg3;
end
endcase
end
end
end
信号 | 描述 |
slv_reg_wren | 辅助信号,用于表征写事务传输时数据寄存控制。当axi_wready、S_AXI_WVALID、axi_awready、S_AXI_AWVALID同时为高,即写地址通道和写数据通道握手成功,在上升沿结束后,根据WADDR对对应寄存器进行赋值 |
slv_regx | 地址数据寄存器,用于锁存写数据通道的WDATA数据. |
BVALID、BRESP时序控制代码分析
always @( posedge S_AXI_ACLK )
begin
if ( S_AXI_ARESETN == 1'b0 )
begin
axi_bvalid <= 0;
axi_bresp <= 2'b0;
end
else
begin
if (axi_awready && S_AXI_AWVALID && ~axi_bvalid && axi_wready && S_AXI_WVALID)
begin
axi_bvalid <= 1'b1;
axi_bresp <= 2'b0; // 'OKAY' response
end
else
begin
if (S_AXI_BREADY && axi_bvalid)
begin
axi_bvalid <= 1'b0;
end
end
end
end
信号 | 条件 | 描述 |
axi_bvalid (默认值为0) | 置高 | 当axi_wready、S_AXI_WVALID、axi_awready、S_AXI_AWVALID同时为高, 即写地址通道和写数据通道握手成功,在上升沿结束后,axi_bvalid置高 |
置低 | S_AXI_BREADY、axi_bvalid同时为高时,axi_bvalid置低. 即axi_bvalid也是脉冲信号 | |
axi_bresp (默认值为0) | 对于AXI-Lite总线,该信号不支持EXOKAY枚举值,因此该信号值为‘OKAY’(2'b00') |
axi4_lite_slave 写事务时序总结
对于xilinx提供的axi4_lite_slave模板代码,写事务时序以及总结如下:
- 写地址通道的AWVALID、写数据通道的WVALID同时为高时,锁存AWADDR的值(此时作为第一个时钟上升沿)
- 在下一个时钟上升沿AWREADY、WREADY同时置高,即写地址通道、写数据通道握手成功的同时,WDATA被锁存到地址对应的寄存器中,数据传输完成.
- 第三个时钟上升沿,写响应通道BVALID信号置高,持续一个时钟周期,返回写事务响应结果.
02 axi4_lite_slave读事务代码分析
对于AXI4-Lite总线读事务而言,axi4-lite_slave接口主要是实现如下时序:
- 读地址通道握手信号ARREADY、ARADDR寄存(latch)的时序控制
- 读数据通道RDATA时序控制
- 读数据通道RVALID、RRESP信号的时序控制
AXI4-Lite读事务仿真逻辑时序如下图所示:
ARREADY时序、ARADDR寄存控制代码分析
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
axi_arready <= 1'b1;
axi_araddr <= S_AXI_ARADDR;
end
else
begin
axi_arready <= 1'b0;
end
end
end
信号 | 条件 | 描述 |
axi_arready (默认值为0) | 置高 | S_AXI_ARVALID为高并且自身为低,axi_arready置高 |
置低 | 置高条件任一不满足,便置低;axi_arready为脉冲信号 | |
axi_araddr (默认值为0) | 寄存 | S_AXI_ARVALID为高并且自身为低,寄存读地址 |
RDATA时序控制代码分析
assign slv_reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid;
always @(*)
begin
// Address decoding for reading registers
case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
2'h0 : reg_data_out <= slv_reg0;
2'h1 : reg_data_out <= slv_reg1;
2'h2 : reg_data_out <= slv_reg2;
2'h3 : reg_data_out <= slv_reg3;
default : reg_data_out <= 0;
endcase
end
always @( posedge S_AXI_ACLK )
begin
if ( S_AXI_ARESETN == 1'b0 )
begin
axi_rdata <= 0;
end
else
begin
if (slv_reg_rden)
begin
axi_rdata <= reg_data_out; // register read data
end
end
end
信号 | 描述 |
slv_reg_rden | 辅助信号,用于表征读事务传输时数据寄存控制。当axi_arready为高、S_AXI_ARVALID 为高、axi_rvalid为低时,即读地址通道握手成功,该信号置高; |
reg_data_out | 辅助信号,通过组合逻辑将寄存的ARADDR对应的寄存器数据赋值给该信号. |
axi_rdata | 读数据信号,当slv_reg_rden为高,在上升沿结束后,返回对应寄存器的数据 |
RVALID、RRESP时序控制代码分析
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)
begin
axi_rvalid <= 1'b1;
axi_rresp <= 2'b0; // 'OKAY' response
end
else if (axi_rvalid && S_AXI_RREADY)
begin
axi_rvalid <= 1'b0;
end
end
end
信号 | 条件 | 描述 |
axi_rvalid (默认值为0) | 置高 | 当axi_arready为高、S_AXI_ARVALID为高、axi_rvalid为低时,读地址通道握手成功,在上升沿结束后,axi_rvalid置高. |
置低 | S_AXI_RREADY、axi_rvalid同时为高时,axi_rvalid置低. 即axi_bvalid也是脉冲信号 | |
axi_rresp (默认值为0) | 对于AXI-Lite总线,该信号不支持EXOKAY枚举值,因此该信号值为‘OKAY’(2'b00') |
03 文章总结
对于使用AXI4-Lite_slave接口,Xilinx的Vivado编译工具可以直接生成模板,使用时直接在该模板上定制自己的接口内容。但杰克认为:对FPGA的学习而言,不能仅仅停留在“会用”阶段,还得深入了解其时序的设计与实现过程,才能在日后快速将其部署到自己的项目中。
言归正传,ARM提供的AMBA的相关资料里面,对握手机制的描述所占篇幅较大,因此对于AXI总线协议而言,握手机制是重中之重,Xilinx提供的axi4-lite_slave模板中,写地址通道、写数据通道是同时握手成功,传输才开始。除握手机制外,还要了解地址、数据寄存的时机。