/* * tlm_gp_data.h * * Created on: 07.11.2015 * Author: eyck */ #ifndef TLM_GP_DATA_H_ #define TLM_GP_DATA_H_ #include #include namespace scv4tlm { struct tlm_gp_data { //--------------- // Constructors //--------------- // Default constructor tlm_gp_data() : address(0) , command(tlm::TLM_IGNORE_COMMAND) , data(0) , data_length(0) , response_status(tlm::TLM_INCOMPLETE_RESPONSE) , dmi(false) , byte_enable(0) , byte_enable_length(0) , streaming_width(0) , gp_option(tlm::TLM_MIN_PAYLOAD) , m_extensions(tlm::max_num_extensions()) , m_ref_count(0) { } explicit tlm_gp_data(tlm::tlm_mm_interface* mm) : address(0) , command(tlm::TLM_IGNORE_COMMAND) , data(0) , data_length(0) , response_status(tlm::TLM_INCOMPLETE_RESPONSE) , dmi(false) , byte_enable(0) , byte_enable_length(0) , streaming_width(0) , gp_option(tlm::TLM_MIN_PAYLOAD) , m_extensions(tlm::max_num_extensions()) , m_ref_count(0) { } int get_ref_count() const { return m_ref_count; } void reset() { //should the other members be reset too? gp_option = tlm::TLM_MIN_PAYLOAD; m_extensions.free_entire_cache(); } ; tlm_gp_data(const tlm::tlm_generic_payload& x) : address(x.get_address()) , command(x.get_command()) , data(x.get_data_ptr()) , data_length(x.get_data_length()) , response_status(x.get_response_status()) , dmi(x.is_dmi_allowed()) , byte_enable(x.get_byte_enable_ptr()) , byte_enable_length(x.get_byte_enable_length()) , streaming_width(x.get_streaming_width()) , gp_option(x.get_gp_option()) , m_extensions(tlm::max_num_extensions()) , m_ref_count(0) { } private: //disabled copy ctor and assignment operator. // Copy constructor tlm_gp_data(const tlm_gp_data& x) : address(x.get_address()) , command(x.get_command()) , data(x.get_data_ptr()) , data_length(x.get_data_length()) , response_status(x.get_response_status()) , dmi(x.is_dmi_allowed()) , byte_enable(x.get_byte_enable_ptr()) , byte_enable_length(x.get_byte_enable_length()) , streaming_width(x.get_streaming_width()) , gp_option(x.gp_option) , m_extensions(tlm::max_num_extensions()) , m_ref_count(0) { } public: // Assignment operator needed for SCV introspection tlm_gp_data& operator=(const tlm_gp_data& x) { command = x.get_command(); address = x.get_address(); data = x.get_data_ptr(); data_length = x.get_data_length(); response_status = x.get_response_status(); byte_enable = x.get_byte_enable_ptr(); byte_enable_length = x.get_byte_enable_length(); streaming_width = x.get_streaming_width(); gp_option = x.get_gp_option(); dmi = x.is_dmi_allowed(); // extension copy: all extension arrays must be of equal size by // construction (i.e. it must either be constructed after C++ // static construction time, or the resize_extensions() method must // have been called prior to using the object) for (unsigned int i = 0; i < m_extensions.size(); i++) { m_extensions[i] = x.get_extension(i); } return (*this); } // non-virtual deep-copying of the object void deep_copy_from(const scv4tlm::tlm_gp_data & other) { command = other.get_command(); address = other.get_address(); data_length = other.get_data_length(); response_status = other.get_response_status(); byte_enable_length = other.get_byte_enable_length(); streaming_width = other.get_streaming_width(); gp_option = other.get_gp_option(); dmi = other.is_dmi_allowed(); // deep copy data // there must be enough space in the target transaction! if (data && other.get_data_ptr()) { memcpy(data, other.get_data_ptr(), data_length); } // deep copy byte enables // there must be enough space in the target transaction! if (byte_enable && other.get_byte_enable_ptr()) { memcpy(byte_enable, other.get_byte_enable_ptr(), byte_enable_length); } // deep copy extensions (sticky and non-sticky) for (unsigned int i = 0; i < other.m_extensions.size(); i++) { if (other.get_extension(i)) { //original has extension i if (!m_extensions[i]) { //We don't: clone. tlm::tlm_extension_base *ext = other.get_extension(i)->clone(); if (ext) //extension may not be clonable. { set_extension(i, ext); } } else { //We already have such extension. Copy original over it. m_extensions[i]->copy_from(*other.get_extension(i)); } } } } // To update the state of the original generic payload from a deep copy // Assumes that "other" was created from the original by calling deep_copy_from // Argument use_byte_enable_on_read determines whether to use or ignores byte enables // when copying back the data array on a read command void update_original_from(const tlm::tlm_generic_payload & other, bool use_byte_enable_on_read = true) { // Copy back extensions that are present on the original // update_extensions_from(other); // Copy back the response status and DMI hint attributes response_status = other.get_response_status(); dmi = other.is_dmi_allowed(); // Copy back the data array for a read command only // deep_copy_from allowed null pointers, and so will we // We assume the arrays are the same size // We test for equal pointers in case the original and the copy share the same array if (is_read() && data && other.get_data_ptr() && data != other.get_data_ptr()) { if (byte_enable && use_byte_enable_on_read) { if (byte_enable_length == 8 && data_length % 8 == 0) { // Optimized implementation copies 64-bit words by masking for (unsigned int i = 0; i < data_length; i += 8) { typedef sc_dt::uint64* u; *reinterpret_cast(&data[i]) &= ~*reinterpret_cast(byte_enable); *reinterpret_cast(&data[i]) |= *reinterpret_cast(&other.get_data_ptr()[i]) & *reinterpret_cast(byte_enable); } } else if (byte_enable_length == 4 && data_length % 4 == 0) { // Optimized implementation copies 32-bit words by masking for (unsigned int i = 0; i < data_length; i += 4) { typedef unsigned int* u; *reinterpret_cast(&data[i]) &= ~*reinterpret_cast(byte_enable); *reinterpret_cast(&data[i]) |= *reinterpret_cast(&other.get_data_ptr()[i]) & *reinterpret_cast(byte_enable); } } else // Unoptimized implementation for (unsigned int i = 0; i < data_length; i++) if (byte_enable[i % byte_enable_length]) data[i] = other.get_data_ptr()[i]; } else memcpy(data, other.get_data_ptr(), data_length); } } /* void update_extensions_from(const tlm::tlm_generic_payload & other) { // deep copy extensions that are already present for (unsigned int i = 0; i < tlm::max_num_extensions(); i++) { if (other.get_extension(i)) { //original has extension i if (m_extensions[i]) { //We have it too. copy. m_extensions[i]->copy_from(*other.get_extension(i)); } } } } */ // Free all extensions. Useful when reusing a cloned transaction that doesn't have memory manager. // normal and sticky extensions are freed and extension array cleared. void free_all_extensions() { m_extensions.free_entire_cache(); for (unsigned int i = 0; i < m_extensions.size(); i++) { if (m_extensions[i]) { m_extensions[i]->free(); m_extensions[i] = 0; } } } //-------------- // Destructor //-------------- virtual ~tlm_gp_data() { for(unsigned int i=0; ifree(); } //---------------- // API (including setters & getters) //--------------- // Command related method bool is_read() const { return (command == tlm::TLM_READ_COMMAND); } void set_read() { command = tlm::TLM_READ_COMMAND; } bool is_write() const { return (command == tlm::TLM_WRITE_COMMAND); } void set_write() { command = tlm::TLM_WRITE_COMMAND; } tlm::tlm_command get_command() const { return command; } void set_command(const tlm::tlm_command command) { this->command = command; } // Address related methods sc_dt::uint64 get_address() const { return address; } void set_address(const sc_dt::uint64 address) { this->address = address; } // Data related methods unsigned char* get_data_ptr() const { return data; } void set_data_ptr(unsigned char* data) { this->data = data; } // Transaction length (in bytes) related methods unsigned int get_data_length() const { return data_length; } void set_data_length(const unsigned int length) { data_length = length; } // Response status related methods bool is_response_ok() const { return (response_status > 0); } bool is_response_error() const { return (response_status <= 0); } tlm::tlm_response_status get_response_status() const { return response_status; } void set_response_status(const tlm::tlm_response_status response_status) { this->response_status = response_status; } std::string get_response_string() const { switch (response_status) { case tlm::TLM_OK_RESPONSE: return "TLM_OK_RESPONSE"; case tlm::TLM_INCOMPLETE_RESPONSE: return "TLM_INCOMPLETE_RESPONSE"; case tlm::TLM_GENERIC_ERROR_RESPONSE: return "TLM_GENERIC_ERROR_RESPONSE"; case tlm::TLM_ADDRESS_ERROR_RESPONSE: return "TLM_ADDRESS_ERROR_RESPONSE"; case tlm::TLM_COMMAND_ERROR_RESPONSE: return "TLM_COMMAND_ERROR_RESPONSE"; case tlm::TLM_BURST_ERROR_RESPONSE: return "TLM_BURST_ERROR_RESPONSE"; case tlm::TLM_BYTE_ENABLE_ERROR_RESPONSE: return "TLM_BYTE_ENABLE_ERROR_RESPONSE"; } return "TLM_UNKNOWN_RESPONSE"; } // Streaming related methods unsigned int get_streaming_width() const { return streaming_width; } void set_streaming_width(const unsigned int streaming_width) { this->streaming_width = streaming_width; } // Byte enable related methods unsigned char* get_byte_enable_ptr() const { return byte_enable; } void set_byte_enable_ptr(unsigned char* byte_enable) { this->byte_enable = byte_enable; } unsigned int get_byte_enable_length() const { return byte_enable_length; } void set_byte_enable_length(const unsigned int byte_enable_length) { this->byte_enable_length = byte_enable_length; } // This is the "DMI-hint" a slave can set this to true if it // wants to indicate that a DMI request would be supported: void set_dmi_allowed(bool dmi_allowed) { dmi = dmi_allowed; } bool is_dmi_allowed() const { return dmi; } // Use full set of attributes in DMI/debug? tlm::tlm_gp_option get_gp_option() const { return gp_option; } void set_gp_option(const tlm::tlm_gp_option gp_opt) { gp_option = gp_opt; } public: /* --------------------------------------------------------------------- */ /* Generic Payload attributes: */ /* --------------------------------------------------------------------- */ /* - m_command : Type of transaction. Three values supported: */ /* - TLM_WRITE_COMMAND */ /* - TLM_READ_COMMAND */ /* - TLM_IGNORE_COMMAND */ /* - m_address : Transaction base address (byte-addressing). */ /* - m_data : When m_command = TLM_WRITE_COMMAND contains a */ /* pointer to the data to be written in the target.*/ /* When m_command = TLM_READ_COMMAND contains a */ /* pointer where to copy the data read from the */ /* target. */ /* - m_length : Total number of bytes of the transaction. */ /* - m_response_status : This attribute indicates whether an error has */ /* occurred during the transaction. */ /* Values supported are: */ /* - TLM_OK_RESP */ /* - TLM_INCOMPLETE_RESP */ /* - TLM_GENERIC_ERROR_RESP */ /* - TLM_ADDRESS_ERROR_RESP */ /* - TLM_COMMAND_ERROR_RESP */ /* - TLM_BURST_ERROR_RESP */ /* - TLM_BYTE_ENABLE_ERROR_RESP */ /* */ /* - m_byte_enable : It can be used to create burst transfers where */ /* the address increment between each beat is greater */ /* than the word length of each beat, or to place */ /* words in selected byte lanes of a bus. */ /* - m_byte_enable_length : For a read or a write command, the target */ /* interpret the byte enable length attribute as the */ /* number of elements in the bytes enable array. */ /* - m_streaming_width : */ /* --------------------------------------------------------------------- */ sc_dt::uint64 address; tlm::tlm_command command; unsigned char* data; unsigned int data_length; tlm::tlm_response_status response_status; bool dmi; unsigned char* byte_enable; unsigned int byte_enable_length; unsigned int streaming_width; tlm::tlm_gp_option gp_option; public: /* --------------------------------------------------------------------- */ /* Dynamic extension mechanism: */ /* --------------------------------------------------------------------- */ /* The extension mechanism is intended to enable initiator modules to */ /* optionally and transparently add data fields to the */ /* tlm_generic_payload. Target modules are free to check for extensions */ /* and may or may not react to the data in the extension fields. The */ /* definition of the extensions' semantics is solely in the */ /* responsibility of the user. */ /* */ /* The following rules apply: */ /* */ /* - Every extension class must be derived from tlm_extension, e.g.: */ /* class my_extension : public tlm_extension { ... } */ /* */ /* - A tlm_generic_payload object should be constructed after C++ */ /* static initialization time. This way it is guaranteed that the */ /* extension array is of sufficient size to hold all possible */ /* extensions. Alternatively, the initiator module can enforce a valid */ /* extension array size by calling the resize_extensions() method */ /* once before the first transaction with the payload object is */ /* initiated. */ /* */ /* - Initiators should use the the set_extension(e) or clear_extension(e)*/ /* methods for manipulating the extension array. The type of the */ /* argument must be a pointer to the specific registered extension */ /* type (my_extension in the above example) and is used to */ /* automatically locate the appropriate index in the array. */ /* */ /* - Targets can check for a specific extension by calling */ /* get_extension(e). e will point to zero if the extension is not */ /* present. */ /* */ /* --------------------------------------------------------------------- */ // Stick the pointer to an extension into the vector, return the // previous value: template T* set_extension(T* ext) { return static_cast(set_extension(T::ID, ext)); } // non-templatized version with manual index: tlm::tlm_extension_base* set_extension(unsigned int index, tlm::tlm_extension_base* ext) { tlm::tlm_extension_base* tmp = m_extensions[index]; m_extensions[index] = ext; return tmp; } // Check for an extension, ext will point to 0 if not present template void get_extension(T*& ext) const { ext = get_extension(); } template T* get_extension() const { return static_cast(get_extension(T::ID)); } // Non-templatized version with manual index: tlm::tlm_extension_base* get_extension(unsigned int index) const { return m_extensions[index]; } //this call just removes the extension from the txn but does not // call free() or tells the MM to do so // it return false if there was active MM so you are now in an unsafe situation // recommended use: when 100% sure there is no MM template void clear_extension(const T* ext) { clear_extension(); } //this call just removes the extension from the txn but does not // call free() or tells the MM to do so // it return false if there was active MM so you are now in an unsafe situation // recommended use: when 100% sure there is no MM template void clear_extension() { clear_extension(T::ID); } //this call removes the extension from the txn and does // call free() or tells the MM to do so when the txn is finally done // recommended use: when not sure there is no MM template void release_extension(T* ext) { release_extension(); } //this call removes the extension from the txn and does // call free() or tells the MM to do so when the txn is finally done // recommended use: when not sure there is no MM template void release_extension() { release_extension(T::ID); } private: // Non-templatized version with manual index void clear_extension(unsigned int index) { m_extensions[index] = static_cast(0); } // Non-templatized version with manual index void release_extension(unsigned int index) { m_extensions[index]->free(); m_extensions[index] = static_cast(0); } public: // Make sure the extension array is large enough. Can be called once by // an initiator module (before issuing the first transaction) to make // sure that the extension array is of correct size. This is only needed // if the initiator cannot guarantee that the generic payload object is // allocated after C++ static construction time. void resize_extensions() { m_extensions.expand(tlm::max_num_extensions()); } private: tlm::tlm_array m_extensions; unsigned int m_ref_count; }; struct tlm_dmi_data { tlm_dmi_data() :dmi_ptr(0) ,dmi_start_address(0) ,dmi_end_address(0) ,dmi_access(tlm::tlm_dmi::DMI_ACCESS_NONE) ,dmi_read_latency(0) ,dmi_write_latency(0) {} tlm_dmi_data(tlm::tlm_dmi& dmi_data) :dmi_ptr(dmi_data.get_dmi_ptr()) ,dmi_start_address(dmi_data.get_start_address()) ,dmi_end_address(dmi_data.get_end_address()) ,dmi_access(dmi_data.get_granted_access()) ,dmi_read_latency(dmi_data.get_read_latency().value()) ,dmi_write_latency(dmi_data.get_write_latency().value()) {} //-------------- // Destructor //-------------- virtual ~tlm_dmi_data() {} unsigned char* dmi_ptr; sc_dt::uint64 dmi_start_address; sc_dt::uint64 dmi_end_address; tlm::tlm_dmi::dmi_access_e dmi_access; sc_dt::uint64 dmi_read_latency; sc_dt::uint64 dmi_write_latency; }; } #endif /* TLM_GP_DATA_H_ */