summaryrefslogtreecommitdiff
path: root/ext/systemc/src/tlm_utils
diff options
context:
space:
mode:
authorMatthias Jung <jungma@eit.uni-kl.de>2017-03-01 18:39:56 +0100
committerMatthias Jung <jungma@eit.uni-kl.de>2017-05-18 08:36:56 +0000
commitaa651c7f8321bf96fc88f9a17285225000a753ec (patch)
treeb13240008c970b47bd74a5007e68136155d272fc /ext/systemc/src/tlm_utils
parent595e692de09e1b7cbc5f57ac01da299afc066fdd (diff)
downloadgem5-aa651c7f8321bf96fc88f9a17285225000a753ec.tar.xz
ext: Include SystemC 2.3.1 into gem5
In the past it happened several times that some changes in gem5 broke the SystemC coupling. Recently Accelera has changed the licence for SystemC from their own licence to Apache2.0, which is compatible with gem5. However, SystemC usually relies on the Boost library, but I was able to exchange the boost calls by c++11 alternatives. The recent SystemC version is placed into /ext and is integrated into gem5's build system. The goal is to integrate some SystemC tests for the CI in some following patches. Change-Id: I4b66ec806b5e3cffc1d7c85d3735ff4fa5b31fd0 Reviewed-on: https://gem5-review.googlesource.com/2240 Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com> Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
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