Expression Type Requirements in Different Contexts
In Verilog and SystemVerilog there are dozens of places where an expression or identifier of a specific type is required, e.g., operators have expectations on operand types, there are limitations on what a class can extend or implement, etc. It may not be obvious at first glance if a variable or net type complies with these requirements. Such non-compliances will be detected and marked by Sigasi (rules 78, 79, 100 and 131).
Extending and Implementing
Interface classes can only extend other interface classes, while classes can only extend classes and only implement interface classes:
class Foo; endclass interface class Bar extends Foo; // Expected interface class but got 'class Foo' endclass class Baz extends Bar // Expected class but got 'interface class Bar' implements Foo; // Expected interface class but got 'class Foo' endclass
Types vs Value Expressions
While let
declarations are advertised as a replacement to preprocessor macros and they can have untyped arguments, you still cannot pass types as arguments (unlike selected system functions):
module test; let my_typename(expr) = {$typename(expr), "!"}; initial $display( "my: %s\nsys: %s", my_typename(int), // Expected value expression but got type: int $typename(int) ); endmodule
Operand Data Types
Unary logical reduction operators expect integral operands:
function logic parity(input real data); parity = ^data; // Expected integral expression but got 'real' parity = ^$realtobits(data); endfunction
Bit-stream Types
You can unpack a stream of bits into an unpacked struct if all its fields are of bit-stream types. Here, one of the struct fields is shortreal
which makes the whole struct non-streamable:
package pkg;
typedef struct {
shortreal data; // shortreal is not a bit-stream type
logic [6:0] unused;
logic parity;
} real_payload;
endpackage
module test (logic [39:0] data);
pkg::real_payload payload;
assign {>>{payload}} = data; // Expected bit-stream data expression but got 'struct pkg::real_payload'
endmodule
These are but a few examples. Sigasi Visual HDL checks numerous other expression expectations in different contexts in SystemVerilog, immediately showing incorrect types and variables usages.
Type Compatibility
Verilog and SystemVerilog’s type compatibility rules can be obscure, especially considering implicit type conversion and complex expression evaluation rules. To help you avoid any pitfalls, the type checker ensures that assigning ports, nets, or variables is done safely. Here are a few examples where Sigasi Visual HDL would report an error:
Unions and Structs
Even though these two union
s and struct
s have the same signature, they implicitly define two anonymous types; they are thus not assignment compatible.
String Variables and Literals
string
variables and literals behave differently.
null
cannot be assigned tostring
variables.- String variables cannot be assigned to
int
variables because they are dynamically sized ordered collections of characters that are not assignment compatible toint
. - However, string literals can be used to initialize
int
s as they are treated asunsigned integer
constants.
Syntax Confusion and Implicit Casting
- The concatenation and assignment pattern syntax confusingly resemble each other a lot.
- It is not always clear what assignments will be implicitly cast.
enum
s are implicitly cast toint
s, but not the other way around.
Classes
Subclasses can be assigned to superclasses, but not vice-versa. Every Apple
is a fruit, but not every Fruit
is an Apple
. Similarly, classes unrelated to one another (Fruit
and Vegetable
) are not assignment compatible.
Ref Ports
The type of the actual value should be equivalent to the formal ref
port type (rule 94).
module test;
task automatic inc(ref [3:0] value, input [3:0] amount);
value += amount;
endtask
bit [3:0] value = 10;
initial begin
// Expected expression type to be equivalent to target type 'logic [3:0]' but got 'bit [3:0]'
inc(value, 5);
$display(value);
end
endmodule