You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用SystemVerilog/Verilog读取文件中的可变长度字符串

处理可变长度事务文件的SystemVerilog实现方案

这个问题在硬件验证里挺常见的——要解析包含可变参数的Write/Read指令文件对吧?用SystemVerilog来实现非常灵活,核心思路是先把每行拆成独立的指令和参数token,再根据指令类型(Write/Read)动态处理后续的可变参数。我给你一套完整的可运行方案,附带详细解释:

核心实现思路

  1. 拆分每行成Token:用SystemVerilog的$strtok函数把整行文本按空格拆分成独立的字符串单元,方便逐个解析。
  2. 区分指令类型:遍历Token时,识别Write/Read指令,分别处理后续参数:
    • Read指令仅需读取紧跟的地址参数
    • Write指令先读地址,再读取后续所有非指令类Token作为数据,直到遇到下一个指令或行结束
  3. 动态存储数据:用动态数组存储可变长度的Write数据,避免固定长度限制。

完整代码示例

module variable_length_file_reader;
  // 定义事务类型枚举,增强代码可读性
  typedef enum {WRITE, READ} txn_type_e;
  
  // 定义事务结构体,存储完整的指令信息
  typedef struct {
    txn_type_e txn_type;
    bit[31:0]  address;
    bit[31:0]  data[]; // 动态数组适配可变长度数据
  } transaction_t;

  transaction_t txn_queue[$]; // 队列存储解析后的所有事务

  initial begin
    int         file_handle;
    string      line_buffer;
    string      token_list[$];
    string      current_token;
    int         token_index;

    // 打开目标文件,添加错误检查
    file_handle = $fopen("transaction.txt", "r");
    if (file_handle == 0) begin
      $error("Failed to open transaction file! Check file path.");
      $finish;
    end

    // 逐行读取文件内容
    while ($fgets(line_buffer, file_handle)) begin
      // 清理行内的换行符和首尾空格,跳过空行
      line_buffer = line_buffer.strip();
      if (line_buffer == "") continue;

      // 将当前行拆分为token数组
      token_list.delete();
      current_token = $strtok(line_buffer, " ");
      while (current_token != "") begin
        token_list.push_back(current_token);
        current_token = $strtok("", " "); // 继续拆分剩余内容
      end

      // 遍历token数组,解析每个事务
      token_index = 0;
      while (token_index < token_list.size()) begin
        transaction_t current_txn;

        if (token_list[token_index] == "Write") begin
          current_txn.txn_type = WRITE;
          // 解析地址参数(十六进制格式)
          $sscanf(token_list[token_index+1], "%h", current_txn.address);
          token_index += 2;

          // 读取后续所有数据,直到遇到下一个指令或行结束
          current_txn.data = new[0];
          while (token_index < token_list.size() && 
                 token_list[token_index] != "Write" && 
                 token_list[token_index] != "Read") begin
            bit[31:0] data_value;
            $sscanf(token_list[token_index], "%h", data_value);
            current_txn.data = {current_txn.data, data_value}; // 动态扩展数组
            token_index += 1;
          end
          txn_queue.push_back(current_txn);
        end 
        else if (token_list[token_index] == "Read") begin
          current_txn.txn_type = READ;
          $sscanf(token_list[token_index+1], "%h", current_txn.address);
          current_txn.data = new[0]; // Read指令无数据
          txn_queue.push_back(current_txn);
          token_index += 2;
        end 
        else begin
          $warning("Unknown token: %s at position %0d, skipping...", 
                   token_list[token_index], token_index);
          token_index += 1;
        end
      end
    end

    // 关闭文件
    $fclose(file_handle);

    // 打印解析结果,验证正确性
    $display("\n=== Parsed Transactions ===");
    foreach(txn_queue[i]) begin
      $display("\nTransaction %0d:", i);
      $display("  Type: %s", txn_queue[i].txn_type.name());
      $display("  Address: 0x%h", txn_queue[i].address);
      if (txn_queue[i].txn_type == WRITE) begin
        $display("  Data Length: %0d", txn_queue[i].data.size());
        foreach(txn_queue[i].data[j]) begin
          $display("    Data%0d: 0x%h", j, txn_queue[i].data[j]);
        end
      end
    end

    $finish;
  end
endmodule

关键细节说明

  • 动态数组data[]:自动适配Write指令的可变数据长度,无需预先定义固定大小
  • $strtok函数:SystemVerilog原生的字符串分割工具,完美解决空格分隔的文本拆分问题
  • 事务队列txn_queue[$]:将解析后的事务统一存储,方便后续对接DUT驱动或验证检查流程
  • 错误处理:包含文件打开失败检查、未知token警告,让代码更健壮

关于Verilog的补充说明

如果必须用传统Verilog(非SystemVerilog)实现,会受限较多:没有动态数组、字符串操作和队列,只能通过逐字符解析或固定长度数组模拟,实现复杂度会高很多,因此优先推荐使用SystemVerilog方案。

内容的提问来源于stack exchange,提问作者Vishwasu Deshpande

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 04:22:46