0

I am generating a binary file from a SystemVerilog simulation environment. Currently, I'm doing the following:

module main;
  byte arr[] = {0,32, 65, 66, 67};
  initial begin
    int fh=$fopen("/home/hagain/tmp/h.bin","w");
    for (int idx=0; idx<arr.size; idx++) begin //{
      $fwrite(fh, "%0s", arr[idx]);
    end //}
    $fclose(fh);
    $system("xxd /home/hagain/tmp/h.bin | tee /home/hagain/tmp/h.txt");
  end
endmodule : main

The problem is, that when b has the value of 0, nothing is written to the file. xxd output is:

0000000: 2041 4243                                 ABC

Same result when casting to string as follows:

$fwrite(fh, string'(arr[idx]));

I tried to change the write command to:

$fwrite(fh, $sformatf("%0c", arr[idx]));

And then I got the same value for the first two bytes ('d0 and 'd32):

0000000: 2020 4142 43                               ABC

Any idea on how to generate this binary file?

3
  • There is no 'b' in your code. You are not writing binary values in the file, you are writing strings. Commented Mar 9, 2022 at 2:58
  • @Serge %b would cause writing a string of binary values. for example, 'hAA would be written as the string 10101010 to the file Commented Mar 10, 2022 at 6:19
  • It is still a string, a stream of character codes. In other words, you encode your data as characters (8 bit per character). When one talks about binary files, usually it contains raw data without encoding them as characters. You talk about 'binary' but write strings. '%b' will only write strings which contain characters '0' , '1' , 'x' and 'z'. Commented Mar 10, 2022 at 12:18

1 Answer 1

1

You cannot have a null(0) character in the middle of a string, it is used to terminate the string.

You should use the %u format specifier for unformated data.

module main;
  byte arr[] = {0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9};
   int fh, c, tmp;
   initial begin
     fh = $fopen("h.bin","wb");
     for (int idx=0; idx<arr.size; idx+=4) begin
       tmp = {<<8{arr[idx+:4]}};
       $fwrite(fh, "%u", tmp);
      end
      $fclose(fh);
      fh  = $fopen("h.bin","r");
      while ((c = $fgetc(fh)) != -1)
        $write("%d ",c[7:0]);
    $display;
   end
endmodule : main

Note that %u writes a 32-bit value in least-significant bytes first order, so I reversed the bytes being written with the streaming operator {<<8{arr[idx+:4]}}. If the number of bytes is not divisible by 4, it will just pad the file with null bytes.

If you need the exact number of bytes, the you will have to use some DPI C code

#include <stdio.h>
#include "svdpi.h"
void DPI_fwrite(const char* filename,
           const svOpenArrayHandle buffer){
  int size = svSize(buffer,1);
  char *buf = (char *)svGetArrayPtr(buffer);
  FILE *fp = fopen(filename,"wb");
  fwrite(buf,1,size,fp);
}

And then import it with

import "DPI-C" function void DPI_fwrite(input string filename, byte buffer[]);
...
DPI_fwrite("filename", arr);
Sign up to request clarification or add additional context in comments.

4 Comments

If I got you right, you mean to replace the %0s in my code with %u I tried that (with VCS, should be noted), and got the same result - the null-character value was not written to the binary file
Updated answer with an example that works with both VCS and Questa on EDAPlayground.com
nice trick (and I had sformatf, which filtered the null character, and that's why it didn't work for me before). Now, the only issue, that I hope you'll help find a way to overcome, is the 4-byte concatenation, as I have 1-byte writes, and not always my streams size divide by 4
Added DPI-C code

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.