What SystemVerilog features should be avoided in synthesis?

SystemVerilog(SV) can be used both as a HDL (Hardware Description Language) and HVL (Hardware Verification Language) and that is why it is often termed an "HDVL".

There are several interesting design constructs in SV which are synthesizable and can be used instead instead of older Verilog constructs, which are helpful in optimizing code and achieving faster results.

  1. enum of SV vs parameter of Verilog while modelling FSM.
  2. Use of logic instead of reg and wire.
  3. Use of always_ff, always_comb, always_latch in place of single always blocks in Verilog.
  4. Use of the unique and priority statements instead of Verilog's full and parallel case statements.
  5. Wide range of data types available in SV.

Now what I have discussed above are those constructs of SystemVerilog which are used in RTL design.

But, the constructs which are used in the Verification Environment are non-synthesizable. They are as follows:

  1. Dynamic arrays and associative arrays.
  2. Program Blocks and Clocking blocks.
  3. Mailboxes
  4. Semaphores
  5. Classes and all their related features.
  6. Tasks
  7. Chandle data types.
  8. Queues.
  9. Constrained random features.
  10. Delay, wait, and event control statements.

Theoretically, if you can write software that is synthesized into machine code to run on a piece of hardware, that software can be synthesized into hardware. And conversely, there are hardware constructs in Verilog-1995 that are not considered synthesizable simply because none of the major vendors ever got around to supporting it (e.g. assign/deassign). We still have people using //synopsis translate on/off because it took so long for them to support `ifdef SYNOPSYS.

Most of what I consider to be safe for synthesis in SystemVerilog is what I call syntactic sugar for Verilog. This is just more convenient ways of writing the same Verilog code with a lot less typing. Examples would be:

  • data types: typedef, struct, enum, int, byte
  • use of those types as ports, arguments and function return values
  • assignment operators: ++ -- +=
  • type casting and bit-streaming
  • packages
  • interfaces
  • port connection shortcuts
  • defaults for function/tasks/macro arguments, and port connections

Most of the constructs that fall into this category are taken from C and don't really change how the code gets synthesized. It's just more convenient to define and reference signals.

The place it gets difficult to synthesize is where there is dynamically allocated storage. This would be class objects, queues, dynamic arrays, and strings. as well as dynamically created processes with fork/join.

I think some people have a misconception about SystemVerilog thinking it is only for Verification when in fact the first version of the standard was the synthesizable subset, and Intel was one of the first users of it as a language for Design.