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