秋招复习-同步fifo

过段时间就要秋招了,打算做一个知识汇总,也算是为秋招做准备吧

首先fifo是first in first out,先进先出。可以想象成一根管子,一端往里边压入(push)小球,另一边往外边弹出(pop)小球。

同步fifo一般有以下几个必备端口

信号名称端口方向位宽说明
clk        I1时钟,读写端口共用
rst_nI        1

复位

winc  I        1push操作
wdataI——要写进去的数据
fullO1满标志
rincI1pop操作
rdataO——读出来的数据
empty  O1空标志

同步fifo的核心是一块双口ram和读写控制逻辑组成。双口ram的端口说明比较显然,就不再介绍了。

fifo的关键原则是写满不溢出,读空不多读。因此空满标志位的产生和双口ram的读写使能信号输入是设计的关键。

module sync_fifo #(
	parameter 	DATA_WIDTH  = 8 	,	//	fifo位宽
	parameter 	FIFO_DEPTH  = 16 		//	fifo深度
	)(
	input 						clk      	 ,
	input 						rst_n    	 ,
 		 
	input 						wr_en 	 	 ,
	input [DATA_WIDTH-1:0]		wr_data 	 ,	//input data
	output 						full     	 ,	//full flag
 
	input 						rd_en 	 	 ,
	output  [DATA_WIDTH-1:0]	rd_data 	 ,	//output data
	output 						empty 	     

);

localparam	ADDR_WIDTH = $clog2(FIFO_DEPTH)	;	//4


reg [ADDR_WIDTH:0] 		wr_ptr 	;	
reg [ADDR_WIDTH:0]		rd_ptr  ;	//读写指针比地址多1位,用于检测空满
reg [DATA_WIDTH-1:0] 	buffer_mem	[0:FIFO_DEPTH-1];	//寄存器堆

wire 	fifo_wr ;
wire 	fifo_rd ;

assign fifo_wr = wr_en && ~full 	;
assign fifo_rd = rd_en && ~empty 	;

