instance_specific_extensions.h revision 12027:1eb7dc7aa10b
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