FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

GoogleのSystemVerilog ParserであるVeribleを試す(1)

f:id:msyksphinz:20200917212059p:plain

GoogleがSystemVerilogのParserを開発していた。見つけたきっかけはGoogleRISC-V向けランダムパタン生成ツールであるRISCV-DVを調査していたのだが、その最中に見つけたものだった。

github.com

github.com

余談であるがriscv-dvの方はUVMをサポートできるシミュレーション環境が必要で、個人では試行できないので試していない。ソースコードを読む時間があれば読んでみたいけど。

で、VeribleはC++で記述されているSystemVerilogのLexer/Parserのようで、開発にはFlex/Bisonを使用しているらしい。既にいくつかのツールを使用することができる。インストールの方法はREADMEに従おう。以下のコマンドを実行すれば/usr/local/binにインストールされる。

# For a system directory that requires root-access, call with -s option.
# (Do _not_ run bazel with sudo.)
bazel run :install -c opt -- -s /usr/local/bin

いくつかのツールがインストールされていることが確認できた。

$ ls -1 /usr/local/bin/verible-*
/usr/local/bin/verible-patch-tool
/usr/local/bin/verible-transform-interactive.sh
/usr/local/bin/verible-verilog-diff
/usr/local/bin/verible-verilog-format
/usr/local/bin/verible-verilog-format-changed-lines-interactive.sh
/usr/local/bin/verible-verilog-kythe-extractor
/usr/local/bin/verible-verilog-lint
/usr/local/bin/verible-verilog-obfuscate
/usr/local/bin/verible-verilog-preprocessor
/usr/local/bin/verible-verilog-syntax

verible-verilog-preprocessor

これはどうも単純なツールだ。プリプロセッサというのはVerilogのマクロのことではなく、ソースコードを処理する前の単純な文字列処理のために使用する。現在はコメントを除去することくらいしかできない。

試しに、昔作った簡単な4ビットカウンタを例に取り上げる。

  • counter_4bit.v
// Function from C-code
import "DPI-C" context task dpi_c_func(input int in, output int out);

module counter_4bit
  (
   input logic        clk,
   input logic        reset_n,
   input logic        en,
   output logic [3:0] cnt
   );

int                   return_value;

task dpi_verilog_task(input int in);
  $display("dpi_verilog_task is called. in = %d", in);

endtask // dpi_verilog_task

// Function from Verilog Task
export "DPI-C" task dpi_verilog_task;

always_ff @(posedge clk, negedge reset_n) begin
  if (!reset_n) begin
    cnt <= 4'h0;
  end else begin
    if (en) begin
      cnt <= cnt + 4'h1;
      /* verilator lint_off WIDTH */
      dpi_c_func (cnt, return_value);
      $display("return_value = %d", return_value);
    end
  end
end

以下のようにコマンドを叩くとすべてのコメントが除去された。使用用途は良く分からないが、なるほど正しく動くようだ。

verible-verilog-preprocessor strip-comments counter_4bit.v
import "DPI-C" context task dpi_c_func(input int in, output int out);

module counter_4bit
  (
   input logic        clk,
   input logic        reset_n,
   input logic        en,
   output logic [3:0] cnt
   );

int                   return_value;

task dpi_verilog_task(input int in);
  $display("dpi_verilog_task is called. in = %d", in);

endtask


export "DPI-C" task dpi_verilog_task;

always_ff @(posedge clk, negedge reset_n) begin
  if (!reset_n) begin
    cnt <= 4'h0;
  end else begin
    if (en) begin
      cnt <= cnt + 4'h1;

      dpi_c_func (cnt, return_value);
      $display("return_value = %d", return_value);
    end
  end
end

endmodule

verible-verilog-diff

これは2つのVerilogファイルの比較ツールだ。比較と言っても等価性検証ツールではなく、トークンベースで一致比較を行う。例えば、上記のcounter_4bit.vトークンと意味を崩さない程度に思いっきりフォーマットを破壊してみた。

  • counter_4bit_mod.v
 // Function from C-code
 import "DPI-C" context task dpi_c_func(input int in, output int out);
 module counter_4bit(
    input logic clk, input logic        reset_n, input logic        en,
    output logic [3:0] cnt);
 int                   return_value;

 task dpi_verilog_task(input int in);
   $display("dpi_verilog_task is called. in = %d", in);
 endtask // dpi_verilog_task

 // Function from Verilog Task
 export "DPI-C" task dpi_verilog_task;
    always_ff    @  (posedge clk,   negedge reset_n) begin
      if (!   reset_n) begin cnt <= 4'h0;     end else begin
        if (en) begin         cnt <= cnt + 4'h1;
          /* verilator lint_off WIDTH */
          dpi_c_func (cnt, return_value);
              $display("return_value = %d", return_value);end end end
 endmodule // counter_4bit
