1/***************************************************************************** 2 3 Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 4 more contributor license agreements. See the NOTICE file distributed 5 with this work for additional information regarding copyright ownership. 6 Accellera licenses this file to you under the Apache License, Version 2.0 7 (the "License"); you may not use this file except in compliance with the 8 License. You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 implied. See the License for the specific language governing 16 permissions and limitations under the License. 17 18 *****************************************************************************/ 19 20/* 21Instance specific extensions, are extension that only a single instance of a module 22may access. They are invisible to all other modules; they are private to this 23instance so to speak. 24 25As they are only of value to a certain instance, this instance knows very well 26when it needs them and when it does not need them any longer (usually when 27a transaction passes through a module for the last time). 28It does not have to care if anyone else in the system may still have a 29reference to the transaction as this one is not able to access the extension 30anyway. 31Therefore the instance is obliged to call set_extension when it wants to add a 32private extension and clear_extension when it does not need it any more. 33 34To get access to an instance specifc extension the module must own a so called 35instance_specific_extension_accessor that provides the exclusive access rights. 36Assuming the instance_specific_extension_accessor of a given module is called m_accessor 37and the transaction of which the private extension is about to be accessed 38is called txn, then the calls have to be 39 40m_accessor(txn).set_extension(...); 41or 42m_accessor(txn).clear_extension(...); 43 44The owner of the private extension is responsible to allocate/deallocate 45the extension before/after setting/clearing the extension. 46*/ 47 48#ifndef __INSTANCE_SPECIFIC_EXTENSIONS_H__ 49#define __INSTANCE_SPECIFIC_EXTENSIONS_H__ 50 51#include <tlm> 52 53namespace tlm_utils { 54 55//Helper to do the numbering of private extension accessors 56inline unsigned int max_num_ispex_accessors(bool increment=false) 57{ 58 static unsigned int max_num = 0; 59 if (increment) ++max_num; 60 return max_num; 61} 62 63//Helper to do the index generation for private extensions 64inline unsigned int max_num_ispex(bool increment=false) 65{ 66 static unsigned int max_num = 0; 67 if (increment) ++max_num; 68 return max_num; 69} 70 71//The private extension base. Similar to normal extension base, but without clone and free 72class ispex_base 73{ 74public: 75 virtual ~ispex_base() {} 76protected: 77 static unsigned int register_private_extension() 78 { 79 return (max_num_ispex(true) - 1); 80 }; 81}; 82 83//The templated private extension. Similar to normal extension 84template <typename T> 85class 86instance_specific_extension : public ispex_base{ 87public: 88 virtual ~instance_specific_extension() {} 89 const static unsigned int priv_id; 90}; 91 92template <typename T> 93const 94unsigned int instance_specific_extension<T>::priv_id = ispex_base::register_private_extension(); 95 96 97//this thing is basically a snippet of the generic_payload 98// it contains all the extension specific code (the extension API so to speak) 99// the differences are: 100// - it calls back to its owner whenever a real (==non-NULL) extension gets set for the first time 101// - it calls back to its owner whenever a living (==non-NULL) extension gets cleared 102template<typename U> 103class instance_specific_extensions_per_accessor{ 104public: 105 106 typedef void (U::*cb)(); 107 108 instance_specific_extensions_per_accessor(U* container, cb inc, cb dec): m_container(container), m_inc(inc), m_dec(dec){ 109 } 110 111 template <typename T> T* set_extension(T* ext) 112 { 113 resize_extensions(); 114 T* tmp = static_cast<T*>(m_extensions[T::priv_id]); 115 m_extensions[T::priv_id] = static_cast<ispex_base*>(ext); 116 if (!tmp && ext) (m_container->*m_inc)(); 117 return tmp; 118 } 119 // non-templatized version with manual index: 120 ispex_base* set_extension(unsigned int index, 121 ispex_base* ext) 122 { 123 resize_extensions(); 124 ispex_base* tmp = m_extensions[index]; 125 m_extensions[index] = ext; 126 if (!tmp && ext) (m_container->*m_inc)(); 127 return tmp; 128 } 129 130 // Check for an extension, ext will point to 0 if not present 131 template <typename T> void get_extension(T*& ext) const 132 { 133 ext = static_cast<T*>(m_extensions[T::priv_id]); 134 } 135 // Non-templatized version: 136 ispex_base* get_extension(unsigned int index) const 137 { 138 return m_extensions[index]; 139 } 140 141 // Clear extension, the argument is needed to find the right index: 142 template <typename T> void clear_extension(const T* ext) 143 { 144 resize_extensions(); 145 if (m_extensions[T::priv_id]) (m_container->*m_dec)(); 146 m_extensions[T::priv_id] = static_cast<ispex_base*>(0); 147 } 148 // Non-templatized version with manual index 149 void clear_extension(unsigned int index) 150 { 151 if (index < m_extensions.size()) 152 { 153 if (m_extensions[index]) (m_container->*m_dec)(); 154 m_extensions[index] = static_cast<ispex_base*>(0); 155 } 156 } 157 158 // Make sure the extension array is large enough. Can be called once by 159 // an initiator module (before issuing the first transaction) to make 160 // sure that the extension array is of correct size. This is only needed 161 // if the initiator cannot guarantee that the generic payload object is 162 // allocated after C++ static construction time. 163 void resize_extensions() 164 { 165 m_extensions.expand(max_num_ispex()); 166 } 167 168private: 169 tlm::tlm_array<ispex_base*> m_extensions; 170 U* m_container; 171 cb m_inc, m_dec; 172 173}; 174 175class instance_specific_extension_container; 176 177 178//the pool for the container, plain as can be 179class instance_specific_extension_container_pool{ 180 friend class instance_specific_extension_carrier; 181 friend class instance_specific_extension_container; 182 instance_specific_extension_container_pool() : unused(NULL){} 183 inline ~instance_specific_extension_container_pool(); 184 inline static instance_specific_extension_container_pool& get_ispexcont_pool(){ static instance_specific_extension_container_pool tmp; return tmp;} 185 inline instance_specific_extension_container* create(); 186 inline void free(instance_specific_extension_container*); 187 188 instance_specific_extension_container* unused; 189}; 190 191class instance_specific_extension_carrier; 192 193//this thing contains the vector of extensions per accessor 194//which can be really large so this one should be pool allocated 195// therefore it keeps a use_count of itself to automatically free itself 196// - to this end it provides callbacks to the extensions per accessor 197// to increment and decrement the use_count 198class instance_specific_extension_container{ 199 friend class instance_specific_extension_container_pool; 200 friend class instance_specific_extension_accessor; 201 friend class instance_specific_extension_carrier; 202 203 instance_specific_extension_container(): use_count(0), next(NULL){resize();} 204 205 void resize(){ 206 m_ispex_per_accessor.resize(max_num_ispex_accessors()); 207 for (unsigned int i=0; i<m_ispex_per_accessor.size(); i++) { 208 m_ispex_per_accessor[i]=new instance_specific_extensions_per_accessor<instance_specific_extension_container>(this, 209 &instance_specific_extension_container::inc_use_count, 210 &instance_specific_extension_container::dec_use_count 211 ); 212 m_ispex_per_accessor[i]->resize_extensions(); 213 } 214 } 215 216 ~instance_specific_extension_container(){ 217 for (unsigned int i=0; i<m_ispex_per_accessor.size(); i++) delete m_ispex_per_accessor[i]; 218 } 219 220 void inc_use_count(){use_count++;} 221 inline void dec_use_count(); 222 223 std::vector<instance_specific_extensions_per_accessor<instance_specific_extension_container>* > m_ispex_per_accessor; 224 unsigned int use_count; 225 tlm::tlm_generic_payload* my_txn; 226 instance_specific_extension_carrier* my_carrier; 227 instance_specific_extension_container* next; //for pooling 228}; 229 230 231inline instance_specific_extension_container_pool::~instance_specific_extension_container_pool(){ 232 while(unused) { instance_specific_extension_container* tmp=unused; unused=unused->next; delete tmp;} 233} 234 235instance_specific_extension_container* instance_specific_extension_container_pool::create(){ 236 if (!unused) {unused=new instance_specific_extension_container();} 237 instance_specific_extension_container* tmp=unused; 238 unused=unused->next; 239 return tmp; 240} 241 242void instance_specific_extension_container_pool::free(instance_specific_extension_container* cont){ 243 cont->next=unused; 244 unused=cont; 245} 246 247//This is the class that actually sits in the extension array 248//we keep this small since that one gets allocated and deallocated all the times 249class instance_specific_extension_carrier: public tlm::tlm_extension<instance_specific_extension_carrier>{ 250 friend class instance_specific_extension_accessor; 251 252public: 253 instance_specific_extension_carrier(){ 254 m_container=instance_specific_extension_container_pool::get_ispexcont_pool().create(); 255 m_container->my_carrier=this; 256 } 257 258 virtual tlm::tlm_extension_base* clone() const { 259 //we don't clone since private info is instance specific and associated to a given txn (the original) 260 //so the deep copied txn will be virgin in terms of private info 261 return NULL; 262 } 263 void copy_from(tlm::tlm_extension_base const &){return;} 264 void free(){return;} 265private: 266 instance_specific_extension_container* m_container; 267}; 268 269inline void instance_specific_extension_container::dec_use_count(){ 270 if ((--use_count)==0) { //if this container isn't used any more 271 instance_specific_extension_container_pool::get_ispexcont_pool().free(this); //we send it back to our pool 272 //we have to do that manually, as we cannot rely on the fact that there is MM in the txn 273 my_txn->clear_extension(my_carrier); //and remove it from the transaction's extension array 274 delete my_carrier; 275 } 276} 277 278 279//This class 'hides' all the instance specific extension stuff from the user 280// he instantiates one of those (e.g. instance_specific_extension_accessor extAcc;) and can then access 281// the private extensions 282// extAcc(txn).extensionAPIFnCall() 283// where extensionAPIFnCall is set_extension, get_extension, clear_extension,... 284class instance_specific_extension_accessor{ 285public: 286 instance_specific_extension_accessor(): m_index(max_num_ispex_accessors(true)-1){} 287 288 template<typename T> 289 inline instance_specific_extensions_per_accessor<instance_specific_extension_container>& operator()(T& txn){ 290 instance_specific_extension_carrier* carrier; 291 txn.get_extension(carrier); 292 if (!carrier){ 293 carrier=new instance_specific_extension_carrier(); 294 carrier->m_container->my_txn=&txn; 295 txn.set_extension(carrier); 296 } 297 return *(carrier->m_container->m_ispex_per_accessor[m_index]); 298 } 299 300protected: 301 unsigned int m_index; 302}; 303 304} 305 306#endif 307