What Goes where in SystemVerilog?

Is it legal SystemVerilog syntax to declare a class inside a program? What about a function inside a generate block? The table below summarizes the syntactically legal combinations (marked with a check ✔ sign). The number of possible combinations is astonishing. And yet I bet some of the valid combinations have never crossed your mind! On the other hand, some combinations may not make any sense at all, for example – of what use might a class inside a generate be?! If you do have a use case for that, please leave a comment!

A few side notes:

  1. This is a purely syntactical analysis, according to the IEEE 1800-2012 standard.
  2. Implementations of the IEEE standard may allow a smaller or larger set of combinations.
  3. You can decorate types, functions, blocks or even assignments in your code with attributes; attributes can be attached to virtually any statement in the code. They are not rigorously speaking members, so that’s why they did not go into the table below.
  4. Access modifiers are also an interesting case. You may use access modifiers only in classes and only for function declarations, task declarations, variable declarations, type declarations (typedefs) and nettype declarations. Compared to Java for instance, you cannot declare a local (private) inner class in SystemVerilog. Parameters also make an interesting case, as they cannot be hidden; even a localparam is always public.
  5. A generate block is actually a for begin…end or if begin…end block inside a module, and is referred as such in the table below. Wrapping these blocks in generate … endgenerate blocks is optional syntax.
  6. Rigorously speaking, a library may only contain design elements, such as modules, primitives, interfaces, programs, packages, or configurations (IEEE 1800-2012 section 33.2.1). However, for brevity we have also checked under the library column the members of “compilation-unit scope name space”, that is functions, tasks, etc. which are not encapsulated by any other language construct (IEEE 1800-2012 section 3.13).
CONTAINERS
library package class module interface program struct union enum checker generate config primitive
M
E
M
B
E
R
S
function
task
event
variable
parameter
#parameter
port
initial block
final block
always block
modport
clocking block
constraint
properties
sequence
instance
assertion
enum item
generate
T
Y
P
E
S
covergoup
class
module
interface
program
struct
union
enum
checker
typedef

 

Comments

13 Responses

  1. I just started glancing through this table, but I immediately saw an error.
    It says that structs and unions contain variables.
    This is not correct.
    They contain data types.
    The very first sentence in the LRM says,
    “A structure represents a collection of data types that can be referenced as a whole, or the individual data types that make up the structure can be referenced by name.”
    And even in the formal syntax, a struct_union_member is data_type_or_void.

    1. Hi Shalom,

      In this table I chose refer to class properties (as defined in IEEE 1800-2012 section 8.2 Classes Overview), module variables (section 3.3 Modules), struct members etc. as “variables”. Many times I’ve wondered what is the SystemVerilog equivalent of the generic term “field” used in software. I felt that the LRM has a preference for the term variable, so I stuck with that one.

      However, strictly speaking of structs, in the same LRM section you mention (7.2 Structures) there is an example using the term field:

      
      struct { bit [7:0] opcode; bit [23:0] addr; } IR; // anonymous structure defines variable IR
      IR.opcode = 1; // set field in IR.
      

      and the formal syntax snippet which I’ve quoted entirely below:

      data_type ::= // from A.2.2.1
      ...
      | struct_union [ packed [ signing ] ] { struct_union_member { struct_union_member } }
      { packed_dimension }
      struct_union_member ::=
      { attribute_instance } [random_qualifier] data_type_or_void list_of_variable_decl_assignments ;
      data_type_or_void ::= data_type | void
      struct_union ::= struct | union [ tagged ]
      

      also uses the term variable (list of variable declaration assignments).

      Best regards,
      Alex

  2. The LRM says about libraries:
    “A library is a named collection of cells. A cell is a design element (see 3.2), such as a module, primitive, interface, program, package, or configuration.”
    So libraries cannot contain functions, tasks, etc.

    1. Hi Shalom,

      Suppose I have a valid SystemVerilog source file containing a single function declaration. This is valid syntax by the following chain of formal syntax rules: source_text, description, package_item, package_or_generate_item_declaration, function_declaration. As per IEEE 1800-2012 section 3.12.1 Compilation units and 3.13 Name spaces paragraph (c) this function will reside in the “compilation-unit scope name space”. As simulators generally have a one-library-per-invocation approach, I’ve chosen to see the “compilation-unit scope name space” as equivalent with the library, and tick these containment combinations in the table (function, task, etc and library). I do agree that it is not rigorous, but I think it better serves the purpose of the table as a quick reference. I will add a note to the original post.

      Thanks,
      Alex

    1. Hi Lior,

      The table specifies where SystemVerilog constructs may be declared, not instantiated or called. Basically the table states that you cannot declare a program inside another program (unlike, for example modules, which can be imbricated).

      Best regards,
      Alex

  3. Always block is not allowed inside a program block. Initial and final blocks are allowed.
    The reason being an always block never terminates whereas initial and final have a finite end.

  4. Can. an interface be instantiated inside a generate statement. If. so is the scope of that interface local to the generate block?

    1. An interface can be instantiated inside a generate block, however, the table above is about declarations. And as the table states, you cannot declare an interface within a generate.
      Regarding the second part of your question, can you please clarify? How and where would you intend to access the interface and its members?

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Subscribe to our newsletter

Do you want to be up to date with our latest articles?