【问题标题】:Read binary file data in Verilog into 2D Array将 Verilog 中的二进制文件数据读入二维数组
【发布时间】:2016-12-14 20:27:25
【问题描述】:

我有一个要从二进制文件加载的数组:

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

我的输入文件是二进制数据,256 字节长(与 r_Image_Raw 的总空间相同)。我尝试使用$fread 来完成此操作,但它仅适用于最后一行的第 4 列:

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

我也尝试过为此使用$fscanf,但在打开综合工具时出现有关打包类型的错误:

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

我觉得这应该很容易做到。我是否创建了一个 2D for 循环并循环通过 r_Image_Raw 变量,一次读取 16 位?我觉得应该没那么复杂。

【问题讨论】:

    标签: verilog system-verilog


    【解决方案1】:

    我意识到我的错误。应该是:

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

    我使用“r”而不是“rb”来指定它是一个二进制文件。有趣的是,“r”确实适用于大多数数据,但无法从文件中读取最后约 13 个位置。

    【讨论】:

    • 以文本模式“r”读取可能会失败,因为它在文件中遇到一个字节,相当于它响应的换行符或其他控制字符。
    【解决方案2】:

    试试这个。

    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
    

    看到 $fread(r16,f_bin) 第一个参数是 reg,第二个 - 文件!

    【讨论】:

      【解决方案3】:

      下面是一个使用 systemverilog 从二进制文件读取的示例

      如 IEEE SV 标准文档中所示,"nchar_code" 将返回读取的字节数/字符数。如果在最后一次读取时已经达到 EOF,则此数字将为零。 请注意,“nchar_code”可以为零尚未达到 EOF,如果数据文件末尾有空格或返回,则会发生这种情况。

      您可以使用 $fread 函数控制要读取的字节数。这是通过以下示例的“data_write_temp”或“mem”的类型定义来完成的。如果 "data_write_temp" 变量的长度为 16 位,那么每次调用 $fread 时它将读取 16 位。此外,$fread 将返回“nchar_code=2”,因为 16 位是 2 字节。如果示例中的“data_write_temp”为 32 位,则 $fread 将读取 nchar_code=4bytes(32bits)。您还可以定义一个数组,$fread 函数将尝试填充该数组。

      让我们定义一个多维数组mem

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

      在示例单词内容中,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).
      

      文件的结构如下(注意@z 显示z 维度块):

      @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
      

      在前面的结构中,数字表示每个维度的索引。 例如w048 表示,索引 z = 0,索引 y= 4 和索引 x= 8 上的单词 w(32 位)值。

      现在,您可以通过多种方式阅读本文。 您可以使用上面声明的类型“mem”在single shot 中读取所有内容,或者您​​可以执行while 循环,直到EOF 使用32 位的“data_write_temp”变量读取32 位的片段。如果您想对每个单词片做一些检查并且您对内存值不感兴趣,那么循环很有趣。

      如果选择多维数组/单次读取,则可以使用 $fread 或使用 SV 标准中定义的特定函数 $readmemh。

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

      等价于

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

      $readmemh 让您无需打开/关闭文件。

      如果您使用 $fread 进行单次读取

        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);
      

      如果您想使用 32b 字读取进行循环。然后看下面的例子。

      该示例使用从文件中读取的数据使用 AHB 验证组件写入 AHB 总线。

          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);
      

      【讨论】:

      • 什么不起作用?代码是一个snip,只是为了告诉你如何使用systemverilog方法
      猜你喜欢
      • 2011-12-24
      • 1970-01-01
      • 1970-01-01
      • 2011-05-14
      • 1970-01-01
      • 1970-01-01
      • 2017-05-20
      • 1970-01-01
      相关资源
      最近更新 更多