《硬件架构的艺术》读书笔记(一)亚稳态

第1章:亚稳态

1.亚稳态来源:是由于违背了触发器的建立和保持时间而产生的。

 

2.在同步时序电路中发生概率较小,在异步时序电路中发生概率较大,这是由于时钟和数据关系在异步时序电路中不固定。

 

3.数据信号在时钟沿到来的建立保持时间窗口中应当保持稳定。

 

4.产生亚稳态可能的条件:

1.输入信号是异步信号;

2.时钟偏移/摆动(上升/下降时间)高于容限值;

3.信号在不同频率或同频率不同相位和偏移的跨时钟域传输;

4.组合逻辑延迟使得数据信号在窗口变化。

 

5.解决方法:

1.采用同步器;

2.延长时钟周期(不适用)。

 

6.亚稳态测试电路:

原理:

异步输入async_in输入到由时钟上升沿触发的寄存器qa。qb和qc都是由时钟的下降沿来触发。

 

当两个互为反相的信号分别传递到qb和qc的输入时,无论qa什么时候出现亚稳态,异或非(XNOR)门的输出都会变为高电平。在寄存器qd输出端捕捉到高电平就表明已经检测到亚稳态时间。

 

当出现亚稳态时,qa输出信号不稳定,qb与qc接受到的信号不能保持稳定的反相关系,故当不稳定时,在XNOR门输出为1.

 

电路图:

 

亚稳态测试电路代码:

module metastab_test(

    input clk,

    input rstn,

    input async_in,

    output async_det

);

    reg qa,qb,qc,qd;

always @ (posedge clk or negedge rstn)

begin

    if(!rstn)

        qa  <=  1'b0;

    else

        qa  <=  async_in;
end

assign  clk_inv  = !clk;

always @ (posedge clk_inv or negedge rstn)

begin

    if(!rstn)

        qb  <=  1'b0;

    else

        qb  <=  qa;

end

always @ (posedge clk_inv or negedge rstn)

begin

    if(!rstn)

        qc  <=  1'b0;

    else

        qc  <=  !qa;

end

assign temp = !(qb ^ qc);

always @ (posedge clk or negedge rstn)

begin

    if(!rstn)

        qd  <=  1'b0;

    else

        qd  <=  temp;

end

assign async_det = qd;

endmodule

 

7.MTBF(平均无故障时间)

 

MTBF = 1/故障率 = e(tr/τ)/Wfcfd

 

tr 为允许超出器件正常传输延迟时间的解析时间;

τ为触发器的亚稳态(解析)时间常数;

W为亚稳态窗口;

fc为时钟频率;

fd为异步信号边沿频率。

 

8.单比特信号异步传输

 

(1)由快到慢(clk_a>clk_b)

主要原理就是先把脉冲信号在clk_a下展宽,变成足够宽的电平信号signal_a,再向clk_b传递,当确认clk_b已经“看见”信号同步过去之后,再清掉signal_a。

 

代码框架如下:

module Sync_Pulse (

                  clk_a,       

                  clk_b,  

                  rst_n,           

                  pulse_a_in,  

                

                  pulse_b_out, 

                  lev_out

                  );

/****************************************************/



    input               clk_a;

    input               clk_b;

    input               rst_n;

    input               pulse_a;

   

    output              pulse_b_out;

    output              b_out;     

   

/****************************************************/ 



    reg                 signal_a;

    reg                 signal_b;

    reg                 signal_b_r1;

    reg                 signal_b_r2;

    reg                 signal_b_a1;

    reg                 signal_b_a2;

   

/****************************************************/

    //在时钟域clk_a下,生成展宽信号signal_a

    always @ (posedge clk_a or negedge rst_n)

        begin

            if (rst_n == 1'b0)

                signal_a <= 1'b0;

            else if (pulse_a_in)            //检测到到输入信号pulse_a_in被拉高,则拉高signal_a

                signal_a <= 1'b1;

            else if (signal_b_a2)           //检测到signal_b1_a2被拉高,则拉低signal_a

                signal_a <= 1'b0;

            else;

        end

   

    //在时钟域clk_b下,采集signal_a,生成signal_b

    always @ (posedge clk_b or negedge rst_n)

        begin

            if (rst_n == 1'b0)

                signal_b <= 1'b0;

            else

                signal_b <= signal_a;

        end

    //多级触发器处理,对接收到的跨时钟信号signal_b打两拍

    always @ (posedge clk_b or negedge rst_n)

        begin

            if (rst_n == 1'b0)

                begin

                    signal_b_r1 <= 1'b0;

                    signal_b_r2 <= 1'b0;

                end

            else

                begin

                    signal_b_r1 <= signal_b;        //对signal_b打两拍

                    signal_b_r2 <= signal_b_r1;

                end

        end

    //在时钟域clk_a下,采集signal_b_r1,signal_b_a2用于反馈来拉低展宽信号signal_a

    always @ (posedge clk_a or negedge rst_n)

        begin

            if (rst_n == 1'b0)

                begin

                    signal_b_a1 <= 1'b0;

                    signal_b_a2 <= 1'b0;

                end

            else

                begin

                    signal_b_a1 <= signal_b_r1;     //对signal_b_r1打两拍,因为同样涉及到跨时钟域  

                    signal_b_a2 <= signal_b_a1;

                end

        end



    assign  pulse_b_out =   signal_b_r1 & (~signal_b_r2);       //clk_b时钟域下的上升沿检测

    assign  lev_out       =   signal_b_r1;                 //电平输出



endmodule

 

(2)由慢到快(clk_a < clk_b)

经验设计采集过程必须寄存两拍。第一拍将输入信号同步化,同步化后的输出可能带来建立/保持时间的冲突,产生亚稳态。需要再寄存一拍,减少亚稳态带来的影响。一般来说两级是最基本要求,如果是高频率设计,则需要增加寄存级数来大幅降低系统的不稳定性。也就是说采用多级触发器来采样来自异步时钟域的信号,级数越多,同步过来的信号越稳定。

此时pulse_b必须是clk_b下的寄存器信号,如果pulse_b是clk_b下的组合逻辑信号,一定要先在clk_b先用D触发器(DFF)抓一拍,再使用两级DFF向clk_a传递。这是因为clk_b下的组合逻辑信号会有毛刺,在clk_b下使用时会由setup/hold时间保证毛刺不会被clk_b采到,但由于异步相位不确定,组合逻辑的毛刺却极有可能被clk_a采到。

 

代码框架如下:

always @ (posedge clk_a or negedge rst_n)

    begin

        if (rst_n == 1'b0)

            begin

               pules_a_r1 <= 1'b0;

               pules_a_r2 <= 1'b0;

               pules_a_r3 <= 1'b0;

            end

        else

            begin                                   //打3拍

               pules_a_r1 <= pulse_b;

               pules_a_r2 <= pules_a_r1;

               pules_a_r3 <= pules_a_r2;

            end

    end



assign pulse_a_pos  = pules_a_r2 & (~pules_a_r3);   //上升沿检测

assign pulse_a_neg  = pules_a_r3 & (~pules_a_r2);   //下降沿检测

assign pulse_a      = pules_a_r2;

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值