The current implementation expects that for a module instantiation with a
ordered list connection all ports are supplied.
But there doesn't seem to be such a requirement in the LRMs. The Verilog
LRM doesn't mention anything in this regard and the SystemVerilog LRM
mentions in section 23.3.2.1 that a blank or omitted port connection is
either left unconnected or uses the default value of the port.
Update the implementation so that it allows to omit trailing ports and only
generates an error message if too many ports are specified in the ordered
port list.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The current check to decide whether a port is an array or a scalar signal
uses the number of pins on the NetNet. If it is larger than one the code
assumes that it is an array.
But for arrays with on a single element the number of pins will be 1 and
the port is incorrectly treated as a scalar signal which results in an
error.
Instead of using the number of pins check for the number of unpacked
dimensions to decide whether the port is an array.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows to use the `return` statement in a task to exit the
task before it reaches the end of its execution. This is defined in section
13.3 ("Tasks") of the LRM (1800-2017).
This is similar to using `disable` to stop a task from within itself with
the difference that `disable` will affect all concurrently running
executions of a task, while `return` will only affect the task from which
it has been called.
The `%disable/flow` vvp instruction allows to implement the required
behavior for task return.
There is one complication in that it is not allowed to call return from
inside a parallel block (fork-join). If a parallel block is unnamed and has
no variable declarations there won't be a NetScope for it. So it is not
possible to detect whether the return is inside a parallel block by
walking up the scope chain.
To solve this add a design global counter that gets incremented when
entering a fork block and decremented when exiting a parallel block. The
return implementation then checks if the counter is non 0 to determine
whether it is in a parallel block.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
foreach loops are supposed to iterate arrays $left to $right. E.g. `reg
x[3:0]` should be iterated from 3 to 0 and `y[1:4]` from 1 to 4.
The current implementation iterates them from $low to $high. Modify this to
either count up or down depending on whether $left or $right is the larger
of the two values.
Note that the same applies for dynamic arrays. But since for dynamic arrays
$left is always 0 and $right is always $high they always count up and we do
not need to differentiate between two different cases.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
In SystemVerilog it is not allowed to assign a value to a enum variable
that is not of the same time as the enum variable.
This is currently enforced for assignment and continuous assignment. But
ignored in other places such as function parameter passing.
Move the enum type check into `elab_rval_expr()` to cover more cases.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
In SystemVerilog identifiers can usually have an additional package scope
in which they should be resolved. At the moment there are many places in
the code base that handle the resolution of the package scope.
Add a common data type for package scoped paths as well as a
symbol_search() variant that works on package scoped identifiers. This
allows to handle package scope resolution in a central place.
Having the code in a central place makes it easier to ensure consistent and
correct behavior. E.g. there are currently some corner case bugs that are
common to all implementations. With the common implementation it only has
to be fixed in one place.
It will also make it easier to eventually implement class scoped
identifiers.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
As a quirk of the (System)Verilog grammar a function or task argument list
with no arguments can not be distinguished from a argument list with a
single empty argument. The iverilog parses it as the latter. There are
currently many places in the code base where this is fixed up in slightly
different ways.
Fix this up in the parser in a central way before passing the arguments to
the elaboration stage.
The existing implementation in some cases removes all empty trailing
arguments. While this works to handle the case for zero arguments it also
hides some errors that should be detected. E.g. in the following 3
arguments are passed to a function which only takes two arguments. But no
error is reported since the explicitly specified empty arguments are
removed.
```
function f(integer a, integer b = 2); ... endfunction
f(1,,);
```
In the new implementation the empty argument will only be removed if there
is exactly one empty argument in the argument list.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The default value for a function or task argument is elaborated once and
then used for each function invocation where no actual value is provided.
This means if a function or task is called multiple times the same NetExpr
is passed as a sub-expression to multiple statements or expressions such as
the function call.
This is causing problems because each expression or statement expects to
have exclusive ownership over its sub-expressions. It can for example
result in a double free or other undefined behavior.
To mitigate this duplicate the default argument expression before it is
given as a sub-expression to another expression or statement.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are no users of the old symbol_search that need the cls_val result.
Remove it as a output parameter of the function.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This includes support at the parser (pform) through enaboration
and the netlist format for the break and continue statements.
Elaboration actually already worked for for-loops, but since the code
generators need more information, this is a rewire of that support to
be explicit about for-loops. This means they are not rewritten as fancy
while loops. The code generators will have to handle that.
Given the elaboration of for-loops now work, write the vvp code generator
support needed to implement it.
Now that for-loops are presented as for-loops to the code generator, the
vlog95 code generator doesn't need to infer them anymore. Generate the code
more directly.
Also update the tests list so that the vlog95_reg tests all pass.
SystemVerilog allows to use the `super` keyword to access properties and
methods of a base class. This is useful if there is for example an
identifier with the same name in the current class as in the base class and
the code wants to access the base class identifier.
To support this a bit of refactoring is required. Currently properties are
internally referenced by name, this does not work if there are multiple
properties of the same. Instead reference properties always by index.
In addition when looking up an identifier that resolves to an object return
both the type and the object itself. This is necessary since both `this`
and `super` resolve to the same object, but each with a different type.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently there is no error checking for continuous assignments to unpacked
arrays. If the lvalue and rvalue net are not compatible undefined behavior
occurs. For some types of incompatibility it will crash during elaboration,
for others it will crash during simulation, and for some it will just work,
even though the assignment is not allowed by the standard.
Implement checking to ensure the two nets are compatible as required by the
standard and report an error otherwise.
Two arrays are considered to be compatible if their element types are
equivalent, they have the same number of ranges and each range has the same
number of elements.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog has explicit support for calling a function
as a statement. This is allowed when the function call is encapsulated in
`void'(...)`. E.g. `void'(f(1, 2, 3));`
We already support calling function calls as statements without the void
cast and emit a warning when doing so.
Adding support for void casts only requires to update the parser to handle
the void cast and then do not emit the warning if a function is called as
a statement as part of a void cast.
Void casting a task or void function call is not allowed and will generate
an elaboration error.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
When calling non-void functions or non-void methods of built-in types as a
task a warning is issued. But when calling a non-void method of a user
defined class as a task an error is generated.
Be consistent here and generate a warning in both cases.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
For loops may have empty initialization statements. In that case some things
can't be done, such as loop unrolling or synthesis, but otherwise it is a
valid thing to do. So generate the correct code in this case.
SystemVerilog allows to skip dimensions in a foreach loop by not specifying
an identifier name for the dimensions. E.g. the following will iterate over
the first and last dimensions, but skip the middle dimension.
```
int x[1][2][3];
foreach(x[a,,b]) ...
```
Add support for this to the parser as well as elaboration.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently when the number of loop variables in a foreach loop is larger
than the number of array dimensions an assertion is triggered.
Turn this into a error message instead for graceful error reporting.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Rather than moving one item at a time form the elaboration_work_list to the
temporary queue use std::swap to exchange them all at once. This is a bit
more efficient.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Trying to add a drive strength or delay to a undriven net will result in an
assertion. Make sure that a driver is added to undriven nets.
A driver is already added for all NetESignals, which covers most expression that
can produce a raw net rvalue. But there are other ways we can end up with just a
net as the rvalue, e.g. when applying a sign cast to a net. The following
example triggers the issue
```
wire [7:0] a;
wire [7:0] b = $signed(a);
```
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Calling a void function (or a regular function and ignoring the result)
from within a class method will currently result in an error unless the
void function itself is a method of the same class.
This is because we add the implicit `this` as an object on which to search
for the function and if we do not find it print an error. Change this to
only print an error if the implicit this was not added and it was a method
call on an object identifier.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows input ports to be variables. If something is connected
to the input port it will be converted to an unresolved wire.
This is handled the same as having a continuous assignment on a
SystemVerilog varibale.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The custom `svector` class is essentially a subset of `std::vector`. There
is no inherent advantage to using `svector`. Both have the same memory
footprint.
`svector` was designed to be of static size, but there are a few places in
the parser where it has to grow at runtime. Handling this becomes a bit
easier by switching to `std::vector` since it is possible to use its
methods which take care of resizing the vector.
This also allows to remove the unused parameter of the `lgate` struct
constructor, which was only needed for compatibility with `svector`.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The `elaborate_rval_expr()` function takes a `data_type_t`, a
`ivl_variable_type_t` and a `width` parameter. In most places the
ivl_variable_type_t and width are directly derived from the data_type_t.
This slightly simplifies the code.
The only place where this is currently not possible is when assigning to a
compound expression like a concatenation, e.g. `{a,b} = c;`.
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>
A `return` statement in a function gets translated into a vvp `%disable`
instruction. This works fine as long as no recursion is involved. The
`%disable` instruction will stop execution of all active threads of a
particular scope. For recursive functions this means as soon as the inner
most function returns all containing outer function calls get disabled as
well. This results in incorrect behavior.
To make recursive functions using the `return` statement work use the new
vvp `%disable/parent` instruction. This instruction will only disable the
closest thread in the thread hierarchy that matches the target scope.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
During parsing parameters and localparams are kept in a separate list only
to be collected into the same list during elaboration.
Store them in the same list during parsing as well, this allows to remove
some duplicated code.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
A module port list may contain unnamed entries, e.g.
module dut(a,);
When performing a wildcard connection, these entries should be skipped,
as there is no name to match.