SystemVerilog Automatic Storage & Time Values

Introduction


SystemVerilog Automatic Storage & Time Values


Hardware description languages present unique challenges when managing data storage and timing. Unlike conventional software languages that rely on stack-based memory allocation, hardware description languages were designed to model physical circuits with static structures. This fundamental difference creates potential pitfalls for verification engineers transitioning from software development backgrounds.


This article examines two critical aspects of SystemVerilog: automatic storage mechanisms for local variables and precise time value specifications. Readers will gain an understanding of why static storage can cause race conditions in testbenches, how the automatic keyword resolves these issues, and the proper methods for specifying time units and precision. Practical examples illustrate correct implementation patterns.


(toc) #title=(Table of Content)


What Is Static vs Automatic Storage in SystemVerilog?


When Verilog was originally developed in the 1980s, its primary objective was hardware description rather than software simulation. Consequently, all language objects received static allocation. Routine arguments and local variables occupied fixed storage locations throughout simulation, unlike stack-based languages such as C or C++.


What Is Static vs Automatic Storage in SystemVerilog?


The Problem with Static Storage in Testbenches


In Verilog-1995, calling a task from multiple locations caused all invocations to share the same static storage for local variables. Different threads overwrote each other's values unpredictably. Consider a memory monitoring task:


  • First call begins waiting for a specific memory address
  • Second call starts before the first completes
  • Second call overwrites the address argument
  • First call now monitors the wrong address

This behavior severely limited the ability to create complex testbenches with reusable routine libraries.


The Automatic Keyword Solution


Verilog-2001 introduced the ability to specify that tasks, functions, and modules use automatic storage. When a routine uses automatic storage, the simulator allocates local variables on a stack, providing each invocation with its own independent copy.


In SystemVerilog, routines default to static storage for both modules and program blocks. Best practice requires making program blocks automatic by placing the automatic keyword in the program statement.


Example: Automatic program block declaration


code

program automatic test;
  task wait_for_mem(input [31:0] addr, expect_data,
             output success);
    while (bus.addr !== addr)
      @(bus.addr);
    success = (bus.data == expect_data);
  endtask
endprogram


Without the automatic modifier, concurrent calls to wait_for_mem would overwrite the addr and expect_data arguments. With automatic storage, each call maintains separate copies.


Variable Initialization Pitfalls


A related issue occurs when initializing local variables within declarations. In static storage contexts, the variable initializes at simulation start rather than when execution enters the containing block.


The Static Initialization Bug


code

program initialization;  // Buggy version
  task check_bus;
    repeat (5) @(posedge clock);
    if (bus_cmd == 'READ) begin
      reg [7:0] local_addr = addr << 2;  // Bug
      $display("Local Addr = %h", local_addr);
    end
  endtask
endprogram


In this example, local_addr initializes at simulation time zero, not when the begin...end block executes. The solution requires declaring the program as automatic:


code

program automatic initialization;  // Correct version
  task check_bus;
    repeat (5) @(posedge clock);
    if (bus_cmd == 'READ) begin
      reg [7:0] local_addr = addr << 2;  // Now correct
      $display("Local Addr = %h", local_addr);
    end
  endtask
endprogram


Time Values and Precision in SystemVerilog


Accurate time specification is essential for hardware verification. SystemVerilog provides several constructs for unambiguous time value definition.


Time Units and Precision Declarations


Traditional Verilog relied on the `` timescale compiler directive, which required compiling files in specific order to ensure proper scaling and precision. SystemVerilog introduced timeunit and timeprecision declarations that eliminate this ambiguity.


Time Values and Precision in SystemVerilog


Each module containing delays should include these declarations:


code

module timing;
  timeunit 1ns;
  timeprecision 1ps;
  // Module contents
endmodule


Time Literals


SystemVerilog allows explicit time value specification with units:


  • 0.1ns – one-tenth of a nanosecond
  • 20ps – twenty picoseconds
  • 2ns – two nanoseconds
  • 41ps – forty-one picoseconds

Using $timeformat and $realtime


The $timeformat system task controls time value display formatting:


code

module timing;
  timeunit 1ns;
  timeprecision 1ps;
  
  initial begin
    $timeformat(-9, 3, "ns", 8);
    #1 $display("@%t", $realtime);    // @1.000ns
    #2ns $display("@%t", $realtime);  // @3.000ns
    #0.1ns $display("@%t", $realtime); // @3.100ns
    #41ps $display("@%t", $realtime);  // @3.141ns
  end
endmodule


The $timeformat parameters specify:


  • Unit number (-9 represents nanoseconds)
  • Precision digits (3 decimal places)
  • Unit string ("ns")
  • Minimum field width (8 characters)

Best Practices for Automatic Storage


Practice Recommendation
Program blocks Always declare as automatic
Task arguments Use automatic storage for concurrent calls
Variable initialization Avoid non-constant initializers in static blocks
Time specification Use timeunit and timeprecision over `timescale

Conclusion


The evolution from static to automatic storage in SystemVerilog represents a significant improvement for verification engineering. By understanding when static allocation causes race conditions and applying the automatic keyword appropriately, engineers can build more reliable and concurrent testbenches. Similarly, explicit time unit and precision declarations eliminate ambiguity in delay specifications, making code more portable and maintainable. As hardware verification complexity continues to increase, proper use of these language features becomes essential for robust testbench development.



FAQs


What does the automatic keyword do in SystemVerilog?

It causes the simulator to allocate local variables on a stack instead of using fixed static storage.



Why is static storage problematic for testbenches?

Static storage causes concurrent task calls to overwrite each other's local variables and arguments.



Do SystemVerilog routines default to automatic or static storage?

Routines default to static storage for both modules and program blocks.



When does a variable initialize in a static storage context?

At simulation start time, not when execution enters the containing block.



What is the difference between timeunit and timeprecision?

timeunit sets the default delay unit; timeprecision sets the simulation precision for rounding.



Can time literals use different units in the same module?

Yes, SystemVerilog accepts time literals with explicit units like 0.1ns or 20ps within the same module.



#buttons=(Ok, Go it!) #days=(20)

Our website uses cookies to enhance your experience. Learn More
Ok, Go it!