Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
8 years ago

Latches in frequecny divider using fsm implementation

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

19 Replies