FPGA学习笔记——跨时钟域(CDC)设计之多bit信号同步

FPGA学习笔记——跨时钟域(CDC)设计

多bit信号同步

  跨时钟域传递多比特信号的问题是,在同步多个信号到一个时钟域时将可能偶发数据变化歪斜(Skew),这种数据歪斜最终会在第二个时钟域的不同时钟上升沿上被采集。即便能够完美地控制和匹配这些多比特信号的走线长度,随着芯片衬底工艺不同,上升和下降的时间也会不一样,这些因素都会产生足够的歪斜导致在精心匹配的多条信号上采样失败。
  为了避免这种多比特跨时钟域信号上的采样歪斜,需要掌握一些不一样的方法。这些方法大致可以分为以下几种:

  1. 多比特信号合并成单比特信号。
  2. MUX同步器
  3. 多周期路径(Multi-Cycle path,MCP)同步法
  4. 握手处理
  5. 格雷码编码处理
  6. 异步FIFO

一、多比特信号融合( Multi-bit signal consolidation)

  一般适用于多个控制信号且控制信号之间有一定逻辑关系,可以合并成单比特信号。

情况1——2个同步控制信号

  例如接收域有一个寄存器,它需要一个加载(Load)信号和一个使能(Enable)信号来加载一个数值到寄存器。如果加载和使能信号在发送时钟域的同一个时钟沿被驱动有效(即两个控制信号需要同时有效),那么这两个控制信号之间就有可能存在产生一个小歪斜的机会,这就可能导致在接收时钟域中这两个信号被同步到不同的时钟周期。在这种情况下,数据是不能被加载到寄存器的。
FPGA学习笔记——跨时钟域(CDC)设计之多bit信号同步_第1张图片
FPGA学习笔记——跨时钟域(CDC)设计之多bit信号同步_第2张图片

解决方法——融合

  解决上述问题的方法非常简单,就是将加载和使能两个控制信号融合成一个单比特控制信号(这两个控制信号本身相同,且同时有效),如图下图所示。
FPGA学习笔记——跨时钟域(CDC)设计之多bit信号同步_第3张图片
FPGA学习笔记——跨时钟域(CDC)设计之多bit信号同步_第4张图片

情况二——两个含相位差的控制信号

  在发送时钟域先后有两个使能信号(注意不同于之前的同时有效),同步到接收时钟域用于控制两级流水寄存器寄存数据。问题是在第一个时钟域中,B_en1控制信号正好稍微在B_en2有效前结束有效,这就导致在接收时钟域时钟上升沿采集B_en1和B_en2脉冲时产生一个细微的缝隙。如图下图所示,
FPGA学习笔记——跨时钟域(CDC)设计之多bit信号同步_第5张图片
FPGA学习笔记——跨时钟域(CDC)设计之多bit信号同步_第6张图片  同步后两个使能控制信号间隔了两个时钟周期,而不是流水一个时钟周期。这样导致数据a2没有及时加载到第二个寄存器。这里需要注意的是,a3会在Aq2_en2有效的时候加载到第二个寄存器,但是在设计要求a1,a2,a3的更新符合一个周期的流水,所以设计出现了问题。

解决方法——融合后增加一个寄存器

  首先是在发送时钟域将两个使能控制信号融合为一个控制信号,其次是要增加一个额外的寄存器将同步后的使能控制信号寄存一拍,这样数据和控制信号形成匹配的流水,如下图所示:FPGA学习笔记——跨时钟域(CDC)设计之多bit信号同步_第7张图片
FPGA学习笔记——跨时钟域(CDC)设计之多bit信号同步_第8张图片

二、MUX 同步器(Mux synchronizer)

  MUX同步器为了同步数据,当数据在源触发器准备就绪时,在源时钟域中产生控制脉冲。然后,根据源域和目标域之间的时钟比,使用两个触发器同步器或脉冲同步器(触发或握手)来同步控制脉冲。同步控制脉冲用于在目的域内对总线上的数据进行采样。以下两种情况时可以使用MUX同步器:

  1. 当源时钟域比目的时钟域慢时,跨时钟域(CDC)位于数据总线上,且数据至少在m+1个目的时钟周器内保持稳定(m指目的时钟域同步器采用触发器的数量)。
  2. 当源时钟域比目的时钟域快时,跨时钟域(CDC)位于数据总线上,且保证数据持续时间足够长。

