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