Discussion:
Implicit Zero Padding?
(too old to reply)
Gary Spivey
2006-10-25 02:18:33 UTC
Permalink
It was my understanding that Verilog would zero pad when assigning a smaller
number to a larger one.
In the following module:

module tilde (output reg[7:0] z, input [3:0] a);
always @* begin
z = ~a;
end
endmodule

I would have expected the upper four bits of z to always be 0. I assumed
that the four bits of a would be inverted, and then the resulting number
would be zero-padded and assigned to z.

However, in ModelSim at least, the upper four bits of z are always 1 -
regardless of the value of a. Can somebody explain this behavior to me? It
appears that either I or ModelSim are mistaken (and I am not taking odds on
which one).

-Gary
John_H
2006-10-25 04:44:03 UTC
Permalink
Post by Gary Spivey
It was my understanding that Verilog would zero pad when assigning a smaller
number to a larger one.
module tilde (output reg[7:0] z, input [3:0] a);
z = ~a;
end
endmodule
I would have expected the upper four bits of z to always be 0. I assumed
that the four bits of a would be inverted, and then the resulting number
would be zero-padded and assigned to z.
However, in ModelSim at least, the upper four bits of z are always 1 -
regardless of the value of a. Can somebody explain this behavior to me? It
appears that either I or ModelSim are mistaken (and I am not taking odds on
which one).
-Gary
I also felt this was odd behavior when I first encountered it. I was
told at the time that the Verilog standard requires the value first be
width extended {0,a} and *then* gets the invert applied {-1,~a}. The
simple workaround is to use explicit extension e.g. {0,~a}. (Feel free
to explicitly define your 0 width)

Anyone care to chime in?
Gary Spivey
2006-10-25 05:02:45 UTC
Permalink
John,

Thanks for the response - what I don't understand is what the Verilog rules
could be? It would seem that all expressions on the RHS would have to be
evaluated BEFORE being expanded and assigned to the LHS? I haven't checked
it out, but what would a reduction operator do? If I had a= 4'b1111 and said
z= &a;
would it zero-pad a to 8 bits and then set z to 0 via the reduction? It
would seem to me that it should have to do the reduction first, and then set
z to 1. - AND, I just checked it in ModelSim and this IS what happens. So,
why does the reduction operator get evaluated BEFORE the zero-pad, but the ~
operator gets evaluated AFTER the zero-pad. They are BOTH unary operators.

-Gary
Post by Gary Spivey
It was my understanding that Verilog would zero pad when assigning a
smaller number to a larger one.
module tilde (output reg[7:0] z, input [3:0] a);
z = ~a;
end
endmodule
I would have expected the upper four bits of z to always be 0. I assumed
that the four bits of a would be inverted, and then the resulting number
would be zero-padded and assigned to z.
However, in ModelSim at least, the upper four bits of z are always 1 -
regardless of the value of a. Can somebody explain this behavior to me?
It appears that either I or ModelSim are mistaken (and I am not taking
odds on which one).
-Gary
I also felt this was odd behavior when I first encountered it. I was told
at the time that the Verilog standard requires the value first be width
extended {0,a} and *then* gets the invert applied {-1,~a}. The simple
workaround is to use explicit extension e.g. {0,~a}. (Feel free to
explicitly define your 0 width)
Anyone care to chime in?
John Penton
2006-10-25 08:55:48 UTC
Permalink
Post by Gary Spivey
Thanks for the response - what I don't understand is what the Verilog
rules could be? It would seem that all expressions on the RHS would
have to be evaluated BEFORE being expanded and assigned to the LHS? I
haven't checked it out, but what would a reduction operator do? If I
had a= 4'b1111 and said z= &a;
would it zero-pad a to 8 bits and then set z to 0 via the reduction?
It would seem to me that it should have to do the reduction first,
and then set z to 1. - AND, I just checked it in ModelSim and this IS
what happens. So, why does the reduction operator get evaluated
BEFORE the zero-pad, but the ~ operator gets evaluated AFTER the
zero-pad. They are BOTH unary operators.
However, the LHS of the ~ operator is 8-bits, therefore the RHS should be
8-bits too (it is a bitwise operator). The LHS of the & reduction operator
is always 1 bit, so the RHS can be anything (since it is a reduction
operator).

