同步fifo的verilogHDL设计实例
0赞
发表于 2014/10/14 14:15:21
阅读(1849)
原创
设计一个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