signed arithmetic

J

Jan Decaluwe

Guest
Hi:

I have been trying to figure out how signed arithmetic in
your favourite language actually works. The 2 (open-source)
simulators I use don't agree on the subject. I have prepared
a small test module (attached) with 3 relevant test cases.

The output of Icarus 0.8.1 is:

p= 15659 s= -24 d=1

The output of cver (gplcver 2.11a) is:

p= -725 s= 40 d=0

Explanations would be great, but just letting me know
what your simulator outputs would already be very useful.

Jan

--
Jan Decaluwe - Resources bvba - http://www.jandecaluwe.com
Losbergenlaan 16, B-3010 Leuven, Belgium
Electronic design with Python:
http://myhdl.jandecaluwe.com
 
I don't think Icarus supports signed for reg types.

Cver does, and in this case, its output is correct (correct being defined
by me as matching the output of Modelsim 6.1a, which in this case, it does).

However, having said that, cver fails miserably on my design which
includes lots of signed and unsigned arithmetic. I haven't had the time
to track this down, but my suspicion is that the problem relates to
parameters and Xilinx primitives rather that signed problems.


Terry Brown

On Fri, 30 Sep 2005 10:41:20
+0200, Jan Decaluwe wrote:

Hi:

I have been trying to figure out how signed arithmetic in
your favourite language actually works. The 2 (open-source)
simulators I use don't agree on the subject. I have prepared
a small test module (attached) with 3 relevant test cases.

The output of Icarus 0.8.1 is:

p= 15659 s= -24 d=1

The output of cver (gplcver 2.11a) is:

p= -725 s= 40 d=0

Explanations would be great, but just letting me know
what your simulator outputs would already be very useful.

Jan
 
I had my first attempt at signed/unsigned math come out not as I expected.

s <= m + b;

m is signed, b is unsigned, so the result should be unsigned if I recall.
Try declaring b as a signed, 1-bit register. My worry here is that a 1-bit
signed value might be considered 0 or -1, not 0 or 1, which may be why your
d <= c==1 comes out false.

n <= 29;

Would the integer be considered unsigned? For a test, consider n<=
$signed(29) or n<= -(-29) to see if cver likes things better.

It's not pleasant.



"Jan Decaluwe" <jan@jandecaluwe.com> wrote in message
news:433CFA30.3060608@jandecaluwe.com...
Hi:

I have been trying to figure out how signed arithmetic in
your favourite language actually works. The 2 (open-source)
simulators I use don't agree on the subject. I have prepared
a small test module (attached) with 3 relevant test cases.

The output of Icarus 0.8.1 is:

p= 15659 s= -24 d=1

The output of cver (gplcver 2.11a) is:

p= -725 s= 40 d=0

Explanations would be great, but just letting me know
what your simulator outputs would already be very useful.

Jan

--
Jan Decaluwe - Resources bvba - http://www.jandecaluwe.com
Losbergenlaan 16, B-3010 Leuven, Belgium
Electronic design with Python:
http://myhdl.jandecaluwe.com

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


module bittest;

reg signed [5:0] m;
reg signed [7:0] n;
reg signed [18:0] p;
reg signed [8:0] s;
reg b;
reg signed c;
reg d;

always @(m, n, c) begin
p <= m * n;
s <= m + b;
d <= c == 1;
end

initial begin
#10;
m <= -25;
n <= 29;
b <= 1;
c <= 1;
#10;
$display("p=%d s=%d d=%d", p, s, d);
end

endmodule
 
Terry Brown wrote:
I don't think Icarus supports signed for reg types.
Perhaps not, but there is evidence it tries to :)

The Icarus parser permits the "signed" qualification as well
as the "$signed" system call, and the simulation does something
different when these are used.

Jan

--
Jan Decaluwe - Resources bvba - http://www.jandecaluwe.com
Losbergenlaan 16, B-3010 Leuven, Belgium
Electronic design with Python:
http://myhdl.jandecaluwe.com
 
Jan Decaluwe wrote:
Hi:

I have been trying to figure out how signed arithmetic in
your favourite language actually works. The 2 (open-source)
simulators I use don't agree on the subject. I have prepared
a small test module (attached) with 3 relevant test cases.

The output of Icarus 0.8.1 is:

p= 15659 s= -24 d=1

The output of cver (gplcver 2.11a) is:

p= -725 s= 40 d=0

Explanations would be great, but just letting me know
what your simulator outputs would already be very useful.
So far so good. Based on the feedback I know that modelsim and
ncsim match the Cver output. It looks like Cver gets it
right and Icarus does not.

Other simulators (in particular vcs) anyone?

