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