All in all, this confusion is a good example of why you should always write
exactly what you mean in verilog. Don't rely on extension or concatination,
or precedence for that matter.

John
--
John Penton, posting as an individual unless specifically indicated
otherwise.
s***@cadence.com
2006-10-25 18:10:37 UTC
Permalink
Post by Gary Spivey
what I don't understand is what the Verilog rules
could be?
They are fairly complex. They generally give you "natural" results, so
you don't have to think about them in most situations. For example, in
your original code, z just gets a wider version of ~a. It is only
because you tried to figure out exactly what the details were that it
seemed strange to you. But when you do need to understand the exact
details, it gets complicated.
Post by Gary Spivey
It would seem that all expressions on the RHS would have to be
evaluated BEFORE being expanded and assigned to the LHS?
Verilog first determines the width of an expression based on the
largest operand in it, including the LHS of any assignment. Then it
extends all operands (actually, all context-determined operands) to the
width of their expression before performing any operations. All
extensions are done as early as possible, in an attempt to avoid
overflows in intermediate results.

For example, if you multiply two 16-bit values together and assign the
result to a 32-bit variable, it will extend the two factors to 32 bits
before the multiply. This gives the equivalent of a full 16x16=32bit
multiply. If it didn't do this, you would just get a 16-bit result
extended to 32 bits, which is not what you want.
Post by Gary Spivey
I haven't checked
it out, but what would a reduction operator do? If I had a= 4'b1111 and said
z= &a;
would it zero-pad a to 8 bits and then set z to 0 via the reduction?
Operands of some operators are specified to be context-determined, and
others to be self-determined. Context-determined operands get their
width from the expression around them. Self-determined operands of an
operator are independent of the expression around them, and compute
their width only based on things in that operand sub-expression.

Which operands are specified to work each way makes a fair amount of
sense. If you are going to AND together two vectors, they need to be
the same width because they are going to be combined in a bitwise
fashion. But if you are shifting one number by another number, there
is no reason that the shift count needs to be the same width as the
value being shifted. Their bits do not directly combine. So a shift
count is a self-determined operand.

When the result of an operation will have a fixed width regardless of
the width of its operand, there is no reason for the operand to care
about the width of the context. This is true of the reduction
operators. The result will always be 1 bit, no matter what the operand
width is. There is no point in extending the operand. Instead, the
1-bit result will be extended to the width of the expression as soon as
it is produced. The operand of a reduction operator is
self-determined.

On the other hand, all the bits of a bitwise NOT will be available to
the expression containing it, and may be assigned or used in another
bitwise operation. So the operand of a bitwise NOT is
context-determined.

It
Post by Gary Spivey
would seem to me that it should have to do the reduction first, and then set
z to 1. - AND, I just checked it in ModelSim and this IS what happens. So,
why does the reduction operator get evaluated BEFORE the zero-pad, but the ~
operator gets evaluated AFTER the zero-pad. They are BOTH unary operators.
But one has a self-determined operand and the other has a
context-determined operand. The Verilog LRM fully specifies this for
all the operands of all the operators. They generally follow a logical
scheme that makes sense. And again, in most cases they are designed to
give reasonable results, so that most users don't have to worry about
them.
Gary Spivey
2006-10-25 22:27:55 UTC
Permalink
Thank you ... that is what I was looking for. I did not expect the Verilog
LRM to be as sophisticated - I figured it would simply sign extend at the
end - more of a type conversion as in 'C'.