Jan

--
Jan Decaluwe - Resources bvba - http://www.jandecaluwe.com
Losbergenlaan 16, B-3010 Leuven, Belgium
Electronic design with Python:
http://myhdl.jandecaluwe.com
 
Jan Decaluwe writes:
Jan> So far so good. Based on the feedback I know that modelsim and
Jan> ncsim match the Cver output. It looks like Cver gets it
Jan> right and Icarus does not.

Jan> Other simulators (in particular vcs) anyone?

VCS gives the output you now probably expect:

Chronologic VCS simulator copyright 1991-2003
Contains Synopsys proprietary information.
Compiler version VCS 7.1.1; Runtime version VCS 7.1.1; Oct 4 15:28 2005
....

p= -725 s= 40 d=0

It seems like a bug has to be solved in Icarus...

Graag gedaan.

--
Johan Van Praet Phone: +32/16/40 81 15
Target Compiler Technologies N.V. Fax: +32/16/40 53 00
Technologielaan 11-0002 mailto:vanpraet@retarget.com
B-3001 Leuven, Belgium http://www.retarget.com
 
The cver results are correct. Here are explanations:

p <= m * n;

Both m and n are signed, so you get the signed multiply you would
expect. The actual details that lead to that result are as follows.

All operands are signed, so the overall expression is signed. That is
propagated back down, so that all operands are treated as signed.

The maximum size comes from the left-hand side, which is 19 bits. So
the overall expression will be 19 bits. That is propagated back down,
so all operands will be extended to 19 bits before any operations.
Because they are all being treated as signed, that will be a
sign-extension to 19 bits. Then the two signed 19-bit values are
multiplied and the 19 bit result is assigned to p.

It turns out not to matter whether the actual multiply operation is
signed or unsigned, since the bottom 19 bits of the result will be the
same either way. What makes the multiply act signed is the fact that
the two operands were sign-extended to the size of the result before
the multiply. If they had been zero-extended, the result would have
acted as if the multiply were unsigned. A synthesis tool will probably
optimize this into a signed 6-bit*8-bit=14-bit multiplier whose result
is then sign-extended to 19 bits, which gives the same result as the
officially defined sequence of operations.

s <= m + b;

While m is signed, b is unsigned. That makes the overall expression
unsigned. That is propagated down to the operands, which will
therefore all be treated as unsigned.

The maximum width comes from the left-hand side again, which is 9 bits.
That is propagated back down, so that all operands will be extended to
9 bits before any operations. Because the operands are all being
treated as unsigned, that extension will be zero-extension.

The width of m is 6 bits, and its value is -25, which will be
represented in twos-complement as 6'b100111. That will get
zero-extended to 6'b000100111. These values are 39 when treated as
unsigned. The width of b is 1 bit, and its value is 1. When
zero-extended to 9 bits, its value is still 1. Adding 1 to 39 gives
40.

d <= c == 1;

The result of a comparison is always 1-bit unsigned. The operands of a
comparison are not affected by anything outside the comparison, but are
affected by each other. Operand c is 1-bit signed. Operand 1 is 32
bits signed (unbased literals are treated as signed, and an
implementation-defined size that must be at least 32 bits, and is 32
bits in all implementations I am aware of). Since both operands are
signed, both operands will be treated as signed. Since the largest
operand is 32 bits, both operands will be extended to 32 bits before
the comparison.

The literal 1 is already 32 bits. The operand c is only 1 bit, which
will be sign-extended to 32 bits. Since the sign bit (the only bit)
has a value of one, the result will be all ones. In other words, a
1-bit signed value can represent two values in twos-complement: 0 and
-1. This one has a value of -1, so sign-extension to 32 bits will
produce a 32-bit wide -1. That is not equal to a 32-bit wide 1, so the
result is false.

If the expression had been (c == 32'd1), then it would have been true,
because 32'd1 is unsigned, so c would have been zero-extended. If the
expression had been (c == 1'sd1) or (c == 1'd1), it would have been
true, because both operands would have been 1 bit wide, so there would
have been no extension, and the comparison would have been between two
single bits that were both 1.

These results are actually pretty straightforward, because there is
only a single operator in the expressions. Where things get confusing
is when there are multiple operators. Languages like C defer
conversions as long as possible, so that intermediate calculations are
only affected by the operands being combined. Verilog has always done
conversions as early as possible, to try to avoid premature overflow of
intermediate results. For mixtures of signed and unsigned operands,
the results can be confusing to someone used to the rules of a language
like C.
 
Johan Van Praet wrote:
Jan Decaluwe writes:


Jan> So far so good. Based on the feedback I know that modelsim and
Jan> ncsim match the Cver output. It looks like Cver gets it
Jan> right and Icarus does not.

Jan> Other simulators (in particular vcs) anyone?

VCS gives the output you now probably expect:

Chronologic VCS simulator copyright 1991-2003
Contains Synopsys proprietary information.
Compiler version VCS 7.1.1; Runtime version VCS 7.1.1; Oct 4 15:28 2005
...

p= -725 s= 40 d=0

It seems like a bug has to be solved in Icarus...
At least two: sign extension with signed operands (first case)
and the interpretation of a single bit as signed/unsigned
(second and third case).

I don't want to be too harsh on Icarus though: I suspect
that the latter cases will be confusing to most people
when they first look at it.

Graag gedaan.
Dankuwel :)

