数字IC设计学习笔记_跨时钟域同步问题 2_多比特信号跨时钟域问题_异步FIFO

数字IC设计学习笔记

跨时钟域同步问题

2 多比特信号跨时钟域问题_异步FIFO

2 异步FIFO

  • 原理图

在这里插入图片描述
异步FIFO的设计主要有5部分组成:

  1. FIFO Memory:双口RAM存储数据
  2. sync_r2w:同步器,同步读数据指针到写时钟域
  3. sync_w2r:同步器,同步写数据指针到读时钟域
  4. wptr_full:处理写指针和满信号的逻辑
  5. rptr_empt:处理读指针和空信号的逻辑
  • Verilog代码
//----TOP module-------------------------------
module asyncfifo_r1#(
	parameter	ADDRSIZE	=	4,
	parameter	DATASIZE	=	8
)
(	
//----write signal ----------------------------
	input wclk,
	input wrst,
	input [DATASIZE-1:0] wdata,
	input winc,
	
	output wfull,
//----read signal ----------------------------
   input rclk,
	input rrst,
	input rinc,
	
	output empty,
	output [DATASIZE-1:0] rdata
    );
 wire [ADDRSIZE-1:0] waddr;
 wire [ADDRSIZE-1:0] raddr;
 wire [ADDRSIZE:0] wptr, rptr, wq2_rptr, rq2_wptr;
 
 FIFOMEM_R0 U1 (
	.wclk (wclk),
	.wdata(wdata),
	.rdata(rdata),
	.waddr (waddr),
	.raddr(raddr),
	.wclken(winc),
	.wfull (wfull)
 );
 
 syn_r2w U2 (
	.wclk(wclk),
	.rst_n(wrst),
	.wq2_rptr(wq2_rptr),
	.rptr(rptr)
 );
 
  sync_w2r_r1 U3 (
	.rclk(rclk),
	.rst_n(rrst),
	.rq2_wptr(rq2_wptr),
	.wptr(wptr)
 );
 
  wptr_full_r1 U4(
  	.wclk(wclk),
	.wrst_n(wrst),
	.winc(winc),
	.wq2_rptr(wq2_rptr),
	.wfull(wfull),
	.waddr(waddr),
	.wptr(wptr)
  );
  
  rptr_empty U5(
  	.rclk(rclk),
	.rst_n(rrst),
	.rinc(rinc),
	.rq2_wptr(rq2_wptr),
	.rempty(empty),
	.raddr(raddr),
	.rptr(rptr)
  ); 
  
  
endmodule

1. FIFO Memory

  • 在FPGA中,我们可以用block ram也可以用distributed ram。
  • Verilog代码
module FIFOMEM_R0#(
	parameter DATASIZE = 8, // memory data word width
	parameter ADDRSIZE = 4	// memory address bits
)
(	
	input 					wclk,
	input	[DATASIZE-1:0]	wdata,
	input	[ADDRSIZE-1:0]	waddr,
	input	[ADDRSIZE-1:0]	raddr,
	input						wclken,
	input						wfull,
	
	output	[DATASIZE-1:0]	rdata
    );
	 localparam DEPTH = 1<< ADDRSIZE;
	 
	 reg [DATASIZE-1:0] mem [0:DEPTH-1];
//read----------------------------------	 
	 assign rdata = mem[raddr];
//write---------------------------------	 
	 always@(posedge wclk)begin
	 if(wclken && !wfull) //写有效且未写满
		mem[waddr] <= wdata;
	 end
endmodule
  • Modelsim仿真
    在这里插入图片描述
    注意:对memory的地址为二进制的地址;对空满判定的地址为格雷码的地址。

2. sync_r2w

  • Verilog代码
module syn_r2w#(
	parameter ADDRSIZE = 4
)
(
	input 					wclk,
	input						rst_n,
	input [ADDRSIZE:0] rptr,
	
	output reg [ADDRSIZE:0] wq2_rptr 
    );
	reg	[ADDRSIZE:0]	wq1_rptr;
	
	always@(posedge wclk or negedge rst_n)begin
		if(!rst_n)begin
			wq1_rptr <= 0;
			wq2_rptr <= 0;
			end else begin
			wq1_rptr <= rptr;
			wq2_rptr <= wq1_rptr;
			end
		end
endmodule
  • Modelsim仿真

在这里插入图片描述
3. sync_w2r

  • Verilog代码
module sync_w2r_r1#(
	parameter ADDRSIZE = 4
)
(
	input rclk,
	input rst_n,
	input [ADDRSIZE:0] wptr,
	
	output reg [ADDRSIZE:0] rq2_wptr
    );
	 reg [ADDRSIZE:0] rq1_wptr;
	 
	 always@(posedge rclk or negedge rst_n)begin
		if(!rst_n)begin
			rq1_wptr <= 0;
			rq2_wptr <= 0;
		end else begin
				rq1_wptr <= wptr;
				rq2_wptr <= rq1_wptr;
		end
	 end
