同步FIFO、异步FIFO详细介绍、verilog代码实现、FIFO最小深度计算、简答题

news2024/12/23 9:53:56

文章目录

  • 前言
  • 一、多bit数据流跨时钟域传输——FIFO
    • 1、FIFO分类
    • 2、常见参数
    • 3、与普通存储器的区别
    • 4、FIFO优缺点
  • 二、同步FIFO
    • 1、计数器法
    • 2、高位扩展法
    • 3、单端口和双端口RAM
      • 3.1 单端口RAM
      • 3.2 双端口RAM
    • 4、例化双端口RAM实现同步FIFO
  • 三、异步FIFO
    • 1、格雷码
      • 1.1 二进制和格雷码之间的转换
      • 1.2 使用格雷码判断空满
      • 1.3 当深度不是2次幂
      • 1.4 异步FIFO能否消除掉亚稳态
      • 1.5 读写判断是存在漏洞,不是真空或者真满
      • 1.6 格雷码产生传输错误
      • 1.7 极端读写时钟域情况
    • 2、例化双端口RAM实现异步FIFO
  • 四、计算FIFO最小深度
    • 1、FIFO写时钟100MHz,读时钟80MHz,每100个写时钟,写入80个数据;每一个读时钟读走一个数据,求最小深度不会溢出
    • 2、一个8bit宽的AFIFO,输入时钟为100MHz,输出时钟为95MHz,设一个package为4Kbit,且两个package之间的发送间距足够大,问AFIFO的深度。
    • 3、A/D采样率50MHz,DSP读A/D速率40MHz,要不丢失地将10万个采样数据送入DSP,在A/D在和DSP之间至少加多大容量(深度)的FIFO才行?
    • 4、异步FIFO要考虑格雷码同步的时间
    • 5、真题
  • 五、读写频率、读写有无空闲周期下最小深度计算
    • 1、fA>fB,读写之间无空闲周期
    • 2、fA>fB,两次连续读写之间有一个周期的延迟
    • 3、fA>fB,读写都有空闲周期/读写使能百分比
    • 4、fA<fB,读写之间无空闲周期
    • 5、fA<fB,读写都有空闲周期/读写使能百分比
    • 6、fA=fB,读写之间无空闲周期
    • 7、fA=fB,读写都有空闲周期/读写使能百分比
    • 8、读写速率相等每100个时钟写入80个数据每10个时钟读取8个数据
  • 六、简答题
    • 1、什么是异步FIFO?画出异步FIFO的结构图。
    • 2、如何判断读空或者写满信号?
    • 3、为什么要用格雷码?在FIFO中使用格雷码的优点
    • 4、异步FIFO设计核心
    • 5、如何验证FIFO?


前言

2023.4.6 把之前学习的内容汇总整理


一、多bit数据流跨时钟域传输——FIFO

大多数数据具有连续性,背靠背传输;需要较快的速度传输
两种解决方法:SRAM(两个时钟域通过其缓冲,这里不讲)、FIFO

1、FIFO分类

同步FIFO:读写时钟为同一时钟,时钟沿同时进行读写,内部所有逻辑为同步逻辑,常用于交互数据缓冲
异步FIFO:读写时钟不同,相互独立

2、常见参数

FIFO宽度:一次读写数据的数据位
FIFO深度:可以存储多少个N位的数据

空标志:FIFO已空或将要空时由FIFO的状态电路送出的一个信号,以阻止FIFO的读操作继续从FIFO中读出数据而造成无效数据的读出(underflow)。读写指针相等时,表示空,发生在复位或者读指针读完最后一个数追上写指针的时候。
满标志:FIFO已满或将要满时由FIFO的状态电路送出的一个信号,以阻止FIFO的写操作继续向FIFO中写数据而造成溢出(overflow)。当读写指针再次相等,表示满。

读时钟:读操作所遵循的时钟,在每个时钟沿来临时读数据。
写时钟:写操作所遵循的时钟,在每个时钟沿来临时写数据。

写指针:总是指向下一个将要被写入的单元,复位时,指向0
读指针:总是指向当前要被读出的数据,复位时,指向第 1 个单元(编号为 0)
在这里插入图片描述

3、与普通存储器的区别

  • 区别:没有外部读写地址线,使用简单