--
Jan Decaluwe - Resources bvba - http://www.jandecaluwe.com
Losbergenlaan 16, B-3010 Leuven, Belgium
Electronic design with Python:
http://myhdl.jandecaluwe.com
 
sharp@cadence.com wrote:
The cver results are correct. Here are explanations:

p <= m * n;

Both m and n are signed, so you get the signed multiply you would
expect. The actual details that lead to that result are as follows.

All operands are signed, so the overall expression is signed. That is
propagated back down, so that all operands are treated as signed.

The maximum size comes from the left-hand side, which is 19 bits. So
the overall expression will be 19 bits. That is propagated back down,
so all operands will be extended to 19 bits before any operations.
Because they are all being treated as signed, that will be a
sign-extension to 19 bits. Then the two signed 19-bit values are
multiplied and the 19 bit result is assigned to p.

It turns out not to matter whether the actual multiply operation is
signed or unsigned, since the bottom 19 bits of the result will be the
same either way. What makes the multiply act signed is the fact that
the two operands were sign-extended to the size of the result before
the multiply. If they had been zero-extended, the result would have
acted as if the multiply were unsigned. A synthesis tool will probably
optimize this into a signed 6-bit*8-bit=14-bit multiplier whose result
is then sign-extended to 19 bits, which gives the same result as the
officially defined sequence of operations.

s <= m + b;

While m is signed, b is unsigned. That makes the overall expression
unsigned. That is propagated down to the operands, which will
therefore all be treated as unsigned.

The maximum width comes from the left-hand side again, which is 9 bits.
That is propagated back down, so that all operands will be extended to
9 bits before any operations. Because the operands are all being
treated as unsigned, that extension will be zero-extension.

The width of m is 6 bits, and its value is -25, which will be
represented in twos-complement as 6'b100111. That will get
zero-extended to 6'b000100111. These values are 39 when treated as
unsigned. The width of b is 1 bit, and its value is 1. When
zero-extended to 9 bits, its value is still 1. Adding 1 to 39 gives
40.

d <= c == 1;

The result of a comparison is always 1-bit unsigned. The operands of a
comparison are not affected by anything outside the comparison, but are
affected by each other. Operand c is 1-bit signed. Operand 1 is 32
bits signed (unbased literals are treated as signed, and an
implementation-defined size that must be at least 32 bits, and is 32
bits in all implementations I am aware of). Since both operands are
signed, both operands will be treated as signed. Since the largest
operand is 32 bits, both operands will be extended to 32 bits before
the comparison.

The literal 1 is already 32 bits. The operand c is only 1 bit, which
will be sign-extended to 32 bits. Since the sign bit (the only bit)
has a value of one, the result will be all ones. In other words, a
1-bit signed value can represent two values in twos-complement: 0 and
-1. This one has a value of -1, so sign-extension to 32 bits will
produce a 32-bit wide -1. That is not equal to a 32-bit wide 1, so the
result is false.

If the expression had been (c == 32'd1), then it would have been true,
because 32'd1 is unsigned, so c would have been zero-extended. If the
expression had been (c == 1'sd1) or (c == 1'd1), it would have been
true, because both operands would have been 1 bit wide, so there would
have been no extension, and the comparison would have been between two
single bits that were both 1.

These results are actually pretty straightforward, because there is
only a single operator in the expressions. Where things get confusing
is when there are multiple operators. Languages like C defer
conversions as long as possible, so that intermediate calculations are
only affected by the operands being combined. Verilog has always done
conversions as early as possible, to try to avoid premature overflow of
intermediate results. For mixtures of signed and unsigned operands,
the results can be confusing to someone used to the rules of a language
like C.
So Icarus has some bugs?
 
More like unsupported features. They support a very small subset of
IEEE 1364-2001 ( verilog 2k ), at this time.

-Art
 

Welcome to EDABoard.com

Sponsor

Back
Top