Read binary file data in Verilog into 2D Array

别来无恙 提交于 2021-02-08 06:10:12

问题


I have an array that I want to load up from a binary file:

parameter c_ROWS = 8;
parameter c_COLS = 16;
reg [15:0]  r_Image_Raw[0:c_ROWS-1][0:c_COLS-1];

My input file is binary data, 256 bytes long (same total space as r_Image_Raw). I tried using $fread to accomplish this, but it only works through the 4th column of the last row:

n_File_ID = $fopen(s_File_Name, "r");
n_Temp = $fread(r_Image_Raw, n_File_ID);

I also tried using $fscanf for this, but I get an error about packed types when opening the synthesis tool:

while (!$feof(n_File_ID))
  n_Temp = $fscanf(n_File_ID, "%h", r_Image_Raw);

I feel like this should be easy to do. Do I have create a 2D for loop and loop through the r_Image_Raw variable, reading in 16 bits at a time? I feel like it should not be that complicated.


回答1:


I realized my mistake. It should be:

n_File_ID = $fopen(s_File_Name, "rb");
n_Temp = $fread(r_Image_Raw, n_File_ID);

I was using "r" and not "rb" to specify that it was a binary file. Interestingly enough, "r" does work for the majority of the data, but it is unable read in the last ~13 locations from the file.




回答2:


Try this.

f_bin       = $fopen(s_File_Name,"rb");

for (r = 0; r < c_ROWS; r = r+1) begin
    for (c = 0; c < c_COLS; c = c+1) begin
        f = $fread(r16,f_bin); 
        r_Image_Raw[r][c] =  r16;   
    end
end

See that $fread(r16,f_bin) first param is reg, second - file!




回答3:


Below an example for reading from a binary file with systemverilog.

As shown in IEEE SV Standard documentation, the "nchar_code" will return the number of bytes/chars read. In case EOF have been already reached on last read this number will be zero. Please, notice that "nchar_code" can be zero but EOF has not been reached, this happens if you have spaces or returns at the end of the data file.

You can control the number of bytes to be read with the $fread function. This is done with the type definition of the "data_write_temp" or "mem" of the below examples. If the "data_write_temp" variable is 16bits long then it will read 16bits each time the $fread is called. Besides, $fread will return "nchar_code=2" because 16bits are 2bytes. In case, "data_write_temp" is 32bits as in the example, the $fread will read nchar_code=4bytes(32bits). You can also define an array and the $fread function will try to fill that array.

Lets define a multidimensional array mem.

 logic [31:0] mem [0:2][0:4][5:8];

In the example word contents, wzyx,

-w shows the start of the word
-z corresponds to words of the [0:2] dimension (3 blocks).
-y corresponds to words of the [0:4] dimension (5 rows).
-x corresponds to words of the [5:8] dimension (4 columns).

The file will be structure as below (notice @z shows the z dimension blocks):

@0 w005 w006 w007 w008
   w015 w016 w017 w018
   w025 w026 w027 w028
   w035 w036 w037 w038
   w045 w046 w047 w048
@1 w105 w106 w107 w108
   w115 w116 w117 w118
   w125 w126 w127 w128
   w135 w136 w137 w138
   w145 w146 w147 w148
@2 w205 w206 w207 w208
   w215 w216 w217 w218
   w225 w226 w227 w228
   w235 w236 w237 w238
   w245 w246 w247 w248

In the previous structure, the numbers shows the index of each dimension. e.g. w048 means, the word w (32bits) value on index z =0, index y= 4 and index x= 8.

Now, you have many ways to read this. You can read all in a single shot using the type "mem" declared above, or you can do a while loop until EOF reading pieces of 32bits using a "data_write_temp" variable of 32bits. The loop is interesting if you want to do something some checks for every word piece and you are not interested having a memory value.

In case multidimensional array / single shot read is chosen, then you can either use $fread or use an specific function $readmemh defined in SV standard.

 $readmemh("mem.data", mem, 1, (3*5*4));

is equivalent to

 $readmemh("mem.data", mem);

The $readmemh spare you the need to open/close the file.

If you use $fread for one shot read

  logic [31:0]          mem [0:2][0:4][5:8];
  register_init_id      = $fopen("mem.data","rb");                 
  nchar_code = $fread(mem, register_init_id);   
  if (nchar_code!=(3*5*4)*4)) begin 
  `uvm_error("do_read_file", $sformatf("Was not possible to read the whole expected bytes")); 
  end    
  $fclose(register_init_id);

In case you wanted to do a loop using 32b word read. Then see the following example.

The example uses the data which is read from the file to write to AHB Bus using an AHB Verification Component.

    logic [31:0] data_write_temp;
    ...
    //DO REGISTER FILE
    register_init_id      = $fopen("../../software/binary.bin","rb");
    if (register_init_id==0) begin `uvm_error("do_read_file", $sformatf("Was not possible to open the register_init_id file")); end 
    count_32b_words=0;
    while(!$feof(register_init_id)) begin            
        nchar_code = $fread(data_write_temp, register_init_id);
        if ((nchar_code!=4)||(nchar_code==0)) begin
            if (nchar_code!=0) begin
                `uvm_error("do_read_file", $sformatf("Was not possible to read from file a whole 4bytes word:%0d",nchar_code));
            end
        end else begin
            tmp_ahb_address = (pnio_pkg::conf_ahb_register_init_file_part1 + 4*count_32b_words);        
            data_write_temp = (data_write_temp << 8*( (tmp_ahb_address)%(DATAWIDTH/(8))));//bit shift if necessary not aligned to 4 bytes        
            `uvm_create_on(m_ahb_xfer,p_sequencer.ahb0_seqr);                         
            assert(m_ahb_xfer.randomize(* solvefaildebug *) with {                                       
                    write  == 1;//perform a write
                    HADDR  == tmp_ahb_address;
                    HSIZE  == SIZE_32_BIT;
                    HBURST == HBURST_SINGLE;
                    HXDATA.size() == 1; //only one data for single bust
                    HXDATA[0]  == data_write_temp;
                }) else $fatal (0, "Randomization failed");                //end assert   
            `uvm_send(m_ahb_xfer);                  
            count_32b_words++;
        end //end if there is a word read
    end //end while    
    $fclose(register_init_id);


来源:https://stackoverflow.com/questions/25024751/read-binary-file-data-in-verilog-into-2d-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!