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