FPGA開発日記

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

オープンソース形式検証ツールSymbiYosysを用いて形式検証に入門する (8. ラウンドロビンアービタを検証する)

カテゴリインデックス:https://msyksphinz.hatenablog.com/entry/2024/12/14/040000

SymbiYosysでラウンドロビンアービタを検証する

ラウンドロビンアービタは、複数のリクエストを公平に処理するための回路である。 SystemVerilogで実装したラウンドロビンアービタを、形式検証ツールであるSymbiYosysを使用して検証してみる。

ラウンドロビンアービタの実装

まず、N入力のラウンドロビンアービタを以下のように実装した。このコードは、テストを流して検証したわけではないが、まあ多分なんとなく動くと思う。

module rr_arbiter #(
  parameter N = 4,
)(
  input logic          i_clk,
  input logic          i_rst_n,
  input logic [N-1:0]  i_req,
  output logic [N-1:0] o_grant
);

localparam LG = $clog2(N);

logic [LG-1:0]         r_last_idx;
logic [LG-1:0]         w_idx_next;

always_comb begin
  w_idx_next = r_last_idx;

  for (int i = 1; i <= N; i++) begin: loop_arbiter
    if (i_req[(r_last_idx + i) % N]) begin
      w_idx_next = (r_last_idx + i) % N;
    end
  end
end

assign o_grant = (1 << w_idx_next);

always @(posedge i_clk or negedge i_rst_n) begin
  if (!i_rst_n) begin
    r_last_idx <= 'h0;
  end else begin
    r_last_idx <= w_idx_next;
  end
end

`ifdef FORMAL
always_comb begin
  assert ((o_grant & (o_grant - 1)) == 0);
  assert (!(~|i_req) || (o_grant == 0));
end
`endif // FORMAL

endmodule // rr_arbiter

アサーションの説明

この実装では、以下の2つのアサーションを設定している:

  1. (o_grant & (o_grant - 1)) == 0: o_grantは常に1ビットのみが出力されることを保証する。
  2. (!(~|i_req) || (o_grant == 0)): i_reqがゼロの時は、何も出力されないことを保証する。

SymbiYosysの設定

SymbiYosysのコンフィグレーションを以下のように設定した。

BMCの場合

[options]
mode bmc
depth 40

[engines]
smtbmc z3

[script]
read -sv -formal rr_arbiter.sv
prep -top rr_arbiter

[files]
rr_arbiter.sv

UMCの場合

[options]
mode prove

[engines]
smtbmc z3

[script]
read -sv -formal rr_arbiter.sv
prep -top rr_arbiter

[files]
rr_arbiter.sv

検証の実行

実際に検証を実行してみる。

$ sby -f rr_arbiter_bmc.sby

しかし、残念ながら検証が完了しない。状態遷移が発生するデザインは、形式検証が難しい場合がある。

SBY 15:34:27 [rr_arbiter_bmc] prep: finished (returncode=0)
SBY 15:34:27 [rr_arbiter_bmc] smt2: starting process "cd rr_arbiter_bmc/model; yosys -ql design_smt2.log design_smt2.ys"
SBY 15:34:27 [rr_arbiter_bmc] smt2: finished (returncode=0)
SBY 15:34:27 [rr_arbiter_bmc] engine_0: starting process "cd rr_arbiter_bmc; yosys-smtbmc -s z3 --presat --noprogress -t 40  --append 0 --dump-vcd engine_0/trace.vcd --dump-yw engine_0/trace.yw --dump-vlogtb engine_0/trace_tb.v --dump-smtc engine_0/trace.smtc model/design_smt2.smt2"
SBY 15:34:27 [rr_arbiter_bmc] engine_0: ##   0:00:00  Solver: z3
SBY 15:34:27 [rr_arbiter_bmc] engine_0: ##   0:00:00  Checking assumptions in step 0..
SBY 15:35:27 [rr_arbiter_bmc] engine_0: ##   0:01:00  waiting for solver (1 minute)
SBY 15:39:27 [rr_arbiter_bmc] engine_0: ##   0:05:00  waiting for solver (5 minutes)
SBY 15:44:27 [rr_arbiter_bmc] engine_0: ##   0:10:00  waiting for solver (10 minutes)
SBY 15:49:27 [rr_arbiter_bmc] engine_0: ##   0:15:00  waiting for solver (15 minutes)