gp.cc (13523:de27641700bb) gp.cc (13586:008fe87c1ad4)
1/*****************************************************************************
2
3 Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
4 more contributor license agreements. See the NOTICE file distributed
5 with this work for additional information regarding copyright ownership.
6 Accellera licenses this file to you under the Apache License, Version 2.0
7 (the "License"); you may not use this file except in compliance with the
8 License. You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
15 implied. See the License for the specific language governing
16 permissions and limitations under the License.
17
18 *****************************************************************************/
19
20#include <cstring> // std::memcpy et.al.
21#include <map>
1/*****************************************************************************
2
3 Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
4 more contributor license agreements. See the NOTICE file distributed
5 with this work for additional information regarding copyright ownership.
6 Accellera licenses this file to you under the Apache License, Version 2.0
7 (the "License"); you may not use this file except in compliance with the
8 License. You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
15 implied. See the License for the specific language governing
16 permissions and limitations under the License.
17
18 *****************************************************************************/
19
20#include <cstring> // std::memcpy et.al.
21#include <map>
22#include <systemc>
23#include <tlm>
24#include <typeindex>
25
22#include <typeindex>
23
24#include "systemc/ext/tlm_core/2/generic_payload/gp.hh"
25
26namespace tlm
27{
28
29template class tlm_array<tlm_extension_base *>;
30
31//---------------------------------------------------------------------------
32// Classes for the extension mechanism
33//---------------------------------------------------------------------------
34
35namespace
36{
37
38class tlm_extension_registry
39{
40 typedef unsigned int key_type;
41 typedef std::map<std::type_index, key_type> type_map;
42 public:
43 static tlm_extension_registry &
44 instance()
45 {
46 if (!instance_) {
47 // Don't cleanup registry.
48 instance_ = new tlm_extension_registry();
49 }
50 return *instance_;
51 }
52
53 unsigned int
54 register_extension(std::type_index type)
55 {
56 type_map::const_iterator it = ids_.find(type);
57
58 if (it == ids_.end()) {
59 // New extension - generate/store ID.
60 type_map::value_type v(type, static_cast<key_type>(ids_.size()));
61 ids_.insert(v);
62 return v.second;
63 }
64 return it->second;
65 }
66
67 static unsigned int
68 max_num_extensions()
69 {
70 return (instance_) ? instance().ids_.size() : 0;
71 }
72
73 private:
74 static tlm_extension_registry *instance_;
75 type_map ids_;
76 tlm_extension_registry() {}
77
78};
79
80tlm_extension_registry *tlm_extension_registry::instance_ = NULL;
81
82} // anonymous namespace
83
84unsigned int
85max_num_extensions()
86{
87 return tlm_extension_registry::max_num_extensions();
88}
89
90unsigned int
91tlm_extension_base::register_extension(const std::type_info &type)
92{
93 return tlm_extension_registry::instance().register_extension(type);
94}
95
96//---------------------------------------------------------------------------
97// The generic payload class:
98//---------------------------------------------------------------------------
99
100tlm_generic_payload::tlm_generic_payload() : m_address(0),
101 m_command(TLM_IGNORE_COMMAND), m_data(0), m_length(0),
102 m_response_status(TLM_INCOMPLETE_RESPONSE), m_dmi(false), m_byte_enable(0),
103 m_byte_enable_length(0), m_streaming_width(0),
104 m_gp_option(TLM_MIN_PAYLOAD), m_extensions(max_num_extensions()), m_mm(0),
105 m_ref_count(0)
106{}
107
108tlm_generic_payload::tlm_generic_payload(tlm_mm_interface *mm): m_address(0),
109 m_command(TLM_IGNORE_COMMAND), m_data(0), m_length(0),
110 m_response_status(TLM_INCOMPLETE_RESPONSE), m_dmi(false), m_byte_enable(0),
111 m_byte_enable_length(0), m_streaming_width(0),
112 m_gp_option(TLM_MIN_PAYLOAD), m_extensions(max_num_extensions()), m_mm(mm),
113 m_ref_count(0)
114{}
115
116void
117tlm_generic_payload::reset()
118{
119 // Should the other members be reset too?
120 m_gp_option = TLM_MIN_PAYLOAD;
121 m_extensions.free_entire_cache();
122};
123
124// Non-virtual deep-copying of the object.
125void
126tlm_generic_payload::deep_copy_from(const tlm_generic_payload &other)
127{
128 m_command = other.get_command();
129 m_address = other.get_address();
130 m_length = other.get_data_length();
131 m_response_status = other.get_response_status();
132 m_byte_enable_length = other.get_byte_enable_length();
133 m_streaming_width = other.get_streaming_width();
134 m_gp_option = other.get_gp_option();
135 m_dmi = other.is_dmi_allowed();
136
137 // Deep copy data.
138 // There must be enough space in the target transaction!
139 if (m_data && other.m_data) {
140 std::memcpy(m_data, other.m_data, m_length);
141 }
142 // Deep copy byte enables.
143 // There must be enough space in the target transaction!
144 if (m_byte_enable && other.m_byte_enable) {
145 std::memcpy(m_byte_enable, other.m_byte_enable, m_byte_enable_length);
146 }
147 // Deep copy extensions (sticky and non-sticky).
148 if (m_extensions.size() < other.m_extensions.size()) {
149 m_extensions.expand(other.m_extensions.size());
150 }
151 for (unsigned int i = 0; i < other.m_extensions.size(); i++) {
152 if (other.m_extensions[i]) {
153 // Original has extension i.
154 if (!m_extensions[i]) {
155 // We don't: clone.
156 tlm_extension_base *ext = other.m_extensions[i]->clone();
157 if (ext) { // Extension may not be clonable.
158 if (has_mm()) {
159 // mm can take care of removing cloned extensions.
160 set_auto_extension(i, ext);
161 } else {
162 // no mm, user will call free_all_extensions().
163 set_extension(i, ext);
164 }
165 }
166 } else {
167 // We already have such extension. Copy original over it.
168 m_extensions[i]->copy_from(*other.m_extensions[i]);
169 }
170 }
171 }
172}
173
174// To update the state of the original generic payload from a deep copy.
175// Assumes that "other" was created from the original by calling
176// deep_copy_from. Argument use_byte_enable_on_read determines whether to use
177// or ignores byte enables when copying back the data array on a read command.
178
179void
180tlm_generic_payload::update_original_from(
181 const tlm_generic_payload &other, bool use_byte_enable_on_read)
182{
183 // Copy back extensions that are present on the original.
184 update_extensions_from(other);
185
186 // Copy back the response status and DMI hint attributes.
187 m_response_status = other.get_response_status();
188 m_dmi = other.is_dmi_allowed();
189
190 // Copy back the data array for a read command only deep_copy_from allowed
191 // null pointers, and so will we.
192 // We assume the arrays are the same size.
193 // We test for equal pointers in case the original and the copy share the
194 // same array.
195
196 if (is_read() && m_data && other.m_data && m_data != other.m_data) {
197 if (m_byte_enable && use_byte_enable_on_read) {
198 if (m_byte_enable_length == 8 && m_length % 8 == 0) {
199 // Optimized implementation copies 64-bit words by masking.
200 for (unsigned int i = 0; i < m_length; i += 8) {
201 typedef sc_dt::uint64 *u;
202 *reinterpret_cast<u>(&m_data[i]) &=
203 ~*reinterpret_cast<u>(m_byte_enable);
204 *reinterpret_cast<u>(&m_data[i]) |=
205 *reinterpret_cast<u>(&other.m_data[i]) &
206 *reinterpret_cast<u>(m_byte_enable);
207 }
208 } else if (m_byte_enable_length == 4 && m_length % 4 == 0) {
209 // Optimized implementation copies 32-bit words by masking.
210 for (unsigned int i = 0; i < m_length; i += 4) {
211 typedef unsigned int *u;
212 *reinterpret_cast<u>(&m_data[i]) &=
213 ~*reinterpret_cast<u>(m_byte_enable);
214 *reinterpret_cast<u>(&m_data[i]) |=
215 *reinterpret_cast<u>(&other.m_data[i]) &
216 *reinterpret_cast<u>(m_byte_enable);
217 }
218 } else {
219 // Unoptimized implementation.
220 for (unsigned int i = 0; i < m_length; i++) {
221 if (m_byte_enable[i % m_byte_enable_length])
222 m_data[i] = other.m_data[i];
223 }
224 }
225 } else {
226 std::memcpy(m_data, other.m_data, m_length);
227 }
228 }
229}
230
231void
232tlm_generic_payload::update_extensions_from(const tlm_generic_payload &other)
233{
234 // Deep copy extensions that are already present.
235 sc_assert(m_extensions.size() <= other.m_extensions.size());
236 for (unsigned int i = 0; i < m_extensions.size(); i++) {
237 if (other.m_extensions[i]) {
238 // Original has extension i.
239 if (m_extensions[i]) {
240 // We have it too. Copy.
241 m_extensions[i]->copy_from(*other.m_extensions[i]);
242 }
243 }
244 }
245}
246
247// Free all extensions. Useful when reusing a cloned transaction that doesn't
248// have memory manager. Normal and sticky extensions are freed and extension
249// array cleared.
250void
251tlm_generic_payload::free_all_extensions()
252{
253 m_extensions.free_entire_cache();
254 for (unsigned int i = 0; i < m_extensions.size(); i++) {
255 if (m_extensions[i]) {
256 m_extensions[i]->free();
257 m_extensions[i] = 0;
258 }
259 }
260}
261
262tlm_generic_payload::~tlm_generic_payload()
263{
264 for (unsigned int i = 0; i < m_extensions.size(); i++) {
265 if (m_extensions[i])
266 m_extensions[i]->free();
267 }
268}
269
270//----------------
271// API (including setters & getters)
272//---------------
273
274std::string
275tlm_generic_payload::get_response_string() const
276{
277 switch (m_response_status) {
278 case TLM_OK_RESPONSE:
279 return "TLM_OK_RESPONSE";
280 case TLM_INCOMPLETE_RESPONSE:
281 return "TLM_INCOMPLETE_RESPONSE";
282 case TLM_GENERIC_ERROR_RESPONSE:
283 return "TLM_GENERIC_ERROR_RESPONSE";
284 case TLM_ADDRESS_ERROR_RESPONSE:
285 return "TLM_ADDRESS_ERROR_RESPONSE";
286 case TLM_COMMAND_ERROR_RESPONSE:
287 return "TLM_COMMAND_ERROR_RESPONSE";
288 case TLM_BURST_ERROR_RESPONSE:
289 return "TLM_BURST_ERROR_RESPONSE";
290 case TLM_BYTE_ENABLE_ERROR_RESPONSE:
291 return "TLM_BYTE_ENABLE_ERROR_RESPONSE";
292 }
293 return "TLM_UNKNOWN_RESPONSE";
294}
295
296/* --------------------------------------------------------------------- */
297/* Dynamic extension mechanism: */
298/* --------------------------------------------------------------------- */
299
300tlm_extension_base *
301tlm_generic_payload::set_extension(unsigned int index, tlm_extension_base *ext)
302{
303 sc_assert(index < m_extensions.size());
304 tlm_extension_base *tmp = m_extensions[index];
305 m_extensions[index] = ext;
306 return tmp;
307}
308
309tlm_extension_base *
310tlm_generic_payload::set_auto_extension(
311 unsigned int index, tlm_extension_base *ext)
312{
313 sc_assert(index < m_extensions.size());
314 tlm_extension_base *tmp = m_extensions[index];
315 m_extensions[index] = ext;
316 if (!tmp)
317 m_extensions.insert_in_cache(&m_extensions[index]);
318 sc_assert(m_mm != 0);
319 return tmp;
320}
321
322tlm_extension_base *
323tlm_generic_payload::get_extension(unsigned int index) const
324{
325 sc_assert(index < m_extensions.size());
326 return m_extensions[index];
327}
328
329void
330tlm_generic_payload::clear_extension(unsigned int index)
331{
332 sc_assert(index < m_extensions.size());
333 m_extensions[index] = static_cast<tlm_extension_base *>(0);
334}
335
336void
337tlm_generic_payload::release_extension(unsigned int index)
338{
339 sc_assert(index < m_extensions.size());
340 if (m_mm) {
341 m_extensions.insert_in_cache(&m_extensions[index]);
342 } else {
343 m_extensions[index]->free();
344 m_extensions[index] = static_cast<tlm_extension_base *>(nullptr);
345 }
346}
347
348void
349tlm_generic_payload::resize_extensions()
350{
351 m_extensions.expand(max_num_extensions());
352}
353
354} // namespace tlm
26namespace tlm
27{
28
29template class tlm_array<tlm_extension_base *>;
30
31//---------------------------------------------------------------------------
32// Classes for the extension mechanism
33//---------------------------------------------------------------------------
34
35namespace
36{
37
38class tlm_extension_registry
39{
40 typedef unsigned int key_type;
41 typedef std::map<std::type_index, key_type> type_map;
42 public:
43 static tlm_extension_registry &
44 instance()
45 {
46 if (!instance_) {
47 // Don't cleanup registry.
48 instance_ = new tlm_extension_registry();
49 }
50 return *instance_;
51 }
52
53 unsigned int
54 register_extension(std::type_index type)
55 {
56 type_map::const_iterator it = ids_.find(type);
57
58 if (it == ids_.end()) {
59 // New extension - generate/store ID.
60 type_map::value_type v(type, static_cast<key_type>(ids_.size()));
61 ids_.insert(v);
62 return v.second;
63 }
64 return it->second;
65 }
66
67 static unsigned int
68 max_num_extensions()
69 {
70 return (instance_) ? instance().ids_.size() : 0;
71 }
72
73 private:
74 static tlm_extension_registry *instance_;
75 type_map ids_;
76 tlm_extension_registry() {}
77
78};
79
80tlm_extension_registry *tlm_extension_registry::instance_ = NULL;
81
82} // anonymous namespace
83
84unsigned int
85max_num_extensions()
86{
87 return tlm_extension_registry::max_num_extensions();
88}
89
90unsigned int
91tlm_extension_base::register_extension(const std::type_info &type)
92{
93 return tlm_extension_registry::instance().register_extension(type);
94}
95
96//---------------------------------------------------------------------------
97// The generic payload class:
98//---------------------------------------------------------------------------
99
100tlm_generic_payload::tlm_generic_payload() : m_address(0),
101 m_command(TLM_IGNORE_COMMAND), m_data(0), m_length(0),
102 m_response_status(TLM_INCOMPLETE_RESPONSE), m_dmi(false), m_byte_enable(0),
103 m_byte_enable_length(0), m_streaming_width(0),
104 m_gp_option(TLM_MIN_PAYLOAD), m_extensions(max_num_extensions()), m_mm(0),
105 m_ref_count(0)
106{}
107
108tlm_generic_payload::tlm_generic_payload(tlm_mm_interface *mm): m_address(0),
109 m_command(TLM_IGNORE_COMMAND), m_data(0), m_length(0),
110 m_response_status(TLM_INCOMPLETE_RESPONSE), m_dmi(false), m_byte_enable(0),
111 m_byte_enable_length(0), m_streaming_width(0),
112 m_gp_option(TLM_MIN_PAYLOAD), m_extensions(max_num_extensions()), m_mm(mm),
113 m_ref_count(0)
114{}
115
116void
117tlm_generic_payload::reset()
118{
119 // Should the other members be reset too?
120 m_gp_option = TLM_MIN_PAYLOAD;
121 m_extensions.free_entire_cache();
122};
123
124// Non-virtual deep-copying of the object.
125void
126tlm_generic_payload::deep_copy_from(const tlm_generic_payload &other)
127{
128 m_command = other.get_command();
129 m_address = other.get_address();
130 m_length = other.get_data_length();
131 m_response_status = other.get_response_status();
132 m_byte_enable_length = other.get_byte_enable_length();
133 m_streaming_width = other.get_streaming_width();
134 m_gp_option = other.get_gp_option();
135 m_dmi = other.is_dmi_allowed();
136
137 // Deep copy data.
138 // There must be enough space in the target transaction!
139 if (m_data && other.m_data) {
140 std::memcpy(m_data, other.m_data, m_length);
141 }
142 // Deep copy byte enables.
143 // There must be enough space in the target transaction!
144 if (m_byte_enable && other.m_byte_enable) {
145 std::memcpy(m_byte_enable, other.m_byte_enable, m_byte_enable_length);
146 }
147 // Deep copy extensions (sticky and non-sticky).
148 if (m_extensions.size() < other.m_extensions.size()) {
149 m_extensions.expand(other.m_extensions.size());
150 }
151 for (unsigned int i = 0; i < other.m_extensions.size(); i++) {
152 if (other.m_extensions[i]) {
153 // Original has extension i.
154 if (!m_extensions[i]) {
155 // We don't: clone.
156 tlm_extension_base *ext = other.m_extensions[i]->clone();
157 if (ext) { // Extension may not be clonable.
158 if (has_mm()) {
159 // mm can take care of removing cloned extensions.
160 set_auto_extension(i, ext);
161 } else {
162 // no mm, user will call free_all_extensions().
163 set_extension(i, ext);
164 }
165 }
166 } else {
167 // We already have such extension. Copy original over it.
168 m_extensions[i]->copy_from(*other.m_extensions[i]);
169 }
170 }
171 }
172}
173
174// To update the state of the original generic payload from a deep copy.
175// Assumes that "other" was created from the original by calling
176// deep_copy_from. Argument use_byte_enable_on_read determines whether to use
177// or ignores byte enables when copying back the data array on a read command.
178
179void
180tlm_generic_payload::update_original_from(
181 const tlm_generic_payload &other, bool use_byte_enable_on_read)
182{
183 // Copy back extensions that are present on the original.
184 update_extensions_from(other);
185
186 // Copy back the response status and DMI hint attributes.
187 m_response_status = other.get_response_status();
188 m_dmi = other.is_dmi_allowed();
189
190 // Copy back the data array for a read command only deep_copy_from allowed
191 // null pointers, and so will we.
192 // We assume the arrays are the same size.
193 // We test for equal pointers in case the original and the copy share the
194 // same array.
195
196 if (is_read() && m_data && other.m_data && m_data != other.m_data) {
197 if (m_byte_enable && use_byte_enable_on_read) {
198 if (m_byte_enable_length == 8 && m_length % 8 == 0) {
199 // Optimized implementation copies 64-bit words by masking.
200 for (unsigned int i = 0; i < m_length; i += 8) {
201 typedef sc_dt::uint64 *u;
202 *reinterpret_cast<u>(&m_data[i]) &=
203 ~*reinterpret_cast<u>(m_byte_enable);
204 *reinterpret_cast<u>(&m_data[i]) |=
205 *reinterpret_cast<u>(&other.m_data[i]) &
206 *reinterpret_cast<u>(m_byte_enable);
207 }
208 } else if (m_byte_enable_length == 4 && m_length % 4 == 0) {
209 // Optimized implementation copies 32-bit words by masking.
210 for (unsigned int i = 0; i < m_length; i += 4) {
211 typedef unsigned int *u;
212 *reinterpret_cast<u>(&m_data[i]) &=
213 ~*reinterpret_cast<u>(m_byte_enable);
214 *reinterpret_cast<u>(&m_data[i]) |=
215 *reinterpret_cast<u>(&other.m_data[i]) &
216 *reinterpret_cast<u>(m_byte_enable);
217 }
218 } else {
219 // Unoptimized implementation.
220 for (unsigned int i = 0; i < m_length; i++) {
221 if (m_byte_enable[i % m_byte_enable_length])
222 m_data[i] = other.m_data[i];
223 }
224 }
225 } else {
226 std::memcpy(m_data, other.m_data, m_length);
227 }
228 }
229}
230
231void
232tlm_generic_payload::update_extensions_from(const tlm_generic_payload &other)
233{
234 // Deep copy extensions that are already present.
235 sc_assert(m_extensions.size() <= other.m_extensions.size());
236 for (unsigned int i = 0; i < m_extensions.size(); i++) {
237 if (other.m_extensions[i]) {
238 // Original has extension i.
239 if (m_extensions[i]) {
240 // We have it too. Copy.
241 m_extensions[i]->copy_from(*other.m_extensions[i]);
242 }
243 }
244 }
245}
246
247// Free all extensions. Useful when reusing a cloned transaction that doesn't
248// have memory manager. Normal and sticky extensions are freed and extension
249// array cleared.
250void
251tlm_generic_payload::free_all_extensions()
252{
253 m_extensions.free_entire_cache();
254 for (unsigned int i = 0; i < m_extensions.size(); i++) {
255 if (m_extensions[i]) {
256 m_extensions[i]->free();
257 m_extensions[i] = 0;
258 }
259 }
260}
261
262tlm_generic_payload::~tlm_generic_payload()
263{
264 for (unsigned int i = 0; i < m_extensions.size(); i++) {
265 if (m_extensions[i])
266 m_extensions[i]->free();
267 }
268}
269
270//----------------
271// API (including setters & getters)
272//---------------
273
274std::string
275tlm_generic_payload::get_response_string() const
276{
277 switch (m_response_status) {
278 case TLM_OK_RESPONSE:
279 return "TLM_OK_RESPONSE";
280 case TLM_INCOMPLETE_RESPONSE:
281 return "TLM_INCOMPLETE_RESPONSE";
282 case TLM_GENERIC_ERROR_RESPONSE:
283 return "TLM_GENERIC_ERROR_RESPONSE";
284 case TLM_ADDRESS_ERROR_RESPONSE:
285 return "TLM_ADDRESS_ERROR_RESPONSE";
286 case TLM_COMMAND_ERROR_RESPONSE:
287 return "TLM_COMMAND_ERROR_RESPONSE";
288 case TLM_BURST_ERROR_RESPONSE:
289 return "TLM_BURST_ERROR_RESPONSE";
290 case TLM_BYTE_ENABLE_ERROR_RESPONSE:
291 return "TLM_BYTE_ENABLE_ERROR_RESPONSE";
292 }
293 return "TLM_UNKNOWN_RESPONSE";
294}
295
296/* --------------------------------------------------------------------- */
297/* Dynamic extension mechanism: */
298/* --------------------------------------------------------------------- */
299
300tlm_extension_base *
301tlm_generic_payload::set_extension(unsigned int index, tlm_extension_base *ext)
302{
303 sc_assert(index < m_extensions.size());
304 tlm_extension_base *tmp = m_extensions[index];
305 m_extensions[index] = ext;
306 return tmp;
307}
308
309tlm_extension_base *
310tlm_generic_payload::set_auto_extension(
311 unsigned int index, tlm_extension_base *ext)
312{
313 sc_assert(index < m_extensions.size());
314 tlm_extension_base *tmp = m_extensions[index];
315 m_extensions[index] = ext;
316 if (!tmp)
317 m_extensions.insert_in_cache(&m_extensions[index]);
318 sc_assert(m_mm != 0);
319 return tmp;
320}
321
322tlm_extension_base *
323tlm_generic_payload::get_extension(unsigned int index) const
324{
325 sc_assert(index < m_extensions.size());
326 return m_extensions[index];
327}
328
329void
330tlm_generic_payload::clear_extension(unsigned int index)
331{
332 sc_assert(index < m_extensions.size());
333 m_extensions[index] = static_cast<tlm_extension_base *>(0);
334}
335
336void
337tlm_generic_payload::release_extension(unsigned int index)
338{
339 sc_assert(index < m_extensions.size());
340 if (m_mm) {
341 m_extensions.insert_in_cache(&m_extensions[index]);
342 } else {
343 m_extensions[index]->free();
344 m_extensions[index] = static_cast<tlm_extension_base *>(nullptr);
345 }
346}
347
348void
349tlm_generic_payload::resize_extensions()
350{
351 m_extensions.expand(max_num_extensions());
352}
353
354} // namespace tlm