4、FIFO优缺点

  • 优点:适用性强,可以用来同步没有任何关系的时钟域间的数据交换,相比于握手协议数据传输速率更快,不同宽度的数据接口也可以用FIFO。
  • 缺点:只能顺序读写,且面积大

二、同步FIFO

1、计数器法

计数器复位时初始化为0,写操作计数器+1,读操作计数器-1,计数器为0表示空,计数器为深度时表示满。

缺点:读写不能同时操作,且计数器会占用额外的资源,当FIFO较大时,可能会降低读写的速度。

关键: 读写指针的变化、空满信号的产生

module sync_fifo
	#(parameter DEPTH = 'd16, parameter WIDTH = 'd8)(
	input clk,
	input rst_n,
	input wr_en,
	input rd_en,
	input [WIDTH-1:0] data_in,
	output [WIDTH-1:0] data_out,
	output empty,
	output full
);

	reg [$clog2(DEPTH):0] cnt;   //计数器范围为0-16
	reg [WIDTH-1:0] mem [DEPTH-1:0];
	reg [$clog2(DEPTH)-1:0] waddr, raddr;
	
	//写操作
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			waddr <= 0;
		else if(wr_en & !full)begin
			mem[waddr] <= data_in;
			waddr <= waddr+1;
		end
	end
	
	//读操作
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			raddr <= 0;
		else if(rd_en & !empty)begin
			data_out <= mem[raddr];
			raddr <= raddr+1;  //注意这里读地址也是+1
		end
	end
	
	//更新计数器
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			cnt <= 0;
		else begin
			case({wr_en, rd_en})
				2'b00: cnt <= cnt;
				2'b01: if(cnt!=0) cnt <= cnt - 1;
				2'b10: if(cnt!=DEPTH) cnt <= cnt + 1;
				2'b11: cnt <= cnt;
			endcase
		end
	end
	
	assign full = (cnt==DEPTH);
	assign empty = (cnt==0);
endmodule

2、高位扩展法

没有扩展的时候,空和满的时候,读写指针是完全相同的,无法进行判断

  • 地址位扩展一位,当写指针增加并越过最后一个FIFO地址时,就将写指针这个未用的MSB加1,其它位回零。对读指针也进行同样的操作。
  • 对于深度为2^n的FIFO,需要的读/写指针位宽为(n+1)位,如对于深度为8的FIFO,需要采用4bit的计数器,0000 ~1000、1001~1111,MSB作为折回标志位,而低3位作为地址指针
  • 如果两个指针的MSB不同,说明写指针比读指针多折回了一次;如r_addr=0000,而w_addr = 1000,为满。
  • 如果两个指针的MSB相同,则说明两个指针折回的次数相等。其余位相等,说明FIFO为空。
module sync_fifo
	#(parameter DEPTH = 'd16, parameter WIDTH = 'd8)(
	input clk,
	input rst_n,
	input wr_en,
	input rd_en,
	input [WIDTH-1:0] data_in,
	output [WIDTH-1:0] data_out,
	output empty,
	output full
);

	reg [WIDTH-1:0] mem [DEPTH-1:0];
	reg [$clog2(DEPTH):0] waddr, raddr;
	
	//写操作
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			waddr <= 0;
		else if(wr_en & !full)begin
			mem[waddr[$clog2(DEPTH)-1:0]] <= data_in;  
			waddr <= waddr+1;
		end
	end
	
	//读操作
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			raddr <= 0;
		else if(rd_en & !empty)begin
			data_out <= mem[raddr[$clog2(DEPTH)-1:0]];  //这里也可以用组合逻辑输出,实现read和data out同步输出
			raddr <= raddr+1;  //注意这里读地址也是+1
		end
	end

	assign empty = (raddr == waddr);
	assign full = (raddr == {~waddr[$clog2(DEPTH)], waddr[$clog2(DEPTH)-1:0]});   //最高位相反
endmodule

3、单端口和双端口RAM

3.1 单端口RAM

module ram_mod(
	input clk,
	input rst_n,
	
	input write_en,
	input [7:0]write_addr,
	input [3:0]write_data,
	
	input read_en,
	input [7:0]read_addr,
	output reg [3:0]read_data
);
    reg [3:0] mem [7:0];
    integer i;
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            for(i=0;i<8;i=i+1)
                mem[i]<=0;
        end
        else if(write_en)
            mem[write_addr]<=write_data;
    end
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            read_data<=0;
        end
        else if(read_en)
            read_data<=mem[read_addr];
    end
