Commit Graph

711 Commits

Author SHA1 Message Date
Lars-Peter Clausen 8f78590bd2 Remove most references to ivl_variable_type_t from the parser
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>
2022-09-15 09:36:19 +02:00
Lars-Peter Clausen b307da0831 pform_make_task_ports(): Reuse `pform_set_net_range()`
`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>
2022-09-15 09:36:19 +02:00
Stephen Williams b1bafe5e02
Merge pull request #766 from larsclausen/remove-unused
Remove unused functions/methods
2022-09-14 09:27:00 -07:00
Stephen Williams fa0217af87
Merge pull request #764 from larsclausen/module-port-list-default
Support default port values in port declarations lists
2022-09-14 09:25:33 -07:00
Lars-Peter Clausen f1e50e927b Remove unused `make_range_from_width()`
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>
2022-09-14 13:50:31 +02:00
Lars-Peter Clausen a19a07254b Support default port values in port declarations lists
Both Verilog (2005) and SystemVerilog support default port values for
variable output ports. SystemVerilog also supports default port values for
input ports. For port declaration lists it is possible to specify the
default value for port identifier.

E.g.

```
module M (
  input integer x, y = 1,
  output integer z, w = 2
) ...
```

Currently the parser only supports specifying the default value for the
first identifier in the list. Extend the parser to also allow to specify
the default value for identifiers in the list.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2022-09-13 14:14:41 +02:00
Lars-Peter Clausen a9bd522fd3 parser: Add a helper rule for optional initializers
There are a few places where it is possible to provide an optional
initializer in the form of `[ = <expression> ]`.

There are currently multiple rules that implement this behavior as well as
few places with duplicated rules, one with and one without the initializer.

Introduce a common helper rule for optional initializers. This allows to
remove some duplicated code from the parser.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2022-09-13 14:14:41 +02:00
Lars-Peter Clausen dd4ae93942 Fix port direction for output port declaration lists with default value
For output port lists with a default value for the first port declaration
all subsequent port declarations are declared as inout ports. This is due
to a small typo when setting the `port_declaration_context` port direction.

Fix this to make sure all ports in the port declaration list are declared
as output ports.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2022-09-13 13:41:46 +02:00
Lars-Peter Clausen a73ee3e3e7 Add support for SystemVerilog sign cast
SystemVerilog supports sign cast where it is possible to change the
signedness of an expression. Syntactical it is similar to width or type
casting, except that the keywords 'signed' or 'unsigned' are used in front
of the cast operator. E.g.

```
  logic [3:0] a = 4'b1000;
  logic [7:0] b = signed'(a); // b is 8'b11111000;
  logic signed [3:0] c = 4'b1000;
  logic signed [7:0] d = unsigned'(c); // d is 8'b00001000;
