summaryrefslogtreecommitdiff
path: root/src/systemc/tlm_core/tlm_2/tlm_generic_payload/tlm_gp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/systemc/tlm_core/tlm_2/tlm_generic_payload/tlm_gp.cpp')
-rw-r--r--src/systemc/tlm_core/tlm_2/tlm_generic_payload/tlm_gp.cpp367
1 files changed, 367 insertions, 0 deletions
diff --git a/src/systemc/tlm_core/tlm_2/tlm_generic_payload/tlm_gp.cpp b/src/systemc/tlm_core/tlm_2/tlm_generic_payload/tlm_gp.cpp
new file mode 100644
index 000000000..6843db312
--- /dev/null
+++ b/src/systemc/tlm_core/tlm_2/tlm_generic_payload/tlm_gp.cpp
@@ -0,0 +1,367 @@
+/*****************************************************************************
+
+ 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 "tlm_core/tlm_2/tlm_generic_payload/tlm_gp.h"
+#include "sysc/utils/sc_typeindex.h" // sc_typeindex
+
+#include <map>
+#include <cstring> // std::memcpy et.al.
+
+using sc_core::sc_type_index;
+
+namespace tlm {
+
+template class SC_API tlm_array<tlm_extension_base*>;
+
+//---------------------------------------------------------------------------
+// Classes for the extension mechanism
+//---------------------------------------------------------------------------
+
+/* anonymous */ 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() /* = default */ {}
+
+}; // class 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:
+//---------------------------------------------------------------------------
+
+//---------------
+// Constructors
+//---------------
+
+// Default constructor
+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;
+ }
+ }
+}
+
+//--------------
+// Destructor
+//--------------
+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*>(0);
+ }
+}
+
+void tlm_generic_payload::resize_extensions()
+{
+ m_extensions.expand(max_num_extensions());
+}
+
+} // namespace tlm