Constrained Randomの考えを使った検証環境のサンプルを作成しました。
本当はclassにrandの変数を定義してconstraintで範囲を決定→randomize()するのですが、
constraintとrandomize()が対応していなかったので、組み込みコマンドの$urandom()と$urandom_range()を使って作成しています。
Constrained Random(制約付きランダム)とは
Constrained Random(制約付きランダム)は、複雑化したRTLのテストを早期に完了させ、人手では見逃すようなケースをテストします。
近年のハードウェアの高機能化によりRTLが複雑になってきています。
それにより、人手ではテストアイテムを上げきることが困難になってきました。工数がかかり、見逃しも出てきます。
そこで、ランダム手法が注目されました。
その名の通り、ランダムなデータを入力とすることで人手では見逃すようテストを作成します。
しかし、完全なランダムだと本来は起こりえない組み合わせの値が入力されることもあります。
そこで、Constrained Randomが主流となりました。
Constrained Randomのメリット・デメリット
メリット
- テストを1つ1つ作成しなくて良い
- 人手では見落とすバグを見つけられる
デメリット
- カバレッジが埋まらない
ピンポイントな条件でしか発火しないカバレッジがあると埋まるまでに時間がかかる - デバッグが困難
テストがFailしたときにテストパラメータから回路にどのような挙動をさせているか理解が困難
サンプル検証環境
Constrained Randomを使った検証環境のサンプルを作成しました。
構成
dut.sv
検証対象の回路です。
in_validが1のときのdinに1を加算したdoutを出力します。
out_validが1のときのdoutが有効データです。
module dut(
input clk,
input rst_n,
input in_valid,
input [5:0] din,
output logic out_valid,
output logic [5:0] dout
);
always_ff @(posedge clk, negedge rst_n) begin
if (!rst_n) begin
dout <= '0;
end
else begin
dout <= din + 1'b1;
end
end
always_ff @(posedge clk, negedge rst_n) begin
if (!rst_n) begin
out_valid <= '0;
end
else begin
out_valid <= in_valid;
end
end
endmodule
monitor.sv
DUTの出力をモニタします。
期待値と異なると、[ERROR]が出力されます。
interface mon_if_t;
logic clk;
logic rst_n;
logic valid;
logic [5:0] din;
logic [5:0] dout;
logic [5:0] exp;
always_ff @(posedge clk, negedge rst_n) begin
if (!rst_n) begin
exp <= '0;
end
else begin
exp <= din + 1'b1;
end
end
endinterface
class monitor #(parameter type mon_if_t = virtual mon_if_t);
mon_if_t mon_if;
int exp;
function new(mon_if_t _mon_if);
mon_if = _mon_if;
endfunction
task start;
forever begin
@(posedge mon_if.clk iff mon_if.valid);
if (mon_if.dout != mon_if.exp) begin
$display("[ERROR]: [act] %d, [exp] %d\n", mon_if.dout, mon_if.exp);
end
end
endtask
endclass
test.sv
テストファイルです。
「SEED」の値を変えることで乱数生成のシードを変更します。
別なテストを作る場合は、「SEED」に異なる値を入れます。異なる結果が得られます。
`define SEED 100
tb.sv
interface dut_if_t;
logic clk;
logic rst_n;
logic in_valid;
logic [5:0] din;
logic out_valid;
logic [5:0] dout;
endinterface
`include "monitor.sv"
`include "test.sv"
module tb;
initial begin
$dumpfile("wave.vcd");
$dumpvars(0,tb);
end
bit clk = 0;
bit rst_n = 0;
always #5 clk = ~clk;
monitor #(virtual mon_if_t) mon;
dut_if_t dut_if();
mon_if_t mon_if();
assign dut_if.clk = clk;
assign dut_if.rst_n = rst_n;
assign mon_if.clk = dut_if.clk;
assign mon_if.rst_n = dut_if.rst_n;
assign mon_if.valid = dut_if.out_valid;
assign mon_if.din = dut_if.din;
assign mon_if.dout = dut_if.dout;
dut i_dut(
.clk(dut_if.clk),
.rst_n(dut_if.rst_n),
.in_valid(dut_if.in_valid),
.din(dut_if.din),
.out_valid(dut_if.out_valid),
.dout(dut_if.dout)
);
int cnt;
initial begin
$urandom(`SEED);
mon = new(mon_if);
@(posedge clk);
rst_n = 1;
fork
mon.start();
join_none
cnt = $urandom_range(1, 100);
for (int i = 1; i <= cnt; i++) begin
dut_if.din = $urandom_range(0, 64);
dut_if.in_valid = $urandom_range(0, 1);
@(posedge clk);
$display("Data count [%d/%d]", i, cnt);
end
$finish;
end
endmodule
出力結果
標準出力に表示される出力です。
期待値と異なると[ERROR]が表示されます。
もちろん、テストファイルの「SEED」の値を変えると出力が異なります。
Data count [ 1/ 36]
Data count [ 2/ 36]
Data count [ 3/ 36]
Data count [ 4/ 36]
***************割愛***************
Data count [ 34/ 36]
Data count [ 35/ 36]
Data count [ 36/ 36]
波形
まとめ
Constrained Randomの考え方で検証環境のサンプルを作成しました。
本当はclassにrandの変数を定義してconstraintで範囲を決定→randomize()するのですが、
対応していないシミュレータもあるので使用しませんでした。
コメント