summaryrefslogtreecommitdiffstats
path: root/decoder/source/etmv4
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 07:24:57 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 07:24:57 +0000
commit070852d8604cece0c31f28ff3eb8d21d9ba415fb (patch)
tree9097175a6a5b8b7e37af9a96269ac0b61a0189cd /decoder/source/etmv4
parentInitial commit. (diff)
downloadlibopencsd-070852d8604cece0c31f28ff3eb8d21d9ba415fb.tar.xz
libopencsd-070852d8604cece0c31f28ff3eb8d21d9ba415fb.zip
Adding upstream version 1.3.3.upstream/1.3.3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'decoder/source/etmv4')
-rw-r--r--decoder/source/etmv4/trc_cmp_cfg_etmv4.cpp111
-rw-r--r--decoder/source/etmv4/trc_etmv4_stack_elem.cpp178
-rw-r--r--decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp1957
-rw-r--r--decoder/source/etmv4/trc_pkt_elem_etmv4i.cpp754
-rw-r--r--decoder/source/etmv4/trc_pkt_proc_etmv4i.cpp1778
5 files changed, 4778 insertions, 0 deletions
diff --git a/decoder/source/etmv4/trc_cmp_cfg_etmv4.cpp b/decoder/source/etmv4/trc_cmp_cfg_etmv4.cpp
new file mode 100644
index 0000000..6f8bf79
--- /dev/null
+++ b/decoder/source/etmv4/trc_cmp_cfg_etmv4.cpp
@@ -0,0 +1,111 @@
+/*
+ * \file trc_cmp_cfg_etmv4.cpp
+ * \brief OpenCSD :
+ *
+ * \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.
+ */
+
+#include "opencsd/etmv4/trc_cmp_cfg_etmv4.h"
+
+EtmV4Config::EtmV4Config()
+{
+ m_cfg.reg_idr0 = 0x28000EA1;
+ m_cfg.reg_idr1 = 0x4100F403;
+ m_cfg.reg_idr2 = 0x00000488;
+ m_cfg.reg_idr8 = 0;
+ m_cfg.reg_idr9 = 0;
+ m_cfg.reg_idr10 = 0;
+ m_cfg.reg_idr11 = 0;
+ m_cfg.reg_idr12 = 0;
+ m_cfg.reg_idr13 = 0;
+ m_cfg.reg_configr = 0xC1;
+ m_cfg.reg_traceidr = 0;
+ m_cfg.arch_ver = ARCH_V7;
+ m_cfg.core_prof = profile_CortexA;
+
+ PrivateInit();
+}
+
+EtmV4Config::EtmV4Config(const ocsd_etmv4_cfg *cfg_regs)
+{
+ m_cfg = *cfg_regs;
+ PrivateInit();
+}
+
+EtmV4Config & EtmV4Config::operator=(const ocsd_etmv4_cfg *p_cfg)
+{
+ m_cfg = *p_cfg;
+ PrivateInit();
+ return *this;
+}
+
+void EtmV4Config::PrivateInit()
+{
+ m_QSuppCalc = false;
+ m_QSuppFilter = false;
+ m_QSuppType = Q_NONE;
+ m_VMIDSzCalc = false;
+ m_VMIDSize = 0;
+ m_condTraceCalc = false;
+ m_CondTrace = COND_TR_DIS;
+ m_MajVer = (uint8_t)((m_cfg.reg_idr1 >> 8) & 0xF);
+ m_MinVer = (uint8_t)((m_cfg.reg_idr1 >> 4) & 0xF);
+}
+
+void EtmV4Config::CalcQSupp()
+{
+ QSuppType qtypes[] = {
+ Q_NONE,
+ Q_ICOUNT_ONLY,
+ Q_NO_ICOUNT_ONLY,
+ Q_FULL
+ };
+ uint8_t Qsupp = (m_cfg.reg_idr0 >> 15) & 0x3;
+ m_QSuppType = qtypes[Qsupp];
+ m_QSuppFilter = (bool)((m_cfg.reg_idr0 & 0x4000) == 0x4000) && (m_QSuppType != Q_NONE);
+ m_QSuppCalc = true;
+}
+
+void EtmV4Config::CalcVMIDSize()
+{
+ uint32_t vmidszF = (m_cfg.reg_idr2 >> 10) & 0x1F;
+ if(vmidszF == 1)
+ m_VMIDSize = 8;
+ else if(FullVersion() > 0x40)
+ {
+ if(vmidszF == 2)
+ m_VMIDSize = 16;
+ else if(vmidszF == 4)
+ m_VMIDSize = 32;
+ }
+ m_VMIDSzCalc = true;
+}
+
+/* End of File trc_cmp_cfg_etmv4.cpp */
diff --git a/decoder/source/etmv4/trc_etmv4_stack_elem.cpp b/decoder/source/etmv4/trc_etmv4_stack_elem.cpp
new file mode 100644
index 0000000..1207444
--- /dev/null
+++ b/decoder/source/etmv4/trc_etmv4_stack_elem.cpp
@@ -0,0 +1,178 @@
+/*
+* \file trc_etmv4_stack_elem.cpp
+* \brief OpenCSD : ETMv4 decoder
+*
+* \copyright Copyright (c) 2017, 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.
+*/
+
+#include "opencsd/etmv4/trc_etmv4_stack_elem.h"
+
+/* implementation of P0 element stack in ETM v4 trace*/
+TrcStackElem *EtmV4P0Stack::createParamElemNoParam(const p0_elem_t p0_type, const bool isP0, const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, bool back /*= false*/)
+{
+ TrcStackElem *pElem = new (std::nothrow) TrcStackElem(p0_type, isP0, root_pkt, root_index);
+ if (pElem)
+ {
+ if (back)
+ push_back(pElem);
+ else
+ push_front(pElem);
+ }
+ return pElem;
+}
+
+TrcStackElemParam *EtmV4P0Stack::createParamElem(const p0_elem_t p0_type, const bool isP0, const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const std::vector<uint32_t> &params)
+{
+ TrcStackElemParam *pElem = new (std::nothrow) TrcStackElemParam(p0_type, isP0, root_pkt, root_index);
+ if (pElem)
+ {
+ int param_idx = 0;
+ int params_to_fill = params.size();
+ while ((param_idx < 4) && params_to_fill)
+ {
+ pElem->setParam(params[param_idx], param_idx);
+ param_idx++;
+ params_to_fill--;
+ }
+ push_front(pElem);
+ }
+ return pElem;
+}
+
+TrcStackElemAtom *EtmV4P0Stack::createAtomElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const ocsd_pkt_atom &atom)
+{
+ TrcStackElemAtom *pElem = new (std::nothrow) TrcStackElemAtom(root_pkt, root_index);
+ if (pElem)
+ {
+ pElem->setAtom(atom);
+ push_front(pElem);
+ }
+ return pElem;
+}
+
+TrcStackElemExcept *EtmV4P0Stack::createExceptElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const bool bSame, const uint16_t excepNum)
+{
+ TrcStackElemExcept *pElem = new (std::nothrow) TrcStackElemExcept(root_pkt, root_index);
+ if (pElem)
+ {
+ pElem->setExcepNum(excepNum);
+ pElem->setPrevSame(bSame);
+ push_front(pElem);
+ }
+ return pElem;
+}
+
+TrcStackElemCtxt *EtmV4P0Stack::createContextElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const etmv4_context_t &context, const uint8_t IS, const bool back /*= false*/)
+{
+ TrcStackElemCtxt *pElem = new (std::nothrow) TrcStackElemCtxt(root_pkt, root_index);
+ if (pElem)
+ {
+ pElem->setContext(context);
+ pElem->setIS(IS);
+ if (back)
+ push_back(pElem);
+ else
+ push_front(pElem);
+ }
+ return pElem;
+
+}
+
+TrcStackElemAddr *EtmV4P0Stack::createAddrElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const etmv4_addr_val_t &addr_val)
+{
+ TrcStackElemAddr *pElem = new (std::nothrow) TrcStackElemAddr(root_pkt, root_index);
+ if (pElem)
+ {
+ pElem->setAddr(addr_val);
+ push_front(pElem);
+ }
+ return pElem;
+}
+
+TrcStackQElem *EtmV4P0Stack::createQElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const int count)
+{
+ TrcStackQElem *pElem = new (std::nothrow) TrcStackQElem(root_pkt, root_index);
+ if (pElem)
+ {
+ pElem->setInstrCount(count);
+ push_front(pElem);
+ }
+ return pElem;
+}
+
+TrcStackElemMarker *EtmV4P0Stack::createMarkerElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const trace_marker_payload_t &marker)
+{
+ TrcStackElemMarker *pElem = new (std::nothrow) TrcStackElemMarker(root_pkt, root_index);
+ if (pElem)
+ {
+ pElem->setMarker(marker);
+ push_front(pElem);
+ }
+ return pElem;
+}
+
+TrcStackElemAddr *EtmV4P0Stack::createSrcAddrElem(const ocsd_etmv4_i_pkt_type root_pkt, const ocsd_trc_index_t root_index, const etmv4_addr_val_t &addr_val)
+{
+ TrcStackElemAddr *pElem = new (std::nothrow) TrcStackElemAddr(root_pkt, root_index, true);
+ if (pElem)
+ {
+ pElem->setAddr(addr_val);
+ push_front(pElem);
+ }
+ return pElem;
+}
+
+// iteration functions
+void EtmV4P0Stack::from_front_init()
+{
+ m_iter = m_P0_stack.begin();
+}
+
+TrcStackElem *EtmV4P0Stack::from_front_next()
+{
+ TrcStackElem *pElem = 0;
+ if (m_iter != m_P0_stack.end())
+ {
+ pElem = *m_iter++;
+ }
+ return pElem;
+}
+
+void EtmV4P0Stack::erase_curr_from_front()
+{
+ std::deque<TrcStackElem *>::iterator erase_iter;
+ erase_iter = m_iter;
+ erase_iter--;
+ m_P0_stack.erase(erase_iter);
+}
+
+
+/* End of file trc_etmv4_stack_elem.cpp */
diff --git a/decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp b/decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp
new file mode 100644
index 0000000..a9b059a
--- /dev/null
+++ b/decoder/source/etmv4/trc_pkt_decode_etmv4i.cpp
@@ -0,0 +1,1957 @@
+/*
+ * \file trc_pkt_decode_etmv4i.cpp
+ * \brief OpenCSD : ETMv4 decoder
+ *
+ * \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.
+ */
+
+#include "opencsd/etmv4/trc_pkt_decode_etmv4i.h"
+
+#include "common/trc_gen_elem.h"
+
+
+#define DCD_NAME "DCD_ETMV4"
+
+static const uint32_t ETMV4_SUPPORTED_DECODE_OP_FLAGS = OCSD_OPFLG_PKTDEC_COMMON |
+ ETE_OPFLG_PKTDEC_SRCADDR_N_ATOMS;
+
+TrcPktDecodeEtmV4I::TrcPktDecodeEtmV4I()
+ : TrcPktDecodeBase(DCD_NAME)
+{
+ initDecoder();
+}
+
+TrcPktDecodeEtmV4I::TrcPktDecodeEtmV4I(int instIDNum)
+ : TrcPktDecodeBase(DCD_NAME,instIDNum)
+{
+ initDecoder();
+}
+
+TrcPktDecodeEtmV4I::~TrcPktDecodeEtmV4I()
+{
+}
+
+/*********************** implementation packet decoding interface */
+
+ocsd_datapath_resp_t TrcPktDecodeEtmV4I::processPacket()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ ocsd_err_t err = OCSD_OK;
+ bool bPktDone = false;
+
+ while(!bPktDone)
+ {
+ switch (m_curr_state)
+ {
+ case NO_SYNC:
+ // output the initial not synced packet to the sink
+ err = m_out_elem.resetElemStack();
+ if (!err)
+ err = m_out_elem.addElemType(m_index_curr_pkt, OCSD_GEN_TRC_ELEM_NO_SYNC);
+ if (!err)
+ {
+ outElem().setUnSyncEOTReason(m_unsync_eot_info);
+ resp = m_out_elem.sendElements();
+ m_curr_state = WAIT_SYNC;
+ }
+ else
+ resp = OCSD_RESP_FATAL_SYS_ERR;
+
+ // fall through to check if the current packet is the async we are waiting for.
+ break;
+
+ case WAIT_SYNC:
+ if(m_curr_packet_in->getType() == ETM4_PKT_I_ASYNC)
+ m_curr_state = WAIT_TINFO;
+ bPktDone = true;
+ break;
+
+ case WAIT_TINFO:
+ m_need_ctxt = true;
+ m_need_addr = true;
+ if(m_curr_packet_in->getType() == ETM4_PKT_I_TRACE_INFO)
+ {
+ doTraceInfoPacket();
+ m_curr_state = DECODE_PKTS;
+ m_return_stack.flush();
+ }
+ /* ETE spec allows early event packets. */
+ else if ((m_config->MajVersion() >= 0x5) &&
+ (m_curr_packet_in->getType() == ETM4_PKT_I_EVENT))
+ {
+ err = decodePacket();
+ if (err)
+ resp = OCSD_RESP_FATAL_INVALID_DATA;
+ }
+ bPktDone = true;
+ break;
+
+ case DECODE_PKTS:
+ // this may change the state to RESOLVE_ELEM if required;
+ err = decodePacket();
+ if (err)
+ {
+#ifdef OCSD_WARN_UNSUPPORTED
+ if (err == OCSD_ERR_UNSUPP_DECODE_PKT)
+ resp = OCSD_RESP_WARN_CONT;
+ else
+#else
+ resp = OCSD_RESP_FATAL_INVALID_DATA;
+#endif
+
+ bPktDone = true;
+ }
+ else if (m_curr_state != RESOLVE_ELEM)
+ bPktDone = true;
+ break;
+
+ case RESOLVE_ELEM:
+ // this will change the state to DECODE_PKTS once required elem resolved &
+ // needed generic packets output
+ resp = resolveElements();
+ if ((m_curr_state == DECODE_PKTS) || (!OCSD_DATA_RESP_IS_CONT(resp)))
+ bPktDone = true;
+ break;
+ }
+ }
+ return resp;
+}
+
+ocsd_datapath_resp_t TrcPktDecodeEtmV4I::onEOT()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ ocsd_err_t err;
+ if ((err = commitElemOnEOT()) != OCSD_OK)
+ {
+ resp = OCSD_RESP_FATAL_INVALID_DATA;
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, "Error flushing element stack at end of trace data."));
+ }
+ else
+ resp = m_out_elem.sendElements();
+ return resp;
+}
+
+ocsd_datapath_resp_t TrcPktDecodeEtmV4I::onReset()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ m_unsync_eot_info = UNSYNC_RESET_DECODER;
+ resetDecoder();
+ return resp;
+}
+
+ocsd_datapath_resp_t TrcPktDecodeEtmV4I::onFlush()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+
+ if (m_curr_state == RESOLVE_ELEM)
+ resp = resolveElements();
+ else
+ resp = m_out_elem.sendElements();
+ return resp;
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::onProtocolConfig()
+{
+ ocsd_err_t err = OCSD_OK;
+
+ // set some static config elements
+ m_CSID = m_config->getTraceID();
+ m_max_spec_depth = m_config->MaxSpecDepth();
+
+ // elements associated with data trace
+#ifdef DATA_TRACE_SUPPORTED
+ m_p0_key_max = m_config->P0_Key_Max();
+ m_cond_key_max_incr = m_config->CondKeyMaxIncr();
+#endif
+
+ m_out_elem.initCSID(m_CSID);
+
+ // set up static trace instruction decode elements
+ m_instr_info.dsb_dmb_waypoints = 0;
+ m_instr_info.wfi_wfe_branch = m_config->wfiwfeBranch() ? 1 : 0;
+ m_instr_info.pe_type.arch = m_config->archVersion();
+ m_instr_info.pe_type.profile = m_config->coreProfile();
+
+ m_IASize64 = (m_config->iaSizeMax() == 64);
+
+ if (m_config->enabledRetStack())
+ {
+ m_return_stack.set_active(true);
+#ifdef TRC_RET_STACK_DEBUG
+ m_return_stack.set_dbg_logger(this);
+#endif
+ }
+
+ // check config compatible with current decoder support level.
+ // at present no data trace, no spec depth, no return stack, no QE
+ // Remove these checks as support is added.
+ if(m_config->enabledDataTrace())
+ {
+ err = OCSD_ERR_HW_CFG_UNSUPP;
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,"ETMv4 instruction decode : Data trace elements not supported"));
+ }
+ else if(m_config->enabledLSP0Trace())
+ {
+ err = OCSD_ERR_HW_CFG_UNSUPP;
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,"ETMv4 instruction decode : LSP0 elements not supported."));
+ }
+ else if(m_config->enabledCondITrace() != EtmV4Config::COND_TR_DIS)
+ {
+ err = OCSD_ERR_HW_CFG_UNSUPP;
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,"ETMv4 instruction decode : Trace on conditional non-branch elements not supported."));
+ }
+ return err;
+}
+
+/************* local decode methods */
+void TrcPktDecodeEtmV4I::initDecoder()
+{
+ // set the operational modes supported.
+ m_supported_op_flags = ETMV4_SUPPORTED_DECODE_OP_FLAGS;
+
+ /* init elements that get set by config */
+ m_max_spec_depth = 0;
+ m_CSID = 0;
+ m_IASize64 = false;
+
+ // elements associated with data trace
+#ifdef DATA_TRACE_SUPPORTED
+ m_p0_key_max = 0;
+ m_cond_key_max_incr = 0;
+#endif
+
+ // reset decoder state to unsynced
+ m_unsync_eot_info = UNSYNC_INIT_DECODER;
+ resetDecoder();
+}
+
+void TrcPktDecodeEtmV4I::resetDecoder()
+{
+ m_curr_state = NO_SYNC;
+ m_timestamp = 0;
+ m_context_id = 0;
+ m_vmid_id = 0;
+ m_is_secure = true;
+ m_is_64bit = false;
+ m_cc_threshold = 0;
+ m_curr_spec_depth = 0;
+ m_need_ctxt = true;
+ m_need_addr = true;
+ m_elem_pending_addr = false;
+ m_prev_overflow = false;
+ m_P0_stack.delete_all();
+ m_out_elem.resetElemStack();
+ m_last_IS = 0;
+ clearElemRes();
+ m_ete_first_ts_marker = false;
+
+ // elements associated with data trace
+#ifdef DATA_TRACE_SUPPORTED
+ m_p0_key = 0;
+ m_cond_c_key = 0;
+ m_cond_r_key = 0;
+#endif
+}
+
+void TrcPktDecodeEtmV4I::onFirstInitOK()
+{
+ // once init, set the output element interface to the out elem list.
+ m_out_elem.initSendIf(this->getTraceElemOutAttachPt());
+}
+
+// Changes a packet into stack of trace elements - these will be resolved and output later
+ocsd_err_t TrcPktDecodeEtmV4I::decodePacket()
+{
+ ocsd_err_t err = OCSD_OK;
+ bool bAllocErr = false;
+ bool is_addr = false;
+
+ switch(m_curr_packet_in->getType())
+ {
+ case ETM4_PKT_I_ASYNC: // nothing to do with this packet.
+ case ETM4_PKT_I_IGNORE: // or this one.
+ break;
+
+ case ETM4_PKT_I_TRACE_INFO:
+ // skip subsequent TInfo packets.
+ m_return_stack.flush();
+ break;
+
+ case ETM4_PKT_I_TRACE_ON:
+ {
+ if (m_P0_stack.createParamElemNoParam(P0_TRC_ON, false, m_curr_packet_in->getType(), m_index_curr_pkt) == 0)
+ bAllocErr = true;
+ }
+ break;
+
+ case ETM4_PKT_I_ATOM_F1:
+ case ETM4_PKT_I_ATOM_F2:
+ case ETM4_PKT_I_ATOM_F3:
+ case ETM4_PKT_I_ATOM_F4:
+ case ETM4_PKT_I_ATOM_F5:
+ case ETM4_PKT_I_ATOM_F6:
+ {
+ if (m_P0_stack.createAtomElem(m_curr_packet_in->getType(), m_index_curr_pkt, m_curr_packet_in->getAtom()) == 0)
+ bAllocErr = true;
+ else
+ m_curr_spec_depth += m_curr_packet_in->getAtom().num;
+ }
+ break;
+
+ case ETM4_PKT_I_CTXT:
+ {
+ if (m_P0_stack.createContextElem(m_curr_packet_in->getType(), m_index_curr_pkt, m_curr_packet_in->getContext(), m_last_IS) == 0)
+ bAllocErr = true;
+ }
+ break;
+
+ case ETM4_PKT_I_ADDR_MATCH:
+ {
+ etmv4_addr_val_t addr;
+
+ addr.val = m_curr_packet_in->getAddrVal();
+ addr.isa = m_last_IS = m_curr_packet_in->getAddrIS();
+
+ if (m_P0_stack.createAddrElem(m_curr_packet_in->getType(), m_index_curr_pkt, addr) == 0)
+ bAllocErr = true;
+ is_addr = true;
+ }
+ break;
+
+ case ETM4_PKT_I_ADDR_CTXT_L_64IS0:
+ case ETM4_PKT_I_ADDR_CTXT_L_64IS1:
+ case ETM4_PKT_I_ADDR_CTXT_L_32IS0:
+ case ETM4_PKT_I_ADDR_CTXT_L_32IS1:
+ {
+ m_last_IS = m_curr_packet_in->getAddrIS();
+ if (m_P0_stack.createContextElem(m_curr_packet_in->getType(), m_index_curr_pkt, m_curr_packet_in->getContext(), m_last_IS) == 0)
+ bAllocErr = true;
+ }
+ case ETM4_PKT_I_ADDR_L_32IS0:
+ case ETM4_PKT_I_ADDR_L_32IS1:
+ case ETM4_PKT_I_ADDR_L_64IS0:
+ case ETM4_PKT_I_ADDR_L_64IS1:
+ case ETM4_PKT_I_ADDR_S_IS0:
+ case ETM4_PKT_I_ADDR_S_IS1:
+ {
+ etmv4_addr_val_t addr;
+
+ addr.val = m_curr_packet_in->getAddrVal();
+ addr.isa = m_last_IS = m_curr_packet_in->getAddrIS();
+
+ if (m_P0_stack.createAddrElem(m_curr_packet_in->getType(), m_index_curr_pkt, addr) == 0)
+ bAllocErr = true;
+ is_addr = true; // may be waiting for target address from indirect branch
+ }
+ break;
+
+ case ETE_PKT_I_SRC_ADDR_MATCH:
+ case ETE_PKT_I_SRC_ADDR_S_IS0:
+ case ETE_PKT_I_SRC_ADDR_S_IS1:
+ case ETE_PKT_I_SRC_ADDR_L_32IS0:
+ case ETE_PKT_I_SRC_ADDR_L_32IS1:
+ case ETE_PKT_I_SRC_ADDR_L_64IS0:
+ case ETE_PKT_I_SRC_ADDR_L_64IS1:
+ {
+ etmv4_addr_val_t addr;
+
+ addr.val = m_curr_packet_in->getAddrVal();
+ addr.isa = m_curr_packet_in->getAddrIS();
+ if (m_P0_stack.createSrcAddrElem(m_curr_packet_in->getType(), m_index_curr_pkt, addr) == 0)
+ bAllocErr = true;
+ m_curr_spec_depth++;
+ }
+ break;
+
+ // Exceptions
+ case ETM4_PKT_I_EXCEPT:
+ {
+ if (m_P0_stack.createExceptElem(m_curr_packet_in->getType(), m_index_curr_pkt,
+ (m_curr_packet_in->exception_info.addr_interp == 0x2),
+ m_curr_packet_in->exception_info.exceptionType) == 0)
+ bAllocErr = true;
+ else
+ m_elem_pending_addr = true; // wait for following packets before marking for commit.
+ }
+ break;
+
+ case ETM4_PKT_I_EXCEPT_RTN:
+ {
+ // P0 element if V7M profile.
+ bool bV7MProfile = (m_config->archVersion() == ARCH_V7) && (m_config->coreProfile() == profile_CortexM);
+ if (m_P0_stack.createParamElemNoParam(P0_EXCEP_RET, bV7MProfile, m_curr_packet_in->getType(), m_index_curr_pkt) == 0)
+ bAllocErr = true;
+ else if (bV7MProfile)
+ m_curr_spec_depth++;
+ }
+ break;
+
+ case ETM4_PKT_I_FUNC_RET:
+ {
+ // P0 element iff V8M profile, otherwise ignore
+ if (OCSD_IS_V8_ARCH(m_config->archVersion()) && (m_config->coreProfile() == profile_CortexM))
+ {
+ if (m_P0_stack.createParamElemNoParam(P0_FUNC_RET, true, m_curr_packet_in->getType(), m_index_curr_pkt) == 0)
+ bAllocErr = true;
+ else
+ m_curr_spec_depth++;
+ }
+ }
+ break;
+
+ // event trace
+ case ETM4_PKT_I_EVENT:
+ {
+ std::vector<uint32_t> params = { 0 };
+ params[0] = (uint32_t)m_curr_packet_in->event_val;
+ if (m_P0_stack.createParamElem(P0_EVENT, false, m_curr_packet_in->getType(), m_index_curr_pkt, params) == 0)
+ bAllocErr = true;
+
+ }
+ break;
+
+ /* cycle count packets */
+ case ETM4_PKT_I_CCNT_F1:
+ case ETM4_PKT_I_CCNT_F2:
+ case ETM4_PKT_I_CCNT_F3:
+ {
+ std::vector<uint32_t> params = { 0 };
+ params[0] = m_curr_packet_in->getCC();
+ if (m_P0_stack.createParamElem(P0_CC, false, m_curr_packet_in->getType(), m_index_curr_pkt, params) == 0)
+ bAllocErr = true;
+
+ }
+ break;
+
+ // timestamp
+ case ETM4_PKT_I_TIMESTAMP:
+ {
+ bool bTSwithCC = m_config->enabledCCI();
+ uint64_t ts = m_curr_packet_in->getTS();
+ std::vector<uint32_t> params = { 0, 0, 0 };
+ params[0] = (uint32_t)(ts & 0xFFFFFFFF);
+ params[1] = (uint32_t)((ts >> 32) & 0xFFFFFFFF);
+ if (bTSwithCC)
+ params[2] = m_curr_packet_in->getCC();
+ if (m_P0_stack.createParamElem(bTSwithCC ? P0_TS_CC : P0_TS, false, m_curr_packet_in->getType(), m_index_curr_pkt, params) == 0)
+ bAllocErr = true;
+
+ }
+ break;
+
+ case ETE_PKT_I_TS_MARKER:
+ {
+ trace_marker_payload_t marker;
+ marker.type = ELEM_MARKER_TS;
+ marker.value = 0;
+ if (m_P0_stack.createMarkerElem(m_curr_packet_in->getType(), m_index_curr_pkt, marker) == 0)
+ bAllocErr = true;
+ }
+ break;
+
+ case ETM4_PKT_I_BAD_SEQUENCE:
+ err = handleBadPacket("Bad byte sequence in packet.", m_index_curr_pkt);
+ break;
+
+ case ETM4_PKT_I_BAD_TRACEMODE:
+ err = handleBadPacket("Invalid packet type for trace mode.", m_index_curr_pkt);
+ break;
+
+ case ETM4_PKT_I_RESERVED:
+ err = handleBadPacket("Reserved packet header", m_index_curr_pkt);
+ break;
+
+ // speculation
+ case ETM4_PKT_I_MISPREDICT:
+ case ETM4_PKT_I_CANCEL_F1_MISPRED:
+ case ETM4_PKT_I_CANCEL_F2:
+ case ETM4_PKT_I_CANCEL_F3:
+ m_elem_res.mispredict = true;
+ if (m_curr_packet_in->getNumAtoms())
+ {
+ if (m_P0_stack.createAtomElem(m_curr_packet_in->getType(), m_index_curr_pkt, m_curr_packet_in->getAtom()) == 0)
+ bAllocErr = true;
+ else
+ m_curr_spec_depth += m_curr_packet_in->getNumAtoms();
+ }
+
+ case ETM4_PKT_I_CANCEL_F1:
+ m_elem_res.P0_cancel = m_curr_packet_in->getCancelElem();
+ break;
+
+ case ETM4_PKT_I_COMMIT:
+ m_elem_res.P0_commit = m_curr_packet_in->getCommitElem();
+ break;
+
+ case ETM4_PKT_I_OVERFLOW:
+ m_prev_overflow = true;
+ case ETM4_PKT_I_DISCARD:
+ m_curr_spec_depth = 0;
+ m_elem_res.discard = true;
+ break;
+
+ /* Q packets */
+ case ETM4_PKT_I_Q:
+ {
+ TrcStackQElem *pQElem = m_P0_stack.createQElem(m_curr_packet_in->getType(), m_index_curr_pkt, m_curr_packet_in->Q_pkt.q_count);
+ if (pQElem)
+ {
+ if (m_curr_packet_in->Q_pkt.addr_present)
+ {
+ etmv4_addr_val_t addr;
+
+ addr.val = m_curr_packet_in->getAddrVal();
+ addr.isa = m_curr_packet_in->getAddrIS();
+ pQElem->setAddr(addr);
+ m_curr_spec_depth++;
+ }
+ else
+ m_elem_pending_addr = true;
+ }
+ else
+ bAllocErr = true;
+ }
+ break;
+
+ /* transactional memory packets */
+ case ETE_PKT_I_TRANS_ST:
+ {
+ if (m_P0_stack.createParamElemNoParam(P0_TRANS_START, m_config->commTransP0(), m_curr_packet_in->getType(), m_index_curr_pkt) == 0)
+ bAllocErr = true;
+ if (m_config->commTransP0())
+ m_curr_spec_depth++;
+ }
+ break;
+
+ case ETE_PKT_I_TRANS_COMMIT:
+ {
+ if (m_P0_stack.createParamElemNoParam(P0_TRANS_COMMIT, false, m_curr_packet_in->getType(), m_index_curr_pkt) == 0)
+ bAllocErr = true;
+ }
+ break;
+
+ case ETE_PKT_I_TRANS_FAIL:
+ {
+ if (m_P0_stack.createParamElemNoParam(P0_TRANS_FAIL, false, m_curr_packet_in->getType(), m_index_curr_pkt) == 0)
+ bAllocErr = true;
+ }
+ break;
+
+ /*** presently unsupported packets ***/
+ /* ETE commit window - not supported in current ETE versions - blocked by packet processor */
+ case ETE_PKT_I_COMMIT_WIN_MV:
+ err = OCSD_ERR_UNSUPP_DECODE_PKT;
+ err = handlePacketSeqErr(err, m_index_curr_pkt, "ETE Commit Window Move, unsupported packet type.");
+ break;
+ /* conditional instruction tracing */
+ case ETM4_PKT_I_COND_FLUSH:
+ case ETM4_PKT_I_COND_I_F1:
+ case ETM4_PKT_I_COND_I_F2:
+ case ETM4_PKT_I_COND_I_F3:
+ case ETM4_PKT_I_COND_RES_F1:
+ case ETM4_PKT_I_COND_RES_F2:
+ case ETM4_PKT_I_COND_RES_F3:
+ case ETM4_PKT_I_COND_RES_F4:
+ // data synchronisation markers
+ case ETM4_PKT_I_NUM_DS_MKR:
+ case ETM4_PKT_I_UNNUM_DS_MKR:
+ // all currently unsupported
+ {
+ ocsd_err_severity_t sev = OCSD_ERR_SEV_ERROR;
+#ifdef OCSD_WARN_UNSUPPORTED
+ sev = OCSD_ERR_SEV_WARN;
+ //resp = OCSD_RESP_WARN_CONT;
+#else
+ //resp = OCSD_RESP_FATAL_INVALID_DATA;
+#endif
+ err = OCSD_ERR_UNSUPP_DECODE_PKT;
+ if (sev == OCSD_ERR_SEV_WARN)
+ LogError(ocsdError(sev, err, "Data trace related, unsupported packet type."));
+ else
+ err = handlePacketSeqErr(err, m_index_curr_pkt, "Data trace related, unsupported packet type.");
+ }
+ break;
+
+ default:
+ // any other packet - bad packet error
+ err = handleBadPacket("Unknown packet type.", m_index_curr_pkt);
+ break;
+ }
+
+ // we need to wait for following address after certain packets
+ // - work out if we have seen enough here...
+ if (is_addr && m_elem_pending_addr)
+ {
+ m_curr_spec_depth++; // increase spec depth for element waiting on address.
+ m_elem_pending_addr = false; // can't be waiting on both
+ }
+
+ if(bAllocErr)
+ {
+ err = OCSD_ERR_MEM;
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_MEM,"Memory allocation error."));
+ }
+ else if(m_curr_spec_depth > m_max_spec_depth)
+ {
+ // auto commit anything above max spec depth
+ // (this will auto commit anything if spec depth not supported!)
+ m_elem_res.P0_commit = m_curr_spec_depth - m_max_spec_depth;
+ }
+
+ if (!err && isElemForRes())
+ m_curr_state = RESOLVE_ELEM;
+ return err;
+}
+
+void TrcPktDecodeEtmV4I::doTraceInfoPacket()
+{
+ m_trace_info = m_curr_packet_in->getTraceInfo();
+ m_cc_threshold = m_curr_packet_in->getCCThreshold();
+ m_curr_spec_depth = m_curr_packet_in->getCurrSpecDepth();
+ /* put a trans marker in stack if started in trans state */
+ if (m_trace_info.bits.in_trans_state)
+ m_P0_stack.createParamElemNoParam(P0_TRANS_TRACE_INIT, false, m_curr_packet_in->getType(), m_index_curr_pkt);
+
+ // elements associated with data trace
+#ifdef DATA_TRACE_SUPPORTED
+ m_p0_key = m_curr_packet_in->getP0Key();
+#endif
+}
+
+/* Element resolution
+ * Commit or cancel elements as required
+ * Send any buffered output packets.
+ */
+ocsd_datapath_resp_t TrcPktDecodeEtmV4I::resolveElements()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ bool Complete = false;
+
+ while (!Complete)
+ {
+ if (m_out_elem.numElemToSend())
+ resp = m_out_elem.sendElements();
+ else if (isElemForRes())
+ {
+ ocsd_err_t err = OCSD_OK;
+ if (m_elem_res.P0_commit)
+ err = commitElements();
+
+ // allow for early flush on context element
+ if (!m_elem_res.P0_commit) {
+
+ if (!err && m_elem_res.P0_cancel)
+ err = cancelElements();
+
+ if (!err && m_elem_res.mispredict)
+ err = mispredictAtom();
+
+ if (!err && m_elem_res.discard)
+ err = discardElements();
+ }
+
+ if (err != OCSD_OK)
+ resp = OCSD_RESP_FATAL_INVALID_DATA;
+ }
+
+ // break out on error or wait request.
+ if (!OCSD_DATA_RESP_IS_CONT(resp))
+ break;
+
+ // completion is nothing to send and nothing to commit
+ Complete = !m_out_elem.numElemToSend() && !isElemForRes();
+
+ // done all elements - need more packets.
+ if (Complete) {
+ // if we are still in resolve, the goto decode.
+ if (m_curr_state == RESOLVE_ELEM)
+ m_curr_state = DECODE_PKTS;
+ }
+ }
+ return resp;
+}
+
+/*
+ * Walks through the element stack, processing from oldest element to the newest,
+ according to the number of P0 elements that need committing.
+ Build a stack of output elements in the process.
+ */
+ocsd_err_t TrcPktDecodeEtmV4I::commitElements()
+{
+ ocsd_err_t err = OCSD_OK;
+ bool bPopElem = true; // do we remove the element from the stack (multi atom elements may need to stay!)
+ int num_commit_req = m_elem_res.P0_commit;
+ ocsd_trc_index_t err_idx = 0;
+ TrcStackElem *pElem = 0; // stacked element pointer
+ bool contextFlush = false;
+
+ err = m_out_elem.resetElemStack();
+
+ while(m_elem_res.P0_commit && !err && !contextFlush)
+ {
+ if (m_P0_stack.size() > 0)
+ {
+ pElem = m_P0_stack.back(); // get oldest element
+ err_idx = pElem->getRootIndex(); // save index in case of error.
+
+ switch (pElem->getP0Type())
+ {
+ // indicates a trace restart - beginning of trace or discontinuiuty
+ case P0_TRC_ON:
+ err = m_out_elem.addElemType(pElem->getRootIndex(), OCSD_GEN_TRC_ELEM_TRACE_ON);
+ if (!err)
+ {
+ m_out_elem.getCurrElem().trace_on_reason = m_prev_overflow ? TRACE_ON_OVERFLOW : TRACE_ON_NORMAL;
+ m_prev_overflow = false;
+ m_return_stack.flush();
+ }
+ break;
+
+ case P0_ADDR:
+ {
+ TrcStackElemAddr *pAddrElem = dynamic_cast<TrcStackElemAddr *>(pElem);
+ m_return_stack.clear_pop_pending(); // address removes the need to pop the indirect address target from the stack
+ if (pAddrElem)
+ {
+ SetInstrInfoInAddrISA(pAddrElem->getAddr().val, pAddrElem->getAddr().isa);
+ m_need_addr = false;
+ }
+ }
+ break;
+
+ case P0_CTXT:
+ {
+ TrcStackElemCtxt *pCtxtElem = dynamic_cast<TrcStackElemCtxt *>(pElem);
+ if (pCtxtElem)
+ {
+ etmv4_context_t ctxt = pCtxtElem->getContext();
+ // check this is an updated context
+ if(ctxt.updated)
+ {
+ err = m_out_elem.addElem(pElem->getRootIndex());
+ if (!err) {
+ updateContext(pCtxtElem, outElem());
+
+ // updated context - need to force this to be output to the client so correct memory
+ // context can be used.
+ contextFlush = true;
+
+ // invalidate memory accessor cacheing - force next memory access out to client to
+ // ensure that the correct memory context is in play when decoding subsequent atoms.
+ invalidateMemAccCache();
+ }
+ }
+ }
+ }
+ break;
+
+ case P0_EVENT:
+ case P0_TS:
+ case P0_CC:
+ case P0_TS_CC:
+ err = processTS_CC_EventElem(pElem);
+ break;
+
+ case P0_MARKER:
+ err = processMarkerElem(pElem);
+ break;
+
+ case P0_ATOM:
+ {
+ TrcStackElemAtom *pAtomElem = dynamic_cast<TrcStackElemAtom *>(pElem);
+
+ if (pAtomElem)
+ {
+ while(!pAtomElem->isEmpty() && m_elem_res.P0_commit && !err)
+ {
+ ocsd_atm_val atom = pAtomElem->commitOldest();
+
+ // check if prev atom left us an indirect address target on the return stack
+ if ((err = returnStackPop()) != OCSD_OK)
+ break;
+
+ // if address and context do instruction trace follower.
+ // otherwise skip atom and reduce committed elements
+ if (!m_need_ctxt && !m_need_addr)
+ {
+ err = processAtom(atom);
+ }
+ m_elem_res.P0_commit--; // mark committed
+ }
+ if (!pAtomElem->isEmpty())
+ bPopElem = false; // don't remove if still atoms to process.
+ }
+ }
+ break;
+
+ case P0_EXCEP:
+ // check if prev atom left us an indirect address target on the return stack
+ if ((err = returnStackPop()) != OCSD_OK)
+ break;
+
+ err = processException(); // output trace + exception elements.
+ m_elem_res.P0_commit--;
+ break;
+
+ case P0_EXCEP_RET:
+ err = m_out_elem.addElemType(pElem->getRootIndex(), OCSD_GEN_TRC_ELEM_EXCEPTION_RET);
+ if (!err)
+ {
+ if (pElem->isP0()) // are we on a core that counts ERET as P0?
+ m_elem_res.P0_commit--;
+ }
+ break;
+
+ case P0_FUNC_RET:
+ // func ret is V8M - data trace only - hint that data has been popped off the stack.
+ // at this point nothing to do till the decoder starts handling data trace.
+ if (pElem->isP0())
+ m_elem_res.P0_commit--;
+ break;
+
+ case P0_SRC_ADDR:
+ err = processSourceAddress();
+ m_elem_res.P0_commit--;
+ break;
+
+ case P0_Q:
+ err = processQElement();
+ m_elem_res.P0_commit--;
+ break;
+
+ case P0_TRANS_START:
+ if (m_config->commTransP0())
+ m_elem_res.P0_commit--;
+ case P0_TRANS_COMMIT:
+ case P0_TRANS_FAIL:
+ case P0_TRANS_TRACE_INIT:
+ err = processTransElem(pElem);
+ break;
+ }
+
+ if(bPopElem)
+ m_P0_stack.delete_back(); // remove element from stack;
+ }
+ else
+ {
+ // too few elements for commit operation - decode error.
+ err = handlePacketSeqErr(OCSD_ERR_COMMIT_PKT_OVERRUN, err_idx, "Not enough elements to commit");
+ }
+ }
+
+ // reduce the spec depth by number of comitted elements
+ m_curr_spec_depth -= (num_commit_req-m_elem_res.P0_commit);
+ return err;
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::returnStackPop()
+{
+ ocsd_err_t err = OCSD_OK;
+ ocsd_isa nextISA;
+
+ if (m_return_stack.pop_pending())
+ {
+ ocsd_vaddr_t popAddr = m_return_stack.pop(nextISA);
+ if (m_return_stack.overflow())
+ {
+ err = OCSD_ERR_RET_STACK_OVERFLOW;
+ err = handlePacketSeqErr(err, OCSD_BAD_TRC_INDEX, "Trace Return Stack Overflow.");
+ }
+ else
+ {
+ m_instr_info.instr_addr = popAddr;
+ m_instr_info.isa = nextISA;
+ m_need_addr = false;
+ }
+ }
+ return err;
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::commitElemOnEOT()
+{
+ ocsd_err_t err = OCSD_OK;
+ TrcStackElem *pElem = 0;
+
+ // nothing outstanding - reset the stack before we add more
+ if (!m_out_elem.numElemToSend())
+ m_out_elem.resetElemStack();
+
+ while((m_P0_stack.size() > 0) && !err)
+ {
+ // scan for outstanding events, TS and CC, that appear before any outstanding
+ // uncommited P0 element.
+ pElem = m_P0_stack.back();
+
+ switch(pElem->getP0Type())
+ {
+ // clear stack and stop
+ case P0_UNKNOWN:
+ case P0_ATOM:
+ case P0_TRC_ON:
+ case P0_EXCEP:
+ case P0_EXCEP_RET:
+ case P0_OVERFLOW:
+ case P0_Q:
+ m_P0_stack.delete_all();
+ break;
+
+ //skip
+ case P0_ADDR:
+ case P0_CTXT:
+ break;
+
+ // trans
+ // P0 trans - clear and stop, otherwise skip
+ case P0_TRANS_START:
+ if (m_config->commTransP0())
+ m_P0_stack.delete_all();
+ break;
+
+ // non-speculative trans fail / commit - could appear at EoT after valid trace
+ // but without a subsequent P0 that would force output.
+ case P0_TRANS_FAIL:
+ case P0_TRANS_COMMIT:
+ if (m_max_spec_depth == 0 || m_curr_spec_depth == 0)
+ err = processTransElem(pElem);
+ break;
+
+ // others - skip non P0
+ case P0_TRANS_TRACE_INIT:
+ break;
+
+ // output
+ case P0_EVENT:
+ case P0_TS:
+ case P0_CC:
+ case P0_TS_CC:
+ err = processTS_CC_EventElem(pElem);
+ break;
+
+ case P0_MARKER:
+ err = processMarkerElem(pElem);
+ break;
+ }
+ m_P0_stack.delete_back();
+ }
+
+ if(!err)
+ {
+ err = m_out_elem.addElemType(m_index_curr_pkt, OCSD_GEN_TRC_ELEM_EO_TRACE);
+ outElem().setUnSyncEOTReason(m_prev_overflow ? UNSYNC_OVERFLOW : UNSYNC_EOT);
+ }
+ return err;
+}
+
+// cancel elements. These not output
+ocsd_err_t TrcPktDecodeEtmV4I::cancelElements()
+{
+ ocsd_err_t err = OCSD_OK;
+ bool P0StackDone = false; // checked all P0 elements on the stack
+ TrcStackElem *pElem = 0; // stacked element pointer
+ EtmV4P0Stack temp;
+ int num_cancel_req = m_elem_res.P0_cancel;
+
+ while (m_elem_res.P0_cancel)
+ {
+ //search the stack for the newest elements
+ if (!P0StackDone)
+ {
+ if (m_P0_stack.size() == 0)
+ P0StackDone = true;
+ else
+ {
+ // get the newest element
+ pElem = m_P0_stack.front();
+ if (pElem->isP0()) {
+ if (pElem->getP0Type() == P0_ATOM)
+ {
+ TrcStackElemAtom *pAtomElem = (TrcStackElemAtom *)pElem;
+ // atom - cancel N atoms
+ m_elem_res.P0_cancel -= pAtomElem->cancelNewest(m_elem_res.P0_cancel);
+ if (pAtomElem->isEmpty())
+ m_P0_stack.delete_front(); // remove the element
+ }
+ else
+ {
+ m_elem_res.P0_cancel--;
+ m_P0_stack.delete_front(); // remove the element
+ }
+ } else {
+ // not P0, make a keep / remove decision
+ switch (pElem->getP0Type())
+ {
+ // keep these
+ case P0_EVENT:
+ case P0_TS:
+ case P0_CC:
+ case P0_TS_CC:
+ case P0_MARKER:
+ m_P0_stack.pop_front(false);
+ temp.push_back(pElem);
+ break;
+
+ default:
+ m_P0_stack.delete_front();
+ break;
+ }
+ }
+ if (m_P0_stack.size() == 0)
+ P0StackDone = true;
+ }
+ }
+ // may have some unseen elements
+ else if (m_unseen_spec_elem)
+ {
+ m_unseen_spec_elem--;
+ m_elem_res.P0_cancel--;
+ }
+ // otherwise we have some sort of overrun
+ else
+ {
+ // too few elements for commit operation - decode error.
+ err = OCSD_ERR_COMMIT_PKT_OVERRUN;
+ err = handlePacketSeqErr(err, m_index_curr_pkt, "Not enough elements to cancel");
+ m_elem_res.P0_cancel = 0;
+ break;
+ }
+ }
+
+ /* restore any saved elements that are unaffected by cancel. */
+ if (temp.size())
+ {
+ while (temp.size())
+ {
+ pElem = temp.back();
+ m_P0_stack.push_front(pElem);
+ temp.pop_back(false);
+ }
+ }
+
+ m_curr_spec_depth -= num_cancel_req - m_elem_res.P0_cancel;
+ return err;
+}
+
+// mispredict an atom
+ocsd_err_t TrcPktDecodeEtmV4I::mispredictAtom()
+{
+ ocsd_err_t err = OCSD_OK;
+ bool bFoundAtom = false, bDone = false;
+ TrcStackElem *pElem = 0;
+
+ m_P0_stack.from_front_init(); // init iterator at front.
+ while (!bDone)
+ {
+ pElem = m_P0_stack.from_front_next();
+ if (pElem)
+ {
+ if (pElem->getP0Type() == P0_ATOM)
+ {
+ TrcStackElemAtom *pAtomElem = dynamic_cast<TrcStackElemAtom *>(pElem);
+ if (pAtomElem)
+ {
+ pAtomElem->mispredictNewest();
+ bFoundAtom = true;
+ }
+ bDone = true;
+ }
+ else if (pElem->getP0Type() == P0_ADDR)
+ {
+ // need to disregard any addresses that appear between mispredict and the atom in question
+ m_P0_stack.erase_curr_from_front();
+ }
+ }
+ else
+ bDone = true;
+ }
+
+ // if missed atom then either overrun error or mispredict on unseen element
+ if (!bFoundAtom && !m_unseen_spec_elem)
+ {
+ err = OCSD_ERR_COMMIT_PKT_OVERRUN;
+ err = handlePacketSeqErr(err, m_index_curr_pkt, "Not found mispredict atom");
+ //LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, m_index_curr_pkt, m_CSID, "Not found mispredict atom"));
+ }
+ m_elem_res.mispredict = false;
+ return err;
+}
+
+// discard elements and flush
+ocsd_err_t TrcPktDecodeEtmV4I::discardElements()
+{
+ ocsd_err_t err = OCSD_OK;
+ TrcStackElem *pElem = 0; // stacked element pointer
+
+ // dump P0, elemnts - output remaining CC / TS
+ while ((m_P0_stack.size() > 0) && !err)
+ {
+ pElem = m_P0_stack.back();
+ if (pElem->getP0Type() == P0_MARKER)
+ err = processMarkerElem(pElem);
+ else
+ err = processTS_CC_EventElem(pElem);
+ m_P0_stack.delete_back();
+ }
+
+ // clear all speculation info
+ clearElemRes();
+ m_curr_spec_depth = 0;
+
+ // set decode state
+ m_curr_state = NO_SYNC;
+ m_unsync_eot_info = m_prev_overflow ? UNSYNC_OVERFLOW : UNSYNC_DISCARD;
+
+ // unsync so need context & address.
+ m_need_ctxt = true;
+ m_need_addr = true;
+ m_elem_pending_addr = false;
+ return err;
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::processTS_CC_EventElem(TrcStackElem *pElem)
+{
+ ocsd_err_t err = OCSD_OK;
+ // ignore ts for ETE if not seen first TS marker on systems that use this.
+ bool bPermitTS = !m_config->eteHasTSMarker() || m_ete_first_ts_marker;
+
+ switch (pElem->getP0Type())
+ {
+ case P0_EVENT:
+ {
+ TrcStackElemParam *pParamElem = dynamic_cast<TrcStackElemParam *>(pElem);
+ if (pParamElem)
+ err = addElemEvent(pParamElem);
+ }
+ break;
+
+ case P0_TS:
+ {
+ TrcStackElemParam *pParamElem = dynamic_cast<TrcStackElemParam *>(pElem);
+ if (pParamElem && bPermitTS)
+ err = addElemTS(pParamElem, false);
+ }
+ break;
+
+ case P0_CC:
+ {
+ TrcStackElemParam *pParamElem = dynamic_cast<TrcStackElemParam *>(pElem);
+ if (pParamElem)
+ err = addElemCC(pParamElem);
+ }
+ break;
+
+ case P0_TS_CC:
+ {
+ TrcStackElemParam *pParamElem = dynamic_cast<TrcStackElemParam *>(pElem);
+ if (pParamElem && bPermitTS)
+ err = addElemTS(pParamElem, true);
+ }
+ break;
+ }
+ return err;
+
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::processMarkerElem(TrcStackElem *pElem)
+{
+ ocsd_err_t err = OCSD_OK;
+ TrcStackElemMarker *pMarkerElem = dynamic_cast<TrcStackElemMarker *>(pElem);
+
+ if (m_config->eteHasTSMarker() && (pMarkerElem->getMarker().type == ELEM_MARKER_TS))
+ m_ete_first_ts_marker = true;
+
+ if (!err)
+ {
+ err = m_out_elem.addElemType(pElem->getRootIndex(), OCSD_GEN_TRC_ELEM_SYNC_MARKER);
+ if (!err)
+ m_out_elem.getCurrElem().setSyncMarker(pMarkerElem->getMarker());
+ }
+ return err;
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::processTransElem(TrcStackElem *pElem)
+{
+ ocsd_err_t err = m_out_elem.addElemType(pElem->getRootIndex(), OCSD_GEN_TRC_ELEM_MEMTRANS);
+ if (!err)
+ {
+ outElem().setTransactionType((trace_memtrans_t)((int)OCSD_MEM_TRANS_FAIL -
+ ((int)P0_TRANS_FAIL - (int)pElem->getP0Type())));
+ }
+ return err;
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::addElemCC(TrcStackElemParam *pParamElem)
+{
+ ocsd_err_t err = OCSD_OK;
+
+ err = m_out_elem.addElemType(pParamElem->getRootIndex(), OCSD_GEN_TRC_ELEM_CYCLE_COUNT);
+ if (!err)
+ outElem().setCycleCount(pParamElem->getParam(0));
+ return err;
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::addElemTS(TrcStackElemParam *pParamElem, bool withCC)
+{
+ ocsd_err_t err = OCSD_OK;
+
+ err = m_out_elem.addElemType(pParamElem->getRootIndex(), OCSD_GEN_TRC_ELEM_TIMESTAMP);
+ if (!err)
+ {
+ outElem().timestamp = (uint64_t)(pParamElem->getParam(0)) | (((uint64_t)pParamElem->getParam(1)) << 32);
+ if (withCC)
+ outElem().setCycleCount(pParamElem->getParam(2));
+ }
+ return err;
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::addElemEvent(TrcStackElemParam *pParamElem)
+{
+ ocsd_err_t err = OCSD_OK;
+
+ err = m_out_elem.addElemType(pParamElem->getRootIndex(), OCSD_GEN_TRC_ELEM_EVENT);
+ if (!err)
+ {
+ outElem().trace_event.ev_type = EVENT_NUMBERED;
+ outElem().trace_event.ev_number = pParamElem->getParam(0);
+ }
+ return err;
+}
+
+void TrcPktDecodeEtmV4I::setElemTraceRange(OcsdTraceElement &elemIn, const instr_range_t &addr_range,
+ const bool executed, ocsd_trc_index_t index)
+{
+ setElemTraceRangeInstr(elemIn, addr_range, executed, index, m_instr_info);
+}
+
+void TrcPktDecodeEtmV4I::setElemTraceRangeInstr(OcsdTraceElement &elemIn, const instr_range_t &addr_range,
+ const bool executed, ocsd_trc_index_t index, ocsd_instr_info &instr)
+{
+ elemIn.setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE);
+ elemIn.setLastInstrInfo(executed, instr.type, instr.sub_type, instr.instr_size);
+ elemIn.setISA(instr.isa);
+ elemIn.setLastInstrCond(instr.is_conditional);
+ elemIn.setAddrRange(addr_range.st_addr, addr_range.en_addr, addr_range.num_instr);
+ if (executed)
+ instr.isa = instr.next_isa;
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::processAtom(const ocsd_atm_val atom)
+{
+ ocsd_err_t err;
+ TrcStackElem *pElem = m_P0_stack.back(); // get the atom element
+ WP_res_t WPRes;
+ instr_range_t addr_range;
+ bool ETE_ERET = false;
+
+ // new element for this processed atom
+ if ((err = m_out_elem.addElem(pElem->getRootIndex())) != OCSD_OK)
+ return err;
+
+ err = traceInstrToWP(addr_range, WPRes);
+ if(err != OCSD_OK)
+ {
+ if(err == OCSD_ERR_UNSUPPORTED_ISA)
+ {
+ m_need_addr = true;
+ m_need_ctxt = true;
+ LogError(ocsdError(OCSD_ERR_SEV_WARN,err,pElem->getRootIndex(),m_CSID,"Warning: unsupported instruction set processing atom packet."));
+ // wait for next context
+ return OCSD_OK;
+ }
+ else
+ {
+ err = handlePacketSeqErr(err, pElem->getRootIndex(), "Error processing atom packet.");
+ //LogError(ocsdError(OCSD_ERR_SEV_ERROR,err,pElem->getRootIndex(),m_CSID,"Error processing atom packet."));
+ return err;
+ }
+ }
+
+ if(WPFound(WPRes))
+ {
+ // save recorded next instuction address
+ ocsd_vaddr_t nextAddr = m_instr_info.instr_addr;
+
+ // action according to waypoint type and atom value
+ switch(m_instr_info.type)
+ {
+ case OCSD_INSTR_BR:
+ if (atom == ATOM_E)
+ {
+ m_instr_info.instr_addr = m_instr_info.branch_addr;
+ if (m_instr_info.is_link)
+ m_return_stack.push(nextAddr, m_instr_info.isa);
+
+ }
+ break;
+
+ case OCSD_INSTR_BR_INDIRECT:
+ if (atom == ATOM_E)
+ {
+ m_need_addr = true; // indirect branch taken - need new address.
+ if (m_instr_info.is_link)
+ m_return_stack.push(nextAddr,m_instr_info.isa);
+ m_return_stack.set_pop_pending(); // need to know next packet before we know what is to happen
+
+ /* ETE does not have ERET trace packets - however to maintain the illusion if we see an ERET
+ output a gen elem ERET packet */
+ if (isETEConfig() && (m_instr_info.sub_type == OCSD_S_INSTR_V8_ERET))
+ ETE_ERET = true;
+ }
+ break;
+ }
+ setElemTraceRange(outElem(), addr_range, (atom == ATOM_E), pElem->getRootIndex());
+
+ if (ETE_ERET)
+ {
+ err = m_out_elem.addElemType(pElem->getRootIndex(), OCSD_GEN_TRC_ELEM_EXCEPTION_RET);
+ if (err)
+ return err;
+ }
+ }
+ else
+ {
+ // no waypoint - likely inaccessible memory range.
+ m_need_addr = true; // need an address update
+
+ if(addr_range.st_addr != addr_range.en_addr)
+ {
+ // some trace before we were out of memory access range
+ setElemTraceRange(outElem(), addr_range, true, pElem->getRootIndex());
+
+ // another element for the nacc...
+ if (WPNacc(WPRes))
+ err = m_out_elem.addElem(pElem->getRootIndex());
+ }
+
+ if(WPNacc(WPRes) && !err)
+ {
+ outElem().setType(OCSD_GEN_TRC_ELEM_ADDR_NACC);
+ outElem().st_addr = m_instr_info.instr_addr;
+ }
+ }
+ return err;
+}
+
+// Exception processor
+ocsd_err_t TrcPktDecodeEtmV4I::processException()
+{
+ ocsd_err_t err;
+ TrcStackElem *pElem = 0;
+ TrcStackElemExcept *pExceptElem = 0;
+ TrcStackElemAddr *pAddressElem = 0;
+ TrcStackElemCtxt *pCtxtElem = 0;
+ bool branch_target = false; // exception address implies prior branch target address
+ ocsd_vaddr_t excep_ret_addr = 0;
+ ocsd_trc_index_t excep_pkt_index;
+ WP_res_t WPRes = WP_NOT_FOUND;
+ bool ETE_resetPkt = false;
+
+ // grab the exception element off the stack
+ pExceptElem = dynamic_cast<TrcStackElemExcept *>(m_P0_stack.back()); // get the exception element
+ excep_pkt_index = pExceptElem->getRootIndex();
+ branch_target = pExceptElem->getPrevSame();
+ if (pExceptElem->getRootPkt() == ETE_PKT_I_PE_RESET)
+ ETE_resetPkt = true;
+ m_P0_stack.pop_back(); // remove the exception element
+
+ // ETE reset has no follow up address, the rest of the exceptions do....
+ if (!ETE_resetPkt)
+ {
+ pElem = m_P0_stack.back(); // look at next element.
+ if (pElem->getP0Type() == P0_CTXT)
+ {
+ pCtxtElem = dynamic_cast<TrcStackElemCtxt *>(pElem);
+ m_P0_stack.pop_back(); // remove the context element
+ pElem = m_P0_stack.back(); // next one should be an address element
+ }
+
+ if (pElem->getP0Type() != P0_ADDR)
+ {
+ // no following address element - indicate processing error.
+
+ err = handlePacketSeqErr(OCSD_ERR_BAD_PACKET_SEQ, m_index_curr_pkt, "Address missing in exception packet.");
+ //LogError(ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_BAD_PACKET_SEQ, excep_pkt_index, m_CSID, "Address missing in exception packet."));
+ return err;
+ }
+ else
+ {
+ // extract address
+ pAddressElem = static_cast<TrcStackElemAddr *>(pElem);
+ excep_ret_addr = pAddressElem->getAddr().val;
+
+ // see if there is an address + optional context element implied
+ // prior to the exception.
+ if (branch_target)
+ {
+ // this was a branch target address - update current setting
+ bool b64bit = m_instr_info.isa == ocsd_isa_aarch64;
+ if (pCtxtElem) {
+ b64bit = pCtxtElem->getContext().SF;
+ }
+
+ // as the exception address was also a branch target address then update the
+ // current maintained address value. This also means that there is no range to
+ // output before the exception packet.
+ m_instr_info.instr_addr = excep_ret_addr;
+ m_instr_info.isa = (pAddressElem->getAddr().isa == 0) ?
+ (b64bit ? ocsd_isa_aarch64 : ocsd_isa_arm) : ocsd_isa_thumb2;
+ m_need_addr = false;
+ }
+ }
+ }
+
+ // need to output something - set up an element
+ if ((err = m_out_elem.addElem(excep_pkt_index)))
+ return err;
+
+ // output a context element if present
+ if (pCtxtElem)
+ {
+ updateContext(pCtxtElem, outElem());
+
+ // used the element - need another for later stages
+ if ((err = m_out_elem.addElem(excep_pkt_index)))
+ return err;
+ }
+
+ if (!ETE_resetPkt)
+ {
+ // if the preferred return address is not the end of the last output range...
+ if (m_instr_info.instr_addr != excep_ret_addr)
+ {
+ bool range_out = false;
+ instr_range_t addr_range;
+
+ // look for match to return address.
+ err = traceInstrToWP(addr_range, WPRes, true, excep_ret_addr);
+
+ if (err != OCSD_OK)
+ {
+ if (err == OCSD_ERR_UNSUPPORTED_ISA)
+ {
+ m_need_addr = true;
+ m_need_ctxt = true;
+ LogError(ocsdError(OCSD_ERR_SEV_WARN, err, excep_pkt_index, m_CSID, "Warning: unsupported instruction set processing exception packet."));
+ }
+ else
+ {
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, excep_pkt_index, m_CSID, "Error processing exception packet."));
+ }
+ return err;
+ }
+
+ if (WPFound(WPRes))
+ {
+ // waypoint address found - output range
+ setElemTraceRange(outElem(), addr_range, true, excep_pkt_index);
+ range_out = true;
+ }
+ else
+ {
+ // no waypoint - likely inaccessible memory range.
+ m_need_addr = true; // need an address update
+
+ if (addr_range.st_addr != addr_range.en_addr)
+ {
+ // some trace before we were out of memory access range
+ setElemTraceRange(outElem(), addr_range, true, excep_pkt_index);
+ range_out = true;
+ }
+ }
+
+ // used the element need another for NACC or EXCEP.
+ if (range_out)
+ {
+ if ((err = m_out_elem.addElem(excep_pkt_index)))
+ return err;
+ }
+ }
+
+ // watchpoint walk resulted in inaccessible memory call...
+ if (WPNacc(WPRes))
+ {
+
+ outElem().setType(OCSD_GEN_TRC_ELEM_ADDR_NACC);
+ outElem().st_addr = m_instr_info.instr_addr;
+
+ // used the element - need another for the final exception packet.
+ if ((err = m_out_elem.addElem(excep_pkt_index)))
+ return err;
+ }
+ }
+
+ // output exception element.
+ outElem().setType(OCSD_GEN_TRC_ELEM_EXCEPTION);
+
+ // add end address as preferred return address to end addr in element
+ outElem().en_addr = excep_ret_addr;
+ outElem().excep_ret_addr = 1;
+ outElem().excep_ret_addr_br_tgt = branch_target;
+ outElem().exception_number = pExceptElem->getExcepNum();
+
+ m_P0_stack.delete_popped(); // clear the used elements from the stack
+ return err;
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::processQElement()
+{
+ ocsd_err_t err = OCSD_OK;
+ TrcStackQElem *pQElem;
+ etmv4_addr_val_t QAddr; // address where trace restarts
+ int iCount = 0;
+
+ pQElem = dynamic_cast<TrcStackQElem *>(m_P0_stack.back()); // get the exception element
+ m_P0_stack.pop_back(); // remove the Q element.
+
+ if (!pQElem->hasAddr()) // no address - it must be next on the stack....
+ {
+ TrcStackElemAddr *pAddressElem = 0;
+ TrcStackElemCtxt *pCtxtElem = 0;
+ TrcStackElem *pElem = 0;
+
+ pElem = m_P0_stack.back(); // look at next element.
+ if (pElem->getP0Type() == P0_CTXT)
+ {
+ pCtxtElem = dynamic_cast<TrcStackElemCtxt *>(pElem);
+ m_P0_stack.pop_back(); // remove the context element
+ pElem = m_P0_stack.back(); // next one should be an address element
+ }
+
+ if (pElem->getP0Type() != P0_ADDR)
+ {
+ // no following address element - indicate processing error.
+ err = OCSD_ERR_BAD_PACKET_SEQ;
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, pQElem->getRootIndex(), m_CSID, "Address missing in Q packet."));
+ m_P0_stack.delete_popped();
+ return err;
+ }
+ pAddressElem = dynamic_cast<TrcStackElemAddr *>(pElem);
+ QAddr = pAddressElem->getAddr();
+ m_P0_stack.pop_back(); // remove the address element
+ m_P0_stack.delete_popped(); // clear used elements
+
+ // return the context element for processing next time.
+ if (pCtxtElem)
+ {
+ // need a new copy at the back - old one will be deleted as popped.
+ m_P0_stack.createContextElem(pCtxtElem->getRootPkt(), pCtxtElem->getRootIndex(), pCtxtElem->getContext(),true);
+ }
+ }
+ else
+ QAddr = pQElem->getAddr();
+
+ // process the Q element with address.
+ iCount = pQElem->getInstrCount();
+
+ bool isBranch = false;
+
+ // need to output something - set up an element
+ if ((err = m_out_elem.addElem(pQElem->getRootIndex())))
+ return err;
+
+ instr_range_t addr_range;
+ addr_range.st_addr = addr_range.en_addr = m_instr_info.instr_addr;
+ addr_range.num_instr = 0;
+
+ // walk iCount instructions
+ for (int i = 0; i < iCount; i++)
+ {
+ uint32_t opcode;
+ uint32_t bytesReq = 4;
+
+ err = accessMemory(m_instr_info.instr_addr, getCurrMemSpace(), &bytesReq, (uint8_t *)&opcode);
+ if (err != OCSD_OK) break;
+
+ if (bytesReq == 4) // got data back
+ {
+ m_instr_info.opcode = opcode;
+ err = instrDecode(&m_instr_info);
+ if (err != OCSD_OK) break;
+
+ // increment address - may be adjusted by direct branch value later
+ m_instr_info.instr_addr += m_instr_info.instr_size;
+ addr_range.num_instr++;
+
+ isBranch = (m_instr_info.type == OCSD_INSTR_BR) ||
+ (m_instr_info.type == OCSD_INSTR_BR_INDIRECT);
+
+ // on a branch no way of knowing if taken - bail out
+ if (isBranch)
+ break;
+ }
+ else
+ break; // missing memory
+
+ }
+
+ if (err == OCSD_OK)
+ {
+ bool inCompleteRange = true;
+ if (iCount && (addr_range.num_instr == (unsigned)iCount))
+ {
+ if ((m_instr_info.instr_addr == QAddr.val) || // complete range
+ (isBranch)) // or ends on branch - only way we know if branch taken.
+ {
+ // output a range and continue
+ inCompleteRange = false;
+ // update the range decoded address in the output packet.
+ addr_range.en_addr = m_instr_info.instr_addr;
+ setElemTraceRange(outElem(), addr_range, true, pQElem->getRootIndex());
+ }
+ }
+
+ if (inCompleteRange)
+ {
+ // unknown instructions executed.
+ addr_range.en_addr = QAddr.val;
+ addr_range.num_instr = iCount;
+
+ outElem().setType(OCSD_GEN_TRC_ELEM_I_RANGE_NOPATH);
+ outElem().setAddrRange(addr_range.st_addr, addr_range.en_addr, addr_range.num_instr);
+ outElem().setISA(calcISA(m_is_64bit, QAddr.isa));
+ }
+
+ // after the Q element, tracing resumes at the address supplied
+ SetInstrInfoInAddrISA(QAddr.val, QAddr.isa);
+ m_need_addr = false;
+ }
+ else
+ {
+ // output error and halt decode.
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, pQElem->getRootIndex(), m_CSID, "Error processing Q packet"));
+ }
+ m_P0_stack.delete_popped();
+ return err;
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::processSourceAddress()
+{
+ ocsd_err_t err = OCSD_OK;
+ TrcStackElemAddr *pElem = dynamic_cast<TrcStackElemAddr *>(m_P0_stack.back()); // get the address element
+ etmv4_addr_val_t srcAddr = pElem->getAddr();
+ uint32_t opcode, bytesReq = 4;
+ ocsd_vaddr_t currAddr = m_instr_info.instr_addr; // get the latest decoded address.
+ instr_range_t out_range;
+ bool bSplitRangeOnN = getComponentOpMode() & ETE_OPFLG_PKTDEC_SRCADDR_N_ATOMS ? true : false;
+
+ // check we can read instruction @ source address
+ err = accessMemory(srcAddr.val, getCurrMemSpace(), &bytesReq, (uint8_t *)&opcode);
+ if (err != OCSD_OK)
+ {
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, pElem->getRootIndex(), m_CSID, "Mem access error processing source address packet."));
+ return err;
+ }
+
+ if (bytesReq != 4)
+ {
+ // can't access - no bytes returned - output nacc.
+ err = m_out_elem.addElemType(pElem->getRootIndex(), OCSD_GEN_TRC_ELEM_ADDR_NACC);
+ outElem().setAddrStart(srcAddr.val);
+ return err;
+ }
+
+ // analyze opcode @ source address.
+ m_instr_info.opcode = opcode;
+ m_instr_info.instr_addr = srcAddr.val;
+ err = instrDecode(&m_instr_info);
+ if (err != OCSD_OK)
+ {
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, pElem->getRootIndex(), m_CSID, "Instruction decode error processing source address packet."));
+ return err;
+ }
+ m_instr_info.instr_addr += m_instr_info.instr_size;
+
+ // initial instruction count for the range.
+ out_range.num_instr = 1;
+
+ // calculate range traced...
+ if (m_need_addr || (currAddr > srcAddr.val))
+ {
+ // we were waiting for a target address, or missing trace
+ // that indicates how we got to the source address.
+ m_need_addr = false;
+ out_range.st_addr = srcAddr.val;
+ }
+ else
+ out_range.st_addr = currAddr;
+ out_range.en_addr = m_instr_info.instr_addr;
+
+ // count instructions
+ if (out_range.en_addr - out_range.st_addr > m_instr_info.instr_size)
+ {
+ if ((m_instr_info.isa != ocsd_isa_thumb2) && !bSplitRangeOnN)
+ {
+ // all 4 byte instructions - just calculate...
+ out_range.num_instr = (uint32_t)(out_range.en_addr - out_range.st_addr) / 4;
+ }
+ else
+ {
+ // need to count T32 - 2 or 4 byte instructions or we are spotting N atoms
+ ocsd_instr_info instr; // going back to start of range so make a copy of info.
+ bool bMemAccErr = false;
+
+ instr.instr_addr = out_range.st_addr;
+ instr.isa = m_instr_info.isa;
+ instr.pe_type = m_instr_info.pe_type;
+ instr.dsb_dmb_waypoints = m_instr_info.dsb_dmb_waypoints;
+ instr.wfi_wfe_branch = m_instr_info.wfi_wfe_branch;
+ out_range.num_instr = 0;
+
+ while ((instr.instr_addr < out_range.en_addr) && !bMemAccErr)
+ {
+ bytesReq = 4;
+ err = accessMemory(instr.instr_addr, getCurrMemSpace(), &bytesReq, (uint8_t *)&opcode);
+ if (err != OCSD_OK)
+ {
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, pElem->getRootIndex(), m_CSID, "Mem access error processing source address packet."));
+ return err;
+ }
+
+ if (bytesReq == 4)
+ {
+ instr.opcode = opcode;
+ err = instrDecode(&instr);
+ if (err != OCSD_OK)
+ {
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR, err, pElem->getRootIndex(), m_CSID, "Instruction decode error processing source address packet."));
+ return err;
+ }
+
+ instr.instr_addr += instr.instr_size;
+ out_range.num_instr++;
+
+ /* if we are doing N atom ranges ...*/
+ if (bSplitRangeOnN && (instr.instr_addr < out_range.en_addr))
+ {
+ if (instr.type != OCSD_INSTR_OTHER)
+ {
+ instr_range_t mid_range = out_range;
+ mid_range.en_addr = instr.instr_addr;
+
+ err = m_out_elem.addElem(pElem->getRootIndex());
+ if (err)
+ return err;
+ setElemTraceRangeInstr(outElem(), mid_range, false, pElem->getRootIndex(), instr);
+
+ out_range.st_addr = mid_range.en_addr;
+ out_range.num_instr = 0;
+ }
+ }
+ }
+ else
+ {
+ // something inaccessible between last and current...
+ bMemAccErr = true;
+
+ err = m_out_elem.addElemType(pElem->getRootIndex(), OCSD_GEN_TRC_ELEM_ADDR_NACC);
+ if (err)
+ return err;
+ outElem().setAddrStart(srcAddr.val);
+
+ // force range to the one instruction
+ out_range.num_instr = 1;
+ out_range.st_addr = srcAddr.val;
+ out_range.en_addr = m_instr_info.instr_addr; // instr after the decoded instruction @ srcAddr.
+ }
+ }
+ }
+ }
+
+ // got to the source address - output trace range, and instruction as E atom.
+ switch (m_instr_info.type)
+ {
+ case OCSD_INSTR_BR:
+ if (m_instr_info.is_link)
+ m_return_stack.push(m_instr_info.instr_addr, m_instr_info.isa);
+ m_instr_info.instr_addr = m_instr_info.branch_addr;
+ break;
+
+ case OCSD_INSTR_BR_INDIRECT:
+ m_need_addr = true; // indirect branch taken - need new address.
+ if (m_instr_info.is_link)
+ m_return_stack.push(m_instr_info.instr_addr, m_instr_info.isa);
+ m_return_stack.set_pop_pending(); // need to know next packet before we know what is to happen
+ break;
+ }
+ m_instr_info.isa = m_instr_info.next_isa;
+
+ // set the trace range element.
+ m_out_elem.addElem(pElem->getRootIndex());
+ setElemTraceRange(outElem(), out_range, true, pElem->getRootIndex());
+ return err;
+}
+
+void TrcPktDecodeEtmV4I::SetInstrInfoInAddrISA(const ocsd_vaddr_t addr_val, const uint8_t isa)
+{
+ m_instr_info.instr_addr = addr_val;
+ m_instr_info.isa = calcISA(m_is_64bit, isa);
+}
+
+// trace an instruction range to a waypoint - and set next address to restart from.
+ocsd_err_t TrcPktDecodeEtmV4I::traceInstrToWP(instr_range_t &range, WP_res_t &WPRes, const bool traceToAddrNext /*= false*/, const ocsd_vaddr_t nextAddrMatch /*= 0*/)
+{
+ uint32_t opcode;
+ uint32_t bytesReq;
+ ocsd_err_t err = OCSD_OK;
+
+ range.st_addr = range.en_addr = m_instr_info.instr_addr;
+ range.num_instr = 0;
+
+ WPRes = WP_NOT_FOUND;
+
+ while(WPRes == WP_NOT_FOUND)
+ {
+ // start off by reading next opcode;
+ bytesReq = 4;
+ err = accessMemory(m_instr_info.instr_addr, getCurrMemSpace(),&bytesReq,(uint8_t *)&opcode);
+ if(err != OCSD_OK) break;
+
+ if(bytesReq == 4) // got data back
+ {
+ m_instr_info.opcode = opcode;
+ err = instrDecode(&m_instr_info);
+ if(err != OCSD_OK) break;
+
+ // increment address - may be adjusted by direct branch value later
+ m_instr_info.instr_addr += m_instr_info.instr_size;
+ range.num_instr++;
+
+ // either walking to match the next instruction address or a real watchpoint
+ if (traceToAddrNext)
+ {
+ if (m_instr_info.instr_addr == nextAddrMatch)
+ WPRes = WP_FOUND;
+ }
+ else if (m_instr_info.type != OCSD_INSTR_OTHER)
+ WPRes = WP_FOUND;
+ }
+ else
+ {
+ // not enough memory accessible.
+ WPRes = WP_NACC;
+ }
+ }
+ // update the range decoded address in the output packet.
+ range.en_addr = m_instr_info.instr_addr;
+ return err;
+}
+
+void TrcPktDecodeEtmV4I::updateContext(TrcStackElemCtxt *pCtxtElem, OcsdTraceElement &elem)
+{
+ etmv4_context_t ctxt = pCtxtElem->getContext();
+
+ elem.setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT);
+
+ // map to output element and local saved state.
+ m_is_64bit = (ctxt.SF != 0);
+ elem.context.bits64 = ctxt.SF;
+ m_is_secure = (ctxt.NS == 0);
+ if (ctxt.NSE)
+ elem.context.security_level = ctxt.NS ? ocsd_sec_realm : ocsd_sec_root;
+ else
+ elem.context.security_level = ctxt.NS ? ocsd_sec_nonsecure : ocsd_sec_secure;
+ elem.context.exception_level = (ocsd_ex_level)ctxt.EL;
+ elem.context.el_valid = 1;
+ if(ctxt.updated_c)
+ {
+ elem.context.ctxt_id_valid = 1;
+ m_context_id = elem.context.context_id = ctxt.ctxtID;
+ }
+ if(ctxt.updated_v)
+ {
+ elem.context.vmid_valid = 1;
+ m_vmid_id = elem.context.vmid = ctxt.VMID;
+ }
+
+ // need to update ISA in case context follows address.
+ elem.isa = m_instr_info.isa = calcISA(m_is_64bit, pCtxtElem->getIS());
+ m_need_ctxt = false;
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::handleBadPacket(const char *reason, ocsd_trc_index_t index /* = OCSD_BAD_TRC_INDEX */)
+{
+ ocsd_err_severity_t sev = OCSD_ERR_SEV_WARN;
+ if (getComponentOpMode() & OCSD_OPFLG_PKTDEC_ERROR_BAD_PKTS)
+ sev = OCSD_ERR_SEV_ERROR;
+
+ return handlePacketErr(OCSD_ERR_BAD_DECODE_PKT, sev, index, reason);
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::handlePacketSeqErr(ocsd_err_t err, ocsd_trc_index_t index, const char *reason)
+{
+ return handlePacketErr(err, OCSD_ERR_SEV_ERROR, index, reason);
+}
+
+ocsd_err_t TrcPktDecodeEtmV4I::handlePacketErr(ocsd_err_t err, ocsd_err_severity_t sev, ocsd_trc_index_t index, const char *reason)
+{
+ bool resetOnBadPackets = true;
+
+ if(getComponentOpMode() & OCSD_OPFLG_PKTDEC_HALT_BAD_PKTS)
+ resetOnBadPackets = false;
+
+ LogError(ocsdError(sev, err, index, getCoreSightTraceID(), reason));
+
+ if (resetOnBadPackets)
+ {
+ // switch to unsync - clear decode state
+ resetDecoder();
+ m_curr_state = NO_SYNC;
+ m_unsync_eot_info = UNSYNC_BAD_PACKET;
+ err = OCSD_OK;
+ }
+ return err;
+
+}
+
+
+inline ocsd_mem_space_acc_t TrcPktDecodeEtmV4I::getCurrMemSpace()
+{
+ static ocsd_mem_space_acc_t SMemSpace[] = {
+ OCSD_MEM_SPACE_EL1S,
+ OCSD_MEM_SPACE_EL1S,
+ OCSD_MEM_SPACE_EL2S,
+ OCSD_MEM_SPACE_EL3
+ };
+
+ static ocsd_mem_space_acc_t NSMemSpace[] = {
+ OCSD_MEM_SPACE_EL1N,
+ OCSD_MEM_SPACE_EL1N,
+ OCSD_MEM_SPACE_EL2,
+ OCSD_MEM_SPACE_EL3
+ };
+
+ /* if no valid EL value - just use S/NS */
+ if (!outElem().context.el_valid)
+ return m_is_secure ? OCSD_MEM_SPACE_S : OCSD_MEM_SPACE_N;
+
+ /* mem space according to EL + S/NS */
+ int el = (int)(outElem().context.exception_level) & 0x3;
+ return m_is_secure ? SMemSpace[el] : NSMemSpace[el];
+}
+/* End of File trc_pkt_decode_etmv4i.cpp */
diff --git a/decoder/source/etmv4/trc_pkt_elem_etmv4i.cpp b/decoder/source/etmv4/trc_pkt_elem_etmv4i.cpp
new file mode 100644
index 0000000..b417540
--- /dev/null
+++ b/decoder/source/etmv4/trc_pkt_elem_etmv4i.cpp
@@ -0,0 +1,754 @@
+/*
+ * \file trc_pkt_elem_etmv4i.cpp
+ * \brief OpenCSD :
+ *
+ * \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.
+ */
+#include <sstream>
+#include <iomanip>
+
+#include "opencsd/etmv4/trc_pkt_elem_etmv4i.h"
+
+EtmV4ITrcPacket::EtmV4ITrcPacket()
+{
+ protocol_version = 0x42; // min protocol version.
+}
+
+EtmV4ITrcPacket::~EtmV4ITrcPacket()
+{
+}
+
+void EtmV4ITrcPacket::initStartState()
+{
+ // clear packet state to start of trace (first sync or post discontinuity)
+
+ // clear all valid bits
+ pkt_valid.val = 0;
+
+ // virtual address
+ v_addr.pkt_bits = 0;
+ v_addr.valid_bits = 0;
+ v_addr_ISA = 0;
+
+ // timestamp
+ ts.bits_changed = 0;
+ ts.timestamp = 0;
+
+ // per packet init
+ initNextPacket();
+}
+
+void EtmV4ITrcPacket::initNextPacket()
+{
+ // clear valid bits for elements that are only valid over a single packet.
+ pkt_valid.bits.cc_valid = 0;
+ pkt_valid.bits.commit_elem_valid = 0;
+ atom.num = 0;
+ context.updated = 0;
+ context.updated_v = 0;
+ context.updated_c = 0;
+ err_type = ETM4_PKT_I_NO_ERR_TYPE;
+}
+
+// printing
+void EtmV4ITrcPacket::toString(std::string &str) const
+{
+ const char *name;
+ const char *desc;
+ std::string valStr, ctxtStr = "";
+
+ name = packetTypeName(type, &desc);
+ str = name + (std::string)" : " + desc;
+
+ // extended descriptions
+ switch (type)
+ {
+ case ETM4_PKT_I_BAD_SEQUENCE:
+ case ETM4_PKT_I_INCOMPLETE_EOT:
+ case ETM4_PKT_I_RESERVED_CFG:
+ name = packetTypeName(err_type, 0);
+ str += "[" + (std::string)name + "]";
+ break;
+
+ case ETM4_PKT_I_ADDR_CTXT_L_32IS0:
+ case ETM4_PKT_I_ADDR_CTXT_L_32IS1:
+ contextStr(ctxtStr);
+ case ETM4_PKT_I_ADDR_L_32IS0:
+ case ETM4_PKT_I_ADDR_L_32IS1:
+ case ETE_PKT_I_SRC_ADDR_L_32IS0:
+ case ETE_PKT_I_SRC_ADDR_L_32IS1:
+ trcPrintableElem::getValStr(valStr, (v_addr.size == VA_64BIT) ? 64 : 32, v_addr.valid_bits, v_addr.val, true, (v_addr.pkt_bits < 32) ? v_addr.pkt_bits : 0);
+ str += "; Addr=" + valStr + "; " + ctxtStr;
+ break;
+
+ case ETM4_PKT_I_ADDR_CTXT_L_64IS0:
+ case ETM4_PKT_I_ADDR_CTXT_L_64IS1:
+ contextStr(ctxtStr);
+ case ETM4_PKT_I_ADDR_L_64IS0:
+ case ETM4_PKT_I_ADDR_L_64IS1:
+ case ETE_PKT_I_SRC_ADDR_L_64IS0:
+ case ETE_PKT_I_SRC_ADDR_L_64IS1:
+ trcPrintableElem::getValStr(valStr, (v_addr.size == VA_64BIT) ? 64 : 32, v_addr.valid_bits, v_addr.val, true, (v_addr.pkt_bits < 64) ? v_addr.pkt_bits : 0);
+ str += "; Addr=" + valStr + "; " + ctxtStr;
+ break;
+
+ case ETM4_PKT_I_CTXT:
+ contextStr(ctxtStr);
+ str += "; " + ctxtStr;
+ break;
+
+ case ETM4_PKT_I_ADDR_S_IS0:
+ case ETM4_PKT_I_ADDR_S_IS1:
+ case ETE_PKT_I_SRC_ADDR_S_IS0:
+ case ETE_PKT_I_SRC_ADDR_S_IS1:
+ trcPrintableElem::getValStr(valStr, (v_addr.size == VA_64BIT) ? 64 : 32, v_addr.valid_bits, v_addr.val, true, v_addr.pkt_bits);
+ str += "; Addr=" + valStr;
+ break;
+
+ case ETM4_PKT_I_ADDR_MATCH:
+ case ETE_PKT_I_SRC_ADDR_MATCH:
+ addrMatchIdx(valStr);
+ str += ", " + valStr;
+ trcPrintableElem::getValStr(valStr, (v_addr.size == VA_64BIT) ? 64 : 32, v_addr.valid_bits, v_addr.val, true);
+ str += "; Addr=" + valStr + "; " + ctxtStr;
+ break;
+
+ case ETM4_PKT_I_ATOM_F1:
+ case ETM4_PKT_I_ATOM_F2:
+ case ETM4_PKT_I_ATOM_F3:
+ case ETM4_PKT_I_ATOM_F4:
+ case ETM4_PKT_I_ATOM_F5:
+ case ETM4_PKT_I_ATOM_F6:
+ atomSeq(valStr);
+ str += "; " + valStr;
+ break;
+
+ case ETM4_PKT_I_EXCEPT:
+ exceptionInfo(valStr);
+ str += "; " + valStr;
+ break;
+
+ case ETM4_PKT_I_TIMESTAMP:
+ {
+ std::ostringstream oss;
+ oss << "; Updated val = " << std::hex << "0x" << ts.timestamp;
+ if (pkt_valid.bits.cc_valid)
+ oss << "; CC=" << std::hex << "0x" << cycle_count;
+ str += oss.str();
+ }
+ break;
+
+ case ETM4_PKT_I_TRACE_INFO:
+ {
+ std::ostringstream oss;
+ oss << "; INFO=" << std::hex << "0x" << trace_info.val;
+ oss << " { CC." << std::dec << trace_info.bits.cc_enabled;
+ if (isETE())
+ oss << ", TSTATE." << std::dec << trace_info.bits.in_trans_state;
+ oss << " }";
+ if (trace_info.bits.cc_enabled)
+ oss << "; CC_THRESHOLD=" << std::hex << "0x" << cc_threshold;
+ str += oss.str();
+ }
+ break;
+
+ case ETM4_PKT_I_CCNT_F1:
+ case ETM4_PKT_I_CCNT_F2:
+ case ETM4_PKT_I_CCNT_F3:
+ {
+ std::ostringstream oss;
+ oss << "; Count=" << std::hex << "0x" << cycle_count;
+ str += oss.str();
+ }
+ break;
+
+ case ETM4_PKT_I_CANCEL_F1:
+ {
+ std::ostringstream oss;
+ oss << "; Cancel(" << std::dec << cancel_elements << ")";
+ str += oss.str();
+ }
+ break;
+
+ case ETM4_PKT_I_CANCEL_F1_MISPRED:
+ {
+ std::ostringstream oss;
+ oss << "; Cancel(" << std::dec << cancel_elements << "), Mispredict";
+ str += oss.str();
+ }
+ break;
+
+ case ETM4_PKT_I_MISPREDICT:
+ {
+ std::ostringstream oss;
+ oss << "; ";
+ if (atom.num) {
+ atomSeq(valStr);
+ oss << "Atom: " << valStr << ", ";
+ }
+ oss << "Mispredict";
+ str += oss.str();
+ }
+ break;
+
+ case ETM4_PKT_I_CANCEL_F2:
+ {
+ std::ostringstream oss;
+ oss << "; ";
+ if (atom.num) {
+ atomSeq(valStr);
+ oss << "Atom: " << valStr << ", ";
+ }
+ oss << "Cancel(1), Mispredict";
+ str += oss.str();
+ }
+ break;
+
+ case ETM4_PKT_I_CANCEL_F3:
+ {
+ std::ostringstream oss;
+ oss << "; ";
+ if (atom.num) {
+ oss << "Atom: E, ";
+ }
+ oss << "Cancel(" << std::dec << cancel_elements << "), Mispredict";
+ str += oss.str();
+ }
+ break;
+
+ case ETM4_PKT_I_COMMIT:
+ {
+ std::ostringstream oss;
+ oss << "; Commit(" << std::dec << commit_elements << ")";
+ str += oss.str();
+ }
+ break;
+
+ case ETM4_PKT_I_Q:
+ {
+ std::ostringstream oss;
+ if (Q_pkt.count_present)
+ {
+ oss << "; Count(" << std::dec << Q_pkt.q_count << ")";
+ str += oss.str();
+ }
+ else
+ str += "; Count(Unknown)";
+
+ if (Q_pkt.addr_match)
+ {
+ addrMatchIdx(valStr);
+ str += "; " + valStr;
+ }
+
+ if (Q_pkt.addr_present || Q_pkt.addr_match)
+ {
+ trcPrintableElem::getValStr(valStr, (v_addr.size == VA_64BIT) ? 64 : 32, v_addr.valid_bits, v_addr.val, true, (v_addr.pkt_bits < 64) ? v_addr.pkt_bits : 0);
+ str += "; Addr=" + valStr;
+ }
+ }
+ break;
+ }
+
+}
+
+void EtmV4ITrcPacket::toStringFmt(const uint32_t fmtFlags, std::string &str) const
+{
+ toString(str); // TBD add in formatted response.
+}
+
+const char *EtmV4ITrcPacket::packetTypeName(const ocsd_etmv4_i_pkt_type type, const char **ppDesc) const
+{
+ const char *pName = "I_UNKNOWN";
+ const char *pDesc = "Unknown Packet Header";
+
+ switch(type)
+ {
+ case ETM4_PKT_I_NOTSYNC:
+ pName = "I_NOT_SYNC";
+ pDesc = "I Stream not synchronised";
+ break;
+
+ case ETM4_PKT_I_INCOMPLETE_EOT:
+ pName = "I_INCOMPLETE_EOT";
+ pDesc = "Incomplete packet at end of trace.";
+ break;
+
+ case ETM4_PKT_I_NO_ERR_TYPE:
+ pName = "I_NO_ERR_TYPE";
+ pDesc = "No Error Type.";
+ break;
+
+ case ETM4_PKT_I_BAD_SEQUENCE:
+ pName = "I_BAD_SEQUENCE";
+ pDesc = "Invalid Sequence in packet.";
+ break;
+
+ case ETM4_PKT_I_BAD_TRACEMODE:
+ pName = "I_BAD_TRACEMODE";
+ pDesc = "Invalid Packet for trace mode.";
+ break;
+
+ case ETM4_PKT_I_RESERVED:
+ pName = "I_RESERVED";
+ pDesc = "Reserved Packet Header";
+ break;
+
+ case ETM4_PKT_I_RESERVED_CFG:
+ pName = "I_RESERVED_CFG";
+ pDesc = "Reserved header for current configuration.";
+ break;
+
+ case ETM4_PKT_I_EXTENSION:
+ pName = "I_EXTENSION";
+ pDesc = "Extension packet header.";
+ break;
+
+ case ETM4_PKT_I_TRACE_INFO:
+ pName = "I_TRACE_INFO";
+ pDesc = "Trace Info.";
+ break;
+
+ case ETM4_PKT_I_TIMESTAMP:
+ pName = "I_TIMESTAMP";
+ pDesc = "Timestamp.";
+ break;
+
+ case ETM4_PKT_I_TRACE_ON:
+ pName = "I_TRACE_ON";
+ pDesc = "Trace On.";
+ break;
+
+ case ETM4_PKT_I_FUNC_RET:
+ pName = "I_FUNC_RET";
+ pDesc = "V8M - function return.";
+ break;
+
+ case ETM4_PKT_I_EXCEPT:
+ pName = "I_EXCEPT";
+ pDesc = "Exception.";
+ break;
+
+ case ETM4_PKT_I_EXCEPT_RTN:
+ pName = "I_EXCEPT_RTN";
+ pDesc = "Exception Return.";
+ break;
+
+ case ETE_PKT_I_COMMIT_WIN_MV:
+ pName = "I_COMMIT_WIN_MV";
+ pDesc = "Commit window move.";
+ break;
+
+ case ETE_PKT_I_TRANS_ST:
+ pName = "I_TRANS_ST";
+ pDesc = "Transaction Start.";
+ break;
+
+ case ETE_PKT_I_TRANS_COMMIT:
+ pName = "I_TRANS_COMMIT";
+ pDesc = "Transaction Commit.";
+ break;
+
+ case ETM4_PKT_I_CCNT_F1:
+ pName = "I_CCNT_F1";
+ pDesc = "Cycle Count format 1.";
+ break;
+
+ case ETM4_PKT_I_CCNT_F2:
+ pName = "I_CCNT_F2";
+ pDesc = "Cycle Count format 2.";
+ break;
+
+ case ETM4_PKT_I_CCNT_F3:
+ pName = "I_CCNT_F3";
+ pDesc = "Cycle Count format 3.";
+ break;
+
+ case ETM4_PKT_I_NUM_DS_MKR:
+ pName = "I_NUM_DS_MKR";
+ pDesc = "Data Synchronisation Marker - Numbered.";
+ break;
+
+ case ETM4_PKT_I_UNNUM_DS_MKR:
+ pName = "I_UNNUM_DS_MKR";
+ pDesc = "Data Synchronisation Marker - Unnumbered.";
+ break;
+
+ case ETM4_PKT_I_COMMIT:
+ pName = "I_COMMIT";
+ pDesc = "Commit";
+ break;
+
+ case ETM4_PKT_I_CANCEL_F1:
+ pName = "I_CANCEL_F1";
+ pDesc = "Cancel Format 1.";
+ break;
+
+ case ETM4_PKT_I_CANCEL_F1_MISPRED:
+ pName = "I_CANCEL_F1_MISPRED";
+ pDesc = "Cancel Format 1 + Mispredict.";
+ break;
+
+
+ case ETM4_PKT_I_MISPREDICT:
+ pName = "I_MISPREDICT";
+ pDesc = "Mispredict.";
+ break;
+
+ case ETM4_PKT_I_CANCEL_F2:
+ pName = "I_CANCEL_F2";
+ pDesc = "Cancel Format 2.";
+ break;
+
+ case ETM4_PKT_I_CANCEL_F3:
+ pName = "I_CANCEL_F3";
+ pDesc = "Cancel Format 3.";
+ break;
+
+ case ETM4_PKT_I_COND_I_F2:
+ pName = "I_COND_I_F2";
+ pDesc = "Conditional Instruction, format 2.";
+ break;
+
+ case ETM4_PKT_I_COND_FLUSH:
+ pName = "I_COND_FLUSH";
+ pDesc = "Conditional Flush.";
+ break;
+
+ case ETM4_PKT_I_COND_RES_F4:
+ pName = "I_COND_RES_F4";
+ pDesc = "Conditional Result, format 4.";
+ break;
+
+ case ETM4_PKT_I_COND_RES_F2:
+ pName = "I_COND_RES_F2";
+ pDesc = "Conditional Result, format 2.";
+ break;
+
+ case ETM4_PKT_I_COND_RES_F3:
+ pName = "I_COND_RES_F3";
+ pDesc = "Conditional Result, format 3.";
+ break;
+
+ case ETM4_PKT_I_COND_RES_F1:
+ pName = "I_COND_RES_F1";
+ pDesc = "Conditional Result, format 1.";
+ break;
+
+ case ETM4_PKT_I_COND_I_F1:
+ pName = "I_COND_I_F1";
+ pDesc = "Conditional Instruction, format 1.";
+ break;
+
+ case ETM4_PKT_I_COND_I_F3:
+ pName = "I_COND_I_F3";
+ pDesc = "Conditional Instruction, format 3.";
+ break;
+
+ case ETM4_PKT_I_IGNORE:
+ pName = "I_IGNORE";
+ pDesc = "Ignore.";
+ break;
+
+ case ETM4_PKT_I_EVENT:
+ pName = "I_EVENT";
+ pDesc = "Trace Event.";
+ break;
+
+ case ETM4_PKT_I_CTXT:
+ pName = "I_CTXT";
+ pDesc = "Context Packet.";
+ break;
+
+ case ETM4_PKT_I_ADDR_CTXT_L_32IS0:
+ pName = "I_ADDR_CTXT_L_32IS0";
+ pDesc = "Address & Context, Long, 32 bit, IS0.";
+ break;
+
+ case ETM4_PKT_I_ADDR_CTXT_L_32IS1:
+ pName = "I_ADDR_CTXT_L_32IS1";
+ pDesc = "Address & Context, Long, 32 bit, IS0.";
+ break;
+
+ case ETM4_PKT_I_ADDR_CTXT_L_64IS0:
+ pName = "I_ADDR_CTXT_L_64IS0";
+ pDesc = "Address & Context, Long, 64 bit, IS0.";
+ break;
+
+ case ETM4_PKT_I_ADDR_CTXT_L_64IS1:
+ pName = "I_ADDR_CTXT_L_64IS1";
+ pDesc = "Address & Context, Long, 64 bit, IS1.";
+ break;
+
+ case ETE_PKT_I_TS_MARKER:
+ pName = "I_TS_MARKER";
+ pDesc = "Timestamp Marker";
+ break;
+
+ case ETM4_PKT_I_ADDR_MATCH:
+ pName = "I_ADDR_MATCH";
+ pDesc = "Exact Address Match.";
+ break;
+
+ case ETM4_PKT_I_ADDR_S_IS0:
+ pName = "I_ADDR_S_IS0";
+ pDesc = "Address, Short, IS0.";
+ break;
+
+ case ETM4_PKT_I_ADDR_S_IS1:
+ pName = "I_ADDR_S_IS1";
+ pDesc = "Address, Short, IS1.";
+ break;
+
+ case ETM4_PKT_I_ADDR_L_32IS0:
+ pName = "I_ADDR_L_32IS0";
+ pDesc = "Address, Long, 32 bit, IS0.";
+ break;
+
+ case ETM4_PKT_I_ADDR_L_32IS1:
+ pName = "I_ADDR_L_32IS1";
+ pDesc = "Address, Long, 32 bit, IS1.";
+ break;
+
+ case ETM4_PKT_I_ADDR_L_64IS0:
+ pName = "I_ADDR_L_64IS0";
+ pDesc = "Address, Long, 64 bit, IS0.";
+ break;
+
+ case ETM4_PKT_I_ADDR_L_64IS1:
+ pName = "I_ADDR_L_64IS1";
+ pDesc = "Address, Long, 64 bit, IS1.";
+ break;
+
+ case ETM4_PKT_I_Q:
+ pName = "I_Q";
+ pDesc = "Q Packet.";
+ break;
+
+ case ETE_PKT_I_SRC_ADDR_MATCH:
+ pName = "I_SRC_ADDR_MATCH";
+ pDesc = "Exact Source Address Match.";
+ break;
+
+ case ETE_PKT_I_SRC_ADDR_S_IS0:
+ pName = "I_SRC_ADDR_S_IS0";
+ pDesc = "Source Address, Short, IS0.";
+ break;
+
+ case ETE_PKT_I_SRC_ADDR_S_IS1:
+ pName = "I_SRC_ADDR_S_IS1";
+ pDesc = "Source Address, Short, IS1.";
+ break;
+
+ case ETE_PKT_I_SRC_ADDR_L_32IS0:
+ pName = "I_SCR_ADDR_L_32IS0";
+ pDesc = "Source Address, Long, 32 bit, IS0.";
+ break;
+
+ case ETE_PKT_I_SRC_ADDR_L_32IS1:
+ pName = "I_SRC_ADDR_L_32IS1";
+ pDesc = "Source Address, Long, 32 bit, IS1.";
+ break;
+
+ case ETE_PKT_I_SRC_ADDR_L_64IS0:
+ pName = "I_SRC_ADDR_L_64IS0";
+ pDesc = "Source Address, Long, 64 bit, IS0.";
+ break;
+
+ case ETE_PKT_I_SRC_ADDR_L_64IS1:
+ pName = "I_SRC_ADDR_L_64IS1";
+ pDesc = "Source Address, Long, 64 bit, IS1.";
+ break;
+
+ case ETM4_PKT_I_ATOM_F6:
+ pName = "I_ATOM_F6";
+ pDesc = "Atom format 6.";
+ break;
+
+ case ETM4_PKT_I_ATOM_F5:
+ pName = "I_ATOM_F5";
+ pDesc = "Atom format 5.";
+ break;
+
+ case ETM4_PKT_I_ATOM_F2:
+ pName = "I_ATOM_F2";
+ pDesc = "Atom format 2.";
+ break;
+
+ case ETM4_PKT_I_ATOM_F4:
+ pName = "I_ATOM_F4";
+ pDesc = "Atom format 4.";
+ break;
+
+ case ETM4_PKT_I_ATOM_F1:
+ pName = "I_ATOM_F1";
+ pDesc = "Atom format 1.";
+ break;
+
+ case ETM4_PKT_I_ATOM_F3:
+ pName = "I_ATOM_F3";
+ pDesc = "Atom format 3.";
+ break;
+
+ case ETM4_PKT_I_ASYNC:
+ pName = "I_ASYNC";
+ pDesc = "Alignment Synchronisation.";
+ break;
+
+ case ETM4_PKT_I_DISCARD:
+ pName = "I_DISCARD";
+ pDesc = "Discard.";
+ break;
+
+ case ETM4_PKT_I_OVERFLOW:
+ pName = "I_OVERFLOW";
+ pDesc = "Overflow.";
+ break;
+
+ case ETE_PKT_I_PE_RESET:
+ pName = "I_PE_RESET";
+ pDesc = "PE Reset.";
+ break;
+
+ case ETE_PKT_I_TRANS_FAIL:
+ pName = "I_TRANS_FAIL";
+ pDesc = "Transaction Fail.";
+ break;
+
+ default:
+ break;
+ }
+
+ if(ppDesc) *ppDesc = pDesc;
+ return pName;
+}
+
+void EtmV4ITrcPacket::contextStr(std::string &ctxtStr) const
+{
+ ctxtStr = "";
+ if(pkt_valid.bits.context_valid)
+ {
+ std::ostringstream oss;
+ if(context.updated)
+ {
+ oss << "Ctxt: " << (context.SF ? "AArch64," : "AArch32, ") << "EL" << context.EL << ", " << (context.NS ? "NS; " : "S; ");
+ if(context.updated_c)
+ {
+ oss << "CID=0x" << std::hex << std::setfill('0') << std::setw(8) << context.ctxtID << "; ";
+ }
+ if(context.updated_v)
+ {
+ oss << "VMID=0x" << std::hex << std::setfill('0') << std::setw(4) << context.VMID << "; ";
+ }
+ }
+ else
+ {
+ oss << "Ctxt: Same";
+ }
+ ctxtStr = oss.str();
+ }
+}
+
+void EtmV4ITrcPacket::atomSeq(std::string &valStr) const
+{
+ std::ostringstream oss;
+ uint32_t bitpattern = atom.En_bits;
+ for(int i = 0; i < atom.num; i++)
+ {
+ oss << ((bitpattern & 0x1) ? "E" : "N");
+ bitpattern >>= 1;
+ }
+ valStr = oss.str();
+}
+
+void EtmV4ITrcPacket::addrMatchIdx(std::string &valStr) const
+{
+ std::ostringstream oss;
+ oss << "[" << (uint16_t)addr_exact_match_idx << "]";
+ valStr = oss.str();
+}
+
+void EtmV4ITrcPacket::exceptionInfo(std::string &valStr) const
+{
+ std::ostringstream oss;
+
+ static const char *ARv8Excep[] = {
+ "PE Reset", "Debug Halt", "Call", "Trap",
+ "System Error", "Reserved", "Inst Debug", "Data Debug",
+ "Reserved", "Reserved", "Alignment", "Inst Fault",
+ "Data Fault", "Reserved", "IRQ", "FIQ"
+ };
+
+ static const char *MExcep[] = {
+ "Reserved", "PE Reset", "NMI", "HardFault",
+ "MemManage", "BusFault", "UsageFault", "Reserved",
+ "Reserved","Reserved","Reserved","SVC",
+ "DebugMonitor", "Reserved","PendSV","SysTick",
+ "IRQ0","IRQ1","IRQ2","IRQ3",
+ "IRQ4","IRQ5","IRQ6","IRQ7",
+ "DebugHalt", "LazyFP Push", "Lockup", "Reserved",
+ "Reserved","Reserved","Reserved","Reserved"
+ };
+
+ if(exception_info.m_type == 0)
+ {
+ if(exception_info.exceptionType < 0x10)
+ oss << " " << ARv8Excep[exception_info.exceptionType] << ";";
+ else
+ oss << " Reserved;";
+
+ }
+ else
+ {
+ if(exception_info.exceptionType < 0x20)
+ oss << " " << MExcep[exception_info.exceptionType] << ";";
+ else if((exception_info.exceptionType >= 0x208) && (exception_info.exceptionType <= 0x3EF))
+ oss << " IRQ" << (int)(exception_info.exceptionType - 0x200) << ";";
+ else
+ oss << " Reserved;";
+ if(exception_info.m_fault_pending)
+ oss << " Fault Pending;";
+ }
+
+ if(exception_info.addr_interp == 0x1)
+ oss << " Ret Addr Follows;";
+ else if(exception_info.addr_interp == 0x2)
+ oss << " Ret Addr Follows, Match Prev;";
+
+ valStr = oss.str();
+}
+
+EtmV4ITrcPacket &EtmV4ITrcPacket::operator =(const ocsd_etmv4_i_pkt* p_pkt)
+{
+ *dynamic_cast<ocsd_etmv4_i_pkt *>(this) = *p_pkt;
+ return *this;
+}
+
+/* End of File trc_pkt_elem_etmv4i.cpp */
diff --git a/decoder/source/etmv4/trc_pkt_proc_etmv4i.cpp b/decoder/source/etmv4/trc_pkt_proc_etmv4i.cpp
new file mode 100644
index 0000000..d0573d6
--- /dev/null
+++ b/decoder/source/etmv4/trc_pkt_proc_etmv4i.cpp
@@ -0,0 +1,1778 @@
+/*
+ * \file trc_pkt_proc_etmv4i.cpp
+ * \brief OpenCSD : Packet processor for ETMv4
+ *
+ * \copyright Copyright (c) 2015, 2019, 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.
+ */
+
+#include "opencsd/etmv4/trc_pkt_proc_etmv4.h"
+#include "common/ocsd_error.h"
+
+#ifdef __GNUC__
+ // G++ doesn't like the ## pasting
+#define ETMV4I_PKTS_NAME "PKTP_ETMV4I"
+#else
+ // VC++ is fine
+#define ETMV4I_PKTS_NAME OCSD_CMPNAME_PREFIX_PKTPROC##"_ETMV4I"
+#endif
+
+static const uint32_t ETMV4_SUPPORTED_OP_FLAGS = OCSD_OPFLG_PKTPROC_COMMON;
+
+// test defines - if testing with ETMv4 sources, disable error on ERET.
+// #define ETE_TRACE_ERET_AS_IGNORE
+
+/* trace etmv4 packet processing class */
+TrcPktProcEtmV4I::TrcPktProcEtmV4I() : TrcPktProcBase(ETMV4I_PKTS_NAME),
+ m_isInit(false),
+ m_first_trace_info(false)
+{
+ m_supported_op_flags = ETMV4_SUPPORTED_OP_FLAGS;
+}
+
+TrcPktProcEtmV4I::TrcPktProcEtmV4I(int instIDNum) : TrcPktProcBase(ETMV4I_PKTS_NAME, instIDNum),
+ m_isInit(false),
+ m_first_trace_info(false)
+{
+ m_supported_op_flags = ETMV4_SUPPORTED_OP_FLAGS;
+}
+
+
+TrcPktProcEtmV4I::~TrcPktProcEtmV4I()
+{
+}
+
+ocsd_err_t TrcPktProcEtmV4I::onProtocolConfig()
+{
+ InitProcessorState();
+ m_config = *TrcPktProcBase::getProtocolConfig();
+ BuildIPacketTable(); // packet table based on config
+ m_curr_packet.setProtocolVersion(m_config.FullVersion());
+ m_isInit = true;
+ statsInit();
+ return OCSD_OK;
+}
+
+ocsd_datapath_resp_t TrcPktProcEtmV4I::processData( const ocsd_trc_index_t index,
+ const uint32_t dataBlockSize,
+ const uint8_t *pDataBlock,
+ uint32_t *numBytesProcessed)
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+
+ if (!m_isInit)
+ return OCSD_RESP_FATAL_NOT_INIT;
+
+ m_trcIn.init(dataBlockSize, pDataBlock, &m_currPacketData);
+ m_blockIndex = index;
+ bool done = false;
+ uint8_t nextByte;
+
+ do
+ {
+ try
+ {
+ while ( (!m_trcIn.empty() || (m_process_state == SEND_PKT)) &&
+ OCSD_DATA_RESP_IS_CONT(resp)
+ )
+ {
+ switch (m_process_state)
+ {
+ case PROC_HDR:
+ m_packet_index = m_blockIndex + m_trcIn.processed();
+ if (m_is_sync)
+ {
+ nextByte = m_trcIn.peekNextByte();
+ m_pIPktFn = m_i_table[nextByte].pptkFn;
+ m_curr_packet.type = m_i_table[nextByte].pkt_type;
+ }
+ else
+ {
+ // unsynced - process data until we see a sync point
+ m_pIPktFn = &TrcPktProcEtmV4I::iNotSync;
+ m_curr_packet.type = ETM4_PKT_I_NOTSYNC;
+ }
+ m_process_state = PROC_DATA;
+
+ case PROC_DATA:
+ // loop till full packet or no more data...
+ while (!m_trcIn.empty() && (m_process_state == PROC_DATA))
+ {
+ nextByte = m_trcIn.peekNextByte();
+ m_trcIn.copyByteToPkt(); // move next byte into the packet
+ (this->*m_pIPktFn)(nextByte);
+ }
+ break;
+
+ case SEND_PKT:
+ resp = outputPacket();
+ InitPacketState();
+ m_process_state = PROC_HDR;
+ break;
+
+ case SEND_UNSYNCED:
+ resp = outputUnsyncedRawPacket();
+ if (m_update_on_unsync_packet_index != 0)
+ {
+ m_packet_index = m_update_on_unsync_packet_index;
+ m_update_on_unsync_packet_index = 0;
+ }
+ m_process_state = PROC_DATA; // after dumping unsynced data, still in data mode.
+ break;
+ }
+ }
+ done = true;
+ }
+ catch(ocsdError &err)
+ {
+ done = true;
+ LogError(err);
+ if( (err.getErrorCode() == OCSD_ERR_BAD_PACKET_SEQ) ||
+ (err.getErrorCode() == OCSD_ERR_INVALID_PCKT_HDR))
+ {
+ // send invalid packets up the pipe to let the next stage decide what to do.
+ if (err.getErrorCode() == OCSD_ERR_INVALID_PCKT_HDR)
+ statsAddBadHdrCount(1);
+ else
+ statsAddBadSeqCount(1);
+ m_process_state = SEND_PKT;
+ done = false;
+ }
+ else
+ {
+ // bail out on any other error.
+ resp = OCSD_RESP_FATAL_INVALID_DATA;
+ }
+ }
+ catch(...)
+ {
+ done = true;
+ /// vv bad at this point.
+ resp = OCSD_RESP_FATAL_SYS_ERR;
+ const ocsdError &fatal = ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_FAIL,m_packet_index,m_config.getTraceID(),"Unknown System Error decoding trace.");
+ LogError(fatal);
+ }
+ } while (!done);
+
+ statsAddTotalCount(m_trcIn.processed());
+ *numBytesProcessed = m_trcIn.processed();
+ return resp;
+}
+
+ocsd_datapath_resp_t TrcPktProcEtmV4I::onEOT()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ if (!m_isInit)
+ return OCSD_RESP_FATAL_NOT_INIT;
+
+ // if we have a partial packet then send to attached sinks
+ if(m_currPacketData.size() != 0)
+ {
+ m_curr_packet.updateErrType(ETM4_PKT_I_INCOMPLETE_EOT);
+ resp = outputPacket();
+ InitPacketState();
+ }
+ return resp;
+}
+
+ocsd_datapath_resp_t TrcPktProcEtmV4I::onReset()
+{
+ if (!m_isInit)
+ return OCSD_RESP_FATAL_NOT_INIT;
+
+ // prepare for new decoding session
+ InitProcessorState();
+ return OCSD_RESP_CONT;
+}
+
+ocsd_datapath_resp_t TrcPktProcEtmV4I::onFlush()
+{
+ if (!m_isInit)
+ return OCSD_RESP_FATAL_NOT_INIT;
+
+ // packet processor never holds on to flushable data (may have partial packet,
+ // but any full packets are immediately sent)
+ return OCSD_RESP_CONT;
+}
+
+void TrcPktProcEtmV4I::InitPacketState()
+{
+ m_currPacketData.clear();
+ m_curr_packet.initNextPacket(); // clear for next packet.
+ m_update_on_unsync_packet_index = 0;
+}
+
+void TrcPktProcEtmV4I::InitProcessorState()
+{
+ InitPacketState();
+ m_pIPktFn = &TrcPktProcEtmV4I::iNotSync;
+ m_packet_index = 0;
+ m_is_sync = false;
+ m_first_trace_info = false;
+ m_sent_notsync_packet = false;
+ m_process_state = PROC_HDR;
+ m_curr_packet.initStartState();
+}
+
+ocsd_datapath_resp_t TrcPktProcEtmV4I::outputPacket()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ resp = outputOnAllInterfaces(m_packet_index,&m_curr_packet,&m_curr_packet.type,m_currPacketData);
+ return resp;
+}
+
+ocsd_datapath_resp_t TrcPktProcEtmV4I::outputUnsyncedRawPacket()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+
+ statsAddUnsyncCount(m_dump_unsynced_bytes);
+ outputRawPacketToMonitor(m_packet_index,&m_curr_packet,m_dump_unsynced_bytes,&m_currPacketData[0]);
+
+ if(!m_sent_notsync_packet)
+ {
+ resp = outputDecodedPacket(m_packet_index,&m_curr_packet);
+ m_sent_notsync_packet = true;
+ }
+
+ if(m_currPacketData.size() <= m_dump_unsynced_bytes)
+ m_currPacketData.clear();
+ else
+ m_currPacketData.erase(m_currPacketData.begin(),m_currPacketData.begin()+m_dump_unsynced_bytes);
+
+ return resp;
+}
+
+void TrcPktProcEtmV4I::iNotSync(const uint8_t lastByte)
+{
+ // is it an extension byte?
+ if (lastByte == 0x00) // TBD : add check for forced sync in here?
+ {
+ if (m_currPacketData.size() > 1)
+ {
+ m_dump_unsynced_bytes = m_currPacketData.size() - 1;
+ m_process_state = SEND_UNSYNCED;
+ // outputting some data then update packet index after so output indexes accurate
+ m_update_on_unsync_packet_index = m_blockIndex + m_trcIn.processed() - 1;
+ }
+ else
+ m_packet_index = m_blockIndex + m_trcIn.processed() - 1; // set it up now otherwise.
+
+ m_pIPktFn = m_i_table[lastByte].pptkFn;
+ }
+ else if (m_currPacketData.size() >= 8)
+ {
+ m_dump_unsynced_bytes = m_currPacketData.size();
+ m_process_state = SEND_UNSYNCED;
+ // outputting some data then update packet index after so output indexes accurate
+ m_update_on_unsync_packet_index = m_blockIndex + m_trcIn.processed();
+ }
+}
+
+void TrcPktProcEtmV4I::iPktNoPayload(const uint8_t lastByte)
+{
+ // some expansion may be required...
+ switch(m_curr_packet.type)
+ {
+ case ETM4_PKT_I_ADDR_MATCH:
+ case ETE_PKT_I_SRC_ADDR_MATCH:
+ m_curr_packet.setAddressExactMatch(lastByte & 0x3);
+ break;
+
+ case ETM4_PKT_I_EVENT:
+ m_curr_packet.setEvent(lastByte & 0xF);
+ break;
+
+ case ETM4_PKT_I_NUM_DS_MKR:
+ case ETM4_PKT_I_UNNUM_DS_MKR:
+ m_curr_packet.setDataSyncMarker(lastByte & 0x7);
+ break;
+
+ // these just need the packet type - no processing required.
+ case ETM4_PKT_I_COND_FLUSH:
+ case ETM4_PKT_I_EXCEPT_RTN:
+ case ETM4_PKT_I_TRACE_ON:
+ case ETM4_PKT_I_FUNC_RET:
+ case ETE_PKT_I_TRANS_ST:
+ case ETE_PKT_I_TRANS_COMMIT:
+ case ETM4_PKT_I_IGNORE:
+ default: break;
+ }
+ m_process_state = SEND_PKT; // now just send it....
+}
+
+void TrcPktProcEtmV4I::iPktReserved(const uint8_t lastByte)
+{
+ m_curr_packet.updateErrType(ETM4_PKT_I_RESERVED, lastByte); // swap type for err type
+ throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_INVALID_PCKT_HDR,m_packet_index,m_config.getTraceID());
+}
+
+void TrcPktProcEtmV4I::iPktInvalidCfg(const uint8_t lastByte)
+{
+ m_curr_packet.updateErrType(ETM4_PKT_I_RESERVED_CFG, lastByte); // swap type for err type
+ throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_INVALID_PCKT_HDR, m_packet_index, m_config.getTraceID());
+}
+
+void TrcPktProcEtmV4I::iPktExtension(const uint8_t lastByte)
+{
+ if(m_currPacketData.size() == 2)
+ {
+ // not sync and not next by 0x00 - not sync sequence
+ if(!m_is_sync && (lastByte != 0x00))
+ {
+ m_pIPktFn = &TrcPktProcEtmV4I::iNotSync;
+ m_curr_packet.type = ETM4_PKT_I_NOTSYNC;
+ return;
+ }
+
+ switch(lastByte)
+ {
+ case 0x03: // discard packet.
+ m_curr_packet.type = ETM4_PKT_I_DISCARD;
+ m_process_state = SEND_PKT;
+ break;
+
+ case 0x05:
+ m_curr_packet.type = ETM4_PKT_I_OVERFLOW;
+ m_process_state = SEND_PKT;
+ break;
+
+ case 0x00:
+ m_curr_packet.type = ETM4_PKT_I_ASYNC;
+ m_pIPktFn = &TrcPktProcEtmV4I::iPktASync; // handle subsequent bytes as async
+ break;
+
+ default:
+ m_curr_packet.err_type = m_curr_packet.type;
+ m_curr_packet.type = ETM4_PKT_I_BAD_SEQUENCE;
+ m_process_state = SEND_PKT;
+ break;
+ }
+ }
+}
+
+void TrcPktProcEtmV4I::iPktASync(const uint8_t lastByte)
+{
+ if(lastByte != 0x00)
+ {
+ // not sync and not next by 0x00 - not sync sequence if < 12
+ if(!m_is_sync && m_currPacketData.size() != 12)
+ {
+ m_pIPktFn = &TrcPktProcEtmV4I::iNotSync;
+ m_curr_packet.type = ETM4_PKT_I_NOTSYNC;
+ return;
+ }
+
+ // 12 bytes and not valid sync sequence - not possible even if not synced
+ m_process_state = SEND_PKT;
+ if((m_currPacketData.size() != 12) || (lastByte != 0x80))
+ {
+ m_curr_packet.type = ETM4_PKT_I_BAD_SEQUENCE;
+ m_curr_packet.err_type = ETM4_PKT_I_ASYNC;
+ }
+ else
+ m_is_sync = true; // found a sync packet, mark decoder as synchronised.
+ }
+ else if(m_currPacketData.size() == 12)
+ {
+ if(!m_is_sync)
+ {
+ // if we are not yet synced then ignore extra leading 0x00.
+ m_dump_unsynced_bytes = 1;
+ m_process_state = SEND_UNSYNCED;
+ }
+ else
+ {
+ // bad periodic ASYNC sequence.
+ m_curr_packet.type = ETM4_PKT_I_BAD_SEQUENCE;
+ m_curr_packet.err_type = ETM4_PKT_I_ASYNC;
+ m_process_state = SEND_PKT;
+ }
+ }
+}
+
+void TrcPktProcEtmV4I::iPktTraceInfo(const uint8_t lastByte)
+{
+ if(m_currPacketData.size() == 1) // header
+ {
+ //clear flags
+ m_tinfo_sections.sectFlags = 0; // mark all sections as incomplete.
+ m_tinfo_sections.ctrlBytes = 1; // assume only a single control section byte for now
+
+ }
+ else if(m_currPacketData.size() == 2) // first payload control byte
+ {
+ // figure out which sections are absent and set to true - opposite of bitfeild in byte;
+ m_tinfo_sections.sectFlags = (~lastByte) & TINFO_ALL_SECT;
+
+ // see if there is an extended control section, otherwise this byte is it.
+ if((lastByte & 0x80) == 0x0)
+ m_tinfo_sections.sectFlags |= TINFO_CTRL;
+
+ }
+ else
+ {
+ if(!(m_tinfo_sections.sectFlags & TINFO_CTRL))
+ {
+ m_tinfo_sections.sectFlags |= (lastByte & 0x80) ? 0 : TINFO_CTRL;
+ m_tinfo_sections.ctrlBytes++;
+ }
+ else if(!(m_tinfo_sections.sectFlags & TINFO_INFO_SECT))
+ m_tinfo_sections.sectFlags |= (lastByte & 0x80) ? 0 : TINFO_INFO_SECT;
+ else if(!(m_tinfo_sections.sectFlags & TINFO_KEY_SECT))
+ m_tinfo_sections.sectFlags |= (lastByte & 0x80) ? 0 : TINFO_KEY_SECT;
+ else if(!(m_tinfo_sections.sectFlags & TINFO_SPEC_SECT))
+ m_tinfo_sections.sectFlags |= (lastByte & 0x80) ? 0 : TINFO_SPEC_SECT;
+ else if(!(m_tinfo_sections.sectFlags & TINFO_CYCT_SECT))
+ m_tinfo_sections.sectFlags |= (lastByte & 0x80) ? 0 : TINFO_CYCT_SECT;
+ else if (!(m_tinfo_sections.sectFlags & TINFO_WNDW_SECT))
+ m_tinfo_sections.sectFlags |= (lastByte & 0x80) ? 0 : TINFO_WNDW_SECT;
+ }
+
+ // all sections accounted for?
+ if(m_tinfo_sections.sectFlags == TINFO_ALL)
+ {
+ // index of first section is number of payload control bytes + 1 for header byte
+ unsigned idx = m_tinfo_sections.ctrlBytes + 1;
+ uint32_t fieldVal = 0;
+ uint8_t presSect = m_currPacketData[1] & TINFO_ALL_SECT; // first payload control byte
+
+ m_curr_packet.clearTraceInfo();
+
+ if((presSect & TINFO_INFO_SECT) && (idx < m_currPacketData.size()))
+ {
+ idx += extractContField(m_currPacketData,idx,fieldVal);
+ m_curr_packet.setTraceInfo(fieldVal);
+ }
+ if((presSect & TINFO_KEY_SECT) && (idx < m_currPacketData.size()))
+ {
+ idx += extractContField(m_currPacketData,idx,fieldVal);
+ m_curr_packet.setTraceInfoKey(fieldVal);
+ }
+ if((presSect & TINFO_SPEC_SECT) && (idx < m_currPacketData.size()))
+ {
+ idx += extractContField(m_currPacketData,idx,fieldVal);
+ m_curr_packet.setTraceInfoSpec(fieldVal);
+ }
+ if((presSect & TINFO_CYCT_SECT) && (idx < m_currPacketData.size()))
+ {
+ idx += extractContField(m_currPacketData,idx,fieldVal);
+ m_curr_packet.setTraceInfoCyct(fieldVal);
+ }
+ if ((presSect & TINFO_WNDW_SECT) && (idx < m_currPacketData.size()))
+ {
+ idx += extractContField(m_currPacketData, idx, fieldVal);
+ /* Trace commit window unsupported in current ETE versions */
+ }
+ m_process_state = SEND_PKT;
+ m_first_trace_info = true;
+ }
+
+}
+
+void TrcPktProcEtmV4I::iPktTimestamp(const uint8_t lastByte)
+{
+ // process the header byte
+ if(m_currPacketData.size() == 1)
+ {
+ m_ccount_done = (bool)((lastByte & 0x1) == 0); // 0 = not present
+ m_ts_done = false;
+ m_ts_bytes = 0;
+ }
+ else
+ {
+ if(!m_ts_done)
+ {
+ m_ts_bytes++;
+ m_ts_done = (m_ts_bytes == 9) || ((lastByte & 0x80) == 0);
+ }
+ else if(!m_ccount_done)
+ {
+ m_ccount_done = (bool)((lastByte & 0x80) == 0);
+ // TBD: check for oorange ccount - bad packet.
+ }
+ }
+
+ if(m_ts_done && m_ccount_done)
+ {
+ int idx = 1;
+ uint64_t tsVal;
+ int ts_bytes = extractTSField64(m_currPacketData, idx, tsVal);
+ int ts_bits;
+
+ // if ts_bytes 8 or less, then cont bits on each byte, otherwise full 64 bit value for 9 bytes
+ ts_bits = ts_bytes < 9 ? ts_bytes * 7 : 64;
+
+ if(!m_curr_packet.pkt_valid.bits.ts_valid && m_first_trace_info)
+ ts_bits = 64; // after trace info, missing bits are all 0.
+
+ m_curr_packet.setTS(tsVal,(uint8_t)ts_bits);
+
+ if((m_currPacketData[0] & 0x1) == 0x1)
+ {
+ uint32_t countVal, countMask;
+
+ idx += ts_bytes;
+ extractContField(m_currPacketData, idx, countVal, 3); // only 3 possible count bytes.
+ countMask = (((uint32_t)1UL << m_config.ccSize()) - 1); // mask of the CC size
+ countVal &= countMask;
+ m_curr_packet.setCycleCount(countVal);
+ }
+
+ m_process_state = SEND_PKT;
+ }
+}
+
+void TrcPktProcEtmV4I::iPktException(const uint8_t lastByte)
+{
+ uint16_t excep_type = 0;
+
+ switch(m_currPacketData.size())
+ {
+ case 1: m_excep_size = 3; break;
+ case 2: if((lastByte & 0x80) == 0x00)
+ m_excep_size = 2;
+ // ETE exception reset or trans failed
+ if (m_config.MajVersion() >= 0x5)
+ {
+ excep_type = (m_currPacketData[1] >> 1) & 0x1F;
+ if ((excep_type == 0x0) || (excep_type == 0x18))
+ m_excep_size = 3;
+ }
+ break;
+ }
+
+ if(m_currPacketData.size() == (unsigned)m_excep_size)
+ {
+ excep_type = (m_currPacketData[1] >> 1) & 0x1F;
+ uint8_t addr_interp = (m_currPacketData[1] & 0x40) >> 5 | (m_currPacketData[1] & 0x1);
+ uint8_t m_fault_pending = 0;
+ uint8_t m_type = (m_config.coreProfile() == profile_CortexM) ? 1 : 0;
+
+ // extended exception packet (probably M class);
+ if(m_currPacketData[1] & 0x80)
+ {
+ excep_type |= ((uint16_t)m_currPacketData[2] & 0x1F) << 5;
+ m_fault_pending = (m_currPacketData[2] >> 5) & 0x1;
+ }
+ m_curr_packet.setExceptionInfo(excep_type,addr_interp,m_fault_pending, m_type);
+ m_process_state = SEND_PKT;
+
+ // ETE exception reset or trans failed
+ if (m_config.MajVersion() >= 0x5)
+ {
+ if ((excep_type == 0x0) || (excep_type == 0x18))
+ {
+ m_curr_packet.set64BitAddress(0, 0);
+ if (excep_type == 0x18)
+ m_curr_packet.setType(ETE_PKT_I_TRANS_FAIL);
+ else
+ m_curr_packet.setType(ETE_PKT_I_PE_RESET);
+ }
+ }
+ // allow the standard address packet handlers to process the address packet field for the exception.
+ }
+}
+
+void TrcPktProcEtmV4I::iPktCycleCntF123(const uint8_t lastByte)
+{
+ ocsd_etmv4_i_pkt_type format = m_curr_packet.type;
+
+ if( m_currPacketData.size() == 1)
+ {
+ m_count_done = m_commit_done = false;
+ m_has_count = true;
+
+ if(format == ETM4_PKT_I_CCNT_F3)
+ {
+ // no commit section for TRCIDR0.COMMOPT == 1
+ if(!m_config.commitOpt1())
+ {
+ m_curr_packet.setCommitElements(((lastByte >> 2) & 0x3) + 1);
+ }
+ // TBD: warning of non-valid CC threshold here?
+ m_curr_packet.setCycleCount(m_curr_packet.getCCThreshold() + (lastByte & 0x3));
+ m_process_state = SEND_PKT;
+ }
+ else if(format == ETM4_PKT_I_CCNT_F1)
+ {
+ if((lastByte & 0x1) == 0x1)
+ {
+ m_has_count = false;
+ m_count_done = true;
+ }
+
+ // no commit section for TRCIDR0.COMMOPT == 1
+ if(m_config.commitOpt1())
+ m_commit_done = true;
+ }
+ }
+ else if((format == ETM4_PKT_I_CCNT_F2) && ( m_currPacketData.size() == 2))
+ {
+ int commit_offset = ((lastByte & 0x1) == 0x1) ? ((int)m_config.MaxSpecDepth() - 15) : 1;
+ int commit_elements = ((lastByte >> 4) & 0xF);
+ commit_elements += commit_offset;
+
+ // TBD: warning if commit elements < 0?
+
+ m_curr_packet.setCycleCount(m_curr_packet.getCCThreshold() + (lastByte & 0xF));
+ m_curr_packet.setCommitElements(commit_elements);
+ m_process_state = SEND_PKT;
+ }
+ else
+ {
+ // F1 and size 2 or more
+ if(!m_commit_done)
+ m_commit_done = ((lastByte & 0x80) == 0x00);
+ else if(!m_count_done)
+ m_count_done = ((lastByte & 0x80) == 0x00);
+ }
+
+ if((format == ETM4_PKT_I_CCNT_F1) && m_commit_done && m_count_done)
+ {
+ int idx = 1; // index into buffer for payload data.
+ uint32_t field_value = 0;
+ // no commit section for TRCIDR0.COMMOPT == 1
+ if(!m_config.commitOpt1())
+ {
+ idx += extractContField(m_currPacketData,idx,field_value);
+ m_curr_packet.setCommitElements(field_value);
+ }
+ if (m_has_count)
+ {
+ extractContField(m_currPacketData, idx, field_value, 3);
+ m_curr_packet.setCycleCount(field_value + m_curr_packet.getCCThreshold());
+ }
+ else
+ m_curr_packet.setCycleCount(0); /* unknown CC marked as 0 after overflow */
+ m_process_state = SEND_PKT;
+ }
+}
+
+void TrcPktProcEtmV4I::iPktSpeclRes(const uint8_t lastByte)
+{
+ if(m_currPacketData.size() == 1)
+ {
+ switch(m_curr_packet.getType())
+ {
+ case ETM4_PKT_I_MISPREDICT:
+ case ETM4_PKT_I_CANCEL_F2:
+ switch(lastByte & 0x3)
+ {
+ case 0x1: m_curr_packet.setAtomPacket(ATOM_PATTERN, 0x1, 1); break; // E
+ case 0x2: m_curr_packet.setAtomPacket(ATOM_PATTERN, 0x3, 2); break; // EE
+ case 0x3: m_curr_packet.setAtomPacket(ATOM_PATTERN, 0x0, 1); break; // N
+ }
+ if (m_curr_packet.getType() == ETM4_PKT_I_CANCEL_F2)
+ m_curr_packet.setCancelElements(1);
+ else
+ m_curr_packet.setCancelElements(0);
+ m_process_state = SEND_PKT;
+ break;
+
+ case ETM4_PKT_I_CANCEL_F3:
+ if(lastByte & 0x1)
+ m_curr_packet.setAtomPacket(ATOM_PATTERN, 0x1, 1); // E
+ m_curr_packet.setCancelElements(((lastByte >> 1) & 0x3) + 2);
+ m_process_state = SEND_PKT;
+ break;
+ }
+ }
+ else
+ {
+ if((lastByte & 0x80) == 0x00)
+ {
+ uint32_t field_val = 0;
+ extractContField(m_currPacketData,1,field_val);
+ if(m_curr_packet.getType() == ETM4_PKT_I_COMMIT)
+ m_curr_packet.setCommitElements(field_val);
+ else
+ m_curr_packet.setCancelElements(field_val);
+ m_process_state = SEND_PKT;
+ }
+ }
+}
+
+void TrcPktProcEtmV4I::iPktCondInstr(const uint8_t lastByte)
+{
+ bool bF1Done = false;
+
+ if(m_currPacketData.size() == 1)
+ {
+ if(m_curr_packet.getType() == ETM4_PKT_I_COND_I_F2)
+ {
+ m_curr_packet.setCondIF2(lastByte & 0x3);
+ m_process_state = SEND_PKT;
+ }
+
+ }
+ else if(m_currPacketData.size() == 2)
+ {
+ if(m_curr_packet.getType() == ETM4_PKT_I_COND_I_F3) // f3 two bytes long
+ {
+ uint8_t num_c_elem = ((lastByte >> 1) & 0x3F) + (lastByte & 0x1);
+ m_curr_packet.setCondIF3(num_c_elem,(bool)((lastByte & 0x1) == 0x1));
+ // TBD: check for 0 num_c_elem in here.
+ m_process_state = SEND_PKT;
+ }
+ else
+ {
+ bF1Done = ((lastByte & 0x80) == 0x00);
+ }
+ }
+ else
+ {
+ bF1Done = ((lastByte & 0x80) == 0x00);
+ }
+
+ if(bF1Done)
+ {
+ uint32_t cond_key = 0;
+ extractContField(m_currPacketData, 1, cond_key);
+ m_process_state = SEND_PKT;
+ }
+}
+
+void TrcPktProcEtmV4I::iPktCondResult(const uint8_t lastByte)
+{
+ if(m_currPacketData.size() == 1)
+ {
+ m_F1P1_done = false; // F1 payload 1 done
+ m_F1P2_done = false; // F1 payload 2 done
+ m_F1has_P2 = false; // F1 has a payload 2
+
+ switch(m_curr_packet.getType())
+ {
+ case ETM4_PKT_I_COND_RES_F1:
+
+ m_F1has_P2 = true;
+ if((lastByte & 0xFC) == 0x6C)// only one payload set
+ {
+ m_F1P2_done = true;
+ m_F1has_P2 = false;
+ }
+ break;
+
+ case ETM4_PKT_I_COND_RES_F2:
+ m_curr_packet.setCondRF2((lastByte & 0x4) ? 2 : 1, lastByte & 0x3);
+ m_process_state = SEND_PKT;
+ break;
+
+ case ETM4_PKT_I_COND_RES_F3:
+ break;
+
+ case ETM4_PKT_I_COND_RES_F4:
+ m_curr_packet.setCondRF4(lastByte & 0x3);
+ m_process_state = SEND_PKT;
+ break;
+ }
+ }
+ else if((m_curr_packet.getType() == ETM4_PKT_I_COND_RES_F3) && (m_currPacketData.size() == 2))
+ {
+ // 2nd F3 packet
+ uint16_t f3_tokens = 0;
+ f3_tokens = (uint16_t)m_currPacketData[1];
+ f3_tokens |= ((uint16_t)m_currPacketData[0] & 0xf) << 8;
+ m_curr_packet.setCondRF3(f3_tokens);
+ m_process_state = SEND_PKT;
+ }
+ else // !first packet - F1
+ {
+ if(!m_F1P1_done)
+ m_F1P1_done = ((lastByte & 0x80) == 0x00);
+ else if(!m_F1P2_done)
+ m_F1P2_done = ((lastByte & 0x80) == 0x00);
+
+ if(m_F1P1_done && m_F1P2_done)
+ {
+ int st_idx = 1;
+ uint32_t key[2];
+ uint8_t result[2];
+ uint8_t CI[2];
+
+ st_idx+= extractCondResult(m_currPacketData,st_idx,key[0],result[0]);
+ CI[0] = m_currPacketData[0] & 0x1;
+ if(m_F1has_P2) // 2nd payload?
+ {
+ extractCondResult(m_currPacketData,st_idx,key[1],result[1]);
+ CI[1] = (m_currPacketData[0] >> 1) & 0x1;
+ }
+ m_curr_packet.setCondRF1(key,result,CI,m_F1has_P2);
+ m_process_state = SEND_PKT;
+ }
+ }
+}
+
+void TrcPktProcEtmV4I::iPktContext(const uint8_t lastByte)
+{
+ bool bSendPacket = false;
+
+ if(m_currPacketData.size() == 1)
+ {
+ if((lastByte & 0x1) == 0)
+ {
+ m_curr_packet.setContextInfo(false); // no update context packet (ctxt same as last time).
+ m_process_state = SEND_PKT;
+ }
+ }
+ else if(m_currPacketData.size() == 2)
+ {
+ if((lastByte & 0xC0) == 0) // no VMID or CID
+ {
+ bSendPacket = true;
+ }
+ else
+ {
+ m_vmidBytes = ((lastByte & 0x40) == 0x40) ? (m_config.vmidSize()/8) : 0;
+ m_ctxtidBytes = ((lastByte & 0x80) == 0x80) ? (m_config.cidSize()/8) : 0;
+ }
+ }
+ else // 3rd byte onwards
+ {
+ if(m_vmidBytes > 0)
+ m_vmidBytes--;
+ else if(m_ctxtidBytes > 0)
+ m_ctxtidBytes--;
+
+ if((m_ctxtidBytes == 0) && (m_vmidBytes == 0))
+ bSendPacket = true;
+ }
+
+ if(bSendPacket)
+ {
+ extractAndSetContextInfo(m_currPacketData,1);
+ m_process_state = SEND_PKT;
+ }
+}
+
+void TrcPktProcEtmV4I::extractAndSetContextInfo(const std::vector<uint8_t> &buffer, const int st_idx)
+{
+ // on input, buffer index points at the info byte - always present
+ uint8_t infoByte = m_currPacketData[st_idx];
+
+ m_curr_packet.setContextInfo(true, (infoByte & 0x3), (infoByte >> 5) & 0x1, (infoByte >> 4) & 0x1, (infoByte >> 3) & 0x1);
+
+ // see if there are VMID and CID bytes, and how many.
+ int nVMID_bytes = ((infoByte & 0x40) == 0x40) ? (m_config.vmidSize()/8) : 0;
+ int nCtxtID_bytes = ((infoByte & 0x80) == 0x80) ? (m_config.cidSize()/8) : 0;
+
+ // extract any VMID and CID
+ int payload_idx = st_idx+1;
+ if(nVMID_bytes)
+ {
+ uint32_t VMID = 0;
+ for(int i = 0; i < nVMID_bytes; i++)
+ {
+ VMID |= ((uint32_t)m_currPacketData[i+payload_idx] << i*8);
+ }
+ payload_idx += nVMID_bytes;
+ m_curr_packet.setContextVMID(VMID);
+ }
+
+ if(nCtxtID_bytes)
+ {
+ uint32_t CID = 0;
+ for(int i = 0; i < nCtxtID_bytes; i++)
+ {
+ CID |= ((uint32_t)m_currPacketData[i+payload_idx] << i*8);
+ }
+ m_curr_packet.setContextCID(CID);
+ }
+}
+
+void TrcPktProcEtmV4I::iPktAddrCtxt(const uint8_t lastByte)
+{
+ if( m_currPacketData.size() == 1)
+ {
+ m_addrIS = 0;
+ m_addrBytes = 4;
+ m_bAddr64bit = false;
+ m_vmidBytes = 0;
+ m_ctxtidBytes = 0;
+ m_bCtxtInfoDone = false;
+
+ switch(m_curr_packet.type)
+ {
+ case ETM4_PKT_I_ADDR_CTXT_L_32IS1:
+ m_addrIS = 1;
+ case ETM4_PKT_I_ADDR_CTXT_L_32IS0:
+ break;
+
+ case ETM4_PKT_I_ADDR_CTXT_L_64IS1:
+ m_addrIS = 1;
+ case ETM4_PKT_I_ADDR_CTXT_L_64IS0:
+ m_addrBytes = 8;
+ m_bAddr64bit = true;
+ break;
+ }
+ }
+ else
+ {
+ if(m_addrBytes == 0)
+ {
+ if(m_bCtxtInfoDone == false)
+ {
+ m_bCtxtInfoDone = true;
+ m_vmidBytes = ((lastByte & 0x40) == 0x40) ? (m_config.vmidSize()/8) : 0;
+ m_ctxtidBytes = ((lastByte & 0x80) == 0x80) ? (m_config.cidSize()/8) : 0;
+ }
+ else
+ {
+ if( m_vmidBytes > 0)
+ m_vmidBytes--;
+ else if(m_ctxtidBytes > 0)
+ m_ctxtidBytes--;
+ }
+ }
+ else
+ m_addrBytes--;
+
+ if((m_addrBytes == 0) && m_bCtxtInfoDone && (m_vmidBytes == 0) && (m_ctxtidBytes == 0))
+ {
+ int st_idx = 1;
+ if(m_bAddr64bit)
+ {
+ uint64_t val64;
+ st_idx+=extract64BitLongAddr(m_currPacketData,st_idx,m_addrIS,val64);
+ m_curr_packet.set64BitAddress(val64,m_addrIS);
+ }
+ else
+ {
+ uint32_t val32;
+ st_idx+=extract32BitLongAddr(m_currPacketData,st_idx,m_addrIS,val32);
+ m_curr_packet.set32BitAddress(val32,m_addrIS);
+ }
+ extractAndSetContextInfo(m_currPacketData,st_idx);
+ m_process_state = SEND_PKT;
+ }
+ }
+}
+
+void TrcPktProcEtmV4I::iPktShortAddr(const uint8_t lastByte)
+{
+ if (m_currPacketData.size() == 1)
+ {
+ m_addr_done = false;
+ m_addrIS = 0;
+ if ((lastByte == ETM4_PKT_I_ADDR_S_IS1) ||
+ (lastByte == ETE_PKT_I_SRC_ADDR_S_IS1))
+ m_addrIS = 1;
+ }
+ else if(!m_addr_done)
+ {
+ m_addr_done = (m_currPacketData.size() == 3) || ((lastByte & 0x80) == 0x00);
+ }
+
+ if(m_addr_done)
+ {
+ uint32_t addr_val = 0;
+ int bits = 0;
+
+ extractShortAddr(m_currPacketData,1,m_addrIS,addr_val,bits);
+ m_curr_packet.updateShortAddress(addr_val,m_addrIS,(uint8_t)bits);
+ m_process_state = SEND_PKT;
+ }
+}
+
+int TrcPktProcEtmV4I::extractShortAddr(const std::vector<uint8_t> &buffer, const int st_idx, const uint8_t IS, uint32_t &value, int &bits)
+{
+ int IS_shift = (IS == 0) ? 2 : 1;
+ int idx = 0;
+
+ bits = 7; // at least 7 bits
+ value = 0;
+ value |= ((uint32_t)(buffer[st_idx+idx] & 0x7F)) << IS_shift;
+
+ if(m_currPacketData[st_idx+idx] & 0x80)
+ {
+ idx++;
+ value |= ((uint32_t)m_currPacketData[st_idx+idx]) << (7 + IS_shift);
+ bits += 8;
+ }
+ idx++;
+ bits += IS_shift;
+ return idx;
+}
+
+void TrcPktProcEtmV4I::iPktLongAddr(const uint8_t lastByte)
+{
+ if(m_currPacketData.size() == 1)
+ {
+ // init the intra-byte data
+ m_addrIS = 0;
+ m_bAddr64bit = false;
+ m_addrBytes = 4;
+
+ switch(m_curr_packet.type)
+ {
+ case ETM4_PKT_I_ADDR_L_32IS1:
+ case ETE_PKT_I_SRC_ADDR_L_32IS1:
+ m_addrIS = 1;
+ case ETM4_PKT_I_ADDR_L_32IS0:
+ case ETE_PKT_I_SRC_ADDR_L_32IS0:
+ m_addrBytes = 4;
+ break;
+
+ case ETM4_PKT_I_ADDR_L_64IS1:
+ case ETE_PKT_I_SRC_ADDR_L_64IS1:
+ m_addrIS = 1;
+ case ETM4_PKT_I_ADDR_L_64IS0:
+ case ETE_PKT_I_SRC_ADDR_L_64IS0:
+ m_addrBytes = 8;
+ m_bAddr64bit = true;
+ break;
+ }
+ }
+ if(m_currPacketData.size() == (unsigned)(1+m_addrBytes))
+ {
+ int st_idx = 1;
+ if(m_bAddr64bit)
+ {
+ uint64_t val64;
+ st_idx+=extract64BitLongAddr(m_currPacketData,st_idx,m_addrIS,val64);
+ m_curr_packet.set64BitAddress(val64,m_addrIS);
+ }
+ else
+ {
+ uint32_t val32;
+ st_idx+=extract32BitLongAddr(m_currPacketData,st_idx,m_addrIS,val32);
+ m_curr_packet.set32BitAddress(val32,m_addrIS);
+ }
+ m_process_state = SEND_PKT;
+ }
+}
+
+void TrcPktProcEtmV4I::iPktQ(const uint8_t lastByte)
+{
+ if(m_currPacketData.size() == 1)
+ {
+ m_Q_type = lastByte & 0xF;
+
+ m_addrBytes = 0;
+ m_count_done = false;
+ m_has_addr = false;
+ m_addr_short = true;
+ m_addr_match = false;
+ m_addrIS = 1;
+ m_QE = 0;
+
+ switch(m_Q_type)
+ {
+ // count only - implied address.
+ case 0x0:
+ case 0x1:
+ case 0x2:
+ m_addr_match = true;
+ m_has_addr = true;
+ m_QE = m_Q_type & 0x3;
+ case 0xC:
+ break;
+
+ // count + short address
+ case 0x5:
+ m_addrIS = 0;
+ case 0x6:
+ m_has_addr = true;
+ m_addrBytes = 2; // short IS0/1
+ break;
+
+ // count + long address
+ case 0xA:
+ m_addrIS = 0;
+ case 0xB:
+ m_has_addr = true;
+ m_addr_short = false;
+ m_addrBytes = 4; // long IS0/1
+ break;
+
+ // no count, no address
+ case 0xF:
+ m_count_done = true;
+ break;
+
+ // reserved values 0x3, 0x4, 0x7, 0x8, 0x9, 0xD, 0xE
+ default:
+ m_curr_packet.err_type = m_curr_packet.type;
+ m_curr_packet.type = ETM4_PKT_I_BAD_SEQUENCE;
+ m_process_state = SEND_PKT;
+ break;
+ }
+ }
+ else
+ {
+ if(m_addrBytes > 0)
+ {
+ if(m_addr_short && m_addrBytes == 2) // short
+ {
+ if((lastByte & 0x80) == 0x00)
+ m_addrBytes--; // short version can have just single byte.
+ }
+ m_addrBytes--;
+ }
+ else if(!m_count_done)
+ {
+ m_count_done = ((lastByte & 0x80) == 0x00);
+ }
+ }
+
+ if(((m_addrBytes == 0) && m_count_done))
+ {
+ int idx = 1; // move past the header
+ int bits = 0;
+ uint32_t q_addr;
+ uint32_t q_count;
+
+ if(m_has_addr)
+ {
+ if(m_addr_match)
+ {
+ m_curr_packet.setAddressExactMatch(m_QE);
+ }
+ else if(m_addr_short)
+ {
+ idx+=extractShortAddr(m_currPacketData,idx,m_addrIS,q_addr,bits);
+ m_curr_packet.updateShortAddress(q_addr,m_addrIS,(uint8_t)bits);
+ }
+ else
+ {
+ idx+=extract32BitLongAddr(m_currPacketData,idx,m_addrIS,q_addr);
+ m_curr_packet.set32BitAddress(q_addr,m_addrIS);
+ }
+ }
+
+ if(m_Q_type != 0xF)
+ {
+ extractContField(m_currPacketData,idx,q_count);
+ m_curr_packet.setQType(true,q_count,m_has_addr,m_addr_match,m_Q_type);
+ }
+ else
+ {
+ m_curr_packet.setQType(false,0,false,false,0xF);
+ }
+ m_process_state = SEND_PKT;
+ }
+
+}
+
+void TrcPktProcEtmV4I::iAtom(const uint8_t lastByte)
+{
+ // patterns lsbit = oldest atom, ms bit = newest.
+ static const uint32_t f4_patterns[] = {
+ 0xE, // EEEN
+ 0x0, // NNNN
+ 0xA, // ENEN
+ 0x5 // NENE
+ };
+
+ uint8_t pattIdx = 0, pattCount = 0;
+ uint32_t pattern;
+
+ // atom packets are single byte, no payload.
+ switch(m_curr_packet.type)
+ {
+ case ETM4_PKT_I_ATOM_F1:
+ m_curr_packet.setAtomPacket(ATOM_PATTERN,(lastByte & 0x1), 1); // 1xE or N
+ break;
+
+ case ETM4_PKT_I_ATOM_F2:
+ m_curr_packet.setAtomPacket(ATOM_PATTERN,(lastByte & 0x3), 2); // 2x (E or N)
+ break;
+
+ case ETM4_PKT_I_ATOM_F3:
+ m_curr_packet.setAtomPacket(ATOM_PATTERN,(lastByte & 0x7), 3); // 3x (E or N)
+ break;
+
+ case ETM4_PKT_I_ATOM_F4:
+ m_curr_packet.setAtomPacket(ATOM_PATTERN,f4_patterns[(lastByte & 0x3)], 4); // 4 atom pattern
+ break;
+
+ case ETM4_PKT_I_ATOM_F5:
+ pattIdx = ((lastByte & 0x20) >> 3) | (lastByte & 0x3);
+ switch(pattIdx)
+ {
+ case 5: // 0b101
+ m_curr_packet.setAtomPacket(ATOM_PATTERN,0x1E, 5); // 5 atom pattern EEEEN
+ break;
+
+ case 1: // 0b001
+ m_curr_packet.setAtomPacket(ATOM_PATTERN,0x00, 5); // 5 atom pattern NNNNN
+ break;
+
+ case 2: //0b010
+ m_curr_packet.setAtomPacket(ATOM_PATTERN,0x0A, 5); // 5 atom pattern NENEN
+ break;
+
+ case 3: //0b011
+ m_curr_packet.setAtomPacket(ATOM_PATTERN,0x15, 5); // 5 atom pattern ENENE
+ break;
+
+ default:
+ // TBD: warn about invalid pattern in here.
+ break;
+ }
+ break;
+
+ case ETM4_PKT_I_ATOM_F6:
+ pattCount = (lastByte & 0x1F) + 3; // count of E's
+ // TBD: check 23 or less at this point?
+ pattern = ((uint32_t)0x1 << pattCount) - 1; // set pattern to string of E's
+ if((lastByte & 0x20) == 0x00) // last atom is E?
+ pattern |= ((uint32_t)0x1 << pattCount);
+ m_curr_packet.setAtomPacket(ATOM_PATTERN,pattern, pattCount+1);
+ break;
+ }
+
+ m_process_state = SEND_PKT;
+}
+
+// header byte processing is table driven.
+void TrcPktProcEtmV4I::BuildIPacketTable()
+{
+ // initialise everything as reserved.
+ for(int i = 0; i < 256; i++)
+ {
+ m_i_table[i].pkt_type = ETM4_PKT_I_RESERVED;
+ m_i_table[i].pptkFn = &TrcPktProcEtmV4I::iPktReserved;
+ }
+
+ // 0x00 - extension
+ m_i_table[0x00].pkt_type = ETM4_PKT_I_EXTENSION;
+ m_i_table[0x00].pptkFn = &TrcPktProcEtmV4I::iPktExtension;
+
+ // 0x01 - Trace info
+ m_i_table[0x01].pkt_type = ETM4_PKT_I_TRACE_INFO;
+ m_i_table[0x01].pptkFn = &TrcPktProcEtmV4I::iPktTraceInfo;
+
+ // b0000001x - timestamp
+ m_i_table[0x02].pkt_type = ETM4_PKT_I_TIMESTAMP;
+ m_i_table[0x02].pptkFn = &TrcPktProcEtmV4I::iPktTimestamp;
+ m_i_table[0x03].pkt_type = ETM4_PKT_I_TIMESTAMP;
+ m_i_table[0x03].pptkFn = &TrcPktProcEtmV4I::iPktTimestamp;
+
+ // b0000 0100 - trace on
+ m_i_table[0x04].pkt_type = ETM4_PKT_I_TRACE_ON;
+ m_i_table[0x04].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload;
+
+
+ // b0000 0101 - Funct ret V8M
+ m_i_table[0x05].pkt_type = ETM4_PKT_I_FUNC_RET;
+ if ((m_config.coreProfile() == profile_CortexM) &&
+ (OCSD_IS_V8_ARCH(m_config.archVersion())) &&
+ (m_config.FullVersion() >= 0x42))
+ {
+ m_i_table[0x05].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload;
+ }
+
+ // b0000 0110 - exception
+ m_i_table[0x06].pkt_type = ETM4_PKT_I_EXCEPT;
+ m_i_table[0x06].pptkFn = &TrcPktProcEtmV4I::iPktException;
+
+ // b0000 0111 - exception return
+ m_i_table[0x07].pkt_type = ETM4_PKT_I_EXCEPT_RTN;
+ if (m_config.MajVersion() >= 0x5) // not valid for ETE
+ {
+#ifdef ETE_TRACE_ERET_AS_IGNORE
+ m_i_table[0x07].pkt_type = ETM4_PKT_I_IGNORE;
+ m_i_table[0x07].pptkFn = &EtmV4IPktProcImpl::iPktNoPayload;
+#else
+ m_i_table[0x07].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg;
+#endif
+ }
+ else
+ m_i_table[0x07].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload;
+
+ // b00001010, b00001011 ETE TRANS packets
+ if (m_config.MajVersion() >= 0x5)
+ {
+ m_i_table[0x0A].pkt_type = ETE_PKT_I_TRANS_ST;
+ m_i_table[0x0A].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload;
+
+ m_i_table[0x0B].pkt_type = ETE_PKT_I_TRANS_COMMIT;
+ m_i_table[0x0B].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload;
+ }
+
+ // b0000 110x - cycle count f2
+ // b0000 111x - cycle count f1
+ for(int i = 0; i < 4; i++)
+ {
+ m_i_table[0x0C+i].pkt_type = (i >= 2) ? ETM4_PKT_I_CCNT_F1 : ETM4_PKT_I_CCNT_F2;
+ m_i_table[0x0C+i].pptkFn = &TrcPktProcEtmV4I::iPktCycleCntF123;
+ }
+
+ // b0001 xxxx - cycle count f3
+ for(int i = 0; i < 16; i++)
+ {
+ m_i_table[0x10+i].pkt_type = ETM4_PKT_I_CCNT_F3;
+ m_i_table[0x10+i].pptkFn = &TrcPktProcEtmV4I::iPktCycleCntF123;
+ }
+
+ // b0010 0xxx - NDSM
+ for(int i = 0; i < 8; i++)
+ {
+ m_i_table[0x20 + i].pkt_type = ETM4_PKT_I_NUM_DS_MKR;
+ if (m_config.enabledDataTrace())
+ m_i_table[0x20+i].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload;
+ else
+ m_i_table[0x20+i].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg;
+ }
+
+ // b0010 10xx, b0010 1100 - UDSM
+ for(int i = 0; i < 5; i++)
+ {
+ m_i_table[0x28+i].pkt_type = ETM4_PKT_I_UNNUM_DS_MKR;
+ if (m_config.enabledDataTrace())
+ m_i_table[0x28+i].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload;
+ else
+ m_i_table[0x28+i].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg;
+ }
+
+ // b0010 1101 - commit
+ m_i_table[0x2D].pkt_type = ETM4_PKT_I_COMMIT;
+ m_i_table[0x2D].pptkFn = &TrcPktProcEtmV4I::iPktSpeclRes;
+
+ // b0010 111x - cancel f1 (mis pred)
+ m_i_table[0x2E].pkt_type = ETM4_PKT_I_CANCEL_F1;
+ m_i_table[0x2E].pptkFn = &TrcPktProcEtmV4I::iPktSpeclRes;
+ m_i_table[0x2F].pkt_type = ETM4_PKT_I_CANCEL_F1_MISPRED;
+ m_i_table[0x2F].pptkFn = &TrcPktProcEtmV4I::iPktSpeclRes;
+
+ // b0011 00xx - mis predict
+ for(int i = 0; i < 4; i++)
+ {
+ m_i_table[0x30+i].pkt_type = ETM4_PKT_I_MISPREDICT;
+ m_i_table[0x30+i].pptkFn = &TrcPktProcEtmV4I::iPktSpeclRes;
+ }
+
+ // b0011 01xx - cancel f2
+ for(int i = 0; i < 4; i++)
+ {
+ m_i_table[0x34+i].pkt_type = ETM4_PKT_I_CANCEL_F2;
+ m_i_table[0x34+i].pptkFn = &TrcPktProcEtmV4I::iPktSpeclRes;
+ }
+
+ // b0011 1xxx - cancel f3
+ for(int i = 0; i < 8; i++)
+ {
+ m_i_table[0x38+i].pkt_type = ETM4_PKT_I_CANCEL_F3;
+ m_i_table[0x38+i].pptkFn = &TrcPktProcEtmV4I::iPktSpeclRes;
+ }
+
+ bool bCondValid = m_config.hasCondTrace() && m_config.enabledCondITrace();
+
+ // b0100 000x, b0100 0010 - cond I f2
+ for (int i = 0; i < 3; i++)
+ {
+ m_i_table[0x40 + i].pkt_type = ETM4_PKT_I_COND_I_F2;
+ if (bCondValid)
+ m_i_table[0x40 + i].pptkFn = &TrcPktProcEtmV4I::iPktCondInstr;
+ else
+ m_i_table[0x40 + i].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg;
+ }
+
+ // b0100 0011 - cond flush
+ m_i_table[0x43].pkt_type = ETM4_PKT_I_COND_FLUSH;
+ if (bCondValid)
+ m_i_table[0x43].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload;
+ else
+ m_i_table[0x43].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg;
+
+ // b0100 010x, b0100 0110 - cond res f4
+ for (int i = 0; i < 3; i++)
+ {
+ m_i_table[0x44 + i].pkt_type = ETM4_PKT_I_COND_RES_F4;
+ if (bCondValid)
+ m_i_table[0x44 + i].pptkFn = &TrcPktProcEtmV4I::iPktCondResult;
+ else
+ m_i_table[0x44 + i].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg;
+ }
+
+ // b0100 100x, b0100 0110 - cond res f2
+ // b0100 110x, b0100 1110 - cond res f2
+ for (int i = 0; i < 3; i++)
+ {
+ m_i_table[0x48 + i].pkt_type = ETM4_PKT_I_COND_RES_F2;
+ if (bCondValid)
+ m_i_table[0x48 + i].pptkFn = &TrcPktProcEtmV4I::iPktCondResult;
+ else
+ m_i_table[0x48 + i].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg;
+ }
+ for (int i = 0; i < 3; i++)
+ {
+ m_i_table[0x4C + i].pkt_type = ETM4_PKT_I_COND_RES_F2;
+ if (bCondValid)
+ m_i_table[0x4C + i].pptkFn = &TrcPktProcEtmV4I::iPktCondResult;
+ else
+ m_i_table[0x4C + i].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg;
+ }
+
+ // b0101xxxx - cond res f3
+ for (int i = 0; i < 16; i++)
+ {
+ m_i_table[0x50 + i].pkt_type = ETM4_PKT_I_COND_RES_F3;
+ if (bCondValid)
+ m_i_table[0x50 + i].pptkFn = &TrcPktProcEtmV4I::iPktCondResult;
+ else
+ m_i_table[0x50 + i].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg;
+ }
+
+ // b011010xx - cond res f1
+ for (int i = 0; i < 4; i++)
+ {
+ m_i_table[0x68 + i].pkt_type = ETM4_PKT_I_COND_RES_F1;
+ if (bCondValid)
+ m_i_table[0x68 + i].pptkFn = &TrcPktProcEtmV4I::iPktCondResult;
+ else
+ m_i_table[0x68 + i].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg;
+ }
+
+ // b0110 1100 - cond instr f1
+ m_i_table[0x6C].pkt_type = ETM4_PKT_I_COND_I_F1;
+ if (bCondValid)
+ m_i_table[0x6C].pptkFn = &TrcPktProcEtmV4I::iPktCondInstr;
+ else
+ m_i_table[0x6C].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg;
+
+ // b0110 1101 - cond instr f3
+ m_i_table[0x6D].pkt_type = ETM4_PKT_I_COND_I_F3;
+ if (bCondValid)
+ m_i_table[0x6D].pptkFn = &TrcPktProcEtmV4I::iPktCondInstr;
+ else
+ m_i_table[0x6D].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg;
+
+ // b0110111x - cond res f1
+ for (int i = 0; i < 2; i++)
+ {
+ // G++ cannot understand [0x6E+i] so change these round
+ m_i_table[i + 0x6E].pkt_type = ETM4_PKT_I_COND_RES_F1;
+ if (bCondValid)
+ m_i_table[i + 0x6E].pptkFn = &TrcPktProcEtmV4I::iPktCondResult;
+ else
+ m_i_table[i + 0x6E].pptkFn = &TrcPktProcEtmV4I::iPktInvalidCfg;
+ }
+
+ // ETM 4.3 introduces ignore packets
+ if (m_config.FullVersion() >= 0x43)
+ {
+ m_i_table[0x70].pkt_type = ETM4_PKT_I_IGNORE;
+ m_i_table[0x70].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload;
+ }
+
+ // b01110001 - b01111111 - event trace
+ for(int i = 0; i < 15; i++)
+ {
+ m_i_table[0x71+i].pkt_type = ETM4_PKT_I_EVENT;
+ m_i_table[0x71+i].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload;
+ }
+
+ // 0b1000 000x - context
+ for(int i = 0; i < 2; i++)
+ {
+ m_i_table[0x80+i].pkt_type = ETM4_PKT_I_CTXT;
+ m_i_table[0x80+i].pptkFn = &TrcPktProcEtmV4I::iPktContext;
+ }
+
+ // 0b1000 0010 to b1000 0011 - addr with ctxt
+ // 0b1000 0101 to b1000 0110 - addr with ctxt
+ for(int i = 0; i < 2; i++)
+ {
+ m_i_table[0x82+i].pkt_type = (i == 0) ? ETM4_PKT_I_ADDR_CTXT_L_32IS0 : ETM4_PKT_I_ADDR_CTXT_L_32IS1;
+ m_i_table[0x82+i].pptkFn = &TrcPktProcEtmV4I::iPktAddrCtxt;
+ }
+
+ for(int i = 0; i < 2; i++)
+ {
+ m_i_table[0x85+i].pkt_type = (i == 0) ? ETM4_PKT_I_ADDR_CTXT_L_64IS0 : ETM4_PKT_I_ADDR_CTXT_L_64IS1;
+ m_i_table[0x85+i].pptkFn = &TrcPktProcEtmV4I::iPktAddrCtxt;
+ }
+
+ // 0b1000 1000 - ETE 1.1 TS Marker. also ETMv4.6
+ if(m_config.FullVersion() >= 0x46)
+ {
+ m_i_table[0x88].pkt_type = ETE_PKT_I_TS_MARKER;
+ m_i_table[0x88].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload;
+ }
+ // 0b1001 0000 to b1001 0010 - exact match addr
+ for(int i = 0; i < 3; i++)
+ {
+ m_i_table[0x90+i].pkt_type = ETM4_PKT_I_ADDR_MATCH;
+ m_i_table[0x90+i].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload;
+ }
+
+ // b1001 0101 - b1001 0110 - addr short address
+ for(int i = 0; i < 2; i++)
+ {
+ m_i_table[0x95+i].pkt_type = (i == 0) ? ETM4_PKT_I_ADDR_S_IS0 : ETM4_PKT_I_ADDR_S_IS1;
+ m_i_table[0x95+i].pptkFn = &TrcPktProcEtmV4I::iPktShortAddr;
+ }
+
+ // b10011010 - b10011011 - addr long address
+ // b10011101 - b10011110 - addr long address
+ for(int i = 0; i < 2; i++)
+ {
+ m_i_table[0x9A+i].pkt_type = (i == 0) ? ETM4_PKT_I_ADDR_L_32IS0 : ETM4_PKT_I_ADDR_L_32IS1;
+ m_i_table[0x9A+i].pptkFn = &TrcPktProcEtmV4I::iPktLongAddr;
+ }
+ for(int i = 0; i < 2; i++)
+ {
+ m_i_table[0x9D+i].pkt_type = (i == 0) ? ETM4_PKT_I_ADDR_L_64IS0 : ETM4_PKT_I_ADDR_L_64IS1;
+ m_i_table[0x9D+i].pptkFn = &TrcPktProcEtmV4I::iPktLongAddr;
+ }
+
+ // b1010xxxx - Q packet
+ for (int i = 0; i < 16; i++)
+ {
+ m_i_table[0xA0 + i].pkt_type = ETM4_PKT_I_Q;
+ // certain Q type codes are reserved.
+ switch (i) {
+ case 0x3:
+ case 0x4:
+ case 0x7:
+ case 0x8:
+ case 0x9:
+ case 0xD:
+ case 0xE:
+ // don't update pkt fn - leave at default reserved.
+ break;
+ default:
+ // if this config supports Q elem - otherwise reserved again.
+ if (m_config.hasQElem())
+ m_i_table[0xA0 + i].pptkFn = &TrcPktProcEtmV4I::iPktQ;
+ }
+ }
+
+ // b10110000 - b10111001 - ETE src address packets
+ if (m_config.FullVersion() >= 0x50)
+ {
+ for (int i = 0; i < 3; i++)
+ {
+ m_i_table[0xB0 + i].pkt_type = ETE_PKT_I_SRC_ADDR_MATCH;
+ m_i_table[0xB0 + i].pptkFn = &TrcPktProcEtmV4I::iPktNoPayload;
+ }
+
+ m_i_table[0xB4].pkt_type = ETE_PKT_I_SRC_ADDR_S_IS0;
+ m_i_table[0xB4].pptkFn = &TrcPktProcEtmV4I::iPktShortAddr;
+ m_i_table[0xB5].pkt_type = ETE_PKT_I_SRC_ADDR_S_IS1;
+ m_i_table[0xB5].pptkFn = &TrcPktProcEtmV4I::iPktShortAddr;
+
+ m_i_table[0xB6].pkt_type = ETE_PKT_I_SRC_ADDR_L_32IS0;
+ m_i_table[0xB6].pptkFn = &TrcPktProcEtmV4I::iPktLongAddr;
+ m_i_table[0xB7].pkt_type = ETE_PKT_I_SRC_ADDR_L_32IS1;
+ m_i_table[0xB7].pptkFn = &TrcPktProcEtmV4I::iPktLongAddr;
+ m_i_table[0xB8].pkt_type = ETE_PKT_I_SRC_ADDR_L_64IS0;
+ m_i_table[0xB8].pptkFn = &TrcPktProcEtmV4I::iPktLongAddr;
+ m_i_table[0xB9].pkt_type = ETE_PKT_I_SRC_ADDR_L_64IS1;
+ m_i_table[0xB9].pptkFn = &TrcPktProcEtmV4I::iPktLongAddr;
+ }
+
+ // Atom Packets - all no payload but have specific pattern generation fn
+ for(int i = 0xC0; i <= 0xD4; i++) // atom f6
+ {
+ m_i_table[i].pkt_type = ETM4_PKT_I_ATOM_F6;
+ m_i_table[i].pptkFn = &TrcPktProcEtmV4I::iAtom;
+ }
+ for(int i = 0xD5; i <= 0xD7; i++) // atom f5
+ {
+ m_i_table[i].pkt_type = ETM4_PKT_I_ATOM_F5;
+ m_i_table[i].pptkFn = &TrcPktProcEtmV4I::iAtom;
+ }
+ for(int i = 0xD8; i <= 0xDB; i++) // atom f2
+ {
+ m_i_table[i].pkt_type = ETM4_PKT_I_ATOM_F2;
+ m_i_table[i].pptkFn = &TrcPktProcEtmV4I::iAtom;
+ }
+ for(int i = 0xDC; i <= 0xDF; i++) // atom f4
+ {
+ m_i_table[i].pkt_type = ETM4_PKT_I_ATOM_F4;
+ m_i_table[i].pptkFn = &TrcPktProcEtmV4I::iAtom;
+ }
+ for(int i = 0xE0; i <= 0xF4; i++) // atom f6
+ {
+ m_i_table[i].pkt_type = ETM4_PKT_I_ATOM_F6;
+ m_i_table[i].pptkFn = &TrcPktProcEtmV4I::iAtom;
+ }
+
+ // atom f5
+ m_i_table[0xF5].pkt_type = ETM4_PKT_I_ATOM_F5;
+ m_i_table[0xF5].pptkFn = &TrcPktProcEtmV4I::iAtom;
+
+ for(int i = 0xF6; i <= 0xF7; i++) // atom f1
+ {
+ m_i_table[i].pkt_type = ETM4_PKT_I_ATOM_F1;
+ m_i_table[i].pptkFn = &TrcPktProcEtmV4I::iAtom;
+ }
+ for(int i = 0xF8; i <= 0xFF; i++) // atom f3
+ {
+ m_i_table[i].pkt_type = ETM4_PKT_I_ATOM_F3;
+ m_i_table[i].pptkFn = &TrcPktProcEtmV4I::iAtom;
+ }
+}
+
+ unsigned TrcPktProcEtmV4I::extractContField(const std::vector<uint8_t> &buffer, const unsigned st_idx, uint32_t &value, const unsigned byte_limit /*= 5*/)
+{
+ unsigned idx = 0;
+ bool lastByte = false;
+ uint8_t byteVal;
+ value = 0;
+ while(!lastByte && (idx < byte_limit)) // max 5 bytes for 32 bit value;
+ {
+ if(buffer.size() > (st_idx + idx))
+ {
+ // each byte has seven bits + cont bit
+ byteVal = buffer[(st_idx + idx)];
+ lastByte = (byteVal & 0x80) != 0x80;
+ value |= ((uint32_t)(byteVal & 0x7F)) << (idx * 7);
+ idx++;
+ }
+ else
+ {
+ throwBadSequenceError("Invalid 32 bit continuation fields in packet");
+ }
+ }
+ return idx;
+}
+
+unsigned TrcPktProcEtmV4I::extractTSField64(const std::vector<uint8_t> &buffer, const unsigned st_idx, uint64_t &value)
+{
+ const unsigned max_byte_idx = 8; /* the 9th byte, index 8, will use full 8 bits for value */
+ unsigned idx = 0;
+ bool lastByte = false;
+ uint8_t byteVal;
+ uint8_t byteValMask = 0x7f;
+
+ /* init value */
+ value = 0;
+ while(!lastByte) // max 9 bytes for 64 bit value;
+ {
+ if(buffer.size() > (st_idx + idx))
+ {
+ // each byte has seven bits + cont bit
+ byteVal = buffer[(st_idx + idx)];
+
+ /* detect the final byte - which uses full 8 bits as value */
+ if (idx == max_byte_idx)
+ {
+ byteValMask = 0xFF; /* last byte of 9, no cont bit */
+ lastByte = true;
+ }
+ else
+ lastByte = (byteVal & 0x80) != 0x80;
+
+ value |= ((uint64_t)(byteVal & byteValMask)) << (idx * 7);
+ idx++;
+ }
+ else
+ {
+ throwBadSequenceError("Invalid 64 bit continuation fields in packet");
+ }
+ }
+ // index is the count of bytes used here.
+ return idx;
+}
+
+ unsigned TrcPktProcEtmV4I::extractCondResult(const std::vector<uint8_t> &buffer, const unsigned st_idx, uint32_t& key, uint8_t &result)
+{
+ unsigned idx = 0;
+ bool lastByte = false;
+ int incr = 0;
+
+ key = 0;
+
+ while(!lastByte && (idx < 6)) // cannot be more than 6 bytes for res + 32 bit key
+ {
+ if(buffer.size() > (st_idx + idx))
+ {
+ if(idx == 0)
+ {
+ result = buffer[st_idx+idx];
+ key = (buffer[st_idx+idx] >> 4) & 0x7;
+ incr+=3;
+ }
+ else
+ {
+ key |= ((uint32_t)(buffer[st_idx+idx] & 0x7F)) << incr;
+ incr+=7;
+ }
+ lastByte = (bool)((buffer[st_idx+idx] & 0x80) == 0);
+ idx++;
+ }
+ else
+ {
+ throwBadSequenceError("Invalid continuation fields in packet");
+ }
+ }
+ return idx;
+}
+
+int TrcPktProcEtmV4I::extract64BitLongAddr(const std::vector<uint8_t> &buffer, const int st_idx, const uint8_t IS, uint64_t &value)
+{
+ value = 0;
+ if(IS == 0)
+ {
+ value |= ((uint64_t)(buffer[st_idx+0] & 0x7F)) << 2;
+ value |= ((uint64_t)(buffer[st_idx+1] & 0x7F)) << 9;
+ }
+ else
+ {
+ value |= ((uint64_t)(buffer[st_idx+0] & 0x7F)) << 1;
+ value |= ((uint64_t)buffer[st_idx+1]) << 8;
+ }
+ value |= ((uint64_t)buffer[st_idx+2]) << 16;
+ value |= ((uint64_t)buffer[st_idx+3]) << 24;
+ value |= ((uint64_t)buffer[st_idx+4]) << 32;
+ value |= ((uint64_t)buffer[st_idx+5]) << 40;
+ value |= ((uint64_t)buffer[st_idx+6]) << 48;
+ value |= ((uint64_t)buffer[st_idx+7]) << 56;
+ return 8;
+}
+
+int TrcPktProcEtmV4I::extract32BitLongAddr(const std::vector<uint8_t> &buffer, const int st_idx, const uint8_t IS, uint32_t &value)
+{
+ value = 0;
+ if(IS == 0)
+ {
+ value |= ((uint32_t)(buffer[st_idx+0] & 0x7F)) << 2;
+ value |= ((uint32_t)(buffer[st_idx+1] & 0x7F)) << 9;
+ }
+ else
+ {
+ value |= ((uint32_t)(buffer[st_idx+0] & 0x7F)) << 1;
+ value |= ((uint32_t)buffer[st_idx+1]) << 8;
+ }
+ value |= ((uint32_t)buffer[st_idx+2]) << 16;
+ value |= ((uint32_t)buffer[st_idx+3]) << 24;
+ return 4;
+}
+
+void TrcPktProcEtmV4I::throwBadSequenceError(const char *pszExtMsg)
+{
+ m_curr_packet.updateErrType(ETM4_PKT_I_BAD_SEQUENCE); // swap type for err type
+ throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_BAD_PACKET_SEQ,m_packet_index,m_config.getTraceID(),pszExtMsg);
+}
+
+
+/* End of File trc_pkt_proc_etmv4i.cpp */