gp.cc revision 13523:de27641700bb
110249Sstephan.diestelhorst@arm.com/***************************************************************************** 210249Sstephan.diestelhorst@arm.com 310249Sstephan.diestelhorst@arm.com Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 410249Sstephan.diestelhorst@arm.com more contributor license agreements. See the NOTICE file distributed 510249Sstephan.diestelhorst@arm.com with this work for additional information regarding copyright ownership. 610249Sstephan.diestelhorst@arm.com Accellera licenses this file to you under the Apache License, Version 2.0 710249Sstephan.diestelhorst@arm.com (the "License"); you may not use this file except in compliance with the 810249Sstephan.diestelhorst@arm.com License. You may obtain a copy of the License at 910249Sstephan.diestelhorst@arm.com 1010249Sstephan.diestelhorst@arm.com http://www.apache.org/licenses/LICENSE-2.0 1110249Sstephan.diestelhorst@arm.com 1210249Sstephan.diestelhorst@arm.com Unless required by applicable law or agreed to in writing, software 1310249Sstephan.diestelhorst@arm.com distributed under the License is distributed on an "AS IS" BASIS, 1410249Sstephan.diestelhorst@arm.com WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 1510249Sstephan.diestelhorst@arm.com implied. See the License for the specific language governing 1610249Sstephan.diestelhorst@arm.com permissions and limitations under the License. 1710249Sstephan.diestelhorst@arm.com 1810249Sstephan.diestelhorst@arm.com *****************************************************************************/ 1910249Sstephan.diestelhorst@arm.com 2010249Sstephan.diestelhorst@arm.com#include <cstring> // std::memcpy et.al. 2110249Sstephan.diestelhorst@arm.com#include <map> 2210249Sstephan.diestelhorst@arm.com#include <systemc> 2310249Sstephan.diestelhorst@arm.com#include <tlm> 2410249Sstephan.diestelhorst@arm.com#include <typeindex> 2510249Sstephan.diestelhorst@arm.com 2610249Sstephan.diestelhorst@arm.comnamespace tlm 2710249Sstephan.diestelhorst@arm.com{ 2810249Sstephan.diestelhorst@arm.com 2910249Sstephan.diestelhorst@arm.comtemplate class tlm_array<tlm_extension_base *>; 3010249Sstephan.diestelhorst@arm.com 3110249Sstephan.diestelhorst@arm.com//--------------------------------------------------------------------------- 3210249Sstephan.diestelhorst@arm.com// Classes for the extension mechanism 3310249Sstephan.diestelhorst@arm.com//--------------------------------------------------------------------------- 3410249Sstephan.diestelhorst@arm.com 3510249Sstephan.diestelhorst@arm.comnamespace 3610249Sstephan.diestelhorst@arm.com{ 3710249Sstephan.diestelhorst@arm.com 3810249Sstephan.diestelhorst@arm.comclass tlm_extension_registry 3910249Sstephan.diestelhorst@arm.com{ 4010249Sstephan.diestelhorst@arm.com typedef unsigned int key_type; 4110249Sstephan.diestelhorst@arm.com typedef std::map<std::type_index, key_type> type_map; 4211793Sbrandon.potter@amd.com public: 4311793Sbrandon.potter@amd.com static tlm_extension_registry & 4410249Sstephan.diestelhorst@arm.com instance() 4510249Sstephan.diestelhorst@arm.com { 4610249Sstephan.diestelhorst@arm.com if (!instance_) { 4710249Sstephan.diestelhorst@arm.com // Don't cleanup registry. 4811800Sbrandon.potter@amd.com instance_ = new tlm_extension_registry(); 4910249Sstephan.diestelhorst@arm.com } 5010249Sstephan.diestelhorst@arm.com return *instance_; 5110249Sstephan.diestelhorst@arm.com } 5211800Sbrandon.potter@amd.com 5310249Sstephan.diestelhorst@arm.com unsigned int 5410249Sstephan.diestelhorst@arm.com register_extension(std::type_index type) 5510249Sstephan.diestelhorst@arm.com { 5610249Sstephan.diestelhorst@arm.com type_map::const_iterator it = ids_.find(type); 5710249Sstephan.diestelhorst@arm.com 5810249Sstephan.diestelhorst@arm.com if (it == ids_.end()) { 5910249Sstephan.diestelhorst@arm.com // New extension - generate/store ID. 6010249Sstephan.diestelhorst@arm.com type_map::value_type v(type, static_cast<key_type>(ids_.size())); 6110249Sstephan.diestelhorst@arm.com ids_.insert(v); 6210249Sstephan.diestelhorst@arm.com return v.second; 6310249Sstephan.diestelhorst@arm.com } 6410249Sstephan.diestelhorst@arm.com return it->second; 6510249Sstephan.diestelhorst@arm.com } 6610249Sstephan.diestelhorst@arm.com 6710249Sstephan.diestelhorst@arm.com static unsigned int 6810249Sstephan.diestelhorst@arm.com max_num_extensions() 6911321Ssteve.reinhardt@amd.com { 7010249Sstephan.diestelhorst@arm.com return (instance_) ? instance().ids_.size() : 0; 7110249Sstephan.diestelhorst@arm.com } 7210249Sstephan.diestelhorst@arm.com 7310249Sstephan.diestelhorst@arm.com private: 7410249Sstephan.diestelhorst@arm.com static tlm_extension_registry *instance_; 7510249Sstephan.diestelhorst@arm.com type_map ids_; 7610249Sstephan.diestelhorst@arm.com tlm_extension_registry() {} 7710249Sstephan.diestelhorst@arm.com 7810249Sstephan.diestelhorst@arm.com}; 7910249Sstephan.diestelhorst@arm.com 8010249Sstephan.diestelhorst@arm.comtlm_extension_registry *tlm_extension_registry::instance_ = NULL; 8110249Sstephan.diestelhorst@arm.com 8210249Sstephan.diestelhorst@arm.com} // anonymous namespace 8310249Sstephan.diestelhorst@arm.com 8410249Sstephan.diestelhorst@arm.comunsigned int 8510249Sstephan.diestelhorst@arm.commax_num_extensions() 8610249Sstephan.diestelhorst@arm.com{ 8710395Sstephan.diestelhorst@arm.com return tlm_extension_registry::max_num_extensions(); 8810395Sstephan.diestelhorst@arm.com} 8910395Sstephan.diestelhorst@arm.com 9010249Sstephan.diestelhorst@arm.comunsigned int 9110249Sstephan.diestelhorst@arm.comtlm_extension_base::register_extension(const std::type_info &type) 9210249Sstephan.diestelhorst@arm.com{ 9310249Sstephan.diestelhorst@arm.com return tlm_extension_registry::instance().register_extension(type); 9410249Sstephan.diestelhorst@arm.com} 9510249Sstephan.diestelhorst@arm.com 9610395Sstephan.diestelhorst@arm.com//--------------------------------------------------------------------------- 9710395Sstephan.diestelhorst@arm.com// The generic payload class: 9810395Sstephan.diestelhorst@arm.com//--------------------------------------------------------------------------- 9910395Sstephan.diestelhorst@arm.com 10010395Sstephan.diestelhorst@arm.comtlm_generic_payload::tlm_generic_payload() : m_address(0), 10110395Sstephan.diestelhorst@arm.com m_command(TLM_IGNORE_COMMAND), m_data(0), m_length(0), 10210395Sstephan.diestelhorst@arm.com m_response_status(TLM_INCOMPLETE_RESPONSE), m_dmi(false), m_byte_enable(0), 10310395Sstephan.diestelhorst@arm.com m_byte_enable_length(0), m_streaming_width(0), 10410395Sstephan.diestelhorst@arm.com m_gp_option(TLM_MIN_PAYLOAD), m_extensions(max_num_extensions()), m_mm(0), 10510395Sstephan.diestelhorst@arm.com m_ref_count(0) 10610395Sstephan.diestelhorst@arm.com{} 10710249Sstephan.diestelhorst@arm.com 10810249Sstephan.diestelhorst@arm.comtlm_generic_payload::tlm_generic_payload(tlm_mm_interface *mm): m_address(0), 10910249Sstephan.diestelhorst@arm.com m_command(TLM_IGNORE_COMMAND), m_data(0), m_length(0), 11010249Sstephan.diestelhorst@arm.com m_response_status(TLM_INCOMPLETE_RESPONSE), m_dmi(false), m_byte_enable(0), 11110249Sstephan.diestelhorst@arm.com m_byte_enable_length(0), m_streaming_width(0), 11210249Sstephan.diestelhorst@arm.com m_gp_option(TLM_MIN_PAYLOAD), m_extensions(max_num_extensions()), m_mm(mm), 11310249Sstephan.diestelhorst@arm.com m_ref_count(0) 11410249Sstephan.diestelhorst@arm.com{} 11510249Sstephan.diestelhorst@arm.com 11610249Sstephan.diestelhorst@arm.comvoid 11710249Sstephan.diestelhorst@arm.comtlm_generic_payload::reset() 11810249Sstephan.diestelhorst@arm.com{ 11910249Sstephan.diestelhorst@arm.com // Should the other members be reset too? 12010249Sstephan.diestelhorst@arm.com m_gp_option = TLM_MIN_PAYLOAD; 12110249Sstephan.diestelhorst@arm.com m_extensions.free_entire_cache(); 12210249Sstephan.diestelhorst@arm.com}; 12310249Sstephan.diestelhorst@arm.com 12410249Sstephan.diestelhorst@arm.com// Non-virtual deep-copying of the object. 12510249Sstephan.diestelhorst@arm.comvoid 12610249Sstephan.diestelhorst@arm.comtlm_generic_payload::deep_copy_from(const tlm_generic_payload &other) 12710249Sstephan.diestelhorst@arm.com{ 12810249Sstephan.diestelhorst@arm.com m_command = other.get_command(); 12910249Sstephan.diestelhorst@arm.com m_address = other.get_address(); 13010249Sstephan.diestelhorst@arm.com m_length = other.get_data_length(); 13110249Sstephan.diestelhorst@arm.com m_response_status = other.get_response_status(); 13210249Sstephan.diestelhorst@arm.com m_byte_enable_length = other.get_byte_enable_length(); 13310249Sstephan.diestelhorst@arm.com m_streaming_width = other.get_streaming_width(); 13410249Sstephan.diestelhorst@arm.com m_gp_option = other.get_gp_option(); 13510249Sstephan.diestelhorst@arm.com m_dmi = other.is_dmi_allowed(); 13610249Sstephan.diestelhorst@arm.com 13710249Sstephan.diestelhorst@arm.com // Deep copy data. 13810249Sstephan.diestelhorst@arm.com // There must be enough space in the target transaction! 13910249Sstephan.diestelhorst@arm.com if (m_data && other.m_data) { 14010249Sstephan.diestelhorst@arm.com std::memcpy(m_data, other.m_data, m_length); 14110249Sstephan.diestelhorst@arm.com } 14210249Sstephan.diestelhorst@arm.com // Deep copy byte enables. 14310249Sstephan.diestelhorst@arm.com // There must be enough space in the target transaction! 14410249Sstephan.diestelhorst@arm.com if (m_byte_enable && other.m_byte_enable) { 14510249Sstephan.diestelhorst@arm.com std::memcpy(m_byte_enable, other.m_byte_enable, m_byte_enable_length); 14610249Sstephan.diestelhorst@arm.com } 14710249Sstephan.diestelhorst@arm.com // Deep copy extensions (sticky and non-sticky). 14810249Sstephan.diestelhorst@arm.com if (m_extensions.size() < other.m_extensions.size()) { 14910249Sstephan.diestelhorst@arm.com m_extensions.expand(other.m_extensions.size()); 15010249Sstephan.diestelhorst@arm.com } 15110249Sstephan.diestelhorst@arm.com for (unsigned int i = 0; i < other.m_extensions.size(); i++) { 15210249Sstephan.diestelhorst@arm.com if (other.m_extensions[i]) { 15310249Sstephan.diestelhorst@arm.com // Original has extension i. 15410249Sstephan.diestelhorst@arm.com if (!m_extensions[i]) { 15510249Sstephan.diestelhorst@arm.com // We don't: clone. 15610249Sstephan.diestelhorst@arm.com tlm_extension_base *ext = other.m_extensions[i]->clone(); 15710249Sstephan.diestelhorst@arm.com if (ext) { // Extension may not be clonable. 15810249Sstephan.diestelhorst@arm.com if (has_mm()) { 15910249Sstephan.diestelhorst@arm.com // mm can take care of removing cloned extensions. 16010249Sstephan.diestelhorst@arm.com set_auto_extension(i, ext); 16110249Sstephan.diestelhorst@arm.com } else { 16210249Sstephan.diestelhorst@arm.com // no mm, user will call free_all_extensions(). 16310249Sstephan.diestelhorst@arm.com set_extension(i, ext); 16410249Sstephan.diestelhorst@arm.com } 16510249Sstephan.diestelhorst@arm.com } 16610249Sstephan.diestelhorst@arm.com } else { 16710249Sstephan.diestelhorst@arm.com // We already have such extension. Copy original over it. 16810249Sstephan.diestelhorst@arm.com m_extensions[i]->copy_from(*other.m_extensions[i]); 16910249Sstephan.diestelhorst@arm.com } 17010249Sstephan.diestelhorst@arm.com } 17110249Sstephan.diestelhorst@arm.com } 17210249Sstephan.diestelhorst@arm.com} 17310249Sstephan.diestelhorst@arm.com 17410249Sstephan.diestelhorst@arm.com// To update the state of the original generic payload from a deep copy. 17511800Sbrandon.potter@amd.com// Assumes that "other" was created from the original by calling 17611800Sbrandon.potter@amd.com// deep_copy_from. Argument use_byte_enable_on_read determines whether to use 17711800Sbrandon.potter@amd.com// or ignores byte enables when copying back the data array on a read command. 17811800Sbrandon.potter@amd.com 17911800Sbrandon.potter@amd.comvoid 18011800Sbrandon.potter@amd.comtlm_generic_payload::update_original_from( 18111800Sbrandon.potter@amd.com const tlm_generic_payload &other, bool use_byte_enable_on_read) 18211800Sbrandon.potter@amd.com{ 18311800Sbrandon.potter@amd.com // Copy back extensions that are present on the original. 18411800Sbrandon.potter@amd.com update_extensions_from(other); 18511800Sbrandon.potter@amd.com 18611800Sbrandon.potter@amd.com // Copy back the response status and DMI hint attributes. 18711800Sbrandon.potter@amd.com m_response_status = other.get_response_status(); 18811800Sbrandon.potter@amd.com m_dmi = other.is_dmi_allowed(); 18911800Sbrandon.potter@amd.com 19011800Sbrandon.potter@amd.com // Copy back the data array for a read command only deep_copy_from allowed 19111800Sbrandon.potter@amd.com // null pointers, and so will we. 19211800Sbrandon.potter@amd.com // We assume the arrays are the same size. 19311800Sbrandon.potter@amd.com // We test for equal pointers in case the original and the copy share the 19411800Sbrandon.potter@amd.com // same array. 19511800Sbrandon.potter@amd.com 19611800Sbrandon.potter@amd.com if (is_read() && m_data && other.m_data && m_data != other.m_data) { 19711800Sbrandon.potter@amd.com if (m_byte_enable && use_byte_enable_on_read) { 19811800Sbrandon.potter@amd.com if (m_byte_enable_length == 8 && m_length % 8 == 0) { 19910249Sstephan.diestelhorst@arm.com // Optimized implementation copies 64-bit words by masking. 20010905Sandreas.sandberg@arm.com for (unsigned int i = 0; i < m_length; i += 8) { 20110249Sstephan.diestelhorst@arm.com typedef sc_dt::uint64 *u; 20210249Sstephan.diestelhorst@arm.com *reinterpret_cast<u>(&m_data[i]) &= 20310249Sstephan.diestelhorst@arm.com ~*reinterpret_cast<u>(m_byte_enable); 20410249Sstephan.diestelhorst@arm.com *reinterpret_cast<u>(&m_data[i]) |= 20510249Sstephan.diestelhorst@arm.com *reinterpret_cast<u>(&other.m_data[i]) & 20610249Sstephan.diestelhorst@arm.com *reinterpret_cast<u>(m_byte_enable); 20710249Sstephan.diestelhorst@arm.com } 20810249Sstephan.diestelhorst@arm.com } else if (m_byte_enable_length == 4 && m_length % 4 == 0) { 20910249Sstephan.diestelhorst@arm.com // Optimized implementation copies 32-bit words by masking. 21010249Sstephan.diestelhorst@arm.com for (unsigned int i = 0; i < m_length; i += 4) { 21110249Sstephan.diestelhorst@arm.com typedef unsigned int *u; 21210905Sandreas.sandberg@arm.com *reinterpret_cast<u>(&m_data[i]) &= 21310905Sandreas.sandberg@arm.com ~*reinterpret_cast<u>(m_byte_enable); 21410905Sandreas.sandberg@arm.com *reinterpret_cast<u>(&m_data[i]) |= 21510249Sstephan.diestelhorst@arm.com *reinterpret_cast<u>(&other.m_data[i]) & 21610249Sstephan.diestelhorst@arm.com *reinterpret_cast<u>(m_byte_enable); 21710249Sstephan.diestelhorst@arm.com } 21810249Sstephan.diestelhorst@arm.com } else { 21910249Sstephan.diestelhorst@arm.com // Unoptimized implementation. 22010249Sstephan.diestelhorst@arm.com for (unsigned int i = 0; i < m_length; i++) { 22110905Sandreas.sandberg@arm.com if (m_byte_enable[i % m_byte_enable_length]) 22210905Sandreas.sandberg@arm.com m_data[i] = other.m_data[i]; 22310905Sandreas.sandberg@arm.com } 22410249Sstephan.diestelhorst@arm.com } 22510249Sstephan.diestelhorst@arm.com } else { 22610249Sstephan.diestelhorst@arm.com std::memcpy(m_data, other.m_data, m_length); 22710905Sandreas.sandberg@arm.com } 22810249Sstephan.diestelhorst@arm.com } 22910395Sstephan.diestelhorst@arm.com} 23010395Sstephan.diestelhorst@arm.com 23110249Sstephan.diestelhorst@arm.comvoid 23210249Sstephan.diestelhorst@arm.comtlm_generic_payload::update_extensions_from(const tlm_generic_payload &other) 23311321Ssteve.reinhardt@amd.com{ 23410395Sstephan.diestelhorst@arm.com // Deep copy extensions that are already present. 23510395Sstephan.diestelhorst@arm.com sc_assert(m_extensions.size() <= other.m_extensions.size()); 23610395Sstephan.diestelhorst@arm.com for (unsigned int i = 0; i < m_extensions.size(); i++) { 23710395Sstephan.diestelhorst@arm.com if (other.m_extensions[i]) { 23810249Sstephan.diestelhorst@arm.com // Original has extension i. 23910249Sstephan.diestelhorst@arm.com if (m_extensions[i]) { 24010249Sstephan.diestelhorst@arm.com // We have it too. Copy. 24110249Sstephan.diestelhorst@arm.com m_extensions[i]->copy_from(*other.m_extensions[i]); 24210905Sandreas.sandberg@arm.com } 24310905Sandreas.sandberg@arm.com } 24410905Sandreas.sandberg@arm.com } 24510249Sstephan.diestelhorst@arm.com} 24610249Sstephan.diestelhorst@arm.com 24710249Sstephan.diestelhorst@arm.com// Free all extensions. Useful when reusing a cloned transaction that doesn't 24810249Sstephan.diestelhorst@arm.com// have memory manager. Normal and sticky extensions are freed and extension 24910249Sstephan.diestelhorst@arm.com// array cleared. 25010249Sstephan.diestelhorst@arm.comvoid 25110249Sstephan.diestelhorst@arm.comtlm_generic_payload::free_all_extensions() 25210249Sstephan.diestelhorst@arm.com{ 25310249Sstephan.diestelhorst@arm.com m_extensions.free_entire_cache(); 25410249Sstephan.diestelhorst@arm.com for (unsigned int i = 0; i < m_extensions.size(); i++) { 25510249Sstephan.diestelhorst@arm.com if (m_extensions[i]) { 25610249Sstephan.diestelhorst@arm.com m_extensions[i]->free(); 25710249Sstephan.diestelhorst@arm.com m_extensions[i] = 0; 25810249Sstephan.diestelhorst@arm.com } 25910249Sstephan.diestelhorst@arm.com } 26010249Sstephan.diestelhorst@arm.com} 26110249Sstephan.diestelhorst@arm.com 26210249Sstephan.diestelhorst@arm.comtlm_generic_payload::~tlm_generic_payload() 26310249Sstephan.diestelhorst@arm.com{ 264 for (unsigned int i = 0; i < m_extensions.size(); i++) { 265 if (m_extensions[i]) 266 m_extensions[i]->free(); 267 } 268} 269 270//---------------- 271// API (including setters & getters) 272//--------------- 273 274std::string 275tlm_generic_payload::get_response_string() const 276{ 277 switch (m_response_status) { 278 case TLM_OK_RESPONSE: 279 return "TLM_OK_RESPONSE"; 280 case TLM_INCOMPLETE_RESPONSE: 281 return "TLM_INCOMPLETE_RESPONSE"; 282 case TLM_GENERIC_ERROR_RESPONSE: 283 return "TLM_GENERIC_ERROR_RESPONSE"; 284 case TLM_ADDRESS_ERROR_RESPONSE: 285 return "TLM_ADDRESS_ERROR_RESPONSE"; 286 case TLM_COMMAND_ERROR_RESPONSE: 287 return "TLM_COMMAND_ERROR_RESPONSE"; 288 case TLM_BURST_ERROR_RESPONSE: 289 return "TLM_BURST_ERROR_RESPONSE"; 290 case TLM_BYTE_ENABLE_ERROR_RESPONSE: 291 return "TLM_BYTE_ENABLE_ERROR_RESPONSE"; 292 } 293 return "TLM_UNKNOWN_RESPONSE"; 294} 295 296/* --------------------------------------------------------------------- */ 297/* Dynamic extension mechanism: */ 298/* --------------------------------------------------------------------- */ 299 300tlm_extension_base * 301tlm_generic_payload::set_extension(unsigned int index, tlm_extension_base *ext) 302{ 303 sc_assert(index < m_extensions.size()); 304 tlm_extension_base *tmp = m_extensions[index]; 305 m_extensions[index] = ext; 306 return tmp; 307} 308 309tlm_extension_base * 310tlm_generic_payload::set_auto_extension( 311 unsigned int index, tlm_extension_base *ext) 312{ 313 sc_assert(index < m_extensions.size()); 314 tlm_extension_base *tmp = m_extensions[index]; 315 m_extensions[index] = ext; 316 if (!tmp) 317 m_extensions.insert_in_cache(&m_extensions[index]); 318 sc_assert(m_mm != 0); 319 return tmp; 320} 321 322tlm_extension_base * 323tlm_generic_payload::get_extension(unsigned int index) const 324{ 325 sc_assert(index < m_extensions.size()); 326 return m_extensions[index]; 327} 328 329void 330tlm_generic_payload::clear_extension(unsigned int index) 331{ 332 sc_assert(index < m_extensions.size()); 333 m_extensions[index] = static_cast<tlm_extension_base *>(0); 334} 335 336void 337tlm_generic_payload::release_extension(unsigned int index) 338{ 339 sc_assert(index < m_extensions.size()); 340 if (m_mm) { 341 m_extensions.insert_in_cache(&m_extensions[index]); 342 } else { 343 m_extensions[index]->free(); 344 m_extensions[index] = static_cast<tlm_extension_base *>(nullptr); 345 } 346} 347 348void 349tlm_generic_payload::resize_extensions() 350{ 351 m_extensions.expand(max_num_extensions()); 352} 353 354} // namespace tlm 355