以牛客网练习题为例:
  描述:在data_en为高期间,data_in将保持不变,data_en为高至少保持3个B时钟周期。表明,当data_en为高时,可将数据进行同步。本题中data_in端数据变化频率很低,相邻两个数据间的变化,至少间隔10个B时钟周期。电路的接口如下图所示。端口说明如下表所示:
FPGA学习笔记——跨时钟域(CDC)设计之多bit信号同步_第9张图片
实现电路图如下:A时钟域异步复位和B时钟域异步复位未在图中标注
FPGA学习笔记——跨时钟域(CDC)设计之多bit信号同步_第10张图片
代码实现:

module    mux_sync(clk_a, clk_b, arst_n, brst_n, data_in, data_out, data_en);

    /********************参数定义********************/

    /*********************IO 说明********************/

	input    wire             clk_a   ;//A时钟域时钟(发送域)
	input    wire             clk_b   ;//B时钟域时钟(接收域)
	input    wire             arst_n  ;//A时钟异步复位
	input    wire             brst_n  ;//B时钟异步复位
	input    wire             data_en ;//A时钟域有效信号,高电平有效
	input    wire    [3:0]    data_in ;//A时钟域数据输入
	output   reg     [3:0]    data_out;//B时钟域数据输出   
	/********************** 内部信号声明 **********************/   
    reg   [3:0]    data_in_reg;    //输入数据暂存寄存器
	reg            a_data_en;      
    reg            b_data_en;
	reg            b_date_en_reg;
	/*************************功能定义*************************/
    /*数据暂存*/
	always@(posedge clk_a or negedge arst_n)
	begin
	    if(!arst_n)
		    data_in_reg <= 1'b0;
      	else 
		    data_in_reg <= data_in;
	end
    
	//使能信号在A时钟域用一个D触发器暂存
	always@(posedge clk_a or negedge arst_n) 
    begin
        if(!arst_n)
		    a_data_en <= 1'b0;
		else
            a_data_en <= data_en;
    end	
	
	//使能信号在B时钟域打两拍(两级电平同步器)
	always@(posedge clk_b or negedge brst_n) 
    begin
        if(!brst_n)
		begin
		    b_date_en_reg<= 1'b0;
		    b_data_en <= 1'b0;
		end
		else
		begin
		    b_date_en_reg <= a_data_en;
			b_data_en <= b_date_en_reg;
		end
    end	
	
	/*根据同步到B时钟域的使能信号b_data_en,更新输出。*/
	always@(posedge clk_b or negedge brst_n)
	    begin
        if(!brst_n)
		    data_out <= 4'b0;
		else
		begin
		    data_out <= b_data_en ? data_in_reg : data_out;
		end
    end	
	
endmodule

RTL视图:
FPGA学习笔记——跨时钟域(CDC)设计之多bit信号同步_第11张图片
若上题中为B时钟域(接收域)的时钟频率时A时钟域(发送域)的时钟频率的几十倍,甚至上百倍。且data_en为脉冲信号时,data_en在在快时钟域打完几拍的时间相对于慢时钟域是非常短暂的,此时慢时钟域中的多bit数据信号可能还处于冒险中间态,则此时选通进入快时钟域的数据就是“毛刺”。
可以在接收域使用边沿同步器,检测data_en的下降沿,以保证此时的多比特数据一定是稳定的。
实现电路图如下:A时钟域异步复位和B时钟域异步复位未在图中标注
FPGA学习笔记——跨时钟域(CDC)设计之多bit信号同步_第12张图片
代码实现