endmodule

3.2 双端口RAM

module dual_port_RAM #(parameter DEPTH = 16,
					   parameter WIDTH = 8)(
	 input wclk
	,input wenc
	,input [$clog2(DEPTH)-1:0] waddr  //深度对2取对数,得到地址的位宽。
	,input [WIDTH-1:0] wdata      	//数据写入
	,input rclk
	,input renc
	,input [$clog2(DEPTH)-1:0] raddr  //深度对2取对数,得到地址的位宽。
	,output reg [WIDTH-1:0] rdata 		//数据输出
);

	reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1];
	
	always @(posedge wclk) begin
		if(wenc)
			RAM_MEM[waddr] <= wdata;
	end 
	
	always @(posedge rclk) begin
		if(renc)
			rdata <= RAM_MEM[raddr];
	end 
endmodule

4、例化双端口RAM实现同步FIFO

在这里插入图片描述

//这里用的是高位扩展法
module sfifo#(
	parameter	WIDTH = 8,
	parameter 	DEPTH = 16
)(
	input 					clk		, 
	input 					rst_n	,
	input 					winc	,
	input 			 		rinc	,
	input 		[WIDTH-1:0]	wdata	,

	output reg				wfull	,
	output reg				rempty	,
	output wire [WIDTH-1:0]	rdata
);

	wire wenc,renc;
	assign wenc = winc && !wfull;
	assign renc = rinc && !rempty;
	reg [$clog2(DEPTH):0] waddr;
	reg [$clog2(DEPTH):0] raddr;

	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			wfull<=0;
			rempty<=0;
		end
		else begin
			rempty<=(raddr==waddr);
			wfull<=(waddr==raddr+DEPTH);
		end
	end

	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			raddr<=0;
		end
		else if(renc)
			raddr<=raddr+1;
	end

	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			waddr<=0;
		end
		else if(wenc)
			waddr<=waddr+1;
	end
	
	//例化双端口RAM
	dual_port_RAM #(.DEPTH(DEPTH),.WIDTH(WIDTH))
	ram(
		.wclk(clk),
		.wenc(wenc),
		.waddr(waddr[DEPTH-1:0]),   //注意这里地址位宽,最高位不是有效地址位
		.wdata(wdata),
		.rclk(clk),
		.renc(renc),
		.raddr(raddr[DEPTH-1:0]),
		.rdata(rdata)
	);
endmodule

三、异步FIFO

在这里插入图片描述

在这里插入图片描述

1、格雷码

格雷码:循环码,相邻两个数值之间只有一位发生改变,发生亚稳态的概率大大降低

二进制码格雷码
000000
001001
010011
011010
100110
101111
110101
111100

1.1 二进制和格雷码之间的转换

在这里插入图片描述

二进制码转化为格雷码:从最右边第一位开始,依次将每一位与左邻一位异或(XOR),作为对应格雷码该位的值,最左边一位不变;

gray = bin ^ (bin>>1);

格雷码转化为二进制码:从左边第二位起,将每位与左边一位解码后的值异或(XOR),作为该位解码后的值(最左边一位依然不变)。

reg [3:0] gray, bin;
bin[3] = gray[3];
bin[2] = bin[3] ^ gray[2];
bin[1] = bin[2] ^ gray[1];
bin[0] = bin[1] ^ gray[0];

1.2 使用格雷码判断空满

  • :两者指针完全相同
  • :最高位和次高位不同,其他位完全相同
  • 7(0111)和15(1111)对应到二进制码的话就只有最高位不高。7(0100)和15(1000)对应到格雷码的话最高位和次高位相反,其他位相同

在这里插入图片描述

在这里插入图片描述

1.3 当深度不是2次幂

  • 并不是一定要用格雷码做读写指针,而是当深度为2次幂的时候,刚好格雷码满足消除亚稳态的需求;
  • 在非2次幂深度情况下,格雷码已经不再适用,此时的解决方法通常有:
    若深度为偶数,可采用最接近的2次幂的格雷码编码,在此基础上修改;
    深度为一般数值时,可自行设计一种逻辑电路,或者查找表,以实现指针每次只跳变一次的功能;
  • 以上方法通常在设计层面较为复杂,若无特定需求,可将FIFO深度设置为2次幂,浪费一些存储空间,来化简控制电路的复杂度。

