scc 2026.07
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 "tlm_array.h"
21#include <deque>
22#include <vector>
23#ifdef CWR_SYSTEMC
24#include <tlm_h/tlm_generic_payload/tlm_gp.h>
25#else
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::nw::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 void set_data(std::vector<uint8_t>&& value) { m_data = std::move(value); }
284 bool is_response_ok() const { return (m_response_status > 0); }
292 bool is_response_error() const { return (m_response_status <= 0); }
300 tlm_response_status get_response_status() const { return m_response_status; }
308 void set_response_status(const tlm_response_status response_status) { m_response_status = response_status; }
316 std::string get_response_string() const;
317
318 struct gp_mm : public tlm_base_mm_interface {
320 if(pool.size()) {
321 auto ret = pool.front();
322 pool.pop_front();
323 return ret;
324 } else
325 return new tlm_network_payload<CMDENUM>(this);
326 }
327 void free(tlm_network_payload_base* gp) override {
328 auto t = dynamic_cast<tlm_network_payload<CMDENUM>*>(gp);
329 t->free_all_extensions();
330 pool.push_back(t);
331 }
332 ~gp_mm() {
333 for(auto n : pool)
334 delete n;
335 }
336
337 private:
338 std::deque<tlm_network_payload<CMDENUM>*> pool;
339 };
340
348 static thread_local gp_mm mm;
349 return mm.create();
350 }
351
352protected:
354 m_command = x.m_command;
355 m_data = x.m_data;
356 m_response_status = x.m_response_status;
357 return *this;
358 }
359 CMDENUM m_command;
360 std::vector<uint8_t> m_data;
361 tlm_response_status m_response_status;
362};
363
364template <typename CMDENUM>
367, m_command(static_cast<CMDENUM>(0))
368, m_response_status(TLM_OK_RESPONSE) {}
369
370template <typename CMDENUM>
373, m_command(static_cast<CMDENUM>(0))
374, m_response_status(TLM_OK_RESPONSE) {}
375
376inline void tlm_network_payload_base::free_all_extensions() {
377 m_extensions.free_entire_cache();
378 for(unsigned int i = 0; i < m_extensions.size(); i++) {
379 if(m_extensions[i]) {
380 m_extensions[i]->free();
381 m_extensions[i] = 0;
382 }
383 }
384}
385
386template <typename CMDENUM> void tlm_network_payload<CMDENUM>::deep_copy_from(const tlm_network_payload& other) {
387 m_command = other.get_command();
388 m_response_status = other.get_response_status();
389 m_data = other.get_data();
390 copy_extensions_from(other);
391}
392
393template <typename CMDENUM> std::string tlm_network_payload<CMDENUM>::get_response_string() const {
394 switch(m_response_status) {
395 case TLM_OK_RESPONSE:
396 return "TLM_OK_RESPONSE";
397 case TLM_INCOMPLETE_RESPONSE:
398 return "TLM_INCOMPLETE_RESPONSE";
399 case TLM_GENERIC_ERROR_RESPONSE:
400 return "TLM_GENERIC_ERROR_RESPONSE";
401 case TLM_ADDRESS_ERROR_RESPONSE:
402 return "TLM_ADDRESS_ERROR_RESPONSE";
403 case TLM_COMMAND_ERROR_RESPONSE:
404 return "TLM_COMMAND_ERROR_RESPONSE";
405 case TLM_BURST_ERROR_RESPONSE:
406 return "TLM_BURST_ERROR_RESPONSE";
407 case TLM_BYTE_ENABLE_ERROR_RESPONSE:
408 return "TLM_BYTE_ENABLE_ERROR_RESPONSE";
409 }
410 return "TLM_UNKNOWN_RESPONSE";
411}
412
413inline tlm_extension_base* tlm_network_payload_base::set_extension(unsigned int index, tlm_extension_base* ext) {
414 sc_assert(index < m_extensions.size());
415 tlm_extension_base* tmp = m_extensions[index];
416 m_extensions[index] = ext;
417 return tmp;
418}
419
420inline tlm_extension_base* tlm_network_payload_base::set_auto_extension(unsigned int index, tlm_extension_base* ext) {
421 sc_assert(index < m_extensions.size());
422 tlm_extension_base* tmp = m_extensions[index];
423 m_extensions[index] = ext;
424 if(!tmp)
425 m_extensions.insert_in_cache(&m_extensions[index]);
426 sc_assert(m_mm != 0);
427 return tmp;
428}
429
430inline tlm_extension_base* tlm_network_payload_base::get_extension(unsigned int index) const {
431 sc_assert(index < m_extensions.size());
432 return m_extensions[index];
433}
434
435inline void tlm_network_payload_base::clear_extension(unsigned int index) {
436 sc_assert(index < m_extensions.size());
437 m_extensions[index] = static_cast<tlm_extension_base*>(0);
438}
439
440inline void tlm_network_payload_base::release_extension(unsigned int index) {
441 sc_assert(index < m_extensions.size());
442 if(m_mm) {
443 m_extensions.insert_in_cache(&m_extensions[index]);
444 } else {
445 m_extensions[index]->free();
446 m_extensions[index] = static_cast<tlm_extension_base*>(0);
447 }
448}
449
450inline void tlm_network_payload_base::update_extensions_from(const tlm_network_payload_base& other) {
451 // deep copy extensions that are already present
452 sc_assert(m_extensions.size() <= other.m_extensions.size());
453 for(unsigned int i = 0; i < m_extensions.size(); i++) {
454 if(other.m_extensions[i]) { // original has extension i
455 if(m_extensions[i]) { // We have it too. copy.
456 m_extensions[i]->copy_from(*other.m_extensions[i]);
457 }
458 }
459 }
460}
461
462inline void tlm_network_payload_base::copy_extensions_from(const tlm_network_payload_base& other) {
463 // deep copy extensions (sticky and non-sticky)
464 if(m_extensions.size() < other.m_extensions.size())
465 m_extensions.expand(other.m_extensions.size());
466 for(unsigned int i = 0; i < other.m_extensions.size(); i++) {
467 if(other.m_extensions[i]) { // original has extension i
468 if(!m_extensions[i]) { // We don't: clone.
469 tlm_extension_base* ext = other.m_extensions[i]->clone();
470 if(ext) { // extension may not be clonable.
471 if(has_mm()) { // mm can take care of removing cloned extensions
472 set_auto_extension(i, ext);
473 } else { // no mm, user will call free_all_extensions().
474 set_extension(i, ext);
475 }
476 }
477 } else { // We already have such extension. Copy original over it.
478 m_extensions[i]->copy_from(*other.m_extensions[i]);
479 }
480 }
481 }
482}
483
484inline void tlm_network_payload_base::resize_extensions() { m_extensions.expand(max_num_extensions()); }
485} // namespace nw
486} // namespace tlm
487#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.
void set_data(std::vector< uint8_t > &&value)
Sets the data in 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.