AXI总线基本机制:
AXI总线共有 5 个独立的通道,分别为写地址,写数据,写回应,读地址,读数据通道。5 条通道相互独立,有一些细小的差别,但共同使用一套握手机制:VALID/READY 机制。
发送方置高 VALID 信号表示发送方已经将数据,地址或者控制信息放到的写总线上,并保持。
接收方置高 READY 信号表示接收方已经做好接收的准备。
所谓的双向流控机制,指的是发送方通过 VALID 信号置起控制发送速度的同时,接收方也可以通过 READY 信号的置起与否控制接收速度,反压发送方的发送速度。
当双方的信息同时为高,时钟上升沿到达后,一次数据传输完成,在 1 到 n 次时钟上升沿后,双方传完了要传的信息后,两信号同时拉低。
AXI总线共有 5 个独立的通道,分别为写地址,写数据,写回应,读地址,读数据通道。5 条通道相互独立,有一些细小的差别,但共同使用一套握手机制:VALID/READY 机制。
发送方置高 VALID 信号表示发送方已经将数据,地址或者控制信息放到的写总线上,并保持。
接收方置高 READY 信号表示接收方已经做好接收的准备。
所谓的双向流控机制,指的是发送方通过 VALID 信号置起控制发送速度的同时,接收方也可以通过 READY 信号的置起与否控制接收速度,反压发送方的发送速度。
当双方的信息同时为高,时钟上升沿到达后,一次数据传输完成,在 1 到 n 次时钟上升沿后,双方传完了要传的信息后,两信号同时拉低。
AXI信号列表:
AXI握手机制是通过控制VALID和READY来进行实现的,VALID和READY的关系有如下,关键就是Valid和Ready同时有效时数据才有效:
写数据端将时序放到总线,并将VALID信号拉高,表示已准备好数据发送。当READY拉高,表示接收端准备好,接收数据,在下图箭头所示时刻完成一次数据的发送。
将待写的地址和数据放到总线,并将对应地址和数据有效信号拉高,表示已准备好发送数据
jesd_config_start : begin
jesd_axi_awaddr <= 'h4;
jesd_axi_awvalid <= 1'b1;
jesd_axi_wdata <= 'h10002;
jesd_axi_wvalid <= 1'b1;
state <= jesd_config1;
end
等待接收端awready信号拉高,表示接收端已准备好接收地址,在信号拉高后的下一个时钟上升沿表示地址已经接收完成。
jesd_config1 : begin
if(jesd_axi_awready)
begin
state <= jesd_config2;
end
else
begin
state <= jesd_config1;
end
end
已经完成地址的写入,数据已经置到总线,等待接收端wready信号拉高,表示接收端已经准备好接收数据,在信号拉高后的下一个时钟上升沿表示数据已经接收完成。
jesd_config2:begin
if(jesd_axi_wready)
begin
state <= jesd_config3;
end
else
begin
state <= jesd_config2;
end
end
jesd_config3:begin
if(jesd_axi_bvalid)
begin
jesd_axi_bready <= 1'b1;
state <= jesd_config4;
end
else
begin
state <= jesd_config3;
end
end
实际仿真结果如下:
AXI读时序:
读数据时,写数据端将地址或数据放到总线,并将READY信号拉高,表示已准备好数据发送。当VALID拉高,表示接收端准备好读取地址或数据信息,在下图箭头所示时刻完成一次数据的读取。
实际仿真结果如下:
完整代码如下:
module axi_lite_wr (
input wire axi_clk,
input wire axi_aresetn,
/*axi-lite wr*/
input wire axi_wready,
input wire axi_awready,
output reg axi_awvalid,
output reg [31:0] axi_wdata,
output reg [11:0] axi_awaddr,
output reg axi_wvalid,
output reg [ 3:0] axi_wstrb,
/*axi-lite rd*/
input wire [ 1:0] axi_bresp,
input wire axi_bvalid,
input wire [31:0] axi_rdata,
input wire [ 1:0] axi_rresp,
input wire axi_rvalid,
input wire axi_arready,
output reg [31:0] axi_araddr,
output reg axi_arvalid,
output reg axi_bready,
output reg axi_rready,
/*user define*/
input wire user_rd_wrn,
input wire user_enable,
input wire [31:0] user_tx_data,
input wire [11:0] user_addr,
output wire [31:0] user_rx_data,
output reg user_status
);
parameter state_idle = 5'd0,
state_wr0 = 5'd1,
state_wr1 = 5'd2,
state_wr2 = 5'd3,
state_wr3 = 5'd4,
state_rd0 = 5'd5,
state_rd1 = 5'd6,
state_rd2 = 5'd7,
state_rd3 = 5'd8,
state_wait = 5'd9;
reg [4:0] state;
reg [7:0] cnt_delay;
always@(posedge axi_clk or negedge axi_aresetn)
begin
if(axi_aresetn==1'b0)
begin
state <= state_idle;
axi_awaddr <= 'h0;
axi_awvalid <= 1'b0;
axi_wdata <= 'h0;
axi_wvalid <= 1'b0;
axi_araddr <= 'h0;
axi_arvalid <= 1'b0;
axi_rready <= 1'b0;
user_status <= 1'b0;
end
else if(user_enable)
begin
case(state)
state_idle : begin
axi_awaddr <= 'h0;
axi_awvalid <= 1'b0;
axi_wdata <= 'h0;
axi_wvalid <= 1'b0;
axi_araddr <= 'h0;
axi_arvalid <= 1'b0;
axi_rready <= 1'b0;
user_status <= 1'b0;
if(user_rd_wrn==1'b0)
begin
state <= state_wr0;
end
else
begin
state <= state_rd0;
end
end
state_wr0 : begin
axi_awaddr <= user_addr;
axi_awvalid <= 1'b1;
axi_wdata <= user_tx_data;
axi_wvalid <= 1'b1;
state <= state_wr1;
user_status <= 1'b1;
end
state_wr1 : begin
if(axi_awready)
begin
state <= state_wr2;
end
else
begin
state <= state_wr1;
end
end
state_wr2 : begin
if(axi_wready)
begin
axi_wvalid <= 1'b0;
axi_awvalid <= 1'b0;
state <= state_wr3;
end
else
begin
state <= state_wr2;
end
end
state_wr3 : begin
if(axi_bvalid)
begin
state <= state_wait;
end
else
begin
state <= state_wr3;
end
end
state_rd0 : begin
axi_araddr <= user_addr;
axi_arvalid <= 1'b1;
axi_rready <= 1'b0;
user_status <= 1'b1;
state <= state_rd1;
end
state_rd1 : begin
if(axi_arready)
begin
state <= state_rd2;
axi_rready <= 1'b1;
end
else
begin
state <= state_rd1;
end
end
state_rd2 : begin
if(axi_rvalid)
begin
if(axi_rresp=='h0)
begin
user_rx_data <= axi_rdata;
state <= state_rd3;
end
else
begin
user_rx_data <= 'h0000ffff;
state <= state_rd3;
end
end
else
begin
state <= state_rd2;
end
end
state_rd3 : begin
axi_rready <= 1'b0;
state <= state_wait;
end
state_wait : begin
if(cnt_delay==20)
begin
state <= state_idle;
cnt_delay <= 'h0;
end
else
begin
state <= state_wait;
cnt_delay <= cnt_delay + 1'b1;
user_status <= 1'b0;
end
end
default : begin
state <= state_idle;
end
endcase
end
end
endmodule