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

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

# include/tlm/tlm_utils/instance_specific_extensions.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 Instance specific extensions, are extension that only a single instance of a module
    00020 may access. They are invisible to all other modules; they are private to this
    00021 instance so to speak.
    00022
    00023 As they are only of value to a certain instance, this instance knows very well
    00024 when it needs them and when it does not need them any longer (usually when
    00025 a transaction passes through a module for the last time).
    00026 It does not have to care if anyone else in the system may still have a
    00027 reference to the transaction as this one is not able to access the extension
    00028 anyway.
    00029 Therefore the instance is obliged to call set_extension when it wants to add a
    00030 private extension and clear_extension when it does not need it any more.
    00031
    00032 To get access to an instance specifc extension the module must own a so called
    00033 instance_specific_extension_accessor that provides the exclusive access rights.
    00034 Assuming the instance_specific_extension_accessor of a given module is called m_accessor
    00035 and the transaction of which the private extension is about to be accessed
    00036 is called txn, then the calls have to be
    00037
    00038 m_accessor(txn).set_extension(...);
    00039 or
    00040 m_accessor(txn).clear_extension(...);
    00041
    00042 The owner of the private extension is responsible to allocate/deallocate
    00043 the extension before/after setting/clearing the extension.
    00044 */
    00045
    00046 #ifndef __INSTANCE_SPECIFIC_EXTENSIONS_H__
    00047 #define __INSTANCE_SPECIFIC_EXTENSIONS_H__
    00048
    00049 #include "tlm.h"
    00050
    00051 namespace tlm_utils {
    00052
    00053 //Helper to do the numbering of private extension accessors
    00054 inline unsigned int max_num_ispex_accessors(bool increment=false)
    00055 {
    00056     static unsigned int max_num = 0;
    00057     if (increment) ++max_num;
    00058     return max_num;
    00059 }
    00060
    00061 //Helper to do the index generation for private extensions
    00062 inline unsigned int max_num_ispex(bool increment=false)
    00063 {
    00064     static unsigned int max_num = 0;
    00065     if (increment) ++max_num;
    00066     return max_num;
    00067 }
    00068
    00069 //The private extension base. Similar to normal extension base, but without clone and free
    00070 class ispex_base
    00071 {
    00072 public:
    00073     virtual ~ispex_base() {}
    00074 protected:
    00075     static unsigned int register_private_extension()
    00076     {
    00077         return (max_num_ispex(true) - 1);
    00078     };
    00079 };
    00080
    00081 //The templated private extension. Similar to normal extension
    00082 template <typename T>
    00083 class
    00084 instance_specific_extension : public ispex_base{
    00085 public:
    00086     virtual ~instance_specific_extension() {}
    00087     const static unsigned int priv_id;
    00088 };
    00089
    00090 template <typename T>
    00091 const
    00092 unsigned int instance_specific_extension<T>::priv_id = ispex_base::register_private_extension();
    00093
    00094
    00095 //this thing is basically a snippet of the generic_payload
    00096 // it contains all the extension specific code (the extension API so to speak)
    00097 // the differences are:
    00098 // - it calls back to its owner whenever a real (==non-NULL) extension gets set for the first time
    00099 // - it calls back to its owner whenever a living (==non-NULL) extension gets cleared
    00100 template<typename U>
    00101 class instance_specific_extensions_per_accessor{
    00102 public:
    00103
    00104   typedef void (U::*cb)();
    00105
    00106   instance_specific_extensions_per_accessor(U* container, cb inc, cb dec): m_container(container), m_inc(inc), m_dec(dec){
    00107   }
    00108
    00109   template <typename T> T* set_extension(T* ext)
    00110   {
    00111       resize_extensions();
    00112       T* tmp = static_cast<T*>(m_extensions[T::priv_id]);
    00113       m_extensions[T::priv_id] = static_cast<ispex_base*>(ext);
    00114       if (!tmp && ext) (m_container->*m_inc)();
    00115       return tmp;
    00116   }
    00117   // non-templatized version with manual index:
    00118   ispex_base* set_extension(unsigned int index,
    00119                                     ispex_base* ext)
    00120   {
    00121       resize_extensions();
    00122       ispex_base* tmp = m_extensions[index];
    00123       m_extensions[index] = ext;
    00124       if (!tmp && ext) (m_container->*m_inc)();
    00125       return tmp;
    00126   }
    00127
    00128   // Check for an extension, ext will point to 0 if not present
    00129   template <typename T> void get_extension(T*& ext) const
    00130   {
    00131       ext = static_cast<T*>(m_extensions[T::priv_id]);
    00132   }
    00133   // Non-templatized version:
    00134    ispex_base* get_extension(unsigned int index) const
    00135   {
    00136       return m_extensions[index];
    00137   }
    00138
    00139   // Clear extension, the argument is needed to find the right index:
    00140   template <typename T> void clear_extension(const T* ext)
    00141   {
    00142       resize_extensions();
    00143       if (m_extensions[T::priv_id]) (m_container->*m_dec)();
    00144       m_extensions[T::priv_id] = static_cast<ispex_base*>(0);
    00145   }
    00146   // Non-templatized version with manual index
    00147   void clear_extension(unsigned int index)
    00148   {
    00149       if (index < m_extensions.size())
    00150       {
    00151           if (m_extensions[index]) (m_container->*m_dec)();
    00152           m_extensions[index] = static_cast<ispex_base*>(0);
    00153       }
    00154   }
    00155
    00156   // Make sure the extension array is large enough. Can be called once by
    00157   // an initiator module (before issuing the first transaction) to make
    00158   // sure that the extension array is of correct size. This is only needed
    00159   // if the initiator cannot guarantee that the generic payload object is
    00160   // allocated after C++ static construction time.
    00161   void resize_extensions()
    00162   {
    00163       m_extensions.expand(max_num_ispex());
    00164   }
    00165
    00166 private:
    00167   tlm::tlm_array<ispex_base*> m_extensions;
    00168   U* m_container;
    00169   cb m_inc, m_dec;
    00170
    00171 };
    00172
    00173 class instance_specific_extension_container;
    00174
    00175
    00176 //the pool for the container, plain as can be
    00177 class instance_specific_extension_container_pool{
    00178   friend class instance_specific_extension_carrier;
    00179   friend class instance_specific_extension_container;
    00180   instance_specific_extension_container_pool() : unused(NULL){}
    00181   inline ~instance_specific_extension_container_pool();
    00182   inline static instance_specific_extension_container_pool& get_ispexcont_pool(){ static instance_specific_extension_container_pool tmp; return tmp;}
    00183   inline instance_specific_extension_container* create();
    00184   inline void free(instance_specific_extension_container*);
    00185
    00186   instance_specific_extension_container* unused;
    00187 };
    00188
    00189 class instance_specific_extension_carrier;
    00190
    00191 //this thing contains the vector of extensions per accessor
    00192 //which can be really large so this one should be pool allocated
    00193 // therefore it keeps a use_count of itself to automatically free itself
    00194 // - to this end it provides callbacks to the extensions per accessor
    00195 //   to increment and decrement the use_count
    00196 class instance_specific_extension_container{
    00197   friend class instance_specific_extension_container_pool;
    00198   friend class instance_specific_extension_accessor;
    00199   friend class instance_specific_extension_carrier;
    00200
    00201   instance_specific_extension_container(): use_count(0), next(NULL){resize();}
    00202
    00203   void resize(){
    00204     m_ispex_per_accessor.resize(max_num_ispex_accessors());
    00205     for (unsigned int i=0; i<m_ispex_per_accessor.size(); i++) {
    00206       m_ispex_per_accessor[i]=new instance_specific_extensions_per_accessor<instance_specific_extension_container>(this,
    00207                                                                                    &instance_specific_extension_container::inc_use_count,
    00208                                                                                    &instance_specific_extension_container::dec_use_count
    00209                                                                                    );
    00210       m_ispex_per_accessor[i]->resize_extensions();
    00211     }
    00212   }
    00213
    00214   ~instance_specific_extension_container(){
    00215     for (unsigned int i=0; i<m_ispex_per_accessor.size(); i++) delete m_ispex_per_accessor[i];
    00216   }
    00217
    00218   void inc_use_count(){use_count++;}
    00219   inline void dec_use_count();
    00220
    00221   std::vector<instance_specific_extensions_per_accessor<instance_specific_extension_container>* > m_ispex_per_accessor;
    00222   unsigned int use_count;
    00223   tlm::tlm_generic_payload* my_txn;
    00224   instance_specific_extension_carrier* my_carrier;
    00225   instance_specific_extension_container* next; //for pooling
    00226 };
    00227
    00228
    00229 inline instance_specific_extension_container_pool::~instance_specific_extension_container_pool(){
    00230   while(unused) { instance_specific_extension_container* tmp=unused; unused=unused->next; delete tmp;}
    00231 }
    00232
    00233 instance_specific_extension_container* instance_specific_extension_container_pool::create(){
    00234   if (!unused) {unused=new instance_specific_extension_container();}
    00235   instance_specific_extension_container* tmp=unused;
    00236   unused=unused->next;
    00237   return tmp;
    00238 }
    00239
    00240 void instance_specific_extension_container_pool::free(instance_specific_extension_container* cont){
    00241   cont->next=unused;
    00242   unused=cont;
    00243 }
    00244
    00245 //This is the class that actually sits in the extension array
    00246 //we keep this small since that one gets allocated and deallocated all the times
    00247 class instance_specific_extension_carrier: public tlm::tlm_extension<instance_specific_extension_carrier>{
    00248   friend class instance_specific_extension_accessor;
    00249
    00250 public:
    00251   instance_specific_extension_carrier(){
    00252     m_container=instance_specific_extension_container_pool::get_ispexcont_pool().create();
    00253     m_container->my_carrier=this;
    00254   }
    00255
    00256   virtual tlm::tlm_extension_base* clone() const {
    00257     //we don't clone since private info is instance specific and associated to a given txn (the original)
    00258     //so the deep copied txn will be virgin in terms of private info
    00259     return NULL;
    00260   }
    00261   void copy_from(tlm::tlm_extension_base const &){return;}
    00262   void free(){return;}
    00263 private:
    00264   instance_specific_extension_container* m_container;
    00265 };
    00266
    00267 inline void instance_specific_extension_container::dec_use_count(){
    00268   if ((--use_count)==0) { //if this container isn't used any more
    00269     instance_specific_extension_container_pool::get_ispexcont_pool().free(this);  //we send it back to our pool
    00270     //we have to do that manually, as we cannot rely on the fact that there is MM in the txn
    00271     my_txn->clear_extension(my_carrier); //and remove it from the transaction's extension array
    00272     delete my_carrier;
    00273   }
    00274 }
    00275
    00276
    00277 //This class 'hides' all the instance specific extension stuff from the user
    00278 // he instantiates one of those (e.g. instance_specific_extension_accessor extAcc;) and can then access
    00279 // the private extensions
    00280 //    extAcc(txn).extensionAPIFnCall()
    00281 //  where extensionAPIFnCall is set_extension, get_extension, clear_extension,...
    00282 class instance_specific_extension_accessor{
    00283 public:
    00284   instance_specific_extension_accessor(): m_index(max_num_ispex_accessors(true)-1){}
    00285
    00286   template<typename T>
    00287   inline instance_specific_extensions_per_accessor<instance_specific_extension_container>& operator()(T& txn){
    00288     instance_specific_extension_carrier* carrier;
    00289     txn.get_extension(carrier);
    00290     if (!carrier){
    00291       carrier=new instance_specific_extension_carrier();
    00292       carrier->m_container->my_txn=&txn;
    00293       txn.set_extension(carrier);
    00294     }
    00295     return *(carrier->m_container->m_ispex_per_accessor[m_index]);
    00296   }
    00297
    00298 protected:
    00299   unsigned int m_index;
    00300 };
    00301
    00302 }
    00303
    00304 #endif