SimpleATInitiator2.h revision 12922
17008SN/A/*****************************************************************************
27008SN/A
37008SN/A  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
47008SN/A  more contributor license agreements.  See the NOTICE file distributed
57008SN/A  with this work for additional information regarding copyright ownership.
67008SN/A  Accellera licenses this file to you under the Apache License, Version 2.0
77008SN/A  (the "License"); you may not use this file except in compliance with the
87008SN/A  License.  You may obtain a copy of the License at
97008SN/A
107008SN/A    http://www.apache.org/licenses/LICENSE-2.0
117008SN/A
127008SN/A  Unless required by applicable law or agreed to in writing, software
137008SN/A  distributed under the License is distributed on an "AS IS" BASIS,
147008SN/A  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
157008SN/A  implied.  See the License for the specific language governing
167008SN/A  permissions and limitations under the License.
177008SN/A
187008SN/A *****************************************************************************/
197008SN/A
207008SN/A//====================================================================
217008SN/A//  Nov 06, 2008
227008SN/A//
237008SN/A//  Updated by:
247008SN/A//    Xiaopeng Qiu, JEDA Technologies, Inc
257008SN/A//    Email:  qiuxp@jedatechnologies.net
267008SN/A//
277008SN/A//  To fix violations of TLM2.0 rules, which are detected by JEDA
286145SN/A//  TLM2.0 checker.
2910441Snilay@cs.wisc.edu//
3010441Snilay@cs.wisc.edu//====================================================================
316145SN/A
329505SN/A#ifndef __SIMPLE_AT_INITIATOR2_H__
3310970Sdavid.hashe@amd.com#define __SIMPLE_AT_INITIATOR2_H__
3410970Sdavid.hashe@amd.com
3510970Sdavid.hashe@amd.com#include "tlm.h"
366145SN/A#include "tlm_utils/simple_initiator_socket.h"
3710970Sdavid.hashe@amd.com//#include <systemc>
387039SN/A#include <cassert>
397039SN/A#include <queue>
4010970Sdavid.hashe@amd.com//#include <iostream>
4110970Sdavid.hashe@amd.com
427039SN/Aclass SimpleATInitiator2 : public sc_core::sc_module
436145SN/A{
447039SN/Apublic:
4510314Snilay@cs.wisc.edu  typedef tlm::tlm_generic_payload                   transaction_type;
466145SN/A  typedef tlm::tlm_phase                             phase_type;
477039SN/A  typedef tlm::tlm_sync_enum                         sync_enum_type;
4810314Snilay@cs.wisc.edu  typedef tlm_utils::simple_initiator_socket<SimpleATInitiator2>  initiator_socket_type;
496145SN/A
507039SN/Apublic:
5110314Snilay@cs.wisc.edu  // extended transaction, holds tlm_generic_payload + data storage
526145SN/A  template <typename DT>
5310970Sdavid.hashe@amd.com  class MyTransaction : public transaction_type
5410970Sdavid.hashe@amd.com  {
557039SN/A  public:
567039SN/A    MyTransaction()
577039SN/A    {
589505SN/A      this->set_data_ptr(reinterpret_cast<unsigned char*>(&mData));
596145SN/A    }
606145SN/A    MyTransaction(tlm::tlm_mm_interface* mm) : transaction_type(mm)
6110441Snilay@cs.wisc.edu    {
62      this->set_data_ptr(reinterpret_cast<unsigned char*>(&mData));
63    }
64
65    void setData(DT& data) { mData = data; }
66    DT getData() const { return mData; }
67
68  private:
69    DT mData;
70  };
71  typedef MyTransaction<unsigned int>  mytransaction_type;
72
73  // Dummy Transaction Pool
74  class SimplePool : public tlm::tlm_mm_interface
75  {
76  public:
77    SimplePool() {}
78    mytransaction_type* claim()
79    {
80      mytransaction_type* t = new mytransaction_type(this);
81      t->acquire();
82      return t;
83    }
84    void release(mytransaction_type* t)
85    {
86      t->release();
87    }
88    void free(tlm::tlm_generic_payload* t)
89    {
90      t->reset();
91      delete t;
92    }
93  };
94
95public:
96  initiator_socket_type socket;
97
98public:
99  SC_HAS_PROCESS(SimpleATInitiator2);
100  SimpleATInitiator2(sc_core::sc_module_name name,
101                     unsigned int nrOfTransactions = 0x5,
102                     unsigned int baseAddress = 0) :
103    sc_core::sc_module(name),
104    socket("socket"),
105    ACCEPT_DELAY(10, sc_core::SC_NS),
106    mNrOfTransactions(nrOfTransactions),
107    mBaseAddress(baseAddress),
108    mTransactionCount(0),
109    mCurrentTransaction(0)
110  {
111    // register nb_transport method
112    socket.register_nb_transport_bw(this, &SimpleATInitiator2::myNBTransport);
113
114    // Initiator thread
115    SC_THREAD(run);
116  }
117
118  bool initTransaction(mytransaction_type*& trans)
119  {
120    if (mTransactionCount < mNrOfTransactions) {
121      trans = transPool.claim();
122      trans->set_address(mBaseAddress + 4*mTransactionCount);
123      trans->setData(mTransactionCount);
124      trans->set_command(tlm::TLM_WRITE_COMMAND);
125
126    } else if (mTransactionCount < 2 * mNrOfTransactions) {
127      trans = transPool.claim();
128      trans->set_address(mBaseAddress + 4*(mTransactionCount - mNrOfTransactions));
129      trans->set_command(tlm::TLM_READ_COMMAND);
130
131    } else {
132      return false;
133    }
134
135    trans->set_data_length(4);
136    trans->set_streaming_width(4);
137
138    ++mTransactionCount;
139    return true;
140  }
141
142  void logStartTransation(mytransaction_type& trans)
143  {
144    if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
145      std::cout << name() << ": Send write request: A = 0x"
146                << std::hex << (unsigned int)trans.get_address()
147                << ", D = 0x" << trans.getData() << std::dec
148                << " @ " << sc_core::sc_time_stamp() << std::endl;
149
150    } else {
151      std::cout << name() << ": Send read request: A = 0x"
152                << std::hex << (unsigned int)trans.get_address() << std::dec
153                << " @ " << sc_core::sc_time_stamp() << std::endl;
154    }
155  }
156
157  void logEndTransaction(mytransaction_type& trans)
158  {
159    if (trans.get_response_status() != tlm::TLM_OK_RESPONSE) {
160      std::cout << name() << ": Received error response @ "
161                << sc_core::sc_time_stamp() << std::endl;
162
163    } else {
164      std::cout << name() <<  ": Received ok response";
165      if (trans.get_command() == tlm::TLM_READ_COMMAND) {
166        std::cout << ": D = 0x" << std::hex << trans.getData() << std::dec;
167      }
168      std::cout << " @ " << sc_core::sc_time_stamp() << std::endl;
169    }
170  }
171
172  //
173  // Simple AT Initiator
174  // - Request must be accepted by the target before the next request can be
175  //   send
176  // - Responses can come out of order
177  // - Responses will be accepted after fixed delay
178  //
179  void run()
180  {
181    phase_type phase;
182    sc_core::sc_time t;
183
184    mytransaction_type* ptrans;
185    while (initTransaction(ptrans)) {
186      // Create transaction and initialise phase and t
187      mytransaction_type& trans = *ptrans;
188      phase = tlm::BEGIN_REQ;
189      t = sc_core::SC_ZERO_TIME;
190
191      logStartTransation(trans);
192
193      switch (socket->nb_transport_fw(trans, phase, t)) {
194      case tlm::TLM_COMPLETED:
195        // Transaction Finished, wait for the returned delay
196        wait(t);
197        logEndTransaction(trans);
198        transPool.release(&trans);
199        break;
200
201      case tlm::TLM_ACCEPTED:
202      case tlm::TLM_UPDATED:
203        switch (phase) {
204        case tlm::BEGIN_REQ:
205          // Request phase not yet finished
206          // Wait until end of request phase before sending new request
207
208          // FIXME
209          mCurrentTransaction = &trans;
210          wait(mEndRequestPhase);
211	  mCurrentTransaction = 0;
212          break;
213
214        case tlm::END_REQ:
215          // Request phase ended
216          if (t != sc_core::SC_ZERO_TIME) {
217            // Wait until end of request time before sending new request
218            wait(t);
219          }
220          break;
221
222        case tlm::BEGIN_RESP:
223          // Request phase ended and response phase already started
224          if (t != sc_core::SC_ZERO_TIME) {
225            // Wait until end of request time before sending new request
226            wait(t);
227          }
228          // Notify end of response phase after ACCEPT delay
229          t += ACCEPT_DELAY;
230          phase = tlm::END_RESP;
231          socket->nb_transport_fw(trans, phase, t);
232          logEndTransaction(trans);
233          transPool.release(&trans);
234          break;
235
236        case tlm::END_RESP:   // fall-through
237        default:
238          // A target should never return with these phases
239          // If phase == END_RESP, nb_transport should have returned true
240          assert(0); exit(1);
241          break;
242        }
243        break;
244
245      default:
246        assert(0); exit(1);
247      };
248    }
249    wait();
250
251  }
252
253  sync_enum_type myNBTransport(transaction_type& trans, phase_type& phase, sc_core::sc_time& t)
254  {
255    switch (phase) {
256    case tlm::END_REQ:
257      assert(t == sc_core::SC_ZERO_TIME); // FIXME: can t != 0?
258      // Request phase ended
259      mEndRequestPhase.notify(sc_core::SC_ZERO_TIME);
260      return tlm::TLM_ACCEPTED;
261
262    case tlm::BEGIN_RESP:
263    {
264      assert(t == sc_core::SC_ZERO_TIME); // FIXME: can t != 0?
265
266      // Notify end of request phase if run thread is waiting for it
267      // FIXME
268      if (&trans == mCurrentTransaction) {
269        mEndRequestPhase.notify(sc_core::SC_ZERO_TIME);
270      }
271
272      assert(dynamic_cast<mytransaction_type*>(&trans));
273      mytransaction_type* myTrans = static_cast<mytransaction_type*>(&trans);
274      assert(myTrans);
275
276      // Notify end of response phase after ACCEPT delay
277      t += ACCEPT_DELAY;
278      phase = tlm::END_RESP;
279      logEndTransaction(*myTrans);
280      transPool.release(myTrans);
281
282      return tlm::TLM_COMPLETED;
283    }
284
285    case tlm::BEGIN_REQ: // fall-through
286    case tlm::END_RESP:  // fall-through
287    default:
288      // A target should never call nb_transport with these phases
289      assert(0); exit(1);
290//      return tlm::TLM_COMPLETED;  //unreachable code
291    };
292  }
293
294private:
295  const sc_core::sc_time ACCEPT_DELAY;
296
297private:
298  unsigned int mNrOfTransactions;
299  unsigned int mBaseAddress;
300  SimplePool transPool;
301  unsigned int mTransactionCount;
302  sc_core::sc_event mEndRequestPhase;
303  transaction_type* mCurrentTransaction;
304};
305
306#endif
307