Variable clock divider - Page 1
Forum section: electronics / general

author: kpow8050
author_rank: Regular Contributor
timestamp: January 15, 2022, 01:34:49 am
content: Hi,I am having trouble getting the following verilog HDL code to compile. My intent is to make a variable frequency divider. The way it works is you give it a divider number and and clock source, using an internal counter it will then count up until this value matches the divider number and change state of the output clock. The counter is then reset. However the compiler is not happy with my assignment of "assign count = count + 1;". Is this not allowed in HDL? How could I keep track of the count? Thanksmoduleclock_divider(input wire[12:0] divider,inputclk,output regclk_out);// This module will divide an input clock signal by the amount in divider (16 bit register)// For finer control of clock divisions change the divider register size// Internal counter memoryreg[12:0] count;always@(posedgeclk)if(count >= divider)beginclk_out <= ~clk_out;count = 0;endassigncount = count + 1;endmodule

author: ataradov
author_rank: Super Contributor
timestamp: January 15, 2022, 01:42:46 am
content: It would be something like this:Code:always @(posedge clk) beginif (count >= divider) beginclk_out <= ~clk_out;count <= 0;end elsecount <= count + 1;end

author: fourfathom
author_rank: Super Contributor
timestamp: January 15, 2022, 01:43:11 am
content: How about this:always @(posedge clk) beginif (count >= divider) beginclk_out <= ~clk_out;count <= 0;endelse count <= count + 1;endOr like this:always @(posedge clk) begincount <= count + 1;if (count >= divider) beginclk_out <= ~clk_out;count <= 0;endend

author: BrianHG
author_rank: Super Contributor
timestamp: January 15, 2022, 01:48:35 am
content: Quote from: fourfathom on January 15, 2022, 01:43:11 amSome compilers and simulators will allow you to get away with simultaneously assigning 2 different results to 'count', but this is considered bad practice. Your first solution and ataradov did it the right way with the 'else'.

author: ataradov
author_rank: Super Contributor
timestamp: January 15, 2022, 01:53:44 am
content: I think all tools should accept this. The last assignment wins.In this case 'else' is better for clarity, but the 'default' value is often necessary in big state machines with a lot of cases and conditions inside them. I use that all the time and never seen any tool complain.This is a very common practice when evaluating the next state, for example. In most cases you want to stay in the current state, and if you have to do the same assignment to the current state in all the blocks, you will go mad and likely miss something.

author: fourfathom
author_rank: Super Contributor
timestamp: January 15, 2022, 01:56:28 am
content: Quote from: BrianHG on January 15, 2022, 01:48:35 amThanks. I've seen it done, and probably have done it myself, but I usually do it the "correct" way. Now I will make a point of it. The shortcut method can save a few lines of code, but to me it feels unnecessarily obscure.[and then this shows up]Quote from: ataradov on January 15, 2022, 01:53:44 amYes, complicated state machines is where I've seen / used that form. Since I'm doing this for fun these days, perhaps I will remain flexible.

author: kpow8050
author_rank: Regular Contributor
timestamp: January 15, 2022, 02:48:17 am
content: Thanks guys. That has fixed the problem. Now I am faced with a new slightly unrelated problem. When I try to pass the divider to this module as a register [12:0] it is giving the following compile error"Error (10133): Verilog HDL Expression error at LaserControl.v(51): illegal part select of unpacked array "pixel_clk_divider_reg".I have been able to pass registers this way before, I'm confused as why it won't work in this instance. The relevant code is shown below// Pixel clock divider// This sets the pixel clock rate (how many pixels/per sec)regpixel_clk_divider_reg[12:0];wirepixel_clk_src;wirepixel_clk_out;clock_divider pixel_clk_divider ( .divider (pixel_clk_divider_reg[12:0]),.clk (pixel_clk_src),.clkout (pixel_clk_out));

