gp.cc revision 13586
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