TLM-2.0: include/tlm/tlm_h/tlm_generic_payload/tlm_endian_conv.h Source File

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

# include/tlm/tlm_h/tlm_generic_payload/tlm_endian_conv.h

Go to the documentation of this file.

    00001 /*****************************************************************************
    00002
    00003   The following code is derived, directly or indirectly, from the SystemC
    00004   source code Copyright (c) 1996-2008 by all Contributors.
    00005   All Rights reserved.
    00006
    00007   The contents of this file are subject to the restrictions and limitations
    00008   set forth in the SystemC Open Source License Version 3.0 (the "License");
    00009   You may not use this file except in compliance with such restrictions and
    00010   limitations. You may obtain instructions on how to receive a copy of the
    00011   License at http://www.systemc.org/. Software distributed by Contributors
    00012   under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
    00013   ANY KIND, either express or implied. See the License for the specific
    00014   language governing rights and limitations under the License.
    00015
    00016 *****************************************************************************/
    00017
    00018
    00019 #ifndef __TLM_ENDIAN_CONV_H__
    00020 #define __TLM_ENDIAN_CONV_H__
    00021
    00022 #include <systemc>
    00023 #include "tlm_gp.h"
    00024
    00025
    00026 namespace tlm {
    00027
    00028
    00029 /*
    00030 Tranaction-Level Modelling
    00031 Endianness Helper Functions
    00032
    00033 DESCRIPTION
    00034 A set of functions for helping users to get the endianness
    00035 right in their TLM models of system initiators.  These functions are
    00036 for use within an initiator.  They can not be used as-is outside
    00037 an initiator because the extension used to store context will not work
    00038 if cascaded, and they do not respect the generic payload mutability
    00039 rules.  However this code may be easily copied and adapted for use
    00040 in bridges, etc..
    00041
    00042 These functions are not compulsory.  There are other legitimate ways to
    00043 achieve the same functionality.  If extra information is available at
    00044 compile time about the nature of an initiator's transactions, this can
    00045 be exploited to accelerate simulations by creating further functions
    00046 similar to those in this file.  In general a functional transaction can be
    00047 described in more than one way by a TLM-2 GP object.
    00048
    00049 The functions convert the endianness of a GP object, either on request or
    00050 response.  They should only be used when the initiator's endianness
    00051 does not match the host's endianness.  They assume 'arithmetic mode'
    00052 meaning that within a data word the byte order is always host-endian.
    00053 For non-arithmetic mode initiators they can be used with a data word
    00054 size of 1 byte.
    00055
    00056 All the functions are templates, for example:
    00057
    00058 template<class DATAWORD> inline void
    00059   to_hostendian_generic(tlm_generic_payload *txn, int sizeof_databus)
    00060
    00061 The template parameter provides the data word width.  Having this as a class
    00062 makes it easy to use it for copy and swap operations within the functions.
    00063 If the assignment operator for this class is overloaded, the endianness
    00064 conversion function may not have the desired effect.
    00065
    00066 All the functions have the same signature except for different names.
    00067
    00068 The principle is that a function to_hostendian_convtype() is called when the
    00069 initiator-endian transaction is created, and the matching function
    00070 from_hostendian_convtype() is called when the transaction is completed, for
    00071 example before read data can be used.  In some cases the from_ function is
    00072 redundant but an empty function is provided anyway.  It is strongly
    00073 recommended that the from_ function is called, in case it ceases to be
    00074 redundant in future versions of this code.
    00075
    00076 No context needs to be managed outside the two functions, except that they
    00077 must be called with the same template parameter and the same bus width.
    00078
    00079 For initiator models that can not easily manage this context information,
    00080 a single entry point for the from_ function is provided, which will be
    00081 a little slower than calling the correct from_ function directly, as
    00082 it can not be inlined.
    00083
    00084 All functions assume power-of-2 bus and data word widths.
    00085
    00086 Functions offered:
    00087
    00088 0) A pair of functions that work for almost all TLM2 GP transactions.  The
    00089 only limitations are that data and bus widths should be powers of 2, and that
    00090 the data length should be an integer number of streaming widths and that the
    00091 streaming width should be an integer number of data words.
    00092 These functions always allocate new data and byte enable buffers and copy
    00093 data one byte at a time.
    00094   tlm_to_hostendian_generic(tlm_generic_payload *txn, int sizeof_databus)
    00095   tlm_from_hostendian_generic(tlm_generic_payload *txn, int sizeof_databus)
    00096
    00097 1) A pair of functions that work for all transactions regardless of data and
    00098 bus data sizes and address alignment except for the the following
    00099 limitations:
    00100 - byte-enables are supported only when byte-enable granularity is no finer
    00101 than the data word (every data word is wholly enabled or wholly disabled)
    00102 - byte-enable-length is not supported (if byte enables are present, the byte
    00103 enable length must be equal to the data length).
    00104 - streaming width is not supported
    00105 - data word wider than bus word is not supported
    00106 A new data buffer and a new byte enable buffer are always allocated.  Byte
    00107 enables are assumed to be needed even if not required for the original
    00108 (unconverted) transaction.  Data is copied to the new buffer on request
    00109 (for writes) or on response (for reads).  Copies are done word-by-word
    00110 where possible.
    00111   tlm_to_hostendian_word(tlm_generic_payload *txn, int sizeof_databus)
    00112   tlm_from_hostendian_word(tlm_generic_payload *txn, int sizeof_databus)
    00113
    00114 2) If the original transaction is both word and bus-aligned then this pair of
    00115 functions can be used.  It will complete faster than the generic function
    00116 because the data reordering function is much simpler and no address
    00117 conversion is required.
    00118 The following limitations apply:
    00119 - byte-enables are supported only when byte-enable granularity is no finer
    00120 than the data word (every data word is wholly enabled or wholly disabled)
    00121 - byte-enable-length is not supported (if byte enables are present, the byte
    00122 enable length must be equal to the data length).
    00123 - streaming width is not supported
    00124 - data word wider than bus word is not supported
    00125 - the transaction must be an integer number of bus words
    00126 - the address must be aligned to the bus width
    00127   tlm_to_hostendian_aligned(tlm_generic_payload *txn, int sizeof_databus)
    00128   tlm_from_hostendian_aligned(tlm_generic_payload *txn, int sizeof_databus)
    00129
    00130 3) For single word transactions that don't cross a bus word boundary it
    00131 is always safe to work in-place and the conversion is very simple.  Again,
    00132 streaming width and byte-enable length are not supported, and byte-enables
    00133 may not changes within a data word.
    00134   tlm_to_hostendian_single(tlm_generic_payload *txn, int sizeof_databus)
    00135   tlm_from_hostendian_single(tlm_generic_payload *txn, int sizeof_databus)
    00136
    00137 4) A single entry point for accessing the correct from_ function without
    00138 needing to store context.
    00139   tlm_from_hostendian(tlm_generic_payload *txn)
    00140 */
    00141
    00142
    00143
    00144 #ifndef uchar
    00145 #define uchar unsigned char
    00146 #else
    00147 #define TLM_END_CONV_DONT_UNDEF_UCHAR
    00148 #endif
    00149
    00150
    00152 // Generic Utilities
    00153
    00154 class tlm_endian_context;
    00155 class tlm_endian_context_pool {
    00156   public:
    00157     tlm_endian_context *first;
    00158     inline tlm_endian_context_pool();
    00159     inline ~tlm_endian_context_pool();
    00160     inline tlm_endian_context *pop();
    00161     inline void push(tlm_endian_context *c);
    00162 };
    00163 static tlm_endian_context_pool global_tlm_endian_context_pool;
    00164
    00165 // an extension to keep the information needed for reconversion of response
    00166 class tlm_endian_context : public tlm_extension<tlm_endian_context> {
    00167   public:
    00168     tlm_endian_context() : dbuf_size(0), bebuf_size(0) {}
    00169     ~tlm_endian_context() {
    00170       if(dbuf_size > 0) delete [] new_dbuf;
    00171       if(bebuf_size > 0) delete [] new_bebuf;
    00172     }
    00173
    00174     sc_dt::uint64 address;     // used by generic, word
    00175     sc_dt::uint64 new_address;     // used by generic
    00176     uchar *data_ptr;     // used by generic, word, aligned
    00177     uchar *byte_enable;  // used by word
    00178     int length;         // used by generic, word
    00179     int stream_width;   // used by generic
    00180
    00181     // used by common entry point on response
    00182     void (*from_f)(tlm_generic_payload *txn, unsigned int sizeof_databus);
    00183     int sizeof_databus;
    00184
    00185     // reordering buffers for data and byte-enables
    00186     uchar *new_dbuf, *new_bebuf;
    00187     int dbuf_size, bebuf_size;
    00188     void establish_dbuf(int len) {
    00189       if(len <= dbuf_size) return;
    00190       if(dbuf_size > 0) delete [] new_dbuf;
    00191       new_dbuf = new uchar[len];
    00192       dbuf_size = len;
    00193     }
    00194     void establish_bebuf(int len) {
    00195       if(len <= bebuf_size) return;
    00196       if(bebuf_size > 0) delete [] new_bebuf;
    00197       new_bebuf = new uchar[len];
    00198       bebuf_size = len;
    00199     }
    00200
    00201     // required for extension management
    00202     void free() {
    00203       global_tlm_endian_context_pool.push(this);
    00204     }
    00205     tlm_extension_base* clone() const {return 0;}
    00206     void copy_from(tlm_extension_base const &) {return;}
    00207
    00208     // for pooling
    00209     tlm_endian_context *next;
    00210 };
    00211 // Assumptions about transaction contexts:
    00212 // 1) only the address attribute of a transaction
    00213 // is mutable.  all other attributes are unchanged from the request to
    00214 // response side conversion.
    00215 // 2) the conversion functions in this file do not respect the mutability
    00216 // rules and do not put the transaction back into its original state after
    00217 // completion.  so if the initiator has any cleaning up to do (eg of byte
    00218 // enable buffers), it needs to store its own context.  the transaction
    00219 // returned to the initiator may contain pointers to data and byte enable
    00220 // that can/must not be deleted.
    00221 // 3) the conversion functions in this file use an extension to store
    00222 // context information.  they do not remove this extension.  the initiator
    00223 // should not remove it unless it deletes the generic payload
    00224 // object.
    00225
    00226 inline tlm_endian_context *establish_context(tlm_generic_payload *txn) {
    00227   tlm_endian_context *tc = txn->get_extension<tlm_endian_context>();
    00228   if(tc == 0) {
    00229     tc = global_tlm_endian_context_pool.pop();
    00230     txn->set_extension(tc);
    00231   }
    00232   return tc;
    00233 }
    00234
    00235 inline tlm_endian_context_pool::tlm_endian_context_pool() : first(0) {}
    00236
    00237 inline tlm_endian_context_pool::~tlm_endian_context_pool() {
    00238   while(first != 0) {
    00239     tlm_endian_context *next = first->next;
    00240     delete first;
    00241     first = next;
    00242   }
    00243 }
    00244
    00245 tlm_endian_context *tlm_endian_context_pool::pop() {
    00246   if(first == 0) return new tlm_endian_context;
    00247   tlm_endian_context *r = first;
    00248   first = first->next;
    00249   return r;
    00250 }
    00251
    00252 void tlm_endian_context_pool::push(tlm_endian_context *c) {
    00253   c->next = first;
    00254   first = c;
    00255 }
    00256
    00257
    00258 // a set of constants for efficient filling of byte enables
    00259 template<class D> class tlm_bool {
    00260   public:
    00261     static D TLM_TRUE;
    00262     static D TLM_FALSE;
    00263     static D make_uchar_array(uchar c) {
    00264       D d;
    00265       uchar *tmp = (uchar *)(&d);
    00266       for(ptrdiff_t i=0; i!=sizeof(D); i++) tmp[i] = c;  // 64BITFIX negligable risk but easy fix //
    00267       return d;
    00268     }
    00269     // also provides an syntax-efficient tester, using a
    00270     // copy constuctor and an implicit cast to boolean
    00271     tlm_bool(D &d) : b(*((uchar*)&d) != TLM_BYTE_DISABLED) {}
    00272     operator bool() const {return b;}
    00273   private:
    00274     bool b;
    00275 };
    00276
    00277 template<class D> D tlm_bool<D>::TLM_TRUE
    00278   = tlm_bool<D>::make_uchar_array(TLM_BYTE_ENABLED);
    00279 template<class D> D tlm_bool<D>::TLM_FALSE
    00280   = tlm_bool<D>::make_uchar_array(TLM_BYTE_DISABLED);
    00281
    00282
    00283
    00285 // function set (0): Utilities
    00286 inline void copy_db0(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
    00287   *dest1 = *src1;
    00288   *dest2 = *src2;
    00289 }
    00290
    00291 inline void copy_dbtrue0(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
    00292   *dest1 = *src1;
    00293   *dest2 = TLM_BYTE_ENABLED;
    00294 }
    00295
    00296 inline void copy_btrue0(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
    00297   *dest2 = TLM_BYTE_ENABLED;
    00298 }
    00299
    00300 inline void copy_b0(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
    00301   *dest2 = *src2;
    00302 }
    00303
    00304 inline void copy_dbyb0(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
    00305   if(*dest2 == TLM_BYTE_ENABLED) *src1 = *dest1;
    00306 }
    00307
    00308
    00309 template<class D,
    00310   void COPY(uchar *he_d, uchar *he_b, uchar *ie_d, uchar *ie_b)>
    00311 inline void loop_generic0(int new_len, int new_stream_width,
    00312   int orig_stream_width, int sizeof_databus,
    00313   sc_dt::uint64 orig_start_address, sc_dt::uint64 new_start_address, int be_length,
    00314   uchar *ie_data, uchar *ie_be, uchar *he_data, uchar *he_be) {
    00315
    00316   for(int orig_sword = 0, new_sword = 0; new_sword < new_len;
    00317       new_sword += new_stream_width, orig_sword += orig_stream_width) {
    00318
    00319     sc_dt::uint64 ie_addr = orig_start_address;
    00320     for(int orig_dword = orig_sword;
    00321       orig_dword < orig_sword + orig_stream_width; orig_dword += sizeof(D)) {
    00322
    00323       for(int curr_byte = orig_dword + sizeof(D) - 1;
    00324           curr_byte >= orig_dword; curr_byte--) {
    00325
    00326         ptrdiff_t he_index = ((ie_addr++) ^ (sizeof_databus - 1))
    00327           - new_start_address + new_sword;  // 64BITFIX //
    00328         COPY(ie_data+curr_byte,
    00329              ie_be+(curr_byte % be_length),  // 64BITRISK no risk of overflow, always positive //
    00330              he_data+he_index, he_be+he_index);
    00331       }
    00332     }
    00333   }
    00334 }
    00335
    00336
    00338 // function set (0): Response
    00339 template<class DATAWORD> inline void
    00340 tlm_from_hostendian_generic(tlm_generic_payload *txn, unsigned int sizeof_databus) {
    00341   if(txn->is_read()) {
    00342     tlm_endian_context *tc = txn->template get_extension<tlm_endian_context>();
    00343     loop_generic0<DATAWORD, &copy_dbyb0>(txn->get_data_length(),
    00344       txn->get_streaming_width(), tc->stream_width, sizeof_databus, tc->address,
    00345       tc->new_address, txn->get_data_length(), tc->data_ptr, 0, txn->get_data_ptr(),
    00346       txn->get_byte_enable_ptr());
    00347   }
    00348 }
    00349
    00350
    00352 // function set (0): Request
    00353 template<class DATAWORD> inline void
    00354 tlm_to_hostendian_generic(tlm_generic_payload *txn, unsigned int sizeof_databus) {
    00355   tlm_endian_context *tc = establish_context(txn);
    00356   tc->from_f = &(tlm_from_hostendian_generic<DATAWORD>);
    00357   tc->sizeof_databus = sizeof_databus;
    00358
    00359   // calculate new size:  nr stream words multiplied by big enough stream width
    00360   int s_width = txn->get_streaming_width();
    00361   int length = txn->get_data_length();
    00362   if(s_width >= length) s_width = length;
    00363   int nr_stream_words = length/s_width;
    00364
    00365   // find out in which bus word the stream word starts and ends
    00366   sc_dt::uint64 new_address = (txn->get_address() & ~(sizeof_databus - 1));
    00367   sc_dt::uint64 end_address = ((txn->get_address() + s_width - 1)
    00368     & ~(sizeof_databus - 1));
    00369
    00370   int new_stream_width = end_address - new_address + sizeof_databus;
    00371   int new_length = new_stream_width * nr_stream_words;
    00372
    00373   // store context
    00374   tc->data_ptr = txn->get_data_ptr();
    00375   tc->address = txn->get_address();
    00376   tc->new_address = new_address;
    00377   tc->stream_width = s_width;
    00378   uchar *orig_be = txn->get_byte_enable_ptr();
    00379   int orig_be_length = txn->get_byte_enable_length();
    00380
    00381   // create data and byte-enable buffers
    00382   txn->set_address(new_address);
    00383   tc->establish_dbuf(new_length);
    00384   txn->set_data_ptr(tc->new_dbuf);
    00385   tc->establish_bebuf(new_length);
    00386   txn->set_byte_enable_ptr(tc->new_bebuf);
    00387   memset(txn->get_byte_enable_ptr(), TLM_BYTE_DISABLED, new_length);
    00388   txn->set_streaming_width(new_stream_width);
    00389   txn->set_data_length(new_length);
    00390   txn->set_byte_enable_length(new_length);
    00391
    00392   // copy data and/or byte enables
    00393   if(txn->is_write()) {
    00394     if(orig_be == 0) {
    00395       loop_generic0<DATAWORD, &copy_dbtrue0>(new_length,
    00396         new_stream_width, s_width, sizeof_databus, tc->address,
    00397         new_address, new_length, tc->data_ptr, 0, txn->get_data_ptr(),
    00398         txn->get_byte_enable_ptr());
    00399     } else {
    00400       loop_generic0<DATAWORD, &copy_db0>(new_length,
    00401         new_stream_width, s_width, sizeof_databus, tc->address,
    00402         new_address, orig_be_length, tc->data_ptr, orig_be, txn->get_data_ptr(),
    00403         txn->get_byte_enable_ptr());
    00404     }
    00405   } else { // read transaction
    00406     if(orig_be == 0) {
    00407       loop_generic0<DATAWORD, &copy_btrue0>(new_length,
    00408         new_stream_width, s_width, sizeof_databus, tc->address,
    00409         new_address, new_length, tc->data_ptr, 0, txn->get_data_ptr(),
    00410         txn->get_byte_enable_ptr());
    00411     } else {
    00412       loop_generic0<DATAWORD, &copy_b0>(new_length,
    00413         new_stream_width, s_width, sizeof_databus, tc->address,
    00414         new_address, orig_be_length, tc->data_ptr, orig_be, txn->get_data_ptr(),
    00415         txn->get_byte_enable_ptr());
    00416     }
    00417   }
    00418 }
    00419
    00420
    00421
    00423 // function set (1): Utilities
    00424 template<class D>
    00425 inline void copy_d1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
    00426   *((D *)dest1) = *((D *)src1);
    00427   *((D *)dest2) = tlm_bool<D>::TLM_TRUE;
    00428 }
    00429
    00430 template<class D>
    00431 inline void copy_db1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
    00432   *((D *)dest1) = *((D *)src1);
    00433   *((D *)dest2) = *((D *)src2);
    00434 }
    00435
    00436 template<class D>
    00437 inline void true_b1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
    00438   *((D *)dest2) = tlm_bool<D>::TLM_TRUE;
    00439 }
    00440
    00441 template<class D>
    00442 inline void copy_b1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
    00443   *((D *)dest2) = *((D *)src2);
    00444 }
    00445
    00446 template<class D>
    00447 inline void copy_dbyb1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
    00448   if(*src2 != TLM_BYTE_DISABLED)  *((D *)src1) = *((D *)dest1);
    00449 }
    00450
    00451 template<class D>
    00452 inline void copy_dbytrue1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
    00453   *((D *)src1) = *((D *)dest1);
    00454 }
    00455
    00456 template<class D> inline void false_b1(uchar *dest1) {
    00457   *((D *)dest1) = tlm_bool<D>::TLM_FALSE;
    00458 }
    00459
    00460 template<class D> inline void no_b1(uchar *dest1) {
    00461 }
    00462
    00463 template<class D,
    00464          void COPY(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2),
    00465          void COPYuchar(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2),
    00466          void FILLFALSE(uchar *dest1), void FILLFALSEuchar(uchar *dest1)>
    00467 inline int loop_word1(
    00468   int bytes_left, int len0, int lenN, int sizeof_databus,
    00469   uchar *start, uchar *end, uchar *src, uchar *bsrc, uchar *dest, uchar *bdest) {
    00470   ptrdiff_t d2b_src = bsrc - src;  // 64BITFIX was int //
    00471   ptrdiff_t d2b_dest = bdest - dest;  // 64BITFIX was int //
    00472   uchar *original_dest = dest;
    00473
    00474   while(true) {
    00475     // len0 bytes at start of a bus word
    00476     if((src >= start) && (src < end)) {
    00477       for(int i=0; i<len0; i++) {
    00478         COPYuchar(src, src+d2b_src, dest, dest+d2b_dest);
    00479         src++;
    00480         dest++;
    00481       }
    00482       bytes_left -= len0;
    00483       if(bytes_left <= 0) return int(dest - original_dest);
    00484     } else {
    00485       for(int i=0; i<len0; i++) {
    00486         FILLFALSEuchar(dest+d2b_dest);
    00487         src++;
    00488         dest++;
    00489       }
    00490     }
    00491     src -= 2 * sizeof(D);
    00492
    00493     // sequence of full data word fragments
    00494     for(unsigned int i=1; i<sizeof_databus/sizeof(D); i++) {
    00495       if((src >= start) && (src < end)) {
    00496         COPY(src, src+d2b_src, dest, dest+d2b_dest);
    00497         bytes_left -= sizeof(D);
    00498       } else {
    00499         FILLFALSE(dest+d2b_dest);
    00500       }
    00501       dest += sizeof(D);
    00502       if(bytes_left <= 0) return int(dest - original_dest);
    00503       src -= sizeof(D);
    00504     }
    00505
    00506     // lenN bytes at end of bus word
    00507     if((src >= start) && (src < end)) {
    00508       for(int i=0; i<lenN; i++) {
    00509         COPYuchar(src, src+d2b_src, dest, dest+d2b_dest);
    00510         src++;
    00511         dest++;
    00512       }
    00513       bytes_left -= lenN;
    00514       if(bytes_left <= 0) return int(dest - original_dest);
    00515     } else {
    00516       for(int i=0; i<lenN; i++) {
    00517         FILLFALSEuchar(dest+d2b_dest);
    00518         src++;
    00519         dest++;
    00520       }
    00521     }
    00522     src += 2 * sizeof_databus;
    00523   }
    00524 }
    00525
    00526
    00528 // function set (1): Response
    00529 template<class DATAWORD> inline void
    00530 tlm_from_hostendian_word(tlm_generic_payload *txn, unsigned int sizeof_databus) {
    00531   if(txn->is_read()) {
    00532     tlm_endian_context *tc = txn->template get_extension<tlm_endian_context>();
    00533     sc_dt::uint64 b_mask = sizeof_databus - 1;
    00534     int d_mask = sizeof(DATAWORD) - 1;
    00535     int a_offset = static_cast<int>(tc->address & b_mask);
    00536     int len0 = (sizeof_databus - a_offset) & d_mask;
    00537     int lenN = sizeof(DATAWORD) - len0;
    00538     uchar *d_start = tc->data_ptr;
    00539     uchar *d_end = ptrdiff_t(tc->length) + d_start;  // 64BITFIX probably redundant //
    00540     uchar *d = ptrdiff_t(((sizeof_databus - a_offset) & ~d_mask) + lenN) + d_start;  // 64BITFIX probably redundant //
    00541
    00542     // iterate over transaction copying data qualified by byte-enables
    00543     if(tc->byte_enable == 0) {
    00544       loop_word1<DATAWORD, &copy_dbytrue1<DATAWORD>,
    00545         &copy_dbytrue1<uchar>, &no_b1<DATAWORD>, &no_b1<uchar> >(
    00546         tc->length, len0, lenN, sizeof_databus, d_start, d_end, d,
    00547         0, txn->get_data_ptr(), 0);
    00548     } else {
    00549       loop_word1<DATAWORD, &copy_dbyb1<DATAWORD>,
    00550         &copy_dbyb1<uchar>, &no_b1<DATAWORD>, &no_b1<uchar> >(
    00551         tc->length, len0, lenN, sizeof_databus, d_start, d_end, d,
    00552         tc->byte_enable - d_start + d, txn->get_data_ptr(), 0);
    00553     }
    00554   }
    00555 }
    00556
    00557
    00559 // function set (1): Request
    00560 template<class DATAWORD> inline void
    00561 tlm_to_hostendian_word(tlm_generic_payload *txn, unsigned int sizeof_databus) {
    00562   tlm_endian_context *tc = establish_context(txn);
    00563   tc->from_f = &(tlm_from_hostendian_word<DATAWORD>);
    00564   tc->sizeof_databus = sizeof_databus;
    00565
    00566   sc_dt::uint64 b_mask = sizeof_databus - 1;
    00567   int d_mask = sizeof(DATAWORD) - 1;
    00568   sc_dt::uint64 a_aligned = txn->get_address() & ~b_mask;
    00569   int a_offset = static_cast<int>(txn->get_address() & b_mask);
    00570   int len0 = (sizeof_databus - a_offset) & d_mask;
    00571   int lenN = sizeof(DATAWORD) - len0;
    00572   uchar *d_start = txn->get_data_ptr();
    00573   uchar *d_end = ptrdiff_t(txn->get_data_length()) + d_start;  // 64BITFIX probably redundant //
    00574   uchar *d = ptrdiff_t(((sizeof_databus - a_offset) & ~d_mask) + lenN) + d_start;  // 64BITFIX probably redundant //
    00575
    00576   // create new data and byte enable buffers
    00577   int long_enough = txn->get_data_length() + 2 * sizeof_databus;
    00578   tc->establish_dbuf(long_enough);
    00579   uchar *new_data = tc->new_dbuf;
    00580   tc->establish_bebuf(long_enough);
    00581   uchar *new_be = tc->new_bebuf;
    00582
    00583   if(txn->is_read()) {
    00584     tc->data_ptr = d_start;
    00585     tc->address = txn->get_address();
    00586     tc->byte_enable = txn->get_byte_enable_ptr();
    00587     tc->length = txn->get_data_length();
    00588     if(txn->get_byte_enable_ptr() == 0) {
    00589       // iterate over transaction creating new byte enables from all-true
    00590       txn->set_data_length(loop_word1<DATAWORD, &true_b1<DATAWORD>,
    00591         &true_b1<uchar>, &false_b1<DATAWORD>, &false_b1<uchar> >(
    00592         txn->get_data_length(), len0, lenN, sizeof_databus,
    00593         d_start, d_end, d, 0, new_data, new_be));
    00594     } else {
    00595       // iterate over transaction copying byte enables
    00596       txn->set_data_length(loop_word1<DATAWORD, &copy_b1<DATAWORD>,
    00597         &copy_b1<uchar>, &false_b1<DATAWORD>, &false_b1<uchar> >(
    00598         txn->get_data_length(), len0, lenN, sizeof_databus, d_start, d_end,
    00599         d, txn->get_byte_enable_ptr() - d_start + d, new_data, new_be));
    00600     }
    00601   } else {
    00602     // WRITE
    00603     if(txn->get_byte_enable_ptr() == 0) {
    00604       // iterate over transaction copying data and creating new byte-enables
    00605       txn->set_data_length(loop_word1<DATAWORD, &copy_d1<DATAWORD>,
    00606         &copy_d1<uchar>, &false_b1<DATAWORD>, &false_b1<uchar> >(
    00607         txn->get_data_length(), len0, lenN, sizeof_databus,
    00608         d_start, d_end, d, 0, new_data, new_be));
    00609     } else {
    00610       // iterate over transaction copying data and byte-enables
    00611       txn->set_data_length(loop_word1<DATAWORD, &copy_db1<DATAWORD>,
    00612         &copy_db1<uchar>, &false_b1<DATAWORD>, &false_b1<uchar> >(
    00613         txn->get_data_length(), len0, lenN, sizeof_databus, d_start, d_end,
    00614         d, txn->get_byte_enable_ptr() - d_start + d, new_data, new_be));
    00615     }
    00616   }
    00617   txn->set_byte_enable_length(txn->get_data_length());
    00618   txn->set_streaming_width(txn->get_data_length());
    00619   txn->set_data_ptr(new_data);
    00620   txn->set_byte_enable_ptr(new_be);
    00621   txn->set_address(a_aligned);
    00622 }
    00623
    00624
    00625
    00627 // function set (2): Utilities
    00628 template<class D> inline void copy_d2(D *src1, D *src2, D *dest1, D *dest2) {
    00629   *dest1 = *src1;
    00630 }
    00631
    00632 template<class D> inline void copy_db2(D *src1, D *src2, D *dest1, D *dest2) {
    00633   *dest1 = *src1;
    00634   *dest2 = *src2;
    00635 }
    00636
    00637 template<class D>
    00638 inline void copy_dbyb2(D *src1, D *src2, D *dest1, D *dest2) {
    00639   if(tlm_bool<D>(*src2)) *dest1 = *src1;
    00640 }
    00641
    00642 template<class D, void COPY(D *src1, D *src2, D *dest1, D *dest2)>
    00643 inline void loop_aligned2(D *src1, D *src2, D *dest1, D *dest2,
    00644     int words, int words_per_bus) {
    00645   ptrdiff_t src1to2 = (char *)src2 - (char *)src1;  // 64BITFIX was int and operands were cast to int //
    00646   ptrdiff_t dest1to2 = (char *)dest2 - (char *)dest1;  // 64BITFIX was int and operands were cast to int //
    00647
    00648   D *done = src1 + ptrdiff_t(words);  // 64BITFIX //
    00649   D *bus_start = src1;
    00650   src1 += ptrdiff_t(words_per_bus - 1);  // 64BITFIX //
    00651
    00652   while(true) {
    00653     COPY(src1, (D *)(src1to2+(char *)src1), dest1, (D *)(dest1to2+(char *)dest1));   // 64BITFIX //
    00654     dest1++;
    00655     if((--src1) < bus_start) {
    00656       bus_start += ptrdiff_t(words_per_bus);  // 64BITFIX //
    00657       if(bus_start == done) break;
    00658       src1 = bus_start + ptrdiff_t(words_per_bus - 1);  // 64BITFIX //
    00659     }
    00660   }
    00661 }
    00662
    00663
    00665 // function set (2): Response
    00666 template<class DATAWORD> inline void
    00667 tlm_from_hostendian_aligned(tlm_generic_payload *txn, unsigned int sizeof_databus) {
    00668   int words_per_bus = sizeof_databus/sizeof(DATAWORD);
    00669   if(words_per_bus == 1) return;
    00670   int words = (txn->get_data_length())/sizeof(DATAWORD);
    00671   tlm_endian_context *tc = txn->template get_extension<tlm_endian_context>();
    00672
    00673   if(txn->get_byte_enable_ptr() == 0) {
    00674     // no byte enables
    00675     if(txn->is_read()) {
    00676       // RD without byte enables.  Copy data to original buffer
    00677       loop_aligned2<DATAWORD, &copy_d2<DATAWORD> >(
    00678         (DATAWORD *)(txn->get_data_ptr()),
    00679         0, (DATAWORD *)(tc->data_ptr), 0, words, words_per_bus);
    00680     }
    00681   } else {
    00682     // byte enables present
    00683     if(txn->is_read()) {
    00684       // RD with byte enables.  Copy data qualified by byte-enables
    00685       loop_aligned2<DATAWORD, &copy_dbyb2<DATAWORD> >(
    00686         (DATAWORD *)(txn->get_data_ptr()),
    00687         (DATAWORD *)(txn->get_byte_enable_ptr()),
    00688         (DATAWORD *)(tc->data_ptr), 0, words, words_per_bus);
    00689     }
    00690   }
    00691 }
    00692
    00693
    00695 // function set (2): Request
    00696 template<class DATAWORD> inline void
    00697 tlm_to_hostendian_aligned(tlm_generic_payload *txn, unsigned int sizeof_databus) {
    00698   tlm_endian_context *tc = establish_context(txn);
    00699   tc->from_f = &(tlm_from_hostendian_aligned<DATAWORD>);
    00700   tc->sizeof_databus = sizeof_databus;
    00701
    00702   int words_per_bus = sizeof_databus/sizeof(DATAWORD);
    00703   if(words_per_bus == 1) return;
    00704   int words = (txn->get_data_length())/sizeof(DATAWORD);
    00705
    00706   DATAWORD *original_be = (DATAWORD *)(txn->get_byte_enable_ptr());
    00707   DATAWORD *original_data = (DATAWORD *)(txn->get_data_ptr());
    00708
    00709   // always allocate a new data buffer
    00710   tc->establish_dbuf(txn->get_data_length());
    00711   txn->set_data_ptr(tc->new_dbuf);
    00712
    00713   if(original_be == 0) {
    00714     // no byte enables
    00715     if(txn->is_write()) {
    00716       // WR no byte enables.  Copy data
    00717       loop_aligned2<DATAWORD, &copy_d2<DATAWORD> >(original_data, 0,
    00718         (DATAWORD *)(txn->get_data_ptr()), 0,
    00719         words, words_per_bus);
    00720     } else {
    00721       // RD no byte enables.  Save original data pointer
    00722       tc->data_ptr = (uchar *)original_data;
    00723     }
    00724   } else {
    00725     // byte enables present
    00726     // allocate a new buffer for them
    00727     tc->establish_bebuf(txn->get_data_length());
    00728     txn->set_byte_enable_ptr(tc->new_bebuf);
    00729     txn->set_byte_enable_length(txn->get_data_length());
    00730
    00731     if(txn->is_write()) {
    00732       // WR with byte enables.  Copy data and BEs
    00733       loop_aligned2<DATAWORD, &copy_db2<DATAWORD> >(original_data, original_be,
    00734         (DATAWORD *)(txn->get_data_ptr()),
    00735         (DATAWORD *)(txn->get_byte_enable_ptr()), words, words_per_bus);
    00736     } else {
    00737       // RD with byte enables.  Save original data pointer
    00738       tc->data_ptr = (uchar *)original_data;
    00739       // Copy byte enables to new buffer
    00740       loop_aligned2<DATAWORD, &copy_d2<DATAWORD> >(original_be, 0,
    00741         (DATAWORD *)(txn->get_byte_enable_ptr()), 0,
    00742         words, words_per_bus);
    00743     }
    00744   }
    00745 }
    00746
    00747
    00748
    00750 // function set (3): Response
    00751 template<class DATAWORD> inline void
    00752 tlm_from_hostendian_single(tlm_generic_payload *txn, unsigned int sizeof_databus) {
    00753   // nothing needs to be done here
    00754 }
    00755
    00756
    00758 // function set (3): Request
    00759 template<class DATAWORD> inline void
    00760 tlm_to_hostendian_single(tlm_generic_payload *txn, unsigned int sizeof_databus) {
    00761   tlm_endian_context *tc = establish_context(txn);
    00762   tc->from_f = &(tlm_from_hostendian_single<DATAWORD>);
    00763   tc->sizeof_databus = sizeof_databus;
    00764
    00765   // only need to change the address, always safe to work in-place
    00766   sc_dt::uint64 mask = sizeof_databus-1;
    00767   sc_dt::uint64 a = txn->get_address();
    00768   txn->set_address((a & ~mask) |
    00769     (sizeof_databus - (a & mask) - sizeof(DATAWORD)));
    00770 }
    00771
    00772
    00773
    00775 // helper function which works for all responses
    00776 inline void tlm_from_hostendian(tlm_generic_payload *txn) {
    00777   tlm_endian_context *tc = txn->get_extension<tlm_endian_context>();
    00778   (*(tc->from_f))(txn, tc->sizeof_databus);
    00779 }
    00780
    00781
    00782 #ifndef TLM_END_CONV_DONT_UNDEF_UCHAR
    00783 #undef uchar
    00784 #endif
    00785
    00786 }  // namespace tlm
    00787
    00788
    00789 #endif  // multiple-inclusion protection
    00790