Verification Engineerの戯言
今回からは、SimpleATXモデルです。SimpleATXは、Approximately-timed coding styleのモデルです。
まずは、TargetモデルのSimpleATTarget1クラスからです。SimpleATTarger1クラスのコンストラクタはつぎのようになっています。
その次に3つのメソッドをSC_METHODマクロでイベント待ちにしています。
各メソッドは、リクエスト終了(mEndRequestEvent)、レスポンス開始(mBeginRequestEvent)、レスポンス終了(mEndResponseEvent)のイベントをトリガにしています。
まずは、TargetモデルのSimpleATTarget1クラスからです。SimpleATTarger1クラスのコンストラクタはつぎのようになっています。
SimpleATTarget1(sc_core::sc_module_name name) : sc_core::sc_module(name), socket("socket"), ACCEPT_DELAY(25, sc_core::SC_NS), RESPONSE_DELAY(100, sc_core::SC_NS) { // register nb_transport method REGISTER_NBTRANSPORT(socket, myNBTransport); SC_METHOD(endRequest) sensitive << mEndRequestEvent; dont_initialize(); SC_METHOD(beginResponse) sensitive << mBeginResponseEvent; dont_initialize(); SC_METHOD(endResponse) sensitive << mEndResponseEvent; dont_initialize(); }Initiatorクラスから呼び出されるnb_transportメソッドとして、myNBTransportメソッドをREGISTER_NBTRANSPORTマクロで登録しています。
その次に3つのメソッドをSC_METHODマクロでイベント待ちにしています。
各メソッドは、リクエスト終了(mEndRequestEvent)、レスポンス開始(mBeginRequestEvent)、レスポンス終了(mEndResponseEvent)のイベントをトリガにしています。
myNBTtransportメソッドは、次のようになっています。
endRequestメソッドを起動します。tはmyNBTransportメソッドに引数でInitiatorクラスからこのTargetクラスまでに加算された時間になり、ACCEPT_DELAYはSimpleATTarget1クラスのリクエスト開始からリクエスト終了までの時間(25ns)になります。つまり、t+25ns時間後にendRequestメソッドが呼び出される。
そして、戻り値としてtlm::TLM_ACCEPTを返します。
sync_enum_type myNBTransport(transaction_type& trans, phase_type& phase, sc_core::sc_time& t) { if (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; } 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]); } // Notify end of request phase after ACCEPT delay if (mEndRequestQueue.empty()) { mEndRequestEvent.notify(t + ACCEPT_DELAY); } mEndRequestQueue.push(&trans); // AT-noTA target // - always return false // - seperate call to indicate end of phase (do not update phase or t) return tlm::TLM_ACCEPTED; } else if (phase == tlm::END_RESP) { // response phase ends after t mEndResponseEvent.notify(t); return tlm::TLM_COMPLETED; } // Not possible assert(0); exit(1); return tlm::TLM_REJECTED; }Initiatorクラスからリクエスト開始(tlm::BEGIN_REQ)が来たときは、トランザクションのコマンドに対応して内部メモリにアクセスします。その後、mEndRequestEvent.notify(t+ACCEPT_DELAY)を実行し、
endRequestメソッドを起動します。tはmyNBTransportメソッドに引数でInitiatorクラスからこのTargetクラスまでに加算された時間になり、ACCEPT_DELAYはSimpleATTarget1クラスのリクエスト開始からリクエスト終了までの時間(25ns)になります。つまり、t+25ns時間後にendRequestメソッドが呼び出される。
そして、戻り値としてtlm::TLM_ACCEPTを返します。
endRequestメソッドでは、Initiatorクラスに対して、phaseをtlm::END_REQにしてnb_transportメソッドを実行します。これにより、Initiatorクラスはリクエストが終了することになります。
その後、mBeginResponseEvent.notify(RESPONSE_DELAY)を実行し、RESPONSE_DELAY後にレスポンス開始のためのbeginResponseメソッドが起動されます。
その後、mBeginResponseEvent.notify(RESPONSE_DELAY)を実行し、RESPONSE_DELAY後にレスポンス開始のためのbeginResponseメソッドが起動されます。
beginResponseメソッドでは、リクエストトランザクションがリード(tlm::TLM_READ_COMMAND)のときは、レスポンストランザクションのデータにメモりデータをコピーし、Initiatorクラスに対して、nb_transportメソッドを実行します。戻り値がtlm::TLM_COMPLETEDのときは、mEndResponseEvent.notify(t)を実行し、endResponseメソッドが起動されます。
Initiatorクラスからリクエスト開始(tlm::BEGIN_RES)が来たときは、mEndResponseEvent.notify(t)を実行し、戻り値としてtlm::TLM_COMPLETEDを返します。