SimpleLTInitiator_ext.h revision 12855:588919e0e4aa
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#ifndef __SIMPLE_LT_INITIATOR_EXT_H__
21#define __SIMPLE_LT_INITIATOR_EXT_H__
22
23#include "tlm.h"
24#include "tlm_utils/simple_initiator_socket.h"
25#include "my_extension.h"
26
27#include <systemc>
28#include <cassert>
29#include <iostream>
30#include <iomanip>
31#include <map>
32
33class SimpleLTInitiator_ext : public sc_core::sc_module
34{
35public:
36  typedef tlm::tlm_generic_payload transaction_type;
37  typedef tlm::tlm_dmi        dmi_type;
38  typedef tlm::tlm_phase      phase_type;
39  typedef tlm::tlm_sync_enum  sync_enum_type;
40  typedef tlm_utils::simple_initiator_socket<SimpleLTInitiator_ext, 32,
41                                my_extended_payload_types> initiator_socket_type;
42
43public:
44  initiator_socket_type socket;
45
46public:
47  SC_HAS_PROCESS(SimpleLTInitiator_ext);
48  SimpleLTInitiator_ext(sc_core::sc_module_name name,
49                        unsigned int nrOfTransactions = 0x5,
50                        unsigned int baseAddress = 0x0) :
51      sc_core::sc_module(name),
52      socket("socket"),
53      mNrOfTransactions(nrOfTransactions),
54      mBaseAddress(baseAddress),
55      mTransactionCount(0)
56  {
57      invalidate(mDMIData);
58
59      // register nb_transport method
60      socket.register_nb_transport_bw(this, &SimpleLTInitiator_ext::myNBTransport);
61      socket.register_invalidate_direct_mem_ptr(this, &SimpleLTInitiator_ext::invalidate_direct_mem_ptr);
62
63      // Initiator thread
64      SC_THREAD(run);
65
66  }
67
68  bool initTransaction(transaction_type& trans)
69  {
70      // initialize DMI hint:
71      trans.set_dmi_allowed(false);
72
73      if (mTransactionCount < mNrOfTransactions)
74      {
75          trans.set_address(mBaseAddress + 4*mTransactionCount);
76          mData = mTransactionCount;
77          trans.set_data_ptr(reinterpret_cast<unsigned char*>(&mData));
78          trans.set_command(tlm::TLM_WRITE_COMMAND);
79
80      }
81      else if (mTransactionCount < 2 * mNrOfTransactions)
82      {
83          trans.set_address(mBaseAddress + 4*(mTransactionCount-mNrOfTransactions));
84          mData = 0;
85          trans.set_data_ptr(reinterpret_cast<unsigned char*>(&mData));
86          trans.set_command(tlm::TLM_READ_COMMAND);
87
88      }
89      else
90      {
91          return false;
92      }
93
94      ++mTransactionCount;
95      return true;
96  }
97
98  void logStartTransation(transaction_type& trans)
99  {
100      if (trans.get_command() == tlm::TLM_WRITE_COMMAND)
101      {
102          std::cout << name() << ": Send write request: A = 0x"
103                    << std::hex << (unsigned int)trans.get_address()
104                    << ", D = 0x" << mData << std::dec
105                    << " @ " << sc_core::sc_time_stamp() << std::endl;
106
107      }
108      else
109      {
110          std::cout << name() << ": Send read request: A = 0x"
111                    << std::hex << (unsigned int)trans.get_address()
112                    << std::dec
113                    << " @ " << sc_core::sc_time_stamp() << std::endl;
114      }
115  }
116
117  void logEndTransaction(transaction_type& trans)
118  {
119      if (trans.get_response_status() != tlm::TLM_OK_RESPONSE) {
120          std::cout << name() << ": Received error response @ "
121                    << sc_core::sc_time_stamp() << std::endl;
122      }
123      else
124      {
125          std::cout << name() <<  ": Received ok response";
126          if (trans.get_command() == tlm::TLM_READ_COMMAND) {
127              std::cout << ": D = 0x" << std::hex << mData << std::dec;
128          }
129          std::cout << " @ " << sc_core::sc_time_stamp() << std::endl;
130      }
131  }
132
133  void run()
134  {
135      transaction_type trans;
136      phase_type phase;
137      sc_core::sc_time t;
138      // make sure that our transaction has the proper extension:
139      my_extension* tmp_ext = new my_extension();
140      tmp_ext->m_data = 11;
141
142      trans.set_extension(tmp_ext);
143
144      while (initTransaction(trans))
145      {
146          // Create transaction and initialise phase and t
147          phase = tlm::BEGIN_REQ;
148          t = sc_core::SC_ZERO_TIME;
149
150          logStartTransation(trans);
151          ///////////////////////////////////////////////////////////
152          // DMI handling:
153          // We use the DMI hint to check if it makes sense to ask for
154          // DMI pointers. The pattern is:
155          // - if the address is covered by a DMI region do a DMI access
156          // - otherwise do a normal transaction
157          //   -> check if we get a DMI hint and acquire the DMI pointers if it
158          //      is set
159          ///////////////////////////////////////////////////////////
160
161          // Check if the address is covered by our DMI region
162          if ( (trans.get_address() >= mDMIData.get_start_address()) &&
163               (trans.get_address() <= mDMIData.get_end_address()) )
164          {
165              // We can handle the data here. As the logEndTransaction is
166              // assuming something to happen in the data structure, we really
167              // need to do this:
168              trans.set_response_status(tlm::TLM_OK_RESPONSE);
169              sc_dt::uint64 tmp = trans.get_address() - mDMIData.get_start_address();
170              if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
171                  *(unsigned int*)&mDMIData.get_dmi_ptr()[tmp] = mData;
172
173              } else {
174                  mData = *(unsigned int*)&mDMIData.get_dmi_ptr()[tmp];
175              }
176
177              // Do the wait immediately. Note that doing the wait here eats
178              //  almost all the performance anyway, so we only gain something
179              // if we're using temporal decoupling.
180              if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
181                  wait(mDMIData.get_write_latency());
182
183              } else {
184                  wait(mDMIData.get_read_latency());
185              }
186
187              logEndTransaction(trans);
188
189          } else { // we need a full transaction
190              switch (socket->nb_transport_fw(trans, phase, t)) {
191              case tlm::TLM_COMPLETED:
192                  // Transaction Finished, wait for the returned delay
193                  wait(t);
194                  break;
195
196              case tlm::TLM_ACCEPTED:
197              case tlm::TLM_UPDATED:
198                  // Transaction not yet finished, wait for the end of it
199                  wait(mEndEvent);
200                  break;
201
202              default:
203                  sc_assert(0); exit(1);
204              };
205
206              logEndTransaction(trans);
207
208              // Acquire DMI pointer if one is available:
209              if (trans.is_dmi_allowed())
210              {
211                  trans.set_write();
212                  dmi_type tmp;
213                  if (socket->get_direct_mem_ptr(trans,
214                                                 tmp))
215                  {
216                      // FIXME: No support for separate read/write ranges
217                      sc_assert(tmp.is_read_write_allowed());
218                      mDMIData = tmp;
219                  }
220              }
221          }
222      }
223      delete tmp_ext;
224      wait();
225
226  }
227
228  sync_enum_type myNBTransport(transaction_type& trans,
229                               phase_type& phase,
230                               sc_core::sc_time& t)
231  {
232      switch (phase) {
233      case tlm::END_REQ:
234          // Request phase ended
235          return tlm::TLM_ACCEPTED;
236
237      case tlm::BEGIN_RESP:
238          sc_assert(t == sc_core::SC_ZERO_TIME); // FIXME: can t != 0?
239          mEndEvent.notify(t);
240          // Not needed to update the phase if true is returned
241          return tlm::TLM_COMPLETED;
242
243      case tlm::BEGIN_REQ: // fall-through
244      case tlm::END_RESP: // fall-through
245      default:
246          // A target should never call nb_transport with these phases
247          sc_assert(0); exit(1);
248//          return tlm::TLM_COMPLETED;  //unreachable code
249      };
250  }
251
252  void invalidate(dmi_type& dmiData)
253  {
254      dmiData.set_start_address(1);
255      dmiData.set_end_address(0);
256  }
257
258  // Invalidate DMI pointer(s)
259  void invalidate_direct_mem_ptr(sc_dt::uint64 start_range,
260                                 sc_dt::uint64 end_range)
261  {
262      // do the invalidation if there is an address range overlap
263      if (start_range <= mDMIData.get_end_address ()&&
264          end_range >= mDMIData.get_start_address()) {
265          std::cout <<  name() << ": got DMI pointer invalidation"
266                    << " @ " << sc_core::sc_time_stamp() << std::endl;
267
268          invalidate(mDMIData);
269      } else {
270          std::cout <<  name() << ": ignored DMI invalidation for addresses "
271                    << std::hex << start_range << ", "
272                    << end_range << std::dec
273                    << " @ " << sc_core::sc_time_stamp() << std::endl;
274      }
275  }
276
277  // Test for transport_dbg, this one should fail in bus_dmi as we address
278  // a target that doesn't support transport_dbg:
279  // FIXME: use a configurable address
280  void end_of_simulation()
281  {
282      std::cout <<  name() << ", <<SimpleLTInitiator1>>:" << std::endl
283                << std::endl;
284      unsigned char data[32];
285
286      transaction_type trans;
287      trans.set_address(mBaseAddress);
288      trans.set_data_length(32);
289      trans.set_data_ptr(data);
290      trans.set_read();
291
292      unsigned int n = socket->transport_dbg(trans);
293
294      std::cout << "Mem @" << std::hex << mBaseAddress << std::endl;
295      unsigned int j = 0;
296
297      if (n > 0)
298      {
299          // always align endianness, so that we don't get a diff when
300          // printing the raw data
301          int e_start = 0;
302          int e_end = 4;
303          int e_increment = 1;
304          if (!tlm::host_has_little_endianness())
305          {
306              e_start = 3;
307              e_end = -1;
308              e_increment = -1;
309          }
310
311          for (unsigned int i=0; i<n; i+=4)
312          {
313              for (int k=e_start; k!=e_end; k+=e_increment)
314              {
315                  std::cout << std::setw(2) << std::setfill('0')
316                            << (int)data[i+k];
317                  j++;
318                  if (j==16) {
319                      j=0;
320                      std::cout << std::endl;
321                  } else {
322                      std::cout << " ";
323                  }
324              }
325          }
326      }
327      else
328      {
329          std::cout << "OK: debug transaction didn't give data." << std::endl;
330      }
331      std::cout << std::dec << std::endl;
332  }
333private:
334  dmi_type mDMIData;
335
336  sc_core::sc_event mEndEvent;
337  unsigned int mNrOfTransactions;
338  unsigned int mBaseAddress;
339  unsigned int mTransactionCount;
340  unsigned int mData;
341};
342
343#endif
344