```

As noted by the LRM section 6.24.1 ("Cast operator") applying a sign cast
to an expression is equivalent to calling the $signed() and $unsigned()
system functions on the expression.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2022-09-11 19:06:22 +02:00
Lars-Peter Clausen d753e6a5d0 Add SystemVerilog `var` keyword support
SystemVerilog adds the `var` keyword that can be used to declare a signal
as a variable.

In contexts where a signal is always a variable it is purely optional and
it makes no difference whether it is specified or not. This is in
  * for loop variable declarations
  * task and function port declarations

For variable declarations as block items when `var` is used it is possible
to omit the explicit data type and use a implicit data type instead. E.g.
all of the following are valid.

```
var x;
var signed y;
var [1:0] z;
```

For module input and output ports the `var` keyword can be used in place of
the net type. It can be combined with either an implicit or explicit data
type.

E.g.
```
input var x
output var [1:0] y
```

inout ports can not be variables and will be reported as an error.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2022-09-10 21:39:10 +02:00
Lars-Peter Clausen 134e7d6f08 Refactor variable lifetime parser rules
Refactor the variable lifetime parser rules so that instead of having too
rules, one with lifetime and one without, there is a single rule where the
lifetime is an optional element.

This helps to avoid a combinatorial explosion of parser rules once we
add `var` support.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2022-09-10 21:39:10 +02:00
Lars-Peter Clausen 8b0346d7b5 Recover from parser errors in all variable declarations
Currently the parser can recover from `integer` or `time` variable
declarations, but not for variables of other types. Refector the parser
rules so that it can recover for all variable types as well as events.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2022-09-10 21:39:10 +02:00
Lars-Peter Clausen e15b125da8 Replace svector with std::vector
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>
2022-05-15 21:56:48 +02:00
Lars-Peter Clausen dddc41891e lgate: Inherit from LineInfo
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>
2022-04-24 17:00:46 +02:00
Lars-Peter Clausen 254e9dc094 pform_set_data_type(): Avoid signal look-up by name
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>
2022-04-18 12:07:16 +02:00
Lars-Peter Clausen 52da910313 Move pform_set_reg_idx() into pform_makewire()
`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>
2022-04-17 09:22:47 +02:00
Lars-Peter Clausen 7aee124cfe pform_makewire(): Remove unused parameters
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>
2022-04-17 09:22:31 +02:00
Stephen Williams 7c5694e516
Merge pull request #673 from larsclausen/package-no-implicit-var
Require explicit data type for package variable declarations
2022-04-10 15:06:26 -07:00
Stephen Williams 3da5b4cf65
Merge pull request #664 from larsclausen/integer-port
Correctly handle separate port type declaration for integer types
2022-04-10 15:05:48 -07:00
Lars-Peter Clausen 8f6a9c5d3c Require explicit data type for package variable declarations
Variable declarations in packages need an explicit data type. Omitting the
data type or using just packed dimensions is not valid syntax. E.g. the
following should not work.

```
package P;
  x;
  [1:0] y;
endpackage
```

The current implementation does accept this tough. To fix this update the
parser to only allow explicit data types for package variable declarations.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2022-04-09 09:15:19 +02:00
Lars-Peter Clausen f6042033d0 Correctly handle separate port type declaration for `integer` and `time`
When using non-ANSI style port declarations it is possible to declare the
port direction and the data type for the port in separate statements. E.g.

```
input x;
reg x;
```

When using packed array dimensions they must match for both declarations.
E.g.

```
input [3:0] x;
reg [3:0] x;
```

But this only applies for vector types, i.e. the packed dimension is
explicitly declared. It does not apply to the `integer` and `time` types,
which have an implicit packed dimension.

The current implementation requires that even for `integer` and `time`
types the implicit dimension needs to be explicitly declared in the port
direction. E.g. the following will result in a elaboration error
complaining about a packed dimension mismatch.

```
module test;
  output x;
  integer x;
endmodule
```

Currently the parser creates a vector_type_t for `time` and `integer`. This
means that e.g. `time` and `reg [63:0]` are indistinguishable during
elaboration, even though they require different behavior.

To fix let the atom2_type_t handle `integer` and `time`. Since it no longer
exclusively handles 2-state types, rename it to atom_type_t.

This also fixes a problem with the vlog95 target unit tests. The vlog95
target translates

```
module test(output integer x);
endmodule
```

to

```
module test(x);
  output x;
  integer x;
endmodule
```

which then fails when being elaborated again. There were some regression
tests that were failing because of this that will now pass.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2022-03-28 10:40:06 +02:00
Lars-Peter Clausen 51eae02e78 Support class method calls without parenthesis
It is possible to call a class method without parenthesis if no arguments
are specified.

At the moment this works when calling a class method by name. But when
using the implicit class handle `this` or `super` it does not work.

Add support for this.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2022-03-28 10:13:58 +02:00
Lars-Peter Clausen da5b9a4e5f Support class constructor without parenthesis
Class constructors can be declared without parenthesis after the `new` when
no arguments are required. Just like for normal function.

In a similar way the base class constructor can also be invoked without
parenthesis after the `new`.

```
class C extends D;
  function new;
    super.new;
  endfunction
endclass
```

