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