在这里插入图片描述
或者在偶数个的时候,去掉头和尾的数字,中间部分也是满足要求
异步FIFO在2N个数据类就可以循环
在这里插入图片描述

1.4 异步FIFO能否消除掉亚稳态

  • 亚稳态不能从根本上消除,只能采取一定的措施使其对电路的影响降低
  • 打两拍只能大幅降低亚稳态发生的概率,但是理论上是不能完全消除的

1.5 读写判断是存在漏洞,不是真空或者真满

  • 写指针通过两级寄存器同步到读时钟域,再和读指针比较进行FIFO空状态判断,因为在两级同步寄存器需要时间,而在这个同步的时间内有可能还会写入新的数据,因此同步后的写指针一定是小于或者等于当前实际的写指针,所以此时判断 FIFO为空不一定是真空,这样更加保守,一共不会出现空读的情况,虽然会影响FIFO的性能,但是并不会出错。
  • 读指针通过两级寄存器同步到写时钟域,再和写指针比较进行FIFO满状态判断,同步后的读指针一定是小于或者等于当前的读指针,所以此时判断FIFO为满不一定是真满。

在这里插入图片描述

1.6 格雷码产生传输错误

  • 保证的是同步后的读写地址即使在出错的情形下,依然能够保证FIFO功能的正确性,不会出现空读满写的错误状态,当然同步后的读写地址出错总是存在的。
  • 地址总线bus skew一定不能超过一个周期,否则可能出现gray码多位数据跳变的情况,这个时候gray码就失去了作用,因为这时候同步后的地址已经不能保证只有1位跳变了。

写指针000 -> 001,假设同步过去变成了000 -> 000,这样会判断为空,但实际上并不为空,此时不能读操作,还是可以写。不会对FIFO的功能造成影响。

1.7 极端读写时钟域情况

  • 写时钟域慢,读时钟域快:读时钟域总是能采集到信号(慢到快),判断空不成问题
    假如读指针从1-9,同步到写时钟域的是7,写指针也在7,那么会判断“满”,会停止写入,其实没满,还差点
    在这里插入图片描述
  • 写时钟域快,读时钟域慢:会出现漏采(只能采集到135)。将读指针传到写时钟域是可以的(慢到快),判断满不成问题
    假设写指针从1-9,同步到读时钟域是7,读指针也在7,会产生“空信号”,会停止读,但实际上没有空
    在这里插入图片描述
  • 当在极端状况下,写很快,读很慢,那一开始就被写满;相反则永远是读空
    总结:写得快,会错误判断产生虚空;读得快,会错误判断产生虚满

2、例化双端口RAM实现异步FIFO

