Forum Discussion
Altera_Forum
Honored Contributor
9 years agoLatches 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? thanks19 Replies
- Altera_Forum
Honored Contributor
Please can you re-post the code with some line feeds/carrige returns?
- Altera_Forum
Honored Contributor
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 - Altera_Forum
Honored Contributor
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 - Altera_Forum
Honored Contributor
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 - Altera_Forum
Honored Contributor
You should use
Always @(posedge in_clk) Using levels of in_clk will give you latch. - Altera_Forum
Honored Contributor
Thank you for your reply.
I want to count both clk rising and falling edges. - Altera_Forum
Honored Contributor
You can't do that in FPGA. Easiest way to do that would be with a 2x clock
- Altera_Forum
Honored Contributor
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? - Altera_Forum
Honored Contributor
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? - Altera_Forum
Honored Contributor
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.