scc 2025.09
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 namespace tlm {
36namespace nw {
37
39
41public:
42 virtual void free(tlm_network_payload_base*) = 0;
43 virtual ~tlm_base_mm_interface() {}
44};
45
60
68 : m_extensions(max_num_extensions())
69 , m_mm(mm)
70 , m_ref_count(0){};
71
75 for(unsigned int i = 0; i < m_extensions.size(); i++)
76 if(m_extensions[i])
77 m_extensions[i]->free();
78 }
79
86 void reset() { m_extensions.free_entire_cache(); }
92 void acquire() {
93 sc_assert(m_mm != 0);
94 m_ref_count++;
95 }
96
102 void release() {
103 sc_assert(m_mm != 0 && m_ref_count > 0);
104 if(--m_ref_count == 0)
105 m_mm->free(this);
106 }
107
114 int get_ref_count() const { return m_ref_count; }
115
116 void set_mm(tlm_base_mm_interface* mm) { m_mm = mm; }
117 bool has_mm() const { return m_mm != 0; }
118
119 void copy_extensions_from(const tlm_network_payload_base& other);
120
121 void update_extensions_from(const tlm_network_payload_base& other);
122 // Free all extensions. Useful when reusing a cloned transaction that doesn't have memory manager.
123 // normal and sticky extensions are freed and extension array cleared.
124 void free_all_extensions();
125 // Stick the pointer to an extension into the vector, return the
126 // previous value:
127 template <typename T> T* set_extension(T* ext) { return static_cast<T*>(set_extension(T::ID, ext)); }
128
129 // non-templatized version with manual index:
130 tlm_extension_base* set_extension(unsigned int index, tlm_extension_base* ext);
131
132 // Stick the pointer to an extension into the vector, return the
133 // previous value and schedule its release
134 template <typename T> T* set_auto_extension(T* ext) { return static_cast<T*>(set_auto_extension(T::ID, ext)); }
135
136 // non-templatized version with manual index:
137 tlm_extension_base* set_auto_extension(unsigned int index, tlm_extension_base* ext);
138
139 // Check for an extension, ext will point to 0 if not present
140 template <typename T> void get_extension(T*& ext) const { ext = get_extension<T>(); }
141 template <typename T> T* get_extension() const { return static_cast<T*>(get_extension(T::ID)); }
142 // Non-templatized version with manual index:
143 tlm_extension_base* get_extension(unsigned int index) const;
144
145 // this call just removes the extension from the txn but does not
146 // call free() or tells the MM to do so
147 // it return false if there was active MM so you are now in an unsafe situation
148 // recommended use: when 100% sure there is no MM
149 template <typename T> void clear_extension(const T* ext) { clear_extension<T>(); }
150
151 // this call just removes the extension from the txn but does not
152 // call free() or tells the MM to do so
153 // it return false if there was active MM so you are now in an unsafe situation
154 // recommended use: when 100% sure there is no MM
155 template <typename T> void clear_extension() { clear_extension(T::ID); }
156
157 // this call removes the extension from the txn and does
158 // call free() or tells the MM to do so when the txn is finally done
159 // recommended use: when not sure there is no MM
160 template <typename T> void release_extension(T* ext) { release_extension<T>(); }
161
162 // this call removes the extension from the txn and does
163 // call free() or tells the MM to do so when the txn is finally done
164 // recommended use: when not sure there is no MM
165 template <typename T> void release_extension() { release_extension(T::ID); }
166
167 size_t get_extension_count() { return m_extensions.size(); }
168
169private:
170 // Non-templatized version with manual index
171 void clear_extension(unsigned int index);
172 // Non-templatized version with manual index
173 void release_extension(unsigned int index);
174
175public:
176 // Make sure the extension array is large enough. Can be called once by
177 // an initiator module (before issuing the first transaction) to make
178 // sure that the extension array is of correct size. This is only needed
179 // if the initiator cannot guarantee that the generic payload object is
180 // allocated after C++ static construction time.
181 void resize_extensions();
182
183private:
184 tlm::tlm_array<tlm_extension_base*> m_extensions;
185 tlm_base_mm_interface* m_mm;
186 unsigned int m_ref_count;
187};
188
199template <typename CMDENUM> struct tlm_network_payload : public tlm_network_payload_base {
214
216
220 virtual ~tlm_network_payload() = default;
236 CMDENUM get_command() const { return m_command; }
244 void set_command(const CMDENUM command) { m_command = command; }
252 std::vector<uint8_t> const& get_data() const { return m_data; }
260 std::vector<uint8_t>& get_data() { return m_data; }
268 void set_data(std::vector<uint8_t> const& value) { m_data = value; }
276 bool is_response_ok() const { return (m_response_status > 0); }
284 bool is_response_error() const { return (m_response_status <= 0); }
292 tlm_response_status get_response_status() const { return m_response_status; }
300 void set_response_status(const tlm_response_status response_status) { m_response_status = response_status; }
308 std::string get_response_string() const;
309
310 struct gp_mm : public tlm_base_mm_interface {
312 if(pool.size()) {
313 auto ret = pool.front();
314 pool.pop_front();
315 return ret;
316 } else
317 return new tlm_network_payload<CMDENUM>(this);
318 }
319 void free(tlm_network_payload_base* gp) override {
320 auto t = dynamic_cast<tlm_network_payload<CMDENUM>*>(gp);
321 t->free_all_extensions();
322 pool.push_back(t);
323 }
324 ~gp_mm() {
325 for(auto n : pool)
326 delete n;
327 }
328
329 private:
330 std::deque<tlm_network_payload<CMDENUM>*> pool;
331 };
332
340 static thread_local gp_mm mm;
341 return mm.create();
342 }
343
344protected:
346 m_command = x.m_command;
347 m_data = x.m_data;
348 m_response_status = x.m_response_status;
349 return *this;
350 }
351 CMDENUM m_command;
352 std::vector<uint8_t> m_data;
353 tlm_response_status m_response_status;
354};
355
356template <typename CMDENUM>
359, m_command(static_cast<CMDENUM>(0))
360, m_response_status(TLM_OK_RESPONSE) {}
361
362template <typename CMDENUM>
365, m_command(static_cast<CMDENUM>(0))
366, m_response_status(TLM_OK_RESPONSE) {}
367
368inline void tlm_network_payload_base::free_all_extensions() {
369 m_extensions.free_entire_cache();
370 for(unsigned int i = 0; i < m_extensions.size(); i++) {
371 if(m_extensions[i]) {
372 m_extensions[i]->free();
373 m_extensions[i] = 0;
374 }
375 }
376}
377
378template <typename CMDENUM> void tlm_network_payload<CMDENUM>::deep_copy_from(const tlm_network_payload& other) {
379 m_command = other.get_command();
380 m_response_status = other.get_response_status();
381 m_data = other.get_data();
382 copy_extensions_from(other);
383}
384
385template <typename CMDENUM> std::string tlm_network_payload<CMDENUM>::get_response_string() const {
386 switch(m_response_status) {
387 case TLM_OK_RESPONSE:
388 return "TLM_OK_RESPONSE";
389 case TLM_INCOMPLETE_RESPONSE:
390 return "TLM_INCOMPLETE_RESPONSE";
391 case TLM_GENERIC_ERROR_RESPONSE:
392 return "TLM_GENERIC_ERROR_RESPONSE";
393 case TLM_ADDRESS_ERROR_RESPONSE:
394 return "TLM_ADDRESS_ERROR_RESPONSE";
395 case TLM_COMMAND_ERROR_RESPONSE:
396 return "TLM_COMMAND_ERROR_RESPONSE";
397 case TLM_BURST_ERROR_RESPONSE:
398 return "TLM_BURST_ERROR_RESPONSE";
399 case TLM_BYTE_ENABLE_ERROR_RESPONSE:
400 return "TLM_BYTE_ENABLE_ERROR_RESPONSE";
401 }
402 return "TLM_UNKNOWN_RESPONSE";
403}
404
405inline tlm_extension_base* tlm_network_payload_base::set_extension(unsigned int index, tlm_extension_base* ext) {
406 sc_assert(index < m_extensions.size());
407 tlm_extension_base* tmp = m_extensions[index];
408 m_extensions[index] = ext;
409 return tmp;
410}
411
412inline tlm_extension_base* tlm_network_payload_base::set_auto_extension(unsigned int index, tlm_extension_base* ext) {
413 sc_assert(index < m_extensions.size());
414 tlm_extension_base* tmp = m_extensions[index];
415 m_extensions[index] = ext;
416 if(!tmp)
417 m_extensions.insert_in_cache(&m_extensions[index]);
418 sc_assert(m_mm != 0);
419 return tmp;
420}
421
422inline tlm_extension_base* tlm_network_payload_base::get_extension(unsigned int index) const {
423 sc_assert(index < m_extensions.size());
424 return m_extensions[index];
425}
426
427inline void tlm_network_payload_base::clear_extension(unsigned int index) {
428 sc_assert(index < m_extensions.size());
429 m_extensions[index] = static_cast<tlm_extension_base*>(0);
430}
431
432inline void tlm_network_payload_base::release_extension(unsigned int index) {
433 sc_assert(index < m_extensions.size());
434 if(m_mm) {
435 m_extensions.insert_in_cache(&m_extensions[index]);
436 } else {
437 m_extensions[index]->free();
438 m_extensions[index] = static_cast<tlm_extension_base*>(0);
439 }
440}
441
442inline void tlm_network_payload_base::update_extensions_from(const tlm_network_payload_base& other) {
443 // deep copy extensions that are already present
444 sc_assert(m_extensions.size() <= other.m_extensions.size());
445 for(unsigned int i = 0; i < m_extensions.size(); i++) {
446 if(other.m_extensions[i]) { // original has extension i
447 if(m_extensions[i]) { // We have it too. copy.
448 m_extensions[i]->copy_from(*other.m_extensions[i]);
449 }
450 }
451 }
452}
453
454inline void tlm_network_payload_base::copy_extensions_from(const tlm_network_payload_base& other) {
455 // deep copy extensions (sticky and non-sticky)
456 if(m_extensions.size() < other.m_extensions.size())
457 m_extensions.expand(other.m_extensions.size());
458 for(unsigned int i = 0; i < other.m_extensions.size(); i++) {
459 if(other.m_extensions[i]) { // original has extension i
460 if(!m_extensions[i]) { // We don't: clone.
461 tlm_extension_base* ext = other.m_extensions[i]->clone();
462 if(ext) { // extension may not be clonable.
463 if(has_mm()) { // mm can take care of removing cloned extensions
464 set_auto_extension(i, ext);
465 } else { // no mm, user will call free_all_extensions().
466 set_extension(i, ext);
467 }
468 }
469 } else { // We already have such extension. Copy original over it.
470 m_extensions[i]->copy_from(*other.m_extensions[i]);
471 }
472 }
473 }
474}
475
476inline void tlm_network_payload_base::resize_extensions() { m_extensions.expand(max_num_extensions()); }
477} // namespace nw
478} // namespace tlm
479#endif /* _TLM_NW_TLM_NETWROK_GP_H_ */
SCC TLM utilities.
Definition cxs_tlm.h:544
SystemC TLM.
Definition dmi_mgr.h:19
A base class for TLM network payloads.
void acquire()
Acquires a reference to the payload.
tlm_network_payload_base(tlm_base_mm_interface *mm)
Constructor with memory management interface.
void release()
Releases a reference to the payload.
tlm_network_payload_base()
Default constructor.
void reset()
Constructor with memory management interface.
int get_ref_count() const
Gets the reference count of the payload.
A class for TLM network payloads with support for extensions and memory management.
tlm_network_payload()
Default constructor.
CMDENUM get_command() const
Gets the command from the payload.
void deep_copy_from(const tlm_network_payload &other)
Non-virtual deep-copying of the object.
std::vector< uint8_t > & get_data()
Gets the data from the payload.
bool is_response_error() const
Checks if the response status is an error.
static tlm_network_payload< CMDENUM > * create()
Creates a new instance of the tlm_network_payload using a thread-local memory manager.
std::vector< uint8_t > const & get_data() const
Gets the data from the payload.
tlm_response_status get_response_status() const
Gets the response status from the payload.
void set_command(const CMDENUM command)
Sets the command in the payload.
std::string get_response_string() const
Gets the response status as a string.
void set_response_status(const tlm_response_status response_status)
Sets the response status in the payload.
virtual ~tlm_network_payload()=default
void set_data(std::vector< uint8_t > const &value)
Sets the data in the payload.
bool is_response_ok() const
Checks if the response status is OK.