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