1/*****************************************************************************
2
3  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
4  more contributor license agreements.  See the NOTICE file distributed
5  with this work for additional information regarding copyright ownership.
6  Accellera licenses this file to you under the Apache License, Version 2.0
7  (the "License"); you may not use this file except in compliance with the
8  License.  You may obtain a copy of the License at
9
10    http://www.apache.org/licenses/LICENSE-2.0
11
12  Unless required by applicable law or agreed to in writing, software
13  distributed under the License is distributed on an "AS IS" BASIS,
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
15  implied.  See the License for the specific language governing
16  permissions and limitations under the License.
17
18 *****************************************************************************/
19
20//====================================================================
21//  Nov 06, 2008
22//
23//  Updated by:
24//    Xiaopeng Qiu, JEDA Technologies, Inc
25//    Email:  qiuxp@jedatechnologies.net
26//
27//  To fix violations of TLM2.0 rules, which are detected by JEDA
28//  TLM2.0 checker.
29//
30//====================================================================
31
32#ifndef __SIMPLE_LT_INITIATOR1_DMI_H__
33#define __SIMPLE_LT_INITIATOR1_DMI_H__
34
35#include "tlm.h"
36#include <systemc>
37#include <cassert>
38#include <iostream>
39#include <iomanip>
40
41class SimpleLTInitiator1_dmi :
42  public sc_core::sc_module,
43  public virtual tlm::tlm_bw_transport_if<>
44{
45public:
46  typedef tlm::tlm_generic_payload      transaction_type;
47  typedef tlm::tlm_dmi                  dmi_type;
48  typedef tlm::tlm_phase                phase_type;
49  typedef tlm::tlm_sync_enum            sync_enum_type;
50  typedef tlm::tlm_fw_transport_if<>    fw_interface_type;
51  typedef tlm::tlm_bw_transport_if<>    bw_interface_type;
52  typedef tlm::tlm_initiator_socket<>   initiator_socket_type;
53
54public:
55  initiator_socket_type socket;
56
57public:
58  SC_HAS_PROCESS(SimpleLTInitiator1_dmi);
59  SimpleLTInitiator1_dmi(sc_core::sc_module_name name,
60                         unsigned int nrOfTransactions = 0x5,
61                         unsigned int baseAddress = 0x0) :
62    sc_core::sc_module(name),
63    socket("socket"),
64    mNrOfTransactions(nrOfTransactions),
65    mBaseAddress(baseAddress),
66    mTransactionCount(0)
67  {
68    invalidate(mDMIData);
69
70    // Bind this initiator's interface to the initiator socket
71    socket(*this);
72
73    // Initiator thread
74    SC_THREAD(run);
75  }
76
77  bool initTransaction(transaction_type& trans)
78  {
79    // initialize DMI hint:
80    trans.set_dmi_allowed(false);
81
82    if (mTransactionCount < mNrOfTransactions) {
83      trans.set_address(mBaseAddress + 4*mTransactionCount);
84      mData = mTransactionCount;
85      trans.set_command(tlm::TLM_WRITE_COMMAND);
86
87    } else if (mTransactionCount < 2 * mNrOfTransactions) {
88      trans.set_address(mBaseAddress + 4*(mTransactionCount-mNrOfTransactions));
89      mData = 0;
90      trans.set_command(tlm::TLM_READ_COMMAND);
91
92    } else {
93      return false;
94    }
95
96    trans.set_data_ptr(reinterpret_cast<unsigned char*>(&mData));
97    trans.set_data_length(4);
98    trans.set_streaming_width(4);
99
100    ++mTransactionCount;
101    return true;
102  }
103
104  void logStartTransation(transaction_type& trans)
105  {
106    if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
107      std::cout << name() << ": Send write request: A = 0x"
108                << std::hex << (unsigned int)trans.get_address()
109                << ", D = 0x" << mData << std::dec
110                << " @ " << sc_core::sc_time_stamp() << std::endl;
111
112    } else {
113      std::cout << name() << ": Send read request: A = 0x"
114                << std::hex << (unsigned int)trans.get_address() << std::dec
115                << " @ " << sc_core::sc_time_stamp() << std::endl;
116    }
117  }
118
119  void logEndTransaction(transaction_type& trans)
120  {
121    if (trans.get_response_status() != tlm::TLM_OK_RESPONSE) {
122      std::cout << name() << ": Received error response @ "
123                << sc_core::sc_time_stamp() << std::endl;
124
125    } else {
126      std::cout << name() <<  ": Received ok response";
127      if (trans.get_command() == tlm::TLM_READ_COMMAND) {
128        std::cout << ": D = 0x" << std::hex << mData << std::dec;
129      }
130      std::cout << " @ " << sc_core::sc_time_stamp() << std::endl;
131    }
132  }
133
134  void run()
135  {
136    transaction_type trans;
137    phase_type phase;
138    sc_core::sc_time t;
139
140    while (initTransaction(trans)) {
141      // Create transaction and initialise phase and t
142      phase = tlm::BEGIN_REQ;
143      t = sc_core::SC_ZERO_TIME;
144
145      logStartTransation(trans);
146
147      ///////////////////////////////////////////////////////////
148      // DMI handling:
149      // We use the DMI hint to check if it makes sense to ask for
150      // DMI pointers. The pattern is:
151      // - if the address is covered by a DMI region do a DMI access
152      // - otherwise do a normal transaction
153      //   -> check if we get a DMI hint and acquire the DMI pointers if it is
154      //      set
155      ///////////////////////////////////////////////////////////
156
157      // Check if the address is covered by our DMI region
158      if ( (trans.get_address() >= mDMIData.get_start_address()) &&
159           (trans.get_address() <= mDMIData.get_end_address()) ) {
160          // We can handle the data here. As the logEndTransaction is assuming
161          // something to happen in the data structure, we really need to
162          // do this:
163          trans.set_response_status(tlm::TLM_OK_RESPONSE);
164          sc_dt::uint64 tmp = trans.get_address() - mDMIData.get_start_address();
165          if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
166              *(unsigned int*)&mDMIData.get_dmi_ptr()[tmp] = mData;
167
168          } else {
169              mData = *(unsigned int*)&mDMIData.get_dmi_ptr()[tmp];
170          }
171
172          // Do the wait immediately. Note that doing the wait here eats almost
173          // all the performance anyway, so we only gain something if we're
174          // using temporal decoupling.
175          if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
176            wait(mDMIData.get_write_latency());
177
178          } else {
179            wait(mDMIData.get_read_latency());
180          }
181
182          logEndTransaction(trans);
183
184      } else { // we need a full transaction
185          sc_dt::uint64 addr = trans.get_address(); //Save address before it is mutated
186          socket->b_transport(trans, t);
187          wait(t);
188          logEndTransaction(trans);
189
190		  // Acquire DMI pointer on is available:
191          if (trans.is_dmi_allowed())
192          {
193              dmi_type tmp;
194              tmp.init();
195              trans.set_address(addr);  //restore address, in case it was mutated.
196              trans.set_write();
197              if ( socket->get_direct_mem_ptr(trans, tmp)
198                   && tmp.is_write_allowed() )
199              {
200                  mDMIData = tmp;
201              }
202          }
203      }
204    }
205    wait();
206  }
207
208  sync_enum_type nb_transport_bw(transaction_type& trans, phase_type& phase, sc_core::sc_time& t)
209  {
210      // We should never be called
211      assert(0);
212      return tlm::TLM_COMPLETED;
213  }
214
215  void invalidate(dmi_type& dmiData)
216  {
217    dmiData.set_start_address(1);
218    dmiData.set_end_address(0);
219  }
220
221  // Invalidate DMI pointer(s)
222  void invalidate_direct_mem_ptr(sc_dt::uint64 start_range,
223                                 sc_dt::uint64 end_range)
224  {
225      // do the invalidation if there is an address range overlap
226      if (start_range <= mDMIData.get_end_address ()&&
227          end_range >= mDMIData.get_start_address()) {
228          std::cout <<  name() << ": got DMI pointer invalidation"
229                    << " @ " << sc_core::sc_time_stamp() << std::endl;
230
231          invalidate(mDMIData);
232      } else {
233          std::cout <<  name() << ": ignored DMI invalidation for addresses "
234                    << std::hex << start_range << ", "
235                    << end_range << std::dec
236                    << " @ " << sc_core::sc_time_stamp() << std::endl;
237      }
238  }
239
240  // Test for transport_dbg:
241  // FIXME: use a configurable address
242  void end_of_simulation()
243  {
244    std::cout <<  name() << ", <<SimpleLTInitiator1>>:" << std::endl
245              << std::endl;
246    unsigned char data[32];
247
248    transaction_type trans;
249    trans.set_address(mBaseAddress);
250    trans.set_data_length(32);
251    trans.set_data_ptr(data);
252    trans.set_read();
253
254    unsigned int n = socket->transport_dbg(trans);
255
256    std::cout << "Mem @" << std::hex << mBaseAddress << std::endl;
257    unsigned int j = 0;
258
259    if (n > 0)
260    {
261        // always align endianness, so that we don't get a diff when
262        // printing the raw data
263        int e_start = 0;
264        int e_end = 4;
265        int e_increment = 1;
266        if (!tlm::host_has_little_endianness())
267        {
268            e_start = 3;
269            e_end = -1;
270            e_increment = -1;
271        }
272
273        for (unsigned int i=0; i<n; i+=4)
274        {
275            for (int k=e_start; k!=e_end; k+=e_increment)
276            {
277                std::cout << std::setw(2) << std::setfill('0')
278                          << (int)data[i+k];
279                j++;
280                if (j==16) {
281                    j=0;
282                    std::cout << std::endl;
283                } else {
284                    std::cout << " ";
285                }
286            }
287        }
288    }
289    else
290    {
291        std::cout << "ERROR: debug transaction didn't give data." << std::endl;
292    }
293    std::cout << std::dec << std::endl;
294  }
295private:
296  dmi_type mDMIData;
297
298  sc_core::sc_event mEndEvent;
299  unsigned int mNrOfTransactions;
300  unsigned int mBaseAddress;
301  unsigned int mTransactionCount;
302  unsigned int mData;
303};
304
305#endif
306