endmodule
  • Modelsim仿真

在这里插入图片描述
4. wptr_full

  • 满信号的产生逻辑放在写时钟域。由于N比特格雷码的低N-1比特具有对称性,比较读写指针时我们像二进制码那样仅仅判断第N比特不等而低N-1比特相等是不够的,会产生错误的满信号。为了产生正确的满信号,我们需要同时判断以下三个条件:
    第N-1比特不相等
    第N-2比特不相等
    低N-3比特全相等

    与空信号类似,为了full信号的寄存器输出,对于写指针我们可以用 wgraynext 而不是 wptr(wptr要比wgraynext晚一拍)。

  • Verilog代码

module wptr_full_r1#(
	parameter ADDRSIZE = 4
)
(
	input wclk,
	input	wrst_n,
	input	winc,
	input	[ADDRSIZE:0] wq2_rptr,
	
	output reg                wfull,
	output     [ADDRSIZE-1:0] waddr,
	output reg [ADDRSIZE:0]    wptr
    );
	 
	wire 					wfull_val;
	wire [ADDRSIZE:0]	wbinnext;
	wire [ADDRSIZE:0] wgraynext;
	reg [ADDRSIZE:0] 	wbin;
	
//----write address---------------//
	assign waddr = wbin[ADDRSIZE-1:0];

//----bin2gray--------------------//
	assign wbinnext = wbin + (winc & ~wfull);

	assign wgraynext = (wbinnext>>1)^ wbinnext;	
//----gray pointer----------------//
	always@(posedge wclk or negedge wrst_n)begin
		if(!wrst_n)begin
			wptr <= 0;
			wbin <= 0;
		end else
		begin
			wptr <= wgraynext;//gray
			wbin <= wbinnext;
			end		
	end

//----write full------------------//
	assign wfull_val = ((wgraynext[ADDRSIZE]     != wq2_rptr[ADDRSIZE]) &&
	                    (wgraynext[ADDRSIZE-1]   != wq2_rptr[ADDRSIZE-1]) &&
							  (wgraynext[ADDRSIZE-2:0] == wq2_rptr[ADDRSIZE-2:0]));
	always@(posedge wclk or negedge wrst_n)begin
		if(!wrst_n)
		wfull <= 0;
		else
		wfull <= wfull_val;
	end
endmodule
  • Modelsim仿真
    在这里插入图片描述
    5. rptr_empty
  • 空信号的产生逻辑放在读时钟域。直接对比读写指针是否相等即可(读指针追上写指针),注意这里的写指针是同步到读时钟域之后的写指针。为了empty信号的寄存器输出,比较时读指针我们可以用
    rgraynext 而不是 rptr(rptr要比rgraynext晚一拍)。
  • Verilog代码
module rptr_empty#(
	parameter ADDRSIZE = 4
)
(
	input 							rclk,
	input								rst_n,
	input 							rinc,
	input	[ADDRSIZE:0] 		rq2_wptr,
	
	output	reg					rempty,
	output	[ADDRSIZE-1:0] 	raddr,
	output	reg [ADDRSIZE:0]	rptr //gray
    );
	 
	reg 			[ADDRSIZE:0] rbin;
	wire        [ADDRSIZE:0] rgraynext;
	wire        [ADDRSIZE:0] rbinnext;
	wire							rempty_val;
	
//----gray pointer---------------------------------------//
	always@(posedge rclk or negedge rst_n)begin
		if(!rst_n)begin
			rbin <= 0;
			rptr <= 0;
		end else
		begin 
			rbin <= rbinnext;
			rptr <= rgraynext;
			end			
	end
	
//----memory address-------------------------------------//
	assign raddr = rbin[ADDRSIZE-1:0];
//----bin2gray-------------------------------------------//
	assign rbinnext = rbin + (rinc & ~rempty);
	assign rgraynext = (rbinnext>>1)^rbinnext; 
	 
//----FIFO empty when rptr == ayncronized wptr-----------//
	assign rempty_val = (rgraynext == rq2_wptr);
	
	always@(posedge rclk or negedge rst_n)begin
		if(!rst_n)begin
			rempty <= 0;
			end else
				rempty <= rempty_val;
	end
endmodule
  • Modelsim仿真
    在这里插入图片描述

【注】:个人学习笔记,如有错误,望不吝赐教,这厢有礼了~~~


猜你喜欢

转载自blog.csdn.net/weixin_50722839/article/details/110149044
今日推荐