使用FSM -Verilog避免在频率分隔器中锁存



我是Verilog和HDL的新手。
我想实现n频分隔线,
哪个计数时钟滴答(pos and neg(,然后从输入库的第一个上升边缘开始计数机制。
另外,clk分隔器必须支持同步rst_n。

我正在使用Altera Quartus和以下代码

module clk_divider_fsm
(
	in_clk,
	rst_n,
	out_clk
);
input in_clk, rst_n;
output out_clk;
parameter prescaler = 10;
parameter BIT_DEPTH = `CLOG2(prescaler);
parameter S0 = 2'b00, S1 = 2'b01, S2 = 2'b10;
parameter CNT_RESET = {BIT_DEPTH{1'b0}};
//parameter CNT_FIRST = {BIT_DEPTH-1{1'b0}, 1'b1};
reg [1:0] ps, ns;
reg out_change;
reg out;
reg [BIT_DEPTH:0] cnt;
initial
begin
	ps = S0;
	ns = S0;
	cnt = CNT_RESET;
	out_change = 1'b0;
	out = 1'b0;
end
always @ (in_clk)
begin
	if(!rst_n)
		ps = S0;
	else
		ps =  ns;
//	begin
//		if(ns != ps)
//			ps =  ns;
//	end
end
always @ (in_clk)
begin
	case(ps)
		S0: begin
			if(in_clk === 1'b1)
			begin
				out_change <= 1'b1;
				ns <= S1;
				cnt <= CNT_RESET + 1'b1;
			end
			else
			begin
				out_change <= 1'b0;
				cnt <= CNT_RESET;
				ns <= S0;
			end
		end
		S1: begin
			if(in_clk === 1'b0)
			begin
				if(cnt == prescaler)
				begin
					cnt <= CNT_RESET + 1'b1;
					out_change <= 1'b1;
					ns <= S2;
				end
				else
				begin
					cnt <= cnt + 1'b1;
					out_change <= 1'b0;
					ns <= S2;
				end
			end
			else
			begin
				out_change = 1'b0;
				ns = S1;
				cnt <= cnt;
			end
		end
		
		S2: begin
			if(in_clk == 1'b1)
			begin
				if(cnt == prescaler)
				begin
					cnt <= CNT_RESET + 1'b1;
					out_change <= 1'b1;
					ns <= S1;
				end
				else
				begin
					cnt <= cnt + 1'b1;
					out_change <= 1'b0;
					ns <= S1;
				end
			end
			else
			begin
				out_change = 1'b0;
				ns = S2;
				cnt <= cnt;
			end
		end
		default: begin
			out_change <= 1'b0;
			cnt <= CNT_RESET;
			ns <= S0;
		end
	endcase
	
	if(!rst_n)
	begin
		ns <= S0;
		cnt <= CNT_RESET;
	end
end
always @ (posedge out_change or negedge rst_n)
begin
	if(!rst_n)
		out <= 1'b0;
	else
		out <= ~out;
end
assign out_clk = (prescaler == 1) ? (in_clk & rst_n) : out;
endmodule

合成后,我会收到有关用于CNT登记的闩锁的警告。
我究竟做错了什么?

您能否通过良好的练习技巧来指导我以后避免这种情况或更优雅的方法来实施这种RTL?

谢谢

always @ (in_clk)
...
always @ (posedge out_change or negedge rst_n)

如果您想同步,就无法做到这一点。您必须在IN_CLK的同一posedge上更改值。但是通常,我们使用PLL/DCM分割时钟。时钟使用特价缓冲区在FPGA中的特殊路由。

[编辑]

always @ (in_clk)

这将合成闩锁。如果您不希望闩锁(和同步(,则必须使用时钟的相同 posedge 触发所有过程(始终@(。在您的情况下,IN_CLK相同的姿势:

always @ (posedge in_clk)

请参阅合成闩锁

最新更新