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_TARGET2_H__
21#define __SIMPLE_AT_TARGET2_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 SimpleATTarget2 : 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<SimpleATTarget2> target_socket_type;
38
39public:
40  target_socket_type socket;
41
42public:
43  SC_HAS_PROCESS(SimpleATTarget2);
44  SimpleATTarget2(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, &SimpleATTarget2::myNBTransport);
52
53    SC_METHOD(beginResponse)
54    sensitive << mBeginResponseEvent;
55    dont_initialize();
56
57    SC_METHOD(endResponse)
58    sensitive << mEndResponseEvent;
59    dont_initialize();
60  }
61
62  //
63  // Simple AT-TA target
64  // - Request is accepted after fixed delay (relative to end of prev request
65  //   phase)
66  // - Response is started after fixed delay (relative to end of prev resp
67  //   phase)
68  //
69  sync_enum_type myNBTransport(transaction_type& trans,
70                               phase_type& phase,
71                               sc_core::sc_time& t)
72  {
73    if (phase == tlm::BEGIN_REQ) {
74      // transactions may be kept in queue after the initiator has send END_REQ
75      trans.acquire();
76
77      sc_dt::uint64 address = trans.get_address();
78      assert(address < 400);
79
80      unsigned int& data = *reinterpret_cast<unsigned int*>(trans.get_data_ptr());
81      if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
82        std::cout << name() << ": Received write request: A = 0x"
83                  << std::hex << (unsigned int)address << ", D = 0x" << data
84                  << std::dec << " @ " << sc_core::sc_time_stamp()
85                  << std::endl;
86
87        *reinterpret_cast<unsigned int*>(&mMem[address]) = data;
88
89      } else {
90        std::cout << name() << ": Received read request: A = 0x"
91                  << std::hex << (unsigned int)address
92                  << std::dec << " @ " << sc_core::sc_time_stamp()
93                  << std::endl;
94
95        data = *reinterpret_cast<unsigned int*>(&mMem[address]);
96      }
97
98      // End request phase after accept delay
99      t += ACCEPT_DELAY;
100      phase = tlm::END_REQ;
101
102      if (mResponseQueue.empty()) {
103        // Start processing transaction after accept delay
104        // Notify begin of response phase after accept delay + response delay
105        mBeginResponseEvent.notify(t + RESPONSE_DELAY);
106      }
107      mResponseQueue.push(&trans);
108
109      // AT-noTA target
110      // - always return false
111      // - immediately return delay to indicate end of phase
112      return tlm::TLM_UPDATED;
113
114    } else if (phase == tlm::END_RESP) {
115
116      // response phase ends after t
117      mEndResponseEvent.notify(t);
118
119      return tlm::TLM_COMPLETED;
120    }
121
122    // Not possible
123    assert(0); exit(1);
124//    return tlm::TLM_COMPLETED;  //unreachable code
125  }
126
127  void beginResponse()
128  {
129    assert(!mResponseQueue.empty());
130    // start response phase of oldest transaction
131    phase_type phase = tlm::BEGIN_RESP;
132    sc_core::sc_time t = sc_core::SC_ZERO_TIME;
133    transaction_type* trans = mResponseQueue.front();
134    assert(trans);
135
136    // Set response data
137    trans->set_response_status(tlm::TLM_OK_RESPONSE);
138    if (trans->get_command() == tlm::TLM_READ_COMMAND) {
139       sc_dt::uint64 address = trans->get_address();
140       assert(address < 400);
141      *reinterpret_cast<unsigned int*>(trans->get_data_ptr()) =
142        *reinterpret_cast<unsigned int*>(&mMem[address]);
143    }
144
145    if (socket->nb_transport_bw(*trans, phase, t) == tlm::TLM_COMPLETED) {
146      // response phase ends after t
147      mEndResponseEvent.notify(t);
148
149    } else {
150      // initiator will call nb_transport to indicate end of response phase
151    }
152  }
153
154  void endResponse()
155  {
156    assert(!mResponseQueue.empty());
157    mResponseQueue.front()->release();
158    mResponseQueue.pop();
159
160    // Start processing next transaction when previous response is accepted.
161    // Notify begin of response phase after RESPONSE delay
162    if (!mResponseQueue.empty()) {
163      mBeginResponseEvent.notify(RESPONSE_DELAY);
164    }
165  }
166
167private:
168  const sc_core::sc_time ACCEPT_DELAY;
169  const sc_core::sc_time RESPONSE_DELAY;
170
171private:
172  unsigned char mMem[400];
173  std::queue<transaction_type*> mResponseQueue;
174  sc_core::sc_event mBeginResponseEvent;
175  sc_core::sc_event mEndResponseEvent;
176};
177
178#endif
179