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 ///  @file at_initiator_explicit.cpp
22 ///  @Details Implements a AT non-blocking initiator
23 //
24 //=============================================================================
25 //  Original Authors:
26 //    Bill Bunton, ESLX
27 //    Charles Wilson, ESLX
28 //    Anna Keist, ESLX
29 //=============================================================================
30 
31 #include "reporting.h"                                // Reporting convenience macros
32 #include "at_initiator_explicit.h"                    // Our header
33 #include "tlm.h"                                      // TLM headers
34 
35 using namespace sc_core;
36 
37 static const char *filename = "at_initiator_explicit.cpp";  ///  filename for reporting
38 
39 //=============================================================================
40 ///Constructor
41 
at_initiator_explicit(sc_module_name name,const unsigned int ID,sc_core::sc_time end_rsp_delay)42 at_initiator_explicit::at_initiator_explicit        // constructor
43 ( sc_module_name name                               // module name
44 , const unsigned int ID                             // initiator ID
45 , sc_core::sc_time end_rsp_delay                    // delay
46 )
47 : sc_module           (name)                        /// init module name
48 , initiator_socket    ("initiator_socket")          /// init socket name
49 , m_send_end_rsp_PEQ  ("send_end_rsp_PEQ")          /// init PEQ name
50 , m_ID            (ID)                              /// init initiator ID
51 , m_end_rsp_delay (end_rsp_delay)                   /// init end response delay
52 
53 {
54   // bind initiator to the export
55   initiator_socket (*this);
56 
57   // register thread process
58   SC_THREAD(initiator_thread);
59 
60   // register method process
61   SC_METHOD(send_end_rsp_method);
62 
63     sensitive << m_send_end_rsp_PEQ.get_event();
64     dont_initialize();
65 }
66 
67 //=============================================================================
68 //
69 //  Initiator thread
70 //
71 //=============================================================================
initiator_thread(void)72 void at_initiator_explicit::initiator_thread(void)  // initiator thread
73 {
74   tlm::tlm_generic_payload *transaction_ptr;        // transaction pointer
75   std::ostringstream       msg;                     // log message
76 
77   while (true)
78   {
79 //=============================================================================
80 // Read FIFO to Get new transaction GP from the traffic generator
81 //=============================================================================
82     transaction_ptr = request_in_port->read();  // get request from input fifo
83 
84     tlm::tlm_phase phase  = tlm::BEGIN_REQ;     // Create phase objects
85     sc_time delay         = SC_ZERO_TIME;       // Create delay objects
86 
87     msg.str("");
88     msg << "Initiator: " << m_ID
89         << " starting new transaction"
90         << endl << "      "
91         << "Initiator: " << m_ID
92         << " nb_transport_fw (GP, "
93         << report::print(phase) << ", "
94         << delay << ")";
95     REPORT_INFO(filename,  __FUNCTION__, msg.str());
96 
97 
98 //-----------------------------------------------------------------------------
99 // Make the non-blocking call and decode returned status (tlm_sync_enum)
100 //-----------------------------------------------------------------------------
101     tlm::tlm_sync_enum
102     return_value = initiator_socket->nb_transport_fw(*transaction_ptr, phase, delay);
103 
104     msg.str("");
105     msg << "Initiator: " << m_ID
106       << " " << report::print(return_value) <<  " (GP, "
107       << report::print(phase) << ", "
108       << delay << ")" << endl;
109 
110     switch (return_value) {
111 //-----------------------------------------------------------------------------
112 //  The target returned COMPLETED this is a 1 phase transaction
113 //    Wait the annotated delay
114 //    Return the transaction to the traffic generator
115 //    Make the next request
116 //-----------------------------------------------------------------------------
117       case tlm::TLM_COMPLETED:
118       {
119         wait(delay + m_end_rsp_delay);              // wait the annotated delay
120 
121         msg << "      "
122           << "Initiator: " << m_ID
123           << " target returned COMPLETED with annotated time ";
124         REPORT_INFO (filename, __FUNCTION__, msg.str() );
125 
126         response_out_port->write(transaction_ptr);  // return txn to traffic gen
127 
128         break;
129       }// end case TLM_COMPLETED
130 
131 //-----------------------------------------------------------------------------
132 // Target returned UPDATED
133 //-----------------------------------------------------------------------------
134       case tlm::TLM_UPDATED:
135       {
136 //-----------------------------------------------------------------------------
137 //  Put poiter in waiting backware path map
138 //    Wait the annotated delay
139 //    Make the next request
140 //-----------------------------------------------------------------------------
141       if( phase == tlm::END_REQ) {
142 
143           m_waiting_bw_path_map.insert(make_pair(transaction_ptr
144                                                   ,Rcved_END_REQ_enum
145                                                   ));
146 
147           wait(delay);                    // wait the annotated delay
148 
149           msg << "      "
150               << "Initiator: " << m_ID
151               << " transaction waiting begin-response on backward path";
152           REPORT_INFO (filename, __FUNCTION__, msg.str() );
153         }
154 
155 //-----------------------------------------------------------------------------
156 //    Wait the annotated delay
157 //    Use payload event queue to schedule sending end response
158 //    Make the next request
159 //-----------------------------------------------------------------------------
160 
161         else if( phase == tlm::BEGIN_RESP) {
162           msg << "      "
163               << "Initiator: " << m_ID
164               << " transaction moved to send-end-response PEQ "
165               << endl;
166 
167           wait(delay);                    // wait the annotated delay
168 
169           m_send_end_rsp_PEQ.notify (*transaction_ptr, m_end_rsp_delay);
170 
171           msg << "      "
172               << "Initiator: " << m_ID
173               << " "  <<  " (GP, "
174               << report::print(phase) << ", "
175               << delay << ")" ;
176           REPORT_INFO (filename, __FUNCTION__, msg.str() )
177         }
178 //-----------------------------------------------------------------------------
179 //-----------------------------------------------------------------------------
180         else {
181           msg << "      "
182           << "Initiator: " << m_ID
183           << " Unexpected phase for UPDATED return from target ";
184           REPORT_FATAL (filename, __FUNCTION__, msg.str() );
185         }
186         break;
187       } // end case TLM_UPDATED
188 
189 
190 //-----------------------------------------------------------------------------
191 //  Target returned ACCEPTED this an explicit response
192 //    Add the transaction pointer to the waiting backward path map
193 //    END REQUEST RULE  wait for the target to response
194 //-----------------------------------------------------------------------------
195       case tlm::TLM_ACCEPTED:
196       {
197         msg << "      "
198         << "Initiator: " << m_ID
199         << " transaction waiting end-request on backward-path ";
200         REPORT_INFO (filename, __FUNCTION__, msg.str() );
201 
202         //  use map to track transaction including current state information
203         m_waiting_bw_path_map.insert (make_pair (transaction_ptr
204                                                 ,Rcved_ACCEPTED_enum
205                                                 ));
206 
207         wait (m_enable_next_request_event);   // wait for the target to response
208 
209         break;
210       } // end case TLM_ACCEPTED
211 
212 
213 //-----------------------------------------------------------------------------
214 // All case covered default
215 //-----------------------------------------------------------------------------
216       default:
217       {
218         msg << "      "
219         << "Initiator: " << m_ID
220         << " Unexpected response to BEGIN_REQ ";
221         REPORT_FATAL (filename, __FUNCTION__, msg.str() );
222         break;
223       }
224     } // end case
225   } // end while true
226 } // end initiator_thread
227 
228 
229 
230 //=============================================================================
231 ///  @fn at_initiator_explicit::nb_transport_bw
232 //
233 ///  @brief non-blocking transport from targets
234 //
235 //=============================================================================
236 tlm::tlm_sync_enum
nb_transport_bw(tlm::tlm_generic_payload & transaction_ref,tlm::tlm_phase & phase,sc_time & delay)237 at_initiator_explicit::nb_transport_bw                  // inbound nb_transport_bw
238 ( tlm::tlm_generic_payload&  transaction_ref            // generic payload
239  , tlm::tlm_phase&            phase                     // tlm phase
240  , sc_time&                   delay                     // delay
241  )
242 
243 {
244   tlm::tlm_sync_enum        status = tlm::TLM_COMPLETED;  // return status reject by default
245   std::ostringstream        msg;                          // log message
246 
247 //=============================================================================
248 // Check waiting backward path map of valid transaction
249 //=============================================================================
250   waiting_bw_path_map::iterator transaction_inter;      // create interator for map
251 
252   transaction_inter  = m_waiting_bw_path_map.find(&transaction_ref);
253 
254   if (transaction_inter == m_waiting_bw_path_map.end() ) {
255 
256 //=============================================================================
257 //  The transaction pointer used by the backward path call does not belong
258 //  to this initiator, this is a major error
259 //=============================================================================
260     msg << "      "
261     << "Initiator: " << m_ID
262     << " Received invalid transaction pointer";
263     REPORT_FATAL (filename, __FUNCTION__, msg.str() );
264   }
265 
266 //=============================================================================
267 //  Normal operation
268 //    Decode backward path phase
269 //=============================================================================
270     else {
271     msg.str ("");
272     msg << "Initiator: " << m_ID
273         << " nb_transport_bw (GP, "
274         << report::print(phase) << ", "
275         << delay << ")"
276         << endl;
277 
278     switch (phase) {
279 //-----------------------------------------------------------------------------
280 // Target has responded with END_REQ
281 //    notify enable next request event
282 //-----------------------------------------------------------------------------
283     case tlm::END_REQ:  {
284         msg << "      "
285             << "Initiator: " << m_ID
286             << " transaction waiting begin-response on backward path"
287             << endl;
288 
289         m_enable_next_request_event.notify(SC_ZERO_TIME);
290 
291         transaction_inter->second = Rcved_END_REQ_enum;
292         status = tlm::TLM_ACCEPTED;
293 
294         msg << "      "
295             << "Initiator: " << m_ID
296             << " " << report::print(status) <<  " (GP, "
297             << report::print(phase) << ", "
298             << delay << ")";
299         REPORT_INFO (filename, __FUNCTION__, msg.str() );
300 
301         break;
302       }
303 
304 //-----------------------------------------------------------------------------
305 //  Target has responded with BEGIN_RESP
306 //    Use payload event queue to schedule sending end response
307 //    If there was no END REQUEST this ends the request phase notify
308 //    enable next request event
309 //-----------------------------------------------------------------------------
310     case tlm::BEGIN_RESP: {
311 
312       msg << "      "
313           << "Initiator: " << m_ID
314           << " transaction moved to send-end-response PEQ "
315           << endl;
316 
317       m_send_end_rsp_PEQ.notify (transaction_ref, m_end_rsp_delay);
318 
319       // check for a synthetic 3-phase transaction (BEGIN_RESP without END_REQ)
320       if (transaction_inter->second == Rcved_ACCEPTED_enum) {
321         m_enable_next_request_event.notify(SC_ZERO_TIME);
322         }
323 
324       m_waiting_bw_path_map.erase(&transaction_ref);    // erase from map
325 
326       status = tlm::TLM_ACCEPTED;
327 
328       msg << "      "
329           << "Initiator: " << m_ID
330           << " " << report::print(status) <<  " (GP, "
331           << report::print(phase) << ", "
332           << delay << ")" ;
333       REPORT_INFO (filename, __FUNCTION__, msg.str() );
334 
335       break;
336     }  // end case BEGIN_RESP
337 
338 
339 //-----------------------------------------------------------------------------
340 // Invalid phase for backward path
341 //-----------------------------------------------------------------------------
342     case tlm::BEGIN_REQ:
343     case tlm::END_RESP:
344       {
345         msg.str ("");
346         msg << m_ID << " Illegal phase on backward path ";
347         REPORT_FATAL(filename, __FUNCTION__, msg.str() );
348         break;
349       }
350 //-----------------------------------------------------------------------------
351 // Unknown phase on backward path
352 //-----------------------------------------------------------------------------
353     default:
354       {
355         msg.str ("");
356         msg << m_ID << " Unknown phase on the backward path ";
357         REPORT_WARNING (filename, __FUNCTION__, msg.str() );
358         break;
359       }
360     } // end switch (phase)
361   }
362     return status;
363 } // end backward nb transport
364 
365 
366 
367 //=============================================================================
368 ///  @fn at_initiator_explicit::send_end_rsp_method
369 //
370 ///  @brief send end response method
371 //
372 ///  @details This method is scheduled to send the end-response timing point.
373 ///           It is sensitive to the m_send_end_rsp_PEQ.get_event() event.
374 //
375 //=============================================================================
send_end_rsp_method(void)376 void at_initiator_explicit::send_end_rsp_method(void) // send end response method
377 {
378   tlm::tlm_generic_payload* transaction_ptr;
379   std::ostringstream        msg;                      // log message
380 
381 //-----------------------------------------------------------------------------
382 //  Process all transactions scheduled for current time a return value of NULL
383 //  indicates that the PEQ is empty at this time
384 //-----------------------------------------------------------------------------
385   while ((transaction_ptr = m_send_end_rsp_PEQ.get_next_transaction()) != NULL)
386   {
387     tlm::tlm_phase phase  = tlm::END_RESP;          // set the appropriate phase
388     sc_time delay         = SC_ZERO_TIME;
389 
390     msg.str("");
391     msg   << "Initiator: " << m_ID
392         << " starting send-end-response method"
393         << endl << "      "
394         << "Initiator: " << m_ID
395         << " nb_transport_fw (GP, "
396         << report::print(phase) << ", "
397         << delay << ")";
398     REPORT_INFO(filename,  __FUNCTION__, msg.str());
399 
400     // call begin response and then decode return status
401     tlm::tlm_sync_enum
402     return_value = initiator_socket->nb_transport_fw(*transaction_ptr, phase, delay);
403 
404     msg.str("");
405     msg << "Initiator: " << m_ID
406       << " " << report::print(return_value) <<  " (GP, "
407       << report::print(phase) << ", "
408       << delay << ")";
409 
410     switch (return_value)
411     {
412       case tlm::TLM_COMPLETED:                        // transaction complete
413       {
414         response_out_port->write(transaction_ptr);    // send GP to output rsp fifo
415 
416         REPORT_INFO (filename, __FUNCTION__, msg.str() );
417         break;
418       }
419 
420       case tlm::TLM_ACCEPTED:
421       case tlm::TLM_UPDATED:
422       {
423         msg << "      "
424             << "Initiator: " << m_ID
425             << report::print(return_value) << " Invalid return value for END_RESP ";
426         REPORT_FATAL(filename,  __FUNCTION__, msg.str());
427         break;
428       }
429 
430       default:
431       {
432         msg << "      "
433             << "Initiator: " << m_ID
434             << report::print(return_value) << " Unknown return value for END_RESP ";
435         REPORT_FATAL(filename,  __FUNCTION__, msg.str());
436         break;
437       }
438     } // end switch
439   } // end while
440 
441     return;
442 } // end send_end_rsp_method
443 
444 
445 //=============================================================================
446 ///  @fn at_initiator_explicit::invalidate_direct_mem_ptr
447 //
448 ///  @brief invalidate direct memory pointer Not implemented
449 //=============================================================================
450 
invalidate_direct_mem_ptr(sc_dt::uint64 start_range,sc_dt::uint64 end_range)451 void at_initiator_explicit::invalidate_direct_mem_ptr   // invalidate_direct_mem_ptr
452 ( sc_dt::uint64 start_range                             // start range
453 , sc_dt::uint64 end_range                               // end range
454 )
455 {
456   std::ostringstream       msg;                         // log message
457 
458   msg.str ("");
459   msg << m_ID << " invalidate_direct_mem_ptr: not implemented";
460   REPORT_INFO(filename, __FUNCTION__, msg.str());
461 }
462 
463