module asyn_fifo#(
	parameter	WIDTH = 8,
	parameter 	DEPTH = 16
)(
	input 					wclk	, 
	input 					rclk	,   
	input 					wrstn	,
	input					rrstn	,
	input 					winc	,
	input 			 		rinc	,
	input 		[WIDTH-1:0]	wdata	,

	output wire				wfull	,
	output wire				rempty	,
	output wire [WIDTH-1:0]	rdata
);
	//双端口RAM的读写使能信号
	wire wenc = winc && !wfull;
	wire renc = rinc && !rempty;
	
	parameter ADD_WIDTH = $clog2(DEPTH);   //地址线宽度
	
	//二进制地址加减
	reg [ADD_WIDTH:0] wptr_bin,rptr_bin;
	wire [ADD_WIDTH:0] wptr_bin_next,rptr_bin_next;
	assign wptr_bin_next = wptr_bin + (winc&!wfull);
	assign rptr_bin_next = rptr_bin + (rinc&!rempty);
	
	//二进制码转换为格雷码
	reg [ADD_WIDTH:0] wptr_gray,rptr_gray;
	wire [ADD_WIDTH:0] wptr_gray_next,rptr_gray_next;
	assign wptr_gray_next = wptr_bin ^ (wptr_bin>>1);
	assign rptr_gray_next = rptr_bin ^ (rptr_bin>>1);

	//更新二进制码和格雷码
	always@(posedge wclk or negedge wrstn)begin
		if(!wrstn)
			{wptr_bin,wptr_gray} <=0;
		else
			{wptr_bin,wptr_gray}<={wptr_bin_next,wptr_gray_next};
	end

	always @ (posedge rclk or negedge rrstn) begin
	    if (!rrstn) begin
	        {rptr_bin,rptr_gray} <= 'd0;
	     end
	    else
	        {rptr_bin,rptr_gray} <= {rptr_bin_next, rptr_gray_next};
	end
	
	//同步格雷码
	reg [ADD_WIDTH:0] wptr_gray_r,wptr_gray_rr;
	always@(posedge rclk or negedge rrstn)begin   //读时钟域同步写格雷码
		if(!rrstn)
			{wptr_gray_r,wptr_gray_rr} <=0;
		else
			{wptr_gray_rr,wptr_gray_r}<={wptr_gray_r,wptr_gray};
	end
	
	reg [ADD_WIDTH:0] rptr_gray_r,rptr_gray_rr;
	always@(posedge wclk or negedge wrstn)begin   //写时钟域同步读格雷码
		if(!wrstn)
			{rptr_gray_rr,rptr_gray_r} <=0;
		else
			{rptr_gray_rr,rptr_gray_r}<={rptr_gray_r,rptr_gray};
	end
	
	//空满标志的产生,利用格雷码判断
	assign rempty = rptr_gray==wptr_gray_rr;
	assign wfull = wptr_gray=={~rptr_gray_rr[ADD_WIDTH:ADD_WIDTH-1],rptr_gray_rr[ADD_WIDTH-2:0]};
	
	//例化双端口RAM
	dual_port_RAM #(.DEPTH(DEPTH),.WIDTH(WIDTH))
	one(
		.wclk(wclk),
		.wenc(wenc),
		.waddr(wptr_bin[ADD_WIDTH-1:0]),   //注意这里地址
		.wdata(wdata),
		.rclk(rclk),
		.renc(renc),
		.raddr(rptr_bin[ADD_WIDTH-1:0]),
		.rdata(rdata)
	);
endmodule

二进制码和格雷码更新这段也可以按照下面这样写,但是不知道和分开定义一个wptr_gray_next,再寄存到wptr_gray有什么区别。这样写的话看上去简单一些。

//二进制地址加减
always@(posedge wclk or negedge wrstn)begin
		if(!wrstn)
			wptr_bin <= 0;
		else if(wenc)
			wptr_bin <= wptr + 1;
end

always@(posedge rclk or negedge wrstn)begin
		if(!rrstn)
			rptr_bin <= 0;
		else if(renc)
			rptr_bin <= rptr + 1;
end
//二进制码转格雷码
always@(posedge wclk or negedge wrstn)begin
		if(!wrstn)
			wptr_gray <= 0;
		else 
			wptr_gray <= wptr_bin ^ (wptr_bin>>1);
end

always@(posedge rclk or negedge wrstn)begin
		if(!wrstn)
			rptr_bin <= 0;
		else if(renc)
			rptr_bin <= rptr_bin ^ (rptr_bin>>1);
end

四、计算FIFO最小深度

  • 一般来说,在不连续传输的写入情况下,才考虑FIFO深度问题,因为假设是连续写入,FIFO总是会满的

  • 在正常情况下,应该是这样的:空闲—Burst突发—空闲—Burst突发—空闲—Burst突发

  • 背靠背传输空闲—Burst突发—Burst突发—空闲—Burst突发—空闲
    如果接收方没法接收所有数据,那么剩余的数据可以被存储在FIFO内部且不会溢出,也就是我们要求的FIFO深度的意思。

  • 在SDRAM的应用中,我们通常使用的读写FIFO是突发长度的2倍,比如突发长度为256,那FIFO的深度设置为512,使得FIFO始终保持半满的状态。可以保证数据的传输。

burst_length:表示这段时间写入的数据量
burst_length/wclk:写入数据的时间
(X/Y)*rclk:每Y个时钟读出X个数据,说明读出效率不是100%,要在rclk基础上打折扣,速度没有rclk
depth:写入和读出两者之差为FIFO中残留的数据,这个也就是理论上的FIFO的最小深度。

depth = burst_length - (burst_length/wclk) * ((X/Y)*rclk)

1、FIFO写时钟100MHz,读时钟80MHz,每100个写时钟,写入80个数据;每一个读时钟读走一个数据,求最小深度不会溢出

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、一个8bit宽的AFIFO,输入时钟为100MHz,输出时钟为95MHz,设一个package为4Kbit,且两个package之间的发送间距足够大,问AFIFO的深度。

