0
votes

I am new to verilog and HDL.
I want to implement a N-frequency divider,
which count clock ticks (pos and neg) and start the counting mechanism from the first rising edge of the input clk.
In addition the clk divider has to support synchronous rst_n.

I am using Altera Quartus and the following code

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

After synthesis I get warnings about latches used for cnt register.
What am I doing wrong?

Can you guide me with good practice tips to avoid such cases in the future or more elegant ways to implement those kind of RTL?

thanks

1

1 Answers

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

If you want to be synchronous you can't do that. You have to change values on the same posedge of in_clk. But in general, we use PLL/DCM to divide clock. Clock follow special routing in FPGA using specials buffers.

[edit]

always @ (in_clk)

This will synthesize latches. If you don't want latch (and be synchronous) you have to trigger all your process (always@) with the same posedge of clock. In your case with the same posedge of in_clk :

always @ (posedge in_clk)

See Synthesizing Latches