欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

同步FIFO存储器verilog实现

程序员文章站 2024-03-17 19:55:46
...

同步FIFO存储器verilog实现

目录:
PART1 原理
PART2 代码框架及思路
PART3 代码实现
PART4 仿真

PART1:原理
FIFO表示先入先出(FIRST IN FIRST OUT),它是一种存储器结构,被广泛应用于芯片设计中。FIFO由存储单元队列或阵列构成,第一个被写入队列的数据也是第一个从队列中读取的数据。FIFO可以满足下列需求:
(1)当输入速率和输出速率不匹配时,作为临时存储单元。
(2)用作不同时钟域之间的同步
(3)输入数据路径和输出数据路径之间数据宽度不匹配时,可用于数据宽度调整电路。
对于同步FIFO,单一时钟用于写入和写出,这一点不同于异步FIFO。同步FIFO只使用了一个时钟,其控制逻辑相对于异步FIFO来说简单得多。
同步FIFO存储器verilog实现

PART2:代码框架及思路
下面是一个宽度为8,深度为4的FIFO。意味着FIFO中有4个存储位置,每个位置可以存储8位数值。
同步FIFO存储器verilog实现

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
aaa@qq.com(*)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
aaa@qq.com(*)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
aaa@qq.com(*)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);
//
aaa@qq.com(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;
aaa@qq.com(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
aaa@qq.com(*) 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

PART4:仿真结果
同步FIFO存储器verilog实现

相关标签: verilog fpga