| /*! |
| * \file trc_pkt_decode_base.h |
| * \brief OpenCSD : Trace Packet decoder base class. |
| * |
| * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. |
| */ |
| |
| /* |
| * Redistribution and use in source and binary forms, with or without modification, |
| * are permitted provided that the following conditions are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * |
| * 3. Neither the name of the copyright holder nor the names of its contributors |
| * may be used to endorse or promote products derived from this software without |
| * specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, |
| * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #ifndef ARM_TRC_PKT_DECODE_BASE_H_INCLUDED |
| #define ARM_TRC_PKT_DECODE_BASE_H_INCLUDED |
| |
| #include "trc_component.h" |
| #include "comp_attach_pt_t.h" |
| |
| #include "interfaces/trc_pkt_in_i.h" |
| #include "interfaces/trc_gen_elem_in_i.h" |
| #include "interfaces/trc_tgt_mem_access_i.h" |
| #include "interfaces/trc_instr_decode_i.h" |
| |
| /** @defgroup ocsd_pkt_decode OpenCSD Library : Packet Decoders. |
| |
| @brief Classes providing Protocol Packet Decoding capability. |
| |
| Packet decoders convert incoming protocol packets from a packet processor, |
| into generic trace elements to be output to an analysis program. |
| |
| Packet decoders can be:- |
| - PE decoders - converting ETM or PTM packets into instruction and data trace elements |
| - SW stimulus decoder - converting STM or ITM packets into software generated trace elements. |
| - Bus decoders - converting HTM packets into bus transaction elements. |
| |
| @{*/ |
| |
| |
| class TrcPktDecodeI : public TraceComponent |
| { |
| public: |
| TrcPktDecodeI(const char *component_name); |
| TrcPktDecodeI(const char *component_name, int instIDNum); |
| virtual ~TrcPktDecodeI() {}; |
| |
| componentAttachPt<ITrcGenElemIn> *getTraceElemOutAttachPt() { return &m_trace_elem_out; }; |
| componentAttachPt<ITargetMemAccess> *getMemoryAccessAttachPt() { return &m_mem_access; }; |
| componentAttachPt<IInstrDecode> *getInstrDecodeAttachPt() { return &m_instr_decode; }; |
| |
| void setUsesMemAccess(bool bUsesMemaccess) { m_uses_memaccess = bUsesMemaccess; }; |
| const bool getUsesMemAccess() const { return m_uses_memaccess; }; |
| |
| void setUsesIDecode(bool bUsesIDecode) { m_uses_idecode = bUsesIDecode; }; |
| const bool getUsesIDecode() const { return m_uses_idecode; }; |
| |
| protected: |
| |
| /* implementation packet decoding interface */ |
| virtual ocsd_datapath_resp_t processPacket() = 0; |
| virtual ocsd_datapath_resp_t onEOT() = 0; |
| virtual ocsd_datapath_resp_t onReset() = 0; |
| virtual ocsd_datapath_resp_t onFlush() = 0; |
| virtual ocsd_err_t onProtocolConfig() = 0; |
| virtual const uint8_t getCoreSightTraceID() = 0; |
| |
| /* init handling */ |
| const bool checkInit(); |
| /* Called on first init confirmation */ |
| virtual void onFirstInitOK() {}; |
| |
| /* data output */ |
| ocsd_datapath_resp_t outputTraceElement(const OcsdTraceElement &elem); // use current index |
| ocsd_datapath_resp_t outputTraceElementIdx(ocsd_trc_index_t idx, const OcsdTraceElement &elem); // use supplied index (where decoder caches elements) |
| |
| /* target access */ |
| ocsd_err_t accessMemory(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, uint32_t *num_bytes, uint8_t *p_buffer); |
| |
| /* instruction decode */ |
| ocsd_err_t instrDecode(ocsd_instr_info *instr_info); |
| |
| componentAttachPt<ITrcGenElemIn> m_trace_elem_out; |
| componentAttachPt<ITargetMemAccess> m_mem_access; |
| componentAttachPt<IInstrDecode> m_instr_decode; |
| |
| ocsd_trc_index_t m_index_curr_pkt; |
| |
| bool m_decode_init_ok; //!< set true if all attachments in place for decode. (remove checks in main throughput paths) |
| bool m_config_init_ok; //!< set true if config set. |
| |
| std::string init_err_msg; //!< error message for init error |
| |
| bool m_uses_memaccess; |
| bool m_uses_idecode; |
| |
| }; |
| |
| inline TrcPktDecodeI::TrcPktDecodeI(const char *component_name) : |
| TraceComponent(component_name), |
| m_index_curr_pkt(0), |
| m_decode_init_ok(false), |
| m_config_init_ok(false), |
| m_uses_memaccess(true), |
| m_uses_idecode(true) |
| { |
| } |
| |
| inline TrcPktDecodeI::TrcPktDecodeI(const char *component_name, int instIDNum) : |
| TraceComponent(component_name, instIDNum), |
| m_index_curr_pkt(0), |
| m_decode_init_ok(false), |
| m_config_init_ok(false), |
| m_uses_memaccess(true), |
| m_uses_idecode(true) |
| { |
| } |
| |
| inline const bool TrcPktDecodeI::checkInit() |
| { |
| if(!m_decode_init_ok) |
| { |
| if(!m_config_init_ok) |
| init_err_msg = "No decoder configuration information"; |
| else if(!m_trace_elem_out.hasAttachedAndEnabled()) |
| init_err_msg = "No element output interface attached and enabled"; |
| else if(m_uses_memaccess && !m_mem_access.hasAttachedAndEnabled()) |
| init_err_msg = "No memory access interface attached and enabled"; |
| else if(m_uses_idecode && !m_instr_decode.hasAttachedAndEnabled()) |
| init_err_msg = "No instruction decoder interface attached and enabled"; |
| else |
| m_decode_init_ok = true; |
| if (m_decode_init_ok) |
| onFirstInitOK(); |
| } |
| return m_decode_init_ok; |
| } |
| |
| inline ocsd_datapath_resp_t TrcPktDecodeI::outputTraceElement(const OcsdTraceElement &elem) |
| { |
| return m_trace_elem_out.first()->TraceElemIn(m_index_curr_pkt,getCoreSightTraceID(), elem); |
| } |
| |
| inline ocsd_datapath_resp_t TrcPktDecodeI::outputTraceElementIdx(ocsd_trc_index_t idx, const OcsdTraceElement &elem) |
| { |
| return m_trace_elem_out.first()->TraceElemIn(idx, getCoreSightTraceID(), elem); |
| } |
| |
| inline ocsd_err_t TrcPktDecodeI::instrDecode(ocsd_instr_info *instr_info) |
| { |
| if(m_uses_idecode) |
| return m_instr_decode.first()->DecodeInstruction(instr_info); |
| return OCSD_ERR_DCD_INTERFACE_UNUSED; |
| } |
| |
| inline ocsd_err_t TrcPktDecodeI::accessMemory(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, uint32_t *num_bytes, uint8_t *p_buffer) |
| { |
| if(m_uses_memaccess) |
| return m_mem_access.first()->ReadTargetMemory(address,getCoreSightTraceID(),mem_space, num_bytes,p_buffer); |
| return OCSD_ERR_DCD_INTERFACE_UNUSED; |
| } |
| |
| /**********************************************************************/ |
| template <class P, class Pc> |
| class TrcPktDecodeBase : public TrcPktDecodeI, public IPktDataIn<P> |
| { |
| public: |
| TrcPktDecodeBase(const char *component_name); |
| TrcPktDecodeBase(const char *component_name, int instIDNum); |
| virtual ~TrcPktDecodeBase(); |
| |
| virtual ocsd_datapath_resp_t PacketDataIn( const ocsd_datapath_op_t op, |
| const ocsd_trc_index_t index_sop, |
| const P *p_packet_in); |
| |
| |
| /* protocol configuration */ |
| ocsd_err_t setProtocolConfig(const Pc *config); |
| const Pc * getProtocolConfig() const { return m_config; }; |
| |
| protected: |
| void ClearConfigObj(); |
| |
| /* the protocol configuration */ |
| Pc * m_config; |
| /* the current input packet */ |
| const P * m_curr_packet_in; |
| |
| }; |
| |
| |
| template <class P, class Pc> TrcPktDecodeBase<P, Pc>::TrcPktDecodeBase(const char *component_name) : |
| TrcPktDecodeI(component_name), |
| m_config(0) |
| { |
| } |
| |
| template <class P, class Pc> TrcPktDecodeBase<P, Pc>::TrcPktDecodeBase(const char *component_name, int instIDNum) : |
| TrcPktDecodeI(component_name,instIDNum), |
| m_config(0) |
| { |
| } |
| |
| template <class P, class Pc> TrcPktDecodeBase<P, Pc>::~TrcPktDecodeBase() |
| { |
| ClearConfigObj(); |
| } |
| |
| template <class P, class Pc> ocsd_datapath_resp_t TrcPktDecodeBase<P, Pc>::PacketDataIn( const ocsd_datapath_op_t op, |
| const ocsd_trc_index_t index_sop, |
| const P *p_packet_in) |
| { |
| ocsd_datapath_resp_t resp = OCSD_RESP_CONT; |
| if(!checkInit()) |
| { |
| LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_NOT_INIT,init_err_msg)); |
| return OCSD_RESP_FATAL_NOT_INIT; |
| } |
| |
| switch(op) |
| { |
| case OCSD_OP_DATA: |
| if(p_packet_in == 0) |
| { |
| LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_INVALID_PARAM_VAL)); |
| resp = OCSD_RESP_FATAL_INVALID_PARAM; |
| } |
| else |
| { |
| m_curr_packet_in = p_packet_in; |
| m_index_curr_pkt = index_sop; |
| resp = processPacket(); |
| } |
| break; |
| |
| case OCSD_OP_EOT: |
| resp = onEOT(); |
| break; |
| |
| case OCSD_OP_FLUSH: |
| resp = onFlush(); |
| break; |
| |
| case OCSD_OP_RESET: |
| resp = onReset(); |
| break; |
| |
| default: |
| LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_INVALID_PARAM_VAL)); |
| resp = OCSD_RESP_FATAL_INVALID_OP; |
| break; |
| } |
| return resp; |
| } |
| |
| /* protocol configuration */ |
| template <class P, class Pc> ocsd_err_t TrcPktDecodeBase<P, Pc>::setProtocolConfig(const Pc *config) |
| { |
| ocsd_err_t err = OCSD_ERR_INVALID_PARAM_VAL; |
| if(config != 0) |
| { |
| ClearConfigObj(); // remove any current config |
| m_config = new (std::nothrow) Pc(*config); // make a copy of the config - don't rely on the object passed in being valid outside the context of the call. |
| if(m_config != 0) |
| { |
| err = onProtocolConfig(); |
| if(err == OCSD_OK) |
| m_config_init_ok = true; |
| } |
| else |
| err = OCSD_ERR_MEM; |
| } |
| return err; |
| } |
| |
| template <class P, class Pc> void TrcPktDecodeBase<P, Pc>::ClearConfigObj() |
| { |
| if(m_config) |
| { |
| delete m_config; |
| m_config = 0; |
| } |
| } |
| |
| /** @}*/ |
| #endif // ARM_TRC_PKT_DECODE_BASE_H_INCLUDED |
| |
| /* End of File trc_pkt_decode_base.h */ |