本帖最后由 mars4zhu 于 2022-11-3 08:50 编辑
竞争与冒险的实测
记录一次HDL代码中的组合电路的信号作为时钟,毛刺带来的影响
两种代码实现流水灯效果,以下代码运行正确的流水灯效果
module test0_pin (
input clk_50M,
input nRST,
input [8:1] KEY,
output [8:1] LED
);
parameter COUNTER_MAX = (50_000_000-1);
reg [31:0] 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 [7:0] rLED;
always @ (posedge clk_50M or negedge nRST) begin
if (!nRST)
rLED <= 8'b0000_0001;
else
rLED[7:0] <= (rCounter == COUNTER_MAX) ?
{rLED[6:0], rLED[7]} : rLED;
end
// ============================
assign LED = (nRST) ? ~rLED : ~KEY;
endmodule
以下代码运行的流水灯效果存在异常
module test0_pin (
input clk_50M,
input nRST,
input [8:1] KEY,
output [8:1] LED
);
parameter COUNTER_MAX = (50_000_000-1);
reg [31:0] 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 [7:0] rLED;
always @ (posedge clk_div or negedge nRST) begin
if (!nRST)
rLED <= 8'b0000_0001;
else
rLED[7:0] <= {rLED[6:0], rLED[7]};
end
// ============================
assign LED = (nRST) ? ~rLED : ~KEY;
endmodule
这两段verilog代码,都是执行流水灯,第二个就跑起来有问题。有时候有一两个LED就一闪而过,似乎clk_div上有毛刺之类的现象。。。 运行效果如视频, 总会跳过几个LED(一闪而过,能看到被跳过的LED有轻微的闪一下),
这段代码,assign语句:
assign clk_div = (!nRST) ? 1'b0 :
( (rCounter < (COUNTER_MAX/2)) ? 1'b0 : 1'b1 );
主要期望的功能是产生分频时钟, clk_div = clk_50M / COUNTER_MAX,这种计数器分频,还可以调节占空比、相移,
但是在运行的时候, 在rCounter变化的那一瞬间,譬如从50M变为0, 由于rCounter是32bit位宽的,各个bit到达比较器的时间会有细微差别,造成比较器看到的信号并不是此时此刻的真正的rCounter的值,所以才会产生毛刺。
而运行行为仿真是很难发现此类问题,行为仿真是按照一种理想器件的无延时特性运行,而实际运行的物理器件具有延时。以下的行为仿真(iverilog + gtkwave)波形图。
以下的网络文章按照有延时的物理特性仿真,就发现了竞争冒险现象的毛刺。
https://zhuanlan.zhihu.com/p/451396150 组合逻辑毛刺消除(竞争冒险)
信号在 IC/FPGA 器件中通过逻辑单元连线时,是存在延时的。延时的大小不仅和连线的长短和逻辑单元的数目有关,而且也和器件的制造工艺、工作环境等有关。因此,信号在器件中传输的时候,所需要的时间是不能精确估计的,当多路信号同时发生跳变的瞬间,就产生了“竞争冒险”。
信号由于经由不同路径传输达到某一汇合点的时间有先有后的现象,就称之为竞争,英文名Race;由于竞争现象所引起的电路输出发生瞬间错误的现象,就称之为冒险,英文名Hazard或者Risk。有竞争不一定有冒险,但出现了冒险就一定存在竞争。发生冒险时往往会出现一些不正确的尖峰信号,这些尖峰信号就是“毛刺”。
当然,打一拍也是有一定原则的,不是想打就打的
1.全局时钟的跳变沿最可靠。 2.来自异步时钟域的输入需要寄存一次以同步化,再寄存一次以减少亚稳态带来的影响。 3.不需要用到跳变沿的来自同一时钟域的输入,没有必要对信号进行寄存。 4.需要用到跳变沿的来自同一时钟域的输入,寄存一次即可。 5.需要用到跳变沿的来自不同时钟域的输入,需要用到3个触发器,前两个用以同步,第3个触发器的输出和第2个的输出经过逻辑门来判断跳变沿。
https://baike.baidu.com/item/%E6%AF%9B%E5%88%BA/24249328
信号在FPGA器件内部通过连线和逻辑单元时,都有一定的延时。延时的大小与连线的长短和逻辑单元的数目有关,同时还受器件的制造工艺、工作电压、温度等条件的影响。信号的高低电平转换也需要一定的过渡时间。由于存在这两方面因素,多路信号的电平值发生变化时,在信号变化的瞬间,组合逻辑的输出有先后顺序,并不是同时变化,往往会出现一些不正确的尖峰信号,这些尖峰信号称为”毛刺”。如果一个组合逻辑电路中有”毛刺”出现,就说明该电路存在”冒险”。(与分立元件不同,由于PLD内部不存在寄生电容电感,这些毛刺将被完整的保留并向下一级传递,因此毛刺现象在LD、FPGA设计中尤为突出) 图6.21给出了一个逻辑冒险的例子,从图6.22的仿真波形可以看出,”A、B、C、D”四个输入信号经过布线延时以后,高低电平变换不是同时发生的,这导致输出信号”OUT”出现了毛刺。(我们无法保证所有连线的长度一致,所以即使四个输入信号在输入端同时变化,但经过PLD内部的走线,到达或门的时间也是不一样的,毛刺必然产生)。可以概括的讲,只要输入信号同时变化,(经过内部走线)组合逻辑必将产生毛刺。 将它们的输出直接连接到时钟输入端、清零或置位端口的设计方法是错误的,这可能会导致严重的后果。 所以我们必须检查设计中所有时钟、清零和置位等对毛刺敏感的输入端口,确保输入不会含有任何毛刺
https://zhuanlan.zhihu.com/p/372453668 时序电路——DFF再理解