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