summaryrefslogtreecommitdiff
path: root/src/systemc/ext/tlm_core/tlm_2/tlm_generic_payload/tlm_endian_conv.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/systemc/ext/tlm_core/tlm_2/tlm_generic_payload/tlm_endian_conv.h')
-rw-r--r--src/systemc/ext/tlm_core/tlm_2/tlm_generic_payload/tlm_endian_conv.h791
1 files changed, 791 insertions, 0 deletions
diff --git a/src/systemc/ext/tlm_core/tlm_2/tlm_generic_payload/tlm_endian_conv.h b/src/systemc/ext/tlm_core/tlm_2/tlm_generic_payload/tlm_endian_conv.h
new file mode 100644
index 000000000..cf17a1ffb
--- /dev/null
+++ b/src/systemc/ext/tlm_core/tlm_2/tlm_generic_payload/tlm_endian_conv.h
@@ -0,0 +1,791 @@
+/*****************************************************************************
+
+ 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 __TLM_ENDIAN_CONV_H__
+#define __TLM_ENDIAN_CONV_H__
+
+#include "tlm_core/tlm_2/tlm_generic_payload/tlm_gp.h"
+
+#include <cstring> // std::memset
+
+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)
+*/
+
+
+
+#ifndef uchar
+#define uchar unsigned char
+#else
+#define TLM_END_CONV_DONT_UNDEF_UCHAR
+#endif
+
+
+///////////////////////////////////////////////////////////////////////////////
+// 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
+ uchar *data_ptr; // used by generic, word, aligned
+ uchar *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
+ uchar *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 uchar[len];
+ dbuf_size = len;
+ }
+ void establish_bebuf(int len) {
+ if(len <= bebuf_size) return;
+ if(bebuf_size > 0) delete [] new_bebuf;
+ new_bebuf = new uchar[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(uchar c) {
+ D d;
+ uchar *tmp = (uchar *)(&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(*((uchar*)&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);
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// function set (0): Utilities
+inline void copy_db0(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
+ *dest1 = *src1;
+ *dest2 = *src2;
+}
+
+inline void copy_dbtrue0(uchar *src1, uchar * /* src2 */, uchar *dest1, uchar *dest2) {
+ *dest1 = *src1;
+ *dest2 = TLM_BYTE_ENABLED;
+}
+
+inline void copy_btrue0(uchar * /* src1 */, uchar * /* src2 */, uchar * /* dest1 */, uchar *dest2) {
+ *dest2 = TLM_BYTE_ENABLED;
+}
+
+inline void copy_b0(uchar * /* src1 */, uchar *src2, uchar * /* dest1 */, uchar *dest2) {
+ *dest2 = *src2;
+}
+
+inline void copy_dbyb0(uchar *src1, uchar * /* src2 */, uchar *dest1, uchar *dest2) {
+ if(*dest2 == TLM_BYTE_ENABLED) *src1 = *dest1;
+}
+
+
+template<class D,
+ void COPY(uchar *he_d, uchar *he_b, uchar *ie_d, uchar *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,
+ uchar *ie_data, uchar *ie_be, uchar *he_data, uchar *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,
+ ie_be+(curr_byte % be_length), // 64BITRISK no risk of overflow, always positive //
+ 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, &copy_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;
+ uchar *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, &copy_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, &copy_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, &copy_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, &copy_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(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
+ *((D *)dest1) = *((D *)src1);
+ *((D *)dest2) = tlm_bool<D>::TLM_TRUE;
+}
+
+template<class D>
+inline void copy_db1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
+ *((D *)dest1) = *((D *)src1);
+ *((D *)dest2) = *((D *)src2);
+}
+
+template<class D>
+inline void true_b1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
+ *((D *)dest2) = tlm_bool<D>::TLM_TRUE;
+}
+
+template<class D>
+inline void copy_b1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
+ *((D *)dest2) = *((D *)src2);
+}
+
+template<class D>
+inline void copy_dbyb1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
+ if(*src2 != TLM_BYTE_DISABLED) *((D *)src1) = *((D *)dest1);
+}
+
+template<class D>
+inline void copy_dbytrue1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
+ *((D *)src1) = *((D *)dest1);
+}
+
+template<class D> inline void false_b1(uchar *dest1) {
+ *((D *)dest1) = tlm_bool<D>::TLM_FALSE;
+}
+
+template<class D> inline void no_b1(uchar *dest1) {
+}
+
+template<class D,
+ void COPY(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2),
+ void COPYuchar(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2),
+ void FILLFALSE(uchar *dest1), void FILLFALSEuchar(uchar *dest1)>
+inline int loop_word1(
+ int bytes_left, int len0, int lenN, int sizeof_databus,
+ uchar *start, uchar *end, uchar *src, uchar *bsrc, uchar *dest, uchar *bdest) {
+ ptrdiff_t d2b_src = bsrc - src; // 64BITFIX was int //
+ ptrdiff_t d2b_dest = bdest - dest; // 64BITFIX was int //
+ uchar *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;
+ uchar *d_start = tc->data_ptr;
+ uchar *d_end = ptrdiff_t(tc->length) + d_start; // 64BITFIX probably redundant //
+ uchar *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, &copy_dbytrue1<DATAWORD>,
+ &copy_dbytrue1<uchar>, &no_b1<DATAWORD>, &no_b1<uchar> >(
+ tc->length, len0, lenN, sizeof_databus, d_start, d_end, d,
+ 0, txn->get_data_ptr(), 0);
+ } else {
+ loop_word1<DATAWORD, &copy_dbyb1<DATAWORD>,
+ &copy_dbyb1<uchar>, &no_b1<DATAWORD>, &no_b1<uchar> >(
+ 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;
+ uchar *d_start = txn->get_data_ptr();
+ uchar *d_end = ptrdiff_t(txn->get_data_length()) + d_start; // 64BITFIX probably redundant //
+ uchar *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);
+ uchar *new_data = tc->new_dbuf;
+ tc->establish_bebuf(long_enough);
+ uchar *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<uchar>, &false_b1<DATAWORD>, &false_b1<uchar> >(
+ 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, &copy_b1<DATAWORD>,
+ &copy_b1<uchar>, &false_b1<DATAWORD>, &false_b1<uchar> >(
+ 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, &copy_d1<DATAWORD>,
+ &copy_d1<uchar>, &false_b1<DATAWORD>, &false_b1<uchar> >(
+ 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, &copy_db1<DATAWORD>,
+ &copy_db1<uchar>, &false_b1<DATAWORD>, &false_b1<uchar> >(
+ 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) {
+ ptrdiff_t src1to2 = (char *)src2 - (char *)src1; // 64BITFIX was int and operands were cast to int //
+ ptrdiff_t dest1to2 = (char *)dest2 - (char *)dest1; // 64BITFIX was int and operands were cast to int //
+
+ 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, &copy_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, &copy_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, &copy_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 = (uchar *)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, &copy_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 = (uchar *)original_data;
+ // Copy byte enables to new buffer
+ loop_aligned2<DATAWORD, &copy_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) {
+ // nothing needs to be done here
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// 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);
+}
+
+
+#ifndef TLM_END_CONV_DONT_UNDEF_UCHAR
+#undef uchar
+#endif
+
+} // namespace tlm
+
+
+#endif // multiple-inclusion protection
+