7
\$\begingroup\$

I'm a new Verilog/HDL programmer, and I'm writing this post to get some feedback from more experienced programmers.

My very first task was to divide a clock by eight.

I know there are some better methods to do this, but as I'm new to HDL, this is my first, naive attempt:

module prescaleMainCLK(CLK, prescaledCLK);
 input CLK;
 output reg prescaledCLK;
 
 // ''Define'' a 4bit counter, max value: 15
 reg [3:0] counter;
 
 initial begin
 // Initialise both variables
 prescaledCLK <= 0;
 counter <= 0;
 end
 
 always @ (posedge CLK) begin
 
 // Did the counter reach its end?
 if (counter > 7) begin
 
 // Reset the counter
 counter <= 0;
 
 // Toggle the prescaled clock output
 prescaledCLK <= ~prescaledCLK;
 
 end else begin
 
 // Increment counter
 counter <= counter + 1;
 
 end
 
 end
 
endmodule

The Simulation output (EDAPlayground) is as I expect it to be:

enter image description here

Now I want to know if that code is suitable for real applications or if there are some things I need to reconsider.

toolic
14.6k5 gold badges29 silver badges204 bronze badges
asked Feb 26, 2016 at 0:23
\$\endgroup\$
0

3 Answers 3

6
\$\begingroup\$

I would recommend using a modern Verilog header:

module prescaleMainCLK(
 input CLK,
 output reg prescaledCLK
);

Adding bit size to your constants is best practice. 'b0 for all zeros with auto sizing. 0 is an integer likely only 32 bits long which can get you in trouble if you start applying to regs bigger than than 32 bits.

The use of initial is only valid in FPGA synthesis; for ASIC you should use a active-low async reset.

reg [3:0] counter;
initial begin
 // Initialise both variables
 counter <= 'b0;
end
always @ (posedge CLK) begin
 counter <= counter + 1'd1;
end

Versus for ASIC:

always @ (posedge CLK or negedge rst_n) begin
 if(~rst_n) begin
 counter <= 'd0;
 end
 else begin
 counter <= counter + 1'd1;
 end
end

You can reuse the counter bits (as mentioned in another answer) for your slower clocks

wire clk_div2 = counter[0];
wire clk_div4 = counter[1];
wire clk_div8 = counter[2];
wire clk_div16 = counter[3];

At faster frequencies this often becomes tricky to balance clocks correctly. A standard industry practice would be to use enables (derived from this counter) for a clock gate. The clock gate allows a pulse from the faster clock through, you lose the 50 50 duty cycle of the clock but balancing the clock tress becomes much easier.

toolic
14.6k5 gold badges29 silver badges204 bronze badges
answered Feb 26, 2016 at 9:51
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Regarding using the more modern verilog header, why do you recommend me using the more modern one? I think the ''old'' one looks more clean. What are the advantages? \$\endgroup\$ Commented Feb 27, 2016 at 23:57
  • 2
    \$\begingroup\$ The new style does not force you to replicate port names multiple times. having to write the same thing multiple times costs time for code maintenance and is source of compilation errors. \$\endgroup\$ Commented Feb 28, 2016 at 10:41
3
\$\begingroup\$

I'm no Verilog expert. However, it's clear that if you just keep adding 1 to a 4-bit counter and letting it wrap around, then prescaledCLK would just be the most significant bit of counter. You should be able to eliminate the conditional, I think.

answered Feb 26, 2016 at 3:40
\$\endgroup\$
1
  • \$\begingroup\$ Thats what I had in mind too \$\endgroup\$ Commented Feb 26, 2016 at 7:28
2
\$\begingroup\$

Overview

The previous answers make a lot of good points which I will try not to reiterate.

There are many good aspects of your code, from a style point of view:

  • The indentation is clear and consistent
  • You adhered to the good Verilog coding practice of using nonblocking assignments for sequential logic
  • You gave meaningful names to the module and the signals

Off-by-1

You stated that the design is a divide-by-8 circuit. However, when I run a simulation, it looks like it divides the input clock by 9. The input clock is 9 times faster than the output clock (prescaledCLK). This is easy to see if you view the counter signal in the waveform viewer. You will see counter range from 0 to 8, which is 9 states.

Also, looking at your waveform image, you can count 9 CLK pulses while the output clock is high.

A minimal change to this line:

if (counter > 7) begin

would generate a divide-by-8 output:

if (counter == 7) begin

Comments

Most of the comments in the code are not needed because they merely state what is obvious from your code. For example:

// Increment counter
counter <= counter + 1;

It is customary to add a block comment to the top of the code to summarize its purpose.

SystemVerilog

Consider using always_ff instead of always. This syntax requires you to enable SystemVerilog features in your simulator, if they are not already enabled by default. The advantage is that it better conveys the design intent and it provides some built-in checks.

Parameter

You could parameterize the design to make it more reusable. Specifically, the counter bit width could be scalable to have any power of 2 divide ratio (2, 4, 8, etc.). Here is example code that applies some of the previous suggestions, as well as leverages from the other answers:

/*
Clock divider
The WIDTH parameter sets the divide ratio.
*/
module prescaleMainCLK 
 #(parameter WIDTH = 4)
(
 input reset,
 input CLK,
 output prescaledCLK
);
 reg [WIDTH-1:0] counter;
 assign prescaledCLK = counter[WIDTH-1];
 always @(posedge CLK or posedge reset) begin
 if (reset) begin
 counter <= 0;
 end else begin
 counter <= counter + 1;
 end
 end
endmodule

By default, this is a 4-bit counter, which yields a divide-by-8 output.

The following would instantiate a divide-by-16 circuit:

prescaleMainCLK 
 #(.WIDTH(5))
 div16
(
 .reset (reset),
 .CLK (CLK),
 .prescaledCLK (prescaledCLK)
);
answered Jun 17 at 11:13
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.