Thanks again.
Post by s***@cadence.com
Post by Gary Spivey
what I don't understand is what the Verilog rules
could be?
They are fairly complex. They generally give you "natural" results, so
you don't have to think about them in most situations. For example, in
your original code, z just gets a wider version of ~a. It is only
because you tried to figure out exactly what the details were that it
seemed strange to you. But when you do need to understand the exact
details, it gets complicated.
Post by Gary Spivey
It would seem that all expressions on the RHS would have to be
evaluated BEFORE being expanded and assigned to the LHS?
Verilog first determines the width of an expression based on the
largest operand in it, including the LHS of any assignment. Then it
extends all operands (actually, all context-determined operands) to the
width of their expression before performing any operations. All
extensions are done as early as possible, in an attempt to avoid
overflows in intermediate results.
For example, if you multiply two 16-bit values together and assign the
result to a 32-bit variable, it will extend the two factors to 32 bits
before the multiply. This gives the equivalent of a full 16x16=32bit
multiply. If it didn't do this, you would just get a 16-bit result
extended to 32 bits, which is not what you want.
Post by Gary Spivey
I haven't checked
it out, but what would a reduction operator do? If I had a= 4'b1111 and said
z= &a;
would it zero-pad a to 8 bits and then set z to 0 via the reduction?
Operands of some operators are specified to be context-determined, and
others to be self-determined. Context-determined operands get their
width from the expression around them. Self-determined operands of an
operator are independent of the expression around them, and compute
their width only based on things in that operand sub-expression.
Which operands are specified to work each way makes a fair amount of
sense. If you are going to AND together two vectors, they need to be
the same width because they are going to be combined in a bitwise
fashion. But if you are shifting one number by another number, there
is no reason that the shift count needs to be the same width as the
value being shifted. Their bits do not directly combine. So a shift
count is a self-determined operand.
When the result of an operation will have a fixed width regardless of
the width of its operand, there is no reason for the operand to care
about the width of the context. This is true of the reduction
operators. The result will always be 1 bit, no matter what the operand
width is. There is no point in extending the operand. Instead, the
1-bit result will be extended to the width of the expression as soon as
it is produced. The operand of a reduction operator is
self-determined.
On the other hand, all the bits of a bitwise NOT will be available to
the expression containing it, and may be assigned or used in another
bitwise operation. So the operand of a bitwise NOT is
context-determined.
It
Post by Gary Spivey
would seem to me that it should have to do the reduction first, and then set
z to 1. - AND, I just checked it in ModelSim and this IS what happens. So,
why does the reduction operator get evaluated BEFORE the zero-pad, but the ~
operator gets evaluated AFTER the zero-pad. They are BOTH unary operators.
But one has a self-determined operand and the other has a
context-determined operand. The Verilog LRM fully specifies this for
all the operands of all the operators. They generally follow a logical
scheme that makes sense. And again, in most cases they are designed to
give reasonable results, so that most users don't have to worry about
them.
Rob Dekker
2006-11-02 03:24:06 UTC
Permalink
Gary,

It you think the sizing rules are confusing or sophisticated , wait until you start using signed operands in expressions.

The sign rules (Verilog 2001 and SystemVerilog) are even more tricky, vague and often counter-intuitive.
Even the simulators did not always agree on these, and in some cases probably still do not.

John Penton gave the best advice : In Verilog, write exactly what you need, and do not rely on implicit
size-extentions or confusing implicit rules that might creap in.

Good luck !

