C:/ESLX/projects/TLMWG/tlm2/include/tlm/tlm_h/tlm_trans/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 #ifndef uchar
00143 #define uchar unsigned char
00144 #else
00145 #define TLM_END_CONV_DONT_UNDEF_UCHAR
00146 #endif
00147 
00149 // Generic Utilities
00150 
00151 // a pool for uchar* buffers of arbitrary but bounded size.  the pool contains
00152 // buffers with a fixed size - the largest so far requested.
00153 class tlm_buffer_pool {
00154   int max_buffer_size;
00155   uchar* pool_head;
00156 
00157   public:
00158     tlm_buffer_pool(): max_buffer_size(32), pool_head(0) {};
00159 
00160     uchar *get_a_buffer(int size) {
00161       if(size > max_buffer_size) {
00162         max_buffer_size = size;
00163         // empty the pool - it will have to grow again naturally
00164         for(uchar *p = pool_head; p != 0; ) {
00165           uchar *q = p;
00166           p = *((uchar **)(p + sizeof(int)));
00167           delete [] q;
00168         }
00169         pool_head = 0;
00170       }
00171       if(pool_head == 0) {
00172         // do a real malloc because pool is empty
00173         // allocate 2 spare spaces, one for the size and the other for the
00174         // next-pointer
00175         pool_head = new uchar[max_buffer_size + sizeof(int) + sizeof(uchar *)];
00176         *((int *)pool_head) = max_buffer_size;
00177         *((uchar **)(pool_head + sizeof(int))) = 0;
00178       }
00179       // now pop the pool and return the old head
00180       uchar *retval = pool_head + sizeof(int) + sizeof(uchar *);
00181       pool_head = *((uchar **)(pool_head + sizeof(int)));
00182       return retval;
00183     };
00184 
00185     void return_buffer(uchar *p) {
00186       // calculate the start of the actual buffer
00187       uchar *q = p - sizeof(int) - sizeof(uchar *);
00188       if(*((int *)q) != max_buffer_size) {
00189         // this buffer's size is out of date.  throw it away
00190         delete [] q;
00191       } else {
00192         // push a buffer into the pool if it has the right size
00193         *((uchar **)(q + sizeof(int))) = pool_head;
00194         pool_head = q;
00195       }
00196     }
00197 
00198     int get_pool_size() {
00199       int s = 0;
00200       for(uchar *p = pool_head; p != 0; p = *((uchar **)(p + sizeof(int))), s++) {}
00201       return s;
00202     }
00203 
00204     int get_buffer_size() {return max_buffer_size;}
00205 };
00206 
00207 static tlm_buffer_pool local_buffer_pool;
00208 
00209 // an extension to keep the information needed for reconversion of response
00210 class tlm_endian_context : public tlm_extension<tlm_endian_context> {
00211   public:
00212     sc_dt::uint64 address;     // used by generic, word
00213     sc_dt::uint64 new_address;     // used by generic
00214     uchar *data_ptr;     // used by generic, word, aligned
00215     uchar *byte_enable;  // used by word
00216     int length;         // used by generic, word
00217     int stream_width;   // used by generic
00218 
00219     // used by common entry point on response
00220     void (*from_f)(tlm_generic_payload *txn, unsigned int sizeof_databus);
00221     int sizeof_databus;
00222 
00223     // required for extension management
00224     tlm_extension_base* clone() const {return 0;}
00225     void free() {delete this;}
00226     void copy_from(tlm_extension_base const &) {return;}
00227 };
00228 // Assumptions about transaction contexts:
00229 // 1) only the address attribute of a transaction
00230 // is mutable.  all other attributes are unchanged from the request to
00231 // response side conversion.
00232 // 2) the conversion functions in this file do not respect the mutability
00233 // rules and do not put the transaction back into its original state after
00234 // completion.  so if the initiator has any cleaning up to do (eg of byte
00235 // enable buffers), it needs to store its own context.  the transaction
00236 // returned to the initiator may contain pointers to data and byte enable
00237 // that can/must not be deleted.
00238 // 3) the conversion functions in this file use an extension to store
00239 // context information.  they do not remove this extension.  the initiator
00240 // should not remove it unless it deletes the generic payload
00241 // object.
00242 
00243 inline tlm_endian_context *establish_context(tlm_generic_payload *txn) {
00244   tlm_endian_context *tc = txn->get_extension<tlm_endian_context>();
00245   if(tc == 0) {
00246     tc = new tlm_endian_context;
00247     txn->set_extension(tc);
00248   }
00249   return tc;
00250 }
00251 
00252 // a set of constants for efficient filling of byte enables
00253 template<class D> class tlm_bool {
00254   public:
00255     static D TLM_TRUE;
00256     static D TLM_FALSE;
00257     static D make_uchar_array(uchar c) {
00258       D d;
00259       uchar *tmp = (uchar *)(&d);
00260       for(unsigned int i=0; i<sizeof(D); i++) tmp[i] = c;
00261       return d;
00262     }
00263     // also provides an syntax-efficient tester, using a
00264     // copy constuctor and an implicit cast to boolean
00265     tlm_bool(D &d) : b(*((uchar*)&d) != TLM_BYTE_DISABLED) {}
00266     operator bool() const {return b;}
00267   private:
00268     bool b;
00269 };
00270 
00271 template<class D> D tlm_bool<D>::TLM_TRUE = tlm_bool<D>::make_uchar_array(TLM_BYTE_ENABLED);
00272 template<class D> D tlm_bool<D>::TLM_FALSE = tlm_bool<D>::make_uchar_array(TLM_BYTE_DISABLED);
00273 
00275 // function set (0): Utilities
00276 inline void copy_db0(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
00277   *dest1 = *src1;
00278   *dest2 = *src2;
00279 }
00280 
00281 inline void copy_dbtrue0(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
00282   *dest1 = *src1;
00283   *dest2 = TLM_BYTE_ENABLED;
00284 }
00285 
00286 inline void copy_btrue0(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
00287   *dest2 = TLM_BYTE_ENABLED;
00288 }
00289 
00290 inline void copy_b0(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
00291   *dest2 = *src2;
00292 }
00293 
00294 inline void copy_dbyb0(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
00295   if(*dest2 == TLM_BYTE_ENABLED) *src1 = *dest1;
00296 }
00297 
00298 
00299 template<class D,
00300   void COPY(uchar *he_d, uchar *he_b, uchar *ie_d, uchar *ie_b)>
00301 inline void loop_generic0(int new_len, int new_stream_width,
00302   int orig_stream_width, int sizeof_databus,
00303   sc_dt::uint64 orig_start_address, sc_dt::uint64 new_start_address, int be_length,
00304   uchar *ie_data, uchar *ie_be, uchar *he_data, uchar *he_be) {
00305 
00306   for(int orig_sword = 0, new_sword = 0; new_sword < new_len;
00307       new_sword += new_stream_width, orig_sword += orig_stream_width) {
00308 
00309     sc_dt::uint64 ie_addr = orig_start_address;
00310     for(int orig_dword = orig_sword;
00311       orig_dword < orig_sword + orig_stream_width; orig_dword += sizeof(D)) {
00312 
00313       for(int curr_byte = orig_dword + sizeof(D) - 1;
00314           curr_byte >= orig_dword; curr_byte--) {
00315 
00316         int he_index = ((ie_addr++) ^ (sizeof_databus - 1))
00317           - new_start_address + new_sword;
00318         COPY(ie_data+curr_byte, ie_be+(curr_byte % be_length),
00319              he_data+he_index, he_be+he_index);
00320       }
00321     }
00322   }
00323 }
00324 
00325 
00327 // function set (0): Response
00328 template<class DATAWORD> inline void
00329 tlm_from_hostendian_generic(tlm_generic_payload *txn, unsigned int sizeof_databus) {
00330   if(txn->is_read()) {
00331     tlm_endian_context *tc = txn->template get_extension<tlm_endian_context>();
00332 
00333     loop_generic0<DATAWORD, &copy_dbyb0>(txn->get_data_length(),
00334       txn->get_streaming_width(), tc->stream_width, sizeof_databus, tc->address,
00335       tc->new_address, txn->get_data_length(), tc->data_ptr, 0, txn->get_data_ptr(),
00336       txn->get_byte_enable_ptr());
00337   }
00338 
00339   local_buffer_pool.return_buffer(txn->get_byte_enable_ptr());
00340   local_buffer_pool.return_buffer(txn->get_data_ptr());
00341 }
00342 
00343 
00345 // function set (0): Request
00346 template<class DATAWORD> inline void
00347 tlm_to_hostendian_generic(tlm_generic_payload *txn, unsigned int sizeof_databus) {
00348   tlm_endian_context *tc = establish_context(txn);
00349   tc->from_f = &(tlm_from_hostendian_generic<DATAWORD>);
00350   tc->sizeof_databus = sizeof_databus;
00351 
00352   // calculate new size:  nr stream words multiplied by big enough stream width
00353   int s_width = txn->get_streaming_width();
00354   int length = txn->get_data_length();
00355   if(s_width >= length) s_width = length;
00356   int nr_stream_words = length/s_width;
00357 
00358   // find out in which bus word the stream word starts and ends
00359   sc_dt::uint64 new_address = (txn->get_address() & ~(sizeof_databus - 1));
00360   sc_dt::uint64 end_address = ((txn->get_address() + s_width - 1)
00361     & ~(sizeof_databus - 1));
00362 
00363   int new_stream_width = end_address - new_address + sizeof_databus;
00364   int new_length = new_stream_width * nr_stream_words;
00365 
00366   // store context
00367   tc->data_ptr = txn->get_data_ptr();
00368   tc->address = txn->get_address();
00369   tc->new_address = new_address;
00370   tc->stream_width = s_width;
00371   uchar *orig_be = txn->get_byte_enable_ptr();
00372   int orig_be_length = txn->get_byte_enable_length();
00373 
00374   // create data and byte-enable buffers
00375   txn->set_address(new_address);
00376   txn->set_data_ptr(local_buffer_pool.get_a_buffer(new_length));
00377   txn->set_byte_enable_ptr(local_buffer_pool.get_a_buffer(new_length));
00378   memset(txn->get_byte_enable_ptr(), TLM_BYTE_DISABLED, new_length);
00379   txn->set_streaming_width(new_stream_width);
00380   txn->set_data_length(new_length);
00381   txn->set_byte_enable_length(new_length);
00382 
00383   // copy data and/or byte enables
00384   if(txn->is_write()) {
00385     if(orig_be == 0) {
00386       loop_generic0<DATAWORD, &copy_dbtrue0>(new_length,
00387         new_stream_width, s_width, sizeof_databus, tc->address,
00388         new_address, new_length, tc->data_ptr, 0, txn->get_data_ptr(),
00389         txn->get_byte_enable_ptr());
00390     } else {
00391       loop_generic0<DATAWORD, &copy_db0>(new_length,
00392         new_stream_width, s_width, sizeof_databus, tc->address,
00393         new_address, orig_be_length, tc->data_ptr, orig_be, txn->get_data_ptr(),
00394         txn->get_byte_enable_ptr());
00395     }
00396   } else { // read transaction
00397     if(orig_be == 0) {
00398       loop_generic0<DATAWORD, &copy_btrue0>(new_length,
00399         new_stream_width, s_width, sizeof_databus, tc->address,
00400         new_address, new_length, tc->data_ptr, 0, txn->get_data_ptr(),
00401         txn->get_byte_enable_ptr());
00402     } else {
00403       loop_generic0<DATAWORD, &copy_b0>(new_length,
00404         new_stream_width, s_width, sizeof_databus, tc->address,
00405         new_address, orig_be_length, tc->data_ptr, orig_be, txn->get_data_ptr(),
00406         txn->get_byte_enable_ptr());
00407     }
00408   }
00409 }
00410 
00411 
00412 
00414 // function set (1): Utilities
00415 template<class D>
00416 inline void copy_d1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
00417   *((D *)dest1) = *((D *)src1);
00418   *((D *)dest2) = tlm_bool<D>::TLM_TRUE;
00419 }
00420 
00421 template<class D>
00422 inline void copy_db1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
00423   *((D *)dest1) = *((D *)src1);
00424   *((D *)dest2) = *((D *)src2);
00425 }
00426 
00427 template<class D>
00428 inline void true_b1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
00429   *((D *)dest2) = tlm_bool<D>::TLM_TRUE;
00430 }
00431 
00432 template<class D>
00433 inline void copy_b1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
00434   *((D *)dest2) = *((D *)src2);
00435 }
00436 
00437 template<class D>
00438 inline void copy_dbyb1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
00439   if(*src2 != TLM_BYTE_DISABLED)  *((D *)src1) = *((D *)dest1);
00440 }
00441 
00442 template<class D>
00443 inline void copy_dbytrue1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
00444   *((D *)src1) = *((D *)dest1);
00445 }
00446 
00447 template<class D> inline void false_b1(uchar *dest1) {
00448   *((D *)dest1) = tlm_bool<D>::TLM_FALSE;
00449 }
00450 
00451 template<class D> inline void no_b1(uchar *dest1) {
00452 }
00453 
00454 template<class D,
00455          void COPY(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2),
00456          void COPYuchar(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2),
00457          void FILLFALSE(uchar *dest1), void FILLFALSEuchar(uchar *dest1)>
00458 inline int loop_word1(
00459   int bytes_left, int len0, int lenN, int sizeof_databus,
00460   uchar *start, uchar *end, uchar *src, uchar *bsrc, uchar *dest, uchar *bdest) {
00461   int d2b_src = bsrc - src;
00462   int d2b_dest = bdest - dest;
00463   uchar *original_dest = dest;
00464 
00465   while(true) {
00466     // len0 bytes at start of a bus word
00467     if((src >= start) && (src < end)) {
00468       for(int i=0; i<len0; i++) {
00469         COPYuchar(src, src+d2b_src, dest, dest+d2b_dest);
00470         src++;
00471         dest++;
00472       }
00473       bytes_left -= len0;
00474       if(bytes_left <= 0) return int(dest - original_dest);
00475     } else {
00476       for(int i=0; i<len0; i++) {
00477         FILLFALSEuchar(dest+d2b_dest);
00478         src++;
00479         dest++;
00480       }
00481     }
00482     src -= 2 * sizeof(D);
00483 
00484     // sequence of full data word fragments
00485     for(unsigned int i=1; i<sizeof_databus/sizeof(D); i++) {
00486       if((src >= start) && (src < end)) {
00487         COPY(src, src+d2b_src, dest, dest+d2b_dest);
00488         bytes_left -= sizeof(D);
00489       } else {
00490         FILLFALSE(dest+d2b_dest);
00491       }
00492       dest += sizeof(D);
00493       if(bytes_left <= 0) return int(dest - original_dest);
00494       src -= sizeof(D);
00495     }
00496 
00497     // lenN bytes at end of bus word
00498     if((src >= start) && (src < end)) {
00499       for(int i=0; i<lenN; i++) {
00500         COPYuchar(src, src+d2b_src, dest, dest+d2b_dest);
00501         src++;
00502         dest++;
00503       }
00504       bytes_left -= lenN;
00505       if(bytes_left <= 0) return int(dest - original_dest);
00506     } else {
00507       for(int i=0; i<lenN; i++) {
00508         FILLFALSEuchar(dest+d2b_dest);
00509         src++;
00510         dest++;
00511       }
00512     }
00513     src += 2 * sizeof_databus;
00514   }
00515 }
00516 
00517 
00519 // function set (1): Response
00520 template<class DATAWORD> inline void
00521 tlm_from_hostendian_word(tlm_generic_payload *txn, unsigned int sizeof_databus) {
00522   if(txn->is_read()) {
00523     tlm_endian_context *tc = txn->template get_extension<tlm_endian_context>();
00524 
00525     sc_dt::uint64 b_mask = sizeof_databus - 1;
00526     int d_mask = sizeof(DATAWORD) - 1;
00527     int a_offset = tc->address & b_mask;
00528     int len0 = (sizeof_databus - a_offset) & d_mask;
00529     int lenN = sizeof(DATAWORD) - len0;
00530     uchar *d_start = tc->data_ptr;
00531     uchar *d_end = tc->length + d_start;
00532     uchar *d = ((sizeof_databus - a_offset) & ~d_mask) + lenN + d_start;
00533 
00534     // iterate over transaction copying data qualified by byte-enables
00535     if(tc->byte_enable == 0) {
00536       loop_word1<DATAWORD, &copy_dbytrue1<DATAWORD>,
00537         &copy_dbytrue1<uchar>, &no_b1<DATAWORD>, &no_b1<uchar> >(
00538         tc->length, len0, lenN, sizeof_databus, d_start, d_end, d,
00539         0, txn->get_data_ptr(), 0);
00540     } else {
00541       loop_word1<DATAWORD, &copy_dbyb1<DATAWORD>,
00542         &copy_dbyb1<uchar>, &no_b1<DATAWORD>, &no_b1<uchar> >(
00543         tc->length, len0, lenN, sizeof_databus, d_start, d_end, d,
00544         tc->byte_enable - d_start + d, txn->get_data_ptr(), 0);
00545     }
00546   }
00547   local_buffer_pool.return_buffer(txn->get_byte_enable_ptr());
00548   local_buffer_pool.return_buffer(txn->get_data_ptr());
00549 }
00550 
00551 
00553 // function set (1): Request
00554 template<class DATAWORD> inline void
00555 tlm_to_hostendian_word(tlm_generic_payload *txn, unsigned int sizeof_databus) {
00556   tlm_endian_context *tc = establish_context(txn);
00557   tc->from_f = &(tlm_from_hostendian_word<DATAWORD>);
00558   tc->sizeof_databus = sizeof_databus;
00559 
00560   sc_dt::uint64 b_mask = sizeof_databus - 1;
00561   int d_mask = sizeof(DATAWORD) - 1;
00562   sc_dt::uint64 a_aligned = txn->get_address() & ~b_mask;
00563   int a_offset = txn->get_address() & b_mask;
00564   int len0 = (sizeof_databus - a_offset) & d_mask;
00565   int lenN = sizeof(DATAWORD) - len0;
00566   uchar *d_start = txn->get_data_ptr();
00567   uchar *d_end = txn->get_data_length() + d_start;
00568   uchar *d = ((sizeof_databus - a_offset) & ~d_mask) + lenN + d_start;
00569 
00570   // create new data and byte enable buffers
00571   int long_enough = txn->get_data_length() + 2 * sizeof_databus;
00572   uchar *new_data = local_buffer_pool.get_a_buffer(long_enough);
00573   uchar *new_be = local_buffer_pool.get_a_buffer(long_enough);
00574 
00575   if(txn->is_read()) {
00576     tc->data_ptr = d_start;
00577     tc->address = txn->get_address();
00578     tc->byte_enable = txn->get_byte_enable_ptr();
00579     tc->length = txn->get_data_length();
00580     if(txn->get_byte_enable_ptr() == 0) {
00581       // iterate over transaction creating new byte enables from all-true
00582       txn->set_data_length(loop_word1<DATAWORD, &true_b1<DATAWORD>,
00583         &true_b1<uchar>, &false_b1<DATAWORD>, &false_b1<uchar> >(
00584         txn->get_data_length(), len0, lenN, sizeof_databus,
00585         d_start, d_end, d, 0, new_data, new_be));
00586     } else {
00587       // iterate over transaction copying byte enables
00588       txn->set_data_length(loop_word1<DATAWORD, &copy_b1<DATAWORD>,
00589         &copy_b1<uchar>, &false_b1<DATAWORD>, &false_b1<uchar> >(
00590         txn->get_data_length(), len0, lenN, sizeof_databus, d_start, d_end,
00591         d, txn->get_byte_enable_ptr() - d_start + d, new_data, new_be));
00592     }
00593   } else {
00594     // WRITE
00595     if(txn->get_byte_enable_ptr() == 0) {
00596       // iterate over transaction copying data and creating new byte-enables
00597       txn->set_data_length(loop_word1<DATAWORD, &copy_d1<DATAWORD>,
00598         &copy_d1<uchar>, &false_b1<DATAWORD>, &false_b1<uchar> >(
00599         txn->get_data_length(), len0, lenN, sizeof_databus,
00600         d_start, d_end, d, 0, new_data, new_be));
00601     } else {
00602       // iterate over transaction copying data and byte-enables
00603       txn->set_data_length(loop_word1<DATAWORD, &copy_db1<DATAWORD>,
00604         &copy_db1<uchar>, &false_b1<DATAWORD>, &false_b1<uchar> >(
00605         txn->get_data_length(), len0, lenN, sizeof_databus, d_start, d_end,
00606         d, txn->get_byte_enable_ptr() - d_start + d, new_data, new_be));
00607     }
00608   }
00609   txn->set_byte_enable_length(txn->get_data_length());
00610   txn->set_streaming_width(txn->get_data_length());
00611   txn->set_data_ptr(new_data);
00612   txn->set_byte_enable_ptr(new_be);
00613   txn->set_address(a_aligned);
00614 }
00615 
00616 
00617 
00619 // function set (2): Utilities
00620 template<class D> inline void copy_d2(D *src1, D *src2, D *dest1, D *dest2) {
00621   *dest1 = *src1;
00622 }
00623 
00624 template<class D> inline void copy_db2(D *src1, D *src2, D *dest1, D *dest2) {
00625   *dest1 = *src1;
00626   *dest2 = *src2;
00627 }
00628 
00629 template<class D>
00630 inline void copy_dbyb2(D *src1, D *src2, D *dest1, D *dest2) {
00631   if(tlm_bool<D>(*src2)) *dest1 = *src1;
00632 }
00633 
00634 template<class D, void COPY(D *src1, D *src2, D *dest1, D *dest2)>
00635 inline void loop_aligned2(D *src1, D *src2, D *dest1, D *dest2,
00636     int words, int words_per_bus) {
00637   int src1to2 = int(src2) - int(src1);
00638   int dest1to2 = int(dest2) - int(dest1);
00639 
00640   D *done = src1 + words;
00641   D *bus_start = src1;
00642   src1 += words_per_bus - 1;
00643 
00644   while(true) {
00645     COPY(src1, (D *)(int(src1)+src1to2), dest1, (D *)(int(dest1)+dest1to2));
00646     dest1++;
00647     if((--src1) < bus_start) {
00648       bus_start += words_per_bus;
00649       if(bus_start == done) break;
00650       src1 = bus_start + words_per_bus - 1;
00651     }
00652   }
00653 }
00654 
00655 
00657 // function set (2): Response
00658 template<class DATAWORD> inline void
00659 tlm_from_hostendian_aligned(tlm_generic_payload *txn, unsigned int sizeof_databus) {
00660   int words_per_bus = sizeof_databus/sizeof(DATAWORD);
00661   if(words_per_bus == 1) return;
00662   int words = (txn->get_data_length())/sizeof(DATAWORD);
00663 
00664   if(txn->get_byte_enable_ptr() == 0) {
00665     // no byte enables
00666     if(txn->is_read()) {
00667       // RD without byte enables.  Copy data to original buffer
00668       tlm_endian_context *tc = txn->template get_extension<tlm_endian_context>();
00669       loop_aligned2<DATAWORD, &copy_d2<DATAWORD> >(
00670         (DATAWORD *)(txn->get_data_ptr()),
00671         0, (DATAWORD *)(tc->data_ptr), 0, words, words_per_bus);
00672     }
00673   } else {
00674     // byte enables present
00675     if(txn->is_read()) {
00676       // RD with byte enables.  Copy data qualified by byte-enables
00677       tlm_endian_context *tc = txn->template get_extension<tlm_endian_context>();
00678       loop_aligned2<DATAWORD, &copy_dbyb2<DATAWORD> >(
00679         (DATAWORD *)(txn->get_data_ptr()),
00680         (DATAWORD *)(txn->get_byte_enable_ptr()),
00681         (DATAWORD *)(tc->data_ptr), 0, words, words_per_bus);
00682     }
00683     local_buffer_pool.return_buffer(txn->get_byte_enable_ptr());
00684   }
00685   // in all cases free the new data buffer
00686   local_buffer_pool.return_buffer(txn->get_data_ptr());
00687 }
00688 
00689 
00691 // function set (2): Request
00692 template<class DATAWORD> inline void
00693 tlm_to_hostendian_aligned(tlm_generic_payload *txn, unsigned int sizeof_databus) {
00694   tlm_endian_context *tc = establish_context(txn);
00695   tc->from_f = &(tlm_from_hostendian_aligned<DATAWORD>);
00696   tc->sizeof_databus = sizeof_databus;
00697 
00698   int words_per_bus = sizeof_databus/sizeof(DATAWORD);
00699   if(words_per_bus == 1) return;
00700   int words = (txn->get_data_length())/sizeof(DATAWORD);
00701 
00702   DATAWORD *original_be = (DATAWORD *)(txn->get_byte_enable_ptr());
00703   DATAWORD *original_data = (DATAWORD *)(txn->get_data_ptr());
00704 
00705   // always allocate a new data buffer
00706   txn->set_data_ptr(local_buffer_pool.get_a_buffer(txn->get_data_length()));
00707 
00708   if(original_be == 0) {
00709     // no byte enables
00710     if(txn->is_write()) {
00711       // WR no byte enables.  Copy data
00712       loop_aligned2<DATAWORD, &copy_d2<DATAWORD> >(original_data, 0,
00713         (DATAWORD *)(txn->get_data_ptr()), 0,
00714         words, words_per_bus);
00715     } else {
00716       // RD no byte enables.  Save original data pointer
00717       tc->data_ptr = (uchar *)original_data;
00718     }
00719   } else {
00720     // byte enables present
00721     // allocate a new buffer for them
00722     txn->set_byte_enable_ptr(
00723       local_buffer_pool.get_a_buffer(txn->get_data_length()));
00724     txn->set_byte_enable_length(txn->get_data_length());
00725 
00726     if(txn->is_write()) {
00727       // WR with byte enables.  Copy data and BEs
00728       loop_aligned2<DATAWORD, &copy_db2<DATAWORD> >(original_data, original_be,
00729         (DATAWORD *)(txn->get_data_ptr()),
00730         (DATAWORD *)(txn->get_byte_enable_ptr()), words, words_per_bus);
00731     } else {
00732       // RD with byte enables.  Save original data pointer
00733       tc->data_ptr = (uchar *)original_data;
00734       // Copy byte enables to new buffer
00735       loop_aligned2<DATAWORD, &copy_d2<DATAWORD> >(original_be, 0,
00736         (DATAWORD *)(txn->get_byte_enable_ptr()), 0,
00737         words, words_per_bus);
00738     }
00739   }
00740 }
00741 
00742 
00743 
00745 // function set (3): Response
00746 template<class DATAWORD> inline void
00747 tlm_from_hostendian_single(tlm_generic_payload *txn, unsigned int sizeof_databus) {
00748   // nothing needs to be done here
00749 }
00750 
00751 
00753 // function set (3): Request
00754 template<class DATAWORD> inline void
00755 tlm_to_hostendian_single(tlm_generic_payload *txn, unsigned int sizeof_databus) {
00756   tlm_endian_context *tc = establish_context(txn);
00757   tc->from_f = &(tlm_from_hostendian_single<DATAWORD>);
00758   tc->sizeof_databus = sizeof_databus;
00759 
00760   // only need to change the address, always safe to work in-place
00761   sc_dt::uint64 mask = sizeof_databus-1;
00762   sc_dt::uint64 a = txn->get_address();
00763   txn->set_address((a & ~mask) |
00764     (sizeof_databus - (a & mask) - sizeof(DATAWORD)));
00765 }
00766 
00767 
00768 
00770 // helper function which works for all responses
00771 inline void tlm_from_hostendian(tlm_generic_payload *txn) {
00772   tlm_endian_context *tc = txn->get_extension<tlm_endian_context>();
00773   (*(tc->from_f))(txn, tc->sizeof_databus);
00774 }
00775 
00776 
00777 #ifndef TLM_END_CONV_DONT_UNDEF_UCHAR
00778 #undef uchar
00779 #endif
00780 
00781 }  // namespace tlm
00782 
00783 
00784 #endif  // multiple-inclusion protection
00785 

Generated on Thu Jun 5 17:43:03 2008 for TLM 2 by  doxygen 1.5.3