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 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, ©_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, ©_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, ©_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, ©_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, ©_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, ©_dbytrue1<DATAWORD>, 638 ©_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, ©_dbyb1<DATAWORD>, 644 ©_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, ©_b1<DATAWORD>, 706 ©_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, ©_d1<DATAWORD>, 720 ©_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, ©_db1<DATAWORD>, 729 ©_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, ©_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, ©_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, ©_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, ©_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, ©_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__ */ 942