gp.cc revision 13516
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
356