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_AT_INITIATOR1_H__ 33#define __SIMPLE_AT_INITIATOR1_H__ 34 35#include "tlm.h" 36#include "tlm_utils/simple_initiator_socket.h" 37//#include <systemc> 38#include <cassert> 39#include <queue> 40//#include <iostream> 41 42class SimpleATInitiator1 : public sc_core::sc_module 43{ 44public: 45 typedef tlm::tlm_generic_payload transaction_type; 46 typedef tlm::tlm_phase phase_type; 47 typedef tlm::tlm_sync_enum sync_enum_type; 48 typedef tlm_utils::simple_initiator_socket<SimpleATInitiator1> initiator_socket_type; 49 50public: 51 // extended transaction, holds tlm_generic_payload + data storage 52 template <typename DT> 53 class MyTransaction : public transaction_type 54 { 55 public: 56 MyTransaction() 57 { 58 this->set_data_ptr(reinterpret_cast<unsigned char*>(&mData)); 59 } 60 MyTransaction(tlm::tlm_mm_interface* mm) : transaction_type(mm) 61 { 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(SimpleATInitiator1); 100 SimpleATInitiator1(sc_core::sc_module_name name, 101 unsigned int nrOfTransactions = 0x5, 102 unsigned int baseAddress = 0x0) : 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, &SimpleATInitiator1::myNBTransport); 113 114 // Initiator thread 115 SC_THREAD(run); 116 117 SC_METHOD(endResponse) 118 sensitive << mEndResponseEvent; 119 dont_initialize(); 120 } 121 122 bool initTransaction(mytransaction_type*& trans) 123 { 124 if (mTransactionCount < mNrOfTransactions) { 125 trans = transPool.claim(); 126 trans->set_address(mBaseAddress + 4*mTransactionCount); 127 trans->setData(mTransactionCount); 128 trans->set_command(tlm::TLM_WRITE_COMMAND); 129 130 } else if (mTransactionCount < 2 * mNrOfTransactions) { 131 trans = transPool.claim(); 132 trans->set_address(mBaseAddress + 4*(mTransactionCount - mNrOfTransactions)); 133 trans->set_command(tlm::TLM_READ_COMMAND); 134 135 } else { 136 return false; 137 } 138 139 trans->set_data_length(4); 140 trans->set_streaming_width(4); 141 142 ++mTransactionCount; 143 return true; 144 } 145 146 void logStartTransation(mytransaction_type& trans) 147 { 148 if (trans.get_command() == tlm::TLM_WRITE_COMMAND) { 149 std::cout << name() << ": Send write request: A = 0x" 150 << std::hex << (unsigned int)trans.get_address() 151 << ", D = 0x" << trans.getData() << std::dec 152 << " @ " << sc_core::sc_time_stamp() << std::endl; 153 154 } else { 155 std::cout << name() << ": Send read request: A = 0x" 156 << std::hex << (int)trans.get_address() << std::dec 157 << " @ " << sc_core::sc_time_stamp() << std::endl; 158 } 159 } 160 161 void logEndTransaction(mytransaction_type& trans) 162 { 163 if (trans.get_response_status() != tlm::TLM_OK_RESPONSE) { 164 std::cout << name() << ": Received error response @ " 165 << sc_core::sc_time_stamp() << std::endl; 166 167 } else { 168 std::cout << name() << ": Received ok response"; 169 if (trans.get_command() == tlm::TLM_READ_COMMAND) { 170 std::cout << ": D = 0x" << trans.getData() << std::dec; 171 } 172 std::cout << " @ " << sc_core::sc_time_stamp() << std::endl; 173 } 174 } 175 176 // 177 // Simple AT Initiator 178 // - Request must be accepted by the target before the next request can be 179 // send 180 // - Responses can come out of order 181 // - Responses will be accepted after fixed delay 182 // 183 void run() 184 { 185 phase_type phase; 186 sc_core::sc_time t; 187 188 mytransaction_type* ptrans; 189 while (initTransaction(ptrans)) { 190 // Create transaction and initialise phase and t 191 mytransaction_type& trans = *ptrans; 192 phase = tlm::BEGIN_REQ; 193 t = sc_core::SC_ZERO_TIME; 194 195 logStartTransation(trans); 196 197 switch (socket->nb_transport_fw(trans, phase, t)) { 198 case tlm::TLM_COMPLETED: 199 // Transaction Finished, wait for the returned delay 200 wait(t); 201 logEndTransaction(trans); 202 transPool.release(&trans); 203 break; 204 205 case tlm::TLM_ACCEPTED: 206 case tlm::TLM_UPDATED: 207 switch (phase) { 208 case tlm::BEGIN_REQ: 209 // Request phase not yet finished 210 // Wait until end of request phase before sending new request 211 212 // FIXME 213 mCurrentTransaction = &trans; 214 wait(mEndRequestPhase); 215 mCurrentTransaction = 0; 216 break; 217 218 case tlm::END_REQ: 219 // Request phase ended 220 if (t != sc_core::SC_ZERO_TIME) { 221 // Wait until end of request time before sending new request 222 wait(t); 223 } 224 break; 225 226 case tlm::BEGIN_RESP: 227 // Request phase ended and response phase already started 228 if (t != sc_core::SC_ZERO_TIME) { 229 // Wait until end of request time before sending new request 230 wait(t); 231 } 232 if (mEndResponseQueue.empty()) { 233 // Notify end of response phase after ACCEPT delay 234 mEndResponseEvent.notify(ACCEPT_DELAY); 235 } 236 mEndResponseQueue.push(&trans); 237 break; 238 239 case tlm::END_RESP: // fall-through 240 default: 241 // A target should never return with these phases 242 // If phase == END_RESP, nb_transport should have returned true 243 assert(0); exit(1); 244 break; 245 } 246 break; 247 248 default: 249 assert(0); exit(1); 250 }; 251 } 252 wait(); 253 } 254 255 sync_enum_type myNBTransport(transaction_type& trans, phase_type& phase, sc_core::sc_time& t) 256 { 257 switch (phase) { 258 case tlm::END_REQ: 259 assert(t == sc_core::SC_ZERO_TIME); // FIXME: can t != 0? 260 // Request phase ended 261 mEndRequestPhase.notify(sc_core::SC_ZERO_TIME); 262 return tlm::TLM_ACCEPTED; 263 264 case tlm::BEGIN_RESP: 265 { 266 assert(t == sc_core::SC_ZERO_TIME); // FIXME: can t != 0? 267 268 // Notify end of request phase if run thread is waiting for it 269 // FIXME 270 if (&trans == mCurrentTransaction) { 271 mEndRequestPhase.notify(sc_core::SC_ZERO_TIME); 272 } 273 274 assert(dynamic_cast<mytransaction_type*>(&trans)); 275 mytransaction_type* myTrans = static_cast<mytransaction_type*>(&trans); 276 assert(myTrans); 277 278 if (mEndResponseQueue.empty()) { 279 // Notify end of response phase after ACCEPT delay 280 mEndResponseEvent.notify(ACCEPT_DELAY); 281 } 282 mEndResponseQueue.push(myTrans); 283 return tlm::TLM_ACCEPTED; 284 } 285 286 case tlm::BEGIN_REQ: // fall-through 287 case tlm::END_RESP: // fall-through 288 default: 289 // A target should never call nb_transport with these phases 290 assert(0); exit(1); 291// return tlm::TLM_COMPLETED; //unreachable code 292 }; 293 } 294 295 void endResponse() 296 { 297 assert(!mEndResponseQueue.empty()); 298 // end response phase 299 phase_type phase = tlm::END_RESP; 300 sc_core::sc_time t = sc_core::SC_ZERO_TIME; 301 mytransaction_type* trans = mEndResponseQueue.front(); 302 assert(trans); 303 mEndResponseQueue.pop(); 304 #if ( ! NDEBUG ) 305 sync_enum_type r = socket->nb_transport_fw(*trans, phase, t); 306 #endif /* ! NDEBUG */ 307 assert(r == tlm::TLM_COMPLETED); // FIXME: target should return TLM_COMPLETED? 308 assert(t == sc_core::SC_ZERO_TIME); // t must be SC_ZERO_TIME 309 310 logEndTransaction(*trans); 311 transPool.release(trans); 312 313 if (!mEndResponseQueue.empty()) { 314 // Notify end of response phase after ACCEPT delay 315 mEndResponseEvent.notify(ACCEPT_DELAY); 316 } 317 } 318 319private: 320 const sc_core::sc_time ACCEPT_DELAY; 321 322private: 323 unsigned int mNrOfTransactions; 324 unsigned int mBaseAddress; 325 SimplePool transPool; 326 unsigned int mTransactionCount; 327 sc_core::sc_event mEndRequestPhase; 328 std::queue<mytransaction_type*> mEndResponseQueue; 329 sc_core::sc_event mEndResponseEvent; 330 transaction_type* mCurrentTransaction; 331}; 332 333#endif 334