Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)
16556 Discussions

Latches in frequecny divider using fsm implementation

Altera_Forum
Honored Contributor II
1,487 Views

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 

 

https://pastebin.com/mkw686h4 

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 ps, ns; reg out_change; reg out; reg 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
0 Kudos
19 Replies
Altera_Forum
Honored Contributor II
746 Views

Please can you re-post the code with some line feeds/carrige returns?

0 Kudos
Altera_Forum
Honored Contributor II
746 Views

https://pastebin.com/mkw686h4 

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 ps, ns; reg out_change; reg out; reg 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
0 Kudos
Altera_Forum
Honored Contributor II
746 Views

I edited the post, however the post cannot be seen right now. 

 

Here is the 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 ps, ns; reg out_change; reg out; reg 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
0 Kudos
Altera_Forum
Honored Contributor II
746 Views

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
0 Kudos
Altera_Forum
Honored Contributor II
746 Views

You should use 

 

Always @(posedge in_clk) 

 

Using levels of in_clk will give you latch.
0 Kudos
Altera_Forum
Honored Contributor II
746 Views

Thank you for your reply. 

I want to count both clk rising and falling edges.
0 Kudos
Altera_Forum
Honored Contributor II
746 Views

You can't do that in FPGA. Easiest way to do that would be with a 2x clock

0 Kudos
Altera_Forum
Honored Contributor II
746 Views

Hi Tricky, thank you for your reply 

Is it possible to use 2 different counters 

one for rising edges and one for falling edges 

and combine those two counters? 

or that cant be achieved neither when using FPGA?
0 Kudos
Altera_Forum
Honored Contributor II
746 Views

In addition,  

Quartus manage to synthesis this module without errors. 

Why it's not possible to have both edges of a signal in sensitivity list?
0 Kudos
Altera_Forum
Honored Contributor II
746 Views

Registers in an FPGA only have a single clock input, hence one register can only use a single clock, either a rising or falling edge. 

You may be able to separate the counters, but they will be in separate clock domains and combining them will not be so trivial. Much easier just to use a 2x clock.
0 Kudos
Altera_Forum
Honored Contributor II
746 Views

Hi Tricky, thank you for your reply. 

I have seen some code examples where the signals in sensitivity list are written without any edge statements. 

Such code can be synthesized ?  

Why quartus doesn't raise any error if such implementation is not compatible with FPGAs?
0 Kudos
Altera_Forum
Honored Contributor II
746 Views

 

--- Quote Start ---  

Hi Tricky, thank you for your reply. 

I have seen some code examples where the signals in sensitivity list are written without any edge statements. 

Such code can be synthesized ?  

Why quartus doesn't raise any error if such implementation is not compatible with FPGAs? 

--- Quote End ---  

 

 

Thats because those blocks will describe assignments for the variables in ALL paths through the block (ie. assigned in all ifs and else), so no latches are created.
0 Kudos
Altera_Forum
Honored Contributor II
746 Views

OK, but as you said previously 

FPGAs doesn't support both falling and rising edges of signal. 

is that means every verilog module targeted for FPGA can't have sensitivity list without stating the edge of the signal? 

 

Thanks
0 Kudos
Altera_Forum
Honored Contributor II
746 Views

 

--- Quote Start ---  

OK, but as you said previously 

FPGAs doesn't support both falling and rising edges of signal. 

is that means every verilog module targeted for FPGA can't have sensitivity list without stating the edge of the signal? 

 

Thanks 

--- Quote End ---  

 

 

Your code is not clocked, it is level sensitive, hence the latches. 

If you wanted to be sentive to the edges, you would write: 

 

always @(posedge clk or negedge clk) begin if (clk = '1') //rising edge action else if (clk = '0') // falling edge action end  

 

This would create a double edge sensitive flop, which is not possible in FPGA. The following code is just level sensitive to the compiler, but not simulation as quartus will ignore the signals in the sensitivity list, and just use what is in the always block, so will not produce a flop: 

 

always @(clk) begin if (clk = '1' ) // stuff to do while clock is '1' else if (clk = '0') // stuff do while clock is '0' end
0 Kudos
Altera_Forum
Honored Contributor II
746 Views

Hi Tricky, 

Thank you for your reply. 

 

If I get it right, 

always @(clk) 

begin 

... 

end 

 

or always @(*) 

 

are supported for compilation only but not for simulation and programming into FPGAs. 

Am I correct? 

 

Thanks
0 Kudos
Altera_Forum
Honored Contributor II
746 Views

 

--- Quote Start ---  

Hi Tricky, 

Thank you for your reply. 

 

If I get it right, 

always @(clk) 

begin 

... 

end 

 

or always @(*) 

 

are supported for compilation only but not for simulation and programming into FPGAs. 

Am I correct? 

 

Thanks 

--- Quote End ---  

 

 

Incorrect. 

They are a legitimate way of coding verilog, for creating logic or latches, which are both suitable for FPGAs.
0 Kudos
Altera_Forum
Honored Contributor II
746 Views

Hi Tricky, 

 

writing 

always@(clk) 

 

means it will execute the process for each changing in clk signal, in other words sesitivity for both rising or falling edges. However as you said FPGAs doesn't support dual edge flip flops. What am I missing? 

 

Sorry, I really don't get it when dual edge sensing is valid and when it's not. And why I don't get any synthesis errors if the HDL code is not suitable for the target device?
0 Kudos
Altera_Forum
Honored Contributor II
746 Views

FPGAs do not support dual edge flip flops. Plus Synthesis tools (but not simulators) ignore the sensitivity list of the always block. Hence, if you write: 

 

always @(clk) 

 

The synthesis tool ignores it, and treats it as  

 

always @(*) 

 

This is because synth tools have to infer logic from your code, and have to follow specific templates to generate specific logic. 

See https://www.altera.com/en_us/pdfs/literature/hb/qts/qts-qps-handbook.pdf , section 2-12 for recommended HDL coding styles. 

 

The problem with writing  

always @(clk) 

 

Is that in simulation it will behave like a dual edge flop, but as synthesis treats it as always @(*), the simulation behaviour and real hardware behaviour will not match. This is why you get warnings about latch generation when you may have a perfectly good simultion.
0 Kudos
Altera_Forum
Honored Contributor II
746 Views

Thank you Tricky

0 Kudos
Reply