//写指针
always @(posedge clk or negedge rst_n) begin
	if(~rst_n) 
		wr_ptr<= {(ADDR_WIDTH+1){1'b0}};
	else if(fifo_wr)
		wr_ptr <= wr_ptr + 1'b1 ;
end

//读指针
always @(posedge clk or negedge rst_n) begin
	if(~rst_n) 
		rd_ptr <= {(ADDR_WIDTH+1){1'b0}};
	else if(fifo_rd)
		rd_ptr <= rd_ptr + 1'b1 ;
end

//空满
assign full  = ({~wr_ptr[ADDR_WIDTH],wr_ptr[ADDR_WIDTH-1:0]}==rd_ptr) ;
assign empty = (wr_ptr==rd_ptr) ;

	dualport_ram #(
			.DATA_WIDTH(DATA_WIDTH),
			.RAM_DEPTH(FIFO_DEPTH),
			.ADDR_WIDTH(ADDR_WIDTH)
		) inst_dualport_ram (
			.clka   (clk),
			.ena    (fifo_wr),
			.addr_a (wr_ptr[ADDR_WIDTH-1:0]),
			.data_a (wr_data),
			.clkb   (clk),
			.enb    (fifo_rd),
			.addr_b (rd_ptr[ADDR_WIDTH-1:0]),
			.data_b (rd_data)
		);

endmodule 
module dualport_ram #(
	parameter 	DATA_WIDTH = 8 ,
	parameter 	RAM_DEPTH  = 16 ,
	parameter	ADDR_WIDTH = $clog2(RAM_DEPTH)
)(
	input 					clka,
	input 					ena,
	input [ADDR_WIDTH-1:0]	addr_a,
	input [DATA_WIDTH-1:0]	data_a,

	input 					clkb,
	input 					enb,
	input [ADDR_WIDTH-1:0]	addr_b,
	output   reg [DATA_WIDTH-1:0]	data_b
);

reg [DATA_WIDTH-1:0]	mem [RAM_DEPTH-1:0] ;

//------------write data--------//
always @(posedge clka ) begin
	if(ena)
		mem[addr_a]<= data_a ;
end
//------------read data---------//

/*
always @(posedge clkb) begin
	if(enb)
		data_b<=mem[addr_b];
end
*/

always @(*) begin
	if(enb)
		data_b=mem[addr_b];
	else 
		data_b=data_b;
end

endmodule

 

代码中重点是fifo_wr和fifo_rd的逻辑以及fifo空满的判断,指针多1位用来判断空满 ;最高位不同,其余位相同时为满,所有位都相同则为空。同步fifo设计看起来比较简单。

下面进行tb仿真验证波形

testbench

`timescale 1ns/100ps

module tb_sync_fifo (); /* this is automatically generated */

	// clock
	logic clk;
	initial begin
		clk = 1'b0;
		forever #(5) clk = ~clk;
	end

	// asynchronous reset
	logic rst_n;

	// (*NOTE*) replace reset, clock, others

	parameter   DATA_WIDTH = 8;
	parameter   FIFO_DEPTH = 16;

	logic                  wr_en;
	logic [DATA_WIDTH-1:0] wr_data;
	logic                  full;

	logic                  rd_en;
	logic [DATA_WIDTH-1:0] rd_data;
	logic                  empty;

	integer cnt;
integer	rand0=$random() %4 +2;
initial begin
	wr_en   = '0;
	wr_data = '0;
	rd_en   = '0;
	rst_n 	= 1'b0;

	repeat(2) @(posedge clk); #1;
	rst_n = 1;
	repeat(3) @(posedge clk); #1;
//test1
	//写16个数据
	for(cnt = 0; cnt<16; cnt=cnt+1) begin
				wr_en   = '1;
				wr_data = cnt+1 ;
				@(posedge clk); //#1;
				wr_en   = '0;
	end
	repeat(rand0) @(posedge clk); 		
	//读16个数据
	for(cnt = 0; cnt<16; cnt=cnt+1) begin
				rd_en   = '1;
				@(posedge clk); //#1;
				rd_en   = '0;
	end	

//test2  写使能大于16T,读使能持续16T
	for(cnt = 0; cnt<20; cnt=cnt+1) begin
				wr_en   = '1;
				wr_data = 101+cnt ;
				@(posedge clk); //#1;
				wr_en   = '0;
	end
	repeat(rand0) @(posedge clk); 		
	//读16个数据
	for(cnt = 0; cnt<16; cnt=cnt+1) begin
				rd_en   = '1;
				@(posedge clk); //#1;
				rd_en   = '0;
	end

//test3  写使能16T,读使能持续20T
	for(cnt = 0; cnt<16; cnt=cnt+1) begin
				wr_en   = '1;
				wr_data = 201+cnt ;
				@(posedge clk); //#1;
				wr_en   = '0;
	end
	repeat(rand0) @(posedge clk); 		
	//读16个数据
	for(cnt = 0; cnt<20; cnt=cnt+1) begin
				rd_en   = '1;
				@(posedge clk); //#1;
				rd_en   = '0;
	end			
end

	sync_fifo #(
			.DATA_WIDTH(DATA_WIDTH),
			.FIFO_DEPTH(FIFO_DEPTH)
		) inst_sync_fifo (
			.clk          (clk),
			.rst_n        (rst_n),
			.wr_en        (wr_en),
			.wr_data      (wr_data),
			.full         (full),
			.rd_en        (rd_en),
			.rd_data      (rd_data),
			.empty        (empty)
		);


endmodule

 

 ram使用组合逻辑读的波形。空满标志位正常,ram的读写逻辑控制时序也正确,

ram使用时序逻辑读的波形 ,读出来的数据比组合逻辑延后一拍。

重点是分析清楚里边的时序关系,保证ram产生正确的读写时能,以及生成正确的fifo空满标志位。

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值