VUnit は VHDL/SystemVerilogのテスティングフレームワークだ。VUnitにはいくつかテストパタンが用意されているが、少し自分でもテストパタンを用意してみよう。
作ってみたのは、32bit×32bit=64bitの符号なし整数の演算器を実装して、VUnitでテストを実行してみよう。この演算器は4サイクルで32bit×32bit=64bitの演算を実行する。
VUnitのテストスイートの実装
VUnitのテストスイートを実装してみる。基本的に、TEST_CASE
にテストを定義して、テスト内容を記述している。
今回は、以下のテストを記述した。
- test_0 :
- test_1 :
- test_2 :
- test_3 :
テストパタンを以下のように実装した。
- vunit/examples/verilog/mult_4cycle/src/test/tb_mult_4cycle.sv
`include "vunit_defines.svh" module tb_mult_4cycle; localparam integer clk_period = 20; // ns logic [63: 0] out_c; logic [31: 0] in_a, in_b; logic clk = 1'b0; logic reset = 1'b1; logic en = 1'b0; `TEST_SUITE begin `TEST_SUITE_SETUP begin #1; reset = 1'b0; end `TEST_CASE("test_0") begin en = 1'b1; in_a = 2; in_b = 3; #(clk_period * 4 * 1ns); en = 1'b0; `CHECK_EQUAL (out_c, {32'h0000_0000, in_a} * {32'h0000_0000, in_b}); end `TEST_CASE("test_1") begin en = 1'b1; in_a = 2726929837; in_b = 13; #(clk_period * 4 * 1ns); en = 1'b0; `CHECK_EQUAL (out_c, {32'h0000_0000, in_a} * {32'h0000_0000, in_b}); end `TEST_CASE("test_2") begin en = 1'b1; in_a = 13; in_b = 2726929837; #(clk_period * 4 * 1ns); en = 1'b0; `CHECK_EQUAL (out_c, {32'h0000_0000, in_a} * {32'h0000_0000, in_b}); end `TEST_CASE("test_3") begin en = 1'b1; in_a = 475228202; in_b = 175707306; #(clk_period * 4 * 1ns); en = 1'b0; `CHECK_EQUAL (out_c, {32'h0000_0000, in_a} * {32'h0000_0000, in_b}); end end `WATCHDOG(10ms); always begin #(clk_period/2 * 1ns); clk <= !clk; end mult_4cycle dut ( .clk (clk), .reset (reset), .en (en), .in_a (in_a), .in_b (in_b), .out_c (out_c) ); endmodule
テスト結果
実行結果は、正しく4つのテストをPassできることを確認した。結局、Pythonフレームワークを使っているとはいえ、結局はVerilogを記述しているので、まあまあ使い易いかな。
おまけ: 4サイクル32bit符号なし整数の乗算器の実装
- vunit/examples/verilog/mult_4cycle/src/mult_4cycle.sv
module mult_4cycle ( input wire clk, input wire reset, input wire en, input wire [31: 0] in_a, input wire [31: 0] in_b, output wire [63: 0] out_c ); logic [63: 0] ab_lo_lo, ab_lo_hi, ab_hi_lo, ab_hi_hi; logic [31: 0] r_a, r_b; always_ff @ (posedge clk, posedge reset) begin if (reset) begin r_a <= 32'h0000_0000; r_b <= 32'h0000_0000; end else begin if (en) begin r_a <= in_a; r_b <= in_b; end end end // always_ff @ logic [ 1: 0] mul_state; localparam state_0 = 2'b00, state_1 = 2'b01, state_2 = 2'b10, state_3 = 2'b11; logic [63: 0] r_total; logic [31: 0] r_total_in; assign r_total_in = ((mul_state == state_0) && en) ? {16'h0000, in_a[15: 0]} * {16'h0000, in_b[15: 0]} : (mul_state == state_1) ? {16'h0000, r_a[15: 0]} * {16'h0000, r_b[31:16]} : (mul_state == state_2) ? {16'h0000, r_a[31:16]} * {16'h0000, r_b[15: 0]} : (mul_state == state_3) ? {16'h0000, r_a[31:16]} * {16'h0000, r_b[31:16]} : 32'h0000_0000; always_ff @ (posedge clk, posedge reset) begin if (reset) begin mul_state <= state_0; r_total <= 64'h0000_0000_0000_0000; end else begin case (mul_state) state_0 : begin if (en) begin r_total <= {32'h0000_0000, r_total_in}; mul_state <= state_1; end end state_1 : begin r_total <= r_total + {16'h0000, r_total_in, 16'h0000}; mul_state <= state_2; end state_2 : begin r_total <= r_total + {16'h0000, r_total_in, 16'h0000}; mul_state <= state_3; end state_3 : begin r_total <= r_total + {r_total_in, 32'h0000_0000}; mul_state <= state_0; end endcase // case (mul_state) end // else: !if(reset) end // always_ff @ assign out_c = r_total; endmodule