From b083094cc8d6c45501df70b7d67ebb6b3c27bbca Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Sat, 21 Nov 2015 19:03:50 +0100 Subject: [PATCH] Added tlm3 recording sockets --- scv_tr_sqlite/scv4tlm/tlm2_recorder.h | 722 ++++++++++++++++++ scv_tr_sqlite/scv4tlm/tlm2_recorder_module.h | 61 ++ scv_tr_sqlite/scv4tlm/tlm_gp_data.h | 557 ++++++++++++++ scv_tr_sqlite/scv4tlm/tlm_gp_data_ext.h | 131 ++++ .../scv4tlm/tlm_rec_initiator_socket.h | 125 +++ scv_tr_sqlite/scv4tlm/tlm_rec_target_socket.h | 119 +++ .../scv4tlm/tlm_recording_extension.h | 77 ++ 7 files changed, 1792 insertions(+) create mode 100644 scv_tr_sqlite/scv4tlm/tlm2_recorder.h create mode 100644 scv_tr_sqlite/scv4tlm/tlm2_recorder_module.h create mode 100644 scv_tr_sqlite/scv4tlm/tlm_gp_data.h create mode 100644 scv_tr_sqlite/scv4tlm/tlm_gp_data_ext.h create mode 100644 scv_tr_sqlite/scv4tlm/tlm_rec_initiator_socket.h create mode 100644 scv_tr_sqlite/scv4tlm/tlm_rec_target_socket.h create mode 100644 scv_tr_sqlite/scv4tlm/tlm_recording_extension.h diff --git a/scv_tr_sqlite/scv4tlm/tlm2_recorder.h b/scv_tr_sqlite/scv4tlm/tlm2_recorder.h new file mode 100644 index 0000000..3791e1f --- /dev/null +++ b/scv_tr_sqlite/scv4tlm/tlm2_recorder.h @@ -0,0 +1,722 @@ +/* + * tlm_recording.h + * + * Created on: 07.11.2015 + * Author: eyck + */ + +#ifndef TLM2_RECORDER_H_ +#define TLM2_RECORDER_H_ + +#include +#include +#include "tlm_gp_data_ext.h" +#include "tlm_recording_extension.h" +#include +#include +#include + +namespace scv4tlm { + +/*! \brief The TLM2 transaction extensions recorder interface + * + * This interface is used by the TLM2 transaction recorder. It can be used to register custom recorder functionality + * to also record the payload extensions + */ +template< typename TYPES = tlm::tlm_base_protocol_types> +struct tlm2_extensions_recording_if { + /*! \brief recording attributes in extensions at the beginning, it is intended to be overload as it does nothing + * + */ + virtual void recordBeginTx(scv_tr_handle& handle, typename TYPES::tlm_payload_type& payload) = 0; + + /*! \brief recording attributes in extensions at the end, it is intended to be overload as it does nothing + * + */ + virtual void recordEndTx(scv_tr_handle& handle, typename TYPES::tlm_payload_type& payload) = 0; + + virtual ~tlm2_extensions_recording_if(){} +}; +/*! \brief The TLM2 transaction recorder + * + * This module records all TLM transaction to a SCV transaction stream for further viewing and analysis. + * The handle of the created transaction is storee in an tlm_extension so that another instance of the scv_tlm2_recorder + * e.g. further down the opath can link to it. + */ +template< typename TYPES = tlm::tlm_base_protocol_types> +class tlm2_recorder: + public virtual tlm::tlm_fw_transport_if, + public virtual tlm::tlm_bw_transport_if, + public sc_core::sc_object { +public: + SC_HAS_PROCESS(tlm2_recorder); + + //! \brief the attribute to selectively enable/disable recording + sc_core::sc_attribute enable; + + //! \brief the attribute to selectively enable/disable timed recording + sc_core::sc_attribute enableTimed; + + //! \brief the port where fw accesses are forwarded to + sc_core::sc_port > fw_port; + + //! \brief the port where bw accesses are forwarded to + sc_core::sc_port > bw_port; + + /*! \brief The constructor of the component + * + * \param name is the SystemC module name of the recorder + * \param tr_db is a pointer to a transaction recording database. If none is provided the default one is retrieved. + * If this database is not initialized (e.g. by not calling scv_tr_db::set_default_db() ) recording is disabled. + */ + tlm2_recorder(bool recording_enabled = true, scv_tr_db* tr_db = scv_tr_db::get_default_db()){ + this->tlm2_recorder::tlm2_recorder(sc_core::sc_gen_unique_name("tlm2_recorder"), recording_enabled, tr_db); + } + /*! \brief The constructor of the component + * + * \param name is the SystemC module name of the recorder + * \param tr_db is a pointer to a transaction recording database. If none is provided the default one is retrieved. + * If this database is not initialized (e.g. by not calling scv_tr_db::set_default_db() ) recording is disabled. + */ + tlm2_recorder(const char* name, bool recording_enabled = true, scv_tr_db* tr_db = scv_tr_db::get_default_db()) + : sc_core::sc_object(name) + , enable("enable", recording_enabled) + , enableTimed("enableTimed", recording_enabled) + , fw_port(sc_core::sc_gen_unique_name("fw")) + , bw_port(sc_core::sc_gen_unique_name("bw")) + , mm(new RecodingMemoryManager()) + , b_timed_peq(this, &tlm2_recorder::btx_cb) + , nb_timed_peq(this, &tlm2_recorder::nbtx_cb) + , m_db(tr_db) + , b_streamHandle(NULL) + , b_streamHandleTimed(NULL) + , b_trTimedHandle(3) + , nb_streamHandle(2) + , nb_streamHandleTimed(2) + , nb_fw_trHandle(3) + , nb_txReqHandle(3) + , nb_bw_trHandle(3) + , nb_txRespHandle(3) + , dmi_streamHandle(NULL) + , dmi_trGetHandle(NULL) + , dmi_trInvalidateHandle(NULL) + , extensionRecording(NULL) + { + } + + virtual ~tlm2_recorder(){ + delete b_streamHandle; + delete b_streamHandleTimed; + for(size_t i = 0; i* extensionRecording){ + this->extensionRecording=extensionRecording; + } +private: + //! \brief the struct to hold the information to be recorded on the timed streams + struct tlm_recording_payload: public TYPES::tlm_payload_type { + scv_tr_handle parent; + uint64 id; + tlm_recording_payload& operator=(const typename TYPES::tlm_payload_type& x){ + id=(uint64)&x; + set_command(x.get_command()); + set_address(x.get_address()); + set_data_ptr(x.get_data_ptr()); + set_data_length(x.get_data_length()); + set_response_status(x.get_response_status()); + set_byte_enable_ptr(x.get_byte_enable_ptr()); + set_byte_enable_length(x.get_byte_enable_length()); + set_streaming_width(x.get_streaming_width()); + return (*this); + + } + explicit tlm_recording_payload(tlm::tlm_mm_interface* mm) : + TYPES::tlm_payload_type(mm), parent(), id(0) { + } + }; + //! \brief Memory manager for the tlm_recording_payload + struct RecodingMemoryManager: public tlm::tlm_mm_interface { + RecodingMemoryManager() : + free_list(0), empties(0) { + } + tlm_recording_payload* allocate() { + typename TYPES::tlm_payload_type* ptr; + if (free_list) { + ptr = free_list->trans; + empties = free_list; + free_list = free_list->next; + } else { + ptr = new tlm_recording_payload(this); + } + return (tlm_recording_payload*) ptr; + } + void free(typename TYPES::tlm_payload_type* trans) { + trans->reset(); + if (!empties) { + empties = new access; + empties->next = free_list; + empties->prev = 0; + if (free_list) + free_list->prev = empties; + } + free_list = empties; + free_list->trans = trans; + empties = free_list->prev; + } + private: + struct access { + typename TYPES::tlm_payload_type* trans; + access* next; + access* prev; + }; + access *free_list, *empties; + }; + RecodingMemoryManager* mm; + //! peq type definition + struct recording_types { + typedef tlm_recording_payload tlm_payload_type; + typedef typename TYPES::tlm_phase_type tlm_phase_type; + }; + //! event queue to hold time points of blocking transactions + tlm_utils::peq_with_cb_and_phase b_timed_peq; + //! event queue to hold time points of non-blocking transactions + tlm_utils::peq_with_cb_and_phase nb_timed_peq; + /*! \brief The thread processing the blocking accesses with their annotated times + * to generate the timed view of blocking tx + */ + void btx_cb(tlm_recording_payload& rec_parts, const typename TYPES::tlm_phase_type& phase); + /*! \brief The thread processing the non-blocking requests with their annotated times + * to generate the timed view of non-blocking tx + */ + void nbtx_cb(tlm_recording_payload& rec_parts, const typename TYPES::tlm_phase_type& phase); + //! transaction recording database + scv_tr_db* m_db; + //! blocking transaction recording stream handle + scv_tr_stream* b_streamHandle; + //! transaction generator handle for blocking transactions + scv_tr_generator* b_trHandle[3]; + //! timed blocking transaction recording stream handle + scv_tr_stream* b_streamHandleTimed; + //! transaction generator handle for blocking transactions with annotated delays + std::vector*> b_trTimedHandle; + std::map btx_handle_map; + + enum DIR{FW, BW}; + //! non-blocking transaction recording stream handle + std::vector nb_streamHandle; + //! non-blocking transaction recording stream handle + std::vector nb_streamHandleTimed; + //! transaction generator handle for forward non-blocking transactions + std::vector*> nb_fw_trHandle; + //! transaction generator handle for forward non-blocking transactions with annotated delays + std::vector*> nb_txReqHandle; + map nbtx_req_handle_map; + //! transaction generator handle for backward non-blocking transactions + std::vector*> nb_bw_trHandle; + //! transaction generator handle for backward non-blocking transactions with annotated delays + std::vector*> nb_txRespHandle; + map nbtx_last_req_handle_map; + + //! dmi transaction recording stream handle + scv_tr_stream* dmi_streamHandle; + //! transaction generator handle for DMI transactions + scv_tr_generator* dmi_trGetHandle; + scv_tr_generator* dmi_trInvalidateHandle; + + tlm2_extensions_recording_if* extensionRecording; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// implementations of functions +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +template< typename TYPES> +void tlm2_recorder::b_transport(typename TYPES::tlm_payload_type& trans, sc_core::sc_time& delay) { + tlm_recording_payload* req; + if (!isRecordingEnabled()) { + fw_port->b_transport(trans, delay); + return; + } + if (b_streamHandle == NULL) { + string basename(this->name()); + b_streamHandle = new scv_tr_stream((basename + ".blocking").c_str(), "TRANSACTOR", m_db); + b_trHandle[tlm::TLM_READ_COMMAND] = new scv_tr_generator("read", *b_streamHandle, "start_delay", + "end_delay"); + b_trHandle[tlm::TLM_WRITE_COMMAND] = new scv_tr_generator("write", *b_streamHandle, "start_delay", + "end_delay"); + b_trHandle[tlm::TLM_IGNORE_COMMAND] = new scv_tr_generator("ignore", *b_streamHandle, "start_delay", + "end_delay"); + } + // Get a handle for the new transaction + scv_tr_handle h = b_trHandle[trans.get_command()]->begin_transaction(delay.value(), sc_time_stamp()); + tlm_gp_data tgd(trans); + + /************************************************************************* + * do the timed notification + *************************************************************************/ + if (enableTimed.value) { + req = mm->allocate(); + req->acquire(); + (*req) = trans; + req->parent = h; + req->id=h.get_id(); +#ifdef DEBUG + cout<<"notify addition of parent with id "<id<<" to btx_handle_map with delay "<recordBeginTx(h, trans); + tlm_recording_extension* preExt = NULL; + + trans.get_extension(preExt); + if (preExt == NULL) { // we are the first recording this transaction + preExt = new tlm_recording_extension(h, this); + trans.set_extension(preExt); + } else { + h.add_relation(rel_str(PREDECESSOR_SUCCESSOR), preExt->txHandle); + } + scv_tr_handle preTx(preExt->txHandle); + + fw_port->b_transport(trans, delay); + trans.get_extension(preExt); + if (preExt->get_creator() == this) { + // clean-up the extension if this is the original creator + delete preExt; + trans.set_extension((tlm_recording_extension*) NULL); + } else { + preExt->txHandle=preTx; + } + + tgd.set_response_status(trans.get_response_status()); + h.record_attribute("trans", tgd); + h.record_attribute("trans.data_value", *(uint64_t*)trans.get_data_ptr()); + if(extensionRecording) extensionRecording->recordEndTx(h, trans); + // End the transaction + b_trHandle[trans.get_command()]->end_transaction(h, delay.value(), sc_time_stamp()); + // and now the stuff for the timed tx + if (enableTimed.value){ +#ifdef DEBUG + cout<<"notify removal of parent with id "<id<<" to btx_handle_map with delay "< +void tlm2_recorder::btx_cb(tlm_recording_payload& rec_parts, const typename TYPES::tlm_phase_type& phase) { + scv_tr_handle h; + if (b_trTimedHandle[0] == NULL) { + std::string basename(this->name()); + b_streamHandleTimed = new scv_tr_stream((basename + ".blocking_annotated").c_str(), "TRANSACTOR", m_db); + b_trTimedHandle[0] = new scv_tr_generator("read", *b_streamHandleTimed); + b_trTimedHandle[1] = new scv_tr_generator("write", *b_streamHandleTimed); + b_trTimedHandle[2] = new scv_tr_generator("ignore", *b_streamHandleTimed); + } + // Now process outstanding recordings + switch (phase) { + case tlm::BEGIN_REQ: + { + tlm_gp_data tgd(rec_parts); + h = b_trTimedHandle[rec_parts.get_command()]->begin_transaction(rec_parts.get_command()); + h.record_attribute("trans", tgd); + h.add_relation(rel_str(PARENT_CHILD), rec_parts.parent); +#ifdef DEBUG + cout<<"adding parent with id "<::iterator it = btx_handle_map.find(rec_parts.id); + sc_assert(it != btx_handle_map.end()); + h = it->second; + btx_handle_map.erase(it); + h.end_transaction(h, rec_parts.get_response_status()); + rec_parts.release(); + } + break; + default: + sc_assert(!"phase not supported!"); + } + return; +} + +template< typename TYPES> +tlm::tlm_sync_enum tlm2_recorder::nb_transport_fw( + typename TYPES::tlm_payload_type& trans, + typename TYPES::tlm_phase_type& phase, + sc_core::sc_time& delay) { + if (!isRecordingEnabled()) + return fw_port->nb_transport_fw(trans, phase, delay); + // initialize stream and generator if not yet done + if (nb_streamHandle[FW] == NULL) { + string basename(this->name()); + nb_streamHandle[FW] = new scv_tr_stream((basename + ".nb_forward").c_str(), "TRANSACTOR", m_db); + nb_fw_trHandle[tlm::TLM_READ_COMMAND] = new scv_tr_generator("read", *nb_streamHandle[FW], "tlm_phase", "tlm_sync"); + nb_fw_trHandle[tlm::TLM_WRITE_COMMAND] = new scv_tr_generator("write", *nb_streamHandle[FW], "tlm_phase", "tlm_sync"); + nb_fw_trHandle[tlm::TLM_IGNORE_COMMAND] = new scv_tr_generator("ignore", *nb_streamHandle[FW], "tlm_phase", "tlm_sync"); + } + /************************************************************************* + * prepare recording + *************************************************************************/ + // Get a handle for the new transaction + scv_tr_handle h = nb_fw_trHandle[trans.get_command()]->begin_transaction((tlm::tlm_phase_enum) (unsigned) phase); + tlm_recording_extension* preExt = NULL; + trans.get_extension(preExt); + if (phase == tlm::BEGIN_REQ && preExt == NULL) { // we are the first recording this transaction + preExt = new tlm_recording_extension(h, this); + trans.set_extension(preExt); + } else if (preExt != NULL) { + // link handle if we have a predecessor + h.add_relation(rel_str(PREDECESSOR_SUCCESSOR), preExt->txHandle); + } else { + sc_assert(preExt!=NULL && "ERROR on forward path in phase other than tlm::BEGIN_REQ"); + } + // update the extension + preExt->txHandle = h; + h.record_attribute("delay", delay.to_string()); + if(extensionRecording) extensionRecording->recordBeginTx(h, trans); + tlm_gp_data tgd(trans); + /************************************************************************* + * do the timed notification + *************************************************************************/ + if (enableTimed.value) { + tlm_recording_payload* req = mm->allocate(); + req->acquire(); + (*req) = trans; + req->parent = h; + nb_timed_peq.notify(*req, phase, delay); + } + /************************************************************************* + * do the access + *************************************************************************/ + tlm::tlm_sync_enum status = fw_port->nb_transport_fw(trans, phase, delay); + /************************************************************************* + * handle recording + *************************************************************************/ + tgd.set_response_status(trans.get_response_status()); + h.record_attribute("trans", tgd); + if(extensionRecording) extensionRecording->recordEndTx(h, trans); + h.record_attribute("tlm_phase[return_path]", (tlm::tlm_phase_enum) (unsigned) phase); + h.record_attribute("delay[return_path]", delay.to_string()); + // get the extension and free the memory if it was mine + if (status == tlm::TLM_COMPLETED || (status == tlm::TLM_ACCEPTED && phase == tlm::END_RESP)) { + trans.get_extension(preExt); + if (preExt->get_creator() == this) { + delete preExt; + trans.set_extension((tlm_recording_extension*) NULL); + } + /************************************************************************* + * do the timed notification if req. finished here + *************************************************************************/ + tlm_recording_payload* req = mm->allocate(); + req->acquire(); + (*req) = trans; + req->parent = h; + nb_timed_peq.notify(*req, (status == tlm::TLM_COMPLETED && phase == tlm::BEGIN_REQ) ? tlm::END_RESP : phase, + delay); + } else if (status == tlm::TLM_UPDATED) { + tlm_recording_payload* req = mm->allocate(); + req->acquire(); + (*req) = trans; + req->parent = h; + nb_timed_peq.notify(*req, phase, delay); + } + // End the transaction + nb_fw_trHandle[trans.get_command()]->end_transaction(h, status); + return status; +} + + +template< typename TYPES> +tlm::tlm_sync_enum tlm2_recorder::nb_transport_bw(typename TYPES::tlm_payload_type& trans, typename TYPES::tlm_phase_type& phase, + sc_core::sc_time& delay) { + if (!isRecordingEnabled()) + return bw_port->nb_transport_bw(trans, phase, delay); + if (nb_streamHandle[BW] == NULL) { + string basename(this->name()); + nb_streamHandle[BW] = new scv_tr_stream((basename + ".nb_backward").c_str(), "TRANSACTOR", m_db); + nb_bw_trHandle[0] = new scv_tr_generator("read", *nb_streamHandle[BW], "tlm_phase", "tlm_sync"); + nb_bw_trHandle[1] = new scv_tr_generator("write", *nb_streamHandle[BW], "tlm_phase", "tlm_sync"); + nb_bw_trHandle[2] = new scv_tr_generator("ignore", *nb_streamHandle[BW], "tlm_phase", "tlm_sync"); + } + /************************************************************************* + * prepare recording + *************************************************************************/ + tlm_recording_extension* preExt = NULL; + trans.get_extension(preExt); + sc_assert(preExt!=NULL && "ERROR on backward path"); + // Get a handle for the new transaction + scv_tr_handle h = nb_bw_trHandle[trans.get_command()]->begin_transaction((tlm::tlm_phase_enum) (unsigned) phase); + // link handle if we have a predecessor and that's not ourself + h.add_relation(rel_str(PREDECESSOR_SUCCESSOR), preExt->txHandle); + // and set the extension handle to this transaction + preExt->txHandle = h; + h.record_attribute("delay", delay.to_string()); + if(extensionRecording) extensionRecording->recordBeginTx(h, trans); + tlm_gp_data tgd(trans); + /************************************************************************* + * do the timed notification + *************************************************************************/ + if (enableTimed.value) { + tlm_recording_payload* req = mm->allocate(); + req->acquire(); + (*req) = trans; + req->parent = h; + nb_timed_peq.notify(*req, phase, delay); + } + /************************************************************************* + * do the access + *************************************************************************/ + tlm::tlm_sync_enum status = bw_port->nb_transport_bw(trans, phase, delay); + /************************************************************************* + * handle recording + *************************************************************************/ + tgd.set_response_status(trans.get_response_status()); + h.record_attribute("trans", tgd); + if(extensionRecording) extensionRecording->recordEndTx(h, trans); + // phase and delay are already recorded + h.record_attribute("phase_upd", (tlm::tlm_phase_enum) (unsigned) phase); + h.record_attribute("delay_upd", delay.to_string()); + // End the transaction + nb_bw_trHandle[trans.get_command()]->end_transaction(h, status); + if (status == tlm::TLM_COMPLETED || (status == tlm::TLM_UPDATED && phase == tlm::END_RESP)) { + // the transaction is finished + trans.get_extension(preExt); + if (preExt->get_creator() == this) { + // clean-up the extension if this is the original creator + delete preExt; + trans.set_extension((tlm_recording_extension*) NULL); + } + /************************************************************************* + * do the timed notification if req. finished here + *************************************************************************/ + tlm_recording_payload* req = mm->allocate(); + req->acquire(); + (*req) = trans; + req->parent = h; + nb_timed_peq.notify(*req, phase, delay); + } + return status; +} + +template< typename TYPES> +void tlm2_recorder::nbtx_cb(tlm_recording_payload& rec_parts, const typename TYPES::tlm_phase_type& phase) { + scv_tr_handle h; + std::map::iterator it; + if (nb_streamHandleTimed[FW] == NULL) { + std::string basename(this->name()); + nb_streamHandleTimed[FW] = new scv_tr_stream((basename + ".nb_request_annotated").c_str(), "TRANSACTOR", m_db); + nb_txReqHandle[0] = new scv_tr_generator<>("read", *nb_streamHandleTimed[FW]); + nb_txReqHandle[1] = new scv_tr_generator<>("write", *nb_streamHandleTimed[FW]); + nb_txReqHandle[2] = new scv_tr_generator<>("ignore", *nb_streamHandleTimed[FW]); + } + if (nb_streamHandleTimed[BW] == NULL) { + std::string basename(this->name()); + nb_streamHandleTimed[BW] = new scv_tr_stream((basename + ".nb_response_annotated").c_str(), "TRANSACTOR", m_db); + nb_txRespHandle[0] = new scv_tr_generator<>("read", *nb_streamHandleTimed[BW]); + nb_txRespHandle[1] = new scv_tr_generator<>("write", *nb_streamHandleTimed[BW]); + nb_txRespHandle[2] = new scv_tr_generator<>("ignore", *nb_streamHandleTimed[BW]); + } + tlm_gp_data tgd(rec_parts); + switch (phase) { // Now process outstanding recordings + case tlm::BEGIN_REQ: + h = nb_txReqHandle[rec_parts.get_command()]->begin_transaction(); + h.record_attribute("trans", tgd); + h.add_relation(rel_str(PARENT_CHILD), rec_parts.parent); +#ifdef NBDEBUG + cout<<"adding parent with id "<second; + nbtx_req_handle_map.erase(it); + h.end_transaction(); + nbtx_last_req_handle_map[rec_parts.id] = h; + break; + case tlm::BEGIN_RESP: +#ifdef NBDEBUG + cout<<"retrieving parent with id "<second; + nbtx_req_handle_map.erase(it); + h.end_transaction(); + nbtx_last_req_handle_map[rec_parts.id] = h; + } + h = nb_txRespHandle[rec_parts.get_command()]->begin_transaction(); + h.record_attribute("trans", tgd); + h.add_relation(rel_str(PARENT_CHILD), rec_parts.parent); + nbtx_req_handle_map[rec_parts.id] = h; + it = nbtx_last_req_handle_map.find(rec_parts.id); + if (it != nbtx_last_req_handle_map.end()) { + scv_tr_handle pred = it->second; + nbtx_last_req_handle_map.erase(it); + h.add_relation(rel_str(PREDECESSOR_SUCCESSOR), pred); + } + break; + case tlm::END_RESP: +#ifdef NBDEBUG + cout<<"retrieving parent with id "<second; + nbtx_req_handle_map.erase(it); + h.end_transaction(); + } + break; + default: + sc_assert(!"phase not supported!"); + } + rec_parts.release(); + return; + +} + +template< typename TYPES> +bool tlm2_recorder::get_direct_mem_ptr(typename TYPES::tlm_payload_type& trans, tlm::tlm_dmi& dmi_data) { + if (!isRecordingEnabled()) { + return fw_port->get_direct_mem_ptr(trans, dmi_data); + } + if (dmi_streamHandle == NULL) { + string basename(this->name()); + dmi_streamHandle = new scv_tr_stream((basename + ".dmi").c_str(), "TRANSACTOR", m_db); + dmi_trGetHandle = new scv_tr_generator("get_dmi_ptr", *b_streamHandle, "trans", + "dmi_data"); + dmi_trInvalidateHandle = new scv_tr_generator("invalidate", *b_streamHandle, "start_delay", + "end_delay"); + } + scv_tr_handle h = dmi_trGetHandle->begin_transaction(tlm_gp_data(trans)); + bool status= fw_port->get_direct_mem_ptr(trans, dmi_data); + dmi_trGetHandle->end_transaction(h, tlm_dmi_data(dmi_data)); + return status; +} +/*! \brief The direct memory interface backward function + * + * This type of transaction is just forwarded and not recorded. + * \param start_addr is the start address of the memory area being invalid + * \param end_addr is the end address of the memory area being invalid + */ +template< typename TYPES> +void tlm2_recorder::invalidate_direct_mem_ptr(sc_dt::uint64 start_addr, sc_dt::uint64 end_addr) { + if (!isRecordingEnabled()) { + bw_port->invalidate_direct_mem_ptr(start_addr, end_addr); + return; + } + if (dmi_streamHandle == NULL) { + string basename(this->name()); + dmi_streamHandle = new scv_tr_stream((basename + ".dmi").c_str(), "TRANSACTOR", m_db); + dmi_trGetHandle = new scv_tr_generator("get_dmi_ptr", *b_streamHandle, "trans", + "dmi_data"); + dmi_trInvalidateHandle = new scv_tr_generator("invalidate", *b_streamHandle, "start_delay", + "end_delay"); + } + scv_tr_handle h = dmi_trInvalidateHandle->begin_transaction(start_addr); + bw_port->invalidate_direct_mem_ptr(start_addr, end_addr); + dmi_trInvalidateHandle->end_transaction(h, end_addr); + return; +} +/*! \brief The debug transportfunction + * + * This type of transaction is just forwarded and not recorded. + * \param trans is the generic payload of the transaction + * \return the sync state of the transaction + */ +template< typename TYPES> +unsigned int tlm2_recorder::transport_dbg(typename TYPES::tlm_payload_type& trans) { + unsigned int count = fw_port->transport_dbg(trans); + return count; +} + +} // namespace + + + +#endif /* TLM2_RECORDER_H_ */ diff --git a/scv_tr_sqlite/scv4tlm/tlm2_recorder_module.h b/scv_tr_sqlite/scv4tlm/tlm2_recorder_module.h new file mode 100644 index 0000000..7fd7f78 --- /dev/null +++ b/scv_tr_sqlite/scv4tlm/tlm2_recorder_module.h @@ -0,0 +1,61 @@ +/* + * tlm_recorder.h + * + * Created on: 07.11.2015 + * Author: eyck + */ + +#ifndef TLM2_RECORDER_MODULE_H_ +#define TLM2_RECORDER_MODULE_H_ + +#include +#include +#include "tlm2_recorder.h" + +namespace scv4tlm { +/*! \brief The TLM2 transaction recorder + * + * This module records all TLM transaction to a SCV transaction stream for further viewing and analysis. + * The handle of the created transaction is storee in an tlm_extension so that another instance of the scv_tlm2_recorder + * e.g. further down the opath can link to it. + * The transaction recorder is simply bound between an existing pair of initiator and target sockets + */ +template +class tlm2_recorder_module: public sc_core::sc_module, public tlm2_recorder { +public: + SC_HAS_PROCESS(tlm2_recorder_module); + //! The target socket of the recorder to be bound to the initiator + tlm::tlm_target_socket target; + //! The initiator to be bound to the target socket + tlm::tlm_initiator_socket initiator; + + + /*! \brief The constructor of the component + * + * \param name is the SystemC module name of the recorder + * \param tr_db is a pointer to a transaction recording database. If none is provided the default one is retrieved. + * If this database is not initialized (e.g. by not calling scv_tr_db::set_default_db() ) recording is disabled. + */ + tlm2_recorder_module(sc_core::sc_module_name name, bool recording_enabled = true, scv_tr_db* tr_db = scv_tr_db::get_default_db()) + : sc_module(name) + , tlm2_recorder(recording_enabled, tr_db) + { + // bind the sockets to the module + target.bind(*this); + initiator.bind(*this); + } + + virtual ~tlm2_recorder_module(){} + + virtual tlm::tlm_fw_transport_if* get_fw_if() { + return initiator.get_base_port().operator->(); + } + virtual tlm::tlm_bw_transport_if* get_bw_if() { + return target.get_base_port().operator->(); + } + +}; +} // namespace + + +#endif /* TLM2_RECORDER_MODULE_H_ */ diff --git a/scv_tr_sqlite/scv4tlm/tlm_gp_data.h b/scv_tr_sqlite/scv4tlm/tlm_gp_data.h new file mode 100644 index 0000000..136ec98 --- /dev/null +++ b/scv_tr_sqlite/scv4tlm/tlm_gp_data.h @@ -0,0 +1,557 @@ +/* + * tlm_gp_data.h + * + * Created on: 07.11.2015 + * Author: eyck + */ + +#ifndef TLM_GP_DATA_H_ +#define TLM_GP_DATA_H_ + +#include +#include + +namespace scv4tlm { + +struct tlm_gp_data { + //--------------- + // Constructors + //--------------- + + // Default constructor + tlm_gp_data() + : address(0) + , command(tlm::TLM_IGNORE_COMMAND) + , data(0) + , data_length(0) + , response_status(tlm::TLM_INCOMPLETE_RESPONSE) + , dmi(false) + , byte_enable(0) + , byte_enable_length(0) + , streaming_width(0) + , gp_option(tlm::TLM_MIN_PAYLOAD) + , m_extensions(tlm::max_num_extensions()) + , m_ref_count(0) + { + } + + explicit tlm_gp_data(tlm::tlm_mm_interface* mm) + : address(0) + , command(tlm::TLM_IGNORE_COMMAND) + , data(0) + , data_length(0) + , response_status(tlm::TLM_INCOMPLETE_RESPONSE) + , dmi(false) + , byte_enable(0) + , byte_enable_length(0) + , streaming_width(0) + , gp_option(tlm::TLM_MIN_PAYLOAD) + , m_extensions(tlm::max_num_extensions()) + , m_ref_count(0) { + } + + int get_ref_count() const { + return m_ref_count; + } + + void reset() { + //should the other members be reset too? + gp_option = tlm::TLM_MIN_PAYLOAD; + m_extensions.free_entire_cache(); + } + ; + + tlm_gp_data(const tlm::tlm_generic_payload& x) + : address(x.get_address()) + , command(x.get_command()) + , data(x.get_data_ptr()) + , data_length(x.get_data_length()) + , response_status(x.get_response_status()) + , dmi(x.is_dmi_allowed()) + , byte_enable(x.get_byte_enable_ptr()) + , byte_enable_length(x.get_byte_enable_length()) + , streaming_width(x.get_streaming_width()) + , gp_option(x.get_gp_option()) + , m_extensions(tlm::max_num_extensions()) + , m_ref_count(0) + { + } +private: + //disabled copy ctor and assignment operator. + // Copy constructor + tlm_gp_data(const tlm_gp_data& x) + : address(x.get_address()) + , command(x.get_command()) + , data(x.get_data_ptr()) + , data_length(x.get_data_length()) + , response_status(x.get_response_status()) + , dmi(x.is_dmi_allowed()) + , byte_enable(x.get_byte_enable_ptr()) + , byte_enable_length(x.get_byte_enable_length()) + , streaming_width(x.get_streaming_width()) + , gp_option(x.gp_option) + , m_extensions(tlm::max_num_extensions()) + , m_ref_count(0) + { + } +public: + // Assignment operator needed for SCV introspection + tlm_gp_data& operator=(const tlm_gp_data& x) { + command = x.get_command(); + address = x.get_address(); + data = x.get_data_ptr(); + data_length = x.get_data_length(); + response_status = x.get_response_status(); + byte_enable = x.get_byte_enable_ptr(); + byte_enable_length = x.get_byte_enable_length(); + streaming_width = x.get_streaming_width(); + gp_option = x.get_gp_option(); + dmi = x.is_dmi_allowed(); + + // extension copy: all extension arrays must be of equal size by + // construction (i.e. it must either be constructed after C++ + // static construction time, or the resize_extensions() method must + // have been called prior to using the object) + for (unsigned int i = 0; i < m_extensions.size(); i++) { + m_extensions[i] = x.get_extension(i); + } + return (*this); + } + + // non-virtual deep-copying of the object + void deep_copy_from(const scv4tlm::tlm_gp_data & other) { + command = other.get_command(); + address = other.get_address(); + data_length = other.get_data_length(); + response_status = other.get_response_status(); + byte_enable_length = other.get_byte_enable_length(); + streaming_width = other.get_streaming_width(); + gp_option = other.get_gp_option(); + dmi = other.is_dmi_allowed(); + + // deep copy data + // there must be enough space in the target transaction! + if (data && other.get_data_ptr()) { + memcpy(data, other.get_data_ptr(), data_length); + } + // deep copy byte enables + // there must be enough space in the target transaction! + if (byte_enable && other.get_byte_enable_ptr()) { + memcpy(byte_enable, other.get_byte_enable_ptr(), byte_enable_length); + } + // deep copy extensions (sticky and non-sticky) + for (unsigned int i = 0; i < other.m_extensions.size(); i++) { + if (other.get_extension(i)) { //original has extension i + if (!m_extensions[i]) { //We don't: clone. + tlm::tlm_extension_base *ext = other.get_extension(i)->clone(); + if (ext) //extension may not be clonable. + { + set_extension(i, ext); + } + } else { //We already have such extension. Copy original over it. + m_extensions[i]->copy_from(*other.get_extension(i)); + } + } + } + } + + // To update the state of the original generic payload from a deep copy + // Assumes that "other" was created from the original by calling deep_copy_from + // Argument use_byte_enable_on_read determines whether to use or ignores byte enables + // when copying back the data array on a read command + + void update_original_from(const tlm::tlm_generic_payload & other, bool use_byte_enable_on_read = true) { + // Copy back extensions that are present on the original + // update_extensions_from(other); + + // Copy back the response status and DMI hint attributes + response_status = other.get_response_status(); + dmi = other.is_dmi_allowed(); + + // Copy back the data array for a read command only + // deep_copy_from allowed null pointers, and so will we + // We assume the arrays are the same size + // We test for equal pointers in case the original and the copy share the same array + + if (is_read() && data && other.get_data_ptr() && data != other.get_data_ptr()) { + if (byte_enable && use_byte_enable_on_read) { + if (byte_enable_length == 8 && data_length % 8 == 0) { + // Optimized implementation copies 64-bit words by masking + for (unsigned int i = 0; i < data_length; i += 8) { + typedef sc_dt::uint64* u; + *reinterpret_cast(&data[i]) &= ~*reinterpret_cast(byte_enable); + *reinterpret_cast(&data[i]) |= *reinterpret_cast(&other.get_data_ptr()[i]) + & *reinterpret_cast(byte_enable); + } + } else if (byte_enable_length == 4 && data_length % 4 == 0) { + // Optimized implementation copies 32-bit words by masking + for (unsigned int i = 0; i < data_length; i += 4) { + typedef unsigned int* u; + *reinterpret_cast(&data[i]) &= ~*reinterpret_cast(byte_enable); + *reinterpret_cast(&data[i]) |= *reinterpret_cast(&other.get_data_ptr()[i]) + & *reinterpret_cast(byte_enable); + } + } else + // Unoptimized implementation + for (unsigned int i = 0; i < data_length; i++) + if (byte_enable[i % byte_enable_length]) + data[i] = other.get_data_ptr()[i]; + } else + memcpy(data, other.get_data_ptr(), data_length); + } + } + + /* + void update_extensions_from(const tlm::tlm_generic_payload & other) { + // deep copy extensions that are already present + for (unsigned int i = 0; i < tlm::max_num_extensions(); i++) { + if (other.get_extension(i)) { //original has extension i + if (m_extensions[i]) { //We have it too. copy. + m_extensions[i]->copy_from(*other.get_extension(i)); + } + } + } + } + */ + + // Free all extensions. Useful when reusing a cloned transaction that doesn't have memory manager. + // normal and sticky extensions are freed and extension array cleared. + void free_all_extensions() { + m_extensions.free_entire_cache(); + for (unsigned int i = 0; i < m_extensions.size(); i++) { + if (m_extensions[i]) { + m_extensions[i]->free(); + m_extensions[i] = 0; + } + } + } + //-------------- + // Destructor + //-------------- + virtual ~tlm_gp_data() { + for(unsigned int i=0; ifree(); + } + + //---------------- + // API (including setters & getters) + //--------------- + + // Command related method + bool is_read() const { + return (command == tlm::TLM_READ_COMMAND); + } + void set_read() { + command = tlm::TLM_READ_COMMAND; + } + bool is_write() const { + return (command == tlm::TLM_WRITE_COMMAND); + } + void set_write() { + command = tlm::TLM_WRITE_COMMAND; + } + tlm::tlm_command get_command() const { + return command; + } + void set_command(const tlm::tlm_command command) { + this->command = command; + } + + // Address related methods + sc_dt::uint64 get_address() const { + return address; + } + void set_address(const sc_dt::uint64 address) { + this->address = address; + } + + // Data related methods + unsigned char* get_data_ptr() const { + return data; + } + void set_data_ptr(unsigned char* data) { + this->data = data; + } + + // Transaction length (in bytes) related methods + unsigned int get_data_length() const { + return data_length; + } + void set_data_length(const unsigned int length) { + data_length = length; + } + + // Response status related methods + bool is_response_ok() const { + return (response_status > 0); + } + bool is_response_error() const { + return (response_status <= 0); + } + tlm::tlm_response_status get_response_status() const { + return response_status; + } + void set_response_status(const tlm::tlm_response_status response_status) { + this->response_status = response_status; + } + std::string get_response_string() const { + switch (response_status) { + case tlm::TLM_OK_RESPONSE: + return "TLM_OK_RESPONSE"; + case tlm::TLM_INCOMPLETE_RESPONSE: + return "TLM_INCOMPLETE_RESPONSE"; + case tlm::TLM_GENERIC_ERROR_RESPONSE: + return "TLM_GENERIC_ERROR_RESPONSE"; + case tlm::TLM_ADDRESS_ERROR_RESPONSE: + return "TLM_ADDRESS_ERROR_RESPONSE"; + case tlm::TLM_COMMAND_ERROR_RESPONSE: + return "TLM_COMMAND_ERROR_RESPONSE"; + case tlm::TLM_BURST_ERROR_RESPONSE: + return "TLM_BURST_ERROR_RESPONSE"; + case tlm::TLM_BYTE_ENABLE_ERROR_RESPONSE: + return "TLM_BYTE_ENABLE_ERROR_RESPONSE"; + } + return "TLM_UNKNOWN_RESPONSE"; + } + + // Streaming related methods + unsigned int get_streaming_width() const { + return streaming_width; + } + void set_streaming_width(const unsigned int streaming_width) { + this->streaming_width = streaming_width; + } + + // Byte enable related methods + unsigned char* get_byte_enable_ptr() const { + return byte_enable; + } + void set_byte_enable_ptr(unsigned char* byte_enable) { + this->byte_enable = byte_enable; + } + unsigned int get_byte_enable_length() const { + return byte_enable_length; + } + void set_byte_enable_length(const unsigned int byte_enable_length) { + this->byte_enable_length = byte_enable_length; + } + + // This is the "DMI-hint" a slave can set this to true if it + // wants to indicate that a DMI request would be supported: + void set_dmi_allowed(bool dmi_allowed) { + dmi = dmi_allowed; + } + bool is_dmi_allowed() const { + return dmi; + } + + // Use full set of attributes in DMI/debug? + tlm::tlm_gp_option get_gp_option() const { + return gp_option; + } + void set_gp_option(const tlm::tlm_gp_option gp_opt) { + gp_option = gp_opt; + } + +public: + + /* --------------------------------------------------------------------- */ + /* Generic Payload attributes: */ + /* --------------------------------------------------------------------- */ + /* - m_command : Type of transaction. Three values supported: */ + /* - TLM_WRITE_COMMAND */ + /* - TLM_READ_COMMAND */ + /* - TLM_IGNORE_COMMAND */ + /* - m_address : Transaction base address (byte-addressing). */ + /* - m_data : When m_command = TLM_WRITE_COMMAND contains a */ + /* pointer to the data to be written in the target.*/ + /* When m_command = TLM_READ_COMMAND contains a */ + /* pointer where to copy the data read from the */ + /* target. */ + /* - m_length : Total number of bytes of the transaction. */ + /* - m_response_status : This attribute indicates whether an error has */ + /* occurred during the transaction. */ + /* Values supported are: */ + /* - TLM_OK_RESP */ + /* - TLM_INCOMPLETE_RESP */ + /* - TLM_GENERIC_ERROR_RESP */ + /* - TLM_ADDRESS_ERROR_RESP */ + /* - TLM_COMMAND_ERROR_RESP */ + /* - TLM_BURST_ERROR_RESP */ + /* - TLM_BYTE_ENABLE_ERROR_RESP */ + /* */ + /* - m_byte_enable : It can be used to create burst transfers where */ + /* the address increment between each beat is greater */ + /* than the word length of each beat, or to place */ + /* words in selected byte lanes of a bus. */ + /* - m_byte_enable_length : For a read or a write command, the target */ + /* interpret the byte enable length attribute as the */ + /* number of elements in the bytes enable array. */ + /* - m_streaming_width : */ + /* --------------------------------------------------------------------- */ + + sc_dt::uint64 address; + tlm::tlm_command command; + unsigned char* data; + unsigned int data_length; + tlm::tlm_response_status response_status; + bool dmi; + unsigned char* byte_enable; + unsigned int byte_enable_length; + unsigned int streaming_width; + tlm::tlm_gp_option gp_option; + +public: + + /* --------------------------------------------------------------------- */ + /* Dynamic extension mechanism: */ + /* --------------------------------------------------------------------- */ + /* The extension mechanism is intended to enable initiator modules to */ + /* optionally and transparently add data fields to the */ + /* tlm_generic_payload. Target modules are free to check for extensions */ + /* and may or may not react to the data in the extension fields. The */ + /* definition of the extensions' semantics is solely in the */ + /* responsibility of the user. */ + /* */ + /* The following rules apply: */ + /* */ + /* - Every extension class must be derived from tlm_extension, e.g.: */ + /* class my_extension : public tlm_extension { ... } */ + /* */ + /* - A tlm_generic_payload object should be constructed after C++ */ + /* static initialization time. This way it is guaranteed that the */ + /* extension array is of sufficient size to hold all possible */ + /* extensions. Alternatively, the initiator module can enforce a valid */ + /* extension array size by calling the resize_extensions() method */ + /* once before the first transaction with the payload object is */ + /* initiated. */ + /* */ + /* - Initiators should use the the set_extension(e) or clear_extension(e)*/ + /* methods for manipulating the extension array. The type of the */ + /* argument must be a pointer to the specific registered extension */ + /* type (my_extension in the above example) and is used to */ + /* automatically locate the appropriate index in the array. */ + /* */ + /* - Targets can check for a specific extension by calling */ + /* get_extension(e). e will point to zero if the extension is not */ + /* present. */ + /* */ + /* --------------------------------------------------------------------- */ + + // Stick the pointer to an extension into the vector, return the + // previous value: + template T* set_extension(T* ext) { + return static_cast(set_extension(T::ID, ext)); + } + + // non-templatized version with manual index: + tlm::tlm_extension_base* set_extension(unsigned int index, tlm::tlm_extension_base* ext) { + tlm::tlm_extension_base* tmp = m_extensions[index]; + m_extensions[index] = ext; + return tmp; + } + + // Check for an extension, ext will point to 0 if not present + template void get_extension(T*& ext) const { + ext = get_extension(); + } + template T* get_extension() const { + return static_cast(get_extension(T::ID)); + } + // Non-templatized version with manual index: + tlm::tlm_extension_base* get_extension(unsigned int index) const { + return m_extensions[index]; + } + + //this call just removes the extension from the txn but does not + // call free() or tells the MM to do so + // it return false if there was active MM so you are now in an unsafe situation + // recommended use: when 100% sure there is no MM + template void clear_extension(const T* ext) { + clear_extension(); + } + + //this call just removes the extension from the txn but does not + // call free() or tells the MM to do so + // it return false if there was active MM so you are now in an unsafe situation + // recommended use: when 100% sure there is no MM + template void clear_extension() { + clear_extension(T::ID); + } + + //this call removes the extension from the txn and does + // call free() or tells the MM to do so when the txn is finally done + // recommended use: when not sure there is no MM + template void release_extension(T* ext) { + release_extension(); + } + + //this call removes the extension from the txn and does + // call free() or tells the MM to do so when the txn is finally done + // recommended use: when not sure there is no MM + template void release_extension() { + release_extension(T::ID); + } + +private: + // Non-templatized version with manual index + void clear_extension(unsigned int index) { + m_extensions[index] = static_cast(0); + } + // Non-templatized version with manual index + void release_extension(unsigned int index) { + m_extensions[index]->free(); + m_extensions[index] = static_cast(0); + } + +public: + // 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(tlm::max_num_extensions()); + } + +private: + tlm::tlm_array m_extensions; + unsigned int m_ref_count; +}; + + +struct tlm_dmi_data { + tlm_dmi_data() + :dmi_ptr(0) + ,dmi_start_address(0) + ,dmi_end_address(0) + ,dmi_access(tlm::tlm_dmi::DMI_ACCESS_NONE) + ,dmi_read_latency(0) + ,dmi_write_latency(0) + {} + + tlm_dmi_data(tlm::tlm_dmi& dmi_data) + :dmi_ptr(dmi_data.get_dmi_ptr()) + ,dmi_start_address(dmi_data.get_start_address()) + ,dmi_end_address(dmi_data.get_end_address()) + ,dmi_access(dmi_data.get_granted_access()) + ,dmi_read_latency(dmi_data.get_read_latency().value()) + ,dmi_write_latency(dmi_data.get_write_latency().value()) + {} + //-------------- + // Destructor + //-------------- + virtual ~tlm_dmi_data() {} + + unsigned char* dmi_ptr; + sc_dt::uint64 dmi_start_address; + sc_dt::uint64 dmi_end_address; + tlm::tlm_dmi::dmi_access_e dmi_access; + sc_dt::uint64 dmi_read_latency; + sc_dt::uint64 dmi_write_latency; + +}; + + +} +#endif /* TLM_GP_DATA_H_ */ diff --git a/scv_tr_sqlite/scv4tlm/tlm_gp_data_ext.h b/scv_tr_sqlite/scv4tlm/tlm_gp_data_ext.h new file mode 100644 index 0000000..1dd611b --- /dev/null +++ b/scv_tr_sqlite/scv4tlm/tlm_gp_data_ext.h @@ -0,0 +1,131 @@ +/* + * tlm_gp_data_ext.h + * + * Created on: 07.11.2015 + * Author: eyck + */ + +#ifndef TLM_GP_DATA_EXT_H_ +#define TLM_GP_DATA_EXT_H_ + +#include "scv.h" +#include "tlm_gp_data.h" + +template<> +class scv_extensions : public scv_enum_base { +public: + SCV_ENUM_CTOR(tlm::tlm_command) { + SCV_ENUM(tlm::TLM_READ_COMMAND); + SCV_ENUM(tlm::TLM_WRITE_COMMAND); + SCV_ENUM(tlm::TLM_IGNORE_COMMAND); + } +}; + +template<> +class scv_extensions : public scv_enum_base { +public: + SCV_ENUM_CTOR(tlm::tlm_response_status) { + SCV_ENUM(tlm::TLM_OK_RESPONSE); + SCV_ENUM(tlm::TLM_INCOMPLETE_RESPONSE); + SCV_ENUM(tlm::TLM_GENERIC_ERROR_RESPONSE); + SCV_ENUM(tlm::TLM_ADDRESS_ERROR_RESPONSE); + SCV_ENUM(tlm::TLM_COMMAND_ERROR_RESPONSE); + SCV_ENUM(tlm::TLM_BURST_ERROR_RESPONSE); + SCV_ENUM(tlm::TLM_BYTE_ENABLE_ERROR_RESPONSE); + } +}; + +template<> +class scv_extensions : public scv_enum_base { +public: + SCV_ENUM_CTOR(tlm::tlm_gp_option) { + SCV_ENUM(tlm::TLM_MIN_PAYLOAD); + SCV_ENUM(tlm::TLM_FULL_PAYLOAD); + SCV_ENUM(tlm::TLM_FULL_PAYLOAD_ACCEPTED); + } +}; + +template<> +class scv_extensions : public scv_enum_base { +public: + SCV_ENUM_CTOR(tlm::tlm_phase_enum) { + SCV_ENUM(tlm::UNINITIALIZED_PHASE); + SCV_ENUM(tlm::BEGIN_REQ); + SCV_ENUM(tlm::END_REQ); + SCV_ENUM(tlm::BEGIN_RESP); + SCV_ENUM(tlm::END_RESP); + } +}; + +template<> +class scv_extensions : public scv_enum_base { +public: + SCV_ENUM_CTOR(tlm::tlm_sync_enum) { + SCV_ENUM(tlm::TLM_ACCEPTED); + SCV_ENUM(tlm::TLM_UPDATED); + SCV_ENUM(tlm::TLM_COMPLETED); + } +}; + +template<> +class scv_extensions : public scv_extensions_base { +public: + scv_extensions address; + scv_extensions command; + scv_extensions data; + scv_extensions data_length; + scv_extensions response_status; + scv_extensions dmi; + scv_extensions byte_enable; + scv_extensions byte_enable_length; + scv_extensions streaming_width; + scv_extensions gp_option; + + SCV_EXTENSIONS_CTOR(scv4tlm::tlm_gp_data) { + //must be in order + SCV_FIELD(address); + SCV_FIELD(command); + SCV_FIELD(data); + SCV_FIELD(data_length); + SCV_FIELD(response_status); + SCV_FIELD(dmi); + SCV_FIELD(byte_enable); + SCV_FIELD(byte_enable_length); + SCV_FIELD(streaming_width); + SCV_FIELD(gp_option); + } +}; + +template<> +class scv_extensions : public scv_enum_base { +public: + SCV_ENUM_CTOR(tlm::tlm_dmi::dmi_access_e) { + SCV_ENUM(tlm::tlm_dmi::DMI_ACCESS_NONE); + SCV_ENUM(tlm::tlm_dmi::DMI_ACCESS_READ); + SCV_ENUM(tlm::tlm_dmi::DMI_ACCESS_WRITE); + SCV_ENUM(tlm::tlm_dmi::DMI_ACCESS_READ_WRITE); + } +}; + +template<> +class scv_extensions : public scv_extensions_base { +public: + scv_extensions dmi_ptr; + scv_extensions dmi_start_address; + scv_extensions dmi_end_address; + scv_extensions dmi_access; + scv_extensions dmi_read_latency; + scv_extensions dmi_write_latency; + SCV_EXTENSIONS_CTOR(scv4tlm::tlm_dmi_data) { + //must be in order + SCV_FIELD(dmi_ptr); + SCV_FIELD(dmi_start_address); + SCV_FIELD(dmi_end_address); + SCV_FIELD(dmi_access); + SCV_FIELD(dmi_read_latency); + SCV_FIELD(dmi_write_latency); + } +}; + + +#endif /* TLM_GP_DATA_EXT_H_ */ diff --git a/scv_tr_sqlite/scv4tlm/tlm_rec_initiator_socket.h b/scv_tr_sqlite/scv4tlm/tlm_rec_initiator_socket.h new file mode 100644 index 0000000..d789e61 --- /dev/null +++ b/scv_tr_sqlite/scv4tlm/tlm_rec_initiator_socket.h @@ -0,0 +1,125 @@ +/* + * tlm_rec_target_socket.h + * + * Created on: 08.11.2015 + * Author: eyck + */ + +#ifndef TLM_REC_INITIATOR_SOCKET_H_ +#define TLM_REC_INITIATOR_SOCKET_H_ + +#include + +#include "tlm2_recorder.h" + +namespace scv4tlm { +template +class tlm_rec_initiator_socket: public tlm::tlm_initiator_socket { + static std::string gen_name(const char* first, const char* second){ + std::stringstream ss; + ss< fw_interface_type; + typedef tlm::tlm_bw_transport_if bw_interface_type; + typedef sc_core::sc_port port_type; + typedef sc_core::sc_export export_type; + typedef tlm::tlm_base_target_socket_b base_target_socket_type; + typedef tlm::tlm_base_initiator_socket_b base_type; + + tlm_rec_initiator_socket() : + tlm::tlm_initiator_socket() +,recorder() +{ +} + + explicit tlm_rec_initiator_socket(const char* name) : + tlm::tlm_initiator_socket(name) + ,recorder(gen_name(name, "rec").c_str()) + { + } + + virtual ~tlm_rec_initiator_socket(){} + + virtual const char* kind() const { + return "tlm_rec_target_socket"; + } + // + // Bind initiator socket to target socket + // - Binds the port of the initiator socket to the export of the target + // socket + // - Binds the port of the target socket to the export of the initiator + // socket + // + virtual void bind(base_target_socket_type& s) { + // initiator.port -> target.export + (this->get_base_port())(recorder); + recorder.fw_port(s.get_base_interface()); + // target.port -> initiator.export + (s.get_base_port())(recorder); + recorder.bw_port(this->get_base_interface()); + } + // + // Bind initiator socket to initiator socket (hierarchical bind) + // - Binds both the export and the port + // + virtual void bind(base_type& s){ + // port + (this->get_base_port())(recorder); + recorder.fw_port(s.get_base_port()); + // export + (s.get_base_export())(recorder); + recorder.bw_port(this->get_base_export()); + } + + // + // Bind interface to socket + // - Binds the interface to the export of this socket + // + virtual void bind(bw_interface_type& ifs) { + (this->get_base_export())(ifs); + } + + void setExtensionRecording(tlm_extensions_recording_if* extensionRecording){ + recorder.setExtensionRecording(extensionRecording); + } + +protected: + scv4tlm::tlm2_recorder recorder; +}; + +} +// namespace scv4tlm + +#endif /* TLM_REC_TARGET_SOCKET_H_ */ diff --git a/scv_tr_sqlite/scv4tlm/tlm_rec_target_socket.h b/scv_tr_sqlite/scv4tlm/tlm_rec_target_socket.h new file mode 100644 index 0000000..5fd9f91 --- /dev/null +++ b/scv_tr_sqlite/scv4tlm/tlm_rec_target_socket.h @@ -0,0 +1,119 @@ +/* + * tlm_rec_target_socket.h + * + * Created on: 08.11.2015 + * Author: eyck + */ + +#ifndef TLM_REC_TARGET_SOCKET_H_ +#define TLM_REC_TARGET_SOCKET_H_ + +#include + +#include "tlm2_recorder.h" + +namespace scv4tlm { +template +class tlm_rec_target_socket: public tlm::tlm_target_socket { + static std::string gen_name(const char* first, const char* second){ + std::stringstream ss; + ss< fw_interface_type; + typedef tlm::tlm_bw_transport_if bw_interface_type; + typedef sc_core::sc_port port_type; + + typedef sc_core::sc_export export_type; + typedef tlm::tlm_base_initiator_socket_b base_initiator_socket_type; + + typedef tlm::tlm_base_target_socket_b base_type; + + tlm_rec_target_socket() : + tlm::tlm_target_socket() + ,recorder() + { + } + + explicit tlm_rec_target_socket(const char* name) : + tlm::tlm_target_socket(name) + ,recorder(gen_name(name, "rec").c_str()) + { + } + + virtual ~tlm_rec_target_socket(){} + + virtual const char* kind() const { + return "tlm_rec_target_socket"; + } + // + // Bind target socket to target socket (hierarchical bind) + // - Binds both the export and the port + // + virtual void bind(base_type& s) { + // export + (this->get_base_export())(s.get_base_export()); // will be handled by bind(fw_interface_type& ifs) + // port + (s.get_base_port())(recorder); // bind the recording interface to the port, recording will use the m_port + } + // + // Bind interface to socket + // - Binds the interface to the export + // + virtual void bind(fw_interface_type& ifs){ + export_type* exp = &this->get_base_export(); + if( this == exp ) { + export_type::bind(recorder); // non-virtual function call + recorder.fw_port(ifs); + recorder.bw_port(this->get_base_port()); + } else { + exp->bind( ifs ); + } + + } + // + // Forward to 'operator->()' of port class + // + bw_interface_type* operator->() { + return &recorder; + } + + scv4tlm::tlm2_recorder& get_recorder(){ + return recorder; + } + +protected: + scv4tlm::tlm2_recorder recorder; +}; + +} +// namespace scv4tlm + +#endif /* TLM_REC_TARGET_SOCKET_H_ */ diff --git a/scv_tr_sqlite/scv4tlm/tlm_recording_extension.h b/scv_tr_sqlite/scv4tlm/tlm_recording_extension.h new file mode 100644 index 0000000..e2bec53 --- /dev/null +++ b/scv_tr_sqlite/scv4tlm/tlm_recording_extension.h @@ -0,0 +1,77 @@ +/* + * tlm2_tx_record_extension.h + * + * Created on: 07.11.2015 + * Author: eyck + */ + +#ifndef TLM_RECORDING_EXTENSION_H_ +#define TLM_RECORDING_EXTENSION_H_ + +#include + +namespace scv4tlm { + +//! transaction relationships +enum tx_rel { + PARENT_CHILD = 0, /*!< indicates parent child relationship */ + PREDECESSOR_SUCCESSOR /*!< indicates predecessor successor relationship */ +}; +//! the string representation of the tx_rel +static char const* tx_rel_str[] = { "PARENT/CHILD", "PRED/SUCC" }; +/*! \brief cast the tx_rel enum to a string + * + * \param tc_rel is the relationship enum + */ +inline const char* rel_str(tx_rel rel) { + return (tx_rel_str[rel]); +} + +/*! \brief generic payload extension class holding the handle of the last recorded SCV transaction + * + * This extension is been used in the \ref scv_tlm2_recorder. The recorder stores the handle to the generated SCV transaction and + * forwrds it along with the generic payload. If the recorder finds an extension containing a valid handle it links the generated + * SCV transdaction to the found one using the \ref PREDECESSOR releationship + */ +struct tlm_recording_extension: public tlm::tlm_extension { + /*! \brief clone the given extension and duplicate the SCV transaction handle. + * + */ + virtual tlm_extension_base* clone() const { + tlm_recording_extension* t = new tlm_recording_extension(this->txHandle, this->creator); + return t; + } + /*! \brief copy data between extensions. + * + * \param from is the source extension. + */ + virtual void copy_from(tlm_extension_base const& from) { + txHandle = static_cast(from).txHandle; + creator = static_cast(from).creator; + } + /*! \brief constructor storing the handle of the transaction and the owner of this extension + * + * \param handle is the handle of the created SCV transaction. + * \param creator_ is the pointer to the owner of this extension (usually an instance of scv_tlm2_recorder). + */ + tlm_recording_extension(scv_tr_handle handle, void* creator_) : + txHandle(handle), creator(creator_) { + } + /*! \brief accessor to the owner, the property is read only. + * + */ + void* get_creator() { + return creator; + } + /*! \brief accessor to the SCV transaction handle. + * + */ + scv_tr_handle txHandle; +private: + //! the owner of this transaction + void* creator; +}; + +} + +#endif /* TLM_RECORDING_EXTENSION_H_ */