There are currently two rules for parsing variable declarations.
One that is used when declaring variables in as a block declaration item
and another that is use everywhere else.
Consolidate those into a single set of rules. This removes a fair bit of
duplicated code in the parser.
A side effect of this refactoring is that class new statements can be used
as variable initializers as allowed by the standard. E.g.
```
module test;
class C;
endlcass
C c = new C;
endmodule
```
This previously was not supported for block item variable declarations.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Variables don't have a delay or strength and the NetNet::Type is known. Add
a small wrapper around pform_makewire() that can be used to create
variables. This will allow to reduce the boilerplate code for variable
declarations.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are a few places where pform_makewire() is used and attributes can be
attached to the created net or variable. At the moment pform_makewire()
doesn't allow to specify the attributes, and they either get dropped
silently or with a warning.
Add support for passing the attributes to pform_makewire() which will then
pass it on to pform_set_data_type() to attach it to the declared net or
variable.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are currently two very similar implementations of pform_makewire().
One that takes a `net_decl_assign_t`, the other a `std::list<decl_assignment_t*>`.
The one that takes a `std::list<decl_assignment_t*>` is a superset of the
other. It can handle both wires and variables, while the other can only
handle wires.
Update the parser to generate a `std::list<decl_assignment_t*>` for wire
declarations. This allows to remove one of the two functions.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Most things that can be declared in a module can also be declared in a
generate block.
But there are a few exceptions that can not be declared in generate block
* module, program or interface declaration
* specify block or specparam
* timeunit
Some of these currently work while some of them trigger an assertion and
cause and application crash.
Add checks to make sure that all of them these are reported as an error and
do not cause a crash.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The "->" operator is rarely used, but exists. Unfortunately, the syntax
is tied up in a horrible mess with the System Verilog constraint list
syntax. Do some flex magic to make it all work.
SystemVerilog allows to omit the default value of a parameter declared in a
parameter port list. In this case the parameter must be overridden for
every module instance. This is defined in section 6.20.1 ("Parameter
declaration syntax") of the LRM (1800-2017).
In addition a module that has a parameter without a default value does not
qualify for automatic toplevel module selection.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are a few system functions that take either an expression or a data
type. This is implemented in the parser by allowing a type identifier as a
primary expression.
But those functions allow any data type, not just typedefs. E.g.
```
$bits(int);
$bits(reg [1:0]);
$bits(struct packed { int x; });
```
Support this by changing the parser rule from TYPE_IDENTIFIER to data_type.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows to completely omit the `parameter` keyword in a
module parameter port list. This is described in section 6.20.1 ("Parameter
declaration syntax") of the LRM (1800-2017).
E.g.
```
module a #(X = 10) ...
module b #(int Y = 20) ...
```
It also allows to redefine the parameter type without having to have a
parameter or localparam before the type.
E.g.
```
module a #(parameter int A = 1, real B = 2.0) ...
module b #(int X = 3, real Y = 4.0) ...
```
Extend the parser to support this.
Note that it is not possible to declare a parameter with an implicit data
type this way.
E.g. the following is not legal SystemVerilog
```
module a #([3:0] A = 1) ...
module b #(int X = 2, signed Y = 3.0) ...
```
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
When encountering a construct that requires SystemVerilog in most cases an
error message is generated when SystemVerilog is not enabled and parsing
simply continues.
Factor the checking and generating of the error message into a helper
function. This slightly reduces boiler plate code and gives consistent
error messages.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
A base class can be referenced by scope. E.g. if the base class is in a
package.
```
package P;
class B;
endclass
endpackage
module test;
class C extends P::B;
endlcass
endmodule
```
To support this let the parser accept a scope identifier for the base
class.
A small change is also necessary to how the base class lockup is done
during elaboration. At the moment the code will search for the base class
by name in the current scope. This doesn't work with scoped identifiers.
But we already have a reference to the base class data type, so we don't
have to search for it by name.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are multiple places in the grammar where either a type identifier or
scoped type identifier is accepted.
Factor this into a common parser rule. This removes some duplicated code.
But it will also be required to avoid reduce-reduce conflicts for future
grammar extensions, e.g. to support type parameters.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently when encountering an end label on a unnamed block
a 'syntax error' will be generated and the parser will give up.
Slightly refactor the parser so that this case is detected, a more specific
error message is generated and the parser can recover and continue.
This also slightly reduces the parser since it allows to merge the almost
identical rules for handling named and unnamed blocks.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Most named constructs support a end label in SystemVerilog. The handling of
this end label is always the same.
* Generate an error if the end label does not match the name of the block
* Generate an error if not in SystemVerilog mode
* Delete the end label
Factor this into a common helper function. This reduces code size a bit and
results in consistent error messages.
The latter requires refreshing of some gold files to match the slightly
different error messages.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
While it is not a particular useful construct it is legal to have a
parallel block with just variable declarations and no statements. E.g.
```
fork
int x;
join
```
At the moment there is a special rule for completely empty parallel
blocks. Remove that rule and change the statement_or_null_list in the
fork/join parser section to a statement_or_null_list_opt. This way it
covers both completely empty parallel blocks as well as parallel blocks
with only variable declarations.
Note that this already works as expected for named parallel blocks.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
When declaring module parameters in the ANSI style parameter list it is
possible to omit the `parameter` or `localparam` keyword. In this case
whether the parameter is local or non-local is inherited from the previous
parameter.
In the current implementation when the type of the parameter is not
specified it will always use parameter. E.g. the following will create a
localparam A and a parameter B, while it should be localparam A and B.
```
module #(localparam A = 1, B = 2);
```
Fix this by remembering whether the previous entry was a parameter or
localparam. This is similar to how the parameter data type is already
remembered.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Verilog-AMS defines parameter value ranges which can restrict the value
that can be assigned to a parameter. It defines this for both `parameter`
and `localparam`. Currently it is only implemented for `parameter`. Support
it for `localparam` as well for consistency.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The code for handling parameter and localparameter declarations is very
similar. Consolidate this into a single helper function.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
While it is not a particular useful construct it is legal to have a
begin/end block with just variable declarations and no statements. E.g.
```
begin
int x;
end
```
At the moment there is a special rule for completely empty begin/end
blocks. Remove that rule and change the statement_or_null_list in the
begin/end block parser section to a statement_or_null_list_opt. This way it
covers both completely empty blocks as well as blocks with only variable
declarations.
Note that this already works as expected for named begin/end blocks.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
packed structs and packed unions as a whole can either be signed or
unsigned. This information is used when it is used as a primary in an
expression, i.e. without accessing any of the members.
Add support for parsing and elaborating signed structs.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Allow scoped identifiers to be used as the base type for packed array
types. Scoped type identifiers can be used the same way as unscoped type
identifiers.
E.g.
```
package p;
typedef logic [1:0] vector;
endpackage
module test;
p::vector [1:0] pa;
endmodule
```
is a valid construct.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
It is possible to directly declare a packed array of a struct or enum,
without having to typedef the struct or enum first. E.g.
```
struct packed {
int x;
} [1:0] pa;
```
Add support to the parser for handling this.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
When creating an enum type it must be added to the scope where it is
declared so it can later be elaborated and the enum and its names can be
referenced in expressions.
In addition the names of the enum must be added to the lexor scope so that
name collisions are detected and can be reported as errors.
This is done with pform_put_enum_type_in_scope() function.
At the moment the function is called from two different places
* When adding a typedef of a enum type
* When creating a signal of a enum type
In addition the enum_type_t is added to a class scope `enum_sets` when
declaring a enum property in a class. But this only makes sure that the
enum gets elaborated, its names are not added to the lexor scope.
This works fine for the most part, but breaks for a few corner cases.
E.g. it is possible to declare a enum type as part of the subtype of
another packed type such as structs or packed arrays. E.g.
```
struct packed {
enum {
A
} e;
} s;
```
This is not covered by either of the cases above and neither do the names
of the enum get added to the lexor scope, nor is the enum type elaborated.
Another corner case that is currently not working is declaring a class
property where the type is a typedef of a enum that is declared outside of
the class. In this case the enum is elaborated again inside the class
scope. E.g. the below is supposed to work, but fails with an already
declared symbol error.
```
typedef enum {
A
} e_t;
class C;
typedef enum {
A
} e1;
e_t e2;
endclass
```
In addition since for enums declared in classes they are only added to
`enum_sets`, but names are not added to the lexor scope, it is possible to
declare a different symbol in the class scope with the same name.
E.g. the following elaborates fine
```
class C;
enum {
A
} e;
typedef int A;
endclass
```
To fix this call pform_put_enum_type_in_scope() when the enum_type_t is
created in the parser. This makes sure that it is handled the same
regardless where the type is declared or used.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Refactor the enum rule by adding a enum_base_type rule which handles the
type specific initialization. This allows to keep the non-type specific
parts in a common rule, which makes it easier to modify in future changes.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
When something goes wrong when parsing a struct member, e.g. the type does
not exist, a nullptr is added to the struct member list. This will cause a
crash when iterating over the list.
E.g.
```
struct packed {
logc x;
} s;
```
Add a check so that nullptr members are not added to the list.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
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.
Unless explicitly declared a wire an enum output port is of variable type
and should be marked as IMPLICT_REG.
Currently this is only done when the base type of the enum is `logic`. But
it should be done for all enums regardless of their base type.
Without this change for example the following snippet
```
typedef enum {
A,
B
} E;
module M (
input E ei,
output E eo
);
always_comb eo = ei;
endmodule
```
fails with the following error message
test_enum.sv:11: error: eo is not a valid l-value in M.
test_enum.sv:8: : eo is declared here as wire.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
For functions without a port list in parantheses, declarations are optional in SystemVerilog.
This is true even in IEEE1800-2005, but not in IEEE1364-2005
The unique, unique0, and priority keywords can decorate case statements
to tell the run time (or synthesis) to do extra tests (or make extra
assumptions). These tests are not implemented in the vvp run time, but
now the decorations make it to the code generators.
Explicit imports should always conflict with local declarations using
the same name. Wildcard imports only conflict if they are referenced
before a local declaration with the same name.
This also unifies the detection of identifier conflicts.
As reported on iverilog-devel on 2018-10-12, a dimension size of zero
could case the compiler to go into an infinite loop. Further tests
showed that unsized or queue dimensions entered as packed dimensions
would cause the compiler to crash.
- make primitive redefinition a warning, not an error
- make edge-sensitive ifnone a warning, not an error
This allows Icarus to be used to simulate designs using third-party
cell libraries that contain such things.
In traditional Verilog, each task_port_item must have an explicit port
direction.
In SystemVerilog, if the port direction is not specified, it should be
inherited from the preceding task_port_item for that task/function, and
only the first task_port_item should infer the direction to be 'input'.
This implements and enforces the full set of rules for determining
timescales in SystemVerilog. The previous relaxation of the rules
that allowed timescales to be redefined within the compilation unit
scope has been removed. Time unit and precision redeclarations are
now recognised after a nested module declaration.
(* my_fancy_attribute *)
foobar1 foobar (clk(clk), rst(rst) ...);
- Modifies PGModule to hold the attribute map (can be verified with pform_dump)
- pform_make_modgate(s) bind the attributes from the parser to the above map
- The attributes from PGModule are inserted into the NetScope of that module
PGModule::elaborate_scope_mod_instances_
- Currently these attributes automatically make it into netlist
- These attributes are accessible via ivl_scope_attr_cnt and ivl_scope_attr_val
from ivl_target.h
Replace explicit comparisons against generation_flag with calls to
the gn_system_verilog helper function, both for code clarity and
to fix a couple of bugs. Also simplify the implementation of the
function, as we already rely on the generation_flag enumeration
being an ordered list.
This just enables the compiler to parse path declarations that
contain part selects. As for bit selects, the part select is
discarded, and if elaboration of specify blocks is enabled,
the path declaration will be applied to the entire vector. If
elaboration is enabled, a warning message will now be output
when a bit or part select is discarded.