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>
For modules, programs and interfaces that have a parameter port list, a
parameter declared inside the scope's body is supposed to be elaborated as
a local parameter.
TThis is described in the Verilog LRM (1364-2005) section 4.10.1 ("Module
parameters") and the SystemVerilog LRM (1800-2017) section 6.20.1
("Parameter declaration syntax").
Implement this by marking a parameter declared in such a way as
non-overridable.
Note that a parameter declared within a named block, function or task can
still be overridden, even if the module has a parameter port list.
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>
SystemVerilog allows to use the `parameter` keyword in a generate
block. If used in a generate block it behaves like a `localparam` and
cannot be overridden.
This is described in section 27.2 ("Generate constructs - Overview") of the
LRM (1800-2017).
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Parameters declared in certain scopes behave like local parameters and can
not be overridden. Rather than making those parameters a localparam track
whether a parameter can be overridden.
This allows to generate better error messages when trying to override the
parameter.
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>
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>
enum_type_t inherits from LineInfo, but also has a LineInfo field called
`li`.
When a enum_type_t is created the LineInfo of the object itself is set to
the location where the type is declared.
The `li` field gets set when a signal of the enum_type_t is created to the
location where the signal is created. The `li` field is then used when
elaborating a netenum_t to set the line information on the netenum_t.
This works fine when the enum is directly used to declare a signal, since
the location of the type and signal declaration are the same and there is
only one signal of that type.
But when using a typedef and declaring multiple signals with the same type
the `li` field will be repeatedly set and eventually point to the last
signal declaration of that type.
On the other hand when using or declaring an enum as part of an aggregate
type such as an array, struct or class the line info will never be
set.
This can cause misleading error messages. E.g.
```
typedef enum {
A, B = A
} e_t;
struct packed {
e_t e;
} s;
```
will generate
```
:0: error: Enumeration name B and A have the same value: 32'sd0
```
To fix this use the LineInfo that was assigned to the enum_type_t itself
when it was declared and remove the `li` field.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
enums for a scope are stored in a std::set. This means when iterating over
the enums during elaboration it is possible that they are elaborated in a
different order than they have been declared in. This causes problems if
one enum references items of the other enum. E.g.
```
enum {
A
} a;
enum {
B = A
} b;
```
In the current implementation whether this works or not depends on the
pointer values of the enum_type_t for `a` and `b`, which can change between
environments.
To make sure that enums are elaborated in the same order use a std::vector
instead of a std::set.
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>
When creating a signal of a packed array it is checked that the base-type
of the packed array is a packed type.
But this check is only done if the packed array itself is the type of the
signal. Placing the packed array in a struct or class will elaborate fine,
but then crash during simulation.
E.g.
```
typedef real myreal;
struct packed {
myreal [1:0] p;
} s;
```
Move the check from signal creation to type elaboration, so that it is not
possible to create a packed type with a non-packed base-type.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Specifying and enum with an invalid dimension range results in an assert or
segfault. E.g. `enum [$] E { ... }`.
Use the `evaluate_ranges()` function to elaborate the enum dimensions. This
functions has proper error checking and recovery built-in.
In addition verify that there is at most one packed dimension.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The IEEE standard specifies that the numbering of generate blocks
restarts at 1 in each new scope, and that the 'else' part of an 'if'
construct is part of the same constuct, so has the same number.
This eliminates some indeterminism in the error messages, which was
causing occasional failures in CI. We don't expect this list to be
very large, so the O(n) insertion time should not be a problem.
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.
The compiler elaborates types on the fly as they are used. For user-
defined types (typedefs) we must do the elaboration in the scope where
the type was declared, not in the scope where it is used.
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 fixes the problem reported in GitHub issue #254, where if the
parser aborted on one compilation unit, spurious errors were reported
for the next compilation unit.
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.
The compilation unit scope is now treated as a specialised form of
package (with an automatically generated name). All items declared
outside a design element are added to the current compilation unit
package. Apart from when searching for a symbol, once we get into
elaboration we can treat these just like any other package.
This adds a -u option to the driver to allow the user to specify that
they want each source file to be treated as a separate compilation
unit, and modifies the compiler to accept a list of files (either on
the command line or via a file specified by a new -F option). This
list of files is then preprocessed and parsed separately, causing all
compiler directives (including macro definitions) to only apply to the
file containing them, as required by the SystemVerilog standard.
Two fixes needed:
- when searching for a base class, we need to look in the root scope
if the base class isn't found in the scope hierarchy
- the classes in the root scope need to be stored in an ordered
list, not a map, to ensure they are elaborated in the order they
were declared. Without this, the compiler may try elaborating an
extended class before its base class is known about.
If there is a syntax error in the source code, pform_makegate may be
passed a null list of port connections. The error is already reported,
so we just need to ignore it.
(* 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.
SystemVerilog allows tasks, functions, and classes to be defined at the
root level or inside packages, so we can't rely on an enclosing module
being present to provide the timescale.
If a static variable declared in a task, function, or block has an
initialisation expression, SystemVerilog requires the declaration to
have an explicit static lifetime. This is supposed to be a compile
error, but for now just output a warning.
Implementing this required adding support in the parser for explicit
lifetimes in variable declarations. For now, just output an error if
the user asks for a lifetime that isn't the default for that scope.
parse.y has been updated to allow declarations outside a module (legal
in SystemVerilog), but not all types of declaration are supported yet.
Output a sorry or error message as appropriate.
First area of Change for "Microsoft Visual Studio Express 2015 RC Web" was for compiling with error when NDEBUG defined. The second and third areas of change for "Microsoft Visual Studio Express 2015 RC Web", the dynamic_cast has to come first so parpkg_test.v, parpkg_test1.v, parpkg_test2.v would pass.