| /***************************************************************************** |
| |
| Licensed to Accellera Systems Initiative Inc. (Accellera) under one or |
| more contributor license agreements. See the NOTICE file distributed |
| with this work for additional information regarding copyright ownership. |
| Accellera licenses this file to you under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with the |
| License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
| implied. See the License for the specific language governing |
| permissions and limitations under the License. |
| |
| *****************************************************************************/ |
| |
| /* |
| Instance specific extensions, are extension that only a single instance of a module |
| may access. They are invisible to all other modules; they are private to this |
| instance so to speak. |
| |
| As they are only of value to a certain instance, this instance knows very well |
| when it needs them and when it does not need them any longer (usually when |
| a transaction passes through a module for the last time). |
| It does not have to care if anyone else in the system may still have a |
| reference to the transaction as this one is not able to access the extension |
| anyway. |
| Therefore the instance is obliged to call set_extension when it wants to add a |
| private extension and clear_extension when it does not need it any more. |
| |
| To get access to an instance specifc extension the module must own a so called |
| instance_specific_extension_accessor that provides the exclusive access rights. |
| Assuming the instance_specific_extension_accessor of a given module is called m_accessor |
| and the transaction of which the private extension is about to be accessed |
| is called txn, then the calls have to be |
| |
| m_accessor(txn).set_extension(...); |
| or |
| m_accessor(txn).clear_extension(...); |
| |
| The owner of the private extension is responsible to allocate/deallocate |
| the extension before/after setting/clearing the extension. |
| */ |
| |
| #ifndef __INSTANCE_SPECIFIC_EXTENSIONS_H__ |
| #define __INSTANCE_SPECIFIC_EXTENSIONS_H__ |
| |
| #include <tlm> |
| |
| namespace tlm_utils { |
| |
| //Helper to do the numbering of private extension accessors |
| inline unsigned int max_num_ispex_accessors(bool increment=false) |
| { |
| static unsigned int max_num = 0; |
| if (increment) ++max_num; |
| return max_num; |
| } |
| |
| //Helper to do the index generation for private extensions |
| inline unsigned int max_num_ispex(bool increment=false) |
| { |
| static unsigned int max_num = 0; |
| if (increment) ++max_num; |
| return max_num; |
| } |
| |
| //The private extension base. Similar to normal extension base, but without clone and free |
| class ispex_base |
| { |
| public: |
| virtual ~ispex_base() {} |
| protected: |
| static unsigned int register_private_extension() |
| { |
| return (max_num_ispex(true) - 1); |
| }; |
| }; |
| |
| //The templated private extension. Similar to normal extension |
| template <typename T> |
| class |
| instance_specific_extension : public ispex_base{ |
| public: |
| virtual ~instance_specific_extension() {} |
| const static unsigned int priv_id; |
| }; |
| |
| template <typename T> |
| const |
| unsigned int instance_specific_extension<T>::priv_id = ispex_base::register_private_extension(); |
| |
| |
| //this thing is basically a snippet of the generic_payload |
| // it contains all the extension specific code (the extension API so to speak) |
| // the differences are: |
| // - it calls back to its owner whenever a real (==non-NULL) extension gets set for the first time |
| // - it calls back to its owner whenever a living (==non-NULL) extension gets cleared |
| template<typename U> |
| class instance_specific_extensions_per_accessor{ |
| public: |
| |
| typedef void (U::*cb)(); |
| |
| instance_specific_extensions_per_accessor(U* container, cb inc, cb dec): m_container(container), m_inc(inc), m_dec(dec){ |
| } |
| |
| template <typename T> T* set_extension(T* ext) |
| { |
| resize_extensions(); |
| T* tmp = static_cast<T*>(m_extensions[T::priv_id]); |
| m_extensions[T::priv_id] = static_cast<ispex_base*>(ext); |
| if (!tmp && ext) (m_container->*m_inc)(); |
| return tmp; |
| } |
| // non-templatized version with manual index: |
| ispex_base* set_extension(unsigned int index, |
| ispex_base* ext) |
| { |
| resize_extensions(); |
| ispex_base* tmp = m_extensions[index]; |
| m_extensions[index] = ext; |
| if (!tmp && ext) (m_container->*m_inc)(); |
| return tmp; |
| } |
| |
| // Check for an extension, ext will point to 0 if not present |
| template <typename T> void get_extension(T*& ext) const |
| { |
| ext = static_cast<T*>(m_extensions[T::priv_id]); |
| } |
| // Non-templatized version: |
| ispex_base* get_extension(unsigned int index) const |
| { |
| return m_extensions[index]; |
| } |
| |
| // Clear extension, the argument is needed to find the right index: |
| template <typename T> void clear_extension(const T* ext) |
| { |
| resize_extensions(); |
| if (m_extensions[T::priv_id]) (m_container->*m_dec)(); |
| m_extensions[T::priv_id] = static_cast<ispex_base*>(0); |
| } |
| // Non-templatized version with manual index |
| void clear_extension(unsigned int index) |
| { |
| if (index < m_extensions.size()) |
| { |
| if (m_extensions[index]) (m_container->*m_dec)(); |
| m_extensions[index] = static_cast<ispex_base*>(0); |
| } |
| } |
| |
| // Make sure the extension array is large enough. Can be called once by |
| // an initiator module (before issuing the first transaction) to make |
| // sure that the extension array is of correct size. This is only needed |
| // if the initiator cannot guarantee that the generic payload object is |
| // allocated after C++ static construction time. |
| void resize_extensions() |
| { |
| m_extensions.expand(max_num_ispex()); |
| } |
| |
| private: |
| tlm::tlm_array<ispex_base*> m_extensions; |
| U* m_container; |
| cb m_inc, m_dec; |
| |
| }; |
| |
| class instance_specific_extension_container; |
| |
| |
| //the pool for the container, plain as can be |
| class instance_specific_extension_container_pool{ |
| friend class instance_specific_extension_carrier; |
| friend class instance_specific_extension_container; |
| instance_specific_extension_container_pool() : unused(NULL){} |
| inline ~instance_specific_extension_container_pool(); |
| inline static instance_specific_extension_container_pool& get_ispexcont_pool(){ static instance_specific_extension_container_pool tmp; return tmp;} |
| inline instance_specific_extension_container* create(); |
| inline void free(instance_specific_extension_container*); |
| |
| instance_specific_extension_container* unused; |
| }; |
| |
| class instance_specific_extension_carrier; |
| |
| //this thing contains the vector of extensions per accessor |
| //which can be really large so this one should be pool allocated |
| // therefore it keeps a use_count of itself to automatically free itself |
| // - to this end it provides callbacks to the extensions per accessor |
| // to increment and decrement the use_count |
| class instance_specific_extension_container{ |
| friend class instance_specific_extension_container_pool; |
| friend class instance_specific_extension_accessor; |
| friend class instance_specific_extension_carrier; |
| |
| instance_specific_extension_container(): use_count(0), next(NULL){resize();} |
| |
| void resize(){ |
| m_ispex_per_accessor.resize(max_num_ispex_accessors()); |
| for (unsigned int i=0; i<m_ispex_per_accessor.size(); i++) { |
| m_ispex_per_accessor[i]=new instance_specific_extensions_per_accessor<instance_specific_extension_container>(this, |
| &instance_specific_extension_container::inc_use_count, |
| &instance_specific_extension_container::dec_use_count |
| ); |
| m_ispex_per_accessor[i]->resize_extensions(); |
| } |
| } |
| |
| ~instance_specific_extension_container(){ |
| for (unsigned int i=0; i<m_ispex_per_accessor.size(); i++) delete m_ispex_per_accessor[i]; |
| } |
| |
| void inc_use_count(){use_count++;} |
| inline void dec_use_count(); |
| |
| std::vector<instance_specific_extensions_per_accessor<instance_specific_extension_container>* > m_ispex_per_accessor; |
| unsigned int use_count; |
| tlm::tlm_generic_payload* my_txn; |
| instance_specific_extension_carrier* my_carrier; |
| instance_specific_extension_container* next; //for pooling |
| }; |
| |
| |
| inline instance_specific_extension_container_pool::~instance_specific_extension_container_pool(){ |
| while(unused) { instance_specific_extension_container* tmp=unused; unused=unused->next; delete tmp;} |
| } |
| |
| instance_specific_extension_container* instance_specific_extension_container_pool::create(){ |
| if (!unused) {unused=new instance_specific_extension_container();} |
| instance_specific_extension_container* tmp=unused; |
| unused=unused->next; |
| return tmp; |
| } |
| |
| void instance_specific_extension_container_pool::free(instance_specific_extension_container* cont){ |
| cont->next=unused; |
| unused=cont; |
| } |
| |
| //This is the class that actually sits in the extension array |
| //we keep this small since that one gets allocated and deallocated all the times |
| class instance_specific_extension_carrier: public tlm::tlm_extension<instance_specific_extension_carrier>{ |
| friend class instance_specific_extension_accessor; |
| |
| public: |
| instance_specific_extension_carrier(){ |
| m_container=instance_specific_extension_container_pool::get_ispexcont_pool().create(); |
| m_container->my_carrier=this; |
| } |
| |
| virtual tlm::tlm_extension_base* clone() const { |
| //we don't clone since private info is instance specific and associated to a given txn (the original) |
| //so the deep copied txn will be virgin in terms of private info |
| return NULL; |
| } |
| void copy_from(tlm::tlm_extension_base const &){return;} |
| void free(){return;} |
| private: |
| instance_specific_extension_container* m_container; |
| }; |
| |
| inline void instance_specific_extension_container::dec_use_count(){ |
| if ((--use_count)==0) { //if this container isn't used any more |
| instance_specific_extension_container_pool::get_ispexcont_pool().free(this); //we send it back to our pool |
| //we have to do that manually, as we cannot rely on the fact that there is MM in the txn |
| my_txn->clear_extension(my_carrier); //and remove it from the transaction's extension array |
| delete my_carrier; |
| } |
| } |
| |
| |
| //This class 'hides' all the instance specific extension stuff from the user |
| // he instantiates one of those (e.g. instance_specific_extension_accessor extAcc;) and can then access |
| // the private extensions |
| // extAcc(txn).extensionAPIFnCall() |
| // where extensionAPIFnCall is set_extension, get_extension, clear_extension,... |
| class instance_specific_extension_accessor{ |
| public: |
| instance_specific_extension_accessor(): m_index(max_num_ispex_accessors(true)-1){} |
| |
| template<typename T> |
| inline instance_specific_extensions_per_accessor<instance_specific_extension_container>& operator()(T& txn){ |
| instance_specific_extension_carrier* carrier; |
| txn.get_extension(carrier); |
| if (!carrier){ |
| carrier=new instance_specific_extension_carrier(); |
| carrier->m_container->my_txn=&txn; |
| txn.set_extension(carrier); |
| } |
| return *(carrier->m_container->m_ispex_per_accessor[m_index]); |
| } |
| |
| protected: |
| unsigned int m_index; |
| }; |
| |
| } |
| |
| #endif |