天天看點

同步FIFO存儲器verilog實作

同步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
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
           

PART4:仿真結果

同步FIFO存儲器verilog實作