113516Sgabeblack@google.com/*****************************************************************************
213516Sgabeblack@google.com
313516Sgabeblack@google.com  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
413516Sgabeblack@google.com  more contributor license agreements.  See the NOTICE file distributed
513516Sgabeblack@google.com  with this work for additional information regarding copyright ownership.
613516Sgabeblack@google.com  Accellera licenses this file to you under the Apache License, Version 2.0
713516Sgabeblack@google.com  (the "License"); you may not use this file except in compliance with the
813516Sgabeblack@google.com  License.  You may obtain a copy of the License at
913516Sgabeblack@google.com
1013516Sgabeblack@google.com    http://www.apache.org/licenses/LICENSE-2.0
1113516Sgabeblack@google.com
1213516Sgabeblack@google.com  Unless required by applicable law or agreed to in writing, software
1313516Sgabeblack@google.com  distributed under the License is distributed on an "AS IS" BASIS,
1413516Sgabeblack@google.com  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
1513516Sgabeblack@google.com  implied.  See the License for the specific language governing
1613516Sgabeblack@google.com  permissions and limitations under the License.
1713516Sgabeblack@google.com
1813516Sgabeblack@google.com *****************************************************************************/
1913516Sgabeblack@google.com
2013516Sgabeblack@google.com#include <cstring>  // std::memcpy et.al.
2113516Sgabeblack@google.com#include <map>
2213523Sgabeblack@google.com#include <typeindex>
2313516Sgabeblack@google.com
2413586Sgabeblack@google.com#include "systemc/ext/tlm_core/2/generic_payload/gp.hh"
2513586Sgabeblack@google.com
2613516Sgabeblack@google.comnamespace tlm
2713516Sgabeblack@google.com{
2813516Sgabeblack@google.com
2913516Sgabeblack@google.comtemplate class tlm_array<tlm_extension_base *>;
3013516Sgabeblack@google.com
3113516Sgabeblack@google.com//---------------------------------------------------------------------------
3213516Sgabeblack@google.com// Classes for the extension mechanism
3313516Sgabeblack@google.com//---------------------------------------------------------------------------
3413516Sgabeblack@google.com
3513516Sgabeblack@google.comnamespace
3613516Sgabeblack@google.com{
3713516Sgabeblack@google.com
3813516Sgabeblack@google.comclass tlm_extension_registry
3913516Sgabeblack@google.com{
4013516Sgabeblack@google.com    typedef unsigned int key_type;
4113523Sgabeblack@google.com    typedef std::map<std::type_index, key_type> type_map;
4213516Sgabeblack@google.com  public:
4313516Sgabeblack@google.com    static tlm_extension_registry &
4413516Sgabeblack@google.com    instance()
4513516Sgabeblack@google.com    {
4613516Sgabeblack@google.com        if (!instance_) {
4713516Sgabeblack@google.com            // Don't cleanup registry.
4813516Sgabeblack@google.com            instance_ = new tlm_extension_registry();
4913516Sgabeblack@google.com        }
5013516Sgabeblack@google.com        return *instance_;
5113516Sgabeblack@google.com    }
5213516Sgabeblack@google.com
5313516Sgabeblack@google.com    unsigned int
5413523Sgabeblack@google.com    register_extension(std::type_index type)
5513516Sgabeblack@google.com    {
5613516Sgabeblack@google.com        type_map::const_iterator it = ids_.find(type);
5713516Sgabeblack@google.com
5813516Sgabeblack@google.com        if (it == ids_.end()) {
5913516Sgabeblack@google.com            // New extension - generate/store ID.
6013516Sgabeblack@google.com            type_map::value_type v(type, static_cast<key_type>(ids_.size()));
6113516Sgabeblack@google.com            ids_.insert(v);
6213516Sgabeblack@google.com            return v.second;
6313516Sgabeblack@google.com        }
6413516Sgabeblack@google.com        return it->second;
6513516Sgabeblack@google.com    }
6613516Sgabeblack@google.com
6713516Sgabeblack@google.com    static unsigned int
6813516Sgabeblack@google.com    max_num_extensions()
6913516Sgabeblack@google.com    {
7013516Sgabeblack@google.com        return (instance_) ? instance().ids_.size() : 0;
7113516Sgabeblack@google.com    }
7213516Sgabeblack@google.com
7313516Sgabeblack@google.com  private:
7413516Sgabeblack@google.com    static tlm_extension_registry *instance_;
7513516Sgabeblack@google.com    type_map ids_;
7613516Sgabeblack@google.com    tlm_extension_registry() {}
7713516Sgabeblack@google.com
7813516Sgabeblack@google.com};
7913516Sgabeblack@google.com
8013516Sgabeblack@google.comtlm_extension_registry *tlm_extension_registry::instance_ = NULL;
8113516Sgabeblack@google.com
8213516Sgabeblack@google.com} // anonymous namespace
8313516Sgabeblack@google.com
8413516Sgabeblack@google.comunsigned int
8513516Sgabeblack@google.commax_num_extensions()
8613516Sgabeblack@google.com{
8713516Sgabeblack@google.com    return tlm_extension_registry::max_num_extensions();
8813516Sgabeblack@google.com}
8913516Sgabeblack@google.com
9013516Sgabeblack@google.comunsigned int
9113516Sgabeblack@google.comtlm_extension_base::register_extension(const std::type_info &type)
9213516Sgabeblack@google.com{
9313516Sgabeblack@google.com    return tlm_extension_registry::instance().register_extension(type);
9413516Sgabeblack@google.com}
9513516Sgabeblack@google.com
9613516Sgabeblack@google.com//---------------------------------------------------------------------------
9713516Sgabeblack@google.com// The generic payload class:
9813516Sgabeblack@google.com//---------------------------------------------------------------------------
9913516Sgabeblack@google.com
10013516Sgabeblack@google.comtlm_generic_payload::tlm_generic_payload() : m_address(0),
10113516Sgabeblack@google.com    m_command(TLM_IGNORE_COMMAND), m_data(0), m_length(0),
10213516Sgabeblack@google.com    m_response_status(TLM_INCOMPLETE_RESPONSE), m_dmi(false), m_byte_enable(0),
10313516Sgabeblack@google.com    m_byte_enable_length(0), m_streaming_width(0),
10413516Sgabeblack@google.com    m_gp_option(TLM_MIN_PAYLOAD), m_extensions(max_num_extensions()), m_mm(0),
10513516Sgabeblack@google.com    m_ref_count(0)
10613516Sgabeblack@google.com{}
10713516Sgabeblack@google.com
10813516Sgabeblack@google.comtlm_generic_payload::tlm_generic_payload(tlm_mm_interface *mm): m_address(0),
10913516Sgabeblack@google.com    m_command(TLM_IGNORE_COMMAND), m_data(0), m_length(0),
11013516Sgabeblack@google.com    m_response_status(TLM_INCOMPLETE_RESPONSE), m_dmi(false), m_byte_enable(0),
11113516Sgabeblack@google.com    m_byte_enable_length(0), m_streaming_width(0),
11213516Sgabeblack@google.com    m_gp_option(TLM_MIN_PAYLOAD), m_extensions(max_num_extensions()), m_mm(mm),
11313516Sgabeblack@google.com    m_ref_count(0)
11413516Sgabeblack@google.com{}
11513516Sgabeblack@google.com
11613516Sgabeblack@google.comvoid
11713516Sgabeblack@google.comtlm_generic_payload::reset()
11813516Sgabeblack@google.com{
11913516Sgabeblack@google.com    // Should the other members be reset too?
12013516Sgabeblack@google.com    m_gp_option = TLM_MIN_PAYLOAD;
12113516Sgabeblack@google.com    m_extensions.free_entire_cache();
12213516Sgabeblack@google.com};
12313516Sgabeblack@google.com
12413516Sgabeblack@google.com// Non-virtual deep-copying of the object.
12513516Sgabeblack@google.comvoid
12613516Sgabeblack@google.comtlm_generic_payload::deep_copy_from(const tlm_generic_payload &other)
12713516Sgabeblack@google.com{
12813516Sgabeblack@google.com    m_command = other.get_command();
12913516Sgabeblack@google.com    m_address = other.get_address();
13013516Sgabeblack@google.com    m_length = other.get_data_length();
13113516Sgabeblack@google.com    m_response_status = other.get_response_status();
13213516Sgabeblack@google.com    m_byte_enable_length = other.get_byte_enable_length();
13313516Sgabeblack@google.com    m_streaming_width = other.get_streaming_width();
13413516Sgabeblack@google.com    m_gp_option = other.get_gp_option();
13513516Sgabeblack@google.com    m_dmi = other.is_dmi_allowed();
13613516Sgabeblack@google.com
13713516Sgabeblack@google.com    // Deep copy data.
13813516Sgabeblack@google.com    // There must be enough space in the target transaction!
13913516Sgabeblack@google.com    if (m_data && other.m_data) {
14013516Sgabeblack@google.com        std::memcpy(m_data, other.m_data, m_length);
14113516Sgabeblack@google.com    }
14213516Sgabeblack@google.com    // Deep copy byte enables.
14313516Sgabeblack@google.com    // There must be enough space in the target transaction!
14413516Sgabeblack@google.com    if (m_byte_enable && other.m_byte_enable) {
14513516Sgabeblack@google.com        std::memcpy(m_byte_enable, other.m_byte_enable, m_byte_enable_length);
14613516Sgabeblack@google.com    }
14713516Sgabeblack@google.com    // Deep copy extensions (sticky and non-sticky).
14813516Sgabeblack@google.com    if (m_extensions.size() < other.m_extensions.size()) {
14913516Sgabeblack@google.com        m_extensions.expand(other.m_extensions.size());
15013516Sgabeblack@google.com    }
15113516Sgabeblack@google.com    for (unsigned int i = 0; i < other.m_extensions.size(); i++) {
15213516Sgabeblack@google.com        if (other.m_extensions[i]) {
15313516Sgabeblack@google.com            // Original has extension i.
15413516Sgabeblack@google.com            if (!m_extensions[i]) {
15513516Sgabeblack@google.com                // We don't: clone.
15613516Sgabeblack@google.com                tlm_extension_base *ext = other.m_extensions[i]->clone();
15713516Sgabeblack@google.com                if (ext) { // Extension may not be clonable.
15813516Sgabeblack@google.com                    if (has_mm()) {
15913516Sgabeblack@google.com                        // mm can take care of removing cloned extensions.
16013516Sgabeblack@google.com                        set_auto_extension(i, ext);
16113516Sgabeblack@google.com                    } else {
16213516Sgabeblack@google.com                        // no mm, user will call free_all_extensions().
16313516Sgabeblack@google.com                        set_extension(i, ext);
16413516Sgabeblack@google.com                    }
16513516Sgabeblack@google.com                }
16613516Sgabeblack@google.com            } else {
16713516Sgabeblack@google.com                // We already have such extension. Copy original over it.
16813516Sgabeblack@google.com                m_extensions[i]->copy_from(*other.m_extensions[i]);
16913516Sgabeblack@google.com            }
17013516Sgabeblack@google.com        }
17113516Sgabeblack@google.com    }
17213516Sgabeblack@google.com}
17313516Sgabeblack@google.com
17413516Sgabeblack@google.com// To update the state of the original generic payload from a deep copy.
17513516Sgabeblack@google.com// Assumes that "other" was created from the original by calling
17613516Sgabeblack@google.com// deep_copy_from. Argument use_byte_enable_on_read determines whether to use
17713516Sgabeblack@google.com// or ignores byte enables when copying back the data array on a read command.
17813516Sgabeblack@google.com
17913516Sgabeblack@google.comvoid
18013516Sgabeblack@google.comtlm_generic_payload::update_original_from(
18113516Sgabeblack@google.com        const tlm_generic_payload &other, bool use_byte_enable_on_read)
18213516Sgabeblack@google.com{
18313516Sgabeblack@google.com    // Copy back extensions that are present on the original.
18413516Sgabeblack@google.com    update_extensions_from(other);
18513516Sgabeblack@google.com
18613516Sgabeblack@google.com    // Copy back the response status and DMI hint attributes.
18713516Sgabeblack@google.com    m_response_status = other.get_response_status();
18813516Sgabeblack@google.com    m_dmi = other.is_dmi_allowed();
18913516Sgabeblack@google.com
19013516Sgabeblack@google.com    // Copy back the data array for a read command only deep_copy_from allowed
19113516Sgabeblack@google.com    // null pointers, and so will we.
19213516Sgabeblack@google.com    // We assume the arrays are the same size.
19313516Sgabeblack@google.com    // We test for equal pointers in case the original and the copy share the
19413516Sgabeblack@google.com    // same array.
19513516Sgabeblack@google.com
19613516Sgabeblack@google.com    if (is_read() && m_data && other.m_data && m_data != other.m_data) {
19713516Sgabeblack@google.com        if (m_byte_enable && use_byte_enable_on_read) {
19813516Sgabeblack@google.com            if (m_byte_enable_length == 8 && m_length % 8 == 0) {
19913516Sgabeblack@google.com                // Optimized implementation copies 64-bit words by masking.
20013516Sgabeblack@google.com                for (unsigned int i = 0; i < m_length; i += 8) {
20113516Sgabeblack@google.com                    typedef sc_dt::uint64 *u;
20213516Sgabeblack@google.com                    *reinterpret_cast<u>(&m_data[i]) &=
20313516Sgabeblack@google.com                        ~*reinterpret_cast<u>(m_byte_enable);
20413516Sgabeblack@google.com                    *reinterpret_cast<u>(&m_data[i]) |=
20513516Sgabeblack@google.com                        *reinterpret_cast<u>(&other.m_data[i]) &
20613516Sgabeblack@google.com                        *reinterpret_cast<u>(m_byte_enable);
20713516Sgabeblack@google.com                }
20813516Sgabeblack@google.com            } else if (m_byte_enable_length == 4 && m_length % 4 == 0) {
20913516Sgabeblack@google.com                // Optimized implementation copies 32-bit words by masking.
21013516Sgabeblack@google.com                for (unsigned int i = 0; i < m_length; i += 4) {
21113516Sgabeblack@google.com                    typedef unsigned int *u;
21213516Sgabeblack@google.com                    *reinterpret_cast<u>(&m_data[i]) &=
21313516Sgabeblack@google.com                        ~*reinterpret_cast<u>(m_byte_enable);
21413516Sgabeblack@google.com                    *reinterpret_cast<u>(&m_data[i]) |=
21513516Sgabeblack@google.com                        *reinterpret_cast<u>(&other.m_data[i]) &
21613516Sgabeblack@google.com                        *reinterpret_cast<u>(m_byte_enable);
21713516Sgabeblack@google.com                }
21813516Sgabeblack@google.com            } else {
21913516Sgabeblack@google.com                // Unoptimized implementation.
22013516Sgabeblack@google.com                for (unsigned int i = 0; i < m_length; i++) {
22113516Sgabeblack@google.com                    if (m_byte_enable[i % m_byte_enable_length])
22213516Sgabeblack@google.com                        m_data[i] = other.m_data[i];
22313516Sgabeblack@google.com                }
22413516Sgabeblack@google.com            }
22513516Sgabeblack@google.com        } else {
22613516Sgabeblack@google.com            std::memcpy(m_data, other.m_data, m_length);
22713516Sgabeblack@google.com        }
22813516Sgabeblack@google.com    }
22913516Sgabeblack@google.com}
23013516Sgabeblack@google.com
23113516Sgabeblack@google.comvoid
23213516Sgabeblack@google.comtlm_generic_payload::update_extensions_from(const tlm_generic_payload &other)
23313516Sgabeblack@google.com{
23413516Sgabeblack@google.com    // Deep copy extensions that are already present.
23513516Sgabeblack@google.com    sc_assert(m_extensions.size() <= other.m_extensions.size());
23613516Sgabeblack@google.com    for (unsigned int i = 0; i < m_extensions.size(); i++) {
23713516Sgabeblack@google.com        if (other.m_extensions[i]) {
23813516Sgabeblack@google.com            // Original has extension i.
23913516Sgabeblack@google.com            if (m_extensions[i]) {
24013516Sgabeblack@google.com                // We have it too. Copy.
24113516Sgabeblack@google.com                m_extensions[i]->copy_from(*other.m_extensions[i]);
24213516Sgabeblack@google.com            }
24313516Sgabeblack@google.com        }
24413516Sgabeblack@google.com    }
24513516Sgabeblack@google.com}
24613516Sgabeblack@google.com
24713516Sgabeblack@google.com// Free all extensions. Useful when reusing a cloned transaction that doesn't
24813516Sgabeblack@google.com// have memory manager. Normal and sticky extensions are freed and extension
24913516Sgabeblack@google.com// array cleared.
25013516Sgabeblack@google.comvoid
25113516Sgabeblack@google.comtlm_generic_payload::free_all_extensions()
25213516Sgabeblack@google.com{
25313516Sgabeblack@google.com    m_extensions.free_entire_cache();
25413516Sgabeblack@google.com    for (unsigned int i = 0; i < m_extensions.size(); i++) {
25513516Sgabeblack@google.com        if (m_extensions[i]) {
25613516Sgabeblack@google.com            m_extensions[i]->free();
25713516Sgabeblack@google.com            m_extensions[i] = 0;
25813516Sgabeblack@google.com        }
25913516Sgabeblack@google.com    }
26013516Sgabeblack@google.com}
26113516Sgabeblack@google.com
26213516Sgabeblack@google.comtlm_generic_payload::~tlm_generic_payload()
26313516Sgabeblack@google.com{
26413516Sgabeblack@google.com    for (unsigned int i = 0; i < m_extensions.size(); i++) {
26513516Sgabeblack@google.com        if (m_extensions[i])
26613516Sgabeblack@google.com            m_extensions[i]->free();
26713516Sgabeblack@google.com    }
26813516Sgabeblack@google.com}
26913516Sgabeblack@google.com
27013516Sgabeblack@google.com//----------------
27113516Sgabeblack@google.com// API (including setters & getters)
27213516Sgabeblack@google.com//---------------
27313516Sgabeblack@google.com
27413516Sgabeblack@google.comstd::string
27513516Sgabeblack@google.comtlm_generic_payload::get_response_string() const
27613516Sgabeblack@google.com{
27713516Sgabeblack@google.com    switch (m_response_status) {
27813516Sgabeblack@google.com      case TLM_OK_RESPONSE:
27913516Sgabeblack@google.com        return "TLM_OK_RESPONSE";
28013516Sgabeblack@google.com      case TLM_INCOMPLETE_RESPONSE:
28113516Sgabeblack@google.com        return "TLM_INCOMPLETE_RESPONSE";
28213516Sgabeblack@google.com      case TLM_GENERIC_ERROR_RESPONSE:
28313516Sgabeblack@google.com        return "TLM_GENERIC_ERROR_RESPONSE";
28413516Sgabeblack@google.com      case TLM_ADDRESS_ERROR_RESPONSE:
28513516Sgabeblack@google.com        return "TLM_ADDRESS_ERROR_RESPONSE";
28613516Sgabeblack@google.com      case TLM_COMMAND_ERROR_RESPONSE:
28713516Sgabeblack@google.com        return "TLM_COMMAND_ERROR_RESPONSE";
28813516Sgabeblack@google.com      case TLM_BURST_ERROR_RESPONSE:
28913516Sgabeblack@google.com        return "TLM_BURST_ERROR_RESPONSE";
29013516Sgabeblack@google.com      case TLM_BYTE_ENABLE_ERROR_RESPONSE:
29113516Sgabeblack@google.com        return "TLM_BYTE_ENABLE_ERROR_RESPONSE";
29213516Sgabeblack@google.com    }
29313516Sgabeblack@google.com    return "TLM_UNKNOWN_RESPONSE";
29413516Sgabeblack@google.com}
29513516Sgabeblack@google.com
29613516Sgabeblack@google.com/* --------------------------------------------------------------------- */
29713516Sgabeblack@google.com/* Dynamic extension mechanism:                                          */
29813516Sgabeblack@google.com/* --------------------------------------------------------------------- */
29913516Sgabeblack@google.com
30013516Sgabeblack@google.comtlm_extension_base *
30113516Sgabeblack@google.comtlm_generic_payload::set_extension(unsigned int index, tlm_extension_base *ext)
30213516Sgabeblack@google.com{
30313516Sgabeblack@google.com    sc_assert(index < m_extensions.size());
30413516Sgabeblack@google.com    tlm_extension_base *tmp = m_extensions[index];
30513516Sgabeblack@google.com    m_extensions[index] = ext;
30613516Sgabeblack@google.com    return tmp;
30713516Sgabeblack@google.com}
30813516Sgabeblack@google.com
30913516Sgabeblack@google.comtlm_extension_base *
31013516Sgabeblack@google.comtlm_generic_payload::set_auto_extension(
31113516Sgabeblack@google.com        unsigned int index, tlm_extension_base *ext)
31213516Sgabeblack@google.com{
31313516Sgabeblack@google.com    sc_assert(index < m_extensions.size());
31413516Sgabeblack@google.com    tlm_extension_base *tmp = m_extensions[index];
31513516Sgabeblack@google.com    m_extensions[index] = ext;
31613516Sgabeblack@google.com    if (!tmp)
31713516Sgabeblack@google.com        m_extensions.insert_in_cache(&m_extensions[index]);
31813516Sgabeblack@google.com    sc_assert(m_mm != 0);
31913516Sgabeblack@google.com    return tmp;
32013516Sgabeblack@google.com}
32113516Sgabeblack@google.com
32213516Sgabeblack@google.comtlm_extension_base *
32313516Sgabeblack@google.comtlm_generic_payload::get_extension(unsigned int index) const
32413516Sgabeblack@google.com{
32513516Sgabeblack@google.com    sc_assert(index < m_extensions.size());
32613516Sgabeblack@google.com    return m_extensions[index];
32713516Sgabeblack@google.com}
32813516Sgabeblack@google.com
32913516Sgabeblack@google.comvoid
33013516Sgabeblack@google.comtlm_generic_payload::clear_extension(unsigned int index)
33113516Sgabeblack@google.com{
33213516Sgabeblack@google.com    sc_assert(index < m_extensions.size());
33313516Sgabeblack@google.com    m_extensions[index] = static_cast<tlm_extension_base *>(0);
33413516Sgabeblack@google.com}
33513516Sgabeblack@google.com
33613516Sgabeblack@google.comvoid
33713516Sgabeblack@google.comtlm_generic_payload::release_extension(unsigned int index)
33813516Sgabeblack@google.com{
33913516Sgabeblack@google.com    sc_assert(index < m_extensions.size());
34013516Sgabeblack@google.com    if (m_mm) {
34113516Sgabeblack@google.com        m_extensions.insert_in_cache(&m_extensions[index]);
34213516Sgabeblack@google.com    } else {
34313516Sgabeblack@google.com        m_extensions[index]->free();
34413516Sgabeblack@google.com        m_extensions[index] = static_cast<tlm_extension_base *>(nullptr);
34513516Sgabeblack@google.com    }
34613516Sgabeblack@google.com}
34713516Sgabeblack@google.com
34813516Sgabeblack@google.comvoid
34913516Sgabeblack@google.comtlm_generic_payload::resize_extensions()
35013516Sgabeblack@google.com{
35113516Sgabeblack@google.com    m_extensions.expand(max_num_extensions());
35213516Sgabeblack@google.com}
35313516Sgabeblack@google.com
35413516Sgabeblack@google.com} // namespace tlm
355