同步fifo的verilogHDL设计实例
原创
设计一个fifo,输入16bit,输出16bit的data,寻址宽度5bit,有空满标志。
top 层如下所示:
1 /* 2 date : 2014/10/14 3 version : modelsim 10.1e-altera 4 design : pengxiaoen 5 function : 同步fifo设计 6 */ 7 module test2 ( 8 clock , 9 reset, 10 in_data , 11 12 ou_data , 13 wr_full , 14 rd_empty , 15 wr_en , 16 rd_en 17 ); 18 19 20 input clock ,reset ; 21 input [15:0] in_data ; // 写入的数据 22 input wr_en ; //写使能 23 input rd_en ; //读使能 24 25 output [15:0] ou_data ; // 读出的数据 26 output wr_full ; //写满标志 27 output rd_empty ; //读空标志 28 29 wire [4:0] add_head; //ram地址头,当读使能有效+1 30 wire [4:0] add_end ; //ram地址尾,当写使能有效+1 31 32 //---------ram 模块,用来存储数据和输出数据-------------------------- 33 data_memory U1_mem( 34 .clock (clock), 35 .reset (reset), 36 .wr_en (wr_en), 37 .rd_en (rd_en), 38 .add_head (add_head) , 39 .add_end (add_end), 40 .in_data (in_data), 41 .ou_data (ou_data) 42 ); 43 44 //------------地址产生器 + 标志产生器--------------------------------- 45 fifo_control U2_cont( 46 .clock (clock), 47 .reset (reset), 48 .wr_en (wr_en), 49 .rd_en (rd_en), 50 .wr_full (wr_full), 51 .rd_empty (rd_empty), 52 .add_head (add_head), 53 .add_end (add_end) 54 ); 55 56 57 endmodule
1 module data_memory ( 2 clock ,reset , 3 wr_en , rd_en , 4 add_head ,add_end , 5 in_data ,ou_data 6 ); 7 input clock ,reset ; // system clock and system reset 8 input wr_en ; // write enable 9 input rd_en ; // read enable 10 input [4:0] add_head ; // memory address head 11 input [4:0] add_end ; // memory address end 12 input [15:0]in_data ; // data input to memory 13 output reg[15:0]ou_data ; // data output 14 15 reg [15:0] mem [0:31] ; //define the memory 16 always @ (posedge clock ) 17 if(!reset) 18 begin 19 ou_data <= 16'dx ; 20 end 21 else 22 begin 23 case ({wr_en, rd_en}) 24 2'b00 : ou_data <= 16'dx ; 25 2'b01 : ou_data <= mem[add_head] ; 26 2'b10 : mem[add_end] <= in_data ; 27 2'b11 : begin 28 ou_data <= mem[add_end] ; 29 mem[add_head] <= in_data ; 30 end 31 endcase 32 end 33 34 endmodule
1 module fifo_control ( 2 clock ,reset , 3 wr_en ,rd_en , 4 wr_full ,rd_empty, 5 add_head,add_end 6 ); 7 input clock ,reset ; // system clock and system reset 8 input wr_en ; // write enable 9 input rd_en ; // read enable 10 output reg wr_full ; // fifo full flag 11 output reg rd_empty ; // fifo empty 12 output reg [4:0] add_head ,add_end ; 13 14 reg [4:0] head_temp , end_temp ; 15 //------地址产生块,依据读写使能进行相应地址递增,并保存原始的位置信息----------------------- 16 always @ (posedge clock) 17 if(!reset) 18 begin 19 head_temp <= 5'd0 ; 20 end_temp <= 5'd0 ; 21 add_head <= 5'd0 ; 22 add_end <= 5'd0 ; 23 end 24 25 else 26 begin 27 case ({wr_en, rd_en}) 28 2'b00 : begin 29 head_temp <= add_head ; 30 end_temp <= add_end ; 31 end 32 2'b01 : begin 33 end_temp <= add_end ; 34 add_head <= add_head + 5'd1 ; 35 end 36 2'b10 : begin 37 head_temp <= add_head ; 38 add_end <= add_end + 5'd1 ; 39 end 40 2'b11 : begin 41 add_head <= add_head + 5'd1 ; 42 add_end <= add_end + 5'd1 ; 43 end 44 endcase 45 end 46 47 //--------标志产生块------------------- 48 always @ (posedge clock) 49 if(!reset) 50 begin 51 wr_full <= 1'd0 ; 52 rd_empty <= 1'd0 ; 53 end 54 else 55 begin 56 case ({wr_en , rd_en}) 57 2'b00 : begin 58 rd_empty <= 1'd0 ; 59 wr_full <= 1'd0 ; 60 end 61 2'b01 : begin 62 wr_full <= 1'd0 ; //写标志复位 63 if ((add_head + 5'd1) == head_temp) 64 rd_empty <= 1'd1 ; //只有切换到写使能才复位 65 end 66 2'b10 : begin 67 rd_empty <= 1'd0 ; //读标志复位 68 if ((add_end + 5'd1) == end_temp) 69 wr_full <= 1'd1 ; //只有切换到读使能才复位 70 end 71 2'b11 : begin 72 rd_empty <= 1'd0 ; 73 wr_full <= 1'd0 ; 74 end 75 endcase 76 end 77 78 79 endmodule
下面附上测试代码
1 `timescale 1ns/1ps 2 3 module test2_tb ; 4 reg clock ,reset ; 5 reg [15:0] in_data ; 6 reg wr_en ; 7 reg rd_en ; 8 9 wire [15:0] ou_data ; 10 wire wr_full ; 11 wire rd_empty ; 12 13 14 test2 U_top ( 15 .clock (clock), 16 .reset (reset), 17 .in_data (in_data), 18 19 .ou_data (ou_data), 20 .wr_full (wr_full), 21 .rd_empty (rd_empty), 22 .wr_en (wr_en), 23 .rd_en (rd_en) 24 ); 25 26 integer i ; 27 28 always #10 clock = ~clock ; 29 30 initial 31 begin 32 clock =1'd0 ; reset = 1'd0 ; wr_en <= 1'd0 ; rd_en <= 1'd0 ; 33 in_data = 16'd0 ; 34 #20 reset = 1'd1 ; wr_en <= 1'd1 ; 35 for (i=0;i<40;i=i+1) // 故意溢出 36 #20 in_data <= in_data + 16'd1 ; 37 38 rd_en <= 1'd1 ; wr_en <= 1'd0 ; 39 #(40*20 ) // 让读空标志位触发 40 $stop ; 41 42 end 43 44 endmodule