What’s new in SystemVerilog-2023? Part 1: SV23 design enhancements

The next revision of the SystemVerilog standard IEEE Std 1800™-2023 was approved on December 6.

SV23 adds various enhancements, not just bug fixes. In this post, I summarize the main ones for the basic design language. In an upcoming post, I will summarize the testbench enhancements, such as Java-style weak references.

Update state variables by passing them to a task or function with ‘ref static’ arguments.

The next state in a SystemVerilog finite-state machine (FSM) is specified with a nonblocking assignment (NBA) that defers the assignment until late in the time step.

Until SV23 an FSM couldn’t be factored into manageable levels with tasks and functions, because a state variable passed as an argument couldn’t be the target of an NBA. This restriction was to prevent the potential mistake of passing an automatic variable.

In SV23 a task/function formal can have direction ‘ref static‘ and be passed a state variable to schedule a nonblocking assignment for it.

You can also refer to a ‘ref static’ argument from a fork-join_any or fork-join_none block in a function because it’s guaranteed that nothing automatic will be passed in so the argument will outlive the the fork block.

The BNF change is tf_port_direction in Syntax 13-1, from “const ref” to “[const] ref [static]”.

Associative array parameters for modules, classes and interfaces

A constant associative array can represent a lookup table keyed by strings, enums, integers, and so on. It can also represent a set by using an associative array of bits.

For example, #(.WEIGHT(‘{ HIGH:5, MEDIUM:3:, LOW:1 })) or #(.WEIGHT(my_weights())) where my_weights() is a function that returns an associative array.

The BNF change is param_assignment in Syntax 6-6 from “unpacked_dimension” to “variable_dimension”.

Python-style multiline string literals using triple quotes.

By bracketing the string with quotation marks three times instead of once, such as “””this”””, there is no need to escape newlines or quotation marks. See 5.9.

C-like conditional compilation with logical operators.

An ifdef/ifndef directive can now use the logical operators !, &&, ||, -> and <->. See Syntax 22-5.

‘Soft’ packed unions aren’t restricted to equal-sized members.

Now with the ‘soft’ qualfier, the size of the union is the size of the longest member. For details of the changes, including new Figure 7-1, see the proposal here.

Type parameters can declare the same restrictions as typedefs.

Now a type parameter can be declared as specifically “type enum”, “type struct”, “type class”, and so on. For details of the new BNF and examples, see the proposal here.

Expressions on unpacked arrays with new “map” method

For example, instead of declaring a temp array, doing

foreach (A[i]) temp[i] = A[i] + B[i];

and calling f( temp ), you can directly call

f( A.map with (item + B[item.index]) )

There is no BNF change for this. It’s a new built-in array manipulation method described in 7.12.5. The examples there use an overly complicated syntax. I would recommend the style of 7.12.4, where the example is “q = arr.find with (item == item.index);”. There are no parentheses after the method name and no declaration of a new variable name instead of the default “item”.

SV23: Nonblocking assignment across a task ref port

Following up to “SystemVerilog — always blocks are needed less and less“, which had an example of an assignment that should have been legal, but wasn’t.

Until now it hasn’t been legal to make a nonblocking assignment (NBA) to a static module variable across a reference port of a function or task. But in the 2023 revision of the standard that restriction has been lifted as long as the reference port has been annotated with the new static qualifier. Thanks to Steven Sharp for driving that enhancement. His enhancement also lifted the restriction against referring to such ports from within a forkjoin_any or forkjoin_none block, again given the new static qualifier.

So here’s the earlier example modified to be legal in SystemVerilog 2023

virtual class C#(type T);
  static task ff(const ref logic clk,
                 const ref T in,
                 ref static T out);
    forever @(posedge clk) out <= in;
  endtask
endclass

module test#(type T) (input logic clk, 
                      input T in,
                      output T out);
  initial C#(T)::ff(clk, in, out);
endmodule

SV23: Terms ‘master’ and ‘slave’ purged from next revision of SystemVerilog standard

In December 2020, the IEEE SA Standards Board resolved, “IEEE standards should be written in such a way as to avoid non-inclusive and insensitive terminology (see IEEE Policy 9.27) and other deprecated terminology (see clause 10 of the IEEE SA Style Manual) except when required by safety, legal, regulatory, and other similar considerations. Terms such as master/slave, blacklist, and whitelist should be avoided.”

John Byler in “What Is the Best Way to Purge Master and Slave Terms From Engineering Documents?” lists some proposed replacements, such as “initiator-target”, and writes

“Whatever terminology replaces master-slave, the critical matter is that a far less degrading alternative is agreed to and implemented as soon as possible.”

A special thanks should go to Don Mills, the SystemVerilog trainer and one of the driving participants in the 2023 revision of the standard, who was the first to raise this issue in the committee.

The SV23 committee eventually went with the “initiator-target” replacement terminology.

