Vengineerの妄想

人生を妄想しています。

SimpleBus (その3)

Verification Engineerの戯言

SimpleBusに接続するイニシエータとしては、
unit_test/tlm/common/include/modelsディレクトリに次の6つが用意されています。
    SimpleLTInitiator1
    SimpleLTInitiator1_DMI
    SimpleLTInitiator2
    SimpleLTInitiator2_DMI
    SimpleLTInitiator3
    SimpleLTInitiator3_DMI
    SimpleATInitiator1
    SimpleATInitiator2
SimpleLTInitiatorXは、Loosely-timed coding styleのモデルで、
SimpleATInitiatorXは、Approximately-timed coding styleのモデルです。
_DMIで終わるものは、DMI(Direct Memory Interface)をサポートするモデルです。

_DMIのありなしは、DMIをサポートするかどうかの違いなので、まずSimpleLTInitiator1_DMIを見ていきましょう。

SimpleLTInitiator_DMIクラスは、tlm::tlm_bw_nb_transport_ifクラスを継承しますので、
必要な次の2つのメソッドです。
    tlm::tlm_sync_enum nb_transport(
            tlm::tlm_generic_payload& trans, 
            tlm::tlm_phase& phase, 
            sc_core::sc_time& t);
 
    void invalidate_direct_mem_ptr(sc_dt::uint64 start_range, 
                                   sc_dt::uint64 end_range);
まずは、nb_transportメソッドです。
  sync_enum_type nb_transport(transaction_type& trans, phase_type& phase, sc_core::sc_time& t)
  {
    switch (phase) {
    case tlm::END_REQ:
      // Request phase ended
      return tlm::TLM_ACCEPTED;

    case tlm::BEGIN_RESP:
      assert(t == sc_core::SC_ZERO_TIME); // FIXME: can t != 0?
      mEndEvent.notify(t);
      // Not needed to update the phase if true is returned
      return tlm::TLM_COMPLETED;

    case tlm::BEGIN_REQ: // fall-through
    case tlm::END_RESP: // fall-through
    default:
      // A target should never call nb_transport with these phases
      assert(0); exit(1);
      return tlm::TLM_REJECTED;
    };
  }
Loosely-timed coding styleのイニシエータモデルのnb_transportメソッドは、
上記のようなコーディングスタイルになります。引数phaseによってアクションが変わります。
受け取ることができるphaseは、END_REQとBEGIN_RESPです。
BEGIN_REQとEND_RESPの場合はエラーになり(assert(0))、シミュレータ(exit(1))が終了します。
phaseがEND_REQのときは、ただ単にtlm::TLM_ACCEPTEDを返すだけです。
一方、phaseがBEGIN_RESPのときは、ターゲットモデルからレスポンスフェーズが開始されたことを
示すので、引数tを使って、mEndEventイベントにnotifyします。その後、tlm::TLM_COMPLETEDを返します。
mEndEventのイベント待ちは、runメソッドで行われています。

次は、invalidate_direct_mem_ptrメソッドです。
  void invalidate(dmi_type& dmiData)
  {
    dmiData.dmi_start_address = 1;
    dmiData.dmi_end_address = 0;
  }

  // Invalidate DMI pointer(s)
  void invalidate_direct_mem_ptr(sc_dt::uint64 start_range,
                                 sc_dt::uint64 end_range)
  {
      // do the invalidation if there is an address range overlap
      if (start_range <= mDMIData.dmi_end_address &&
          end_range >= mDMIData.dmi_start_address) {
          std::cout <<  name() << ": got DMI pointer invalidation"
                    << " @ " << sc_core::sc_time_stamp() << std::endl;
          
          invalidate(mDMIData);
      } else {
          std::cout <<  name() << ": ignored DMI invalidation for addresses "
                    << std::hex << start_range << ", "
                    << end_range << std::dec
                    << " @ " << sc_core::sc_time_stamp() << std::endl;
      }
  }
引数(start_rangeとend_range)の間のアドレスとmDMIDataのアドレスレンジとを比較し、
アドレス内であれば、データポインタを無効化しています。アドレス外のときはメッセージを表示します。
実際に無効化しているのは、invalidateメソッドです。

次回は、runメソッドについて

P.S
昨日、6000訪問者を達成しました。ありがとうございました。