Problem with type propagation in equality test

23 views
Skip to first unread message

Evan Lavelle

unread,
Oct 31, 2007, 6:58:15 AM10/31/07
to
I've got some test code below which carries out the assignment

k = (($signed(3'b110) >>> 1) === 3'b111);

On the face of it, k should evaluate to 1. However, the more
trustworthy of my test sims both agree that it's 0; they report

i is '1'; j is '111'; k is '0'

Any thoughts on what the correct answer is, and why?

Thanks -

Evan

---------------------------
module test;
reg i, k;
reg [2:0] j;
initial
begin
i = ($signed(3'b111) === 3'b111);
j = $signed(3'b110) >>> 1;
k = (($signed(3'b110) >>> 1) === 3'b111);
$display("i is '%b'; j is '%b'; k is '%b'", i, j, k);
end
endmodule

John_H

unread,
Oct 31, 2007, 1:43:05 PM10/31/07
to
What if you specify the last constant in k as signed?
k = (($signed(3'b110) >>> 1) === 3'sb111);

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

"Evan Lavelle" <nos...@nospam.com> wrote in message
news:3angi356rs5q2661c...@4ax.com...

Evan Lavelle

unread,
Oct 31, 2007, 1:51:37 PM10/31/07
to
On Wed, 31 Oct 2007 10:43:05 -0700, "John_H"
<news...@johnhandwork.com> wrote:

>What if you specify the last constant in k as signed?
>k = (($signed(3'b110) >>> 1) === 3'sb111);

That works, in that it gives an answer of 1 (I actually tried $signed
rather than 'sb). Re-casting the $signed expr back to unsigned
($unsigned($signed..)) also works, and is my current fix. However, it
would be nice to find out what's going on here.

Evan

Stephen Williams

unread,
Oct 31, 2007, 2:16:50 PM10/31/07
to
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Evan Lavelle wrote:
> ---------------------------
> module test;
> reg i, k;
> reg [2:0] j;
> initial
> begin
> i = ($signed(3'b111) === 3'b111);
> j = $signed(3'b110) >>> 1;
> k = (($signed(3'b110) >>> 1) === 3'b111);
> $display("i is '%b'; j is '%b'; k is '%b'", i, j, k);
> end
> endmodule
>

I would love to see the outputs that Modelsim, ncsim and VCS get
with this program (exactly as you wrote it). It seems that Icarus
Verilog has a bug here so I would like to see this program and the
outputs from the big 3 attached to a bug report.

- --
Steve Williams "The woods are lovely, dark and deep.
steve at icarus.com But I have promises to keep,
http://www.icarus.com and lines to code before I sleep,
http://www.picturel.com And lines to code before I sleep."
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org

iD8DBQFHKMaSrPt1Sc2b3ikRAr6hAKCUeSLil7KcrsBuWcnU85uVg3EM9gCgok4E
gJnDUfga8vIPY5c0Jdzk5UE=
=IHCp
-----END PGP SIGNATURE-----

Evan Lavelle

unread,
Oct 31, 2007, 2:49:28 PM10/31/07
to
On Wed, 31 Oct 2007 11:16:50 -0700, Stephen Williams
<spam...@icarus.com> wrote:

>I would love to see the outputs that Modelsim, ncsim and VCS get
>with this program (exactly as you wrote it). It seems that Icarus
>Verilog has a bug here so I would like to see this program and the
>outputs from the big 3 attached to a bug report.

ModelSim gives the answer that I reported (1, 111, 0). Interestingly,
gpl-cver gives the answer that I expected (1, 111, 1).

After some more thought, it seems to me that the (1, 111, 0) answer
may be correct. From 5.5.2, "The relational and equality operators
have operands that are neither fully self-determined nor fully
context-determined. The operands shall affect each other as if they
were context-determined operands with a result type and size (maximum
of the two operand sizes) determined from them." Since 3'b111 is
unsigned, the unsignedness is presumably propagated back to the
$signed(3'b110), the $signed is then dumped, and a logical downshift
is then carried out. Actually, I've just tested this, by changing

k = (($signed(3'b110) >>> 1) === 3'b111);

to

k = (($signed(3'b110) >>> 1) === 3'b011);

and both ModelSim and ISE now report that k is 1. Still, I don't like
it.

Evan

John_H

unread,
Oct 31, 2007, 3:00:11 PM10/31/07
to
"Evan Lavelle" <nos...@nospam.com> wrote in message
news:70ghi3dnfvapdm83f...@4ax.com...

Personally, I've never had use for the === equality and, instead, use == all
the time. If you used the ==, you may have received your desired result.


Evan Lavelle

unread,
Nov 1, 2007, 5:59:52 AM11/1/07
to
On Wed, 31 Oct 2007 18:49:28 +0000, Evan Lavelle <nos...@nospam.com>
wrote:

>k = (($signed(3'b110) >>> 1) === 3'b111);
>
>to
>
>k = (($signed(3'b110) >>> 1) === 3'b011);
>
>and both ModelSim and ISE now report that k is 1. Still, I don't like
>it.
>

I didn't say why I didn't like it. I don't want to flog a dead horse,
but there's an interesting issue here. In 2001, '>>' is the logical
right shift, and '>>>' is the arithmetic right shift. According to the
LRM:

>The arithmetic right shift shall fill the vacated bit positions with zeroes if the result
>type is unsigned. It shall fill the vacated bit positions with the value of the most significant (i.e., sign) bit of
>the left operand if the result type is signed.

Intuitively, then, you would always expect ($signed(x) >>> 1) to fill
the top vacated bit with the sign bit. But the LRM states that the
operation performed actually depends on the *result* type (which is
actually not correct; see below). This means that my original
operation was actually a *logical* right shift:

k = (($signed(3'b110) >>> 1) === 3'b111); // false

k = (($signed(3'b110) >>> 1) === 3'b011); // true

*********************************************************
Conclusion 1: '>>>' is *not* an arithmetic right-shift; what it does
is actually context-determined. Sometimes it's a logical right shift,
sometimes it's an arithmetic right shift.
*********************************************************

Secondly: not so important, but the LRM is incorrect when it states in
5.1.12 that the operation performed depends on the result type,
because the result type of a comparison or equality operator is always
1-bit unsigned, which in principle means that '>>>' would never work.
However, the exception in 5.5.2 basically states that you can ignore
the result type for equality and comparison ops. Conclusion 2: if you
try to use an arithmetic right shift in an equality or comparison op,
what it actually does depends on the type of the right-hand operand.

Conclusion 3: if ModelSim is right, and I think it is, '>>>' is
broken.

Evan

gabor

unread,
Nov 1, 2007, 11:46:45 AM11/1/07
to


I think the "result type" is where you can see your problem. While
the number being shifted is signed in your case, the result after
the shift is unsigned. Perhaps you wanted $signed(3'b110 >>> 1)?

Evan Lavelle

unread,
Nov 1, 2007, 12:54:02 PM11/1/07
to
On Thu, 01 Nov 2007 08:46:45 -0700, gabor <ga...@alacron.com> wrote:

>I think the "result type" is where you can see your problem. While
>the number being shifted is signed in your case, the result after
>the shift is unsigned. Perhaps you wanted $signed(3'b110 >>> 1)?

I've got 3 sims which agree that $signed(3'b110 >>> 1) evaluates to
3'b011 (code below). This is what you'd expect - $signed is just a
function which evaluates the input expression and returns a signed
value with the same size and value as the input.

I think the problem is not that "the number being shifted is signed in
your case, the result after the shift is unsigned", but that the
number being shifted is actually converted to unsigned before the
shift, after the '$signed' returns a signed number, and so the '>>>'
becomes a logical right shift.

Evan

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


module test;
reg i, k;

reg [2:0] j, l;


initial
begin
i = ($signed(3'b111) === 3'b111);
j = $signed(3'b110) >>> 1;

k = (($signed(3'b110) >>> 1) === 3'b011);

l = $signed(3'b110 >>> 1);
$display("i is '%b'; j is '%b'; k is '%b'; l is '%b'", i, j,
k, l);
end
endmodule

Evan Lavelle

unread,
Nov 1, 2007, 1:00:33 PM11/1/07
to
On Thu, 01 Nov 2007 16:54:02 +0000, Evan Lavelle <nos...@nospam.com>
wrote:

>I've got 3 sims which agree that $signed(3'b110 >>> 1) evaluates to


>3'b011 (code below). This is what you'd expect - $signed is just a
>function which evaluates the input expression and returns a signed
>value with the same size and value as the input.

Actually, to be more precise, the $signed forces the input expression
to be self-determined - you can use it to prevent type propagation
into the input expression (just like using a single-element
concatentation). In other words, you can't use it to force part of the
input expression to become signed; it's only the result which is
signed.

Evan

sh...@cadence.com

unread,
Nov 1, 2007, 9:50:12 PM11/1/07
to
On Nov 1, 5:59 am, Evan Lavelle <nos...@nospam.com> wrote:
>
> *********************************************************
> Conclusion 1: '>>>' is *not* an arithmetic right-shift; what it does
> is actually context-determined. Sometimes it's a logical right shift,
> sometimes it's an arithmetic right shift.
> *********************************************************

Yes, it is badly named. It is only arithmetic in a signed
expression. It is really a shift that works the way that '>>' should
have worked. Unfortunately, '>>' could not be changed in Verilog-2001
and remain backward compatible, because there were a few signed types
even in Verilog-1995, and '>>' did a logical shift for those too.

Given that there was already an operator that did a logical shift, no
matter what, it might have made sense to define '>>>' as an operator
that always did an arithmetic shift. However, you didn't get that for
'/' or '>' or any of the other operators that care about signedness.
They all have a signed and unsigned flavor. So '>>>' was defined as
the shift that has two proper flavors, to replace the old "broken"
shift that didn't.

> Secondly: not so important, but the LRM is incorrect when it states in
> 5.1.12 that the operation performed depends on the result type,
> because the result type of a comparison or equality operator is always
> 1-bit unsigned, which in principle means that '>>>' would never work.
> However, the exception in 5.5.2 basically states that you can ignore
> the result type for equality and comparison ops.

That is why the exception says to treat them "as if" there were a
result type that was determined from them. I like to regard the
compares as a two-step process, with an intermediate result determined
from the operands. The first step is the comparison of the values,
which requires the operands to be the same size. The second step is
the reduction of that result to a one-bit truth value. For the
equality comparisons, that two-step process can be represented
explicitly. (a != b) works exactly like (|(a ^ b)). The
operands of the XOR determine the type/size of the result of the XOR,
which is propagated back down to them. But that result is the operand
of the reduction-OR, which is self-determined. So the final result is
1 bit, and the XOR does not affect its size or type, or vice versa.

sh...@cadence.com

unread,
Nov 1, 2007, 10:16:24 PM11/1/07
to

Yes, $signed doesn't do a very good job at its stated purpose. Unless
you convert everything in the expression to signed, the result of
$signed will get converted right back to unsigned before anything else
is done with it. As you note here, it is actually more powerful as a
mechanism to protect its argument from the rest of the expression.
And for that purpose, $unsigned does the same thing.

Evan Lavelle

unread,
Nov 2, 2007, 5:09:59 AM11/2/07
to
Thanks - very informative.

Evan

Reply all
Reply to author
Forward
0 new messages