diff options
Diffstat (limited to 'ext/systemc/src/tlm_core/tlm_2/tlm_generic_payload/tlm_gp.h')
-rw-r--r-- | ext/systemc/src/tlm_core/tlm_2/tlm_generic_payload/tlm_gp.h | 642 |
1 files changed, 642 insertions, 0 deletions
diff --git a/ext/systemc/src/tlm_core/tlm_2/tlm_generic_payload/tlm_gp.h b/ext/systemc/src/tlm_core/tlm_2/tlm_generic_payload/tlm_gp.h new file mode 100644 index 000000000..965e059ab --- /dev/null +++ b/ext/systemc/src/tlm_core/tlm_2/tlm_generic_payload/tlm_gp.h @@ -0,0 +1,642 @@ +/***************************************************************************** + + Licensed to Accellera Systems Initiative Inc. (Accellera) under one or + more contributor license agreements. See the NOTICE file distributed + with this work for additional information regarding copyright ownership. + Accellera licenses this file to you under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with the + License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + *****************************************************************************/ + +// 12-Jan-2009 John Aynsley Bug fix. has_mm() and get_ref_count() should both be const +// 23-Mar-2009 John Aynsley Add method update_original_from() +// 20-Apr-2009 John Aynsley Bug fix for 64-bit machines: unsigned long int -> unsigned int +// 5-May-2011 JA and Philipp Hartmann Add tlm_gp_option, set_gp_option, get_gp_option +// 11-May-2011 John Aynsley Add run-time check to release() + + +#ifndef __TLM_GP_H__ +#define __TLM_GP_H__ + +#include <systemc> +#include "tlm_core/tlm_2/tlm_generic_payload/tlm_array.h" + +namespace tlm { + +class +tlm_generic_payload; + +class tlm_mm_interface { +public: + virtual void free(tlm_generic_payload*) = 0; + virtual ~tlm_mm_interface() {} +}; + +//--------------------------------------------------------------------------- +// Classes and helper functions for the extension mechanism +//--------------------------------------------------------------------------- +// Helper function: +inline unsigned int max_num_extensions(bool increment=false) +{ + static unsigned int max_num = 0; + if (increment) ++max_num; + return max_num; +} + +// This class can be used for storing pointers to the extension classes, used +// in tlm_generic_payload: +class tlm_extension_base +{ +public: + virtual tlm_extension_base* clone() const = 0; + virtual void free() { delete this; } + virtual void copy_from(tlm_extension_base const &) = 0; +protected: + virtual ~tlm_extension_base() {} + static unsigned int register_extension() + { + return (max_num_extensions(true) - 1); + }; +}; + +// Base class for all extension classes, derive your extension class in +// the following way: +// class my_extension : public tlm_extension<my_extension> { ... +// This triggers proper extension registration during C++ static +// contruction time. my_extension::ID will hold the unique index in the +// tlm_generic_payload::m_extensions array. +template <typename T> +class tlm_extension : public tlm_extension_base +{ +public: + virtual tlm_extension_base* clone() const = 0; + virtual void copy_from(tlm_extension_base const &ext) = 0; //{assert(typeid(this)==typeid(ext)); assert(ID === ext.ID); assert(0);} + virtual ~tlm_extension() {} + const static unsigned int ID; +}; + +template <typename T> +const +unsigned int tlm_extension<T>::ID = tlm_extension_base::register_extension(); + +//--------------------------------------------------------------------------- +// enumeration types +//--------------------------------------------------------------------------- +enum tlm_command { + TLM_READ_COMMAND, + TLM_WRITE_COMMAND, + TLM_IGNORE_COMMAND +}; + +enum tlm_response_status { + TLM_OK_RESPONSE = 1, + TLM_INCOMPLETE_RESPONSE = 0, + TLM_GENERIC_ERROR_RESPONSE = -1, + TLM_ADDRESS_ERROR_RESPONSE = -2, + TLM_COMMAND_ERROR_RESPONSE = -3, + TLM_BURST_ERROR_RESPONSE = -4, + TLM_BYTE_ENABLE_ERROR_RESPONSE = -5 +}; + +enum tlm_gp_option { + TLM_MIN_PAYLOAD, + TLM_FULL_PAYLOAD, + TLM_FULL_PAYLOAD_ACCEPTED +}; + +#define TLM_BYTE_DISABLED 0x0 +#define TLM_BYTE_ENABLED 0xff + +//--------------------------------------------------------------------------- +// The generic payload class: +//--------------------------------------------------------------------------- +class tlm_generic_payload { + +public: + //--------------- + // Constructors + //--------------- + + // Default constructor + tlm_generic_payload() + : m_address(0) + , m_command(TLM_IGNORE_COMMAND) + , m_data(0) + , m_length(0) + , m_response_status(TLM_INCOMPLETE_RESPONSE) + , m_dmi(false) + , m_byte_enable(0) + , m_byte_enable_length(0) + , m_streaming_width(0) + , m_gp_option(TLM_MIN_PAYLOAD) + , m_extensions(max_num_extensions()) + , m_mm(0) + , m_ref_count(0) + { + } + + explicit tlm_generic_payload(tlm_mm_interface* mm) + : m_address(0) + , m_command(TLM_IGNORE_COMMAND) + , m_data(0) + , m_length(0) + , m_response_status(TLM_INCOMPLETE_RESPONSE) + , m_dmi(false) + , m_byte_enable(0) + , m_byte_enable_length(0) + , m_streaming_width(0) + , m_gp_option(TLM_MIN_PAYLOAD) + , m_extensions(max_num_extensions()) + , m_mm(mm) + , m_ref_count(0) + { + } + + void acquire(){assert(m_mm != 0); m_ref_count++;} + void release(){assert(m_mm != 0 && m_ref_count > 0); if (--m_ref_count==0) m_mm->free(this);} + int get_ref_count() const {return m_ref_count;} + void set_mm(tlm_mm_interface* mm) { m_mm = mm; } + bool has_mm() const { return m_mm != 0; } + + void reset(){ + //should the other members be reset too? + m_gp_option = TLM_MIN_PAYLOAD; + m_extensions.free_entire_cache(); + }; + + +private: + //disabled copy ctor and assignment operator. + // Copy constructor + tlm_generic_payload(const tlm_generic_payload& x) + : m_address(x.get_address()) + , m_command(x.get_command()) + , m_data(x.get_data_ptr()) + , m_length(x.get_data_length()) + , m_response_status(x.get_response_status()) + , m_dmi(x.is_dmi_allowed()) + , m_byte_enable(x.get_byte_enable_ptr()) + , m_byte_enable_length(x.get_byte_enable_length()) + , m_streaming_width(x.get_streaming_width()) + , m_gp_option(x.m_gp_option) + , m_extensions(max_num_extensions()) + { + // copy all extensions + for(unsigned int i=0; i<m_extensions.size(); i++) + { + m_extensions[i] = x.get_extension(i); + } + } + + // Assignment operator + tlm_generic_payload& operator= (const tlm_generic_payload& x) + { + m_command = x.get_command(); + m_address = x.get_address(); + m_data = x.get_data_ptr(); + m_length = x.get_data_length(); + m_response_status = x.get_response_status(); + m_byte_enable = x.get_byte_enable_ptr(); + m_byte_enable_length = x.get_byte_enable_length(); + m_streaming_width = x.get_streaming_width(); + m_gp_option = x.get_gp_option(); + m_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); + } +public: + // non-virtual deep-copying of the object + void deep_copy_from(const tlm_generic_payload & other) + { + m_command = other.get_command(); + m_address = other.get_address(); + m_length = other.get_data_length(); + m_response_status = other.get_response_status(); + m_byte_enable_length = other.get_byte_enable_length(); + m_streaming_width = other.get_streaming_width(); + m_gp_option = other.get_gp_option(); + m_dmi = other.is_dmi_allowed(); + + // deep copy data + // there must be enough space in the target transaction! + if(m_data && other.m_data) + { + memcpy(m_data, other.m_data, m_length); + } + // deep copy byte enables + // there must be enough space in the target transaction! + if(m_byte_enable && other.m_byte_enable) + { + memcpy(m_byte_enable, other.m_byte_enable, m_byte_enable_length); + } + // deep copy extensions (sticky and non-sticky) + for(unsigned int i=0; i<other.m_extensions.size(); i++) + { + if(other.m_extensions[i]) + { //original has extension i + if(!m_extensions[i]) + { //We don't: clone. + tlm_extension_base *ext = other.m_extensions[i]->clone(); + if(ext) //extension may not be clonable. + { + if(has_mm()) + { //mm can take care of removing cloned extensions + set_auto_extension(i, ext); + } + else + { // no mm, user will call free_all_extensions(). + set_extension(i, ext); + } + } + } + else + { //We already have such extension. Copy original over it. + m_extensions[i]->copy_from(*other.m_extensions[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_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 + m_response_status = other.get_response_status(); + m_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() && m_data && other.m_data && m_data != other.m_data) + { + if (m_byte_enable && use_byte_enable_on_read) + { + if (m_byte_enable_length == 8 && m_length % 8 == 0 ) + { + // Optimized implementation copies 64-bit words by masking + for (unsigned int i = 0; i < m_length; i += 8) + { + typedef sc_dt::uint64* u; + *reinterpret_cast<u>(&m_data[i]) &= ~*reinterpret_cast<u>(m_byte_enable); + *reinterpret_cast<u>(&m_data[i]) |= *reinterpret_cast<u>(&other.m_data[i]) & + *reinterpret_cast<u>(m_byte_enable); + } + } + else if (m_byte_enable_length == 4 && m_length % 4 == 0 ) + { + // Optimized implementation copies 32-bit words by masking + for (unsigned int i = 0; i < m_length; i += 4) + { + typedef unsigned int* u; + *reinterpret_cast<u>(&m_data[i]) &= ~*reinterpret_cast<u>(m_byte_enable); + *reinterpret_cast<u>(&m_data[i]) |= *reinterpret_cast<u>(&other.m_data[i]) & + *reinterpret_cast<u>(m_byte_enable); + } + } + else + // Unoptimized implementation + for (unsigned int i = 0; i < m_length; i++) + if ( m_byte_enable[i % m_byte_enable_length] ) + m_data[i] = other.m_data[i]; + } + else + memcpy(m_data, other.m_data, m_length); + } + } + + void update_extensions_from(const tlm_generic_payload & other) + { + // deep copy extensions that are already present + for(unsigned int i=0; i<other.m_extensions.size(); i++) + { + if(other.m_extensions[i]) + { //original has extension i + if(m_extensions[i]) + { //We have it too. copy. + m_extensions[i]->copy_from(*other.m_extensions[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_generic_payload() { + for(unsigned int i=0; i<m_extensions.size(); i++) + if(m_extensions[i]) m_extensions[i]->free(); + } + + //---------------- + // API (including setters & getters) + //--------------- + + // Command related method + bool is_read() const {return (m_command == TLM_READ_COMMAND);} + void set_read() {m_command = TLM_READ_COMMAND;} + bool is_write() const {return (m_command == TLM_WRITE_COMMAND);} + void set_write() {m_command = TLM_WRITE_COMMAND;} + tlm_command get_command() const {return m_command;} + void set_command(const tlm_command command) {m_command = command;} + + // Address related methods + sc_dt::uint64 get_address() const {return m_address;} + void set_address(const sc_dt::uint64 address) {m_address = address;} + + // Data related methods + unsigned char* get_data_ptr() const {return m_data;} + void set_data_ptr(unsigned char* data) {m_data = data;} + + // Transaction length (in bytes) related methods + unsigned int get_data_length() const {return m_length;} + void set_data_length(const unsigned int length) {m_length = length;} + + // Response status related methods + bool is_response_ok() const {return (m_response_status > 0);} + bool is_response_error() const {return (m_response_status <= 0);} + tlm_response_status get_response_status() const {return m_response_status;} + void set_response_status(const tlm_response_status response_status) + {m_response_status = response_status;} + std::string get_response_string() const + { + switch(m_response_status) + { + case TLM_OK_RESPONSE: return "TLM_OK_RESPONSE"; + case TLM_INCOMPLETE_RESPONSE: return "TLM_INCOMPLETE_RESPONSE"; + case TLM_GENERIC_ERROR_RESPONSE: return "TLM_GENERIC_ERROR_RESPONSE"; + case TLM_ADDRESS_ERROR_RESPONSE: return "TLM_ADDRESS_ERROR_RESPONSE"; + case TLM_COMMAND_ERROR_RESPONSE: return "TLM_COMMAND_ERROR_RESPONSE"; + case TLM_BURST_ERROR_RESPONSE: return "TLM_BURST_ERROR_RESPONSE"; + case 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 m_streaming_width;} + void set_streaming_width(const unsigned int streaming_width) {m_streaming_width = streaming_width; } + + // Byte enable related methods + unsigned char* get_byte_enable_ptr() const {return m_byte_enable;} + void set_byte_enable_ptr(unsigned char* byte_enable){m_byte_enable = byte_enable;} + unsigned int get_byte_enable_length() const {return m_byte_enable_length;} + void set_byte_enable_length(const unsigned int byte_enable_length){m_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) { m_dmi = dmi_allowed; } + bool is_dmi_allowed() const { return m_dmi; } + + // Use full set of attributes in DMI/debug? + tlm_gp_option get_gp_option() const { return m_gp_option; } + void set_gp_option( const tlm_gp_option gp_opt ) { m_gp_option = gp_opt; } + +private: + + /* --------------------------------------------------------------------- */ + /* 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 m_address; + tlm_command m_command; + unsigned char* m_data; + unsigned int m_length; + tlm_response_status m_response_status; + bool m_dmi; + unsigned char* m_byte_enable; + unsigned int m_byte_enable_length; + unsigned int m_streaming_width; + tlm_gp_option m_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<my_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 <typename T> T* set_extension(T* ext) + { + return static_cast<T*>(set_extension(T::ID, ext)); + } + + // non-templatized version with manual index: + tlm_extension_base* set_extension(unsigned int index, + tlm_extension_base* ext) + { + tlm_extension_base* tmp = m_extensions[index]; + m_extensions[index] = ext; + return tmp; + } + + // Stick the pointer to an extension into the vector, return the + // previous value and schedule its release + template <typename T> T* set_auto_extension(T* ext) + { + return static_cast<T*>(set_auto_extension(T::ID, ext)); + } + + // non-templatized version with manual index: + tlm_extension_base* set_auto_extension(unsigned int index, + tlm_extension_base* ext) + { + tlm_extension_base* tmp = m_extensions[index]; + m_extensions[index] = ext; + if (!tmp) m_extensions.insert_in_cache(&m_extensions[index]); + assert(m_mm != 0); + return tmp; + } + + // Check for an extension, ext will point to 0 if not present + template <typename T> void get_extension(T*& ext) const + { + ext = get_extension<T>(); + } + template <typename T> T* get_extension() const + { + return static_cast<T*>(get_extension(T::ID)); + } + // Non-templatized version with manual index: + 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 <typename T> void clear_extension(const T* ext) + { + clear_extension<T>(); + } + + //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 <typename T> 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 <typename T> void release_extension(T* ext) + { + release_extension<T>(); + } + + //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 <typename T> 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<tlm_extension_base*>(0); + } + // Non-templatized version with manual index + void release_extension(unsigned int index) + { + if (m_mm) + { + m_extensions.insert_in_cache(&m_extensions[index]); + } + else + { + m_extensions[index]->free(); + m_extensions[index] = static_cast<tlm_extension_base*>(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(max_num_extensions()); + } + +private: + tlm_array<tlm_extension_base*> m_extensions; + tlm_mm_interface* m_mm; + unsigned int m_ref_count; +}; + +} // namespace tlm + +#endif /* __TLM_GP_H__ */ |