verilogsimulationsystem-verilogtest-bench

How can I automatically scale a $display column width?


Disclaimer: I answered my own question, which is explicitly encouraged. I noticed a colleague at work writing code that left the simulation log file difficult to read. I searched the site for a solution, but found none.


I want to $display strings in a column like in a fixed-width table. However, I don't know what the maximum column width of my strings is ahead of time.

Let's say I have an array of SystemVerilog strings (names). When I $display them, I guess at a width for the column (10), but my guess is too small:

module tb;

string names [5];

initial begin
    names = '{
        "ALU"           ,
        "COMPARATOR_3"  ,
        "MEMORY"        ,
        "FLOP"          ,
        "ram_macro_with_a_long_name"
    };

    // Display all elements of the array
    foreach (names[i]) begin
        $display("| %10s |", names[i]);
    end
end

endmodule

This is the output:

|        ALU |
| COMPARATOR_3 |
|     MEMORY |
|       FLOP |
| ram_macro_with_a_long_name |

This is the output I want:

|                        ALU |
|                 COMPARATOR |
|                     MEMORY |
|                       FLOP |
| ram_macro_with_a_long_name |

I could guess a really big number (like 100), but it might be a lot bigger than I need.

How can I automatically scale the width of the $display?


Solution

  • Loop through the array to calculate the maximum string length using the len array method. Refer to IEEE Std 1800-2017, section 6.16 String data type. Then create the format string using $sformatf.

    module tb;
    
    string names [5];
    int maxlen = 0;
    string fmt;
    
    initial begin
        names = '{
            "ALU"           ,
            "COMPARATOR"    ,
            "MEMORY"        ,
            "FLOP"          ,
            "ram_macro_with_a_long_name"
        };
    
        // First, lets calculate the maximum string length
        foreach (names[i]) begin
            if (names[i].len() > maxlen) maxlen = names[i].len();
        end
    
        // Create the format which will be used by $display
        //      %%  ... double "%" is needed to create a literal "%"
        //      %0d ... this formats the maxlen number
        //      s   ... string format
        //      |   ... this is just the character I chose for the start/end of the field
        fmt = $sformatf("| %%%0ds |", maxlen);
    
        // Display all elements of the array
        foreach (names[i]) begin
            $display($sformatf(fmt, names[i]));
        end
    end
    
    endmodule
    

    This is the output:

    |                        ALU |
    |                 COMPARATOR |
    |                     MEMORY |
    |                       FLOP |
    | ram_macro_with_a_long_name |
    

    Here is a runnable example on edaplayground.


    The output above is right-justified. To get left-justified output, use:

    fmt = $sformatf("| %%-%0ds |", maxlen);
    

    Output:

    | ALU                        |
    | COMPARATOR                 |
    | MEMORY                     |
    | FLOP                       |
    | ram_macro_with_a_long_name |