记录一次竞争与冒险的实测(HDL代码中的组合电路的信号作为时钟,毛刺带来的影响)
<div class='showpostmsg'> 本帖最后由 mars4zhu 于 2022-11-3 08:50 编辑<h1>竞争与冒险的实测<a href="http://summerdawn.top:7081/contention_race/contention_race.html#id1" title="Permalink to this heading"></a></h1>
<p>记录一次HDL代码中的组合电路的信号作为时钟,毛刺带来的影响</p>
<p>两种代码实现流水灯效果,以下代码运行正确的流水灯效果</p>
<pre style="background:#555; padding:10px; color:#ddd !important;">
module test0_pin (
inputclk_50M,
inputnRST,
input KEY,
output LED
);
parameter COUNTER_MAX = (50_000_000-1);
reg rCounter;
always @ (posedge clk_50M or negedge nRST) begin
if (!nRST) begin
rCounter <= 32'd0;
end
else begin
rCounter <= (rCounter >= COUNTER_MAX) ? 32'd0 : (rCounter + 32'd1);
end
end
// ============================
reg rLED;
always @ (posedge clk_50M or negedge nRST) begin
if (!nRST)
rLED <= 8'b0000_0001;
else
rLED <= (rCounter == COUNTER_MAX) ?
{rLED, rLED} : rLED;
end
// ============================
assign LED = (nRST) ? ~rLED : ~KEY;
endmodule
</pre>
<p></p>
<p>以下代码运行的流水灯效果存在异常</p>
<pre style="background:#555; padding:10px; color:#ddd !important;">
module test0_pin (
inputclk_50M,
inputnRST,
input KEY,
output LED
);
parameter COUNTER_MAX = (50_000_000-1);
reg rCounter;
always @ (posedge clk_50M or negedge nRST) begin
if (!nRST) begin
rCounter <= 32'd0;
end
else begin
rCounter <= (rCounter >= COUNTER_MAX) ? 32'd0 : (rCounter + 32'd1);
end
end
// ============================
wire clk_div;
assign clk_div = (!nRST) ? 1'b0 :
( (rCounter < (COUNTER_MAX/2)) ? 1'b0 : 1'b1 );
reg rLED;
always @ (posedge clk_div or negedge nRST) begin
if (!nRST)
rLED <= 8'b0000_0001;
else
rLED <= {rLED, rLED};
end
// ============================
assign LED = (nRST) ? ~rLED : ~KEY;
endmodule
</pre>
<p> </p>
<p></p>
<p>这两段verilog代码,都是执行流水灯,第二个就跑起来有问题。有时候有一两个LED就一闪而过,似乎clk_div上有毛刺之类的现象。。。 运行效果如视频, 总会跳过几个LED(一闪而过,能看到被跳过的LED有轻微的闪一下),</p>
<p>这段代码,assign语句:</p>
<pre style="background:#555; padding:10px; color:#ddd !important;">
assign clk_div = (!nRST) ? 1'b0 :
( (rCounter < (COUNTER_MAX/2)) ? 1'b0 : 1'b1 );
</pre>
<p>主要期望的功能是产生分频时钟, clk_div = clk_50M / COUNTER_MAX,这种计数器分频,还可以调节占空比、相移,</p>
<p>但是在运行的时候, 在rCounter变化的那一瞬间,譬如从50M变为0, 由于rCounter是32bit位宽的,各个bit到达比较器的时间会有细微差别,造成比较器看到的信号并不是此时此刻的真正的rCounter的值,所以才会产生毛刺。</p>
<p></p>
<p>而运行行为仿真是很难发现此类问题,行为仿真是按照一种理想器件的无延时特性运行,而实际运行的物理器件具有延时。以下的行为仿真(iverilog + gtkwave)波形图。</p>
<p></p>
<p>以下的网络文章按照有延时的物理特性仿真,就发现了竞争冒险现象的毛刺。</p>
<p><a href="https://zhuanlan.zhihu.com/p/451396150">https://zhuanlan.zhihu.com/p/451396150</a> 组合逻辑毛刺消除(竞争冒险)</p>
<p>信号在 IC/FPGA 器件中通过逻辑单元连线时,是存在延时的。延时的大小不仅和连线的长短和逻辑单元的数目有关,而且也和器件的制造工艺、工作环境等有关。因此,信号在器件中传输的时候,所需要的时间是不能精确估计的,当多路信号同时发生跳变的瞬间,就产生了“竞争冒险”。</p>
<p>信号由于经由不同路径传输达到某一汇合点的时间有先有后的现象,就称之为竞争,英文名Race;由于竞争现象所引起的电路输出发生瞬间错误的现象,就称之为冒险,英文名Hazard或者Risk。有竞争不一定有冒险,但出现了冒险就一定存在竞争。发生冒险时往往会出现一些不正确的尖峰信号,这些尖峰信号就是“毛刺”。</p>
<p>当然,打一拍也是有一定原则的,不是想打就打的</p>
<p>1.全局时钟的跳变沿最可靠。 2.来自异步时钟域的输入需要寄存一次以同步化,再寄存一次以减少亚稳态带来的影响。 3.不需要用到跳变沿的来自同一时钟域的输入,没有必要对信号进行寄存。 4.需要用到跳变沿的来自同一时钟域的输入,寄存一次即可。 5.需要用到跳变沿的来自不同时钟域的输入,需要用到3个触发器,前两个用以同步,第3个触发器的输出和第2个的输出经过逻辑门来判断跳变沿。</p>
<p><a href="https://baike.baidu.com/item/%E6%AF%9B%E5%88%BA/24249328">https://baike.baidu.com/item/%E6%AF%9B%E5%88%BA/24249328</a></p>
<p>信号在FPGA器件内部通过连线和逻辑单元时,都有一定的延时。延时的大小与连线的长短和逻辑单元的数目有关,同时还受器件的制造工艺、工作电压、温度等条件的影响。信号的高低电平转换也需要一定的过渡时间。由于存在这两方面因素,多路信号的电平值发生变化时,在信号变化的瞬间,组合逻辑的输出有先后顺序,并不是同时变化,往往会出现一些不正确的尖峰信号,这些尖峰信号称为”毛刺”。如果一个组合逻辑电路中有”毛刺”出现,就说明该电路存在”冒险”。(与分立元件不同,由于PLD内部不存在寄生电容电感,这些毛刺将被完整的保留并向下一级传递,因此毛刺现象在LD、FPGA设计中尤为突出) 图6.21给出了一个逻辑冒险的例子,从图6.22的仿真波形可以看出,”A、B、C、D”四个输入信号经过布线延时以后,高低电平变换不是同时发生的,这导致输出信号”OUT”出现了毛刺。(我们无法保证所有连线的长度一致,所以即使四个输入信号在输入端同时变化,但经过PLD内部的走线,到达或门的时间也是不一样的,毛刺必然产生)。可以概括的讲,只要输入信号同时变化,(经过内部走线)组合逻辑必将产生毛刺。 将它们的输出直接连接到时钟输入端、清零或置位端口的设计方法是错误的,这可能会导致严重的后果。 所以我们必须检查设计中所有时钟、清零和置位等对毛刺敏感的输入端口,确保输入不会含有任何毛刺</p>
<p><a href="https://zhuanlan.zhihu.com/p/372453668">https://zhuanlan.zhihu.com/p/372453668</a> 时序电路——DFF再理解</p>
</div><script> var loginstr = '<div class="locked">查看精华帖全部内容,请<a href="javascript:;" style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
if(parseInt(discuz_uid)==0){
(function($){
var postHeight = getTextHeight(400);
$(".showpostmsg").html($(".showpostmsg").html());
$(".showpostmsg").after(loginstr);
$(".showpostmsg").css({height:postHeight,overflow:"hidden"});
})(jQuery);
}
</script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script> <p>手边没有板子,只能学习学习代码了</p>
LED可以玩出这水平,学习了。 <p>很好的例子!</p> <p>把竞争冒险讲清楚了!:loveliness:</p> <p>大概看了下你的代码,很多地方不规范,或者说Verilog不建议这样写,找一个Verilog设计规范,会避免很多问题,也会对设计有一定的提升</p>
<p>把竞争冒险讲清楚了,学习了</p>
<p>把竞争冒险讲清楚了,学习了</p>
页:
[1]