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_AT_TARGET1_H__
21#define __SIMPLE_AT_TARGET1_H__
22
23#include "tlm.h"
24#include "tlm_utils/simple_target_socket.h"
25//#include <systemc>
26#include <cassert>
27#include <vector>
28#include <queue>
29//#include <iostream>
30
31class SimpleATTarget1 : public sc_core::sc_module
32{
33public:
34  typedef tlm::tlm_generic_payload            transaction_type;
35  typedef tlm::tlm_phase                      phase_type;
36  typedef tlm::tlm_sync_enum                  sync_enum_type;
37  typedef tlm_utils::simple_target_socket<SimpleATTarget1> target_socket_type;
38
39public:
40  target_socket_type socket;
41
42public:
43  SC_HAS_PROCESS(SimpleATTarget1);
44  SimpleATTarget1(sc_core::sc_module_name name) :
45    sc_core::sc_module(name),
46    socket("socket"),
47    ACCEPT_DELAY(25, sc_core::SC_NS),
48    RESPONSE_DELAY(100, sc_core::SC_NS)
49  {
50    // register nb_transport method
51    socket.register_nb_transport_fw(this, &SimpleATTarget1::myNBTransport);
52
53    SC_METHOD(endRequest)
54    sensitive << mEndRequestEvent;
55    dont_initialize();
56
57    SC_METHOD(beginResponse)
58    sensitive << mBeginResponseEvent;
59    dont_initialize();
60
61    SC_METHOD(endResponse)
62    sensitive << mEndResponseEvent;
63    dont_initialize();
64  }
65
66  //
67  // Simple AT target
68  // - Request is accepted after ACCEPT delay (relative to end of prev request
69  //   phase)
70  // - Response is started after RESPONSE delay (relative to end of prev resp
71  //   phase)
72  //
73  sync_enum_type myNBTransport(transaction_type& trans, phase_type& phase, sc_core::sc_time& t)
74  {
75    if (phase == tlm::BEGIN_REQ) {
76      // transactions may be kept in queue after the initiator has send END_REQ
77      trans.acquire();
78
79      sc_dt::uint64 address = trans.get_address();
80      assert(address < 400);
81
82      unsigned int& data = *reinterpret_cast<unsigned int*>(trans.get_data_ptr());
83      if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
84        std::cout << name() << ": Received write request: A = 0x"
85                  << std::hex << (unsigned int)address << ", D = 0x"
86                  << data << std::dec
87                  << " @ " << sc_core::sc_time_stamp() << std::endl;
88
89        *reinterpret_cast<unsigned int*>(&mMem[address]) = data;
90
91      } else {
92        std::cout << name() << ": Received read request: A = 0x"
93                  << std::hex << (unsigned int)address << std::dec
94                  << " @ " << sc_core::sc_time_stamp() << std::endl;
95
96        data = *reinterpret_cast<unsigned int*>(&mMem[address]);
97      }
98
99      // Notify end of request phase after ACCEPT delay
100      if (mEndRequestQueue.empty()) {
101        mEndRequestEvent.notify(t + ACCEPT_DELAY);
102      }
103      mEndRequestQueue.push(&trans);
104
105      // AT-noTA target
106      // - always return false
107      // - seperate call to indicate end of phase (do not update phase or t)
108      return tlm::TLM_ACCEPTED;
109
110    } else if (phase == tlm::END_RESP) {
111
112      // response phase ends after t
113      mEndResponseEvent.notify(t);
114
115      return tlm::TLM_COMPLETED;
116    }
117
118    // Not possible
119    assert(0); exit(1);
120//    return tlm::TLM_COMPLETED;  //unreachable code
121  }
122
123  void endRequest()
124  {
125    assert(!mEndRequestQueue.empty());
126    // end request phase of oldest transaction
127    phase_type phase = tlm::END_REQ;
128    sc_core::sc_time t = sc_core::SC_ZERO_TIME;
129    transaction_type* trans = mEndRequestQueue.front();
130    assert(trans);
131    mEndRequestQueue.pop();
132    #if ( ! NDEBUG )
133    sync_enum_type r = socket->nb_transport_bw(*trans, phase, t);
134    #endif /* ! NDEBUG */
135    assert(r == tlm::TLM_ACCEPTED); // FIXME: initiator should return TLM_ACCEPTED?
136    assert(t == sc_core::SC_ZERO_TIME); // t must be SC_ZERO_TIME
137
138    // Notify end of request phase for next transaction after ACCEPT delay
139    if (!mEndRequestQueue.empty()) {
140      mEndRequestEvent.notify(ACCEPT_DELAY);
141    }
142
143    if (mResponseQueue.empty()) {
144      // Start processing transaction
145      // Notify begin of response phase after RESPONSE delay
146      mBeginResponseEvent.notify(RESPONSE_DELAY);
147    }
148    mResponseQueue.push(trans);
149  }
150
151  void beginResponse()
152  {
153    assert(!mResponseQueue.empty());
154    // start response phase of oldest transaction
155    phase_type phase = tlm::BEGIN_RESP;
156    sc_core::sc_time t = sc_core::SC_ZERO_TIME;
157    transaction_type* trans = mResponseQueue.front();
158    assert(trans);
159
160    // Set response data
161    trans->set_response_status(tlm::TLM_OK_RESPONSE);
162    if (trans->get_command() == tlm::TLM_READ_COMMAND) {
163       sc_dt::uint64 address = trans->get_address();
164       assert(address < 400);
165      *reinterpret_cast<unsigned int*>(trans->get_data_ptr()) =
166        *reinterpret_cast<unsigned int*>(&mMem[address]);
167    }
168
169    switch (socket->nb_transport_bw(*trans, phase, t)) {
170    case tlm::TLM_COMPLETED:
171      // response phase ends after t
172      mEndResponseEvent.notify(t);
173      break;
174
175    case tlm::TLM_ACCEPTED:
176    case tlm::TLM_UPDATED:
177     // initiator will call nb_transport to indicate end of response phase
178     break;
179
180    default:
181      assert(0); exit(1);
182    };
183  }
184
185  void endResponse()
186  {
187    assert(!mResponseQueue.empty());
188    mResponseQueue.front()->release();
189    mResponseQueue.pop();
190
191    if (!mResponseQueue.empty()) {
192      // Start processing next transaction
193      // Notify begin of response phase after RESPONSE delay
194      mBeginResponseEvent.notify(RESPONSE_DELAY);
195    }
196  }
197
198private:
199  const sc_core::sc_time ACCEPT_DELAY;
200  const sc_core::sc_time RESPONSE_DELAY;
201
202private:
203  unsigned char mMem[400];
204  std::queue<transaction_type*> mEndRequestQueue;
205  sc_core::sc_event mEndRequestEvent;
206  std::queue<transaction_type*> mResponseQueue;
207  sc_core::sc_event mBeginResponseEvent;
208  sc_core::sc_event mEndResponseEvent;
209};
210
211#endif
212