author: BrianHG
author_rank: Super Contributor
timestamp: January 15, 2022, 03:05:06 am
content: Quote from: kpow8050 on January 15, 2022, 02:48:17 amreg[12:0]pixel_clk_divider_reg;What you did was make a 1 bit array reg 'pixel_clk_divider_reg' with 13 addresses.

author: asmi
author_rank: Super Contributor
timestamp: January 15, 2022, 03:31:59 am
content: Quote from: BrianHG on January 15, 2022, 01:48:35 amAnd those which won't, need to be thrown away because they are not compliant with the standard.Quote from: BrianHG on January 15, 2022, 01:48:35 amBy whom? Verilog specification explicitly defines how this should behave (last assignment wins) so it is fully compliant and supported. I myself use it all the time for "default" assignments to help avoid latches.

author: BrianHG
author_rank: Super Contributor
timestamp: January 15, 2022, 03:42:15 am
content: Not logically closing the bounds around your code can lead to uncleanly practices even if they are fully functional.

author: asmi
author_rank: Super Contributor
timestamp: January 15, 2022, 04:08:35 am
content: Quote from: BrianHG on January 15, 2022, 03:42:15 amI strongly disagree. Using default assignment massively improve code readability because there is less noise in the code, especially in larger modules. And since code is read MUCH more often than it's written, any effort to make code easier to read and understand will be well rewarded later on. This is especially so for HDL, because many people have noted (myself included) that it's harder to read and understand someone else's code than in conventional programming languages. I suspect it's because "normal" programming languages tend to operate using higher level abstractions that HDL, even SystemVerilog seriously lags behind in this department, not to mention older languages. That's why there are so many attempts to devise higher-level language which would "compile" into lower level HDL like Verilog, using Python, Java, whatever else.Also it leads to less code, and it's a well established by many studies fact that less code means less bugs.

author: BrianHG
author_rank: Super Contributor
timestamp: January 15, 2022, 05:02:44 am
content: That is a lack of coding design quality. The ''default'' should be evident, not something you rely on the compiler to fabricate for you. There should not be any addition of lines of code. It should not generate more signalling noise in your design.

author: kpow8050
author_rank: Regular Contributor
timestamp: January 15, 2022, 05:13:12 am
content: Quote from: BrianHG on January 15, 2022, 03:05:06 amThanks BrianHG. One more thing, when I have a register declared within a module, is that local in scope or global for the whole project? The desired behavior I want is for the registers I declare within a module (outside of the always @ section) to never overwrite each other say in instances where I instantiate the same module multiple times. Thanks

author: fourfathom
author_rank: Super Contributor
timestamp: January 15, 2022, 05:14:24 am
content: Quote from: BrianHG on January 15, 2022, 05:02:44 amI don't think the issue at hand has anything to do with "something the complier fabricates for you". In either case the default is clearly defined -- through the use of "else" in one case, and through the "last assignment" rule in the other. In its favor, the "last assignment" lets you avoid having multiple "else"s scattered throughout a complicated state machine or similar code.

author: fourfathom
author_rank: Super Contributor
timestamp: January 15, 2022, 05:16:45 am
content: Quote from: kpow8050 on January 15, 2022, 05:13:12 amIt's local. You can instantiate multiple instances of a module, or have many different modules using a register with a common name (such as your "reg [12:0] count;"), and there will be no conflict.

author: kpow8050
author_rank: Regular Contributor
timestamp: January 15, 2022, 05:21:11 am
content: Great, that's working how I expected.

author: asmi
author_rank: Super Contributor
timestamp: January 15, 2022, 05:34:07 am
content: Quote from: BrianHG on January 15, 2022, 05:02:44 amYou got this backwards. Defaults are always super-evident because they are always on top of the state machine. If not using them, you will have to hunt though all states and state transitions to figure out what the value is supposed to be. And the larger and more complex state machine is, the harger it will be to understand what the code is doing what the state of each variable is supposed to be.Lack of coding quality is repeating the same statement over and over again in all branches and states.