传输数据个数 = 时间 * 速度(频率)
深度 = (读写速率差) * (写入数据需要的时间)

传输数据个数:4Kbit/8bit =500 word
写入500个word所需时间:500/100
该时间内读取的个数:500/100*95
(1)深度 = 写个数 - 读个数 = 500 - 500/100 * 95 = 25
(2)深度 = (100-95) * (500/100) = 25

3、A/D采样率50MHz,DSP读A/D速率40MHz,要不丢失地将10万个采样数据送入DSP,在A/D在和DSP之间至少加多大容量(深度)的FIFO才行?

FIFO用于缓冲块数据流,一般用在快时钟域写慢时钟域读
FIFO深度 /(写入速率 - 读出速率)= FIFO被填满时间 > 数据包传送时间= 数据量 / 写入速率
FIFO写满的时间 > 数据包传输的时间
FIFO深度 = (写入速率 - 读出速率)* 数据包传送时间
100000 / 50MHz = 1/ 500 s = 2ms
(50MHz - 40MHz) * 1/500 = 20k

4、异步FIFO要考虑格雷码同步的时间

在这里插入图片描述

5、真题

在这里插入图片描述

五、读写频率、读写有无空闲周期下最小深度计算

1、fA>fB,读写之间无空闲周期

写速率fA=80MHz,读速率fB=50MHz,突发长度Burst Length = 120,读写之间没有空闲周期,是连续读写一个突发长度。
120-120/80*50 = 120 - 75 = 45

2、fA>fB,两次连续读写之间有一个周期的延迟

同case1,两次连续读写之间通常有延迟

3、fA>fB,读写都有空闲周期/读写使能百分比

写速率fA=80MHz,读速率fB=50MHz,突发长度Burst Length = 120

两个连续写入之间的空闲周期为=1,两个连续读取之间的空闲周期为=3
写使能占得百分比为=50%=1/2,读使能占得百分比为=25%=1/4

答: 两个连续写入之间的空闲周期为1的意思是,每写入一个数据,要等待一个周期,再写入下一个数据。这也可以理解为每两个周期,写入一个数据。同理每四个周期,读取一个数据。相当于读写频率降低了。
120-120/40*12.5=82.5=83

4、fA<fB,读写之间无空闲周期

写进去的数据总是被读走了,所以FIFO深度为1即可

5、fA<fB,读写都有空闲周期/读写使能百分比

写速率fA=30MHz,读速率fB=50MHz,突发长度Burst Length = 120
两个连续写入之间的空闲周期为=1,两个连续读取之间的空闲周期为=3
120-120/30*12.5=20(实际上这道题目写速率比读快)

6、fA=fB,读写之间无空闲周期

读写为同一时钟,可以不需要FIFO,直接写入的值给输出。如果读写时钟存在相位差,那么FIFO深度为1即可。

7、fA=fB,读写都有空闲周期/读写使能百分比

写速率fA= 50MHz,读速率fB=50MHz,突发长度Burst Length = 120
两个连续写入之间的空闲周期为=1,两个连续读取之间的空闲周期为=3
120-120/25*12.5=60(实际上这道题目写速率比读快)

8、读写速率相等每100个时钟写入80个数据每10个时钟读取8个数据

考虑背靠背情况:160-160*8/10=32

六、简答题

1、什么是异步FIFO?画出异步FIFO的结构图。

  • 读写时钟域不同。在写时钟域下将数据放入缓存区,读时钟域下将数据读取出来
  • 没有外部读写地址线,只能按照顺序读写
  • 写指针指向下一个要写入的位置,读指针指向当前要读取的位置。复位时,都指向零,是写指针下一个要写入的位置,读指针当前读取的位置,所以是“读空/empty”

2、如何判断读空或者写满信号?

直接根据地址是否相等不能判断空或者满。
对指针增加一位最高有效位MSB,n位指针,n-1位表示访问FIFO所需的地址位数。n位完全相同表示“空”;MSB不同,n-1位完全相同表示“满”

