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