Icarus VerilogとSCVの連携(VPI)

機能検証

Verilog RTLのデザインをSCV(SystemC Verification Library)で検証する環境のサンプルです。

GitHub - Kenji-Ishimaru/scv_iv_sample: Co-simulation of SCV and Icarus Verilog
Co-simulation of SCV and Icarus Verilog. Contribute to Kenji-Ishimaru/scv_iv_sample development by creating an account o...

サンプルの動作環境

このサンプルは次の環境で動作を確認しました。

サンプルの概要

サンプルの基本的な構成は、Icarus VerilogとSystemCの連携(VPI)と同じです。Verilogでインスタンス化したmod_aという簡単なRTLに対して、SVCでランダムデータの入力を行い、SystemCでRTLの出力とリファレンスデータの一致確認を行っています。

サンプルの概要

DUTのmod_a.vは、8ビットの2入力を内部で加算して出力する単純な回路です。

module mod_a (
  input        clk,
  input        rst_x,
  input        i_valid,
  input  [7:0] i_in_a,
  input  [7:0] i_in_b,
  output reg   o_valid,
  output reg [7:0] o_out
);

always @(posedge clk or negedge rst_x) begin
  if (~rst_x) begin
    o_valid <= 1'b0;
    o_out <= 8'h0;
  end else begin
    o_valid <= i_valid;
    o_out <= i_in_a + i_in_b;
  end
end

endmodule

ランダムデータ用の構造体

RTLのDUTは、i_valid, i_in_a, i_in_bという3つの入力があります。この入力データをランダムに生成するために、data_tという構造体を定義します。

struct data_t {
  sc_uint<1> valid;
  sc_uint<8> a;
  sc_uint<8> b;
};

data_tに対応するscv_extensions<data_t> classを作成します。

#ifndef DATA_EXT_H
#define DATA_EXT_H

#include "scv.h"
#include "data.h"

template<>
class scv_extensions<data_t> : public scv_extensions_base<data_t> {
public:
  scv_extensions<sc_uint<1> > valid;
  scv_extensions<sc_uint<8> > a;
  scv_extensions<sc_uint<8> > b;

  SCV_EXTENSIONS_CTOR(data_t) {
    SCV_FIELD(valid);
    SCV_FIELD(a);
    SCV_FIELD(b);
  }
};
#endif //DATA_EXT_H

コンパイルスクリプト

SystemC関連のソースファイルは、g++で事前にコンパイルしておき、iverilog-vpiでVPI用のCファイルとリンクさせます。-lscvオプションが必要です。

# compile verilog
iverilog -c ../bin/cmd.txt \
    -v \
    -y ${RTL_DIR} \
    -o ${TOP_MODULE} \
    ${sim_file}

g++ -c -fPIC \
    -I${SYSC_DIR} \
    -I${STUB_DIR} \
    -I${SYSTEMC_DIR}/include \
    ${SYSC_DIR}/mod_a.cpp

g++ -c  -fPIC \
    -I${SYSC_DIR} \
    -I${STUB_DIR} \
    -I${SYSTEMC_DIR}/include \
    ${SYSC_DIR}/mod_a_tb.cpp

iverilog-vpi \
    -I${SYSC_DIR} \
    -I${STUB_DIR} \
    ${STUB_DIR}/vpi_stub.c \
    mod_a.o mod_a_tb.o -lscv -lsystemc -L${SYSTEMC_DIR}/lib-linux64
# simulation
export LD_LIBRARY_PATH=${SYSTEMC_DIR}/lib-linux64
vvp -M. -mvpi_stub ${TOP_MODULE} -v

ランダムデータの生成

mod_a::stimulus()内でランダムデータを生成しています。制約条件のあるランダムデータを生成する場合は、 scv_constraint_baseを派生させた制約条件のクラスを作成する必要があります。

SCV_CONSTRAINT

SCV_CONSTRAINTを使うと、「ランダムかつi_in_aとi_in_bを同じ値にする」といった制約条件を指定することができます。

class my_constraint1: public scv_constraint_base {
public:
  scv_smart_ptr < data_t > p ;
  SCV_CONSTRAINT_CTOR(my_constraint1) {
    SCV_CONSTRAINT ( p->a() == p->b() );
  }
};

keep_only

keep_onlyを使うと、ランダムデータの生成範囲を指定できます。

