Verilog 竞争与冒险

消除办法:

  • 增加滤波电容,滤除窄脉冲
  • 修改逻辑,增加冗余项
  • 使用时钟同步电路,利用触发器进行打拍延迟
module competition_hazrad
	(
	input clk,
	input rstn,
	input en,
	input din_rvs,
	input flag
	);
	
	wire condition = din_rvs & en;
	always @(posedge clk or negedge !rstn) begin
		if(!rstn) begin
			flag <= 1'b0;
		end
		else begin
			flag <= condition;
		end
endmodule

->出现了毛刺,尖峰脉冲 改进一下:

module clap_delay
	(
	input clk,
	input rstn,
	input en,
	input din_rvs,
	output reg flag
	);
	reg din_rvs_r;
	reg en_r;
	always @(posedge clk or !rstn) begin
		if(!rstn) begin
			din_rvs_r <= 1'b0;
			en_r <= 1'b0;
		end
		else begin
			din_rvs_r <= din_rvs;
			en_r <= en;
		end
	end
	
	wire condition = din_rvs_r&en_r;
	always @(posedge clk or negedge !rstn) begin
		if(!rstn) begin
			flag <= 1'b0;
		end
		else begin
			flag <= condition;
		end
	end
endmodule
  • 采用格雷码计数器

Verilog书写规范:

  • 时序电路建模时,用非阻塞赋值
always @(posedge clk)begin
	a = b;
	b = a;
end

非常容易阻塞!!!!

always @(posedge clk) begin
	a<=b;
	b<=a;
end

并行不堵车

  • 组合逻辑建模时,用阻塞赋值
always @(*) begin
	C <= A&B;
	F <= C&D;
end
//依旧用的旧的C,Error!
always @(*) begin
	C = A&B;
	F = C&D;
end
  • 在同一个always块中建立时序和组合逻辑模型时,用非阻塞赋值
always @(posedge clk or negedge rst_n)
	if(!rst_n)begin
		q<= 1'b0;
	end
	else begin
		q<=a&b;
	end
end
  • 在同一个always块中不要及使用阻塞又使用非阻塞
always @(*) begin
	C = A&B;
	F <= C&D;
end

乍一看没什么问题 F还是得等到阻塞完了才能赋值

always @(*) begin
	C <= A&B;
	F = C&D;
end
//不多说了
always @(posedge clk or negedge rst_n)
	if(!rst_n) begin
		q<=1'b0;
	end
	else begin
		q=a&b;
	end
end
  • 不要在多个always块为同一个变量赋值
  • 避免latch产生

Verilog Latch

Whats Latch Latch(锁存器)->电平触发的存储单元,数据存储的动作取决于输入时钟信号的电平值,锁存器使能时,

Pasted image 20260819120814.png

输出才会随着数据输入变化。 Latch的危害:

  • 输入状态可能多次变化,容易产生毛刺,增加了下一级电路的不确定性
  • 大部分FPGA资源中,可能需要比触发器更多的资源实现Latch结构
  • 锁存器的出现使得静态时序分析变得复杂 一般的设计中,应该避免Latch的产生

if结构不完整

缺少else结构,系统默认else分支下的q值保持不变,所以q会被综合为latch结构

module module1_latch1(
	input data,
	input en,
	output reg q);
	
	always @(*) begin
		if(en) q=data;
	end
endmodule

补全if-else结构或者对信号赋初值

always @(*) begin
	if(en) q=data;
	else q=1'b0;
end

always @(*) begin
	q = 1'b0;
	if(en) q = data;
end

时序逻辑中,不完整的if-else结构,不会产生latch

module module1_ff(
	input clk,
	input data,
	input en,
	output reg q);
	
	always @(posedge clk)begin
		if(en) q<=data;
	end
endmodule

组合逻辑下,条件语句中有很多赋值语句时,每个分支语句下赋值语句的不完整也是会产生latch

module module1_latch1(
	input data1;
	input data2;
	input en,
	output reg q1,
	output reg q2);
	
	always @(*) begin
		if(en) q1=data1;
		else q2 = data2;
	end
endmodule

也可以通过补充完整赋值语句或者赋初值来避免latch

always @(*) begin
	if(en)begin
		q1=data1;
		q2= 1;b0;
	end
	else begin
		q1=1'b0;
		q2=data2;
	end
end

case结构不完整

case语句产生Latch原理同if-else类似

module module1_latch2(
	input data1,
	input data2,
	input [1:0] sel,
	output reg q);
	
	always @(*) begin
		case(sel)
			2'b00:q=data1;
			2'b01:q=data2;
		end
	end
endmodule

解决也是将选项列表补充完整或是赋初值

always @(*) begin
	case(sel)
		2'b00: q=data1;
		2'b01: q=data2;
		default: q=1'b0;
	endcase
end
always @(*) begin
	case(sel)
		2'b00: q=data1;
		2'b01: q=data2;
		2'b10,2'b11:
			q=1'b0;
	endcase
end

原信号赋值或判断

组合逻辑中,若一个信号的赋值源头有信号本身,或者判断条件有其信号的逻辑,则也会产生latch。

reg a,b;
always @(*) begin
	if(a&b) a=1'b1;
	else a=1'b0;
end

reg c;
wire [1:0] sel;
always @(*) begin
	case(sel)
	2'b00: c=c;
	2'b01: c=1'b1;
	default:c=1'n0;
	endcase
end

wire d,sel2;
assign d= (sel2&&d)?1'b0:1'b1;

避免latch的方法,即在组合逻辑中避免这种写法,神之一手说是

reg a,b;
reg a_r;

always (@posedge clk)
	a_r <=a;
always $(*) begin
	if(a_r&b) a = 1'b1;
	else a =1'b0;
end

敏感信号列表不完整

敏感列表没有列全,该触发的时候没有触发,那么相关寄存器还是会保存之前的结果,因而生成锁存器。