author: kpow8050
author_rank: Regular Contributor
timestamp: January 15, 2022, 05:54:35 am
content: I have decided to add a reset function to the variable clock divider, however i am unsure of the best way to implement it. The way I am thinking is to have it reset on the falling edge of the clock, since the rising edge is already being used to set the state of the output, if I can use the falling edge to reset the output if reset is high then I can do it synchronously. I have added another always section to the code as shown below, however it won't compile. The error"Error (10170): Verilog HDL syntax error at clock_divider.v(20) near text "endmodule"; expecting ";"". Is it not possible to have more than one always in a module? How should I write this? Sorry for all the questionsCode:// This module will divide an input clock signal by the amount in divider (16 bit register)// For finer control of clock divisions change the divider register size// Internal counter memoryreg [12:0] count;always @(posedge clk)if (count >= divider) beginclk_out <= ~clk_out;count = 0;end elsecount <= count + 1;always @(negedge clk)if (reset)clk_out <= 0;elseendmodule

author: ataradov
author_rank: Super Contributor
timestamp: January 15, 2022, 06:06:52 am
content: You are missing the statement after 'else'. But also, you can't assign the same register from two different always blocks.Code:always @(posedge clk) beginif (reset)clk_out <= 0;else if (count >= divider) beginclk_out <= ~clk_out;count <= 0;end elsecount <= count + 1;endAlso, pay attention to "<=" and "=". They are not the same and mean entirely different thing.

author: asmi
author_rank: Super Contributor
timestamp: January 15, 2022, 06:39:14 am
content: It's also a bad idea to use both edges in FPGA designs, as it effectively halves allowed combinatorial delays. Don't do that.

author: ataradov
author_rank: Super Contributor
timestamp: January 15, 2022, 06:50:52 am
content: Oh, yes, I "automatically" missed negedge. This is something you should not do for sure.

author: kpow8050
author_rank: Regular Contributor
timestamp: January 15, 2022, 07:12:19 am
content: Quote from: asmi on January 15, 2022, 06:39:14 amAhh, I see. I will make sure not to do that in future designs. Was thinking it would save an extra clock pulse. But I guess if timing is that critical I can just up the clock frequency

author: Bassman59
author_rank: Super Contributor
timestamp: January 15, 2022, 04:06:59 pm
content: Quote from: asmi on January 15, 2022, 05:34:07 amAsmi is exactly right here. The idea that you set a default assignment at the top of a process and then override it below (like in a state machine) is well understood and is actually (in my humble opinion) less prone to errors of the sort of "I need to set the signal in state X and then clear it in the next state ... what if I add another state in between?" (Yes, yes, yes, you are supposed to re-run your verification after making this change.) And yes, this applies to both VHDL and Verilog.I like to use the term "one-shot" for this sort of thing.What's cool is that you can implement a state-duration timer with this kind of construct. Rather than having a decrementing counter in each state, have the counter outside of the machine decoder, decrementing to zero when it stops. Assign the "duration" value to the timer in one state, and in the next state, wait for that timer to go to zero before continuing. Something like this. Here, we'll strobe enable for one clock, and then wait for some number of clocks before continuing.Code:MyTimedStates : process (clk) isbeginif rising_edge(clk) thenstrobe <= '0'; -- clear previously-set one-shot strobeDurationTimer : if timer > 0timer <= timer - 1;end if DurationTimer;MyDecoder : case (foostate) iswhen S_FOO =>strobe <= '1'; -- strobe for one clock-- start the timer. Use a signal instead of constant and you-- have a run-time variable timer.timer <= 100;foostate <= S_BAR;when S_BAR =>-- Wait for timer to expire, then we can strobe again.WaitForDuration : if timer = 0 thenstrobe <= '1';timer <= 200; -- wait longer this time.foostate <= S_BLETCH;end if WaitForDuration;when S_BLETCH =>WaitAgain : if timer = 0 then-- we're done, go to beginningfoostate <= S_FOO;end if WaitAgain;end case MyDecoder;end if;end process MyTimedStates;This makes a whole lot more sense than having a decrementing counter in each state for the timing.