SimpleLTInitiator2_DMI.h revision 12922
110298Salexandru.dutu@amd.com/*****************************************************************************
210298Salexandru.dutu@amd.com
310298Salexandru.dutu@amd.com  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
410298Salexandru.dutu@amd.com  more contributor license agreements.  See the NOTICE file distributed
510298Salexandru.dutu@amd.com  with this work for additional information regarding copyright ownership.
610298Salexandru.dutu@amd.com  Accellera licenses this file to you under the Apache License, Version 2.0
710298Salexandru.dutu@amd.com  (the "License"); you may not use this file except in compliance with the
810298Salexandru.dutu@amd.com  License.  You may obtain a copy of the License at
910298Salexandru.dutu@amd.com
1010298Salexandru.dutu@amd.com    http://www.apache.org/licenses/LICENSE-2.0
1110298Salexandru.dutu@amd.com
1210298Salexandru.dutu@amd.com  Unless required by applicable law or agreed to in writing, software
1310298Salexandru.dutu@amd.com  distributed under the License is distributed on an "AS IS" BASIS,
1410298Salexandru.dutu@amd.com  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
1510298Salexandru.dutu@amd.com  implied.  See the License for the specific language governing
1610298Salexandru.dutu@amd.com  permissions and limitations under the License.
1710298Salexandru.dutu@amd.com
1810298Salexandru.dutu@amd.com *****************************************************************************/
1910298Salexandru.dutu@amd.com
2010298Salexandru.dutu@amd.com//====================================================================
2110298Salexandru.dutu@amd.com//  Nov 06, 2008
2210298Salexandru.dutu@amd.com//
2310298Salexandru.dutu@amd.com//  Updated by:
2410298Salexandru.dutu@amd.com//    Xiaopeng Qiu, JEDA Technologies, Inc
2510298Salexandru.dutu@amd.com//    Email:  qiuxp@jedatechnologies.net
2610298Salexandru.dutu@amd.com//
2710298Salexandru.dutu@amd.com//  To fix violations of TLM2.0 rules, which are detected by JEDA
2810298Salexandru.dutu@amd.com//  TLM2.0 checker.
2910298Salexandru.dutu@amd.com//
3010298Salexandru.dutu@amd.com//====================================================================
3110298Salexandru.dutu@amd.com
3210298Salexandru.dutu@amd.com#ifndef __SIMPLE_LT_INITIATOR2_DMI_H__
3310298Salexandru.dutu@amd.com#define __SIMPLE_LT_INITIATOR2_DMI_H__
3410298Salexandru.dutu@amd.com
3510298Salexandru.dutu@amd.com#include "tlm.h"
3610298Salexandru.dutu@amd.com#include "tlm_utils/simple_initiator_socket.h"
3710298Salexandru.dutu@amd.com#include <systemc>
3810298Salexandru.dutu@amd.com#include <cassert>
3910298Salexandru.dutu@amd.com#include <iostream>
4010298Salexandru.dutu@amd.com#include <iomanip>
4110298Salexandru.dutu@amd.com#include <map>
4210298Salexandru.dutu@amd.com
4310298Salexandru.dutu@amd.comclass SimpleLTInitiator2_dmi : public sc_core::sc_module
4411800Sbrandon.potter@amd.com{
4511800Sbrandon.potter@amd.compublic:
4610298Salexandru.dutu@amd.com  typedef tlm::tlm_generic_payload                      transaction_type;
4710298Salexandru.dutu@amd.com  typedef tlm::tlm_dmi                                  dmi_type;
4810298Salexandru.dutu@amd.com  typedef tlm::tlm_phase                                phase_type;
4910298Salexandru.dutu@amd.com  typedef tlm::tlm_sync_enum                            sync_enum_type;
5010298Salexandru.dutu@amd.com  typedef tlm_utils::simple_initiator_socket<SimpleLTInitiator2_dmi> initiator_socket_type;
5110298Salexandru.dutu@amd.com
5210298Salexandru.dutu@amd.compublic:
5310298Salexandru.dutu@amd.com  initiator_socket_type socket;
5410298Salexandru.dutu@amd.com
5510298Salexandru.dutu@amd.compublic:
5610298Salexandru.dutu@amd.com  SC_HAS_PROCESS(SimpleLTInitiator2_dmi);
5710298Salexandru.dutu@amd.com  SimpleLTInitiator2_dmi(sc_core::sc_module_name name,
5810298Salexandru.dutu@amd.com                  unsigned int nrOfTransactions = 0x5,
5910298Salexandru.dutu@amd.com                  unsigned int baseAddress = 0x0) :
6010298Salexandru.dutu@amd.com    sc_core::sc_module(name),
6110298Salexandru.dutu@amd.com    socket("socket"),
6210298Salexandru.dutu@amd.com    mNrOfTransactions(nrOfTransactions),
6310298Salexandru.dutu@amd.com    mBaseAddress(baseAddress),
6410298Salexandru.dutu@amd.com    mTransactionCount(0)
6510298Salexandru.dutu@amd.com  {
6610298Salexandru.dutu@amd.com    mDMIDataReads.first.set_start_address(1);
6710298Salexandru.dutu@amd.com    mDMIDataReads.first.set_end_address(0);
6810298Salexandru.dutu@amd.com    mDMIDataWrites.first.set_start_address(1);
6910298Salexandru.dutu@amd.com    mDMIDataWrites.first.set_end_address(0);
7010298Salexandru.dutu@amd.com
7110298Salexandru.dutu@amd.com    // register invalidate method
7210298Salexandru.dutu@amd.com    socket.register_invalidate_direct_mem_ptr(this, &SimpleLTInitiator2_dmi::invalidate_direct_mem_ptr);
7310298Salexandru.dutu@amd.com
7410298Salexandru.dutu@amd.com    // Initiator thread
7510298Salexandru.dutu@amd.com    SC_THREAD(run);
7610298Salexandru.dutu@amd.com  }
7710298Salexandru.dutu@amd.com
7810298Salexandru.dutu@amd.com  bool initTransaction(transaction_type& trans)
7910298Salexandru.dutu@amd.com  {
8010298Salexandru.dutu@amd.com    if (mTransactionCount < mNrOfTransactions) {
8110298Salexandru.dutu@amd.com      trans.set_address(mBaseAddress + 4*mTransactionCount);
8210298Salexandru.dutu@amd.com      mData = mTransactionCount;
8310298Salexandru.dutu@amd.com      trans.set_command(tlm::TLM_WRITE_COMMAND);
8410298Salexandru.dutu@amd.com
8510298Salexandru.dutu@amd.com    } else if (mTransactionCount < 2 * mNrOfTransactions) {
8610298Salexandru.dutu@amd.com      trans.set_address(mBaseAddress + 4*(mTransactionCount-mNrOfTransactions));
8710298Salexandru.dutu@amd.com      mData = 0;
8810298Salexandru.dutu@amd.com      trans.set_command(tlm::TLM_READ_COMMAND);
8910298Salexandru.dutu@amd.com
9010298Salexandru.dutu@amd.com    } else {
9110298Salexandru.dutu@amd.com      return false;
9210298Salexandru.dutu@amd.com    }
9310298Salexandru.dutu@amd.com
9410298Salexandru.dutu@amd.com    trans.set_data_ptr(reinterpret_cast<unsigned char*>(&mData));
9510298Salexandru.dutu@amd.com    trans.set_data_length(4);
9610298Salexandru.dutu@amd.com    trans.set_streaming_width(4);
9710298Salexandru.dutu@amd.com    trans.set_dmi_allowed(false);
9810298Salexandru.dutu@amd.com    trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
9910298Salexandru.dutu@amd.com
10010298Salexandru.dutu@amd.com    ++mTransactionCount;
10110298Salexandru.dutu@amd.com    return true;
10210298Salexandru.dutu@amd.com  }
10312448Sgabeblack@google.com
10410298Salexandru.dutu@amd.com  void logStartTransation(transaction_type& trans)
10510298Salexandru.dutu@amd.com  {
10610298Salexandru.dutu@amd.com    if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
10710298Salexandru.dutu@amd.com      std::cout << name() << ": Send write request: A = 0x"
10810298Salexandru.dutu@amd.com                << std::hex << (unsigned int)trans.get_address()
10910298Salexandru.dutu@amd.com                << ", D = 0x" << mData << std::dec
11010298Salexandru.dutu@amd.com                << " @ " << sc_core::sc_time_stamp() << std::endl;
11110298Salexandru.dutu@amd.com
11210298Salexandru.dutu@amd.com    } else {
11310298Salexandru.dutu@amd.com      std::cout << name() << ": Send read request: A = 0x"
11410298Salexandru.dutu@amd.com                << std::hex << (unsigned int)trans.get_address() << std::dec
11510298Salexandru.dutu@amd.com                << " @ " << sc_core::sc_time_stamp() << std::endl;
11610298Salexandru.dutu@amd.com    }
11710298Salexandru.dutu@amd.com  }
11810298Salexandru.dutu@amd.com
11910298Salexandru.dutu@amd.com  void logEndTransaction(transaction_type& trans)
12010298Salexandru.dutu@amd.com  {
12110298Salexandru.dutu@amd.com    if (trans.get_response_status() != tlm::TLM_OK_RESPONSE) {
12210298Salexandru.dutu@amd.com      std::cout << name() << ": Received error response @ "
12310298Salexandru.dutu@amd.com                << sc_core::sc_time_stamp() << std::endl;
12410298Salexandru.dutu@amd.com
12510298Salexandru.dutu@amd.com    } else {
12610298Salexandru.dutu@amd.com      std::cout << name() <<  ": Received ok response";
12710298Salexandru.dutu@amd.com      if (trans.get_command() == tlm::TLM_READ_COMMAND) {
12810298Salexandru.dutu@amd.com        std::cout << ": D = 0x" << std::hex << mData << std::dec;
12910298Salexandru.dutu@amd.com      }
13010298Salexandru.dutu@amd.com      std::cout << " @ " << sc_core::sc_time_stamp() << std::endl;
13110298Salexandru.dutu@amd.com    }
13210298Salexandru.dutu@amd.com  }
13310298Salexandru.dutu@amd.com
13410298Salexandru.dutu@amd.com  std::pair<dmi_type, bool>& getDMIData(const transaction_type& trans)
13510298Salexandru.dutu@amd.com  {
13610298Salexandru.dutu@amd.com    if (trans.get_command() == tlm::TLM_READ_COMMAND) {
13710298Salexandru.dutu@amd.com      return mDMIDataReads;
13812446Sgabeblack@google.com
13910298Salexandru.dutu@amd.com    } else { // WRITE
14010298Salexandru.dutu@amd.com      return mDMIDataWrites;
14110556Salexandru.dutu@amd.com    }
14212432Sgabeblack@google.com  }
14310298Salexandru.dutu@amd.com
14410298Salexandru.dutu@amd.com  void run()
14511175Sandreas.hansson@arm.com  {
14610298Salexandru.dutu@amd.com    transaction_type trans;
14710558Salexandru.dutu@amd.com    sc_core::sc_time t;
14811175Sandreas.hansson@arm.com
14911175Sandreas.hansson@arm.com    while (initTransaction(trans)) {
15011175Sandreas.hansson@arm.com      // Create transaction and initialise t
15111168Sandreas.hansson@arm.com      t = sc_core::SC_ZERO_TIME;
15211168Sandreas.hansson@arm.com
15310298Salexandru.dutu@amd.com      logStartTransation(trans);
15410298Salexandru.dutu@amd.com
155      ///////////////////////////////////////////////////////////
156      // DMI handling:
157      // We do *not* use the DMI hint to check if it makes sense to ask for
158      // DMI pointers. So the pattern is:
159      // - if the address is not covered by a DMI region try to acquire DMI
160      //   pointers
161      // - if we have a DMI pointer, do the DMI "transaction"
162      // - otherwise fall back to a normal transaction
163      ///////////////////////////////////////////////////////////
164
165      std::pair<dmi_type, bool>& dmi_data = getDMIData(trans);
166
167      // Check if we need to acquire a DMI pointer
168      if((trans.get_address() < dmi_data.first.get_start_address()) ||
169         (trans.get_address() > dmi_data.first.get_end_address()) )
170      {
171          sc_dt::uint64 address = trans.get_address(); //save original address
172          dmi_data.second =
173            socket->get_direct_mem_ptr(trans,
174                                       dmi_data.first);
175          trans.set_address(address);
176      }
177      // Do DMI "transaction" if we have a valid region
178      if (dmi_data.second &&
179          (trans.get_address() >= dmi_data.first.get_start_address()) &&
180          (trans.get_address() <= dmi_data.first.get_end_address()) )
181      {
182          // We can handle the data here. As the logEndTransaction is assuming
183          // something to happen in the data structure, we really need to
184          // do this:
185          trans.set_response_status(tlm::TLM_OK_RESPONSE);
186          sc_dt::uint64 tmp = trans.get_address() - dmi_data.first.get_start_address();
187          if (trans.get_command() == tlm::TLM_WRITE_COMMAND)
188          {
189              *(unsigned int*)&dmi_data.first.get_dmi_ptr()[tmp] = mData;
190          }
191          else
192          {
193              mData = *(unsigned int*)&dmi_data.first.get_dmi_ptr()[tmp];
194          }
195
196          // Do the wait immediately. Note that doing the wait here eats almost
197          // all the performance anyway, so we only gain something if we're
198          // using temporal decoupling.
199          if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
200            wait(dmi_data.first.get_write_latency());
201
202          } else {
203            wait(dmi_data.first.get_read_latency());
204          }
205      }
206      else // we need a full transaction
207      {
208          socket->b_transport(trans, t);
209          wait(t);
210      }
211      logEndTransaction(trans);
212    }
213    wait();
214
215  }
216
217  // Invalidate DMI pointer(s)
218  void invalidate_direct_mem_ptr(sc_dt::uint64 start_range,
219                                 sc_dt::uint64 end_range)
220  {
221    // FIXME: probably faster to always invalidate everything?
222    if (start_range <= mDMIDataReads.first.get_end_address ()&&
223        end_range >= mDMIDataReads.first.get_start_address()) {
224        mDMIDataReads.second = false;
225    }
226    if (start_range <= mDMIDataWrites.first.get_end_address ()&&
227        end_range >= mDMIDataWrites.first.get_start_address()) {
228      mDMIDataWrites.second = false;
229    }
230  }
231
232  // Test for transport_dbg, this one should fail in bus_dmi as we address
233  // a target that doesn't support transport_dbg:
234  // FIXME: use a configurable address
235  void end_of_simulation()
236  {
237    std::cout <<  name() << ", <<SimpleLTInitiator1>>:" << std::endl
238              << std::endl;
239    unsigned char data[32];
240
241    transaction_type trans;
242    trans.set_address(mBaseAddress);
243    trans.set_data_length(32);
244    trans.set_data_ptr(data);
245    trans.set_read();
246
247    unsigned int n = socket->transport_dbg(trans);
248
249    std::cout << "Mem @" << std::hex << mBaseAddress << std::endl;
250    unsigned int j = 0;
251
252    if (n > 0)
253    {
254        // always align endianness, so that we don't get a diff when
255        // printing the raw data
256        int e_start = 0;
257        int e_end = 4;
258        int e_increment = 1;
259        if (!tlm::host_has_little_endianness())
260        {
261            e_start = 3;
262            e_end = -1;
263            e_increment = -1;
264        }
265
266        for (unsigned int i=0; i<n; i+=4)
267        {
268            for (int k=e_start; k!=e_end; k+=e_increment)
269            {
270                std::cout << std::setw(2) << std::setfill('0')
271                          << (int)data[i+k];
272                j++;
273                if (j==16) {
274                    j=0;
275                    std::cout << std::endl;
276                } else {
277                    std::cout << " ";
278                }
279            }
280        }
281    }
282    else
283    {
284        std::cout << "OK: debug transaction didn't give data." << std::endl;
285    }
286    std::cout << std::dec << std::endl;
287  }
288private:
289  std::pair<dmi_type, bool> mDMIDataReads;
290  std::pair<dmi_type, bool> mDMIDataWrites;
291
292  sc_core::sc_event mEndEvent;
293  unsigned int mNrOfTransactions;
294  unsigned int mBaseAddress;
295  unsigned int mTransactionCount;
296  unsigned int mData;
297};
298
299#endif
300