class my_constraint2: public scv_constraint_base {
public:
  scv_smart_ptr < data_t > p ;
  SCV_CONSTRAINT_CTOR(my_constraint2) {
    p->a.keep_only(1,7);  // aは1~7の範囲
    p->b.keep_only(8,15); // bは8~15の範囲
  }
};

mod_a::stimulus()

ランダムデータを生成するには、scv_smart_ptr()もしくは制約条件を指定したclassをインスタンス化します。ランダムデータは、next()メソッドをコールすると生成されます。次の例は、scv_smart_ptr, my_constraint1, my_constraint2, my_constraint3という順で、それぞれ5回のランダムデータ生成を行っています。 RTLへのデータの書き込みは、ランダムデータ生成後に行っています。

void mod_a::stimulus() {
  scv_smart_ptr<data_t> data_p ("data");
  my_constraint1 c1("const1");
  my_constraint2 c2("const2");
  my_constraint3 c3("const3");
  scv_random::set_global_seed(100);
  while (true) {
    while (rst_x.read() == 0)
       wait();
    cout<<"#"<<sc_time_stamp()<<" rst_x is deasserted " << endl;
    // no constraint
    for (int i = 0; i < 5; i++) {
      data_p->next();
      scv_out << "Random value for " << std::hex << data_p->get_name() << ":" << endl;
      data_p->print(scv_out, 0, 2);
      // RTLにランダムデータをセット
      i_valid.write(data_p->valid.read());
      i_in_a.write(data_p->a.read());
      i_in_b.write(data_p->b.read());
      wait();
    }
    // constraint1
    for (int i = 0; i < 5; i++) {
      c1.p->next();
      scv_out << "Random value for " << std::hex << c1.p->get_name() << ":" << endl;
      c1.p->print(scv_out, 0, 2);
      i_valid.write(c1.p->valid.read());
      i_in_a.write(c1.p->a.read());
      i_in_b.write(c1.p->b.read());
      wait();
    }
    // constraint2
    for (int i = 0; i < 5; i++) {
      c2.p->next();
      scv_out << "Random value for " << std::hex << c2.p->get_name() << ":" << endl;
      c2.p->print(scv_out, 0, 2);
      i_valid.write(c2.p->valid.read());
      i_in_a.write(c2.p->a.read());
      i_in_b.write(c2.p->b.read());
      wait();
    }
    // constraint3
    for (int i = 0; i < 5; i++) {
      c3.p->next();
      scv_out << "Random value for " << std::hex << c3.p->get_name() << ":" << endl;
      c3.p->print(scv_out, 0, 2);
      i_valid.write(c3.p->valid.read());
      i_in_a.write(c3.p->a.read());
      i_in_b.write(c3.p->b.read());
      wait();
    }
    i_valid.write(0);
    wait(10);
    sim_done = true;
    std::cout << "=======================================" << std::endl;
    std::cout << " The simulation is successfully done." << std::endl;
    std::cout << "=======================================" << std::endl;
    wait();
  }
}

 

実行結果

シミュレーションを実行すると、次のようなログが表示されます。SCVで生成されたランダムデータでDUTが動作しているのが分かります。

シミュレーション結果の波形
Icarus Verilog started
VCD info: dumpfile dump.vcd opened for output.
#0 s SystemC started
#100 ns rst_x is deasserted
Random value for data:
  {
    valid:0
    a:76
    b:60
  }
Random value for data:
  {
    valid:1
    a:3f
    b:d1
  }
(中略)
Mon Input: #270 ns i_valid = 1 i_in_a = 0aa i_in_b = 0f7
Mon Output: #270 ns o_valid = 1 o_out = 0c5
Random value for :
  {
    valid:1
    a:77
    b:f8
  }
Mon Input: #280 ns i_valid = 1 i_in_a = 024 i_in_b = 065
Mon Output: #280 ns o_valid = 1 o_out = 0a1
Random value for :
  {
    valid:1
    a:fd
    b:d2
  }
Mon Input: #290 ns i_valid = 1 i_in_a = 077 i_in_b = 0f8
Mon Output: #290 ns o_valid = 1 o_out = 089
Mon Input: #300 ns i_valid = 1 i_in_a = 0fd i_in_b = 0d2
Mon Output: #300 ns o_valid = 1 o_out = 06f
Mon Input: #310 ns i_valid = 0 i_in_a = 0fd i_in_b = 0d2
Mon Output: #310 ns o_valid = 1 o_out = 0cf
=======================================
 The simulation is successfully done.
=======================================
#410 ns SystemC stopped

Info: /OSCI/SystemC: Simulation stopped by user.

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