清霜一梦

同步fifo的verilogHDL设计实例

0
阅读(2004)

原创

设计一个fifo,输入16bit,输出16bit的data,寻址宽度5bit,有空满标志。

 top 层如下所示:

/*
date :  2014/10/14
version : modelsim 10.1e-altera 
design  : pengxiaoen 
function : 同步fifo设计
*/
module test2 (
                    clock ,
                    reset,
                    in_data ,
                    
                    ou_data ,
                    wr_full ,
                    rd_empty ,
                    wr_en ,
                    rd_en 
                    );
                    
                    
input  clock ,reset ; 
input  [15:0] in_data ; // 写入的数据
input         wr_en  ; //写使能
input         rd_en  ; //读使能

output  [15:0] ou_data ; // 读出的数据
output         wr_full ;  //写满标志
output         rd_empty ;  //读空标志
 
wire [4:0]  add_head; //ram地址头,当读使能有效+1 
wire [4:0]  add_end ; //ram地址尾,当写使能有效+1 

//---------ram 模块,用来存储数据和输出数据--------------------------
data_memory  U1_mem(  
                            .clock (clock),
                            .reset (reset),
                            .wr_en  (wr_en),  
                            .rd_en  (rd_en),
                            .add_head (add_head) ,
                            .add_end (add_end),
                            .in_data (in_data),
                            .ou_data (ou_data)
                            );

//------------地址产生器 + 标志产生器---------------------------------                            
fifo_control U2_cont(
                            .clock (clock),
                            .reset (reset),
                            .wr_en (wr_en),
                            .rd_en (rd_en),
                            .wr_full (wr_full),
                            .rd_empty (rd_empty),
                            .add_head (add_head),
                            .add_end (add_end)
                            );                            
        

endmodule
module  data_memory (
                            clock ,reset ,
                            wr_en  ,  rd_en  ,
                            add_head ,add_end ,
                            in_data ,ou_data 
                            );
  input           clock ,reset ; // system clock and system reset  
  input           wr_en  ;     // write enable 
  input           rd_en ;      // read enable 
  input   [4:0]   add_head ;  // memory address head 
  input   [4:0]   add_end ;   // memory address end 
  input     [15:0]in_data ;   // data input to memory 
  output    reg[15:0]ou_data ;   // data output
                            
  reg [15:0] mem [0:31]  ;   //define the memory                          
  always @ (posedge clock )
        if(!reset)
                begin
                        ou_data  <=  16'dx ;
                end 
        else 
                begin 
                        case ({wr_en, rd_en})
                            2'b00  :  ou_data       <=  16'dx ; 
                            2'b01  :  ou_data       <=  mem[add_head] ;
                            2'b10  :  mem[add_end] <=  in_data ;
                            2'b11  :  begin 
                                                ou_data       <=  mem[add_end] ;
                                                mem[add_head] <=  in_data ;
                                         end 
                        endcase 
                end 
    
endmodule
module fifo_control (
                            clock ,reset ,
                            wr_en ,rd_en ,
                            wr_full ,rd_empty,
                            add_head,add_end 
                            );
  input            clock ,reset ;   // system clock and system reset 
  input            wr_en ;          // write enable 
  input            rd_en  ;         // read  enable 
  output reg       wr_full ;        // fifo full flag                             
  output reg       rd_empty ;       // fifo empty 
  output reg [4:0] add_head  ,add_end ; 
    
 reg  [4:0] head_temp , end_temp ;     
 //------地址产生块,依据读写使能进行相应地址递增,并保存原始的位置信息-----------------------
  always @ (posedge clock)
        if(!reset)
                begin 
                        head_temp <=   5'd0  ;
                        end_temp  <=   5'd0  ;
                        add_head  <=   5'd0  ;
                        add_end   <=   5'd0  ; 
                end 
                        
        else 
                begin 
                        case ({wr_en, rd_en})
                                2'b00  :   begin 
                                                        head_temp  <=  add_head  ;
                                                        end_temp   <=  add_end   ;
                                              end 
                                2'b01  :   begin 
                                                        end_temp  <=   add_end ; 
                                                        add_head  <=   add_head + 5'd1 ;
                                              end    
                                2'b10  :   begin 
                                                        head_temp <=   add_head ; 
                                                        add_end   <=   add_end  + 5'd1 ;
                                              end 
                                2'b11  :   begin
                                                        add_head  <=  add_head  +  5'd1  ; 
                                                        add_end   <=  add_end   +  5'd1  ;
                                              end 
                        endcase 
                end 
        
//--------标志产生块-------------------                            
  always @ (posedge clock)
        if(!reset)
                begin 
                        wr_full   <=   1'd0  ; 
                        rd_empty  <=   1'd0  ; 
                end 
        else
                begin 
                        case ({wr_en , rd_en})
                                2'b00 :  begin   
                                                    rd_empty  <=  1'd0 ; 
                                                    wr_full   <=  1'd0 ;
                                        end 
                                2'b01 :  begin 
                                                    wr_full  <=  1'd0 ; //写标志复位
                                                    if ((add_head +  5'd1) == head_temp)
                                                            rd_empty  <=  1'd1 ; //只有切换到写使能才复位
                                        end 
                                2'b10 :  begin 
                                                    rd_empty  <=  1'd0 ; //读标志复位
                                                    if ((add_end +  5'd1) == end_temp)
                                                            wr_full  <=  1'd1 ; //只有切换到读使能才复位    
                                        end 
                                2'b11 : begin
                                                    rd_empty  <=  1'd0 ; 
                                                    wr_full   <=  1'd0 ;
                                        end 
                        endcase 
                end 

                            
endmodule

下面附上测试代码

`timescale  1ns/1ps 

module test2_tb ; 
reg clock ,reset ; 
reg [15:0] in_data ; 
reg        wr_en ; 
reg        rd_en ; 

wire [15:0] ou_data ; 
wire        wr_full ; 
wire        rd_empty ; 


test2  U_top (
                    .clock (clock),
                    .reset (reset),
                    .in_data (in_data),
                    
                    .ou_data (ou_data),
                    .wr_full (wr_full),
                    .rd_empty (rd_empty),
                    .wr_en (wr_en),
                    .rd_en (rd_en)
                    );
            
integer i ; 
            
always #10  clock = ~clock ; 

initial 
    begin 
            clock =1'd0 ;   reset = 1'd0  ;   wr_en <= 1'd0 ;  rd_en  <= 1'd0 ;
            in_data = 16'd0 ; 
            #20 reset = 1'd1 ; wr_en <= 1'd1 ; 
          for (i=0;i<40;i=i+1) // 故意溢出
                #20 in_data  <=  in_data + 16'd1 ; 
                
            rd_en  <=  1'd1 ; wr_en <= 1'd0 ;
            #(40*20 ) // 让读空标志位触发
            $stop   ; 
            
    end 

endmodule