endian_conv.hh (13521:74fa3ac44057) endian_conv.hh (13586:008fe87c1ad4)
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
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 "tlm_core/2/generic_payload/gp.hh"
26#include "gp.hh"
27
28namespace tlm
29{
30
31/*
32Tranaction-Level Modelling
33Endianness Helper Functions
34
35DESCRIPTION
36A set of functions for helping users to get the endianness
37right in their TLM models of system initiators. These functions are
38for use within an initiator. They can not be used as-is outside
39an initiator because the extension used to store context will not work
40if cascaded, and they do not respect the generic payload mutability
41rules. However this code may be easily copied and adapted for use
42in bridges, etc..
43
44These functions are not compulsory. There are other legitimate ways to
45achieve the same functionality. If extra information is available at
46compile time about the nature of an initiator's transactions, this can
47be exploited to accelerate simulations by creating further functions
48similar to those in this file. In general a functional transaction can be
49described in more than one way by a TLM-2 GP object.
50
51The functions convert the endianness of a GP object, either on request or
52response. They should only be used when the initiator's endianness
53does not match the host's endianness. They assume 'arithmetic mode'
54meaning that within a data word the byte order is always host-endian.
55For non-arithmetic mode initiators they can be used with a data word
56size of 1 byte.
57
58All the functions are templates, for example:
59
60template<class DATAWORD> inline void
61 to_hostendian_generic(tlm_generic_payload *txn, int sizeof_databus)
62
63The template parameter provides the data word width. Having this as a class
64makes it easy to use it for copy and swap operations within the functions.
65If the assignment operator for this class is overloaded, the endianness
66conversion function may not have the desired effect.
67
68All the functions have the same signature except for different names.
69
70The principle is that a function to_hostendian_convtype() is called when the
71initiator-endian transaction is created, and the matching function
72from_hostendian_convtype() is called when the transaction is completed, for
73example before read data can be used. In some cases the from_ function is
74redundant but an empty function is provided anyway. It is strongly
75recommended that the from_ function is called, in case it ceases to be
76redundant in future versions of this code.
77
78No context needs to be managed outside the two functions, except that they
79must be called with the same template parameter and the same bus width.
80
81For initiator models that can not easily manage this context information,
82a single entry point for the from_ function is provided, which will be
83a little slower than calling the correct from_ function directly, as
84it can not be inlined.
85
86All functions assume power-of-2 bus and data word widths.
87
88Functions offered:
89
900) A pair of functions that work for almost all TLM2 GP transactions. The
91only limitations are that data and bus widths should be powers of 2, and that
92the data length should be an integer number of streaming widths and that the
93streaming width should be an integer number of data words.
94These functions always allocate new data and byte enable buffers and copy
95data one byte at a time.
96 tlm_to_hostendian_generic(tlm_generic_payload *txn, int sizeof_databus)
97 tlm_from_hostendian_generic(tlm_generic_payload *txn, int sizeof_databus)
98
991) A pair of functions that work for all transactions regardless of data and
100bus data sizes and address alignment except for the the following
101limitations:
102- byte-enables are supported only when byte-enable granularity is no finer
103than the data word (every data word is wholly enabled or wholly disabled)
104- byte-enable-length is not supported (if byte enables are present, the byte
105enable length must be equal to the data length).
106- streaming width is not supported
107- data word wider than bus word is not supported
108A new data buffer and a new byte enable buffer are always allocated. Byte
109enables are assumed to be needed even if not required for the original
110(unconverted) transaction. Data is copied to the new buffer on request
111(for writes) or on response (for reads). Copies are done word-by-word
112where possible.
113 tlm_to_hostendian_word(tlm_generic_payload *txn, int sizeof_databus)
114 tlm_from_hostendian_word(tlm_generic_payload *txn, int sizeof_databus)
115
1162) If the original transaction is both word and bus-aligned then this pair of
117functions can be used. It will complete faster than the generic function
118because the data reordering function is much simpler and no address
119conversion is required.
120The following limitations apply:
121- byte-enables are supported only when byte-enable granularity is no finer
122than the data word (every data word is wholly enabled or wholly disabled)
123- byte-enable-length is not supported (if byte enables are present, the byte
124enable length must be equal to the data length).
125- streaming width is not supported
126- data word wider than bus word is not supported
127- the transaction must be an integer number of bus words
128- the address must be aligned to the bus width
129 tlm_to_hostendian_aligned(tlm_generic_payload *txn, int sizeof_databus)
130 tlm_from_hostendian_aligned(tlm_generic_payload *txn, int sizeof_databus)
131
1323) For single word transactions that don't cross a bus word boundary it
133is always safe to work in-place and the conversion is very simple. Again,
134streaming width and byte-enable length are not supported, and byte-enables
135may not changes within a data word.
136 tlm_to_hostendian_single(tlm_generic_payload *txn, int sizeof_databus)
137 tlm_from_hostendian_single(tlm_generic_payload *txn, int sizeof_databus)
138
1394) A single entry point for accessing the correct from_ function without
140needing to store context.
141 tlm_from_hostendian(tlm_generic_payload *txn)
142*/
143
144///////////////////////////////////////////////////////////////////////////////
145// Generic Utilities
146
147class tlm_endian_context;
148
149class tlm_endian_context_pool
150{
151 public:
152 tlm_endian_context *first;
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
159static tlm_endian_context_pool global_tlm_endian_context_pool;
160
161// an extension to keep the information needed for reconversion of response
162class tlm_endian_context : public tlm_extension<tlm_endian_context>
163{
164 public:
165 tlm_endian_context() : dbuf_size(0), bebuf_size(0) {}
166
167 ~tlm_endian_context() {
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);
183 int sizeof_databus;
184
185 // Reordering buffers for data and byte-enables.
186 unsigned char *new_dbuf, *new_bebuf;
187 int dbuf_size, bebuf_size;
188
189 void
190 establish_dbuf(int len)
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
201 establish_bebuf(int len)
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.
212 void free() { global_tlm_endian_context_pool.push(this); }
213 tlm_extension_base *clone() const { return 0; }
214 void copy_from(tlm_extension_base const &) { return; }
215
216 // For pooling.
217 tlm_endian_context *next;
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
235inline tlm_endian_context *
236establish_context(tlm_generic_payload *txn)
237{
238 tlm_endian_context *tc = txn->get_extension<tlm_endian_context>();
239 if (tc == 0) {
240 tc = global_tlm_endian_context_pool.pop();
241 txn->set_extension(tc);
242 }
243 return tc;
244}
245
246inline tlm_endian_context_pool::tlm_endian_context_pool() : first(0) {}
247
248inline tlm_endian_context_pool::~tlm_endian_context_pool()
249{
250 while (first != 0) {
251 tlm_endian_context *next = first->next;
252 delete first;
253 first = next;
254 }
255}
256
257tlm_endian_context *
258tlm_endian_context_pool::pop()
259{
260 if (first == 0)
261 return new tlm_endian_context;
262 tlm_endian_context *r = first;
263 first = first->next;
264 return r;
265}
266
267void tlm_endian_context_pool::push(tlm_endian_context *c)
268{
269 c->next = first;
270 first = c;
271}
272
273
274// A set of constants for efficient filling of byte enables.
275template <class D>
276class 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
299template<class D>
300D tlm_bool<D>::TLM_TRUE = tlm_bool<D>::make_uchar_array(TLM_BYTE_ENABLED);
301template<class D>
302D tlm_bool<D>::TLM_FALSE = tlm_bool<D>::make_uchar_array(TLM_BYTE_DISABLED);
303
304
305
306inline void
307copy_db0(unsigned char *src1, unsigned char *src2,
308 unsigned char *dest1, unsigned char *dest2)
309{
310 *dest1 = *src1;
311 *dest2 = *src2;
312}
313
314inline void
315copy_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
322inline void
323copy_btrue0(unsigned char * /* src1 */, unsigned char * /* src2 */,
324 unsigned char * /* dest1 */, unsigned char *dest2)
325{
326 *dest2 = TLM_BYTE_ENABLED;
327}
328
329inline void
330copy_b0(unsigned char * /* src1 */, unsigned char *src2,
331 unsigned char * /* dest1 */, unsigned char *dest2)
332{
333 *dest2 = *src2;
334}
335
336inline void
337copy_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
345template <class D,
346 void COPY(unsigned char *he_d, unsigned char *he_b,
347 unsigned char *ie_d, unsigned char *ie_b)>
348inline void
349loop_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
375///////////////////////////////////////////////////////////////////////////////
376// function set (0): Response
377///////////////////////////////////////////////////////////////////////////////
378
379template <class DATAWORD>
380inline void
381tlm_from_hostendian_generic(tlm_generic_payload *txn,
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
396///////////////////////////////////////////////////////////////////////////////
397// function set (0): Request
398template <class DATAWORD>
399inline void
400tlm_to_hostendian_generic(tlm_generic_payload *txn,
401 unsigned int sizeof_databus)
402{
403 tlm_endian_context *tc = establish_context(txn);
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
472///////////////////////////////////////////////////////////////////////////////
473// function set (1): Utilities
474///////////////////////////////////////////////////////////////////////////////
475
476template <class D>
477inline void
478copy_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
485template <class D>
486inline void
487copy_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
494template <class D>
495inline void
496true_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
502template <class D>
503inline void
504copy_b1(unsigned char *src1, unsigned char *src2,
505 unsigned char *dest1, unsigned char *dest2)
506{
507 *((D *)dest2) = *((D *)src2);
508}
509
510template <class D>
511inline void
512copy_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
519template <class D>
520inline void
521copy_dbytrue1(unsigned char *src1, unsigned char *src2,
522 unsigned char *dest1, unsigned char *dest2)
523{
524 *((D *)src1) = *((D *)dest1);
525}
526
527template<class D>
528inline void
529false_b1(unsigned char *dest1)
530{
531 *((D *)dest1) = tlm_bool<D>::TLM_FALSE;
532}
533
534template<class D>
535inline void
536no_b1(unsigned char *dest1)
537{}
538
539template<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)>
546inline int
547loop_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
612///////////////////////////////////////////////////////////////////////////////
613// function set (1): Response
614///////////////////////////////////////////////////////////////////////////////
615
616template <class DATAWORD>
617inline void
618tlm_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
655///////////////////////////////////////////////////////////////////////////////
656// function set (1): Request
657///////////////////////////////////////////////////////////////////////////////
658
659template <class DATAWORD>
660inline void
661tlm_to_hostendian_word(tlm_generic_payload *txn, unsigned int sizeof_databus)
662{
663 tlm_endian_context *tc = establish_context(txn);
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 }
737 txn->set_byte_enable_length(txn->get_data_length());
738 txn->set_streaming_width(txn->get_data_length());
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
746///////////////////////////////////////////////////////////////////////////////
747// function set (2): Utilities
748///////////////////////////////////////////////////////////////////////////////
749
750template <class D>
751inline void copy_d2(D *src1, D *src2, D *dest1, D *dest2) { *dest1 = *src1; }
752
753template <class D>
754inline void
755copy_db2(D *src1, D *src2, D *dest1, D *dest2)
756{
757 *dest1 = *src1;
758 *dest2 = *src2;
759}
760
761template <class D>
762inline void
763copy_dbyb2(D *src1, D *src2, D *dest1, D *dest2)
764{
765 if (tlm_bool<D>(*src2))
766 *dest1 = *src1;
767}
768
769template <class D, void COPY(D *src1, D *src2, D *dest1, D *dest2)>
770inline void
771loop_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
797///////////////////////////////////////////////////////////////////////////////
798// function set (2): Response
799///////////////////////////////////////////////////////////////////////////////
800
801template <class DATAWORD>
802inline void
803tlm_from_hostendian_aligned(
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
833///////////////////////////////////////////////////////////////////////////////
834// function set (2): Request
835///////////////////////////////////////////////////////////////////////////////
836
837template <class DATAWORD>
838inline void
839tlm_to_hostendian_aligned(
840 tlm_generic_payload *txn, unsigned int sizeof_databus)
841{
842 tlm_endian_context *tc = establish_context(txn);
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);
874 txn->set_byte_enable_length(txn->get_data_length());
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
896///////////////////////////////////////////////////////////////////////////////
897// function set (3): Response
898///////////////////////////////////////////////////////////////////////////////
899
900template <class DATAWORD>
901inline void
902tlm_from_hostendian_single(
903 tlm_generic_payload *txn, unsigned int sizeof_databus)
904{}
905
906
907///////////////////////////////////////////////////////////////////////////////
908// function set (3): Request
909///////////////////////////////////////////////////////////////////////////////
910
911template <class DATAWORD>
912inline void
913tlm_to_hostendian_single(tlm_generic_payload *txn, unsigned int sizeof_databus)
914{
915 tlm_endian_context *tc = establish_context(txn);
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
928///////////////////////////////////////////////////////////////////////////////
929// helper function which works for all responses
930///////////////////////////////////////////////////////////////////////////////
931
932inline void
933tlm_from_hostendian(tlm_generic_payload *txn)
934{
935 tlm_endian_context *tc = txn->get_extension<tlm_endian_context>();
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__ */
27
28namespace tlm
29{
30
31/*
32Tranaction-Level Modelling
33Endianness Helper Functions
34
35DESCRIPTION
36A set of functions for helping users to get the endianness
37right in their TLM models of system initiators. These functions are
38for use within an initiator. They can not be used as-is outside
39an initiator because the extension used to store context will not work
40if cascaded, and they do not respect the generic payload mutability
41rules. However this code may be easily copied and adapted for use
42in bridges, etc..
43
44These functions are not compulsory. There are other legitimate ways to
45achieve the same functionality. If extra information is available at
46compile time about the nature of an initiator's transactions, this can
47be exploited to accelerate simulations by creating further functions
48similar to those in this file. In general a functional transaction can be
49described in more than one way by a TLM-2 GP object.
50
51The functions convert the endianness of a GP object, either on request or
52response. They should only be used when the initiator's endianness
53does not match the host's endianness. They assume 'arithmetic mode'
54meaning that within a data word the byte order is always host-endian.
55For non-arithmetic mode initiators they can be used with a data word
56size of 1 byte.
57
58All the functions are templates, for example:
59
60template<class DATAWORD> inline void
61 to_hostendian_generic(tlm_generic_payload *txn, int sizeof_databus)
62
63The template parameter provides the data word width. Having this as a class
64makes it easy to use it for copy and swap operations within the functions.
65If the assignment operator for this class is overloaded, the endianness
66conversion function may not have the desired effect.
67
68All the functions have the same signature except for different names.
69
70The principle is that a function to_hostendian_convtype() is called when the
71initiator-endian transaction is created, and the matching function
72from_hostendian_convtype() is called when the transaction is completed, for
73example before read data can be used. In some cases the from_ function is
74redundant but an empty function is provided anyway. It is strongly
75recommended that the from_ function is called, in case it ceases to be
76redundant in future versions of this code.
77
78No context needs to be managed outside the two functions, except that they
79must be called with the same template parameter and the same bus width.
80
81For initiator models that can not easily manage this context information,
82a single entry point for the from_ function is provided, which will be
83a little slower than calling the correct from_ function directly, as
84it can not be inlined.
85
86All functions assume power-of-2 bus and data word widths.
87
88Functions offered:
89
900) A pair of functions that work for almost all TLM2 GP transactions. The
91only limitations are that data and bus widths should be powers of 2, and that
92the data length should be an integer number of streaming widths and that the
93streaming width should be an integer number of data words.
94These functions always allocate new data and byte enable buffers and copy
95data one byte at a time.
96 tlm_to_hostendian_generic(tlm_generic_payload *txn, int sizeof_databus)
97 tlm_from_hostendian_generic(tlm_generic_payload *txn, int sizeof_databus)
98
991) A pair of functions that work for all transactions regardless of data and
100bus data sizes and address alignment except for the the following
101limitations:
102- byte-enables are supported only when byte-enable granularity is no finer
103than the data word (every data word is wholly enabled or wholly disabled)
104- byte-enable-length is not supported (if byte enables are present, the byte
105enable length must be equal to the data length).
106- streaming width is not supported
107- data word wider than bus word is not supported
108A new data buffer and a new byte enable buffer are always allocated. Byte
109enables are assumed to be needed even if not required for the original
110(unconverted) transaction. Data is copied to the new buffer on request
111(for writes) or on response (for reads). Copies are done word-by-word
112where possible.
113 tlm_to_hostendian_word(tlm_generic_payload *txn, int sizeof_databus)
114 tlm_from_hostendian_word(tlm_generic_payload *txn, int sizeof_databus)
115
1162) If the original transaction is both word and bus-aligned then this pair of
117functions can be used. It will complete faster than the generic function
118because the data reordering function is much simpler and no address
119conversion is required.
120The following limitations apply:
121- byte-enables are supported only when byte-enable granularity is no finer
122than the data word (every data word is wholly enabled or wholly disabled)
123- byte-enable-length is not supported (if byte enables are present, the byte
124enable length must be equal to the data length).
125- streaming width is not supported
126- data word wider than bus word is not supported
127- the transaction must be an integer number of bus words
128- the address must be aligned to the bus width
129 tlm_to_hostendian_aligned(tlm_generic_payload *txn, int sizeof_databus)
130 tlm_from_hostendian_aligned(tlm_generic_payload *txn, int sizeof_databus)
131
1323) For single word transactions that don't cross a bus word boundary it
133is always safe to work in-place and the conversion is very simple. Again,
134streaming width and byte-enable length are not supported, and byte-enables
135may not changes within a data word.
136 tlm_to_hostendian_single(tlm_generic_payload *txn, int sizeof_databus)
137 tlm_from_hostendian_single(tlm_generic_payload *txn, int sizeof_databus)
138
1394) A single entry point for accessing the correct from_ function without
140needing to store context.
141 tlm_from_hostendian(tlm_generic_payload *txn)
142*/
143
144///////////////////////////////////////////////////////////////////////////////
145// Generic Utilities
146
147class tlm_endian_context;
148
149class tlm_endian_context_pool
150{
151 public:
152 tlm_endian_context *first;
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
159static tlm_endian_context_pool global_tlm_endian_context_pool;
160
161// an extension to keep the information needed for reconversion of response
162class tlm_endian_context : public tlm_extension<tlm_endian_context>
163{
164 public:
165 tlm_endian_context() : dbuf_size(0), bebuf_size(0) {}
166
167 ~tlm_endian_context() {
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);
183 int sizeof_databus;
184
185 // Reordering buffers for data and byte-enables.
186 unsigned char *new_dbuf, *new_bebuf;
187 int dbuf_size, bebuf_size;
188
189 void
190 establish_dbuf(int len)
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
201 establish_bebuf(int len)
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.
212 void free() { global_tlm_endian_context_pool.push(this); }
213 tlm_extension_base *clone() const { return 0; }
214 void copy_from(tlm_extension_base const &) { return; }
215
216 // For pooling.
217 tlm_endian_context *next;
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
235inline tlm_endian_context *
236establish_context(tlm_generic_payload *txn)
237{
238 tlm_endian_context *tc = txn->get_extension<tlm_endian_context>();
239 if (tc == 0) {
240 tc = global_tlm_endian_context_pool.pop();
241 txn->set_extension(tc);
242 }
243 return tc;
244}
245
246inline tlm_endian_context_pool::tlm_endian_context_pool() : first(0) {}
247
248inline tlm_endian_context_pool::~tlm_endian_context_pool()
249{
250 while (first != 0) {
251 tlm_endian_context *next = first->next;
252 delete first;
253 first = next;
254 }
255}
256
257tlm_endian_context *
258tlm_endian_context_pool::pop()
259{
260 if (first == 0)
261 return new tlm_endian_context;
262 tlm_endian_context *r = first;
263 first = first->next;
264 return r;
265}
266
267void tlm_endian_context_pool::push(tlm_endian_context *c)
268{
269 c->next = first;
270 first = c;
271}
272
273
274// A set of constants for efficient filling of byte enables.
275template <class D>
276class 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
299template<class D>
300D tlm_bool<D>::TLM_TRUE = tlm_bool<D>::make_uchar_array(TLM_BYTE_ENABLED);
301template<class D>
302D tlm_bool<D>::TLM_FALSE = tlm_bool<D>::make_uchar_array(TLM_BYTE_DISABLED);
303
304
305
306inline void
307copy_db0(unsigned char *src1, unsigned char *src2,
308 unsigned char *dest1, unsigned char *dest2)
309{
310 *dest1 = *src1;
311 *dest2 = *src2;
312}
313
314inline void
315copy_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
322inline void
323copy_btrue0(unsigned char * /* src1 */, unsigned char * /* src2 */,
324 unsigned char * /* dest1 */, unsigned char *dest2)
325{
326 *dest2 = TLM_BYTE_ENABLED;
327}
328
329inline void
330copy_b0(unsigned char * /* src1 */, unsigned char *src2,
331 unsigned char * /* dest1 */, unsigned char *dest2)
332{
333 *dest2 = *src2;
334}
335
336inline void
337copy_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
345template <class D,
346 void COPY(unsigned char *he_d, unsigned char *he_b,
347 unsigned char *ie_d, unsigned char *ie_b)>
348inline void
349loop_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
375///////////////////////////////////////////////////////////////////////////////
376// function set (0): Response
377///////////////////////////////////////////////////////////////////////////////
378
379template <class DATAWORD>
380inline void
381tlm_from_hostendian_generic(tlm_generic_payload *txn,
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
396///////////////////////////////////////////////////////////////////////////////
397// function set (0): Request
398template <class DATAWORD>
399inline void
400tlm_to_hostendian_generic(tlm_generic_payload *txn,
401 unsigned int sizeof_databus)
402{
403 tlm_endian_context *tc = establish_context(txn);
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
472///////////////////////////////////////////////////////////////////////////////
473// function set (1): Utilities
474///////////////////////////////////////////////////////////////////////////////
475
476template <class D>
477inline void
478copy_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
485template <class D>
486inline void
487copy_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
494template <class D>
495inline void
496true_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
502template <class D>
503inline void
504copy_b1(unsigned char *src1, unsigned char *src2,
505 unsigned char *dest1, unsigned char *dest2)
506{
507 *((D *)dest2) = *((D *)src2);
508}
509
510template <class D>
511inline void
512copy_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
519template <class D>
520inline void
521copy_dbytrue1(unsigned char *src1, unsigned char *src2,
522 unsigned char *dest1, unsigned char *dest2)
523{
524 *((D *)src1) = *((D *)dest1);
525}
526
527template<class D>
528inline void
529false_b1(unsigned char *dest1)
530{
531 *((D *)dest1) = tlm_bool<D>::TLM_FALSE;
532}
533
534template<class D>
535inline void
536no_b1(unsigned char *dest1)
537{}
538
539template<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)>
546inline int
547loop_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
612///////////////////////////////////////////////////////////////////////////////
613// function set (1): Response
614///////////////////////////////////////////////////////////////////////////////
615
616template <class DATAWORD>
617inline void
618tlm_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
655///////////////////////////////////////////////////////////////////////////////
656// function set (1): Request
657///////////////////////////////////////////////////////////////////////////////
658
659template <class DATAWORD>
660inline void
661tlm_to_hostendian_word(tlm_generic_payload *txn, unsigned int sizeof_databus)
662{
663 tlm_endian_context *tc = establish_context(txn);
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 }
737 txn->set_byte_enable_length(txn->get_data_length());
738 txn->set_streaming_width(txn->get_data_length());
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
746///////////////////////////////////////////////////////////////////////////////
747// function set (2): Utilities
748///////////////////////////////////////////////////////////////////////////////
749
750template <class D>
751inline void copy_d2(D *src1, D *src2, D *dest1, D *dest2) { *dest1 = *src1; }
752
753template <class D>
754inline void
755copy_db2(D *src1, D *src2, D *dest1, D *dest2)
756{
757 *dest1 = *src1;
758 *dest2 = *src2;
759}
760
761template <class D>
762inline void
763copy_dbyb2(D *src1, D *src2, D *dest1, D *dest2)
764{
765 if (tlm_bool<D>(*src2))
766 *dest1 = *src1;
767}
768
769template <class D, void COPY(D *src1, D *src2, D *dest1, D *dest2)>
770inline void
771loop_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
797///////////////////////////////////////////////////////////////////////////////
798// function set (2): Response
799///////////////////////////////////////////////////////////////////////////////
800
801template <class DATAWORD>
802inline void
803tlm_from_hostendian_aligned(
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
833///////////////////////////////////////////////////////////////////////////////
834// function set (2): Request
835///////////////////////////////////////////////////////////////////////////////
836
837template <class DATAWORD>
838inline void
839tlm_to_hostendian_aligned(
840 tlm_generic_payload *txn, unsigned int sizeof_databus)
841{
842 tlm_endian_context *tc = establish_context(txn);
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);
874 txn->set_byte_enable_length(txn->get_data_length());
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
896///////////////////////////////////////////////////////////////////////////////
897// function set (3): Response
898///////////////////////////////////////////////////////////////////////////////
899
900template <class DATAWORD>
901inline void
902tlm_from_hostendian_single(
903 tlm_generic_payload *txn, unsigned int sizeof_databus)
904{}
905
906
907///////////////////////////////////////////////////////////////////////////////
908// function set (3): Request
909///////////////////////////////////////////////////////////////////////////////
910
911template <class DATAWORD>
912inline void
913tlm_to_hostendian_single(tlm_generic_payload *txn, unsigned int sizeof_databus)
914{
915 tlm_endian_context *tc = establish_context(txn);
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
928///////////////////////////////////////////////////////////////////////////////
929// helper function which works for all responses
930///////////////////////////////////////////////////////////////////////////////
931
932inline void
933tlm_from_hostendian(tlm_generic_payload *txn)
934{
935 tlm_endian_context *tc = txn->get_extension<tlm_endian_context>();
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__ */