gp.cc revision 13516
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 <systemc> 23#include <tlm> 24 25using sc_core::sc_type_index; 26 27namespace tlm 28{ 29 30template class tlm_array<tlm_extension_base *>; 31 32//--------------------------------------------------------------------------- 33// Classes for the extension mechanism 34//--------------------------------------------------------------------------- 35 36namespace 37{ 38 39class tlm_extension_registry 40{ 41 typedef unsigned int key_type; 42 typedef std::map<sc_core::sc_type_index, key_type> type_map; 43 public: 44 static tlm_extension_registry & 45 instance() 46 { 47 if (!instance_) { 48 // Don't cleanup registry. 49 instance_ = new tlm_extension_registry(); 50 } 51 return *instance_; 52 } 53 54 unsigned int 55 register_extension(sc_type_index type) 56 { 57 type_map::const_iterator it = ids_.find(type); 58 59 if (it == ids_.end()) { 60 // New extension - generate/store ID. 61 type_map::value_type v(type, static_cast<key_type>(ids_.size())); 62 ids_.insert(v); 63 return v.second; 64 } 65 return it->second; 66 } 67 68 static unsigned int 69 max_num_extensions() 70 { 71 return (instance_) ? instance().ids_.size() : 0; 72 } 73 74 private: 75 static tlm_extension_registry *instance_; 76 type_map ids_; 77 tlm_extension_registry() {} 78 79}; 80 81tlm_extension_registry *tlm_extension_registry::instance_ = NULL; 82 83} // anonymous namespace 84 85unsigned int 86max_num_extensions() 87{ 88 return tlm_extension_registry::max_num_extensions(); 89} 90 91unsigned int 92tlm_extension_base::register_extension(const std::type_info &type) 93{ 94 return tlm_extension_registry::instance().register_extension(type); 95} 96 97//--------------------------------------------------------------------------- 98// The generic payload class: 99//--------------------------------------------------------------------------- 100 101tlm_generic_payload::tlm_generic_payload() : m_address(0), 102 m_command(TLM_IGNORE_COMMAND), m_data(0), m_length(0), 103 m_response_status(TLM_INCOMPLETE_RESPONSE), m_dmi(false), m_byte_enable(0), 104 m_byte_enable_length(0), m_streaming_width(0), 105 m_gp_option(TLM_MIN_PAYLOAD), m_extensions(max_num_extensions()), m_mm(0), 106 m_ref_count(0) 107{} 108 109tlm_generic_payload::tlm_generic_payload(tlm_mm_interface *mm): m_address(0), 110 m_command(TLM_IGNORE_COMMAND), m_data(0), m_length(0), 111 m_response_status(TLM_INCOMPLETE_RESPONSE), m_dmi(false), m_byte_enable(0), 112 m_byte_enable_length(0), m_streaming_width(0), 113 m_gp_option(TLM_MIN_PAYLOAD), m_extensions(max_num_extensions()), m_mm(mm), 114 m_ref_count(0) 115{} 116 117void 118tlm_generic_payload::reset() 119{ 120 // Should the other members be reset too? 121 m_gp_option = TLM_MIN_PAYLOAD; 122 m_extensions.free_entire_cache(); 123}; 124 125// Non-virtual deep-copying of the object. 126void 127tlm_generic_payload::deep_copy_from(const tlm_generic_payload &other) 128{ 129 m_command = other.get_command(); 130 m_address = other.get_address(); 131 m_length = other.get_data_length(); 132 m_response_status = other.get_response_status(); 133 m_byte_enable_length = other.get_byte_enable_length(); 134 m_streaming_width = other.get_streaming_width(); 135 m_gp_option = other.get_gp_option(); 136 m_dmi = other.is_dmi_allowed(); 137 138 // Deep copy data. 139 // There must be enough space in the target transaction! 140 if (m_data && other.m_data) { 141 std::memcpy(m_data, other.m_data, m_length); 142 } 143 // Deep copy byte enables. 144 // There must be enough space in the target transaction! 145 if (m_byte_enable && other.m_byte_enable) { 146 std::memcpy(m_byte_enable, other.m_byte_enable, m_byte_enable_length); 147 } 148 // Deep copy extensions (sticky and non-sticky). 149 if (m_extensions.size() < other.m_extensions.size()) { 150 m_extensions.expand(other.m_extensions.size()); 151 } 152 for (unsigned int i = 0; i < other.m_extensions.size(); i++) { 153 if (other.m_extensions[i]) { 154 // Original has extension i. 155 if (!m_extensions[i]) { 156 // We don't: clone. 157 tlm_extension_base *ext = other.m_extensions[i]->clone(); 158 if (ext) { // Extension may not be clonable. 159 if (has_mm()) { 160 // mm can take care of removing cloned extensions. 161 set_auto_extension(i, ext); 162 } else { 163 // no mm, user will call free_all_extensions(). 164 set_extension(i, ext); 165 } 166 } 167 } else { 168 // We already have such extension. Copy original over it. 169 m_extensions[i]->copy_from(*other.m_extensions[i]); 170 } 171 } 172 } 173} 174 175// To update the state of the original generic payload from a deep copy. 176// Assumes that "other" was created from the original by calling 177// deep_copy_from. Argument use_byte_enable_on_read determines whether to use 178// or ignores byte enables when copying back the data array on a read command. 179 180void 181tlm_generic_payload::update_original_from( 182 const tlm_generic_payload &other, bool use_byte_enable_on_read) 183{ 184 // Copy back extensions that are present on the original. 185 update_extensions_from(other); 186 187 // Copy back the response status and DMI hint attributes. 188 m_response_status = other.get_response_status(); 189 m_dmi = other.is_dmi_allowed(); 190 191 // Copy back the data array for a read command only deep_copy_from allowed 192 // null pointers, and so will we. 193 // We assume the arrays are the same size. 194 // We test for equal pointers in case the original and the copy share the 195 // same array. 196 197 if (is_read() && m_data && other.m_data && m_data != other.m_data) { 198 if (m_byte_enable && use_byte_enable_on_read) { 199 if (m_byte_enable_length == 8 && m_length % 8 == 0) { 200 // Optimized implementation copies 64-bit words by masking. 201 for (unsigned int i = 0; i < m_length; i += 8) { 202 typedef sc_dt::uint64 *u; 203 *reinterpret_cast<u>(&m_data[i]) &= 204 ~*reinterpret_cast<u>(m_byte_enable); 205 *reinterpret_cast<u>(&m_data[i]) |= 206 *reinterpret_cast<u>(&other.m_data[i]) & 207 *reinterpret_cast<u>(m_byte_enable); 208 } 209 } else if (m_byte_enable_length == 4 && m_length % 4 == 0) { 210 // Optimized implementation copies 32-bit words by masking. 211 for (unsigned int i = 0; i < m_length; i += 4) { 212 typedef unsigned int *u; 213 *reinterpret_cast<u>(&m_data[i]) &= 214 ~*reinterpret_cast<u>(m_byte_enable); 215 *reinterpret_cast<u>(&m_data[i]) |= 216 *reinterpret_cast<u>(&other.m_data[i]) & 217 *reinterpret_cast<u>(m_byte_enable); 218 } 219 } else { 220 // Unoptimized implementation. 221 for (unsigned int i = 0; i < m_length; i++) { 222 if (m_byte_enable[i % m_byte_enable_length]) 223 m_data[i] = other.m_data[i]; 224 } 225 } 226 } else { 227 std::memcpy(m_data, other.m_data, m_length); 228 } 229 } 230} 231 232void 233tlm_generic_payload::update_extensions_from(const tlm_generic_payload &other) 234{ 235 // Deep copy extensions that are already present. 236 sc_assert(m_extensions.size() <= other.m_extensions.size()); 237 for (unsigned int i = 0; i < m_extensions.size(); i++) { 238 if (other.m_extensions[i]) { 239 // Original has extension i. 240 if (m_extensions[i]) { 241 // We have it too. Copy. 242 m_extensions[i]->copy_from(*other.m_extensions[i]); 243 } 244 } 245 } 246} 247 248// Free all extensions. Useful when reusing a cloned transaction that doesn't 249// have memory manager. Normal and sticky extensions are freed and extension 250// array cleared. 251void 252tlm_generic_payload::free_all_extensions() 253{ 254 m_extensions.free_entire_cache(); 255 for (unsigned int i = 0; i < m_extensions.size(); i++) { 256 if (m_extensions[i]) { 257 m_extensions[i]->free(); 258 m_extensions[i] = 0; 259 } 260 } 261} 262 263tlm_generic_payload::~tlm_generic_payload() 264{ 265 for (unsigned int i = 0; i < m_extensions.size(); i++) { 266 if (m_extensions[i]) 267 m_extensions[i]->free(); 268 } 269} 270 271//---------------- 272// API (including setters & getters) 273//--------------- 274 275std::string 276tlm_generic_payload::get_response_string() const 277{ 278 switch (m_response_status) { 279 case TLM_OK_RESPONSE: 280 return "TLM_OK_RESPONSE"; 281 case TLM_INCOMPLETE_RESPONSE: 282 return "TLM_INCOMPLETE_RESPONSE"; 283 case TLM_GENERIC_ERROR_RESPONSE: 284 return "TLM_GENERIC_ERROR_RESPONSE"; 285 case TLM_ADDRESS_ERROR_RESPONSE: 286 return "TLM_ADDRESS_ERROR_RESPONSE"; 287 case TLM_COMMAND_ERROR_RESPONSE: 288 return "TLM_COMMAND_ERROR_RESPONSE"; 289 case TLM_BURST_ERROR_RESPONSE: 290 return "TLM_BURST_ERROR_RESPONSE"; 291 case TLM_BYTE_ENABLE_ERROR_RESPONSE: 292 return "TLM_BYTE_ENABLE_ERROR_RESPONSE"; 293 } 294 return "TLM_UNKNOWN_RESPONSE"; 295} 296 297/* --------------------------------------------------------------------- */ 298/* Dynamic extension mechanism: */ 299/* --------------------------------------------------------------------- */ 300 301tlm_extension_base * 302tlm_generic_payload::set_extension(unsigned int index, tlm_extension_base *ext) 303{ 304 sc_assert(index < m_extensions.size()); 305 tlm_extension_base *tmp = m_extensions[index]; 306 m_extensions[index] = ext; 307 return tmp; 308} 309 310tlm_extension_base * 311tlm_generic_payload::set_auto_extension( 312 unsigned int index, tlm_extension_base *ext) 313{ 314 sc_assert(index < m_extensions.size()); 315 tlm_extension_base *tmp = m_extensions[index]; 316 m_extensions[index] = ext; 317 if (!tmp) 318 m_extensions.insert_in_cache(&m_extensions[index]); 319 sc_assert(m_mm != 0); 320 return tmp; 321} 322 323tlm_extension_base * 324tlm_generic_payload::get_extension(unsigned int index) const 325{ 326 sc_assert(index < m_extensions.size()); 327 return m_extensions[index]; 328} 329 330void 331tlm_generic_payload::clear_extension(unsigned int index) 332{ 333 sc_assert(index < m_extensions.size()); 334 m_extensions[index] = static_cast<tlm_extension_base *>(0); 335} 336 337void 338tlm_generic_payload::release_extension(unsigned int index) 339{ 340 sc_assert(index < m_extensions.size()); 341 if (m_mm) { 342 m_extensions.insert_in_cache(&m_extensions[index]); 343 } else { 344 m_extensions[index]->free(); 345 m_extensions[index] = static_cast<tlm_extension_base *>(nullptr); 346 } 347} 348 349void 350tlm_generic_payload::resize_extensions() 351{ 352 m_extensions.expand(max_num_extensions()); 353} 354 355} // namespace tlm 356