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