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// 12-Jan-2009 John Aynsley Bug fix. has_mm() and get_ref_count() should both be const 21// 23-Mar-2009 John Aynsley Add method update_original_from() 22// 20-Apr-2009 John Aynsley Bug fix for 64-bit machines: unsigned long int -> unsigned int 23// 5-May-2011 JA and Philipp Hartmann Add tlm_gp_option, set_gp_option, get_gp_option 24// 11-May-2011 John Aynsley Add run-time check to release() 25 26 27#ifndef __TLM_GP_H__ 28#define __TLM_GP_H__ 29 30#include <systemc> 31#include "tlm_core/tlm_2/tlm_generic_payload/tlm_array.h" 32 33namespace tlm { 34 35class 36tlm_generic_payload; 37 38class tlm_mm_interface { 39public: 40 virtual void free(tlm_generic_payload*) = 0; 41 virtual ~tlm_mm_interface() {} 42}; 43 44//--------------------------------------------------------------------------- 45// Classes and helper functions for the extension mechanism 46//--------------------------------------------------------------------------- 47// Helper function: 48inline unsigned int max_num_extensions(bool increment=false) 49{ 50 static unsigned int max_num = 0; 51 if (increment) ++max_num; 52 return max_num; 53} 54 55// This class can be used for storing pointers to the extension classes, used 56// in tlm_generic_payload: 57class tlm_extension_base 58{ 59public: 60 virtual tlm_extension_base* clone() const = 0; 61 virtual void free() { delete this; } 62 virtual void copy_from(tlm_extension_base const &) = 0; 63protected: 64 virtual ~tlm_extension_base() {} 65 static unsigned int register_extension() 66 { 67 return (max_num_extensions(true) - 1); 68 }; 69}; 70 71// Base class for all extension classes, derive your extension class in 72// the following way: 73// class my_extension : public tlm_extension<my_extension> { ... 74// This triggers proper extension registration during C++ static 75// contruction time. my_extension::ID will hold the unique index in the 76// tlm_generic_payload::m_extensions array. 77template <typename T> 78class tlm_extension : public tlm_extension_base 79{ 80public: 81 virtual tlm_extension_base* clone() const = 0; 82 virtual void copy_from(tlm_extension_base const &ext) = 0; //{assert(typeid(this)==typeid(ext)); assert(ID === ext.ID); assert(0);} 83 virtual ~tlm_extension() {} 84 const static unsigned int ID; 85}; 86 87template <typename T> 88const 89unsigned int tlm_extension<T>::ID = tlm_extension_base::register_extension(); 90 91//--------------------------------------------------------------------------- 92// enumeration types 93//--------------------------------------------------------------------------- 94enum tlm_command { 95 TLM_READ_COMMAND, 96 TLM_WRITE_COMMAND, 97 TLM_IGNORE_COMMAND 98}; 99 100enum tlm_response_status { 101 TLM_OK_RESPONSE = 1, 102 TLM_INCOMPLETE_RESPONSE = 0, 103 TLM_GENERIC_ERROR_RESPONSE = -1, 104 TLM_ADDRESS_ERROR_RESPONSE = -2, 105 TLM_COMMAND_ERROR_RESPONSE = -3, 106 TLM_BURST_ERROR_RESPONSE = -4, 107 TLM_BYTE_ENABLE_ERROR_RESPONSE = -5 108}; 109 110enum tlm_gp_option { 111 TLM_MIN_PAYLOAD, 112 TLM_FULL_PAYLOAD, 113 TLM_FULL_PAYLOAD_ACCEPTED 114}; 115 116#define TLM_BYTE_DISABLED 0x0 117#define TLM_BYTE_ENABLED 0xff 118 119//--------------------------------------------------------------------------- 120// The generic payload class: 121//--------------------------------------------------------------------------- 122class tlm_generic_payload { 123 124public: 125 //--------------- 126 // Constructors 127 //--------------- 128 129 // Default constructor 130 tlm_generic_payload() 131 : m_address(0) 132 , m_command(TLM_IGNORE_COMMAND) 133 , m_data(0) 134 , m_length(0) 135 , m_response_status(TLM_INCOMPLETE_RESPONSE) 136 , m_dmi(false) 137 , m_byte_enable(0) 138 , m_byte_enable_length(0) 139 , m_streaming_width(0) 140 , m_gp_option(TLM_MIN_PAYLOAD) 141 , m_extensions(max_num_extensions()) 142 , m_mm(0) 143 , m_ref_count(0) 144 { 145 } 146 147 explicit tlm_generic_payload(tlm_mm_interface* mm) 148 : m_address(0) 149 , m_command(TLM_IGNORE_COMMAND) 150 , m_data(0) 151 , m_length(0) 152 , m_response_status(TLM_INCOMPLETE_RESPONSE) 153 , m_dmi(false) 154 , m_byte_enable(0) 155 , m_byte_enable_length(0) 156 , m_streaming_width(0) 157 , m_gp_option(TLM_MIN_PAYLOAD) 158 , m_extensions(max_num_extensions()) 159 , m_mm(mm) 160 , m_ref_count(0) 161 { 162 } 163 164 void acquire(){assert(m_mm != 0); m_ref_count++;} 165 void release(){assert(m_mm != 0 && m_ref_count > 0); if (--m_ref_count==0) m_mm->free(this);} 166 int get_ref_count() const {return m_ref_count;} 167 void set_mm(tlm_mm_interface* mm) { m_mm = mm; } 168 bool has_mm() const { return m_mm != 0; } 169 170 void reset(){ 171 //should the other members be reset too? 172 m_gp_option = TLM_MIN_PAYLOAD; 173 m_extensions.free_entire_cache(); 174 }; 175 176 177private: 178 //disabled copy ctor and assignment operator. 179 // Copy constructor 180 tlm_generic_payload(const tlm_generic_payload& x) 181 : m_address(x.get_address()) 182 , m_command(x.get_command()) 183 , m_data(x.get_data_ptr()) 184 , m_length(x.get_data_length()) 185 , m_response_status(x.get_response_status()) 186 , m_dmi(x.is_dmi_allowed()) 187 , m_byte_enable(x.get_byte_enable_ptr()) 188 , m_byte_enable_length(x.get_byte_enable_length()) 189 , m_streaming_width(x.get_streaming_width()) 190 , m_gp_option(x.m_gp_option) 191 , m_extensions(max_num_extensions()) 192 { 193 // copy all extensions 194 for(unsigned int i=0; i<m_extensions.size(); i++) 195 { 196 m_extensions[i] = x.get_extension(i); 197 } 198 } 199 200 // Assignment operator 201 tlm_generic_payload& operator= (const tlm_generic_payload& x) 202 { 203 m_command = x.get_command(); 204 m_address = x.get_address(); 205 m_data = x.get_data_ptr(); 206 m_length = x.get_data_length(); 207 m_response_status = x.get_response_status(); 208 m_byte_enable = x.get_byte_enable_ptr(); 209 m_byte_enable_length = x.get_byte_enable_length(); 210 m_streaming_width = x.get_streaming_width(); 211 m_gp_option = x.get_gp_option(); 212 m_dmi = x.is_dmi_allowed(); 213 214 // extension copy: all extension arrays must be of equal size by 215 // construction (i.e. it must either be constructed after C++ 216 // static construction time, or the resize_extensions() method must 217 // have been called prior to using the object) 218 for(unsigned int i=0; i<m_extensions.size(); i++) 219 { 220 m_extensions[i] = x.get_extension(i); 221 } 222 return (*this); 223 } 224public: 225 // non-virtual deep-copying of the object 226 void deep_copy_from(const tlm_generic_payload & other) 227 { 228 m_command = other.get_command(); 229 m_address = other.get_address(); 230 m_length = other.get_data_length(); 231 m_response_status = other.get_response_status(); 232 m_byte_enable_length = other.get_byte_enable_length(); 233 m_streaming_width = other.get_streaming_width(); 234 m_gp_option = other.get_gp_option(); 235 m_dmi = other.is_dmi_allowed(); 236 237 // deep copy data 238 // there must be enough space in the target transaction! 239 if(m_data && other.m_data) 240 { 241 memcpy(m_data, other.m_data, m_length); 242 } 243 // deep copy byte enables 244 // there must be enough space in the target transaction! 245 if(m_byte_enable && other.m_byte_enable) 246 { 247 memcpy(m_byte_enable, other.m_byte_enable, m_byte_enable_length); 248 } 249 // deep copy extensions (sticky and non-sticky) 250 for(unsigned int i=0; i<other.m_extensions.size(); i++) 251 { 252 if(other.m_extensions[i]) 253 { //original has extension i 254 if(!m_extensions[i]) 255 { //We don't: clone. 256 tlm_extension_base *ext = other.m_extensions[i]->clone(); 257 if(ext) //extension may not be clonable. 258 { 259 if(has_mm()) 260 { //mm can take care of removing cloned extensions 261 set_auto_extension(i, ext); 262 } 263 else 264 { // no mm, user will call free_all_extensions(). 265 set_extension(i, ext); 266 } 267 } 268 } 269 else 270 { //We already have such extension. Copy original over it. 271 m_extensions[i]->copy_from(*other.m_extensions[i]); 272 } 273 } 274 } 275 } 276 277 // To update the state of the original generic payload from a deep copy 278 // Assumes that "other" was created from the original by calling deep_copy_from 279 // Argument use_byte_enable_on_read determines whether to use or ignores byte enables 280 // when copying back the data array on a read command 281 282 void update_original_from(const tlm_generic_payload & other, 283 bool use_byte_enable_on_read = true) 284 { 285 // Copy back extensions that are present on the original 286 update_extensions_from(other); 287 288 // Copy back the response status and DMI hint attributes 289 m_response_status = other.get_response_status(); 290 m_dmi = other.is_dmi_allowed(); 291 292 // Copy back the data array for a read command only 293 // deep_copy_from allowed null pointers, and so will we 294 // We assume the arrays are the same size 295 // We test for equal pointers in case the original and the copy share the same array 296 297 if(is_read() && m_data && other.m_data && m_data != other.m_data) 298 { 299 if (m_byte_enable && use_byte_enable_on_read) 300 { 301 if (m_byte_enable_length == 8 && m_length % 8 == 0 ) 302 { 303 // Optimized implementation copies 64-bit words by masking 304 for (unsigned int i = 0; i < m_length; i += 8) 305 { 306 typedef sc_dt::uint64* u; 307 *reinterpret_cast<u>(&m_data[i]) &= ~*reinterpret_cast<u>(m_byte_enable); 308 *reinterpret_cast<u>(&m_data[i]) |= *reinterpret_cast<u>(&other.m_data[i]) & 309 *reinterpret_cast<u>(m_byte_enable); 310 } 311 } 312 else if (m_byte_enable_length == 4 && m_length % 4 == 0 ) 313 { 314 // Optimized implementation copies 32-bit words by masking 315 for (unsigned int i = 0; i < m_length; i += 4) 316 { 317 typedef unsigned int* u; 318 *reinterpret_cast<u>(&m_data[i]) &= ~*reinterpret_cast<u>(m_byte_enable); 319 *reinterpret_cast<u>(&m_data[i]) |= *reinterpret_cast<u>(&other.m_data[i]) & 320 *reinterpret_cast<u>(m_byte_enable); 321 } 322 } 323 else 324 // Unoptimized implementation 325 for (unsigned int i = 0; i < m_length; i++) 326 if ( m_byte_enable[i % m_byte_enable_length] ) 327 m_data[i] = other.m_data[i]; 328 } 329 else 330 memcpy(m_data, other.m_data, m_length); 331 } 332 } 333 334 void update_extensions_from(const tlm_generic_payload & other) 335 { 336 // deep copy extensions that are already present 337 for(unsigned int i=0; i<other.m_extensions.size(); i++) 338 { 339 if(other.m_extensions[i]) 340 { //original has extension i 341 if(m_extensions[i]) 342 { //We have it too. copy. 343 m_extensions[i]->copy_from(*other.m_extensions[i]); 344 } 345 } 346 } 347 } 348 349 // Free all extensions. Useful when reusing a cloned transaction that doesn't have memory manager. 350 // normal and sticky extensions are freed and extension array cleared. 351 void free_all_extensions() 352 { 353 m_extensions.free_entire_cache(); 354 for(unsigned int i=0; i<m_extensions.size(); i++) 355 { 356 if(m_extensions[i]) 357 { 358 m_extensions[i]->free(); 359 m_extensions[i] = 0; 360 } 361 } 362 } 363 //-------------- 364 // Destructor 365 //-------------- 366 virtual ~tlm_generic_payload() { 367 for(unsigned int i=0; i<m_extensions.size(); i++) 368 if(m_extensions[i]) m_extensions[i]->free(); 369 } 370 371 //---------------- 372 // API (including setters & getters) 373 //--------------- 374 375 // Command related method 376 bool is_read() const {return (m_command == TLM_READ_COMMAND);} 377 void set_read() {m_command = TLM_READ_COMMAND;} 378 bool is_write() const {return (m_command == TLM_WRITE_COMMAND);} 379 void set_write() {m_command = TLM_WRITE_COMMAND;} 380 tlm_command get_command() const {return m_command;} 381 void set_command(const tlm_command command) {m_command = command;} 382 383 // Address related methods 384 sc_dt::uint64 get_address() const {return m_address;} 385 void set_address(const sc_dt::uint64 address) {m_address = address;} 386 387 // Data related methods 388 unsigned char* get_data_ptr() const {return m_data;} 389 void set_data_ptr(unsigned char* data) {m_data = data;} 390 391 // Transaction length (in bytes) related methods 392 unsigned int get_data_length() const {return m_length;} 393 void set_data_length(const unsigned int length) {m_length = length;} 394 395 // Response status related methods 396 bool is_response_ok() const {return (m_response_status > 0);} 397 bool is_response_error() const {return (m_response_status <= 0);} 398 tlm_response_status get_response_status() const {return m_response_status;} 399 void set_response_status(const tlm_response_status response_status) 400 {m_response_status = response_status;} 401 std::string get_response_string() const 402 { 403 switch(m_response_status) 404 { 405 case TLM_OK_RESPONSE: return "TLM_OK_RESPONSE"; 406 case TLM_INCOMPLETE_RESPONSE: return "TLM_INCOMPLETE_RESPONSE"; 407 case TLM_GENERIC_ERROR_RESPONSE: return "TLM_GENERIC_ERROR_RESPONSE"; 408 case TLM_ADDRESS_ERROR_RESPONSE: return "TLM_ADDRESS_ERROR_RESPONSE"; 409 case TLM_COMMAND_ERROR_RESPONSE: return "TLM_COMMAND_ERROR_RESPONSE"; 410 case TLM_BURST_ERROR_RESPONSE: return "TLM_BURST_ERROR_RESPONSE"; 411 case TLM_BYTE_ENABLE_ERROR_RESPONSE: return "TLM_BYTE_ENABLE_ERROR_RESPONSE"; 412 } 413 return "TLM_UNKNOWN_RESPONSE"; 414 } 415 416 // Streaming related methods 417 unsigned int get_streaming_width() const {return m_streaming_width;} 418 void set_streaming_width(const unsigned int streaming_width) {m_streaming_width = streaming_width; } 419 420 // Byte enable related methods 421 unsigned char* get_byte_enable_ptr() const {return m_byte_enable;} 422 void set_byte_enable_ptr(unsigned char* byte_enable){m_byte_enable = byte_enable;} 423 unsigned int get_byte_enable_length() const {return m_byte_enable_length;} 424 void set_byte_enable_length(const unsigned int byte_enable_length){m_byte_enable_length = byte_enable_length;} 425 426 // This is the "DMI-hint" a slave can set this to true if it 427 // wants to indicate that a DMI request would be supported: 428 void set_dmi_allowed(bool dmi_allowed) { m_dmi = dmi_allowed; } 429 bool is_dmi_allowed() const { return m_dmi; } 430 431 // Use full set of attributes in DMI/debug? 432 tlm_gp_option get_gp_option() const { return m_gp_option; } 433 void set_gp_option( const tlm_gp_option gp_opt ) { m_gp_option = gp_opt; } 434 435private: 436 437 /* --------------------------------------------------------------------- */ 438 /* Generic Payload attributes: */ 439 /* --------------------------------------------------------------------- */ 440 /* - m_command : Type of transaction. Three values supported: */ 441 /* - TLM_WRITE_COMMAND */ 442 /* - TLM_READ_COMMAND */ 443 /* - TLM_IGNORE_COMMAND */ 444 /* - m_address : Transaction base address (byte-addressing). */ 445 /* - m_data : When m_command = TLM_WRITE_COMMAND contains a */ 446 /* pointer to the data to be written in the target.*/ 447 /* When m_command = TLM_READ_COMMAND contains a */ 448 /* pointer where to copy the data read from the */ 449 /* target. */ 450 /* - m_length : Total number of bytes of the transaction. */ 451 /* - m_response_status : This attribute indicates whether an error has */ 452 /* occurred during the transaction. */ 453 /* Values supported are: */ 454 /* - TLM_OK_RESP */ 455 /* - TLM_INCOMPLETE_RESP */ 456 /* - TLM_GENERIC_ERROR_RESP */ 457 /* - TLM_ADDRESS_ERROR_RESP */ 458 /* - TLM_COMMAND_ERROR_RESP */ 459 /* - TLM_BURST_ERROR_RESP */ 460 /* - TLM_BYTE_ENABLE_ERROR_RESP */ 461 /* */ 462 /* - m_byte_enable : It can be used to create burst transfers where */ 463 /* the address increment between each beat is greater */ 464 /* than the word length of each beat, or to place */ 465 /* words in selected byte lanes of a bus. */ 466 /* - m_byte_enable_length : For a read or a write command, the target */ 467 /* interpret the byte enable length attribute as the */ 468 /* number of elements in the bytes enable array. */ 469 /* - m_streaming_width : */ 470 /* --------------------------------------------------------------------- */ 471 472 sc_dt::uint64 m_address; 473 tlm_command m_command; 474 unsigned char* m_data; 475 unsigned int m_length; 476 tlm_response_status m_response_status; 477 bool m_dmi; 478 unsigned char* m_byte_enable; 479 unsigned int m_byte_enable_length; 480 unsigned int m_streaming_width; 481 tlm_gp_option m_gp_option; 482 483public: 484 485 /* --------------------------------------------------------------------- */ 486 /* Dynamic extension mechanism: */ 487 /* --------------------------------------------------------------------- */ 488 /* The extension mechanism is intended to enable initiator modules to */ 489 /* optionally and transparently add data fields to the */ 490 /* tlm_generic_payload. Target modules are free to check for extensions */ 491 /* and may or may not react to the data in the extension fields. The */ 492 /* definition of the extensions' semantics is solely in the */ 493 /* responsibility of the user. */ 494 /* */ 495 /* The following rules apply: */ 496 /* */ 497 /* - Every extension class must be derived from tlm_extension, e.g.: */ 498 /* class my_extension : public tlm_extension<my_extension> { ... } */ 499 /* */ 500 /* - A tlm_generic_payload object should be constructed after C++ */ 501 /* static initialization time. This way it is guaranteed that the */ 502 /* extension array is of sufficient size to hold all possible */ 503 /* extensions. Alternatively, the initiator module can enforce a valid */ 504 /* extension array size by calling the resize_extensions() method */ 505 /* once before the first transaction with the payload object is */ 506 /* initiated. */ 507 /* */ 508 /* - Initiators should use the the set_extension(e) or clear_extension(e)*/ 509 /* methods for manipulating the extension array. The type of the */ 510 /* argument must be a pointer to the specific registered extension */ 511 /* type (my_extension in the above example) and is used to */ 512 /* automatically locate the appropriate index in the array. */ 513 /* */ 514 /* - Targets can check for a specific extension by calling */ 515 /* get_extension(e). e will point to zero if the extension is not */ 516 /* present. */ 517 /* */ 518 /* --------------------------------------------------------------------- */ 519 520 // Stick the pointer to an extension into the vector, return the 521 // previous value: 522 template <typename T> T* set_extension(T* ext) 523 { 524 return static_cast<T*>(set_extension(T::ID, ext)); 525 } 526 527 // non-templatized version with manual index: 528 tlm_extension_base* set_extension(unsigned int index, 529 tlm_extension_base* ext) 530 { 531 tlm_extension_base* tmp = m_extensions[index]; 532 m_extensions[index] = ext; 533 return tmp; 534 } 535 536 // Stick the pointer to an extension into the vector, return the 537 // previous value and schedule its release 538 template <typename T> T* set_auto_extension(T* ext) 539 { 540 return static_cast<T*>(set_auto_extension(T::ID, ext)); 541 } 542 543 // non-templatized version with manual index: 544 tlm_extension_base* set_auto_extension(unsigned int index, 545 tlm_extension_base* ext) 546 { 547 tlm_extension_base* tmp = m_extensions[index]; 548 m_extensions[index] = ext; 549 if (!tmp) m_extensions.insert_in_cache(&m_extensions[index]); 550 assert(m_mm != 0); 551 return tmp; 552 } 553 554 // Check for an extension, ext will point to 0 if not present 555 template <typename T> void get_extension(T*& ext) const 556 { 557 ext = get_extension<T>(); 558 } 559 template <typename T> T* get_extension() const 560 { 561 return static_cast<T*>(get_extension(T::ID)); 562 } 563 // Non-templatized version with manual index: 564 tlm_extension_base* get_extension(unsigned int index) const 565 { 566 return m_extensions[index]; 567 } 568 569 //this call just removes the extension from the txn but does not 570 // call free() or tells the MM to do so 571 // it return false if there was active MM so you are now in an unsafe situation 572 // recommended use: when 100% sure there is no MM 573 template <typename T> void clear_extension(const T* ext) 574 { 575 clear_extension<T>(); 576 } 577 578 //this call just removes the extension from the txn but does not 579 // call free() or tells the MM to do so 580 // it return false if there was active MM so you are now in an unsafe situation 581 // recommended use: when 100% sure there is no MM 582 template <typename T> void clear_extension() 583 { 584 clear_extension(T::ID); 585 } 586 587 //this call removes the extension from the txn and does 588 // call free() or tells the MM to do so when the txn is finally done 589 // recommended use: when not sure there is no MM 590 template <typename T> void release_extension(T* ext) 591 { 592 release_extension<T>(); 593 } 594 595 //this call removes the extension from the txn and does 596 // call free() or tells the MM to do so when the txn is finally done 597 // recommended use: when not sure there is no MM 598 template <typename T> void release_extension() 599 { 600 release_extension(T::ID); 601 } 602 603private: 604 // Non-templatized version with manual index 605 void clear_extension(unsigned int index) 606 { 607 m_extensions[index] = static_cast<tlm_extension_base*>(0); 608 } 609 // Non-templatized version with manual index 610 void release_extension(unsigned int index) 611 { 612 if (m_mm) 613 { 614 m_extensions.insert_in_cache(&m_extensions[index]); 615 } 616 else 617 { 618 m_extensions[index]->free(); 619 m_extensions[index] = static_cast<tlm_extension_base*>(0); 620 } 621 } 622 623public: 624 // Make sure the extension array is large enough. Can be called once by 625 // an initiator module (before issuing the first transaction) to make 626 // sure that the extension array is of correct size. This is only needed 627 // if the initiator cannot guarantee that the generic payload object is 628 // allocated after C++ static construction time. 629 void resize_extensions() 630 { 631 m_extensions.expand(max_num_extensions()); 632 } 633 634private: 635 tlm_array<tlm_extension_base*> m_extensions; 636 tlm_mm_interface* m_mm; 637 unsigned int m_ref_count; 638}; 639 640} // namespace tlm 641 642#endif /* __TLM_GP_H__ */ 643