- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Please can you re-post the code with some line feeds/carrige returns?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You should use
Always @(posedge in_clk) Using levels of in_clk will give you latch.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you for your reply.
I want to count both clk rising and falling edges.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You can't do that in FPGA. Easiest way to do that would be with a 2x clock
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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?- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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?- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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?- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- 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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- 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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- 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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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?- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you Tricky
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page