Vengineerの妄想(準備期間)

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

SimpleBus (その4)

Verification Engineerの戯言

昨日に続き、SimplTLInitiator_DMIクラスについてです。

SimpleTLInitiator1_DMIクラスのrunメソッドは、次のようになっています。
  void run()
  {
    transaction_type trans;
    phase_type phase;
    sc_core::sc_time t;
    
    while (initTransaction(trans)) {
      phase = tlm::BEGIN_REQ;
      t = sc_core::SC_ZERO_TIME;

      // Check if the address is covered by our DMI region
      if ( (trans.get_address() >= mDMIData.dmi_start_address) &&
           (trans.get_address() <= mDMIData.dmi_end_address) ) {
          ここは、DMIのコードなので後ほど、
      } else { 
          switch (socket->nb_transport(trans, phase, t)) {
          case tlm::TLM_COMPLETED:
              wait(t);
              break;
              
          case tlm::TLM_ACCEPTED:
          case tlm::TLM_UPDATED:
              wait(mEndEvent);
              break;

          case tlm::TLM_REJECTED:
          default:
            assert(0); exit(1);
          };
          // Acquire DMI pointer if we get the hint:
          if (trans.get_dmi_allowed())
          {
              dmi_type tmp;
              dmi_mode_type tmp_mode;
              tmp_mode.type = tlm::tlm_dmi_mode::WRITE;
              if ( socket->get_direct_mem_ptr(trans.get_address(),
                                              tmp_mode,
                                              tmp) &&
                   (tmp_mode.type != tlm::tlm_dmi_mode::READ))
              {
                  mDMIData = tmp;
              }
          }
      }
    }
    sc_core::sc_stop();
    wait();
  }
initTransactionメソッドでトランザクションを生成します。
生成したトランザクションがDMI内のアドレスかどうかを調べ、DMI内のアドレスであれば、
DMIで処理し、そうでないときはsocketに対して、nb_transportメソッドを実行し、
外部へのトランザクションを発生します。

nb_transportメソッドの戻り値によってアクションが変わります。
tlm::TLM_COMPLETEDであれば、t時間ウエイトします。
tlm::TLM_ACCEPTEDあるいはtlm::TLM_UPDATEDであれば、mEndEventが発生するまでウエイトします。
mEndEventをnotifyするのは、ターゲット側から呼び出されるnb_transportメソッドです。

tlm::TLM_REJECTEDの場合は、アサートし、シミュレーションは終了します。

このコードは、Loosely-timed coding styleのイニシエータソケットの戻り値に対するコードになるようです。

次に引数のtransからDMIができるかどうか(trans.get_dmi_allowed())をチェックし、
YesのときはDMIのためのメモリポインタをソケットのget_direct_mem_ptrメソッドで獲得します。
なぜこのようにするかというと、最初からDMIをサポートするかどうかわからないので、最初の1回目のトランザクションの結果で
DMIがサポートしているかどうかを知ることができるからだと思います。

トランザクションがDMIのアドレス内のときは次のように処理を行います。
         trans.set_response_status(tlm::TLM_OK_RESPONSE);
          sc_dt::uint64 tmp = trans.get_address() - mDMIData.dmi_start_address;
          assert(hasHostEndianness(mDMIData.endianness));
          if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
              *(unsigned int*)&mDMIData.dmi_ptr[tmp] = mData;

          } else {
              mData = *(unsigned int*)&mDMIData.dmi_ptr[tmp];
          }
          if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
            wait(mDMIData.write_latency);

          } else {
            wait(mDMIData.read_latency);
          }
DMIのデータポインタを使って直接ターゲット内のメモリにアクセスします。
その後、アクセスに必要な時間、ウエイトします。