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

Generated on Thu Jun 5 17:43:04 2008 for TLM 2 by  doxygen 1.5.3