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__ */
|