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 #include "lt_initiator_extension_mandatory.h"
21 
22 using namespace sc_core;
23 
24 static const char *filename = "lt_initiator_extension_mandatory.cpp";  ///  filename for reporting
25 
lt_initiator_extension_mandatory(sc_module_name name,unsigned int num_trans=5,sc_dt::uint64 base_address=0)26 lt_initiator_extension_mandatory::lt_initiator_extension_mandatory  ///< constructor
27 ( sc_module_name name                                               ///< instance
28 , unsigned int            num_trans    = 5                          ///< number of transactions
29 , sc_dt::uint64           base_address = 0                          ///< base address
30 )
31 : sc_module               ( name                     )              ///< instance name
32 , m_socket                ( "LT_initiator_mandatory" )              ///< socket
33 , m_transaction_max       ( num_trans                )              ///< transaction maximum
34 , m_base_address          ( base_address             )              ///< base address
35 , m_transaction_count     ( 0                        )              ///< transaction count
36 {
37   invalidate_dmi_properties ();
38 
39   // register transport methods
40 
41   m_socket.register_nb_transport_bw           ( this, &lt_initiator_extension_mandatory::nb_transport_bw           );
42   m_socket.register_invalidate_direct_mem_ptr ( this, &lt_initiator_extension_mandatory::invalidate_direct_mem_ptr );
43 
44   // Initiator thread
45 
46   SC_THREAD ( initiator_thread );
47 }
48 
49 bool                                                                ///< transaction created
create_transaction(transaction_type & trans)50 lt_initiator_extension_mandatory::create_transaction                ///< create transaction
51 ( transaction_type  &trans                                          ///< transaction
52 )
53 {
54   static bool  new_transaction ( true );                            ///< new transaction flag
55 
56   if ( new_transaction )
57   {
58     // initialize DMI state:
59 
60     trans.set_dmi_allowed     ( false                     );
61     trans.set_data_length     ( 4                         );
62     trans.set_streaming_width ( trans.get_data_length ()  );
63 
64     if ( m_transaction_count < m_transaction_max )
65     {
66       trans.set_address ( m_base_address + ( 4 * m_transaction_count ) );
67 
68       m_data = m_transaction_count;
69 
70       trans.set_data_ptr  ( reinterpret_cast<unsigned char*>(&m_data) );
71       trans.set_command   ( tlm::TLM_WRITE_COMMAND                    );
72     }
73     else if ( m_transaction_count < ( 2 * m_transaction_max ) )
74     {
75       trans.set_address ( m_base_address + ( 4 * ( m_transaction_count - m_transaction_max ) ) );
76 
77       m_data = 0;
78 
79       trans.set_data_ptr  ( reinterpret_cast<unsigned char*>(&m_data) );
80       trans.set_command   ( tlm::TLM_READ_COMMAND                     );
81     }
82     else
83     {
84       new_transaction = false;
85     }
86 
87     m_transaction_count++;
88   }
89 
90   return new_transaction;
91 }
92 
93 void
log_start(transaction_type & trans)94 lt_initiator_extension_mandatory::log_start                         ///< log transaction start
95 ( transaction_type  &trans                                          ///< transaction
96 )
97 {
98   ostringstream  msg;                                               ///< log message
99 
100   msg.str ( "" );
101 
102   msg << "Creating "
103       << ( ( trans.get_command () == tlm::TLM_WRITE_COMMAND ) ? "write" : "read" )
104       << " transaction - Addr: 0x" << internal << setw ( sizeof(sc_dt::uint64) * 2 )
105       << setfill( '0' ) << uppercase << hex << trans.get_address ();
106 
107   if (trans.get_command() == tlm::TLM_WRITE_COMMAND)
108   {
109     msg << " Data: 0x" << internal << setw ( sizeof ( m_data ) * 2 )
110         << setfill( '0' ) << uppercase << hex << m_data;
111   }
112 
113   REPORT_INFO ( filename,  __FUNCTION__, msg.str () );
114 }
115 
116 void
log_end(transaction_type & trans)117 lt_initiator_extension_mandatory::log_end                           ///< log transaction end
118 ( transaction_type  &trans                                          ///< transaction
119 )
120 {
121   ostringstream msg;                                                ///< log message
122 
123   msg.str ( "" );
124 
125   msg << "Received ";
126 
127   if ( trans.get_response_status() != tlm::TLM_OK_RESPONSE )
128   {
129     msg << "invalid response " << trans.get_response_status ();
130   }
131   else
132   {
133     msg << "TLM_OK_RESPONSE";
134 
135     if (trans.get_command() == tlm::TLM_READ_COMMAND)
136     {
137       msg << ", Data: 0x" << internal << setw ( sizeof ( m_data ) * 2 )
138           << setfill( '0' ) << uppercase << hex << m_data;
139     }
140   }
141 
142   REPORT_INFO ( filename,  __FUNCTION__, msg.str () );
143 }
144 
145 void
initiator_thread(void)146 lt_initiator_extension_mandatory::initiator_thread      ///< initiator thread
147 ( void
148 )
149 {
150   transaction_type  trans;                              ///< transaction
151   phase_type        phase;                              ///< phase
152   sc_time           t;                                  ///< time
153   ostringstream     msg;                                ///< log message
154 
155   // make sure that our transaction has the proper extension:
156 
157   extension_initiator_id* extension_ptr = new extension_initiator_id ();
158 
159   extension_ptr->m_initiator_id = "generic ID";
160 
161   trans.set_extension ( extension_ptr );
162 
163   while ( create_transaction ( trans ) )
164   {
165     // initialize phase and time
166 
167     phase = tlm::BEGIN_REQ;
168     t     = SC_ZERO_TIME;
169 
170     log_start ( trans );
171 
172     ///////////////////////////////////////////////////////////
173     // DMI handling:
174     // We use the DMI hint to check if it makes sense to ask for
175     // DMI pointers. The pattern is:
176     // - if the address is covered by a DMI region do a DMI access
177     // - otherwise do a normal transaction
178     //   -> check if we get a DMI hint and acquire the DMI pointers if it
179     //      is set
180     ///////////////////////////////////////////////////////////
181 
182     // Check if the address is covered by our DMI region
183     if  (  ( trans.get_address () >= m_dmi_properties.get_start_address () )
184         && ( trans.get_address () <= m_dmi_properties.get_end_address   () ) )
185     {
186       // We can handle the data here. As the logEndTransaction is
187       // assuming something to happen in the data structure, we really
188       // need to do this:
189 
190       trans.set_response_status(tlm::TLM_OK_RESPONSE);
191 
192       sc_dt::uint64 tmp = trans.get_address() - m_dmi_properties.get_start_address();
193 
194       if (trans.get_command() == tlm::TLM_WRITE_COMMAND)
195       {
196         *(unsigned int*)&m_dmi_properties.get_dmi_ptr()[tmp] = m_data;
197       }
198       else
199       {
200         m_data = *(unsigned int*)&m_dmi_properties.get_dmi_ptr () [ tmp ];
201       }
202 
203       // Do the wait immediately. Note that doing the wait here eats
204       //  almost all the performance anyway, so we only gain something
205       // if we're using temporal decoupling.
206 
207       if (trans.get_command() == tlm::TLM_WRITE_COMMAND)
208       {
209         wait ( m_dmi_properties.get_write_latency () );
210       }
211       else
212       {
213         wait ( m_dmi_properties.get_read_latency () );
214       }
215 
216       log_end ( trans );
217     }
218     else
219     {
220       // we need a full transaction
221       switch (m_socket->nb_transport_fw(trans, phase, t))
222       {
223         case tlm::TLM_COMPLETED:
224         {
225           // Transaction Finished, wait for the returned delay
226           wait(t);
227           break;
228         }
229 
230         case tlm::TLM_ACCEPTED:
231         case tlm::TLM_UPDATED:
232         {
233           // Transaction not yet finished, wait for the end of it
234           wait(mEndEvent);
235           break;
236         }
237 
238         default:
239         {
240           assert(0); exit(1);
241         }
242       }
243 
244       log_end ( trans );
245 
246       // Acquire DMI pointer if one is available:
247       if (trans.is_dmi_allowed())
248       {
249         trans.set_write();
250 
251         dmi_type  tmp;
252 
253         if (m_socket->get_direct_mem_ptr(trans, tmp))
254         {
255           // FIXME: No support for separate read/write ranges
256           assert(tmp.is_read_write_allowed());
257 
258           m_dmi_properties = tmp;
259         }
260       }
261     }
262   }
263 
264   delete extension_ptr;
265 
266   wait();
267 }
268 
269 tlm::tlm_sync_enum                                        ///< response
nb_transport_bw(transaction_type & trans,phase_type & phase,sc_time & t)270 lt_initiator_extension_mandatory::nb_transport_bw         ///< non-blocking backward transport
271 ( transaction_type  &trans                                ///< transaction
272 , phase_type        &phase                                ///< phase
273 , sc_time           &t                                    ///< time
274 )
275 {
276   tlm::tlm_sync_enum  response;                           ///< response
277   ostringstream  msg;                                ///< log message
278 
279   switch (phase)
280   {
281     case tlm::END_REQ:
282     {
283       // Request phase ended
284       response = tlm::TLM_ACCEPTED;
285 
286       break;
287     }
288 
289     case tlm::BEGIN_RESP:
290     {
291       assert(t == SC_ZERO_TIME); // FIXME: can t != 0?
292 
293       mEndEvent.notify (t);
294 
295       // Not needed to update the phase if true is returned
296       response = tlm::TLM_COMPLETED;
297 
298       break;
299     }
300 
301     case tlm::BEGIN_REQ:
302     case tlm::END_RESP:
303     default:
304     {
305       // A target should never call nb_transport with these phases
306       assert(0); exit(1);
307     }
308   }
309 
310   return response;
311 }
312 
313 void
invalidate_dmi_properties(void)314 lt_initiator_extension_mandatory::invalidate_dmi_properties       ///< invalidate DMI properties
315 ( void
316 )
317 {
318   m_dmi_properties.set_start_address ( 1 );
319   m_dmi_properties.set_end_address   ( 0 );
320 }
321 
322 // Invalidate DMI pointer(s)
323 
324 void
invalidate_direct_mem_ptr(sc_dt::uint64 start_range,sc_dt::uint64 end_range)325 lt_initiator_extension_mandatory::invalidate_direct_mem_ptr
326 ( sc_dt::uint64 start_range
327 , sc_dt::uint64 end_range
328 )
329 {
330   ostringstream       msg;                     ///< log message
331 
332   msg.str ( "" );
333 
334   msg << "Received invalidate request - ";
335 
336   // see if request is in range
337 
338   if (  ( start_range <= end_range                             )
339      && ( start_range <= m_dmi_properties.get_end_address   () )
340      && ( end_range   >= m_dmi_properties.get_start_address () ) )
341   {
342     msg << "valid request";
343 
344     // invalidate the DMI properties
345 
346     invalidate_dmi_properties ();
347   }
348   else
349   {
350     msg << "not in our DMI address range";
351   }
352 
353   REPORT_INFO ( filename,  __FUNCTION__, msg.str () );
354 }
355