simple_target_socket.h revision 13511
113511Sgabeblack@google.com/***************************************************************************** 213511Sgabeblack@google.com 313511Sgabeblack@google.com Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 413511Sgabeblack@google.com more contributor license agreements. See the NOTICE file distributed 513511Sgabeblack@google.com with this work for additional information regarding copyright ownership. 613511Sgabeblack@google.com Accellera licenses this file to you under the Apache License, Version 2.0 713511Sgabeblack@google.com (the "License"); you may not use this file except in compliance with the 813511Sgabeblack@google.com License. You may obtain a copy of the License at 913511Sgabeblack@google.com 1013511Sgabeblack@google.com http://www.apache.org/licenses/LICENSE-2.0 1113511Sgabeblack@google.com 1213511Sgabeblack@google.com Unless required by applicable law or agreed to in writing, software 1313511Sgabeblack@google.com distributed under the License is distributed on an "AS IS" BASIS, 1413511Sgabeblack@google.com WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 1513511Sgabeblack@google.com implied. See the License for the specific language governing 1613511Sgabeblack@google.com permissions and limitations under the License. 1713511Sgabeblack@google.com 1813511Sgabeblack@google.com *****************************************************************************/ 1913511Sgabeblack@google.com 2013511Sgabeblack@google.com// ***************************************************************************** 2113511Sgabeblack@google.com// Modified by John Aynsley, Doulos, Feb 2009, 2213511Sgabeblack@google.com// Fix a bug in simple_target_socket and simple_target_socket_tagged 2313511Sgabeblack@google.com// with the addition of one new line of code in each: wait(*e); 2413511Sgabeblack@google.com// ***************************************************************************** 2513511Sgabeblack@google.com 2613511Sgabeblack@google.com// ***************************************************************************** 2713511Sgabeblack@google.com// Modified by John Aynsley on behalf of Robert Guenzel, May 2011, 2813511Sgabeblack@google.com// Fix a bug in simple_target_socket and simple_target_socket_tagged 2913511Sgabeblack@google.com// with the addition of one new line of code in each: wait(t); 3013511Sgabeblack@google.com// ***************************************************************************** 3113511Sgabeblack@google.com 3213511Sgabeblack@google.com 3313511Sgabeblack@google.com#ifndef TLM_UTILS_SIMPLE_TARGET_SOCKET_H_INCLUDED_ 3413511Sgabeblack@google.com#define TLM_UTILS_SIMPLE_TARGET_SOCKET_H_INCLUDED_ 3513511Sgabeblack@google.com 3613511Sgabeblack@google.com#ifndef SC_INCLUDE_DYNAMIC_PROCESSES // needed for sc_spawn 3713511Sgabeblack@google.com# define SC_INCLUDE_DYNAMIC_PROCESSES 3813511Sgabeblack@google.com#endif 3913511Sgabeblack@google.com 4013511Sgabeblack@google.com#include <systemc> 4113511Sgabeblack@google.com#include <tlm> 4213511Sgabeblack@google.com#include "tlm_utils/convenience_socket_bases.h" 4313511Sgabeblack@google.com#include "tlm_utils/peq_with_get.h" 4413511Sgabeblack@google.com 4513511Sgabeblack@google.comnamespace tlm_utils { 4613511Sgabeblack@google.com 4713511Sgabeblack@google.comtemplate< typename MODULE, unsigned int BUSWIDTH, typename TYPES 4813511Sgabeblack@google.com , sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND > 4913511Sgabeblack@google.comclass simple_target_socket_b 5013511Sgabeblack@google.com : public tlm::tlm_target_socket<BUSWIDTH, TYPES, 1, POL> 5113511Sgabeblack@google.com , protected simple_socket_base 5213511Sgabeblack@google.com{ 5313511Sgabeblack@google.com friend class fw_process; 5413511Sgabeblack@google.com friend class bw_process; 5513511Sgabeblack@google.compublic: 5613511Sgabeblack@google.com typedef typename TYPES::tlm_payload_type transaction_type; 5713511Sgabeblack@google.com typedef typename TYPES::tlm_phase_type phase_type; 5813511Sgabeblack@google.com typedef tlm::tlm_sync_enum sync_enum_type; 5913511Sgabeblack@google.com typedef tlm::tlm_fw_transport_if<TYPES> fw_interface_type; 6013511Sgabeblack@google.com typedef tlm::tlm_bw_transport_if<TYPES> bw_interface_type; 6113511Sgabeblack@google.com typedef tlm::tlm_target_socket<BUSWIDTH,TYPES,1,POL> base_type; 6213511Sgabeblack@google.com 6313511Sgabeblack@google.compublic: 6413511Sgabeblack@google.com static const char* default_name() 6513511Sgabeblack@google.com { return sc_core::sc_gen_unique_name("simple_target_socket"); } 6613511Sgabeblack@google.com 6713511Sgabeblack@google.com explicit simple_target_socket_b(const char* n = default_name()) 6813511Sgabeblack@google.com : base_type(n) 6913511Sgabeblack@google.com , m_fw_process(this) 7013511Sgabeblack@google.com , m_bw_process(this) 7113511Sgabeblack@google.com { 7213511Sgabeblack@google.com bind(m_fw_process); 7313511Sgabeblack@google.com } 7413511Sgabeblack@google.com 7513511Sgabeblack@google.com using base_type::bind; 7613511Sgabeblack@google.com 7713511Sgabeblack@google.com // bw transport must come thru us. 7813511Sgabeblack@google.com tlm::tlm_bw_transport_if<TYPES> * operator ->() {return &m_bw_process;} 7913511Sgabeblack@google.com 8013511Sgabeblack@google.com // REGISTER_XXX 8113511Sgabeblack@google.com void register_nb_transport_fw(MODULE* mod, 8213511Sgabeblack@google.com sync_enum_type (MODULE::*cb)(transaction_type&, 8313511Sgabeblack@google.com phase_type&, 8413511Sgabeblack@google.com sc_core::sc_time&)) 8513511Sgabeblack@google.com { 8613511Sgabeblack@google.com elaboration_check("register_nb_transport_fw"); 8713511Sgabeblack@google.com m_fw_process.set_nb_transport_ptr(mod, cb); 8813511Sgabeblack@google.com } 8913511Sgabeblack@google.com 9013511Sgabeblack@google.com void register_b_transport(MODULE* mod, 9113511Sgabeblack@google.com void (MODULE::*cb)(transaction_type&, 9213511Sgabeblack@google.com sc_core::sc_time&)) 9313511Sgabeblack@google.com { 9413511Sgabeblack@google.com elaboration_check("register_b_transport"); 9513511Sgabeblack@google.com m_fw_process.set_b_transport_ptr(mod, cb); 9613511Sgabeblack@google.com } 9713511Sgabeblack@google.com 9813511Sgabeblack@google.com void register_transport_dbg(MODULE* mod, 9913511Sgabeblack@google.com unsigned int (MODULE::*cb)(transaction_type&)) 10013511Sgabeblack@google.com { 10113511Sgabeblack@google.com elaboration_check("register_transport_dbg"); 10213511Sgabeblack@google.com m_fw_process.set_transport_dbg_ptr(mod, cb); 10313511Sgabeblack@google.com } 10413511Sgabeblack@google.com 10513511Sgabeblack@google.com void register_get_direct_mem_ptr(MODULE* mod, 10613511Sgabeblack@google.com bool (MODULE::*cb)(transaction_type&, 10713511Sgabeblack@google.com tlm::tlm_dmi&)) 10813511Sgabeblack@google.com { 10913511Sgabeblack@google.com elaboration_check("register_get_direct_mem_ptr"); 11013511Sgabeblack@google.com m_fw_process.set_get_direct_mem_ptr(mod, cb); 11113511Sgabeblack@google.com } 11213511Sgabeblack@google.com 11313511Sgabeblack@google.comprotected: 11413511Sgabeblack@google.com void start_of_simulation() 11513511Sgabeblack@google.com { 11613511Sgabeblack@google.com base_type::start_of_simulation(); 11713511Sgabeblack@google.com m_fw_process.start_of_simulation(); 11813511Sgabeblack@google.com } 11913511Sgabeblack@google.com 12013511Sgabeblack@google.comprivate: 12113511Sgabeblack@google.com //make call on bw path. 12213511Sgabeblack@google.com sync_enum_type bw_nb_transport(transaction_type &trans, phase_type &phase, sc_core::sc_time &t) 12313511Sgabeblack@google.com { 12413511Sgabeblack@google.com return base_type::operator ->()->nb_transport_bw(trans, phase, t); 12513511Sgabeblack@google.com } 12613511Sgabeblack@google.com 12713511Sgabeblack@google.com void bw_invalidate_direct_mem_ptr(sc_dt::uint64 s,sc_dt::uint64 e) 12813511Sgabeblack@google.com { 12913511Sgabeblack@google.com base_type::operator ->()->invalidate_direct_mem_ptr(s, e); 13013511Sgabeblack@google.com } 13113511Sgabeblack@google.com 13213511Sgabeblack@google.com //Helper class to handle bw path calls 13313511Sgabeblack@google.com // Needed to detect transaction end when called from b_transport. 13413511Sgabeblack@google.com class bw_process : public tlm::tlm_bw_transport_if<TYPES> 13513511Sgabeblack@google.com { 13613511Sgabeblack@google.com public: 13713511Sgabeblack@google.com bw_process(simple_target_socket_b *p_own) : m_owner(p_own) 13813511Sgabeblack@google.com { 13913511Sgabeblack@google.com } 14013511Sgabeblack@google.com 14113511Sgabeblack@google.com sync_enum_type nb_transport_bw(transaction_type &trans, phase_type &phase, sc_core::sc_time &t) 14213511Sgabeblack@google.com { 14313511Sgabeblack@google.com typename std::map<transaction_type*, sc_core::sc_event *>::iterator it = 14413511Sgabeblack@google.com m_owner->m_pending_trans.find(&trans); 14513511Sgabeblack@google.com 14613511Sgabeblack@google.com if(it == m_owner->m_pending_trans.end()) { 14713511Sgabeblack@google.com // Not a blocking call, forward. 14813511Sgabeblack@google.com return m_owner->bw_nb_transport(trans, phase, t); 14913511Sgabeblack@google.com 15013511Sgabeblack@google.com } 15113511Sgabeblack@google.com 15213511Sgabeblack@google.com if (phase == tlm::END_REQ) { 15313511Sgabeblack@google.com m_owner->m_end_request.notify(sc_core::SC_ZERO_TIME); 15413511Sgabeblack@google.com return tlm::TLM_ACCEPTED; 15513511Sgabeblack@google.com } 15613511Sgabeblack@google.com if (phase == tlm::BEGIN_RESP) { 15713511Sgabeblack@google.com if (m_owner->m_current_transaction == &trans) { 15813511Sgabeblack@google.com m_owner->m_end_request.notify(sc_core::SC_ZERO_TIME); 15913511Sgabeblack@google.com } 16013511Sgabeblack@google.com //TODO: add response-accept delay? 16113511Sgabeblack@google.com it->second->notify(t); 16213511Sgabeblack@google.com m_owner->m_pending_trans.erase(it); 16313511Sgabeblack@google.com return tlm::TLM_COMPLETED; 16413511Sgabeblack@google.com } 16513511Sgabeblack@google.com m_owner->display_error("invalid phase received"); 16613511Sgabeblack@google.com return tlm::TLM_COMPLETED; 16713511Sgabeblack@google.com } 16813511Sgabeblack@google.com 16913511Sgabeblack@google.com void invalidate_direct_mem_ptr(sc_dt::uint64 s,sc_dt::uint64 e) 17013511Sgabeblack@google.com { 17113511Sgabeblack@google.com return m_owner->bw_invalidate_direct_mem_ptr(s, e); 17213511Sgabeblack@google.com } 17313511Sgabeblack@google.com 17413511Sgabeblack@google.com private: 17513511Sgabeblack@google.com simple_target_socket_b *m_owner; 17613511Sgabeblack@google.com }; 17713511Sgabeblack@google.com 17813511Sgabeblack@google.com class fw_process : public tlm::tlm_fw_transport_if<TYPES>, 17913511Sgabeblack@google.com public tlm::tlm_mm_interface 18013511Sgabeblack@google.com { 18113511Sgabeblack@google.com public: 18213511Sgabeblack@google.com typedef sync_enum_type (MODULE::*NBTransportPtr)(transaction_type&, 18313511Sgabeblack@google.com phase_type&, 18413511Sgabeblack@google.com sc_core::sc_time&); 18513511Sgabeblack@google.com typedef void (MODULE::*BTransportPtr)(transaction_type&, 18613511Sgabeblack@google.com sc_core::sc_time&); 18713511Sgabeblack@google.com typedef unsigned int (MODULE::*TransportDbgPtr)(transaction_type&); 18813511Sgabeblack@google.com typedef bool (MODULE::*GetDirectMemPtr)(transaction_type&, 18913511Sgabeblack@google.com tlm::tlm_dmi&); 19013511Sgabeblack@google.com 19113511Sgabeblack@google.com fw_process(simple_target_socket_b *p_own) : 19213511Sgabeblack@google.com m_owner(p_own), 19313511Sgabeblack@google.com m_mod(0), 19413511Sgabeblack@google.com m_nb_transport_ptr(0), 19513511Sgabeblack@google.com m_b_transport_ptr(0), 19613511Sgabeblack@google.com m_transport_dbg_ptr(0), 19713511Sgabeblack@google.com m_get_direct_mem_ptr(0), 19813511Sgabeblack@google.com m_peq(sc_core::sc_gen_unique_name("m_peq")), 19913511Sgabeblack@google.com m_response_in_progress(false) 20013511Sgabeblack@google.com {} 20113511Sgabeblack@google.com 20213511Sgabeblack@google.com void start_of_simulation() 20313511Sgabeblack@google.com { 20413511Sgabeblack@google.com if (!m_b_transport_ptr && m_nb_transport_ptr) { // only spawn b2nb_thread, if needed 20513511Sgabeblack@google.com sc_core::sc_spawn_options opts; 20613511Sgabeblack@google.com opts.set_sensitivity(&m_peq.get_event()); 20713511Sgabeblack@google.com opts.dont_initialize(); 20813511Sgabeblack@google.com sc_core::sc_spawn(sc_bind(&fw_process::b2nb_thread, this), 20913511Sgabeblack@google.com sc_core::sc_gen_unique_name("b2nb_thread"), &opts); 21013511Sgabeblack@google.com } 21113511Sgabeblack@google.com } 21213511Sgabeblack@google.com 21313511Sgabeblack@google.com void set_nb_transport_ptr(MODULE* mod, NBTransportPtr p) 21413511Sgabeblack@google.com { 21513511Sgabeblack@google.com if (m_nb_transport_ptr) { 21613511Sgabeblack@google.com m_owner->display_warning("non-blocking callback already registered"); 21713511Sgabeblack@google.com return; 21813511Sgabeblack@google.com } 21913511Sgabeblack@google.com sc_assert(!m_mod || m_mod == mod); 22013511Sgabeblack@google.com m_mod = mod; 22113511Sgabeblack@google.com m_nb_transport_ptr = p; 22213511Sgabeblack@google.com } 22313511Sgabeblack@google.com 22413511Sgabeblack@google.com void set_b_transport_ptr(MODULE* mod, BTransportPtr p) 22513511Sgabeblack@google.com { 22613511Sgabeblack@google.com if (m_b_transport_ptr) { 22713511Sgabeblack@google.com m_owner->display_warning("blocking callback already registered"); 22813511Sgabeblack@google.com return; 22913511Sgabeblack@google.com } 23013511Sgabeblack@google.com sc_assert(!m_mod || m_mod == mod); 23113511Sgabeblack@google.com m_mod = mod; 23213511Sgabeblack@google.com m_b_transport_ptr = p; 23313511Sgabeblack@google.com } 23413511Sgabeblack@google.com 23513511Sgabeblack@google.com void set_transport_dbg_ptr(MODULE* mod, TransportDbgPtr p) 23613511Sgabeblack@google.com { 23713511Sgabeblack@google.com if (m_transport_dbg_ptr) { 23813511Sgabeblack@google.com m_owner->display_warning("debug callback already registered"); 23913511Sgabeblack@google.com return; 24013511Sgabeblack@google.com } 24113511Sgabeblack@google.com sc_assert(!m_mod || m_mod == mod); 24213511Sgabeblack@google.com m_mod = mod; 24313511Sgabeblack@google.com m_transport_dbg_ptr = p; 24413511Sgabeblack@google.com } 24513511Sgabeblack@google.com 24613511Sgabeblack@google.com void set_get_direct_mem_ptr(MODULE* mod, GetDirectMemPtr p) 24713511Sgabeblack@google.com { 24813511Sgabeblack@google.com if (m_get_direct_mem_ptr) { 24913511Sgabeblack@google.com m_owner->display_warning("get DMI pointer callback already registered"); 25013511Sgabeblack@google.com return; 25113511Sgabeblack@google.com } 25213511Sgabeblack@google.com sc_assert(!m_mod || m_mod == mod); 25313511Sgabeblack@google.com m_mod = mod; 25413511Sgabeblack@google.com m_get_direct_mem_ptr = p; 25513511Sgabeblack@google.com } 25613511Sgabeblack@google.com// Interface implementation 25713511Sgabeblack@google.com sync_enum_type nb_transport_fw(transaction_type& trans, 25813511Sgabeblack@google.com phase_type& phase, 25913511Sgabeblack@google.com sc_core::sc_time& t) 26013511Sgabeblack@google.com { 26113511Sgabeblack@google.com if (m_nb_transport_ptr) { 26213511Sgabeblack@google.com // forward call 26313511Sgabeblack@google.com sc_assert(m_mod); 26413511Sgabeblack@google.com return (m_mod->*m_nb_transport_ptr)(trans, phase, t); 26513511Sgabeblack@google.com } 26613511Sgabeblack@google.com 26713511Sgabeblack@google.com // nb->b conversion 26813511Sgabeblack@google.com if (m_b_transport_ptr) { 26913511Sgabeblack@google.com if (phase == tlm::BEGIN_REQ) { 27013511Sgabeblack@google.com // prepare thread to do blocking call 27113511Sgabeblack@google.com process_handle_class * ph = m_process_handle.get_handle(&trans); 27213511Sgabeblack@google.com 27313511Sgabeblack@google.com if (!ph) { // create new dynamic process 27413511Sgabeblack@google.com ph = new process_handle_class(&trans); 27513511Sgabeblack@google.com m_process_handle.put_handle(ph); 27613511Sgabeblack@google.com 27713511Sgabeblack@google.com sc_core::sc_spawn_options opts; 27813511Sgabeblack@google.com opts.dont_initialize(); 27913511Sgabeblack@google.com opts.set_sensitivity(&ph->m_e); 28013511Sgabeblack@google.com 28113511Sgabeblack@google.com sc_core::sc_spawn(sc_bind(&fw_process::nb2b_thread,this, ph), 28213511Sgabeblack@google.com sc_core::sc_gen_unique_name("nb2b_thread"), &opts); 28313511Sgabeblack@google.com } 28413511Sgabeblack@google.com 28513511Sgabeblack@google.com ph->m_e.notify(t); 28613511Sgabeblack@google.com return tlm::TLM_ACCEPTED; 28713511Sgabeblack@google.com } 28813511Sgabeblack@google.com if (phase == tlm::END_RESP) { 28913511Sgabeblack@google.com m_response_in_progress = false; 29013511Sgabeblack@google.com m_end_response.notify(t); 29113511Sgabeblack@google.com return tlm::TLM_COMPLETED; 29213511Sgabeblack@google.com } 29313511Sgabeblack@google.com m_owner->display_error("invalid phase received"); 29413511Sgabeblack@google.com return tlm::TLM_COMPLETED; 29513511Sgabeblack@google.com } 29613511Sgabeblack@google.com m_owner->display_error("no non-blocking transport callback registered"); 29713511Sgabeblack@google.com return tlm::TLM_COMPLETED; 29813511Sgabeblack@google.com } 29913511Sgabeblack@google.com 30013511Sgabeblack@google.com void b_transport(transaction_type& trans, sc_core::sc_time& t) 30113511Sgabeblack@google.com { 30213511Sgabeblack@google.com if (m_b_transport_ptr) { 30313511Sgabeblack@google.com // forward call 30413511Sgabeblack@google.com sc_assert(m_mod); 30513511Sgabeblack@google.com (m_mod->*m_b_transport_ptr)(trans, t); 30613511Sgabeblack@google.com return; 30713511Sgabeblack@google.com } 30813511Sgabeblack@google.com 30913511Sgabeblack@google.com // b->nb conversion 31013511Sgabeblack@google.com if (m_nb_transport_ptr) { 31113511Sgabeblack@google.com m_peq.notify(trans, t); 31213511Sgabeblack@google.com t = sc_core::SC_ZERO_TIME; 31313511Sgabeblack@google.com 31413511Sgabeblack@google.com mm_end_event_ext mm_ext; 31513511Sgabeblack@google.com const bool mm_added = !trans.has_mm(); 31613511Sgabeblack@google.com 31713511Sgabeblack@google.com if (mm_added) { 31813511Sgabeblack@google.com trans.set_mm(this); 31913511Sgabeblack@google.com trans.set_auto_extension(&mm_ext); 32013511Sgabeblack@google.com trans.acquire(); 32113511Sgabeblack@google.com } 32213511Sgabeblack@google.com 32313511Sgabeblack@google.com // wait until transaction is finished 32413511Sgabeblack@google.com sc_core::sc_event end_event; 32513511Sgabeblack@google.com m_owner->m_pending_trans[&trans] = &end_event; 32613511Sgabeblack@google.com sc_core::wait(end_event); 32713511Sgabeblack@google.com 32813511Sgabeblack@google.com if (mm_added) { 32913511Sgabeblack@google.com // release will not delete the transaction, it will notify mm_ext.done 33013511Sgabeblack@google.com trans.release(); 33113511Sgabeblack@google.com if (trans.get_ref_count()) { 33213511Sgabeblack@google.com sc_core::wait(mm_ext.done); 33313511Sgabeblack@google.com } 33413511Sgabeblack@google.com trans.set_mm(0); 33513511Sgabeblack@google.com } 33613511Sgabeblack@google.com return; 33713511Sgabeblack@google.com } 33813511Sgabeblack@google.com 33913511Sgabeblack@google.com // should not be reached 34013511Sgabeblack@google.com m_owner->display_error("no blocking transport callback registered"); 34113511Sgabeblack@google.com } 34213511Sgabeblack@google.com 34313511Sgabeblack@google.com unsigned int transport_dbg(transaction_type& trans) 34413511Sgabeblack@google.com { 34513511Sgabeblack@google.com if (m_transport_dbg_ptr) { 34613511Sgabeblack@google.com // forward call 34713511Sgabeblack@google.com sc_assert(m_mod); 34813511Sgabeblack@google.com return (m_mod->*m_transport_dbg_ptr)(trans); 34913511Sgabeblack@google.com } 35013511Sgabeblack@google.com // No debug support 35113511Sgabeblack@google.com return 0; 35213511Sgabeblack@google.com } 35313511Sgabeblack@google.com 35413511Sgabeblack@google.com bool get_direct_mem_ptr(transaction_type& trans, 35513511Sgabeblack@google.com tlm::tlm_dmi& dmi_data) 35613511Sgabeblack@google.com { 35713511Sgabeblack@google.com if (m_get_direct_mem_ptr) { 35813511Sgabeblack@google.com // forward call 35913511Sgabeblack@google.com sc_assert(m_mod); 36013511Sgabeblack@google.com return (m_mod->*m_get_direct_mem_ptr)(trans, dmi_data); 36113511Sgabeblack@google.com } 36213511Sgabeblack@google.com // No DMI support 36313511Sgabeblack@google.com dmi_data.allow_read_write(); 36413511Sgabeblack@google.com dmi_data.set_start_address(0x0); 36513511Sgabeblack@google.com dmi_data.set_end_address((sc_dt::uint64)-1); 36613511Sgabeblack@google.com return false; 36713511Sgabeblack@google.com } 36813511Sgabeblack@google.com 36913511Sgabeblack@google.com private: 37013511Sgabeblack@google.com 37113511Sgabeblack@google.com// dynamic process handler for nb2b conversion 37213511Sgabeblack@google.com 37313511Sgabeblack@google.com class process_handle_class { 37413511Sgabeblack@google.com public: 37513511Sgabeblack@google.com explicit process_handle_class(transaction_type * trans) 37613511Sgabeblack@google.com : m_trans(trans),m_suspend(false) {} 37713511Sgabeblack@google.com 37813511Sgabeblack@google.com transaction_type* m_trans; 37913511Sgabeblack@google.com sc_core::sc_event m_e; 38013511Sgabeblack@google.com bool m_suspend; 38113511Sgabeblack@google.com }; 38213511Sgabeblack@google.com 38313511Sgabeblack@google.com class process_handle_list { 38413511Sgabeblack@google.com public: 38513511Sgabeblack@google.com process_handle_list() {} 38613511Sgabeblack@google.com 38713511Sgabeblack@google.com ~process_handle_list() { 38813511Sgabeblack@google.com for( typename std::vector<process_handle_class*>::iterator 38913511Sgabeblack@google.com it=v.begin(), end = v.end(); it != end; ++it ) 39013511Sgabeblack@google.com delete *it; 39113511Sgabeblack@google.com } 39213511Sgabeblack@google.com 39313511Sgabeblack@google.com process_handle_class* get_handle(transaction_type *trans) 39413511Sgabeblack@google.com { 39513511Sgabeblack@google.com typename std::vector<process_handle_class*>::iterator it; 39613511Sgabeblack@google.com 39713511Sgabeblack@google.com for(it = v.begin(); it != v.end(); it++) { 39813511Sgabeblack@google.com if ((*it)->m_suspend) { // found suspended dynamic process, re-use it 39913511Sgabeblack@google.com (*it)->m_trans = trans; // replace to new one 40013511Sgabeblack@google.com (*it)->m_suspend = false; 40113511Sgabeblack@google.com return *it; 40213511Sgabeblack@google.com } 40313511Sgabeblack@google.com } 40413511Sgabeblack@google.com return NULL; // no suspended process 40513511Sgabeblack@google.com } 40613511Sgabeblack@google.com 40713511Sgabeblack@google.com void put_handle(process_handle_class* ph) 40813511Sgabeblack@google.com { 40913511Sgabeblack@google.com v.push_back(ph); 41013511Sgabeblack@google.com } 41113511Sgabeblack@google.com 41213511Sgabeblack@google.com private: 41313511Sgabeblack@google.com std::vector<process_handle_class*> v; 41413511Sgabeblack@google.com }; 41513511Sgabeblack@google.com 41613511Sgabeblack@google.com process_handle_list m_process_handle; 41713511Sgabeblack@google.com 41813511Sgabeblack@google.com 41913511Sgabeblack@google.com void nb2b_thread(process_handle_class* h) 42013511Sgabeblack@google.com { 42113511Sgabeblack@google.com 42213511Sgabeblack@google.com while(1) { 42313511Sgabeblack@google.com transaction_type *trans = h->m_trans; 42413511Sgabeblack@google.com sc_core::sc_time t = sc_core::SC_ZERO_TIME; 42513511Sgabeblack@google.com 42613511Sgabeblack@google.com // forward call 42713511Sgabeblack@google.com sc_assert(m_mod); 42813511Sgabeblack@google.com (m_mod->*m_b_transport_ptr)(*trans, t); 42913511Sgabeblack@google.com 43013511Sgabeblack@google.com sc_core::wait(t); 43113511Sgabeblack@google.com 43213511Sgabeblack@google.com // return path 43313511Sgabeblack@google.com while (m_response_in_progress) { 43413511Sgabeblack@google.com sc_core::wait(m_end_response); 43513511Sgabeblack@google.com } 43613511Sgabeblack@google.com t = sc_core::SC_ZERO_TIME; 43713511Sgabeblack@google.com phase_type phase = tlm::BEGIN_RESP; 43813511Sgabeblack@google.com sync_enum_type sync = m_owner->bw_nb_transport(*trans, phase, t); 43913511Sgabeblack@google.com if ( !(sync == tlm::TLM_COMPLETED || 44013511Sgabeblack@google.com (sync == tlm::TLM_UPDATED && phase == tlm::END_RESP)) ) { 44113511Sgabeblack@google.com m_response_in_progress = true; 44213511Sgabeblack@google.com } 44313511Sgabeblack@google.com 44413511Sgabeblack@google.com // suspend until next transaction 44513511Sgabeblack@google.com h->m_suspend = true; 44613511Sgabeblack@google.com sc_core::wait(); 44713511Sgabeblack@google.com } 44813511Sgabeblack@google.com } 44913511Sgabeblack@google.com 45013511Sgabeblack@google.com void b2nb_thread() 45113511Sgabeblack@google.com { 45213511Sgabeblack@google.com while (true) { 45313511Sgabeblack@google.com transaction_type* trans; 45413511Sgabeblack@google.com while ((trans = m_peq.get_next_transaction())!=0) { 45513511Sgabeblack@google.com sc_assert(m_mod); 45613511Sgabeblack@google.com sc_assert(m_nb_transport_ptr); 45713511Sgabeblack@google.com phase_type phase = tlm::BEGIN_REQ; 45813511Sgabeblack@google.com sc_core::sc_time t = sc_core::SC_ZERO_TIME; 45913511Sgabeblack@google.com 46013511Sgabeblack@google.com switch ((m_mod->*m_nb_transport_ptr)(*trans, phase, t)) { 46113511Sgabeblack@google.com case tlm::TLM_COMPLETED: 46213511Sgabeblack@google.com { 46313511Sgabeblack@google.com // notify transaction is finished 46413511Sgabeblack@google.com typename std::map<transaction_type*, sc_core::sc_event *>::iterator it = 46513511Sgabeblack@google.com m_owner->m_pending_trans.find(trans); 46613511Sgabeblack@google.com sc_assert(it != m_owner->m_pending_trans.end()); 46713511Sgabeblack@google.com it->second->notify(t); 46813511Sgabeblack@google.com m_owner->m_pending_trans.erase(it); 46913511Sgabeblack@google.com break; 47013511Sgabeblack@google.com } 47113511Sgabeblack@google.com 47213511Sgabeblack@google.com case tlm::TLM_ACCEPTED: 47313511Sgabeblack@google.com case tlm::TLM_UPDATED: 47413511Sgabeblack@google.com switch (phase) { 47513511Sgabeblack@google.com case tlm::BEGIN_REQ: 47613511Sgabeblack@google.com m_owner->m_current_transaction = trans; 47713511Sgabeblack@google.com sc_core::wait(m_owner->m_end_request); 47813511Sgabeblack@google.com m_owner->m_current_transaction = 0; 47913511Sgabeblack@google.com break; 48013511Sgabeblack@google.com 48113511Sgabeblack@google.com case tlm::END_REQ: 48213511Sgabeblack@google.com sc_core::wait(t); 48313511Sgabeblack@google.com break; 48413511Sgabeblack@google.com 48513511Sgabeblack@google.com case tlm::BEGIN_RESP: 48613511Sgabeblack@google.com { 48713511Sgabeblack@google.com phase = tlm::END_RESP; 48813511Sgabeblack@google.com sc_core::wait(t); // This line is a bug fix added in TLM-2.0.2 48913511Sgabeblack@google.com t = sc_core::SC_ZERO_TIME; 49013511Sgabeblack@google.com (m_mod->*m_nb_transport_ptr)(*trans, phase, t); 49113511Sgabeblack@google.com 49213511Sgabeblack@google.com // notify transaction is finished 49313511Sgabeblack@google.com typename std::map<transaction_type*, sc_core::sc_event *>::iterator it = 49413511Sgabeblack@google.com m_owner->m_pending_trans.find(trans); 49513511Sgabeblack@google.com sc_assert(it != m_owner->m_pending_trans.end()); 49613511Sgabeblack@google.com it->second->notify(t); 49713511Sgabeblack@google.com m_owner->m_pending_trans.erase(it); 49813511Sgabeblack@google.com break; 49913511Sgabeblack@google.com } 50013511Sgabeblack@google.com 50113511Sgabeblack@google.com default: 50213511Sgabeblack@google.com m_owner->display_error("invalid phase received"); 50313511Sgabeblack@google.com } 50413511Sgabeblack@google.com break; 50513511Sgabeblack@google.com 50613511Sgabeblack@google.com default: 50713511Sgabeblack@google.com m_owner->display_error("invalid sync value received"); 50813511Sgabeblack@google.com } 50913511Sgabeblack@google.com } 51013511Sgabeblack@google.com sc_core::wait(); 51113511Sgabeblack@google.com } 51213511Sgabeblack@google.com } 51313511Sgabeblack@google.com 51413511Sgabeblack@google.com void free(tlm::tlm_generic_payload* trans) 51513511Sgabeblack@google.com { 51613511Sgabeblack@google.com mm_end_event_ext* ext = trans->template get_extension<mm_end_event_ext>(); 51713511Sgabeblack@google.com sc_assert(ext); 51813511Sgabeblack@google.com // notif event first before freeing extensions (reset) 51913511Sgabeblack@google.com ext->done.notify(); 52013511Sgabeblack@google.com trans->reset(); 52113511Sgabeblack@google.com } 52213511Sgabeblack@google.com 52313511Sgabeblack@google.com private: 52413511Sgabeblack@google.com struct mm_end_event_ext : public tlm::tlm_extension<mm_end_event_ext> 52513511Sgabeblack@google.com { 52613511Sgabeblack@google.com tlm::tlm_extension_base* clone() const { return NULL; } 52713511Sgabeblack@google.com void free() {} 52813511Sgabeblack@google.com void copy_from(tlm::tlm_extension_base const &) {} 52913511Sgabeblack@google.com sc_core::sc_event done; 53013511Sgabeblack@google.com }; 53113511Sgabeblack@google.com 53213511Sgabeblack@google.com private: 53313511Sgabeblack@google.com simple_target_socket_b *m_owner; 53413511Sgabeblack@google.com MODULE* m_mod; 53513511Sgabeblack@google.com NBTransportPtr m_nb_transport_ptr; 53613511Sgabeblack@google.com BTransportPtr m_b_transport_ptr; 53713511Sgabeblack@google.com TransportDbgPtr m_transport_dbg_ptr; 53813511Sgabeblack@google.com GetDirectMemPtr m_get_direct_mem_ptr; 53913511Sgabeblack@google.com peq_with_get<transaction_type> m_peq; 54013511Sgabeblack@google.com bool m_response_in_progress; 54113511Sgabeblack@google.com sc_core::sc_event m_end_response; 54213511Sgabeblack@google.com }; 54313511Sgabeblack@google.com 54413511Sgabeblack@google.comprivate: 54513511Sgabeblack@google.com const sc_core::sc_object* get_socket() const { return this; } 54613511Sgabeblack@google.comprivate: 54713511Sgabeblack@google.com fw_process m_fw_process; 54813511Sgabeblack@google.com bw_process m_bw_process; 54913511Sgabeblack@google.com std::map<transaction_type*, sc_core::sc_event *> m_pending_trans; 55013511Sgabeblack@google.com sc_core::sc_event m_end_request; 55113511Sgabeblack@google.com transaction_type* m_current_transaction; 55213511Sgabeblack@google.com}; 55313511Sgabeblack@google.com 55413511Sgabeblack@google.comtemplate< typename MODULE, unsigned int BUSWIDTH = 32 55513511Sgabeblack@google.com , typename TYPES = tlm::tlm_base_protocol_types > 55613511Sgabeblack@google.comclass simple_target_socket 55713511Sgabeblack@google.com : public simple_target_socket_b<MODULE,BUSWIDTH,TYPES> 55813511Sgabeblack@google.com{ 55913511Sgabeblack@google.com typedef simple_target_socket_b<MODULE,BUSWIDTH,TYPES> socket_b; 56013511Sgabeblack@google.compublic: 56113511Sgabeblack@google.com simple_target_socket() : socket_b() {} 56213511Sgabeblack@google.com explicit simple_target_socket(const char* name) : socket_b(name) {} 56313511Sgabeblack@google.com}; 56413511Sgabeblack@google.com 56513511Sgabeblack@google.comtemplate< typename MODULE, unsigned int BUSWIDTH = 32 56613511Sgabeblack@google.com , typename TYPES = tlm::tlm_base_protocol_types > 56713511Sgabeblack@google.comclass simple_target_socket_optional 56813511Sgabeblack@google.com : public simple_target_socket_b<MODULE,BUSWIDTH,TYPES,sc_core::SC_ZERO_OR_MORE_BOUND> 56913511Sgabeblack@google.com{ 57013511Sgabeblack@google.com typedef simple_target_socket_b<MODULE,BUSWIDTH,TYPES,sc_core::SC_ZERO_OR_MORE_BOUND> socket_b; 57113511Sgabeblack@google.compublic: 57213511Sgabeblack@google.com simple_target_socket_optional() : socket_b() {} 57313511Sgabeblack@google.com explicit simple_target_socket_optional(const char* name) : socket_b(name) {} 57413511Sgabeblack@google.com}; 57513511Sgabeblack@google.com 57613511Sgabeblack@google.com//ID Tagged version 57713511Sgabeblack@google.comtemplate< typename MODULE, unsigned int BUSWIDTH, typename TYPES 57813511Sgabeblack@google.com , sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND > 57913511Sgabeblack@google.comclass simple_target_socket_tagged_b 58013511Sgabeblack@google.com : public tlm::tlm_target_socket<BUSWIDTH, TYPES, 1, POL> 58113511Sgabeblack@google.com , protected simple_socket_base 58213511Sgabeblack@google.com{ 58313511Sgabeblack@google.com friend class fw_process; 58413511Sgabeblack@google.com friend class bw_process; 58513511Sgabeblack@google.compublic: 58613511Sgabeblack@google.com typedef typename TYPES::tlm_payload_type transaction_type; 58713511Sgabeblack@google.com typedef typename TYPES::tlm_phase_type phase_type; 58813511Sgabeblack@google.com typedef tlm::tlm_sync_enum sync_enum_type; 58913511Sgabeblack@google.com typedef tlm::tlm_fw_transport_if<TYPES> fw_interface_type; 59013511Sgabeblack@google.com typedef tlm::tlm_bw_transport_if<TYPES> bw_interface_type; 59113511Sgabeblack@google.com typedef tlm::tlm_target_socket<BUSWIDTH,TYPES,1,POL> base_type; 59213511Sgabeblack@google.com 59313511Sgabeblack@google.compublic: 59413511Sgabeblack@google.com static const char* default_name() 59513511Sgabeblack@google.com { return sc_core::sc_gen_unique_name("simple_target_socket_tagged"); } 59613511Sgabeblack@google.com 59713511Sgabeblack@google.com explicit simple_target_socket_tagged_b(const char* n = default_name()) 59813511Sgabeblack@google.com : base_type(n) 59913511Sgabeblack@google.com , m_fw_process(this) 60013511Sgabeblack@google.com , m_bw_process(this) 60113511Sgabeblack@google.com { 60213511Sgabeblack@google.com bind(m_fw_process); 60313511Sgabeblack@google.com } 60413511Sgabeblack@google.com 60513511Sgabeblack@google.com using base_type::bind; 60613511Sgabeblack@google.com 60713511Sgabeblack@google.com // bw transport must come thru us. 60813511Sgabeblack@google.com tlm::tlm_bw_transport_if<TYPES> * operator ->() {return &m_bw_process;} 60913511Sgabeblack@google.com 61013511Sgabeblack@google.com // REGISTER_XXX 61113511Sgabeblack@google.com void register_nb_transport_fw(MODULE* mod, 61213511Sgabeblack@google.com sync_enum_type (MODULE::*cb)(int id, 61313511Sgabeblack@google.com transaction_type&, 61413511Sgabeblack@google.com phase_type&, 61513511Sgabeblack@google.com sc_core::sc_time&), 61613511Sgabeblack@google.com int id) 61713511Sgabeblack@google.com { 61813511Sgabeblack@google.com elaboration_check("register_nb_transport_fw"); 61913511Sgabeblack@google.com m_fw_process.set_nb_transport_ptr(mod, cb); 62013511Sgabeblack@google.com m_fw_process.set_nb_transport_user_id(id); 62113511Sgabeblack@google.com } 62213511Sgabeblack@google.com 62313511Sgabeblack@google.com void register_b_transport(MODULE* mod, 62413511Sgabeblack@google.com void (MODULE::*cb)(int id, 62513511Sgabeblack@google.com transaction_type&, 62613511Sgabeblack@google.com sc_core::sc_time&), 62713511Sgabeblack@google.com int id) 62813511Sgabeblack@google.com { 62913511Sgabeblack@google.com elaboration_check("register_b_transport"); 63013511Sgabeblack@google.com m_fw_process.set_b_transport_ptr(mod, cb); 63113511Sgabeblack@google.com m_fw_process.set_b_transport_user_id(id); 63213511Sgabeblack@google.com } 63313511Sgabeblack@google.com 63413511Sgabeblack@google.com void register_transport_dbg(MODULE* mod, 63513511Sgabeblack@google.com unsigned int (MODULE::*cb)(int id, 63613511Sgabeblack@google.com transaction_type&), 63713511Sgabeblack@google.com int id) 63813511Sgabeblack@google.com { 63913511Sgabeblack@google.com elaboration_check("register_transport_dbg"); 64013511Sgabeblack@google.com m_fw_process.set_transport_dbg_ptr(mod, cb); 64113511Sgabeblack@google.com m_fw_process.set_transport_dbg_user_id(id); 64213511Sgabeblack@google.com } 64313511Sgabeblack@google.com 64413511Sgabeblack@google.com void register_get_direct_mem_ptr(MODULE* mod, 64513511Sgabeblack@google.com bool (MODULE::*cb)(int id, 64613511Sgabeblack@google.com transaction_type&, 64713511Sgabeblack@google.com tlm::tlm_dmi&), 64813511Sgabeblack@google.com int id) 64913511Sgabeblack@google.com { 65013511Sgabeblack@google.com elaboration_check("register_get_direct_mem_ptr"); 65113511Sgabeblack@google.com m_fw_process.set_get_direct_mem_ptr(mod, cb); 65213511Sgabeblack@google.com m_fw_process.set_get_dmi_user_id(id); 65313511Sgabeblack@google.com } 65413511Sgabeblack@google.com 65513511Sgabeblack@google.comprotected: 65613511Sgabeblack@google.com void start_of_simulation() 65713511Sgabeblack@google.com { 65813511Sgabeblack@google.com base_type::start_of_simulation(); 65913511Sgabeblack@google.com m_fw_process.start_of_simulation(); 66013511Sgabeblack@google.com } 66113511Sgabeblack@google.com 66213511Sgabeblack@google.comprivate: 66313511Sgabeblack@google.com //make call on bw path. 66413511Sgabeblack@google.com sync_enum_type bw_nb_transport(transaction_type &trans, phase_type &phase, sc_core::sc_time &t) 66513511Sgabeblack@google.com { 66613511Sgabeblack@google.com return base_type::operator ->()->nb_transport_bw(trans, phase, t); 66713511Sgabeblack@google.com } 66813511Sgabeblack@google.com 66913511Sgabeblack@google.com void bw_invalidate_direct_mem_ptr(sc_dt::uint64 s,sc_dt::uint64 e) 67013511Sgabeblack@google.com { 67113511Sgabeblack@google.com base_type::operator ->()->invalidate_direct_mem_ptr(s, e); 67213511Sgabeblack@google.com } 67313511Sgabeblack@google.com 67413511Sgabeblack@google.com //Helper class to handle bw path calls 67513511Sgabeblack@google.com // Needed to detect transaction end when called from b_transport. 67613511Sgabeblack@google.com class bw_process : public tlm::tlm_bw_transport_if<TYPES> 67713511Sgabeblack@google.com { 67813511Sgabeblack@google.com public: 67913511Sgabeblack@google.com bw_process(simple_target_socket_tagged_b *p_own) : m_owner(p_own) 68013511Sgabeblack@google.com { 68113511Sgabeblack@google.com } 68213511Sgabeblack@google.com 68313511Sgabeblack@google.com sync_enum_type nb_transport_bw(transaction_type &trans, phase_type &phase, sc_core::sc_time &t) 68413511Sgabeblack@google.com { 68513511Sgabeblack@google.com typename std::map<transaction_type*, sc_core::sc_event *>::iterator it = 68613511Sgabeblack@google.com m_owner->m_pending_trans.find(&trans); 68713511Sgabeblack@google.com 68813511Sgabeblack@google.com if(it == m_owner->m_pending_trans.end()) { 68913511Sgabeblack@google.com // Not a blocking call, forward. 69013511Sgabeblack@google.com return m_owner->bw_nb_transport(trans, phase, t); 69113511Sgabeblack@google.com } 69213511Sgabeblack@google.com if (phase == tlm::END_REQ) { 69313511Sgabeblack@google.com m_owner->m_end_request.notify(sc_core::SC_ZERO_TIME); 69413511Sgabeblack@google.com return tlm::TLM_ACCEPTED; 69513511Sgabeblack@google.com } 69613511Sgabeblack@google.com if (phase == tlm::BEGIN_RESP) { 69713511Sgabeblack@google.com if (m_owner->m_current_transaction == &trans) { 69813511Sgabeblack@google.com m_owner->m_end_request.notify(sc_core::SC_ZERO_TIME); 69913511Sgabeblack@google.com } 70013511Sgabeblack@google.com //TODO: add response-accept delay? 70113511Sgabeblack@google.com it->second->notify(t); 70213511Sgabeblack@google.com m_owner->m_pending_trans.erase(it); 70313511Sgabeblack@google.com return tlm::TLM_COMPLETED; 70413511Sgabeblack@google.com } 70513511Sgabeblack@google.com m_owner->display_error("invalid phase received"); 70613511Sgabeblack@google.com return tlm::TLM_COMPLETED; 70713511Sgabeblack@google.com } 70813511Sgabeblack@google.com 70913511Sgabeblack@google.com void invalidate_direct_mem_ptr(sc_dt::uint64 s,sc_dt::uint64 e) 71013511Sgabeblack@google.com { 71113511Sgabeblack@google.com return m_owner->bw_invalidate_direct_mem_ptr(s, e); 71213511Sgabeblack@google.com } 71313511Sgabeblack@google.com 71413511Sgabeblack@google.com private: 71513511Sgabeblack@google.com simple_target_socket_tagged_b *m_owner; 71613511Sgabeblack@google.com }; 71713511Sgabeblack@google.com 71813511Sgabeblack@google.com class fw_process : public tlm::tlm_fw_transport_if<TYPES>, 71913511Sgabeblack@google.com public tlm::tlm_mm_interface 72013511Sgabeblack@google.com { 72113511Sgabeblack@google.com public: 72213511Sgabeblack@google.com typedef sync_enum_type (MODULE::*NBTransportPtr)(int id, 72313511Sgabeblack@google.com transaction_type&, 72413511Sgabeblack@google.com phase_type&, 72513511Sgabeblack@google.com sc_core::sc_time&); 72613511Sgabeblack@google.com typedef void (MODULE::*BTransportPtr)(int id, 72713511Sgabeblack@google.com transaction_type&, 72813511Sgabeblack@google.com sc_core::sc_time&); 72913511Sgabeblack@google.com typedef unsigned int (MODULE::*TransportDbgPtr)(int id, 73013511Sgabeblack@google.com transaction_type&); 73113511Sgabeblack@google.com typedef bool (MODULE::*GetDirectMemPtr)(int id, 73213511Sgabeblack@google.com transaction_type&, 73313511Sgabeblack@google.com tlm::tlm_dmi&); 73413511Sgabeblack@google.com 73513511Sgabeblack@google.com fw_process(simple_target_socket_tagged_b *p_own) : 73613511Sgabeblack@google.com m_owner(p_own), 73713511Sgabeblack@google.com m_mod(0), 73813511Sgabeblack@google.com m_nb_transport_ptr(0), 73913511Sgabeblack@google.com m_b_transport_ptr(0), 74013511Sgabeblack@google.com m_transport_dbg_ptr(0), 74113511Sgabeblack@google.com m_get_direct_mem_ptr(0), 74213511Sgabeblack@google.com m_nb_transport_user_id(0), 74313511Sgabeblack@google.com m_b_transport_user_id(0), 74413511Sgabeblack@google.com m_transport_dbg_user_id(0), 74513511Sgabeblack@google.com m_get_dmi_user_id(0), 74613511Sgabeblack@google.com m_peq(sc_core::sc_gen_unique_name("m_peq")), 74713511Sgabeblack@google.com m_response_in_progress(false) 74813511Sgabeblack@google.com {} 74913511Sgabeblack@google.com 75013511Sgabeblack@google.com void start_of_simulation() 75113511Sgabeblack@google.com { 75213511Sgabeblack@google.com if (!m_b_transport_ptr && m_nb_transport_ptr) { // only spawn b2nb_thread, if needed 75313511Sgabeblack@google.com sc_core::sc_spawn_options opts; 75413511Sgabeblack@google.com opts.set_sensitivity(&m_peq.get_event()); 75513511Sgabeblack@google.com opts.dont_initialize(); 75613511Sgabeblack@google.com sc_core::sc_spawn(sc_bind(&fw_process::b2nb_thread, this), 75713511Sgabeblack@google.com sc_core::sc_gen_unique_name("b2nb_thread"), &opts); 75813511Sgabeblack@google.com } 75913511Sgabeblack@google.com } 76013511Sgabeblack@google.com 76113511Sgabeblack@google.com void set_nb_transport_user_id(int id) { m_nb_transport_user_id = id; } 76213511Sgabeblack@google.com void set_b_transport_user_id(int id) { m_b_transport_user_id = id; } 76313511Sgabeblack@google.com void set_transport_dbg_user_id(int id) { m_transport_dbg_user_id = id; } 76413511Sgabeblack@google.com void set_get_dmi_user_id(int id) { m_get_dmi_user_id = id; } 76513511Sgabeblack@google.com 76613511Sgabeblack@google.com void set_nb_transport_ptr(MODULE* mod, NBTransportPtr p) 76713511Sgabeblack@google.com { 76813511Sgabeblack@google.com if (m_nb_transport_ptr) { 76913511Sgabeblack@google.com m_owner->display_warning("non-blocking callback already registered"); 77013511Sgabeblack@google.com return; 77113511Sgabeblack@google.com } 77213511Sgabeblack@google.com sc_assert(!m_mod || m_mod == mod); 77313511Sgabeblack@google.com m_mod = mod; 77413511Sgabeblack@google.com m_nb_transport_ptr = p; 77513511Sgabeblack@google.com } 77613511Sgabeblack@google.com 77713511Sgabeblack@google.com void set_b_transport_ptr(MODULE* mod, BTransportPtr p) 77813511Sgabeblack@google.com { 77913511Sgabeblack@google.com if (m_b_transport_ptr) { 78013511Sgabeblack@google.com m_owner->display_warning("blocking callback already registered"); 78113511Sgabeblack@google.com return; 78213511Sgabeblack@google.com } 78313511Sgabeblack@google.com sc_assert(!m_mod || m_mod == mod); 78413511Sgabeblack@google.com m_mod = mod; 78513511Sgabeblack@google.com m_b_transport_ptr = p; 78613511Sgabeblack@google.com } 78713511Sgabeblack@google.com 78813511Sgabeblack@google.com void set_transport_dbg_ptr(MODULE* mod, TransportDbgPtr p) 78913511Sgabeblack@google.com { 79013511Sgabeblack@google.com if (m_transport_dbg_ptr) { 79113511Sgabeblack@google.com m_owner->display_warning("debug callback already registered"); 79213511Sgabeblack@google.com return; 79313511Sgabeblack@google.com } 79413511Sgabeblack@google.com sc_assert(!m_mod || m_mod == mod); 79513511Sgabeblack@google.com m_mod = mod; 79613511Sgabeblack@google.com m_transport_dbg_ptr = p; 79713511Sgabeblack@google.com } 79813511Sgabeblack@google.com 79913511Sgabeblack@google.com void set_get_direct_mem_ptr(MODULE* mod, GetDirectMemPtr p) 80013511Sgabeblack@google.com { 80113511Sgabeblack@google.com if (m_get_direct_mem_ptr) { 80213511Sgabeblack@google.com m_owner->display_warning("get DMI pointer callback already registered"); 80313511Sgabeblack@google.com } 80413511Sgabeblack@google.com sc_assert(!m_mod || m_mod == mod); 80513511Sgabeblack@google.com m_mod = mod; 80613511Sgabeblack@google.com m_get_direct_mem_ptr = p; 80713511Sgabeblack@google.com } 80813511Sgabeblack@google.com// Interface implementation 80913511Sgabeblack@google.com sync_enum_type nb_transport_fw(transaction_type& trans, 81013511Sgabeblack@google.com phase_type& phase, 81113511Sgabeblack@google.com sc_core::sc_time& t) 81213511Sgabeblack@google.com { 81313511Sgabeblack@google.com if (m_nb_transport_ptr) { 81413511Sgabeblack@google.com // forward call 81513511Sgabeblack@google.com sc_assert(m_mod); 81613511Sgabeblack@google.com return (m_mod->*m_nb_transport_ptr)(m_nb_transport_user_id, trans, phase, t); 81713511Sgabeblack@google.com } 81813511Sgabeblack@google.com 81913511Sgabeblack@google.com // nb->b conversion 82013511Sgabeblack@google.com if (m_b_transport_ptr) { 82113511Sgabeblack@google.com if (phase == tlm::BEGIN_REQ) { 82213511Sgabeblack@google.com 82313511Sgabeblack@google.com // prepare thread to do blocking call 82413511Sgabeblack@google.com process_handle_class * ph = m_process_handle.get_handle(&trans); 82513511Sgabeblack@google.com 82613511Sgabeblack@google.com if (!ph) { // create new dynamic process 82713511Sgabeblack@google.com ph = new process_handle_class(&trans); 82813511Sgabeblack@google.com m_process_handle.put_handle(ph); 82913511Sgabeblack@google.com 83013511Sgabeblack@google.com sc_core::sc_spawn_options opts; 83113511Sgabeblack@google.com opts.dont_initialize(); 83213511Sgabeblack@google.com opts.set_sensitivity(&ph->m_e); 83313511Sgabeblack@google.com 83413511Sgabeblack@google.com sc_core::sc_spawn(sc_bind(&fw_process::nb2b_thread, this, ph), 83513511Sgabeblack@google.com sc_core::sc_gen_unique_name("nb2b_thread"), &opts); 83613511Sgabeblack@google.com } 83713511Sgabeblack@google.com 83813511Sgabeblack@google.com ph->m_e.notify(t); 83913511Sgabeblack@google.com return tlm::TLM_ACCEPTED; 84013511Sgabeblack@google.com } 84113511Sgabeblack@google.com if (phase == tlm::END_RESP) { 84213511Sgabeblack@google.com m_response_in_progress = false; 84313511Sgabeblack@google.com m_end_response.notify(t); 84413511Sgabeblack@google.com return tlm::TLM_COMPLETED; 84513511Sgabeblack@google.com } 84613511Sgabeblack@google.com m_owner->display_error("invalid phase"); 84713511Sgabeblack@google.com return tlm::TLM_COMPLETED; 84813511Sgabeblack@google.com } 84913511Sgabeblack@google.com 85013511Sgabeblack@google.com m_owner->display_error("no non-blocking transport callback registered"); 85113511Sgabeblack@google.com return tlm::TLM_COMPLETED; 85213511Sgabeblack@google.com } 85313511Sgabeblack@google.com 85413511Sgabeblack@google.com void b_transport(transaction_type& trans, sc_core::sc_time& t) 85513511Sgabeblack@google.com { 85613511Sgabeblack@google.com if (m_b_transport_ptr) { 85713511Sgabeblack@google.com // forward call 85813511Sgabeblack@google.com sc_assert(m_mod); 85913511Sgabeblack@google.com (m_mod->*m_b_transport_ptr)(m_b_transport_user_id, trans, t); 86013511Sgabeblack@google.com return; 86113511Sgabeblack@google.com } 86213511Sgabeblack@google.com 86313511Sgabeblack@google.com // b->nb conversion 86413511Sgabeblack@google.com if (m_nb_transport_ptr) { 86513511Sgabeblack@google.com m_peq.notify(trans, t); 86613511Sgabeblack@google.com t = sc_core::SC_ZERO_TIME; 86713511Sgabeblack@google.com 86813511Sgabeblack@google.com mm_end_event_ext mm_ext; 86913511Sgabeblack@google.com const bool mm_added = !trans.has_mm(); 87013511Sgabeblack@google.com 87113511Sgabeblack@google.com if (mm_added){ 87213511Sgabeblack@google.com trans.set_mm(this); 87313511Sgabeblack@google.com trans.set_auto_extension(&mm_ext); 87413511Sgabeblack@google.com trans.acquire(); 87513511Sgabeblack@google.com } 87613511Sgabeblack@google.com 87713511Sgabeblack@google.com // wait until transaction is finished 87813511Sgabeblack@google.com sc_core::sc_event end_event; 87913511Sgabeblack@google.com m_owner->m_pending_trans[&trans] = &end_event; 88013511Sgabeblack@google.com sc_core::wait(end_event); 88113511Sgabeblack@google.com 88213511Sgabeblack@google.com if (mm_added) { 88313511Sgabeblack@google.com // release will not delete the transaction, it will notify mm_ext.done 88413511Sgabeblack@google.com trans.release(); 88513511Sgabeblack@google.com if (trans.get_ref_count()) { 88613511Sgabeblack@google.com sc_core::wait(mm_ext.done); 88713511Sgabeblack@google.com } 88813511Sgabeblack@google.com trans.set_mm(0); 88913511Sgabeblack@google.com } 89013511Sgabeblack@google.com return; 89113511Sgabeblack@google.com } 89213511Sgabeblack@google.com 89313511Sgabeblack@google.com m_owner->display_error("no transport callback registered"); 89413511Sgabeblack@google.com } 89513511Sgabeblack@google.com 89613511Sgabeblack@google.com unsigned int transport_dbg(transaction_type& trans) 89713511Sgabeblack@google.com { 89813511Sgabeblack@google.com if (m_transport_dbg_ptr) { 89913511Sgabeblack@google.com // forward call 90013511Sgabeblack@google.com sc_assert(m_mod); 90113511Sgabeblack@google.com return (m_mod->*m_transport_dbg_ptr)(m_transport_dbg_user_id, trans); 90213511Sgabeblack@google.com } 90313511Sgabeblack@google.com // No debug support 90413511Sgabeblack@google.com return 0; 90513511Sgabeblack@google.com } 90613511Sgabeblack@google.com 90713511Sgabeblack@google.com bool get_direct_mem_ptr(transaction_type& trans, 90813511Sgabeblack@google.com tlm::tlm_dmi& dmi_data) 90913511Sgabeblack@google.com { 91013511Sgabeblack@google.com if (m_get_direct_mem_ptr) { 91113511Sgabeblack@google.com // forward call 91213511Sgabeblack@google.com sc_assert(m_mod); 91313511Sgabeblack@google.com return (m_mod->*m_get_direct_mem_ptr)(m_get_dmi_user_id, trans, dmi_data); 91413511Sgabeblack@google.com } 91513511Sgabeblack@google.com // No DMI support 91613511Sgabeblack@google.com dmi_data.allow_read_write(); 91713511Sgabeblack@google.com dmi_data.set_start_address(0x0); 91813511Sgabeblack@google.com dmi_data.set_end_address((sc_dt::uint64)-1); 91913511Sgabeblack@google.com return false; 92013511Sgabeblack@google.com } 92113511Sgabeblack@google.com 92213511Sgabeblack@google.com private: 92313511Sgabeblack@google.com// dynamic process handler for nb2b conversion 92413511Sgabeblack@google.com 92513511Sgabeblack@google.com class process_handle_class { 92613511Sgabeblack@google.com public: 92713511Sgabeblack@google.com explicit process_handle_class(transaction_type * trans) 92813511Sgabeblack@google.com : m_trans(trans),m_suspend(false){} 92913511Sgabeblack@google.com 93013511Sgabeblack@google.com transaction_type* m_trans; 93113511Sgabeblack@google.com sc_core::sc_event m_e; 93213511Sgabeblack@google.com bool m_suspend; 93313511Sgabeblack@google.com }; 93413511Sgabeblack@google.com 93513511Sgabeblack@google.com class process_handle_list { 93613511Sgabeblack@google.com public: 93713511Sgabeblack@google.com process_handle_list() {} 93813511Sgabeblack@google.com 93913511Sgabeblack@google.com ~process_handle_list() { 94013511Sgabeblack@google.com for( typename std::vector<process_handle_class*>::iterator 94113511Sgabeblack@google.com it=v.begin(), end = v.end(); it != end; ++it ) 94213511Sgabeblack@google.com delete *it; 94313511Sgabeblack@google.com } 94413511Sgabeblack@google.com 94513511Sgabeblack@google.com process_handle_class* get_handle(transaction_type *trans) 94613511Sgabeblack@google.com { 94713511Sgabeblack@google.com typename std::vector<process_handle_class*>::iterator it; 94813511Sgabeblack@google.com 94913511Sgabeblack@google.com for(it = v.begin(); it != v.end(); it++) { 95013511Sgabeblack@google.com if ((*it)->m_suspend) { // found suspended dynamic process, re-use it 95113511Sgabeblack@google.com (*it)->m_trans = trans; // replace to new one 95213511Sgabeblack@google.com (*it)->m_suspend = false; 95313511Sgabeblack@google.com return *it; 95413511Sgabeblack@google.com } 95513511Sgabeblack@google.com } 95613511Sgabeblack@google.com return NULL; // no suspended process 95713511Sgabeblack@google.com } 95813511Sgabeblack@google.com 95913511Sgabeblack@google.com void put_handle(process_handle_class* ph) 96013511Sgabeblack@google.com { 96113511Sgabeblack@google.com v.push_back(ph); 96213511Sgabeblack@google.com } 96313511Sgabeblack@google.com 96413511Sgabeblack@google.com private: 96513511Sgabeblack@google.com std::vector<process_handle_class*> v; 96613511Sgabeblack@google.com }; 96713511Sgabeblack@google.com 96813511Sgabeblack@google.com process_handle_list m_process_handle; 96913511Sgabeblack@google.com 97013511Sgabeblack@google.com void nb2b_thread(process_handle_class* h) 97113511Sgabeblack@google.com { 97213511Sgabeblack@google.com 97313511Sgabeblack@google.com while(1) { 97413511Sgabeblack@google.com transaction_type * trans = h->m_trans; 97513511Sgabeblack@google.com sc_core::sc_time t = sc_core::SC_ZERO_TIME; 97613511Sgabeblack@google.com 97713511Sgabeblack@google.com // forward call 97813511Sgabeblack@google.com sc_assert(m_mod); 97913511Sgabeblack@google.com (m_mod->*m_b_transport_ptr)(m_b_transport_user_id, *trans, t); 98013511Sgabeblack@google.com 98113511Sgabeblack@google.com sc_core::wait(t); 98213511Sgabeblack@google.com 98313511Sgabeblack@google.com // return path 98413511Sgabeblack@google.com while (m_response_in_progress) { 98513511Sgabeblack@google.com sc_core::wait(m_end_response); 98613511Sgabeblack@google.com } 98713511Sgabeblack@google.com t = sc_core::SC_ZERO_TIME; 98813511Sgabeblack@google.com phase_type phase = tlm::BEGIN_RESP; 98913511Sgabeblack@google.com sync_enum_type sync = m_owner->bw_nb_transport(*trans, phase, t); 99013511Sgabeblack@google.com if ( !(sync == tlm::TLM_COMPLETED || 99113511Sgabeblack@google.com (sync == tlm::TLM_UPDATED && phase == tlm::END_RESP)) ) { 99213511Sgabeblack@google.com m_response_in_progress = true; 99313511Sgabeblack@google.com } 99413511Sgabeblack@google.com 99513511Sgabeblack@google.com // suspend until next transaction 99613511Sgabeblack@google.com h->m_suspend = true; 99713511Sgabeblack@google.com sc_core::wait(); 99813511Sgabeblack@google.com } 99913511Sgabeblack@google.com } 100013511Sgabeblack@google.com 100113511Sgabeblack@google.com void b2nb_thread() 100213511Sgabeblack@google.com { 100313511Sgabeblack@google.com while (true) { 100413511Sgabeblack@google.com transaction_type* trans; 100513511Sgabeblack@google.com while ((trans = m_peq.get_next_transaction())!=0) { 100613511Sgabeblack@google.com sc_assert(m_mod); 100713511Sgabeblack@google.com sc_assert(m_nb_transport_ptr); 100813511Sgabeblack@google.com phase_type phase = tlm::BEGIN_REQ; 100913511Sgabeblack@google.com sc_core::sc_time t = sc_core::SC_ZERO_TIME; 101013511Sgabeblack@google.com 101113511Sgabeblack@google.com switch ((m_mod->*m_nb_transport_ptr)(m_nb_transport_user_id, *trans, phase, t)) { 101213511Sgabeblack@google.com case tlm::TLM_COMPLETED: 101313511Sgabeblack@google.com { 101413511Sgabeblack@google.com // notify transaction is finished 101513511Sgabeblack@google.com typename std::map<transaction_type*, sc_core::sc_event *>::iterator it = 101613511Sgabeblack@google.com m_owner->m_pending_trans.find(trans); 101713511Sgabeblack@google.com sc_assert(it != m_owner->m_pending_trans.end()); 101813511Sgabeblack@google.com it->second->notify(t); 101913511Sgabeblack@google.com m_owner->m_pending_trans.erase(it); 102013511Sgabeblack@google.com break; 102113511Sgabeblack@google.com } 102213511Sgabeblack@google.com 102313511Sgabeblack@google.com case tlm::TLM_ACCEPTED: 102413511Sgabeblack@google.com case tlm::TLM_UPDATED: 102513511Sgabeblack@google.com switch (phase) { 102613511Sgabeblack@google.com case tlm::BEGIN_REQ: 102713511Sgabeblack@google.com m_owner->m_current_transaction = trans; 102813511Sgabeblack@google.com sc_core::wait(m_owner->m_end_request); 102913511Sgabeblack@google.com m_owner->m_current_transaction = 0; 103013511Sgabeblack@google.com break; 103113511Sgabeblack@google.com 103213511Sgabeblack@google.com case tlm::END_REQ: 103313511Sgabeblack@google.com sc_core::wait(t); 103413511Sgabeblack@google.com break; 103513511Sgabeblack@google.com 103613511Sgabeblack@google.com case tlm::BEGIN_RESP: 103713511Sgabeblack@google.com { 103813511Sgabeblack@google.com phase = tlm::END_RESP; 103913511Sgabeblack@google.com sc_core::wait(t); // This line is a bug fix added in TLM-2.0.2 104013511Sgabeblack@google.com t = sc_core::SC_ZERO_TIME; 104113511Sgabeblack@google.com (m_mod->*m_nb_transport_ptr)(m_nb_transport_user_id, *trans, phase, t); 104213511Sgabeblack@google.com 104313511Sgabeblack@google.com // notify transaction is finished 104413511Sgabeblack@google.com typename std::map<transaction_type*, sc_core::sc_event *>::iterator it = 104513511Sgabeblack@google.com m_owner->m_pending_trans.find(trans); 104613511Sgabeblack@google.com sc_assert(it != m_owner->m_pending_trans.end()); 104713511Sgabeblack@google.com it->second->notify(t); 104813511Sgabeblack@google.com m_owner->m_pending_trans.erase(it); 104913511Sgabeblack@google.com break; 105013511Sgabeblack@google.com } 105113511Sgabeblack@google.com 105213511Sgabeblack@google.com default: 105313511Sgabeblack@google.com m_owner->display_error("invalid phase received"); 105413511Sgabeblack@google.com }; 105513511Sgabeblack@google.com break; 105613511Sgabeblack@google.com 105713511Sgabeblack@google.com default: 105813511Sgabeblack@google.com m_owner->display_error("invalid sync value received"); 105913511Sgabeblack@google.com } 106013511Sgabeblack@google.com } 106113511Sgabeblack@google.com sc_core::wait(); 106213511Sgabeblack@google.com } 106313511Sgabeblack@google.com } 106413511Sgabeblack@google.com 106513511Sgabeblack@google.com void free(tlm::tlm_generic_payload* trans) 106613511Sgabeblack@google.com { 106713511Sgabeblack@google.com mm_end_event_ext* ext = trans->template get_extension<mm_end_event_ext>(); 106813511Sgabeblack@google.com sc_assert(ext); 106913511Sgabeblack@google.com // notif event first before freeing extensions (reset) 107013511Sgabeblack@google.com ext->done.notify(); 107113511Sgabeblack@google.com trans->reset(); 107213511Sgabeblack@google.com } 107313511Sgabeblack@google.com 107413511Sgabeblack@google.com private: 107513511Sgabeblack@google.com struct mm_end_event_ext : public tlm::tlm_extension<mm_end_event_ext> 107613511Sgabeblack@google.com { 107713511Sgabeblack@google.com tlm::tlm_extension_base* clone() const { return NULL; } 107813511Sgabeblack@google.com void free() {} 107913511Sgabeblack@google.com void copy_from(tlm::tlm_extension_base const &) {} 108013511Sgabeblack@google.com sc_core::sc_event done; 108113511Sgabeblack@google.com }; 108213511Sgabeblack@google.com 108313511Sgabeblack@google.com private: 108413511Sgabeblack@google.com simple_target_socket_tagged_b *m_owner; 108513511Sgabeblack@google.com MODULE* m_mod; 108613511Sgabeblack@google.com NBTransportPtr m_nb_transport_ptr; 108713511Sgabeblack@google.com BTransportPtr m_b_transport_ptr; 108813511Sgabeblack@google.com TransportDbgPtr m_transport_dbg_ptr; 108913511Sgabeblack@google.com GetDirectMemPtr m_get_direct_mem_ptr; 109013511Sgabeblack@google.com int m_nb_transport_user_id; 109113511Sgabeblack@google.com int m_b_transport_user_id; 109213511Sgabeblack@google.com int m_transport_dbg_user_id; 109313511Sgabeblack@google.com int m_get_dmi_user_id; 109413511Sgabeblack@google.com peq_with_get<transaction_type> m_peq; 109513511Sgabeblack@google.com bool m_response_in_progress; 109613511Sgabeblack@google.com sc_core::sc_event m_end_response; 109713511Sgabeblack@google.com }; 109813511Sgabeblack@google.com 109913511Sgabeblack@google.comprivate: 110013511Sgabeblack@google.com const sc_core::sc_object* get_socket() const { return this; } 110113511Sgabeblack@google.comprivate: 110213511Sgabeblack@google.com fw_process m_fw_process; 110313511Sgabeblack@google.com bw_process m_bw_process; 110413511Sgabeblack@google.com std::map<transaction_type*, sc_core::sc_event *> m_pending_trans; 110513511Sgabeblack@google.com sc_core::sc_event m_end_request; 110613511Sgabeblack@google.com transaction_type* m_current_transaction; 110713511Sgabeblack@google.com}; 110813511Sgabeblack@google.com 110913511Sgabeblack@google.comtemplate< typename MODULE, unsigned int BUSWIDTH = 32 111013511Sgabeblack@google.com , typename TYPES = tlm::tlm_base_protocol_types > 111113511Sgabeblack@google.comclass simple_target_socket_tagged 111213511Sgabeblack@google.com : public simple_target_socket_tagged_b<MODULE,BUSWIDTH,TYPES> 111313511Sgabeblack@google.com{ 111413511Sgabeblack@google.com typedef simple_target_socket_tagged_b<MODULE,BUSWIDTH,TYPES> socket_b; 111513511Sgabeblack@google.compublic: 111613511Sgabeblack@google.com simple_target_socket_tagged() : socket_b() {} 111713511Sgabeblack@google.com explicit simple_target_socket_tagged(const char* name) : socket_b(name) {} 111813511Sgabeblack@google.com}; 111913511Sgabeblack@google.com 112013511Sgabeblack@google.comtemplate< typename MODULE, unsigned int BUSWIDTH = 32 112113511Sgabeblack@google.com , typename TYPES = tlm::tlm_base_protocol_types > 112213511Sgabeblack@google.comclass simple_target_socket_tagged_optional 112313511Sgabeblack@google.com : public simple_target_socket_tagged_b<MODULE,BUSWIDTH,TYPES,sc_core::SC_ZERO_OR_MORE_BOUND> 112413511Sgabeblack@google.com{ 112513511Sgabeblack@google.com typedef simple_target_socket_tagged_b<MODULE,BUSWIDTH,TYPES,sc_core::SC_ZERO_OR_MORE_BOUND> socket_b; 112613511Sgabeblack@google.compublic: 112713511Sgabeblack@google.com simple_target_socket_tagged_optional() : socket_b() {} 112813511Sgabeblack@google.com explicit simple_target_socket_tagged_optional(const char* name) : socket_b(name) {} 112913511Sgabeblack@google.com}; 113013511Sgabeblack@google.com 113113511Sgabeblack@google.com} // namespace tlm_utils 113213511Sgabeblack@google.com#endif // TLM_UTILS_SIMPLE_TARGET_SOCKET_H_INCLUDED_ 1133