AXI-Stream FIFO
在FPGA中,遇到数据流传输时经常会用到AXI-Stream协议,它主要包含tdata,tvalid,tready三个信号。
信号名称 | 功能 |
---|---|
tdata | 由发送数据端(主机端master)发送,为需要传输的数据 |
tvalid | 由发送数据端(主机端master)发送,代表数据有效 |
tready | 由接收数据端(从机端slave)发送,代表可接收数据 |
tkeep / tstrb / tuser … | 由发送数据端(主机端master)发送,一般可等同于额外需要传输的数据 |
当遇到从机端可能无法响应主机端发来请求的情况时,需要使用FIFO进行数据同步。对于FIFO的实现可以采用如下方式:
下述代码通过位拓展的方式实现了一个深度为1的FWFT FIFO,这种方式使用存储及触发器资源的数量最少。
module axis_fifo #(
parameter TDATA_WIDTH = 1,
parameter FIFO_DEPTH = 1
) (
input logic clk,
input logic [TDATA_WIDTH - 1 : 0] m_axis_tdata,
input logic m_axis_tvalid,
output logic m_axis_tready,
output logic [TDATA_WIDTH - 1 : 0] s_axis_tdata,
output logic s_axis_tvalid,
input logic s_axis_tready
);
logic fifo_rd_cnt_r = 1'b0, fifo_wr_cnt_r = 1'b0;
always_ff @(posedge clk) begin
if (m_axis_tvalid & m_axis_tready) begin
fifo_wr_cnt_r <= ~fifo_wr_cnt_r;
end
end
always_ff @(posedge clk) begin
if (s_axis_tvalid & s_axis_tready) begin
fifo_rd_cnt_r <= ~fifo_rd_cnt_r;
end
end
assign m_axis_tready = fifo_wr_cnt_r == fifo_rd_cnt_r;
assign s_axis_tvalid = fifo_wr_cnt_r != fifo_rd_cnt_r;
logic [TDATA_WIDTH - 1 : 0] ram;
always_ff @(posedge clk) begin
if (m_axis_tvalid & m_axis_tready) begin
ram <= m_axis_tdata;
end
end
always_comb begin
s_axis_tdata = ram;
end
endmodule
通过仿真可以看到,数据能够进行缓存输出。
上述代码的问题在于无法满足连续数据流的读写需求。
为了解决上述问题,通常需要使用深度大于1的fifo。
这里以深度为2为例,fifo的实现方式如下
module axis_fifo_3 #(
parameter TDATA_WIDTH = 1,
parameter FIFO_DEPTH = 2 // 2 ** n
) (
input logic clk,
input logic [TDATA_WIDTH - 1 : 0] m_axis_tdata,
input logic m_axis_tvalid,
output logic m_axis_tready,
output logic [TDATA_WIDTH - 1 : 0] s_axis_tdata,
output logic s_axis_tvalid,
input logic s_axis_tready
);
localparam FIFO_DEPTH_WIDTH = $clog2(FIFO_DEPTH);
logic [FIFO_DEPTH_WIDTH : 0] fifo_rd_cnt_r = 'b0, fifo_wr_cnt_r = 'b0;
always_ff @(posedge clk) begin
if (m_axis_tvalid & m_axis_tready) begin
fifo_wr_cnt_r <= fifo_wr_cnt_r + 'd1;
end
end
always_ff @(posedge clk) begin
if (s_axis_tvalid & s_axis_tready) begin
fifo_rd_cnt_r <= fifo_rd_cnt_r + 'd1;
end
end
assign m_axis_tready = ~((fifo_wr_cnt_r[FIFO_DEPTH_WIDTH] != fifo_rd_cnt_r[FIFO_DEPTH_WIDTH]) && (fifo_wr_cnt_r[FIFO_DEPTH_WIDTH - 1 : 0] == fifo_rd_cnt_r[FIFO_DEPTH_WIDTH - 1 : 0]));
assign s_axis_tvalid = ~(fifo_wr_cnt_r == fifo_rd_cnt_r);
logic [TDATA_WIDTH - 1 : 0] ram[FIFO_DEPTH - 1:0];
always_ff @(posedge clk) begin
if (m_axis_tvalid & m_axis_tready) begin
ram[fifo_wr_cnt_r[FIFO_DEPTH_WIDTH - 1 : 0]] <= m_axis_tdata;
end
end
always_comb begin
s_axis_tdata = ram[fifo_rd_cnt_r[FIFO_DEPTH_WIDTH - 1 : 0]];
end
endmodule
通过仿真可以看到,在连续数据流情况下,数据能够进行缓存输出。
完整代码
完整工程可于公众号回复AXIS_FIFO下载。