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