simple_target_socket.h (13513:bbf275465d3d) simple_target_socket.h (13586:008fe87c1ad4)
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
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>
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"
25
32
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__ */
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__ */