tlm_endian_conv.h revision 12027
12SN/A/*****************************************************************************
22188SN/A
32SN/A  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
42SN/A  more contributor license agreements.  See the NOTICE file distributed
52SN/A  with this work for additional information regarding copyright ownership.
62SN/A  Accellera licenses this file to you under the Apache License, Version 2.0
72SN/A  (the "License"); you may not use this file except in compliance with the
82SN/A  License.  You may obtain a copy of the License at
92SN/A
102SN/A    http://www.apache.org/licenses/LICENSE-2.0
112SN/A
122SN/A  Unless required by applicable law or agreed to in writing, software
132SN/A  distributed under the License is distributed on an "AS IS" BASIS,
142SN/A  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
152SN/A  implied.  See the License for the specific language governing
162SN/A  permissions and limitations under the License.
172SN/A
182SN/A *****************************************************************************/
192SN/A
202SN/A
212SN/A#ifndef __TLM_ENDIAN_CONV_H__
222SN/A#define __TLM_ENDIAN_CONV_H__
232SN/A
242SN/A#include <systemc>
252SN/A#include "tlm_core/tlm_2/tlm_generic_payload/tlm_gp.h"
262SN/A
272665SN/A
282665SN/Anamespace tlm {
292665SN/A
302665SN/A
312665SN/A/*
322SN/ATranaction-Level Modelling
332SN/AEndianness Helper Functions
342SN/A
352SN/ADESCRIPTION
362465SN/AA set of functions for helping users to get the endianness
371717SN/Aright in their TLM models of system initiators.  These functions are
382683Sktlim@umich.edufor use within an initiator.  They can not be used as-is outside
392680SN/Aan initiator because the extension used to store context will not work
405529Snate@binkert.orgif cascaded, and they do not respect the generic payload mutability
412SN/Arules.  However this code may be easily copied and adapted for use
421858SN/Ain bridges, etc..
433565Sgblack@eecs.umich.edu
445529Snate@binkert.orgThese functions are not compulsory.  There are other legitimate ways to
451917SN/Aachieve the same functionality.  If extra information is available at
461070SN/Acompile time about the nature of an initiator's transactions, this can
471917SN/Abe exploited to accelerate simulations by creating further functions
482188SN/Asimilar to those in this file.  In general a functional transaction can be
491917SN/Adescribed in more than one way by a TLM-2 GP object.
502290SN/A
511070SN/AThe functions convert the endianness of a GP object, either on request or
521917SN/Aresponse.  They should only be used when the initiator's endianness
532SN/Adoes not match the host's endianness.  They assume 'arithmetic mode'
545529Snate@binkert.orgmeaning that within a data word the byte order is always host-endian.
55360SN/AFor non-arithmetic mode initiators they can be used with a data word
562519SN/Asize of 1 byte.
572SN/A
582SN/AAll the functions are templates, for example:
592SN/A
602SN/Atemplate<class DATAWORD> inline void
612SN/A  to_hostendian_generic(tlm_generic_payload *txn, int sizeof_databus)
621858SN/A
632683Sktlim@umich.eduThe template parameter provides the data word width.  Having this as a class
643453Sgblack@eecs.umich.edumakes it easy to use it for copy and swap operations within the functions.
652683Sktlim@umich.eduIf the assignment operator for this class is overloaded, the endianness
663402Sktlim@umich.educonversion function may not have the desired effect.
672683Sktlim@umich.edu
682521SN/AAll the functions have the same signature except for different names.
692SN/A
702683Sktlim@umich.eduThe principle is that a function to_hostendian_convtype() is called when the
712190SN/Ainitiator-endian transaction is created, and the matching function
722680SN/Afrom_hostendian_convtype() is called when the transaction is completed, for
732290SN/Aexample before read data can be used.  In some cases the from_ function is
742526SN/Aredundant but an empty function is provided anyway.  It is strongly
751917SN/Arecommended that the from_ function is called, in case it ceases to be
765529Snate@binkert.orgredundant in future versions of this code.
771982SN/A
781917SN/ANo context needs to be managed outside the two functions, except that they
792683Sktlim@umich.edumust be called with the same template parameter and the same bus width.
802683Sktlim@umich.edu
811917SN/AFor initiator models that can not easily manage this context information,
821917SN/Aa single entry point for the from_ function is provided, which will be
831917SN/Aa little slower than calling the correct from_ function directly, as
841917SN/Ait can not be inlined.
851917SN/A
861917SN/AAll functions assume power-of-2 bus and data word widths.
871917SN/A
881917SN/AFunctions offered:
892521SN/A
905482Snate@binkert.org0) A pair of functions that work for almost all TLM2 GP transactions.  The
913548Sgblack@eecs.umich.eduonly limitations are that data and bus widths should be powers of 2, and that
922SN/Athe data length should be an integer number of streaming widths and that the
932SN/Astreaming width should be an integer number of data words.
944997Sgblack@eecs.umich.eduThese functions always allocate new data and byte enable buffers and copy
954997Sgblack@eecs.umich.edudata one byte at a time.
963402Sktlim@umich.edu  tlm_to_hostendian_generic(tlm_generic_payload *txn, int sizeof_databus)
974997Sgblack@eecs.umich.edu  tlm_from_hostendian_generic(tlm_generic_payload *txn, int sizeof_databus)
982SN/A
992526SN/A1) A pair of functions that work for all transactions regardless of data and
1002683Sktlim@umich.edubus data sizes and address alignment except for the the following
1012SN/Alimitations:
1022190SN/A- byte-enables are supported only when byte-enable granularity is no finer
1032862Sktlim@umich.eduthan the data word (every data word is wholly enabled or wholly disabled)
1042862Sktlim@umich.edu- byte-enable-length is not supported (if byte enables are present, the byte
1052864Sktlim@umich.eduenable length must be equal to the data length).
1062862Sktlim@umich.edu- streaming width is not supported
1073402Sktlim@umich.edu- data word wider than bus word is not supported
1082862Sktlim@umich.eduA new data buffer and a new byte enable buffer are always allocated.  Byte
1093402Sktlim@umich.eduenables are assumed to be needed even if not required for the original
1102862Sktlim@umich.edu(unconverted) transaction.  Data is copied to the new buffer on request
1112190SN/A(for writes) or on response (for reads).  Copies are done word-by-word
1122683Sktlim@umich.eduwhere possible.
1132862Sktlim@umich.edu  tlm_to_hostendian_word(tlm_generic_payload *txn, int sizeof_databus)
1142190SN/A  tlm_from_hostendian_word(tlm_generic_payload *txn, int sizeof_databus)
1152190SN/A
1162683Sktlim@umich.edu2) If the original transaction is both word and bus-aligned then this pair of
1171070SN/Afunctions can be used.  It will complete faster than the generic function
1183486Sktlim@umich.edubecause the data reordering function is much simpler and no address
1193486Sktlim@umich.educonversion is required.
1203486Sktlim@umich.eduThe following limitations apply:
1213486Sktlim@umich.edu- byte-enables are supported only when byte-enable granularity is no finer
1222680SN/Athan the data word (every data word is wholly enabled or wholly disabled)
1231070SN/A- byte-enable-length is not supported (if byte enables are present, the byte
1241070SN/Aenable length must be equal to the data length).
1251917SN/A- streaming width is not supported
1262683Sktlim@umich.edu- data word wider than bus word is not supported
127180SN/A- the transaction must be an integer number of bus words
128180SN/A- the address must be aligned to the bus width
1291858SN/A  tlm_to_hostendian_aligned(tlm_generic_payload *txn, int sizeof_databus)
1302235SN/A  tlm_from_hostendian_aligned(tlm_generic_payload *txn, int sizeof_databus)
131180SN/A
1322235SN/A3) For single word transactions that don't cross a bus word boundary it
133180SN/Ais always safe to work in-place and the conversion is very simple.  Again,
134180SN/Astreaming width and byte-enable length are not supported, and byte-enables
1352862Sktlim@umich.edumay not changes within a data word.
1362862Sktlim@umich.edu  tlm_to_hostendian_single(tlm_generic_payload *txn, int sizeof_databus)
1372313SN/A  tlm_from_hostendian_single(tlm_generic_payload *txn, int sizeof_databus)
1382313SN/A
1392680SN/A4) A single entry point for accessing the correct from_ function without
1402313SN/Aneeding to store context.
1412680SN/A  tlm_from_hostendian(tlm_generic_payload *txn)
1422313SN/A*/
1432313SN/A
1442680SN/A
1452313SN/A
1462361SN/A#ifndef uchar
1473548Sgblack@eecs.umich.edu#define uchar unsigned char
1482361SN/A#else
1492361SN/A#define TLM_END_CONV_DONT_UNDEF_UCHAR
1502361SN/A#endif
1512235SN/A
152180SN/A
153180SN/A///////////////////////////////////////////////////////////////////////////////
154180SN/A// Generic Utilities
1552680SN/A
156180SN/Aclass tlm_endian_context;
157180SN/Aclass tlm_endian_context_pool {
1582SN/A  public:
1592864Sktlim@umich.edu    tlm_endian_context *first;
1602864Sktlim@umich.edu    inline tlm_endian_context_pool();
1612864Sktlim@umich.edu    inline ~tlm_endian_context_pool();
1622864Sktlim@umich.edu    inline tlm_endian_context *pop();
1632864Sktlim@umich.edu    inline void push(tlm_endian_context *c);
1642864Sktlim@umich.edu};
1652864Sktlim@umich.edustatic tlm_endian_context_pool global_tlm_endian_context_pool;
1662864Sktlim@umich.edu
1672864Sktlim@umich.edu// an extension to keep the information needed for reconversion of response
1683548Sgblack@eecs.umich.educlass tlm_endian_context : public tlm_extension<tlm_endian_context> {
1692864Sktlim@umich.edu  public:
1702864Sktlim@umich.edu    tlm_endian_context() : dbuf_size(0), bebuf_size(0) {}
1712864Sktlim@umich.edu    ~tlm_endian_context() {
1722864Sktlim@umich.edu      if(dbuf_size > 0) delete [] new_dbuf;
1732864Sktlim@umich.edu      if(bebuf_size > 0) delete [] new_bebuf;
1742864Sktlim@umich.edu    }
1752864Sktlim@umich.edu
1762862Sktlim@umich.edu    sc_dt::uint64 address;     // used by generic, word
1772862Sktlim@umich.edu    sc_dt::uint64 new_address;     // used by generic
1782862Sktlim@umich.edu    uchar *data_ptr;     // used by generic, word, aligned
1792862Sktlim@umich.edu    uchar *byte_enable;  // used by word
1802862Sktlim@umich.edu    int length;         // used by generic, word
1812862Sktlim@umich.edu    int stream_width;   // used by generic
1822862Sktlim@umich.edu
1832862Sktlim@umich.edu    // used by common entry point on response
1842862Sktlim@umich.edu    void (*from_f)(tlm_generic_payload *txn, unsigned int sizeof_databus);
1852915Sktlim@umich.edu    int sizeof_databus;
1862862Sktlim@umich.edu
1872862Sktlim@umich.edu    // reordering buffers for data and byte-enables
1882862Sktlim@umich.edu    uchar *new_dbuf, *new_bebuf;
1892683Sktlim@umich.edu    int dbuf_size, bebuf_size;
190217SN/A    void establish_dbuf(int len) {
1912862Sktlim@umich.edu      if(len <= dbuf_size) return;
192223SN/A      if(dbuf_size > 0) delete [] new_dbuf;
193223SN/A      new_dbuf = new uchar[len];
194217SN/A      dbuf_size = len;
195217SN/A    }
196217SN/A    void establish_bebuf(int len) {
197217SN/A      if(len <= bebuf_size) return;
1982683Sktlim@umich.edu      if(bebuf_size > 0) delete [] new_bebuf;
199217SN/A      new_bebuf = new uchar[len];
2002862Sktlim@umich.edu      bebuf_size = len;
201237SN/A    }
202223SN/A
203217SN/A    // required for extension management
204217SN/A    void free() {
2052683Sktlim@umich.edu      global_tlm_endian_context_pool.push(this);
2062683Sktlim@umich.edu    }
2072683Sktlim@umich.edu    tlm_extension_base* clone() const {return 0;}
2082683Sktlim@umich.edu    void copy_from(tlm_extension_base const &) {return;}
2092683Sktlim@umich.edu
2102683Sktlim@umich.edu    // for pooling
2112683Sktlim@umich.edu    tlm_endian_context *next;
2122683Sktlim@umich.edu};
213217SN/A// Assumptions about transaction contexts:
214217SN/A// 1) only the address attribute of a transaction
2152683Sktlim@umich.edu// is mutable.  all other attributes are unchanged from the request to
2162SN/A// response side conversion.
2172680SN/A// 2) the conversion functions in this file do not respect the mutability
2182SN/A// rules and do not put the transaction back into its original state after
2192SN/A// completion.  so if the initiator has any cleaning up to do (eg of byte
2202188SN/A// enable buffers), it needs to store its own context.  the transaction
2212188SN/A// returned to the initiator may contain pointers to data and byte enable
2224400Srdreslin@umich.edu// that can/must not be deleted.
2235543Ssaidi@eecs.umich.edu// 3) the conversion functions in this file use an extension to store
2245543Ssaidi@eecs.umich.edu// context information.  they do not remove this extension.  the initiator
2254400Srdreslin@umich.edu// should not remove it unless it deletes the generic payload
2262290SN/A// object.
2272680SN/A
2282290SN/Ainline tlm_endian_context *establish_context(tlm_generic_payload *txn) {
2292290SN/A  tlm_endian_context *tc = txn->get_extension<tlm_endian_context>();
2302683Sktlim@umich.edu  if(tc == 0) {
231393SN/A    tc = global_tlm_endian_context_pool.pop();
232393SN/A    txn->set_extension(tc);
233393SN/A  }
2342683Sktlim@umich.edu  return tc;
235393SN/A}
2362680SN/A
237393SN/Ainline tlm_endian_context_pool::tlm_endian_context_pool() : first(0) {}
238393SN/A
2392188SN/Ainline tlm_endian_context_pool::~tlm_endian_context_pool() {
2402188SN/A  while(first != 0) {
2412188SN/A    tlm_endian_context *next = first->next;
2421858SN/A    delete first;
2432SN/A    first = next;
244393SN/A  }
2452680SN/A}
2462SN/A
2472SN/Atlm_endian_context *tlm_endian_context_pool::pop() {
2482SN/A  if(first == 0) return new tlm_endian_context;
2492188SN/A  tlm_endian_context *r = first;
2502680SN/A  first = first->next;
2512683Sktlim@umich.edu  return r;
2522SN/A}
2532SN/A
2542SN/Avoid tlm_endian_context_pool::push(tlm_endian_context *c) {
2552683Sktlim@umich.edu  c->next = first;
256393SN/A  first = c;
2572680SN/A}
258393SN/A
259393SN/A
2602680SN/A// a set of constants for efficient filling of byte enables
2612683Sktlim@umich.edutemplate<class D> class tlm_bool {
262393SN/A  public:
263393SN/A    static D TLM_TRUE;
264393SN/A    static D TLM_FALSE;
2652683Sktlim@umich.edu    static D make_uchar_array(uchar c) {
266393SN/A      D d;
2672680SN/A      uchar *tmp = (uchar *)(&d);
268393SN/A      for(ptrdiff_t i=0; i!=sizeof(D); i++) tmp[i] = c;  // 64BITFIX negligable risk but easy fix //
269393SN/A      return d;
2702680SN/A    }
2712683Sktlim@umich.edu    // also provides an syntax-efficient tester, using a
272393SN/A    // copy constuctor and an implicit cast to boolean
273393SN/A    tlm_bool(D &d) : b(*((uchar*)&d) != TLM_BYTE_DISABLED) {}
274393SN/A    operator bool() const {return b;}
275393SN/A  private:
2762683Sktlim@umich.edu    bool b;
2772SN/A};
2782330SN/A
2792341SN/Atemplate<class D> D tlm_bool<D>::TLM_TRUE
2802341SN/A  = tlm_bool<D>::make_uchar_array(TLM_BYTE_ENABLED);
2812330SN/Atemplate<class D> D tlm_bool<D>::TLM_FALSE
2822SN/A  = tlm_bool<D>::make_uchar_array(TLM_BYTE_DISABLED);
283716SN/A
284716SN/A
2852683Sktlim@umich.edu
2862190SN/A///////////////////////////////////////////////////////////////////////////////
2872680SN/A// function set (0): Utilities
2882190SN/Ainline void copy_db0(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
2892190SN/A  *dest1 = *src1;
290  *dest2 = *src2;
291}
292
293inline void copy_dbtrue0(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
294  *dest1 = *src1;
295  *dest2 = TLM_BYTE_ENABLED;
296}
297
298inline void copy_btrue0(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
299  *dest2 = TLM_BYTE_ENABLED;
300}
301
302inline void copy_b0(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
303  *dest2 = *src2;
304}
305
306inline void copy_dbyb0(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
307  if(*dest2 == TLM_BYTE_ENABLED) *src1 = *dest1;
308}
309
310
311template<class D,
312  void COPY(uchar *he_d, uchar *he_b, uchar *ie_d, uchar *ie_b)>
313inline void loop_generic0(int new_len, int new_stream_width,
314  int orig_stream_width, int sizeof_databus,
315  sc_dt::uint64 orig_start_address, sc_dt::uint64 new_start_address, int be_length,
316  uchar *ie_data, uchar *ie_be, uchar *he_data, uchar *he_be) {
317
318  for(int orig_sword = 0, new_sword = 0; new_sword < new_len;
319      new_sword += new_stream_width, orig_sword += orig_stream_width) {
320
321    sc_dt::uint64 ie_addr = orig_start_address;
322    for(int orig_dword = orig_sword;
323      orig_dword < orig_sword + orig_stream_width; orig_dword += sizeof(D)) {
324
325      for(int curr_byte = orig_dword + sizeof(D) - 1;
326          curr_byte >= orig_dword; curr_byte--) {
327
328        ptrdiff_t he_index = ((ie_addr++) ^ (sizeof_databus - 1))
329          - new_start_address + new_sword;  // 64BITFIX //
330        COPY(ie_data+curr_byte,
331             ie_be+(curr_byte % be_length),  // 64BITRISK no risk of overflow, always positive //
332             he_data+he_index, he_be+he_index);
333      }
334    }
335  }
336}
337
338
339///////////////////////////////////////////////////////////////////////////////
340// function set (0): Response
341template<class DATAWORD> inline void
342tlm_from_hostendian_generic(tlm_generic_payload *txn, unsigned int sizeof_databus) {
343  if(txn->is_read()) {
344    tlm_endian_context *tc = txn->template get_extension<tlm_endian_context>();
345    loop_generic0<DATAWORD, &copy_dbyb0>(txn->get_data_length(),
346      txn->get_streaming_width(), tc->stream_width, sizeof_databus, tc->address,
347      tc->new_address, txn->get_data_length(), tc->data_ptr, 0, txn->get_data_ptr(),
348      txn->get_byte_enable_ptr());
349  }
350}
351
352
353///////////////////////////////////////////////////////////////////////////////
354// function set (0): Request
355template<class DATAWORD> inline void
356tlm_to_hostendian_generic(tlm_generic_payload *txn, unsigned int sizeof_databus) {
357  tlm_endian_context *tc = establish_context(txn);
358  tc->from_f = &(tlm_from_hostendian_generic<DATAWORD>);
359  tc->sizeof_databus = sizeof_databus;
360
361  // calculate new size:  nr stream words multiplied by big enough stream width
362  int s_width = txn->get_streaming_width();
363  int length = txn->get_data_length();
364  if(s_width >= length) s_width = length;
365  int nr_stream_words = length/s_width;
366
367  // find out in which bus word the stream word starts and ends
368  sc_dt::uint64 new_address = (txn->get_address() & ~(sizeof_databus - 1));
369  sc_dt::uint64 end_address = ((txn->get_address() + s_width - 1)
370    & ~(sizeof_databus - 1));
371
372  int new_stream_width = end_address - new_address + sizeof_databus;
373  int new_length = new_stream_width * nr_stream_words;
374
375  // store context
376  tc->data_ptr = txn->get_data_ptr();
377  tc->address = txn->get_address();
378  tc->new_address = new_address;
379  tc->stream_width = s_width;
380  uchar *orig_be = txn->get_byte_enable_ptr();
381  int orig_be_length = txn->get_byte_enable_length();
382
383  // create data and byte-enable buffers
384  txn->set_address(new_address);
385  tc->establish_dbuf(new_length);
386  txn->set_data_ptr(tc->new_dbuf);
387  tc->establish_bebuf(new_length);
388  txn->set_byte_enable_ptr(tc->new_bebuf);
389  memset(txn->get_byte_enable_ptr(), TLM_BYTE_DISABLED, new_length);
390  txn->set_streaming_width(new_stream_width);
391  txn->set_data_length(new_length);
392  txn->set_byte_enable_length(new_length);
393
394  // copy data and/or byte enables
395  if(txn->is_write()) {
396    if(orig_be == 0) {
397      loop_generic0<DATAWORD, &copy_dbtrue0>(new_length,
398        new_stream_width, s_width, sizeof_databus, tc->address,
399        new_address, new_length, tc->data_ptr, 0, txn->get_data_ptr(),
400        txn->get_byte_enable_ptr());
401    } else {
402      loop_generic0<DATAWORD, &copy_db0>(new_length,
403        new_stream_width, s_width, sizeof_databus, tc->address,
404        new_address, orig_be_length, tc->data_ptr, orig_be, txn->get_data_ptr(),
405        txn->get_byte_enable_ptr());
406    }
407  } else { // read transaction
408    if(orig_be == 0) {
409      loop_generic0<DATAWORD, &copy_btrue0>(new_length,
410        new_stream_width, s_width, sizeof_databus, tc->address,
411        new_address, new_length, tc->data_ptr, 0, txn->get_data_ptr(),
412        txn->get_byte_enable_ptr());
413    } else {
414      loop_generic0<DATAWORD, &copy_b0>(new_length,
415        new_stream_width, s_width, sizeof_databus, tc->address,
416        new_address, orig_be_length, tc->data_ptr, orig_be, txn->get_data_ptr(),
417        txn->get_byte_enable_ptr());
418    }
419  }
420}
421
422
423
424///////////////////////////////////////////////////////////////////////////////
425// function set (1): Utilities
426template<class D>
427inline void copy_d1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
428  *((D *)dest1) = *((D *)src1);
429  *((D *)dest2) = tlm_bool<D>::TLM_TRUE;
430}
431
432template<class D>
433inline void copy_db1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
434  *((D *)dest1) = *((D *)src1);
435  *((D *)dest2) = *((D *)src2);
436}
437
438template<class D>
439inline void true_b1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
440  *((D *)dest2) = tlm_bool<D>::TLM_TRUE;
441}
442
443template<class D>
444inline void copy_b1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
445  *((D *)dest2) = *((D *)src2);
446}
447
448template<class D>
449inline void copy_dbyb1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
450  if(*src2 != TLM_BYTE_DISABLED)  *((D *)src1) = *((D *)dest1);
451}
452
453template<class D>
454inline void copy_dbytrue1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
455  *((D *)src1) = *((D *)dest1);
456}
457
458template<class D> inline void false_b1(uchar *dest1) {
459  *((D *)dest1) = tlm_bool<D>::TLM_FALSE;
460}
461
462template<class D> inline void no_b1(uchar *dest1) {
463}
464
465template<class D,
466         void COPY(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2),
467         void COPYuchar(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2),
468         void FILLFALSE(uchar *dest1), void FILLFALSEuchar(uchar *dest1)>
469inline int loop_word1(
470  int bytes_left, int len0, int lenN, int sizeof_databus,
471  uchar *start, uchar *end, uchar *src, uchar *bsrc, uchar *dest, uchar *bdest) {
472  ptrdiff_t d2b_src = bsrc - src;  // 64BITFIX was int //
473  ptrdiff_t d2b_dest = bdest - dest;  // 64BITFIX was int //
474  uchar *original_dest = dest;
475
476  while(true) {
477    // len0 bytes at start of a bus word
478    if((src >= start) && (src < end)) {
479      for(int i=0; i<len0; i++) {
480        COPYuchar(src, src+d2b_src, dest, dest+d2b_dest);
481        src++;
482        dest++;
483      }
484      bytes_left -= len0;
485      if(bytes_left <= 0) return int(dest - original_dest);
486    } else {
487      for(int i=0; i<len0; i++) {
488        FILLFALSEuchar(dest+d2b_dest);
489        src++;
490        dest++;
491      }
492    }
493    src -= 2 * sizeof(D);
494
495    // sequence of full data word fragments
496    for(unsigned int i=1; i<sizeof_databus/sizeof(D); i++) {
497      if((src >= start) && (src < end)) {
498        COPY(src, src+d2b_src, dest, dest+d2b_dest);
499        bytes_left -= sizeof(D);
500      } else {
501        FILLFALSE(dest+d2b_dest);
502      }
503      dest += sizeof(D);
504      if(bytes_left <= 0) return int(dest - original_dest);
505      src -= sizeof(D);
506    }
507
508    // lenN bytes at end of bus word
509    if((src >= start) && (src < end)) {
510      for(int i=0; i<lenN; i++) {
511        COPYuchar(src, src+d2b_src, dest, dest+d2b_dest);
512        src++;
513        dest++;
514      }
515      bytes_left -= lenN;
516      if(bytes_left <= 0) return int(dest - original_dest);
517    } else {
518      for(int i=0; i<lenN; i++) {
519        FILLFALSEuchar(dest+d2b_dest);
520        src++;
521        dest++;
522      }
523    }
524    src += 2 * sizeof_databus;
525  }
526}
527
528
529///////////////////////////////////////////////////////////////////////////////
530// function set (1): Response
531template<class DATAWORD> inline void
532tlm_from_hostendian_word(tlm_generic_payload *txn, unsigned int sizeof_databus) {
533  if(txn->is_read()) {
534    tlm_endian_context *tc = txn->template get_extension<tlm_endian_context>();
535    sc_dt::uint64 b_mask = sizeof_databus - 1;
536    int d_mask = sizeof(DATAWORD) - 1;
537    int a_offset = static_cast<int>(tc->address & b_mask);
538    int len0 = (sizeof_databus - a_offset) & d_mask;
539    int lenN = sizeof(DATAWORD) - len0;
540    uchar *d_start = tc->data_ptr;
541    uchar *d_end = ptrdiff_t(tc->length) + d_start;  // 64BITFIX probably redundant //
542    uchar *d = ptrdiff_t(((sizeof_databus - a_offset) & ~d_mask) + lenN) + d_start;  // 64BITFIX probably redundant //
543
544    // iterate over transaction copying data qualified by byte-enables
545    if(tc->byte_enable == 0) {
546      loop_word1<DATAWORD, &copy_dbytrue1<DATAWORD>,
547        &copy_dbytrue1<uchar>, &no_b1<DATAWORD>, &no_b1<uchar> >(
548        tc->length, len0, lenN, sizeof_databus, d_start, d_end, d,
549        0, txn->get_data_ptr(), 0);
550    } else {
551      loop_word1<DATAWORD, &copy_dbyb1<DATAWORD>,
552        &copy_dbyb1<uchar>, &no_b1<DATAWORD>, &no_b1<uchar> >(
553        tc->length, len0, lenN, sizeof_databus, d_start, d_end, d,
554        tc->byte_enable - d_start + d, txn->get_data_ptr(), 0);
555    }
556  }
557}
558
559
560///////////////////////////////////////////////////////////////////////////////
561// function set (1): Request
562template<class DATAWORD> inline void
563tlm_to_hostendian_word(tlm_generic_payload *txn, unsigned int sizeof_databus) {
564  tlm_endian_context *tc = establish_context(txn);
565  tc->from_f = &(tlm_from_hostendian_word<DATAWORD>);
566  tc->sizeof_databus = sizeof_databus;
567
568  sc_dt::uint64 b_mask = sizeof_databus - 1;
569  int d_mask = sizeof(DATAWORD) - 1;
570  sc_dt::uint64 a_aligned = txn->get_address() & ~b_mask;
571  int a_offset = static_cast<int>(txn->get_address() & b_mask);
572  int len0 = (sizeof_databus - a_offset) & d_mask;
573  int lenN = sizeof(DATAWORD) - len0;
574  uchar *d_start = txn->get_data_ptr();
575  uchar *d_end = ptrdiff_t(txn->get_data_length()) + d_start;  // 64BITFIX probably redundant //
576  uchar *d = ptrdiff_t(((sizeof_databus - a_offset) & ~d_mask) + lenN) + d_start;  // 64BITFIX probably redundant //
577
578  // create new data and byte enable buffers
579  int long_enough = txn->get_data_length() + 2 * sizeof_databus;
580  tc->establish_dbuf(long_enough);
581  uchar *new_data = tc->new_dbuf;
582  tc->establish_bebuf(long_enough);
583  uchar *new_be = tc->new_bebuf;
584
585  if(txn->is_read()) {
586    tc->data_ptr = d_start;
587    tc->address = txn->get_address();
588    tc->byte_enable = txn->get_byte_enable_ptr();
589    tc->length = txn->get_data_length();
590    if(txn->get_byte_enable_ptr() == 0) {
591      // iterate over transaction creating new byte enables from all-true
592      txn->set_data_length(loop_word1<DATAWORD, &true_b1<DATAWORD>,
593        &true_b1<uchar>, &false_b1<DATAWORD>, &false_b1<uchar> >(
594        txn->get_data_length(), len0, lenN, sizeof_databus,
595        d_start, d_end, d, 0, new_data, new_be));
596    } else {
597      // iterate over transaction copying byte enables
598      txn->set_data_length(loop_word1<DATAWORD, &copy_b1<DATAWORD>,
599        &copy_b1<uchar>, &false_b1<DATAWORD>, &false_b1<uchar> >(
600        txn->get_data_length(), len0, lenN, sizeof_databus, d_start, d_end,
601        d, txn->get_byte_enable_ptr() - d_start + d, new_data, new_be));
602    }
603  } else {
604    // WRITE
605    if(txn->get_byte_enable_ptr() == 0) {
606      // iterate over transaction copying data and creating new byte-enables
607      txn->set_data_length(loop_word1<DATAWORD, &copy_d1<DATAWORD>,
608        &copy_d1<uchar>, &false_b1<DATAWORD>, &false_b1<uchar> >(
609        txn->get_data_length(), len0, lenN, sizeof_databus,
610        d_start, d_end, d, 0, new_data, new_be));
611    } else {
612      // iterate over transaction copying data and byte-enables
613      txn->set_data_length(loop_word1<DATAWORD, &copy_db1<DATAWORD>,
614        &copy_db1<uchar>, &false_b1<DATAWORD>, &false_b1<uchar> >(
615        txn->get_data_length(), len0, lenN, sizeof_databus, d_start, d_end,
616        d, txn->get_byte_enable_ptr() - d_start + d, new_data, new_be));
617    }
618  }
619  txn->set_byte_enable_length(txn->get_data_length());
620  txn->set_streaming_width(txn->get_data_length());
621  txn->set_data_ptr(new_data);
622  txn->set_byte_enable_ptr(new_be);
623  txn->set_address(a_aligned);
624}
625
626
627
628///////////////////////////////////////////////////////////////////////////////
629// function set (2): Utilities
630template<class D> inline void copy_d2(D *src1, D *src2, D *dest1, D *dest2) {
631  *dest1 = *src1;
632}
633
634template<class D> inline void copy_db2(D *src1, D *src2, D *dest1, D *dest2) {
635  *dest1 = *src1;
636  *dest2 = *src2;
637}
638
639template<class D>
640inline void copy_dbyb2(D *src1, D *src2, D *dest1, D *dest2) {
641  if(tlm_bool<D>(*src2)) *dest1 = *src1;
642}
643
644template<class D, void COPY(D *src1, D *src2, D *dest1, D *dest2)>
645inline void loop_aligned2(D *src1, D *src2, D *dest1, D *dest2,
646    int words, int words_per_bus) {
647  ptrdiff_t src1to2 = (char *)src2 - (char *)src1;  // 64BITFIX was int and operands were cast to int //
648  ptrdiff_t dest1to2 = (char *)dest2 - (char *)dest1;  // 64BITFIX was int and operands were cast to int //
649
650  D *done = src1 + ptrdiff_t(words);  // 64BITFIX //
651  D *bus_start = src1;
652  src1 += ptrdiff_t(words_per_bus - 1);  // 64BITFIX //
653
654  while(true) {
655    COPY(src1, (D *)(src1to2+(char *)src1), dest1, (D *)(dest1to2+(char *)dest1));   // 64BITFIX //
656    dest1++;
657    if((--src1) < bus_start) {
658      bus_start += ptrdiff_t(words_per_bus);  // 64BITFIX //
659      if(bus_start == done) break;
660      src1 = bus_start + ptrdiff_t(words_per_bus - 1);  // 64BITFIX //
661    }
662  }
663}
664
665
666///////////////////////////////////////////////////////////////////////////////
667// function set (2): Response
668template<class DATAWORD> inline void
669tlm_from_hostendian_aligned(tlm_generic_payload *txn, unsigned int sizeof_databus) {
670  int words_per_bus = sizeof_databus/sizeof(DATAWORD);
671  if(words_per_bus == 1) return;
672  int words = (txn->get_data_length())/sizeof(DATAWORD);
673  tlm_endian_context *tc = txn->template get_extension<tlm_endian_context>();
674
675  if(txn->get_byte_enable_ptr() == 0) {
676    // no byte enables
677    if(txn->is_read()) {
678      // RD without byte enables.  Copy data to original buffer
679      loop_aligned2<DATAWORD, &copy_d2<DATAWORD> >(
680        (DATAWORD *)(txn->get_data_ptr()),
681        0, (DATAWORD *)(tc->data_ptr), 0, words, words_per_bus);
682    }
683  } else {
684    // byte enables present
685    if(txn->is_read()) {
686      // RD with byte enables.  Copy data qualified by byte-enables
687      loop_aligned2<DATAWORD, &copy_dbyb2<DATAWORD> >(
688        (DATAWORD *)(txn->get_data_ptr()),
689        (DATAWORD *)(txn->get_byte_enable_ptr()),
690        (DATAWORD *)(tc->data_ptr), 0, words, words_per_bus);
691    }
692  }
693}
694
695
696///////////////////////////////////////////////////////////////////////////////
697// function set (2): Request
698template<class DATAWORD> inline void
699tlm_to_hostendian_aligned(tlm_generic_payload *txn, unsigned int sizeof_databus) {
700  tlm_endian_context *tc = establish_context(txn);
701  tc->from_f = &(tlm_from_hostendian_aligned<DATAWORD>);
702  tc->sizeof_databus = sizeof_databus;
703
704  int words_per_bus = sizeof_databus/sizeof(DATAWORD);
705  if(words_per_bus == 1) return;
706  int words = (txn->get_data_length())/sizeof(DATAWORD);
707
708  DATAWORD *original_be = (DATAWORD *)(txn->get_byte_enable_ptr());
709  DATAWORD *original_data = (DATAWORD *)(txn->get_data_ptr());
710
711  // always allocate a new data buffer
712  tc->establish_dbuf(txn->get_data_length());
713  txn->set_data_ptr(tc->new_dbuf);
714
715  if(original_be == 0) {
716    // no byte enables
717    if(txn->is_write()) {
718      // WR no byte enables.  Copy data
719      loop_aligned2<DATAWORD, &copy_d2<DATAWORD> >(original_data, 0,
720        (DATAWORD *)(txn->get_data_ptr()), 0,
721        words, words_per_bus);
722    } else {
723      // RD no byte enables.  Save original data pointer
724      tc->data_ptr = (uchar *)original_data;
725    }
726  } else {
727    // byte enables present
728    // allocate a new buffer for them
729    tc->establish_bebuf(txn->get_data_length());
730    txn->set_byte_enable_ptr(tc->new_bebuf);
731    txn->set_byte_enable_length(txn->get_data_length());
732
733    if(txn->is_write()) {
734      // WR with byte enables.  Copy data and BEs
735      loop_aligned2<DATAWORD, &copy_db2<DATAWORD> >(original_data, original_be,
736        (DATAWORD *)(txn->get_data_ptr()),
737        (DATAWORD *)(txn->get_byte_enable_ptr()), words, words_per_bus);
738    } else {
739      // RD with byte enables.  Save original data pointer
740      tc->data_ptr = (uchar *)original_data;
741      // Copy byte enables to new buffer
742      loop_aligned2<DATAWORD, &copy_d2<DATAWORD> >(original_be, 0,
743        (DATAWORD *)(txn->get_byte_enable_ptr()), 0,
744        words, words_per_bus);
745    }
746  }
747}
748
749
750
751///////////////////////////////////////////////////////////////////////////////
752// function set (3): Response
753template<class DATAWORD> inline void
754tlm_from_hostendian_single(tlm_generic_payload *txn, unsigned int sizeof_databus) {
755  // nothing needs to be done here
756}
757
758
759///////////////////////////////////////////////////////////////////////////////
760// function set (3): Request
761template<class DATAWORD> inline void
762tlm_to_hostendian_single(tlm_generic_payload *txn, unsigned int sizeof_databus) {
763  tlm_endian_context *tc = establish_context(txn);
764  tc->from_f = &(tlm_from_hostendian_single<DATAWORD>);
765  tc->sizeof_databus = sizeof_databus;
766
767  // only need to change the address, always safe to work in-place
768  sc_dt::uint64 mask = sizeof_databus-1;
769  sc_dt::uint64 a = txn->get_address();
770  txn->set_address((a & ~mask) |
771    (sizeof_databus - (a & mask) - sizeof(DATAWORD)));
772}
773
774
775
776///////////////////////////////////////////////////////////////////////////////
777// helper function which works for all responses
778inline void tlm_from_hostendian(tlm_generic_payload *txn) {
779  tlm_endian_context *tc = txn->get_extension<tlm_endian_context>();
780  (*(tc->from_f))(txn, tc->sizeof_databus);
781}
782
783
784#ifndef TLM_END_CONV_DONT_UNDEF_UCHAR
785#undef uchar
786#endif
787
788}  // namespace tlm
789
790
791#endif  // multiple-inclusion protection
792
793