diff options
Diffstat (limited to 'ext/systemc/src/tlm_utils/instance_specific_extensions.h')
-rw-r--r-- | ext/systemc/src/tlm_utils/instance_specific_extensions.h | 306 |
1 files changed, 306 insertions, 0 deletions
diff --git a/ext/systemc/src/tlm_utils/instance_specific_extensions.h b/ext/systemc/src/tlm_utils/instance_specific_extensions.h new file mode 100644 index 000000000..b17b86219 --- /dev/null +++ b/ext/systemc/src/tlm_utils/instance_specific_extensions.h @@ -0,0 +1,306 @@ +/***************************************************************************** + + 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 |