Added tlm3 recording sockets
This commit is contained in:
		
							
								
								
									
										722
									
								
								scv_tr_sqlite/scv4tlm/tlm2_recorder.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										722
									
								
								scv_tr_sqlite/scv4tlm/tlm2_recorder.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,722 @@ | ||||
| /* | ||||
|  * tlm_recording.h | ||||
|  * | ||||
|  *  Created on: 07.11.2015 | ||||
|  *      Author: eyck | ||||
|  */ | ||||
|  | ||||
| #ifndef TLM2_RECORDER_H_ | ||||
| #define TLM2_RECORDER_H_ | ||||
|  | ||||
| #include <scv.h> | ||||
| #include <tlm> | ||||
| #include "tlm_gp_data_ext.h" | ||||
| #include "tlm_recording_extension.h" | ||||
| #include <map> | ||||
| #include <string> | ||||
| #include <vector> | ||||
|  | ||||
| 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<TYPES>, | ||||
| 		public virtual tlm::tlm_bw_transport_if<TYPES>, | ||||
| 		public sc_core::sc_object { | ||||
| public: | ||||
| 	SC_HAS_PROCESS(tlm2_recorder<TYPES>); | ||||
|  | ||||
| 	//! \brief the attribute to selectively enable/disable recording | ||||
| 	sc_core::sc_attribute<bool> enable; | ||||
|  | ||||
| 	//! \brief the attribute to selectively enable/disable timed recording | ||||
| 	sc_core::sc_attribute<bool> enableTimed; | ||||
|  | ||||
| 	//! \brief the port where fw accesses are forwarded to | ||||
| 	sc_core::sc_port<tlm::tlm_fw_transport_if<TYPES> > fw_port; | ||||
|  | ||||
| 	//! \brief the port where bw accesses are forwarded to | ||||
| 	sc_core::sc_port<tlm::tlm_bw_transport_if<TYPES> > 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<b_trTimedHandle.size(); ++i) delete b_trTimedHandle[i]; | ||||
| 		for(size_t i = 0; i<nb_streamHandle.size(); ++i) delete nb_streamHandle[i]; | ||||
| 		for(size_t i = 0; i<nb_streamHandleTimed.size(); ++i) delete nb_streamHandleTimed[i]; | ||||
| 		for(size_t i = 0; i<nb_fw_trHandle.size(); ++i) delete nb_fw_trHandle[i]; | ||||
| 		for(size_t i = 0; i<nb_txReqHandle.size(); ++i) delete nb_txReqHandle[i]; | ||||
| 		for(size_t i = 0; i<nb_bw_trHandle.size(); ++i) delete nb_bw_trHandle[i]; | ||||
| 		for(size_t i = 0; i<nb_txRespHandle.size(); ++i) delete nb_txRespHandle[i]; | ||||
| 		delete dmi_streamHandle; | ||||
| 		delete dmi_trGetHandle; | ||||
| 		delete dmi_trInvalidateHandle; | ||||
| 		delete extensionRecording; | ||||
| 	} | ||||
|  | ||||
| 	// TLM-2.0 interface methods for initiator and target sockets, surrounded with Tx Recording | ||||
| 	/*! \brief The non-blocking forward transport function | ||||
| 	 * | ||||
| 	 * This type of transaction is forwarded and recorded to a transaction stream named "nb_fw" with current timestamps. | ||||
| 	 * \param trans is the generic payload of the transaction | ||||
| 	 * \param phase is the current phase of the transaction | ||||
| 	 * \param delay is the annotated delay | ||||
| 	 * \return the sync state of the transaction | ||||
| 	 */ | ||||
| 	virtual tlm::tlm_sync_enum nb_transport_fw(typename TYPES::tlm_payload_type& trans, typename TYPES::tlm_phase_type& phase, | ||||
| 			sc_core::sc_time& delay); | ||||
|  | ||||
| 	/*! \brief The non-blocking backward transport function | ||||
| 	 * | ||||
| 	 * This type of transaction is forwarded and recorded to a transaction stream named "nb_bw" with current timestamps. | ||||
| 	 * \param trans is the generic payload of the transaction | ||||
| 	 * \param phase is the current phase of the transaction | ||||
| 	 * \param delay is the annotated delay | ||||
| 	 * \return the sync state of the transaction | ||||
| 	 */ | ||||
| 	virtual tlm::tlm_sync_enum nb_transport_bw(typename TYPES::tlm_payload_type& trans, typename TYPES::tlm_phase_type& phase, | ||||
| 			sc_core::sc_time& delay); | ||||
|  | ||||
| 	/*! \brief The blocking transport function | ||||
| 	 * | ||||
| 	 * This type of transaction is forwarded and recorded to a transaction stream named "b_tx" with current timestamps. Additionally a "b_tx_timed" | ||||
| 	 * is been created recording the transactions at their annotated delay | ||||
| 	 * \param trans is the generic payload of the transaction | ||||
| 	 * \param delay is the annotated delay | ||||
| 	 */ | ||||
| 	virtual void b_transport(typename TYPES::tlm_payload_type& trans, sc_core::sc_time& delay); | ||||
|  | ||||
| 	/*! \brief The direct memory interface forward function | ||||
| 	 * | ||||
| 	 * This type of transaction is just forwarded and not recorded. | ||||
| 	 * \param trans is the generic payload of the transaction | ||||
| 	 * \param dmi_data is the structure holding the dmi information | ||||
| 	 * \return if the dmi structure is valid | ||||
| 	 */ | ||||
| 	virtual bool get_direct_mem_ptr(typename TYPES::tlm_payload_type& trans, tlm::tlm_dmi& dmi_data); | ||||
| 	/*! \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 | ||||
| 	 */ | ||||
| 	virtual void invalidate_direct_mem_ptr(sc_dt::uint64 start_addr, sc_dt::uint64 end_addr); | ||||
| 	/*! \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 | ||||
| 	 */ | ||||
| 	virtual unsigned int transport_dbg(typename TYPES::tlm_payload_type& trans); | ||||
| 	/*! \brief get the current state of transaction recording | ||||
| 	 * | ||||
| 	 * \return if true transaction recording is enabled otherwise transaction recording is bypassed | ||||
| 	 */ | ||||
| 	const bool isRecordingEnabled() const { | ||||
| 		return m_db != NULL && enable.value; | ||||
| 	} | ||||
|  | ||||
| 	void setExtensionRecording(tlm2_extensions_recording_if<TYPES>* 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<tlm2_recorder, recording_types> b_timed_peq; | ||||
| 	//! event queue to hold time points of non-blocking transactions | ||||
| 	tlm_utils::peq_with_cb_and_phase<tlm2_recorder, recording_types> 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<sc_dt::uint64, sc_dt::uint64>* 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<scv_tr_generator<tlm::tlm_command, tlm::tlm_response_status>*> b_trTimedHandle; | ||||
| 	std::map<uint64, scv_tr_handle> btx_handle_map; | ||||
|  | ||||
| 	enum DIR{FW, BW}; | ||||
| 	//! non-blocking transaction recording stream handle | ||||
| 	std::vector<scv_tr_stream*> nb_streamHandle; | ||||
| 	//! non-blocking transaction recording stream handle | ||||
| 	std::vector<scv_tr_stream*> nb_streamHandleTimed; | ||||
| 	//! transaction generator handle for forward non-blocking transactions | ||||
| 	std::vector<scv_tr_generator<tlm::tlm_phase_enum, tlm::tlm_sync_enum>*> nb_fw_trHandle; | ||||
| 	//! transaction generator handle for forward non-blocking transactions with annotated delays | ||||
| 	std::vector<scv_tr_generator<>*> nb_txReqHandle; | ||||
| 	map<uint64, scv_tr_handle> nbtx_req_handle_map; | ||||
| 	//! transaction generator handle for backward non-blocking transactions | ||||
| 	std::vector<scv_tr_generator<tlm::tlm_phase_enum, tlm::tlm_sync_enum>*> nb_bw_trHandle; | ||||
| 	//! transaction generator handle for backward non-blocking transactions with annotated delays | ||||
| 	std::vector<scv_tr_generator<>*> nb_txRespHandle; | ||||
| 	map<uint64, scv_tr_handle> nbtx_last_req_handle_map; | ||||
|  | ||||
| 	//! dmi transaction recording stream handle | ||||
| 	scv_tr_stream* dmi_streamHandle; | ||||
| 	//! transaction generator handle for DMI transactions | ||||
| 	scv_tr_generator<tlm_gp_data, tlm_dmi_data>* dmi_trGetHandle; | ||||
| 	scv_tr_generator<sc_dt::uint64, sc_dt::uint64>* dmi_trInvalidateHandle; | ||||
|  | ||||
| 	tlm2_extensions_recording_if<TYPES>* extensionRecording; | ||||
| }; | ||||
|  | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| // implementations of functions | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|  | ||||
| template< typename TYPES> | ||||
| void tlm2_recorder<TYPES>::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<sc_dt::uint64, sc_dt::uint64>("read", *b_streamHandle, "start_delay", | ||||
| 				"end_delay"); | ||||
| 		b_trHandle[tlm::TLM_WRITE_COMMAND] = new scv_tr_generator<sc_dt::uint64, sc_dt::uint64>("write", *b_streamHandle, "start_delay", | ||||
| 				"end_delay"); | ||||
| 		b_trHandle[tlm::TLM_IGNORE_COMMAND] = new scv_tr_generator<sc_dt::uint64, sc_dt::uint64>("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 "<<req->id<<" to btx_handle_map with delay "<<delay<<std::endl; | ||||
| #endif | ||||
| 		b_timed_peq.notify(*req, tlm::BEGIN_REQ, delay); | ||||
| 	} | ||||
|  | ||||
| 	if(extensionRecording) extensionRecording->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 "<<req->id<<" to btx_handle_map with delay "<<delay<<std::endl; | ||||
| #endif | ||||
| 		b_timed_peq.notify(*req, tlm::END_RESP, delay); | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| template< typename TYPES> | ||||
| void tlm2_recorder<TYPES>::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<tlm::tlm_command, tlm::tlm_response_status>("read", *b_streamHandleTimed); | ||||
| 		b_trTimedHandle[1] = new scv_tr_generator<tlm::tlm_command, tlm::tlm_response_status>("write", *b_streamHandleTimed); | ||||
| 		b_trTimedHandle[2] = new scv_tr_generator<tlm::tlm_command, tlm::tlm_response_status>("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 "<<rec_parts.id<<" to btx_handle_map"<<std::endl; | ||||
| #endif | ||||
| 		btx_handle_map[rec_parts.id] = h; | ||||
| 	} | ||||
| 	break; | ||||
| 	case tlm::END_RESP: { | ||||
| #ifdef DEBUG | ||||
| 		cout<<"retrieving parent with id "<<rec_parts.id<<" from btx_handle_map"<<std::endl; | ||||
| #endif | ||||
| 		std::map<uint64, scv_tr_handle>::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<TYPES>::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<tlm::tlm_phase_enum, tlm::tlm_sync_enum>("read", *nb_streamHandle[FW], "tlm_phase", "tlm_sync"); | ||||
| 		nb_fw_trHandle[tlm::TLM_WRITE_COMMAND] = new scv_tr_generator<tlm::tlm_phase_enum, tlm::tlm_sync_enum>("write", *nb_streamHandle[FW], "tlm_phase", "tlm_sync"); | ||||
| 		nb_fw_trHandle[tlm::TLM_IGNORE_COMMAND] = new scv_tr_generator<tlm::tlm_phase_enum, tlm::tlm_sync_enum>("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<TYPES>::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<tlm::tlm_phase_enum, tlm::tlm_sync_enum>("read", *nb_streamHandle[BW], "tlm_phase", "tlm_sync"); | ||||
| 		nb_bw_trHandle[1] = new scv_tr_generator<tlm::tlm_phase_enum, tlm::tlm_sync_enum>("write", *nb_streamHandle[BW], "tlm_phase", "tlm_sync"); | ||||
| 		nb_bw_trHandle[2] = new scv_tr_generator<tlm::tlm_phase_enum, tlm::tlm_sync_enum>("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<TYPES>::nbtx_cb(tlm_recording_payload& rec_parts, const typename TYPES::tlm_phase_type& phase) { | ||||
| 	scv_tr_handle h; | ||||
| 	std::map<uint64, scv_tr_handle>::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 "<<rec_parts.id<<" to nbtx_req_handle_map"<<std::endl; | ||||
| #endif | ||||
| 		nbtx_req_handle_map[rec_parts.id] = h; | ||||
| 		break; | ||||
| 	case tlm::END_REQ: | ||||
| #ifdef NBDEBUG | ||||
| 		cout<<"retrieving parent with id "<<rec_parts.id<<" from nbtx_req_handle_map"<<std::endl; | ||||
| #endif | ||||
| 		it = nbtx_req_handle_map.find(rec_parts.id); | ||||
| 		sc_assert(it != nbtx_req_handle_map.end()); | ||||
| 		h = it->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 "<<rec_parts.id<<" from nbtx_req_handle_map"<<std::endl; | ||||
| #endif | ||||
| 		it = nbtx_req_handle_map.find(rec_parts.id); | ||||
| 		if (it != nbtx_req_handle_map.end()) { | ||||
| 			h = it->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 "<<rec_parts.id<<" from nbtx_req_handle_map"<<std::endl; | ||||
| #endif | ||||
| 		it = nbtx_req_handle_map.find(rec_parts.id); | ||||
| 		if (it != nbtx_req_handle_map.end()) { | ||||
| 			h = it->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<TYPES>::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<tlm_gp_data, tlm_dmi_data>("get_dmi_ptr", *b_streamHandle, "trans", | ||||
| 				"dmi_data"); | ||||
| 		dmi_trInvalidateHandle = new scv_tr_generator<sc_dt::uint64, sc_dt::uint64>("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<TYPES>::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<tlm_gp_data, tlm_dmi_data>("get_dmi_ptr", *b_streamHandle, "trans", | ||||
| 				"dmi_data"); | ||||
| 		dmi_trInvalidateHandle = new scv_tr_generator<sc_dt::uint64, sc_dt::uint64>("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<TYPES>::transport_dbg(typename TYPES::tlm_payload_type& trans) { | ||||
| 	unsigned int count = fw_port->transport_dbg(trans); | ||||
| 	return count; | ||||
| } | ||||
|  | ||||
| } // namespace | ||||
|  | ||||
|  | ||||
|  | ||||
| #endif /* TLM2_RECORDER_H_ */ | ||||
							
								
								
									
										61
									
								
								scv_tr_sqlite/scv4tlm/tlm2_recorder_module.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								scv_tr_sqlite/scv4tlm/tlm2_recorder_module.h
									
									
									
									
									
										Normal file
									
								
							| @@ -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 <tlm_utils/simple_initiator_socket.h> | ||||
| #include <tlm_utils/simple_target_socket.h> | ||||
| #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<unsigned int BUSWIDTH = 32, typename TYPES=tlm::tlm_base_protocol_types> | ||||
| class tlm2_recorder_module: public sc_core::sc_module, public tlm2_recorder<TYPES> { | ||||
| public: | ||||
| 	SC_HAS_PROCESS(tlm2_recorder_module); | ||||
| 	//! The target socket of the recorder to be bound to the initiator | ||||
| 	tlm::tlm_target_socket<BUSWIDTH, TYPES, 1> target; | ||||
| 	//! The initiator to be bound to the target socket | ||||
| 	tlm::tlm_initiator_socket<BUSWIDTH, TYPES, 1> 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<TYPES>(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<tlm::tlm_base_protocol_types>* get_fw_if() { | ||||
| 		return initiator.get_base_port().operator->(); | ||||
| 	} | ||||
| 	virtual tlm::tlm_bw_transport_if<tlm::tlm_base_protocol_types>* get_bw_if() { | ||||
| 		return target.get_base_port().operator->(); | ||||
| 	} | ||||
|  | ||||
| }; | ||||
| } // namespace | ||||
|  | ||||
|  | ||||
| #endif /* TLM2_RECORDER_MODULE_H_ */ | ||||
							
								
								
									
										557
									
								
								scv_tr_sqlite/scv4tlm/tlm_gp_data.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										557
									
								
								scv_tr_sqlite/scv4tlm/tlm_gp_data.h
									
									
									
									
									
										Normal file
									
								
							| @@ -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 <tlm> | ||||
| #include <assert.h> | ||||
|  | ||||
| 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<u>(&data[i]) &= ~*reinterpret_cast<u>(byte_enable); | ||||
| 						*reinterpret_cast<u>(&data[i]) |= *reinterpret_cast<u>(&other.get_data_ptr()[i]) | ||||
| 										& *reinterpret_cast<u>(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<u>(&data[i]) &= ~*reinterpret_cast<u>(byte_enable); | ||||
| 						*reinterpret_cast<u>(&data[i]) |= *reinterpret_cast<u>(&other.get_data_ptr()[i]) | ||||
| 										& *reinterpret_cast<u>(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; i<m_extensions.size(); i++) | ||||
| 			if(m_extensions[i]) m_extensions[i]->free(); | ||||
| 	} | ||||
|  | ||||
| 	//---------------- | ||||
| 	// 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<my_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<typename T> T* set_extension(T* ext) { | ||||
| 		return static_cast<T*>(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<typename T> void get_extension(T*& ext) const { | ||||
| 		ext = get_extension<T>(); | ||||
| 	} | ||||
| 	template<typename T> T* get_extension() const { | ||||
| 		return static_cast<T*>(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<typename T> void clear_extension(const T* ext) { | ||||
| 		clear_extension<T>(); | ||||
| 	} | ||||
|  | ||||
| 	//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<typename T> 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<typename T> void release_extension(T* ext) { | ||||
| 		release_extension<T>(); | ||||
| 	} | ||||
|  | ||||
| 	//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<typename T> 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<tlm::tlm_extension_base*>(0); | ||||
| 	} | ||||
| 	// Non-templatized version with manual index | ||||
| 	void release_extension(unsigned int index) { | ||||
| 		m_extensions[index]->free(); | ||||
| 		m_extensions[index] = static_cast<tlm::tlm_extension_base*>(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<tlm::tlm_extension_base*> 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_ */ | ||||
							
								
								
									
										131
									
								
								scv_tr_sqlite/scv4tlm/tlm_gp_data_ext.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								scv_tr_sqlite/scv4tlm/tlm_gp_data_ext.h
									
									
									
									
									
										Normal file
									
								
							| @@ -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<tlm::tlm_command> : public scv_enum_base<tlm::tlm_command> { | ||||
| 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<tlm::tlm_response_status> : public scv_enum_base<tlm::tlm_response_status> { | ||||
| 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<tlm::tlm_gp_option> : public scv_enum_base<tlm::tlm_gp_option> { | ||||
| 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<tlm::tlm_phase_enum> : public scv_enum_base<tlm::tlm_phase_enum> { | ||||
| 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<tlm::tlm_sync_enum> : public scv_enum_base<tlm::tlm_sync_enum> { | ||||
| 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<scv4tlm::tlm_gp_data> : public scv_extensions_base<scv4tlm::tlm_gp_data> { | ||||
| public: | ||||
| 	scv_extensions<sc_dt::uint64>            address; | ||||
| 	scv_extensions<tlm::tlm_command>         command; | ||||
| 	scv_extensions<unsigned char*>           data; | ||||
| 	scv_extensions<unsigned int>             data_length; | ||||
| 	scv_extensions<tlm::tlm_response_status> response_status; | ||||
| 	scv_extensions<bool>                     dmi; | ||||
| 	scv_extensions<unsigned char*>           byte_enable; | ||||
| 	scv_extensions<unsigned int>             byte_enable_length; | ||||
| 	scv_extensions<unsigned int>             streaming_width; | ||||
| 	scv_extensions<tlm::tlm_gp_option>       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<tlm::tlm_dmi::dmi_access_e> : public scv_enum_base<tlm::tlm_dmi::dmi_access_e> { | ||||
| 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<scv4tlm::tlm_dmi_data> : public scv_extensions_base<scv4tlm::tlm_dmi_data> { | ||||
| public: | ||||
| 	scv_extensions<unsigned char*>   dmi_ptr; | ||||
| 	scv_extensions<sc_dt::uint64>    dmi_start_address; | ||||
| 	scv_extensions<sc_dt::uint64>    dmi_end_address; | ||||
| 	scv_extensions<tlm::tlm_dmi::dmi_access_e> dmi_access; | ||||
| 	scv_extensions<sc_dt::uint64> dmi_read_latency; | ||||
| 	scv_extensions<sc_dt::uint64> 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_ */ | ||||
							
								
								
									
										125
									
								
								scv_tr_sqlite/scv4tlm/tlm_rec_initiator_socket.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								scv_tr_sqlite/scv4tlm/tlm_rec_initiator_socket.h
									
									
									
									
									
										Normal file
									
								
							| @@ -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 <tlm_core/tlm_2/tlm_sockets/tlm_initiator_socket.h> | ||||
|  | ||||
| #include "tlm2_recorder.h" | ||||
|  | ||||
| namespace scv4tlm { | ||||
| template<unsigned int BUSWIDTH = 32, typename TYPES = tlm::tlm_base_protocol_types, int N = 1 | ||||
| #if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714) | ||||
| 		, sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND | ||||
| #endif | ||||
| 		> | ||||
| class tlm_rec_initiator_socket: public tlm::tlm_initiator_socket<BUSWIDTH | ||||
| , TYPES | ||||
| , N | ||||
| #if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714) | ||||
| , POL | ||||
| #endif | ||||
| > { | ||||
| 	static std::string gen_name(const char* first, const char* second){ | ||||
| 		std::stringstream ss; | ||||
| 		ss<<first<<"_"<<second; | ||||
| 		return ss.str(); | ||||
| 	} | ||||
| public: | ||||
| 	typedef tlm::tlm_fw_transport_if<TYPES>  fw_interface_type; | ||||
| 	typedef tlm::tlm_bw_transport_if<TYPES>  bw_interface_type; | ||||
| 	typedef sc_core::sc_port<fw_interface_type, N | ||||
| #if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714) | ||||
| 			, POL | ||||
| #endif | ||||
| 			>   port_type; | ||||
| 	typedef sc_core::sc_export<bw_interface_type> export_type; | ||||
| 	typedef tlm::tlm_base_target_socket_b<BUSWIDTH, | ||||
| 			fw_interface_type, | ||||
| 			bw_interface_type> base_target_socket_type; | ||||
| 	typedef tlm::tlm_base_initiator_socket_b<BUSWIDTH, | ||||
| 			fw_interface_type, | ||||
| 			bw_interface_type> base_type; | ||||
|  | ||||
| 	tlm_rec_initiator_socket() : | ||||
| 		tlm::tlm_initiator_socket<BUSWIDTH | ||||
| 		, TYPES | ||||
| 		, N | ||||
| #if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714) | ||||
| , POL | ||||
| #endif | ||||
| >() | ||||
| ,recorder() | ||||
| { | ||||
| } | ||||
|  | ||||
| 	explicit tlm_rec_initiator_socket(const char* name) : | ||||
| 						tlm::tlm_initiator_socket<BUSWIDTH | ||||
| 						, TYPES | ||||
| 						, N | ||||
| #if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714) | ||||
| 						, POL | ||||
| #endif | ||||
| 						>(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<TYPES>* extensionRecording){ | ||||
| 		recorder.setExtensionRecording(extensionRecording); | ||||
| 	} | ||||
|  | ||||
| protected: | ||||
| 	scv4tlm::tlm2_recorder<TYPES> recorder; | ||||
| }; | ||||
|  | ||||
| } | ||||
| // namespace scv4tlm | ||||
|  | ||||
| #endif /* TLM_REC_TARGET_SOCKET_H_ */ | ||||
							
								
								
									
										119
									
								
								scv_tr_sqlite/scv4tlm/tlm_rec_target_socket.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								scv_tr_sqlite/scv4tlm/tlm_rec_target_socket.h
									
									
									
									
									
										Normal file
									
								
							| @@ -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 <tlm_core/tlm_2/tlm_sockets/tlm_target_socket.h> | ||||
|  | ||||
| #include "tlm2_recorder.h" | ||||
|  | ||||
| namespace scv4tlm { | ||||
| template<unsigned int BUSWIDTH = 32, typename TYPES = tlm::tlm_base_protocol_types, int N = 1 | ||||
| #if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714) | ||||
| 		, sc_core::sc_port_policy POL = sc_core::SC_ONE_OR_MORE_BOUND | ||||
| #endif | ||||
| 		> | ||||
| class tlm_rec_target_socket: public tlm::tlm_target_socket<BUSWIDTH | ||||
| , TYPES | ||||
| , N | ||||
| #if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714) | ||||
| , POL | ||||
| #endif | ||||
| > { | ||||
| 	static std::string gen_name(const char* first, const char* second){ | ||||
| 		std::stringstream ss; | ||||
| 		ss<<first<<"_"<<second; | ||||
| 		return ss.str(); | ||||
| 	} | ||||
| public: | ||||
| 	typedef tlm::tlm_fw_transport_if<TYPES>  fw_interface_type; | ||||
| 	typedef tlm::tlm_bw_transport_if<TYPES>  bw_interface_type; | ||||
| 	typedef sc_core::sc_port<bw_interface_type, N | ||||
| #if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714) | ||||
| 			, POL | ||||
| #endif | ||||
| 			>   port_type; | ||||
|  | ||||
| 	typedef sc_core::sc_export<fw_interface_type> export_type; | ||||
| 	typedef tlm::tlm_base_initiator_socket_b<BUSWIDTH, fw_interface_type, bw_interface_type>  base_initiator_socket_type; | ||||
|  | ||||
| 	typedef tlm::tlm_base_target_socket_b<BUSWIDTH,	fw_interface_type, bw_interface_type> base_type; | ||||
|  | ||||
| 	tlm_rec_target_socket() : | ||||
| 		tlm::tlm_target_socket<BUSWIDTH | ||||
| 		, TYPES | ||||
| 		, N | ||||
| #if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714) | ||||
| 		, POL | ||||
| #endif | ||||
| 		>() | ||||
| 		,recorder() | ||||
| 	{ | ||||
| 	} | ||||
|  | ||||
| 	explicit tlm_rec_target_socket(const char* name) : | ||||
| 		tlm::tlm_target_socket<BUSWIDTH | ||||
| 		, TYPES | ||||
| 		, N | ||||
| #if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714) | ||||
| 		, POL | ||||
| #endif | ||||
| 		>(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<TYPES>& get_recorder(){ | ||||
| 		return recorder; | ||||
| 	} | ||||
|  | ||||
| protected: | ||||
| 	scv4tlm::tlm2_recorder<TYPES> recorder; | ||||
| }; | ||||
|  | ||||
| } | ||||
| // namespace scv4tlm | ||||
|  | ||||
| #endif /* TLM_REC_TARGET_SOCKET_H_ */ | ||||
							
								
								
									
										77
									
								
								scv_tr_sqlite/scv4tlm/tlm_recording_extension.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								scv_tr_sqlite/scv4tlm/tlm_recording_extension.h
									
									
									
									
									
										Normal file
									
								
							| @@ -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 <scv.h> | ||||
|  | ||||
| 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<tlm_recording_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<tlm_recording_extension const &>(from).txHandle; | ||||
| 		creator = static_cast<tlm_recording_extension const &>(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_ */ | ||||
		Reference in New Issue
	
	Block a user