diff options
author | Gabe Black <gabeblack@google.com> | 2018-12-08 01:58:26 -0800 |
---|---|---|
committer | Gabe Black <gabeblack@google.com> | 2019-01-09 01:31:53 +0000 |
commit | 7364acfc758a30f81aa75844f6b96b1e4e19990a (patch) | |
tree | 1b38a95be59607d1199d3ba52b46d04afc4cbee4 /src/systemc/tlm_core | |
parent | 3e1e21da61d79b79534a18398b1dde2cc4e473cb (diff) | |
download | gem5-7364acfc758a30f81aa75844f6b96b1e4e19990a.tar.xz |
systemc: Initial import of TLM headers from Accellera.
These headers will need to be cleaned up and have some Accellera
specific quirks ironed out of them, but I'll do that in a later change
to make it clear what those changes are.
Change-Id: Ia4e08633ab552b4c616c66c9b7e2bbd78ebfe7b9
Reviewed-on: https://gem5-review.googlesource.com/c/15055
Reviewed-by: Anthony Gutierrez <anthony.gutierrez@amd.com>
Maintainer: Anthony Gutierrez <anthony.gutierrez@amd.com>
Diffstat (limited to 'src/systemc/tlm_core')
3 files changed, 529 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 diff --git a/src/systemc/tlm_core/tlm_2/tlm_generic_payload/tlm_phase.cpp b/src/systemc/tlm_core/tlm_2/tlm_generic_payload/tlm_phase.cpp new file mode 100644 index 000000000..5f3fb25e0 --- /dev/null +++ b/src/systemc/tlm_core/tlm_2/tlm_generic_payload/tlm_phase.cpp @@ -0,0 +1,113 @@ +/***************************************************************************** + + 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_phase.h" +#include "sysc/utils/sc_string_view.h" +#include "sysc/utils/sc_typeindex.h" +#include "sysc/utils/sc_report.h" +#include <cstring> +#include <map> + +using sc_core::sc_string_view; +using sc_core::sc_type_index; + +namespace tlm { +/* anonymous */ namespace { + +struct tlm_phase_registry +{ + typedef unsigned int key_type; + + static tlm_phase_registry& instance() + { static tlm_phase_registry inst; return inst; } + + unsigned int register_phase(sc_type_index type, sc_string_view name) + { + type_map::const_iterator it = ids_.find( type ); + + if( name.empty() ) { + SC_REPORT_FATAL( sc_core::SC_ID_INTERNAL_ERROR_, + "unexpected empty tlm_phase name" ); + return UNINITIALIZED_PHASE; + } + + if( it == ids_.end() ) { // new phase - generate/store ID and name + type_map::value_type v( type, static_cast<key_type>(names_.size()) ); + names_.push_back( name_table::value_type(name.data(), name.size()) ); + ids_.insert( v ); + return v.second; + } + + if( names_[it->second] != name ) { + SC_REPORT_FATAL( sc_core::SC_ID_INTERNAL_ERROR_, + "tlm_phase registration failed: duplicate type info" ); + sc_core::sc_abort(); + } + return it->second; + } + + const char* get_name( key_type id ) const + { + sc_assert( id < names_.size() ); + return names_[id].c_str(); + } + +private: + typedef std::map<sc_type_index, key_type> type_map; + typedef std::vector<std::string> name_table; + + type_map ids_; + name_table names_; + + tlm_phase_registry() + : names_( END_RESP+1 ) + { +# define BUILTIN_PHASE(phase) \ + names_[phase] = #phase + + BUILTIN_PHASE( UNINITIALIZED_PHASE ); + BUILTIN_PHASE( BEGIN_REQ ); + BUILTIN_PHASE( END_REQ ); + BUILTIN_PHASE( BEGIN_RESP ); + BUILTIN_PHASE( END_RESP ); + } + +}; // class tlm_phase_registry + +} // anonymous namespace + +tlm_phase::tlm_phase( unsigned int id ) + : m_id(id) +{ + // TODO: validate id? + // TODO: add deprecation warning? +} + +tlm_phase::tlm_phase( const std::type_info& type, const char* name ) + : m_id( tlm_phase_registry::instance().register_phase(type, name) ) +{} + +const char* +tlm_phase::get_name() const +{ + return tlm_phase_registry::instance().get_name( m_id ); +} + +} // namespace tlm +// Taf! diff --git a/src/systemc/tlm_core/tlm_2/tlm_quantum/tlm_global_quantum.cpp b/src/systemc/tlm_core/tlm_2/tlm_quantum/tlm_global_quantum.cpp new file mode 100644 index 000000000..8ac09cc9b --- /dev/null +++ b/src/systemc/tlm_core/tlm_2/tlm_quantum/tlm_global_quantum.cpp @@ -0,0 +1,49 @@ +/***************************************************************************** + + 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_quantum/tlm_global_quantum.h" +#include "sysc/kernel/sc_simcontext.h" // sc_time_stamp + +namespace tlm { + +tlm_global_quantum::tlm_global_quantum() + : m_global_quantum(sc_core::SC_ZERO_TIME) +{} + + +tlm_global_quantum& tlm_global_quantum::instance() +{ + static tlm_global_quantum instance_; + return instance_; +} + + +sc_core::sc_time +tlm_global_quantum::compute_local_quantum() +{ + if (m_global_quantum != sc_core::SC_ZERO_TIME) { + const sc_core::sc_time current = sc_core::sc_time_stamp(); + const sc_core::sc_time g_quant = m_global_quantum; + return g_quant - (current % g_quant); + } else { + return sc_core::SC_ZERO_TIME; + } +} + +} // namespace tlm |