Rob
Thank you ... that is what I was looking for. I did not expect the Verilog LRM to be as sophisticated - I figured it would simply
sign extend at the end - more of a type conversion as in 'C'.
Thanks again.
Post by s***@cadence.com
Post by Gary Spivey
what I don't understand is what the Verilog rules
could be?
They are fairly complex. They generally give you "natural" results, so
you don't have to think about them in most situations. For example, in
your original code, z just gets a wider version of ~a. It is only
because you tried to figure out exactly what the details were that it
seemed strange to you. But when you do need to understand the exact
details, it gets complicated.
Post by Gary Spivey
It would seem that all expressions on the RHS would have to be
evaluated BEFORE being expanded and assigned to the LHS?
Verilog first determines the width of an expression based on the
largest operand in it, including the LHS of any assignment. Then it
extends all operands (actually, all context-determined operands) to the
width of their expression before performing any operations. All
extensions are done as early as possible, in an attempt to avoid
overflows in intermediate results.
For example, if you multiply two 16-bit values together and assign the
result to a 32-bit variable, it will extend the two factors to 32 bits
before the multiply. This gives the equivalent of a full 16x16=32bit
multiply. If it didn't do this, you would just get a 16-bit result
extended to 32 bits, which is not what you want.
Post by Gary Spivey
I haven't checked
it out, but what would a reduction operator do? If I had a= 4'b1111 and said
z= &a;
would it zero-pad a to 8 bits and then set z to 0 via the reduction?
Operands of some operators are specified to be context-determined, and
others to be self-determined. Context-determined operands get their
width from the expression around them. Self-determined operands of an
operator are independent of the expression around them, and compute
their width only based on things in that operand sub-expression.
Which operands are specified to work each way makes a fair amount of
sense. If you are going to AND together two vectors, they need to be
the same width because they are going to be combined in a bitwise
fashion. But if you are shifting one number by another number, there
is no reason that the shift count needs to be the same width as the
value being shifted. Their bits do not directly combine. So a shift
count is a self-determined operand.
When the result of an operation will have a fixed width regardless of
the width of its operand, there is no reason for the operand to care
about the width of the context. This is true of the reduction
operators. The result will always be 1 bit, no matter what the operand
width is. There is no point in extending the operand. Instead, the
1-bit result will be extended to the width of the expression as soon as
it is produced. The operand of a reduction operator is
self-determined.
On the other hand, all the bits of a bitwise NOT will be available to
the expression containing it, and may be assigned or used in another
bitwise operation. So the operand of a bitwise NOT is
context-determined.
It
Post by Gary Spivey
would seem to me that it should have to do the reduction first, and then set
z to 1. - AND, I just checked it in ModelSim and this IS what happens. So,
why does the reduction operator get evaluated BEFORE the zero-pad, but the ~
operator gets evaluated AFTER the zero-pad. They are BOTH unary operators.
But one has a self-determined operand and the other has a
context-determined operand. The Verilog LRM fully specifies this for
all the operands of all the operators. They generally follow a logical
scheme that makes sense. And again, in most cases they are designed to
give reasonable results, so that most users don't have to worry about
them.
s***@cadence.com
2006-11-03 17:54:26 UTC
Permalink
Post by Rob Dekker
It you think the sizing rules are confusing or sophisticated , wait until you start using signed operands in expressions.
The sign rules (Verilog 2001 and SystemVerilog) are even more tricky, vague and often counter-intuitive.
Even the simulators did not always agree on these, and in some cases probably still do not.
They are not really that tricky, but they are very counter-intuitive to
anyone used to other languages. The LRM text is unclear enough that
implementors were able to twist it to make their own interpretations
that were more intuitive to them, instead of the simpler intended
meaning.

The problem with adding signed arithmetic to Verilog was that the most
important signed operation is the sign extension for implicit
conversions. Since Verilog does its size extensions as early as
possible and those other languages do theirs as late as possible, there
was no way to make Verilog signedness behave like those other
languages. Trying to do so would have made the behavior in corner
cases even more bizarre and difficult to specify.
Post by Rob Dekker
John Penton gave the best advice : In Verilog, write exactly what you need, and do not rely on implicit
size-extentions or confusing implicit rules that might creap in.
For signed arithmetic, the best thing to do is to avoid mixing signed
and unsigned operands. If you want signed arithmetic, make sure all of
the operands are signed. If any of them are unsigned, then everything
will be done unsigned (within the same context-determined expression,
that is).

v***@gmail.com
2006-10-25 05:09:30 UTC
Permalink
Hi Gary
Since the input "a" of width 4 is assigned to output z of width 8,
first the input "a" is made 8 bits by appending 4 zeros on left hand
side and then tilde (~) operation takes place.

This is true with VCS also.

-Vinayak
Post by Gary Spivey
It was my understanding that Verilog would zero pad when assigning a smaller
number to a larger one.
module tilde (output reg[7:0] z, input [3:0] a);
z = ~a;
end
endmodule
I would have expected the upper four bits of z to always be 0. I assumed
that the four bits of a would be inverted, and then the resulting number
would be zero-padded and assigned to z.
However, in ModelSim at least, the upper four bits of z are always 1 -
regardless of the value of a. Can somebody explain this behavior to me? It
appears that either I or ModelSim are mistaken (and I am not taking odds on
which one).
-Gary
Loading...