Use explicitly sized constants?

P

Paul Marciano

Guest
Hi.

Given:

reg [7:0] a;
reg [7:0] b;

is there any value in:

a <= 8'h12;
b <= b + 8'h12;

over:

a <= h12;
b <= b + h12;


I find myself writing 1'b1, 1'b0 and <size>'h0 a lot... and not knowing
what to write when I have a variable of a parameterized size.

It there any real value in being so explicit in unambiguous
expressions?

Thanks,
Paul.
 
Paul Marciano wrote:
Hi.

Given:

reg [7:0] a;
reg [7:0] b;

is there any value in:

a <= 8'h12;
b <= b + 8'h12;

over:

a <= h12;
b <= b + h12;

I find myself writing 1'b1, 1'b0 and <size>'h0 a lot... and not knowing
what to write when I have a variable of a parameterized size.

It there any real value in being so explicit in unambiguous
expressions?
FWIW, I always indicate the width of the constants.

Verilog allows you to assign to and operate on variables of different
sizes. Yes, it does have rules about truncation and word width
expansion, but I find it easier to be explicit about sizes ...
especially when the reg/variable is declared a couple hundred lines of
code above where you use it!

Look at it this way. If you've ever been bit by

reg [1:0] foo;

foo <= 2'b10;

if (foo == 2)
....

you'll be explicit about things, too ...

-a
 
I'm sorry, but am I missing something here? I can't see anything wrong
with the lines above.
 
arju...@gmail.com wrote:
I'm sorry, but am I missing something here? I can't see anything wrong
with the lines above.
Think it through.

reg [1:0] foo;

... do stuff ..
foo <= 2'b10;
if (foo == 2)
...
else
....

Put succinctly, 2'b10 is not equal to 2, so the if statement always
takes the false branch.

Ask yourself why.

-a
 
"Andy Peters" <Bassman59a@yahoo.com> wrote in message
news:1131991674.831186.139330@g43g2000cwa.googlegroups.com...
arju...@gmail.com wrote:
I'm sorry, but am I missing something here? I can't see anything wrong
with the lines above.

Think it through.

reg [1:0] foo;

... do stuff ..
foo <= 2'b10;
if (foo == 2)
...
else
....

Put succinctly, 2'b10 is not equal to 2, so the if statement always
takes the false branch.

Ask yourself why.

