1/*****************************************************************************
2
3  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
4  more contributor license agreements.  See the NOTICE file distributed
5  with this work for additional information regarding copyright ownership.
6  Accellera licenses this file to you under the Apache License, Version 2.0
7  (the "License"); you may not use this file except in compliance with the
8  License.  You may obtain a copy of the License at
9
10    http://www.apache.org/licenses/LICENSE-2.0
11
12  Unless required by applicable law or agreed to in writing, software
13  distributed under the License is distributed on an "AS IS" BASIS,
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
15  implied.  See the License for the specific language governing
16  permissions and limitations under the License.
17
18 *****************************************************************************/
19
20
21#ifndef __TLM_ENDIAN_CONV_H__
22#define __TLM_ENDIAN_CONV_H__
23
24#include <systemc>
25#include "tlm_core/tlm_2/tlm_generic_payload/tlm_gp.h"
26
27
28namespace tlm {
29
30
31/*
32Tranaction-Level Modelling
33Endianness Helper Functions
34
35DESCRIPTION
36A set of functions for helping users to get the endianness
37right in their TLM models of system initiators.  These functions are
38for use within an initiator.  They can not be used as-is outside
39an initiator because the extension used to store context will not work
40if cascaded, and they do not respect the generic payload mutability
41rules.  However this code may be easily copied and adapted for use
42in bridges, etc..
43
44These functions are not compulsory.  There are other legitimate ways to
45achieve the same functionality.  If extra information is available at
46compile time about the nature of an initiator's transactions, this can
47be exploited to accelerate simulations by creating further functions
48similar to those in this file.  In general a functional transaction can be
49described in more than one way by a TLM-2 GP object.
50
51The functions convert the endianness of a GP object, either on request or
52response.  They should only be used when the initiator's endianness
53does not match the host's endianness.  They assume 'arithmetic mode'
54meaning that within a data word the byte order is always host-endian.
55For non-arithmetic mode initiators they can be used with a data word
56size of 1 byte.
57
58All the functions are templates, for example:
59
60template<class DATAWORD> inline void
61  to_hostendian_generic(tlm_generic_payload *txn, int sizeof_databus)
62
63The template parameter provides the data word width.  Having this as a class
64makes it easy to use it for copy and swap operations within the functions.
65If the assignment operator for this class is overloaded, the endianness
66conversion function may not have the desired effect.
67
68All the functions have the same signature except for different names.
69
70The principle is that a function to_hostendian_convtype() is called when the
71initiator-endian transaction is created, and the matching function
72from_hostendian_convtype() is called when the transaction is completed, for
73example before read data can be used.  In some cases the from_ function is
74redundant but an empty function is provided anyway.  It is strongly
75recommended that the from_ function is called, in case it ceases to be
76redundant in future versions of this code.
77
78No context needs to be managed outside the two functions, except that they
79must be called with the same template parameter and the same bus width.
80
81For initiator models that can not easily manage this context information,
82a single entry point for the from_ function is provided, which will be
83a little slower than calling the correct from_ function directly, as
84it can not be inlined.
85
86All functions assume power-of-2 bus and data word widths.
87
88Functions offered:
89
900) A pair of functions that work for almost all TLM2 GP transactions.  The
91only limitations are that data and bus widths should be powers of 2, and that
92the data length should be an integer number of streaming widths and that the
93streaming width should be an integer number of data words.
94These functions always allocate new data and byte enable buffers and copy
95data one byte at a time.
96  tlm_to_hostendian_generic(tlm_generic_payload *txn, int sizeof_databus)
97  tlm_from_hostendian_generic(tlm_generic_payload *txn, int sizeof_databus)
98
991) A pair of functions that work for all transactions regardless of data and
100bus data sizes and address alignment except for the the following
101limitations:
102- byte-enables are supported only when byte-enable granularity is no finer
103than the data word (every data word is wholly enabled or wholly disabled)
104- byte-enable-length is not supported (if byte enables are present, the byte
105enable length must be equal to the data length).
106- streaming width is not supported
107- data word wider than bus word is not supported
108A new data buffer and a new byte enable buffer are always allocated.  Byte
109enables are assumed to be needed even if not required for the original
110(unconverted) transaction.  Data is copied to the new buffer on request
111(for writes) or on response (for reads).  Copies are done word-by-word
112where possible.
113  tlm_to_hostendian_word(tlm_generic_payload *txn, int sizeof_databus)
114  tlm_from_hostendian_word(tlm_generic_payload *txn, int sizeof_databus)
115
1162) If the original transaction is both word and bus-aligned then this pair of
117functions can be used.  It will complete faster than the generic function
118because the data reordering function is much simpler and no address
119conversion is required.
120The following limitations apply:
121- byte-enables are supported only when byte-enable granularity is no finer
122than the data word (every data word is wholly enabled or wholly disabled)
123- byte-enable-length is not supported (if byte enables are present, the byte
124enable length must be equal to the data length).
125- streaming width is not supported
126- data word wider than bus word is not supported
127- the transaction must be an integer number of bus words
128- the address must be aligned to the bus width
129  tlm_to_hostendian_aligned(tlm_generic_payload *txn, int sizeof_databus)
130  tlm_from_hostendian_aligned(tlm_generic_payload *txn, int sizeof_databus)
131
1323) For single word transactions that don't cross a bus word boundary it
133is always safe to work in-place and the conversion is very simple.  Again,
134streaming width and byte-enable length are not supported, and byte-enables
135may not changes within a data word.
136  tlm_to_hostendian_single(tlm_generic_payload *txn, int sizeof_databus)
137  tlm_from_hostendian_single(tlm_generic_payload *txn, int sizeof_databus)
138
1394) A single entry point for accessing the correct from_ function without
140needing to store context.
141  tlm_from_hostendian(tlm_generic_payload *txn)
142*/
143
144
145
146#ifndef uchar
147#define uchar unsigned char
148#else
149#define TLM_END_CONV_DONT_UNDEF_UCHAR
150#endif
151
152
153///////////////////////////////////////////////////////////////////////////////
154// Generic Utilities
155
156class tlm_endian_context;
157class tlm_endian_context_pool {
158  public:
159    tlm_endian_context *first;
160    inline tlm_endian_context_pool();
161    inline ~tlm_endian_context_pool();
162    inline tlm_endian_context *pop();
163    inline void push(tlm_endian_context *c);
164};
165static tlm_endian_context_pool global_tlm_endian_context_pool;
166
167// an extension to keep the information needed for reconversion of response
168class tlm_endian_context : public tlm_extension<tlm_endian_context> {
169  public:
170    tlm_endian_context() : dbuf_size(0), bebuf_size(0) {}
171    ~tlm_endian_context() {
172      if(dbuf_size > 0) delete [] new_dbuf;
173      if(bebuf_size > 0) delete [] new_bebuf;
174    }
175
176    sc_dt::uint64 address;     // used by generic, word
177    sc_dt::uint64 new_address;     // used by generic
178    uchar *data_ptr;     // used by generic, word, aligned
179    uchar *byte_enable;  // used by word
180    int length;         // used by generic, word
181    int stream_width;   // used by generic
182
183    // used by common entry point on response
184    void (*from_f)(tlm_generic_payload *txn, unsigned int sizeof_databus);
185    int sizeof_databus;
186
187    // reordering buffers for data and byte-enables
188    uchar *new_dbuf, *new_bebuf;
189    int dbuf_size, bebuf_size;
190    void establish_dbuf(int len) {
191      if(len <= dbuf_size) return;
192      if(dbuf_size > 0) delete [] new_dbuf;
193      new_dbuf = new uchar[len];
194      dbuf_size = len;
195    }
196    void establish_bebuf(int len) {
197      if(len <= bebuf_size) return;
198      if(bebuf_size > 0) delete [] new_bebuf;
199      new_bebuf = new uchar[len];
200      bebuf_size = len;
201    }
202
203    // required for extension management
204    void free() {
205      global_tlm_endian_context_pool.push(this);
206    }
207    tlm_extension_base* clone() const {return 0;}
208    void copy_from(tlm_extension_base const &) {return;}
209
210    // for pooling
211    tlm_endian_context *next;
212};
213// Assumptions about transaction contexts:
214// 1) only the address attribute of a transaction
215// is mutable.  all other attributes are unchanged from the request to
216// response side conversion.
217// 2) the conversion functions in this file do not respect the mutability
218// rules and do not put the transaction back into its original state after
219// completion.  so if the initiator has any cleaning up to do (eg of byte
220// enable buffers), it needs to store its own context.  the transaction
221// returned to the initiator may contain pointers to data and byte enable
222// that can/must not be deleted.
223// 3) the conversion functions in this file use an extension to store
224// context information.  they do not remove this extension.  the initiator
225// should not remove it unless it deletes the generic payload
226// object.
227
228inline tlm_endian_context *establish_context(tlm_generic_payload *txn) {
229  tlm_endian_context *tc = txn->get_extension<tlm_endian_context>();
230  if(tc == 0) {
231    tc = global_tlm_endian_context_pool.pop();
232    txn->set_extension(tc);
233  }
234  return tc;
235}
236
237inline tlm_endian_context_pool::tlm_endian_context_pool() : first(0) {}
238
239inline tlm_endian_context_pool::~tlm_endian_context_pool() {
240  while(first != 0) {
241    tlm_endian_context *next = first->next;
242    delete first;
243    first = next;
244  }
245}
246
247tlm_endian_context *tlm_endian_context_pool::pop() {
248  if(first == 0) return new tlm_endian_context;
249  tlm_endian_context *r = first;
250  first = first->next;
251  return r;
252}
253
254void tlm_endian_context_pool::push(tlm_endian_context *c) {
255  c->next = first;
256  first = c;
257}
258
259
260// a set of constants for efficient filling of byte enables
261template<class D> class tlm_bool {
262  public:
263    static D TLM_TRUE;
264    static D TLM_FALSE;
265    static D make_uchar_array(uchar c) {
266      D d;
267      uchar *tmp = (uchar *)(&d);
268      for(ptrdiff_t i=0; i!=sizeof(D); i++) tmp[i] = c;  // 64BITFIX negligable risk but easy fix //
269      return d;
270    }
271    // also provides an syntax-efficient tester, using a
272    // copy constuctor and an implicit cast to boolean
273    tlm_bool(D &d) : b(*((uchar*)&d) != TLM_BYTE_DISABLED) {}
274    operator bool() const {return b;}
275  private:
276    bool b;
277};
278
279template<class D> D tlm_bool<D>::TLM_TRUE
280  = tlm_bool<D>::make_uchar_array(TLM_BYTE_ENABLED);
281template<class D> D tlm_bool<D>::TLM_FALSE
282  = tlm_bool<D>::make_uchar_array(TLM_BYTE_DISABLED);
283
284
285
286///////////////////////////////////////////////////////////////////////////////
287// function set (0): Utilities
288inline void copy_db0(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
289  *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