The parser used to have behavior that was dependent on the
`ivl_variable_type_t` of a signal. It also used the `ivl_variable_type_t`
of a signal to decide whether a signal can be re-declared as part of a
non-ANSI port declaration.
Neither of these is done anymore and most of the reference to
`ivl_variable_type_t` can be removed from the parser. The only thing it is
still needed for is to decide whether a vector type is 4-state or 2-state.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
`pform_make_task_ports()` has code very similar to `pform_set_net_range()`.
Use that helper function instead of duplicating the code.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The last user of the `make_range_from_width()` was removed in commit
f6042033d0 ("Correctly handle separate port type declaration for
`integer` and `time`").
Remove the function itself as well.
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 lgate struct has its own fields for tracking file and line number,
while everything else that has this information attached inherits from the
LineInfo class.
Make lgate also inherit from LineInfo for consistency.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The `pform_set_data_type()` function is used to set the data type as well
as attributes on a list of signals. Currently the signals are passed as a
list of signal names and then the function looks up the actual signals from
the names.
Refactor the code to directly pass a list of signals. This will allow to
skip the look-up by name.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
`pform_set_reg_idx()` is always called right after `pform_makewire()`. Move
it into the function. This avoids the extra lookup that
`pform_set_reg_idx()` does to get the PWire from the name.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are a few parameters for `pform_makewire()` and related functions
that always get passed the same value.
* port_type is always NetNet::NOT_A_PORT
* attr is always 0
Remove these parameters.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The `pform_set_param_from_type()` function is not used. The last user was
removed in commit 16646c547c ("Rework parsing of parameter types").
Remove the function itself.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are a couple of different functions for the different data types that
are called when the type of a signal is set. But they all effectively do
the same.
Consolidate this code by moving the common code into the main
pform_set_data_type() function.
This allows to remove most of the type specific functions and eliminates
some duplicated code. It ensures consistent and data type independent
behavior at the parser level. Something that will be required to eventually
support type parameters.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently there is a mix of passing line information either as `struct
vlltype` or as a separate `const char *file` and `unsigned lineno`.
For consistency always use the struct vlltype variant.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There is a function prototype for `pform_make_reals()`, but the function
is never declared nor used. Remove it.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
While a variable can have any data type the data type for nets is quite
restricted.
The SystemVerilog LRM section 6.7.1 ("Net declarations with built-in net
types") requires that the data type of a wire is either a 4-state packed or
a unpacked struct or unpacked array of 4-state packed types.
As an extension to this iverilog allows real data type for wires as well as
2-state packed types.
Add a check that reports an error if a net with any other type is declared.
In addition in Verilog a net can not have an explicit data type at all. It
can only have a packed dimension and a signed flag. As an extension to this
Icarus also allows wires to be of `real` data type.
Note that in Verilog mode the data type is checked in the parser since only
the parser knows whether the data type is an implicit type (`input reg
[7:0]` and `input [7:0] x` elaborate the same). But for SystemVerilog the
type is checked during elaboration since due to forward typedefs and type
parameters the type is not necessarily known in the parser.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows unpacked array dimensions on non-ANSI style task and
function ports.
To support this refactor pform_make_task_ports() to accept a of
pform_port_t, which in addition to the identifier name also allows to
specify per port unpacked dimensions.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Tasks and functions support two types of port declarations. Either ANSI
style, in parenthesis after the task name, or non-ANSI style, as
declaration statements in the task body.
In the current implementation SystemVerilog types are only accept for ANSI
style port declarations, while non-ANSI style only accept Verilog types
(reg, integer, time, real).
Add support for SystemVerilog data types for non-ansi style ports.
This also makes the parsing rules simpler since we can use `data_type` to
match all data types and don't need a explicit rule for each supported data
type.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows `parameter` and `localparam` to declare constants
within a class scope. E.g.
```SystemVerilog
class C;
localparam A = 10;
endclass
```
In this context both declare a local parameter that can not be overwritten.
Supporting this can be achieved for the most part by adding a parser
sub-rule in class declaration rule. In addition some extra support code is
needed to mark the parameter as non-overridable.
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>
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>
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>
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>
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>
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.
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.
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