module    mux_sync(clk_a, clk_b, arst_n, brst_n, data_in, data_out, data_en);

    /********************参数定义********************/

    /*********************IO 说明********************/

	input    wire             clk_a   ;//A时钟域时钟(发送域)
	input    wire             clk_b   ;//B时钟域时钟(接收域)
	input    wire             arst_n  ;//A时钟异步复位
	input    wire             brst_n  ;//B时钟异步复位
	input    wire             data_en ;//A时钟域有效信号,高电平有效
	input    wire    [3:0]    data_in ;//A时钟域数据输入
	output   reg     [3:0]    data_out;//B时钟域数据输出   
	/********************** 内部信号声明 **********************/   
    reg   [3:0]    data_in_reg;    //输入数据暂存寄存器
	reg            a_data_en;      
    reg            b_data_en;
	reg            b_date_en_reg;
	reg            edge_reg;
	wire           edge_flag;
	/*************************功能定义*************************/
    /*数据暂存*/
	always@(posedge clk_a or negedge arst_n)
	begin
	    if(!arst_n)
		    data_in_reg <= 1'b0;
      	else 
		    data_in_reg <= data_in;
	end
    
	//使能信号在A时钟域用一个D触发器暂存
	always@(posedge clk_a or negedge arst_n) 
    begin
        if(!arst_n)
		    a_data_en <= 1'b0;
		else
            a_data_en <= data_en;
    end	
	
	//使能信号在B时钟域打两拍(两级电平同步器)
	always@(posedge clk_b or negedge brst_n) 
    begin
        if(!brst_n)
		begin
		    b_date_en_reg<= 1'b0;
		    b_data_en <= 1'b0;
		end
		else
		begin
		    b_date_en_reg <= a_data_en;
			b_data_en <= b_date_en_reg;
		end
    end	
	
	//下降沿检测
	always@(posedge clk_b or negedge brst_n)
	begin
	    if(!brst_n)
	        edge_reg <= 1'b0;
		else
		    edge_reg <= b_data_en;
	end
	assign  edge_flag = ~b_data_en & edge_reg;
	
	
	/*根据同步到B时钟域的使能信号b_data_en,更新输出。*/
	always@(posedge clk_b or negedge brst_n)
	begin
        if(!brst_n)
		    data_out <= 4'b0;
		else
		    data_out <= edge_flag ? data_in_reg : data_out;
    end	
	
endmodule

RTL视图:
FPGA学习笔记——跨时钟域(CDC)设计之多bit信号同步_第13张图片

三、多周期路径同步法

  多周期路径规划是一种通用的安全传递多比特跨时钟域信号技术。多周期路径规划是指在传输非同步数据到接收时钟域时配上一个同步的控制信号,数据和控制信号被同时发送到接收时钟域,同时控制信号在接收时钟域使用两级寄存器同步到接收时钟域,使用此同步后的控制信号来加载数据,这样数据就可以在目的寄存器被安全加载。 使用这种技术有以下两个好处:

  • 在时钟域之间发送数据的时候发送时钟域无须计算对应脉冲宽度。
  • 发送时钟域只需切换一个使能到接收时钟域来显示数据已经被传递且已准备被加载。使能信号无须返回到其原始状态,

  个人感觉多周期路径同步法包含MUX同步器和握手同步方式。其中MUX同步器相当于开环的多周期路径同步。而完全握手方式相当于带确认反馈的多周期路径同步,部分握手方式相当于带反馈的闭环多周期路径同步。

四、握手同步方式

  解决总线同步问题最基本的方法是保持寄存器和握手信号。保持寄存器用于进行数据锁存和采样,握手信号指示接收域中的电路何时可以对总线进行采样,以及发送域电路何时可以更新保持寄存器当前的内容。握手协议是一种闭环的数据同步方法,更像是基于MUX同步器的应答机制的扩展,其主要结构如下图所示,
FPGA学习笔记——跨时钟域(CDC)设计之多bit信号同步_第14张图片
  握手同步方式分为完全握手和部分握手两种基本类型。 每种类型的握手都使用上述的结构,但每种握手都有自己的设计权衡。握手信号指示接收域何时可以对总线数据进行采样,以及发送域何时可以更新当前数据锁存器中保存的内容。数据路径主要由发送时钟域的数据锁存模块以及接收时钟域的数据采集模块组成。

完全握手同步方式

  完全握手的特点是发送域和接收域两端在发送请求或者终止请求之前都需要等待对端的回应。完全握手在收发两侧都使用的是电平同步器。当接收域需要通知发送域它正在积极处理请求时,通常会采用完全握手。完全握手要求发送域推迟它的下一个请求,直到它检测到无效的确认信号。以下是完全握手的流程和时序:
FPGA学习笔记——跨时钟域(CDC)设计之多bit信号同步_第15张图片
FPGA学习笔记——跨时钟域(CDC)设计之多bit信号同步_第16张图片
  用前缀t_表示发送域,用前缀r_表示接收域,发送时钟用t_clk表示,接收时钟用r_clk表示。数据由发送域向接收域传输;以下是完全握手的工作步骤:

  1. 当发送域数据准备好后,发送域将t_req信号置为有效;
  2. 接收域采用两级电平同步器同步t_req信号,并把同步后的信号命名为r_req_sync2;
  3. 接收域检测到t_req_sync2信号有效时, 在下一个r_clk周期中,接收域将r_ack信号置为有效,并使用r_clk对发送域数据进行采样,可以得到r_data_out;
  4. 发送域采用两级电平同步器同步r_ack信号,并把同步后的信号命名为t_ack_sync2;
  5. 发送域检测到t_ack_sync2信号有效时,接收域将t_req信号置为无效;
  6. 接收域在经过两个r_clk周期后检测到r_req_sync2信号无效;
  7. 在下一个r_clk周期中,接收域将r_ack置为无效
  8. 发送域在通过两级电平同步器后检测到r_ack信号无效时,完成一次完全握手,发送域可以输入新的数据。
       这里,全部握手在发送域中最多需要5个周期,在接收域中最多需要6个周期。
      全握手协议在异步数据跨时钟的安全性方面很强,因为通过检测请求与响应信号,每一侧电路都清楚地知道对端的状态。但是这种方式也有其不足,那就是完成所有交互的整个过程要花费很多个时钟周期,数据信号跨时钟的延时比较大。

部分握手同步方式

  部分握手协议则可以缩短握手的过程,提高数据传输的效率,但使用部分握手信号时,收发双方不等对方响应就中止各自的请求,并继续执行握手命令序列。部分握手类型比全握手类型在可靠性方面稍弱,因为握手信号并不指示各自电路的状态,收发侧都必须保存状态信息。但是,由于无需等待其他电路的响应,完整的时间周期花费时间较少。有两种部分握手方案,区别在于握手所采用的信号类型。一种所用的部分握手方法在发送侧使用电平信号来发送请求,在接收侧使用脉冲信号来发送响应;另一种所用的部分握手方法在发送侧与接收侧都使用脉冲信号。

1.部分握手同步方式1

  在第一种部分握手方式中,接收域对请求信号使用电平同步器,发送域对确认信号使用脉冲同步器。在此握手协议中,应答脉冲仅在接收域检测到请求信号时出现。这允许发送域通过控制其请求信号的时序来控制脉冲进入同步器的间隔。为了确保部分握手同步方式成立,发送域中止请求信号至少持续发送域1个时钟周期长,否则接收域就不能区别前一个请求和新的请求。以下是部分握手1的流程和时序:
FPGA学习笔记——跨时钟域(CDC)设计之多bit信号同步_第17张图片

FPGA学习笔记——跨时钟域(CDC)设计之多bit信号同步_第18张图片
  用前缀t_表示发送域,用前缀r_表示接收域,发送时钟用t_clk表示,接收时钟用r_clk表示。数据由发送域向接收域传输;以下是部分握手1的工作步骤:

  1. 当发送域数据准备好后,发送域将t_req信号置为有效;
  2. 接收域采用两级电平同步器同步t_req信号,并把同步后的信号命名为r_req_sync2;
  3. 接收域检测到t_req_sync2信号有效时, 在下一个r_clk周期中,接收域将产生一个接收域时钟周期的脉冲信号r_ack,并使用r_clk对发送域数据进行采样,可以得到r_data_out;
  4. 发送域采用脉冲同步器同步r_ack脉冲信号,并把同步后的信号命名为t_ack_pusle;
  5. 发送域检测到t_ack_pusle信号有效时,接收域将t_req信号置为无效;
  6. 接收域在经过两个r_clk周期后检测到r_req_sync2信号无效时;完成一次完全握手,发送域可以输入新的数据。

  完整的部分握手1在发送域中最多需要3个周期,在接收域中最多需要5个周期。部分握手1在发送域中使用的时钟周期比完全握手少2个时钟周期,在接收域中使用的时钟周期少1个时钟周期。

2.部分握手同步方式2

  在第二种部分握手方式中,发送域用一个单时钟宽度脉冲发出它的请求,而接收域也用一个单时钟宽度脉冲响应这个请求。这种情况下,发送域和接受域都需要保存状态,以指示请求正待处理。这种握手类型使用的是脉冲同步器,但如果其中一个电路时钟比另一个电路时钟快两倍,则可以用边沿检测同步器来代替。完整的时序是:发送侧时钟域最多2个时钟周期,接收侧最多3个时钟周期。以下是部分握手2的流程和时序:
