LRM interpretation. Precedence of unary '~' over '==' (or no

C

Charles Gardiner

Guest
Hi,

first a brief description of what I am trying to do in verilog (I have to convert
one of my VHDL solutions for a customer who only has a verilgo tool suite):

In my logic I have a reset counter which has the function of extending the reset
pulse for sixteen clocks after the reset is deactivated. Since I like to reset
everything to zero, my solution is that the counter counts up. On reaching the
maximum value the reset should be deactivated. Since I have this construct in
different places, and different counters might have different widths, I don't want
to always have to check that my vector width for counter max comparison is
correct. So, to stop the counter, I compare the inverted counter with zero. My
verilog code for the extended reset is:


reg s_hot_reset;
reg [3:0] s_hot_reset_count;

214 always @(posedge i_clk_125 or negedge i_rst_n) begin
215 if (i_rst_n == 1'b0) begin
. . .
220 s_hot_reset <= 1'b0;
221 s_hot_reset_count <= 'b0;
222 end
223 else begin
. . .
228 s_hot_reset <= (~s_hot_reset_count == 'b0) ? 1'b0 : 1'b1;
229
230 if ((s_dl_up_d2_prev == 1'b1) && (s_dl_up_d2 == 1'b0))
231 // A falling dl_up edge activates hot reset
232 s_hot_reset_count <= 'b0;
233 else
234 if (~s_hot_reset_count != 'b0)
235 s_hot_reset_count <= s_hot_reset_count + 1;
236 end
237 end


Now the fun starts:
My own simulator works the way I expect this to work, i.e. for instance in line
228, s_hot_reset is set to 1'b0 when the counter has reached it's max. value
(inverted counter compared with a vector having all bits set to '0')

On my customer's simulator, line 228 never gets set to 1'b0 and line 234 never
goes true. I am currently having a heated (email) discussion with the support for
my customer's simulator. He has been chucking quotes from LRM-2005 section 2.5 at
me explaining why he thinks he is doing it correctly. My objection that the unary
operator '~' must be evaluated completely first (i.e. before comparison and the
operand expansion induced by the '==' operator) is falling on deaf ears.

Essentially he is explaining to me that for instance in line 228, when the counter
has reached 4'b1111, it is forcebly extended to 32'h0000000F (due to the operator
expansion rules in 5.4) then inverted (to 32'hFFFFFFF0) and then compared to
32'h0, which of course indeed is never true.


So may I ask what the experts here think? Should operator expansion (induced by
the '==' or '!=' operator) have precedence over the unary '~' operator or not. If
so, what exactly is then the meaning of operator precedence in Verilog. Why for
instance should
if (~s_hot_reset_count != 'b0)
simulate differently to
assign s_hot_reset_count_bar = ~s_hot_reset_count;
if (s_hot_reset_count_bar != 'b0)

(This is so much easier in VHDL. Comparing two unequal length vectors is always
false. Full stop. To match the lengths you have nice helpers like 'length, resize
etc. etc. Yes, it might be verbose but tool manufacturers from A to Z (and
therefore users as well) know there is only one way to do it correctly.)
 
Chris Briggs schrieb:
I forget the subtleties of Verilog's expression sizing rules. You can
probably search this ng and get a good description. However, I think
the other guy has a point because you used an unsized constant ('b0),
which gets treated as being (at least) 32 bits wide.
Yes I see the point with the unsized operand. But my question is basically what is
the unsized operand here (from the view of the LRM)

1) s_hot_reset_count i.e. resizing (induced by the '==' operator) before the unary '~'

or 2)
a temporary internally undeclared operand made by inverting s_hot_reset_count and
having the same length as s_hot_reset_count (4 bits). i.e. operator precedence of
'~' before '=='

Surely the LRM must have a rule on this. I do have the 2005 version myself and
read it that 2) is correct. For instance in 5.1.4 I see
"The operators shall follow the associativity rules while evaluating an expression
as described in 5.1.2" and 5.1.2 is essentially the table of operator precedences
with '~' very definitely as having higher precedence than '=='.

Two simulators with two results cannot be the intention of the LRM.

I think the simple solution is to make the constant the same width as
your counter:
if (~s_hot_reset_count != 4'b0)
That is indeed what I am doing as a workaround, but this means I always have to
watch for correct vector lengths in comparisons. I wanted my solution here to be
self-adjusting. i.e. if for some reason I have to change the counter width to
seven bits, I only need to change the declaration.
 
On Thu, 22 Apr 2010 20:26:26 +0200, Charles Gardiner wrote:

Yes I see the point with the unsized operand. But my question is basically what is
the unsized operand here (from the view of the LRM)
You wrote something like...

reg [3:0] count;
...
if (~count == 'b0) ...

'b0 isn't "unsized", it's the size of integer - which is at least
32 bits (although its exact size is not defined by the LRM).

So the semantics of this expression go like this...

(1)
Determine the context width. It's the widest of any operand.
Clearly, then, it's the width of integer. Let's say 32 bits for the
sake of the discussion; that will be right for most simulators.

(2)
Widen all operands to the context width. So the
expression now becomes, in effect,

~({28'b0, count}) == 32'b0

(3)
Perform the arithmetic operations. Surprise, it's false.

Surely the LRM must have a rule on this.
Yes.

Two simulators with two results cannot be the intention of the LRM.
No; one of them is wrong.

I think the simple solution is to make the constant the same width as
your counter:
if (~s_hot_reset_count != 4'b0)


That is indeed what I am doing as a workaround, but this means I always have to
watch for correct vector lengths in comparisons. I wanted my solution here to be
self-adjusting. i.e. if for some reason I have to change the counter width to
seven bits, I only need to change the declaration.
As someone else said, using reduction-AND is handy in
this particular situation. Generally, though, it's better
to be very, very careful.

Please don't complain too much about the problems when you
change the size of the counter. Wouldn't this have been better?

parameter counter_width = 4;
...
reg [counter_width-1:0] count;
...
if (count == {counter_width{1'b1}}) ...

--
Jonathan Bromley
 
I forget the subtleties of Verilog's expression sizing rules. You can
probably search this ng and get a good description. However, I think
the other guy has a point because you used an unsized constant ('b0),
which gets treated as being (at least) 32 bits wide.

I think the simple solution is to make the constant the same width as
your counter:
if (~s_hot_reset_count != 4'b0)

And in general avoid unsized constants. SystemVerilog has auto-sized
constants for all-0s and all-1s, specified with '0 and '1
respectively, that could help you here if your (and their) tools
support SV.

-cb
 
On Apr 22, 10:37 am, Charles Gardiner
<charles.gardi...@invalid.invalid> wrote:
Hi,

first a brief description of what I am trying to do in verilog (I have to convert
one of my VHDL solutions for a customer who only has a verilgo tool suite):

In my logic I have a reset counter which has the function of extending the reset
pulse for sixteen clocks after the reset is deactivated. Since I like to reset
everything to zero, my solution is that the counter counts up. On reaching the
maximum value the reset should be deactivated. Since I have this construct in
different places, and different counters might have different widths, I don't want
to always have to check that my vector width for counter max comparison is
correct. So, to stop the counter, I compare the inverted counter with zero. My
verilog code for the extended reset is:

   reg         s_hot_reset;
   reg [3:0]   s_hot_reset_count;

   214     always @(posedge i_clk_125 or negedge i_rst_n) begin
   215        if (i_rst_n == 1'b0) begin
   . . .
   220           s_hot_reset          <= 1'b0;
   221           s_hot_reset_count    <= 'b0;
   222        end
   223        else begin
   . . .
   228           s_hot_reset <= (~s_hot_reset_count == 'b0) ? 1'b0 : 1'b1;
   229
   230           if ((s_dl_up_d2_prev == 1'b1) && (s_dl_up_d2 == 1'b0))
   231                 // A falling dl_up edge activates hot reset
   232              s_hot_reset_count <= 'b0;
   233           else
   234              if (~s_hot_reset_count != 'b0)
   235                 s_hot_reset_count <= s_hot_reset_count + 1;
   236        end
   237     end

Now the fun starts:
My own simulator works the way I expect this to work, i.e. for instance in line
228, s_hot_reset is set to 1'b0 when the counter has reached it's max. value
(inverted counter compared with a vector having all bits set to '0')

On my customer's simulator, line 228 never gets set to 1'b0 and line 234 never
goes true. I am currently having a heated (email) discussion with the support for
my customer's simulator. He has been chucking quotes from LRM-2005 section 2.5 at
me explaining why he thinks he is doing it correctly. My objection that the unary
operator '~' must be evaluated completely first (i.e. before comparison and the
operand expansion induced by the '==' operator) is falling on deaf ears.

Essentially he is explaining to me that for instance in line 228, when the counter
has reached 4'b1111, it is forcebly extended to 32'h0000000F (due to the operator
expansion rules in 5.4) then inverted (to 32'hFFFFFFF0) and then compared to
32'h0, which of course indeed is never true.

So may I ask what the experts here think? Should operator expansion (induced by
the '==' or '!=' operator) have precedence over the unary '~' operator or not. If
so, what exactly is then the meaning of operator precedence in Verilog. Why for
instance should
             if (~s_hot_reset_count != 'b0)
simulate differently to
             assign s_hot_reset_count_bar = ~s_hot_reset_count;
             if (s_hot_reset_count_bar != 'b0)

(This is so much easier in VHDL. Comparing two unequal length vectors is always
false. Full stop. To match the lengths you have nice helpers like 'length, resize
etc. etc. Yes, it might be verbose but tool manufacturers from A to Z (and
therefore users as well) know there is only one way to do it correctly.)
I have been bitten by similar issues in the past, you might want to
take a look
at the reduction operators to sidestep this issue:
s_hot_reset <= &s_hot_reset_count ? 1'b0 : 1'b1;
or
s_hot_reset <= ~&s_hot_reset_count;

John Providenza
 
Your customer's simulator is correct, and yours is incorrect.

Context-dependent operands are extended to the size of the
context before any operators are applied. It doesn't matter
that the other operand that caused the extension won't be
combined with this one until some later operator.

This is unusual for a programming language. Most of them
delay conversions as long as possible, until just before the
operator that had the mismatching operands. Verilog does
them as early as possible instead, apparently in an attempt
to avoid overflowing intermediate values.

There are a variety of ways to solve your problem. You could
do a reduction-AND, which will only be true if all the bits
are 1 (and which has a self-determined operand).

You could compare to 1'b0 instead of 'b0 (which is effectively
32 bits). The 1-bit zero will get extended to your counter size,
and your counter won't get extended at all. Unlike the 4'b0
solution, it doesn't depend on knowing the counter size.

There are other more esoteric solutions. For example, you could
convert the value to signed and compare to a signed 0. The sign-
extension would make it extend to all-1, which would invert to 0.
Or skip the inversion and compare to -1.

You could shield the counter value from extension by using an
operator whose operands are not context-determined. For example,
a concatenation: {~count} != 'b0. This is obscure and hard for
the reader to follow though.
 
BTW, this is not related to operator precedence. Your suggestion
that it is was based on the assumption that conversions to make
operands match is an inherent part of the operator that combines
them. In Verilog, the conversions are separated from the operators
and done earlier. It does the conversion required by the == before
it does the ~ operation, but it does not do the == operation before
it does the ~ operation.
 

Welcome to EDABoard.com

Sponsor

Back
Top