This goes all the way down to the vvp level, where we create support
for arrays of objects, generate the new code in the -tvvp code
generator, and elaborate the arrays in the first place.
If an expression contains a division, remainder, or right shift operation,
set the expression min_width to UINT_MAX to flag that the expression width
cannot be pruned. Using UINT_MAX ensures that the min_width won't change
as we continue to elaborate the expression.
Internally, treat the "$" as a special expression type that takes
as an argument the signal that is being indexed. In the vvp target,
use the $last system function to implement this.
This works by translating it to a $size() system function call.
The $size function is already implemented for dynamic queues and
it is easy enough to expand it for queues.
The netparray_t::slice_dimensions bug was the most insidious and
caused all manner of confusion. Also fix some other packed array
and unpacked array (and mixed) indexing calculations.
When an expression is elaborated, the compiler converts multiplies with
one constamt zero operand into a constant zero value. This is only valid
if the other operand is not a 4-state variable.
Unsized expressions can expand to extremely large widths. Usually this
is actually a mistake in the source code, but it can lead to the compiler
temporarily using extremely large amounts of memory, or in the worst
case, crashing. This adds a cap on the width of unsized expressions (by
default 65536 bits, but overridable by the user), and causes a warning
message to be output when the cap is reached.
The verinum arithmetic operators now observe the standard Verilog
rules for calculating the result width if all operands are sized.
If any operand is unsized, the result is lossless, as before.
They also now all observe the standard rules for handling partially
undefined operands (if any operand bit is 'x', the entire result is
'x').
I've also added the unary '-' operator, and renamed v_not() to be
the unary '~' operator. This has allowed some simplification in
other parts of the compiler.
This changes the verinum pow() function to use the more efficient algorithm
used in the vvp runtime. It will still be slow if the left operand is unsized
and the right operand is large, as it will expand the result vector to avoid
overflow.
The code should only look at the real argument that exist any missing
arguments default to not being defined and hence needs to use the
default expression. Found with valgrind.
It is better to leave the handling of PChainConstructor calls to
the elaboration, instead of stripping them out early. This allows
for handling the arguments of the chain constructor in the correct
scope.
It is more common to find an unsized number on the right hand side
of a binary operator than on the left hand side, particularly for
comparison operations (e.g. x < 10 rather than 10 > x), so testing
the width of the right operand first is less likely to result in
the width needing to be retested. Counting the number of times an
operand width is retested when running the test suite confirms this;
before this change an operand width was retested 4869 times, after
the change an operand width was retested 99 times.
To be strictly compliant with the standard and compatible with other
EDA tools, unsized numbers should be treated as having a fixed size
(the same size as an integer). The -gstrict-expr-width option is
extended to allow the user to enable this behaviour.