FPGA学习笔记——跨时钟域(CDC)设计之多bit信号同步_第19张图片
FPGA学习笔记——跨时钟域(CDC)设计之多bit信号同步_第20张图片
  用前缀t_表示发送域,用前缀r_表示接收域,发送时钟用t_clk表示,接收时钟用r_clk表示。数据由发送域向接收域传输;以下是部分握手1的工作步骤:

  1. 当发送域数据准备好后,发送域将产生一个单时钟宽度脉冲的t_req_pluse信号;
  2. 接收域采用脉冲同步器检测t_req_pluse,将检测到的信号命名为r_req_pluse;
  3. 接收域检测到t_req_pluse时, 在下一个r_clk周期中,接收域将产生一个单时钟宽度脉冲的r_ack_pluse,并使用r_clk对发送域数据进行采样,可以得到r_data_out;
  4. 发送域采用脉冲同步器同步r_ack_pluse脉冲信号,并把同步后的信号命名为t_ack_pusle;完成一次完全握手,发送域可以输入新的数据。
总结

FPGA学习笔记——跨时钟域(CDC)设计之多bit信号同步_第21张图片

牛客网——使用握手信号实现跨时钟域数据传输题目

分别编写一个数据发送模块和一个数据接收模块,模块的时钟信号分别为clk_a,clk_b。两个时钟的频率不相同。数据发送模块循环发送0-7,在每个数据传输完成之后,间隔5个时钟,发送下一个数据。请在两个模块之间添加必要的握手信号,保证数据传输不丢失。
模块的接口信号图如下:FPGA学习笔记——跨时钟域(CDC)设计之多bit信号同步_第22张图片
data_req和data_ack的作用说明:
data_req表示数据请求接受信号。当data_out发出时,该信号拉高,在确认数据被成功接收之前,保持为高,期间data应该保持不变,等待接收端接收数据。
当数据接收端检测到data_req为高,表示该时刻的信号data有效,保存数据,并拉高data_ack。
当数据发送端检测到data_ack,表示上一个发送的数据已经被接收。撤销data_req,然后可以改变数据data。等到下次发送时,再一次拉高data_req。
输入描述:
clk_a:发送端时钟信号
clk_b:接收端时钟信号
rst_n:复位信号,低电平有效
data_ack:数据接收确认信号

输出描述:
data:发送的数据
data_req:请求接收数据

数据发送模块:

