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

Generated on Wed Dec 21 2022 10:22:42 for gem5 by doxygen 1.9.1