其实绝大多数的异步FIFO不会设计成深度为1的FIFO,但是我看很多题都是说到了这个,既然是FIFO那就是控数据流的,设计成深度为1岂不是效率很低?
我寻思这就涉及到了一个最小深度的问题,就是对于写满读快或者读写频率相同但是相位不同的FIFO,我看很多FIFO深度专题都是说之为1,那岂不是每次写FIFO的中间间隔很长?那还可以当成FIFO来用吗?
这里留给大家思考,如果连续的读写异步的FIFO深度多少合适呢?~~
回到题目里面深度为1的异步FIFO,设计起来思路很简单,写的时候FULL拉高,然后读出去的时候FULL再拉低,同理读的时候EMPTY拉高,写进来的时候EMPTY再拉低
也就是对读写的信号做个脉冲同步就行
然后读写数据的时候 满的时候不能写,空的时候不能读。
代码如下:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
// BRAD
// Create Date: 2022/07/02 10:28:03
// Design Name:
// Module Name: sync_fifo_onebit
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
//外面的逻辑数据写的时候如果FULL为高就不要写了
//外面的逻辑数据读的时候如果EMPTY为高就不要读了
module sync_fifo_onebit#(
parameter WIDTH = 32
)(
input clka,
input clkb,
input rstn,
input write_en,
input read_en,
input [WIDTH-1:0] push_data,
output [WIDTH-1:0] pop_data,
output reg full,
output reg empty
);
reg [WIDTH-1:0] pop_data_r;
reg [WIDTH-1:0] mem_reg;
reg toggle_a;
reg toggle_a_br0;
reg toggle_a_br1;
reg toggle_a_br2;
reg toggle_b;
reg toggle_b_ar0;
reg toggle_b_ar1;
reg toggle_b_ar2;
assign pop_data = pop_data_r;
always@(posedge clka or negedge rstn)begin
if(~rstn)
mem_reg <= {WIDTH{1'b0}};
else if(write_en)
mem_reg <= push_data;
end
always@(posedge clka or negedge rstn)begin
if(~rstn)
toggle_a <= 1'b0;
else if(write_en)
toggle_a <= ~toggle_a;
end
always@(posedge clka or negedge rstn)begin
if(~rstn)
begin
toggle_b_ar0 <= 1'b0;
toggle_b_ar1 <= 1'b0;
toggle_b_ar2 <= 1'b0;
end
else
begin
toggle_b_ar0 <= toggle_b;
toggle_b_ar1 <= toggle_b_ar0;
toggle_b_ar2 <= toggle_b_ar1;
end
end
always@(posedge clkb or negedge rstn)begin
if(~rstn)
pop_data_r <= {WIDTH{1'b0}};
else if(read_en)
pop_data_r <= mem_reg;
end
always@(posedge clkb or negedge rstn)begin
if(~rstn)
toggle_b <= 1'b0;
else if(read_en)
toggle_b <= ~toggle_b;
end
always@(posedge clkb or negedge rstn)begin
if(~rstn)
begin
toggle_a_br0 <= 1'b0;
toggle_a_br1 <= 1'b0;
toggle_a_br2 <= 1'b0;
end
else
begin
toggle_a_br0 <= toggle_a;
toggle_a_br1 <= toggle_a_br0;
toggle_a_br2 <= toggle_a_br1;
end
end
always@(*)begin
if(~rstn)
full = 1'b0;
else if(write_en)
full = 1'b1;
else if(toggle_b_ar2 ^ toggle_b_ar1)
full = 1'b0;
else
full = full;
end
always@(*)begin
if(~rstn)
empty = 1'b1;
else if(read_en)
empty = 1'b1;
else if(toggle_a_br2 ^ toggle_a_br1)
empty = 1'b0;
else
empty = empty;
end
endmodule
对应的TB如下所示
`timescale 1ns / 1ps
//
// Company:
// Engineer:
// BRAD
// Create Date: 2022/07/02 11:28:49
// Design Name:
// Module Name: tb_sync_fifo_onebit
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module tb_sync_fifo_onebit(
);
reg clka = 0;
reg clkb = 0;
reg rstn = 0;
reg write_en = 0;
reg read_en = 0;
reg [31:0] push_data =32'b0;
wire [31:0] pop_data;
wire full;
wire empty;
parameter period_a = 4;
parameter period_b = 6;
initial begin
forever #(period_a/2) clka <= ~clka;
end
initial begin
forever #(period_b/2) clkb <= ~clkb;
end
initial begin
#(period_a*2) rstn <= 1'b1;
end
always@(posedge clka or negedge rstn)begin
if(~rstn)begin
push_data <= 32'b0;
write_en <= 1'b0;
end
else if(~full)
begin
push_data <= push_data + 1'b1;
write_en <= 1'b1;
end
else if(full)
begin
push_data <= push_data;
write_en <= 1'b0;
end
end
always@(posedge clkb or negedge rstn)begin
if(~rstn)
read_en <= 1'b0;
else if(~empty)
read_en <= 1'b1;
else if(empty)
read_en <= 1'b0;
end
sync_fifo_onebit DUT(
.clka (clka ),
.clkb (clkb ),
.rstn (rstn ),
.write_en (write_en ),
.read_en (read_en ),
.push_data (push_data),
.pop_data (pop_data ),
.full (full ),
.empty (empty )
);
endmodule
读写数据还算正常