Standards and innovation: Accellera’s Portable Stimulus Standard

According to “CEO Interview: Adnan Hamid of Breker Systems

Has Accellera’s Portable Stimulus Standard helped move the chip design verification community closer to adopting Portable Stimulus tools?
Oh yes, clearly. For a number of years, we have been working with power users who were unconcerned with developing models using the Breker proprietary language based on C++. Indeed, our original language is more advanced than the standard. It has procedural as well as declarative constructs, and our power users are still actively employing it. However, to allow mainstream users to enjoy the benefits of these tools, they had to be assured that models they develop could be supported by multiple vendors, and this is where the standard has proven useful. We have seen a significant uptick in our business from the mainstream market as a result of its release last June. We fully expect it to overtake other verification languages over the next few years as it matures.

VHDL-2019 — what’s new?

According to Jonas Julian Jensen

Here are some highlights of the upcoming VHDL-2019 revision:

  • Interfaces
  • Garbage collection
  • 64-bit integers
  • Conditional compilation
  • Shared variables on entities
  • Generics on protected types
  • Generics on subprograms
  • Partially connected vectors in port maps
  • For a more detailed description of the changes and new features, continue reading the rest of this post.

    VHDL-2018 — SV-style interfaces (“records with directions”)

    VHDL-2018, the ten-year revision of IEEE 1076-2008, is currently in ballot and is expected to go to RevCom in October 2018. (You’ll see references on the web to “VHDL-2017”, but that was before delays in editing.)

    According to the working group chair Jim Lewis

    The top item on my list is interfaces as it benefits RTL and testbench design. VHDL-2017 interfaces are simply a record type plus a declared mode. The declared mode allows an entire interface to be bundled into a single signal with each element having separate input/output directions (in, out, and inout). For testbenches, this simplifies writing verification components using entities and architectures, and allows a style that is either just like RTL code or simpler behavioral code.

    Here’s a presentation about all the enhancements in VHDL-2018 by Lieven Lemiengre

    Slice a SystemVerilog interface in the receiving modules

    A common use pattern for SystemVerilog interfaces is that one server is connected to N clients, and the interconnect is like an N-element array of structs, where the server uses the entire array, but each client uses only one element of the array. In practice, it’s easier to express the interconnect as several arrays, one for each struct field.

    I made this problem too complicated in “How to slice a SystemVerilog interface“, because each of the server and the clients were being passed different interface instances, and the instance passed to the server was even of a different type of interface than the instances passed to the clients.

    The more natural way is to pass them all the same instance, and restrict access to single elements inside the clients. As in the earlier entry, this restriction is done with a second interface. But the trick here is that the client must be passed its own index.

    `define _ import GLOBAL_PARAMETERS::*;
    package GLOBAL_PARAMETERS;
      localparam type requestType = byte;
      localparam type responseType = int;
      localparam int N = 16;
    endpackage:GLOBAL_PARAMETERS
    
    module testMod `_ (/*...*/);
      wire clk, rst;
      IFC U(clk, rst);
      for (genvar INDEX = 0; INDEX != N; ++INDEX) begin:GEN
        clientMod#(INDEX) client(U.clientMp);
      end
      serverMod server(U.serverMp);
    endmodule:testMod
    
    module clientMod `_ #(INDEX)(IFC.clientMp bigifc);
      IFC_SLICE#(INDEX) U(bigifc);
      always_ff @(posedge U.clk, negedge U.rst) begin
        if (!U.rst) 
          U.requestWrite(0);
        else
          U.requestWrite(1);
      end
      // ...
    endmodule:clientMod
    
    module serverMod `_ (IFC.serverMp bigifc);
      // ...
    endmodule:serverMod
    
    interface automatic IFC `_ (input clk, rst);
      var requestType Requests[N-1:0];
      var responseType Responses[N-1:0];
    
      function requestType requestRead(int index);
        return Requests[index];
      endfunction
    
      function responseType responseRead(int index);
        return Responses[index];
      endfunction
    
      function void requestWrite(int index, requestType request);
        Requests[index] <= request;
      endfunction
    
      function void responseWrite(int index, responseType response);
        Responses[index] <= response;
      endfunction
    
      modport clientMp(output Requests, input Responses,
                       import requestWrite, responseRead,
                       input clk, rst);
    
      modport serverMp(input Requests, output Responses,
                       import requestRead, responseWrite,
                       input clk, rst);
    endinterface:IFC
    
    interface automatic IFC_SLICE `_ #(INDEX)(IFC.clientMp bigifc);
      wire clk = bigifc.clk;
      wire rst = bigifc.rst;
    
      function void requestWrite(requestType request);
        bigifc.requestWrite(INDEX, request);
      endfunction
    
      function responseType responseRead();
        return bigifc.responseRead(INDEX);
      endfunction
    endinterface:IFC_SLICE
    
    
    Copyright © 2016 Brad Pierce