Search code examples
arrayssystem-verilogdynamic-arrays

Formatting Dynamic Array of Bits as String in SystemVerilog


How can I format a dynamic array of bits (or more correctly, logics) as a string, e.g., for UVM's convert2string? For example, I would like to convert

logic        vdyn[];  
...  
vdyn = new [16] ('{0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1});  

to the string 0097.

I thought the following would work (the # are just to delimit the string for readability):

  fmt = $sformatf("#%%%0dh#", (vdyn.size-1)/4 + 1); // "#%4h#"
  vstr = $sformatf(fmt, { >> {vdyn}});

but it returns # x#, at least in Questa 10.3d (I suspect this is a bug - I'd be interested if it works on other simulators).

I tried converting it to a packed array first, but that runs into other problems. Without a size constraint on the result, the source value always gets left-justified in the destination variable, e.g.:

logic [63:0] v64;
...
v64 = {>> {vdyn}}; // 64'h0097000000000000

There's no way to print out just the part I want without using variable-size slices. The following works, but it requires that I know the size of the array at compile time:

v64 = 16'({>> {vdyn}});  // 64'h0000000000000097

The best thing I've found is the following "double-reverse" (note that I'm using << here, not >>):

     v64 = {<< {vdyn}};    // 64'he900000000000000 
     v64 = {<< {v64}};     // 64'h0000000000000097
     vstr = $sformatf(fmt, v64); // #0097#

It seems kind of hokey to have to do this, though. By the way, combining the first two statements into one doesn't work:

     v64 = {<< {{<< {vdyn}}}};     // 64'hZ900000000000000

(v64[63] is z for some reason). Again, I suspect this is a bug in Questa 10.3d.


Solution

  • Try casting a slice of the array and loop through. For example an 4 entry slice that is cast to a 4-bits value. A slize can be done with the -: or +: operator (See IEEE Std 1800-2012 § 7.4.3 Operations on arrays and § 7.4.6 Indexing and slicing of arrays)

    vstr = "";
    for(int i=vdyn.size()-1; i>=0; i-=4) begin
      vstr = $sformatf("%h%s", 4'({>>{vdyn[i -: 4]}}), vstr);
    end
    vstr = $sformatf("#%s#", vstr); // user formatting
    

    The 4s in the code can be changed to something else depending how much leading 0 or a non-power-of-two formatting is desired, but it must be a numeric constant


    I tried your code on some other simulators. vstr = $sformatf(fmt, { >> {vdyn}}); sometimes gave me compiling errors. Casting the array to something bigger than its expected max size seems to work

    fmt = $sformatf("#%%%0dh#", (vdyn.size-1)/4 + 1); // "#%4h#"
    vstr = $sformatf(fmt, 128'({ >> {vdyn}})); // works iff 128>=vdyn.size