TLM-2.0: include/tlm/tlm_utils/simple_target_socket.h Source File

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

# include/tlm/tlm_utils/simple_target_socket.h

Go to the documentation of this file.

    00001 /*****************************************************************************
    00002
    00003   The following code is derived, directly or indirectly, from the SystemC
    00004   source code Copyright (c) 1996-2008 by all Contributors.
    00005   All Rights reserved.
    00006
    00007   The contents of this file are subject to the restrictions and limitations
    00008   set forth in the SystemC Open Source License Version 3.0 (the "License");
    00009   You may not use this file except in compliance with such restrictions and
    00010   limitations. You may obtain instructions on how to receive a copy of the
    00011   License at http://www.systemc.org/. Software distributed by Contributors
    00012   under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
    00013   ANY KIND, either express or implied. See the License for the specific
    00014   language governing rights and limitations under the License.
    00015
    00016  *****************************************************************************/
    00017
    00018 // *****************************************************************************
    00019 // Modified by John Aynsley, Doulos, Feb 2009,
    00020 // Fix a bug in simple_target_socket and simple_target_socket_tagged
    00021 // with the addition of one new line of code in each:  wait(*e);
    00022 // *****************************************************************************
    00023
    00024
    00025 #ifndef __SIMPLE_TARGET_SOCKET_H__
    00026 #define __SIMPLE_TARGET_SOCKET_H__
    00027
    00028 #include "tlm.h"
    00029 #include "peq_with_get.h"
    00030 #include <sstream>
    00031
    00032 namespace tlm_utils {
    00033
    00034 template <typename MODULE,
    00035           unsigned int BUSWIDTH = 32,
    00036           typename TYPES = tlm::tlm_base_protocol_types>
    00037 class simple_target_socket :
    00038   public tlm::tlm_target_socket<BUSWIDTH, TYPES>
    00039 {
    00040   friend class fw_process;
    00041   friend class bw_process;
    00042 public:
    00043   typedef typename TYPES::tlm_payload_type              transaction_type;
    00044   typedef typename TYPES::tlm_phase_type                phase_type;
    00045   typedef tlm::tlm_sync_enum                            sync_enum_type;
    00046   typedef tlm::tlm_fw_transport_if<TYPES>               fw_interface_type;
    00047   typedef tlm::tlm_bw_transport_if<TYPES>               bw_interface_type;
    00048   typedef tlm::tlm_target_socket<BUSWIDTH, TYPES>       base_type;
    00049
    00050 public:
    00051   simple_target_socket() :
    00052     base_type(sc_core::sc_gen_unique_name("simple_target_socket")),
    00053     m_fw_process(this),
    00054     m_bw_process(this)
    00055   {
    00056     bind(m_fw_process);
    00057   }
    00058
    00059   explicit simple_target_socket(const char* n) :
    00060     base_type(n),
    00061     m_fw_process(this),
    00062     m_bw_process(this)
    00063   {
    00064     bind(m_fw_process);
    00065   }
    00066
    00067   // bw transport must come thru us.
    00068   tlm::tlm_bw_transport_if<TYPES> * operator ->() {return &m_bw_process;}
    00069
    00070   // REGISTER_XXX
    00071   void register_nb_transport_fw(MODULE* mod,
    00072                                 sync_enum_type (MODULE::*cb)(transaction_type&,
    00073                                                              phase_type&,
    00074                                                              sc_core::sc_time&))
    00075   {
    00076     assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
    00077     m_fw_process.set_nb_transport_ptr(mod, cb);
    00078   }
    00079
    00080   void register_b_transport(MODULE* mod,
    00081                             void (MODULE::*cb)(transaction_type&,
    00082                                                sc_core::sc_time&))
    00083   {
    00084     assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
    00085     m_fw_process.set_b_transport_ptr(mod, cb);
    00086   }
    00087
    00088   void register_transport_dbg(MODULE* mod,
    00089                               unsigned int (MODULE::*cb)(transaction_type&))
    00090   {
    00091     assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
    00092     m_fw_process.set_transport_dbg_ptr(mod, cb);
    00093   }
    00094
    00095   void register_get_direct_mem_ptr(MODULE* mod,
    00096                                    bool (MODULE::*cb)(transaction_type&,
    00097                                                       tlm::tlm_dmi&))
    00098   {
    00099     assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
    00100     m_fw_process.set_get_direct_mem_ptr(mod, cb);
    00101   }
    00102
    00103 private:
    00104   //make call on bw path.
    00105   sync_enum_type bw_nb_transport(transaction_type &trans, phase_type &phase, sc_core::sc_time &t)
    00106   {
    00107     return base_type::operator ->()->nb_transport_bw(trans, phase, t);
    00108   }
    00109
    00110   void bw_invalidate_direct_mem_ptr(sc_dt::uint64 s,sc_dt::uint64 e)
    00111   {
    00112     base_type::operator ->()->invalidate_direct_mem_ptr(s, e);
    00113   }
    00114
    00115   //Helper class to handle bw path calls
    00116   // Needed to detect transaction end when called from b_transport.
    00117   class bw_process : public tlm::tlm_bw_transport_if<TYPES>
    00118   {
    00119   public:
    00120     bw_process(simple_target_socket *p_own) : m_owner(p_own)
    00121     {
    00122     }
    00123
    00124     sync_enum_type nb_transport_bw(transaction_type &trans, phase_type &phase, sc_core::sc_time &t)
    00125     {
    00126       typename std::map<transaction_type*, sc_core::sc_event *>::iterator it;
    00127
    00128       it = m_owner->m_pending_trans.find(&trans);
    00129       if(it == m_owner->m_pending_trans.end()) {
    00130         // Not a blocking call, forward.
    00131         return m_owner->bw_nb_transport(trans, phase, t);
    00132
    00133       } else {
    00134         if (phase == tlm::END_REQ) {
    00135           m_owner->m_end_request.notify(sc_core::SC_ZERO_TIME);
    00136           return tlm::TLM_ACCEPTED;
    00137
    00138         } else if (phase == tlm::BEGIN_RESP) {
    00139           if (m_owner->m_current_transaction == &trans) {
    00140             m_owner->m_end_request.notify(sc_core::SC_ZERO_TIME);
    00141           }
    00142           //TODO: add response-accept delay?
    00143           it->second->notify(t);
    00144           m_owner->m_pending_trans.erase(it);
    00145           return tlm::TLM_COMPLETED;
    00146
    00147         } else {
    00148           assert(0); exit(1);
    00149         }
    00150
    00151 //        return tlm::TLM_COMPLETED;  //Should not reach here
    00152       }
    00153     }
    00154
    00155     void invalidate_direct_mem_ptr(sc_dt::uint64 s,sc_dt::uint64 e)
    00156     {
    00157       return m_owner->bw_invalidate_direct_mem_ptr(s, e);
    00158     }
    00159
    00160   private:
    00161     simple_target_socket *m_owner;
    00162   };
    00163
    00164   class fw_process : public tlm::tlm_fw_transport_if<TYPES>,
    00165                     public tlm::tlm_mm_interface
    00166   {
    00167   public:
    00168     typedef sync_enum_type (MODULE::*NBTransportPtr)(transaction_type&,
    00169                                                      phase_type&,
    00170                                                      sc_core::sc_time&);
    00171     typedef void (MODULE::*BTransportPtr)(transaction_type&,
    00172                                           sc_core::sc_time&);
    00173     typedef unsigned int (MODULE::*TransportDbgPtr)(transaction_type&);
    00174     typedef bool (MODULE::*GetDirectMemPtr)(transaction_type&,
    00175                                             tlm::tlm_dmi&);
    00176
    00177     fw_process(simple_target_socket *p_own) :
    00178       m_name(p_own->name()),
    00179       m_owner(p_own),
    00180       m_mod(0),
    00181       m_nb_transport_ptr(0),
    00182       m_b_transport_ptr(0),
    00183       m_transport_dbg_ptr(0),
    00184       m_get_direct_mem_ptr(0),
    00185       m_peq(sc_core::sc_gen_unique_name("m_peq")),
    00186       m_response_in_progress(false)
    00187     {
    00188       sc_core::sc_spawn_options opts;
    00189       opts.set_sensitivity(&m_peq.get_event());
    00190       sc_core::sc_spawn(sc_bind(&fw_process::b2nb_thread, this),
    00191                         sc_core::sc_gen_unique_name("b2nb_thread"), &opts);
    00192     }
    00193
    00194     void set_nb_transport_ptr(MODULE* mod, NBTransportPtr p)
    00195     {
    00196       if (m_nb_transport_ptr) {
    00197         std::stringstream s;
    00198         s << m_name << ": non-blocking callback allready registered";
    00199         SC_REPORT_WARNING("/OSCI_TLM-2/simple_socket",s.str().c_str());
    00200       } else {
    00201         assert(!m_mod || m_mod == mod);
    00202         m_mod = mod;
    00203         m_nb_transport_ptr = p;
    00204       }
    00205     }
    00206
    00207     void set_b_transport_ptr(MODULE* mod, BTransportPtr p)
    00208     {
    00209       if (m_b_transport_ptr) {
    00210         std::stringstream s;
    00211         s << m_name << ": blocking callback allready registered";
    00212         SC_REPORT_WARNING("/OSCI_TLM-2/simple_socket",s.str().c_str());
    00213       } else {
    00214         assert(!m_mod || m_mod == mod);
    00215         m_mod = mod;
    00216         m_b_transport_ptr = p;
    00217       }
    00218     }
    00219
    00220     void set_transport_dbg_ptr(MODULE* mod, TransportDbgPtr p)
    00221     {
    00222       if (m_transport_dbg_ptr) {
    00223         std::stringstream s;
    00224         s << m_name << ": debug callback allready registered";
    00225         SC_REPORT_WARNING("/OSCI_TLM-2/simple_socket",s.str().c_str());
    00226       } else {
    00227         assert(!m_mod || m_mod == mod);
    00228         m_mod = mod;
    00229         m_transport_dbg_ptr = p;
    00230       }
    00231     }
    00232
    00233     void set_get_direct_mem_ptr(MODULE* mod, GetDirectMemPtr p)
    00234     {
    00235       if (m_get_direct_mem_ptr) {
    00236         std::stringstream s;
    00237         s << m_name << ": get DMI pointer callback allready registered";
    00238         SC_REPORT_WARNING("/OSCI_TLM-2/simple_socket",s.str().c_str());
    00239       } else {
    00240         assert(!m_mod || m_mod == mod);
    00241         m_mod = mod;
    00242         m_get_direct_mem_ptr = p;
    00243       }
    00244     }
    00245 // Interface implementation
    00246     sync_enum_type nb_transport_fw(transaction_type& trans,
    00247                                    phase_type& phase,
    00248                                    sc_core::sc_time& t)
    00249     {
    00250       if (m_nb_transport_ptr) {
    00251         // forward call
    00252         assert(m_mod);
    00253         return (m_mod->*m_nb_transport_ptr)(trans, phase, t);
    00254
    00255       } else if (m_b_transport_ptr) {
    00256         if (phase == tlm::BEGIN_REQ) {
    00257           // create thread to do blocking call
    00258           sc_core::sc_spawn_options opts;
    00259           opts.dont_initialize();
    00260           sc_core::sc_event *e = new sc_core::sc_event;
    00261           opts.set_sensitivity(e);
    00262
    00263           //       sc_core::sc_spawn(sc_bind(&fw_process::nb2b_thread, this, sc_ref(trans), e),
    00264           //                  sc_core::sc_gen_unique_name("nb2b_thread"), &opts);
    00265
    00266           process_handle_class * ph = m_process_handle.get_handle(&trans,e);
    00267
    00268           if (!ph) { // create new dynamic process
    00269             ph = new process_handle_class(&trans,e);
    00270             m_process_handle.put_handle(ph);
    00271
    00272             sc_core::sc_spawn(sc_bind(&fw_process::nb2b_thread,this, ph, sc_ref(trans), e),
    00273                             sc_core::sc_gen_unique_name("nb2b_thread"), &opts);
    00274           } else { // reuse existing dynamic process and resume it
    00275             ph->m_wakeup.notify(); // immidiate notification
    00276           }
    00277
    00278
    00279           e->notify(t);
    00280           return tlm::TLM_ACCEPTED;
    00281
    00282         } else if (phase == tlm::END_RESP) {
    00283           m_response_in_progress = false;
    00284           m_end_response.notify(t);
    00285           return tlm::TLM_COMPLETED;
    00286
    00287         } else {
    00288           assert(0); exit(1);
    00289 //          return tlm::TLM_COMPLETED;   ///< unreachable code
    00290         }
    00291
    00292       } else {
    00293         std::stringstream s;
    00294         s << m_name << ": no non-blocking transport callback registered";
    00295         SC_REPORT_ERROR("/OSCI_TLM-2/simple_socket",s.str().c_str());
    00296       }
    00297       return tlm::TLM_ACCEPTED;
    00298     }
    00299
    00300     void b_transport(transaction_type& trans, sc_core::sc_time& t)
    00301     {
    00302       if (m_b_transport_ptr) {
    00303         // forward call
    00304         assert(m_mod);
    00305         (m_mod->*m_b_transport_ptr)(trans, t);
    00306         return;
    00307
    00308       } else if (m_nb_transport_ptr) {
    00309         m_peq.notify(trans, t);
    00310         t = sc_core::SC_ZERO_TIME;
    00311
    00312         mm_end_event_ext mm_ext;
    00313         const bool mm_added = !trans.has_mm();
    00314
    00315         if (mm_added) {
    00316           trans.set_mm(this);
    00317           trans.set_auto_extension(&mm_ext);
    00318           trans.acquire();
    00319         }
    00320
    00321         // wait until transaction is finished
    00322         sc_core::sc_event end_event;
    00323         m_owner->m_pending_trans[&trans] = &end_event;
    00324         sc_core::wait(end_event);
    00325
    00326         if (mm_added) {
    00327           // release will not delete the transaction, it will notify mm_ext.done
    00328           trans.release();
    00329           if (trans.get_ref_count()) {
    00330             sc_core::wait(mm_ext.done);
    00331           }
    00332           trans.set_mm(0);
    00333         }
    00334
    00335       } else {
    00336         std::stringstream s;
    00337         s << m_name << ": no blocking transport callback registered";
    00338         SC_REPORT_ERROR("/OSCI_TLM-2/simple_socket",s.str().c_str());
    00339       }
    00340     }
    00341
    00342     unsigned int transport_dbg(transaction_type& trans)
    00343     {
    00344       if (m_transport_dbg_ptr) {
    00345         // forward call
    00346         assert(m_mod);
    00347         return (m_mod->*m_transport_dbg_ptr)(trans);
    00348
    00349       } else {
    00350         // No debug support
    00351         return 0;
    00352       }
    00353     }
    00354
    00355     bool get_direct_mem_ptr(transaction_type& trans,
    00356                             tlm::tlm_dmi&  dmi_data)
    00357     {
    00358       if (m_get_direct_mem_ptr) {
    00359         // forward call
    00360         assert(m_mod);
    00361         return (m_mod->*m_get_direct_mem_ptr)(trans, dmi_data);
    00362
    00363       } else {
    00364         // No DMI support
    00365         dmi_data.allow_read_write();
    00366         dmi_data.set_start_address(0x0);
    00367         dmi_data.set_end_address((sc_dt::uint64)-1);
    00368         return false;
    00369       }
    00370     }
    00371
    00372   private:
    00373
    00374 // dynamic process handler for nb2b conversion
    00375
    00376     class process_handle_class {
    00377     public:
    00378       process_handle_class(transaction_type * trans,
    00379                            sc_core::sc_event* e):
    00380         m_trans(trans),m_e(e),m_suspend(false){}
    00381
    00382       transaction_type*  m_trans;
    00383       sc_core::sc_event* m_e;
    00384       sc_core::sc_event  m_wakeup;
    00385       bool m_suspend;
    00386     };
    00387
    00388     class process_handle_list {
    00389     public:
    00390       process_handle_list() {}
    00391
    00392       process_handle_class* get_handle(transaction_type *trans,sc_core::sc_event* e)
    00393       {
    00394         typename std::vector<process_handle_class*>::iterator it;
    00395
    00396         for(it = v.begin(); it != v.end(); it++) {
    00397           if ((*it)->m_suspend) {  // found suspended dynamic process, re-use it
    00398             (*it)->m_trans = trans; // replace to new one
    00399             (*it)->m_e = e;
    00400             return *it;
    00401           }
    00402         }
    00403         return NULL; // no suspended process
    00404       }
    00405
    00406       void put_handle(process_handle_class* ph)
    00407       {
    00408         v.push_back(ph);
    00409       }
    00410
    00411     private:
    00412       std::vector<process_handle_class*> v;
    00413     };
    00414
    00415     process_handle_list m_process_handle;
    00416
    00417
    00418     void nb2b_thread(process_handle_class* h,transaction_type &trans1, sc_core::sc_event *e1)
    00419     {
    00420       transaction_type *trans = &trans1;
    00421       sc_core::sc_event* e = e1;
    00422
    00423       while(1) {
    00424
    00425         sc_core::sc_time t = sc_core::SC_ZERO_TIME;
    00426
    00427         // forward call
    00428         assert(m_mod);
    00429         (m_mod->*m_b_transport_ptr)(*trans, t);
    00430
    00431         sc_core::wait(t);
    00432
    00433         // return path
    00434         while (m_response_in_progress) {
    00435           sc_core::wait(m_end_response);
    00436         }
    00437         t = sc_core::SC_ZERO_TIME;
    00438         phase_type phase = tlm::BEGIN_RESP;
    00439         if (m_owner->bw_nb_transport(*trans, phase, t) != tlm::TLM_COMPLETED) {
    00440           m_response_in_progress = true;
    00441         }
    00442
    00443         // cleanup
    00444         delete e;
    00445
    00446         // suspend until next transaction
    00447         h->m_suspend = true;
    00448         sc_core::wait(h->m_wakeup);
    00449
    00450         // start next transaction
    00451         h->m_suspend = false;
    00452         trans = h->m_trans;
    00453         e = h->m_e;
    00454
    00455         sc_core::wait(*e); // JA bug fix
    00456       }
    00457     }
    00458
    00459     void b2nb_thread()
    00460     {
    00461       while (true) {
    00462         sc_core::wait(m_peq.get_event());
    00463
    00464         transaction_type* trans;
    00465         while ((trans = m_peq.get_next_transaction())!=0) {
    00466           assert(m_mod);
    00467           assert(m_nb_transport_ptr);
    00468           phase_type phase = tlm::BEGIN_REQ;
    00469           sc_core::sc_time t = sc_core::SC_ZERO_TIME;
    00470
    00471           switch ((m_mod->*m_nb_transport_ptr)(*trans, phase, t)) {
    00472           case tlm::TLM_COMPLETED:
    00473           {
    00474             // notify transaction is finished
    00475             typename std::map<transaction_type*, sc_core::sc_event *>::iterator it =
    00476               m_owner->m_pending_trans.find(trans);
    00477             assert(it != m_owner->m_pending_trans.end());
    00478             it->second->notify(t);
    00479             m_owner->m_pending_trans.erase(it);
    00480             break;
    00481           }
    00482
    00483           case tlm::TLM_ACCEPTED:
    00484           case tlm::TLM_UPDATED:
    00485             switch (phase) {
    00486             case tlm::BEGIN_REQ:
    00487               m_owner->m_current_transaction = trans;
    00488               sc_core::wait(m_owner->m_end_request);
    00489               m_owner->m_current_transaction = 0;
    00490               break;
    00491
    00492             case tlm::END_REQ:
    00493               sc_core::wait(t);
    00494               break;
    00495
    00496             case tlm::BEGIN_RESP:
    00497             {
    00498               phase = tlm::END_RESP;
    00499               t = sc_core::SC_ZERO_TIME;
    00500               (m_mod->*m_nb_transport_ptr)(*trans, phase, t);
    00501
    00502               // notify transaction is finished
    00503               typename std::map<transaction_type*, sc_core::sc_event *>::iterator it =
    00504                 m_owner->m_pending_trans.find(trans);
    00505               assert(it != m_owner->m_pending_trans.end());
    00506               it->second->notify(t);
    00507               m_owner->m_pending_trans.erase(it);
    00508               break;
    00509             }
    00510
    00511             default:
    00512               assert(0); exit(1);
    00513             };
    00514             break;
    00515
    00516           default:
    00517             assert(0); exit(1);
    00518           };
    00519         }
    00520       }
    00521     }
    00522
    00523     void free(tlm::tlm_generic_payload* trans)
    00524     {
    00525       mm_end_event_ext* ext = trans->template get_extension<mm_end_event_ext>();
    00526       assert(ext);
    00527       // notif event first before freeing extensions (reset)
    00528       ext->done.notify();
    00529       trans->reset();
    00530     }
    00531
    00532   private:
    00533     struct mm_end_event_ext : public tlm::tlm_extension<mm_end_event_ext>
    00534     {
    00535       tlm::tlm_extension_base* clone() const { return NULL; }
    00536       void free() {}
    00537       void copy_from(tlm::tlm_extension_base const &) {}
    00538       sc_core::sc_event done;
    00539     };
    00540
    00541   private:
    00542     const std::string m_name;
    00543     simple_target_socket *m_owner;
    00544     MODULE* m_mod;
    00545     NBTransportPtr m_nb_transport_ptr;
    00546     BTransportPtr m_b_transport_ptr;
    00547     TransportDbgPtr m_transport_dbg_ptr;
    00548     GetDirectMemPtr m_get_direct_mem_ptr;
    00549     peq_with_get<transaction_type> m_peq;
    00550     bool m_response_in_progress;
    00551     sc_core::sc_event m_end_response;
    00552   };
    00553
    00554 private:
    00555   fw_process m_fw_process;
    00556   bw_process m_bw_process;
    00557   std::map<transaction_type*, sc_core::sc_event *> m_pending_trans;
    00558   sc_core::sc_event m_end_request;
    00559   transaction_type* m_current_transaction;
    00560 };
    00561
    00562 //ID Tagged version
    00563 template <typename MODULE,
    00564           unsigned int BUSWIDTH = 32,
    00565           typename TYPES = tlm::tlm_base_protocol_types>
    00566 class simple_target_socket_tagged :
    00567   public tlm::tlm_target_socket<BUSWIDTH, TYPES>
    00568 {
    00569   friend class fw_process;
    00570   friend class bw_process;
    00571 public:
    00572   typedef typename TYPES::tlm_payload_type              transaction_type;
    00573   typedef typename TYPES::tlm_phase_type                phase_type;
    00574   typedef tlm::tlm_sync_enum                            sync_enum_type;
    00575   typedef tlm::tlm_fw_transport_if<TYPES>               fw_interface_type;
    00576   typedef tlm::tlm_bw_transport_if<TYPES>               bw_interface_type;
    00577   typedef tlm::tlm_target_socket<BUSWIDTH, TYPES>       base_type;
    00578
    00579 public:
    00580   simple_target_socket_tagged() :
    00581     base_type(sc_core::sc_gen_unique_name("simple_target_socket_tagged")),
    00582     m_fw_process(this),
    00583     m_bw_process(this)
    00584   {
    00585     bind(m_fw_process);
    00586   }
    00587
    00588   explicit simple_target_socket_tagged(const char* n) :
    00589     base_type(n),
    00590     m_fw_process(this),
    00591     m_bw_process(this)
    00592   {
    00593     bind(m_fw_process);
    00594   }
    00595
    00596   // bw transport must come thru us.
    00597   tlm::tlm_bw_transport_if<TYPES> * operator ->() {return &m_bw_process;}
    00598
    00599   // REGISTER_XXX
    00600   void register_nb_transport_fw(MODULE* mod,
    00601                                 sync_enum_type (MODULE::*cb)(int id,
    00602                                                              transaction_type&,
    00603                                                              phase_type&,
    00604                                                              sc_core::sc_time&),
    00605                                 int id)
    00606   {
    00607     assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
    00608     m_fw_process.set_nb_transport_ptr(mod, cb);
    00609     m_fw_process.set_nb_transport_user_id(id);
    00610   }
    00611
    00612   void register_b_transport(MODULE* mod,
    00613                             void (MODULE::*cb)(int id,
    00614                                                transaction_type&,
    00615                                                sc_core::sc_time&),
    00616                             int id)
    00617   {
    00618     assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
    00619     m_fw_process.set_b_transport_ptr(mod, cb);
    00620     m_fw_process.set_b_transport_user_id(id);
    00621   }
    00622
    00623   void register_transport_dbg(MODULE* mod,
    00624                               unsigned int (MODULE::*cb)(int id,
    00625                                                          transaction_type&),
    00626                               int id)
    00627   {
    00628     assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
    00629     m_fw_process.set_transport_dbg_ptr(mod, cb);
    00630     m_fw_process.set_transport_dbg_user_id(id);
    00631   }
    00632
    00633   void register_get_direct_mem_ptr(MODULE* mod,
    00634                                    bool (MODULE::*cb)(int id,
    00635                                                       transaction_type&,
    00636                                                       tlm::tlm_dmi&),
    00637                                    int id)
    00638   {
    00639     assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
    00640     m_fw_process.set_get_direct_mem_ptr(mod, cb);
    00641     m_fw_process.set_get_dmi_user_id(id);
    00642   }
    00643
    00644 private:
    00645   //make call on bw path.
    00646   sync_enum_type bw_nb_transport(transaction_type &trans, phase_type &phase, sc_core::sc_time &t)
    00647   {
    00648     return base_type::operator ->()->nb_transport_bw(trans, phase, t);
    00649   }
    00650
    00651   void bw_invalidate_direct_mem_ptr(sc_dt::uint64 s,sc_dt::uint64 e)
    00652   {
    00653     base_type::operator ->()->invalidate_direct_mem_ptr(s, e);
    00654   }
    00655
    00656   //Helper class to handle bw path calls
    00657   // Needed to detect transaction end when called from b_transport.
    00658   class bw_process : public tlm::tlm_bw_transport_if<TYPES>
    00659   {
    00660   public:
    00661     bw_process(simple_target_socket_tagged *p_own) : m_owner(p_own)
    00662     {
    00663     }
    00664
    00665     sync_enum_type nb_transport_bw(transaction_type &trans, phase_type &phase, sc_core::sc_time &t)
    00666     {
    00667       typename std::map<transaction_type*, sc_core::sc_event *>::iterator it;
    00668
    00669       it = m_owner->m_pending_trans.find(&trans);
    00670       if(it == m_owner->m_pending_trans.end()) {
    00671         // Not a blocking call, forward.
    00672         return m_owner->bw_nb_transport(trans, phase, t);
    00673
    00674       } else {
    00675         if (phase == tlm::END_REQ) {
    00676           m_owner->m_end_request.notify(sc_core::SC_ZERO_TIME);
    00677           return tlm::TLM_ACCEPTED;
    00678
    00679         } else if (phase == tlm::BEGIN_RESP) {
    00680           if (m_owner->m_current_transaction == &trans) {
    00681             m_owner->m_end_request.notify(sc_core::SC_ZERO_TIME);
    00682           }
    00683           //TODO: add response-accept delay?
    00684           it->second->notify(t);
    00685           m_owner->m_pending_trans.erase(it);
    00686           return tlm::TLM_COMPLETED;
    00687
    00688         } else {
    00689           assert(0); exit(1);
    00690         }
    00691
    00692 //        return tlm::TLM_COMPLETED;  //Should not reach here
    00693       }
    00694     }
    00695
    00696     void invalidate_direct_mem_ptr(sc_dt::uint64 s,sc_dt::uint64 e)
    00697     {
    00698       return m_owner->bw_invalidate_direct_mem_ptr(s, e);
    00699     }
    00700
    00701   private:
    00702     simple_target_socket_tagged *m_owner;
    00703   };
    00704
    00705   class fw_process : public tlm::tlm_fw_transport_if<TYPES>,
    00706                      public tlm::tlm_mm_interface
    00707   {
    00708   public:
    00709     typedef sync_enum_type (MODULE::*NBTransportPtr)(int id,
    00710                                                      transaction_type&,
    00711                                                      phase_type&,
    00712                                                      sc_core::sc_time&);
    00713     typedef void (MODULE::*BTransportPtr)(int id,
    00714                                           transaction_type&,
    00715                                           sc_core::sc_time&);
    00716     typedef unsigned int (MODULE::*TransportDbgPtr)(int id,
    00717                                                     transaction_type&);
    00718     typedef bool (MODULE::*GetDirectMemPtr)(int id,
    00719                                             transaction_type&,
    00720                                             tlm::tlm_dmi&);
    00721
    00722     fw_process(simple_target_socket_tagged *p_own) :
    00723       m_name(p_own->name()),
    00724       m_owner(p_own),
    00725       m_mod(0),
    00726       m_nb_transport_ptr(0),
    00727       m_b_transport_ptr(0),
    00728       m_transport_dbg_ptr(0),
    00729       m_get_direct_mem_ptr(0),
    00730       m_nb_transport_user_id(0),
    00731       m_b_transport_user_id(0),
    00732       m_transport_dbg_user_id(0),
    00733       m_get_dmi_user_id(0),
    00734       m_peq(sc_core::sc_gen_unique_name("m_peq")),
    00735       m_response_in_progress(false)
    00736     {
    00737       sc_core::sc_spawn_options opts;
    00738       opts.set_sensitivity(&m_peq.get_event());
    00739       sc_core::sc_spawn(sc_bind(&fw_process::b2nb_thread, this),
    00740                         sc_core::sc_gen_unique_name("b2nb_thread"), &opts);
    00741     }
    00742
    00743     void set_nb_transport_user_id(int id) { m_nb_transport_user_id = id; }
    00744     void set_b_transport_user_id(int id) { m_b_transport_user_id = id; }
    00745     void set_transport_dbg_user_id(int id) { m_transport_dbg_user_id = id; }
    00746     void set_get_dmi_user_id(int id) { m_get_dmi_user_id = id; }
    00747
    00748     void set_nb_transport_ptr(MODULE* mod, NBTransportPtr p)
    00749     {
    00750       if (m_nb_transport_ptr) {
    00751         std::stringstream s;
    00752         s << m_name << ": non-blocking callback allready registered";
    00753         SC_REPORT_WARNING("/OSCI_TLM-2/simple_socket",s.str().c_str());
    00754       } else {
    00755         assert(!m_mod || m_mod == mod);
    00756         m_mod = mod;
    00757         m_nb_transport_ptr = p;
    00758       }
    00759     }
    00760
    00761     void set_b_transport_ptr(MODULE* mod, BTransportPtr p)
    00762     {
    00763       if (m_b_transport_ptr) {
    00764         std::stringstream s;
    00765         s << m_name << ": blocking callback allready registered";
    00766         SC_REPORT_WARNING("/OSCI_TLM-2/simple_socket",s.str().c_str());
    00767       } else {
    00768         assert(!m_mod || m_mod == mod);
    00769         m_mod = mod;
    00770         m_b_transport_ptr = p;
    00771       }
    00772     }
    00773
    00774     void set_transport_dbg_ptr(MODULE* mod, TransportDbgPtr p)
    00775     {
    00776       if (m_transport_dbg_ptr) {
    00777         std::stringstream s;
    00778         s << m_name << ": debug callback allready registered";
    00779         SC_REPORT_WARNING("/OSCI_TLM-2/simple_socket",s.str().c_str());
    00780       } else {
    00781         assert(!m_mod || m_mod == mod);
    00782         m_mod = mod;
    00783         m_transport_dbg_ptr = p;
    00784       }
    00785     }
    00786
    00787     void set_get_direct_mem_ptr(MODULE* mod, GetDirectMemPtr p)
    00788     {
    00789       if (m_get_direct_mem_ptr) {
    00790         std::stringstream s;
    00791         s << m_name << ": get DMI pointer callback allready registered";
    00792         SC_REPORT_WARNING("/OSCI_TLM-2/simple_socket",s.str().c_str());
    00793       } else {
    00794         assert(!m_mod || m_mod == mod);
    00795         m_mod = mod;
    00796         m_get_direct_mem_ptr = p;
    00797       }
    00798     }
    00799 // Interface implementation
    00800     sync_enum_type nb_transport_fw(transaction_type& trans,
    00801                                    phase_type& phase,
    00802                                    sc_core::sc_time& t)
    00803     {
    00804       if (m_nb_transport_ptr) {
    00805         // forward call
    00806         assert(m_mod);
    00807         return (m_mod->*m_nb_transport_ptr)(m_nb_transport_user_id, trans, phase, t);
    00808
    00809       } else if (m_b_transport_ptr) {
    00810         if (phase == tlm::BEGIN_REQ) {
    00811           // create thread to do blocking call
    00812           sc_core::sc_spawn_options opts;
    00813           opts.dont_initialize();
    00814           sc_core::sc_event *e = new sc_core::sc_event;
    00815           opts.set_sensitivity(e);
    00816
    00817           // sc_core::sc_spawn(sc_bind(&fw_process::nb2b_thread, this, sc_ref(trans), e),
    00818           //                  sc_core::sc_gen_unique_name("nb2b_thread"), &opts);
    00819
    00820           process_handle_class * ph = m_process_handle.get_handle(&trans,e);
    00821
    00822           if (!ph) { // create new dynamic process
    00823             ph = new process_handle_class(&trans,e);
    00824             m_process_handle.put_handle(ph);
    00825
    00826             sc_core::sc_spawn(sc_bind(&fw_process::nb2b_thread, this, ph, sc_ref(trans), e),
    00827                             sc_core::sc_gen_unique_name("nb2b_thread"), &opts);
    00828           } else { // reuse existing dynamic process and resume it
    00829             ph->m_wakeup.notify(); // immidiate notification
    00830           }
    00831
    00832           e->notify(t);
    00833           return tlm::TLM_ACCEPTED;
    00834
    00835         } else if (phase == tlm::END_RESP) {
    00836           m_response_in_progress = false;
    00837           m_end_response.notify(t);
    00838           return tlm::TLM_COMPLETED;
    00839
    00840         } else {
    00841           assert(0); exit(1);
    00842 //          return tlm::TLM_COMPLETED;   ///< unreachable code
    00843         }
    00844
    00845       } else {
    00846         std::stringstream s;
    00847         s << m_name << ": no non-blocking transport callback registered";
    00848         SC_REPORT_ERROR("/OSCI_TLM-2/simple_socket",s.str().c_str());
    00849       }
    00850       return tlm::TLM_ACCEPTED;
    00851     }
    00852
    00853     void b_transport(transaction_type& trans, sc_core::sc_time& t)
    00854     {
    00855       if (m_b_transport_ptr) {
    00856         // forward call
    00857         assert(m_mod);
    00858         (m_mod->*m_b_transport_ptr)(m_b_transport_user_id, trans, t);
    00859         return;
    00860
    00861       } else if (m_nb_transport_ptr) {
    00862         m_peq.notify(trans, t);
    00863         t = sc_core::SC_ZERO_TIME;
    00864
    00865         mm_end_event_ext mm_ext;
    00866         const bool mm_added = !trans.has_mm();
    00867
    00868         if (mm_added){
    00869           trans.set_mm(this);
    00870           trans.set_auto_extension(&mm_ext);
    00871           trans.acquire();
    00872         }
    00873
    00874         // wait until transaction is finished
    00875         sc_core::sc_event end_event;
    00876         m_owner->m_pending_trans[&trans] = &end_event;
    00877         sc_core::wait(end_event);
    00878
    00879         if (mm_added) {
    00880           // release will not delete the transaction, it will notify mm_ext.done
    00881           trans.release();
    00882           if (trans.get_ref_count()) {
    00883             sc_core::wait(mm_ext.done);
    00884           }
    00885           trans.set_mm(0);
    00886         }
    00887
    00888       } else {
    00889         std::stringstream s;
    00890         s << m_name << ": no transport callback registered";
    00891         SC_REPORT_ERROR("/OSCI_TLM-2/simple_socket",s.str().c_str());
    00892       }
    00893     }
    00894
    00895     unsigned int transport_dbg(transaction_type& trans)
    00896     {
    00897       if (m_transport_dbg_ptr) {
    00898         // forward call
    00899         assert(m_mod);
    00900         return (m_mod->*m_transport_dbg_ptr)(m_transport_dbg_user_id, trans);
    00901
    00902       } else {
    00903         // No debug support
    00904         return 0;
    00905       }
    00906     }
    00907
    00908     bool get_direct_mem_ptr(transaction_type& trans,
    00909                             tlm::tlm_dmi&  dmi_data)
    00910     {
    00911       if (m_get_direct_mem_ptr) {
    00912         // forward call
    00913         assert(m_mod);
    00914         return (m_mod->*m_get_direct_mem_ptr)(m_get_dmi_user_id, trans, dmi_data);
    00915
    00916       } else {
    00917         // No DMI support
    00918         dmi_data.allow_read_write();
    00919         dmi_data.set_start_address(0x0);
    00920         dmi_data.set_end_address((sc_dt::uint64)-1);
    00921         return false;
    00922       }
    00923     }
    00924
    00925   private:
    00926 // dynamic process handler for nb2b conversion
    00927
    00928     class process_handle_class {
    00929     public:
    00930       process_handle_class(transaction_type * trans,
    00931                            sc_core::sc_event* e):
    00932         m_trans(trans),m_e(e),m_suspend(false){}
    00933
    00934       transaction_type*  m_trans;
    00935       sc_core::sc_event* m_e;
    00936       sc_core::sc_event  m_wakeup;
    00937       bool m_suspend;
    00938     };
    00939
    00940     class process_handle_list {
    00941     public:
    00942       process_handle_list() {}
    00943
    00944       process_handle_class* get_handle(transaction_type *trans,sc_core::sc_event* e)
    00945       {
    00946         typename std::vector<process_handle_class*>::iterator it;
    00947
    00948         for(it = v.begin(); it != v.end(); it++) {
    00949           if ((*it)->m_suspend) {  // found suspended dynamic process, re-use it
    00950             (*it)->m_trans = trans; // replace to new one
    00951             (*it)->m_e = e;
    00952             return *it;
    00953           }
    00954         }
    00955         return NULL; // no suspended process
    00956       }
    00957
    00958       void put_handle(process_handle_class* ph)
    00959       {
    00960         v.push_back(ph);
    00961       }
    00962
    00963     private:
    00964       std::vector<process_handle_class*> v;
    00965     };
    00966
    00967     process_handle_list m_process_handle;
    00968
    00969     void nb2b_thread(process_handle_class* h,transaction_type &trans1, sc_core::sc_event *e1)
    00970     {
    00971       transaction_type *trans = &trans1;
    00972       sc_core::sc_event* e = e1;
    00973
    00974       while(1) {
    00975         sc_core::sc_time t = sc_core::SC_ZERO_TIME;
    00976
    00977         // forward call
    00978         assert(m_mod);
    00979         (m_mod->*m_b_transport_ptr)(m_b_transport_user_id, *trans, t);
    00980
    00981         sc_core::wait(t);
    00982
    00983         // return path
    00984         while (m_response_in_progress) {
    00985           sc_core::wait(m_end_response);
    00986         }
    00987         t = sc_core::SC_ZERO_TIME;
    00988         phase_type phase = tlm::BEGIN_RESP;
    00989         if (m_owner->bw_nb_transport(*trans, phase, t) != tlm::TLM_COMPLETED) {
    00990           m_response_in_progress = true;
    00991         }
    00992
    00993         // cleanup
    00994         delete e;
    00995
    00996         // suspend until next transaction
    00997         h->m_suspend = true;
    00998         sc_core::wait(h->m_wakeup);
    00999
    01000         // start next transaction
    01001         h->m_suspend = false;
    01002         trans = h->m_trans;
    01003         e = h->m_e;
    01004
    01005         sc_core::wait(*e); // JA bug fix
    01006       }
    01007     }
    01008
    01009     void b2nb_thread()
    01010     {
    01011       while (true) {
    01012         sc_core::wait(m_peq.get_event());
    01013
    01014         transaction_type* trans;
    01015         while ((trans = m_peq.get_next_transaction())!=0) {
    01016           assert(m_mod);
    01017           assert(m_nb_transport_ptr);
    01018           phase_type phase = tlm::BEGIN_REQ;
    01019           sc_core::sc_time t = sc_core::SC_ZERO_TIME;
    01020
    01021           switch ((m_mod->*m_nb_transport_ptr)(m_nb_transport_user_id, *trans, phase, t)) {
    01022           case tlm::TLM_COMPLETED:
    01023           {
    01024             // notify transaction is finished
    01025             typename std::map<transaction_type*, sc_core::sc_event *>::iterator it =
    01026               m_owner->m_pending_trans.find(trans);
    01027             assert(it != m_owner->m_pending_trans.end());
    01028             it->second->notify(t);
    01029             m_owner->m_pending_trans.erase(it);
    01030             break;
    01031           }
    01032
    01033           case tlm::TLM_ACCEPTED:
    01034           case tlm::TLM_UPDATED:
    01035             switch (phase) {
    01036             case tlm::BEGIN_REQ:
    01037               m_owner->m_current_transaction = trans;
    01038               sc_core::wait(m_owner->m_end_request);
    01039               m_owner->m_current_transaction = 0;
    01040               break;
    01041
    01042             case tlm::END_REQ:
    01043               sc_core::wait(t);
    01044               break;
    01045
    01046             case tlm::BEGIN_RESP:
    01047             {
    01048               phase = tlm::END_RESP;
    01049               t = sc_core::SC_ZERO_TIME;
    01050               (m_mod->*m_nb_transport_ptr)(m_nb_transport_user_id, *trans, phase, t);
    01051
    01052               // notify transaction is finished
    01053               typename std::map<transaction_type*, sc_core::sc_event *>::iterator it =
    01054                 m_owner->m_pending_trans.find(trans);
    01055               assert(it != m_owner->m_pending_trans.end());
    01056               it->second->notify(t);
    01057               m_owner->m_pending_trans.erase(it);
    01058               break;
    01059             }
    01060
    01061             default:
    01062               assert(0); exit(1);
    01063             };
    01064             break;
    01065
    01066           default:
    01067             assert(0); exit(1);
    01068           };
    01069         }
    01070       }
    01071     }
    01072
    01073     void free(tlm::tlm_generic_payload* trans)
    01074     {
    01075       mm_end_event_ext* ext = trans->template get_extension<mm_end_event_ext>();
    01076       assert(ext);
    01077       // notif event first before freeing extensions (reset)
    01078       ext->done.notify();
    01079       trans->reset();
    01080     }
    01081
    01082   private:
    01083     struct mm_end_event_ext : public tlm::tlm_extension<mm_end_event_ext>
    01084     {
    01085       tlm::tlm_extension_base* clone() const { return NULL; }
    01086       void free() {}
    01087       void copy_from(tlm::tlm_extension_base const &) {}
    01088       sc_core::sc_event done;
    01089     };
    01090
    01091   private:
    01092     const std::string m_name;
    01093     simple_target_socket_tagged *m_owner;
    01094     MODULE* m_mod;
    01095     NBTransportPtr m_nb_transport_ptr;
    01096     BTransportPtr m_b_transport_ptr;
    01097     TransportDbgPtr m_transport_dbg_ptr;
    01098     GetDirectMemPtr m_get_direct_mem_ptr;
    01099     int m_nb_transport_user_id;
    01100     int m_b_transport_user_id;
    01101     int m_transport_dbg_user_id;
    01102     int m_get_dmi_user_id;
    01103     peq_with_get<transaction_type> m_peq;
    01104     bool m_response_in_progress;
    01105     sc_core::sc_event m_end_response;
    01106   };
    01107
    01108 private:
    01109   fw_process m_fw_process;
    01110   bw_process m_bw_process;
    01111   std::map<transaction_type*, sc_core::sc_event *> m_pending_trans;
    01112   sc_core::sc_event m_end_request;
    01113   transaction_type* m_current_transaction;
    01114 };
    01115
    01116 }
    01117
    01118 #endif