Deleted Added
sdiff udiff text old ( 13513:bbf275465d3d ) new ( 13586:008fe87c1ad4 )
full compact
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 __SYSTEMC_EXT_TLM_UTILS_SIMPLE_TARGET_SOCKET_H__
21#define __SYSTEMC_EXT_TLM_UTILS_SIMPLE_TARGET_SOCKET_H__
22
23#include "../core/sc_event.hh"
24#include "../core/sc_module.hh"
25#include "../core/sc_port.hh"
26#include "../tlm_core/2/generic_payload/gp.hh"
27#include "../tlm_core/2/interfaces/fw_bw_ifs.hh"
28#include "../tlm_core/2/sockets/target_socket.hh"
29#include "../utils/sc_report_handler.hh"
30#include "convenience_socket_bases.h"
31#include "peq_with_get.h"
32
33namespace tlm_utils
34{
35
36template <typename MODULE, unsigned int BUSWIDTH, typename TYPES,
37 sc_core::sc_port_policy POL=sc_core::SC_ONE_OR_MORE_BOUND>
38class simple_target_socket_b :
39 public tlm::tlm_target_socket<BUSWIDTH, TYPES, 1, POL>,
40 protected simple_socket_base
41{
42 friend class fw_process;
43 friend class bw_process;
44 public:
45 typedef typename TYPES::tlm_payload_type transaction_type;
46 typedef typename TYPES::tlm_phase_type phase_type;
47 typedef tlm::tlm_sync_enum sync_enum_type;
48 typedef tlm::tlm_fw_transport_if<TYPES> fw_interface_type;
49 typedef tlm::tlm_bw_transport_if<TYPES> bw_interface_type;
50 typedef tlm::tlm_target_socket<BUSWIDTH, TYPES, 1, POL> base_type;
51
52 public:
53 static const char *
54 default_name()
55 {
56 return sc_core::sc_gen_unique_name("simple_target_socket");
57 }
58
59 explicit simple_target_socket_b(const char *n=default_name()) :
60 base_type(n), m_fw_process(this), m_bw_process(this)
61 {
62 bind(m_fw_process);
63 }
64
65 using base_type::bind;
66
67 // bw transport must come through us.
68 tlm::tlm_bw_transport_if<TYPES> *operator -> () { return &m_bw_process; }
69
70 // REGISTER_XXX
71 void
72 register_nb_transport_fw(MODULE *mod,
73 sync_enum_type (MODULE::*cb)(
74 transaction_type &, phase_type &, sc_core::sc_time &))
75 {
76 elaboration_check("register_nb_transport_fw");
77 m_fw_process.set_nb_transport_ptr(mod, cb);
78 }
79
80 void
81 register_b_transport(MODULE *mod,
82 void (MODULE::*cb)(transaction_type &, sc_core::sc_time &))
83 {
84 elaboration_check("register_b_transport");
85 m_fw_process.set_b_transport_ptr(mod, cb);
86 }
87
88 void
89 register_transport_dbg(MODULE *mod,
90 unsigned int (MODULE::*cb)(transaction_type &))
91 {
92 elaboration_check("register_transport_dbg");
93 m_fw_process.set_transport_dbg_ptr(mod, cb);
94 }
95
96 void
97 register_get_direct_mem_ptr(MODULE *mod,
98 bool (MODULE::*cb)(transaction_type &, tlm::tlm_dmi &))
99 {
100 elaboration_check("register_get_direct_mem_ptr");
101 m_fw_process.set_get_direct_mem_ptr(mod, cb);
102 }
103
104 protected:
105 void
106 start_of_simulation()
107 {
108 base_type::start_of_simulation();
109 m_fw_process.start_of_simulation();
110 }
111
112 private:
113 // Make call on bw path.
114 sync_enum_type
115 bw_nb_transport(transaction_type &trans, phase_type &phase,
116 sc_core::sc_time &t)
117 {
118 return base_type::operator -> ()->nb_transport_bw(trans, phase, t);
119 }
120
121 void
122 bw_invalidate_direct_mem_ptr(sc_dt::uint64 s, sc_dt::uint64 e)
123 {
124 base_type::operator -> ()->invalidate_direct_mem_ptr(s, e);
125 }
126
127 // Helper class to handle bw path calls Needed to detect transaction end
128 // when called from b_transport.
129 class bw_process : public tlm::tlm_bw_transport_if<TYPES>
130 {
131 public:
132 bw_process(simple_target_socket_b *p_own) : m_owner(p_own) {}
133
134 sync_enum_type
135 nb_transport_bw(transaction_type &trans, phase_type &phase,
136 sc_core::sc_time &t)
137 {
138 typename std::map<transaction_type *,
139 sc_core::sc_event *>::iterator it =
140 m_owner->m_pending_trans.find(&trans);
141
142 if (it == m_owner->m_pending_trans.end()) {
143 // Not a blocking call, forward.
144 return m_owner->bw_nb_transport(trans, phase, t);
145
146 }
147
148 if (phase == tlm::END_REQ) {
149 m_owner->m_end_request.notify(sc_core::SC_ZERO_TIME);
150 return tlm::TLM_ACCEPTED;
151 }
152 if (phase == tlm::BEGIN_RESP) {
153 if (m_owner->m_current_transaction == &trans) {
154 m_owner->m_end_request.notify(sc_core::SC_ZERO_TIME);
155 }
156 it->second->notify(t);
157 m_owner->m_pending_trans.erase(it);
158 return tlm::TLM_COMPLETED;
159 }
160 m_owner->display_error("invalid phase received");
161 return tlm::TLM_COMPLETED;
162 }
163
164 void
165 invalidate_direct_mem_ptr(sc_dt::uint64 s, sc_dt::uint64 e)
166 {
167 return m_owner->bw_invalidate_direct_mem_ptr(s, e);
168 }
169
170 private:
171 simple_target_socket_b *m_owner;
172 };
173
174 class fw_process : public tlm::tlm_fw_transport_if<TYPES>,
175 public tlm::tlm_mm_interface
176 {
177 public:
178 typedef sync_enum_type (MODULE::*NBTransportPtr)(
179 transaction_type &, phase_type &, sc_core::sc_time &);
180 typedef void (MODULE::*BTransportPtr)(
181 transaction_type &, sc_core::sc_time &);
182 typedef unsigned int (MODULE::*TransportDbgPtr)(transaction_type &);
183 typedef bool (MODULE::*GetDirectMemPtr)(
184 transaction_type &, tlm::tlm_dmi &);
185
186 fw_process(simple_target_socket_b *p_own) :
187 m_owner(p_own), m_mod(0), m_nb_transport_ptr(0),
188 m_b_transport_ptr(0), m_transport_dbg_ptr(0),
189 m_get_direct_mem_ptr(0),
190 m_peq(sc_core::sc_gen_unique_name("m_peq")),
191 m_response_in_progress(false)
192 {}
193
194 void
195 start_of_simulation()
196 {
197 // Only spawn b2nb_thread, if needed.
198 if (!m_b_transport_ptr && m_nb_transport_ptr) {
199 sc_core::sc_spawn_options opts;
200 opts.set_sensitivity(&m_peq.get_event());
201 opts.dont_initialize();
202 sc_core::sc_spawn(sc_bind(&fw_process::b2nb_thread, this),
203 sc_core::sc_gen_unique_name("b2nb_thread"), &opts);
204 }
205 }
206
207 void
208 set_nb_transport_ptr(MODULE *mod, NBTransportPtr p)
209 {
210 if (m_nb_transport_ptr) {
211 m_owner->display_warning(
212 "non-blocking callback already registered");
213 return;
214 }
215 sc_assert(!m_mod || m_mod == mod);
216 m_mod = mod;
217 m_nb_transport_ptr = p;
218 }
219
220 void
221 set_b_transport_ptr(MODULE *mod, BTransportPtr p)
222 {
223 if (m_b_transport_ptr) {
224 m_owner->display_warning(
225 "blocking callback already registered");
226 return;
227 }
228 sc_assert(!m_mod || m_mod == mod);
229 m_mod = mod;
230 m_b_transport_ptr = p;
231 }
232
233 void
234 set_transport_dbg_ptr(MODULE *mod, TransportDbgPtr p)
235 {
236 if (m_transport_dbg_ptr) {
237 m_owner->display_warning("debug callback already registered");
238 return;
239 }
240 sc_assert(!m_mod || m_mod == mod);
241 m_mod = mod;
242 m_transport_dbg_ptr = p;
243 }
244
245 void
246 set_get_direct_mem_ptr(MODULE *mod, GetDirectMemPtr p)
247 {
248 if (m_get_direct_mem_ptr) {
249 m_owner->display_warning(
250 "get DMI pointer callback already registered");
251 return;
252 }
253 sc_assert(!m_mod || m_mod == mod);
254 m_mod = mod;
255 m_get_direct_mem_ptr = p;
256 }
257
258 // Interface implementation.
259 sync_enum_type
260 nb_transport_fw(transaction_type &trans, phase_type &phase,
261 sc_core::sc_time & t)
262 {
263 if (m_nb_transport_ptr) {
264 // Forward call.
265 sc_assert(m_mod);
266 return (m_mod->*m_nb_transport_ptr)(trans, phase, t);
267 }
268
269 // nb->b conversion
270 if (m_b_transport_ptr) {
271 if (phase == tlm::BEGIN_REQ) {
272 // Prepare thread to do blocking call.
273 process_handle_class *ph =
274 m_process_handle.get_handle(&trans);
275
276 if (!ph) { // Create new dynamic process.
277 ph = new process_handle_class(&trans);
278 m_process_handle.put_handle(ph);
279
280 sc_core::sc_spawn_options opts;
281 opts.dont_initialize();
282 opts.set_sensitivity(&ph->m_e);
283
284 sc_core::sc_spawn(
285 sc_bind(&fw_process::nb2b_thread, this, ph),
286 sc_core::sc_gen_unique_name("nb2b_thread"),
287 &opts);
288 }
289
290 ph->m_e.notify(t);
291 return tlm::TLM_ACCEPTED;
292 }
293 if (phase == tlm::END_RESP) {
294 m_response_in_progress = false;
295 m_end_response.notify(t);
296 return tlm::TLM_COMPLETED;
297 }
298 m_owner->display_error("invalid phase received");
299 return tlm::TLM_COMPLETED;
300 }
301 m_owner->display_error(
302 "no non-blocking transport callback registered");
303 return tlm::TLM_COMPLETED;
304 }
305
306 void
307 b_transport(transaction_type &trans, sc_core::sc_time &t)
308 {
309 if (m_b_transport_ptr) {
310 // Forward call.
311 sc_assert(m_mod);
312 (m_mod->*m_b_transport_ptr)(trans, t);
313 return;
314 }
315
316 // b->nb conversion
317 if (m_nb_transport_ptr) {
318 m_peq.notify(trans, t);
319 t = sc_core::SC_ZERO_TIME;
320
321 mm_end_event_ext mm_ext;
322 const bool mm_added = !trans.has_mm();
323
324 if (mm_added) {
325 trans.set_mm(this);
326 trans.set_auto_extension(&mm_ext);
327 trans.acquire();
328 }
329
330 // Wait until transaction is finished.
331 sc_core::sc_event end_event;
332 m_owner->m_pending_trans[&trans] = &end_event;
333 sc_core::wait(end_event);
334
335 if (mm_added) {
336 // Release will not delete the transaction, it will
337 // notify mm_ext.done.
338 trans.release();
339 if (trans.get_ref_count()) {
340 sc_core::wait(mm_ext.done);
341 }
342 trans.set_mm(0);
343 }
344 return;
345 }
346
347 // Should not be reached.
348 m_owner->display_error(
349 "no blocking transport callback registered");
350 }
351
352 unsigned int
353 transport_dbg(transaction_type &trans)
354 {
355 if (m_transport_dbg_ptr) {
356 // Forward call.
357 sc_assert(m_mod);
358 return (m_mod->*m_transport_dbg_ptr)(trans);
359 }
360 // No debug support.
361 return 0;
362 }
363
364 bool
365 get_direct_mem_ptr(transaction_type &trans, tlm::tlm_dmi &dmi_data)
366 {
367 if (m_get_direct_mem_ptr) {
368 // Forward call.
369 sc_assert(m_mod);
370 return (m_mod->*m_get_direct_mem_ptr)(trans, dmi_data);
371 }
372 // No DMI support.
373 dmi_data.allow_read_write();
374 dmi_data.set_start_address(0x0);
375 dmi_data.set_end_address((sc_dt::uint64)-1);
376 return false;
377 }
378
379 private:
380
381 // Dynamic process handler for nb2b conversion.
382
383 class process_handle_class
384 {
385 public:
386 explicit process_handle_class(transaction_type *trans) :
387 m_trans(trans), m_suspend(false)
388 {}
389
390 transaction_type *m_trans;
391 sc_core::sc_event m_e;
392 bool m_suspend;
393 };
394
395 class process_handle_list
396 {
397 public:
398 process_handle_list() {}
399
400 ~process_handle_list()
401 {
402 for (typename std::vector<
403 process_handle_class *>::iterator it = v.begin(),
404 end = v.end(); it != end; ++it) {
405 delete *it;
406 }
407 }
408
409 process_handle_class *
410 get_handle(transaction_type *trans)
411 {
412 typename std::vector<process_handle_class *>::iterator it;
413
414 for (it = v.begin(); it != v.end(); it++) {
415 if ((*it)->m_suspend) {
416 // Found suspended dynamic process, re-use it.
417 (*it)->m_trans = trans; // Replace to new one.
418 (*it)->m_suspend = false;
419 return *it;
420 }
421 }
422 return NULL; // No suspended process.
423 }
424
425 void
426 put_handle(process_handle_class *ph)
427 {
428 v.push_back(ph);
429 }
430
431 private:
432 std::vector<process_handle_class*> v;
433 };
434
435 process_handle_list m_process_handle;
436
437 void
438 nb2b_thread(process_handle_class *h)
439 {
440 while (1) {
441 transaction_type *trans = h->m_trans;
442 sc_core::sc_time t = sc_core::SC_ZERO_TIME;
443
444 // Forward call.
445 sc_assert(m_mod);
446 (m_mod->*m_b_transport_ptr)(*trans, t);
447
448 sc_core::wait(t);
449
450 // Return path.
451 while (m_response_in_progress) {
452 sc_core::wait(m_end_response);
453 }
454 t = sc_core::SC_ZERO_TIME;
455 phase_type phase = tlm::BEGIN_RESP;
456 sync_enum_type sync =
457 m_owner->bw_nb_transport(*trans, phase, t);
458 if (!(sync == tlm::TLM_COMPLETED ||
459 (sync == tlm::TLM_UPDATED &&
460 phase == tlm::END_RESP))) {
461 m_response_in_progress = true;
462 }
463
464 // Suspend until next transaction.
465 h->m_suspend = true;
466 sc_core::wait();
467 }
468 }
469
470 void
471 b2nb_thread()
472 {
473 while (true) {
474 transaction_type *trans;
475 while ((trans = m_peq.get_next_transaction()) != 0) {
476 sc_assert(m_mod);
477 sc_assert(m_nb_transport_ptr);
478 phase_type phase = tlm::BEGIN_REQ;
479 sc_core::sc_time t = sc_core::SC_ZERO_TIME;
480
481 switch ((m_mod->*m_nb_transport_ptr)(*trans, phase, t)) {
482 case tlm::TLM_COMPLETED:
483 {
484 // Notify transaction is finished.
485 typename std::map<transaction_type *,
486 sc_core::sc_event *>::iterator it =
487 m_owner->m_pending_trans.find(trans);
488 sc_assert(it != m_owner->m_pending_trans.end());
489 it->second->notify(t);
490 m_owner->m_pending_trans.erase(it);
491 break;
492 }
493
494 case tlm::TLM_ACCEPTED:
495 case tlm::TLM_UPDATED:
496 switch (phase) {
497 case tlm::BEGIN_REQ:
498 m_owner->m_current_transaction = trans;
499 sc_core::wait(m_owner->m_end_request);
500 m_owner->m_current_transaction = 0;
501 break;
502
503 case tlm::END_REQ:
504 sc_core::wait(t);
505 break;
506
507 case tlm::BEGIN_RESP:
508 {
509 phase = tlm::END_RESP;
510 // This line is a bug fix added in TLM-2.0.2
511 sc_core::wait(t);
512 t = sc_core::SC_ZERO_TIME;
513 (m_mod->*m_nb_transport_ptr)(
514 *trans, phase, t);
515
516 // Notify transaction is finished.
517 typename std::map<transaction_type *,
518 sc_core::sc_event *>::iterator it =
519 m_owner->m_pending_trans.find(
520 trans);
521 sc_assert(it !=
522 m_owner->m_pending_trans.end());
523 it->second->notify(t);
524 m_owner->m_pending_trans.erase(it);
525 break;
526 }
527
528 default:
529 m_owner->display_error("invalid phase received");
530 }
531 break;
532
533 default:
534 m_owner->display_error("invalid sync value received");
535 }
536 }
537 sc_core::wait();
538 }
539 }
540
541 void
542 free(tlm::tlm_generic_payload *trans)
543 {
544 mm_end_event_ext *ext =
545 trans->template get_extension<mm_end_event_ext>();
546 sc_assert(ext);
547 // Notify event first before freeing extensions (reset).
548 ext->done.notify();
549 trans->reset();
550 }
551
552 private:
553 struct mm_end_event_ext : public tlm::tlm_extension<mm_end_event_ext>
554 {
555 tlm::tlm_extension_base *clone() const { return NULL; }
556 void free() {}
557 void copy_from(tlm::tlm_extension_base const &) {}
558 sc_core::sc_event done;
559 };
560
561 private:
562 simple_target_socket_b *m_owner;
563 MODULE *m_mod;
564 NBTransportPtr m_nb_transport_ptr;
565 BTransportPtr m_b_transport_ptr;
566 TransportDbgPtr m_transport_dbg_ptr;
567 GetDirectMemPtr m_get_direct_mem_ptr;
568 peq_with_get<transaction_type> m_peq;
569 bool m_response_in_progress;
570 sc_core::sc_event m_end_response;
571 };
572
573 private:
574 const sc_core::sc_object *get_socket() const { return this; }
575
576 private:
577 fw_process m_fw_process;
578 bw_process m_bw_process;
579 std::map<transaction_type *, sc_core::sc_event *> m_pending_trans;
580 sc_core::sc_event m_end_request;
581 transaction_type* m_current_transaction;
582};
583
584template <typename MODULE, unsigned int BUSWIDTH=32,
585 typename TYPES=tlm::tlm_base_protocol_types>
586class simple_target_socket :
587 public simple_target_socket_b<MODULE, BUSWIDTH, TYPES>
588{
589 typedef simple_target_socket_b<MODULE, BUSWIDTH, TYPES> socket_b;
590 public:
591 simple_target_socket() : socket_b() {}
592 explicit simple_target_socket(const char *name) : socket_b(name) {}
593};
594
595template <typename MODULE, unsigned int BUSWIDTH=32,
596 typename TYPES=tlm::tlm_base_protocol_types>
597class simple_target_socket_optional :
598 public simple_target_socket_b<MODULE, BUSWIDTH, TYPES,
599 sc_core::SC_ZERO_OR_MORE_BOUND>
600{
601 typedef simple_target_socket_b<MODULE, BUSWIDTH, TYPES,
602 sc_core::SC_ZERO_OR_MORE_BOUND> socket_b;
603 public:
604 simple_target_socket_optional() : socket_b() {}
605 explicit simple_target_socket_optional(const char *name) :
606 socket_b(name)
607 {}
608};
609
610// ID Tagged version.
611template <typename MODULE, unsigned int BUSWIDTH, typename TYPES,
612 sc_core::sc_port_policy POL=sc_core::SC_ONE_OR_MORE_BOUND>
613class simple_target_socket_tagged_b :
614 public tlm::tlm_target_socket<BUSWIDTH, TYPES, 1, POL>,
615 protected simple_socket_base
616{
617 friend class fw_process;
618 friend class bw_process;
619 public:
620 typedef typename TYPES::tlm_payload_type transaction_type;
621 typedef typename TYPES::tlm_phase_type phase_type;
622 typedef tlm::tlm_sync_enum sync_enum_type;
623 typedef tlm::tlm_fw_transport_if<TYPES> fw_interface_type;
624 typedef tlm::tlm_bw_transport_if<TYPES> bw_interface_type;
625 typedef tlm::tlm_target_socket<BUSWIDTH, TYPES, 1, POL> base_type;
626
627 public:
628 static const char *
629 default_name()
630 {
631 return sc_core::sc_gen_unique_name("simple_target_socket_tagged");
632 }
633
634 explicit simple_target_socket_tagged_b(const char *n=default_name()) :
635 base_type(n), m_fw_process(this), m_bw_process(this)
636 {
637 bind(m_fw_process);
638 }
639
640 using base_type::bind;
641
642 // bw transport must come through us.
643 tlm::tlm_bw_transport_if<TYPES> *operator -> () { return &m_bw_process; }
644
645 // REGISTER_XXX
646 void
647 register_nb_transport_fw(MODULE *mod,
648 sync_enum_type (MODULE::*cb)(int id, transaction_type &,
649 phase_type &, sc_core::sc_time &),
650 int id)
651 {
652 elaboration_check("register_nb_transport_fw");
653 m_fw_process.set_nb_transport_ptr(mod, cb);
654 m_fw_process.set_nb_transport_user_id(id);
655 }
656
657 void
658 register_b_transport(MODULE *mod,
659 void (MODULE::*cb)(int id, transaction_type &,
660 sc_core::sc_time &),
661 int id)
662 {
663 elaboration_check("register_b_transport");
664 m_fw_process.set_b_transport_ptr(mod, cb);
665 m_fw_process.set_b_transport_user_id(id);
666 }
667
668 void
669 register_transport_dbg(MODULE *mod,
670 unsigned int (MODULE::*cb)(int id, transaction_type &), int id)
671 {
672 elaboration_check("register_transport_dbg");
673 m_fw_process.set_transport_dbg_ptr(mod, cb);
674 m_fw_process.set_transport_dbg_user_id(id);
675 }
676
677 void
678 register_get_direct_mem_ptr(MODULE *mod,
679 bool (MODULE::*cb)(int id, transaction_type &, tlm::tlm_dmi &),
680 int id)
681 {
682 elaboration_check("register_get_direct_mem_ptr");
683 m_fw_process.set_get_direct_mem_ptr(mod, cb);
684 m_fw_process.set_get_dmi_user_id(id);
685 }
686
687 protected:
688 void
689 start_of_simulation()
690 {
691 base_type::start_of_simulation();
692 m_fw_process.start_of_simulation();
693 }
694
695 private:
696 // Make call on bw path.
697 sync_enum_type
698 bw_nb_transport(transaction_type &trans, phase_type &phase,
699 sc_core::sc_time &t)
700 {
701 return base_type::operator -> ()->nb_transport_bw(trans, phase, t);
702 }
703
704 void
705 bw_invalidate_direct_mem_ptr(sc_dt::uint64 s, sc_dt::uint64 e)
706 {
707 base_type::operator -> ()->invalidate_direct_mem_ptr(s, e);
708 }
709
710 // Helper class to handle bw path calls Needed to detect transaction
711 // end when called from b_transport.
712 class bw_process : public tlm::tlm_bw_transport_if<TYPES>
713 {
714 public:
715 bw_process(simple_target_socket_tagged_b *p_own) : m_owner(p_own) {}
716
717 sync_enum_type
718 nb_transport_bw(transaction_type &trans, phase_type &phase,
719 sc_core::sc_time &t)
720 {
721 typename std::map<transaction_type *,
722 sc_core::sc_event *>::iterator it =
723 m_owner->m_pending_trans.find(&trans);
724
725 if (it == m_owner->m_pending_trans.end()) {
726 // Not a blocking call, forward.
727 return m_owner->bw_nb_transport(trans, phase, t);
728 }
729 if (phase == tlm::END_REQ) {
730 m_owner->m_end_request.notify(sc_core::SC_ZERO_TIME);
731 return tlm::TLM_ACCEPTED;
732 }
733 if (phase == tlm::BEGIN_RESP) {
734 if (m_owner->m_current_transaction == &trans) {
735 m_owner->m_end_request.notify(sc_core::SC_ZERO_TIME);
736 }
737 it->second->notify(t);
738 m_owner->m_pending_trans.erase(it);
739 return tlm::TLM_COMPLETED;
740 }
741 m_owner->display_error("invalid phase received");
742 return tlm::TLM_COMPLETED;
743 }
744
745 void
746 invalidate_direct_mem_ptr(sc_dt::uint64 s, sc_dt::uint64 e)
747 {
748 return m_owner->bw_invalidate_direct_mem_ptr(s, e);
749 }
750
751 private:
752 simple_target_socket_tagged_b *m_owner;
753 };
754
755 class fw_process : public tlm::tlm_fw_transport_if<TYPES>,
756 public tlm::tlm_mm_interface
757 {
758 public:
759 typedef sync_enum_type (MODULE::*NBTransportPtr)(
760 int id, transaction_type &, phase_type &,
761 sc_core::sc_time &);
762 typedef void (MODULE::*BTransportPtr)(
763 int id, transaction_type &, sc_core::sc_time &);
764 typedef unsigned int (MODULE::*TransportDbgPtr)(
765 int id, transaction_type &);
766 typedef bool (MODULE::*GetDirectMemPtr)(
767 int id, transaction_type &, tlm::tlm_dmi &);
768
769 fw_process(simple_target_socket_tagged_b *p_own) :
770 m_owner(p_own), m_mod(0), m_nb_transport_ptr(0),
771 m_b_transport_ptr(0), m_transport_dbg_ptr(0),
772 m_get_direct_mem_ptr(0), m_nb_transport_user_id(0),
773 m_b_transport_user_id(0), m_transport_dbg_user_id(0),
774 m_get_dmi_user_id(0),
775 m_peq(sc_core::sc_gen_unique_name("m_peq")),
776 m_response_in_progress(false)
777 {}
778
779 void
780 start_of_simulation()
781 {
782 if (!m_b_transport_ptr && m_nb_transport_ptr) {
783 // Only spawn b2nb_thread if needed.
784 sc_core::sc_spawn_options opts;
785 opts.set_sensitivity(&m_peq.get_event());
786 opts.dont_initialize();
787 sc_core::sc_spawn(sc_bind(&fw_process::b2nb_thread, this),
788 sc_core::sc_gen_unique_name("b2nb_thread"), &opts);
789 }
790 }
791
792 void set_nb_transport_user_id(int id) { m_nb_transport_user_id = id; }
793 void set_b_transport_user_id(int id) { m_b_transport_user_id = id; }
794 void
795 set_transport_dbg_user_id(int id)
796 {
797 m_transport_dbg_user_id = id;
798 }
799 void set_get_dmi_user_id(int id) { m_get_dmi_user_id = id; }
800
801 void
802 set_nb_transport_ptr(MODULE *mod, NBTransportPtr p)
803 {
804 if (m_nb_transport_ptr) {
805 m_owner->display_warning(
806 "non-blocking callback already registered");
807 return;
808 }
809 sc_assert(!m_mod || m_mod == mod);
810 m_mod = mod;
811 m_nb_transport_ptr = p;
812 }
813
814 void
815 set_b_transport_ptr(MODULE* mod, BTransportPtr p)
816 {
817 if (m_b_transport_ptr) {
818 m_owner->display_warning(
819 "blocking callback already registered");
820 return;
821 }
822 sc_assert(!m_mod || m_mod == mod);
823 m_mod = mod;
824 m_b_transport_ptr = p;
825 }
826
827 void
828 set_transport_dbg_ptr(MODULE *mod, TransportDbgPtr p)
829 {
830 if (m_transport_dbg_ptr) {
831 m_owner->display_warning(
832 "debug callback already registered");
833 return;
834 }
835 sc_assert(!m_mod || m_mod == mod);
836 m_mod = mod;
837 m_transport_dbg_ptr = p;
838 }
839
840 void
841 set_get_direct_mem_ptr(MODULE *mod, GetDirectMemPtr p)
842 {
843 if (m_get_direct_mem_ptr) {
844 m_owner->display_warning(
845 "get DMI pointer callback already registered");
846 }
847 sc_assert(!m_mod || m_mod == mod);
848 m_mod = mod;
849 m_get_direct_mem_ptr = p;
850 }
851
852 // Interface implementation.
853 sync_enum_type
854 nb_transport_fw(transaction_type &trans, phase_type &phase,
855 sc_core::sc_time &t)
856 {
857 if (m_nb_transport_ptr) {
858 // Forward call.
859 sc_assert(m_mod);
860 return (m_mod->*m_nb_transport_ptr)(
861 m_nb_transport_user_id, trans, phase, t);
862 }
863
864 // nb->b conversion
865 if (m_b_transport_ptr) {
866 if (phase == tlm::BEGIN_REQ) {
867
868 // Prepare thread to do blocking call.
869 process_handle_class *ph =
870 m_process_handle.get_handle(&trans);
871
872 if (!ph) { // Create new dynamic process.
873 ph = new process_handle_class(&trans);
874 m_process_handle.put_handle(ph);
875
876 sc_core::sc_spawn_options opts;
877 opts.dont_initialize();
878 opts.set_sensitivity(&ph->m_e);
879
880 sc_core::sc_spawn(
881 sc_bind(&fw_process::nb2b_thread, this, ph),
882 sc_core::sc_gen_unique_name("nb2b_thread"),
883 &opts);
884 }
885
886 ph->m_e.notify(t);
887 return tlm::TLM_ACCEPTED;
888 }
889 if (phase == tlm::END_RESP) {
890 m_response_in_progress = false;
891 m_end_response.notify(t);
892 return tlm::TLM_COMPLETED;
893 }
894 m_owner->display_error("invalid phase");
895 return tlm::TLM_COMPLETED;
896 }
897
898 m_owner->display_error(
899 "no non-blocking transport callback registered");
900 return tlm::TLM_COMPLETED;
901 }
902
903 void
904 b_transport(transaction_type &trans, sc_core::sc_time &t)
905 {
906 if (m_b_transport_ptr) {
907 // Forward call.
908 sc_assert(m_mod);
909 (m_mod->*m_b_transport_ptr)(m_b_transport_user_id, trans, t);
910 return;
911 }
912
913 // b->nb conversion
914 if (m_nb_transport_ptr) {
915 m_peq.notify(trans, t);
916 t = sc_core::SC_ZERO_TIME;
917
918 mm_end_event_ext mm_ext;
919 const bool mm_added = !trans.has_mm();
920
921 if (mm_added) {
922 trans.set_mm(this);
923 trans.set_auto_extension(&mm_ext);
924 trans.acquire();
925 }
926
927 // Wait until transaction is finished.
928 sc_core::sc_event end_event;
929 m_owner->m_pending_trans[&trans] = &end_event;
930 sc_core::wait(end_event);
931
932 if (mm_added) {
933 // Release will not delete the transaction, it will
934 // notify mm_ext.done.
935 trans.release();
936 if (trans.get_ref_count()) {
937 sc_core::wait(mm_ext.done);
938 }
939 trans.set_mm(0);
940 }
941 return;
942 }
943
944 m_owner->display_error("no transport callback registered");
945 }
946
947 unsigned int
948 transport_dbg(transaction_type &trans)
949 {
950 if (m_transport_dbg_ptr) {
951 // Forward call.
952 sc_assert(m_mod);
953 return (m_mod->*m_transport_dbg_ptr)(
954 m_transport_dbg_user_id, trans);
955 }
956 // No debug support.
957 return 0;
958 }
959
960 bool
961 get_direct_mem_ptr(transaction_type &trans, tlm::tlm_dmi &dmi_data)
962 {
963 if (m_get_direct_mem_ptr) {
964 // Forward call.
965 sc_assert(m_mod);
966 return (m_mod->*m_get_direct_mem_ptr)(
967 m_get_dmi_user_id, trans, dmi_data);
968 }
969 // No DMI support.
970 dmi_data.allow_read_write();
971 dmi_data.set_start_address(0x0);
972 dmi_data.set_end_address((sc_dt::uint64)-1);
973 return false;
974 }
975
976 private:
977
978 // Dynamic process handler for nb2b conversion.
979 class process_handle_class
980 {
981 public:
982 explicit process_handle_class(transaction_type *trans) :
983 m_trans(trans), m_suspend(false)
984 {}
985
986 transaction_type *m_trans;
987 sc_core::sc_event m_e;
988 bool m_suspend;
989 };
990
991 class process_handle_list
992 {
993 public:
994 process_handle_list() {}
995
996 ~process_handle_list()
997 {
998 for (typename std::vector<
999 process_handle_class *>::iterator it = v.begin(),
1000 end = v.end(); it != end; ++it) {
1001 delete *it;
1002 }
1003 }
1004
1005 process_handle_class *
1006 get_handle(transaction_type *trans)
1007 {
1008 typename std::vector<process_handle_class *>::iterator it;
1009
1010 for (it = v.begin(); it != v.end(); it++) {
1011 if ((*it)->m_suspend) {
1012 // Found suspended dynamic process, re-use it.
1013 (*it)->m_trans = trans; // Replace to new one.
1014 (*it)->m_suspend = false;
1015 return *it;
1016 }
1017 }
1018 return NULL; // No suspended process.
1019 }
1020
1021 void put_handle(process_handle_class *ph) { v.push_back(ph); }
1022
1023 private:
1024 std::vector<process_handle_class *> v;
1025 };
1026
1027 process_handle_list m_process_handle;
1028
1029 void
1030 nb2b_thread(process_handle_class *h)
1031 {
1032
1033 while (1) {
1034 transaction_type *trans = h->m_trans;
1035 sc_core::sc_time t = sc_core::SC_ZERO_TIME;
1036
1037 // Forward call.
1038 sc_assert(m_mod);
1039 (m_mod->*m_b_transport_ptr)(
1040 m_b_transport_user_id, *trans, t);
1041
1042 sc_core::wait(t);
1043
1044 // Return path.
1045 while (m_response_in_progress) {
1046 sc_core::wait(m_end_response);
1047 }
1048 t = sc_core::SC_ZERO_TIME;
1049 phase_type phase = tlm::BEGIN_RESP;
1050 sync_enum_type sync =
1051 m_owner->bw_nb_transport(*trans, phase, t);
1052 if (!(sync == tlm::TLM_COMPLETED ||
1053 (sync == tlm::TLM_UPDATED &&
1054 phase == tlm::END_RESP))) {
1055 m_response_in_progress = true;
1056 }
1057
1058 // Suspend until next transaction.
1059 h->m_suspend = true;
1060 sc_core::wait();
1061 }
1062 }
1063
1064 void
1065 b2nb_thread()
1066 {
1067 while (true) {
1068 transaction_type *trans;
1069 while ((trans = m_peq.get_next_transaction()) != 0) {
1070 sc_assert(m_mod);
1071 sc_assert(m_nb_transport_ptr);
1072 phase_type phase = tlm::BEGIN_REQ;
1073 sc_core::sc_time t = sc_core::SC_ZERO_TIME;
1074
1075 switch ((m_mod->*m_nb_transport_ptr)(
1076 m_nb_transport_user_id, *trans, phase, t)) {
1077 case tlm::TLM_COMPLETED:
1078 {
1079 // Notify transaction is finished.
1080 typename std::map<transaction_type *,
1081 sc_core::sc_event *>::iterator it =
1082 m_owner->m_pending_trans.find(trans);
1083 sc_assert(it != m_owner->m_pending_trans.end());
1084 it->second->notify(t);
1085 m_owner->m_pending_trans.erase(it);
1086 break;
1087 }
1088
1089 case tlm::TLM_ACCEPTED:
1090 case tlm::TLM_UPDATED:
1091 switch (phase) {
1092 case tlm::BEGIN_REQ:
1093 m_owner->m_current_transaction = trans;
1094 sc_core::wait(m_owner->m_end_request);
1095 m_owner->m_current_transaction = 0;
1096 break;
1097
1098 case tlm::END_REQ:
1099 sc_core::wait(t);
1100 break;
1101
1102 case tlm::BEGIN_RESP:
1103 {
1104 phase = tlm::END_RESP;
1105 // This line is a bug fix added in TLM-2.0.2.
1106 sc_core::wait(t);
1107 t = sc_core::SC_ZERO_TIME;
1108 (m_mod->*m_nb_transport_ptr)(
1109 m_nb_transport_user_id,
1110 *trans, phase, t);
1111
1112 // Notify transaction is finished.
1113 typename std::map<transaction_type *,
1114 sc_core::sc_event *>::iterator it =
1115 m_owner->m_pending_trans.find(
1116 trans);
1117 sc_assert(it !=
1118 m_owner->m_pending_trans.end());
1119 it->second->notify(t);
1120 m_owner->m_pending_trans.erase(it);
1121 break;
1122 }
1123
1124 default:
1125 m_owner->display_error("invalid phase received");
1126 };
1127 break;
1128
1129 default:
1130 m_owner->display_error("invalid sync value received");
1131 }
1132 }
1133 sc_core::wait();
1134 }
1135 }
1136
1137 void
1138 free(tlm::tlm_generic_payload *trans)
1139 {
1140 mm_end_event_ext *ext =
1141 trans->template get_extension<mm_end_event_ext>();
1142 sc_assert(ext);
1143 // Notify event first before freeing extensions (reset).
1144 ext->done.notify();
1145 trans->reset();
1146 }
1147
1148 private:
1149 struct mm_end_event_ext : public tlm::tlm_extension<mm_end_event_ext>
1150 {
1151 tlm::tlm_extension_base *clone() const { return NULL; }
1152 void free() {}
1153 void copy_from(tlm::tlm_extension_base const &) {}
1154 sc_core::sc_event done;
1155 };
1156
1157 private:
1158 simple_target_socket_tagged_b *m_owner;
1159 MODULE *m_mod;
1160 NBTransportPtr m_nb_transport_ptr;
1161 BTransportPtr m_b_transport_ptr;
1162 TransportDbgPtr m_transport_dbg_ptr;
1163 GetDirectMemPtr m_get_direct_mem_ptr;
1164 int m_nb_transport_user_id;
1165 int m_b_transport_user_id;
1166 int m_transport_dbg_user_id;
1167 int m_get_dmi_user_id;
1168 peq_with_get<transaction_type> m_peq;
1169 bool m_response_in_progress;
1170 sc_core::sc_event m_end_response;
1171 };
1172
1173 private:
1174 const sc_core::sc_object *get_socket() const { return this; }
1175
1176 private:
1177 fw_process m_fw_process;
1178 bw_process m_bw_process;
1179 std::map<transaction_type *, sc_core::sc_event *> m_pending_trans;
1180 sc_core::sc_event m_end_request;
1181 transaction_type* m_current_transaction;
1182};
1183
1184template <typename MODULE, unsigned int BUSWIDTH=32,
1185 typename TYPES=tlm::tlm_base_protocol_types>
1186class simple_target_socket_tagged :
1187 public simple_target_socket_tagged_b<MODULE, BUSWIDTH, TYPES>
1188{
1189 typedef simple_target_socket_tagged_b<MODULE, BUSWIDTH, TYPES> socket_b;
1190 public:
1191 simple_target_socket_tagged() : socket_b() {}
1192 explicit simple_target_socket_tagged(const char *name) : socket_b(name) {}
1193};
1194
1195template <typename MODULE, unsigned int BUSWIDTH=32,
1196 typename TYPES=tlm::tlm_base_protocol_types>
1197class simple_target_socket_tagged_optional :
1198 public simple_target_socket_tagged_b<MODULE, BUSWIDTH, TYPES,
1199 sc_core::SC_ZERO_OR_MORE_BOUND>
1200{
1201 typedef simple_target_socket_tagged_b<
1202 MODULE, BUSWIDTH, TYPES, sc_core::SC_ZERO_OR_MORE_BOUND> socket_b;
1203 public:
1204 simple_target_socket_tagged_optional() : socket_b() {}
1205 explicit simple_target_socket_tagged_optional(const char *name) :
1206 socket_b(name)
1207 {}
1208};
1209
1210} // namespace tlm_utils
1211
1212#endif /* __SYSTEMC_EXT_TLM_UTILS_SIMPLE_TARGET_SOCKET_H__ */