112855Sgabeblack@google.com/*****************************************************************************
212855Sgabeblack@google.com
312855Sgabeblack@google.com  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
412855Sgabeblack@google.com  more contributor license agreements.  See the NOTICE file distributed
512855Sgabeblack@google.com  with this work for additional information regarding copyright ownership.
612855Sgabeblack@google.com  Accellera licenses this file to you under the Apache License, Version 2.0
712855Sgabeblack@google.com  (the "License"); you may not use this file except in compliance with the
812855Sgabeblack@google.com  License.  You may obtain a copy of the License at
912855Sgabeblack@google.com
1012855Sgabeblack@google.com    http://www.apache.org/licenses/LICENSE-2.0
1112855Sgabeblack@google.com
1212855Sgabeblack@google.com  Unless required by applicable law or agreed to in writing, software
1312855Sgabeblack@google.com  distributed under the License is distributed on an "AS IS" BASIS,
1412855Sgabeblack@google.com  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
1512855Sgabeblack@google.com  implied.  See the License for the specific language governing
1612855Sgabeblack@google.com  permissions and limitations under the License.
1712855Sgabeblack@google.com
1812855Sgabeblack@google.com *****************************************************************************/
1912855Sgabeblack@google.com
2012855Sgabeblack@google.com
2112855Sgabeblack@google.com/*
2212855Sgabeblack@google.comThis C++ programme runs single transactions through a single
2312855Sgabeblack@google.comendianness conversion function, then through a simple memory model,
2412855Sgabeblack@google.comthen converts it back.
2512855Sgabeblack@google.comTakes the initial memory state as input and provides the final
2612855Sgabeblack@google.commemory state as output.
2712855Sgabeblack@google.com*/
2812855Sgabeblack@google.com
2912855Sgabeblack@google.com
3012855Sgabeblack@google.com#define BUFFER_SIZE 2048
3112855Sgabeblack@google.com
3212855Sgabeblack@google.com#include<systemc>
3312855Sgabeblack@google.com#include "tlm.h"
3412855Sgabeblack@google.com#include<iostream>
3512855Sgabeblack@google.com#include<time.h>
3612855Sgabeblack@google.com#include <fstream>
3712855Sgabeblack@google.com
3812855Sgabeblack@google.comusing namespace std;
3912855Sgabeblack@google.comusing namespace tlm;
4012855Sgabeblack@google.comusing namespace sc_dt;
4112855Sgabeblack@google.com
4212855Sgabeblack@google.com
4312855Sgabeblack@google.com// simple set of types with known sizeof(), for testing //
4412855Sgabeblack@google.comtemplate<int SIZE> class dt {
4512855Sgabeblack@google.com  char content[SIZE];
4612855Sgabeblack@google.com};
4712855Sgabeblack@google.com
4812855Sgabeblack@google.com
4912855Sgabeblack@google.com#define convert(function) \
5012855Sgabeblack@google.com  switch(data_width) { \
5112855Sgabeblack@google.com    case 1:  function<dt<1> >(&txn,bus_width); break; \
5212855Sgabeblack@google.com    case 2:  function<dt<2> >(&txn,bus_width); break; \
5312855Sgabeblack@google.com    case 4:  function<dt<4> >(&txn,bus_width); break; \
5412855Sgabeblack@google.com    case 8:  function<dt<8> >(&txn,bus_width); break; \
5512855Sgabeblack@google.com    case 16:  function<dt<16> >(&txn,bus_width); break; \
5612855Sgabeblack@google.com    case 32:  function<dt<32> >(&txn,bus_width); break; \
5712855Sgabeblack@google.com    default:  cout << "bad data width\n"; \
5812855Sgabeblack@google.com    exit(1); \
5912855Sgabeblack@google.com  }
6012855Sgabeblack@google.com
6112855Sgabeblack@google.com
6212855Sgabeblack@google.com// forward declarations - see below
6312855Sgabeblack@google.comtemplate<class DATAWORD> inline void
6412855Sgabeblack@google.comlocal_single_tohe(tlm_generic_payload *txn, unsigned int sizeof_databus);
6512855Sgabeblack@google.comtemplate<class DATAWORD> inline void
6612855Sgabeblack@google.comlocal_single_fromhe(tlm_generic_payload *txn, unsigned int sizeof_databus);
6712855Sgabeblack@google.com
6812855Sgabeblack@google.com
6912855Sgabeblack@google.comvoid test_a_conversion(char cmd, tlm_generic_payload &txn, std::ifstream & fin) {
7012855Sgabeblack@google.com
7112855Sgabeblack@google.com  if(cmd == 'R') txn.set_read();
7212855Sgabeblack@google.com  else txn.set_write();
7312855Sgabeblack@google.com
7412855Sgabeblack@google.com  fin.ignore(10000,'=');
7512855Sgabeblack@google.com  uint64 a;
7612855Sgabeblack@google.com  fin >> a;
7712855Sgabeblack@google.com  txn.set_address(a);
7812855Sgabeblack@google.com
7912855Sgabeblack@google.com  fin.ignore(10000,'=');
8012855Sgabeblack@google.com  int l;
8112855Sgabeblack@google.com  fin >> l;
8212855Sgabeblack@google.com  txn.set_data_length(l);
8312855Sgabeblack@google.com
8412855Sgabeblack@google.com  int bus_width;
8512855Sgabeblack@google.com  fin.ignore(10000,'=');  fin >> bus_width;
8612855Sgabeblack@google.com
8712855Sgabeblack@google.com  int data_width;
8812855Sgabeblack@google.com  fin.ignore(10000,'=');  fin >> data_width;
8912855Sgabeblack@google.com
9012855Sgabeblack@google.com  int initiator_offset;
9112855Sgabeblack@google.com  fin.ignore(10000,'=');  fin >> initiator_offset;
9212855Sgabeblack@google.com
9312855Sgabeblack@google.com  unsigned char *original_byte_enable = 0;
9412855Sgabeblack@google.com  unsigned char *byte_enable_legible =
9512855Sgabeblack@google.com    new unsigned char[txn.get_data_length() + 1];
9612855Sgabeblack@google.com  memset(byte_enable_legible, 0, txn.get_data_length() + 1);
9712855Sgabeblack@google.com  fin.ignore(10000,'=');
9812855Sgabeblack@google.com  for(unsigned b=0; b<txn.get_data_length(); b++) {
9912855Sgabeblack@google.com    char tmp; fin >> tmp;
10012855Sgabeblack@google.com    if((tmp=='0')||(tmp=='1')||(tmp=='x')) byte_enable_legible[b]=tmp;
10112855Sgabeblack@google.com    else break;
10212855Sgabeblack@google.com  }
10312855Sgabeblack@google.com  if((byte_enable_legible[0] == '1') || (byte_enable_legible[0] == '0')) {
10412855Sgabeblack@google.com    txn.set_byte_enable_ptr(new unsigned char[txn.get_data_length()]);
10512855Sgabeblack@google.com    txn.set_byte_enable_length(txn.get_data_length());
10612855Sgabeblack@google.com    original_byte_enable = txn.get_byte_enable_ptr();
10712855Sgabeblack@google.com    for(unsigned int i=0; i<txn.get_data_length(); i++) {
10812855Sgabeblack@google.com      if(byte_enable_legible[i] == '0') {
10912855Sgabeblack@google.com        txn.get_byte_enable_ptr()[i] = TLM_BYTE_DISABLED;
11012855Sgabeblack@google.com      } else if(byte_enable_legible[i] == '1') {
11112855Sgabeblack@google.com        txn.get_byte_enable_ptr()[i] = TLM_BYTE_ENABLED;
11212855Sgabeblack@google.com      } else {
11312855Sgabeblack@google.com        // not enough byte enables
11412855Sgabeblack@google.com        txn.set_byte_enable_length(i);
11512855Sgabeblack@google.com        break;
11612855Sgabeblack@google.com      }
11712855Sgabeblack@google.com    }
11812855Sgabeblack@google.com  } else {
11912855Sgabeblack@google.com    txn.set_byte_enable_ptr(0);
12012855Sgabeblack@google.com    txn.set_byte_enable_length(0);
12112855Sgabeblack@google.com  }
12212855Sgabeblack@google.com
12312855Sgabeblack@google.com  int stream_width;
12412855Sgabeblack@google.com  fin.ignore(10000,'=');  fin >> stream_width;
12512855Sgabeblack@google.com  txn.set_streaming_width(stream_width);
12612855Sgabeblack@google.com
12712855Sgabeblack@google.com  cout << "enter initiator memory state = ("<< BUFFER_SIZE << " characters)\n";
12812855Sgabeblack@google.com  unsigned char initiator_mem[BUFFER_SIZE+1];
12912855Sgabeblack@google.com  memset(initiator_mem, 0, BUFFER_SIZE+1);
13012855Sgabeblack@google.com  fin.ignore(10000,'=');  fin >> initiator_mem;
13112855Sgabeblack@google.com
13212855Sgabeblack@google.com  txn.set_data_ptr(initiator_mem + initiator_offset);
13312855Sgabeblack@google.com
13412855Sgabeblack@google.com  cout << "enter target memory state = ("<< BUFFER_SIZE << " characters)\n";
13512855Sgabeblack@google.com  unsigned char target_mem[BUFFER_SIZE+1];
13612855Sgabeblack@google.com  memset(target_mem, 0, BUFFER_SIZE+1);
13712855Sgabeblack@google.com  fin.ignore(10000,'=');  fin >> target_mem;
13812855Sgabeblack@google.com
13912855Sgabeblack@google.com  cout << "enter converter choice = (0 => generic, 1 => word, 2 => aligned, 3 => single)\n";
14012855Sgabeblack@google.com  int converter;
14112855Sgabeblack@google.com  fin.ignore(10000,'=');  fin >> converter;
14212855Sgabeblack@google.com
14312855Sgabeblack@google.com  cout << "Initiator Intent\n";
14412855Sgabeblack@google.com  cout << "  Cmd = " << cmd << endl;
14512855Sgabeblack@google.com  cout << "  Addr = " << txn.get_address() << endl;
14612855Sgabeblack@google.com  cout << "  Len = " << txn.get_data_length() << endl;
14712855Sgabeblack@google.com  cout << "  Bus Width = " << bus_width << endl;
14812855Sgabeblack@google.com  cout << "  Data Word = " << data_width << endl;
14912855Sgabeblack@google.com#ifdef VERBOSE
15012855Sgabeblack@google.com  cout << "  Initiator offset and txn data pointer = " << initiator_offset << ", " << int(txn.get_data_ptr()) << endl;
15112855Sgabeblack@google.com  cout << "  Byte enables and byte enable pointer = " << byte_enable_legible << ", " << int(txn.get_byte_enable_ptr()) << endl;
15212855Sgabeblack@google.com#else
15312855Sgabeblack@google.com  cout << "  Initiator offset = " << initiator_offset << endl;
15412855Sgabeblack@google.com  cout << "  Byte enables = " << byte_enable_legible << endl;
15512855Sgabeblack@google.com#endif
15612855Sgabeblack@google.com  cout << "  Byte enable length = " << txn.get_byte_enable_length() << endl;
15712855Sgabeblack@google.com  cout << "  Streaming width = " << txn.get_streaming_width() << endl;
15812855Sgabeblack@google.com  cout << "  Initiator memory = " << initiator_mem << endl;
15912855Sgabeblack@google.com  cout << "  Target memory = " << target_mem << endl;
16012855Sgabeblack@google.com  cout << "  Converter = " << converter << endl << endl;
16112855Sgabeblack@google.com
16212855Sgabeblack@google.com  // initiator //
16312855Sgabeblack@google.com  switch(converter) {
16412855Sgabeblack@google.com    case 0:  convert(tlm_to_hostendian_generic); break;
16512855Sgabeblack@google.com    case 1:  convert(tlm_to_hostendian_word); break;
16612855Sgabeblack@google.com    case 2:  convert(tlm_to_hostendian_aligned); break;
16712855Sgabeblack@google.com    case 3:  convert(tlm_to_hostendian_single); break;
16812855Sgabeblack@google.com    case 4:  convert(local_single_tohe); break;
16912855Sgabeblack@google.com    default:  cout << "no such converter as " << converter << endl;
17012855Sgabeblack@google.com    exit(1);
17112855Sgabeblack@google.com  }
17212855Sgabeblack@google.com
17312855Sgabeblack@google.com  cout << "Converted Transaction\n";
17412855Sgabeblack@google.com  cout << "  Addr = " << txn.get_address() << endl;
17512855Sgabeblack@google.com  cout << "  Len = " << txn.get_data_length() << endl;
17612855Sgabeblack@google.com#ifdef VERBOSE
17712855Sgabeblack@google.com  cout << "  Txn data pointer = " << int(txn.get_data_ptr()) << endl;
17812855Sgabeblack@google.com  if(txn.get_byte_enable_ptr() != 0) {
17912855Sgabeblack@google.com    cout << "  Byte enables and byte enable pointer = ";
18012855Sgabeblack@google.com    for(unsigned int i=0; i<txn.get_data_length(); i++)
18112855Sgabeblack@google.com      cout << (txn.get_byte_enable_ptr()[i] ? '1' : '0');
18212855Sgabeblack@google.com    cout << ", " << int(txn.get_byte_enable_ptr()) << endl;
18312855Sgabeblack@google.com  }
18412855Sgabeblack@google.com#else
18512855Sgabeblack@google.com  cout << "  Txn data pointer = " <<
18612855Sgabeblack@google.com    (txn.get_data_ptr() == initiator_mem+initiator_offset ? "unchanged" : "changed") << endl;
18712855Sgabeblack@google.com  if(txn.get_byte_enable_ptr() != 0) {
18812855Sgabeblack@google.com    cout << "  Byte enables and byte enable pointer = ";
18912855Sgabeblack@google.com    for(unsigned int i=0; i<txn.get_data_length(); i++)
19012855Sgabeblack@google.com      cout << (txn.get_byte_enable_ptr()[i] ? '1' : '0');
19112855Sgabeblack@google.com    cout << ", " <<
19212855Sgabeblack@google.com     (txn.get_byte_enable_ptr() == original_byte_enable ? "unchanged" : "changed") << endl;
19312855Sgabeblack@google.com  }
19412855Sgabeblack@google.com#endif
19512855Sgabeblack@google.com  cout << "  Byte enable length = " << txn.get_byte_enable_length() << endl;
19612855Sgabeblack@google.com  cout << "  Streaming width = " << txn.get_streaming_width() << endl;
19712855Sgabeblack@google.com  cout << endl;
19812855Sgabeblack@google.com
19912855Sgabeblack@google.com  // target //
20012855Sgabeblack@google.com  int sw = txn.get_streaming_width();
20112855Sgabeblack@google.com  if((txn.get_data_length()/sw)*sw != txn.get_data_length()) {
20212855Sgabeblack@google.com    cout << "ERROR: Data length not a multiple of streaming width\n";
20312855Sgabeblack@google.com    exit(1);
20412855Sgabeblack@google.com  }
20512855Sgabeblack@google.com  for(unsigned int ss = 0; ss < txn.get_data_length(); ss += sw) {
20612855Sgabeblack@google.com    if(txn.get_byte_enable_ptr() == 0) {
20712855Sgabeblack@google.com      // simple transaction can be processed by mem-copy
20812855Sgabeblack@google.com      if(txn.is_read())
20912855Sgabeblack@google.com        memcpy(ss+txn.get_data_ptr(), target_mem+txn.get_address(), sw);
21012855Sgabeblack@google.com      else
21112855Sgabeblack@google.com        memcpy(target_mem+txn.get_address(), ss+txn.get_data_ptr(), sw);
21212855Sgabeblack@google.com    } else {
21312855Sgabeblack@google.com      // complex transaction, byte enables, maybe shorter than data
21412855Sgabeblack@google.com      int bel = txn.get_byte_enable_length();
21512855Sgabeblack@google.com      if(txn.is_read()) {
21612855Sgabeblack@google.com        for(int j=0; j<sw; j++) {
21712855Sgabeblack@google.com          if(txn.get_byte_enable_ptr()[(ss+j) % bel])
21812855Sgabeblack@google.com            (txn.get_data_ptr())[ss+j] = target_mem[j+txn.get_address()];
21912855Sgabeblack@google.com        }
22012855Sgabeblack@google.com      } else {
22112855Sgabeblack@google.com        for(int j=0; j<sw; j++) {
22212855Sgabeblack@google.com          if(txn.get_byte_enable_ptr()[(ss+j) % bel])
22312855Sgabeblack@google.com            target_mem[j+txn.get_address()] = (txn.get_data_ptr())[ss+j];
22412855Sgabeblack@google.com        }
22512855Sgabeblack@google.com      }
22612855Sgabeblack@google.com    }
22712855Sgabeblack@google.com  }
22812855Sgabeblack@google.com
22912855Sgabeblack@google.com  // initiator again //
23012855Sgabeblack@google.com  if((rand() & 0x100) && (converter < 4)) {
23112855Sgabeblack@google.com#ifdef VERBOSE
23212855Sgabeblack@google.com    cout << "using single entry point for response\n";
23312855Sgabeblack@google.com#endif
23412855Sgabeblack@google.com    tlm_from_hostendian(&txn);
23512855Sgabeblack@google.com  } else {
23612855Sgabeblack@google.com#ifdef VERBOSE
23712855Sgabeblack@google.com    cout << "using specific entry point for response\n";
23812855Sgabeblack@google.com#endif
23912855Sgabeblack@google.com    switch(converter) {
24012855Sgabeblack@google.com      case 0:  convert(tlm_from_hostendian_generic); break;
24112855Sgabeblack@google.com      case 1:  convert(tlm_from_hostendian_word); break;
24212855Sgabeblack@google.com      case 2:  convert(tlm_from_hostendian_aligned); break;
24312855Sgabeblack@google.com      case 3:  convert(tlm_from_hostendian_single); break;
24412855Sgabeblack@google.com      case 4:  convert(local_single_fromhe); break;
24512855Sgabeblack@google.com      default:  cout << "no such converter as " << converter << endl;
24612855Sgabeblack@google.com      exit(1);
24712855Sgabeblack@google.com    }
24812855Sgabeblack@google.com  }
24912855Sgabeblack@google.com
25012855Sgabeblack@google.com  // print the results //
25112855Sgabeblack@google.com  cout << "Memory States after Transaction\n";
25212855Sgabeblack@google.com  cout << "  initiator = " << initiator_mem << endl;
25312855Sgabeblack@google.com  cout << "  target = " << target_mem << endl << endl;
25412855Sgabeblack@google.com
25512855Sgabeblack@google.com  // clean up
25612855Sgabeblack@google.com  delete [] byte_enable_legible;
25712855Sgabeblack@google.com  if(original_byte_enable != 0) delete [] original_byte_enable;
25812855Sgabeblack@google.com}
25912855Sgabeblack@google.com
26012855Sgabeblack@google.com
26112855Sgabeblack@google.comvoid pool_status() {
26212855Sgabeblack@google.com  cout << "Pool status: ";
26312855Sgabeblack@google.com  tlm_endian_context *f = global_tlm_endian_context_pool.first;
26412855Sgabeblack@google.com  while(f!=0) {
26512855Sgabeblack@google.com    cout << "(" << f->dbuf_size << "," << f->bebuf_size << ") ";
26612855Sgabeblack@google.com    f = f->next;
26712855Sgabeblack@google.com  }
26812855Sgabeblack@google.com  cout << endl;
26912855Sgabeblack@google.com}
27012855Sgabeblack@google.com
27112855Sgabeblack@google.com
27212855Sgabeblack@google.comint sc_main(int argc, char **argv) {
27312855Sgabeblack@google.com
27412855Sgabeblack@google.com  #include <string>
27512855Sgabeblack@google.com
27612855Sgabeblack@google.com  // no command line parameters //
27712855Sgabeblack@google.com  // get everything from stdin and build transaction object //
27812855Sgabeblack@google.com  cout << "\nTLM-2 Endianness Conversion Helper Functions Tester\n";
27912855Sgabeblack@google.com  cout << "March 2008\n";
28012855Sgabeblack@google.com  cout << "January 2012 Updated to read from endian_conv/input.txt\n\n";
28112855Sgabeblack@google.com
28212855Sgabeblack@google.com  std::string filename;
28312855Sgabeblack@google.com  std::ifstream fin;
28412855Sgabeblack@google.com
28512855Sgabeblack@google.com  if (1 == argc)
28612855Sgabeblack@google.com      filename = "endian_conv/input.txt";
28712855Sgabeblack@google.com  else if (2 == argc)
28812855Sgabeblack@google.com      filename = argv[1];
28912855Sgabeblack@google.com  else {
29012855Sgabeblack@google.com    std::cerr << "Too many input arguments" << std::endl;
29112855Sgabeblack@google.com	return 1;
29212855Sgabeblack@google.com  }
29312855Sgabeblack@google.com
29412855Sgabeblack@google.com
29512855Sgabeblack@google.com  fin.open(filename.c_str(), ios_base::in);
29612855Sgabeblack@google.com  if (!fin) {
29712855Sgabeblack@google.com    std::cerr << "Could not open input filename " << filename << std::endl;
29812855Sgabeblack@google.com    return 1;
29912855Sgabeblack@google.com  }
30012855Sgabeblack@google.com
30112855Sgabeblack@google.com  srand(time(NULL));
30212855Sgabeblack@google.com  const int nr_txns_in_pool = 7;
30312855Sgabeblack@google.com  const int txn_to_cycle = 4;
30412855Sgabeblack@google.com  tlm_generic_payload *txns[nr_txns_in_pool];
30512855Sgabeblack@google.com  for(int i=0; i < nr_txns_in_pool; i++) txns[i] = new tlm_generic_payload;
30612855Sgabeblack@google.com
30712855Sgabeblack@google.com  for(int i=0; true; i = ((i+1) % nr_txns_in_pool)) {
30812855Sgabeblack@google.com    cout << i << " enter {R|W}, addr=a, len=l, bus width=b, word width=w, initiator offset=i, be={x|01}, stream width=s\n";
30912855Sgabeblack@google.com    pool_status();
31012855Sgabeblack@google.com    char command;
31112855Sgabeblack@google.com    fin >> command;
31212855Sgabeblack@google.com    if(fin.eof()) break;
31312855Sgabeblack@google.com    if((command != 'R') && (command != 'W')) break;
31412855Sgabeblack@google.com    if(i==txn_to_cycle) {
31512855Sgabeblack@google.com      // should cause 2 extensions to get pushed to the pool once they've been used
31612855Sgabeblack@google.com      delete txns[i];
31712855Sgabeblack@google.com      pool_status();
31812855Sgabeblack@google.com      delete txns[i-1];
31912855Sgabeblack@google.com      pool_status();
32012855Sgabeblack@google.com      // and popped back later when these new ones establish contexts
32112855Sgabeblack@google.com      txns[i] = new tlm_generic_payload;
32212855Sgabeblack@google.com      txns[i-1] = new tlm_generic_payload;
32312855Sgabeblack@google.com      pool_status();
32412855Sgabeblack@google.com    }
32512855Sgabeblack@google.com    test_a_conversion(command, *txns[i], fin);
32612855Sgabeblack@google.com  }
32712855Sgabeblack@google.com
32812855Sgabeblack@google.com  for(int i=0; i < nr_txns_in_pool; i++) {
32912855Sgabeblack@google.com    delete txns[i];
33012855Sgabeblack@google.com    pool_status();
33112855Sgabeblack@google.com  }
33212855Sgabeblack@google.com  return 0;
33312855Sgabeblack@google.com}
33412855Sgabeblack@google.com
33512855Sgabeblack@google.com
33612855Sgabeblack@google.com// converter functions for non-aligned single transactions
33712855Sgabeblack@google.com// included here for validation only.  not designed for general use.
33812855Sgabeblack@google.com
33912855Sgabeblack@google.comunsigned char *original_dptr;
34012855Sgabeblack@google.comsc_dt::uint64 original_addr;
34112855Sgabeblack@google.com
34212855Sgabeblack@google.comtemplate<class DATAWORD> inline void
34312855Sgabeblack@google.comlocal_single_tohe(tlm_generic_payload *txn, unsigned int sizeof_databus) {
34412855Sgabeblack@google.com  if(txn->get_data_length() != sizeof(DATAWORD)) {
34512855Sgabeblack@google.com    cout << "Error:  local_single_tohe() wrongly called\n";
34612855Sgabeblack@google.com    exit(1);
34712855Sgabeblack@google.com  }
34812855Sgabeblack@google.com
34912855Sgabeblack@google.com  sc_dt::uint64 mask = sizeof_databus - 1;
35012855Sgabeblack@google.com
35112855Sgabeblack@google.com  // set up new buffers, length and address
35212855Sgabeblack@google.com  if(sizeof(DATAWORD) > sizeof_databus)
35312855Sgabeblack@google.com    txn->set_data_length(sizeof_databus + sizeof(DATAWORD));
35412855Sgabeblack@google.com  else
35512855Sgabeblack@google.com    txn->set_data_length(2 * sizeof_databus);
35612855Sgabeblack@google.com  txn->set_streaming_width(txn->get_data_length());
35712855Sgabeblack@google.com  unsigned char *new_data = new unsigned char[txn->get_data_length()];
35812855Sgabeblack@google.com  unsigned char *new_be = new unsigned char[txn->get_data_length()];
35912855Sgabeblack@google.com  // drive all BEs to zero initially
36012855Sgabeblack@google.com  for(unsigned int i=0; i<txn->get_data_length(); i++) new_be[i] = 0;
36112855Sgabeblack@google.com  sc_dt::uint64 new_addr = txn->get_address() & ~mask;
36212855Sgabeblack@google.com
36312855Sgabeblack@google.com  // Comments assume arithmetic mode big endian initiator modelled on little
36412855Sgabeblack@google.com  // endian host (but the functionality is the same for LE initiator on BE host)
36512855Sgabeblack@google.com
36612855Sgabeblack@google.com  // iterate over the initiator word byte by byte, MSB first
36712855Sgabeblack@google.com  unsigned char *curr_d = txn->get_data_ptr() + sizeof(DATAWORD) - 1;
36812855Sgabeblack@google.com  unsigned char *curr_b = txn->get_byte_enable_ptr() + sizeof(DATAWORD) - 1;
36912855Sgabeblack@google.com
37012855Sgabeblack@google.com  // initiator intent is to put the MSB at the address given in the transaction
37112855Sgabeblack@google.com  sc_dt::uint64 curr_a = txn->get_address();
37212855Sgabeblack@google.com
37312855Sgabeblack@google.com  // iterate copying data and byte enables
37412855Sgabeblack@google.com  for( ; curr_d >= txn->get_data_ptr(); curr_d--, curr_b--, curr_a++) {
37512855Sgabeblack@google.com    // work out the address in the TLM interpretation of the initiator's intent
37612855Sgabeblack@google.com    sc_dt::uint64 he_addr = curr_a ^ mask;
37712855Sgabeblack@google.com    int idx = he_addr - new_addr;
37812855Sgabeblack@google.com    if(txn->is_write()) new_data[idx] = *curr_d;
37912855Sgabeblack@google.com    if(txn->get_byte_enable_ptr() == 0) new_be[idx] = 1;
38012855Sgabeblack@google.com    else new_be[idx] = *curr_b;
38112855Sgabeblack@google.com  }
38212855Sgabeblack@google.com
38312855Sgabeblack@google.com  // replace the pointers
38412855Sgabeblack@google.com  original_dptr = txn->get_data_ptr();
38512855Sgabeblack@google.com  txn->set_data_ptr(new_data);
38612855Sgabeblack@google.com  txn->set_byte_enable_ptr(new_be);
38712855Sgabeblack@google.com  txn->set_byte_enable_length(txn->get_data_length());
38812855Sgabeblack@google.com  original_addr = txn->get_address();
38912855Sgabeblack@google.com  txn->set_address(new_addr);
39012855Sgabeblack@google.com}
39112855Sgabeblack@google.com
39212855Sgabeblack@google.com
39312855Sgabeblack@google.comtemplate<class DATAWORD> inline void
39412855Sgabeblack@google.comlocal_single_fromhe(tlm_generic_payload *txn, unsigned int sizeof_databus) {
39512855Sgabeblack@google.com  sc_dt::uint64 mask = sizeof_databus - 1;
39612855Sgabeblack@google.com
39712855Sgabeblack@google.com  // Comments assume arithmetic mode big endian initiator modelled on little
39812855Sgabeblack@google.com  // endian host (but the functionality is the same for LE initiator on BE host)
39912855Sgabeblack@google.com
40012855Sgabeblack@google.com  // iterate over the initiator word byte by byte, MSB first
40112855Sgabeblack@google.com  unsigned char *curr_d = original_dptr + sizeof(DATAWORD) - 1;
40212855Sgabeblack@google.com
40312855Sgabeblack@google.com  // initiator intent is to put the MSB at the address given in the transaction
40412855Sgabeblack@google.com  sc_dt::uint64 curr_a = original_addr;
40512855Sgabeblack@google.com
40612855Sgabeblack@google.com  // iterate copying data and byte enables
40712855Sgabeblack@google.com  for( ; curr_d >= original_dptr; curr_d--, curr_a++) {
40812855Sgabeblack@google.com    // work out the address in the TLM interpretation of the initiator's intent
40912855Sgabeblack@google.com    sc_dt::uint64 he_addr = curr_a ^ mask;
41012855Sgabeblack@google.com    int idx = he_addr - txn->get_address();
41112855Sgabeblack@google.com    if((txn->is_read()) && (txn->get_byte_enable_ptr()[idx] != 0))
41212855Sgabeblack@google.com      *curr_d = txn->get_data_ptr()[idx];
41312855Sgabeblack@google.com  }
41412855Sgabeblack@google.com
41512855Sgabeblack@google.com  // clean up
41612855Sgabeblack@google.com  delete [] txn->get_data_ptr();
41712855Sgabeblack@google.com  delete [] txn->get_byte_enable_ptr();
41812855Sgabeblack@google.com}
41912855Sgabeblack@google.com
420