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#ifndef __SIMPLE_LT_INITIATOR_EXT_H__
2112855Sgabeblack@google.com#define __SIMPLE_LT_INITIATOR_EXT_H__
2212855Sgabeblack@google.com
2312855Sgabeblack@google.com#include "tlm.h"
2412855Sgabeblack@google.com#include "tlm_utils/simple_initiator_socket.h"
2512855Sgabeblack@google.com#include "my_extension.h"
2612855Sgabeblack@google.com
2712855Sgabeblack@google.com#include <systemc>
2812855Sgabeblack@google.com#include <cassert>
2912855Sgabeblack@google.com#include <iostream>
3012855Sgabeblack@google.com#include <iomanip>
3112855Sgabeblack@google.com#include <map>
3212855Sgabeblack@google.com
3312855Sgabeblack@google.comclass SimpleLTInitiator_ext : public sc_core::sc_module
3412855Sgabeblack@google.com{
3512855Sgabeblack@google.compublic:
3612855Sgabeblack@google.com  typedef tlm::tlm_generic_payload transaction_type;
3712855Sgabeblack@google.com  typedef tlm::tlm_dmi        dmi_type;
3812855Sgabeblack@google.com  typedef tlm::tlm_phase      phase_type;
3912855Sgabeblack@google.com  typedef tlm::tlm_sync_enum  sync_enum_type;
4012855Sgabeblack@google.com  typedef tlm_utils::simple_initiator_socket<SimpleLTInitiator_ext, 32,
4112855Sgabeblack@google.com                                my_extended_payload_types> initiator_socket_type;
4212855Sgabeblack@google.com
4312855Sgabeblack@google.compublic:
4412855Sgabeblack@google.com  initiator_socket_type socket;
4512855Sgabeblack@google.com
4612855Sgabeblack@google.compublic:
4712855Sgabeblack@google.com  SC_HAS_PROCESS(SimpleLTInitiator_ext);
4812855Sgabeblack@google.com  SimpleLTInitiator_ext(sc_core::sc_module_name name,
4912855Sgabeblack@google.com                        unsigned int nrOfTransactions = 0x5,
5012855Sgabeblack@google.com                        unsigned int baseAddress = 0x0) :
5112855Sgabeblack@google.com      sc_core::sc_module(name),
5212855Sgabeblack@google.com      socket("socket"),
5312855Sgabeblack@google.com      mNrOfTransactions(nrOfTransactions),
5412855Sgabeblack@google.com      mBaseAddress(baseAddress),
5512855Sgabeblack@google.com      mTransactionCount(0)
5612855Sgabeblack@google.com  {
5712855Sgabeblack@google.com      invalidate(mDMIData);
5812855Sgabeblack@google.com
5912855Sgabeblack@google.com      // register nb_transport method
6012855Sgabeblack@google.com      socket.register_nb_transport_bw(this, &SimpleLTInitiator_ext::myNBTransport);
6112855Sgabeblack@google.com      socket.register_invalidate_direct_mem_ptr(this, &SimpleLTInitiator_ext::invalidate_direct_mem_ptr);
6212855Sgabeblack@google.com
6312855Sgabeblack@google.com      // Initiator thread
6412855Sgabeblack@google.com      SC_THREAD(run);
6512855Sgabeblack@google.com
6612855Sgabeblack@google.com  }
6712855Sgabeblack@google.com
6812855Sgabeblack@google.com  bool initTransaction(transaction_type& trans)
6912855Sgabeblack@google.com  {
7012855Sgabeblack@google.com      // initialize DMI hint:
7112855Sgabeblack@google.com      trans.set_dmi_allowed(false);
7212855Sgabeblack@google.com
7312855Sgabeblack@google.com      if (mTransactionCount < mNrOfTransactions)
7412855Sgabeblack@google.com      {
7512855Sgabeblack@google.com          trans.set_address(mBaseAddress + 4*mTransactionCount);
7612855Sgabeblack@google.com          mData = mTransactionCount;
7712855Sgabeblack@google.com          trans.set_data_ptr(reinterpret_cast<unsigned char*>(&mData));
7812855Sgabeblack@google.com          trans.set_command(tlm::TLM_WRITE_COMMAND);
7912855Sgabeblack@google.com
8012855Sgabeblack@google.com      }
8112855Sgabeblack@google.com      else if (mTransactionCount < 2 * mNrOfTransactions)
8212855Sgabeblack@google.com      {
8312855Sgabeblack@google.com          trans.set_address(mBaseAddress + 4*(mTransactionCount-mNrOfTransactions));
8412855Sgabeblack@google.com          mData = 0;
8512855Sgabeblack@google.com          trans.set_data_ptr(reinterpret_cast<unsigned char*>(&mData));
8612855Sgabeblack@google.com          trans.set_command(tlm::TLM_READ_COMMAND);
8712855Sgabeblack@google.com
8812855Sgabeblack@google.com      }
8912855Sgabeblack@google.com      else
9012855Sgabeblack@google.com      {
9112855Sgabeblack@google.com          return false;
9212855Sgabeblack@google.com      }
9312855Sgabeblack@google.com
9412855Sgabeblack@google.com      ++mTransactionCount;
9512855Sgabeblack@google.com      return true;
9612855Sgabeblack@google.com  }
9712855Sgabeblack@google.com
9812855Sgabeblack@google.com  void logStartTransation(transaction_type& trans)
9912855Sgabeblack@google.com  {
10012855Sgabeblack@google.com      if (trans.get_command() == tlm::TLM_WRITE_COMMAND)
10112855Sgabeblack@google.com      {
10212855Sgabeblack@google.com          std::cout << name() << ": Send write request: A = 0x"
10312855Sgabeblack@google.com                    << std::hex << (unsigned int)trans.get_address()
10412855Sgabeblack@google.com                    << ", D = 0x" << mData << std::dec
10512855Sgabeblack@google.com                    << " @ " << sc_core::sc_time_stamp() << std::endl;
10612855Sgabeblack@google.com
10712855Sgabeblack@google.com      }
10812855Sgabeblack@google.com      else
10912855Sgabeblack@google.com      {
11012855Sgabeblack@google.com          std::cout << name() << ": Send read request: A = 0x"
11112855Sgabeblack@google.com                    << std::hex << (unsigned int)trans.get_address()
11212855Sgabeblack@google.com                    << std::dec
11312855Sgabeblack@google.com                    << " @ " << sc_core::sc_time_stamp() << std::endl;
11412855Sgabeblack@google.com      }
11512855Sgabeblack@google.com  }
11612855Sgabeblack@google.com
11712855Sgabeblack@google.com  void logEndTransaction(transaction_type& trans)
11812855Sgabeblack@google.com  {
11912855Sgabeblack@google.com      if (trans.get_response_status() != tlm::TLM_OK_RESPONSE) {
12012855Sgabeblack@google.com          std::cout << name() << ": Received error response @ "
12112855Sgabeblack@google.com                    << sc_core::sc_time_stamp() << std::endl;
12212855Sgabeblack@google.com      }
12312855Sgabeblack@google.com      else
12412855Sgabeblack@google.com      {
12512855Sgabeblack@google.com          std::cout << name() <<  ": Received ok response";
12612855Sgabeblack@google.com          if (trans.get_command() == tlm::TLM_READ_COMMAND) {
12712855Sgabeblack@google.com              std::cout << ": D = 0x" << std::hex << mData << std::dec;
12812855Sgabeblack@google.com          }
12912855Sgabeblack@google.com          std::cout << " @ " << sc_core::sc_time_stamp() << std::endl;
13012855Sgabeblack@google.com      }
13112855Sgabeblack@google.com  }
13212855Sgabeblack@google.com
13312855Sgabeblack@google.com  void run()
13412855Sgabeblack@google.com  {
13512855Sgabeblack@google.com      transaction_type trans;
13612855Sgabeblack@google.com      phase_type phase;
13712855Sgabeblack@google.com      sc_core::sc_time t;
13812855Sgabeblack@google.com      // make sure that our transaction has the proper extension:
13912855Sgabeblack@google.com      my_extension* tmp_ext = new my_extension();
14012855Sgabeblack@google.com      tmp_ext->m_data = 11;
14112855Sgabeblack@google.com
14212855Sgabeblack@google.com      trans.set_extension(tmp_ext);
14312855Sgabeblack@google.com
14412855Sgabeblack@google.com      while (initTransaction(trans))
14512855Sgabeblack@google.com      {
14612855Sgabeblack@google.com          // Create transaction and initialise phase and t
14712855Sgabeblack@google.com          phase = tlm::BEGIN_REQ;
14812855Sgabeblack@google.com          t = sc_core::SC_ZERO_TIME;
14912855Sgabeblack@google.com
15012855Sgabeblack@google.com          logStartTransation(trans);
15112855Sgabeblack@google.com          ///////////////////////////////////////////////////////////
15212855Sgabeblack@google.com          // DMI handling:
15312855Sgabeblack@google.com          // We use the DMI hint to check if it makes sense to ask for
15412855Sgabeblack@google.com          // DMI pointers. The pattern is:
15512855Sgabeblack@google.com          // - if the address is covered by a DMI region do a DMI access
15612855Sgabeblack@google.com          // - otherwise do a normal transaction
15712855Sgabeblack@google.com          //   -> check if we get a DMI hint and acquire the DMI pointers if it
15812855Sgabeblack@google.com          //      is set
15912855Sgabeblack@google.com          ///////////////////////////////////////////////////////////
16012855Sgabeblack@google.com
16112855Sgabeblack@google.com          // Check if the address is covered by our DMI region
16212855Sgabeblack@google.com          if ( (trans.get_address() >= mDMIData.get_start_address()) &&
16312855Sgabeblack@google.com               (trans.get_address() <= mDMIData.get_end_address()) )
16412855Sgabeblack@google.com          {
16512855Sgabeblack@google.com              // We can handle the data here. As the logEndTransaction is
16612855Sgabeblack@google.com              // assuming something to happen in the data structure, we really
16712855Sgabeblack@google.com              // need to do this:
16812855Sgabeblack@google.com              trans.set_response_status(tlm::TLM_OK_RESPONSE);
16912855Sgabeblack@google.com              sc_dt::uint64 tmp = trans.get_address() - mDMIData.get_start_address();
17012855Sgabeblack@google.com              if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
17112855Sgabeblack@google.com                  *(unsigned int*)&mDMIData.get_dmi_ptr()[tmp] = mData;
17212855Sgabeblack@google.com
17312855Sgabeblack@google.com              } else {
17412855Sgabeblack@google.com                  mData = *(unsigned int*)&mDMIData.get_dmi_ptr()[tmp];
17512855Sgabeblack@google.com              }
17612855Sgabeblack@google.com
17712855Sgabeblack@google.com              // Do the wait immediately. Note that doing the wait here eats
17812855Sgabeblack@google.com              //  almost all the performance anyway, so we only gain something
17912855Sgabeblack@google.com              // if we're using temporal decoupling.
18012855Sgabeblack@google.com              if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
18112855Sgabeblack@google.com                  wait(mDMIData.get_write_latency());
18212855Sgabeblack@google.com
18312855Sgabeblack@google.com              } else {
18412855Sgabeblack@google.com                  wait(mDMIData.get_read_latency());
18512855Sgabeblack@google.com              }
18612855Sgabeblack@google.com
18712855Sgabeblack@google.com              logEndTransaction(trans);
18812855Sgabeblack@google.com
18912855Sgabeblack@google.com          } else { // we need a full transaction
19012855Sgabeblack@google.com              switch (socket->nb_transport_fw(trans, phase, t)) {
19112855Sgabeblack@google.com              case tlm::TLM_COMPLETED:
19212855Sgabeblack@google.com                  // Transaction Finished, wait for the returned delay
19312855Sgabeblack@google.com                  wait(t);
19412855Sgabeblack@google.com                  break;
19512855Sgabeblack@google.com
19612855Sgabeblack@google.com              case tlm::TLM_ACCEPTED:
19712855Sgabeblack@google.com              case tlm::TLM_UPDATED:
19812855Sgabeblack@google.com                  // Transaction not yet finished, wait for the end of it
19912855Sgabeblack@google.com                  wait(mEndEvent);
20012855Sgabeblack@google.com                  break;
20112855Sgabeblack@google.com
20212855Sgabeblack@google.com              default:
20312855Sgabeblack@google.com                  sc_assert(0); exit(1);
20412855Sgabeblack@google.com              };
20512855Sgabeblack@google.com
20612855Sgabeblack@google.com              logEndTransaction(trans);
20712855Sgabeblack@google.com
20812855Sgabeblack@google.com              // Acquire DMI pointer if one is available:
20912855Sgabeblack@google.com              if (trans.is_dmi_allowed())
21012855Sgabeblack@google.com              {
21112855Sgabeblack@google.com                  trans.set_write();
21212855Sgabeblack@google.com                  dmi_type tmp;
21312855Sgabeblack@google.com                  if (socket->get_direct_mem_ptr(trans,
21412855Sgabeblack@google.com                                                 tmp))
21512855Sgabeblack@google.com                  {
21612855Sgabeblack@google.com                      // FIXME: No support for separate read/write ranges
21712855Sgabeblack@google.com                      sc_assert(tmp.is_read_write_allowed());
21812855Sgabeblack@google.com                      mDMIData = tmp;
21912855Sgabeblack@google.com                  }
22012855Sgabeblack@google.com              }
22112855Sgabeblack@google.com          }
22212855Sgabeblack@google.com      }
22312855Sgabeblack@google.com      delete tmp_ext;
22412855Sgabeblack@google.com      wait();
22512855Sgabeblack@google.com
22612855Sgabeblack@google.com  }
22712855Sgabeblack@google.com
22812855Sgabeblack@google.com  sync_enum_type myNBTransport(transaction_type& trans,
22912855Sgabeblack@google.com                               phase_type& phase,
23012855Sgabeblack@google.com                               sc_core::sc_time& t)
23112855Sgabeblack@google.com  {
23212855Sgabeblack@google.com      switch (phase) {
23312855Sgabeblack@google.com      case tlm::END_REQ:
23412855Sgabeblack@google.com          // Request phase ended
23512855Sgabeblack@google.com          return tlm::TLM_ACCEPTED;
23612855Sgabeblack@google.com
23712855Sgabeblack@google.com      case tlm::BEGIN_RESP:
23812855Sgabeblack@google.com          sc_assert(t == sc_core::SC_ZERO_TIME); // FIXME: can t != 0?
23912855Sgabeblack@google.com          mEndEvent.notify(t);
24012855Sgabeblack@google.com          // Not needed to update the phase if true is returned
24112855Sgabeblack@google.com          return tlm::TLM_COMPLETED;
24212855Sgabeblack@google.com
24312855Sgabeblack@google.com      case tlm::BEGIN_REQ: // fall-through
24412855Sgabeblack@google.com      case tlm::END_RESP: // fall-through
24512855Sgabeblack@google.com      default:
24612855Sgabeblack@google.com          // A target should never call nb_transport with these phases
24712855Sgabeblack@google.com          sc_assert(0); exit(1);
24812855Sgabeblack@google.com//          return tlm::TLM_COMPLETED;  //unreachable code
24912855Sgabeblack@google.com      };
25012855Sgabeblack@google.com  }
25112855Sgabeblack@google.com
25212855Sgabeblack@google.com  void invalidate(dmi_type& dmiData)
25312855Sgabeblack@google.com  {
25412855Sgabeblack@google.com      dmiData.set_start_address(1);
25512855Sgabeblack@google.com      dmiData.set_end_address(0);
25612855Sgabeblack@google.com  }
25712855Sgabeblack@google.com
25812855Sgabeblack@google.com  // Invalidate DMI pointer(s)
25912855Sgabeblack@google.com  void invalidate_direct_mem_ptr(sc_dt::uint64 start_range,
26012855Sgabeblack@google.com                                 sc_dt::uint64 end_range)
26112855Sgabeblack@google.com  {
26212855Sgabeblack@google.com      // do the invalidation if there is an address range overlap
26312855Sgabeblack@google.com      if (start_range <= mDMIData.get_end_address ()&&
26412855Sgabeblack@google.com          end_range >= mDMIData.get_start_address()) {
26512855Sgabeblack@google.com          std::cout <<  name() << ": got DMI pointer invalidation"
26612855Sgabeblack@google.com                    << " @ " << sc_core::sc_time_stamp() << std::endl;
26712855Sgabeblack@google.com
26812855Sgabeblack@google.com          invalidate(mDMIData);
26912855Sgabeblack@google.com      } else {
27012855Sgabeblack@google.com          std::cout <<  name() << ": ignored DMI invalidation for addresses "
27112855Sgabeblack@google.com                    << std::hex << start_range << ", "
27212855Sgabeblack@google.com                    << end_range << std::dec
27312855Sgabeblack@google.com                    << " @ " << sc_core::sc_time_stamp() << std::endl;
27412855Sgabeblack@google.com      }
27512855Sgabeblack@google.com  }
27612855Sgabeblack@google.com
27712855Sgabeblack@google.com  // Test for transport_dbg, this one should fail in bus_dmi as we address
27812855Sgabeblack@google.com  // a target that doesn't support transport_dbg:
27912855Sgabeblack@google.com  // FIXME: use a configurable address
28012855Sgabeblack@google.com  void end_of_simulation()
28112855Sgabeblack@google.com  {
28212855Sgabeblack@google.com      std::cout <<  name() << ", <<SimpleLTInitiator1>>:" << std::endl
28312855Sgabeblack@google.com                << std::endl;
28412855Sgabeblack@google.com      unsigned char data[32];
28512855Sgabeblack@google.com
28612855Sgabeblack@google.com      transaction_type trans;
28712855Sgabeblack@google.com      trans.set_address(mBaseAddress);
28812855Sgabeblack@google.com      trans.set_data_length(32);
28912855Sgabeblack@google.com      trans.set_data_ptr(data);
29012855Sgabeblack@google.com      trans.set_read();
29112855Sgabeblack@google.com
29212855Sgabeblack@google.com      unsigned int n = socket->transport_dbg(trans);
29312855Sgabeblack@google.com
29412855Sgabeblack@google.com      std::cout << "Mem @" << std::hex << mBaseAddress << std::endl;
29512855Sgabeblack@google.com      unsigned int j = 0;
29612855Sgabeblack@google.com
29712855Sgabeblack@google.com      if (n > 0)
29812855Sgabeblack@google.com      {
29912855Sgabeblack@google.com          // always align endianness, so that we don't get a diff when
30012855Sgabeblack@google.com          // printing the raw data
30112855Sgabeblack@google.com          int e_start = 0;
30212855Sgabeblack@google.com          int e_end = 4;
30312855Sgabeblack@google.com          int e_increment = 1;
30412855Sgabeblack@google.com          if (!tlm::host_has_little_endianness())
30512855Sgabeblack@google.com          {
30612855Sgabeblack@google.com              e_start = 3;
30712855Sgabeblack@google.com              e_end = -1;
30812855Sgabeblack@google.com              e_increment = -1;
30912855Sgabeblack@google.com          }
31012855Sgabeblack@google.com
31112855Sgabeblack@google.com          for (unsigned int i=0; i<n; i+=4)
31212855Sgabeblack@google.com          {
31312855Sgabeblack@google.com              for (int k=e_start; k!=e_end; k+=e_increment)
31412855Sgabeblack@google.com              {
31512855Sgabeblack@google.com                  std::cout << std::setw(2) << std::setfill('0')
31612855Sgabeblack@google.com                            << (int)data[i+k];
31712855Sgabeblack@google.com                  j++;
31812855Sgabeblack@google.com                  if (j==16) {
31912855Sgabeblack@google.com                      j=0;
32012855Sgabeblack@google.com                      std::cout << std::endl;
32112855Sgabeblack@google.com                  } else {
32212855Sgabeblack@google.com                      std::cout << " ";
32312855Sgabeblack@google.com                  }
32412855Sgabeblack@google.com              }
32512855Sgabeblack@google.com          }
32612855Sgabeblack@google.com      }
32712855Sgabeblack@google.com      else
32812855Sgabeblack@google.com      {
32912855Sgabeblack@google.com          std::cout << "OK: debug transaction didn't give data." << std::endl;
33012855Sgabeblack@google.com      }
33112855Sgabeblack@google.com      std::cout << std::dec << std::endl;
33212855Sgabeblack@google.com  }
33312855Sgabeblack@google.comprivate:
33412855Sgabeblack@google.com  dmi_type mDMIData;
33512855Sgabeblack@google.com
33612855Sgabeblack@google.com  sc_core::sc_event mEndEvent;
33712855Sgabeblack@google.com  unsigned int mNrOfTransactions;
33812855Sgabeblack@google.com  unsigned int mBaseAddress;
33912855Sgabeblack@google.com  unsigned int mTransactionCount;
34012855Sgabeblack@google.com  unsigned int mData;
34112855Sgabeblack@google.com};
34212855Sgabeblack@google.com
34312855Sgabeblack@google.com#endif
344