Vengineerの妄想(準備期間)

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

SimpleBus (その8)

Verification Engineerの戯言

今回と次回では、SimpleLTTarget1/2について説明します。

SimpleBusに接続するターゲットとしては、
unit_test/tlm/common/include/modelsディレクトリに次の6つが用意されています。
    SimpleLTTarget1
    SimpleLTTarget2
SimpleLTTarget1クラスは、tlm::tlm_fw_nb_transport_ifクラスを継承しますので、
必要な次の3つのメソッドです。
    sync_enum_type nb_transport(transaction_type& trans, 
                                phase_type& phase, 
                                sc_core::sc_time& t);

    unsigned int transport_dbg(tlm::tlm_debug_payload& r);

    bool get_direct_mem_ptr(const sc_dt::uint64& address,
                            dmi_mode_type& dmi_mode,
                            tlm::tlm_dmi&  dmi_data);
まずは、nb_transportメソッドです。
  sync_enum_type nb_transport(transaction_type& trans, 
                              phase_type& phase, 
                              sc_core::sc_time& t)
  {
    assert(phase == tlm::BEGIN_REQ);

    sc_dt::uint64 address = trans.get_address();
    assert(address < 400);

    unsigned int& data = *reinterpret_cast<unsigned int*>(trans.get_data_ptr());
    if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
      std::cout << name() << ": Received write request: A = 0x"
                << std::hex << (unsigned int)address
                << ", D = 0x" << data << std::dec
                << " @ " << sc_core::sc_time_stamp() << std::endl;

      *reinterpret_cast<unsigned int*>(&mMem[address]) = data;
      t += sc_core::sc_time(10, sc_core::SC_NS);

    } else {
      std::cout << name() << ": Received read request: A = 0x"
                << std::hex << (unsigned int)address << std::dec
                << " @ " << sc_core::sc_time_stamp() << std::endl;

      data = *reinterpret_cast<unsigned int*>(&mMem[address]);
      t += sc_core::sc_time(100, sc_core::SC_NS);
    }

    trans.set_response_status(tlm::TLM_OK_RESPONSE);

    trans.set_dmi_allowed(true);

    // LT target
    // - always return true
    // - not necessary to update phase (if true is returned)
    return tlm::TLM_COMPLETED;
  }
引数transに対して、get_addressメソッドget_commandメソッドget_data_ptrメソッド
で受信トランザクションからアドレス、コマンド、データポインタを獲得します。
get_commandメソッドの戻り値がtlm::TLM_WRITE_COMMANDのときは、ライトなので、
get_data_ptrメソッドで獲得したデータを内部メモリ(mMem[address])にストアし、引数tに10(SC_NS)を設定します。
tlm::TLM_READ_COMMANDのときは、リードなので内部メモリ(mMem[address])の値をdataにロードし、
引数tに100(SC_NS)を代入します。引数tに代入した値は、トランザクションを送信してきたイニシエータに渡され、
イニシエータ内でウエイトする時間として使われます。
その後に、set_response_stateコマンドでステータスとしてtlm::TLM_OK_RESPONSEを設定します。
最後にset_dmi_allowedメソッドでDMIが使えることを設定し、tlm::TLM_COMPLETEDを戻り値とします。
イニシエータでは、この戻り値を受けて処理をします。ちなみに次のコードは、'''SimpleLTInitiator1クラスの部分です。
        switch (socket->nb_transport(trans, phase, t)) {
          case tlm::TLM_COMPLETED:
              wait(t);
              break;
引数tに設定した時間、イニシエータでウエイト(wait(t))します。

次に、transport_dbgメソッドです。このメソッドは、デバッグ用です。
  unsigned int transport_dbg(tlm::tlm_debug_payload& r)
  {
    if (r.address >= 400) return 0;

    unsigned int tmp = (int)r.address;
    unsigned int num_bytes;
    if (tmp + r.num_bytes >= 400) {
      num_bytes = 400 - tmp;

    } else {
      num_bytes = r.num_bytes;
    }
    if (r.do_read) {
      for (unsigned int i = 0; i < num_bytes; ++i) {
        r.data[i] = mMem[i + tmp];
      }

    } else {
      for (unsigned int i = 0; i < num_bytes; ++i) {
        mMem[i + tmp] = r.data[i];
      }
    }
    return num_bytes;
  }
transport_dbgメソッドでは、最大400バイトまでリード/ライトできるようになっています。
戻り値は、アクセスしたバイト数です。

途中ですが、今日はここまで。