Today I encountered a very peculiar piece of test code, and everyone is stumped at why it operates the way it does. The simplified version of it would look something like this (please pay attention to the fact that the test is written inside a task
):
task TEST();
logic [9:0] a;
assign a = 10'd512;
#10ns;
assign a = a/2;
#100ns;
endtask
My questions are:
-
The expectation was that
a
would continue to be divided by 2 every unit of delta time, until its value reaches0
. But instead, in simulation (using Xcelium), it is only divided once, and the end result isa = 256
. Why is that? A colleague confirmed with a small test thatassign
functions as normal in a task if the RHS does not contain the LHS variable. So I am guessing it has something to do with it essentially being an always@(…) block where the only variable in the sensitivity list is also the LHS variable, but I cannot find a description for what happens in that specific case anywhere. -
I was confused why the code compiles successfully and even without any warnings while having 2
assign
statements for the same variable. While searching for an answer, I found Section 10.6.1 of LRM version 1800-2017 says:
If the keyword assign is applied to a variable for which there is already a procedural continuous
assignment, then this new procedural continuous assignment shall deassign the variable before making the new procedural continuous assignment.
And now I am even more confused, why does the LRM say this, if having two assign
statements for the same variable would generally cause compilation (multiple driver) errors in a module, instead of keeping the last assign
statement and disregarding the others?
DeFalco is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
You are confusing, structural continuous assignments with procedural continuous assignments. This is common since both constructs use the same assign
keyword.
You can have multiple continuous assignments (drivers) on a net, but only one continuous assignment to a variable.
A procedural continuous assignment overrides all procedural assignments to a variable, and replaces any previous procedural continuous assignment to that variable.
Procedural continuous assignments were originally intended to model asynchronous behavior in a separate process from the synchronous behavior of a flip-flop. However, most synthesis tools have chosen to restrict the modeling of a flip-flop to a single (always
) process. This construct is rarely used now.
2