3、为什么要用格雷码?在FIFO中使用格雷码的优点

  • 二进制码在传输时可能会发生多bit位同时变化得情况,如0111->1000,这样容易发生亚稳态。格雷码是循环码,相邻两位之间只有1bit发生改变,降低亚稳态发生的概率
  • 多bit信号变化时会产生竞争冒险,消除竞争冒险
  • 多bit传输时,格雷码跳变较少,功耗降低,有利于低功耗设计
  • 格雷码出错只是一位发生错误,降低了错误对系统的影响,保证FIFO功能的正确性,只会出现假空或者假满

4、异步FIFO设计核心

  • 格雷码+指针同步

5、如何验证FIFO?

在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/418315.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

spring5(五):AOP操作

spring5&#xff08;五&#xff09;&#xff1a;AOP操作前言一、代理模式1、场景模拟2、代理模式2.1 概念2.2 静态代理2.3 动态代理二、AOP概述1、什么是 AOP?2、相关术语3、作用三、AOP底层原理1、AOP 底层使用动态代理2、AOP&#xff08;JDK 动态代理&#xff09;2.1 编写 J…

VR全景展示,VR全景平台,助理全景展示新模式

引言&#xff1a; VR全景展示是一种新型的展示方式&#xff0c;它利用虚拟现实技术和全景拍摄技术&#xff0c;使参观者可以身临其境地进入虚拟展览空间。这种展示方式不仅能够提供更加沉浸式的参观体验&#xff0c;还可以解决传统展览所面临的时间和地域限制等问题。 VR全景展…

【Java实战篇】Day7.在线教育网课平台

文章目录一、需求&#xff1a;课程审核1、需求分析2、建表与数据模型3、接口定义4、Mapper层开发5、Service层开发6、完善controller层二、需求&#xff1a;课程发布1、需求分析2、建表与数据模型3、技术方案4、接口定义5、消息处理SDK6、Mapper层开发7、Service层开发8、页面静…

unity,射手游戏

文章目录介绍一&#xff0c;制作玩家具体函数脚本PlayerCharacter三、 制作玩家控制脚本 PlayerController&#xff0c;调用上面的函数方法四、 制作子弹脚本 shell五、 给玩家挂载脚本六、 制作坦克脚本七、 给坦克添加组件八、 开始游戏&#xff0c;播放动画九、 下载介绍 3…

seata学习笔记

Seata 官网&#xff1a; https://seata.io/zh-cn/index.html 是什么&#xff1f; Seata 是一款开源的分布式事务解决方案&#xff0c;致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式&#xff0c;为用户打造一站式的分布式…

MySQL中的float类型慎用!慎用!慎用!

在前端输入一串数字后有时候展示值与输入的内容一致&#xff0c;有时候却不一致。经分析&#xff0c;原来是MySQL数据库中字该字段的类型是float&#xff0c;该字段的值超过6位有效数字后就会进行四舍五入截取&#xff0c;举例来说&#xff1a;假设float类型字段的输入值是1234…

十八、MySQL 变量、分支结构IF、CASE...WHEN详解

文章目录一、变量1.1 系统变量1.1.1 系统变量分类1.1.2 查看系统变量1.2 用户变量1.2.1 用户变量分类1.2.2 会话用户变量1.2.3 局部变量1.2.4 对比会话用户变量与局部变量二、定义条件与处理程序2.1 案例分析2.2 定义条件2.3 定义处理程序2.4 案例解决三、流程控制3.1 分支结构…

[C++]类与对象下篇

目录 类与对象下篇&#xff1a;&#xff1a; 1.再谈构造函数 2.static成员 3.友元 4.内部类 5.匿名对象 6.拷贝对象时的编译器优化 7.再次理解封装 8.求12...n(不能使用乘除法、循环、条件判断) 9.计算日期到天数的转换 10.日期差值 11.打印日期 12.累加天数 类与对象下篇&…

数据结构与算法七 堆

一 堆 1.1 堆定义 堆是计算机科学中一类特殊的数据结构的统称&#xff0c;堆通常可以被看做是一棵完全二叉树的数组对象。 堆的特性&#xff1a; 它是完全二叉树&#xff0c;除了树的最后一层结点不需要是满的&#xff0c;其它的每一层从左到右都是满的&#xff0c;如果最后…

4月最新编程排行出炉,第一名ChatGPT都在用~

