Vengineerの妄想(準備期間)

人生は短いけど、長いです。人生を楽しみましょう!

OVM : ovm_transactionクラスの例題:examples/hello_world/ovm

Verification Engineerの戯言

ovm_transactionクラスの例題としては、examples/hello_world/ovmディレクトリがあるようです。
packet.svファイルovm_transactionクラスを継承するpacketクラスがあります。
このpacketクラスproducerクラス(producer.sv)consumerクラス(consumer.sv)クラス間で転送します。
2つのクラスは、topクラス(top.sv)クラスでtlm_fifoクラスで接続します。
    class top extends ovm_component;

      producer #(packet) p1;
      producer #(packet) p2;
      tlm_fifo #(packet) f;
      consumer #(packet) c;

      `ovm_component_utils(top)

      function new (string name, ovm_component parent=null);
        super.new(name,parent);

        p1 = new("producer1",this);
        p2 = new("producer2",this);
        f  = new("fifo",this);
        c  = new("consumer",this);

        p1.out.connect( c.in );
        p2.out.connect( f.blocking_put_export );
        c.out.connect( f.get_export );
      endfunction

    endclass
producerクラスインスタンスp2のoutポートとconsumerクラスインスタンスcのoutポートがtlm_fifoクラスインスタンスfで接続されています。また、インスタンスp1のoutポートは、インスタンスcのinポートと直接接続されています。

packetクラスは、producerクラスrun関数内でclone関数で生成されます。
  task run();
    T p;
    string image, num;

    for (count =0; count < num_packets; count++) begin

      $cast(p, proto.clone());
      num.itoa(count);
      p.set_name({get_name(),"-",num});
      p.set_initiator(this);

      if (recording_detail!=OVM_NONE)
        p.enable_recording("packet_stream");

      void'(p.randomize());
      if (`ovm_msg_detail(OVM_HIGH))
        p.print();

      out.put(p);

      #10;

    end
  endtask
proto.clone()でパケットを生成し、pに$castを使って代入します。
その後、set_name関数で名前を設定し、set_initiator関数でイニシエータとして自分自身(this)を設定します。
recording_detail変数がOVM_NONE以外のときは、enable_recording関数でトランザクションを記録します。
次のrandomize関数でメンバー変数の値を生成し、`ovm_msg_detail(OVM_HIGH)マクロの戻り値がtrueの時は、print関数で内部状態を表示します。最後に、outポートへパケットをput関数で送信します。

packetクラスに対するset_nameset_inhitiatorenable_recordingrandomizeprint関数は、すべてpacketクラスではなく、祖先のクラス内で定義されています。
このうち、set_initiatorenable_recordingのみがpacketクラスの親クラスであるovm_transactionクラスで定義されています。

パケットを受け取るconsumerクラスでは、受信したパケットをputタスクに渡してトランザクションを記録しています。
パケットを受信するrunタスク
    task run ();
      T p;
      while(out.size()) begin
        out.get(p);
        put(p);
      end
    endtask
outポートにデータがある(out.size)まで、データを受信(out.get(p))し、トランザクションを記録する(put(p))

    task put (T p);
      lock.get();
      count++;
      accept_tr(p);
      #10;
      void'(begin_tr(p));
      #30; 
      end_tr(p); 
      lock.put();
    endtask 
putタスクの最初と最後は、セマファ(lock)で囲んでいます。
accept_trbegin_trend_trの3つがトランザクション関連の関数です。

検証、Verification、SystemVerilog、OVM、Open Verification Methodology