diff options
Diffstat (limited to 'src/systemc/ext/tlm_core/2/generic_payload/endian_conv.hh')
-rw-r--r-- | src/systemc/ext/tlm_core/2/generic_payload/endian_conv.hh | 941 |
1 files changed, 941 insertions, 0 deletions
diff --git a/src/systemc/ext/tlm_core/2/generic_payload/endian_conv.hh b/src/systemc/ext/tlm_core/2/generic_payload/endian_conv.hh new file mode 100644 index 000000000..07dcef74c --- /dev/null +++ b/src/systemc/ext/tlm_core/2/generic_payload/endian_conv.hh @@ -0,0 +1,941 @@ +/***************************************************************************** + + 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. + + *****************************************************************************/ + + +#ifndef __SYSTEMC_EXT_TLM_CORE_2_GENERIC_PAYLOAD_ENDIAN_CONV_HH__ +#define __SYSTEMC_EXT_TLM_CORE_2_GENERIC_PAYLOAD_ENDIAN_CONV_HH__ + +#include <cstring> // std::memset + +#include "tlm_core/2/generic_payload/gp.hh" + +namespace tlm +{ + +/* +Tranaction-Level Modelling +Endianness Helper Functions + +DESCRIPTION +A set of functions for helping users to get the endianness +right in their TLM models of system initiators. These functions are +for use within an initiator. They can not be used as-is outside +an initiator because the extension used to store context will not work +if cascaded, and they do not respect the generic payload mutability +rules. However this code may be easily copied and adapted for use +in bridges, etc.. + +These functions are not compulsory. There are other legitimate ways to +achieve the same functionality. If extra information is available at +compile time about the nature of an initiator's transactions, this can +be exploited to accelerate simulations by creating further functions +similar to those in this file. In general a functional transaction can be +described in more than one way by a TLM-2 GP object. + +The functions convert the endianness of a GP object, either on request or +response. They should only be used when the initiator's endianness +does not match the host's endianness. They assume 'arithmetic mode' +meaning that within a data word the byte order is always host-endian. +For non-arithmetic mode initiators they can be used with a data word +size of 1 byte. + +All the functions are templates, for example: + +template<class DATAWORD> inline void + to_hostendian_generic(tlm_generic_payload *txn, int sizeof_databus) + +The template parameter provides the data word width. Having this as a class +makes it easy to use it for copy and swap operations within the functions. +If the assignment operator for this class is overloaded, the endianness +conversion function may not have the desired effect. + +All the functions have the same signature except for different names. + +The principle is that a function to_hostendian_convtype() is called when the +initiator-endian transaction is created, and the matching function +from_hostendian_convtype() is called when the transaction is completed, for +example before read data can be used. In some cases the from_ function is +redundant but an empty function is provided anyway. It is strongly +recommended that the from_ function is called, in case it ceases to be +redundant in future versions of this code. + +No context needs to be managed outside the two functions, except that they +must be called with the same template parameter and the same bus width. + +For initiator models that can not easily manage this context information, +a single entry point for the from_ function is provided, which will be +a little slower than calling the correct from_ function directly, as +it can not be inlined. + +All functions assume power-of-2 bus and data word widths. + +Functions offered: + +0) A pair of functions that work for almost all TLM2 GP transactions. The +only limitations are that data and bus widths should be powers of 2, and that +the data length should be an integer number of streaming widths and that the +streaming width should be an integer number of data words. +These functions always allocate new data and byte enable buffers and copy +data one byte at a time. + tlm_to_hostendian_generic(tlm_generic_payload *txn, int sizeof_databus) + tlm_from_hostendian_generic(tlm_generic_payload *txn, int sizeof_databus) + +1) A pair of functions that work for all transactions regardless of data and +bus data sizes and address alignment except for the the following +limitations: +- byte-enables are supported only when byte-enable granularity is no finer +than the data word (every data word is wholly enabled or wholly disabled) +- byte-enable-length is not supported (if byte enables are present, the byte +enable length must be equal to the data length). +- streaming width is not supported +- data word wider than bus word is not supported +A new data buffer and a new byte enable buffer are always allocated. Byte +enables are assumed to be needed even if not required for the original +(unconverted) transaction. Data is copied to the new buffer on request +(for writes) or on response (for reads). Copies are done word-by-word +where possible. + tlm_to_hostendian_word(tlm_generic_payload *txn, int sizeof_databus) + tlm_from_hostendian_word(tlm_generic_payload *txn, int sizeof_databus) + +2) If the original transaction is both word and bus-aligned then this pair of +functions can be used. It will complete faster than the generic function +because the data reordering function is much simpler and no address +conversion is required. +The following limitations apply: +- byte-enables are supported only when byte-enable granularity is no finer +than the data word (every data word is wholly enabled or wholly disabled) +- byte-enable-length is not supported (if byte enables are present, the byte +enable length must be equal to the data length). +- streaming width is not supported +- data word wider than bus word is not supported +- the transaction must be an integer number of bus words +- the address must be aligned to the bus width + tlm_to_hostendian_aligned(tlm_generic_payload *txn, int sizeof_databus) + tlm_from_hostendian_aligned(tlm_generic_payload *txn, int sizeof_databus) + +3) For single word transactions that don't cross a bus word boundary it +is always safe to work in-place and the conversion is very simple. Again, +streaming width and byte-enable length are not supported, and byte-enables +may not changes within a data word. + tlm_to_hostendian_single(tlm_generic_payload *txn, int sizeof_databus) + tlm_from_hostendian_single(tlm_generic_payload *txn, int sizeof_databus) + +4) A single entry point for accessing the correct from_ function without +needing to store context. + tlm_from_hostendian(tlm_generic_payload *txn) +*/ + +/////////////////////////////////////////////////////////////////////////////// +// Generic Utilities + +class tlm_endian_context; + +class tlm_endian_context_pool +{ + public: + tlm_endian_context *first; + inline tlm_endian_context_pool(); + inline ~tlm_endian_context_pool(); + inline tlm_endian_context *pop(); + inline void push(tlm_endian_context *c); +}; + +static tlm_endian_context_pool global_tlm_endian_context_pool; + +// an extension to keep the information needed for reconversion of response +class tlm_endian_context : public tlm_extension<tlm_endian_context> +{ + public: + tlm_endian_context() : dbuf_size(0), bebuf_size(0) {} + + ~tlm_endian_context() { + if (dbuf_size > 0) + delete [] new_dbuf; + if (bebuf_size > 0) + delete [] new_bebuf; + } + + sc_dt::uint64 address; // Used by generic, word. + sc_dt::uint64 new_address; // Used by generic. + unsigned char *data_ptr; // Used by generic, word, aligned. + unsigned char *byte_enable; // Used by word. + int length; // Used by generic, word. + int stream_width; // Used by generic. + + // Used by common entry point on response. + void (*from_f)(tlm_generic_payload *txn, unsigned int sizeof_databus); + int sizeof_databus; + + // Reordering buffers for data and byte-enables. + unsigned char *new_dbuf, *new_bebuf; + int dbuf_size, bebuf_size; + + void + establish_dbuf(int len) + { + if (len <= dbuf_size) + return; + if (dbuf_size > 0) + delete [] new_dbuf; + new_dbuf = new unsigned char[len]; + dbuf_size = len; + } + + void + establish_bebuf(int len) + { + if (len <= bebuf_size) + return; + if (bebuf_size > 0) + delete [] new_bebuf; + new_bebuf = new unsigned char[len]; + bebuf_size = len; + } + + // Required for extension management. + void free() { global_tlm_endian_context_pool.push(this); } + tlm_extension_base *clone() const { return 0; } + void copy_from(tlm_extension_base const &) { return; } + + // For pooling. + tlm_endian_context *next; +}; + +// Assumptions about transaction contexts: +// 1) only the address attribute of a transaction +// is mutable. all other attributes are unchanged from the request to +// response side conversion. +// 2) the conversion functions in this file do not respect the mutability +// rules and do not put the transaction back into its original state after +// completion. so if the initiator has any cleaning up to do (eg of byte +// enable buffers), it needs to store its own context. the transaction +// returned to the initiator may contain pointers to data and byte enable +// that can/must not be deleted. +// 3) the conversion functions in this file use an extension to store +// context information. they do not remove this extension. the initiator +// should not remove it unless it deletes the generic payload +// object. + +inline tlm_endian_context * +establish_context(tlm_generic_payload *txn) +{ + tlm_endian_context *tc = txn->get_extension<tlm_endian_context>(); + if (tc == 0) { + tc = global_tlm_endian_context_pool.pop(); + txn->set_extension(tc); + } + return tc; +} + +inline tlm_endian_context_pool::tlm_endian_context_pool() : first(0) {} + +inline tlm_endian_context_pool::~tlm_endian_context_pool() +{ + while (first != 0) { + tlm_endian_context *next = first->next; + delete first; + first = next; + } +} + +tlm_endian_context * +tlm_endian_context_pool::pop() +{ + if (first == 0) + return new tlm_endian_context; + tlm_endian_context *r = first; + first = first->next; + return r; +} + +void tlm_endian_context_pool::push(tlm_endian_context *c) +{ + c->next = first; + first = c; +} + + +// A set of constants for efficient filling of byte enables. +template <class D> +class tlm_bool +{ + public: + static D TLM_TRUE; + static D TLM_FALSE; + static D + make_uchar_array(unsigned char c) + { + D d; + unsigned char *tmp = (unsigned char *)(&d); + for (ptrdiff_t i = 0; i != sizeof(D); i++) + tmp[i] = c; // 64BITFIX negligable risk but easy fix. + return d; + } + + // Also provides an syntax-efficient tester, using a + // copy constuctor and an implicit cast to boolean. + tlm_bool(D &d) : b(*((unsigned char *)&d) != TLM_BYTE_DISABLED) {} + operator bool() const { return b; } + private: + bool b; +}; + +template<class D> +D tlm_bool<D>::TLM_TRUE = tlm_bool<D>::make_uchar_array(TLM_BYTE_ENABLED); +template<class D> +D tlm_bool<D>::TLM_FALSE = tlm_bool<D>::make_uchar_array(TLM_BYTE_DISABLED); + + + +inline void +copy_db0(unsigned char *src1, unsigned char *src2, + unsigned char *dest1, unsigned char *dest2) +{ + *dest1 = *src1; + *dest2 = *src2; +} + +inline void +copy_dbtrue0(unsigned char *src1, unsigned char * /* src2 */, + unsigned char *dest1, unsigned char *dest2) +{ + *dest1 = *src1; + *dest2 = TLM_BYTE_ENABLED; +} + +inline void +copy_btrue0(unsigned char * /* src1 */, unsigned char * /* src2 */, + unsigned char * /* dest1 */, unsigned char *dest2) +{ + *dest2 = TLM_BYTE_ENABLED; +} + +inline void +copy_b0(unsigned char * /* src1 */, unsigned char *src2, + unsigned char * /* dest1 */, unsigned char *dest2) +{ + *dest2 = *src2; +} + +inline void +copy_dbyb0(unsigned char *src1, unsigned char * /* src2 */, + unsigned char *dest1, unsigned char *dest2) +{ + if (*dest2 == TLM_BYTE_ENABLED) + *src1 = *dest1; +} + + +template <class D, + void COPY(unsigned char *he_d, unsigned char *he_b, + unsigned char *ie_d, unsigned char *ie_b)> +inline void +loop_generic0(int new_len, int new_stream_width, int orig_stream_width, + int sizeof_databus, sc_dt::uint64 orig_start_address, + sc_dt::uint64 new_start_address, int be_length, + unsigned char *ie_data, unsigned char *ie_be, + unsigned char *he_data, unsigned char *he_be) +{ + for (int orig_sword = 0, new_sword = 0; new_sword < new_len; + new_sword += new_stream_width, orig_sword += orig_stream_width) { + sc_dt::uint64 ie_addr = orig_start_address; + for (int orig_dword = orig_sword; + orig_dword < orig_sword + orig_stream_width; + orig_dword += sizeof(D)) { + for (int curr_byte = orig_dword + sizeof(D) - 1; + curr_byte >= orig_dword; curr_byte--) { + ptrdiff_t he_index = ((ie_addr++) ^ (sizeof_databus - 1)) - + new_start_address + new_sword; // 64BITFIX + COPY(ie_data + curr_byte, + // 64BITRISK no risk of overflow, always positive. + ie_be + (curr_byte % be_length), + he_data + he_index, he_be + he_index); + } + } + } +} + + +/////////////////////////////////////////////////////////////////////////////// +// function set (0): Response +/////////////////////////////////////////////////////////////////////////////// + +template <class DATAWORD> +inline void +tlm_from_hostendian_generic(tlm_generic_payload *txn, + unsigned int sizeof_databus) +{ + if (txn->is_read()) { + tlm_endian_context *tc = + txn->template get_extension<tlm_endian_context>(); + loop_generic0<DATAWORD, ©_dbyb0>(txn->get_data_length(), + txn->get_streaming_width(), tc->stream_width, sizeof_databus, + tc->address, tc->new_address, txn->get_data_length(), + tc->data_ptr, 0, txn->get_data_ptr(), + txn->get_byte_enable_ptr()); + } +} + + +/////////////////////////////////////////////////////////////////////////////// +// function set (0): Request +template <class DATAWORD> +inline void +tlm_to_hostendian_generic(tlm_generic_payload *txn, + unsigned int sizeof_databus) +{ + tlm_endian_context *tc = establish_context(txn); + tc->from_f = &(tlm_from_hostendian_generic<DATAWORD>); + tc->sizeof_databus = sizeof_databus; + + // Calculate new size: nr stream words multiplied by big enough stream + // width. + int s_width = txn->get_streaming_width(); + int length = txn->get_data_length(); + if (s_width >= length) + s_width = length; + int nr_stream_words = length / s_width; + + // Find out in which bus word the stream word starts and ends. + sc_dt::uint64 new_address = (txn->get_address() & ~(sizeof_databus - 1)); + sc_dt::uint64 end_address = ((txn->get_address() + s_width - 1) & + ~(sizeof_databus - 1)); + + int new_stream_width = end_address - new_address + sizeof_databus; + int new_length = new_stream_width * nr_stream_words; + + // Store context. + tc->data_ptr = txn->get_data_ptr(); + tc->address = txn->get_address(); + tc->new_address = new_address; + tc->stream_width = s_width; + unsigned char *orig_be = txn->get_byte_enable_ptr(); + int orig_be_length = txn->get_byte_enable_length(); + + // Create data and byte-enable buffers. + txn->set_address(new_address); + tc->establish_dbuf(new_length); + txn->set_data_ptr(tc->new_dbuf); + tc->establish_bebuf(new_length); + txn->set_byte_enable_ptr(tc->new_bebuf); + std::memset(txn->get_byte_enable_ptr(), TLM_BYTE_DISABLED, new_length); + txn->set_streaming_width(new_stream_width); + txn->set_data_length(new_length); + txn->set_byte_enable_length(new_length); + + // Copy data and/or byte enables. + if (txn->is_write()) { + if (orig_be == 0) { + loop_generic0<DATAWORD, ©_dbtrue0>( + new_length, new_stream_width, s_width, sizeof_databus, + tc->address, new_address, new_length, tc->data_ptr, 0, + txn->get_data_ptr(), txn->get_byte_enable_ptr()); + } else { + loop_generic0<DATAWORD, ©_db0>(new_length, new_stream_width, + s_width, sizeof_databus, tc->address, new_address, + orig_be_length, tc->data_ptr, orig_be, + txn->get_data_ptr(), txn->get_byte_enable_ptr()); + } + } else { + // Read transaction. + if (orig_be == 0) { + loop_generic0<DATAWORD, ©_btrue0>(new_length, + new_stream_width, s_width, sizeof_databus, tc->address, + new_address, new_length, tc->data_ptr, 0, + txn->get_data_ptr(), txn->get_byte_enable_ptr()); + } else { + loop_generic0<DATAWORD, ©_b0>(new_length, new_stream_width, + s_width, sizeof_databus, tc->address, new_address, + orig_be_length, tc->data_ptr, orig_be, + txn->get_data_ptr(), txn->get_byte_enable_ptr()); + } + } +} + + +/////////////////////////////////////////////////////////////////////////////// +// function set (1): Utilities +/////////////////////////////////////////////////////////////////////////////// + +template <class D> +inline void +copy_d1(unsigned char *src1, unsigned char *src2, + unsigned char *dest1, unsigned char *dest2) +{ + *((D *)dest1) = *((D *)src1); + *((D *)dest2) = tlm_bool<D>::TLM_TRUE; +} + +template <class D> +inline void +copy_db1(unsigned char *src1, unsigned char *src2, + unsigned char *dest1, unsigned char *dest2) +{ + *((D *)dest1) = *((D *)src1); + *((D *)dest2) = *((D *)src2); +} + +template <class D> +inline void +true_b1(unsigned char *src1, unsigned char *src2, + unsigned char *dest1, unsigned char *dest2) +{ + *((D *)dest2) = tlm_bool<D>::TLM_TRUE; +} + +template <class D> +inline void +copy_b1(unsigned char *src1, unsigned char *src2, + unsigned char *dest1, unsigned char *dest2) +{ + *((D *)dest2) = *((D *)src2); +} + +template <class D> +inline void +copy_dbyb1(unsigned char *src1, unsigned char *src2, + unsigned char *dest1, unsigned char *dest2) +{ + if (*src2 != TLM_BYTE_DISABLED) + *((D *)src1) = *((D *)dest1); +} + +template <class D> +inline void +copy_dbytrue1(unsigned char *src1, unsigned char *src2, + unsigned char *dest1, unsigned char *dest2) +{ + *((D *)src1) = *((D *)dest1); +} + +template<class D> +inline void +false_b1(unsigned char *dest1) +{ + *((D *)dest1) = tlm_bool<D>::TLM_FALSE; +} + +template<class D> +inline void +no_b1(unsigned char *dest1) +{} + +template<class D, + void COPY(unsigned char *src1, unsigned char *src2, + unsigned char *dest1, unsigned char *dest2), + void COPYuchar(unsigned char *src1, unsigned char *src2, + unsigned char *dest1, unsigned char *dest2), + void FILLFALSE(unsigned char *dest1), + void FILLFALSEuchar(unsigned char *dest1)> +inline int +loop_word1(int bytes_left, int len0, int lenN, int sizeof_databus, + unsigned char *start, unsigned char *end, + unsigned char *src, unsigned char *bsrc, + unsigned char *dest, unsigned char *bdest) +{ + ptrdiff_t d2b_src = bsrc - src; // 64BITFIX was int + ptrdiff_t d2b_dest = bdest - dest; // 64BITFIX was int + unsigned char *original_dest = dest; + + while (true) { + // len0 bytes at start of a bus word. + if ((src >= start) && (src < end)) { + for (int i = 0; i < len0; i++) { + COPYuchar(src, src + d2b_src, dest, dest + d2b_dest); + src++; + dest++; + } + bytes_left -= len0; + if (bytes_left <= 0) + return int(dest - original_dest); + } else { + for (int i = 0; i < len0; i++) { + FILLFALSEuchar(dest + d2b_dest); + src++; + dest++; + } + } + src -= 2 * sizeof(D); + + // Sequence of full data word fragments. + for (unsigned int i = 1; i < sizeof_databus / sizeof(D); i++) { + if ((src >= start) && (src < end)) { + COPY(src, src + d2b_src, dest, dest + d2b_dest); + bytes_left -= sizeof(D); + } else { + FILLFALSE(dest + d2b_dest); + } + dest += sizeof(D); + if (bytes_left <= 0) + return int(dest - original_dest); + src -= sizeof(D); + } + + // lenN bytes at end of bus word. + if ((src >= start) && (src < end)) { + for (int i = 0; i < lenN; i++) { + COPYuchar(src, src + d2b_src, dest, dest + d2b_dest); + src++; + dest++; + } + bytes_left -= lenN; + if (bytes_left <= 0) + return int(dest - original_dest); + } else { + for (int i = 0; i < lenN; i++) { + FILLFALSEuchar(dest + d2b_dest); + src++; + dest++; + } + } + src += 2 * sizeof_databus; + } +} + + +/////////////////////////////////////////////////////////////////////////////// +// function set (1): Response +/////////////////////////////////////////////////////////////////////////////// + +template <class DATAWORD> +inline void +tlm_from_hostendian_word(tlm_generic_payload *txn, unsigned int sizeof_databus) +{ + if (txn->is_read()) { + tlm_endian_context *tc = + txn->template get_extension<tlm_endian_context>(); + sc_dt::uint64 b_mask = sizeof_databus - 1; + int d_mask = sizeof(DATAWORD) - 1; + int a_offset = static_cast<int>(tc->address & b_mask); + int len0 = (sizeof_databus - a_offset) & d_mask; + int lenN = sizeof(DATAWORD) - len0; + unsigned char *d_start = tc->data_ptr; + unsigned char *d_end = + ptrdiff_t(tc->length) + d_start; // 64BITFIX probably redundant + unsigned char *d = + ptrdiff_t(((sizeof_databus - a_offset) & ~d_mask) + lenN) + + d_start; // 64BITFIX probably redundant + + // Iterate over transaction copying data qualified by byte-enables. + if (tc->byte_enable == 0) { + loop_word1<DATAWORD, ©_dbytrue1<DATAWORD>, + ©_dbytrue1<unsigned char>, &no_b1<DATAWORD>, + &no_b1<unsigned char>>( + tc->length, len0, lenN, sizeof_databus, + d_start, d_end, d, 0, txn->get_data_ptr(), 0); + } else { + loop_word1<DATAWORD, ©_dbyb1<DATAWORD>, + ©_dbyb1<unsigned char>, &no_b1<DATAWORD>, + &no_b1<unsigned char>>( + tc->length, len0, lenN, sizeof_databus, + d_start, d_end, d, + tc->byte_enable - d_start + d, + txn->get_data_ptr(), 0); + } + } +} + + +/////////////////////////////////////////////////////////////////////////////// +// function set (1): Request +/////////////////////////////////////////////////////////////////////////////// + +template <class DATAWORD> +inline void +tlm_to_hostendian_word(tlm_generic_payload *txn, unsigned int sizeof_databus) +{ + tlm_endian_context *tc = establish_context(txn); + tc->from_f = &(tlm_from_hostendian_word<DATAWORD>); + tc->sizeof_databus = sizeof_databus; + + sc_dt::uint64 b_mask = sizeof_databus - 1; + int d_mask = sizeof(DATAWORD) - 1; + sc_dt::uint64 a_aligned = txn->get_address() & ~b_mask; + int a_offset = static_cast<int>(txn->get_address() & b_mask); + int len0 = (sizeof_databus - a_offset) & d_mask; + int lenN = sizeof(DATAWORD) - len0; + unsigned char *d_start = txn->get_data_ptr(); + unsigned char *d_end = + ptrdiff_t(txn->get_data_length()) + d_start; + // 64BITFIX probably redundant. + unsigned char *d = + ptrdiff_t(((sizeof_databus - a_offset) & ~d_mask) + lenN) + d_start; + // 64BITFIX probably redundant. + + // Create new data and byte enable buffers. + int long_enough = txn->get_data_length() + 2 * sizeof_databus; + tc->establish_dbuf(long_enough); + unsigned char *new_data = tc->new_dbuf; + tc->establish_bebuf(long_enough); + unsigned char *new_be = tc->new_bebuf; + + if (txn->is_read()) { + tc->data_ptr = d_start; + tc->address = txn->get_address(); + tc->byte_enable = txn->get_byte_enable_ptr(); + tc->length = txn->get_data_length(); + if (txn->get_byte_enable_ptr() == 0) { + // Iterate over transaction creating new byte enables from all-true + txn->set_data_length( + loop_word1<DATAWORD, &true_b1<DATAWORD>, + &true_b1<unsigned char>, &false_b1<DATAWORD>, + &false_b1<unsigned char>>( + txn->get_data_length(), len0, lenN, + sizeof_databus, d_start, d_end, d, 0, + new_data, new_be)); + } else { + // iterate over transaction copying byte enables + txn->set_data_length( + loop_word1<DATAWORD, ©_b1<DATAWORD>, + ©_b1<unsigned char>, &false_b1<DATAWORD>, + &false_b1<unsigned char>>( + txn->get_data_length(), len0, lenN, + sizeof_databus, d_start, d_end, d, + txn->get_byte_enable_ptr() - d_start + d, + new_data, new_be)); + } + } else { + // WRITE + if (txn->get_byte_enable_ptr() == 0) { + // Iterate over transaction copying data and creating new + // byte-enables. + txn->set_data_length( + loop_word1<DATAWORD, ©_d1<DATAWORD>, + ©_d1<unsigned char>, &false_b1<DATAWORD>, + &false_b1<unsigned char>>( + txn->get_data_length(), len0, lenN, + sizeof_databus, d_start, d_end, d, 0, + new_data, new_be)); + } else { + // Iterate over transaction copying data and byte-enables. + txn->set_data_length( + loop_word1<DATAWORD, ©_db1<DATAWORD>, + ©_db1<unsigned char>, &false_b1<DATAWORD>, + &false_b1<unsigned char>>( + txn->get_data_length(), len0, lenN, + sizeof_databus, d_start, d_end, d, + txn->get_byte_enable_ptr() - d_start + d, + new_data, new_be)); + } + } + txn->set_byte_enable_length(txn->get_data_length()); + txn->set_streaming_width(txn->get_data_length()); + txn->set_data_ptr(new_data); + txn->set_byte_enable_ptr(new_be); + txn->set_address(a_aligned); +} + + + +/////////////////////////////////////////////////////////////////////////////// +// function set (2): Utilities +/////////////////////////////////////////////////////////////////////////////// + +template <class D> +inline void copy_d2(D *src1, D *src2, D *dest1, D *dest2) { *dest1 = *src1; } + +template <class D> +inline void +copy_db2(D *src1, D *src2, D *dest1, D *dest2) +{ + *dest1 = *src1; + *dest2 = *src2; +} + +template <class D> +inline void +copy_dbyb2(D *src1, D *src2, D *dest1, D *dest2) +{ + if (tlm_bool<D>(*src2)) + *dest1 = *src1; +} + +template <class D, void COPY(D *src1, D *src2, D *dest1, D *dest2)> +inline void +loop_aligned2(D *src1, D *src2, D *dest1, D *dest2, int words, + int words_per_bus) +{ + // 64BITFIX was int and operands were cast to int. + ptrdiff_t src1to2 = (char *)src2 - (char *)src1; + // 64BITFIX was int and operands were cast to int. + ptrdiff_t dest1to2 = (char *)dest2 - (char *)dest1; + + D *done = src1 + ptrdiff_t(words); // 64BITFIX. + D *bus_start = src1; + src1 += ptrdiff_t(words_per_bus - 1); // 64BITFIX. + + while (true) { + COPY(src1, (D *)(src1to2 + (char *)src1), dest1, + (D *)(dest1to2 + (char *)dest1)); // 64BITFIX. + dest1++; + if ((--src1) < bus_start) { + bus_start += ptrdiff_t(words_per_bus); // 64BITFIX. + if (bus_start == done) + break; + src1 = bus_start + ptrdiff_t(words_per_bus - 1); // 64BITFIX. + } + } +} + + +/////////////////////////////////////////////////////////////////////////////// +// function set (2): Response +/////////////////////////////////////////////////////////////////////////////// + +template <class DATAWORD> +inline void +tlm_from_hostendian_aligned( + tlm_generic_payload *txn, unsigned int sizeof_databus) +{ + int words_per_bus = sizeof_databus / sizeof(DATAWORD); + if (words_per_bus == 1) + return; + int words = (txn->get_data_length()) / sizeof(DATAWORD); + tlm_endian_context *tc = txn->template get_extension<tlm_endian_context>(); + + if (txn->get_byte_enable_ptr() == 0) { + // no byte enables + if (txn->is_read()) { + // RD without byte enables. Copy data to original buffer. + loop_aligned2<DATAWORD, ©_d2<DATAWORD>>( + (DATAWORD *)(txn->get_data_ptr()), 0, + (DATAWORD *)(tc->data_ptr), 0, words, words_per_bus); + } + } else { + // byte enables present + if (txn->is_read()) { + // RD with byte enables. Copy data qualified by byte-enables. + loop_aligned2<DATAWORD, ©_dbyb2<DATAWORD>>( + (DATAWORD *)(txn->get_data_ptr()), + (DATAWORD *)(txn->get_byte_enable_ptr()), + (DATAWORD *)(tc->data_ptr), 0, words, words_per_bus); + } + } +} + + +/////////////////////////////////////////////////////////////////////////////// +// function set (2): Request +/////////////////////////////////////////////////////////////////////////////// + +template <class DATAWORD> +inline void +tlm_to_hostendian_aligned( + tlm_generic_payload *txn, unsigned int sizeof_databus) +{ + tlm_endian_context *tc = establish_context(txn); + tc->from_f = &(tlm_from_hostendian_aligned<DATAWORD>); + tc->sizeof_databus = sizeof_databus; + + int words_per_bus = sizeof_databus / sizeof(DATAWORD); + if (words_per_bus == 1) + return; + int words = (txn->get_data_length()) / sizeof(DATAWORD); + + DATAWORD *original_be = (DATAWORD *)(txn->get_byte_enable_ptr()); + DATAWORD *original_data = (DATAWORD *)(txn->get_data_ptr()); + + // Always allocate a new data buffer. + tc->establish_dbuf(txn->get_data_length()); + txn->set_data_ptr(tc->new_dbuf); + + if (original_be == 0) { + // No byte enables. + if (txn->is_write()) { + // WR no byte enables. Copy data. + loop_aligned2<DATAWORD, ©_d2<DATAWORD>>( + original_data, 0, (DATAWORD *)(txn->get_data_ptr()), 0, + words, words_per_bus); + } else { + // RD no byte enables. Save original data pointer. + tc->data_ptr = (unsigned char *)original_data; + } + } else { + // Byte enables present. + // Allocate a new buffer for them. + tc->establish_bebuf(txn->get_data_length()); + txn->set_byte_enable_ptr(tc->new_bebuf); + txn->set_byte_enable_length(txn->get_data_length()); + + if (txn->is_write()) { + // WR with byte enables. Copy data and BEs. + loop_aligned2<DATAWORD, ©_db2<DATAWORD>>( + original_data, original_be, + (DATAWORD *)(txn->get_data_ptr()), + (DATAWORD *)(txn->get_byte_enable_ptr()), + words, words_per_bus); + } else { + // RD with byte enables. Save original data pointer. + tc->data_ptr = (unsigned char *)original_data; + // Copy byte enables to new buffer. + loop_aligned2<DATAWORD, ©_d2<DATAWORD>>( + original_be, 0, (DATAWORD *)(txn->get_byte_enable_ptr()), + 0, words, words_per_bus); + } + } +} + + + +/////////////////////////////////////////////////////////////////////////////// +// function set (3): Response +/////////////////////////////////////////////////////////////////////////////// + +template <class DATAWORD> +inline void +tlm_from_hostendian_single( + tlm_generic_payload *txn, unsigned int sizeof_databus) +{} + + +/////////////////////////////////////////////////////////////////////////////// +// function set (3): Request +/////////////////////////////////////////////////////////////////////////////// + +template <class DATAWORD> +inline void +tlm_to_hostendian_single(tlm_generic_payload *txn, unsigned int sizeof_databus) +{ + tlm_endian_context *tc = establish_context(txn); + tc->from_f = &(tlm_from_hostendian_single<DATAWORD>); + tc->sizeof_databus = sizeof_databus; + + // Only need to change the address, always safe to work in-place. + sc_dt::uint64 mask = sizeof_databus - 1; + sc_dt::uint64 a = txn->get_address(); + txn->set_address((a & ~mask) | + (sizeof_databus - (a & mask) - sizeof(DATAWORD))); +} + + + +/////////////////////////////////////////////////////////////////////////////// +// helper function which works for all responses +/////////////////////////////////////////////////////////////////////////////// + +inline void +tlm_from_hostendian(tlm_generic_payload *txn) +{ + tlm_endian_context *tc = txn->get_extension<tlm_endian_context>(); + (*(tc->from_f))(txn, tc->sizeof_databus); +} + +} // namespace tlm + +#endif /* __SYSTEMC_EXT_TLM_CORE_2_GENERIC_PAYLOAD_ENDIAN_CONV_HH__ */ |