verible-verilog-diff counter_4bit.v counter_4bit_mod.v
Inputs match.

これだけフォーマットを崩してもファイルが等価であるということを確認できる。一方でbeginendの対応や、コメント部分が異なっている場合には正しく検証できない。コメントに関してはverilog-preprocessorを使えば何とかなりそうだが、beginendについては現在は手が無いようだ。

verible-verilog-obfuscate

これはVerilogファイルの暗号化ツールだ。Verilog内の変数に暗号化をかけて内容を読みにくくすることが目的のようだ。 例えば上記のcounter_4bit.vを入力すると以下のようになる。

$ verible-verilog-obfuscate < counter_4bit.v
// Function from C-code
import "DPI-C" context task WmqWxwAWVw(input int ZU, output int kCm);

module iHyAeiXbPg65
  (
   input logic        wNf,
   input logic        ivsMflg,
   input logic        Hs,
   output logic [3:0] lkM
   );

int                   RXJ2WqMPENW0;

task vsRZkyKcHqiuWPhC(input int ZU);
  $display("dpi_verilog_task is called. in = %d", ZU);

endtask // dpi_verilog_task

// Function from Verilog Task
export "DPI-C" task vsRZkyKcHqiuWPhC;

always_ff @(posedge wNf, negedge ivsMflg) begin
  if (!ivsMflg) begin
    lkM <= 4'h0;
  end else begin
    if (Hs) begin
      lkM <= lkM + 4'h1;
      /* verilator lint_off WIDTH */
      WmqWxwAWVw (lkM, RXJ2WqMPENW0);
      $display("return_value = %d", RXJ2WqMPENW0);
    end
  end
end

endmodule // counter_4bit

モジュール名から何から何まで、可能な限り変数名や関数名などもハッシュ化してしまう。これはIPを提供する会社が自社の内部デザインを読み取られないようにするために便利なツールだろう。

verible-verilog-format

これはVerilogのフォーマッターだ。フォーマットに関してはいくつかコンフィグレーションが存在しないと不便だと思うが、verible-verilog-formatではオプションでフォーマットを指定するようだ。

$ verible-verilog-format --helpfull
...
  Flags from verilog/tools/formatter/verilog_format.cc:
    --case_items_alignment (Format case items:
      {align,flush-left,preserve,infer}); default: infer;
    --class_member_variables_alignment (Format class member variables:
      {align,flush-left,preserve,infer}); default: infer;
    --failsafe_success (If true, always exit with 0 status, even if there were
      input errors or internal errors. In all error conditions, the original
      text is always preserved. This is useful in deploying services where
      fail-safe behaviors should be considered a success.); default: true;
...
    --try_wrap_long_lines (If true, let the formatter attempt to optimize line
      wrapping decisions where wrapping is needed, else leave them unformatted.
      This is a short-term measure to reduce risk-of-harm.); default: false;
    --verify_convergence (If true, and not incrementally formatting with
      --lines, verify that re-formatting the formatted output yields no further
      changes, i.e. formatting is convergent.); default: true;

試しに、上記のフォーマットをぐちゃぐちゃにしたcounter_4bit_mod.vを入力してみた。

$ verible-verilog-format counter_4bit_mod.v
// Function from C-code
import "DPI-C" context task dpi_c_func(input int in, output int out);
module counter_4bit (
    input  logic       clk,
    input  logic       reset_n,
    input  logic       en,
    output logic [3:0] cnt
);
  int return_value;

  task dpi_verilog_task(input int in);
    $display("dpi_verilog_task is called. in = %d", in);
  endtask  // dpi_verilog_task

  // Function from Verilog Task
  export "DPI-C"
  task dpi_verilog_task
  ;
  always_ff @(posedge clk, negedge reset_n) begin
    if (!reset_n) begin
      cnt <= 4'h0;
    end else begin
      if (en) begin
        cnt <= cnt + 4'h1;
        /* verilator lint_off WIDTH */
        dpi_c_func(cnt, return_value);
        $display("return_value = %d", return_value);
      end
    end
  end
endmodule  // counter_4bit

おお、綺麗にフォーマットされた!まあ他人のコードですらここまで汚くするのはあまりないので、簡単に整形したい場合とか、チーム内でルールを設ける場合に使用すると良さそうだ。