112027Sjungma@eit.uni-kl.de/*****************************************************************************
212027Sjungma@eit.uni-kl.de
312027Sjungma@eit.uni-kl.de  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
412027Sjungma@eit.uni-kl.de  more contributor license agreements.  See the NOTICE file distributed
512027Sjungma@eit.uni-kl.de  with this work for additional information regarding copyright ownership.
612027Sjungma@eit.uni-kl.de  Accellera licenses this file to you under the Apache License, Version 2.0
712027Sjungma@eit.uni-kl.de  (the "License"); you may not use this file except in compliance with the
812027Sjungma@eit.uni-kl.de  License.  You may obtain a copy of the License at
912027Sjungma@eit.uni-kl.de
1012027Sjungma@eit.uni-kl.de    http://www.apache.org/licenses/LICENSE-2.0
1112027Sjungma@eit.uni-kl.de
1212027Sjungma@eit.uni-kl.de  Unless required by applicable law or agreed to in writing, software
1312027Sjungma@eit.uni-kl.de  distributed under the License is distributed on an "AS IS" BASIS,
1412027Sjungma@eit.uni-kl.de  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
1512027Sjungma@eit.uni-kl.de  implied.  See the License for the specific language governing
1612027Sjungma@eit.uni-kl.de  permissions and limitations under the License.
1712027Sjungma@eit.uni-kl.de
1812027Sjungma@eit.uni-kl.de *****************************************************************************/
1912027Sjungma@eit.uni-kl.de
2012027Sjungma@eit.uni-kl.de/*
2112027Sjungma@eit.uni-kl.deInstance specific extensions, are extension that only a single instance of a module
2212027Sjungma@eit.uni-kl.demay access. They are invisible to all other modules; they are private to this
2312027Sjungma@eit.uni-kl.deinstance so to speak.
2412027Sjungma@eit.uni-kl.de
2512027Sjungma@eit.uni-kl.deAs they are only of value to a certain instance, this instance knows very well
2612027Sjungma@eit.uni-kl.dewhen it needs them and when it does not need them any longer (usually when
2712027Sjungma@eit.uni-kl.dea transaction passes through a module for the last time).
2812027Sjungma@eit.uni-kl.deIt does not have to care if anyone else in the system may still have a
2912027Sjungma@eit.uni-kl.dereference to the transaction as this one is not able to access the extension
3012027Sjungma@eit.uni-kl.deanyway.
3112027Sjungma@eit.uni-kl.deTherefore the instance is obliged to call set_extension when it wants to add a
3212027Sjungma@eit.uni-kl.deprivate extension and clear_extension when it does not need it any more.
3312027Sjungma@eit.uni-kl.de
3412027Sjungma@eit.uni-kl.deTo get access to an instance specifc extension the module must own a so called
3512027Sjungma@eit.uni-kl.deinstance_specific_extension_accessor that provides the exclusive access rights.
3612027Sjungma@eit.uni-kl.deAssuming the instance_specific_extension_accessor of a given module is called m_accessor
3712027Sjungma@eit.uni-kl.deand the transaction of which the private extension is about to be accessed
3812027Sjungma@eit.uni-kl.deis called txn, then the calls have to be
3912027Sjungma@eit.uni-kl.de
4012027Sjungma@eit.uni-kl.dem_accessor(txn).set_extension(...);
4112027Sjungma@eit.uni-kl.deor
4212027Sjungma@eit.uni-kl.dem_accessor(txn).clear_extension(...);
4312027Sjungma@eit.uni-kl.de
4412027Sjungma@eit.uni-kl.deThe owner of the private extension is responsible to allocate/deallocate
4512027Sjungma@eit.uni-kl.dethe extension before/after setting/clearing the extension.
4612027Sjungma@eit.uni-kl.de*/
4712027Sjungma@eit.uni-kl.de
4812027Sjungma@eit.uni-kl.de#ifndef __INSTANCE_SPECIFIC_EXTENSIONS_H__
4912027Sjungma@eit.uni-kl.de#define __INSTANCE_SPECIFIC_EXTENSIONS_H__
5012027Sjungma@eit.uni-kl.de
5112027Sjungma@eit.uni-kl.de#include <tlm>
5212027Sjungma@eit.uni-kl.de
5312027Sjungma@eit.uni-kl.denamespace tlm_utils {
5412027Sjungma@eit.uni-kl.de
5512027Sjungma@eit.uni-kl.de//Helper to do the numbering of private extension accessors
5612027Sjungma@eit.uni-kl.deinline unsigned int max_num_ispex_accessors(bool increment=false)
5712027Sjungma@eit.uni-kl.de{
5812027Sjungma@eit.uni-kl.de    static unsigned int max_num = 0;
5912027Sjungma@eit.uni-kl.de    if (increment) ++max_num;
6012027Sjungma@eit.uni-kl.de    return max_num;
6112027Sjungma@eit.uni-kl.de}
6212027Sjungma@eit.uni-kl.de
6312027Sjungma@eit.uni-kl.de//Helper to do the index generation for private extensions
6412027Sjungma@eit.uni-kl.deinline unsigned int max_num_ispex(bool increment=false)
6512027Sjungma@eit.uni-kl.de{
6612027Sjungma@eit.uni-kl.de    static unsigned int max_num = 0;
6712027Sjungma@eit.uni-kl.de    if (increment) ++max_num;
6812027Sjungma@eit.uni-kl.de    return max_num;
6912027Sjungma@eit.uni-kl.de}
7012027Sjungma@eit.uni-kl.de
7112027Sjungma@eit.uni-kl.de//The private extension base. Similar to normal extension base, but without clone and free
7212027Sjungma@eit.uni-kl.declass ispex_base
7312027Sjungma@eit.uni-kl.de{
7412027Sjungma@eit.uni-kl.depublic:
7512027Sjungma@eit.uni-kl.de    virtual ~ispex_base() {}
7612027Sjungma@eit.uni-kl.deprotected:
7712027Sjungma@eit.uni-kl.de    static unsigned int register_private_extension()
7812027Sjungma@eit.uni-kl.de    {
7912027Sjungma@eit.uni-kl.de        return (max_num_ispex(true) - 1);
8012027Sjungma@eit.uni-kl.de    };
8112027Sjungma@eit.uni-kl.de};
8212027Sjungma@eit.uni-kl.de
8312027Sjungma@eit.uni-kl.de//The templated private extension. Similar to normal extension
8412027Sjungma@eit.uni-kl.detemplate <typename T>
8512027Sjungma@eit.uni-kl.declass
8612027Sjungma@eit.uni-kl.deinstance_specific_extension : public ispex_base{
8712027Sjungma@eit.uni-kl.depublic:
8812027Sjungma@eit.uni-kl.de    virtual ~instance_specific_extension() {}
8912027Sjungma@eit.uni-kl.de    const static unsigned int priv_id;
9012027Sjungma@eit.uni-kl.de};
9112027Sjungma@eit.uni-kl.de
9212027Sjungma@eit.uni-kl.detemplate <typename T>
9312027Sjungma@eit.uni-kl.deconst
9412027Sjungma@eit.uni-kl.deunsigned int instance_specific_extension<T>::priv_id = ispex_base::register_private_extension();
9512027Sjungma@eit.uni-kl.de
9612027Sjungma@eit.uni-kl.de
9712027Sjungma@eit.uni-kl.de//this thing is basically a snippet of the generic_payload
9812027Sjungma@eit.uni-kl.de// it contains all the extension specific code (the extension API so to speak)
9912027Sjungma@eit.uni-kl.de// the differences are:
10012027Sjungma@eit.uni-kl.de// - it calls back to its owner whenever a real (==non-NULL) extension gets set for the first time
10112027Sjungma@eit.uni-kl.de// - it calls back to its owner whenever a living (==non-NULL) extension gets cleared
10212027Sjungma@eit.uni-kl.detemplate<typename U>
10312027Sjungma@eit.uni-kl.declass instance_specific_extensions_per_accessor{
10412027Sjungma@eit.uni-kl.depublic:
10512027Sjungma@eit.uni-kl.de
10612027Sjungma@eit.uni-kl.de  typedef void (U::*cb)();
10712027Sjungma@eit.uni-kl.de
10812027Sjungma@eit.uni-kl.de  instance_specific_extensions_per_accessor(U* container, cb inc, cb dec): m_container(container), m_inc(inc), m_dec(dec){
10912027Sjungma@eit.uni-kl.de  }
11012027Sjungma@eit.uni-kl.de
11112027Sjungma@eit.uni-kl.de  template <typename T> T* set_extension(T* ext)
11212027Sjungma@eit.uni-kl.de  {
11312027Sjungma@eit.uni-kl.de      resize_extensions();
11412027Sjungma@eit.uni-kl.de      T* tmp = static_cast<T*>(m_extensions[T::priv_id]);
11512027Sjungma@eit.uni-kl.de      m_extensions[T::priv_id] = static_cast<ispex_base*>(ext);
11612027Sjungma@eit.uni-kl.de      if (!tmp && ext) (m_container->*m_inc)();
11712027Sjungma@eit.uni-kl.de      return tmp;
11812027Sjungma@eit.uni-kl.de  }
11912027Sjungma@eit.uni-kl.de  // non-templatized version with manual index:
12012027Sjungma@eit.uni-kl.de  ispex_base* set_extension(unsigned int index,
12112027Sjungma@eit.uni-kl.de                                    ispex_base* ext)
12212027Sjungma@eit.uni-kl.de  {
12312027Sjungma@eit.uni-kl.de      resize_extensions();
12412027Sjungma@eit.uni-kl.de      ispex_base* tmp = m_extensions[index];
12512027Sjungma@eit.uni-kl.de      m_extensions[index] = ext;
12612027Sjungma@eit.uni-kl.de      if (!tmp && ext) (m_container->*m_inc)();
12712027Sjungma@eit.uni-kl.de      return tmp;
12812027Sjungma@eit.uni-kl.de  }
12912027Sjungma@eit.uni-kl.de
13012027Sjungma@eit.uni-kl.de  // Check for an extension, ext will point to 0 if not present
13112027Sjungma@eit.uni-kl.de  template <typename T> void get_extension(T*& ext) const
13212027Sjungma@eit.uni-kl.de  {
13312027Sjungma@eit.uni-kl.de      ext = static_cast<T*>(m_extensions[T::priv_id]);
13412027Sjungma@eit.uni-kl.de  }
13512027Sjungma@eit.uni-kl.de  // Non-templatized version:
13612027Sjungma@eit.uni-kl.de   ispex_base* get_extension(unsigned int index) const
13712027Sjungma@eit.uni-kl.de  {
13812027Sjungma@eit.uni-kl.de      return m_extensions[index];
13912027Sjungma@eit.uni-kl.de  }
14012027Sjungma@eit.uni-kl.de
14112027Sjungma@eit.uni-kl.de  // Clear extension, the argument is needed to find the right index:
14212027Sjungma@eit.uni-kl.de  template <typename T> void clear_extension(const T* ext)
14312027Sjungma@eit.uni-kl.de  {
14412027Sjungma@eit.uni-kl.de      resize_extensions();
14512027Sjungma@eit.uni-kl.de      if (m_extensions[T::priv_id]) (m_container->*m_dec)();
14612027Sjungma@eit.uni-kl.de      m_extensions[T::priv_id] = static_cast<ispex_base*>(0);
14712027Sjungma@eit.uni-kl.de  }
14812027Sjungma@eit.uni-kl.de  // Non-templatized version with manual index
14912027Sjungma@eit.uni-kl.de  void clear_extension(unsigned int index)
15012027Sjungma@eit.uni-kl.de  {
15112027Sjungma@eit.uni-kl.de      if (index < m_extensions.size())
15212027Sjungma@eit.uni-kl.de      {
15312027Sjungma@eit.uni-kl.de          if (m_extensions[index]) (m_container->*m_dec)();
15412027Sjungma@eit.uni-kl.de          m_extensions[index] = static_cast<ispex_base*>(0);
15512027Sjungma@eit.uni-kl.de      }
15612027Sjungma@eit.uni-kl.de  }
15712027Sjungma@eit.uni-kl.de
15812027Sjungma@eit.uni-kl.de  // Make sure the extension array is large enough. Can be called once by
15912027Sjungma@eit.uni-kl.de  // an initiator module (before issuing the first transaction) to make
16012027Sjungma@eit.uni-kl.de  // sure that the extension array is of correct size. This is only needed
16112027Sjungma@eit.uni-kl.de  // if the initiator cannot guarantee that the generic payload object is
16212027Sjungma@eit.uni-kl.de  // allocated after C++ static construction time.
16312027Sjungma@eit.uni-kl.de  void resize_extensions()
16412027Sjungma@eit.uni-kl.de  {
16512027Sjungma@eit.uni-kl.de      m_extensions.expand(max_num_ispex());
16612027Sjungma@eit.uni-kl.de  }
16712027Sjungma@eit.uni-kl.de
16812027Sjungma@eit.uni-kl.deprivate:
16912027Sjungma@eit.uni-kl.de  tlm::tlm_array<ispex_base*> m_extensions;
17012027Sjungma@eit.uni-kl.de  U* m_container;
17112027Sjungma@eit.uni-kl.de  cb m_inc, m_dec;
17212027Sjungma@eit.uni-kl.de
17312027Sjungma@eit.uni-kl.de};
17412027Sjungma@eit.uni-kl.de
17512027Sjungma@eit.uni-kl.declass instance_specific_extension_container;
17612027Sjungma@eit.uni-kl.de
17712027Sjungma@eit.uni-kl.de
17812027Sjungma@eit.uni-kl.de//the pool for the container, plain as can be
17912027Sjungma@eit.uni-kl.declass instance_specific_extension_container_pool{
18012027Sjungma@eit.uni-kl.de  friend class instance_specific_extension_carrier;
18112027Sjungma@eit.uni-kl.de  friend class instance_specific_extension_container;
18212027Sjungma@eit.uni-kl.de  instance_specific_extension_container_pool() : unused(NULL){}
18312027Sjungma@eit.uni-kl.de  inline ~instance_specific_extension_container_pool();
18412027Sjungma@eit.uni-kl.de  inline static instance_specific_extension_container_pool& get_ispexcont_pool(){ static instance_specific_extension_container_pool tmp; return tmp;}
18512027Sjungma@eit.uni-kl.de  inline instance_specific_extension_container* create();
18612027Sjungma@eit.uni-kl.de  inline void free(instance_specific_extension_container*);
18712027Sjungma@eit.uni-kl.de
18812027Sjungma@eit.uni-kl.de  instance_specific_extension_container* unused;
18912027Sjungma@eit.uni-kl.de};
19012027Sjungma@eit.uni-kl.de
19112027Sjungma@eit.uni-kl.declass instance_specific_extension_carrier;
19212027Sjungma@eit.uni-kl.de
19312027Sjungma@eit.uni-kl.de//this thing contains the vector of extensions per accessor
19412027Sjungma@eit.uni-kl.de//which can be really large so this one should be pool allocated
19512027Sjungma@eit.uni-kl.de// therefore it keeps a use_count of itself to automatically free itself
19612027Sjungma@eit.uni-kl.de// - to this end it provides callbacks to the extensions per accessor
19712027Sjungma@eit.uni-kl.de//   to increment and decrement the use_count
19812027Sjungma@eit.uni-kl.declass instance_specific_extension_container{
19912027Sjungma@eit.uni-kl.de  friend class instance_specific_extension_container_pool;
20012027Sjungma@eit.uni-kl.de  friend class instance_specific_extension_accessor;
20112027Sjungma@eit.uni-kl.de  friend class instance_specific_extension_carrier;
20212027Sjungma@eit.uni-kl.de
20312027Sjungma@eit.uni-kl.de  instance_specific_extension_container(): use_count(0), next(NULL){resize();}
20412027Sjungma@eit.uni-kl.de
20512027Sjungma@eit.uni-kl.de  void resize(){
20612027Sjungma@eit.uni-kl.de    m_ispex_per_accessor.resize(max_num_ispex_accessors());
20712027Sjungma@eit.uni-kl.de    for (unsigned int i=0; i<m_ispex_per_accessor.size(); i++) {
20812027Sjungma@eit.uni-kl.de      m_ispex_per_accessor[i]=new instance_specific_extensions_per_accessor<instance_specific_extension_container>(this,
20912027Sjungma@eit.uni-kl.de                                                                                   &instance_specific_extension_container::inc_use_count,
21012027Sjungma@eit.uni-kl.de                                                                                   &instance_specific_extension_container::dec_use_count
21112027Sjungma@eit.uni-kl.de                                                                                   );
21212027Sjungma@eit.uni-kl.de      m_ispex_per_accessor[i]->resize_extensions();
21312027Sjungma@eit.uni-kl.de    }
21412027Sjungma@eit.uni-kl.de  }
21512027Sjungma@eit.uni-kl.de
21612027Sjungma@eit.uni-kl.de  ~instance_specific_extension_container(){
21712027Sjungma@eit.uni-kl.de    for (unsigned int i=0; i<m_ispex_per_accessor.size(); i++) delete m_ispex_per_accessor[i];
21812027Sjungma@eit.uni-kl.de  }
21912027Sjungma@eit.uni-kl.de
22012027Sjungma@eit.uni-kl.de  void inc_use_count(){use_count++;}
22112027Sjungma@eit.uni-kl.de  inline void dec_use_count();
22212027Sjungma@eit.uni-kl.de
22312027Sjungma@eit.uni-kl.de  std::vector<instance_specific_extensions_per_accessor<instance_specific_extension_container>* > m_ispex_per_accessor;
22412027Sjungma@eit.uni-kl.de  unsigned int use_count;
22512027Sjungma@eit.uni-kl.de  tlm::tlm_generic_payload* my_txn;
22612027Sjungma@eit.uni-kl.de  instance_specific_extension_carrier* my_carrier;
22712027Sjungma@eit.uni-kl.de  instance_specific_extension_container* next; //for pooling
22812027Sjungma@eit.uni-kl.de};
22912027Sjungma@eit.uni-kl.de
23012027Sjungma@eit.uni-kl.de
23112027Sjungma@eit.uni-kl.deinline instance_specific_extension_container_pool::~instance_specific_extension_container_pool(){
23212027Sjungma@eit.uni-kl.de  while(unused) { instance_specific_extension_container* tmp=unused; unused=unused->next; delete tmp;}
23312027Sjungma@eit.uni-kl.de}
23412027Sjungma@eit.uni-kl.de
23512027Sjungma@eit.uni-kl.deinstance_specific_extension_container* instance_specific_extension_container_pool::create(){
23612027Sjungma@eit.uni-kl.de  if (!unused) {unused=new instance_specific_extension_container();}
23712027Sjungma@eit.uni-kl.de  instance_specific_extension_container* tmp=unused;
23812027Sjungma@eit.uni-kl.de  unused=unused->next;
23912027Sjungma@eit.uni-kl.de  return tmp;
24012027Sjungma@eit.uni-kl.de}
24112027Sjungma@eit.uni-kl.de
24212027Sjungma@eit.uni-kl.devoid instance_specific_extension_container_pool::free(instance_specific_extension_container* cont){
24312027Sjungma@eit.uni-kl.de  cont->next=unused;
24412027Sjungma@eit.uni-kl.de  unused=cont;
24512027Sjungma@eit.uni-kl.de}
24612027Sjungma@eit.uni-kl.de
24712027Sjungma@eit.uni-kl.de//This is the class that actually sits in the extension array
24812027Sjungma@eit.uni-kl.de//we keep this small since that one gets allocated and deallocated all the times
24912027Sjungma@eit.uni-kl.declass instance_specific_extension_carrier: public tlm::tlm_extension<instance_specific_extension_carrier>{
25012027Sjungma@eit.uni-kl.de  friend class instance_specific_extension_accessor;
25112027Sjungma@eit.uni-kl.de
25212027Sjungma@eit.uni-kl.depublic:
25312027Sjungma@eit.uni-kl.de  instance_specific_extension_carrier(){
25412027Sjungma@eit.uni-kl.de    m_container=instance_specific_extension_container_pool::get_ispexcont_pool().create();
25512027Sjungma@eit.uni-kl.de    m_container->my_carrier=this;
25612027Sjungma@eit.uni-kl.de  }
25712027Sjungma@eit.uni-kl.de
25812027Sjungma@eit.uni-kl.de  virtual tlm::tlm_extension_base* clone() const {
25912027Sjungma@eit.uni-kl.de    //we don't clone since private info is instance specific and associated to a given txn (the original)
26012027Sjungma@eit.uni-kl.de    //so the deep copied txn will be virgin in terms of private info
26112027Sjungma@eit.uni-kl.de    return NULL;
26212027Sjungma@eit.uni-kl.de  }
26312027Sjungma@eit.uni-kl.de  void copy_from(tlm::tlm_extension_base const &){return;}
26412027Sjungma@eit.uni-kl.de  void free(){return;}
26512027Sjungma@eit.uni-kl.deprivate:
26612027Sjungma@eit.uni-kl.de  instance_specific_extension_container* m_container;
26712027Sjungma@eit.uni-kl.de};
26812027Sjungma@eit.uni-kl.de
26912027Sjungma@eit.uni-kl.deinline void instance_specific_extension_container::dec_use_count(){
27012027Sjungma@eit.uni-kl.de  if ((--use_count)==0) { //if this container isn't used any more
27112027Sjungma@eit.uni-kl.de    instance_specific_extension_container_pool::get_ispexcont_pool().free(this);  //we send it back to our pool
27212027Sjungma@eit.uni-kl.de    //we have to do that manually, as we cannot rely on the fact that there is MM in the txn
27312027Sjungma@eit.uni-kl.de    my_txn->clear_extension(my_carrier); //and remove it from the transaction's extension array
27412027Sjungma@eit.uni-kl.de    delete my_carrier;
27512027Sjungma@eit.uni-kl.de  }
27612027Sjungma@eit.uni-kl.de}
27712027Sjungma@eit.uni-kl.de
27812027Sjungma@eit.uni-kl.de
27912027Sjungma@eit.uni-kl.de//This class 'hides' all the instance specific extension stuff from the user
28012027Sjungma@eit.uni-kl.de// he instantiates one of those (e.g. instance_specific_extension_accessor extAcc;) and can then access
28112027Sjungma@eit.uni-kl.de// the private extensions
28212027Sjungma@eit.uni-kl.de//    extAcc(txn).extensionAPIFnCall()
28312027Sjungma@eit.uni-kl.de//  where extensionAPIFnCall is set_extension, get_extension, clear_extension,...
28412027Sjungma@eit.uni-kl.declass instance_specific_extension_accessor{
28512027Sjungma@eit.uni-kl.depublic:
28612027Sjungma@eit.uni-kl.de  instance_specific_extension_accessor(): m_index(max_num_ispex_accessors(true)-1){}
28712027Sjungma@eit.uni-kl.de
28812027Sjungma@eit.uni-kl.de  template<typename T>
28912027Sjungma@eit.uni-kl.de  inline instance_specific_extensions_per_accessor<instance_specific_extension_container>& operator()(T& txn){
29012027Sjungma@eit.uni-kl.de    instance_specific_extension_carrier* carrier;
29112027Sjungma@eit.uni-kl.de    txn.get_extension(carrier);
29212027Sjungma@eit.uni-kl.de    if (!carrier){
29312027Sjungma@eit.uni-kl.de      carrier=new instance_specific_extension_carrier();
29412027Sjungma@eit.uni-kl.de      carrier->m_container->my_txn=&txn;
29512027Sjungma@eit.uni-kl.de      txn.set_extension(carrier);
29612027Sjungma@eit.uni-kl.de    }
29712027Sjungma@eit.uni-kl.de    return *(carrier->m_container->m_ispex_per_accessor[m_index]);
29812027Sjungma@eit.uni-kl.de  }
29912027Sjungma@eit.uni-kl.de
30012027Sjungma@eit.uni-kl.deprotected:
30112027Sjungma@eit.uni-kl.de  unsigned int m_index;
30212027Sjungma@eit.uni-kl.de};
30312027Sjungma@eit.uni-kl.de
30412027Sjungma@eit.uni-kl.de}
30512027Sjungma@eit.uni-kl.de
30612027Sjungma@eit.uni-kl.de#endif
307