Default argument dimension & type in SV subroutines

Hi All,

I was referring to following quote from SV LRM: 13.3 Tasks

An array can be specified as a formal argument to a task. For example:
// the resultant declaration of b is input [3:0][7:0] b[3:0]
task mytask4(input [3:0][7:0] a, b[3:0], output [3:0][7:0] y[1:0]);
...
endtask

(Q1) I am aware that all 3 arguments would be of logic type and that b inherits input direction, but why does b inherit the packed dimensions ( [3:0][7:0] ) from a?

SV LRM: 13.3 Functions states ::

To indicate the return type of a function, its declaration can either include an
explicit data_type_or_void or use an implicit syntax that indicates only the
ranges of the packed dimensions and, optionally, the signedness.
When the implicit syntax is used, the return type is the same as if the implicit 
syntax had been immediately preceded by the logic keyword. In particular, the
implicit syntax can be empty, in which case the return type is a logic scalar. 

So, function [15:0] f1(); // f1() has default return type as logic [15:0]

(Q2) Where would the keyword signed be written? After or before the packed dimensions?

function [15:0] signed f1_sign1();
       // or
function signed [15:0] f1_sign2(); 

Same section of the LRM states

Once a direction is given, subsequent formals default to the same direction.
The const and static qualifiers on the ref direction are included in this default.

I get the first line that directions are sticky. If the 2nd argument is missing a direction, it will inherit it from 1st argument

(Q3) What does the 2nd line ( The const and static …. ) mean?

(Q4) Does the LRM mention regarding inheriting packed dimensions from previous arguments?

(a) In below function declaration, would ‘b’ inherit the packed dimensions [3:0][7:0] ?

// Is 'b' implicitly input logic [3:0][7:0] b [3:0] ?
function [3:0][7:0] myfunc4(input [3:0][7:0] a, b[3:0]);
....
endfunction 

(b) In below function declaration, does y inherit packed dimension [7:0] ?

// Is 'y' of type input logic [7:0] y ?
function [15:0] myfunc1 (input [7:0] x,y);
 myfunc1 = x * y - 1; // return value assigned to function name
endfunction

Thanks

Answering your questions requires a basic understanding of the formal syntax (BNF).

A data type is defined as follows:

data_type ::=
  integer_vector_type [signing ] { packed_dimension }
| integer_atom_type [ signing ]
| type_reference
| // a few more terms I left out
integer_vector_type := bit | logic | reg
integer_atom_type := integer | int | byte | …
signing ::= signed | unsigned

The optional {packed dimension} is considered part of the basic data type. Note that the identifier declaration for packed_dimension appears to the left of the identifier, while the declaration for unpacked_dimension appears to the right. It is not considered part of the basic type, but rather a complex or aggregate type. In a list of identifier declarations, if no basic data type is specified for the next identifier, the basic data type of the previous identifier is inherited. So, to answer (Q1) and (Q4), b inherits the basic type, which includes the packed dimension but not unpacked dimensions. You can circumvent this BNF restriction by using a typedef because it’s considered a basic type syntactically.

typedef int array_t[]; // dynamic array
task mytask4(input array_t a, b, c[]);

The input arguments a and b are both dynamic arrays of int. c is a two dimensional dynamic array of int

The BNF I’ve shown at the beginning dictates where the signed or unsigned keywords should appear, (Q2).

The ref qualifiers: const and static are explained in section 13.5.2 Pass by reference of the IEEE 1800-2023 SystemVerilog LRM. A const ref argument is read-only and never written from within the procedure. It doesn’t imply that it has a constant value. A ref static argument must be passed with an actual argument that has a static lifetime. With plain ref arguments, there are many restrictions on what you can do with them because, inside the task, you are unaware of the lifetime of a variable passed by reference. ref static arguments can have non-blocking assignments and be reference inside fork/join_none blocks.

1 Like