目录:
PART1 原理
PART2 代码框架及思路
PART3 代码实现
PART4 仿真
PART1:原理
FIFO表示先入先出(FIRST IN FIRST OUT),它是一种存储器结构,被广泛应用于芯片设计中。FIFO由存储单元队列或阵列构成,第一个被写入队列的数据也是第一个从队列中读取的数据。FIFO可以满足下列需求:
(1)当输入速率和输出速率不匹配时,作为临时存储单元。
(2)用作不同时钟域之间的同步
(3)输入数据路径和输出数据路径之间数据宽度不匹配时,可用于数据宽度调整电路。
对于同步FIFO,单一时钟用于写入和写出,这一点不同于异步FIFO。同步FIFO只使用了一个时钟,其控制逻辑相对于异步FIFO来说简单得多。
PART2:代码框架及思路
下面是一个宽度为8,深度为4的FIFO。意味着FIFO中有4个存储位置,每个位置可以存储8位数值。
clk:时钟
reset:复位
write_en:写入端使能
write_ptr:写入指针,控制写入数据写入哪个位置
write_data:写入的数据
read_en:读出端使能
read_ptr:读出端指针,控制读出哪个位置的数据
fifo_full:FIFO已满
fifo_empty:FIFO已空
fifo_room_avail:FIFO还有多少位置剩余
fifo_data_avail:FIFO已经填充了几个数据
我们要确保发生两种情形,一是给满的FIFO写入数据,二是从空的FIFO中读取数据,他们分别被称为上溢和下溢,因此引入fifo_full和fifo_empty两种信号。并且,应当在快写满或者快读空的时候产生信号,避免因为延时产生上溢或下溢,因此引入fifo_room_avail和fifo_data_avail能具体反映出存储器数据深度信息。
PART3:代码实现
语言:verilog
环境:modelsim
FIFO:
module synch_fifo
#(parameter FIFO_PTR = 4,
FIFO_WIDTH = 32,
FIFO_DEPTH = 16)
(clk,reset,write_en,write_data,
read_en,read_data,
fifo_full,fifo_empty,
fifo_room_avail,fifo_data_avail);
input clk,reset;
input write_en,read_en;
input[FIFO_WIDTH-1:0] write_data;
output[FIFO_WIDTH-1:0] read_data;
output[FIFO_PTR:0] fifo_full,fifo_empty;
output [FIFO_PTR:0] fifo_room_avail,fifo_data_avail;
//
reg [FIFO_PTR-1:0] write_ptr,write_ptr_nxt;
reg [FIFO_PTR-1:0] read_ptr,read_ptr_nxt;
reg [FIFO_PTR:0] num_rest,num_rest_nxt;
reg fifo_full,fifo_empty;
wire fifo_full_nxt,fifo_empty_nxt;
reg [FIFO_PTR:0] fifo_room_avail;
wire [FIFO_PTR:0] fifo_room_avail_nxt;
wire [FIFO_PTR:0] fifo_data_avail;
//wirte point control logic
always@(*)begin
write_ptr_nxt = write_ptr;
if(write_en)begin
if(write_ptr_nxt == FIFO_DEPTH-1) write_ptr_nxt = 'd0;
else write_ptr_nxt = write_ptr_nxt + 1;
end
end
//read point conrol logic
always@(*)begin
read_ptr_nxt = read_ptr;
if(read_en)begin
if(read_ptr_nxt == FIFO_DEPTH-1) read_ptr_nxt = 'd0;
else read_ptr_nxt = read_ptr_nxt + 1;
end
end
//calculate number of occupied entries in the FIFO
always@(*)begin
num_rest_nxt = num_rest;
if(read_en&&write_en)begin
num_rest_nxt = num_rest;
end
else if(read_en)begin
num_rest_nxt = num_rest + 1;
end
else if(write_en)begin
num_rest_nxt = num_rest - 1;
end
end
//
assign fifo_room_avail_nxt = num_rest_nxt;
assign fifo_data_avail = FIFO_DEPTH - num_rest;
assign fifo_full_nxt = (num_rest_nxt == 0);
assign fifo_empty_nxt = (num_rest_nxt == FIFO_DEPTH);
//
always@(posedge clk or negedge reset)begin
if(!reset)begin
write_ptr <= 'd0;
read_ptr <= 'd0;
num_rest <= FIFO_DEPTH;
fifo_full <= 'd0;
fifo_empty <= 'd1;
fifo_room_avail <= FIFO_DEPTH;
end
else begin
write_ptr <= write_ptr_nxt;
read_ptr <= read_ptr_nxt;
num_rest <= num_rest_nxt;
fifo_full <= fifo_full_nxt;
fifo_empty <= fifo_empty_nxt;
fifo_room_avail <= fifo_room_avail_nxt;
end
end
//SRAM memory instantiation
sram sram_fifo
(.clk(clk),.reset(reset),
.data_in(write_data),
.read_ptr(read_ptr),
.write_ptr(write_ptr),
.wr_en(write_en),.rd_en(read_en),
.read_data(read_data));
endmodule
FIFO中还调用了RAM作为存储,RAM代码如下:
module sram (clk,reset,data_in,read_ptr,write_ptr,wr_en,rd_en,read_data);
input clk,reset;
input wr_en, rd_en;
input [7:0] data_in;
input [1:0] read_ptr,write_ptr;
output [7:0] read_data;
reg [7:0] reg0,reg1,reg2,reg3;
wire [7:0] reg0_nxt,reg1_nxt,reg2_nxt,reg3_nxt;
reg[7:0] read_data,read_data_nxt;
wire write_ptr_match0,write_ptr_match1,write_ptr_match2,write_ptr_match3;
wire read_ptr_match0,read_ptr_match1,read_ptr_match2,read_ptr_match3;
assign write_ptr_match0 = (write_ptr == 2'b00);
assign write_ptr_match1 = (write_ptr == 2'b01);
assign write_ptr_match2 = (write_ptr == 2'b10);
assign write_ptr_match3 = (write_ptr == 2'b11);
assign read_ptr_match0 = (read_ptr == 2'b00);
assign read_ptr_match1 = (read_ptr == 2'b01);
assign read_ptr_match2 = (read_ptr == 2'b10);
assign read_ptr_match3 = (read_ptr == 2'b11);
assign reg0_nxt = (write_ptr_match0&&wr_en)? data_in:reg0;
assign reg1_nxt = (write_ptr_match1&&wr_en)? data_in:reg1;
assign reg2_nxt = (write_ptr_match2&&wr_en)? data_in:reg2;
assign reg3_nxt = (write_ptr_match3&&wr_en)? data_in:reg3;
always@(posedge clk or negedge reset)begin
if(!reset)begin
reg0 <= 'd0;
reg1 <= 'd0;
reg2 <= 'd0;
reg3 <= 'd0;
read_data <= 4'b0000;
end
else begin
reg0 <= reg0_nxt;
reg1 <= reg1_nxt;
reg2 <= reg2_nxt;
reg3 <= reg3_nxt;
read_data <= read_data_nxt;
end
end
always@(*) begin
read_data_nxt = read_data;
if(rd_en)begin
case(1'b1)
read_ptr_match0:read_data_nxt = reg0;
read_ptr_match1:read_data_nxt = reg1;
read_ptr_match2:read_data_nxt = reg2;
read_ptr_match3:read_data_nxt = reg3;
endcase
end
end
endmodule
测试代码:
`timescale 1ns/1ns
module testbench;
parameter CLK_HALF_PERIOD = 'd5;
parameter FIFO_PTR = 'd2,
FIFO_WIDTH = 'd8,
FIFO_DEPTH = 'd4;
reg clk_tb,reset_tb;
reg write_en_tb,read_en_tb;
reg [FIFO_WIDTH-1:0] write_data_tb;
wire [FIFO_WIDTH-1:0] read_data_tb;
wire fifo_full_tb,fifo_empty_tb;
wire [FIFO_PTR:0]fifo_room_avail_tb,fifo_data_avail_tb;
//
initial begin
clk_tb = 'd0;
forever #CLK_HALF_PERIOD clk_tb = ~clk_tb;
end
initial begin
reset_tb = 'd0;
#20 reset_tb = 1'b1;
end
initial begin
write_en_tb = 'd0;
read_en_tb = 'd0;
write_data_tb ='d0;
#50;
write_en_tb = 1'b1;
write_data_tb =8'hA1;
read_en_tb = 'd0;
#10;
write_en_tb = 1'b1;
write_data_tb =8'hA2;
read_en_tb = 1'b1;
#10;
write_data_tb =8'hA3;
#500;
write_en_tb = 'd0;
read_en_tb ='d0;
end
synch_fifo #(FIFO_PTR,FIFO_WIDTH,FIFO_DEPTH)
synch_fifo_test
(.clk(clk_tb),.reset(reset_tb),.write_en(write_en_tb),.write_data(write_data_tb),
.read_en(read_en_tb),.read_data(read_data_tb),
.fifo_full(fifo_full_tb),.fifo_empty(fifo_empty_tb),
.fifo_room_avail(fifo_room_avail_tb),.fifo_data_avail(fifo_data_avail_tb));
endmodule