SystemVerilog|コンパイル後にテストを切り替る~$test$plusargs~

Systemverilog
田中太郎
田中太郎

SystemVerilogではコンパイル後に値を代入することができます

その機能を応用して、コンパイル後にテストを入れ替えます

サマリ

テストファイルが大量にあるとき、DUT、テストベンチを何度もコンパイルすることになります

そこで、複数のテスト、DUT、テストベンチを一度にコンパイルしてシミュレーション時にテストを切り替えるテスト環境を作成しました

背景

ハードウェアはソフトウェアと違い、完成後の修正が容易ではないため、ガチガチにテストします

ハードウェアのテスト環境は、

・検証対象であるDUT(Design Under Test)

・DUTへの入力を作るテスト

・DUTの出力が正しいかチェックするテストベンチ

から成り立っています

テストを実行するには、DUT、実行するテスト、テストベンチをコンパイルして実行ファイルを生成します

別なテストを実行するときは、テストを切り替えてコンパイルをやり直す必要があります

なので、テストが大量にあると、DUT、テストベンチを何度もコンパイルすることになり、無駄な時間が生じます

目的

テストをまとめてコンパイルして実行時に切り替えることで、テスト全体にかかる時間を削減します

コンパイル後にテストを切り替えるテスト環境を作成する

テスト環境のイメージ図を以下に示します

DUT(Design Under Test)

テスト対象となるRTLです

dinで入力された値に1を足して出力するだけの回路です

dut.sv
module dut(
    input clk,
    input rst_b,
    input [3:0] din,
    output logic [3:0] dout
);
    always_ff@(posedge clk, negedge rst_b) begin
        if (!rst_b) begin
            dout <= '0;
        end
        else begin
            dout <= din + 1'b1;
        end
    end
endmodule

テストベンチ

DUTをインスタンスしているだけで、チェック機能はありません

tb.sv
module tb;

initial begin
    $dumpfile("wave.vcd"); // icarus verilogのシミュレータを使うおまじない
    $dumpvars(0,tb);
end

logic clk;
logic rst_b;
logic [3:0] din;
logic [3:0] dout;

dut #(
) u_dut(
    .clk(clk),
    .rst_b(rst_b),
    .din(din),
    .dout(dout)
);

endmodule

テスト

test1, test2の2つあります

test1はdinに’d5, test2はdinに’d15を代入するだけのテストです

test1.sv
module test1;

reg clk = 0;
always #5 clk = !clk;

reg rst_b = 0;
initial #20 rst_b = 1;

initial begin
    if ($test$plusargs("test1")) begin // 実行時に+test1を指定するとTrue、しないとFalseが返ってきます
        seq;
        #500;
        $finish;
    end
end

always@* begin
    if ($test$plusargs("test1")) begin // test1を実行するとき、test1で生成した信号をDUTに与えます
        tb.clk = clk;
        tb.rst_b = rst_b;
        tb.din = din;
    end
end

logic [3:0] din;
task seq;
    #50;
    din = 5;
    $display("din %b:%d", din, din);
    #10;
    $display("dout %b:%d", tb.dout, tb.dout);
endtask

endmodule
test2.sv
module test2;

reg clk = 0;
always #5 clk = !clk;

reg rst_b = 0;
initial #20 rst_b = 1;

initial begin
    if ($test$plusargs("test2")) begin
        seq;
        #500;
        $finish;
    end
end

always@* begin
    if ($test$plusargs("test2")) begin
        tb.clk = clk;
        tb.rst_b = rst_b;
        tb.din = din;
    end
end

logic [3:0] din;
task seq;
    #50;
    din = 14;
    $display("din %b:%d", din, din);
    #10;
    $display("dout %b:%d", tb.dout, tb.dout);
endtask

endmodule

シミュレーションを実行する

シミュレーションはIcarus Verilogを使用します

まず、コンパイルします

iverilog -g2009 tb.sv dut.sv test1.sv test2.sv

コンパイルが成功したらa.outが生成されます

同じ実行ファイルでtest1, test2をそれぞれ実行してみましょう

test1を実行する

test1はdinに’d5を入れるテストです

test1を実行してみましょう

vvp a.out +test1
# 実行結果
# din 0101:5
# dout 0110:6

test2を実行する

test2はdinに’d14を入れるテストです

test2を実行してみましょう

vvp a.out +test2
# 実行結果
# din 1110:14
# dout 1111:15

同じ実行ファイルでテストを切り替えることができました

まとめ

DUT、テストベンチ、テストをまとめてコンパイルして、シミュレーション時に切り替えられました。

コメント

タイトルとURLをコピーしました