gp.cc revision 13523:de27641700bb
110249Sstephan.diestelhorst@arm.com/*****************************************************************************
210249Sstephan.diestelhorst@arm.com
310249Sstephan.diestelhorst@arm.com  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
410249Sstephan.diestelhorst@arm.com  more contributor license agreements.  See the NOTICE file distributed
510249Sstephan.diestelhorst@arm.com  with this work for additional information regarding copyright ownership.
610249Sstephan.diestelhorst@arm.com  Accellera licenses this file to you under the Apache License, Version 2.0
710249Sstephan.diestelhorst@arm.com  (the "License"); you may not use this file except in compliance with the
810249Sstephan.diestelhorst@arm.com  License.  You may obtain a copy of the License at
910249Sstephan.diestelhorst@arm.com
1010249Sstephan.diestelhorst@arm.com    http://www.apache.org/licenses/LICENSE-2.0
1110249Sstephan.diestelhorst@arm.com
1210249Sstephan.diestelhorst@arm.com  Unless required by applicable law or agreed to in writing, software
1310249Sstephan.diestelhorst@arm.com  distributed under the License is distributed on an "AS IS" BASIS,
1410249Sstephan.diestelhorst@arm.com  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
1510249Sstephan.diestelhorst@arm.com  implied.  See the License for the specific language governing
1610249Sstephan.diestelhorst@arm.com  permissions and limitations under the License.
1710249Sstephan.diestelhorst@arm.com
1810249Sstephan.diestelhorst@arm.com *****************************************************************************/
1910249Sstephan.diestelhorst@arm.com
2010249Sstephan.diestelhorst@arm.com#include <cstring>  // std::memcpy et.al.
2110249Sstephan.diestelhorst@arm.com#include <map>
2210249Sstephan.diestelhorst@arm.com#include <systemc>
2310249Sstephan.diestelhorst@arm.com#include <tlm>
2410249Sstephan.diestelhorst@arm.com#include <typeindex>
2510249Sstephan.diestelhorst@arm.com
2610249Sstephan.diestelhorst@arm.comnamespace tlm
2710249Sstephan.diestelhorst@arm.com{
2810249Sstephan.diestelhorst@arm.com
2910249Sstephan.diestelhorst@arm.comtemplate class tlm_array<tlm_extension_base *>;
3010249Sstephan.diestelhorst@arm.com
3110249Sstephan.diestelhorst@arm.com//---------------------------------------------------------------------------
3210249Sstephan.diestelhorst@arm.com// Classes for the extension mechanism
3310249Sstephan.diestelhorst@arm.com//---------------------------------------------------------------------------
3410249Sstephan.diestelhorst@arm.com
3510249Sstephan.diestelhorst@arm.comnamespace
3610249Sstephan.diestelhorst@arm.com{
3710249Sstephan.diestelhorst@arm.com
3810249Sstephan.diestelhorst@arm.comclass tlm_extension_registry
3910249Sstephan.diestelhorst@arm.com{
4010249Sstephan.diestelhorst@arm.com    typedef unsigned int key_type;
4110249Sstephan.diestelhorst@arm.com    typedef std::map<std::type_index, key_type> type_map;
4211793Sbrandon.potter@amd.com  public:
4311793Sbrandon.potter@amd.com    static tlm_extension_registry &
4410249Sstephan.diestelhorst@arm.com    instance()
4510249Sstephan.diestelhorst@arm.com    {
4610249Sstephan.diestelhorst@arm.com        if (!instance_) {
4710249Sstephan.diestelhorst@arm.com            // Don't cleanup registry.
4811800Sbrandon.potter@amd.com            instance_ = new tlm_extension_registry();
4910249Sstephan.diestelhorst@arm.com        }
5010249Sstephan.diestelhorst@arm.com        return *instance_;
5110249Sstephan.diestelhorst@arm.com    }
5211800Sbrandon.potter@amd.com
5310249Sstephan.diestelhorst@arm.com    unsigned int
5410249Sstephan.diestelhorst@arm.com    register_extension(std::type_index type)
5510249Sstephan.diestelhorst@arm.com    {
5610249Sstephan.diestelhorst@arm.com        type_map::const_iterator it = ids_.find(type);
5710249Sstephan.diestelhorst@arm.com
5810249Sstephan.diestelhorst@arm.com        if (it == ids_.end()) {
5910249Sstephan.diestelhorst@arm.com            // New extension - generate/store ID.
6010249Sstephan.diestelhorst@arm.com            type_map::value_type v(type, static_cast<key_type>(ids_.size()));
6110249Sstephan.diestelhorst@arm.com            ids_.insert(v);
6210249Sstephan.diestelhorst@arm.com            return v.second;
6310249Sstephan.diestelhorst@arm.com        }
6410249Sstephan.diestelhorst@arm.com        return it->second;
6510249Sstephan.diestelhorst@arm.com    }
6610249Sstephan.diestelhorst@arm.com
6710249Sstephan.diestelhorst@arm.com    static unsigned int
6810249Sstephan.diestelhorst@arm.com    max_num_extensions()
6911321Ssteve.reinhardt@amd.com    {
7010249Sstephan.diestelhorst@arm.com        return (instance_) ? instance().ids_.size() : 0;
7110249Sstephan.diestelhorst@arm.com    }
7210249Sstephan.diestelhorst@arm.com
7310249Sstephan.diestelhorst@arm.com  private:
7410249Sstephan.diestelhorst@arm.com    static tlm_extension_registry *instance_;
7510249Sstephan.diestelhorst@arm.com    type_map ids_;
7610249Sstephan.diestelhorst@arm.com    tlm_extension_registry() {}
7710249Sstephan.diestelhorst@arm.com
7810249Sstephan.diestelhorst@arm.com};
7910249Sstephan.diestelhorst@arm.com
8010249Sstephan.diestelhorst@arm.comtlm_extension_registry *tlm_extension_registry::instance_ = NULL;
8110249Sstephan.diestelhorst@arm.com
8210249Sstephan.diestelhorst@arm.com} // anonymous namespace
8310249Sstephan.diestelhorst@arm.com
8410249Sstephan.diestelhorst@arm.comunsigned int
8510249Sstephan.diestelhorst@arm.commax_num_extensions()
8610249Sstephan.diestelhorst@arm.com{
8710395Sstephan.diestelhorst@arm.com    return tlm_extension_registry::max_num_extensions();
8810395Sstephan.diestelhorst@arm.com}
8910395Sstephan.diestelhorst@arm.com
9010249Sstephan.diestelhorst@arm.comunsigned int
9110249Sstephan.diestelhorst@arm.comtlm_extension_base::register_extension(const std::type_info &type)
9210249Sstephan.diestelhorst@arm.com{
9310249Sstephan.diestelhorst@arm.com    return tlm_extension_registry::instance().register_extension(type);
9410249Sstephan.diestelhorst@arm.com}
9510249Sstephan.diestelhorst@arm.com
9610395Sstephan.diestelhorst@arm.com//---------------------------------------------------------------------------
9710395Sstephan.diestelhorst@arm.com// The generic payload class:
9810395Sstephan.diestelhorst@arm.com//---------------------------------------------------------------------------
9910395Sstephan.diestelhorst@arm.com
10010395Sstephan.diestelhorst@arm.comtlm_generic_payload::tlm_generic_payload() : m_address(0),
10110395Sstephan.diestelhorst@arm.com    m_command(TLM_IGNORE_COMMAND), m_data(0), m_length(0),
10210395Sstephan.diestelhorst@arm.com    m_response_status(TLM_INCOMPLETE_RESPONSE), m_dmi(false), m_byte_enable(0),
10310395Sstephan.diestelhorst@arm.com    m_byte_enable_length(0), m_streaming_width(0),
10410395Sstephan.diestelhorst@arm.com    m_gp_option(TLM_MIN_PAYLOAD), m_extensions(max_num_extensions()), m_mm(0),
10510395Sstephan.diestelhorst@arm.com    m_ref_count(0)
10610395Sstephan.diestelhorst@arm.com{}
10710249Sstephan.diestelhorst@arm.com
10810249Sstephan.diestelhorst@arm.comtlm_generic_payload::tlm_generic_payload(tlm_mm_interface *mm): m_address(0),
10910249Sstephan.diestelhorst@arm.com    m_command(TLM_IGNORE_COMMAND), m_data(0), m_length(0),
11010249Sstephan.diestelhorst@arm.com    m_response_status(TLM_INCOMPLETE_RESPONSE), m_dmi(false), m_byte_enable(0),
11110249Sstephan.diestelhorst@arm.com    m_byte_enable_length(0), m_streaming_width(0),
11210249Sstephan.diestelhorst@arm.com    m_gp_option(TLM_MIN_PAYLOAD), m_extensions(max_num_extensions()), m_mm(mm),
11310249Sstephan.diestelhorst@arm.com    m_ref_count(0)
11410249Sstephan.diestelhorst@arm.com{}
11510249Sstephan.diestelhorst@arm.com
11610249Sstephan.diestelhorst@arm.comvoid
11710249Sstephan.diestelhorst@arm.comtlm_generic_payload::reset()
11810249Sstephan.diestelhorst@arm.com{
11910249Sstephan.diestelhorst@arm.com    // Should the other members be reset too?
12010249Sstephan.diestelhorst@arm.com    m_gp_option = TLM_MIN_PAYLOAD;
12110249Sstephan.diestelhorst@arm.com    m_extensions.free_entire_cache();
12210249Sstephan.diestelhorst@arm.com};
12310249Sstephan.diestelhorst@arm.com
12410249Sstephan.diestelhorst@arm.com// Non-virtual deep-copying of the object.
12510249Sstephan.diestelhorst@arm.comvoid
12610249Sstephan.diestelhorst@arm.comtlm_generic_payload::deep_copy_from(const tlm_generic_payload &other)
12710249Sstephan.diestelhorst@arm.com{
12810249Sstephan.diestelhorst@arm.com    m_command = other.get_command();
12910249Sstephan.diestelhorst@arm.com    m_address = other.get_address();
13010249Sstephan.diestelhorst@arm.com    m_length = other.get_data_length();
13110249Sstephan.diestelhorst@arm.com    m_response_status = other.get_response_status();
13210249Sstephan.diestelhorst@arm.com    m_byte_enable_length = other.get_byte_enable_length();
13310249Sstephan.diestelhorst@arm.com    m_streaming_width = other.get_streaming_width();
13410249Sstephan.diestelhorst@arm.com    m_gp_option = other.get_gp_option();
13510249Sstephan.diestelhorst@arm.com    m_dmi = other.is_dmi_allowed();
13610249Sstephan.diestelhorst@arm.com
13710249Sstephan.diestelhorst@arm.com    // Deep copy data.
13810249Sstephan.diestelhorst@arm.com    // There must be enough space in the target transaction!
13910249Sstephan.diestelhorst@arm.com    if (m_data && other.m_data) {
14010249Sstephan.diestelhorst@arm.com        std::memcpy(m_data, other.m_data, m_length);
14110249Sstephan.diestelhorst@arm.com    }
14210249Sstephan.diestelhorst@arm.com    // Deep copy byte enables.
14310249Sstephan.diestelhorst@arm.com    // There must be enough space in the target transaction!
14410249Sstephan.diestelhorst@arm.com    if (m_byte_enable && other.m_byte_enable) {
14510249Sstephan.diestelhorst@arm.com        std::memcpy(m_byte_enable, other.m_byte_enable, m_byte_enable_length);
14610249Sstephan.diestelhorst@arm.com    }
14710249Sstephan.diestelhorst@arm.com    // Deep copy extensions (sticky and non-sticky).
14810249Sstephan.diestelhorst@arm.com    if (m_extensions.size() < other.m_extensions.size()) {
14910249Sstephan.diestelhorst@arm.com        m_extensions.expand(other.m_extensions.size());
15010249Sstephan.diestelhorst@arm.com    }
15110249Sstephan.diestelhorst@arm.com    for (unsigned int i = 0; i < other.m_extensions.size(); i++) {
15210249Sstephan.diestelhorst@arm.com        if (other.m_extensions[i]) {
15310249Sstephan.diestelhorst@arm.com            // Original has extension i.
15410249Sstephan.diestelhorst@arm.com            if (!m_extensions[i]) {
15510249Sstephan.diestelhorst@arm.com                // We don't: clone.
15610249Sstephan.diestelhorst@arm.com                tlm_extension_base *ext = other.m_extensions[i]->clone();
15710249Sstephan.diestelhorst@arm.com                if (ext) { // Extension may not be clonable.
15810249Sstephan.diestelhorst@arm.com                    if (has_mm()) {
15910249Sstephan.diestelhorst@arm.com                        // mm can take care of removing cloned extensions.
16010249Sstephan.diestelhorst@arm.com                        set_auto_extension(i, ext);
16110249Sstephan.diestelhorst@arm.com                    } else {
16210249Sstephan.diestelhorst@arm.com                        // no mm, user will call free_all_extensions().
16310249Sstephan.diestelhorst@arm.com                        set_extension(i, ext);
16410249Sstephan.diestelhorst@arm.com                    }
16510249Sstephan.diestelhorst@arm.com                }
16610249Sstephan.diestelhorst@arm.com            } else {
16710249Sstephan.diestelhorst@arm.com                // We already have such extension. Copy original over it.
16810249Sstephan.diestelhorst@arm.com                m_extensions[i]->copy_from(*other.m_extensions[i]);
16910249Sstephan.diestelhorst@arm.com            }
17010249Sstephan.diestelhorst@arm.com        }
17110249Sstephan.diestelhorst@arm.com    }
17210249Sstephan.diestelhorst@arm.com}
17310249Sstephan.diestelhorst@arm.com
17410249Sstephan.diestelhorst@arm.com// To update the state of the original generic payload from a deep copy.
17511800Sbrandon.potter@amd.com// Assumes that "other" was created from the original by calling
17611800Sbrandon.potter@amd.com// deep_copy_from. Argument use_byte_enable_on_read determines whether to use
17711800Sbrandon.potter@amd.com// or ignores byte enables when copying back the data array on a read command.
17811800Sbrandon.potter@amd.com
17911800Sbrandon.potter@amd.comvoid
18011800Sbrandon.potter@amd.comtlm_generic_payload::update_original_from(
18111800Sbrandon.potter@amd.com        const tlm_generic_payload &other, bool use_byte_enable_on_read)
18211800Sbrandon.potter@amd.com{
18311800Sbrandon.potter@amd.com    // Copy back extensions that are present on the original.
18411800Sbrandon.potter@amd.com    update_extensions_from(other);
18511800Sbrandon.potter@amd.com
18611800Sbrandon.potter@amd.com    // Copy back the response status and DMI hint attributes.
18711800Sbrandon.potter@amd.com    m_response_status = other.get_response_status();
18811800Sbrandon.potter@amd.com    m_dmi = other.is_dmi_allowed();
18911800Sbrandon.potter@amd.com
19011800Sbrandon.potter@amd.com    // Copy back the data array for a read command only deep_copy_from allowed
19111800Sbrandon.potter@amd.com    // null pointers, and so will we.
19211800Sbrandon.potter@amd.com    // We assume the arrays are the same size.
19311800Sbrandon.potter@amd.com    // We test for equal pointers in case the original and the copy share the
19411800Sbrandon.potter@amd.com    // same array.
19511800Sbrandon.potter@amd.com
19611800Sbrandon.potter@amd.com    if (is_read() && m_data && other.m_data && m_data != other.m_data) {
19711800Sbrandon.potter@amd.com        if (m_byte_enable && use_byte_enable_on_read) {
19811800Sbrandon.potter@amd.com            if (m_byte_enable_length == 8 && m_length % 8 == 0) {
19910249Sstephan.diestelhorst@arm.com                // Optimized implementation copies 64-bit words by masking.
20010905Sandreas.sandberg@arm.com                for (unsigned int i = 0; i < m_length; i += 8) {
20110249Sstephan.diestelhorst@arm.com                    typedef sc_dt::uint64 *u;
20210249Sstephan.diestelhorst@arm.com                    *reinterpret_cast<u>(&m_data[i]) &=
20310249Sstephan.diestelhorst@arm.com                        ~*reinterpret_cast<u>(m_byte_enable);
20410249Sstephan.diestelhorst@arm.com                    *reinterpret_cast<u>(&m_data[i]) |=
20510249Sstephan.diestelhorst@arm.com                        *reinterpret_cast<u>(&other.m_data[i]) &
20610249Sstephan.diestelhorst@arm.com                        *reinterpret_cast<u>(m_byte_enable);
20710249Sstephan.diestelhorst@arm.com                }
20810249Sstephan.diestelhorst@arm.com            } else if (m_byte_enable_length == 4 && m_length % 4 == 0) {
20910249Sstephan.diestelhorst@arm.com                // Optimized implementation copies 32-bit words by masking.
21010249Sstephan.diestelhorst@arm.com                for (unsigned int i = 0; i < m_length; i += 4) {
21110249Sstephan.diestelhorst@arm.com                    typedef unsigned int *u;
21210905Sandreas.sandberg@arm.com                    *reinterpret_cast<u>(&m_data[i]) &=
21310905Sandreas.sandberg@arm.com                        ~*reinterpret_cast<u>(m_byte_enable);
21410905Sandreas.sandberg@arm.com                    *reinterpret_cast<u>(&m_data[i]) |=
21510249Sstephan.diestelhorst@arm.com                        *reinterpret_cast<u>(&other.m_data[i]) &
21610249Sstephan.diestelhorst@arm.com                        *reinterpret_cast<u>(m_byte_enable);
21710249Sstephan.diestelhorst@arm.com                }
21810249Sstephan.diestelhorst@arm.com            } else {
21910249Sstephan.diestelhorst@arm.com                // Unoptimized implementation.
22010249Sstephan.diestelhorst@arm.com                for (unsigned int i = 0; i < m_length; i++) {
22110905Sandreas.sandberg@arm.com                    if (m_byte_enable[i % m_byte_enable_length])
22210905Sandreas.sandberg@arm.com                        m_data[i] = other.m_data[i];
22310905Sandreas.sandberg@arm.com                }
22410249Sstephan.diestelhorst@arm.com            }
22510249Sstephan.diestelhorst@arm.com        } else {
22610249Sstephan.diestelhorst@arm.com            std::memcpy(m_data, other.m_data, m_length);
22710905Sandreas.sandberg@arm.com        }
22810249Sstephan.diestelhorst@arm.com    }
22910395Sstephan.diestelhorst@arm.com}
23010395Sstephan.diestelhorst@arm.com
23110249Sstephan.diestelhorst@arm.comvoid
23210249Sstephan.diestelhorst@arm.comtlm_generic_payload::update_extensions_from(const tlm_generic_payload &other)
23311321Ssteve.reinhardt@amd.com{
23410395Sstephan.diestelhorst@arm.com    // Deep copy extensions that are already present.
23510395Sstephan.diestelhorst@arm.com    sc_assert(m_extensions.size() <= other.m_extensions.size());
23610395Sstephan.diestelhorst@arm.com    for (unsigned int i = 0; i < m_extensions.size(); i++) {
23710395Sstephan.diestelhorst@arm.com        if (other.m_extensions[i]) {
23810249Sstephan.diestelhorst@arm.com            // Original has extension i.
23910249Sstephan.diestelhorst@arm.com            if (m_extensions[i]) {
24010249Sstephan.diestelhorst@arm.com                // We have it too. Copy.
24110249Sstephan.diestelhorst@arm.com                m_extensions[i]->copy_from(*other.m_extensions[i]);
24210905Sandreas.sandberg@arm.com            }
24310905Sandreas.sandberg@arm.com        }
24410905Sandreas.sandberg@arm.com    }
24510249Sstephan.diestelhorst@arm.com}
24610249Sstephan.diestelhorst@arm.com
24710249Sstephan.diestelhorst@arm.com// Free all extensions. Useful when reusing a cloned transaction that doesn't
24810249Sstephan.diestelhorst@arm.com// have memory manager. Normal and sticky extensions are freed and extension
24910249Sstephan.diestelhorst@arm.com// array cleared.
25010249Sstephan.diestelhorst@arm.comvoid
25110249Sstephan.diestelhorst@arm.comtlm_generic_payload::free_all_extensions()
25210249Sstephan.diestelhorst@arm.com{
25310249Sstephan.diestelhorst@arm.com    m_extensions.free_entire_cache();
25410249Sstephan.diestelhorst@arm.com    for (unsigned int i = 0; i < m_extensions.size(); i++) {
25510249Sstephan.diestelhorst@arm.com        if (m_extensions[i]) {
25610249Sstephan.diestelhorst@arm.com            m_extensions[i]->free();
25710249Sstephan.diestelhorst@arm.com            m_extensions[i] = 0;
25810249Sstephan.diestelhorst@arm.com        }
25910249Sstephan.diestelhorst@arm.com    }
26010249Sstephan.diestelhorst@arm.com}
26110249Sstephan.diestelhorst@arm.com
26210249Sstephan.diestelhorst@arm.comtlm_generic_payload::~tlm_generic_payload()
26310249Sstephan.diestelhorst@arm.com{
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