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
|