tlm_endian_conv.h revision 12027
12SN/A/***************************************************************************** 22188SN/A 32SN/A Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 42SN/A more contributor license agreements. See the NOTICE file distributed 52SN/A with this work for additional information regarding copyright ownership. 62SN/A Accellera licenses this file to you under the Apache License, Version 2.0 72SN/A (the "License"); you may not use this file except in compliance with the 82SN/A License. You may obtain a copy of the License at 92SN/A 102SN/A http://www.apache.org/licenses/LICENSE-2.0 112SN/A 122SN/A Unless required by applicable law or agreed to in writing, software 132SN/A distributed under the License is distributed on an "AS IS" BASIS, 142SN/A WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 152SN/A implied. See the License for the specific language governing 162SN/A permissions and limitations under the License. 172SN/A 182SN/A *****************************************************************************/ 192SN/A 202SN/A 212SN/A#ifndef __TLM_ENDIAN_CONV_H__ 222SN/A#define __TLM_ENDIAN_CONV_H__ 232SN/A 242SN/A#include <systemc> 252SN/A#include "tlm_core/tlm_2/tlm_generic_payload/tlm_gp.h" 262SN/A 272665SN/A 282665SN/Anamespace tlm { 292665SN/A 302665SN/A 312665SN/A/* 322SN/ATranaction-Level Modelling 332SN/AEndianness Helper Functions 342SN/A 352SN/ADESCRIPTION 362465SN/AA set of functions for helping users to get the endianness 371717SN/Aright in their TLM models of system initiators. These functions are 382683Sktlim@umich.edufor use within an initiator. They can not be used as-is outside 392680SN/Aan initiator because the extension used to store context will not work 405529Snate@binkert.orgif cascaded, and they do not respect the generic payload mutability 412SN/Arules. However this code may be easily copied and adapted for use 421858SN/Ain bridges, etc.. 433565Sgblack@eecs.umich.edu 445529Snate@binkert.orgThese functions are not compulsory. There are other legitimate ways to 451917SN/Aachieve the same functionality. If extra information is available at 461070SN/Acompile time about the nature of an initiator's transactions, this can 471917SN/Abe exploited to accelerate simulations by creating further functions 482188SN/Asimilar to those in this file. In general a functional transaction can be 491917SN/Adescribed in more than one way by a TLM-2 GP object. 502290SN/A 511070SN/AThe functions convert the endianness of a GP object, either on request or 521917SN/Aresponse. They should only be used when the initiator's endianness 532SN/Adoes not match the host's endianness. They assume 'arithmetic mode' 545529Snate@binkert.orgmeaning that within a data word the byte order is always host-endian. 55360SN/AFor non-arithmetic mode initiators they can be used with a data word 562519SN/Asize of 1 byte. 572SN/A 582SN/AAll the functions are templates, for example: 592SN/A 602SN/Atemplate<class DATAWORD> inline void 612SN/A to_hostendian_generic(tlm_generic_payload *txn, int sizeof_databus) 621858SN/A 632683Sktlim@umich.eduThe template parameter provides the data word width. Having this as a class 643453Sgblack@eecs.umich.edumakes it easy to use it for copy and swap operations within the functions. 652683Sktlim@umich.eduIf the assignment operator for this class is overloaded, the endianness 663402Sktlim@umich.educonversion function may not have the desired effect. 672683Sktlim@umich.edu 682521SN/AAll the functions have the same signature except for different names. 692SN/A 702683Sktlim@umich.eduThe principle is that a function to_hostendian_convtype() is called when the 712190SN/Ainitiator-endian transaction is created, and the matching function 722680SN/Afrom_hostendian_convtype() is called when the transaction is completed, for 732290SN/Aexample before read data can be used. In some cases the from_ function is 742526SN/Aredundant but an empty function is provided anyway. It is strongly 751917SN/Arecommended that the from_ function is called, in case it ceases to be 765529Snate@binkert.orgredundant in future versions of this code. 771982SN/A 781917SN/ANo context needs to be managed outside the two functions, except that they 792683Sktlim@umich.edumust be called with the same template parameter and the same bus width. 802683Sktlim@umich.edu 811917SN/AFor initiator models that can not easily manage this context information, 821917SN/Aa single entry point for the from_ function is provided, which will be 831917SN/Aa little slower than calling the correct from_ function directly, as 841917SN/Ait can not be inlined. 851917SN/A 861917SN/AAll functions assume power-of-2 bus and data word widths. 871917SN/A 881917SN/AFunctions offered: 892521SN/A 905482Snate@binkert.org0) A pair of functions that work for almost all TLM2 GP transactions. The 913548Sgblack@eecs.umich.eduonly limitations are that data and bus widths should be powers of 2, and that 922SN/Athe data length should be an integer number of streaming widths and that the 932SN/Astreaming width should be an integer number of data words. 944997Sgblack@eecs.umich.eduThese functions always allocate new data and byte enable buffers and copy 954997Sgblack@eecs.umich.edudata one byte at a time. 963402Sktlim@umich.edu tlm_to_hostendian_generic(tlm_generic_payload *txn, int sizeof_databus) 974997Sgblack@eecs.umich.edu tlm_from_hostendian_generic(tlm_generic_payload *txn, int sizeof_databus) 982SN/A 992526SN/A1) A pair of functions that work for all transactions regardless of data and 1002683Sktlim@umich.edubus data sizes and address alignment except for the the following 1012SN/Alimitations: 1022190SN/A- byte-enables are supported only when byte-enable granularity is no finer 1032862Sktlim@umich.eduthan the data word (every data word is wholly enabled or wholly disabled) 1042862Sktlim@umich.edu- byte-enable-length is not supported (if byte enables are present, the byte 1052864Sktlim@umich.eduenable length must be equal to the data length). 1062862Sktlim@umich.edu- streaming width is not supported 1073402Sktlim@umich.edu- data word wider than bus word is not supported 1082862Sktlim@umich.eduA new data buffer and a new byte enable buffer are always allocated. Byte 1093402Sktlim@umich.eduenables are assumed to be needed even if not required for the original 1102862Sktlim@umich.edu(unconverted) transaction. Data is copied to the new buffer on request 1112190SN/A(for writes) or on response (for reads). Copies are done word-by-word 1122683Sktlim@umich.eduwhere possible. 1132862Sktlim@umich.edu tlm_to_hostendian_word(tlm_generic_payload *txn, int sizeof_databus) 1142190SN/A tlm_from_hostendian_word(tlm_generic_payload *txn, int sizeof_databus) 1152190SN/A 1162683Sktlim@umich.edu2) If the original transaction is both word and bus-aligned then this pair of 1171070SN/Afunctions can be used. It will complete faster than the generic function 1183486Sktlim@umich.edubecause the data reordering function is much simpler and no address 1193486Sktlim@umich.educonversion is required. 1203486Sktlim@umich.eduThe following limitations apply: 1213486Sktlim@umich.edu- byte-enables are supported only when byte-enable granularity is no finer 1222680SN/Athan the data word (every data word is wholly enabled or wholly disabled) 1231070SN/A- byte-enable-length is not supported (if byte enables are present, the byte 1241070SN/Aenable length must be equal to the data length). 1251917SN/A- streaming width is not supported 1262683Sktlim@umich.edu- data word wider than bus word is not supported 127180SN/A- the transaction must be an integer number of bus words 128180SN/A- the address must be aligned to the bus width 1291858SN/A tlm_to_hostendian_aligned(tlm_generic_payload *txn, int sizeof_databus) 1302235SN/A tlm_from_hostendian_aligned(tlm_generic_payload *txn, int sizeof_databus) 131180SN/A 1322235SN/A3) For single word transactions that don't cross a bus word boundary it 133180SN/Ais always safe to work in-place and the conversion is very simple. Again, 134180SN/Astreaming width and byte-enable length are not supported, and byte-enables 1352862Sktlim@umich.edumay not changes within a data word. 1362862Sktlim@umich.edu tlm_to_hostendian_single(tlm_generic_payload *txn, int sizeof_databus) 1372313SN/A tlm_from_hostendian_single(tlm_generic_payload *txn, int sizeof_databus) 1382313SN/A 1392680SN/A4) A single entry point for accessing the correct from_ function without 1402313SN/Aneeding to store context. 1412680SN/A tlm_from_hostendian(tlm_generic_payload *txn) 1422313SN/A*/ 1432313SN/A 1442680SN/A 1452313SN/A 1462361SN/A#ifndef uchar 1473548Sgblack@eecs.umich.edu#define uchar unsigned char 1482361SN/A#else 1492361SN/A#define TLM_END_CONV_DONT_UNDEF_UCHAR 1502361SN/A#endif 1512235SN/A 152180SN/A 153180SN/A/////////////////////////////////////////////////////////////////////////////// 154180SN/A// Generic Utilities 1552680SN/A 156180SN/Aclass tlm_endian_context; 157180SN/Aclass tlm_endian_context_pool { 1582SN/A public: 1592864Sktlim@umich.edu tlm_endian_context *first; 1602864Sktlim@umich.edu inline tlm_endian_context_pool(); 1612864Sktlim@umich.edu inline ~tlm_endian_context_pool(); 1622864Sktlim@umich.edu inline tlm_endian_context *pop(); 1632864Sktlim@umich.edu inline void push(tlm_endian_context *c); 1642864Sktlim@umich.edu}; 1652864Sktlim@umich.edustatic tlm_endian_context_pool global_tlm_endian_context_pool; 1662864Sktlim@umich.edu 1672864Sktlim@umich.edu// an extension to keep the information needed for reconversion of response 1683548Sgblack@eecs.umich.educlass tlm_endian_context : public tlm_extension<tlm_endian_context> { 1692864Sktlim@umich.edu public: 1702864Sktlim@umich.edu tlm_endian_context() : dbuf_size(0), bebuf_size(0) {} 1712864Sktlim@umich.edu ~tlm_endian_context() { 1722864Sktlim@umich.edu if(dbuf_size > 0) delete [] new_dbuf; 1732864Sktlim@umich.edu if(bebuf_size > 0) delete [] new_bebuf; 1742864Sktlim@umich.edu } 1752864Sktlim@umich.edu 1762862Sktlim@umich.edu sc_dt::uint64 address; // used by generic, word 1772862Sktlim@umich.edu sc_dt::uint64 new_address; // used by generic 1782862Sktlim@umich.edu uchar *data_ptr; // used by generic, word, aligned 1792862Sktlim@umich.edu uchar *byte_enable; // used by word 1802862Sktlim@umich.edu int length; // used by generic, word 1812862Sktlim@umich.edu int stream_width; // used by generic 1822862Sktlim@umich.edu 1832862Sktlim@umich.edu // used by common entry point on response 1842862Sktlim@umich.edu void (*from_f)(tlm_generic_payload *txn, unsigned int sizeof_databus); 1852915Sktlim@umich.edu int sizeof_databus; 1862862Sktlim@umich.edu 1872862Sktlim@umich.edu // reordering buffers for data and byte-enables 1882862Sktlim@umich.edu uchar *new_dbuf, *new_bebuf; 1892683Sktlim@umich.edu int dbuf_size, bebuf_size; 190217SN/A void establish_dbuf(int len) { 1912862Sktlim@umich.edu if(len <= dbuf_size) return; 192223SN/A if(dbuf_size > 0) delete [] new_dbuf; 193223SN/A new_dbuf = new uchar[len]; 194217SN/A dbuf_size = len; 195217SN/A } 196217SN/A void establish_bebuf(int len) { 197217SN/A if(len <= bebuf_size) return; 1982683Sktlim@umich.edu if(bebuf_size > 0) delete [] new_bebuf; 199217SN/A new_bebuf = new uchar[len]; 2002862Sktlim@umich.edu bebuf_size = len; 201237SN/A } 202223SN/A 203217SN/A // required for extension management 204217SN/A void free() { 2052683Sktlim@umich.edu global_tlm_endian_context_pool.push(this); 2062683Sktlim@umich.edu } 2072683Sktlim@umich.edu tlm_extension_base* clone() const {return 0;} 2082683Sktlim@umich.edu void copy_from(tlm_extension_base const &) {return;} 2092683Sktlim@umich.edu 2102683Sktlim@umich.edu // for pooling 2112683Sktlim@umich.edu tlm_endian_context *next; 2122683Sktlim@umich.edu}; 213217SN/A// Assumptions about transaction contexts: 214217SN/A// 1) only the address attribute of a transaction 2152683Sktlim@umich.edu// is mutable. all other attributes are unchanged from the request to 2162SN/A// response side conversion. 2172680SN/A// 2) the conversion functions in this file do not respect the mutability 2182SN/A// rules and do not put the transaction back into its original state after 2192SN/A// completion. so if the initiator has any cleaning up to do (eg of byte 2202188SN/A// enable buffers), it needs to store its own context. the transaction 2212188SN/A// returned to the initiator may contain pointers to data and byte enable 2224400Srdreslin@umich.edu// that can/must not be deleted. 2235543Ssaidi@eecs.umich.edu// 3) the conversion functions in this file use an extension to store 2245543Ssaidi@eecs.umich.edu// context information. they do not remove this extension. the initiator 2254400Srdreslin@umich.edu// should not remove it unless it deletes the generic payload 2262290SN/A// object. 2272680SN/A 2282290SN/Ainline tlm_endian_context *establish_context(tlm_generic_payload *txn) { 2292290SN/A tlm_endian_context *tc = txn->get_extension<tlm_endian_context>(); 2302683Sktlim@umich.edu if(tc == 0) { 231393SN/A tc = global_tlm_endian_context_pool.pop(); 232393SN/A txn->set_extension(tc); 233393SN/A } 2342683Sktlim@umich.edu return tc; 235393SN/A} 2362680SN/A 237393SN/Ainline tlm_endian_context_pool::tlm_endian_context_pool() : first(0) {} 238393SN/A 2392188SN/Ainline tlm_endian_context_pool::~tlm_endian_context_pool() { 2402188SN/A while(first != 0) { 2412188SN/A tlm_endian_context *next = first->next; 2421858SN/A delete first; 2432SN/A first = next; 244393SN/A } 2452680SN/A} 2462SN/A 2472SN/Atlm_endian_context *tlm_endian_context_pool::pop() { 2482SN/A if(first == 0) return new tlm_endian_context; 2492188SN/A tlm_endian_context *r = first; 2502680SN/A first = first->next; 2512683Sktlim@umich.edu return r; 2522SN/A} 2532SN/A 2542SN/Avoid tlm_endian_context_pool::push(tlm_endian_context *c) { 2552683Sktlim@umich.edu c->next = first; 256393SN/A first = c; 2572680SN/A} 258393SN/A 259393SN/A 2602680SN/A// a set of constants for efficient filling of byte enables 2612683Sktlim@umich.edutemplate<class D> class tlm_bool { 262393SN/A public: 263393SN/A static D TLM_TRUE; 264393SN/A static D TLM_FALSE; 2652683Sktlim@umich.edu static D make_uchar_array(uchar c) { 266393SN/A D d; 2672680SN/A uchar *tmp = (uchar *)(&d); 268393SN/A for(ptrdiff_t i=0; i!=sizeof(D); i++) tmp[i] = c; // 64BITFIX negligable risk but easy fix // 269393SN/A return d; 2702680SN/A } 2712683Sktlim@umich.edu // also provides an syntax-efficient tester, using a 272393SN/A // copy constuctor and an implicit cast to boolean 273393SN/A tlm_bool(D &d) : b(*((uchar*)&d) != TLM_BYTE_DISABLED) {} 274393SN/A operator bool() const {return b;} 275393SN/A private: 2762683Sktlim@umich.edu bool b; 2772SN/A}; 2782330SN/A 2792341SN/Atemplate<class D> D tlm_bool<D>::TLM_TRUE 2802341SN/A = tlm_bool<D>::make_uchar_array(TLM_BYTE_ENABLED); 2812330SN/Atemplate<class D> D tlm_bool<D>::TLM_FALSE 2822SN/A = tlm_bool<D>::make_uchar_array(TLM_BYTE_DISABLED); 283716SN/A 284716SN/A 2852683Sktlim@umich.edu 2862190SN/A/////////////////////////////////////////////////////////////////////////////// 2872680SN/A// function set (0): Utilities 2882190SN/Ainline void copy_db0(uchar *src1, uchar *src2, uchar *dest1, uchar *dest2) { 2892190SN/A *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