tlm_endian_conv.h revision 12027
1/***************************************************************************** 2 3 Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 4 more contributor license agreements. See the NOTICE file distributed 5 with this work for additional information regarding copyright ownership. 6 Accellera licenses this file to you under the Apache License, Version 2.0 7 (the "License"); you may not use this file except in compliance with the 8 License. You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 implied. See the License for the specific language governing 16 permissions and limitations under the License. 17 18 *****************************************************************************/ 19 20 21#ifndef __TLM_ENDIAN_CONV_H__ 22#define __TLM_ENDIAN_CONV_H__ 23 24#include <systemc> 25#include "tlm_core/tlm_2/tlm_generic_payload/tlm_gp.h" 26 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 146#ifndef uchar 147#define uchar unsigned char 148#else 149#define TLM_END_CONV_DONT_UNDEF_UCHAR 150#endif 151 152 153/////////////////////////////////////////////////////////////////////////////// 154// Generic Utilities 155 156class tlm_endian_context; 157class tlm_endian_context_pool { 158 public: 159 tlm_endian_context *first; 160 inline tlm_endian_context_pool(); 161 inline ~tlm_endian_context_pool(); 162 inline tlm_endian_context *pop(); 163 inline void push(tlm_endian_context *c); 164}; 165static tlm_endian_context_pool global_tlm_endian_context_pool; 166 167// an extension to keep the information needed for reconversion of response 168class tlm_endian_context : public tlm_extension<tlm_endian_context> { 169 public: 170 tlm_endian_context() : dbuf_size(0), bebuf_size(0) {} 171 ~tlm_endian_context() { 172 if(dbuf_size > 0) delete [] new_dbuf; 173 if(bebuf_size > 0) delete [] new_bebuf; 174 } 175 176 sc_dt::uint64 address; // used by generic, word 177 sc_dt::uint64 new_address; // used by generic 178 uchar *data_ptr; // used by generic, word, aligned 179 uchar *byte_enable; // used by word 180 int length; // used by generic, word 181 int stream_width; // used by generic 182 183 // used by common entry point on response 184 void (*from_f)(tlm_generic_payload *txn, unsigned int sizeof_databus); 185 int sizeof_databus; 186 187 // reordering buffers for data and byte-enables 188 uchar *new_dbuf, *new_bebuf; 189 int dbuf_size, bebuf_size; 190 void establish_dbuf(int len) { 191 if(len <= dbuf_size) return; 192 if(dbuf_size > 0) delete [] new_dbuf; 193 new_dbuf = new uchar[len]; 194 dbuf_size = len; 195 } 196 void establish_bebuf(int len) { 197 if(len <= bebuf_size) return; 198 if(bebuf_size > 0) delete [] new_bebuf; 199 new_bebuf = new uchar[len]; 200 bebuf_size = len; 201 } 202 203 // required for extension management 204 void free() { 205 global_tlm_endian_context_pool.push(this); 206 } 207 tlm_extension_base* clone() const {return 0;} 208 void copy_from(tlm_extension_base const &) {return;} 209 210 // for pooling 211 tlm_endian_context *next; 212}; 213// Assumptions about transaction contexts: 214// 1) only the address attribute of a transaction 215// is mutable. all other attributes are unchanged from the request to 216// response side conversion. 217// 2) the conversion functions in this file do not respect the mutability 218// rules and do not put the transaction back into its original state after 219// completion. so if the initiator has any cleaning up to do (eg of byte 220// enable buffers), it needs to store its own context. the transaction 221// returned to the initiator may contain pointers to data and byte enable 222// that can/must not be deleted. 223// 3) the conversion functions in this file use an extension to store 224// context information. they do not remove this extension. the initiator 225// should not remove it unless it deletes the generic payload 226// object. 227 228inline tlm_endian_context *establish_context(tlm_generic_payload *txn) { 229 tlm_endian_context *tc = txn->get_extension<tlm_endian_context>(); 230 if(tc == 0) { 231 tc = global_tlm_endian_context_pool.pop(); 232 txn->set_extension(tc); 233 } 234 return tc; 235} 236 237inline tlm_endian_context_pool::tlm_endian_context_pool() : first(0) {} 238 239inline tlm_endian_context_pool::~tlm_endian_context_pool() { 240 while(first != 0) { 241 tlm_endian_context *next = first->next; 242 delete first; 243 first = next; 244 } 245} 246 247tlm_endian_context *tlm_endian_context_pool::pop() { 248 if(first == 0) return new tlm_endian_context; 249 tlm_endian_context *r = first; 250 first = first->next; 251 return r; 252} 253 254void tlm_endian_context_pool::push(tlm_endian_context *c) { 255 c->next = first; 256 first = c; 257} 258 259 260// a set of constants for efficient filling of byte enables 261template<class D> class tlm_bool { 262 public: 263 static D TLM_TRUE; 264 static D TLM_FALSE; 265 static D make_uchar_array(uchar c) { 266 D d; 267 uchar *tmp = (uchar *)(&d); 268 for(ptrdiff_t i=0; i!=sizeof(D); i++) tmp[i] = c; // 64BITFIX negligable risk but easy fix // 269 return d; 270 } 271 // also provides an syntax-efficient tester, using a 272 // copy constuctor and an implicit cast to boolean 273 tlm_bool(D &d) : b(*((uchar*)&d) != TLM_BYTE_DISABLED) {} 274 operator bool() const {return b;} 275 private: 276 bool b; 277}; 278 279template<class D> D tlm_bool<D>::TLM_TRUE 280 = tlm_bool<D>::make_uchar_array(TLM_BYTE_ENABLED); 281template<class D> D tlm_bool<D>::TLM_FALSE 282 = tlm_bool<D>::make_uchar_array(TLM_BYTE_DISABLED); 283 284 285 286/////////////////////////////////////////////////////////////////////////////// 287// function set (0): Utilities 288inline void copy_db0(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) { 289 *dest1 = *src1; 290 *dest2 = *src2; 291} 292 293inline void copy_dbtrue0(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) { 294 *dest1 = *src1; 295 *dest2 = TLM_BYTE_ENABLED; 296} 297 298inline void copy_btrue0(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) { 299 *dest2 = TLM_BYTE_ENABLED; 300} 301 302inline void copy_b0(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) { 303 *dest2 = *src2; 304} 305 306inline void copy_dbyb0(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) { 307 if(*dest2 == TLM_BYTE_ENABLED) *src1 = *dest1; 308} 309 310 311template<class D, 312 void COPY(uchar *he_d, uchar *he_b, uchar *ie_d, uchar *ie_b)> 313inline void loop_generic0(int new_len, int new_stream_width, 314 int orig_stream_width, int sizeof_databus, 315 sc_dt::uint64 orig_start_address, sc_dt::uint64 new_start_address, int be_length, 316 uchar *ie_data, uchar *ie_be, uchar *he_data, uchar *he_be) { 317 318 for(int orig_sword = 0, new_sword = 0; new_sword < new_len; 319 new_sword += new_stream_width, orig_sword += orig_stream_width) { 320 321 sc_dt::uint64 ie_addr = orig_start_address; 322 for(int orig_dword = orig_sword; 323 orig_dword < orig_sword + orig_stream_width; orig_dword += sizeof(D)) { 324 325 for(int curr_byte = orig_dword + sizeof(D) - 1; 326 curr_byte >= orig_dword; curr_byte--) { 327 328 ptrdiff_t he_index = ((ie_addr++) ^ (sizeof_databus - 1)) 329 - new_start_address + new_sword; // 64BITFIX // 330 COPY(ie_data+curr_byte, 331 ie_be+(curr_byte % be_length), // 64BITRISK no risk of overflow, always positive // 332 he_data+he_index, he_be+he_index); 333 } 334 } 335 } 336} 337 338 339/////////////////////////////////////////////////////////////////////////////// 340// function set (0): Response 341template<class DATAWORD> inline void 342tlm_from_hostendian_generic(tlm_generic_payload *txn, unsigned int sizeof_databus) { 343 if(txn->is_read()) { 344 tlm_endian_context *tc = txn->template get_extension<tlm_endian_context>(); 345 loop_generic0<DATAWORD, ©_dbyb0>(txn->get_data_length(), 346 txn->get_streaming_width(), tc->stream_width, sizeof_databus, tc->address, 347 tc->new_address, txn->get_data_length(), tc->data_ptr, 0, txn->get_data_ptr(), 348 txn->get_byte_enable_ptr()); 349 } 350} 351 352 353/////////////////////////////////////////////////////////////////////////////// 354// function set (0): Request 355template<class DATAWORD> inline void 356tlm_to_hostendian_generic(tlm_generic_payload *txn, unsigned int sizeof_databus) { 357 tlm_endian_context *tc = establish_context(txn); 358 tc->from_f = &(tlm_from_hostendian_generic<DATAWORD>); 359 tc->sizeof_databus = sizeof_databus; 360 361 // calculate new size: nr stream words multiplied by big enough stream width 362 int s_width = txn->get_streaming_width(); 363 int length = txn->get_data_length(); 364 if(s_width >= length) s_width = length; 365 int nr_stream_words = length/s_width; 366 367 // find out in which bus word the stream word starts and ends 368 sc_dt::uint64 new_address = (txn->get_address() & ~(sizeof_databus - 1)); 369 sc_dt::uint64 end_address = ((txn->get_address() + s_width - 1) 370 & ~(sizeof_databus - 1)); 371 372 int new_stream_width = end_address - new_address + sizeof_databus; 373 int new_length = new_stream_width * nr_stream_words; 374 375 // store context 376 tc->data_ptr = txn->get_data_ptr(); 377 tc->address = txn->get_address(); 378 tc->new_address = new_address; 379 tc->stream_width = s_width; 380 uchar *orig_be = txn->get_byte_enable_ptr(); 381 int orig_be_length = txn->get_byte_enable_length(); 382 383 // create data and byte-enable buffers 384 txn->set_address(new_address); 385 tc->establish_dbuf(new_length); 386 txn->set_data_ptr(tc->new_dbuf); 387 tc->establish_bebuf(new_length); 388 txn->set_byte_enable_ptr(tc->new_bebuf); 389 memset(txn->get_byte_enable_ptr(), TLM_BYTE_DISABLED, new_length); 390 txn->set_streaming_width(new_stream_width); 391 txn->set_data_length(new_length); 392 txn->set_byte_enable_length(new_length); 393 394 // copy data and/or byte enables 395 if(txn->is_write()) { 396 if(orig_be == 0) { 397 loop_generic0<DATAWORD, ©_dbtrue0>(new_length, 398 new_stream_width, s_width, sizeof_databus, tc->address, 399 new_address, new_length, tc->data_ptr, 0, txn->get_data_ptr(), 400 txn->get_byte_enable_ptr()); 401 } else { 402 loop_generic0<DATAWORD, ©_db0>(new_length, 403 new_stream_width, s_width, sizeof_databus, tc->address, 404 new_address, orig_be_length, tc->data_ptr, orig_be, txn->get_data_ptr(), 405 txn->get_byte_enable_ptr()); 406 } 407 } else { // read transaction 408 if(orig_be == 0) { 409 loop_generic0<DATAWORD, ©_btrue0>(new_length, 410 new_stream_width, s_width, sizeof_databus, tc->address, 411 new_address, new_length, tc->data_ptr, 0, txn->get_data_ptr(), 412 txn->get_byte_enable_ptr()); 413 } else { 414 loop_generic0<DATAWORD, ©_b0>(new_length, 415 new_stream_width, s_width, sizeof_databus, tc->address, 416 new_address, orig_be_length, tc->data_ptr, orig_be, txn->get_data_ptr(), 417 txn->get_byte_enable_ptr()); 418 } 419 } 420} 421 422 423 424/////////////////////////////////////////////////////////////////////////////// 425// function set (1): Utilities 426template<class D> 427inline void copy_d1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) { 428 *((D *)dest1) = *((D *)src1); 429 *((D *)dest2) = tlm_bool<D>::TLM_TRUE; 430} 431 432template<class D> 433inline void copy_db1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) { 434 *((D *)dest1) = *((D *)src1); 435 *((D *)dest2) = *((D *)src2); 436} 437 438template<class D> 439inline void true_b1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) { 440 *((D *)dest2) = tlm_bool<D>::TLM_TRUE; 441} 442 443template<class D> 444inline void copy_b1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) { 445 *((D *)dest2) = *((D *)src2); 446} 447 448template<class D> 449inline void copy_dbyb1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) { 450 if(*src2 != TLM_BYTE_DISABLED) *((D *)src1) = *((D *)dest1); 451} 452 453template<class D> 454inline void copy_dbytrue1(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) { 455 *((D *)src1) = *((D *)dest1); 456} 457 458template<class D> inline void false_b1(uchar *dest1) { 459 *((D *)dest1) = tlm_bool<D>::TLM_FALSE; 460} 461 462template<class D> inline void no_b1(uchar *dest1) { 463} 464 465template<class D, 466 void COPY(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2), 467 void COPYuchar(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2), 468 void FILLFALSE(uchar *dest1), void FILLFALSEuchar(uchar *dest1)> 469inline int loop_word1( 470 int bytes_left, int len0, int lenN, int sizeof_databus, 471 uchar *start, uchar *end, uchar *src, uchar *bsrc, uchar *dest, uchar *bdest) { 472 ptrdiff_t d2b_src = bsrc - src; // 64BITFIX was int // 473 ptrdiff_t d2b_dest = bdest - dest; // 64BITFIX was int // 474 uchar *original_dest = dest; 475 476 while(true) { 477 // len0 bytes at start of a bus word 478 if((src >= start) && (src < end)) { 479 for(int i=0; i<len0; i++) { 480 COPYuchar(src, src+d2b_src, dest, dest+d2b_dest); 481 src++; 482 dest++; 483 } 484 bytes_left -= len0; 485 if(bytes_left <= 0) return int(dest - original_dest); 486 } else { 487 for(int i=0; i<len0; i++) { 488 FILLFALSEuchar(dest+d2b_dest); 489 src++; 490 dest++; 491 } 492 } 493 src -= 2 * sizeof(D); 494 495 // sequence of full data word fragments 496 for(unsigned int i=1; i<sizeof_databus/sizeof(D); i++) { 497 if((src >= start) && (src < end)) { 498 COPY(src, src+d2b_src, dest, dest+d2b_dest); 499 bytes_left -= sizeof(D); 500 } else { 501 FILLFALSE(dest+d2b_dest); 502 } 503 dest += sizeof(D); 504 if(bytes_left <= 0) return int(dest - original_dest); 505 src -= sizeof(D); 506 } 507 508 // lenN bytes at end of bus word 509 if((src >= start) && (src < end)) { 510 for(int i=0; i<lenN; i++) { 511 COPYuchar(src, src+d2b_src, dest, dest+d2b_dest); 512 src++; 513 dest++; 514 } 515 bytes_left -= lenN; 516 if(bytes_left <= 0) return int(dest - original_dest); 517 } else { 518 for(int i=0; i<lenN; i++) { 519 FILLFALSEuchar(dest+d2b_dest); 520 src++; 521 dest++; 522 } 523 } 524 src += 2 * sizeof_databus; 525 } 526} 527 528 529/////////////////////////////////////////////////////////////////////////////// 530// function set (1): Response 531template<class DATAWORD> inline void 532tlm_from_hostendian_word(tlm_generic_payload *txn, unsigned int sizeof_databus) { 533 if(txn->is_read()) { 534 tlm_endian_context *tc = txn->template get_extension<tlm_endian_context>(); 535 sc_dt::uint64 b_mask = sizeof_databus - 1; 536 int d_mask = sizeof(DATAWORD) - 1; 537 int a_offset = static_cast<int>(tc->address & b_mask); 538 int len0 = (sizeof_databus - a_offset) & d_mask; 539 int lenN = sizeof(DATAWORD) - len0; 540 uchar *d_start = tc->data_ptr; 541 uchar *d_end = ptrdiff_t(tc->length) + d_start; // 64BITFIX probably redundant // 542 uchar *d = ptrdiff_t(((sizeof_databus - a_offset) & ~d_mask) + lenN) + d_start; // 64BITFIX probably redundant // 543 544 // iterate over transaction copying data qualified by byte-enables 545 if(tc->byte_enable == 0) { 546 loop_word1<DATAWORD, ©_dbytrue1<DATAWORD>, 547 ©_dbytrue1<uchar>, &no_b1<DATAWORD>, &no_b1<uchar> >( 548 tc->length, len0, lenN, sizeof_databus, d_start, d_end, d, 549 0, txn->get_data_ptr(), 0); 550 } else { 551 loop_word1<DATAWORD, ©_dbyb1<DATAWORD>, 552 ©_dbyb1<uchar>, &no_b1<DATAWORD>, &no_b1<uchar> >( 553 tc->length, len0, lenN, sizeof_databus, d_start, d_end, d, 554 tc->byte_enable - d_start + d, txn->get_data_ptr(), 0); 555 } 556 } 557} 558 559 560/////////////////////////////////////////////////////////////////////////////// 561// function set (1): Request 562template<class DATAWORD> inline void 563tlm_to_hostendian_word(tlm_generic_payload *txn, unsigned int sizeof_databus) { 564 tlm_endian_context *tc = establish_context(txn); 565 tc->from_f = &(tlm_from_hostendian_word<DATAWORD>); 566 tc->sizeof_databus = sizeof_databus; 567 568 sc_dt::uint64 b_mask = sizeof_databus - 1; 569 int d_mask = sizeof(DATAWORD) - 1; 570 sc_dt::uint64 a_aligned = txn->get_address() & ~b_mask; 571 int a_offset = static_cast<int>(txn->get_address() & b_mask); 572 int len0 = (sizeof_databus - a_offset) & d_mask; 573 int lenN = sizeof(DATAWORD) - len0; 574 uchar *d_start = txn->get_data_ptr(); 575 uchar *d_end = ptrdiff_t(txn->get_data_length()) + d_start; // 64BITFIX probably redundant // 576 uchar *d = ptrdiff_t(((sizeof_databus - a_offset) & ~d_mask) + lenN) + d_start; // 64BITFIX probably redundant // 577 578 // create new data and byte enable buffers 579 int long_enough = txn->get_data_length() + 2 * sizeof_databus; 580 tc->establish_dbuf(long_enough); 581 uchar *new_data = tc->new_dbuf; 582 tc->establish_bebuf(long_enough); 583 uchar *new_be = tc->new_bebuf; 584 585 if(txn->is_read()) { 586 tc->data_ptr = d_start; 587 tc->address = txn->get_address(); 588 tc->byte_enable = txn->get_byte_enable_ptr(); 589 tc->length = txn->get_data_length(); 590 if(txn->get_byte_enable_ptr() == 0) { 591 // iterate over transaction creating new byte enables from all-true 592 txn->set_data_length(loop_word1<DATAWORD, &true_b1<DATAWORD>, 593 &true_b1<uchar>, &false_b1<DATAWORD>, &false_b1<uchar> >( 594 txn->get_data_length(), len0, lenN, sizeof_databus, 595 d_start, d_end, d, 0, new_data, new_be)); 596 } else { 597 // iterate over transaction copying byte enables 598 txn->set_data_length(loop_word1<DATAWORD, ©_b1<DATAWORD>, 599 ©_b1<uchar>, &false_b1<DATAWORD>, &false_b1<uchar> >( 600 txn->get_data_length(), len0, lenN, sizeof_databus, d_start, d_end, 601 d, txn->get_byte_enable_ptr() - d_start + d, new_data, new_be)); 602 } 603 } else { 604 // WRITE 605 if(txn->get_byte_enable_ptr() == 0) { 606 // iterate over transaction copying data and creating new byte-enables 607 txn->set_data_length(loop_word1<DATAWORD, ©_d1<DATAWORD>, 608 ©_d1<uchar>, &false_b1<DATAWORD>, &false_b1<uchar> >( 609 txn->get_data_length(), len0, lenN, sizeof_databus, 610 d_start, d_end, d, 0, new_data, new_be)); 611 } else { 612 // iterate over transaction copying data and byte-enables 613 txn->set_data_length(loop_word1<DATAWORD, ©_db1<DATAWORD>, 614 ©_db1<uchar>, &false_b1<DATAWORD>, &false_b1<uchar> >( 615 txn->get_data_length(), len0, lenN, sizeof_databus, d_start, d_end, 616 d, txn->get_byte_enable_ptr() - d_start + d, new_data, new_be)); 617 } 618 } 619 txn->set_byte_enable_length(txn->get_data_length()); 620 txn->set_streaming_width(txn->get_data_length()); 621 txn->set_data_ptr(new_data); 622 txn->set_byte_enable_ptr(new_be); 623 txn->set_address(a_aligned); 624} 625 626 627 628/////////////////////////////////////////////////////////////////////////////// 629// function set (2): Utilities 630template<class D> inline void copy_d2(D *src1, D *src2, D *dest1, D *dest2) { 631 *dest1 = *src1; 632} 633 634template<class D> inline void copy_db2(D *src1, D *src2, D *dest1, D *dest2) { 635 *dest1 = *src1; 636 *dest2 = *src2; 637} 638 639template<class D> 640inline void copy_dbyb2(D *src1, D *src2, D *dest1, D *dest2) { 641 if(tlm_bool<D>(*src2)) *dest1 = *src1; 642} 643 644template<class D, void COPY(D *src1, D *src2, D *dest1, D *dest2)> 645inline void loop_aligned2(D *src1, D *src2, D *dest1, D *dest2, 646 int words, int words_per_bus) { 647 ptrdiff_t src1to2 = (char *)src2 - (char *)src1; // 64BITFIX was int and operands were cast to int // 648 ptrdiff_t dest1to2 = (char *)dest2 - (char *)dest1; // 64BITFIX was int and operands were cast to int // 649 650 D *done = src1 + ptrdiff_t(words); // 64BITFIX // 651 D *bus_start = src1; 652 src1 += ptrdiff_t(words_per_bus - 1); // 64BITFIX // 653 654 while(true) { 655 COPY(src1, (D *)(src1to2+(char *)src1), dest1, (D *)(dest1to2+(char *)dest1)); // 64BITFIX // 656 dest1++; 657 if((--src1) < bus_start) { 658 bus_start += ptrdiff_t(words_per_bus); // 64BITFIX // 659 if(bus_start == done) break; 660 src1 = bus_start + ptrdiff_t(words_per_bus - 1); // 64BITFIX // 661 } 662 } 663} 664 665 666/////////////////////////////////////////////////////////////////////////////// 667// function set (2): Response 668template<class DATAWORD> inline void 669tlm_from_hostendian_aligned(tlm_generic_payload *txn, unsigned int sizeof_databus) { 670 int words_per_bus = sizeof_databus/sizeof(DATAWORD); 671 if(words_per_bus == 1) return; 672 int words = (txn->get_data_length())/sizeof(DATAWORD); 673 tlm_endian_context *tc = txn->template get_extension<tlm_endian_context>(); 674 675 if(txn->get_byte_enable_ptr() == 0) { 676 // no byte enables 677 if(txn->is_read()) { 678 // RD without byte enables. Copy data to original buffer 679 loop_aligned2<DATAWORD, ©_d2<DATAWORD> >( 680 (DATAWORD *)(txn->get_data_ptr()), 681 0, (DATAWORD *)(tc->data_ptr), 0, words, words_per_bus); 682 } 683 } else { 684 // byte enables present 685 if(txn->is_read()) { 686 // RD with byte enables. Copy data qualified by byte-enables 687 loop_aligned2<DATAWORD, ©_dbyb2<DATAWORD> >( 688 (DATAWORD *)(txn->get_data_ptr()), 689 (DATAWORD *)(txn->get_byte_enable_ptr()), 690 (DATAWORD *)(tc->data_ptr), 0, words, words_per_bus); 691 } 692 } 693} 694 695 696/////////////////////////////////////////////////////////////////////////////// 697// function set (2): Request 698template<class DATAWORD> inline void 699tlm_to_hostendian_aligned(tlm_generic_payload *txn, unsigned int sizeof_databus) { 700 tlm_endian_context *tc = establish_context(txn); 701 tc->from_f = &(tlm_from_hostendian_aligned<DATAWORD>); 702 tc->sizeof_databus = sizeof_databus; 703 704 int words_per_bus = sizeof_databus/sizeof(DATAWORD); 705 if(words_per_bus == 1) return; 706 int words = (txn->get_data_length())/sizeof(DATAWORD); 707 708 DATAWORD *original_be = (DATAWORD *)(txn->get_byte_enable_ptr()); 709 DATAWORD *original_data = (DATAWORD *)(txn->get_data_ptr()); 710 711 // always allocate a new data buffer 712 tc->establish_dbuf(txn->get_data_length()); 713 txn->set_data_ptr(tc->new_dbuf); 714 715 if(original_be == 0) { 716 // no byte enables 717 if(txn->is_write()) { 718 // WR no byte enables. Copy data 719 loop_aligned2<DATAWORD, ©_d2<DATAWORD> >(original_data, 0, 720 (DATAWORD *)(txn->get_data_ptr()), 0, 721 words, words_per_bus); 722 } else { 723 // RD no byte enables. Save original data pointer 724 tc->data_ptr = (uchar *)original_data; 725 } 726 } else { 727 // byte enables present 728 // allocate a new buffer for them 729 tc->establish_bebuf(txn->get_data_length()); 730 txn->set_byte_enable_ptr(tc->new_bebuf); 731 txn->set_byte_enable_length(txn->get_data_length()); 732 733 if(txn->is_write()) { 734 // WR with byte enables. Copy data and BEs 735 loop_aligned2<DATAWORD, ©_db2<DATAWORD> >(original_data, original_be, 736 (DATAWORD *)(txn->get_data_ptr()), 737 (DATAWORD *)(txn->get_byte_enable_ptr()), words, words_per_bus); 738 } else { 739 // RD with byte enables. Save original data pointer 740 tc->data_ptr = (uchar *)original_data; 741 // Copy byte enables to new buffer 742 loop_aligned2<DATAWORD, ©_d2<DATAWORD> >(original_be, 0, 743 (DATAWORD *)(txn->get_byte_enable_ptr()), 0, 744 words, words_per_bus); 745 } 746 } 747} 748 749 750 751/////////////////////////////////////////////////////////////////////////////// 752// function set (3): Response 753template<class DATAWORD> inline void 754tlm_from_hostendian_single(tlm_generic_payload *txn, unsigned int sizeof_databus) { 755 // nothing needs to be done here 756} 757 758 759/////////////////////////////////////////////////////////////////////////////// 760// function set (3): Request 761template<class DATAWORD> inline void 762tlm_to_hostendian_single(tlm_generic_payload *txn, unsigned int sizeof_databus) { 763 tlm_endian_context *tc = establish_context(txn); 764 tc->from_f = &(tlm_from_hostendian_single<DATAWORD>); 765 tc->sizeof_databus = sizeof_databus; 766 767 // only need to change the address, always safe to work in-place 768 sc_dt::uint64 mask = sizeof_databus-1; 769 sc_dt::uint64 a = txn->get_address(); 770 txn->set_address((a & ~mask) | 771 (sizeof_databus - (a & mask) - sizeof(DATAWORD))); 772} 773 774 775 776/////////////////////////////////////////////////////////////////////////////// 777// helper function which works for all responses 778inline void tlm_from_hostendian(tlm_generic_payload *txn) { 779 tlm_endian_context *tc = txn->get_extension<tlm_endian_context>(); 780 (*(tc->from_f))(txn, tc->sizeof_databus); 781} 782 783 784#ifndef TLM_END_CONV_DONT_UNDEF_UCHAR 785#undef uchar 786#endif 787 788} // namespace tlm 789 790 791#endif // multiple-inclusion protection 792 793