Using an edge control with a named event is invalid. The existing elaboration
code already reports an error for `posedge` and `negedge`, but the `edge` case
falls through to the default path and triggers an assert.
Handle `PEEvent::EDGE` like the other edge-control cases and report the same
kind of error instead.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog defines a special case that allows to assign string literals
to byte arrays. Each character of the string is copied to 1 element of the
byte array.
The size of string literal and the byte array does not have to match. If
the string literal is longer it is truncated. If it is shorter it will be
padded with null-bytes.
The assignment is done left aligned, the first character ends up in the
left most entry of the array. This means the order will differ whether the
array is declared with ascending or descending element order.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Output port expressions must support continuous assignment. Assignment
patterns for unpacked array output ports are currently elaborated as
temporary arrays and the connection is silently discarded.
Report an error instead.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently, when a constant bit/part select is found in the implicit
sensitivity list for an always_* construct, it is replaced by the
entire signal. If there is more than one bit/part select from the
same signal, that signal gets added to the list multiple times. This
breaks the algorithm used to detect duplicate events in the nodangle
functor, causing it to erroneously merge non-identical events in some
cases.
The proper fix is to support sensitivity at the bit/part level, as
required by IEEE 1800. But for now, just make sure we only include
the entire signal once, regardless of how many different bit/part
selects we find. Enhance the "sorry" message to report which signals
are contributing excessively to the process sensitivity.
SystemVerilog makes all of the initialisation, condition, and step
components of a for loop optional. We already support this for the
initialisation and step components.
This only applies to simple identifiers. Only return a match if the
lexical position of the identifier being searched is later in the
source text than the lexical position of a matching symbol.
SystemVerilog allows variables to be driven by continuous assignments,
including port connections. Internally we handle this by converting
the NetNet from a REG to an UNRESOLVED_WIRE. Here we handle the case
of an unpacked array variable connected to a module output port.
This fixes issue #1001.
`std::vector<netrange_t>` is used for signal array dimensions. As such it is
used in quite a few places.
Add a typedef that can be used as a shorthand to refer to it. This helps to
keep lines where this is used from growing to overly long.
The new type is called `netranges_t`.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
In addition to providing positional arguments for task and functions
SystemVerilog allows to bind arguments by name. This is similar to how
module ports can be bound by name.
```
task t(int a, int b); ... endtask
...
t(.b(1), .a(2));
```
Extend the parser and elaboration stage to be able to handle this. During
elaboration the named argument list is transformed into a purely positional
list so that later stages like synthesis do not have to care about the
names.
For system functions and tasks all arguments must be unnamed, otherwise an
error will be reported.
In addition to functions and tasks arguments can also be bound by name for
the various different ways of invoking a class constructor.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are some corner cases around class constructor chaining that can
result in chained constructors not being called, or being called multiple
times.
This is primarily related to that a class can have either an explicit
constructor called `new` and an implicit constructor called `new@` and how
the lookup of them is done.
Lookup is currently done independently for the implicit and explicit
constructor using the `method_from_name()` method. `method_from_name()`
will search the whole class hierarchy for a class method. If a class
doesn't have a method by that name it will look in the parent class and so
on.
As a result the lookup for the explicit constructor can return the explicit
constructor of a parent class if the class itself only has an implicit
constructor and vice versa.
E.g. in the following example the constructor of D will not be called
because the implicit constructor for C is found when looking for a implicit
constructor in D.
```
class C;
int x = 10;
endclass
class D extends C;
function new;
$display("D");
endfunction
endclass
class E extends D;
int y;
function new;
y = 20;
endfunction
endclass
E e = new;
```
There is a similar case where the constructor of a base class can be called
multiple times if the base class has an explicit constructor and the
derived class has an implicit constructor. In that case the derived class
constructor will call the base class constructor, but the code that is
emitted for the `new` statement will call both of them.
To mitigate this introduce a new method to lookup the constructor that will
search for either the explicit or implicit constructor in the current class
and only continue to search in the base class if neither is found.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows to declare const variables. These variables are
read-only and can not be assigned a value after their declaration. It is
only possible to assign an initial value as an initializer.
E.g.
```
const int x = 10;
x = 20; // Error
```
The LRM requires that for variable declarations with static storage the
initializer is a constant expression with the extension that other const
variables are also allowed. const variables with automatic storage can
be initialized by any expression.
Checking if an expression contains only const variables requires a bit more
work to implement. So for now be more lenient that what the standard
requires and allow arbitrary expressions to initialize const variables even
for those with static storage.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows to use assignment patterns to assign values to an
array. E.g. `int a[4] = '{1, 2, 3, 4}`.
Each value is evaluated in the context of the element type of the array.
Nested assignment patterns are supported. E.g. `int a[2][2] = '{'{1, 2},
'{1, 2}};`
Add initial support for array assignment patterns for both continuous as
well as procedural assignments.
For continuous assignments the assignment pattern is synthesized into an
array of nets. Each pin is connected to one of the assignment pattern
values and then the whole net array is connected to target array.
For procedural assignments it is unrolled in the vvp backend. E.g
effectively turning `a = '{1, 2};` into `a[0] = 1; a[1] = 2;`.
Not yet supported are indexed initializers or `default`.
E.g. `int a[10] = '{1:10, default: 20};`
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
`ivl_assert()` is similar to `assert()` except that it will also include
source file and line information about the expression for which the assert
was triggered.
Use `ivl_assert()` instead of `assert()` where the line information is
available. This will generate better bug reports and make it easier to
diagnose why an assert is triggered.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
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>