diff options
Diffstat (limited to 'src/systemc/tlm_core/tlm_2/tlm_generic_payload/tlm_gp.cc')
-rw-r--r-- | src/systemc/tlm_core/tlm_2/tlm_generic_payload/tlm_gp.cc | 355 |
1 files changed, 355 insertions, 0 deletions
diff --git a/src/systemc/tlm_core/tlm_2/tlm_generic_payload/tlm_gp.cc b/src/systemc/tlm_core/tlm_2/tlm_generic_payload/tlm_gp.cc new file mode 100644 index 000000000..ff3c92bd9 --- /dev/null +++ b/src/systemc/tlm_core/tlm_2/tlm_generic_payload/tlm_gp.cc @@ -0,0 +1,355 @@ +/***************************************************************************** + + Licensed to Accellera Systems Initiative Inc. (Accellera) under one or + more contributor license agreements. See the NOTICE file distributed + with this work for additional information regarding copyright ownership. + Accellera licenses this file to you under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with the + License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + *****************************************************************************/ + +#include <cstring> // std::memcpy et.al. +#include <map> +#include <systemc> +#include <tlm> + +using sc_core::sc_type_index; + +namespace tlm +{ + +template class tlm_array<tlm_extension_base *>; + +//--------------------------------------------------------------------------- +// Classes for the extension mechanism +//--------------------------------------------------------------------------- + +namespace +{ + +class tlm_extension_registry +{ + typedef unsigned int key_type; + typedef std::map<sc_core::sc_type_index, key_type> type_map; + public: + static tlm_extension_registry & + instance() + { + if (!instance_) { + // Don't cleanup registry. + instance_ = new tlm_extension_registry(); + } + return *instance_; + } + + unsigned int + register_extension(sc_type_index type) + { + type_map::const_iterator it = ids_.find(type); + + if (it == ids_.end()) { + // New extension - generate/store ID. + type_map::value_type v(type, static_cast<key_type>(ids_.size())); + ids_.insert(v); + return v.second; + } + return it->second; + } + + static unsigned int + max_num_extensions() + { + return (instance_) ? instance().ids_.size() : 0; + } + + private: + static tlm_extension_registry *instance_; + type_map ids_; + tlm_extension_registry() {} + +}; + +tlm_extension_registry *tlm_extension_registry::instance_ = NULL; + +} // anonymous namespace + +unsigned int +max_num_extensions() +{ + return tlm_extension_registry::max_num_extensions(); +} + +unsigned int +tlm_extension_base::register_extension(const std::type_info &type) +{ + return tlm_extension_registry::instance().register_extension(type); +} + +//--------------------------------------------------------------------------- +// The generic payload class: +//--------------------------------------------------------------------------- + +tlm_generic_payload::tlm_generic_payload() : m_address(0), + m_command(TLM_IGNORE_COMMAND), m_data(0), m_length(0), + m_response_status(TLM_INCOMPLETE_RESPONSE), m_dmi(false), m_byte_enable(0), + m_byte_enable_length(0), m_streaming_width(0), + m_gp_option(TLM_MIN_PAYLOAD), m_extensions(max_num_extensions()), m_mm(0), + m_ref_count(0) +{} + +tlm_generic_payload::tlm_generic_payload(tlm_mm_interface *mm): m_address(0), + m_command(TLM_IGNORE_COMMAND), m_data(0), m_length(0), + m_response_status(TLM_INCOMPLETE_RESPONSE), m_dmi(false), m_byte_enable(0), + m_byte_enable_length(0), m_streaming_width(0), + m_gp_option(TLM_MIN_PAYLOAD), m_extensions(max_num_extensions()), m_mm(mm), + m_ref_count(0) +{} + +void +tlm_generic_payload::reset() +{ + // Should the other members be reset too? + m_gp_option = TLM_MIN_PAYLOAD; + m_extensions.free_entire_cache(); +}; + +// Non-virtual deep-copying of the object. +void +tlm_generic_payload::deep_copy_from(const tlm_generic_payload &other) +{ + m_command = other.get_command(); + m_address = other.get_address(); + m_length = other.get_data_length(); + m_response_status = other.get_response_status(); + m_byte_enable_length = other.get_byte_enable_length(); + m_streaming_width = other.get_streaming_width(); + m_gp_option = other.get_gp_option(); + m_dmi = other.is_dmi_allowed(); + + // Deep copy data. + // There must be enough space in the target transaction! + if (m_data && other.m_data) { + std::memcpy(m_data, other.m_data, m_length); + } + // Deep copy byte enables. + // There must be enough space in the target transaction! + if (m_byte_enable && other.m_byte_enable) { + std::memcpy(m_byte_enable, other.m_byte_enable, m_byte_enable_length); + } + // Deep copy extensions (sticky and non-sticky). + if (m_extensions.size() < other.m_extensions.size()) { + m_extensions.expand(other.m_extensions.size()); + } + for (unsigned int i = 0; i < other.m_extensions.size(); i++) { + if (other.m_extensions[i]) { + // Original has extension i. + if (!m_extensions[i]) { + // We don't: clone. + tlm_extension_base *ext = other.m_extensions[i]->clone(); + if (ext) { // Extension may not be clonable. + if (has_mm()) { + // mm can take care of removing cloned extensions. + set_auto_extension(i, ext); + } else { + // no mm, user will call free_all_extensions(). + set_extension(i, ext); + } + } + } else { + // We already have such extension. Copy original over it. + m_extensions[i]->copy_from(*other.m_extensions[i]); + } + } + } +} + +// To update the state of the original generic payload from a deep copy. +// Assumes that "other" was created from the original by calling +// deep_copy_from. Argument use_byte_enable_on_read determines whether to use +// or ignores byte enables when copying back the data array on a read command. + +void +tlm_generic_payload::update_original_from( + const tlm_generic_payload &other, bool use_byte_enable_on_read) +{ + // Copy back extensions that are present on the original. + update_extensions_from(other); + + // Copy back the response status and DMI hint attributes. + m_response_status = other.get_response_status(); + m_dmi = other.is_dmi_allowed(); + + // Copy back the data array for a read command only deep_copy_from allowed + // null pointers, and so will we. + // We assume the arrays are the same size. + // We test for equal pointers in case the original and the copy share the + // same array. + + if (is_read() && m_data && other.m_data && m_data != other.m_data) { + if (m_byte_enable && use_byte_enable_on_read) { + if (m_byte_enable_length == 8 && m_length % 8 == 0) { + // Optimized implementation copies 64-bit words by masking. + for (unsigned int i = 0; i < m_length; i += 8) { + typedef sc_dt::uint64 *u; + *reinterpret_cast<u>(&m_data[i]) &= + ~*reinterpret_cast<u>(m_byte_enable); + *reinterpret_cast<u>(&m_data[i]) |= + *reinterpret_cast<u>(&other.m_data[i]) & + *reinterpret_cast<u>(m_byte_enable); + } + } else if (m_byte_enable_length == 4 && m_length % 4 == 0) { + // Optimized implementation copies 32-bit words by masking. + for (unsigned int i = 0; i < m_length; i += 4) { + typedef unsigned int *u; + *reinterpret_cast<u>(&m_data[i]) &= + ~*reinterpret_cast<u>(m_byte_enable); + *reinterpret_cast<u>(&m_data[i]) |= + *reinterpret_cast<u>(&other.m_data[i]) & + *reinterpret_cast<u>(m_byte_enable); + } + } else { + // Unoptimized implementation. + for (unsigned int i = 0; i < m_length; i++) { + if (m_byte_enable[i % m_byte_enable_length]) + m_data[i] = other.m_data[i]; + } + } + } else { + std::memcpy(m_data, other.m_data, m_length); + } + } +} + +void +tlm_generic_payload::update_extensions_from(const tlm_generic_payload &other) +{ + // Deep copy extensions that are already present. + sc_assert(m_extensions.size() <= other.m_extensions.size()); + for (unsigned int i = 0; i < m_extensions.size(); i++) { + if (other.m_extensions[i]) { + // Original has extension i. + if (m_extensions[i]) { + // We have it too. Copy. + m_extensions[i]->copy_from(*other.m_extensions[i]); + } + } + } +} + +// Free all extensions. Useful when reusing a cloned transaction that doesn't +// have memory manager. Normal and sticky extensions are freed and extension +// array cleared. +void +tlm_generic_payload::free_all_extensions() +{ + m_extensions.free_entire_cache(); + for (unsigned int i = 0; i < m_extensions.size(); i++) { + if (m_extensions[i]) { + m_extensions[i]->free(); + m_extensions[i] = 0; + } + } +} + +tlm_generic_payload::~tlm_generic_payload() +{ + for (unsigned int i = 0; i < m_extensions.size(); i++) { + if (m_extensions[i]) + m_extensions[i]->free(); + } +} + +//---------------- +// API (including setters & getters) +//--------------- + +std::string +tlm_generic_payload::get_response_string() const +{ + switch (m_response_status) { + case TLM_OK_RESPONSE: + return "TLM_OK_RESPONSE"; + case TLM_INCOMPLETE_RESPONSE: + return "TLM_INCOMPLETE_RESPONSE"; + case TLM_GENERIC_ERROR_RESPONSE: + return "TLM_GENERIC_ERROR_RESPONSE"; + case TLM_ADDRESS_ERROR_RESPONSE: + return "TLM_ADDRESS_ERROR_RESPONSE"; + case TLM_COMMAND_ERROR_RESPONSE: + return "TLM_COMMAND_ERROR_RESPONSE"; + case TLM_BURST_ERROR_RESPONSE: + return "TLM_BURST_ERROR_RESPONSE"; + case TLM_BYTE_ENABLE_ERROR_RESPONSE: + return "TLM_BYTE_ENABLE_ERROR_RESPONSE"; + } + return "TLM_UNKNOWN_RESPONSE"; +} + +/* --------------------------------------------------------------------- */ +/* Dynamic extension mechanism: */ +/* --------------------------------------------------------------------- */ + +tlm_extension_base * +tlm_generic_payload::set_extension(unsigned int index, tlm_extension_base *ext) +{ + sc_assert(index < m_extensions.size()); + tlm_extension_base *tmp = m_extensions[index]; + m_extensions[index] = ext; + return tmp; +} + +tlm_extension_base * +tlm_generic_payload::set_auto_extension( + unsigned int index, tlm_extension_base *ext) +{ + sc_assert(index < m_extensions.size()); + tlm_extension_base *tmp = m_extensions[index]; + m_extensions[index] = ext; + if (!tmp) + m_extensions.insert_in_cache(&m_extensions[index]); + sc_assert(m_mm != 0); + return tmp; +} + +tlm_extension_base * +tlm_generic_payload::get_extension(unsigned int index) const +{ + sc_assert(index < m_extensions.size()); + return m_extensions[index]; +} + +void +tlm_generic_payload::clear_extension(unsigned int index) +{ + sc_assert(index < m_extensions.size()); + m_extensions[index] = static_cast<tlm_extension_base *>(0); +} + +void +tlm_generic_payload::release_extension(unsigned int index) +{ + sc_assert(index < m_extensions.size()); + if (m_mm) { + m_extensions.insert_in_cache(&m_extensions[index]); + } else { + m_extensions[index]->free(); + m_extensions[index] = static_cast<tlm_extension_base *>(nullptr); + } +} + +void +tlm_generic_payload::resize_extensions() +{ + m_extensions.expand(max_num_extensions()); +} + +} // namespace tlm |