作为一名合格的&#xff08;准&#xff09;程序员&#xff0c;必做的一件事是关注编程语言的热度&#xff0c;编程榜代表了编程语言的市场占比变化&#xff0c;它的变化更预示着未来的科技风向和机会&#xff01; 快跟着一起看看本月排行有何看点&#xff1a; 4月Tiobe排行榜前…

【CSS】使用 固定定位 实现顶部导航栏 ( 核心要点 | 固定定位元素居中设置 | 代码示例 )

文章目录一、核心要点分析1、顶部导航栏要点2、固定定位垂直居中设置二、代码示例一、核心要点分析 实现下图所示功能 : 上方有一个固定导航栏 , 水平居中设置 ;左右两侧各一个广告栏 , 垂直居中设置 ; 1、顶部导航栏要点 顶部导航栏要点 : 使用固定定位 , 上边偏移设置为 0 …

Linux Ubuntu虚拟机下载安装以及初始配置--VMware、Ubuntu、Xshell、Xftp

一、下载准备 Ubuntu系统下载链接&#xff08;系统本身&#xff09;&#xff1a;官网链接 VMware虚拟机下载链接&#xff08;搭载Ubuntu系统&#xff09;&#xff1a;网盘链接密码XMKD Xshell下载链接&#xff08;虚拟机远程连接&#xff09;&#xff1a;官网链接 Xftp下载…

MySQL索引数据结构入门

之前松哥写过一个 MySQL 系列&#xff0c;但是当时是基于 MySQL5.7 的&#xff0c;最近有空在看 MySQL8 的文档&#xff0c;发现和 MySQL5.7 相比还是有不少变化&#xff0c;同时 MySQL 又是小伙伴们在面试时一个非常重要的知识点&#xff0c;因此松哥打算最近再抽空和小伙伴们…

PyQt5学习笔记一、安装PyQt5和在PyCharm中配置工具

一、安装PyQt5 1. 可以在cmd窗口安装PyQt5和工具 可以在cmd窗口使用命令 pip install PyQt5 安装PyQt5&#xff0c;若指定版本使用命令 pip install PyQt5version&#xff0c;此时同时安装了PyQt5和sip。参考链接 在cmd命令窗口安装Python模块_Mr. 李大白的博客-CSDN博客htt…

potPlay——记忆播放位置、各种快捷键

potPlay——记忆播放位置、各种快捷键potPlay——各种快捷键简洁版完整版快捷键列表potPlay——记忆播放位置potPlay——各种快捷键 简洁版 Q 复位 亮度&#xff0c;对比度&#xff0c;色度复位键 W/E 调暗/调亮 R/T 对比度 Y/U 饱和度 I/O 色彩度 D 上一帧 F 下一帧 M 静音 …

Docker开启并配置远程安全访问

前言 在工作学习中&#xff0c;为了提高项目部署效率&#xff0c;一般会在Idea中直接使用Docker插件连接服务器Docker容器&#xff0c;然后将项目打包与DockerFile一起build成Docker镜像部署运行。但是不可能服务器总是跟着主机的&#xff0c;因此呢时常会面临的一个问题就是从…

【微信小程序】-- uni-app 项目--- 购物车 -- 配置 tabBar 效果(五十一)

&#x1f48c; 所属专栏&#xff1a;【微信小程序开发教程】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &…

事务的ACID特性

1. 絮絮叨叨 重温Apache ORC时&#xff0c;发现ORC支持ACID想起自己之前一度不知道ACID是哪些单词的缩写&#xff0c;更别提面试中常提到的事物隔离级别等知识了因此&#xff0c;特地学习一下数据库中事务的ACID 2. ACID 2.1 What’s transaction&#xff1f; 考虑一个真实…

42.原型对象 prototype

目录 1 面向对象与面向过程 2 原型对象 prototype 3 在内置对象中添加方法 4 constructor 属性 5 实例对象原型 __proto__ 6 原型继承 7 原型链与instanceof 7.1 原型链 7.2 instanceof 8 案例-模态框 1 面向对象与面向过程 编程思想有 面向过程 与 面向…

几何-九种二次曲面类型

&#xff08;一&#xff09;椭圆锥面 &#xff08;1&#xff09;把z平方看成一个一直变大的常数&#xff0c;那么可以看出延z方向&#xff0c;是一个一直变大的椭圆。 &#xff08;2&#xff09;把一个x或y赋予0&#xff0c;显然是一个两条关于原点对称的直线。 由上即可判断…