FPGA实现AXI4总线的读写_如何写axi4逻辑
一、AXI4 接口描述
二、地址通道的控制信号与地址描述
1、地址ID
AWID[3:0]与ARID[3:0]:对于只有一个主机从机设备,该值可设置为任意
2、地址结构
AWADDR[31:0]与ARADDR[31:0]:AXI协议是基于burst(突发)的,主机只给出突发传输的第一个字节的地址,从机必须计算突发传输后续的地址。突发传输不能跨4KB边界(防止突发跨越两个从机的边界,也限制了从机所需支持的地址自增数
3、突发长度
AWLEN[7:0]与ARLEN[7:0]:ARLEN[7:0]决定读传输的突发长度,AWLEN[7:0]决定写传输的突发长度。AXI4扩展突发长度支持INCR突发类型为116次突发传输(Burst_Length=AxLEN[7:0]+1)
4、突发大小
ARSIZE[2:0],读突发传输;AWSIZE[2:0],写突发传输。
5、突发类型
AWBURST[1:0]与ARBURST[1:0]:
FIXED:突发传输过程中地址固定,用于FIFO访问
INCR:增量突发,传输过程中,地址递增。增加量取决AxSIZE的值
WRAP:回环突发,和增量突发类似,但会在特定高地址的边界处回到低地址处。回环突发的长度只能是2,4,8,16次传输,传输首地址和每次传输的大小对齐。最低的地址整个传输的数据大小对齐。回环边界等于(AxSIZE*AxLEN)
三、数据通道信号描述
1、WDATA与RDATA:写与读数据线信号
WSTRB:有效字节,WSTRB[n:0]对应于对应的写字节,WSTRB[n]对应WDATA[8n+7:8n],也就是对于的数据宽度的字节数是否有效。WVALID为低时,WSTRB可以为任意值,WVALID为高时,WSTRB为高的字节线必须指示有效的数据。对于一般应用,将WSTRB全部置1即可,保证全部数据有效。读通道无该信号。
2、WLAST与RLAST
写与读最后一个字节,拉高表示传输最后一个字节,也意味着传输结束
3、burst[1:0]
描述读写相应结构
四、突发写时序:
AXI4突发写可以分为7个状态,写空闲,写通道写地址等待,写通道写地址,写数据等待,写数据循环,接受写应答,写结束这7种状态。之所以划分为7个状态是为了后续写程序的状态机做准备。
7种状态
1、写空闲:等待触发突发信号
2、写通道写地址等待:准备好写地址AWADDR,然后拉高AWVALID。
3、写通道写地址:从机接受到AWVALID,发出AWREADY。
4、写数据等待:准备好数据WDATA,拉高WVALID。
5、写数据循环:从机接受WVALID,确认数据WDATA有效并且接受,发出WREADY,AXI是突发传输:循环该操作到接受到WLAST最后一个数据标志位。
6、接受写应答:接受到从机发出的BVALID,主机发出BREADY。
7、写结束:拉低未拉低的信号,进入写空闲
五、突发读时序
AXI4突发读可以分为6个状态,读空闲,读通道写地址等待,读通道写地址,读数据等待,读数据循环,读结束这6种状态。之所以划分为6个状态是为了后续写程序的状态机做准备。
6种状态
1、读空闲:等待触发突发信号。
2、读通道写地址等待:准备好写地址ARADDR,然后拉高ARVALID。
3、读通道写地址:从机接受到ARVALID,发出ARREADY。
4、读数据等待:从机准备好数据WDATA,从机拉高RVALID。
5、读数据循环:主机接受RVALID,确认数据RDATA有效并且接受,发出RREADY给从机,AXI是突发传输:循环该操作到接受到RLAST最后一个数据标志位
6、读结束:拉低未拉低的信号,进入读空闲
注:
1、读数据必须总是跟在与其数据相关联的地址之后。
2、写响应必须总是跟在与其相关联的写事务的最后出现。
六、写时序状态机
七、写时序代码
module axi4_write(
input clk ,
input resetn ,
input enable_write , //写使能
input [31:0] w_addr , //地址
input [63:0] w_data , //数据
output reg write_done , //写完成
output reg write_data , //表示数据写入,突发模式下可用于切换数据的指示信号
//axi4写通道地址通道
output [3:0] m_axi_awid , //写地址ID,用来标志一组写信号
output reg[31:0] m_axi_awaddr ,//写地址,给出一次写突发传输的写地址
output [7:0] m_axi_awlen , //突发长度,给出突发传输的次数
output [2:0] m_axi_awsize , //突发大小,给出每次突发传输的字节数
output [1:0] m_axi_awburst , //突发类型
output m_axi_awlock , //总线锁信号,可提供操作的原子性
output [3:0] m_axi_awcache , //内存类型,表明一次传输是怎样通过系统的
output [2:0] m_axi_awprot , //保护类型,表明一次传输的特权级及安全等级
output [3:0] m_axi_awqos , //质量服务QoS
output reg m_axi_awvalid , //有效信号,表明此通道的地址控制信号有效
input m_axi_awready , //表明“从”可以接收地址和对应的控制信号
//axi4写通道数据通道
output reg[63:0] m_axi_wdata , //写数据
output [7:0] m_axi_wstrb , //写数据有效的字节线
output reg m_axi_wlast , //表明此次传输是最后一个突发传输
output reg m_axi_wvalid , //写有效,表明此次写有效
input m_axi_wready , //表明从机可以接收写数据
//axi4写通道应答通道
input [3:0] m_axi_bid , //写响应ID TAG
input [1:0] m_axi_bresp , //写响应,表明写传输的状态
input m_axi_bvalid , //写响应有效
output reg m_axi_bready //表明主机能够接收写响应
);
//*******************参数*****************************
localparam W_IDLEW = 3'b001 ; //空闲等待
localparam W_DRIVEW = 3'b011 ; //准备、取地址
localparam W_HANDS = 3'b010 ; //握手
localparam W_WSTBR = 3'b110 ; //突发
localparam W_WAIT = 3'b111 ; //等待结束的信息
localparam W_END = 3'b101 ; //写数据阶段
parameter LEN_NUM = 1 ;
parameter AWID = 0 ;
//*********内部信号******************************
reg [2:0] state , next_state ;
reg wready_over ;
reg [7:0] len ;
assign m_axi_awid = AWID[3:0] ; // [3:0] //写地址ID,用来标志一组写信号
assign m_axi_awlen = LEN_NUM-1 ; // [7:0] //突发长度,给出突发传输的次数
assign m_axi_awsize = 3'b011 ; // [2:0] //突发大小,给出每次突发传输的字节数
assign m_axi_awburst = 2'b10 ; // [1:0] //突发类型
assign m_axi_awlock = 1'b0 ; // //总线锁信号,可提供操作的原子性
assign m_axi_awcache = 4'b0010 ; // [3:0] //内存类型,表明一次传输是怎样通过系统的
assign m_axi_awprot = 3'b000 ; // [2:0] //保护类型,表明一次传输的特权级及安全等级
assign m_axi_awqos = 4'b0000 ; // [3:0] //质量服务QoS
assign m_axi_wstrb = 8'hff ;
//状态机
always @(*) begin
state = next_state ;
end
always @(posedge clk or negedge resetn) begin
if(!resetn) begin
wready_over<=0;
end
else if(state==W_IDLEW || state==W_END )
wready_over<=0;
else if(m_axi_wready)
wready_over<=1;
end
always @(posedge clk or negedge resetn) begin
if(!resetn) begin
next_state <= W_IDLEW ;
len <=0 ;
end
else case(state)
W_IDLEW : if(enable_write) next_state <= W_DRIVEW ; else next_state<=W_IDLEW ;
W_DRIVEW: if(m_axi_awready) begin
next_state <= W_HANDS ;
len<=LEN_NUM-1 ;
end
else next_state<=W_DRIVEW ;
W_HANDS : if(wready_over && len==0)
next_state <= W_WAIT ;
else if(wready_over ) next_state <= W_WSTBR ;
else next_state<=W_HANDS ;
W_WSTBR : if(len==1) next_state <= W_WAIT ;
else begin
next_state <= W_WSTBR ;
len <=len-1 ;
end
W_WAIT : next_state<=W_END ;
W_END : if(m_axi_bvalid)next_state <= W_IDLEW ; else next_state<=W_END ;
default : next_state<=W_IDLEW ;
endcase
end
// 组合逻辑输出
always @(* ) begin
case(state)
W_IDLEW : begin
m_axi_wlast = 0 ;
m_axi_awaddr = 0 ;
m_axi_awvalid = 0 ;
m_axi_wdata = 0 ;
m_axi_wvalid = 0 ;
m_axi_bready = 0 ;
write_done = 0 ;
write_data = 0 ;
end
W_DRIVEW: begin
m_axi_wlast = 0 ;
m_axi_awaddr = w_addr ;
m_axi_awvalid = 1 ;
m_axi_wdata = 0 ;
m_axi_wvalid = 0 ;
m_axi_bready = 0 ;
write_done = 0 ;
write_data = 0 ;
end
W_HANDS : begin
m_axi_wlast = 0 ;
m_axi_awaddr = 0 ;
m_axi_awvalid = 0 ;
m_axi_wdata = 0 ;
m_axi_wvalid = 0 ;
m_axi_bready = 0 ;
write_done = 0 ;
write_data = 0 ;
end
W_WSTBR : begin
m_axi_wlast = 0 ;
m_axi_awaddr = 0 ;
m_axi_awvalid = 0 ;
m_axi_wdata = w_data ;
m_axi_wvalid = 1 ;
m_axi_bready = 0 ;
write_done = 0 ;
write_data = 1 ;
end
W_WAIT : begin
m_axi_wlast = 1 ;
m_axi_awaddr = 0 ;
m_axi_awvalid = 0 ;
m_axi_wdata = w_data ;
m_axi_wvalid = 1 ;
m_axi_bready = 0 ;
write_done = 1 ;
write_data = 1 ;
end
W_END : begin
m_axi_wlast = 0 ;
m_axi_awaddr = 0 ;
m_axi_awvalid = 0 ;
m_axi_wdata = 0 ;
m_axi_wvalid = 0 ;
m_axi_bready = 1 ;
write_done = 0 ;
write_data = 0 ;
end
default : begin
m_axi_wlast = 0 ;
m_axi_awaddr = 0 ;
m_axi_awvalid = 0 ;
m_axi_wdata = 0 ;
m_axi_wvalid = 0 ;
m_axi_bready = 0 ;
write_done = 0 ;
write_data = 0 ;
end
endcase
end
endmodule
八、读时序状态机
九、读时序代码
module axi4_read(
input resetn ,//axi复位
input clk , //axi时钟
input enable_read ,
output read_data ,
output read_done ,
input [31:0] r_addr ,
output reg [63:0] r_data ,
//axi读通道写地址
output [3:0] m_axi_arid , //读地址ID,用来标志一组写信号
output reg [31:0] m_axi_araddr , //读地址,给出一次写突发传输的读地址
output [7:0] m_axi_arlen , //突发长度,给出突发传输的次数
output [2:0] m_axi_arsize , //突发大小,给出每次突发传输的字节数
output [1:0] m_axi_arburst , //突发类型
output [1:0] m_axi_arlock , //总线锁信号,可提供操作的原子性
output [3:0] m_axi_arcache , //内存类型,表明一次传输是怎样通过系统的
output [2:0] m_axi_arprot , //保护类型,表明一次传输的特权级及安全等级
output [3:0] m_axi_arqos , //质量服务QOS
output reg m_axi_arvalid , //有效信号,表明此通道的地址控制信号有效
input m_axi_arready , //表明“从”可以接收地址和对应的控制信号
//axi读通道读数据
input [3:0] m_axi_rid , //读ID tag
input [63:0] m_axi_rdata , //读数据
input [1:0] m_axi_rresp , //读响应,表明读传输的状态
input m_axi_rlast , //表明读突发的最后一次传输
input m_axi_rvalid , //表明此通道信号有效
output reg m_axi_rready //表明主机能够接收读数据和响应信息
);
//
localparam [2:0] R_IDLER = 3'b001 ;
localparam [2:0] R_WAIT = 3'b011 ;
localparam [2:0] R_BURST = 3'b010 ;
localparam [2:0] R_END = 3'b110 ;
parameter ARID = 0 ;
parameter RD_LEN = 1 ;
//
reg [2:0] state , next_state ;
reg rvalid_over ;
//
assign m_axi_arid = ARID[3:0] ;//地址id
assign m_axi_arlen = RD_LEN-32'd1 ;//突发长度
assign m_axi_arsize = 3'b011 ;//表示AXI总线每个数据宽度是8字节,64位
assign m_axi_arburst = 2'b01 ;//地址递增方式传输
assign m_axi_arlock = 1'b0 ;
assign m_axi_arcache = 4'b0010 ;
assign m_axi_arprot = 3'b000 ;
assign m_axi_arqos = 4'b0000 ;
assign read_data = m_axi_rvalid ;
assign read_done = m_axi_rlast ;
//axi读状态机
always @(*) begin
state = next_state ;
end
//
always @(posedge clk or negedge resetn) begin
if(!resetn) begin
rvalid_over <=0 ;
end
else if(state==R_IDLER) begin
rvalid_over <=0 ;
end
else if(m_axi_rvalid)begin
rvalid_over <= 1 ;
end
end
always @(posedge clk or negedge resetn) begin
if(!resetn)
next_state <= R_IDLER;
else case(state)
R_IDLER : if(enable_read) next_state <= R_WAIT ;else next_state<=R_IDLER ;
R_WAIT : if(m_axi_arready) next_state<=R_BURST ;else next_state<=R_WAIT ;
R_BURST : if(m_axi_rlast) next_state<=R_END ;else next_state <= R_BURST ;
R_END : if(rvalid_over) next_state<=R_IDLER;else next_state<=R_END ;
default : next_state<=R_IDLER ;
endcase
end
//
always @(*) begin
case(state)
R_IDLER : begin
m_axi_araddr = 0 ;
m_axi_arvalid = 0 ;
m_axi_rready = 0 ;
r_data = 0 ;
end
R_WAIT : begin
m_axi_araddr = r_addr ;
m_axi_arvalid = 1 ;
m_axi_rready = 0 ;
r_data = 0 ;
end
R_BURST : begin
m_axi_araddr = 0 ;
m_axi_arvalid = 0 ;
m_axi_rready = 1 ;
r_data = m_axi_rdata ;
end
R_END : begin
m_axi_araddr = 0 ;
m_axi_arvalid = 0 ;
m_axi_rready = 1 ;
r_data = 0 ;
end
default : begin
m_axi_araddr = 0 ;
m_axi_arvalid = 0 ;
m_axi_rready = 0 ;
r_data = 0 ;
end
endcase
end
endmodule