-a
2'b10 is not equal to 2 in the sense of "case equality" (===) but is in the
sense of "logical equality" (==).
Sign extension is not applied to unsigned values.
There might be a problem for (~2'b01==2), however.
 
John_H wrote:
"Andy Peters" <Bassman59a@yahoo.com> wrote in message
Put succinctly, 2'b10 is not equal to 2, so the if statement always
takes the false branch.

2'b10 is not equal to 2 in the sense of "case equality" (===) but is in the
sense of "logical equality" (==).
As there are no z or x values involved in Andy's example (or mine) I
don't see the difference. If I change my example to use ===, Modelsim
still shows my expected result.

Regards,
Paul.
 
The problem exhibited in the program has nothing to do with
sized/unsized (or even signed/unsigned) constants and everything to do
with non-blocking assigns.

foo <= 2'b10;
if (foo == 2)
At the point of the if statement the value of foo may (or may not be)
2, because the non-blocking assign does not take effect immediately.
foo does not change value to 2 until the "update event" happens.

You cannot depend on a non-blocking assignment affecting the value of
a variable (reg) until "some time" has passed. If you want the change
of the value and you want that change to affect later uses of the same
value in the same always block (and you intend the code to be
synthesizable), you want to use a blocking assign.

(In non-synthesizable code, you can put in a #delay, wait statement or
similar construct that causes time to pass, but that's a whole other
model. In synthesizable code, a single execution of an always block
should occur entirely within one instant of time, excluding the
delayed updates resulting from non-blocking assigns. And the dealys
updates due to non-blocking assigns should be pictured as happening at
the "appropriate" time after the always block is executed.)

Now, if you use a blocking assign, you need to be aware of their
semantics. Generally speaking blocking assigns are for combinatorial
logic and should only be used in "combinatorial" always blocks or in a
fashion hwere the effects of the blocking assign cannot escape the
always block (e.g. to "temporary" variables local to an always block).
There are exceptions to that rule if you are coding a latch, but that
doesn't look like your intent.

You might want to see one of the regular contributors (e.g. Cliff
Cumming's) numerous posting on the topic (blocking versus non-blocking
designs and #delays etc.)

------------------------------------------------------------------------

Now, to the respondent who suggested that some mysterious numeric
properties involving sign-extension may be involved, that may be true
sometimes, but it doesn't apply here. The code is using an unsigned
reg and an integer constant 2, which is guaranteed by the standard to
use at least 32 bits for its representation. The unsigned reg is thus
0 extended to the smae length (i.e. at least 32 bits) and that matches
the value of 2. Now, if one is using "2" in a place where width
matters, it is wider than 2'b10 (and it isn't self-defining and it is
"signed"), but it always has the same "value".

Hope this helps,
-Chris

*****************************************************************************
Chris Clark Internet : compres@world.std.com
Compiler Resources, Inc. Web Site : http://world.std.com/~compres
23 Bailey Rd voice : (508) 435-5016
Berlin, MA 01503 USA fax : (978) 838-0263 (24 hours)
------------------------------------------------------------------------------
 
Wasn't the original question about sized versus unsized and weren't the code
examples assumed to be lines from differect sections of code that are
outside the blocking/nonblocking question?

Or did I miss the thread of this discussion entirely?



"Chris F Clark" <cfc@shell01.TheWorld.com> wrote in message
news:sddy83rexye.fsf@shell01.TheWorld.com...
The problem exhibited in the program has nothing to do with
sized/unsized (or even signed/unsigned) constants and everything to do
with non-blocking assigns.

foo <= 2'b10;
if (foo == 2)

At the point of the if statement the value of foo may (or may not be)
2, because the non-blocking assign does not take effect immediately.
foo does not change value to 2 until the "update event" happens.

You cannot depend on a non-blocking assignment affecting the value of
a variable (reg) until "some time" has passed. If you want the change
of the value and you want that change to affect later uses of the same
value in the same always block (and you intend the code to be
synthesizable), you want to use a blocking assign.

(In non-synthesizable code, you can put in a #delay, wait statement or
similar construct that causes time to pass, but that's a whole other
model. In synthesizable code, a single execution of an always block
should occur entirely within one instant of time, excluding the
delayed updates resulting from non-blocking assigns. And the dealys
updates due to non-blocking assigns should be pictured as happening at
the "appropriate" time after the always block is executed.)

Now, if you use a blocking assign, you need to be aware of their
semantics. Generally speaking blocking assigns are for combinatorial
logic and should only be used in "combinatorial" always blocks or in a
fashion hwere the effects of the blocking assign cannot escape the
always block (e.g. to "temporary" variables local to an always block).
There are exceptions to that rule if you are coding a latch, but that
doesn't look like your intent.

You might want to see one of the regular contributors (e.g. Cliff
Cumming's) numerous posting on the topic (blocking versus non-blocking
designs and #delays etc.)

------------------------------------------------------------------------

Now, to the respondent who suggested that some mysterious numeric
properties involving sign-extension may be involved, that may be true
sometimes, but it doesn't apply here. The code is using an unsigned
reg and an integer constant 2, which is guaranteed by the standard to
use at least 32 bits for its representation. The unsigned reg is thus
0 extended to the smae length (i.e. at least 32 bits) and that matches
the value of 2. Now, if one is using "2" in a place where width
matters, it is wider than 2'b10 (and it isn't self-defining and it is
"signed"), but it always has the same "value".

Hope this helps,
-Chris

*****************************************************************************
Chris Clark Internet : compres@world.std.com
Compiler Resources, Inc. Web Site : http://world.std.com/~compres
23 Bailey Rd voice : (508) 435-5016
Berlin, MA 01503 USA fax : (978) 838-0263 (24 hours)
------------------------------------------------------------------------------
 
That was my understanding too. (Although Chris is perfectly right in
saying the test foo == 2 fails if it occurs before the NBA update event
occurs.)
 
John_H wrote:
Wasn't the original question about sized versus unsized and weren't the code
examples assumed to be lines from differect sections of code that are
outside the blocking/nonblocking question?

Or did I miss the thread of this discussion entirely?
John, you're correct - my question is about sized vs. unsized and
whether or not there's a problem with using unsized numbers, from a
style or real perspective.

Andy stepped in with 2'b10 is not the same as 2... and that has caused
confusion. I'm hoping Andy will clarify his statements because
according to my simulations he is in error.


Verilog's assignment/event sequencing and x/z values were not part of
the question.


As an aside, I did read a comment in the XST guide saying that sized
numbers MUST be used in case statements otherwise XST may synthesize to
bad logic... so that's one concrete data point. I don't know if that's
just an XST thing or a general Verilog rule, though.


Regards,
Paul.
 
The verilog language (and hence the simulators) have clear rules for
expanding and truncating the width of operands in expressions. So, in
general, there is no simulation problem with using an "unsized" constant. I
use the word "unsized" in quotes, since it is not, in fact, unsized;
according to Verilog, a constant without a specifically stated size defaults
to 32 bits, so 'h12 is the equivalent of 32'h12.

With that in mind, there is one reason to use explicitely sized constants
when you are dealing with SYNTHESIS. Synthesis tools also respect the rules
of verilog, and hence will not produce incorrect results if you use a
wrongly sized constant. However, it can make a difference in terms of
synthesis effectiveness, both in terms of synthesis runtime and final
quality of results.

When synthesis encounters an unsized constant, it does what it should, and
assumes it is 32 bits wide. That, in turn, determines the size of the
operators that must be used in the expression, so for example.

wire [8:0] a,b,c;

assign b = a + 1;
assign c = a + 1'b1;

results in two very different operations in synthesis. For 'c', synthesis
infers a 8 bit incrementor, whereas for b it infers a 32 bit adder (since
the '1' is 32 bits wide). Many/most of the inputs of the adder are '0' (the
top 24 bits of the 'a' input and the top 31 bits of the other input; the
last bit is a constant 1). Synthesis then goes and does optimization that
will result in the removal of much of the logic in the 32 bit adder, and
will end up with something that is pretty similar (in the end) to an 8 bit
incrementer. However, synthesis has spent run time doing a great deal of
constant propagation and logic minimization for nothing. Furthermore, the
initial implementation for the adder/incrementor might be different (say,
using a carry lookahead adder instead of a ripple incrementor), which could
result in different final results even after all the minimization.

One last point relates to warning messages. Some synthesis tools (i.e.
synopsys) don't flatten larger inferred operators (designware adders), even
though it does do the minimization/reduction after the inferring. Thus, in
the final result, the designware operator will still exist in the hierarchy.
In the case of the 8 bit incrementor, all ports of this part will be used.
However, in the case of the adder, only 8 of the 64 inputs and 8 of the 32
outputs are used. In some versions of synopsys, this will result in 2
warning messages for each unused ports (the port of the DW module is not
used, and there is nothing connected to the port in the instantiation). So,
the 2 extra characters in the Verilog code will save you 160 useless warning
messages. Since we all (as good designers) look through each and every one
of the warning messages in the synthesis report (right???), this will end up
saving a good deal of time in the end.

Avrum


"Paul Marciano" <pm940@yahoo.com> wrote in message
news:1132024187.084196.109070@g47g2000cwa.googlegroups.com...
John_H wrote:
Wasn't the original question about sized versus unsized and weren't the
code
examples assumed to be lines from differect sections of code that are
outside the blocking/nonblocking question?

Or did I miss the thread of this discussion entirely?

John, you're correct - my question is about sized vs. unsized and
whether or not there's a problem with using unsized numbers, from a
style or real perspective.

Andy stepped in with 2'b10 is not the same as 2... and that has caused
confusion. I'm hoping Andy will clarify his statements because
according to my simulations he is in error.


Verilog's assignment/event sequencing and x/z values were not part of
the question.


As an aside, I did read a comment in the XST guide saying that sized
numbers MUST be used in case statements otherwise XST may synthesize to
bad logic... so that's one concrete data point. I don't know if that's
just an XST thing or a general Verilog rule, though.


Regards,
Paul.
 
I apologize for taking the discussion in the wrong direction. the
program at hand had that problem and from the Verilog "standard"
perspective didn't use 2 and 2'b10 in a way that they can be
distinguished. That being said, I wouldn't be surprised if there were
tools that specifically wanted one to use sized numbers. the "size" of
2 is not defined in the standard (except that the internal
representation must be alteast 32 bits) and one cannot use 2 in
contexts where the size of the number matters (e.g. concatnations). I
wouldn't be surprised if some tool made that restriction even
stronger. It would be subsetting the standard, but any
"synthesizable" code is already a subset, since the standard is full
of non-synthesizable constructs.

Thus, if you fix the blocking/non-blocking issue and then "simulate"
the program with any standard compliant simulator, you should not be
able to get the simulator to give the wrong answer. Whether you can
synthesize the code using a particular tool or not is a separate
question, which the Verilog standard doesn't address.

So, I apologize and I'll let the conversation continue on its normal
flow.

-Chris Clark
 
Avrum wrote:

(snip)

With that in mind, there is one reason to use explicitely sized constants
when you are dealing with SYNTHESIS. Synthesis tools also respect the rules
of verilog, and hence will not produce incorrect results if you use a
wrongly sized constant. However, it can make a difference in terms of
synthesis effectiveness, both in terms of synthesis runtime and final
quality of results.

When synthesis encounters an unsized constant, it does what it should, and
assumes it is 32 bits wide. That, in turn, determines the size of the
operators that must be used in the expression, so for example.

wire [8:0] a,b,c;

assign b = a + 1;
assign c = a + 1'b1;

results in two very different operations in synthesis. For 'c', synthesis
infers a 8 bit incrementor, whereas for b it infers a 32 bit adder (since
the '1' is 32 bits wide).
I think you meant 9 bit, but some synthesis tools try to generate one
more bit as a possible carry, and then give a warning on the assignment.
If I understand verilog, it should generate N and not N+1 bit for this
case. Also, tools I know of are pretty good at removing unused logic,
so it should in the end generate the appropriate bits in either case.

-- glen
 
On Tue, 15 Nov 2005 10:53:29 -0500, "Avrum"
<noasvpraumm@nospamsympatico.ca> wrote:

wire [8:0] a,b,c;

assign b = a + 1;
assign c = a + 1'b1;

results in two very different operations in synthesis. For 'c', synthesis
infers a 8 bit incrementor, whereas for b it infers a 32 bit adder (since
the '1' is 32 bits wide).
Did you actually try this with any recent commercial quality
synthesizers ? If it does what you suggest you should return it and
ask for your money back. For any synthesizer worth the CD it's printed
on, the result of b & c should exactly be the same. In any case the
maximum size of the adder/incrementor is 9 for this example.
 
The example picked was too simple to illustrate the problem. However,
there are real (but very rare) issues with bit widths (and especially
using unsized constants), including a right-shift in an expression
often exposes the issues, as in:

wire [8:0] a,b,c;

assign a = h'1ff;
assign b = (a + 1) >> 1;
assign c = (a + 1'b1) >> 1;

Now, the language standard mandates the b and c should get different
results as the intermediate value given to the right-shift operator
has different widths and in the first case should not overflow, but in
the second case should. Thus, b should be h'100 and c should be
h'000; Well, that is if I did the arithmetic in my head correctly.

I don't recall all the details, but I think that there are very few
operators that actually expose the bit widths of intermediate
expressions right-shift and concatenate (which explicitly requires
sized operands) are the only two the I remember--division would too,
but I don't think of that as efficiently synthesizable. However, you
cannot tell if expressions involving just +, -, *, &, |, etc. use 32
bits or 9 bits for intermediate calculations since the overflow
properties of unsigned arithmetic mask the differences. Thus, whether
a synthesizer first generated a 32 bit adder and pruned it to 9 bits
or generated only a 9 bit adder to begin with, should be generally
indistinguishable (and a synthesizer can know when it will be
distinguishable and do the right thing in those cases).

-Chris
 
Chris F Clark wrote:
I apologize for taking the discussion in the wrong direction. the
program at hand had that problem and from the Verilog "standard"
perspective didn't use 2 and 2'b10 in a way that they can be
distinguished.
that's exactly it.

I wish I still had the code that failed ... it was something obvious
and silly if one is fully aware of Verilog's extension rules.

That being said, I wouldn't be surprised if there were
tools that specifically wanted one to use sized numbers. the "size" of
2 is not defined in the standard (except that the internal
representation must be alteast 32 bits) and one cannot use 2 in
contexts where the size of the number matters (e.g. concatnations). I
wouldn't be surprised if some tool made that restriction even
stronger. It would be subsetting the standard, but any
"synthesizable" code is already a subset, since the standard is full
of non-synthesizable constructs.
In the case of the failure we uncovered, simulation and synthesis
matched -- of course, one would hope that Mentor's ModelSim produces
the same results as Mentor's Precision Synthesis.

And the issue had nothing to do with blocking vs non-blocking
operators. Everything was coded using strict synchronous processes
with non-blocking operators. My cheesy example was not as clear as it
should have been.

I am trying to recall the exact failure. It was eye-opening.

-a
 
On 14 Nov 2005 10:07:54 -0800, "Andy Peters" <Bassman59a@yahoo.com>
wrote:

arju...@gmail.com wrote:
I'm sorry, but am I missing something here? I can't see anything wrong
with the lines above.

Think it through.

reg [1:0] foo;

... do stuff ..
foo <= 2'b10;
if (foo == 2)
...
else
....

Put succinctly, 2'b10 is not equal to 2,
Since when ? Did you try this in your simulator ?
 
Andy Peters wrote:
arju...@gmail.com wrote:
I'm sorry, but am I missing something here? I can't see anything wrong
with the lines above.

Think it through.

reg [1:0] foo;

... do stuff ..
foo <= 2'b10;
if (foo == 2)
...
else
....

Put succinctly, 2'b10 is not equal to 2, so the if statement always
takes the false branch.

Ask yourself why.

-a
Sorry Andy, I still don't get it.

This:

module mymod(
input clk,
input reset,
output reg [1:0] r
);

always @(posedge clk)
if (reset)
r <= 2'b00;
else if (r == 2)
r <= 2'b01;
else
r <= r + 2'b01;


endmodule

Works as expected. r's sequence is 00,01,10,01,10,..., so the "if (r
== 2)" works perfectly.

I thought you might be talking about signed vs. unsigned (with 2'b10
being interpreted as -2), but not according to Modelsim and Icarus.

Are you talking about a specifc tool issue or a Verilog language issue?
If it's a Verilog language issue please be specific.

Your statement isn't supported by what the tools are showing me. I'm a
beginner, so again please be more specific.

Thanks,
Paul.
 

Welcome to EDABoard.com

Sponsor

Back
Top