module  data_driver(
    input    clk_a,                //发送端时钟信号
	input    rst_n,                //复位信号,低电平有效
	input    data_ack,             //数据接收确人信号
	output   reg    [3:0]    data, //发送数据
	output   reg    data_req       //请求接收信号
    );

    /********************参数定义********************/

    /*********************IO 说明********************/

	/********************** 内部信号声明 **********************/
    reg    [2:0]    cnt_reg;
	reg             data_ack_sync1;
	reg             data_ack_sync2;
	/*************************功能定义*************************/
    //计数
	always@(posedge clk_a or negedge rst_n)
	begin
	    if(!rst_n)
		    cnt_reg <= 3'd0;
        else if(data_ack_sync1 && !data_ack_sync2 == 1'b1)
            cnt_reg <= 3'd0;
        else if(data_req == 1'b1)
            cnt_reg <= cnt_reg;
		else
		    cnt_reg <= cnt_reg + 1'b1;
	end
	
	//data_ack两级同步
	always@(posedge clk_a or negedge rst_n)
	begin
	    if(!rst_n)
		begin
		    data_ack_sync1 <= 1'b0;
			data_ack_sync2 <= 1'b0;
		end
		else
		begin
		    data_ack_sync1 <= data_ack;
			data_ack_sync2 <= data_ack_sync1;
		end 
	end
	
    //请求接收信号
    always@(posedge clk_a or negedge rst_n)
	begin
	    if(!rst_n)
		    data_req <= 1'b0;
		else if(cnt_reg == 3'd4)
	        data_req <= 1'b1;
		else if(data_ack_sync2 == 1'b1)
		    data_req <= 1'b0;
		else
		    data_req <= data_req;  
	end 
	
	//发送数据
	always@(posedge clk_a or negedge rst_n)
	begin
	    if(!rst_n)
		    data <= 4'd0;
		else if(data == 4'd7 && data_ack_sync2 == 1'b1 && data_req == 1'b1 )
		    data <= 4'd0;
		else 
		begin
		    if(data_ack_sync2 == 1'b1 && data_req == 1'b1 )
		        data <= data + 1'b1;
			else
		        data <= data;
		end
	end
	
endmodule

数据接收模块

module  data_receiver(
    input             clk_b,   //接收端时钟信号
	input             rst_n,   //复位信号,低电平有效
	input    [3:0]    data,    //接收数据
	input             data_req,    //请求接收信号
    output   reg      data_ack//数据接收确人信号
    );

    /********************参数定义********************/

    /*********************IO 说明********************/

	/********************** 内部信号声明 **********************/
	reg             data_req_sync1;
	reg             data_req_sync2;
	/*************************功能定义*************************/	
	//data_req两级同步
	always@(posedge clk_b or negedge rst_n)
	begin
	    if(!rst_n)
		begin
		    data_req_sync1 <= 1'b0;
			data_req_sync2 <= 1'b0;
		end
		else
		begin
		    data_req_sync1 <= data_req;
			data_req_sync2 <= data_req_sync1;
		end 
	end
	
    //数据接收确人信号
    always@(posedge clk_b or negedge rst_n)
	begin
	    if(!rst_n)
		    data_ack <= 1'b0;
		else if(data_req_sync2 == 1'b1)
		    data_ack <= 1'b1;
		else
		    data_ack <= 1'b0;  
	end 
	
endmodule

功能仿真
FPGA学习笔记——跨时钟域(CDC)设计之多bit信号同步_第23张图片

五、格雷码编码方式

  通过编码的方式将多位信号转化为每次只有一位变化的信号,将“多比特”的跨时钟域变换成“单比特”进行处理。格雷码的特点是相邻的两个编码之间只有1位不同,消除了在同一个时钟沿,多比特信号或者数据同时变化所带来的跨时钟域问题。
  应用局限:只有在数据在相数值间连续变化的情况下才有用,不适用于大多数信号传输或者数据传输的情况。一般用于跨时钟域的计数器设计,如异步FIFO的读写地址,其他场合基本没有用到。

六、异步FIFO

  数据流的传输与指示信号不同在于:数据流大多具有连续性,及背靠背传输;数据流要求信号具有较快的传输速度。跨时钟域传输数据用得最多的方法就是使用先人先出(FIFO)结构。FIFO可以用于在两个异步时钟域之间传输多比特信号。通常看到的FIFO应用包括在两个标准总线之间传输数据,以及从可突发访问的存储器中读出数据或者对其写入数据。
  异步FIFO有两个端口,一个端口写人输入数据,另一个端口读出数据。两个端口工作在相互独立的时钟域内,通过各自的指针(地址)来读写数据。由于每个端口工作在相互独立的时钟域内,因此读写操作可以独立实现并且不会出现任何差错。FIFO有满标志和空标志,当FIFO变满时,应停止写操作,直到FIFO中出现空闲空间;同样,当FIFO为空时,应停止读操作,直到有新的数据被写人FIFO中。异步FIFO结构如下图所示
FPGA学习笔记——跨时钟域(CDC)设计之多bit信号同步_第24张图片

FIFO 的参数

  • 宽度:一次读写操作的数据位
  • 深度:可以存储的N位数据的数目(宽度为N)
  • 满标志:FIFO已满时,由FIFO的状态电路送出的信号,阻止FIFO写操作
  • 空标志:FIFO已空时,由FIFO的状态电路送出的信号,阻止FIFO读操作
  • 读时钟:读操作所遵循的时钟
  • 写时钟:写操作所遵循的时钟

异步FIFO的设计主要有7部分组成

  • 双口RAM存储数据
  • 同步读数据指针到写时钟域
  • 同步写数据指针到读时钟域
  • 写指针控制逻辑
  • 满信号状态判断
  • 读指针控制逻辑
  • 空信号状态判断

参考文章

1.Synchronizer techniques for multi-clock domain SoCs & FPGAs
2.Clock Domain Crossing Techniques for FPGA
3.Clock Domain Crossing (CDC) Design & Verification Techniques Using SystemVerilog
4.2021年秋招面经分享·华为【海思·芯片与器件工程师】

你可能感兴趣的:(FPGA,#,同步电路设计与跨时钟域,fpga开发,学习)