scc  2022.4.0
SystemC components library
tlm_signal_gp.h
1 /*******************************************************************************
2  * Copyright 2018-2022 MINRES Technologies GmbH
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *******************************************************************************/
16 
17 #ifndef _TLM_TLM_SIGNAL_GP_H_
18 #define _TLM_TLM_SIGNAL_GP_H_
19 
20 #include <deque>
21 #ifdef CWR_SYSTEMC
22 #include <tlm_h/tlm_generic_payload/tlm_gp.h>
23 #else
24 #include <tlm_core/tlm_2/tlm_generic_payload/tlm_gp.h>
25 #endif
26 
28 namespace tlm {
30 namespace scc {
31 
32 struct tlm_generic_payload_base;
33 
35 public:
36  virtual void free(tlm_generic_payload_base*) = 0;
37  virtual ~tlm_base_mm_interface() {}
38 };
39 
42  : tlm_generic_payload_base(nullptr) {}
43 
45  : m_extensions(max_num_extensions())
46  , m_mm(mm)
47  , m_ref_count(0){};
48 
49  virtual ~tlm_generic_payload_base() {
50  for(unsigned int i = 0; i < m_extensions.size(); i++)
51  if(m_extensions[i])
52  m_extensions[i]->free();
53  }
54 
55  void reset() { m_extensions.free_entire_cache(); }
56 
57  void acquire() {
58  sc_assert(m_mm != 0);
59  m_ref_count++;
60  }
61 
62  void release() {
63  sc_assert(m_mm != 0 && m_ref_count > 0);
64  if(--m_ref_count == 0)
65  m_mm->free(this);
66  }
67 
68  int get_ref_count() const { return m_ref_count; }
69 
70  void set_mm(tlm_base_mm_interface* mm) { m_mm = mm; }
71  bool has_mm() const { return m_mm != 0; }
72 
73  void copy_extensions_from(const tlm_generic_payload_base& other);
74 
75  void update_extensions_from(const tlm_generic_payload_base& other);
76  // Free all extensions. Useful when reusing a cloned transaction that doesn't have memory manager.
77  // normal and sticky extensions are freed and extension array cleared.
78  void free_all_extensions();
79  // Stick the pointer to an extension into the vector, return the
80  // previous value:
81  template <typename T> T* set_extension(T* ext) { return static_cast<T*>(set_extension(T::ID, ext)); }
82 
83  // non-templatized version with manual index:
84  tlm_extension_base* set_extension(unsigned int index, tlm_extension_base* ext);
85 
86  // Stick the pointer to an extension into the vector, return the
87  // previous value and schedule its release
88  template <typename T> T* set_auto_extension(T* ext) { return static_cast<T*>(set_auto_extension(T::ID, ext)); }
89 
90  // non-templatized version with manual index:
91  tlm_extension_base* set_auto_extension(unsigned int index, tlm_extension_base* ext);
92 
93  // Check for an extension, ext will point to 0 if not present
94  template <typename T> void get_extension(T*& ext) const { ext = get_extension<T>(); }
95  template <typename T> T* get_extension() const { return static_cast<T*>(get_extension(T::ID)); }
96  // Non-templatized version with manual index:
97  tlm_extension_base* get_extension(unsigned int index) const;
98 
99  // this call just removes the extension from the txn but does not
100  // call free() or tells the MM to do so
101  // it return false if there was active MM so you are now in an unsafe situation
102  // recommended use: when 100% sure there is no MM
103  template <typename T> void clear_extension(const T* ext) { clear_extension<T>(); }
104 
105  // this call just removes the extension from the txn but does not
106  // call free() or tells the MM to do so
107  // it return false if there was active MM so you are now in an unsafe situation
108  // recommended use: when 100% sure there is no MM
109  template <typename T> void clear_extension() { clear_extension(T::ID); }
110 
111  // this call removes the extension from the txn and does
112  // call free() or tells the MM to do so when the txn is finally done
113  // recommended use: when not sure there is no MM
114  template <typename T> void release_extension(T* ext) { release_extension<T>(); }
115 
116  // this call removes the extension from the txn and does
117  // call free() or tells the MM to do so when the txn is finally done
118  // recommended use: when not sure there is no MM
119  template <typename T> void release_extension() { release_extension(T::ID); }
120 
121 private:
122  // Non-templatized version with manual index
123  void clear_extension(unsigned int index);
124  // Non-templatized version with manual index
125  void release_extension(unsigned int index);
126 
127 public:
128  // Make sure the extension array is large enough. Can be called once by
129  // an initiator module (before issuing the first transaction) to make
130  // sure that the extension array is of correct size. This is only needed
131  // if the initiator cannot guarantee that the generic payload object is
132  // allocated after C++ static construction time.
133  void resize_extensions();
134 
135 private:
136  tlm_array<tlm_extension_base*> m_extensions;
137  tlm_base_mm_interface* m_mm;
138  unsigned int m_ref_count;
139 };
140 
141 template <typename SIG = bool> struct tlm_signal_gp : public tlm_generic_payload_base {
142 
143  tlm_signal_gp();
144 
145  explicit tlm_signal_gp(tlm_base_mm_interface* mm);
146 
147  tlm_signal_gp(const tlm_signal_gp<SIG>& x) = delete;
148  tlm_signal_gp<SIG>& operator=(const tlm_signal_gp<SIG>& x) = delete;
149 
150  //--------------
151  // Destructor
152  //--------------
153  virtual ~tlm_signal_gp(){};
154  // non-virtual deep-copying of the object
155 
156  void deep_copy_from(const tlm_signal_gp& other);
157 
158  tlm_command get_command() const { return m_command; }
159  void set_command(const tlm_command command) { m_command = command; }
160 
161  SIG get_value() const { return m_value; }
162  void set_value(const SIG value) { m_value = value; }
163 
164  // Response status related methods
165  bool is_response_ok() const { return (m_response_status > 0); }
166  bool is_response_error() const { return (m_response_status <= 0); }
167  tlm_response_status get_response_status() const { return m_response_status; }
168  void set_response_status(const tlm_response_status response_status) { m_response_status = response_status; }
169  std::string get_response_string() const;
170 
171  struct gp_mm : public tlm_base_mm_interface {
172  tlm_signal_gp<SIG>* create() {
173  if(pool.size()) {
174  auto ret = pool.front();
175  pool.pop_front();
176  return ret;
177  } else
178  return new tlm_signal_gp<SIG>(this);
179  }
180  void free(tlm_generic_payload_base* gp) override {
181  auto t = dynamic_cast<tlm_signal_gp<SIG>*>(gp);
182  t->free_all_extensions();
183  pool.push_back(t);
184  }
185  ~gp_mm() {
186  for(auto n : pool)
187  delete n;
188  }
189 
190  private:
191  std::deque<tlm_signal_gp<SIG>*> pool;
192  };
193 
194  static tlm_signal_gp<SIG>* create() {
195  static thread_local gp_mm mm;
196  return mm.create();
197  }
198 
199 protected:
200  tlm_command m_command;
201  SIG m_value;
202  tlm_response_status m_response_status;
203 
204 public:
205 };
206 
207 template <typename SIG>
208 inline tlm_signal_gp<SIG>::tlm_signal_gp()
209 : tlm_generic_payload_base()
210 , m_command(TLM_IGNORE_COMMAND)
211 , m_response_status(TLM_OK_RESPONSE) {}
212 
213 template <typename SIG>
214 inline tlm_signal_gp<SIG>::tlm_signal_gp(tlm_base_mm_interface* mm)
215 : tlm_generic_payload_base(mm)
216 , m_command(TLM_IGNORE_COMMAND)
217 , m_response_status(TLM_OK_RESPONSE) {}
218 
219 inline void tlm_generic_payload_base::free_all_extensions() {
220  m_extensions.free_entire_cache();
221  for(unsigned int i = 0; i < m_extensions.size(); i++) {
222  if(m_extensions[i]) {
223  m_extensions[i]->free();
224  m_extensions[i] = 0;
225  }
226  }
227 }
228 
229 template <typename SIG> void tlm_signal_gp<SIG>::deep_copy_from(const tlm_signal_gp& other) {
230  m_command = other.get_command();
231  m_response_status = other.get_response_status();
232  m_value = other.get_value();
233  copy_extensions_from(other);
234 }
235 
236 template <typename SIG> std::string tlm_signal_gp<SIG>::get_response_string() const {
237  switch(m_response_status) {
238  case TLM_OK_RESPONSE:
239  return "TLM_OK_RESPONSE";
240  case TLM_INCOMPLETE_RESPONSE:
241  return "TLM_INCOMPLETE_RESPONSE";
242  case TLM_GENERIC_ERROR_RESPONSE:
243  return "TLM_GENERIC_ERROR_RESPONSE";
244  case TLM_ADDRESS_ERROR_RESPONSE:
245  return "TLM_ADDRESS_ERROR_RESPONSE";
246  case TLM_COMMAND_ERROR_RESPONSE:
247  return "TLM_COMMAND_ERROR_RESPONSE";
248  case TLM_BURST_ERROR_RESPONSE:
249  return "TLM_BURST_ERROR_RESPONSE";
250  case TLM_BYTE_ENABLE_ERROR_RESPONSE:
251  return "TLM_BYTE_ENABLE_ERROR_RESPONSE";
252  }
253  return "TLM_UNKNOWN_RESPONSE";
254 }
255 
256 inline tlm_extension_base* tlm_generic_payload_base::set_extension(unsigned int index, tlm_extension_base* ext) {
257  sc_assert(index < m_extensions.size());
258  tlm_extension_base* tmp = m_extensions[index];
259  m_extensions[index] = ext;
260  return tmp;
261 }
262 
263 inline tlm_extension_base* tlm_generic_payload_base::set_auto_extension(unsigned int index, tlm_extension_base* ext) {
264  sc_assert(index < m_extensions.size());
265  tlm_extension_base* tmp = m_extensions[index];
266  m_extensions[index] = ext;
267  if(!tmp)
268  m_extensions.insert_in_cache(&m_extensions[index]);
269  sc_assert(m_mm != 0);
270  return tmp;
271 }
272 
273 inline tlm_extension_base* tlm_generic_payload_base::get_extension(unsigned int index) const {
274  sc_assert(index < m_extensions.size());
275  return m_extensions[index];
276 }
277 
278 inline void tlm_generic_payload_base::clear_extension(unsigned int index) {
279  sc_assert(index < m_extensions.size());
280  m_extensions[index] = static_cast<tlm_extension_base*>(0);
281 }
282 
283 inline void tlm_generic_payload_base::release_extension(unsigned int index) {
284  sc_assert(index < m_extensions.size());
285  if(m_mm) {
286  m_extensions.insert_in_cache(&m_extensions[index]);
287  } else {
288  m_extensions[index]->free();
289  m_extensions[index] = static_cast<tlm_extension_base*>(0);
290  }
291 }
292 
293 inline void tlm_generic_payload_base::update_extensions_from(const tlm_generic_payload_base& other) {
294  // deep copy extensions that are already present
295  sc_assert(m_extensions.size() <= other.m_extensions.size());
296  for(unsigned int i = 0; i < m_extensions.size(); i++) {
297  if(other.m_extensions[i]) { // original has extension i
298  if(m_extensions[i]) { // We have it too. copy.
299  m_extensions[i]->copy_from(*other.m_extensions[i]);
300  }
301  }
302  }
303 }
304 
305 inline void tlm_generic_payload_base::copy_extensions_from(const tlm_generic_payload_base& other) {
306  // deep copy extensions (sticky and non-sticky)
307  if(m_extensions.size() < other.m_extensions.size())
308  m_extensions.expand(other.m_extensions.size());
309  for(unsigned int i = 0; i < other.m_extensions.size(); i++) {
310  if(other.m_extensions[i]) { // original has extension i
311  if(!m_extensions[i]) { // We don't: clone.
312  tlm_extension_base* ext = other.m_extensions[i]->clone();
313  if(ext) { // extension may not be clonable.
314  if(has_mm()) { // mm can take care of removing cloned extensions
315  set_auto_extension(i, ext);
316  } else { // no mm, user will call free_all_extensions().
317  set_extension(i, ext);
318  }
319  }
320  } else { // We already have such extension. Copy original over it.
321  m_extensions[i]->copy_from(*other.m_extensions[i]);
322  }
323  }
324  }
325 }
326 
327 inline void tlm_generic_payload_base::resize_extensions() { m_extensions.expand(max_num_extensions()); }
328 } // namespace scc
329 } // namespace tlm
330 #endif /* _TLM_TLM_SIGNAL_GP_H_ */
SCC SystemC utilities.
SystemC TLM.