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