summaryrefslogtreecommitdiff
path: root/ext/systemc/src/tlm_utils
diff options
context:
space:
mode:
Diffstat (limited to 'ext/systemc/src/tlm_utils')
-rw-r--r--ext/systemc/src/tlm_utils/README.txt85
-rw-r--r--ext/systemc/src/tlm_utils/instance_specific_extensions.h306
-rw-r--r--ext/systemc/src/tlm_utils/multi_passthrough_initiator_socket.h299
-rw-r--r--ext/systemc/src/tlm_utils/multi_passthrough_target_socket.h340
-rw-r--r--ext/systemc/src/tlm_utils/multi_socket_bases.h418
-rw-r--r--ext/systemc/src/tlm_utils/passthrough_target_socket.h479
-rw-r--r--ext/systemc/src/tlm_utils/peq_with_cb_and_phase.h301
-rw-r--r--ext/systemc/src/tlm_utils/peq_with_get.h94
-rw-r--r--ext/systemc/src/tlm_utils/simple_initiator_socket.h292
-rw-r--r--ext/systemc/src/tlm_utils/simple_target_socket.h1114
-rwxr-xr-xext/systemc/src/tlm_utils/tlm2_base_protocol_checker.h1055
-rw-r--r--ext/systemc/src/tlm_utils/tlm_quantumkeeper.h172
12 files changed, 4955 insertions, 0 deletions
diff --git a/ext/systemc/src/tlm_utils/README.txt b/ext/systemc/src/tlm_utils/README.txt
new file mode 100644
index 000000000..8be587bdf
--- /dev/null
+++ b/ext/systemc/src/tlm_utils/README.txt
@@ -0,0 +1,85 @@
+
+TLM-2.0 standard utilities
+==========================
+
+Dir: include/tlm_utils
+
+SubDirs:
+
+Files: README.txt
+ instance_specific_extensions.h
+ multi_passthrough_initiator_socket.h
+ multi_passthrough_target_socket.h
+ multi_socket_bases.h
+ peq_with_get.h
+ simple_initiator_socket.h
+ simple_target_socket.h
+ peq_with_cb_and_phase.h
+ passthrough_target_socket.h
+ tlm_quantumkeeper.h
+
+
+Comments
+========
+
+This directory contains a number of ease-of-use and convenience implementations
+for the interoperability standard. All objects defined in the header files of
+this directory are contained in the tlm_util namespace.
+There is no tlm_utils.h header files containing all includes in order to avoid
+additional dependencies for TLM 2.0
+
+Files:
+ simple_initiator_socket.h
+ version of an initiator socket that has a default implementation of all
+ interfaces and allows to register an implementation for any of the
+ interfaces to the socket, either unique interfaces or tagged interfaces
+ (carrying an additional id)
+
+ simple_target_socket.h
+ version of a target socket that has a default implementation of all
+ interfaces and allows to register an implementation for any of the
+ interfaces to the socket, either unique interfaces or tagged interfaces
+ (carrying an additional id)
+ This socket allows to register only 1 of the transport interfaces
+ (blocking or non-blocking) and implements a conversion in case the
+ socket is used on the other interface
+
+ passthrough_target_socket.h
+ version of a target socket that has a default implementation of all
+ interfaces and allows to register an implementation for any of the
+ interfaces to the socket.
+
+ multi_passthrough_initiator_socket.h
+ an implementation of a socket that allows to bind multiple targets to the
+ same initiator socket. Implements a mechanism to allow to identify in the
+ backward path through which index of the socket the call passed through
+
+ multi_passthrough_target_socket.h
+ an implementation of a socket that allows to bind multiple initiators to
+ the same target socket. Implements a mechanism to allow to identify in the
+ forward path through which index of the socket the call passed through
+
+ multi_socket_bases.h
+ contains base class definitions used by the multi_passthrough sockets
+
+ peq_with_get.h
+ payload event queue (PEQ) implementation using a pull interface.
+ Has a get_next_transaction API that returns the transaction that is
+ scheduled in the event queue
+
+ peq_with_cb_and_phase.h
+ another payload event queue, this one with a push interface (callback
+ mechanism ). Allows to register a callback that will be called whenever
+ the event in the event queue is triggered, the callback gets transaction
+ and phase as arguments
+
+ instance_specific_extensions.h
+ is an implementation for adding extentions in the generic payload that
+ are specific to an instance along the path of a transaction, to allow that
+ extentions of the same type can be used by the different blocks along
+ the path of the transaction
+
+ tlm_quantumkeeper.h
+ is an convenience object used to keep track of the local time in
+ an initiator (how much it has run ahead of the SystemC time), to
+ synchronize with SystemC time etc.
diff --git a/ext/systemc/src/tlm_utils/instance_specific_extensions.h b/ext/systemc/src/tlm_utils/instance_specific_extensions.h
new file mode 100644
index 000000000..b17b86219
--- /dev/null
+++ b/ext/systemc/src/tlm_utils/instance_specific_extensions.h
@@ -0,0 +1,306 @@
+/*****************************************************************************
+
+ Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
+ more contributor license agreements. See the NOTICE file distributed
+ with this work for additional information regarding copyright ownership.
+ Accellera licenses this file to you under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with the
+ License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ permissions and limitations under the License.
+
+ *****************************************************************************/
+
+/*
+Instance specific extensions, are extension that only a single instance of a module
+may access. They are invisible to all other modules; they are private to this
+instance so to speak.
+
+As they are only of value to a certain instance, this instance knows very well
+when it needs them and when it does not need them any longer (usually when
+a transaction passes through a module for the last time).
+It does not have to care if anyone else in the system may still have a
+reference to the transaction as this one is not able to access the extension
+anyway.
+Therefore the instance is obliged to call set_extension when it wants to add a
+private extension and clear_extension when it does not need it any more.
+
+To get access to an instance specifc extension the module must own a so called
+instance_specific_extension_accessor that provides the exclusive access rights.
+Assuming the instance_specific_extension_accessor of a given module is called m_accessor
+and the transaction of which the private extension is about to be accessed
+is called txn, then the calls have to be
+
+m_accessor(txn).set_extension(...);
+or
+m_accessor(txn).clear_extension(...);
+
+The owner of the private extension is responsible to allocate/deallocate
+the extension before/after setting/clearing the extension.
+*/
+
+#ifndef __INSTANCE_SPECIFIC_EXTENSIONS_H__
+#define __INSTANCE_SPECIFIC_EXTENSIONS_H__
+
+#include <tlm>
+
+namespace tlm_utils {
+
+//Helper to do the numbering of private extension accessors
+inline unsigned int max_num_ispex_accessors(bool increment=false)
+{
+ static unsigned int max_num = 0;
+ if (increment) ++max_num;
+ return max_num;
+}
+
+//Helper to do the index generation for private extensions
+inline unsigned int max_num_ispex(bool increment=false)
+{
+ static unsigned int max_num = 0;
+ if (increment) ++max_num;
+ return max_num;
+}
+
+//The private extension base. Similar to normal extension base, but without clone and free
+class ispex_base
+{
+public:
+ virtual ~ispex_base() {}
+protected:
+ static unsigned int register_private_extension()
+ {
+ return (max_num_ispex(true) - 1);
+ };
+};
+
+//The templated private extension. Similar to normal extension
+template <typename T>
+class
+instance_specific_extension : public ispex_base{
+public:
+ virtual ~instance_specific_extension() {}
+ const static unsigned int priv_id;
+};
+
+template <typename T>
+const
+unsigned int instance_specific_extension<T>::priv_id = ispex_base::register_private_extension();
+
+
+//this thing is basically a snippet of the generic_payload
+// it contains all the extension specific code (the extension API so to speak)
+// the differences are:
+// - it calls back to its owner whenever a real (==non-NULL) extension gets set for the first time
+// - it calls back to its owner whenever a living (==non-NULL) extension gets cleared
+template<typename U>
+class instance_specific_extensions_per_accessor{
+public:
+
+ typedef void (U::*cb)();
+
+ instance_specific_extensions_per_accessor(U* container, cb inc, cb dec): m_container(container), m_inc(inc), m_dec(dec){
+ }
+
+ template <typename T> T* set_extension(T* ext)
+ {
+ resize_extensions();
+ T* tmp = static_cast<T*>(m_extensions[T::priv_id]);
+ m_extensions[T::priv_id] = static_cast<ispex_base*>(ext);
+ if (!tmp && ext) (m_container->*m_inc)();
+ return tmp;
+ }
+ // non-templatized version with manual index:
+ ispex_base* set_extension(unsigned int index,
+ ispex_base* ext)
+ {
+ resize_extensions();
+ ispex_base* tmp = m_extensions[index];
+ m_extensions[index] = ext;
+ if (!tmp && ext) (m_container->*m_inc)();
+ return tmp;
+ }
+
+ // Check for an extension, ext will point to 0 if not present
+ template <typename T> void get_extension(T*& ext) const
+ {
+ ext = static_cast<T*>(m_extensions[T::priv_id]);
+ }
+ // Non-templatized version:
+ ispex_base* get_extension(unsigned int index) const
+ {
+ return m_extensions[index];
+ }
+
+ // Clear extension, the argument is needed to find the right index:
+ template <typename T> void clear_extension(const T* ext)
+ {
+ resize_extensions();
+ if (m_extensions[T::priv_id]) (m_container->*m_dec)();
+ m_extensions[T::priv_id] = static_cast<ispex_base*>(0);
+ }
+ // Non-templatized version with manual index
+ void clear_extension(unsigned int index)
+ {
+ if (index < m_extensions.size())
+ {
+ if (m_extensions[index]) (m_container->*m_dec)();
+ m_extensions[index] = static_cast<ispex_base*>(0);
+ }
+ }
+
+ // Make sure the extension array is large enough. Can be called once by
+ // an initiator module (before issuing the first transaction) to make
+ // sure that the extension array is of correct size. This is only needed
+ // if the initiator cannot guarantee that the generic payload object is
+ // allocated after C++ static construction time.
+ void resize_extensions()
+ {
+ m_extensions.expand(max_num_ispex());
+ }
+
+private:
+ tlm::tlm_array<ispex_base*> m_extensions;
+ U* m_container;
+ cb m_inc, m_dec;
+
+};
+
+class instance_specific_extension_container;
+
+
+//the pool for the container, plain as can be
+class instance_specific_extension_container_pool{
+ friend class instance_specific_extension_carrier;
+ friend class instance_specific_extension_container;
+ instance_specific_extension_container_pool() : unused(NULL){}
+ inline ~instance_specific_extension_container_pool();
+ inline static instance_specific_extension_container_pool& get_ispexcont_pool(){ static instance_specific_extension_container_pool tmp; return tmp;}
+ inline instance_specific_extension_container* create();
+ inline void free(instance_specific_extension_container*);
+
+ instance_specific_extension_container* unused;
+};
+
+class instance_specific_extension_carrier;
+
+//this thing contains the vector of extensions per accessor
+//which can be really large so this one should be pool allocated
+// therefore it keeps a use_count of itself to automatically free itself
+// - to this end it provides callbacks to the extensions per accessor
+// to increment and decrement the use_count
+class instance_specific_extension_container{
+ friend class instance_specific_extension_container_pool;
+ friend class instance_specific_extension_accessor;
+ friend class instance_specific_extension_carrier;
+
+ instance_specific_extension_container(): use_count(0), next(NULL){resize();}
+
+ void resize(){
+ m_ispex_per_accessor.resize(max_num_ispex_accessors());
+ for (unsigned int i=0; i<m_ispex_per_accessor.size(); i++) {
+ m_ispex_per_accessor[i]=new instance_specific_extensions_per_accessor<instance_specific_extension_container>(this,
+ &instance_specific_extension_container::inc_use_count,
+ &instance_specific_extension_container::dec_use_count
+ );
+ m_ispex_per_accessor[i]->resize_extensions();
+ }
+ }
+
+ ~instance_specific_extension_container(){
+ for (unsigned int i=0; i<m_ispex_per_accessor.size(); i++) delete m_ispex_per_accessor[i];
+ }
+
+ void inc_use_count(){use_count++;}
+ inline void dec_use_count();
+
+ std::vector<instance_specific_extensions_per_accessor<instance_specific_extension_container>* > m_ispex_per_accessor;
+ unsigned int use_count;
+ tlm::tlm_generic_payload* my_txn;
+ instance_specific_extension_carrier* my_carrier;
+ instance_specific_extension_container* next; //for pooling
+};
+
+
+inline instance_specific_extension_container_pool::~instance_specific_extension_container_pool(){
+ while(unused) { instance_specific_extension_container* tmp=unused; unused=unused->next; delete tmp;}
+}
+
+instance_specific_extension_container* instance_specific_extension_container_pool::create(){
+ if (!unused) {unused=new instance_specific_extension_container();}
+ instance_specific_extension_container* tmp=unused;
+ unused=unused->next;
+ return tmp;
+}
+
+void instance_specific_extension_container_pool::free(instance_specific_extension_container* cont){
+ cont->next=unused;
+ unused=cont;
+}
+
+//This is the class that actually sits in the extension array
+//we keep this small since that one gets allocated and deallocated all the times
+class instance_specific_extension_carrier: public tlm::tlm_extension<instance_specific_extension_carrier>{
+ friend class instance_specific_extension_accessor;
+
+public:
+ instance_specific_extension_carrier(){
+ m_container=instance_specific_extension_container_pool::get_ispexcont_pool().create();
+ m_container->my_carrier=this;
+ }
+
+ virtual tlm::tlm_extension_base* clone() const {
+ //we don't clone since private info is instance specific and associated to a given txn (the original)
+ //so the deep copied txn will be virgin in terms of private info
+ return NULL;
+ }
+ void copy_from(tlm::tlm_extension_base const &){return;}
+ void free(){return;}
+private:
+ instance_specific_extension_container* m_container;
+};
+
+inline void instance_specific_extension_container::dec_use_count(){
+ if ((--use_count)==0) { //if this container isn't used any more
+ instance_specific_extension_container_pool::get_ispexcont_pool().free(this); //we send it back to our pool
+ //we have to do that manually, as we cannot rely on the fact that there is MM in the txn
+ my_txn->clear_extension(my_carrier); //and remove it from the transaction's extension array
+ delete my_carrier;
+ }
+}
+
+
+//This class 'hides' all the instance specific extension stuff from the user
+// he instantiates one of those (e.g. instance_specific_extension_accessor extAcc;) and can then access
+// the private extensions
+// extAcc(txn).extensionAPIFnCall()
+// where extensionAPIFnCall is set_extension, get_extension, clear_extension,...
+class instance_specific_extension_accessor{
+public:
+ instance_specific_extension_accessor(): m_index(max_num_ispex_accessors(true)-1){}
+
+ template<typename T>
+ inline instance_specific_extensions_per_accessor<instance_specific_extension_container>& operator()(T& txn){
+ instance_specific_extension_carrier* carrier;
+ txn.get_extension(carrier);
+ if (!carrier){
+ carrier=new instance_specific_extension_carrier();
+ carrier->m_container->my_txn=&txn;
+ txn.set_extension(carrier);
+ }
+ return *(carrier->m_container->m_ispex_per_accessor[m_index]);
+ }
+
+protected:
+ unsigned int m_index;
+};
+
+}
+
+#endif
diff --git a/ext/systemc/src/tlm_utils/multi_passthrough_initiator_socket.h b/ext/systemc/src/tlm_utils/multi_passthrough_initiator_socket.h
new file mode 100644
index 000000000..6404d84bb
--- /dev/null
+++ b/ext/systemc/src/tlm_utils/multi_passthrough_initiator_socket.h
@@ -0,0 +1,299 @@
+/*****************************************************************************
+
+ Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
+ more contributor license agreements. See the NOTICE file distributed
+ with this work for additional information regarding copyright ownership.
+ Accellera licenses this file to you under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with the
+ License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ permissions and limitations under the License.
+
+ *****************************************************************************/
+#ifndef __MULTI_PASSTHROUGH_INITIATOR_SOCKET_H__
+#define __MULTI_PASSTHROUGH_INITIATOR_SOCKET_H__
+
+#include "multi_socket_bases.h"
+
+namespace tlm_utils {
+
+/*
+This class implements a trivial multi initiator socket.
+The triviality refers to the fact that the socket does not
+do blocking to non-blocking or non-blocking to blocking conversions.
+
+It allows to connect multiple targets to this socket.
+The user has to register callbacks for the bw interface methods
+he likes to use. The callbacks are basically equal to the bw interface
+methods but carry an additional integer that indicates to which
+index of this socket the calling target is connected.
+*/
+template <typename MODULE,
+ unsigned int BUSWIDTH = 32,
+ typename TYPES = tlm::tlm_base_protocol_types,
+ unsigned int N=0
+#if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714)
+ ,sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND
+#endif
+ >
+class multi_passthrough_initiator_socket: public multi_init_base< BUSWIDTH,
+ TYPES,
+ N
+#if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714)
+ ,POL
+#endif
+ >
+{
+
+public:
+
+ //typedefs
+ // tlm 2.0 types for nb_transport
+ typedef typename TYPES::tlm_payload_type transaction_type;
+ typedef typename TYPES::tlm_phase_type phase_type;
+ typedef tlm::tlm_sync_enum sync_enum_type;
+
+ // typedefs to keep the fn ptr notations short
+ typedef sync_enum_type (MODULE::*nb_cb)(int,
+ transaction_type&,
+ phase_type&,
+ sc_core::sc_time&);
+ typedef void (MODULE::*dmi_cb)(int, sc_dt::uint64, sc_dt::uint64);
+
+ typedef multi_init_base<BUSWIDTH,
+ TYPES,
+ N
+#if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714)
+ ,POL
+#endif
+ > base_type;
+
+ typedef typename base_type::base_target_socket_type base_target_socket_type;
+
+ //CTOR
+ multi_passthrough_initiator_socket()
+ : base_type(sc_core::sc_gen_unique_name("multi_passthrough_initiator_socket"))
+ , m_hierarch_bind(0)
+ , m_beoe_disabled(false)
+ , m_dummy(42)
+ {
+ }
+
+ //CTOR
+ multi_passthrough_initiator_socket(const char* name)
+ : base_type(name)
+ , m_hierarch_bind(0)
+ , m_beoe_disabled(false)
+ , m_dummy(42)
+ {
+ }
+
+ ~multi_passthrough_initiator_socket(){
+ //clean up everything allocated by 'new'
+ for (unsigned int i=0; i<m_binders.size(); i++) delete m_binders[i];
+ }
+
+ //simple helpers for warnings an errors to shorten in code notation
+ void display_warning(const std::string& text) const {
+ std::stringstream s;
+ s<<"WARNING in instance "<<base_type::name()<<": "<<text;
+ SC_REPORT_WARNING("/OSCI_TLM-2/multi_socket", s.str().c_str());
+ }
+
+ void display_error(const std::string& text) const {
+ std::stringstream s;
+ s<<"ERROR in instance "<<base_type::name()<<": "<<text;
+ SC_REPORT_ERROR("/OSCI_TLM-2/multi_socket", s.str().c_str());
+ }
+
+
+ //register callback for nb transport of bw interface
+ void register_nb_transport_bw(MODULE* mod,
+ sync_enum_type (MODULE::*cb)(int,
+ transaction_type&,
+ phase_type&,
+ sc_core::sc_time&))
+ {
+ //warn if there already is a callback
+ if (!m_nb_f.empty()){
+ display_warning("NBTransport_bw callback already registered.");
+ return;
+ }
+
+ //set the functor
+ m_nb_f.set_function(mod, cb);
+ }
+
+ //register callback for dmi function of bw interface
+ void register_invalidate_direct_mem_ptr(MODULE* mod,
+ void (MODULE::*cb)(int, sc_dt::uint64, sc_dt::uint64))
+ {
+ //warn if there already is a callback
+ if (!m_dmi_f.empty()){
+ display_warning("InvalidateDMI callback already registered.");
+ return;
+ }
+
+ //set the functor
+ m_dmi_f.set_function(mod, cb);
+ }
+
+ //Override virtual functions of the tlm_initiator_socket:
+ // this function is called whenever an sc_port (as part of a target socket)
+ // wants to bind to the export of the underlying tlm_initiator_socket
+ //At this time a callback binder is created an returned to the sc_port
+ // of the target socket, so that it binds to the callback binder
+ virtual tlm::tlm_bw_transport_if<TYPES>& get_base_interface()
+ {
+ m_binders.push_back(new callback_binder_bw<TYPES>(m_binders.size()));
+ return *m_binders[m_binders.size()-1];
+ }
+
+ // const overload not allowed for multi-sockets
+ virtual const tlm::tlm_bw_transport_if<TYPES>& get_base_interface() const
+ {
+ display_error("'get_base_interface()' const not allowed for multi-sockets.");
+ return base_type::get_base_interface();
+ }
+
+ //Override virtual functions of the tlm_initiator_socket:
+ // this function is called whenever an sc_export (as part of a initiator socket)
+ // wants to bind to the export of the underlying tlm_initiator_socket
+ // i.e. a hierarchical bind takes place
+ virtual sc_core::sc_export<tlm::tlm_bw_transport_if<TYPES> >& get_base_export()
+ {
+ if (!m_beoe_disabled) //we are not bound hierarchically
+ base_type::m_export.bind(m_dummy); //so we bind the dummy to avoid a SystemC error
+ return base_type::get_base_export(); //and then return our own export so that the hierarchical binding is set up properly
+ }
+
+ virtual const sc_core::sc_export<tlm::tlm_bw_transport_if<TYPES> >& get_base_export() const
+ {
+ return base_type::get_base_export();
+ }
+
+ //bind against a target socket
+ virtual void bind(base_target_socket_type& s)
+ {
+ //error if this socket is already bound hierarchically
+ if (m_hierarch_bind)
+ display_error("Already hierarchically bound.");
+
+ base_type::bind(s); //satisfy systemC, leads to a call to get_base_interface()
+
+ //try to cast the target socket into a fw interface
+ sc_core::sc_export<tlm::tlm_fw_transport_if<TYPES> >* p_ex_s=dynamic_cast<sc_core::sc_export<tlm::tlm_fw_transport_if<TYPES> >*>(&s);
+ if (!p_ex_s) display_error("Multi socket not bound to tlm_socket.");
+
+ //try a cast into a multi sockets
+ multi_to_multi_bind_base<TYPES>* test=dynamic_cast<multi_to_multi_bind_base<TYPES>*> (p_ex_s);
+ if (test) //did we just do a multi-multi bind??
+ //if that is the case the multi target socket must have just created a callback binder
+ // which we want to get from it.
+ //Moreover, we also just created one, which we will pass to it.
+ m_sockets.push_back(test->get_last_binder(m_binders[m_binders.size()-1]));
+ else{ // if not just bind normally
+ sc_core::sc_export<tlm::tlm_fw_transport_if<TYPES> >& ex_s=*p_ex_s;
+ m_sockets.push_back(&((tlm::tlm_fw_transport_if<TYPES>&)ex_s)); //store the interface we are bound against
+ }
+ }
+
+ //operator notation for direct bind
+ void operator() (base_target_socket_type& s)
+ {
+ bind(s);
+ }
+
+ //SystemC standard callback before end of elaboration
+ void before_end_of_elaboration(){
+ //if our export hasn't been bound yet (due to a hierarch binding)
+ // we bind it now to avoid a SystemC error.
+ //We must do that, because it is legal not to register a callback on this socket
+ // as the user might only use b_transport
+ if (!base_type::m_export.get_interface()){
+ base_type::m_export.bind(m_dummy);
+ }
+
+ //'break' here if the socket was told not to do callback binding
+ if (m_beoe_disabled) return;
+
+ //get the callback binders of the top of the hierachical bind chain
+ // NOTE: this could be the same socket if there is no hierachical bind
+ std::vector<callback_binder_bw<TYPES>* >& binders=get_hierarch_bind()->get_binders();
+
+ //get the interfaces bound to the top of the hierachical bind chain
+ // NOTE: this could be the same socket if there is no hierachical bind
+ m_used_sockets=get_hierarch_bind()->get_sockets();
+
+ //register the callbacks of this socket with the callback binders
+ // we just got from the top of the hierachical bind chain
+ for (unsigned int i=0; i<binders.size(); i++) {
+ binders[i]->set_callbacks(m_nb_f, m_dmi_f);
+ }
+ }
+
+ //
+ // Bind multi initiator socket to multi initiator socket (hierarchical bind)
+ //
+ virtual void bind(base_type& s)
+ {
+ if (m_binders.size()) //a multi socket is either bound hierarchically or directly
+ display_error("Socket already directly bound.");
+ if (m_hierarch_bind){
+ display_warning("Socket already bound hierarchically. Bind attempt ignored.");
+ return;
+ }
+
+ //remember to which socket we are hierarchically bound and disable it,
+ // so that it won't try to register callbacks itself
+ s.disable_cb_bind();
+ m_hierarch_bind=&s;
+ base_type::bind(s); //satisfy SystemC
+ }
+
+ //operator notation for hierarchical bind
+ void operator() (base_type& s)
+ {
+ bind(s);
+ }
+
+ //get access to sub port
+ tlm::tlm_fw_transport_if<TYPES>* operator[](int i){return m_used_sockets[i];}
+
+ //get the number of bound targets
+ // NOTE: this is only valid at end of elaboration!
+ unsigned int size() {return get_hierarch_bind()->get_sockets().size();}
+
+protected:
+ //implementation of base class interface
+ base_type* get_hierarch_bind(){if (m_hierarch_bind) return m_hierarch_bind->get_hierarch_bind(); else return this;}
+ void disable_cb_bind(){ m_beoe_disabled=true;}
+ std::vector<callback_binder_bw<TYPES>* >& get_binders(){return m_binders;}
+ std::vector<tlm::tlm_fw_transport_if<TYPES>*>& get_sockets(){return m_sockets;}
+ //vector of connected sockets
+ std::vector<tlm::tlm_fw_transport_if<TYPES>*> m_sockets;
+ std::vector<tlm::tlm_fw_transport_if<TYPES>*> m_used_sockets;
+ //vector of binders that convert untagged interface into tagged interface
+ std::vector<callback_binder_bw<TYPES>*> m_binders;
+
+ base_type* m_hierarch_bind; //pointer to hierarchical bound multi port
+ bool m_beoe_disabled; // bool that remembers whether this socket shall bind callbacks or not
+ callback_binder_bw<TYPES> m_dummy; //a callback binder that is bound to the underlying export
+ // in case there was no real bind
+
+ //callbacks as functors
+ // (allows to pass the callback to another socket that does not know the type of the module that owns
+ // the callbacks)
+ typename callback_binder_bw<TYPES>::nb_func_type m_nb_f;
+ typename callback_binder_bw<TYPES>::dmi_func_type m_dmi_f;
+};
+
+}
+
+#endif
diff --git a/ext/systemc/src/tlm_utils/multi_passthrough_target_socket.h b/ext/systemc/src/tlm_utils/multi_passthrough_target_socket.h
new file mode 100644
index 000000000..03270f7a1
--- /dev/null
+++ b/ext/systemc/src/tlm_utils/multi_passthrough_target_socket.h
@@ -0,0 +1,340 @@
+/*****************************************************************************
+
+ Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
+ more contributor license agreements. See the NOTICE file distributed
+ with this work for additional information regarding copyright ownership.
+ Accellera licenses this file to you under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with the
+ License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ permissions and limitations under the License.
+
+ *****************************************************************************/
+#ifndef __MULTI_PASSTHROUGH_TARGET_SOCKET_H__
+#define __MULTI_PASSTHROUGH_TARGET_SOCKET_H__
+
+#include "tlm_utils/multi_socket_bases.h"
+#include <sstream>
+
+namespace tlm_utils {
+
+/*
+This class implements a trivial multi target socket.
+The triviality refers to the fact that the socket does not
+do blocking to non-blocking or non-blocking to blocking conversions.
+
+It allows to connect multiple initiators to this socket.
+The user has to register callbacks for the fw interface methods
+he likes to use. The callbacks are basically equal to the fw interface
+methods but carry an additional integer that indicates to which
+index of this socket the calling initiator is connected.
+*/
+template <typename MODULE,
+ unsigned int BUSWIDTH = 32,
+ typename TYPES = tlm::tlm_base_protocol_types,
+ unsigned int N=0
+#if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714)
+ ,sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND
+#endif
+ >
+class multi_passthrough_target_socket: public multi_target_base< BUSWIDTH,
+ TYPES,
+ N
+#if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714)
+ ,POL
+#endif
+ >
+ , public multi_to_multi_bind_base<TYPES>
+{
+
+public:
+
+ //typedefs
+ // tlm 2.0 types for nb_transport
+ typedef typename TYPES::tlm_payload_type transaction_type;
+ typedef typename TYPES::tlm_phase_type phase_type;
+ typedef tlm::tlm_sync_enum sync_enum_type;
+
+ // typedefs to keep the fn ptr notations short
+ typedef sync_enum_type (MODULE::*nb_cb)(int, transaction_type&, phase_type&, sc_core::sc_time&);
+ typedef void (MODULE::*b_cb)(int, transaction_type&, sc_core::sc_time&);
+ typedef unsigned int (MODULE::*dbg_cb)(int, transaction_type& txn);
+ typedef bool (MODULE::*dmi_cb)(int, transaction_type& txn, tlm::tlm_dmi& dmi);
+
+ typedef multi_target_base<BUSWIDTH,
+ TYPES,
+ N
+#if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714)
+ ,POL
+#endif
+ > base_type;
+
+ typedef typename base_type::base_initiator_socket_type base_initiator_socket_type;
+
+ //CTOR
+ multi_passthrough_target_socket()
+ : base_type(sc_core::sc_gen_unique_name("multi_passthrough_target_socket"))
+ , m_hierarch_bind(0)
+ , m_eoe_disabled(false)
+ , m_export_callback_created(false)
+ {
+ }
+
+ //CTOR
+ multi_passthrough_target_socket(const char* name)
+ : base_type(name)
+ , m_hierarch_bind(0)
+ , m_eoe_disabled(false)
+ , m_export_callback_created(false)
+ {
+ }
+
+ ~multi_passthrough_target_socket(){
+ //clean up everything allocated by 'new'
+ for (unsigned int i=0; i<m_binders.size(); i++) delete m_binders[i];
+ }
+
+ //simple helpers for warnings an errors to shorten in code notation
+ void display_warning(const std::string& text) const {
+ std::stringstream s;
+ s<<"WARNING in instance "<<base_type::name()<<": "<<text;
+ SC_REPORT_WARNING("/OSCI_TLM-2/multi_socket", s.str().c_str());
+ }
+
+ void display_error(const std::string& text) const {
+ std::stringstream s;
+ s<<"ERROR in instance "<<base_type::name()<<": "<<text;
+ SC_REPORT_ERROR("/OSCI_TLM-2/multi_socket", s.str().c_str());
+ }
+
+ void check_export_binding()
+ {
+ //if our export hasn't been bound yet (due to a hierarch binding)
+ // we bind it now.
+ //We do that here as the user of the target port HAS to bind at least on callback,
+ //otherwise the socket was useless. Nevertheless, the target socket may still
+ // stay unbound afterwards.
+ if (!sc_core::sc_export<tlm::tlm_fw_transport_if<TYPES> >::get_interface())
+ {
+ // We bind to a callback_binder that will be used as the first interface
+ // i.e. calls to the sc_export will have the same ID as calls from the first initator
+ // socket bound
+ callback_binder_fw<TYPES> * binder;
+
+ if (m_binders.size() == 0)
+ {
+ binder = new callback_binder_fw<TYPES>(m_binders.size());
+ m_binders.push_back(binder);
+ m_export_callback_created = true;
+ }
+ else
+ {
+ binder = m_binders[0];
+ }
+
+ sc_core::sc_export<tlm::tlm_fw_transport_if<TYPES> >::bind(*binder);
+ }
+ }
+
+ //register callback for nb transport of fw interface
+ void register_nb_transport_fw(MODULE* mod,
+ nb_cb cb)
+ {
+ check_export_binding();
+
+ //warn if there already is a callback
+ if (!m_nb_f.empty()){
+ display_warning("NBTransport_bw callback already registered.");
+ return;
+ }
+
+ //set the functor
+ m_nb_f.set_function(mod, cb);
+ }
+
+ //register callback for b transport of fw interface
+ void register_b_transport(MODULE* mod,
+ b_cb cb)
+ {
+ check_export_binding();
+
+ //warn if there already is a callback
+ if (!m_b_f.empty()){
+ display_warning("BTransport callback already registered.");
+ return;
+ }
+
+ //set the functor
+ m_b_f.set_function(mod, cb);
+ }
+
+ //register callback for debug transport of fw interface
+ void register_transport_dbg(MODULE* mod,
+ dbg_cb cb)
+ {
+ check_export_binding();
+
+ //warn if there already is a callback
+ if (!m_dbg_f.empty()){
+ display_warning("DebugTransport callback already registered.");
+ return;
+ }
+
+ //set the functor
+ m_dbg_f.set_function(mod, cb);
+ }
+
+ //register callback for DMI of fw interface
+ void register_get_direct_mem_ptr(MODULE* mod,
+ dmi_cb cb)
+ {
+ check_export_binding();
+
+ //warn if there already is a callback
+ if (!m_dmi_f.empty()){
+ display_warning("DMI callback already registered.");
+ return;
+ }
+
+ //set the functor
+ m_dmi_f.set_function(mod, cb);
+ }
+
+
+ //Override virtual functions of the tlm_target_socket:
+ // this function is called whenever an sc_port (as part of a init socket)
+ // wants to bind to the export of the underlying tlm_target_socket
+ //At this time a callback binder is created an returned to the sc_port
+ // of the init socket, so that it binds to the callback binder
+ virtual tlm::tlm_fw_transport_if<TYPES>& get_base_interface()
+ {
+ //error if this socket is already bound hierarchically
+ if (m_hierarch_bind) display_error("Socket already bound hierarchically.");
+
+ if (!m_export_callback_created)
+ m_binders.push_back(new callback_binder_fw<TYPES>(m_binders.size()));
+ else
+ m_export_callback_created = false;
+
+ return *m_binders[m_binders.size()-1];
+ }
+
+ // const overload not allowed for multi-sockets
+ virtual const tlm::tlm_fw_transport_if<TYPES>& get_base_interface() const
+ {
+ display_error("'get_base_interface()' const not allowed for multi-sockets.");
+ return base_type::get_base_interface();
+ }
+
+ //just return the export of the underlying tlm_target_socket in case of a hierarchical bind
+ virtual sc_core::sc_export<tlm::tlm_fw_transport_if<TYPES> >& get_base_export()
+ {
+ return *this;
+ }
+
+ //just return the export of the underlying tlm_target_socket in case of a hierarchical bind
+ virtual const sc_core::sc_export<tlm::tlm_fw_transport_if<TYPES> >& get_base_export() const
+ {
+ return base_type::get_base_export();
+ }
+
+ //the standard end of elaboration callback
+ void end_of_elaboration(){
+ //'break' here if the socket was told not to do callback binding
+ if (m_eoe_disabled) return;
+
+ //get the callback binders and the multi binds of the top of the hierachical bind chain
+ // NOTE: this could be the same socket if there is no hierachical bind
+ std::vector<callback_binder_fw<TYPES>* >& binders=get_hierarch_bind()->get_binders();
+ std::map<unsigned int, tlm::tlm_bw_transport_if<TYPES>*>& multi_binds=get_hierarch_bind()->get_multi_binds();
+
+ //iterate over all binders
+ for (unsigned int i=0; i<binders.size(); i++) {
+ binders[i]->set_callbacks(m_nb_f, m_b_f, m_dmi_f, m_dbg_f); //set the callbacks for the binder
+ if (multi_binds.find(i)!=multi_binds.end()) //check if this connection is multi-multi
+ //if so remember the interface
+ m_sockets.push_back(multi_binds[i]);
+ else{ //if we are bound to a normal socket
+ //get the calling port and try to cast it into a tlm socket base
+ base_initiator_socket_type* test=dynamic_cast<base_initiator_socket_type*>(binders[i]->get_other_side());
+ if (!test){display_error("Not bound to tlm_socket.");}
+ m_sockets.push_back(&test->get_base_interface()); //remember the interface
+ }
+ }
+ }
+
+ //
+ // Bind multi target socket to multi target socket (hierarchical bind)
+ //
+ virtual void bind(base_type& s)
+ {
+ //warn if already bound hierarchically
+ if (m_eoe_disabled){
+ display_warning("Socket already bound hierarchically. Bind attempt ignored.");
+ return;
+ }
+
+ //disable our own end of elaboration call
+ disable_cb_bind();
+
+ //inform the bound target socket that it is bound hierarchically now
+ s.set_hierarch_bind((base_type*)this);
+ base_type::bind(s); //satisfy SystemC
+ }
+
+ //operator notation for hierarchical bind
+ void operator() (base_type& s)
+ {
+ bind(s);
+ }
+
+ //get access to sub port
+ tlm::tlm_bw_transport_if<TYPES>* operator[](int i){return m_sockets[i];}
+
+ //get number of bound initiators
+ // NOTE: this is only valid at end of elaboration!
+ unsigned int size(){return get_hierarch_bind()->get_binders().size();}
+
+protected:
+ //implementation of base class interface
+ base_type* get_hierarch_bind(){if (m_hierarch_bind) return m_hierarch_bind->get_hierarch_bind(); else return this;}
+ std::map<unsigned int, tlm::tlm_bw_transport_if<TYPES>*>& get_multi_binds(){return m_multi_binds;}
+ void set_hierarch_bind(base_type* h){m_hierarch_bind=h;}
+ tlm::tlm_fw_transport_if<TYPES>* get_last_binder(tlm::tlm_bw_transport_if<TYPES>* other){
+ m_multi_binds[m_binders.size()-1]=other;
+ return m_binders[m_binders.size()-1];
+ }
+
+ //map that stores to which index a multi init socket is connected
+ // and the interface of the multi init socket
+ std::map<unsigned int, tlm::tlm_bw_transport_if<TYPES>*> m_multi_binds;
+
+ void disable_cb_bind(){ m_eoe_disabled=true;}
+ std::vector<callback_binder_fw<TYPES>* >& get_binders(){return m_binders;}
+ //vector of connected sockets
+ std::vector<tlm::tlm_bw_transport_if<TYPES>*> m_sockets;
+ //vector of binders that convert untagged interface into tagged interface
+ std::vector<callback_binder_fw<TYPES>*> m_binders;
+
+ base_type* m_hierarch_bind; //pointer to hierarchical bound multi port
+ bool m_eoe_disabled; //bool that diables callback bindings at end of elaboration
+ bool m_export_callback_created; // bool to indicate that a callback has already been created for export binding
+
+ //callbacks as functors
+ // (allows to pass the callback to another socket that does not know the type of the module that owns
+ // the callbacks)
+ typename callback_binder_fw<TYPES>::nb_func_type m_nb_f;
+ typename callback_binder_fw<TYPES>::b_func_type m_b_f;
+ typename callback_binder_fw<TYPES>::debug_func_type m_dbg_f;
+ typename callback_binder_fw<TYPES>::dmi_func_type m_dmi_f;
+};
+
+}
+
+#endif
diff --git a/ext/systemc/src/tlm_utils/multi_socket_bases.h b/ext/systemc/src/tlm_utils/multi_socket_bases.h
new file mode 100644
index 000000000..457398495
--- /dev/null
+++ b/ext/systemc/src/tlm_utils/multi_socket_bases.h
@@ -0,0 +1,418 @@
+/*****************************************************************************
+
+ Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
+ more contributor license agreements. See the NOTICE file distributed
+ with this work for additional information regarding copyright ownership.
+ Accellera licenses this file to you under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with the
+ License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ permissions and limitations under the License.
+
+ *****************************************************************************/
+
+#ifndef __MULTI_SOCKET_BASES_H__
+#define __MULTI_SOCKET_BASES_H__
+
+#include <systemc>
+#include <tlm>
+
+#include <map>
+#include <sstream>
+
+namespace tlm_utils {
+
+template <typename signature>
+struct fn_container{
+ signature function;
+};
+
+#define TLM_DEFINE_FUNCTOR(name) \
+template <typename MODULE, typename TRAITS> \
+inline TLM_RET_VAL static_##name( void* mod \
+ , void* fn \
+ , int index \
+ , TLM_FULL_ARG_LIST) \
+{ \
+ typedef fn_container<TLM_RET_VAL (MODULE::*)(int, TLM_FULL_ARG_LIST)> fn_container_type; \
+ MODULE* tmp_mod=static_cast<MODULE*>(mod); \
+ fn_container_type* tmp_cb =static_cast<fn_container_type*> (fn); \
+ return (tmp_mod->*(tmp_cb->function))(index, TLM_ARG_LIST_WITHOUT_TYPES); \
+}\
+\
+template <typename MODULE, typename TRAITS> \
+inline void delete_fn_container_of_##name(void* fn) \
+{ \
+ typedef fn_container<TLM_RET_VAL (MODULE::*)(int, TLM_FULL_ARG_LIST)> fn_container_type; \
+ fn_container_type* tmp_cb =static_cast<fn_container_type*> (fn); \
+ if (tmp_cb) delete tmp_cb;\
+} \
+\
+template <typename TRAITS> \
+class name##_functor{ \
+public: \
+ typedef typename TRAITS::tlm_payload_type payload_type; \
+ typedef typename TRAITS::tlm_phase_type phase_type; \
+ typedef TLM_RET_VAL (*call_fn)(void*,void*, int, TLM_FULL_ARG_LIST); \
+ typedef void (*del_fn)(void*); \
+\
+ name##_functor(): m_fn(0), m_del_fn(0), m_mod(0), m_mem_fn(0){} \
+ ~name##_functor(){if (m_del_fn) (*m_del_fn)(m_mem_fn);} \
+\
+ template <typename MODULE> \
+ void set_function(MODULE* mod, TLM_RET_VAL (MODULE::*cb)(int, TLM_FULL_ARG_LIST)){ \
+ typedef fn_container<TLM_RET_VAL (MODULE::*)(int, TLM_FULL_ARG_LIST)> fn_container_type; \
+ m_fn=&static_##name<MODULE,TRAITS>;\
+ m_del_fn=&delete_fn_container_of_##name<MODULE,TRAITS>;\
+ m_del_fn(m_mem_fn); \
+ fn_container_type* tmp= new fn_container_type(); \
+ tmp->function=cb; \
+ m_mod=static_cast<void*>(mod); \
+ m_mem_fn=static_cast<void*>(tmp); \
+ } \
+ \
+ TLM_RET_VAL operator()(int index, TLM_FULL_ARG_LIST){ \
+ return m_fn(m_mod,m_mem_fn, index, TLM_ARG_LIST_WITHOUT_TYPES); \
+ } \
+\
+ bool empty(){return (m_mod==0 || m_mem_fn==0 || m_fn==0);}\
+\
+protected: \
+ call_fn m_fn;\
+ del_fn m_del_fn; \
+ void* m_mod; \
+ void* m_mem_fn; \
+private: \
+ name##_functor& operator=(const name##_functor&); \
+}
+
+
+#define TLM_RET_VAL tlm::tlm_sync_enum
+#define TLM_FULL_ARG_LIST typename TRAITS::tlm_payload_type& txn, typename TRAITS::tlm_phase_type& ph, sc_core::sc_time& t
+#define TLM_ARG_LIST_WITHOUT_TYPES txn,ph,t
+TLM_DEFINE_FUNCTOR(nb_transport);
+#undef TLM_RET_VAL
+#undef TLM_FULL_ARG_LIST
+#undef TLM_ARG_LIST_WITHOUT_TYPES
+
+#define TLM_RET_VAL void
+#define TLM_FULL_ARG_LIST typename TRAITS::tlm_payload_type& txn, sc_core::sc_time& t
+#define TLM_ARG_LIST_WITHOUT_TYPES txn,t
+TLM_DEFINE_FUNCTOR(b_transport);
+#undef TLM_RET_VAL
+#undef TLM_FULL_ARG_LIST
+#undef TLM_ARG_LIST_WITHOUT_TYPES
+
+#define TLM_RET_VAL unsigned int
+#define TLM_FULL_ARG_LIST typename TRAITS::tlm_payload_type& txn
+#define TLM_ARG_LIST_WITHOUT_TYPES txn
+TLM_DEFINE_FUNCTOR(debug_transport);
+#undef TLM_RET_VAL
+#undef TLM_FULL_ARG_LIST
+#undef TLM_ARG_LIST_WITHOUT_TYPES
+
+#define TLM_RET_VAL bool
+#define TLM_FULL_ARG_LIST typename TRAITS::tlm_payload_type& txn, tlm::tlm_dmi& dmi
+#define TLM_ARG_LIST_WITHOUT_TYPES txn,dmi
+TLM_DEFINE_FUNCTOR(get_dmi_ptr);
+#undef TLM_RET_VAL
+#undef TLM_FULL_ARG_LIST
+#undef TLM_ARG_LIST_WITHOUT_TYPES
+
+#define TLM_RET_VAL void
+#define TLM_FULL_ARG_LIST sc_dt::uint64 l, sc_dt::uint64 u
+#define TLM_ARG_LIST_WITHOUT_TYPES l,u
+TLM_DEFINE_FUNCTOR(invalidate_dmi);
+#undef TLM_RET_VAL
+#undef TLM_FULL_ARG_LIST
+#undef TLM_ARG_LIST_WITHOUT_TYPES
+
+#undef TLM_DEFINE_FUNCTOR
+
+/*
+This class implements the fw interface.
+It allows to register a callback for each of the fw interface methods.
+The callbacks simply forward the fw interface call, but add the id (an int)
+of the callback binder to the signature of the call.
+*/
+template <typename TYPES>
+class callback_binder_fw: public tlm::tlm_fw_transport_if<TYPES>{
+ public:
+ //typedefs according to the used TYPES class
+ typedef typename TYPES::tlm_payload_type transaction_type;
+ typedef typename TYPES::tlm_phase_type phase_type;
+ typedef tlm::tlm_sync_enum sync_enum_type;
+
+ //typedefs for the callbacks
+ typedef nb_transport_functor<TYPES> nb_func_type;
+ typedef b_transport_functor<TYPES> b_func_type;
+ typedef debug_transport_functor<TYPES> debug_func_type;
+ typedef get_dmi_ptr_functor<TYPES> dmi_func_type;
+
+ //ctor: an ID is needed to create a callback binder
+ callback_binder_fw(int id): m_id(id), m_nb_f(0), m_b_f(0), m_dbg_f(0), m_dmi_f(0), m_caller_port(0) {
+ }
+
+ //the nb_transport method of the fw interface
+ sync_enum_type nb_transport_fw(transaction_type& txn,
+ phase_type& p,
+ sc_core::sc_time& t){
+ //check if a callback is registered
+ if ((m_nb_f == 0) || (m_nb_f && m_nb_f->empty())) {
+ //std::cerr<<"No function registered"<<std::endl;
+ SC_REPORT_ERROR("/OSCI_TLM-2/multi_socket","Call to nb_transport_fw without a registered callback for nb_transport_fw.");
+ }
+ else
+ return (*m_nb_f)(m_id, txn, p, t); //do the callback
+ return tlm::TLM_ACCEPTED; //unreachable
+ }
+
+ //the b_transport method of the fw interface
+ void b_transport(transaction_type& trans,sc_core::sc_time& t){
+ //check if a callback is registered
+ if ((m_b_f == 0) || (m_b_f && m_b_f->empty())) {
+ SC_REPORT_ERROR("/OSCI_TLM-2/multi_socket","Call to b_transport without a registered callback for b_transport.");
+ }
+ else
+ (*m_b_f)(m_id, trans,t); //do the callback
+ }
+
+ //the DMI method of the fw interface
+ bool get_direct_mem_ptr(transaction_type& trans, tlm::tlm_dmi& dmi_data){
+ //check if a callback is registered
+ if ((m_dmi_f == 0) && (m_dmi_f && m_dmi_f->empty())) {
+ dmi_data.allow_none();
+ dmi_data.set_start_address(0x0);
+ dmi_data.set_end_address((sc_dt::uint64)-1);
+ return false;
+ }
+ else
+ return (*m_dmi_f)(m_id, trans,dmi_data); //do the callback
+ }
+
+ //the debug method of the fw interface
+ unsigned int transport_dbg(transaction_type& trans){
+ //check if a callback is registered
+ if ((m_dbg_f == 0) || (m_dbg_f && m_dbg_f->empty())) {
+ return 0;
+ }
+ else
+ return (*m_dbg_f)(m_id, trans); //do the callback
+ }
+
+ //the SystemC standard callback register_port:
+ // - called when a port if bound to the interface
+ // - allowd to find out who is bound to that callback binder
+ void register_port(sc_core::sc_port_base& b, const char* name){
+ m_caller_port=&b;
+ }
+
+ //register callbacks for all fw interface methods at once
+ void set_callbacks(nb_func_type& cb1, b_func_type& cb2, dmi_func_type& cb3, debug_func_type& cb4){
+ m_nb_f=&cb1;
+ m_b_f=&cb2;
+ m_dmi_f=&cb3;
+ m_dbg_f=&cb4;
+ }
+
+ //getter method to get the port that is bound to that callback binder
+ // NOTE: this will only return a valid value at end of elaboration
+ // (but not before end of elaboration!)
+ sc_core::sc_port_base* get_other_side(){return m_caller_port;}
+
+ private:
+ //the ID of the callback binder
+ int m_id;
+
+ //the callbacks
+ nb_func_type* m_nb_f;
+ b_func_type* m_b_f;
+ debug_func_type* m_dbg_f;
+ dmi_func_type* m_dmi_f;
+
+ //the port bound to that callback binder
+ sc_core::sc_port_base* m_caller_port;
+};
+
+/*
+This class implements the bw interface.
+It allows to register a callback for each of the bw interface methods.
+The callbacks simply forward the bw interface call, but add the id (an int)
+of the callback binder to the signature of the call.
+*/
+template <typename TYPES>
+class callback_binder_bw: public tlm::tlm_bw_transport_if<TYPES>{
+ public:
+ //typedefs according to the used TYPES class
+ typedef typename TYPES::tlm_payload_type transaction_type;
+ typedef typename TYPES::tlm_phase_type phase_type;
+ typedef tlm::tlm_sync_enum sync_enum_type;
+
+ //typedefs for the callbacks
+ typedef nb_transport_functor<TYPES> nb_func_type;
+ typedef invalidate_dmi_functor<TYPES> dmi_func_type;
+
+ //ctor: an ID is needed to create a callback binder
+ callback_binder_bw(int id): m_id(id), m_nb_f(0), m_dmi_f(0) {
+ }
+
+ //the nb_transport method of the bw interface
+ sync_enum_type nb_transport_bw(transaction_type& txn,
+ phase_type& p,
+ sc_core::sc_time& t){
+ //check if a callback is registered
+ if ((m_nb_f == 0) || (m_nb_f && m_nb_f->empty())) {
+ SC_REPORT_ERROR("/OSCI_TLM-2/multi_socket","Call to nb_transport_bw without a registered callback for nb_transport_bw");
+ }
+ else
+ return (*m_nb_f)(m_id, txn, p, t); //do the callback
+ return tlm::TLM_ACCEPTED; //unreachable
+ }
+
+ //the DMI method of the bw interface
+ void invalidate_direct_mem_ptr(sc_dt::uint64 l, sc_dt::uint64 u){
+ //check if a callback is registered
+ if ((m_dmi_f == 0) || (m_dmi_f && m_dmi_f->empty())) {
+ return;
+ }
+ else
+ (*m_dmi_f)(m_id,l,u); //do the callback
+ }
+
+ //register callbacks for all bw interface methods at once
+ void set_callbacks(nb_func_type& cb1, dmi_func_type& cb2){
+ m_nb_f=&cb1;
+ m_dmi_f=&cb2;
+ }
+
+ private:
+ //the ID of the callback binder
+ int m_id;
+ //the callbacks
+ nb_func_type* m_nb_f;
+ dmi_func_type* m_dmi_f;
+};
+
+
+/*
+This class forms the base for multi initiator sockets.
+It enforces a multi initiator socket to implement all functions
+needed to do hierarchical bindings.
+*/
+template <unsigned int BUSWIDTH = 32,
+ typename TYPES = tlm::tlm_base_protocol_types,
+ unsigned int N=0
+#if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714)
+ ,sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND
+#endif
+ >
+class multi_init_base: public tlm::tlm_initiator_socket<BUSWIDTH,
+ TYPES,
+ N
+#if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714)
+ ,POL
+#endif
+ >{
+public:
+ //typedef for the base type: the standard tlm initiator socket
+ typedef tlm::tlm_initiator_socket<BUSWIDTH,
+ TYPES,
+ N
+#if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714)
+ ,POL
+#endif
+ > base_type;
+
+ //this method shall disable the code that does the callback binding
+ // that registers callbacks to binders
+ virtual void disable_cb_bind()=0;
+
+ //this method shall return the multi_init_base to which the
+ // multi_init_base is bound hierarchically
+ // If the base is not bound hierarchically it shall return a pointer to itself
+ virtual multi_init_base* get_hierarch_bind()=0;
+
+ //this method shall return a vector of the callback binders of multi initiator socket
+ virtual std::vector<callback_binder_bw<TYPES>* >& get_binders()=0;
+
+ //this method shall return a vector of all target interfaces bound to this multi init socket
+ virtual std::vector<tlm::tlm_fw_transport_if<TYPES>*>& get_sockets()=0;
+
+ //ctor and dtor
+ virtual ~multi_init_base(){}
+ multi_init_base():base_type(sc_core::sc_gen_unique_name("multi_init_base")){}
+ multi_init_base(const char* name):base_type(name){}
+};
+
+/*
+This class forms the base for multi target sockets.
+It enforces a multi target socket to implement all functions
+needed to do hierarchical bindings.
+*/
+template <unsigned int BUSWIDTH = 32,
+ typename TYPES = tlm::tlm_base_protocol_types,
+ unsigned int N=0
+#if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714)
+ ,sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND
+#endif
+ >
+class multi_target_base: public tlm::tlm_target_socket<BUSWIDTH,
+ TYPES,
+ N
+#if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714)
+ ,POL
+#endif
+ >{
+public:
+ //typedef for the base type: the standard tlm target socket
+ typedef tlm::tlm_target_socket<BUSWIDTH,
+ TYPES,
+ N
+#if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714)
+ ,POL
+#endif
+ > base_type;
+
+ //this method shall return the multi_init_base to which the
+ // multi_init_base is bound hierarchically
+ // If the base is not bound hierarchically it shall return a pointer to itself
+ virtual multi_target_base* get_hierarch_bind()=0;
+
+ //this method shall inform the multi target socket that it is bound
+ // hierarchically and to which other multi target socket it is bound hierarchically
+ virtual void set_hierarch_bind(multi_target_base*)=0;
+
+ //this method shall return a vector of the callback binders of multi initiator socket
+ virtual std::vector<callback_binder_fw<TYPES>* >& get_binders()=0;
+
+ //this method shall return a map of all multi initiator sockets that are bound to this multi target
+ // the key of the map is the index at which the multi initiator i bound, while the value
+ // is the interface of the multi initiator socket that is bound at that index
+ virtual std::map<unsigned int, tlm::tlm_bw_transport_if<TYPES>*>& get_multi_binds()=0;
+
+ //ctor and dtor
+ virtual ~multi_target_base(){}
+ multi_target_base():base_type(sc_core::sc_gen_unique_name("multi_target_base")){}
+ multi_target_base(const char* name):base_type(name){}
+};
+
+/*
+All multi sockets must additionally derive from this class.
+It enforces a multi socket to implement a function
+needed to do multi init to multi target bindings.
+*/
+template <typename TYPES>
+class multi_to_multi_bind_base{
+public:
+ virtual ~multi_to_multi_bind_base(){}
+ virtual tlm::tlm_fw_transport_if<TYPES>* get_last_binder(tlm::tlm_bw_transport_if<TYPES>*)=0;
+};
+
+}
+#endif
diff --git a/ext/systemc/src/tlm_utils/passthrough_target_socket.h b/ext/systemc/src/tlm_utils/passthrough_target_socket.h
new file mode 100644
index 000000000..1a3b14df7
--- /dev/null
+++ b/ext/systemc/src/tlm_utils/passthrough_target_socket.h
@@ -0,0 +1,479 @@
+/*****************************************************************************
+
+ Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
+ more contributor license agreements. See the NOTICE file distributed
+ with this work for additional information regarding copyright ownership.
+ Accellera licenses this file to you under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with the
+ License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ permissions and limitations under the License.
+
+ *****************************************************************************/
+
+#ifndef __PASSTHROUGH_TARGET_SOCKET_H__
+#define __PASSTHROUGH_TARGET_SOCKET_H__
+
+#include <tlm>
+#include <sstream>
+
+namespace tlm_utils {
+
+template <typename MODULE,
+ unsigned int BUSWIDTH = 32,
+ typename TYPES = tlm::tlm_base_protocol_types>
+class passthrough_target_socket :
+ public tlm::tlm_target_socket<BUSWIDTH, TYPES>
+{
+public:
+ typedef typename TYPES::tlm_payload_type transaction_type;
+ typedef typename TYPES::tlm_phase_type phase_type;
+ typedef tlm::tlm_sync_enum sync_enum_type;
+ typedef tlm::tlm_fw_transport_if<TYPES> fw_interface_type;
+ typedef tlm::tlm_bw_transport_if<TYPES> bw_interface_type;
+ typedef tlm::tlm_target_socket<BUSWIDTH, TYPES> base_type;
+
+public:
+ passthrough_target_socket() :
+ base_type(sc_core::sc_gen_unique_name("passthrough_target_socket")),
+ m_process(this->name())
+ {
+ bind(m_process);
+ }
+
+ explicit passthrough_target_socket(const char* n) :
+ base_type(n),
+ m_process(this->name())
+ {
+ bind(m_process);
+ }
+
+ using tlm::tlm_target_socket<BUSWIDTH, TYPES>::bind;
+
+ // REGISTER_XXX
+ void register_nb_transport_fw(MODULE* mod,
+ sync_enum_type (MODULE::*cb)(transaction_type&,
+ phase_type&,
+ sc_core::sc_time&))
+ {
+ m_process.set_nb_transport_ptr(mod, cb);
+ }
+
+ void register_b_transport(MODULE* mod,
+ void (MODULE::*cb)(transaction_type&,
+ sc_core::sc_time&))
+ {
+ m_process.set_b_transport_ptr(mod, cb);
+ }
+
+ void register_transport_dbg(MODULE* mod,
+ unsigned int (MODULE::*cb)(transaction_type&))
+ {
+ m_process.set_transport_dbg_ptr(mod, cb);
+ }
+
+ void register_get_direct_mem_ptr(MODULE* mod,
+ bool (MODULE::*cb)(transaction_type&,
+ tlm::tlm_dmi&))
+ {
+ m_process.set_get_direct_mem_ptr(mod, cb);
+ }
+
+private:
+ class process : public tlm::tlm_fw_transport_if<TYPES>
+ {
+ public:
+ typedef sync_enum_type (MODULE::*NBTransportPtr)(transaction_type&,
+ phase_type&,
+ sc_core::sc_time&);
+ typedef void (MODULE::*BTransportPtr)(transaction_type&,
+ sc_core::sc_time&);
+ typedef unsigned int (MODULE::*TransportDbgPtr)(transaction_type&);
+ typedef bool (MODULE::*GetDirectMem_ptr)(transaction_type&,
+ tlm::tlm_dmi&);
+
+ process(const std::string& name) :
+ m_name(name),
+ m_mod(0),
+ m_nb_transport_ptr(0),
+ m_b_transport_ptr(0),
+ m_transport_dbg_ptr(0),
+ m_get_direct_mem_ptr(0)
+ {
+ }
+
+ void set_nb_transport_ptr(MODULE* mod, NBTransportPtr p)
+ {
+ if (m_nb_transport_ptr) {
+ std::stringstream s;
+ s << m_name << ": non-blocking callback allready registered";
+ SC_REPORT_WARNING("/OSCI_TLM-2/passthrough_socket",s.str().c_str());
+
+ } else {
+ assert(!m_mod || m_mod == mod);
+ m_mod = mod;
+ m_nb_transport_ptr = p;
+ }
+ }
+
+ void set_b_transport_ptr(MODULE* mod, BTransportPtr p)
+ {
+ if (m_b_transport_ptr) {
+ std::stringstream s;
+ s << m_name << ": blocking callback allready registered";
+ SC_REPORT_WARNING("/OSCI_TLM-2/passthrough_socket",s.str().c_str());
+ } else {
+ assert(!m_mod || m_mod == mod);
+ m_mod = mod;
+ m_b_transport_ptr = p;
+ }
+ }
+
+ void set_transport_dbg_ptr(MODULE* mod, TransportDbgPtr p)
+ {
+ if (m_transport_dbg_ptr) {
+ std::stringstream s;
+ s << m_name << ": debug callback allready registered";
+ SC_REPORT_WARNING("/OSCI_TLM-2/passthrough_socket",s.str().c_str());
+ } else {
+ assert(!m_mod || m_mod == mod);
+ m_mod = mod;
+ m_transport_dbg_ptr = p;
+ }
+ }
+
+ void set_get_direct_mem_ptr(MODULE* mod, GetDirectMem_ptr p)
+ {
+ if (m_get_direct_mem_ptr) {
+ std::stringstream s;
+ s << m_name << ": get DMI pointer callback allready registered";
+ SC_REPORT_WARNING("/OSCI_TLM-2/passthrough_socket",s.str().c_str());
+ } else {
+ assert(!m_mod || m_mod == mod);
+ m_mod = mod;
+ m_get_direct_mem_ptr = p;
+ }
+ }
+
+ sync_enum_type nb_transport_fw(transaction_type& trans,
+ phase_type& phase,
+ sc_core::sc_time& t)
+ {
+ if (m_nb_transport_ptr) {
+ // forward call
+ assert(m_mod);
+ return (m_mod->*m_nb_transport_ptr)(trans, phase, t);
+
+ } else {
+ std::stringstream s;
+ s << m_name << ": no non-blocking callback registered";
+ SC_REPORT_ERROR("/OSCI_TLM-2/passthrough_socket",s.str().c_str());
+ }
+ return tlm::TLM_ACCEPTED; ///< unreachable code
+ }
+
+ void b_transport(transaction_type& trans, sc_core::sc_time& t)
+ {
+ if (m_b_transport_ptr) {
+ // forward call
+ assert(m_mod);
+ return (m_mod->*m_b_transport_ptr)(trans, t);
+
+ } else {
+ std::stringstream s;
+ s << m_name << ": no blocking callback registered";
+ SC_REPORT_ERROR("/OSCI_TLM-2/passthrough_socket",s.str().c_str());
+ }
+ }
+
+ unsigned int transport_dbg(transaction_type& trans)
+ {
+ if (m_transport_dbg_ptr) {
+ // forward call
+ assert(m_mod);
+ return (m_mod->*m_transport_dbg_ptr)(trans);
+
+ } else {
+ // No debug support
+ return 0;
+ }
+ }
+
+ bool get_direct_mem_ptr(transaction_type& trans,
+ tlm::tlm_dmi& dmi_data)
+ {
+ if (m_get_direct_mem_ptr) {
+ // forward call
+ assert(m_mod);
+ return (m_mod->*m_get_direct_mem_ptr)(trans, dmi_data);
+
+ } else {
+ // No DMI support
+ dmi_data.allow_read_write();
+ dmi_data.set_start_address(0x0);
+ dmi_data.set_end_address((sc_dt::uint64)-1);
+ return false;
+ }
+ }
+
+ private:
+ const std::string m_name;
+ MODULE* m_mod;
+ NBTransportPtr m_nb_transport_ptr;
+ BTransportPtr m_b_transport_ptr;
+ TransportDbgPtr m_transport_dbg_ptr;
+ GetDirectMem_ptr m_get_direct_mem_ptr;
+ };
+
+private:
+ process m_process;
+};
+
+//ID Tagged version
+template <typename MODULE,
+ unsigned int BUSWIDTH = 32,
+ typename TYPES = tlm::tlm_base_protocol_types>
+class passthrough_target_socket_tagged :
+ public tlm::tlm_target_socket<BUSWIDTH, TYPES>
+{
+public:
+ typedef typename TYPES::tlm_payload_type transaction_type;
+ typedef typename TYPES::tlm_phase_type phase_type;
+ typedef tlm::tlm_sync_enum sync_enum_type;
+ typedef tlm::tlm_fw_transport_if<TYPES> fw_interface_type;
+ typedef tlm::tlm_bw_transport_if<TYPES> bw_interface_type;
+ typedef tlm::tlm_target_socket<BUSWIDTH, TYPES> base_type;
+
+public:
+ passthrough_target_socket_tagged() :
+ base_type(sc_core::sc_gen_unique_name("passthrough_target_socket_tagged")),
+ m_process(this->name())
+ {
+ bind(m_process);
+ }
+
+ explicit passthrough_target_socket_tagged(const char* n) :
+ base_type(n),
+ m_process(this->name())
+ {
+ bind(m_process);
+ }
+
+ using tlm::tlm_target_socket<BUSWIDTH, TYPES>::bind;
+
+ // REGISTER_XXX
+ void register_nb_transport_fw(MODULE* mod,
+ sync_enum_type (MODULE::*cb)(int id,
+ transaction_type&,
+ phase_type&,
+ sc_core::sc_time&),
+ int id)
+ {
+ m_process.set_nb_transport_ptr(mod, cb);
+ m_process.set_nb_transport_user_id(id);
+ }
+
+ void register_b_transport(MODULE* mod,
+ void (MODULE::*cb)(int id,
+ transaction_type&,
+ sc_core::sc_time&),
+ int id)
+ {
+ m_process.set_b_transport_ptr(mod, cb);
+ m_process.set_b_transport_user_id(id);
+ }
+
+ void register_transport_dbg(MODULE* mod,
+ unsigned int (MODULE::*cb)(int id,
+ transaction_type&),
+ int id)
+ {
+ m_process.set_transport_dbg_ptr(mod, cb);
+ m_process.set_transport_dbg_user_id(id);
+ }
+
+ void register_get_direct_mem_ptr(MODULE* mod,
+ bool (MODULE::*cb)(int id,
+ transaction_type&,
+ tlm::tlm_dmi&),
+ int id)
+ {
+ m_process.set_get_direct_mem_ptr(mod, cb);
+ m_process.set_get_dmi_user_id(id);
+ }
+
+private:
+ class process : public tlm::tlm_fw_transport_if<TYPES>
+ {
+ public:
+ typedef sync_enum_type (MODULE::*NBTransportPtr)(int id,
+ transaction_type&,
+ phase_type&,
+ sc_core::sc_time&);
+ typedef void (MODULE::*BTransportPtr)(int id,
+ transaction_type&,
+ sc_core::sc_time&);
+ typedef unsigned int (MODULE::*TransportDbgPtr)(int id,
+ transaction_type&);
+ typedef bool (MODULE::*GetDirectMem_ptr)(int id,
+ transaction_type&,
+ tlm::tlm_dmi&);
+
+ process(const std::string& name) :
+ m_name(name),
+ m_mod(0),
+ m_nb_transport_ptr(0),
+ m_b_transport_ptr(0),
+ m_transport_dbg_ptr(0),
+ m_get_direct_mem_ptr(0),
+ m_nb_transport_user_id(0),
+ m_b_transport_user_id(0),
+ m_transport_dbg_user_id(0),
+ m_get_dmi_user_id(0)
+ {
+ }
+
+ void set_nb_transport_user_id(int id) { m_nb_transport_user_id = id; }
+ void set_b_transport_user_id(int id) { m_b_transport_user_id = id; }
+ void set_transport_dbg_user_id(int id) { m_transport_dbg_user_id = id; }
+ void set_get_dmi_user_id(int id) { m_get_dmi_user_id = id; }
+
+ void set_nb_transport_ptr(MODULE* mod, NBTransportPtr p)
+ {
+ if (m_nb_transport_ptr) {
+ std::stringstream s;
+ s << m_name << ": non-blocking callback allready registered";
+ SC_REPORT_WARNING("/OSCI_TLM-2/passthrough_socket",s.str().c_str());
+ } else {
+ assert(!m_mod || m_mod == mod);
+ m_mod = mod;
+ m_nb_transport_ptr = p;
+ }
+ }
+
+ void set_b_transport_ptr(MODULE* mod, BTransportPtr p)
+ {
+ if (m_b_transport_ptr) {
+ std::stringstream s;
+ s << m_name << ": blocking callback allready registered";
+ SC_REPORT_WARNING("/OSCI_TLM-2/passthrough_socket",s.str().c_str());
+ } else {
+ assert(!m_mod || m_mod == mod);
+ m_mod = mod;
+ m_b_transport_ptr = p;
+ }
+ }
+
+ void set_transport_dbg_ptr(MODULE* mod, TransportDbgPtr p)
+ {
+ if (m_transport_dbg_ptr) {
+ std::stringstream s;
+ s << m_name << ": debug callback allready registered";
+ SC_REPORT_WARNING("/OSCI_TLM-2/passthrough_socket",s.str().c_str());
+ } else {
+ assert(!m_mod || m_mod == mod);
+ m_mod = mod;
+ m_transport_dbg_ptr = p;
+ }
+ }
+
+ void set_get_direct_mem_ptr(MODULE* mod, GetDirectMem_ptr p)
+ {
+ if (m_get_direct_mem_ptr) {
+ std::stringstream s;
+ s << m_name << ": get DMI pointer callback allready registered";
+ SC_REPORT_WARNING("/OSCI_TLM-2/passthrough_socket",s.str().c_str());
+ } else {
+ assert(!m_mod || m_mod == mod);
+ m_mod = mod;
+ m_get_direct_mem_ptr = p;
+ }
+ }
+
+ sync_enum_type nb_transport_fw(transaction_type& trans,
+ phase_type& phase,
+ sc_core::sc_time& t)
+ {
+ if (m_nb_transport_ptr) {
+ // forward call
+ assert(m_mod);
+ return (m_mod->*m_nb_transport_ptr)(m_nb_transport_user_id, trans, phase, t);
+
+ } else {
+ std::stringstream s;
+ s << m_name << ": no non-blocking callback registered";
+ SC_REPORT_ERROR("/OSCI_TLM-2/passthrough_socket",s.str().c_str());
+ }
+ return tlm::TLM_ACCEPTED; ///< unreachable code
+ }
+
+ void b_transport(transaction_type& trans, sc_core::sc_time& t)
+ {
+ if (m_b_transport_ptr) {
+ // forward call
+ assert(m_mod);
+ return (m_mod->*m_b_transport_ptr)(m_b_transport_user_id, trans, t);
+
+ } else {
+ std::stringstream s;
+ s << m_name << ": no blocking callback registered";
+ SC_REPORT_ERROR("/OSCI_TLM-2/passthrough_socket",s.str().c_str());
+ }
+ }
+
+ unsigned int transport_dbg(transaction_type& trans)
+ {
+ if (m_transport_dbg_ptr) {
+ // forward call
+ assert(m_mod);
+ return (m_mod->*m_transport_dbg_ptr)(m_transport_dbg_user_id, trans);
+
+ } else {
+ // No debug support
+ return 0;
+ }
+ }
+
+ bool get_direct_mem_ptr(transaction_type& trans,
+ tlm::tlm_dmi& dmi_data)
+ {
+ if (m_get_direct_mem_ptr) {
+ // forward call
+ assert(m_mod);
+ return (m_mod->*m_get_direct_mem_ptr)(m_get_dmi_user_id, trans, dmi_data);
+
+ } else {
+ // No DMI support
+ dmi_data.allow_read_write();
+ dmi_data.set_start_address(0x0);
+ dmi_data.set_end_address((sc_dt::uint64)-1);
+ return false;
+ }
+ }
+
+ private:
+ const std::string m_name;
+ MODULE* m_mod;
+ NBTransportPtr m_nb_transport_ptr;
+ BTransportPtr m_b_transport_ptr;
+ TransportDbgPtr m_transport_dbg_ptr;
+ GetDirectMem_ptr m_get_direct_mem_ptr;
+ int m_nb_transport_user_id;
+ int m_b_transport_user_id;
+ int m_transport_dbg_user_id;
+ int m_get_dmi_user_id;
+ };
+
+private:
+ process m_process;
+};
+
+}
+
+#endif
diff --git a/ext/systemc/src/tlm_utils/peq_with_cb_and_phase.h b/ext/systemc/src/tlm_utils/peq_with_cb_and_phase.h
new file mode 100644
index 000000000..60f96e6bd
--- /dev/null
+++ b/ext/systemc/src/tlm_utils/peq_with_cb_and_phase.h
@@ -0,0 +1,301 @@
+/*****************************************************************************
+
+ Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
+ more contributor license agreements. See the NOTICE file distributed
+ with this work for additional information regarding copyright ownership.
+ Accellera licenses this file to you under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with the
+ License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ permissions and limitations under the License.
+
+ *****************************************************************************/
+
+// 12-Jan-2009 John Aynsley Bug fix. Phase argument to notify should be const
+// 20-Mar-2009 John Aynsley Add cancel_all() method
+
+
+#ifndef __PEQ_WITH_CB_AND_PHASE_H__
+#define __PEQ_WITH_CB_AND_PHASE_H__
+
+#ifndef SC_INCLUDE_DYNAMIC_PROCESSES // needed for sc_spawn
+# define SC_INCLUDE_DYNAMIC_PROCESSES
+#endif
+
+#include <vector>
+#include <systemc>
+#include <tlm>
+
+namespace tlm_utils {
+
+template <typename PAYLOAD>
+class time_ordered_list
+{
+public:
+ struct element
+ {
+ struct element *next;
+ PAYLOAD p;
+ sc_core::sc_time t;
+ sc_dt::uint64 d;
+ element(PAYLOAD& p, sc_core::sc_time t, sc_dt::uint64 d): p(p),t(t),d(d) {}
+ element(){}
+ };
+
+ element *nill;
+ element *empties;
+ element *list;
+ unsigned int size;
+
+ time_ordered_list()
+ : nill(new element()),
+ empties(NULL),
+ list(nill),
+ size(0)
+ {
+ }
+
+ ~time_ordered_list() {
+ reset();
+ while(empties){
+ struct element *e=empties->next;
+ delete empties;
+ empties=e;
+ }
+ delete nill;
+ }
+
+ void reset() {
+ while(size) {
+ delete_top();
+ }
+ }
+
+ void insert(const PAYLOAD& p, sc_core::sc_time t) {
+ if (!empties) {
+ empties=new struct element();
+ empties->next=NULL;
+ }
+
+ struct element *e=empties;
+ empties=empties->next;
+ e->p=p;
+ e->t=t;
+ e->d=sc_core::sc_delta_count();
+
+ struct element * ancestor=nill;
+ struct element * iterator=list;
+ while (iterator!=nill && iterator->t<=t){
+ ancestor=iterator;
+ iterator=iterator->next;
+ }
+ if (ancestor==nill){
+ e->next=list;
+ list=e;
+ }
+ else {
+ e->next=iterator;
+ ancestor->next=e;
+ }
+ size++;
+ }
+
+ void delete_top(){
+ if (list != nill) {
+ struct element *e=list;
+ list=list->next;
+ e->next=empties;
+ empties=e;
+ size--;
+ }
+ }
+
+ unsigned int get_size()
+ {
+ return size;
+ }
+
+ PAYLOAD &top()
+ {
+ return list->p;
+ }
+ sc_core::sc_time top_time()
+ {
+ return list->t;
+ }
+
+ sc_dt::uint64& top_delta()
+ {
+ return list->d;
+ }
+
+ sc_core::sc_time next_time()
+ {
+ return list->next->t;
+ }
+};
+
+//---------------------------------------------------------------------------
+/**
+ * An event queue that can contain any number of pending
+ * notifications. Each notification have an associate payload.
+ */
+//---------------------------------------------------------------------------
+template<typename OWNER,typename TYPES=tlm::tlm_base_protocol_types>
+class peq_with_cb_and_phase:
+ public sc_core::sc_object
+{
+
+ typedef typename TYPES::tlm_payload_type tlm_payload_type;
+ typedef typename TYPES::tlm_phase_type tlm_phase_type;
+ typedef std::pair<tlm_payload_type*, tlm_phase_type> PAYLOAD;
+ typedef void (OWNER::*cb)(tlm_payload_type&, const tlm_phase_type&);
+
+ class delta_list{
+ public:
+ delta_list(){
+ reset();
+ entries.resize(100);
+ }
+
+ inline void insert(const PAYLOAD& p){
+ if (size==entries.size()){
+ entries.resize(entries.size()*2);
+ }
+ entries[size++]=p;
+ }
+
+ inline PAYLOAD& get(){
+ return entries[out++];
+ }
+
+ inline bool next(){
+ return out<size;
+ }
+
+ inline void reset(){
+ size=0;
+ out=0;
+ }
+ public:
+ unsigned int size;
+ private:
+ std::vector<PAYLOAD> entries;
+ unsigned int out;
+ };
+
+public:
+
+ peq_with_cb_and_phase(OWNER* _owner, cb _cb)
+ :sc_core::sc_object( sc_core::sc_gen_unique_name( "peq_with_cb_and_phase" ) )
+ ,m_owner(_owner)
+ ,m_cb(_cb)
+ {
+ sc_core::sc_spawn_options opts;
+ opts.spawn_method();
+ opts.set_sensitivity(&m_e);
+ opts.dont_initialize();
+ sc_core::sc_spawn(sc_bind(&peq_with_cb_and_phase::fec, this),
+ sc_core::sc_gen_unique_name("fec"), &opts);
+ }
+
+ peq_with_cb_and_phase(const char* _name, OWNER* _owner,cb _cb)
+ : sc_core::sc_object( _name )
+ ,m_owner(_owner)
+ ,m_cb(_cb)
+ {
+ sc_core::sc_spawn_options opts;
+ opts.spawn_method();
+ opts.set_sensitivity(&m_e);
+ opts.dont_initialize();
+ sc_core::sc_spawn(sc_bind(&peq_with_cb_and_phase::fec, this),
+ sc_core::sc_gen_unique_name("fec"), &opts);
+ }
+
+ ~peq_with_cb_and_phase(){}
+
+ void notify (tlm_payload_type& t, const tlm_phase_type& p, const sc_core::sc_time& when){
+ //t.aquire();
+ if (when==sc_core::SC_ZERO_TIME) {
+ if (sc_core::sc_delta_count() & (sc_dt::uint64)0x1) //uneven delta cycle so delta delay is for even cylce
+ m_even_delta.insert(PAYLOAD(&t,p));
+ else
+ m_uneven_delta.insert(PAYLOAD(&t,p)); //even delta cycle so delta delay is for uneven delta
+ m_e.notify(sc_core::SC_ZERO_TIME);
+ }
+ else {
+ m_ppq.insert(PAYLOAD(&t,p), when + sc_core::sc_time_stamp() );
+ m_e.notify(when); // note, this will only over-right the "newest" event.
+ }
+ }
+
+ void notify (tlm_payload_type& t, const tlm_phase_type& p){
+ m_immediate_yield.insert(PAYLOAD(&t,p));
+ m_e.notify(); // immediate notification
+ }
+
+ // Cancel all events from the event queue
+ void cancel_all() {
+ m_ppq.reset();
+ m_uneven_delta.reset();
+ m_even_delta.reset();
+ m_immediate_yield.reset();
+ m_e.cancel();
+ }
+
+private:
+
+ void fec(){
+ //immediate yield notifications
+ while(m_immediate_yield.next()) {PAYLOAD& tmp=m_immediate_yield.get(); (m_owner->*m_cb)(*tmp.first, tmp.second);} //tmp.first->release();}
+ m_immediate_yield.reset();
+
+ //delta notifications
+ if (sc_core::sc_delta_count() & (sc_dt::uint64) 0x1) {//uneven delta so put out all payloads for uneven delta
+ while (m_uneven_delta.next()) {PAYLOAD& tmp=m_uneven_delta.get(); (m_owner->*m_cb)(*tmp.first, tmp.second);} //tmp.first->release();}
+ m_uneven_delta.reset();
+ if (m_even_delta.size) m_e.notify(sc_core::SC_ZERO_TIME);
+ }
+ else {
+ while (m_even_delta.next()) {PAYLOAD& tmp=m_even_delta.get(); (m_owner->*m_cb)(*tmp.first, tmp.second);} //tmp.first->release();}
+ m_even_delta.reset();
+ if (m_uneven_delta.size) m_e.notify(sc_core::SC_ZERO_TIME);
+ }
+ if (!m_ppq.get_size()) return; //there were only delta notification
+
+ //timed notifications
+ const sc_core::sc_time now=sc_core::sc_time_stamp();
+ sc_core::sc_time top=m_ppq.top_time();
+
+ while(m_ppq.get_size() && top==now) { // push all active ones into target
+ PAYLOAD& tmp=m_ppq.top();
+ (m_owner->*m_cb)(*tmp.first, tmp.second); //tmp.first->release();}
+ m_ppq.delete_top();
+ top=m_ppq.top_time();
+ }
+ if ( m_ppq.get_size()) {
+ m_e.notify( top - now) ;
+ }
+
+ }
+
+ OWNER* m_owner;
+ cb m_cb;
+
+ time_ordered_list<PAYLOAD> m_ppq;
+ delta_list m_uneven_delta;
+ delta_list m_even_delta;
+ delta_list m_immediate_yield;
+
+ sc_core::sc_event m_e; // default event
+};
+
+}
+
+#endif // __PEQ_WITH_CB_AND_PHASE_H__
diff --git a/ext/systemc/src/tlm_utils/peq_with_get.h b/ext/systemc/src/tlm_utils/peq_with_get.h
new file mode 100644
index 000000000..5c85f25d5
--- /dev/null
+++ b/ext/systemc/src/tlm_utils/peq_with_get.h
@@ -0,0 +1,94 @@
+/*****************************************************************************
+
+ Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
+ more contributor license agreements. See the NOTICE file distributed
+ with this work for additional information regarding copyright ownership.
+ Accellera licenses this file to you under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with the
+ License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ permissions and limitations under the License.
+
+ *****************************************************************************/
+
+// 12-Jan-2009 John Aynsley Bug fix. sc_time argument to notify should be const
+// 20-Mar-2009 John Aynsley Add cancel_all() method
+
+
+#ifndef __PEQ_WITH_GET_H__
+#define __PEQ_WITH_GET_H__
+
+#include <systemc>
+//#include <tlm>
+#include <map>
+
+namespace tlm_utils {
+
+template <class PAYLOAD>
+class peq_with_get : public sc_core::sc_object
+{
+public:
+ typedef PAYLOAD transaction_type;
+ typedef std::pair<const sc_core::sc_time, transaction_type*> pair_type;
+
+public:
+ peq_with_get(const char* name) : sc_core::sc_object(name)
+ {
+ }
+
+ void notify(transaction_type& trans, const sc_core::sc_time& t)
+ {
+ m_scheduled_events.insert(pair_type(t + sc_core::sc_time_stamp(), &trans));
+ m_event.notify(t);
+ }
+
+ void notify(transaction_type& trans)
+ {
+ m_scheduled_events.insert(pair_type(sc_core::sc_time_stamp(), &trans));
+ m_event.notify(); // immediate notification
+ }
+
+ // needs to be called until it returns 0
+ transaction_type* get_next_transaction()
+ {
+ if (m_scheduled_events.empty()) {
+ return 0;
+ }
+
+ sc_core::sc_time now = sc_core::sc_time_stamp();
+ if (m_scheduled_events.begin()->first <= now) {
+ transaction_type* trans = m_scheduled_events.begin()->second;
+ m_scheduled_events.erase(m_scheduled_events.begin());
+ return trans;
+ }
+
+ m_event.notify(m_scheduled_events.begin()->first - now);
+
+ return 0;
+ }
+
+ sc_core::sc_event& get_event()
+ {
+ return m_event;
+ }
+
+ // Cancel all events from the event queue
+ void cancel_all() {
+ m_scheduled_events.clear();
+ m_event.cancel();
+ }
+
+private:
+ std::multimap<const sc_core::sc_time, transaction_type*> m_scheduled_events;
+ sc_core::sc_event m_event;
+};
+
+}
+
+#endif
diff --git a/ext/systemc/src/tlm_utils/simple_initiator_socket.h b/ext/systemc/src/tlm_utils/simple_initiator_socket.h
new file mode 100644
index 000000000..4609fd885
--- /dev/null
+++ b/ext/systemc/src/tlm_utils/simple_initiator_socket.h
@@ -0,0 +1,292 @@
+/*****************************************************************************
+
+ Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
+ more contributor license agreements. See the NOTICE file distributed
+ with this work for additional information regarding copyright ownership.
+ Accellera licenses this file to you under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with the
+ License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ permissions and limitations under the License.
+
+ *****************************************************************************/
+
+#ifndef __SIMPLE_INITIATOR_SOCKET_H__
+#define __SIMPLE_INITIATOR_SOCKET_H__
+
+#include <tlm>
+#include <sstream>
+
+namespace tlm_utils {
+
+template <typename MODULE,
+ unsigned int BUSWIDTH = 32,
+ typename TYPES = tlm::tlm_base_protocol_types>
+class simple_initiator_socket :
+ public tlm::tlm_initiator_socket<BUSWIDTH, TYPES>
+{
+public:
+ typedef typename TYPES::tlm_payload_type transaction_type;
+ typedef typename TYPES::tlm_phase_type phase_type;
+ typedef tlm::tlm_sync_enum sync_enum_type;
+ typedef tlm::tlm_fw_transport_if<TYPES> fw_interface_type;
+ typedef tlm::tlm_bw_transport_if<TYPES> bw_interface_type;
+ typedef tlm::tlm_initiator_socket<BUSWIDTH, TYPES> base_type;
+
+public:
+ simple_initiator_socket() :
+ base_type(sc_core::sc_gen_unique_name("simple_initiator_socket")),
+ m_process(this->name())
+ {
+ this->m_export.bind(m_process);
+ }
+
+ explicit simple_initiator_socket(const char* n) :
+ base_type(n),
+ m_process(this->name())
+ {
+ this->m_export.bind(m_process);
+ }
+
+ void register_nb_transport_bw(MODULE* mod,
+ sync_enum_type (MODULE::*cb)(transaction_type&,
+ phase_type&,
+ sc_core::sc_time&))
+ {
+ m_process.set_transport_ptr(mod, cb);
+ }
+
+ void register_invalidate_direct_mem_ptr(MODULE* mod,
+ void (MODULE::*cb)(sc_dt::uint64, sc_dt::uint64))
+ {
+ m_process.set_invalidate_direct_mem_ptr(mod, cb);
+ }
+
+private:
+ class process : public tlm::tlm_bw_transport_if<TYPES>
+ {
+ public:
+ typedef sync_enum_type (MODULE::*TransportPtr)(transaction_type&,
+ phase_type&,
+ sc_core::sc_time&);
+ typedef void (MODULE::*InvalidateDirectMemPtr)(sc_dt::uint64,
+ sc_dt::uint64);
+
+ process(const std::string& name) :
+ m_name(name),
+ m_mod(0),
+ m_transport_ptr(0),
+ m_invalidate_direct_mem_ptr(0)
+ {
+ }
+
+ void set_transport_ptr(MODULE* mod, TransportPtr p)
+ {
+ if (m_transport_ptr) {
+ std::stringstream s;
+ s << m_name << ": non-blocking callback allready registered";
+ SC_REPORT_WARNING("/OSCI_TLM-2/simple_socket",s.str().c_str());
+ } else {
+ assert(!m_mod || m_mod == mod);
+ m_mod = mod;
+ m_transport_ptr = p;
+ }
+ }
+
+ void set_invalidate_direct_mem_ptr(MODULE* mod, InvalidateDirectMemPtr p)
+ {
+ if (m_invalidate_direct_mem_ptr) {
+ std::stringstream s;
+ s << m_name << ": invalidate DMI callback allready registered";
+ SC_REPORT_WARNING("/OSCI_TLM-2/simple_socket",s.str().c_str());
+ } else {
+ assert(!m_mod || m_mod == mod);
+ m_mod = mod;
+ m_invalidate_direct_mem_ptr = p;
+ }
+ }
+
+ sync_enum_type nb_transport_bw(transaction_type& trans, phase_type& phase, sc_core::sc_time& t)
+ {
+ if (m_transport_ptr) {
+ // forward call
+ assert(m_mod);
+ return (m_mod->*m_transport_ptr)(trans, phase, t);
+
+ } else {
+ std::stringstream s;
+ s << m_name << ": no transport callback registered";
+ SC_REPORT_ERROR("/OSCI_TLM-2/simple_socket",s.str().c_str());
+ }
+ return tlm::TLM_ACCEPTED; ///< unreachable code
+ }
+
+ void invalidate_direct_mem_ptr(sc_dt::uint64 start_range,
+ sc_dt::uint64 end_range)
+ {
+ if (m_invalidate_direct_mem_ptr) {
+ // forward call
+ assert(m_mod);
+ (m_mod->*m_invalidate_direct_mem_ptr)(start_range, end_range);
+ }
+ }
+
+ private:
+ const std::string m_name;
+ MODULE* m_mod;
+ TransportPtr m_transport_ptr;
+ InvalidateDirectMemPtr m_invalidate_direct_mem_ptr;
+ };
+
+private:
+ process m_process;
+};
+
+// Tagged version
+
+template <typename MODULE,
+ unsigned int BUSWIDTH = 32,
+ typename TYPES = tlm::tlm_base_protocol_types>
+class simple_initiator_socket_tagged :
+ public tlm::tlm_initiator_socket<BUSWIDTH, TYPES>
+{
+public:
+ typedef typename TYPES::tlm_payload_type transaction_type;
+ typedef typename TYPES::tlm_phase_type phase_type;
+ typedef tlm::tlm_sync_enum sync_enum_type;
+ typedef tlm::tlm_fw_transport_if<TYPES> fw_interface_type;
+ typedef tlm::tlm_bw_transport_if<TYPES> bw_interface_type;
+ typedef tlm::tlm_initiator_socket<BUSWIDTH, TYPES> base_type;
+
+public:
+ simple_initiator_socket_tagged() :
+ base_type(sc_core::sc_gen_unique_name("simple_initiator_socket_tagged")),
+ m_process(this->name())
+ {
+ this->m_export.bind(m_process);
+ }
+
+ explicit simple_initiator_socket_tagged(const char* n) :
+ base_type(n),
+ m_process(this->name())
+ {
+ this->m_export.bind(m_process);
+ }
+
+ void register_nb_transport_bw(MODULE* mod,
+ sync_enum_type (MODULE::*cb)(int,
+ transaction_type&,
+ phase_type&,
+ sc_core::sc_time&),
+ int id)
+ {
+ m_process.set_transport_ptr(mod, cb);
+ m_process.set_transport_user_id(id);
+ }
+
+ void register_invalidate_direct_mem_ptr(MODULE* mod,
+ void (MODULE::*cb)(int, sc_dt::uint64, sc_dt::uint64),
+ int id)
+ {
+ m_process.set_invalidate_direct_mem_ptr(mod, cb);
+ m_process.set_invalidate_dmi_user_id(id);
+ }
+
+private:
+ class process : public tlm::tlm_bw_transport_if<TYPES>
+ {
+ public:
+ typedef sync_enum_type (MODULE::*TransportPtr)(int,
+ transaction_type&,
+ phase_type&,
+ sc_core::sc_time&);
+ typedef void (MODULE::*InvalidateDirectMemPtr)(int,
+ sc_dt::uint64,
+ sc_dt::uint64);
+
+ process(const std::string& name) :
+ m_name(name),
+ m_mod(0),
+ m_transport_ptr(0),
+ m_invalidate_direct_mem_ptr(0),
+ m_transport_user_id(0),
+ m_invalidate_direct_mem_user_id(0)
+ {
+ }
+
+ void set_transport_user_id(int id) { m_transport_user_id = id; }
+ void set_invalidate_dmi_user_id(int id) { m_invalidate_direct_mem_user_id = id; }
+
+ void set_transport_ptr(MODULE* mod, TransportPtr p)
+ {
+ if (m_transport_ptr) {
+ std::stringstream s;
+ s << m_name << ": non-blocking callback allready registered";
+ SC_REPORT_WARNING("/OSCI_TLM-2/simple_socket",s.str().c_str());
+ } else {
+ assert(!m_mod || m_mod == mod);
+ m_mod = mod;
+ m_transport_ptr = p;
+ }
+ }
+
+ void set_invalidate_direct_mem_ptr(MODULE* mod, InvalidateDirectMemPtr p)
+ {
+ if (m_invalidate_direct_mem_ptr) {
+ std::stringstream s;
+ s << m_name << ": invalidate DMI callback allready registered";
+ SC_REPORT_WARNING("/OSCI_TLM-2/simple_socket",s.str().c_str());
+ } else {
+ assert(!m_mod || m_mod == mod);
+ m_mod = mod;
+ m_invalidate_direct_mem_ptr = p;
+ }
+ }
+
+ sync_enum_type nb_transport_bw(transaction_type& trans, phase_type& phase, sc_core::sc_time& t)
+ {
+ if (m_transport_ptr) {
+ // forward call
+ assert(m_mod);
+ return (m_mod->*m_transport_ptr)(m_transport_user_id, trans, phase, t);
+
+ } else {
+ std::stringstream s;
+ s << m_name << ": no transport callback registered";
+ SC_REPORT_ERROR("/OSCI_TLM-2/simple_socket",s.str().c_str());
+ }
+ return tlm::TLM_ACCEPTED; ///< unreachable code
+ }
+
+ void invalidate_direct_mem_ptr(sc_dt::uint64 start_range,
+ sc_dt::uint64 end_range)
+ {
+ if (m_invalidate_direct_mem_ptr) {
+ // forward call
+ assert(m_mod);
+ (m_mod->*m_invalidate_direct_mem_ptr)(m_invalidate_direct_mem_user_id, start_range, end_range);
+ }
+ }
+
+ private:
+ const std::string m_name;
+ MODULE* m_mod;
+ TransportPtr m_transport_ptr;
+ InvalidateDirectMemPtr m_invalidate_direct_mem_ptr;
+ int m_transport_user_id;
+ int m_invalidate_direct_mem_user_id;
+ };
+
+private:
+ process m_process;
+};
+
+}
+
+#endif
diff --git a/ext/systemc/src/tlm_utils/simple_target_socket.h b/ext/systemc/src/tlm_utils/simple_target_socket.h
new file mode 100644
index 000000000..34ed1a7f4
--- /dev/null
+++ b/ext/systemc/src/tlm_utils/simple_target_socket.h
@@ -0,0 +1,1114 @@
+/*****************************************************************************
+
+ Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
+ more contributor license agreements. See the NOTICE file distributed
+ with this work for additional information regarding copyright ownership.
+ Accellera licenses this file to you under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with the
+ License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ permissions and limitations under the License.
+
+ *****************************************************************************/
+
+// *****************************************************************************
+// Modified by John Aynsley, Doulos, Feb 2009,
+// Fix a bug in simple_target_socket and simple_target_socket_tagged
+// with the addition of one new line of code in each: wait(*e);
+// *****************************************************************************
+
+// *****************************************************************************
+// Modified by John Aynsley on behalf of Robert Guenzel, May 2011,
+// Fix a bug in simple_target_socket and simple_target_socket_tagged
+// with the addition of one new line of code in each: wait(t);
+// *****************************************************************************
+
+
+#ifndef __SIMPLE_TARGET_SOCKET_H__
+#define __SIMPLE_TARGET_SOCKET_H__
+
+#ifndef SC_INCLUDE_DYNAMIC_PROCESSES // needed for sc_spawn
+# define SC_INCLUDE_DYNAMIC_PROCESSES
+#endif
+
+#include <systemc>
+#include <tlm>
+#include "tlm_utils/peq_with_get.h"
+#include <sstream>
+
+namespace tlm_utils {
+
+template <typename MODULE,
+ unsigned int BUSWIDTH = 32,
+ typename TYPES = tlm::tlm_base_protocol_types>
+class simple_target_socket :
+ public tlm::tlm_target_socket<BUSWIDTH, TYPES>
+{
+ friend class fw_process;
+ friend class bw_process;
+public:
+ typedef typename TYPES::tlm_payload_type transaction_type;
+ typedef typename TYPES::tlm_phase_type phase_type;
+ typedef tlm::tlm_sync_enum sync_enum_type;
+ typedef tlm::tlm_fw_transport_if<TYPES> fw_interface_type;
+ typedef tlm::tlm_bw_transport_if<TYPES> bw_interface_type;
+ typedef tlm::tlm_target_socket<BUSWIDTH, TYPES> base_type;
+
+public:
+ simple_target_socket() :
+ base_type(sc_core::sc_gen_unique_name("simple_target_socket")),
+ m_fw_process(this),
+ m_bw_process(this)
+ {
+ bind(m_fw_process);
+ }
+
+ explicit simple_target_socket(const char* n) :
+ base_type(n),
+ m_fw_process(this),
+ m_bw_process(this)
+ {
+ bind(m_fw_process);
+ }
+
+ using tlm::tlm_target_socket<BUSWIDTH, TYPES>::bind;
+
+ // bw transport must come thru us.
+ tlm::tlm_bw_transport_if<TYPES> * operator ->() {return &m_bw_process;}
+
+ // REGISTER_XXX
+ void register_nb_transport_fw(MODULE* mod,
+ sync_enum_type (MODULE::*cb)(transaction_type&,
+ phase_type&,
+ sc_core::sc_time&))
+ {
+ assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
+ m_fw_process.set_nb_transport_ptr(mod, cb);
+ }
+
+ void register_b_transport(MODULE* mod,
+ void (MODULE::*cb)(transaction_type&,
+ sc_core::sc_time&))
+ {
+ assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
+ m_fw_process.set_b_transport_ptr(mod, cb);
+ }
+
+ void register_transport_dbg(MODULE* mod,
+ unsigned int (MODULE::*cb)(transaction_type&))
+ {
+ assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
+ m_fw_process.set_transport_dbg_ptr(mod, cb);
+ }
+
+ void register_get_direct_mem_ptr(MODULE* mod,
+ bool (MODULE::*cb)(transaction_type&,
+ tlm::tlm_dmi&))
+ {
+ assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
+ m_fw_process.set_get_direct_mem_ptr(mod, cb);
+ }
+
+private:
+ //make call on bw path.
+ sync_enum_type bw_nb_transport(transaction_type &trans, phase_type &phase, sc_core::sc_time &t)
+ {
+ return base_type::operator ->()->nb_transport_bw(trans, phase, t);
+ }
+
+ void bw_invalidate_direct_mem_ptr(sc_dt::uint64 s,sc_dt::uint64 e)
+ {
+ base_type::operator ->()->invalidate_direct_mem_ptr(s, e);
+ }
+
+ //Helper class to handle bw path calls
+ // Needed to detect transaction end when called from b_transport.
+ class bw_process : public tlm::tlm_bw_transport_if<TYPES>
+ {
+ public:
+ bw_process(simple_target_socket *p_own) : m_owner(p_own)
+ {
+ }
+
+ sync_enum_type nb_transport_bw(transaction_type &trans, phase_type &phase, sc_core::sc_time &t)
+ {
+ typename std::map<transaction_type*, sc_core::sc_event *>::iterator it;
+
+ it = m_owner->m_pending_trans.find(&trans);
+ if(it == m_owner->m_pending_trans.end()) {
+ // Not a blocking call, forward.
+ return m_owner->bw_nb_transport(trans, phase, t);
+
+ } else {
+ if (phase == tlm::END_REQ) {
+ m_owner->m_end_request.notify(sc_core::SC_ZERO_TIME);
+ return tlm::TLM_ACCEPTED;
+
+ } else if (phase == tlm::BEGIN_RESP) {
+ if (m_owner->m_current_transaction == &trans) {
+ m_owner->m_end_request.notify(sc_core::SC_ZERO_TIME);
+ }
+ //TODO: add response-accept delay?
+ it->second->notify(t);
+ m_owner->m_pending_trans.erase(it);
+ return tlm::TLM_COMPLETED;
+
+ } else {
+ assert(0); exit(1);
+ }
+
+// return tlm::TLM_COMPLETED; //Should not reach here
+ }
+ }
+
+ void invalidate_direct_mem_ptr(sc_dt::uint64 s,sc_dt::uint64 e)
+ {
+ return m_owner->bw_invalidate_direct_mem_ptr(s, e);
+ }
+
+ private:
+ simple_target_socket *m_owner;
+ };
+
+ class fw_process : public tlm::tlm_fw_transport_if<TYPES>,
+ public tlm::tlm_mm_interface
+ {
+ public:
+ typedef sync_enum_type (MODULE::*NBTransportPtr)(transaction_type&,
+ phase_type&,
+ sc_core::sc_time&);
+ typedef void (MODULE::*BTransportPtr)(transaction_type&,
+ sc_core::sc_time&);
+ typedef unsigned int (MODULE::*TransportDbgPtr)(transaction_type&);
+ typedef bool (MODULE::*GetDirectMemPtr)(transaction_type&,
+ tlm::tlm_dmi&);
+
+ fw_process(simple_target_socket *p_own) :
+ m_name(p_own->name()),
+ m_owner(p_own),
+ m_mod(0),
+ m_nb_transport_ptr(0),
+ m_b_transport_ptr(0),
+ m_transport_dbg_ptr(0),
+ m_get_direct_mem_ptr(0),
+ m_peq(sc_core::sc_gen_unique_name("m_peq")),
+ m_response_in_progress(false)
+ {
+ sc_core::sc_spawn_options opts;
+ opts.set_sensitivity(&m_peq.get_event());
+ sc_core::sc_spawn(sc_bind(&fw_process::b2nb_thread, this),
+ sc_core::sc_gen_unique_name("b2nb_thread"), &opts);
+ }
+
+ void set_nb_transport_ptr(MODULE* mod, NBTransportPtr p)
+ {
+ if (m_nb_transport_ptr) {
+ std::stringstream s;
+ s << m_name << ": non-blocking callback allready registered";
+ SC_REPORT_WARNING("/OSCI_TLM-2/simple_socket",s.str().c_str());
+ } else {
+ assert(!m_mod || m_mod == mod);
+ m_mod = mod;
+ m_nb_transport_ptr = p;
+ }
+ }
+
+ void set_b_transport_ptr(MODULE* mod, BTransportPtr p)
+ {
+ if (m_b_transport_ptr) {
+ std::stringstream s;
+ s << m_name << ": blocking callback allready registered";
+ SC_REPORT_WARNING("/OSCI_TLM-2/simple_socket",s.str().c_str());
+ } else {
+ assert(!m_mod || m_mod == mod);
+ m_mod = mod;
+ m_b_transport_ptr = p;
+ }
+ }
+
+ void set_transport_dbg_ptr(MODULE* mod, TransportDbgPtr p)
+ {
+ if (m_transport_dbg_ptr) {
+ std::stringstream s;
+ s << m_name << ": debug callback allready registered";
+ SC_REPORT_WARNING("/OSCI_TLM-2/simple_socket",s.str().c_str());
+ } else {
+ assert(!m_mod || m_mod == mod);
+ m_mod = mod;
+ m_transport_dbg_ptr = p;
+ }
+ }
+
+ void set_get_direct_mem_ptr(MODULE* mod, GetDirectMemPtr p)
+ {
+ if (m_get_direct_mem_ptr) {
+ std::stringstream s;
+ s << m_name << ": get DMI pointer callback allready registered";
+ SC_REPORT_WARNING("/OSCI_TLM-2/simple_socket",s.str().c_str());
+ } else {
+ assert(!m_mod || m_mod == mod);
+ m_mod = mod;
+ m_get_direct_mem_ptr = p;
+ }
+ }
+// Interface implementation
+ sync_enum_type nb_transport_fw(transaction_type& trans,
+ phase_type& phase,
+ sc_core::sc_time& t)
+ {
+ if (m_nb_transport_ptr) {
+ // forward call
+ assert(m_mod);
+ return (m_mod->*m_nb_transport_ptr)(trans, phase, t);
+
+ } else if (m_b_transport_ptr) {
+ if (phase == tlm::BEGIN_REQ) {
+ // prepare thread to do blocking call
+ process_handle_class * ph = m_process_handle.get_handle(&trans);
+
+ if (!ph) { // create new dynamic process
+ ph = new process_handle_class(&trans);
+ m_process_handle.put_handle(ph);
+
+ sc_core::sc_spawn_options opts;
+ opts.dont_initialize();
+ opts.set_sensitivity(&ph->m_e);
+
+ sc_core::sc_spawn(sc_bind(&fw_process::nb2b_thread,this, ph),
+ sc_core::sc_gen_unique_name("nb2b_thread"), &opts);
+ }
+
+ ph->m_e.notify(t);
+ return tlm::TLM_ACCEPTED;
+
+ } else if (phase == tlm::END_RESP) {
+ m_response_in_progress = false;
+ m_end_response.notify(t);
+ return tlm::TLM_COMPLETED;
+
+ } else {
+ assert(0); exit(1);
+// return tlm::TLM_COMPLETED; ///< unreachable code
+ }
+
+ } else {
+ std::stringstream s;
+ s << m_name << ": no non-blocking transport callback registered";
+ SC_REPORT_ERROR("/OSCI_TLM-2/simple_socket",s.str().c_str());
+ }
+ return tlm::TLM_ACCEPTED; ///< unreachable code
+ }
+
+ void b_transport(transaction_type& trans, sc_core::sc_time& t)
+ {
+ if (m_b_transport_ptr) {
+ // forward call
+ assert(m_mod);
+ (m_mod->*m_b_transport_ptr)(trans, t);
+ return;
+
+ } else if (m_nb_transport_ptr) {
+ m_peq.notify(trans, t);
+ t = sc_core::SC_ZERO_TIME;
+
+ mm_end_event_ext mm_ext;
+ const bool mm_added = !trans.has_mm();
+
+ if (mm_added) {
+ trans.set_mm(this);
+ trans.set_auto_extension(&mm_ext);
+ trans.acquire();
+ }
+
+ // wait until transaction is finished
+ sc_core::sc_event end_event;
+ m_owner->m_pending_trans[&trans] = &end_event;
+ sc_core::wait(end_event);
+
+ if (mm_added) {
+ // release will not delete the transaction, it will notify mm_ext.done
+ trans.release();
+ if (trans.get_ref_count()) {
+ sc_core::wait(mm_ext.done);
+ }
+ trans.set_mm(0);
+ }
+
+ } else {
+ std::stringstream s;
+ s << m_name << ": no blocking transport callback registered";
+ SC_REPORT_ERROR("/OSCI_TLM-2/simple_socket",s.str().c_str());
+ }
+ }
+
+ unsigned int transport_dbg(transaction_type& trans)
+ {
+ if (m_transport_dbg_ptr) {
+ // forward call
+ assert(m_mod);
+ return (m_mod->*m_transport_dbg_ptr)(trans);
+
+ } else {
+ // No debug support
+ return 0;
+ }
+ }
+
+ bool get_direct_mem_ptr(transaction_type& trans,
+ tlm::tlm_dmi& dmi_data)
+ {
+ if (m_get_direct_mem_ptr) {
+ // forward call
+ assert(m_mod);
+ return (m_mod->*m_get_direct_mem_ptr)(trans, dmi_data);
+
+ } else {
+ // No DMI support
+ dmi_data.allow_read_write();
+ dmi_data.set_start_address(0x0);
+ dmi_data.set_end_address((sc_dt::uint64)-1);
+ return false;
+ }
+ }
+
+ private:
+
+// dynamic process handler for nb2b conversion
+
+ class process_handle_class {
+ public:
+ explicit process_handle_class(transaction_type * trans)
+ : m_trans(trans),m_suspend(false) {}
+
+ transaction_type* m_trans;
+ sc_core::sc_event m_e;
+ bool m_suspend;
+ };
+
+ class process_handle_list {
+ public:
+ process_handle_list() {}
+
+ ~process_handle_list() {
+ for( typename std::vector<process_handle_class*>::iterator
+ it=v.begin(), end = v.end(); it != end; ++it )
+ delete *it;
+ }
+
+ process_handle_class* get_handle(transaction_type *trans)
+ {
+ typename std::vector<process_handle_class*>::iterator it;
+
+ for(it = v.begin(); it != v.end(); it++) {
+ if ((*it)->m_suspend) { // found suspended dynamic process, re-use it
+ (*it)->m_trans = trans; // replace to new one
+ (*it)->m_suspend = false;
+ return *it;
+ }
+ }
+ return NULL; // no suspended process
+ }
+
+ void put_handle(process_handle_class* ph)
+ {
+ v.push_back(ph);
+ }
+
+ private:
+ std::vector<process_handle_class*> v;
+ };
+
+ process_handle_list m_process_handle;
+
+
+ void nb2b_thread(process_handle_class* h)
+ {
+
+ while(1) {
+ transaction_type *trans = h->m_trans;
+ sc_core::sc_time t = sc_core::SC_ZERO_TIME;
+
+ // forward call
+ assert(m_mod);
+ (m_mod->*m_b_transport_ptr)(*trans, t);
+
+ sc_core::wait(t);
+
+ // return path
+ while (m_response_in_progress) {
+ sc_core::wait(m_end_response);
+ }
+ t = sc_core::SC_ZERO_TIME;
+ phase_type phase = tlm::BEGIN_RESP;
+ sync_enum_type sync = m_owner->bw_nb_transport(*trans, phase, t);
+ if ( !(sync == tlm::TLM_COMPLETED ||
+ (sync == tlm::TLM_UPDATED && phase == tlm::END_RESP)) ) {
+ m_response_in_progress = true;
+ }
+
+ // suspend until next transaction
+ h->m_suspend = true;
+ sc_core::wait();
+ }
+ }
+
+ void b2nb_thread()
+ {
+ while (true) {
+ sc_core::wait(m_peq.get_event());
+
+ transaction_type* trans;
+ while ((trans = m_peq.get_next_transaction())!=0) {
+ assert(m_mod);
+ assert(m_nb_transport_ptr);
+ phase_type phase = tlm::BEGIN_REQ;
+ sc_core::sc_time t = sc_core::SC_ZERO_TIME;
+
+ switch ((m_mod->*m_nb_transport_ptr)(*trans, phase, t)) {
+ case tlm::TLM_COMPLETED:
+ {
+ // notify transaction is finished
+ typename std::map<transaction_type*, sc_core::sc_event *>::iterator it =
+ m_owner->m_pending_trans.find(trans);
+ assert(it != m_owner->m_pending_trans.end());
+ it->second->notify(t);
+ m_owner->m_pending_trans.erase(it);
+ break;
+ }
+
+ case tlm::TLM_ACCEPTED:
+ case tlm::TLM_UPDATED:
+ switch (phase) {
+ case tlm::BEGIN_REQ:
+ m_owner->m_current_transaction = trans;
+ sc_core::wait(m_owner->m_end_request);
+ m_owner->m_current_transaction = 0;
+ break;
+
+ case tlm::END_REQ:
+ sc_core::wait(t);
+ break;
+
+ case tlm::BEGIN_RESP:
+ {
+ phase = tlm::END_RESP;
+ sc_core::wait(t); // This line is a bug fix added in TLM-2.0.2
+ t = sc_core::SC_ZERO_TIME;
+ (m_mod->*m_nb_transport_ptr)(*trans, phase, t);
+
+ // notify transaction is finished
+ typename std::map<transaction_type*, sc_core::sc_event *>::iterator it =
+ m_owner->m_pending_trans.find(trans);
+ assert(it != m_owner->m_pending_trans.end());
+ it->second->notify(t);
+ m_owner->m_pending_trans.erase(it);
+ break;
+ }
+
+ default:
+ assert(0); exit(1);
+ };
+ break;
+
+ default:
+ assert(0); exit(1);
+ };
+ }
+ }
+ }
+
+ void free(tlm::tlm_generic_payload* trans)
+ {
+ mm_end_event_ext* ext = trans->template get_extension<mm_end_event_ext>();
+ assert(ext);
+ // notif event first before freeing extensions (reset)
+ ext->done.notify();
+ trans->reset();
+ }
+
+ private:
+ struct mm_end_event_ext : public tlm::tlm_extension<mm_end_event_ext>
+ {
+ tlm::tlm_extension_base* clone() const { return NULL; }
+ void free() {}
+ void copy_from(tlm::tlm_extension_base const &) {}
+ sc_core::sc_event done;
+ };
+
+ private:
+ const std::string m_name;
+ simple_target_socket *m_owner;
+ MODULE* m_mod;
+ NBTransportPtr m_nb_transport_ptr;
+ BTransportPtr m_b_transport_ptr;
+ TransportDbgPtr m_transport_dbg_ptr;
+ GetDirectMemPtr m_get_direct_mem_ptr;
+ peq_with_get<transaction_type> m_peq;
+ bool m_response_in_progress;
+ sc_core::sc_event m_end_response;
+ };
+
+private:
+ fw_process m_fw_process;
+ bw_process m_bw_process;
+ std::map<transaction_type*, sc_core::sc_event *> m_pending_trans;
+ sc_core::sc_event m_end_request;
+ transaction_type* m_current_transaction;
+};
+
+//ID Tagged version
+template <typename MODULE,
+ unsigned int BUSWIDTH = 32,
+ typename TYPES = tlm::tlm_base_protocol_types>
+class simple_target_socket_tagged :
+ public tlm::tlm_target_socket<BUSWIDTH, TYPES>
+{
+ friend class fw_process;
+ friend class bw_process;
+public:
+ typedef typename TYPES::tlm_payload_type transaction_type;
+ typedef typename TYPES::tlm_phase_type phase_type;
+ typedef tlm::tlm_sync_enum sync_enum_type;
+ typedef tlm::tlm_fw_transport_if<TYPES> fw_interface_type;
+ typedef tlm::tlm_bw_transport_if<TYPES> bw_interface_type;
+ typedef tlm::tlm_target_socket<BUSWIDTH, TYPES> base_type;
+
+public:
+ simple_target_socket_tagged() :
+ base_type(sc_core::sc_gen_unique_name("simple_target_socket_tagged")),
+ m_fw_process(this),
+ m_bw_process(this)
+ {
+ bind(m_fw_process);
+ }
+
+ explicit simple_target_socket_tagged(const char* n) :
+ base_type(n),
+ m_fw_process(this),
+ m_bw_process(this)
+ {
+ bind(m_fw_process);
+ }
+
+ using tlm::tlm_target_socket<BUSWIDTH, TYPES>::bind;
+
+ // bw transport must come thru us.
+ tlm::tlm_bw_transport_if<TYPES> * operator ->() {return &m_bw_process;}
+
+ // REGISTER_XXX
+ void register_nb_transport_fw(MODULE* mod,
+ sync_enum_type (MODULE::*cb)(int id,
+ transaction_type&,
+ phase_type&,
+ sc_core::sc_time&),
+ int id)
+ {
+ assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
+ m_fw_process.set_nb_transport_ptr(mod, cb);
+ m_fw_process.set_nb_transport_user_id(id);
+ }
+
+ void register_b_transport(MODULE* mod,
+ void (MODULE::*cb)(int id,
+ transaction_type&,
+ sc_core::sc_time&),
+ int id)
+ {
+ assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
+ m_fw_process.set_b_transport_ptr(mod, cb);
+ m_fw_process.set_b_transport_user_id(id);
+ }
+
+ void register_transport_dbg(MODULE* mod,
+ unsigned int (MODULE::*cb)(int id,
+ transaction_type&),
+ int id)
+ {
+ assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
+ m_fw_process.set_transport_dbg_ptr(mod, cb);
+ m_fw_process.set_transport_dbg_user_id(id);
+ }
+
+ void register_get_direct_mem_ptr(MODULE* mod,
+ bool (MODULE::*cb)(int id,
+ transaction_type&,
+ tlm::tlm_dmi&),
+ int id)
+ {
+ assert(!sc_core::sc_get_curr_simcontext()->elaboration_done());
+ m_fw_process.set_get_direct_mem_ptr(mod, cb);
+ m_fw_process.set_get_dmi_user_id(id);
+ }
+
+private:
+ //make call on bw path.
+ sync_enum_type bw_nb_transport(transaction_type &trans, phase_type &phase, sc_core::sc_time &t)
+ {
+ return base_type::operator ->()->nb_transport_bw(trans, phase, t);
+ }
+
+ void bw_invalidate_direct_mem_ptr(sc_dt::uint64 s,sc_dt::uint64 e)
+ {
+ base_type::operator ->()->invalidate_direct_mem_ptr(s, e);
+ }
+
+ //Helper class to handle bw path calls
+ // Needed to detect transaction end when called from b_transport.
+ class bw_process : public tlm::tlm_bw_transport_if<TYPES>
+ {
+ public:
+ bw_process(simple_target_socket_tagged *p_own) : m_owner(p_own)
+ {
+ }
+
+ sync_enum_type nb_transport_bw(transaction_type &trans, phase_type &phase, sc_core::sc_time &t)
+ {
+ typename std::map<transaction_type*, sc_core::sc_event *>::iterator it;
+
+ it = m_owner->m_pending_trans.find(&trans);
+ if(it == m_owner->m_pending_trans.end()) {
+ // Not a blocking call, forward.
+ return m_owner->bw_nb_transport(trans, phase, t);
+
+ } else {
+ if (phase == tlm::END_REQ) {
+ m_owner->m_end_request.notify(sc_core::SC_ZERO_TIME);
+ return tlm::TLM_ACCEPTED;
+
+ } else if (phase == tlm::BEGIN_RESP) {
+ if (m_owner->m_current_transaction == &trans) {
+ m_owner->m_end_request.notify(sc_core::SC_ZERO_TIME);
+ }
+ //TODO: add response-accept delay?
+ it->second->notify(t);
+ m_owner->m_pending_trans.erase(it);
+ return tlm::TLM_COMPLETED;
+
+ } else {
+ assert(0); exit(1);
+ }
+
+// return tlm::TLM_COMPLETED; //Should not reach here
+ }
+ }
+
+ void invalidate_direct_mem_ptr(sc_dt::uint64 s,sc_dt::uint64 e)
+ {
+ return m_owner->bw_invalidate_direct_mem_ptr(s, e);
+ }
+
+ private:
+ simple_target_socket_tagged *m_owner;
+ };
+
+ class fw_process : public tlm::tlm_fw_transport_if<TYPES>,
+ public tlm::tlm_mm_interface
+ {
+ public:
+ typedef sync_enum_type (MODULE::*NBTransportPtr)(int id,
+ transaction_type&,
+ phase_type&,
+ sc_core::sc_time&);
+ typedef void (MODULE::*BTransportPtr)(int id,
+ transaction_type&,
+ sc_core::sc_time&);
+ typedef unsigned int (MODULE::*TransportDbgPtr)(int id,
+ transaction_type&);
+ typedef bool (MODULE::*GetDirectMemPtr)(int id,
+ transaction_type&,
+ tlm::tlm_dmi&);
+
+ fw_process(simple_target_socket_tagged *p_own) :
+ m_name(p_own->name()),
+ m_owner(p_own),
+ m_mod(0),
+ m_nb_transport_ptr(0),
+ m_b_transport_ptr(0),
+ m_transport_dbg_ptr(0),
+ m_get_direct_mem_ptr(0),
+ m_nb_transport_user_id(0),
+ m_b_transport_user_id(0),
+ m_transport_dbg_user_id(0),
+ m_get_dmi_user_id(0),
+ m_peq(sc_core::sc_gen_unique_name("m_peq")),
+ m_response_in_progress(false)
+ {
+ sc_core::sc_spawn_options opts;
+ opts.set_sensitivity(&m_peq.get_event());
+ sc_core::sc_spawn(sc_bind(&fw_process::b2nb_thread, this),
+ sc_core::sc_gen_unique_name("b2nb_thread"), &opts);
+ }
+
+ void set_nb_transport_user_id(int id) { m_nb_transport_user_id = id; }
+ void set_b_transport_user_id(int id) { m_b_transport_user_id = id; }
+ void set_transport_dbg_user_id(int id) { m_transport_dbg_user_id = id; }
+ void set_get_dmi_user_id(int id) { m_get_dmi_user_id = id; }
+
+ void set_nb_transport_ptr(MODULE* mod, NBTransportPtr p)
+ {
+ if (m_nb_transport_ptr) {
+ std::stringstream s;
+ s << m_name << ": non-blocking callback allready registered";
+ SC_REPORT_WARNING("/OSCI_TLM-2/simple_socket",s.str().c_str());
+ } else {
+ assert(!m_mod || m_mod == mod);
+ m_mod = mod;
+ m_nb_transport_ptr = p;
+ }
+ }
+
+ void set_b_transport_ptr(MODULE* mod, BTransportPtr p)
+ {
+ if (m_b_transport_ptr) {
+ std::stringstream s;
+ s << m_name << ": blocking callback allready registered";
+ SC_REPORT_WARNING("/OSCI_TLM-2/simple_socket",s.str().c_str());
+ } else {
+ assert(!m_mod || m_mod == mod);
+ m_mod = mod;
+ m_b_transport_ptr = p;
+ }
+ }
+
+ void set_transport_dbg_ptr(MODULE* mod, TransportDbgPtr p)
+ {
+ if (m_transport_dbg_ptr) {
+ std::stringstream s;
+ s << m_name << ": debug callback allready registered";
+ SC_REPORT_WARNING("/OSCI_TLM-2/simple_socket",s.str().c_str());
+ } else {
+ assert(!m_mod || m_mod == mod);
+ m_mod = mod;
+ m_transport_dbg_ptr = p;
+ }
+ }
+
+ void set_get_direct_mem_ptr(MODULE* mod, GetDirectMemPtr p)
+ {
+ if (m_get_direct_mem_ptr) {
+ std::stringstream s;
+ s << m_name << ": get DMI pointer callback allready registered";
+ SC_REPORT_WARNING("/OSCI_TLM-2/simple_socket",s.str().c_str());
+ } else {
+ assert(!m_mod || m_mod == mod);
+ m_mod = mod;
+ m_get_direct_mem_ptr = p;
+ }
+ }
+// Interface implementation
+ sync_enum_type nb_transport_fw(transaction_type& trans,
+ phase_type& phase,
+ sc_core::sc_time& t)
+ {
+ if (m_nb_transport_ptr) {
+ // forward call
+ assert(m_mod);
+ return (m_mod->*m_nb_transport_ptr)(m_nb_transport_user_id, trans, phase, t);
+
+ } else if (m_b_transport_ptr) {
+ if (phase == tlm::BEGIN_REQ) {
+
+ // prepare thread to do blocking call
+ process_handle_class * ph = m_process_handle.get_handle(&trans);
+
+ if (!ph) { // create new dynamic process
+ ph = new process_handle_class(&trans);
+ m_process_handle.put_handle(ph);
+
+ sc_core::sc_spawn_options opts;
+ opts.dont_initialize();
+ opts.set_sensitivity(&ph->m_e);
+
+ sc_core::sc_spawn(sc_bind(&fw_process::nb2b_thread, this, ph),
+ sc_core::sc_gen_unique_name("nb2b_thread"), &opts);
+ }
+
+ ph->m_e.notify(t);
+ return tlm::TLM_ACCEPTED;
+
+ } else if (phase == tlm::END_RESP) {
+ m_response_in_progress = false;
+ m_end_response.notify(t);
+ return tlm::TLM_COMPLETED;
+
+ } else {
+ assert(0); exit(1);
+// return tlm::TLM_COMPLETED; ///< unreachable code
+ }
+
+ } else {
+ std::stringstream s;
+ s << m_name << ": no non-blocking transport callback registered";
+ SC_REPORT_ERROR("/OSCI_TLM-2/simple_socket",s.str().c_str());
+ }
+ return tlm::TLM_ACCEPTED; ///< unreachable code
+ }
+
+ void b_transport(transaction_type& trans, sc_core::sc_time& t)
+ {
+ if (m_b_transport_ptr) {
+ // forward call
+ assert(m_mod);
+ (m_mod->*m_b_transport_ptr)(m_b_transport_user_id, trans, t);
+ return;
+
+ } else if (m_nb_transport_ptr) {
+ m_peq.notify(trans, t);
+ t = sc_core::SC_ZERO_TIME;
+
+ mm_end_event_ext mm_ext;
+ const bool mm_added = !trans.has_mm();
+
+ if (mm_added){
+ trans.set_mm(this);
+ trans.set_auto_extension(&mm_ext);
+ trans.acquire();
+ }
+
+ // wait until transaction is finished
+ sc_core::sc_event end_event;
+ m_owner->m_pending_trans[&trans] = &end_event;
+ sc_core::wait(end_event);
+
+ if (mm_added) {
+ // release will not delete the transaction, it will notify mm_ext.done
+ trans.release();
+ if (trans.get_ref_count()) {
+ sc_core::wait(mm_ext.done);
+ }
+ trans.set_mm(0);
+ }
+
+ } else {
+ std::stringstream s;
+ s << m_name << ": no transport callback registered";
+ SC_REPORT_ERROR("/OSCI_TLM-2/simple_socket",s.str().c_str());
+ }
+ }
+
+ unsigned int transport_dbg(transaction_type& trans)
+ {
+ if (m_transport_dbg_ptr) {
+ // forward call
+ assert(m_mod);
+ return (m_mod->*m_transport_dbg_ptr)(m_transport_dbg_user_id, trans);
+
+ } else {
+ // No debug support
+ return 0;
+ }
+ }
+
+ bool get_direct_mem_ptr(transaction_type& trans,
+ tlm::tlm_dmi& dmi_data)
+ {
+ if (m_get_direct_mem_ptr) {
+ // forward call
+ assert(m_mod);
+ return (m_mod->*m_get_direct_mem_ptr)(m_get_dmi_user_id, trans, dmi_data);
+
+ } else {
+ // No DMI support
+ dmi_data.allow_read_write();
+ dmi_data.set_start_address(0x0);
+ dmi_data.set_end_address((sc_dt::uint64)-1);
+ return false;
+ }
+ }
+
+ private:
+// dynamic process handler for nb2b conversion
+
+ class process_handle_class {
+ public:
+ explicit process_handle_class(transaction_type * trans)
+ : m_trans(trans),m_suspend(false){}
+
+ transaction_type* m_trans;
+ sc_core::sc_event m_e;
+ bool m_suspend;
+ };
+
+ class process_handle_list {
+ public:
+ process_handle_list() {}
+
+ ~process_handle_list() {
+ for( typename std::vector<process_handle_class*>::iterator
+ it=v.begin(), end = v.end(); it != end; ++it )
+ delete *it;
+ }
+
+ process_handle_class* get_handle(transaction_type *trans)
+ {
+ typename std::vector<process_handle_class*>::iterator it;
+
+ for(it = v.begin(); it != v.end(); it++) {
+ if ((*it)->m_suspend) { // found suspended dynamic process, re-use it
+ (*it)->m_trans = trans; // replace to new one
+ (*it)->m_suspend = false;
+ return *it;
+ }
+ }
+ return NULL; // no suspended process
+ }
+
+ void put_handle(process_handle_class* ph)
+ {
+ v.push_back(ph);
+ }
+
+ private:
+ std::vector<process_handle_class*> v;
+ };
+
+ process_handle_list m_process_handle;
+
+ void nb2b_thread(process_handle_class* h)
+ {
+
+ while(1) {
+ transaction_type * trans = h->m_trans;
+ sc_core::sc_time t = sc_core::SC_ZERO_TIME;
+
+ // forward call
+ assert(m_mod);
+ (m_mod->*m_b_transport_ptr)(m_b_transport_user_id, *trans, t);
+
+ sc_core::wait(t);
+
+ // return path
+ while (m_response_in_progress) {
+ sc_core::wait(m_end_response);
+ }
+ t = sc_core::SC_ZERO_TIME;
+ phase_type phase = tlm::BEGIN_RESP;
+ sync_enum_type sync = m_owner->bw_nb_transport(*trans, phase, t);
+ if ( !(sync == tlm::TLM_COMPLETED ||
+ (sync == tlm::TLM_UPDATED && phase == tlm::END_RESP)) ) {
+ m_response_in_progress = true;
+ }
+
+ // suspend until next transaction
+ h->m_suspend = true;
+ sc_core::wait();
+ }
+ }
+
+ void b2nb_thread()
+ {
+ while (true) {
+ sc_core::wait(m_peq.get_event());
+
+ transaction_type* trans;
+ while ((trans = m_peq.get_next_transaction())!=0) {
+ assert(m_mod);
+ assert(m_nb_transport_ptr);
+ phase_type phase = tlm::BEGIN_REQ;
+ sc_core::sc_time t = sc_core::SC_ZERO_TIME;
+
+ switch ((m_mod->*m_nb_transport_ptr)(m_nb_transport_user_id, *trans, phase, t)) {
+ case tlm::TLM_COMPLETED:
+ {
+ // notify transaction is finished
+ typename std::map<transaction_type*, sc_core::sc_event *>::iterator it =
+ m_owner->m_pending_trans.find(trans);
+ assert(it != m_owner->m_pending_trans.end());
+ it->second->notify(t);
+ m_owner->m_pending_trans.erase(it);
+ break;
+ }
+
+ case tlm::TLM_ACCEPTED:
+ case tlm::TLM_UPDATED:
+ switch (phase) {
+ case tlm::BEGIN_REQ:
+ m_owner->m_current_transaction = trans;
+ sc_core::wait(m_owner->m_end_request);
+ m_owner->m_current_transaction = 0;
+ break;
+
+ case tlm::END_REQ:
+ sc_core::wait(t);
+ break;
+
+ case tlm::BEGIN_RESP:
+ {
+ phase = tlm::END_RESP;
+ sc_core::wait(t); // This line is a bug fix added in TLM-2.0.2
+ t = sc_core::SC_ZERO_TIME;
+ (m_mod->*m_nb_transport_ptr)(m_nb_transport_user_id, *trans, phase, t);
+
+ // notify transaction is finished
+ typename std::map<transaction_type*, sc_core::sc_event *>::iterator it =
+ m_owner->m_pending_trans.find(trans);
+ assert(it != m_owner->m_pending_trans.end());
+ it->second->notify(t);
+ m_owner->m_pending_trans.erase(it);
+ break;
+ }
+
+ default:
+ assert(0); exit(1);
+ };
+ break;
+
+ default:
+ assert(0); exit(1);
+ };
+ }
+ }
+ }
+
+ void free(tlm::tlm_generic_payload* trans)
+ {
+ mm_end_event_ext* ext = trans->template get_extension<mm_end_event_ext>();
+ assert(ext);
+ // notif event first before freeing extensions (reset)
+ ext->done.notify();
+ trans->reset();
+ }
+
+ private:
+ struct mm_end_event_ext : public tlm::tlm_extension<mm_end_event_ext>
+ {
+ tlm::tlm_extension_base* clone() const { return NULL; }
+ void free() {}
+ void copy_from(tlm::tlm_extension_base const &) {}
+ sc_core::sc_event done;
+ };
+
+ private:
+ const std::string m_name;
+ simple_target_socket_tagged *m_owner;
+ MODULE* m_mod;
+ NBTransportPtr m_nb_transport_ptr;
+ BTransportPtr m_b_transport_ptr;
+ TransportDbgPtr m_transport_dbg_ptr;
+ GetDirectMemPtr m_get_direct_mem_ptr;
+ int m_nb_transport_user_id;
+ int m_b_transport_user_id;
+ int m_transport_dbg_user_id;
+ int m_get_dmi_user_id;
+ peq_with_get<transaction_type> m_peq;
+ bool m_response_in_progress;
+ sc_core::sc_event m_end_response;
+ };
+
+private:
+ fw_process m_fw_process;
+ bw_process m_bw_process;
+ std::map<transaction_type*, sc_core::sc_event *> m_pending_trans;
+ sc_core::sc_event m_end_request;
+ transaction_type* m_current_transaction;
+};
+
+}
+
+#endif
diff --git a/ext/systemc/src/tlm_utils/tlm2_base_protocol_checker.h b/ext/systemc/src/tlm_utils/tlm2_base_protocol_checker.h
new file mode 100755
index 000000000..3dbca9e49
--- /dev/null
+++ b/ext/systemc/src/tlm_utils/tlm2_base_protocol_checker.h
@@ -0,0 +1,1055 @@
+
+// Filename: tlm2_base_protocol_checker.h
+
+//----------------------------------------------------------------------
+// Copyright (c) 2008-2013 by Doulos Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//----------------------------------------------------------------------
+
+// Author: John Aynsley, Doulos
+
+// Version 1, 11 July 2008
+// Version 2, 16 July 2008 Only generate ref_count > 1 warning from 1st checker of path
+// Version 3, 17 July 2008 Support compilation under SystemC 2.1.v1
+// Version 4, 12 Aug 2008 Add header #include <map>
+// Version 5, 08 Sep 2008 Fix bugs in message text
+// Version 6, 01 Aug 2010 Update messages to refer to OSCI TLM-2.0 LRM of July 2009
+// Version 7, 25 Oct 2011 Minor bug fix for certain compilers: replace u_char with uchar_t
+// Version 8, 02 Nov 2011 Support the endianness conversion functions by excluding the
+// tlm_endian_context extension from the protocol checks
+// Version 9, 17 Aug 2012 Fix LRM reference on line 805 (should be 8.2.11 a) [NOT YET RELEASED]
+// Version 10, 3 Jan 2013 Updated messages to refer to IEEE Std 1666-2011, the combined SystemC + TLM-2.0 LRM
+// Added checks related to the generic payload option attribute
+// Version 11, 14 Mar 2016 Fix minor bug - start_phase should be a copy, not a reference
+
+// TLM-2.0 Base Protocol Compliance Checker
+
+/*
+Instantiate this checker module in-line between initiator and target, initiator and interconnect,
+or interconnect and target by binding the target_socket and initiator_socket
+Binding two checkers either side of an interconnect component, or interleaving a series of
+checkers with interconnect components, will enable some deeper checks as against having just
+a single checker
+
+For example
+
+ Initiator *initiator;
+ Bus *bus;
+ Memory *memory;
+ ...
+ initiator->socket.bind(bus->target_socket);
+ bus->initiator_socket.bind(memory->socket);
+
+might become
+
+ tlm_utils::tlm2_base_protocol_checker<32> *checker1;
+ tlm_utils::tlm2_base_protocol_checker<32> *checker2;
+ ...
+ initiator->socket.bind(checker1->target_socket);
+ checker1->initiator_socket.bind(bus->target_socket);
+ bus->initiator_socket.bind(checker2->target_socket);
+ checker2->initiator_socket.bind(memory->socket);
+
+
+GENERAL FEATURES OF THE BASE PROTOCOL CHECKER
+
+The checks are relatively expensive, hence by default the number of checks is limited.
+A maximum number can be set explicitly by calling set_num_checks(max)
+Checking can be deactivated at any time by calling set_num_checks(0)
+All checkers decrement a single global count, because having some checkers running and
+others not can cause bogus violation reports
+It is not permitted to turn checks on by calling set_num_checks() once checking has been
+deactivated, because this could cause bogus violation reports
+
+The DMI and debug checks are unaffected by the num_checks count (because they are cheap)
+
+The error messages contain User Manual references
+
+The checker is designed to be used with a transaction pool: otherwise it could consume
+a lot of memory. The checker keeps a local copy of each transaction object
+Failures are reported with a severity of SC_ERROR. The actions may be overridden by calling:
+ sc_report_handler::set_actions("tlm2_protocol_checker", ...);
+
+SPECIFIC CHECKS
+
+nb_transport: phase sequence BEGIN_REQ -> END_REQ -> BEGIN_RESP -> END_RESP
+Must not have two outstanding requests or responses (exclusion rules)
+Must not have decreasing timing annotations on calls to or returns from nb_transport_fw/bw
+Phase extensions permitted and ignored
+Must not call b_transport during nb_transport phase sequence and vice-versa
+
+nb_transport: memory manager must be set
+nb_transport: reference count must be non-zero
+First checker in BEGIN_REQ path should see ref_count == 1 (warning only)
+An interconnect component that sets a memory manager should also clear it
+An interconnect component that sets extensions with no memory manager should also clear them
+(Does not bother with these memory manager checks for DMI and debug)
+
+Transaction object must be properly initialized
+Many generic payload attributes must not be modified during the transaction lifetime
+Transaction object must not be re-allocated for a new transaction while still in use
+DMI descriptor must be properly initialized
+Debug transaction must be properly initialized
+Debug byte count must be less than data_length
+
+Checks that require multiple checkers to be instantiated along a transaction path:
+The BEGIN_RESP path must be the reverse of the BEGIN_REQ path
+Transaction object must not be sent with BEGIN_REQ while participating in a previous response
+Interconnect component must not set response status attribute to TLM_OK_RESPONSE
+Interconnect component must not modify data array on the response path
+
+Generic payload option attribute (IEEE Std 1666-2011, SystemC 2.3.x)
+gp_option must be properly initialized and only used for DMI and debug transport
+When gp_option is used, other gp attributes must be initalized and used as per the transport interfaces
+*/
+
+
+// ******************** PREAMBLE ********************
+
+
+#ifndef __tlm2_base_protocol_checker__
+#define __tlm2_base_protocol_checker__
+
+#include "systemc"
+using std::cout;
+using std::endl;
+using std::dec;
+using std::hex;
+
+#include "tlm.h"
+#include <sstream>
+#include <map>
+
+
+namespace tlm_utils {
+
+
+// Number of checks remaining
+const sc_dt::uint64 default_num_checks = 100000;
+static sc_dt::uint64 num_checks = default_num_checks;
+
+
+// Types used when building a trace of the transaction path
+typedef unsigned char uchar_t;
+typedef std::deque<sc_core::sc_module*> deque_t;
+
+struct path_t {
+ path_t () { response_in_progress = false; ok_response = false; resp_data_ptr = 0; }
+
+ bool response_in_progress;
+ bool ok_response;
+ deque_t path;
+ uchar_t* resp_data_ptr; // Copy of data on response path
+};
+
+// Global variable used for checks involving multiple checkers along a transaction path
+static std::map<tlm::tlm_generic_payload*, path_t> shared_map;
+
+
+// ******************** CLASS DEFINITION ********************
+
+
+template <unsigned int BUSWIDTH = 32>
+class tlm2_base_protocol_checker
+
+: public sc_core::sc_module
+, public tlm::tlm_fw_transport_if<tlm::tlm_base_protocol_types>
+, public tlm::tlm_bw_transport_if<tlm::tlm_base_protocol_types>
+{
+public:
+
+ // Instantiate and bind checker inline between an existing pair of initiator and target sockets
+
+ tlm::tlm_target_socket <BUSWIDTH, tlm::tlm_base_protocol_types, 1> target_socket;
+ tlm::tlm_initiator_socket<BUSWIDTH, tlm::tlm_base_protocol_types, 1> initiator_socket;
+
+ SC_CTOR(tlm2_base_protocol_checker)
+ : m_request_in_progress(0), m_response_in_progress(0)
+ {
+ target_socket .bind( *this );
+ initiator_socket.bind( *this );
+ }
+
+
+ // Access methods for num_checks count
+
+ static void set_num_checks(sc_dt::uint64 n) {
+ if (num_checks == 0)
+ SC_REPORT_FATAL("tlm2_protocol_checker", "Method set_num_checks called after checking has stopped due to maximum number of checks being reached");
+ num_checks = n;
+ }
+
+ static sc_dt::uint64 get_num_checks() { return num_checks; }
+
+
+ // TLM-2.0 interface methods for initiator and target sockets, instrumented with checks
+
+ virtual tlm::tlm_sync_enum nb_transport_fw(
+ tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_core::sc_time& delay)
+ {
+ tlm::tlm_phase start_phase = phase;
+
+ if (num_checks)
+ nb_transport_fw_pre_checks( trans, phase, delay );
+
+ tlm::tlm_sync_enum status;
+ status = initiator_socket->nb_transport_fw( trans, phase, delay );
+
+ if (num_checks)
+ nb_transport_fw_post_checks( trans, start_phase, phase, delay, status );
+
+ return status;
+ }
+
+ virtual tlm::tlm_sync_enum nb_transport_bw(
+ tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_core::sc_time& delay)
+ {
+ if (num_checks)
+ nb_transport_bw_pre_checks( trans, phase, delay );
+
+ tlm::tlm_sync_enum status;
+ status = target_socket->nb_transport_bw( trans, phase, delay );
+
+ if (num_checks)
+ nb_transport_bw_post_checks( trans, phase, delay, status );
+
+ return status;
+ }
+
+ virtual void b_transport( tlm::tlm_generic_payload& trans, sc_core::sc_time& delay )
+ {
+ if (num_checks)
+ b_transport_pre_checks( trans, delay );
+
+ initiator_socket->b_transport( trans, delay );
+
+ if (num_checks)
+ b_transport_post_checks( trans, delay );
+ }
+
+ virtual bool get_direct_mem_ptr(tlm::tlm_generic_payload& trans,
+ tlm::tlm_dmi& dmi_data)
+ {
+ get_direct_mem_ptr_pre_checks( trans, dmi_data );
+
+ bool status;
+ status = initiator_socket->get_direct_mem_ptr( trans, dmi_data );
+
+ get_direct_mem_ptr_post_checks( trans, dmi_data );
+ return status;
+ }
+
+ virtual void invalidate_direct_mem_ptr(sc_dt::uint64 start_range,
+ sc_dt::uint64 end_range)
+ {
+ target_socket->invalidate_direct_mem_ptr(start_range, end_range);
+ }
+
+ virtual unsigned int transport_dbg(tlm::tlm_generic_payload& trans)
+ {
+ transport_dbg_pre_checks( trans );
+
+ unsigned int count;
+ count = initiator_socket->transport_dbg( trans );
+
+ transport_dbg_post_checks( trans, count );
+ return count;
+ }
+
+
+private:
+ void b_transport_pre_checks( tlm::tlm_generic_payload& trans, sc_core::sc_time& delay);
+
+ void b_transport_post_checks( tlm::tlm_generic_payload& trans, sc_core::sc_time& delay);
+
+ void nb_transport_fw_pre_checks(
+ tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_core::sc_time& delay);
+
+ void nb_transport_fw_post_checks(
+ tlm::tlm_generic_payload& trans, tlm::tlm_phase& start_phase, tlm::tlm_phase& phase,
+ sc_core::sc_time& delay, tlm::tlm_sync_enum status);
+
+ void nb_transport_bw_pre_checks(
+ tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_core::sc_time& delay);
+
+ void nb_transport_bw_post_checks(
+ tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_core::sc_time& delay,
+ tlm::tlm_sync_enum status);
+
+ void nb_transport_response_checks(
+ tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_core::sc_time& delay,
+ const char* txt2, const char* txt3, const char* txt4);
+
+ void check_initial_state( tlm::tlm_generic_payload& trans, const char* txt2 );
+ void check_trans_not_modified( tlm::tlm_generic_payload& trans, const char* txt2 );
+ void check_response_path( tlm::tlm_generic_payload& trans, const char* txt2 );
+ void remember_gp_option( tlm::tlm_generic_payload& trans );
+
+ void get_direct_mem_ptr_pre_checks( tlm::tlm_generic_payload& trans, tlm::tlm_dmi& dmi_data );
+
+ void get_direct_mem_ptr_post_checks( tlm::tlm_generic_payload& trans, tlm::tlm_dmi& dmi_data );
+
+ void transport_dbg_pre_checks( tlm::tlm_generic_payload& trans );
+
+ void transport_dbg_post_checks( tlm::tlm_generic_payload& trans, unsigned int count );
+
+ void tlm2error( tlm::tlm_generic_payload& trans, const char* ref, bool warning = false );
+
+private:
+
+ struct state_t {
+ state_t() { b_call = 0; ph = tlm::UNINITIALIZED_PHASE; gp = 0; }
+
+ bool has_mm;
+ unsigned int b_call; // Number of b_transport calls in progress
+ tlm::tlm_phase ph;
+ sc_core::sc_time time; // Current time + annotated delay
+ tlm::tlm_generic_payload* gp; // Points to new data and byte enable buffers
+ uchar_t* data_ptr; // Stores original pointers
+ uchar_t* byte_enable_ptr;
+ };
+
+ // Transaction state for the specific hop where this checker is inlined
+ std::map<tlm::tlm_generic_payload*, state_t> m_map;
+
+ // Flags for exclusion rules
+ tlm::tlm_generic_payload* m_request_in_progress;
+ tlm::tlm_generic_payload* m_response_in_progress;
+
+ std::ostringstream txt;
+
+};
+
+
+
+// ******************** MEMBER FUNCTION DEFINITIONS ********************
+
+
+#define BOILERPLATE \
+template <unsigned int BUSWIDTH> \
+void tlm2_base_protocol_checker<BUSWIDTH>::
+
+
+BOILERPLATE
+b_transport_pre_checks(
+ tlm::tlm_generic_payload& trans, sc_core::sc_time& delay)
+{
+ ++ m_map[&trans].b_call;
+
+ if ( trans.has_mm() && trans.get_ref_count() == 0)
+ {
+ txt << "Transaction passed to b_transport with memory manager and reference count of 0";
+ tlm2error(trans, "14.5 t)");
+ }
+ check_initial_state(trans, "b_transport");
+
+#if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714)
+ if (sc_core::sc_get_current_process_handle().proc_kind() == sc_core::SC_METHOD_PROC_)
+ {
+ txt << "b_transport called from method process";
+ tlm2error(trans, "11.1.1.4 b)");
+ }
+#endif
+
+ if (m_map[&trans].ph > 0 && m_map[&trans].ph < 4)
+ {
+ txt << "b_transport called during a sequence of nb_transport calls";
+ tlm2error(trans, "15.2.10 c)");
+ }
+}
+
+
+BOILERPLATE
+b_transport_post_checks(
+ tlm::tlm_generic_payload& trans, sc_core::sc_time& delay)
+{
+ check_response_path(trans, "b_transport");
+ check_trans_not_modified(trans, "b_transport");
+ -- m_map[&trans].b_call;
+}
+
+
+BOILERPLATE
+nb_transport_fw_pre_checks(
+ tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_core::sc_time& delay)
+{
+ if ( !trans.has_mm() )
+ {
+ txt << "Transaction passed to nb_transport_fw with no memory manager set";
+ tlm2error(trans, "14.5 i)");
+ }
+ if ( trans.get_ref_count() == 0)
+ {
+ txt << "Transaction passed to nb_transport_fw with reference count of 0";
+ tlm2error(trans, "14.5 t)");
+ }
+
+ switch (phase)
+ {
+ case tlm::BEGIN_REQ:
+ check_initial_state(trans, "nb_transport_fw");
+
+ if (m_map[&trans].ph > 0 && m_map[&trans].ph < 4) // END_RESP -> BEGIN_REQ is legal
+ {
+ txt << "Phase " << phase << " sent out-of-sequence on forward path, detected in nb_transport_fw";
+ tlm2error(trans, "15.2.4");
+ }
+
+ if (m_request_in_progress)
+ {
+ txt << "Transaction violates BEGIN_REQ exclusion rule, detected in nb_transport_fw";
+ tlm2error(trans, "15.2.6 e)");
+ }
+ m_request_in_progress = &trans;
+
+ if (m_map[&trans].b_call)
+ {
+ txt << "nb_transport_fw called during a b_transport call";
+ tlm2error(trans, "15.2.10 c)");
+ }
+ break;
+
+ case tlm::END_REQ:
+ case tlm::BEGIN_RESP:
+ case tlm::UNINITIALIZED_PHASE:
+ txt << "Phase " << phase << " sent on forward path, detected in nb_transport_fw";
+ tlm2error(trans, " 15.2.3 c)");
+ break;
+
+ case tlm::END_RESP:
+ if (m_map[&trans].ph != tlm::BEGIN_RESP)
+ {
+ txt << "Phase " << phase << " sent out-of-sequence on forward path, detected in nb_transport_fw";
+ tlm2error(trans, "15.2.4");
+ }
+ m_response_in_progress = 0;
+ break;
+ }
+
+ if (phase < 5) // Ignore extended phases
+ m_map[&trans].ph = phase;
+
+ if (sc_core::sc_time_stamp() + delay < m_map[&trans].time)
+ {
+ txt << "nb_transport_fw called with decreasing timing annotation:"
+ << " delay = " << delay
+ << ", sc_time_stamp() + delay from previous call = " << m_map[&trans].time;
+ tlm2error(trans, "15.2.7 c)");
+ }
+ m_map[&trans].time = sc_core::sc_time_stamp() + delay;
+}
+
+
+BOILERPLATE
+nb_transport_fw_post_checks(
+ tlm::tlm_generic_payload& trans, tlm::tlm_phase& start_phase, tlm::tlm_phase& phase,
+ sc_core::sc_time& delay, tlm::tlm_sync_enum status)
+{
+ if (status == tlm::TLM_UPDATED)
+ {
+ nb_transport_response_checks(
+ trans, phase, delay, "(forward) return", "Return from nb_transport_fw", "nb_transport_fw");
+ }
+ else if (status == tlm::TLM_COMPLETED)
+ {
+ if (start_phase == tlm::BEGIN_REQ)
+ check_response_path(trans, "nb_transport_fw");
+ m_request_in_progress = 0;
+ m_map[&trans].ph = tlm::UNINITIALIZED_PHASE;
+ }
+
+ // Transaction object should not be re-allocated, even during the END_RESP phase
+ //if (phase != tlm::END_RESP)
+ {
+ std::ostringstream txt;
+ txt << "nb_transport_fw, phase = " << phase;
+ check_trans_not_modified(trans, txt.str().c_str());
+ }
+}
+
+
+BOILERPLATE
+nb_transport_bw_pre_checks(
+ tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_core::sc_time& delay)
+{
+ if ( !trans.has_mm() )
+ {
+ txt << "Transaction passed to nb_transport_bw with no memory manager set";
+ tlm2error(trans, "14.5 i)");
+ }
+ if ( trans.get_ref_count() == 0)
+ {
+ txt << "Transaction passed to nb_transport_bw with reference count of 0";
+ tlm2error(trans, "14.5 t)");
+ }
+ nb_transport_response_checks(
+ trans, phase, delay, "backward", "nb_transport_bw called", "nb_transport_bw");
+}
+
+
+BOILERPLATE
+nb_transport_bw_post_checks(
+ tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_core::sc_time& delay,
+ tlm::tlm_sync_enum status)
+{
+ if (status == tlm::TLM_UPDATED)
+ {
+ switch (phase)
+ {
+ case tlm::BEGIN_REQ:
+ txt << "Phase " << phase << " sent out-of-sequence on (backward) return path, detected in nb_transport_bw";
+ tlm2error(trans, "15.2.4");
+ break;
+
+ case tlm::END_REQ:
+ case tlm::BEGIN_RESP:
+ case tlm::UNINITIALIZED_PHASE:
+ txt << "Phase " << phase << " sent on (backward) return path, detected in nb_transport_bw";
+ tlm2error(trans, "15.2.3 c)");
+ break;
+
+ case tlm::END_RESP:
+ if (m_map[&trans].ph != tlm::BEGIN_RESP)
+ {
+ txt << "Phase " << phase << " sent out-of-sequence on (backward) return path, detected in nb_transport_bw";
+ tlm2error(trans, "15.2.4");
+ }
+
+ m_response_in_progress = 0;
+ break;
+ }
+
+ if (phase < 5) // Ignore extended phases
+ m_map[&trans].ph = phase;
+
+ if (sc_core::sc_time_stamp() + delay < m_map[&trans].time)
+ {
+ txt << "Return from nb_transport_bw with decreasing timing annotation:"
+ << " delay = " << delay
+ << ", sc_time_stamp() + delay from previous call = " << m_map[&trans].time;
+ tlm2error(trans, "15.2.7 c)");
+ }
+ m_map[&trans].time = sc_core::sc_time_stamp() + delay;
+ }
+ else if (status == tlm::TLM_COMPLETED)
+ {
+ m_response_in_progress = 0;
+ m_map[&trans].ph = tlm::UNINITIALIZED_PHASE;
+ }
+
+ // Transaction object should not be re-allocated, even during the END_RESP phase
+ //if (phase != tlm::END_RESP)
+ {
+ std::ostringstream txt;
+ txt << "nb_transport_bw, phase = " << phase;
+ check_trans_not_modified(trans, txt.str().c_str());
+ }
+}
+
+
+BOILERPLATE
+nb_transport_response_checks(
+ tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_core::sc_time& delay,
+ const char* txt2, const char* txt3, const char* txt4)
+{
+ if (trans.is_response_ok())
+ if (shared_map[&trans].response_in_progress && !shared_map[&trans].ok_response)
+ {
+ txt << "Interconnect component sets response status attribute to TLM_OK_RESPONSE"
+ << ", detected in " << txt4;
+ tlm2error(trans, "14.7");
+
+ }
+
+ switch (phase)
+ {
+ case tlm::BEGIN_REQ:
+ case tlm::END_RESP:
+ case tlm::UNINITIALIZED_PHASE:
+ txt << "Phase " << phase << " sent on " << txt2 << " path"
+ << ", detected in " << txt4;
+ tlm2error(trans, "15.2.3 c)");
+ break;
+
+ case tlm::END_REQ:
+ if (m_map[&trans].ph != tlm::BEGIN_REQ)
+ {
+ txt << "Phase " << phase << " sent out-of-sequence on " << txt2 << " path"
+ << ", detected in " << txt4;
+ tlm2error(trans, "15.2.4");
+ }
+
+ m_request_in_progress = 0;
+ break;
+
+ case tlm::BEGIN_RESP:
+ if (m_map[&trans].ph != tlm::BEGIN_REQ && m_map[&trans].ph != tlm::END_REQ)
+ {
+ txt << "Phase " << phase << " sent out-of-sequence on " << txt2 << " path"
+ << ", detected in " << txt4;
+ tlm2error(trans, "15.2.4");
+ }
+
+ if (&trans == m_request_in_progress)
+ m_request_in_progress = 0;
+
+ if (m_response_in_progress)
+ {
+ txt << "Transaction violates BEGIN_RESP exclusion rule"
+ << ", detected in " << txt4;
+ tlm2error(trans, "15.2.6 f)");
+ }
+ m_response_in_progress = &trans;
+
+ check_response_path(trans, txt4);
+ break;
+ }
+
+ if (phase < 5) // Ignore extended phases
+ m_map[&trans].ph = phase;
+
+ if (sc_core::sc_time_stamp() + delay < m_map[&trans].time)
+ {
+ txt << txt3 << " with decreasing timing annotation:"
+ << " delay = " << delay
+ << ", sc_time_stamp() + delay from previous call = " << m_map[&trans].time;
+ tlm2error(trans, "15.2.7 c)");
+ }
+ m_map[&trans].time = sc_core::sc_time_stamp() + delay;
+}
+
+
+BOILERPLATE
+check_initial_state(
+ tlm::tlm_generic_payload& trans, const char* txt2 )
+{
+ if (num_checks > 0)
+ {
+ --num_checks;
+ if (num_checks == 0)
+ SC_REPORT_INFO("tlm2_protocol_checker", "Checkers deactivated after executing the set number of checks");
+ }
+
+ if ( trans.has_mm() && trans.get_ref_count() > 1 && shared_map[&trans].path.empty() )
+ {
+ txt << "New transaction passed to " << txt2 << " with reference count = "
+ << trans.get_ref_count();
+ tlm2error(trans, "14.5 t)", true);
+ }
+ if (trans.get_data_ptr() == 0 && trans.get_command() != tlm::TLM_IGNORE_COMMAND)
+ {
+ txt << "Transaction not properly initialized: data_ptr == 0, detected in " << txt2;
+ tlm2error(trans, "14.11 e)");
+ }
+ if (trans.get_data_length() == 0 && trans.get_command() != tlm::TLM_IGNORE_COMMAND)
+ {
+ txt << "Transaction not properly initialized: data_langth == 0, detected in " << txt2;
+ tlm2error(trans, "14.12 d)");
+ }
+ if (trans.get_byte_enable_ptr() != 0 && trans.get_byte_enable_length() == 0)
+ {
+ txt << "Transaction not properly initialized: "
+ << "byte_enable_ptr != 0 and byte_enable_length == 0, detected in " << txt2;
+ tlm2error(trans, "14.14 f)");
+ }
+ if (trans.get_streaming_width() == 0)
+ {
+ txt << "Transaction not properly initialized: streaming_width == 0, detected in " << txt2;
+ tlm2error(trans, "14.15 f)");
+ }
+ if (trans.is_dmi_allowed())
+ {
+ txt << "Transaction not properly initialized: dmi_allowed == true, detected in " << txt2;
+ tlm2error(trans, "14.16");
+ }
+ if (trans.get_response_status() != tlm::TLM_INCOMPLETE_RESPONSE)
+ {
+ txt << "Transaction not properly initialized: response_status != TLM_INCOMPLETE_RESPONSE, detected in " << txt2;
+ tlm2error(trans, "14.17 e)");
+ }
+ if (trans.get_gp_option() != tlm::TLM_MIN_PAYLOAD)
+ {
+ txt << "Transaction not properly initialized: gp_option != TLM_MIN_PAYLOAD, detected in " << txt2;
+ tlm2error(trans, "14.8 g)");
+ }
+
+ // Setup clones of transaction and buffers in map
+ tlm::tlm_generic_payload* gp = m_map[&trans].gp;
+ if (gp == 0)
+ gp = new tlm::tlm_generic_payload; // Memory leak: transactions are never cleared from map
+ else
+ {
+ delete [] gp->get_data_ptr();
+ gp->free_all_extensions();
+ }
+ gp->set_data_ptr( new uchar_t[trans.get_data_length()] );
+ m_map[&trans].data_ptr = trans.get_data_ptr();
+
+ if (gp->get_byte_enable_ptr())
+ delete [] gp->get_byte_enable_ptr();
+ if (trans.get_byte_enable_ptr())
+ gp->set_byte_enable_ptr( new uchar_t[trans.get_byte_enable_length()] );
+ else
+ gp->set_byte_enable_ptr(0);
+ m_map[&trans].byte_enable_ptr = trans.get_byte_enable_ptr();
+
+ gp->deep_copy_from(trans);
+ m_map[&trans].gp = gp;
+ m_map[&trans].time = sc_core::SC_ZERO_TIME;
+ m_map[&trans].has_mm = trans.has_mm();
+
+ // Store request path checker sequence
+ if (shared_map[&trans].resp_data_ptr)
+ {
+ delete [] shared_map[&trans].resp_data_ptr;
+ shared_map[&trans].resp_data_ptr = 0;
+ }
+ if (shared_map[&trans].response_in_progress)
+ {
+ txt << "Transaction object sent with BEGIN_REQ while still being used on a previous response path, detected in " << txt2;
+ tlm2error(trans, "14.5 x)");
+ }
+ shared_map[&trans].ok_response = false;
+ shared_map[&trans].path.push_back(this);
+}
+
+
+BOILERPLATE
+remember_gp_option(
+ tlm::tlm_generic_payload& trans)
+{
+ // Setup clone of transaction in map in order to check gp_option only
+ tlm::tlm_generic_payload* gp = m_map[&trans].gp;
+ if (gp == 0)
+ gp = new tlm::tlm_generic_payload; // Memory leak: transactions are never cleared from map
+ gp->set_gp_option( trans.get_gp_option() );
+ m_map[&trans].gp = gp;
+}
+
+
+BOILERPLATE
+check_trans_not_modified(
+ tlm::tlm_generic_payload& trans, const char* txt2 )
+{
+ tlm::tlm_generic_payload* init = m_map[&trans].gp;
+
+ if (trans.get_command() != init->get_command())
+ {
+ txt << "Command attribute modified during transaction lifetime, detected in " << txt2;
+ tlm2error(trans, "14.7");
+ }
+ if (trans.get_data_ptr() != m_map[&trans].data_ptr)
+ {
+ txt << "Data pointer attribute modified during transaction lifetime, detected in " << txt2;
+ tlm2error(trans, "14.7");
+ }
+ if (trans.get_data_length() != init->get_data_length())
+ {
+ txt << "Data length attribute modified during transaction lifetime, detected in " << txt2;
+ tlm2error(trans, "14.7");
+ }
+ if (trans.get_command() == tlm::TLM_WRITE_COMMAND)
+ for (unsigned int i = 0; i < init->get_data_length(); i++)
+ if (trans.get_data_ptr()[i] != init->get_data_ptr()[i])
+ {
+ txt << "Data array modified during transaction lifetime, detected in " << txt2;
+ tlm2error(trans, "14.7");
+ }
+ if (trans.get_byte_enable_ptr() != m_map[&trans].byte_enable_ptr)
+ {
+ txt << "Byte enable pointer attribute modified during transaction lifetime, detected in " << txt2;
+ tlm2error(trans, "14.7");
+ }
+ if (trans.get_byte_enable_length() != init->get_byte_enable_length())
+ {
+ txt << "Byte enable length attribute modified during transaction lifetime, detected in " << txt2;
+ tlm2error(trans, "14.7");
+ }
+ if (trans.get_byte_enable_ptr())
+ for (unsigned int i = 0; i < init->get_byte_enable_length(); i++)
+ if (trans.get_byte_enable_ptr()[i] != init->get_byte_enable_ptr()[i])
+ {
+ txt << "Byte enable array modified during transaction lifetime, detected in " << txt2;
+ tlm2error(trans, "14.7");
+ }
+ if (trans.get_streaming_width() != init->get_streaming_width())
+ {
+ txt << "Streaming width attribute modified during transaction lifetime, detected in " << txt2;
+ tlm2error(trans, "14.7");
+ }
+ if (init->get_gp_option() == tlm::TLM_MIN_PAYLOAD && trans.get_gp_option() != tlm::TLM_MIN_PAYLOAD)
+ {
+ txt << "Generic payload option attribute modified during transaction lifetime, detected in " << txt2;
+ tlm2error(trans, "14.8 g)");
+ }
+ if ( !m_map[&trans].has_mm )
+ {
+ if (trans.has_mm())
+ {
+ txt << "Interconnect component sets a memory manager, but does not clear it on return, detected in " << txt2;
+ tlm2error(trans, "14.5 aa)");
+ }
+
+ for (unsigned int i = 0; i < tlm::max_num_extensions(); i++)
+ // Exclude tlm_endian_context extension from the check because it is not cloned in m_map
+ if (i != tlm::tlm_endian_context::ID)
+ if (trans.get_extension(i))
+ if ( !m_map[&trans].gp->get_extension(i) )
+ {
+ txt << "Extension set (index = " << i << ") without also being deleted in the absence of a memory manager, detected in " << txt2;
+ tlm2error(trans, "14.5 aa)");
+ }
+ }
+
+ uchar_t* resp_data_ptr = shared_map[&trans].resp_data_ptr;
+ if (resp_data_ptr)
+ for (unsigned int i = 0; i < trans.get_data_length(); i++)
+ if (trans.get_data_ptr()[i] != resp_data_ptr[i])
+ {
+ txt << "Transaction data array modified in interconnect component on response path, detected in " << txt2;
+ tlm2error(trans, "14.7");
+ }
+}
+
+
+BOILERPLATE
+check_response_path(
+ tlm::tlm_generic_payload& trans, const char* txt2 )
+{
+ if ( !shared_map[&trans].path.empty() )
+ {
+ if ( this != shared_map[&trans].path.back() )
+ {
+ txt << "BEGIN_RESP path is not the reverse of the BEGIN_REQ path.";
+ txt << "\nBEGIN_REQ path includes these checkers: -> ";
+ deque_t path = shared_map[&trans].path;
+ for (deque_t::iterator i = path.begin(); i < path.end(); i++)
+ txt << (*i)->name() << " -> ";
+ txt << "\nDetected in " << txt2;
+ tlm2error(trans, "15.2.11 a)");
+ }
+ shared_map[&trans].path.pop_back();
+ shared_map[&trans].response_in_progress = !shared_map[&trans].path.empty();
+ shared_map[&trans].ok_response = trans.is_response_ok();
+
+ // Create a copy of the data array for comparison on the response path
+ if ( !shared_map[&trans].resp_data_ptr )
+ {
+ shared_map[&trans].resp_data_ptr = new uchar_t[trans.get_data_length()];
+ memcpy(shared_map[&trans].resp_data_ptr, trans.get_data_ptr(), trans.get_data_length());
+ }
+ }
+}
+
+
+BOILERPLATE
+get_direct_mem_ptr_pre_checks(
+ tlm::tlm_generic_payload& trans, tlm::tlm_dmi& dmi_data )
+{
+ remember_gp_option(trans);
+
+ if (dmi_data.get_dmi_ptr() != 0)
+ {
+ txt << "DMI descriptor not properly initialized: dmi_ptr != 0";
+ tlm2error(trans, "11.2.5 f)");
+ }
+ if (!dmi_data.is_none_allowed())
+ {
+ txt << "DMI descriptor not properly initialized: granted_access != DMI_ACCESS_NONE";
+ tlm2error(trans, "11.2.5 a)");
+ }
+ if (dmi_data.get_start_address() != 0)
+ {
+ txt << "DMI descriptor not properly initialized: start_address != 0";
+ tlm2error(trans, "11.2.5 u)");
+ }
+ if (dmi_data.get_end_address() != (sc_dt::uint64)(-1))
+ {
+ txt << "DMI descriptor not properly initialized: end_address != 0";
+ tlm2error(trans, "11.2.5 u)");
+ }
+ if (dmi_data.get_read_latency() != sc_core::SC_ZERO_TIME)
+ {
+ txt << "DMI descriptor not properly initialized: read_latency != SC_ZERO_TIME";
+ tlm2error(trans, "11.2.5 ac)");
+ }
+ if (dmi_data.get_write_latency() != sc_core::SC_ZERO_TIME)
+ {
+ txt << "DMI descriptor not properly initialized: write_latency != SC_ZERO_TIME";
+ tlm2error(trans, "11.2.5 ac)");
+ }
+
+ if (trans.get_gp_option() == tlm::TLM_FULL_PAYLOAD)
+ {
+ /*
+ if (trans.is_dmi_allowed()) // Would be rather brutal to flag dmi_allowed as an arror for a DMI transaction!
+ {
+ txt << "DMI transaction not properly initialized: dmi_allowed == true";
+ tlm2error(trans, "14.8 e) & 14.16");
+ }
+ */
+ if (trans.get_response_status() != tlm::TLM_INCOMPLETE_RESPONSE)
+ {
+ txt << "DMI transaction not properly initialized: response_status != TLM_INCOMPLETE_RESPONSE";
+ tlm2error(trans, "14.8 e) & 14.17 e)");
+ }
+ }
+ else if (trans.get_gp_option() == tlm::TLM_FULL_PAYLOAD_ACCEPTED)
+ {
+ txt << "DMI transaction not properly initialized: gp_option == TLM_FULL_PAYLOAD_ACCEPTED";
+ tlm2error(trans, "14.8 c) & e) & j)");
+ }
+}
+
+
+BOILERPLATE
+get_direct_mem_ptr_post_checks( tlm::tlm_generic_payload& trans, tlm::tlm_dmi& dmi_data )
+{
+ tlm::tlm_generic_payload* init = m_map[&trans].gp;
+
+ if (init->get_gp_option() == tlm::TLM_MIN_PAYLOAD && trans.get_gp_option() != tlm::TLM_MIN_PAYLOAD)
+ {
+ txt << "DMI transaction gp_option attribute value TLM_MIN_PAYLOAD modified during transaction lifetime";
+ tlm2error(trans, "14.8 h)");
+ }
+ else if (init->get_gp_option() == tlm::TLM_FULL_PAYLOAD && trans.get_gp_option() == tlm::TLM_MIN_PAYLOAD)
+ {
+ txt << "DMI transaction gp_option attribute value changed from TLM_FULL_PAYLOAD to TLM_MIN_PAYLOAD";
+ tlm2error(trans, "14.8 j)");
+ }
+}
+
+
+BOILERPLATE
+transport_dbg_pre_checks( tlm::tlm_generic_payload& trans )
+{
+ remember_gp_option(trans);
+
+ if (trans.get_data_length() > 0 && trans.get_data_ptr() == 0)
+ {
+ txt << "Debug transaction has data_ptr == 0";
+ tlm2error(trans, "11.3.4 l)");
+ }
+
+ if (trans.get_gp_option() == tlm::TLM_FULL_PAYLOAD)
+ {
+ if (trans.get_byte_enable_ptr() != 0 && trans.get_byte_enable_length() == 0)
+ {
+ txt << "Debug transaction not properly initialized: "
+ << "byte_enable_ptr != 0 and byte_enable_length == 0";
+ tlm2error(trans, "14.8 f) & 14.14 f)");
+ }
+ if (trans.get_streaming_width() == 0)
+ {
+ txt << "Debug transaction not properly initialized: streaming_width == 0";
+ tlm2error(trans, "14.8 f) & 14.15 f)");
+ }
+ if (trans.is_dmi_allowed())
+ {
+ txt << "Debug transaction not properly initialized: dmi_allowed == true";
+ tlm2error(trans, "14.8 f) & 14.16");
+ }
+ if (trans.get_response_status() != tlm::TLM_INCOMPLETE_RESPONSE)
+ {
+ txt << "Debug transaction not properly initialized: response_status != TLM_INCOMPLETE_RESPONSE";
+ tlm2error(trans, "14.8 f) & 14.17 e)");
+ }
+ }
+ else if (trans.get_gp_option() == tlm::TLM_FULL_PAYLOAD_ACCEPTED)
+ {
+ txt << "Debug transaction not properly initialized: gp_option == TLM_FULL_PAYLOAD_ACCEPTED";
+ tlm2error(trans, "14.8 c) & f) & l)");
+ }}
+
+
+BOILERPLATE
+transport_dbg_post_checks( tlm::tlm_generic_payload& trans, unsigned int count )
+{
+ tlm::tlm_generic_payload* init = m_map[&trans].gp;
+
+ if (trans.get_data_length() > 0 && trans.get_data_ptr() == 0)
+ {
+ txt << "Debug transaction has data_ptr == 0";
+ tlm2error(trans, "11.3.4 l)");
+ }
+ if (count > trans.get_data_length())
+ {
+ txt << "Count returned from transport_dbg is greater than data_length";
+ tlm2error(trans, "11.3.4 s)");
+ }
+
+ if (init->get_gp_option() == tlm::TLM_MIN_PAYLOAD && trans.get_gp_option() != tlm::TLM_MIN_PAYLOAD)
+ {
+ txt << "Debug transaction gp_option attribute value TLM_MIN_PAYLOAD modified during transaction lifetime";
+ tlm2error(trans, "14.8 h)");
+ }
+ else if (init->get_gp_option() == tlm::TLM_FULL_PAYLOAD && trans.get_gp_option() == tlm::TLM_MIN_PAYLOAD)
+ {
+ txt << "Debug transaction gp_option attribute value changed from TLM_FULL_PAYLOAD to TLM_MIN_PAYLOAD";
+ tlm2error(trans, "14.8 l)");
+ }}
+
+
+BOILERPLATE
+tlm2error( tlm::tlm_generic_payload& trans, const char* ref, bool warning )
+{
+ txt << "\n\nRefer to IEEE Std 1666-2011, clause " << ref;
+ txt << "\n\nChecker instance: " << this->name();
+ txt << "\n\nTransaction details:";
+ txt << "\n has_mm = " << dec << trans.has_mm() << " (bool)";
+ txt << "\n ref_count = " << dec << trans.get_ref_count() << " (int)";
+ txt << "\n\n gp_option = " <<
+ (trans.get_gp_option() == tlm::TLM_MIN_PAYLOAD ? "TLM_MIN_PAYLOAD"
+ :trans.get_gp_option() == tlm::TLM_FULL_PAYLOAD ? "TLM_FULL_PAYLOAD"
+ : "TLM_FULL_PAYLOAD_ACCEPTED");
+ txt << "\n command = " <<
+ (trans.get_command() == tlm::TLM_READ_COMMAND ? "TLM_READ_COMMAND"
+ :trans.get_command() == tlm::TLM_WRITE_COMMAND ? "TLM_WRITE_COMMAND"
+ : "TLM_IGNORE_COMMAND");
+ txt << "\n address = " << hex << trans.get_address() << " (hex)";
+ txt << "\n data_ptr = " << hex
+ << reinterpret_cast<int*>(trans.get_data_ptr()) << " (hex)";
+ txt << "\n data_length = " << hex << trans.get_data_length() << " (hex)";
+ txt << "\n streaming_width = " << hex << trans.get_streaming_width() << " (hex)";
+ txt << "\n byte_enable_ptr = " << hex
+ << reinterpret_cast<int*>(trans.get_byte_enable_ptr()) << " (hex)";
+ txt << "\n byte_enable_length = " << hex << trans.get_byte_enable_length() << " (hex)";
+ txt << "\n dmi_allowed = " << dec << trans.is_dmi_allowed() << " (bool)";
+ txt << "\n response_status = " << trans.get_response_string();
+
+ bool extensions_present = false;
+ for (unsigned int i = 0; i < tlm::max_num_extensions(); i++)
+ {
+ tlm::tlm_extension_base* ext = trans.get_extension(i);
+ if (ext)
+ {
+ if (!extensions_present)
+ txt << "\n\n extensions:";
+ txt << "\n index = " << i << " type = " << typeid(*ext).name();
+ extensions_present = true;
+ }
+ }
+
+ txt << "\n\n";
+ if (warning)
+ SC_REPORT_WARNING("tlm2_protocol_checker", txt.str().c_str());
+ else
+ SC_REPORT_ERROR("tlm2_protocol_checker", txt.str().c_str());
+}
+
+
+
+} // namespace tlm_utils
+
+#endif // __tlm2_base_protocol_checker__
diff --git a/ext/systemc/src/tlm_utils/tlm_quantumkeeper.h b/ext/systemc/src/tlm_utils/tlm_quantumkeeper.h
new file mode 100644
index 000000000..ed211665f
--- /dev/null
+++ b/ext/systemc/src/tlm_utils/tlm_quantumkeeper.h
@@ -0,0 +1,172 @@
+/*****************************************************************************
+
+ Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
+ more contributor license agreements. See the NOTICE file distributed
+ with this work for additional information regarding copyright ownership.
+ Accellera licenses this file to you under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with the
+ License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ permissions and limitations under the License.
+
+ *****************************************************************************/
+
+// 20-Mar-2009 John Aynsley Add set_and_sync() method
+
+
+#ifndef __TLM_QUANTUMKEEPER_H__
+#define __TLM_QUANTUMKEEPER_H__
+
+#include "tlm_core/tlm_2/tlm_quantum/tlm_global_quantum.h"
+
+namespace tlm_utils {
+
+ //
+ // tlm_quantumkeeper class
+ //
+ // The tlm_quantumkeeper class is used to keep track of the local time in
+ // an initiator (how much it has run ahead of the SystemC time), to
+ // synchronize with SystemC time etc.
+ //
+ class tlm_quantumkeeper
+ {
+ public:
+ //
+ // Static setters/getters for the global quantum value.
+ //
+ // The global quantum is the maximum time an initiator can run ahead of
+ // systemC time. All initiators will synchronize on timingpoints that are
+ // multiples of the global quantum value.
+ //
+ static void set_global_quantum(const sc_core::sc_time& t)
+ {
+ tlm::tlm_global_quantum::instance().set(t);
+ }
+
+ static const sc_core::sc_time& get_global_quantum()
+ {
+ return tlm::tlm_global_quantum::instance().get();
+ }
+
+ public:
+ tlm_quantumkeeper() :
+ m_next_sync_point(sc_core::SC_ZERO_TIME),
+ m_local_time(sc_core::SC_ZERO_TIME)
+ {
+ }
+
+ virtual ~tlm_quantumkeeper() {}
+
+ //
+ // Increment the local time (the time the initiator is ahead of the
+ // systemC time) After incrementing the local time an initiator should
+ // check (with the need_sync method) if a sync is required.
+ //
+ virtual void inc(const sc_core::sc_time& t)
+ {
+ m_local_time += t;
+ }
+
+ //
+ // Sets the local time (the time the initiator is ahead of the
+ // systemC time) After changing the local time an initiator should
+ // check (with the need_sync method) if a sync is required.
+ //
+ virtual void set(const sc_core::sc_time& t)
+ {
+ m_local_time = t;
+ }
+
+ //
+ // Checks if a sync to systemC is required for this initiator. This will
+ // be the case if the local time becomes greater than the local (current)
+ // quantum value for this initiator.
+ //
+ virtual bool need_sync() const
+ {
+ return sc_core::sc_time_stamp() + m_local_time >= m_next_sync_point;
+ }
+
+ //
+ // Synchronize to systemC. This call will do a wait for the time the
+ // initiator was running ahead of systemC time and reset the
+ // tlm_quantumkeeper.
+ //
+ virtual void sync()
+ {
+ sc_core::wait(m_local_time);
+ reset();
+ }
+
+ //
+ // Non-virtual convenience method to set the local time and sync only if needed
+ //
+ void set_and_sync(const sc_core::sc_time& t)
+ {
+ set(t);
+ if (need_sync())
+ sync();
+ }
+
+ //
+ // Resets the local time to SC_ZERO_TIME and computes the value of the
+ // next local quantum. This method should be called by an initiator after
+ // a wait because of a synchronization request by a target (TLM_ACCEPTED,
+ // or TLM_UPDATED).
+ //
+ virtual void reset()
+ {
+ m_local_time = sc_core::SC_ZERO_TIME;
+ m_next_sync_point = sc_core::sc_time_stamp() + compute_local_quantum();
+ }
+
+ //
+ // Helper function to get the current systemC time, taken the local time
+ // into account. The current systemC time is calculated as the time
+ // returned by sc_time_stamp incremeneted with the time the initiator is
+ // running ahead.
+ //
+ virtual sc_core::sc_time get_current_time() const
+ {
+ return sc_core::sc_time_stamp() + m_local_time;
+ }
+
+ //
+ // Helper functions to get the time the initiator is running ahead of
+ // systenC (local time). This time should be passed to a target in the
+ // nb_transport call
+ //
+ virtual sc_core::sc_time get_local_time() const
+ {
+ return m_local_time;
+ }
+
+ protected:
+ //
+ // Calculate the next local quantum for this initiator.
+ //
+ // The method can be overloaded in a derived object if an initiator wants
+ // to use another local quantum. This derived object should also take the
+ // global quantum into account. It's local quantum should not be set to a
+ // value that is larger than the quantum returned by the
+ // compute_local_quantum of the tlm_global_quantum singleton.
+ //
+ virtual sc_core::sc_time compute_local_quantum()
+ {
+ return tlm::tlm_global_quantum::instance().compute_local_quantum();
+ }
+
+ protected:
+ sc_core::sc_time m_next_sync_point;
+ sc_core::sc_time m_local_time;
+ };
+
+} // namespace tlm
+
+#endif