Add support for this by making the parenthesis optional in the parser.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2022-03-28 10:13:58 +02:00
Lars-Peter Clausen e3bc99dbf3 Don't allow non-ANSI ports for class constructors
Class constructors don't allow for non-ANSI ports. E.g. the following is
not valid.

```
class C;
  function new();
    input int i;
  endfunction
endclass
```

The parser will currently accept this, but otherwise ignore the non-ANSI
port. Modify the parser rules so that this is a syntax error.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2022-03-28 10:13:58 +02:00
Lars-Peter Clausen 967e3455fe Add parser helper rule for class identifiers
There are a few places in the grammar that follow the pattern of
`implicit_class_handle '.' hierarchy_identifier` and then splice the two
identifier paths into a single one. Factor this into a common helper rule
to avoid duplicated code.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2022-03-28 10:13:58 +02:00
Lars-Peter Clausen 9810ce6e60 Add parser helper rules for optional argument list
There are a few places in the grammar where it is possible to specify a
argument list in parenthesis or nothing. E.g. a task invocation.

```
task t(int a = 10);
endtask

initial begin
  // All 3 are valid syntax
  t(1);
  t();
  t;
end
```

Factor this out into a common rule to be able to remove some duplicated
code.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2022-03-28 10:12:24 +02:00
Lars-Peter Clausen ad9f5a3aa6 Add parser helper rule for optional task port list
There are a few places in the grammar where it is possible to specify a
task/function port list in parenthesis or nothing. E.g. task and function
prototypes. Factor this out into a common rule to be able to remove some
duplicated code.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2022-03-28 10:11:37 +02:00
Stephen Williams d480c4d7d0
Merge pull request #659 from larsclausen/typedef-overwrite
Support typedef overwrites with unpacked dimensions and in classes
2022-03-27 15:49:55 -07:00
Lars-Peter Clausen 4bf0d62cd1 Support type identifier base type for enum
The base type for an enum type can be a type identifier for a typedef as
long as it resolves to a vector or integer type with at most one packed
dimension. This is described in section 6.19 ("Enumerations") of the LRM
(1800-2017). E.g.

```
typedef bit [3:0] T;
enum T {
 A
} e;
```

Add support for this by allowing to specify a type identifier as the base
type for an enum in the parser. During elaboration it is checked whether
the type identifier resolves to a valid enum base type.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2022-03-25 21:55:34 +01:00
Lars-Peter Clausen b30d3fc8d7 Support typedef overwrites in class scopes
It is possible to declare a new typedef that shadows an existing typedef in
a higher level scope. E.g.

```
typedef int T;
class C;
  typedef real T;
endclass
```

In the current implementation this works for scopes that are not class
scopes.

Update the parser to also support this in class scopes by re-using the
existing parser rule that is used for the other scopes.

Reusing the existing rule also adds support for class forward typedes
inside classes.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2022-03-23 10:53:56 +01:00
Lars-Peter Clausen 23e1143ad6 Support unpacked dimensions on typedef overwrites
It is possible to declare a new typedef that shadows an existing typedef in
a higher level scope. E.g.

```
typedef int T;
module M;
  typedef real T;
endmodule
```

In the current implementation this only works as long as the new type is
a not an array type.

Update the parser to allow to specify unpacked dimension when overwriting
a typedef from a different scope.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2022-03-23 10:53:56 +01:00
Lars-Peter Clausen aaffceff42 parser: Fix UDP registered output syntax
The parser currently expects `reg output` for UDP registered output. But
the correct syntax is `output reg`. Fix this to accept the correct syntax.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2022-03-19 12:59:20 +01:00
Stephen Williams 5bc1c08c67
Merge pull request #641 from larsclausen/lineinfo
parser: Consistently pass line information as `vlltype`
2022-03-13 14:35:09 -07:00
Lars-Peter Clausen 56f36a96d3 parser: Consistently pass line information as `vlltype`
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>
2022-03-12 16:18:31 +01:00
Lars-Peter Clausen 3939126625 Handle empty class item declarations in parser
The SystemVerilog grammar explicitly allows an empty class item
declaration. The empty class item declaration is just a semicolon and has
no effect.

