1/***************************************************************************** 2 3 Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 4 more contributor license agreements. See the NOTICE file distributed 5 with this work for additional information regarding copyright ownership. 6 Accellera licenses this file to you under the Apache License, Version 2.0 7 (the "License"); you may not use this file except in compliance with the 8 License. You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 implied. See the License for the specific language governing 16 permissions and limitations under the License. 17 18 *****************************************************************************/ 19 20#include <cstring> // std::memcpy et.al. 21#include <map> 22#include <typeindex> 23 24#include "systemc/ext/tlm_core/2/generic_payload/gp.hh" 25 26namespace tlm 27{ 28 29template class tlm_array<tlm_extension_base *>; 30 31//--------------------------------------------------------------------------- 32// Classes for the extension mechanism 33//--------------------------------------------------------------------------- 34 35namespace 36{ 37 38class tlm_extension_registry 39{ 40 typedef unsigned int key_type; 41 typedef std::map<std::type_index, key_type> type_map; 42 public: 43 static tlm_extension_registry & 44 instance() 45 { 46 if (!instance_) { 47 // Don't cleanup registry. 48 instance_ = new tlm_extension_registry(); 49 } 50 return *instance_; 51 } 52 53 unsigned int 54 register_extension(std::type_index type) 55 { 56 type_map::const_iterator it = ids_.find(type); 57 58 if (it == ids_.end()) { 59 // New extension - generate/store ID. 60 type_map::value_type v(type, static_cast<key_type>(ids_.size())); 61 ids_.insert(v); 62 return v.second; 63 } 64 return it->second; 65 } 66 67 static unsigned int 68 max_num_extensions() 69 { 70 return (instance_) ? instance().ids_.size() : 0; 71 } 72 73 private: 74 static tlm_extension_registry *instance_; 75 type_map ids_; 76 tlm_extension_registry() {} 77 78}; 79 80tlm_extension_registry *tlm_extension_registry::instance_ = NULL; 81 82} // anonymous namespace 83 84unsigned int 85max_num_extensions() 86{ 87 return tlm_extension_registry::max_num_extensions(); 88} 89 90unsigned int 91tlm_extension_base::register_extension(const std::type_info &type) 92{ 93 return tlm_extension_registry::instance().register_extension(type); 94} 95 96//--------------------------------------------------------------------------- 97// The generic payload class: 98//--------------------------------------------------------------------------- 99 100tlm_generic_payload::tlm_generic_payload() : m_address(0), 101 m_command(TLM_IGNORE_COMMAND), m_data(0), m_length(0), 102 m_response_status(TLM_INCOMPLETE_RESPONSE), m_dmi(false), m_byte_enable(0), 103 m_byte_enable_length(0), m_streaming_width(0), 104 m_gp_option(TLM_MIN_PAYLOAD), m_extensions(max_num_extensions()), m_mm(0), 105 m_ref_count(0) 106{} 107 108tlm_generic_payload::tlm_generic_payload(tlm_mm_interface *mm): m_address(0), 109 m_command(TLM_IGNORE_COMMAND), m_data(0), m_length(0), 110 m_response_status(TLM_INCOMPLETE_RESPONSE), m_dmi(false), m_byte_enable(0), 111 m_byte_enable_length(0), m_streaming_width(0), 112 m_gp_option(TLM_MIN_PAYLOAD), m_extensions(max_num_extensions()), m_mm(mm), 113 m_ref_count(0) 114{} 115 116void 117tlm_generic_payload::reset() 118{ 119 // Should the other members be reset too? 120 m_gp_option = TLM_MIN_PAYLOAD; 121 m_extensions.free_entire_cache(); 122}; 123 124// Non-virtual deep-copying of the object. 125void 126tlm_generic_payload::deep_copy_from(const tlm_generic_payload &other) 127{ 128 m_command = other.get_command(); 129 m_address = other.get_address(); 130 m_length = other.get_data_length(); 131 m_response_status = other.get_response_status(); 132 m_byte_enable_length = other.get_byte_enable_length(); 133 m_streaming_width = other.get_streaming_width(); 134 m_gp_option = other.get_gp_option(); 135 m_dmi = other.is_dmi_allowed(); 136 137 // Deep copy data. 138 // There must be enough space in the target transaction! 139 if (m_data && other.m_data) { 140 std::memcpy(m_data, other.m_data, m_length); 141 } 142 // Deep copy byte enables. 143 // There must be enough space in the target transaction! 144 if (m_byte_enable && other.m_byte_enable) { 145 std::memcpy(m_byte_enable, other.m_byte_enable, m_byte_enable_length); 146 } 147 // Deep copy extensions (sticky and non-sticky). 148 if (m_extensions.size() < other.m_extensions.size()) { 149 m_extensions.expand(other.m_extensions.size()); 150 } 151 for (unsigned int i = 0; i < other.m_extensions.size(); i++) { 152 if (other.m_extensions[i]) { 153 // Original has extension i. 154 if (!m_extensions[i]) { 155 // We don't: clone. 156 tlm_extension_base *ext = other.m_extensions[i]->clone(); 157 if (ext) { // Extension may not be clonable. 158 if (has_mm()) { 159 // mm can take care of removing cloned extensions. 160 set_auto_extension(i, ext); 161 } else { 162 // no mm, user will call free_all_extensions(). 163 set_extension(i, ext); 164 } 165 } 166 } else { 167 // We already have such extension. Copy original over it. 168 m_extensions[i]->copy_from(*other.m_extensions[i]); 169 } 170 } 171 } 172} 173 174// To update the state of the original generic payload from a deep copy. 175// Assumes that "other" was created from the original by calling 176// deep_copy_from. Argument use_byte_enable_on_read determines whether to use 177// or ignores byte enables when copying back the data array on a read command. 178 179void 180tlm_generic_payload::update_original_from( 181 const tlm_generic_payload &other, bool use_byte_enable_on_read) 182{ 183 // Copy back extensions that are present on the original. 184 update_extensions_from(other); 185 186 // Copy back the response status and DMI hint attributes. 187 m_response_status = other.get_response_status(); 188 m_dmi = other.is_dmi_allowed(); 189 190 // Copy back the data array for a read command only deep_copy_from allowed 191 // null pointers, and so will we. 192 // We assume the arrays are the same size. 193 // We test for equal pointers in case the original and the copy share the 194 // same array. 195 196 if (is_read() && m_data && other.m_data && m_data != other.m_data) { 197 if (m_byte_enable && use_byte_enable_on_read) { 198 if (m_byte_enable_length == 8 && m_length % 8 == 0) { 199 // Optimized implementation copies 64-bit words by masking. 200 for (unsigned int i = 0; i < m_length; i += 8) { 201 typedef sc_dt::uint64 *u; 202 *reinterpret_cast<u>(&m_data[i]) &= 203 ~*reinterpret_cast<u>(m_byte_enable); 204 *reinterpret_cast<u>(&m_data[i]) |= 205 *reinterpret_cast<u>(&other.m_data[i]) & 206 *reinterpret_cast<u>(m_byte_enable); 207 } 208 } else if (m_byte_enable_length == 4 && m_length % 4 == 0) { 209 // Optimized implementation copies 32-bit words by masking. 210 for (unsigned int i = 0; i < m_length; i += 4) { 211 typedef unsigned int *u; 212 *reinterpret_cast<u>(&m_data[i]) &= 213 ~*reinterpret_cast<u>(m_byte_enable); 214 *reinterpret_cast<u>(&m_data[i]) |= 215 *reinterpret_cast<u>(&other.m_data[i]) & 216 *reinterpret_cast<u>(m_byte_enable); 217 } 218 } else { 219 // Unoptimized implementation. 220 for (unsigned int i = 0; i < m_length; i++) { 221 if (m_byte_enable[i % m_byte_enable_length]) 222 m_data[i] = other.m_data[i]; 223 } 224 } 225 } else { 226 std::memcpy(m_data, other.m_data, m_length); 227 } 228 } 229} 230 231void 232tlm_generic_payload::update_extensions_from(const tlm_generic_payload &other) 233{ 234 // Deep copy extensions that are already present. 235 sc_assert(m_extensions.size() <= other.m_extensions.size()); 236 for (unsigned int i = 0; i < m_extensions.size(); i++) { 237 if (other.m_extensions[i]) { 238 // Original has extension i. 239 if (m_extensions[i]) { 240 // We have it too. Copy. 241 m_extensions[i]->copy_from(*other.m_extensions[i]); 242 } 243 } 244 } 245} 246 247// Free all extensions. Useful when reusing a cloned transaction that doesn't 248// have memory manager. Normal and sticky extensions are freed and extension 249// array cleared. 250void 251tlm_generic_payload::free_all_extensions() 252{ 253 m_extensions.free_entire_cache(); 254 for (unsigned int i = 0; i < m_extensions.size(); i++) { 255 if (m_extensions[i]) { 256 m_extensions[i]->free(); 257 m_extensions[i] = 0; 258 } 259 } 260} 261 262tlm_generic_payload::~tlm_generic_payload() 263{ 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