2
\$\begingroup\$

I'm trying to understand how non-blocking statements interact with certain procedural statements in Verilog.

If I have the following block of code inside a module

input clk;
.
.
.
parameter divider = 12;
reg [3:0] clk_counter = 0;
.
.
.
always @(posedge clk)
begin
    clk_counter <= clk_counter + 1;
    if(clk_counter == divider)
       clk_counter <= 0;
end

I understand that hardware description languages are not like procedural languages, and therefore it is a good idea to get out of the habit of thinking about them as if they were, but atm I am just trying to wrap my head around some of Verilog's behavioral constructs to make programming in it easier. With that said, here's my question

Will Verilog evaluate the right side of clk_counter <= clk_counter + 1; and then enter the if(clk_counter == divider) loop and use clk_counter's old original value (i.e., not clk_counter + 1) to evaluate the conditional statement?

Edit: My extraordinarily underdeveloped understanding of Verilog is showing. As was pointed out, the compiler isn't going to actually evaluate the conditional. I am aware of this. What I meant in asking my question was: can I assume that Verilog will build a circuit that will behaviorally mimic what we would consider to be an evaluation of the righthand side of clk_counter <= clk_counter + 1; and use ```clk_counter``'s old value (i.e., that stored in the flip flop) when evaluating the conditional. I am not experienced enough with the language to imagine what this circuit might look like because I am still working out in my mind how Verilog's behavioral constructs interact with each other.

\$\endgroup\$
2
  • \$\begingroup\$ It will never equal the parameter divider. 4 bits isn't enough to represent the number 123. \$\endgroup\$
    – IanJ
    Feb 11, 2021 at 2:03
  • \$\begingroup\$ @IanJ Sorry, yes, ignore that, I should've been a little more discerning when writing out this code, I just wanted a simple example. You can assume that branch would eventually serve a purpose. \$\endgroup\$
    – Harry
    Feb 11, 2021 at 3:26

3 Answers 3

1
\$\begingroup\$

Yes, you are right. It will use the old value when evaluating the conditional. All the statements are evaluated in order, but none of the assignment take place until after the clock "ticks". So the last assignment will "win" if there are multiple assignments to the same register.

\$\endgroup\$
1
\$\begingroup\$

Your reasoning is correct. Non-blocking statements in Verilog work in the following fashion:

The expressions on the right-hand side get evaluated sequentially but they do not get assigned immediately. The assignment takes place at the end of the time step. In your example, clk_counter + 1 is evaluated but not assigned to clk_counter right away. The value of clk_counter before entering the block is used for evaluating all the expressions (assuming only non-blocking statements).

Why does Verilog do this? To prevent ambiguity.

Consider a case in which the same variable is being updated in 2 different procedural blocks using blocking assignments. Both the blocks start at the same time. Which assignment takes place first? This is crucial because the expressions following this will use this value. It'd probably be up to the simulator to decide which expression to assign first. In case of non-blocking assignments, all the expressions are evaluated in parallel without any ambiguity since all the assignments take place at the end of the time step.

As for the circuit, you can think of clk_counter and divider being fed to a comparator whose output will act as a select signal to a multiplexer which chooses the data value to be fed to the clk_counter register.

\$\endgroup\$
0
\$\begingroup\$

Harry,

As others have said clk_counter will be updated at the rising edge of the clock.

In your example code, you have created a 13-state counter (0 through 12).

When you synthesize code, blocking and non-blocking yield the same circuitry (in a sequential block). But, in simulation, they behave differently.

Your example, in simulation, if blocking assignments are used for clk_counter, it would end up being a 12-state counter. (When clk_counter is 11 entering the main body, it would get incremented to 12, then immediately set to 0.

Generally it is recommended to only use non-blocking assignments in sequential blocks. (so that synthesized and simulated behavior are consistent).

An alternative way to write the meat of your loop is below. This eliminates any ambiguity as to which assignment takes precedence since there is no perceived conflict.

if (clk_counter >= divider) clk_counter <= 0;
else                        clk_counter <= clk_counter + 1;
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.