E.g. the following is legal
```
class C
  int x;;;
endclass
```

Add support to the parser to accept empty class item declarations.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2022-03-11 21:33:57 +01:00
Lars-Peter Clausen f67cdddecf Don't make input `integer` ports variables
In Verilog module input ports can only have a packed dimensions and a
signed flag, but no explicit data type.

In SystemVerilog an explicit data type can be specified for module input
ports. Such a port is a net, regardless of the data type, unless
explicitly made a variable using the `var` keyword.

This works for the most part in the current implementation, but for some
data types such as `reg` and `integer` the input port is turned into a
variable. And since input port's can't be variables in the current
implementation this results in an error.

Fix this by completely removing the `reg_flag` that is used to indicate
that a certain data type is always a variable. There is no such restriction
on data types for SystemVerilog and for Verilog there are already checks in
place that a input port can only have an implicit (or real) data type.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2022-03-03 10:30:28 +01:00
Lars-Peter Clausen 472598dd74 Report errors for nets with invalid data type
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>
2022-03-03 10:30:12 +01:00
Stephen Williams 5b65a583a1
Merge pull request #628 from larsclausen/module-output-var-types
Make output ports with data type variables
2022-02-27 15:08:46 -08:00
Lars-Peter Clausen 046893d97f Make output ports with data type variables
In SystemVerilog output ports are a variable if either:
 * They are explicitly declared a variable (with the `var` keyword)
 * There is no explicit net type, but a explicit data type

This is in detail described in section 23.2.2.3 ("Rules for determining port
kind, data type, and direction") of the LRM (1800-2017).

E.g.
```
output x // Net
output [1:0] x // Net
output signed x // Net
output wire x // Net
output wire logic x // Net
output var x // Variable
output logic x // Variable
output var logic x // Variable
output int x // Variable
output real x // Variable
output string x // Variable
output some_typedef x // Variable
```

At the moment the code checks for certain data types and only makes the
output port a variable for those. And it is even different data types
depending on whether the port is declared ANSI or non-ANSI style.

Change this so that if a data type is specified and it is not a implicit
data type (i.e. only ranges or `signed`) then the output is of type
variable.

This ensures consistent and correct behavior.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2022-02-27 13:28:26 +01:00
Lars-Peter Clausen 28bbebf98c Consolidate task and function item parser rules
Task and function item rules are identical. Consolidate them into a single
set of rules to remove some duplicated code.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2022-02-27 11:35:59 +01:00
Stephen Williams 978717f914
Merge pull request #623 from larsclausen/task-ports-sv
Support SystemVerilog non-ansi task/function port declarations
2022-02-26 09:16:33 -08:00
Lars-Peter Clausen b0c386182a Support unpacked array dimensions on non-ansi style task ports
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>
2022-02-25 10:43:28 +01:00
Lars-Peter Clausen c631ff2483 Support SystemVerilog types for non-ansi task port declarations
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>
2022-02-25 10:42:56 +01:00
Lars-Peter Clausen d104e28dbf Support non-overridable parameters in classes
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>
2022-02-19 13:45:22 +01:00
Stephen Williams cc0a8c8dd2
Merge pull request #618 from larsclausen/signal-decl-consolidation
Consolidate signal declaration
2022-02-18 08:27:52 -08:00
Lars-Peter Clausen f6394c5fe6 Consolidate variable declaration parsing rules
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>
2022-02-18 11:59:09 +01:00
Lars-Peter Clausen 9da057ceb1 Add helper function for creating variable declarations
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>
2022-02-18 11:59:09 +01:00
Lars-Peter Clausen 6708c0f6df pform_makewire(): Allow to specify attributes
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>
2022-02-18 11:59:09 +01:00
Lars-Peter Clausen a5e9358d42 Consolidate pform_makewire() variants
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>
2022-02-18 11:58:31 +01:00
Lars-Peter Clausen 6730ead119 Generate error for invalid declarations within generate block
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>
2022-02-16 11:23:39 +01:00