The signedness of an expression can change depending on its context. E.g.
for an arithmetic operation with one unsigned operand all operands are
treated as unsigned.
This is currently not considered when accessing class properties. This can
lead to incorrect behavior with regards to sign extension.
E.g. the following will print 4294967295 rather than 65535.
```
class C;
shortint x = -1;
endclass
...
C c = new;
$display(c.x + 32'h0);
```
Furthermore the return value is not expanded to the width of its context.
This can cause vvp to crash with an exception when it expects a vector on
the stack to have a certain width. E.g.
```
class C;
shortint x = -1;
endclass
...
C c = new;
int x;
bit a = 1'b1;
x = a ? c.x : 64'h0;
```
Solve both of this by using `pad_to_width()` on the property expression if
it is a vectorable type. Since any identifier, not just class properties,
need to have this done insert this on the common path and remove the
`pad_to_width()` call on individual paths.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The signedness of an expression can change depending on its context. E.g.
for an arithmetic operation with one unsigned operand all operands are
treated as unsigned.
For methods, both on built-in SystemVerilog types as well as user defined
classes, this is currently not considered. This can lead to incorrect behavior
if the value is sign extended.
E.g. the following will print 4294967295 rather than 65535.
```
shortint q[$];
q.push_back(-1);
$display(q.pop_front() + 32'h0);
```
Furthermore the return value is not expanded to the width of its context.
This can cause vvp to crash with an exception when it expects a vector on
the stack to have a certain width.
E.g.
```
int d[];
longint x;
bit a = 1'b1;
x = a ? d.size() : 64'h0;
```
Solve both of this by using `pad_to_width()` on the method return value if
it is a vectorable type. Since any function call, not just methods, needs
to have this done to its return value insert this on the common path.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
When calling a queue method without parenthesis it gets elaborated through
the PEIdent path. On this path the type, width and signdess are not
reported for the method call. This leads to incorrect behavior in contexts
where those are important.
Correctly report the type, the same as when the method is called with
parenthesis.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The result for the built-in methods for the SystemVerilog types is
currently always unsigned. This can lead to incorrect behavior if the value
is sign extended or passed as an argument to a system function (e.g.
$display).
For most built-in methods this does not matter, since even though they have
a signed return type, they will not return a negative value. E.g. the
string `len()` or queue `size()` functions.
It does make a difference though for the queue `pop_front()` and
`pop_back()` methods. Their return type is the element type of the queue.
If the element type is signed and the value in queue is negative is will be
handled incorrectly.
E.g. the following will print `4294967295` rather than `-1`.
```
int q[$];
q.push_back(-1);
$display(q.pop_front());
```
To correctly support this consistently assign the actual data type of the
built-in method's return value to the `NetESFunc`, rather than just the width
and base type. The width, base type and also the signedness can be derived
from the data type.
Note that this only fixes the default signedness, but not the case where
the signedness of the expression is changed by its context (e.g. in
arithmetic expression). Handling this will require some additional work.
Also note that assigning the actual data type is also required to support type
checking on the return value, e.g. as needed for enum types.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
It is allowed to access a constant declared in a class scope, such as a
enum value or parameter, on an object of that class type. This is described
in section 8.5 ("Object properties and object parameter data") of the LRM
(1800-2017).
E.g.
```
class C
enum { A } e;
endclass
C c = new;
c.e = c.A;
```
Support this by in addition of searching for class properties on the object
also search for constants in the class scope.
A bit of refactoring is needed around the parameter elaboration functions
since they expect a non-const NetScope, but for classes we only have a
const scope available.
The non-const scope is needed to be able to mark specparams as
non-annotatable. Since classes can't have specparams this part is factored
out into a separate function the NetScope parameter for the shared
functions is made const.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The NetScope class has a method called find_parameter() that looks up the
parameter and returns a iterator to it. This is only ever used to get the
line information of the parameter.
Refactor the function so that it only returns the line info. This will
allow to call this function on a const NetScope object.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
For unpacked statically sized array types $bits() is supposed to return the
total size of the array. Accumulated the number of unpacked dimensions and
multiply it by the packed with of the base type to get the right result.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Assigning a value to an enum signal that is not of the same type as the
enum requires an explicit cast.
To support this attach the type of a type cast to the resulting expression.
This allows the assignment elaboration to confirm that value has been
explicitly cast to the right type.
Also handle the case where the value is a constant. In this case create a
NetEConstEnum instead of a NetEConst as the resulting expression.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The scope_ field of the NetEConstEnum class is initialized in the
constructor, but never used anywhere again. Remove it.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently explicit cast is supported to atom2 and vector types. packed
struct, packed array and enum are not supported.
An explicit cast to packed type works the same for all packed types though.
Add support for handling also packed structs, packed arrays and enums by
make the code more generic and querying the packed base type from the
ivl_type_t.
To correctly handle enums a bit more work is necessary, which will be done
in a follow up patch.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
(replacing assertions)
The IEEE standard either requires out-of-bounds bits to be ignored on
write, returned as 1'bx on read, or requires a compile-time error message.
The latter is easier to implement.
If we have a bit/part select that is selecting one or more sub-arrays, e.g.
wire [3:0][3:0] foo;
assign foo[1] = 4'd1;
we need to take into account the bit width of the sub-array when calculating
the bit width of the select.
There are too many ad hoc handlers of symbol_search partial results.
Rewrite symbol_search to clean up things like partial results and
member/method detections. Use this reworked symbol_search function
to rewrite expression elaborate for the PECallFunction expressions.
Parameters can have string type and do the usual string stuff,
and also implement some of the string methods on string parameters
so that they evaluate down to constants.
Use the common data_type_or_implicit rules to support type
definitions for parameters. This eliminates a bunch of special
rules in parse.y, and opens the door for parameters having
more complex types.
This.new is not allowed.
super.new beyond the first statement is not allowed.
And while I'm at it, clean up the use of "@" and "#" in
the code as tokens for this and super.
A NetESelect is used for accessing packed struct members and also for
accessing dynamic array elements. In these cases the expr_type() and
enumeration() methods should reflect the member/element type.
When -pfileline=1 is used the queue procedural warnings have file
and line information added to the messages. Also switch the trace
debugging to be off by default.
Also, Add some preliminary missing darray functionality.
When strings are arguments to functions/tasks, that doesn't suddenly
make them implicitly scalar. Strings are vectors and should be treated
that was, even if they are IMPLICIT_REG.
We don't support evaluating user-defined system functions at compile
time. If possible, defer evaluation until run time. If used in a
constant expression, output a "sorry" message.
Casting from signed to unsigned types and vice versa is legal in SV,
as is casting from a larger to a smaller size. Obey Verilog rules
for expression bit width and signedness.