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, <_initiator_extension_mandatory::nb_transport_bw );
42 m_socket.register_invalidate_direct_mem_ptr ( this, <_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