使用fsm避免频繁分频器中的锁存器 - Verilog

时间:2017-06-07 20:27:51

标签: verilog system-verilog hdl quartus

我是verilog和HDL的新手 我想实现一个N分频器,
计数时钟滴答(pos和neg)并从输入clk的第一个上升沿开始计数机制 此外,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?

感谢

1 个答案:

答案 0 :(得分:1)

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)

请参阅Synthesizing Latches