TLM-2.0  2.0.4
Accellera TLM-2.0 proof-of-concept library
tlm_endian_conv.h
Go to the documentation of this file.
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 
25 
26 #include <cstring> // std::memset
27 
28 namespace tlm {
29 
30 /*
31 Tranaction-Level Modelling
32 Endianness Helper Functions
33 
34 DESCRIPTION
35 A set of functions for helping users to get the endianness
36 right in their TLM models of system initiators. These functions are
37 for use within an initiator. They can not be used as-is outside
38 an initiator because the extension used to store context will not work
39 if cascaded, and they do not respect the generic payload mutability
40 rules. However this code may be easily copied and adapted for use
41 in bridges, etc..
42 
43 These functions are not compulsory. There are other legitimate ways to
44 achieve the same functionality. If extra information is available at
45 compile time about the nature of an initiator's transactions, this can
46 be exploited to accelerate simulations by creating further functions
47 similar to those in this file. In general a functional transaction can be
48 described in more than one way by a TLM-2 GP object.
49 
50 The functions convert the endianness of a GP object, either on request or
51 response. They should only be used when the initiator's endianness
52 does not match the host's endianness. They assume 'arithmetic mode'
53 meaning that within a data word the byte order is always host-endian.
54 For non-arithmetic mode initiators they can be used with a data word
55 size of 1 byte.
56 
57 All the functions are templates, for example:
58 
59 template<class DATAWORD> inline void
60  to_hostendian_generic(tlm_generic_payload *txn, int sizeof_databus)
61 
62 The template parameter provides the data word width. Having this as a class
63 makes it easy to use it for copy and swap operations within the functions.
64 If the assignment operator for this class is overloaded, the endianness
65 conversion function may not have the desired effect.
66 
67 All the functions have the same signature except for different names.
68 
69 The principle is that a function to_hostendian_convtype() is called when the
70 initiator-endian transaction is created, and the matching function
71 from_hostendian_convtype() is called when the transaction is completed, for
72 example before read data can be used. In some cases the from_ function is
73 redundant but an empty function is provided anyway. It is strongly
74 recommended that the from_ function is called, in case it ceases to be
75 redundant in future versions of this code.
76 
77 No context needs to be managed outside the two functions, except that they
78 must be called with the same template parameter and the same bus width.
79 
80 For initiator models that can not easily manage this context information,
81 a single entry point for the from_ function is provided, which will be
82 a little slower than calling the correct from_ function directly, as
83 it can not be inlined.
84 
85 All functions assume power-of-2 bus and data word widths.
86 
87 Functions offered:
88 
89 0) A pair of functions that work for almost all TLM2 GP transactions. The
90 only limitations are that data and bus widths should be powers of 2, and that
91 the data length should be an integer number of streaming widths and that the
92 streaming width should be an integer number of data words.
93 These functions always allocate new data and byte enable buffers and copy
94 data one byte at a time.
95  tlm_to_hostendian_generic(tlm_generic_payload *txn, int sizeof_databus)
96  tlm_from_hostendian_generic(tlm_generic_payload *txn, int sizeof_databus)
97 
98 1) A pair of functions that work for all transactions regardless of data and
99 bus data sizes and address alignment except for the the following
100 limitations:
101 - byte-enables are supported only when byte-enable granularity is no finer
102 than the data word (every data word is wholly enabled or wholly disabled)
103 - byte-enable-length is not supported (if byte enables are present, the byte
104 enable length must be equal to the data length).
105 - streaming width is not supported
106 - data word wider than bus word is not supported
107 A new data buffer and a new byte enable buffer are always allocated. Byte
108 enables are assumed to be needed even if not required for the original
109 (unconverted) transaction. Data is copied to the new buffer on request
110 (for writes) or on response (for reads). Copies are done word-by-word
111 where possible.
112  tlm_to_hostendian_word(tlm_generic_payload *txn, int sizeof_databus)
113  tlm_from_hostendian_word(tlm_generic_payload *txn, int sizeof_databus)
114 
115 2) If the original transaction is both word and bus-aligned then this pair of
116 functions can be used. It will complete faster than the generic function
117 because the data reordering function is much simpler and no address
118 conversion is required.
119 The following limitations apply:
120 - byte-enables are supported only when byte-enable granularity is no finer
121 than the data word (every data word is wholly enabled or wholly disabled)
122 - byte-enable-length is not supported (if byte enables are present, the byte
123 enable length must be equal to the data length).
124 - streaming width is not supported
125 - data word wider than bus word is not supported
126 - the transaction must be an integer number of bus words
127 - the address must be aligned to the bus width
128  tlm_to_hostendian_aligned(tlm_generic_payload *txn, int sizeof_databus)
129  tlm_from_hostendian_aligned(tlm_generic_payload *txn, int sizeof_databus)
130 
131 3) For single word transactions that don't cross a bus word boundary it
132 is always safe to work in-place and the conversion is very simple. Again,
133 streaming width and byte-enable length are not supported, and byte-enables
134 may not changes within a data word.
135  tlm_to_hostendian_single(tlm_generic_payload *txn, int sizeof_databus)
136  tlm_from_hostendian_single(tlm_generic_payload *txn, int sizeof_databus)
137 
138 4) A single entry point for accessing the correct from_ function without
139 needing to store context.
140  tlm_from_hostendian(tlm_generic_payload *txn)
141 */
142 
143 
144 
145 #ifndef uchar
146 #define uchar unsigned char
147 #else
148 #define TLM_END_CONV_DONT_UNDEF_UCHAR
149 #endif
150 
151 
153 // Generic Utilities
154 
155 class tlm_endian_context;
157  public:
159  inline tlm_endian_context_pool();
160  inline ~tlm_endian_context_pool();
161  inline tlm_endian_context *pop();
162  inline void push(tlm_endian_context *c);
163 };
165 
166 // an extension to keep the information needed for reconversion of response
167 class tlm_endian_context : public tlm_extension<tlm_endian_context> {
168  public:
169  tlm_endian_context() : dbuf_size(0), bebuf_size(0) {}
171  if(dbuf_size > 0) delete [] new_dbuf;
172  if(bebuf_size > 0) delete [] new_bebuf;
173  }
174 
175  sc_dt::uint64 address; // used by generic, word
176  sc_dt::uint64 new_address; // used by generic
177  uchar *data_ptr; // used by generic, word, aligned
178  uchar *byte_enable; // used by word
179  int length; // used by generic, word
180  int stream_width; // used by generic
181 
182  // used by common entry point on response
183  void (*from_f)(tlm_generic_payload *txn, unsigned int sizeof_databus);
185 
186  // reordering buffers for data and byte-enables
187  uchar *new_dbuf, *new_bebuf;
188  int dbuf_size, bebuf_size;
189  void establish_dbuf(int len) {
190  if(len <= dbuf_size) return;
191  if(dbuf_size > 0) delete [] new_dbuf;
192  new_dbuf = new uchar[len];
193  dbuf_size = len;
194  }
195  void establish_bebuf(int len) {
196  if(len <= bebuf_size) return;
197  if(bebuf_size > 0) delete [] new_bebuf;
198  new_bebuf = new uchar[len];
199  bebuf_size = len;
200  }
201 
202  // required for extension management
203  void free() {
204  global_tlm_endian_context_pool.push(this);
205  }
206  tlm_extension_base* clone() const {return 0;}
207  void copy_from(tlm_extension_base const &) {return;}
208 
209  // for pooling
211 };
212 // Assumptions about transaction contexts:
213 // 1) only the address attribute of a transaction
214 // is mutable. all other attributes are unchanged from the request to
215 // response side conversion.
216 // 2) the conversion functions in this file do not respect the mutability
217 // rules and do not put the transaction back into its original state after
218 // completion. so if the initiator has any cleaning up to do (eg of byte
219 // enable buffers), it needs to store its own context. the transaction
220 // returned to the initiator may contain pointers to data and byte enable
221 // that can/must not be deleted.
222 // 3) the conversion functions in this file use an extension to store
223 // context information. they do not remove this extension. the initiator
224 // should not remove it unless it deletes the generic payload
225 // object.
226 
229  if(tc == 0) {
230  tc = global_tlm_endian_context_pool.pop();
231  txn->set_extension(tc);
232  }
233  return tc;
234 }
235 
237 
239  while(first != 0) {
240  tlm_endian_context *next = first->next;
241  delete first;
242  first = next;
243  }
244 }
245 
247  if(first == 0) return new tlm_endian_context;
249  first = first->next;
250  return r;
251 }
252 
254  c->next = first;
255  first = c;
256 }
257 
258 
259 // a set of constants for efficient filling of byte enables
260 template<class D> class tlm_bool {
261  public:
262  static D TLM_TRUE;
263  static D TLM_FALSE;
264  static D make_uchar_array(uchar c) {
265  D d;
266  uchar *tmp = (uchar *)(&d);
267  for(ptrdiff_t i=0; i!=sizeof(D); i++) tmp[i] = c; // 64BITFIX negligable risk but easy fix //
268  return d;
269  }
270  // also provides an syntax-efficient tester, using a
271  // copy constuctor and an implicit cast to boolean
272  tlm_bool(D &d) : b(*((uchar*)&d) != TLM_BYTE_DISABLED) {}
273  operator bool() const {return b;}
274  private:
275  bool b;
276 };
277 
278 template<class D> D tlm_bool<D>::TLM_TRUE
280 template<class D> D tlm_bool<D>::TLM_FALSE
282 
283 
284 
286 // function set (0): Utilities
287 inline void copy_db0(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
288  *dest1 = *src1;
289  *dest2 = *src2;
290 }
291 
292 inline void copy_dbtrue0(uchar *src1, uchar * /* src2 */, uchar *dest1, uchar *dest2) {
293  *dest1 = *src1;
294  *dest2 = TLM_BYTE_ENABLED;
295 }
296 
297 inline void copy_btrue0(uchar * /* src1 */, uchar * /* src2 */, uchar * /* dest1 */, uchar *dest2) {
298  *dest2 = TLM_BYTE_ENABLED;
299 }
300 
301 inline void copy_b0(uchar * /* src1 */, uchar *src2, uchar * /* dest1 */, uchar *dest2) {
302  *dest2 = *src2;
303 }
304 
305 inline void copy_dbyb0(uchar *src1, uchar * /* src2 */, uchar *dest1, uchar *dest2) {
306  if(*dest2 == TLM_BYTE_ENABLED) *src1 = *dest1;
307 }
308 
309 
310 template<class D,
311  void COPY(uchar *he_d, uchar *he_b, uchar *ie_d, uchar *ie_b)>
312 inline void loop_generic0(int new_len, int new_stream_width,
313  int orig_stream_width, int sizeof_databus,
314  sc_dt::uint64 orig_start_address, sc_dt::uint64 new_start_address, int be_length,
315  uchar *ie_data, uchar *ie_be, uchar *he_data, uchar *he_be) {
316 
317  for(int orig_sword = 0, new_sword = 0; new_sword < new_len;
318  new_sword += new_stream_width, orig_sword += orig_stream_width) {
319 
320  sc_dt::uint64 ie_addr = orig_start_address;
321  for(int orig_dword = orig_sword;
322  orig_dword < orig_sword + orig_stream_width; orig_dword += sizeof(D)) {
323 
324  for(int curr_byte = orig_dword + sizeof(D) - 1;
325  curr_byte >= orig_dword; curr_byte--) {
326 
327  ptrdiff_t he_index = ((ie_addr++) ^ (sizeof_databus - 1))
328  - new_start_address + new_sword; // 64BITFIX //
329  COPY(ie_data+curr_byte,
330  ie_be+(curr_byte % be_length), // 64BITRISK no risk of overflow, always positive //
331  he_data+he_index, he_be+he_index);
332  }
333  }
334  }
335 }
336 
337 
339 // function set (0): Response
340 template<class DATAWORD> inline void
341 tlm_from_hostendian_generic(tlm_generic_payload *txn, unsigned int sizeof_databus) {
342  if(txn->is_read()) {
343  tlm_endian_context *tc = txn->template get_extension<tlm_endian_context>();
344  loop_generic0<DATAWORD, &copy_dbyb0>(txn->get_data_length(),
345  txn->get_streaming_width(), tc->stream_width, sizeof_databus, tc->address,
346  tc->new_address, txn->get_data_length(), tc->data_ptr, 0, txn->get_data_ptr(),
347  txn->get_byte_enable_ptr());
348  }
349 }
350 
351 
353 // function set (0): Request
354 template<class DATAWORD> inline void
355 tlm_to_hostendian_generic(tlm_generic_payload *txn, unsigned int sizeof_databus) {
357  tc->from_f = &(tlm_from_hostendian_generic<DATAWORD>);
358  tc->sizeof_databus = sizeof_databus;
359 
360  // calculate new size: nr stream words multiplied by big enough stream width
361  int s_width = txn->get_streaming_width();
362  int length = txn->get_data_length();
363  if(s_width >= length) s_width = length;
364  int nr_stream_words = length/s_width;
365 
366  // find out in which bus word the stream word starts and ends
367  sc_dt::uint64 new_address = (txn->get_address() & ~(sizeof_databus - 1));
368  sc_dt::uint64 end_address = ((txn->get_address() + s_width - 1)
369  & ~(sizeof_databus - 1));
370 
371  int new_stream_width = end_address - new_address + sizeof_databus;
372  int new_length = new_stream_width * nr_stream_words;
373 
374  // store context
375  tc->data_ptr = txn->get_data_ptr();
376  tc->address = txn->get_address();
377  tc->new_address = new_address;
378  tc->stream_width = s_width;
379  uchar *orig_be = txn->get_byte_enable_ptr();
380  int orig_be_length = txn->get_byte_enable_length();
381 
382  // create data and byte-enable buffers
383  txn->set_address(new_address);
384  tc->establish_dbuf(new_length);
385  txn->set_data_ptr(tc->new_dbuf);
386  tc->establish_bebuf(new_length);
387  txn->set_byte_enable_ptr(tc->new_bebuf);
388  std::memset(txn->get_byte_enable_ptr(), TLM_BYTE_DISABLED, new_length);
389  txn->set_streaming_width(new_stream_width);
390  txn->set_data_length(new_length);
391  txn->set_byte_enable_length(new_length);
392 
393  // copy data and/or byte enables
394  if(txn->is_write()) {
395  if(orig_be == 0) {
396  loop_generic0<DATAWORD, &copy_dbtrue0>(new_length,
397  new_stream_width, s_width, sizeof_databus, tc->address,
398  new_address, new_length, tc->data_ptr, 0, txn->get_data_ptr(),
399  txn->get_byte_enable_ptr());
400  } else {
401  loop_generic0<DATAWORD, &copy_db0>(new_length,
402  new_stream_width, s_width, sizeof_databus, tc->address,
403  new_address, orig_be_length, tc->data_ptr, orig_be, txn->get_data_ptr(),
404  txn->get_byte_enable_ptr());
405  }
406  } else { // read transaction
407  if(orig_be == 0) {
408  loop_generic0<DATAWORD, &copy_btrue0>(new_length,
409  new_stream_width, s_width, sizeof_databus, tc->address,
410  new_address, new_length, tc->data_ptr, 0, txn->get_data_ptr(),
411  txn->get_byte_enable_ptr());
412  } else {
413  loop_generic0<DATAWORD, &copy_b0>(new_length,
414  new_stream_width, s_width, sizeof_databus, tc->address,
415  new_address, orig_be_length, tc->data_ptr, orig_be, txn->get_data_ptr(),
416  txn->get_byte_enable_ptr());
417  }
418  }
419 }
420 
421 
422 
424 // function set (1): Utilities
425 template<class D>
426 inline void copy_d1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
427  *((D *)dest1) = *((D *)src1);
428  *((D *)dest2) = tlm_bool<D>::TLM_TRUE;
429 }
430 
431 template<class D>
432 inline void copy_db1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
433  *((D *)dest1) = *((D *)src1);
434  *((D *)dest2) = *((D *)src2);
435 }
436 
437 template<class D>
438 inline void true_b1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
439  *((D *)dest2) = tlm_bool<D>::TLM_TRUE;
440 }
441 
442 template<class D>
443 inline void copy_b1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
444  *((D *)dest2) = *((D *)src2);
445 }
446 
447 template<class D>
448 inline void copy_dbyb1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
449  if(*src2 != TLM_BYTE_DISABLED) *((D *)src1) = *((D *)dest1);
450 }
451 
452 template<class D>
453 inline void copy_dbytrue1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) {
454  *((D *)src1) = *((D *)dest1);
455 }
456 
457 template<class D> inline void false_b1(uchar *dest1) {
458  *((D *)dest1) = tlm_bool<D>::TLM_FALSE;
459 }
460 
461 template<class D> inline void no_b1(uchar *dest1) {
462 }
463 
464 template<class D,
465  void COPY(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2),
466  void COPYuchar(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2),
467  void FILLFALSE(uchar *dest1), void FILLFALSEuchar(uchar *dest1)>
468 inline int loop_word1(
469  int bytes_left, int len0, int lenN, int sizeof_databus,
470  uchar *start, uchar *end, uchar *src, uchar *bsrc, uchar *dest, uchar *bdest) {
471  ptrdiff_t d2b_src = bsrc - src; // 64BITFIX was int //
472  ptrdiff_t d2b_dest = bdest - dest; // 64BITFIX was int //
473  uchar *original_dest = dest;
474 
475  while(true) {
476  // len0 bytes at start of a bus word
477  if((src >= start) && (src < end)) {
478  for(int i=0; i<len0; i++) {
479  COPYuchar(src, src+d2b_src, dest, dest+d2b_dest);
480  src++;
481  dest++;
482  }
483  bytes_left -= len0;
484  if(bytes_left <= 0) return int(dest - original_dest);
485  } else {
486  for(int i=0; i<len0; i++) {
487  FILLFALSEuchar(dest+d2b_dest);
488  src++;
489  dest++;
490  }
491  }
492  src -= 2 * sizeof(D);
493 
494  // sequence of full data word fragments
495  for(unsigned int i=1; i<sizeof_databus/sizeof(D); i++) {
496  if((src >= start) && (src < end)) {
497  COPY(src, src+d2b_src, dest, dest+d2b_dest);
498  bytes_left -= sizeof(D);
499  } else {
500  FILLFALSE(dest+d2b_dest);
501  }
502  dest += sizeof(D);
503  if(bytes_left <= 0) return int(dest - original_dest);
504  src -= sizeof(D);
505  }
506 
507  // lenN bytes at end of bus word
508  if((src >= start) && (src < end)) {
509  for(int i=0; i<lenN; i++) {
510  COPYuchar(src, src+d2b_src, dest, dest+d2b_dest);
511  src++;
512  dest++;
513  }
514  bytes_left -= lenN;
515  if(bytes_left <= 0) return int(dest - original_dest);
516  } else {
517  for(int i=0; i<lenN; i++) {
518  FILLFALSEuchar(dest+d2b_dest);
519  src++;
520  dest++;
521  }
522  }
523  src += 2 * sizeof_databus;
524  }
525 }
526 
527 
529 // function set (1): Response
530 template<class DATAWORD> inline void
531 tlm_from_hostendian_word(tlm_generic_payload *txn, unsigned int sizeof_databus) {
532  if(txn->is_read()) {
533  tlm_endian_context *tc = txn->template get_extension<tlm_endian_context>();
534  sc_dt::uint64 b_mask = sizeof_databus - 1;
535  int d_mask = sizeof(DATAWORD) - 1;
536  int a_offset = static_cast<int>(tc->address & b_mask);
537  int len0 = (sizeof_databus - a_offset) & d_mask;
538  int lenN = sizeof(DATAWORD) - len0;
539  uchar *d_start = tc->data_ptr;
540  uchar *d_end = ptrdiff_t(tc->length) + d_start; // 64BITFIX probably redundant //
541  uchar *d = ptrdiff_t(((sizeof_databus - a_offset) & ~d_mask) + lenN) + d_start; // 64BITFIX probably redundant //
542 
543  // iterate over transaction copying data qualified by byte-enables
544  if(tc->byte_enable == 0) {
545  loop_word1<DATAWORD, &copy_dbytrue1<DATAWORD>,
546  &copy_dbytrue1<uchar>, &no_b1<DATAWORD>, &no_b1<uchar> >(
547  tc->length, len0, lenN, sizeof_databus, d_start, d_end, d,
548  0, txn->get_data_ptr(), 0);
549  } else {
550  loop_word1<DATAWORD, &copy_dbyb1<DATAWORD>,
551  &copy_dbyb1<uchar>, &no_b1<DATAWORD>, &no_b1<uchar> >(
552  tc->length, len0, lenN, sizeof_databus, d_start, d_end, d,
553  tc->byte_enable - d_start + d, txn->get_data_ptr(), 0);
554  }
555  }
556 }
557 
558 
560 // function set (1): Request
561 template<class DATAWORD> inline void
562 tlm_to_hostendian_word(tlm_generic_payload *txn, unsigned int sizeof_databus) {
564  tc->from_f = &(tlm_from_hostendian_word<DATAWORD>);
565  tc->sizeof_databus = sizeof_databus;
566 
567  sc_dt::uint64 b_mask = sizeof_databus - 1;
568  int d_mask = sizeof(DATAWORD) - 1;
569  sc_dt::uint64 a_aligned = txn->get_address() & ~b_mask;
570  int a_offset = static_cast<int>(txn->get_address() & b_mask);
571  int len0 = (sizeof_databus - a_offset) & d_mask;
572  int lenN = sizeof(DATAWORD) - len0;
573  uchar *d_start = txn->get_data_ptr();
574  uchar *d_end = ptrdiff_t(txn->get_data_length()) + d_start; // 64BITFIX probably redundant //
575  uchar *d = ptrdiff_t(((sizeof_databus - a_offset) & ~d_mask) + lenN) + d_start; // 64BITFIX probably redundant //
576 
577  // create new data and byte enable buffers
578  int long_enough = txn->get_data_length() + 2 * sizeof_databus;
579  tc->establish_dbuf(long_enough);
580  uchar *new_data = tc->new_dbuf;
581  tc->establish_bebuf(long_enough);
582  uchar *new_be = tc->new_bebuf;
583 
584  if(txn->is_read()) {
585  tc->data_ptr = d_start;
586  tc->address = txn->get_address();
587  tc->byte_enable = txn->get_byte_enable_ptr();
588  tc->length = txn->get_data_length();
589  if(txn->get_byte_enable_ptr() == 0) {
590  // iterate over transaction creating new byte enables from all-true
591  txn->set_data_length(loop_word1<DATAWORD, &true_b1<DATAWORD>,
592  &true_b1<uchar>, &false_b1<DATAWORD>, &false_b1<uchar> >(
593  txn->get_data_length(), len0, lenN, sizeof_databus,
594  d_start, d_end, d, 0, new_data, new_be));
595  } else {
596  // iterate over transaction copying byte enables
597  txn->set_data_length(loop_word1<DATAWORD, &copy_b1<DATAWORD>,
598  &copy_b1<uchar>, &false_b1<DATAWORD>, &false_b1<uchar> >(
599  txn->get_data_length(), len0, lenN, sizeof_databus, d_start, d_end,
600  d, txn->get_byte_enable_ptr() - d_start + d, new_data, new_be));
601  }
602  } else {
603  // WRITE
604  if(txn->get_byte_enable_ptr() == 0) {
605  // iterate over transaction copying data and creating new byte-enables
606  txn->set_data_length(loop_word1<DATAWORD, &copy_d1<DATAWORD>,
607  &copy_d1<uchar>, &false_b1<DATAWORD>, &false_b1<uchar> >(
608  txn->get_data_length(), len0, lenN, sizeof_databus,
609  d_start, d_end, d, 0, new_data, new_be));
610  } else {
611  // iterate over transaction copying data and byte-enables
612  txn->set_data_length(loop_word1<DATAWORD, &copy_db1<DATAWORD>,
613  &copy_db1<uchar>, &false_b1<DATAWORD>, &false_b1<uchar> >(
614  txn->get_data_length(), len0, lenN, sizeof_databus, d_start, d_end,
615  d, txn->get_byte_enable_ptr() - d_start + d, new_data, new_be));
616  }
617  }
620  txn->set_data_ptr(new_data);
621  txn->set_byte_enable_ptr(new_be);
622  txn->set_address(a_aligned);
623 }
624 
625 
626 
628 // function set (2): Utilities
629 template<class D> inline void copy_d2(D *src1, D *src2, D *dest1, D *dest2) {
630  *dest1 = *src1;
631 }
632 
633 template<class D> inline void copy_db2(D *src1, D *src2, D *dest1, D *dest2) {
634  *dest1 = *src1;
635  *dest2 = *src2;
636 }
637 
638 template<class D>
639 inline void copy_dbyb2(D *src1, D *src2, D *dest1, D *dest2) {
640  if(tlm_bool<D>(*src2)) *dest1 = *src1;
641 }
642 
643 template<class D, void COPY(D *src1, D *src2, D *dest1, D *dest2)>
644 inline void loop_aligned2(D *src1, D *src2, D *dest1, D *dest2,
645  int words, int words_per_bus) {
646  ptrdiff_t src1to2 = (char *)src2 - (char *)src1; // 64BITFIX was int and operands were cast to int //
647  ptrdiff_t dest1to2 = (char *)dest2 - (char *)dest1; // 64BITFIX was int and operands were cast to int //
648 
649  D *done = src1 + ptrdiff_t(words); // 64BITFIX //
650  D *bus_start = src1;
651  src1 += ptrdiff_t(words_per_bus - 1); // 64BITFIX //
652 
653  while(true) {
654  COPY(src1, (D *)(src1to2+(char *)src1), dest1, (D *)(dest1to2+(char *)dest1)); // 64BITFIX //
655  dest1++;
656  if((--src1) < bus_start) {
657  bus_start += ptrdiff_t(words_per_bus); // 64BITFIX //
658  if(bus_start == done) break;
659  src1 = bus_start + ptrdiff_t(words_per_bus - 1); // 64BITFIX //
660  }
661  }
662 }
663 
664 
666 // function set (2): Response
667 template<class DATAWORD> inline void
668 tlm_from_hostendian_aligned(tlm_generic_payload *txn, unsigned int sizeof_databus) {
669  int words_per_bus = sizeof_databus/sizeof(DATAWORD);
670  if(words_per_bus == 1) return;
671  int words = (txn->get_data_length())/sizeof(DATAWORD);
672  tlm_endian_context *tc = txn->template get_extension<tlm_endian_context>();
673 
674  if(txn->get_byte_enable_ptr() == 0) {
675  // no byte enables
676  if(txn->is_read()) {
677  // RD without byte enables. Copy data to original buffer
678  loop_aligned2<DATAWORD, &copy_d2<DATAWORD> >(
679  (DATAWORD *)(txn->get_data_ptr()),
680  0, (DATAWORD *)(tc->data_ptr), 0, words, words_per_bus);
681  }
682  } else {
683  // byte enables present
684  if(txn->is_read()) {
685  // RD with byte enables. Copy data qualified by byte-enables
686  loop_aligned2<DATAWORD, &copy_dbyb2<DATAWORD> >(
687  (DATAWORD *)(txn->get_data_ptr()),
688  (DATAWORD *)(txn->get_byte_enable_ptr()),
689  (DATAWORD *)(tc->data_ptr), 0, words, words_per_bus);
690  }
691  }
692 }
693 
694 
696 // function set (2): Request
697 template<class DATAWORD> inline void
698 tlm_to_hostendian_aligned(tlm_generic_payload *txn, unsigned int sizeof_databus) {
700  tc->from_f = &(tlm_from_hostendian_aligned<DATAWORD>);
701  tc->sizeof_databus = sizeof_databus;
702 
703  int words_per_bus = sizeof_databus/sizeof(DATAWORD);
704  if(words_per_bus == 1) return;
705  int words = (txn->get_data_length())/sizeof(DATAWORD);
706 
707  DATAWORD *original_be = (DATAWORD *)(txn->get_byte_enable_ptr());
708  DATAWORD *original_data = (DATAWORD *)(txn->get_data_ptr());
709 
710  // always allocate a new data buffer
711  tc->establish_dbuf(txn->get_data_length());
712  txn->set_data_ptr(tc->new_dbuf);
713 
714  if(original_be == 0) {
715  // no byte enables
716  if(txn->is_write()) {
717  // WR no byte enables. Copy data
718  loop_aligned2<DATAWORD, &copy_d2<DATAWORD> >(original_data, 0,
719  (DATAWORD *)(txn->get_data_ptr()), 0,
720  words, words_per_bus);
721  } else {
722  // RD no byte enables. Save original data pointer
723  tc->data_ptr = (uchar *)original_data;
724  }
725  } else {
726  // byte enables present
727  // allocate a new buffer for them
728  tc->establish_bebuf(txn->get_data_length());
729  txn->set_byte_enable_ptr(tc->new_bebuf);
731 
732  if(txn->is_write()) {
733  // WR with byte enables. Copy data and BEs
734  loop_aligned2<DATAWORD, &copy_db2<DATAWORD> >(original_data, original_be,
735  (DATAWORD *)(txn->get_data_ptr()),
736  (DATAWORD *)(txn->get_byte_enable_ptr()), words, words_per_bus);
737  } else {
738  // RD with byte enables. Save original data pointer
739  tc->data_ptr = (uchar *)original_data;
740  // Copy byte enables to new buffer
741  loop_aligned2<DATAWORD, &copy_d2<DATAWORD> >(original_be, 0,
742  (DATAWORD *)(txn->get_byte_enable_ptr()), 0,
743  words, words_per_bus);
744  }
745  }
746 }
747 
748 
749 
751 // function set (3): Response
752 template<class DATAWORD> inline void
753 tlm_from_hostendian_single(tlm_generic_payload *txn, unsigned int sizeof_databus) {
754  // nothing needs to be done here
755 }
756 
757 
759 // function set (3): Request
760 template<class DATAWORD> inline void
761 tlm_to_hostendian_single(tlm_generic_payload *txn, unsigned int sizeof_databus) {
763  tc->from_f = &(tlm_from_hostendian_single<DATAWORD>);
764  tc->sizeof_databus = sizeof_databus;
765 
766  // only need to change the address, always safe to work in-place
767  sc_dt::uint64 mask = sizeof_databus-1;
768  sc_dt::uint64 a = txn->get_address();
769  txn->set_address((a & ~mask) |
770  (sizeof_databus - (a & mask) - sizeof(DATAWORD)));
771 }
772 
773 
774 
776 // helper function which works for all responses
779  (*(tc->from_f))(txn, tc->sizeof_databus);
780 }
781 
782 
783 #ifndef TLM_END_CONV_DONT_UNDEF_UCHAR
784 #undef uchar
785 #endif
786 
787 } // namespace tlm
788 
789 
790 #endif // multiple-inclusion protection
791 
void tlm_from_hostendian(tlm_generic_payload *txn)
unsigned int get_byte_enable_length() const
Definition: tlm_gp.h:214
void set_address(const sc_dt::uint64 address)
Definition: tlm_gp.h:189
unsigned int get_data_length() const
Definition: tlm_gp.h:196
void get_extension(T *&ext) const
Definition: tlm_gp.h:334
void tlm_to_hostendian_aligned(tlm_generic_payload *txn, unsigned int sizeof_databus)
tlm_endian_context * establish_context(tlm_generic_payload *txn)
void tlm_from_hostendian_aligned(tlm_generic_payload *txn, unsigned int sizeof_databus)
void copy_from(tlm_extension_base const &)
unsigned char * get_byte_enable_ptr() const
Definition: tlm_gp.h:212
void copy_d2(D *src1, D *src2, D *dest1, D *dest2)
void set_byte_enable_length(const unsigned int byte_enable_length)
Definition: tlm_gp.h:215
void copy_dbyb0(uchar *src1, uchar *, uchar *dest1, uchar *dest2)
tlm_endian_context * next
void tlm_to_hostendian_generic(tlm_generic_payload *txn, unsigned int sizeof_databus)
void copy_b0(uchar *, uchar *src2, uchar *, uchar *dest2)
void copy_db0(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2)
void copy_dbytrue1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2)
void tlm_from_hostendian_word(tlm_generic_payload *txn, unsigned int sizeof_databus)
void set_data_ptr(unsigned char *data)
Definition: tlm_gp.h:193
void copy_dbyb1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2)
uint64_t uint64
tlm_endian_context * pop()
uint64 const sc_uint_base int b
void false_b1(uchar *dest1)
void copy_dbtrue0(uchar *src1, uchar *, uchar *dest1, uchar *dest2)
void establish_dbuf(int len)
void copy_d1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2)
void no_b1(uchar *dest1)
void set_streaming_width(const unsigned int streaming_width)
Definition: tlm_gp.h:209
unsigned char uchar
void push(tlm_endian_context *c)
#define TLM_BYTE_DISABLED
Definition: tlm_gp.h:112
bool is_write() const
Definition: tlm_gp.h:182
void loop_aligned2(D *src1, D *src2, D *dest1, D *dest2, int words, int words_per_bus)
tlm_endian_context * first
void copy_db2(D *src1, D *src2, D *dest1, D *dest2)
void tlm_from_hostendian_generic(tlm_generic_payload *txn, unsigned int sizeof_databus)
static D TLM_FALSE
void tlm_from_hostendian_single(tlm_generic_payload *txn, unsigned int sizeof_databus)
static D make_uchar_array(uchar c)
int loop_word1(int bytes_left, int len0, int lenN, int sizeof_databus, uchar *start, uchar *end, uchar *src, uchar *bsrc, uchar *dest, uchar *bdest)
void(* from_f)(tlm_generic_payload *txn, unsigned int sizeof_databus)
bool is_read() const
Definition: tlm_gp.h:180
void copy_db1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2)
sc_dt::uint64 get_address() const
Definition: tlm_gp.h:188
void tlm_to_hostendian_word(tlm_generic_payload *txn, unsigned int sizeof_databus)
#define TLM_BYTE_ENABLED
Definition: tlm_gp.h:113
void copy_btrue0(uchar *, uchar *, uchar *, uchar *dest2)
void tlm_to_hostendian_single(tlm_generic_payload *txn, unsigned int sizeof_databus)
void set_data_length(const unsigned int length)
Definition: tlm_gp.h:197
void copy_dbyb2(D *src1, D *src2, D *dest1, D *dest2)
tlm_extension_base * clone() const
void establish_bebuf(int len)
void copy_b1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2)
unsigned int get_streaming_width() const
Definition: tlm_gp.h:208
void true_b1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2)
void set_byte_enable_ptr(unsigned char *byte_enable)
Definition: tlm_gp.h:213
static tlm_endian_context_pool global_tlm_endian_context_pool
unsigned char * get_data_ptr() const
Definition: tlm_gp.h:192
T * set_extension(T *ext)
Definition: tlm_gp.h:313
void loop_generic0(int new_len, int new_stream_width, int orig_stream_width, int sizeof_databus, sc_dt::uint64 orig_start_address, sc_dt::uint64 new_start_address, int be_length, uchar *ie_data, uchar *ie_be, uchar *he_data, uchar *he_be)