summaryrefslogtreecommitdiffstats
path: root/decoder/source/etmv3
diff options
context:
space:
mode:
Diffstat (limited to 'decoder/source/etmv3')
-rw-r--r--decoder/source/etmv3/trc_cmp_cfg_etmv3.cpp65
-rw-r--r--decoder/source/etmv3/trc_pkt_decode_etmv3.cpp681
-rw-r--r--decoder/source/etmv3/trc_pkt_elem_etmv3.cpp688
-rw-r--r--decoder/source/etmv3/trc_pkt_proc_etmv3.cpp122
-rw-r--r--decoder/source/etmv3/trc_pkt_proc_etmv3_impl.cpp1224
-rw-r--r--decoder/source/etmv3/trc_pkt_proc_etmv3_impl.h175
6 files changed, 2955 insertions, 0 deletions
diff --git a/decoder/source/etmv3/trc_cmp_cfg_etmv3.cpp b/decoder/source/etmv3/trc_cmp_cfg_etmv3.cpp
new file mode 100644
index 0000000..f2556e4
--- /dev/null
+++ b/decoder/source/etmv3/trc_cmp_cfg_etmv3.cpp
@@ -0,0 +1,65 @@
+/*
+ * \file trc_cmp_cfg_etmv3.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/etmv3/trc_cmp_cfg_etmv3.h"
+
+EtmV3Config::EtmV3Config()
+{
+ // defaults set ETMv3.4, V7A, instruction only.
+ m_cfg.arch_ver = ARCH_V7;
+ m_cfg.core_prof = profile_CortexA;
+ m_cfg.reg_ccer = 0;
+ m_cfg.reg_idr = 0x4100F240; // default trace IDR value
+ m_cfg.reg_ctrl = 0;
+}
+
+EtmV3Config::EtmV3Config(const ocsd_etmv3_cfg *cfg_regs)
+{
+ m_cfg = *cfg_regs;
+}
+
+EtmV3Config::EtmTraceMode const EtmV3Config::GetTraceMode() const
+{
+ int mode = 0 + ( isDataValTrace() ? 1 : 0 ) + (isDataAddrTrace() ? 2 : 0) + (isInstrTrace() ? 0 : 3);
+ return (EtmTraceMode)mode;
+}
+
+const int EtmV3Config::CtxtIDBytes() const
+{
+ int ctxtIdsizes[] = { 0, 1, 2, 4 };
+ return ctxtIdsizes[(m_cfg.reg_ctrl >> 14) & 0x3];
+}
+
+/* End of File trc_cmp_cfg_etmv3.cpp */
diff --git a/decoder/source/etmv3/trc_pkt_decode_etmv3.cpp b/decoder/source/etmv3/trc_pkt_decode_etmv3.cpp
new file mode 100644
index 0000000..e68a73f
--- /dev/null
+++ b/decoder/source/etmv3/trc_pkt_decode_etmv3.cpp
@@ -0,0 +1,681 @@
+/*!
+ * \file trc_pkt_decode_etmv3.cpp
+ * \brief OpenCSD : ETMv3 trace packet decode.
+ *
+ * \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/etmv3/trc_pkt_decode_etmv3.h"
+
+#define DCD_NAME "DCD_ETMV3"
+
+TrcPktDecodeEtmV3::TrcPktDecodeEtmV3() :
+ TrcPktDecodeBase(DCD_NAME)
+{
+ initDecoder();
+}
+
+TrcPktDecodeEtmV3::TrcPktDecodeEtmV3(int instIDNum) :
+ TrcPktDecodeBase(DCD_NAME, instIDNum)
+{
+ initDecoder();
+}
+
+TrcPktDecodeEtmV3::~TrcPktDecodeEtmV3()
+{
+}
+
+
+/* implementation packet decoding interface */
+ocsd_datapath_resp_t TrcPktDecodeEtmV3::processPacket()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ bool bPktDone = false;
+
+ if(!m_config)
+ return OCSD_RESP_FATAL_NOT_INIT;
+
+ // iterate round the state machine, waiting for sync, then decoding packets.
+ while(!bPktDone)
+ {
+ switch(m_curr_state)
+ {
+ case NO_SYNC:
+ // output the initial not synced packet to the sink
+ resp = sendUnsyncPacket();
+ m_curr_state = WAIT_ASYNC; // immediate wait for ASync and actually check out the packet
+ break;
+
+ case WAIT_ASYNC:
+ // if async, wait for ISync, but this packet done.
+ if(m_curr_packet_in->getType() == ETM3_PKT_A_SYNC)
+ m_curr_state = WAIT_ISYNC;
+ bPktDone = true;
+ break;
+
+ case WAIT_ISYNC:
+ m_bWaitISync = true; // we are waiting for ISync
+ if((m_curr_packet_in->getType() == ETM3_PKT_I_SYNC) ||
+ (m_curr_packet_in->getType() == ETM3_PKT_I_SYNC_CYCLE))
+ {
+ // process the ISync immediately as the first ISync seen.
+ resp = processISync((m_curr_packet_in->getType() == ETM3_PKT_I_SYNC_CYCLE),true);
+ m_curr_state = SEND_PKTS;
+ m_bWaitISync = false;
+ }
+ // something like TS, CC, PHDR+CC, which after ASYNC may be valid prior to ISync
+ else if(preISyncValid(m_curr_packet_in->getType()))
+ {
+ // decode anything that might be valid - send will be set automatically
+ resp = decodePacket(bPktDone);
+ }
+ else
+ bPktDone = true;
+ break;
+
+ case DECODE_PKTS:
+ resp = decodePacket(bPktDone);
+ break;
+
+ case SEND_PKTS:
+ resp = m_outputElemList.sendElements();
+ if(OCSD_DATA_RESP_IS_CONT(resp))
+ m_curr_state = m_bWaitISync ? WAIT_ISYNC : DECODE_PKTS;
+ bPktDone = true;
+ break;
+
+ default:
+ bPktDone = true;
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_FAIL,m_index_curr_pkt,"Unknown Decoder State"));
+ resetDecoder(); // mark decoder as unsynced - dump any current state.
+ resp = OCSD_RESP_FATAL_SYS_ERR;
+ break;
+ }
+ }
+
+ return resp;
+}
+
+ocsd_datapath_resp_t TrcPktDecodeEtmV3::onEOT()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ OcsdTraceElement *pElem = 0;
+ try {
+ pElem = GetNextOpElem(resp);
+ pElem->setType(OCSD_GEN_TRC_ELEM_EO_TRACE);
+ pElem->setUnSyncEOTReason(UNSYNC_EOT);
+ m_outputElemList.commitAllPendElem();
+ m_curr_state = SEND_PKTS;
+ resp = m_outputElemList.sendElements();
+ if(OCSD_DATA_RESP_IS_CONT(resp))
+ m_curr_state = DECODE_PKTS;
+ }
+ catch(ocsdError &err)
+ {
+ LogError(err);
+ resetDecoder(); // mark decoder as unsynced - dump any current state.
+ }
+ return resp;
+}
+
+ocsd_datapath_resp_t TrcPktDecodeEtmV3::onReset()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ m_unsync_info = UNSYNC_RESET_DECODER;
+ resetDecoder();
+ return resp;
+}
+
+ocsd_datapath_resp_t TrcPktDecodeEtmV3::onFlush()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ if(m_curr_state == SEND_PKTS)
+ {
+ resp = m_outputElemList.sendElements();
+ if(OCSD_DATA_RESP_IS_CONT(resp))
+ m_curr_state = m_bWaitISync ? WAIT_ISYNC : DECODE_PKTS;
+ }
+ return resp;
+}
+
+ocsd_err_t TrcPktDecodeEtmV3::onProtocolConfig()
+{
+ ocsd_err_t err = OCSD_OK;
+ if(m_config)
+ {
+ // set some static config elements
+ m_CSID = m_config->getTraceID();
+
+ // check config compatible with current decoder support level.
+ // at present no data trace;
+ if(m_config->GetTraceMode() != EtmV3Config::TM_INSTR_ONLY)
+ {
+ err = OCSD_ERR_HW_CFG_UNSUPP;
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,"ETMv3 trace decoder : data trace decode not yet supported"));
+ }
+
+ // need to set up core profile info in follower
+ ocsd_arch_profile_t arch_profile;
+ arch_profile.arch = m_config->getArchVersion();
+ arch_profile.profile = m_config->getCoreProfile();
+ m_code_follower.setArchProfile(arch_profile);
+ m_code_follower.setMemSpaceCSID(m_CSID);
+ m_outputElemList.initCSID(m_CSID);
+ }
+ else
+ err = OCSD_ERR_NOT_INIT;
+ return err;
+}
+
+/* local decode methods */
+
+// initialise on creation
+void TrcPktDecodeEtmV3::initDecoder()
+{
+ m_CSID = 0;
+ resetDecoder();
+ m_unsync_info = UNSYNC_INIT_DECODER;
+ m_code_follower.initInterfaces(getMemoryAccessAttachPt(),getInstrDecodeAttachPt());
+ m_outputElemList.initSendIf(getTraceElemOutAttachPt());
+}
+
+// reset for first use / re-use.
+void TrcPktDecodeEtmV3::resetDecoder()
+{
+ m_curr_state = NO_SYNC; // mark as not synced
+ m_bNeedAddr = true;
+ m_bSentUnknown = false;
+ m_bWaitISync = false;
+ m_outputElemList.reset();
+}
+
+OcsdTraceElement *TrcPktDecodeEtmV3::GetNextOpElem(ocsd_datapath_resp_t &resp)
+{
+ OcsdTraceElement *pElem = m_outputElemList.getNextElem(m_index_curr_pkt);
+ if(pElem == 0)
+ {
+ resp = OCSD_RESP_FATAL_NOT_INIT;
+ throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_MEM,m_index_curr_pkt,m_CSID,"Memory Allocation Error - fatal");
+ }
+ return pElem;
+}
+
+bool TrcPktDecodeEtmV3::preISyncValid(ocsd_etmv3_pkt_type pkt_type)
+{
+ bool bValid = false;
+ // its a timestamp
+ if((pkt_type == ETM3_PKT_TIMESTAMP) ||
+ // or we are cycleacc and its a packet that can have CC in it
+ (m_config->isCycleAcc() && ((pkt_type == ETM3_PKT_CYCLE_COUNT) || (pkt_type == ETM3_PKT_P_HDR)))
+ )
+ bValid = true;
+ return bValid;
+}
+
+// simple packet transforms handled here, more complex processing passed on to specific routines.
+ocsd_datapath_resp_t TrcPktDecodeEtmV3::decodePacket(bool &pktDone)
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ bool bISyncHasCC = false;
+ OcsdTraceElement *pElem = 0;
+ pktDone = false;
+
+ // there may be pended packets that can now be committed.
+ // only the branch address with exception and cancel element can cancel
+ // if not one of those, commit immediately, otherwise defer to branch address handler.
+ if(m_curr_packet_in->getType() != ETM3_PKT_BRANCH_ADDRESS)
+ m_outputElemList.commitAllPendElem();
+
+ try {
+
+ switch(m_curr_packet_in->getType())
+ {
+
+ case ETM3_PKT_NOTSYNC:
+ // mark as not synced - must have lost sync in the packet processor somehow
+ throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,m_index_curr_pkt,m_CSID,"Trace Packet Synchronisation Lost");
+ break;
+
+ // no action for these packets - ignore and continue
+ case ETM3_PKT_INCOMPLETE_EOT:
+ case ETM3_PKT_A_SYNC:
+ case ETM3_PKT_IGNORE:
+ break;
+
+ // markers for valid packets
+ case ETM3_PKT_CYCLE_COUNT:
+ pElem = GetNextOpElem(resp);
+ pElem->setType(OCSD_GEN_TRC_ELEM_CYCLE_COUNT);
+ pElem->setCycleCount(m_curr_packet_in->getCycleCount());
+ break;
+
+ case ETM3_PKT_TRIGGER:
+ pElem = GetNextOpElem(resp);
+ pElem->setType(OCSD_GEN_TRC_ELEM_EVENT);
+ pElem->setEvent(EVENT_TRIGGER,0);
+ break;
+
+ case ETM3_PKT_BRANCH_ADDRESS:
+ resp = processBranchAddr();
+ break;
+
+ case ETM3_PKT_I_SYNC_CYCLE:
+ bISyncHasCC = true;
+ case ETM3_PKT_I_SYNC:
+ resp = processISync(bISyncHasCC);
+ break;
+
+ case ETM3_PKT_P_HDR:
+ resp = processPHdr();
+ break;
+
+ case ETM3_PKT_CONTEXT_ID:
+ pElem = GetNextOpElem(resp);
+ pElem->setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT);
+ m_PeContext.setCtxtID(m_curr_packet_in->getCtxtID());
+ pElem->setContext(m_PeContext);
+ break;
+
+ case ETM3_PKT_VMID:
+ pElem = GetNextOpElem(resp);
+ pElem->setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT);
+ m_PeContext.setVMID(m_curr_packet_in->getVMID());
+ pElem->setContext(m_PeContext);
+ break;
+
+ case ETM3_PKT_EXCEPTION_ENTRY:
+ pElem = GetNextOpElem(resp);
+ pElem->setType(OCSD_GEN_TRC_ELEM_EXCEPTION);
+ pElem->setExcepMarker(); // exception entries are always v7M data markers in ETMv3 trace.
+ break;
+
+ case ETM3_PKT_EXCEPTION_EXIT:
+ pElem = GetNextOpElem(resp);
+ pElem->setType(OCSD_GEN_TRC_ELEM_EXCEPTION_RET);
+ pendExceptionReturn();
+ break;
+
+ case ETM3_PKT_TIMESTAMP:
+ pElem = GetNextOpElem(resp);
+ pElem->setType(OCSD_GEN_TRC_ELEM_TIMESTAMP);
+ pElem->setTS(m_curr_packet_in->getTS());
+ break;
+
+ // data packets - data trace not supported at present
+ case ETM3_PKT_STORE_FAIL:
+ case ETM3_PKT_OOO_DATA:
+ case ETM3_PKT_OOO_ADDR_PLC:
+ case ETM3_PKT_NORM_DATA:
+ case ETM3_PKT_DATA_SUPPRESSED:
+ case ETM3_PKT_VAL_NOT_TRACED:
+ case ETM3_PKT_BAD_TRACEMODE:
+ resp = OCSD_RESP_FATAL_INVALID_DATA;
+ throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,m_index_curr_pkt,m_CSID,"Invalid packet type : Data Tracing decode not supported.");
+ break;
+
+ // packet errors
+ case ETM3_PKT_BAD_SEQUENCE:
+ resp = OCSD_RESP_FATAL_INVALID_DATA;
+ throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,m_index_curr_pkt,m_CSID,"Bad Packet sequence.");
+ break;
+
+ default:
+ case ETM3_PKT_RESERVED:
+ resp = OCSD_RESP_FATAL_INVALID_DATA;
+ throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,m_index_curr_pkt,m_CSID,"Reserved or unknown packet ID.");
+ break;
+ }
+ m_curr_state = m_outputElemList.elemToSend() ? SEND_PKTS : DECODE_PKTS;
+ pktDone = !m_outputElemList.elemToSend();
+ }
+ catch(ocsdError &err)
+ {
+ LogError(err);
+ m_unsync_info = UNSYNC_BAD_PACKET;
+ resetDecoder(); // mark decoder as unsynced - dump any current state.
+ pktDone = true;
+ }
+ catch(...)
+ {
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_FAIL,m_index_curr_pkt,m_CSID,"Bad Packet sequence."));
+ resp = OCSD_RESP_FATAL_SYS_ERR;
+ m_unsync_info = UNSYNC_BAD_PACKET;
+ resetDecoder(); // mark decoder as unsynced - dump any current state.
+ pktDone = true;
+ }
+ return resp;
+}
+
+ocsd_datapath_resp_t TrcPktDecodeEtmV3::sendUnsyncPacket()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ OcsdTraceElement *pElem = 0;
+ try {
+ pElem = GetNextOpElem(resp);
+ pElem->setType(OCSD_GEN_TRC_ELEM_NO_SYNC);
+ pElem->setUnSyncEOTReason(m_unsync_info);
+ resp = m_outputElemList.sendElements();
+ }
+ catch(ocsdError &err)
+ {
+ LogError(err);
+ m_unsync_info = UNSYNC_BAD_PACKET;
+ resetDecoder(); // mark decoder as unsynced - dump any current state.
+ }
+ return resp;
+}
+
+void TrcPktDecodeEtmV3::setNeedAddr(bool bNeedAddr)
+{
+ m_bNeedAddr = bNeedAddr;
+ m_bSentUnknown = false;
+}
+
+ocsd_datapath_resp_t TrcPktDecodeEtmV3::processISync(const bool withCC, const bool firstSync /* = false */)
+{
+ // map ISync reason to generic reason codes.
+ static trace_on_reason_t on_map[] = { TRACE_ON_NORMAL, TRACE_ON_NORMAL,
+ TRACE_ON_OVERFLOW, TRACE_ON_EX_DEBUG };
+
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ bool ctxtUpdate = m_curr_packet_in->isCtxtUpdated();
+ OcsdTraceElement *pElem = 0;
+
+ try {
+
+ pElem = GetNextOpElem(resp);
+
+ if(firstSync || (m_curr_packet_in->getISyncReason() != iSync_Periodic))
+ {
+ pElem->setType(OCSD_GEN_TRC_ELEM_TRACE_ON);
+ pElem->setTraceOnReason(on_map[(int)m_curr_packet_in->getISyncReason()]);
+ pElem = GetNextOpElem(resp);
+ }
+
+ // look for context changes....
+ if(ctxtUpdate || firstSync)
+ {
+ // if not first time out, read existing context in output element,
+ // otherwise we are setting it new.
+ if(firstSync)
+ m_PeContext.resetCtxt();
+
+ if(m_curr_packet_in->isCtxtIDUpdated())
+ m_PeContext.setCtxtID(m_curr_packet_in->getCtxtID());
+ if(m_curr_packet_in->isVMIDUpdated())
+ m_PeContext.setVMID(m_curr_packet_in->getVMID());
+ if(m_curr_packet_in->isCtxtFlagsUpdated())
+ {
+ m_PeContext.setEL(m_curr_packet_in->isHyp() ? ocsd_EL2 : ocsd_EL_unknown);
+ m_PeContext.setSecLevel(m_curr_packet_in->isNS() ? ocsd_sec_nonsecure : ocsd_sec_secure);
+ }
+
+ // prepare the context packet
+ pElem->setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT);
+ pElem->setContext(m_PeContext);
+ pElem->setISA(m_curr_packet_in->ISA());
+
+ // with cycle count...
+ if(m_curr_packet_in->getISyncHasCC())
+ pElem->setCycleCount(m_curr_packet_in->getCycleCount());
+
+ }
+
+ // set ISync address - if it is a valid I address
+ if(!m_curr_packet_in->getISyncNoAddr())
+ {
+ if(m_curr_packet_in->getISyncIsLSiPAddr())
+ {
+ // TBD: handle extra data processing instruction for data trace
+ // need to output E atom relating to the data instruction
+ // rare - on start-up case.
+
+ // main instruction address saved in data address for this packet type.
+ m_IAddr = m_curr_packet_in->getDataAddr();
+ }
+ else
+ {
+ m_IAddr = m_curr_packet_in->getAddr();
+ }
+ setNeedAddr(false); // ready to process atoms.
+ }
+ m_curr_state = m_outputElemList.elemToSend() ? SEND_PKTS : DECODE_PKTS;
+ }
+ catch(ocsdError &err)
+ {
+ LogError(err);
+ m_unsync_info = UNSYNC_BAD_PACKET;
+ resetDecoder(); // mark decoder as unsynced - dump any current state.
+ }
+ return resp;
+}
+
+ocsd_datapath_resp_t TrcPktDecodeEtmV3::processBranchAddr()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ OcsdTraceElement *pElem = 0;
+ bool bUpdatePEContext = false;
+
+ // might need to cancel something ... if the last output was an instruction range or excep return
+ if(m_curr_packet_in->isExcepCancel())
+ m_outputElemList.cancelPendElem();
+ else
+ m_outputElemList.commitAllPendElem(); // otherwise commit any pending elements.
+
+ // record the address
+ m_IAddr = m_curr_packet_in->getAddr();
+ setNeedAddr(false); // no longer need an address.
+
+ // exception packet - may need additional output
+ if(m_curr_packet_in->isExcepPkt())
+ {
+ // exeception packet may have exception, context change, or both.
+ // check for context change
+ if(m_curr_packet_in->isCtxtUpdated())
+ {
+
+ ocsd_sec_level sec = m_curr_packet_in->isNS() ? ocsd_sec_nonsecure : ocsd_sec_secure;
+ if(sec != m_PeContext.getSecLevel())
+ {
+ m_PeContext.setSecLevel(sec);
+ bUpdatePEContext = true;
+ }
+ ocsd_ex_level pkt_el = m_curr_packet_in->isHyp() ? ocsd_EL2 : ocsd_EL_unknown;
+ if(pkt_el != m_PeContext.getEL())
+ {
+ m_PeContext.setEL(pkt_el);
+ bUpdatePEContext = true;
+ }
+ }
+
+ // now decide if we need to send any packets out.
+ try {
+
+ if(bUpdatePEContext)
+ {
+ pElem = GetNextOpElem(resp);
+ pElem->setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT);
+ pElem->setContext(m_PeContext);
+ }
+
+ // check for exception
+ if(m_curr_packet_in->excepNum() != 0)
+ {
+ pElem = GetNextOpElem(resp);
+ pElem->setType(OCSD_GEN_TRC_ELEM_EXCEPTION);
+ pElem->setExceptionNum(m_curr_packet_in->excepNum());
+ }
+
+ // finally - do we have anything to send yet?
+ m_curr_state = m_outputElemList.elemToSend() ? SEND_PKTS : DECODE_PKTS;
+ }
+ catch(ocsdError &err)
+ {
+ LogError(err);
+ m_unsync_info = UNSYNC_BAD_PACKET;
+ resetDecoder(); // mark decoder as unsynced - dump any current state.
+ }
+ }
+ return resp;
+}
+
+
+ocsd_datapath_resp_t TrcPktDecodeEtmV3::processPHdr()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ OcsdTraceElement *pElem = 0;
+ ocsd_isa isa;
+ Etmv3Atoms atoms(m_config->isCycleAcc());
+
+ atoms.initAtomPkt(m_curr_packet_in,m_index_curr_pkt);
+ isa = m_curr_packet_in->ISA();
+ m_code_follower.setMemSpaceAccess((m_PeContext.getSecLevel() == ocsd_sec_secure) ? OCSD_MEM_SPACE_S : OCSD_MEM_SPACE_N);
+
+ try
+ {
+ do
+ {
+ // if we do not have a valid address then send any cycle count elements
+ // and stop processing
+ if(m_bNeedAddr)
+ {
+ // output unknown address packet or a cycle count packet
+ if(!m_bSentUnknown || m_config->isCycleAcc())
+ {
+ pElem = GetNextOpElem(resp);
+ if(m_bSentUnknown || !atoms.numAtoms())
+ pElem->setType(OCSD_GEN_TRC_ELEM_CYCLE_COUNT);
+ else
+ pElem->setType(OCSD_GEN_TRC_ELEM_ADDR_UNKNOWN);
+ if(m_config->isCycleAcc())
+ pElem->setCycleCount(atoms.getRemainCC());
+ m_bSentUnknown = true;
+ }
+ atoms.clearAll(); // skip remaining atoms
+ }
+ else // have an address, can process atoms
+ {
+ pElem = GetNextOpElem(resp);
+ pElem->setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE);
+
+ // cycle accurate may have a cycle count to use
+ if(m_config->isCycleAcc())
+ {
+ // note: it is possible to have a CC only atom packet.
+ if(!atoms.numAtoms()) // override type if CC only
+ pElem->setType(OCSD_GEN_TRC_ELEM_CYCLE_COUNT);
+ // set cycle count
+ pElem->setCycleCount(atoms.getAtomCC());
+ }
+
+ // now process the atom
+ if(atoms.numAtoms())
+ {
+ m_code_follower.setISA(isa);
+ m_code_follower.followSingleAtom(m_IAddr,atoms.getCurrAtomVal());
+
+ // valid code range
+ if(m_code_follower.hasRange())
+ {
+ pElem->setAddrRange(m_IAddr,m_code_follower.getRangeEn());
+ pElem->setLastInstrInfo(atoms.getCurrAtomVal() == ATOM_E,
+ m_code_follower.getInstrType(),
+ m_code_follower.getInstrSubType(),m_code_follower.getInstrSize());
+ pElem->setLastInstrCond(m_code_follower.isCondInstr());
+ pElem->setISA(isa);
+ if(m_code_follower.hasNextAddr())
+ m_IAddr = m_code_follower.getNextAddr();
+ else
+ setNeedAddr(true);
+ }
+
+ // next address has new ISA?
+ if(m_code_follower.ISAChanged())
+ isa = m_code_follower.nextISA();
+
+ // there is a nacc
+ if(m_code_follower.isNacc())
+ {
+ if(m_code_follower.hasRange())
+ {
+ pElem = GetNextOpElem(resp);
+ pElem->setType(OCSD_GEN_TRC_ELEM_ADDR_NACC);
+ }
+ else
+ pElem->updateType(OCSD_GEN_TRC_ELEM_ADDR_NACC);
+ pElem->setAddrStart(m_code_follower.getNaccAddr());
+ setNeedAddr(true);
+ m_code_follower.clearNacc(); // we have generated some code for the nacc.
+ }
+ }
+
+ atoms.clearAtom(); // next atom
+ }
+ }
+ while(atoms.numAtoms());
+
+ // is tha last element an atom?
+ int numElem = m_outputElemList.getNumElem();
+ if(numElem >= 1)
+ {
+ // if the last thing is an instruction range, pend it - could be cancelled later.
+ if(m_outputElemList.getElemType(numElem-1) == OCSD_GEN_TRC_ELEM_INSTR_RANGE)
+ m_outputElemList.pendLastNElem(1);
+ }
+
+ // finally - do we have anything to send yet?
+ m_curr_state = m_outputElemList.elemToSend() ? SEND_PKTS : DECODE_PKTS;
+ }
+ catch(ocsdError &err)
+ {
+ LogError(err);
+ m_unsync_info = UNSYNC_BAD_PACKET;
+ resetDecoder(); // mark decoder as unsynced - dump any current state.
+ }
+ return resp;
+}
+
+// if v7M -> pend only ERET, if V7A/R pend ERET and prev instr.
+void TrcPktDecodeEtmV3::pendExceptionReturn()
+{
+ int pendElem = 1;
+ if(m_config->getCoreProfile() != profile_CortexM)
+ {
+ int nElem = m_outputElemList.getNumElem();
+ if(nElem > 1)
+ {
+ if(m_outputElemList.getElemType(nElem - 2) == OCSD_GEN_TRC_ELEM_INSTR_RANGE)
+ pendElem = 2; // need to pend instr+eret for A/R
+ }
+ }
+ m_outputElemList.pendLastNElem(pendElem);
+}
+
+/* End of File trc_pkt_decode_etmv3.cpp */
diff --git a/decoder/source/etmv3/trc_pkt_elem_etmv3.cpp b/decoder/source/etmv3/trc_pkt_elem_etmv3.cpp
new file mode 100644
index 0000000..74034c3
--- /dev/null
+++ b/decoder/source/etmv3/trc_pkt_elem_etmv3.cpp
@@ -0,0 +1,688 @@
+/*
+ * \file trc_pkt_elem_etmv3.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 <cstring>
+#include <sstream>
+#include <iomanip>
+
+#include "opencsd/etmv3/trc_pkt_elem_etmv3.h"
+
+EtmV3TrcPacket::EtmV3TrcPacket()
+{
+ m_pkt_data.addr.size = VA_32BIT; // etm v3 only handles 32 bit addresses.
+}
+
+EtmV3TrcPacket::~EtmV3TrcPacket()
+{
+}
+
+// update interface - set packet values
+
+// clear this packet info
+void EtmV3TrcPacket::Clear()
+{
+ // clear structure flags and counter elements etc, that work per packet.
+ // leave intra packet data unchanged
+ m_pkt_data.addr.pkt_bits = 0;
+ m_pkt_data.prev_isa = m_pkt_data.curr_isa; // mark ISA as not changed
+ m_pkt_data.exception.bits.present = 0;
+ m_pkt_data.atom.num = 0;
+ m_pkt_data.cycle_count = 0;
+ m_pkt_data.context.updated = 0;
+ m_pkt_data.context.updated_c = 0;
+ m_pkt_data.context.updated_v = 0;
+ m_pkt_data.data.ooo_tag = 0;
+ m_pkt_data.data.value = 0;
+ m_pkt_data.data.update_addr = 0;
+ m_pkt_data.data.update_be = 0;
+ m_pkt_data.data.update_dval = 0;
+ m_pkt_data.ts_update_bits = 0;
+ m_pkt_data.isync_info.has_cycle_count = 0;
+ m_pkt_data.isync_info.has_LSipAddress = 0;
+ m_pkt_data.isync_info.no_address = 0;
+}
+
+// reset all state including intra packet
+void EtmV3TrcPacket::ResetState()
+{
+ memset(&m_pkt_data,0,sizeof(ocsd_etmv3_pkt));
+ m_pkt_data.curr_isa = m_pkt_data.prev_isa = ocsd_isa_unknown;
+}
+
+void EtmV3TrcPacket::UpdateAddress(const ocsd_vaddr_t partAddrVal, const int updateBits)
+{
+ ocsd_vaddr_t validMask = OCSD_VA_MASK;
+ validMask >>= OCSD_MAX_VA_BITSIZE-updateBits;
+ m_pkt_data.addr.pkt_bits = updateBits;
+ m_pkt_data.addr.val &= ~validMask;
+ m_pkt_data.addr.val |= (partAddrVal & validMask);
+ if(updateBits > m_pkt_data.addr.valid_bits)
+ m_pkt_data.addr.valid_bits = updateBits;
+}
+
+void EtmV3TrcPacket::UpdateDataAddress(const uint32_t value, const uint8_t valid_bits)
+{
+ // ETMv3 data addresses 32 bits.
+ uint32_t validMask = 0xFFFFFFFF;
+ validMask >>= 32-valid_bits;
+ m_pkt_data.addr.pkt_bits = valid_bits;
+ m_pkt_data.addr.val &= ~validMask;
+ m_pkt_data.addr.val |= (value & validMask);
+ if(valid_bits > m_pkt_data.addr.valid_bits)
+ m_pkt_data.addr.valid_bits = valid_bits;
+ m_pkt_data.data.update_addr = 1;
+}
+
+void EtmV3TrcPacket::UpdateTimestamp(const uint64_t tsVal, const uint8_t updateBits)
+{
+ uint64_t validMask = ~0ULL;
+ validMask >>= 64-updateBits;
+ m_pkt_data.timestamp &= ~validMask;
+ m_pkt_data.timestamp |= (tsVal & validMask);
+ m_pkt_data.ts_update_bits = updateBits;
+}
+
+
+
+void EtmV3TrcPacket::SetException( const ocsd_armv7_exception type,
+ const uint16_t number,
+ const bool cancel,
+ const bool cm_type,
+ const int irq_n /*= 0*/,
+ const int resume /* = 0*/)
+{
+ // initial data
+ m_pkt_data.exception.bits.cancel = cancel ? 1 : 0;
+ m_pkt_data.exception.bits.cm_irq_n = irq_n;
+ m_pkt_data.exception.bits.cm_resume = resume;
+ m_pkt_data.exception.bits.cm_type = cm_type ? 1 : 0;
+ m_pkt_data.exception.number = number;
+ m_pkt_data.exception.type = type;
+
+ // mark as valid in this packet
+ m_pkt_data.exception.bits.present = 1;
+}
+
+bool EtmV3TrcPacket::UpdateAtomFromPHdr(const uint8_t pHdr, const bool cycleAccurate)
+{
+ bool bValid = true;
+ uint8_t E = 0, N = 0;
+ if(!cycleAccurate)
+ {
+ if((pHdr & 0x3) == 0x0)
+ {
+ E = ((pHdr >> 2) & 0xF);
+ N = (pHdr & 0x40) ? 1 : 0;
+ m_pkt_data.atom.num = E+N;
+ m_pkt_data.atom.En_bits = (((uint32_t)0x1) << E) - 1;
+ m_pkt_data.p_hdr_fmt = 1;
+ }
+ else if((pHdr & 0x3) == 0x2)
+ {
+ m_pkt_data.atom.num = 2;
+ m_pkt_data.p_hdr_fmt = 2;
+ m_pkt_data.atom.En_bits = (pHdr & 0x8 ? 0 : 1) | (pHdr & 0x4 ? 0 : 0x2);
+ }
+ else
+ bValid = false;
+ }
+ else
+ {
+ uint8_t pHdr_code = pHdr & 0xA3;
+ switch(pHdr_code)
+ {
+ case 0x80:
+ m_pkt_data.p_hdr_fmt = 1;
+ E = ((pHdr >> 2) & 0x7);
+ N = (pHdr & 0x40) ? 1 : 0;
+ m_pkt_data.atom.num = E+N;
+ if(m_pkt_data.atom.num)
+ {
+ m_pkt_data.atom.En_bits = (((uint32_t)0x1) << E) - 1;
+ m_pkt_data.cycle_count = E+N;
+ }
+ else
+ bValid = false; // deprecated 8b'10000000 code
+
+ break;
+
+ case 0x82:
+ m_pkt_data.p_hdr_fmt = 2;
+ if(pHdr & 0x10)
+ {
+ m_pkt_data.p_hdr_fmt = 4;
+ m_pkt_data.atom.num = 1;
+ m_pkt_data.cycle_count = 0;
+ m_pkt_data.atom.En_bits = pHdr & 0x04 ? 0 : 1;
+ }
+ else
+ {
+ m_pkt_data.atom.num = 2;
+ m_pkt_data.cycle_count = 1;
+ m_pkt_data.atom.En_bits = (pHdr & 0x8 ? 0 : 1) | (pHdr & 0x4 ? 0 : 0x2);
+ }
+ break;
+
+ case 0xA0:
+ m_pkt_data.p_hdr_fmt = 3;
+ m_pkt_data.cycle_count = ((pHdr >> 2) & 7) + 1;
+ E = pHdr & 0x40 ? 1 : 0;
+ m_pkt_data.atom.num = E;
+ m_pkt_data.atom.En_bits = E;
+ break;
+
+ default:
+ bValid = false;
+ break;
+
+ }
+ }
+ return bValid;
+}
+
+EtmV3TrcPacket &EtmV3TrcPacket::operator =(const ocsd_etmv3_pkt* p_pkt)
+{
+ m_pkt_data = *p_pkt;
+ return *this;
+}
+
+ // printing
+void EtmV3TrcPacket::toString(std::string &str) const
+{
+ const char *name;
+ const char *desc;
+ std::string valStr, ctxtStr = "";
+
+ name = packetTypeName(m_pkt_data.type, &desc);
+ str = name + (std::string)" : " + desc;
+
+ switch(m_pkt_data.type)
+ {
+ // print the original header type for the bad sequences.
+ case ETM3_PKT_BAD_SEQUENCE:
+ case ETM3_PKT_BAD_TRACEMODE:
+ name = packetTypeName(m_pkt_data.err_type,0);
+ str += "[" + (std::string)name + "]";
+ break;
+
+ case ETM3_PKT_BRANCH_ADDRESS:
+ getBranchAddressStr(valStr);
+ str += "; " + valStr;
+ break;
+
+ case ETM3_PKT_I_SYNC_CYCLE:
+ case ETM3_PKT_I_SYNC:
+ getISyncStr(valStr);
+ str += "; " + valStr;
+ break;
+
+ case ETM3_PKT_P_HDR:
+ getAtomStr(valStr);
+ str += "; " + valStr;
+ break;
+
+ case ETM3_PKT_CYCLE_COUNT:
+ {
+ std::ostringstream oss;
+ oss << "; Cycles=" << m_pkt_data.cycle_count;
+ str += oss.str();
+ }
+ break;
+
+ case ETM3_PKT_CONTEXT_ID:
+ {
+ std::ostringstream oss;
+ oss << "; CtxtID=" << std::hex << "0x" << m_pkt_data.context.ctxtID;
+ str += oss.str();
+ }
+ break;
+
+ case ETM3_PKT_VMID:
+ {
+ std::ostringstream oss;
+ oss << "; VMID=" << std::hex << "0x" << m_pkt_data.context.VMID;
+ str += oss.str();
+ }
+ break;
+
+ case ETM3_PKT_TIMESTAMP:
+ {
+ std::ostringstream oss;
+ oss << "; TS=" << std::hex << "0x" << m_pkt_data.timestamp << " (" << std::dec << m_pkt_data.timestamp << ") ";
+ str += oss.str();
+ }
+ break;
+
+ case ETM3_PKT_OOO_DATA:
+ {
+ std::ostringstream oss;
+ oss << "; Val=" << std::hex << "0x" << m_pkt_data.data.value;
+ oss << "; OO_Tag=" << std::hex << "0x" << m_pkt_data.data.ooo_tag;
+ str += oss.str();
+ }
+ break;
+
+ case ETM3_PKT_VAL_NOT_TRACED:
+ if(m_pkt_data.data.update_addr)
+ {
+ trcPrintableElem::getValStr(valStr,32, m_pkt_data.data.addr.valid_bits,
+ m_pkt_data.data.addr.val,true,m_pkt_data.data.addr.pkt_bits);
+ str += "; Addr=" + valStr;
+ }
+ break;
+
+ case ETM3_PKT_OOO_ADDR_PLC:
+ if(m_pkt_data.data.update_addr)
+ {
+ trcPrintableElem::getValStr(valStr,32, m_pkt_data.data.addr.valid_bits,
+ m_pkt_data.data.addr.val,true,m_pkt_data.data.addr.pkt_bits);
+ str += "; Addr=" + valStr;
+ }
+ {
+ std::ostringstream oss;
+ oss << "; OO_Tag=" << std::hex << "0x" << m_pkt_data.data.ooo_tag;
+ str += oss.str();
+ }
+ break;
+
+ case ETM3_PKT_NORM_DATA:
+ if(m_pkt_data.data.update_addr)
+ {
+ trcPrintableElem::getValStr(valStr,32, m_pkt_data.data.addr.valid_bits,
+ m_pkt_data.data.addr.val,true,m_pkt_data.data.addr.pkt_bits);
+ str += "; Addr=" + valStr;
+ }
+ if(m_pkt_data.data.update_dval)
+ {
+ std::ostringstream oss;
+ oss << "; Val=" << std::hex << "0x" << m_pkt_data.data.value;
+ str += oss.str();
+ }
+ break;
+ }
+}
+
+void EtmV3TrcPacket::toStringFmt(const uint32_t fmtFlags, std::string &str) const
+{
+ // no formatting implemented at present.
+ toString(str);
+}
+
+const char *EtmV3TrcPacket::packetTypeName(const ocsd_etmv3_pkt_type type, const char **ppDesc) const
+{
+ const char *pName = "I_RESERVED";
+ const char *pDesc = "Reserved Packet Header";
+
+ switch(type)
+ {
+// markers for unknown packets
+ // case ETM3_PKT_NOERROR:, //!< no error in packet - supplimentary data.
+ case ETM3_PKT_NOTSYNC: //!< no sync found yet
+ pName = "NOTSYNC";
+ pDesc = "Trace Stream not synchronised";
+ break;
+
+ case ETM3_PKT_INCOMPLETE_EOT: //!< flushing incomplete/empty packet at end of trace.
+ pName = "INCOMPLETE_EOT.";
+ pDesc = "Incomplete packet at end of trace data.";
+ break;
+
+// markers for valid packets
+ case ETM3_PKT_BRANCH_ADDRESS:
+ pName = "BRANCH_ADDRESS";
+ pDesc = "Branch address.";
+ break;
+
+ case ETM3_PKT_A_SYNC:
+ pName = "A_SYNC";
+ pDesc = "Alignment Synchronisation.";
+ break;
+
+ case ETM3_PKT_CYCLE_COUNT:
+ pName = "CYCLE_COUNT";
+ pDesc = "Cycle Count.";
+ break;
+
+ case ETM3_PKT_I_SYNC:
+ pName = "I_SYNC";
+ pDesc = "Instruction Packet synchronisation.";
+ break;
+
+ case ETM3_PKT_I_SYNC_CYCLE:
+ pName = "I_SYNC_CYCLE";
+ pDesc = "Instruction Packet synchronisation with cycle count.";
+ break;
+
+ case ETM3_PKT_TRIGGER:
+ pName = "TRIGGER";
+ pDesc = "Trace Trigger Event.";
+ break;
+
+ case ETM3_PKT_P_HDR:
+ pName = "P_HDR";
+ pDesc = "Atom P-header.";
+ break;
+
+ case ETM3_PKT_STORE_FAIL:
+ pName = "STORE_FAIL";
+ pDesc = "Data Store Failed.";
+ break;
+
+ case ETM3_PKT_OOO_DATA:
+ pName = "OOO_DATA";
+ pDesc = "Out of Order data value packet.";
+ break;
+
+ case ETM3_PKT_OOO_ADDR_PLC:
+ pName = "OOO_ADDR_PLC";
+ pDesc = "Out of Order data address placeholder.";
+ break;
+
+ case ETM3_PKT_NORM_DATA:
+ pName = "NORM_DATA";
+ pDesc = "Data trace packet.";
+ break;
+
+ case ETM3_PKT_DATA_SUPPRESSED:
+ pName = "DATA_SUPPRESSED";
+ pDesc = "Data trace suppressed.";
+ break;
+
+ case ETM3_PKT_VAL_NOT_TRACED:
+ pName = "VAL_NOT_TRACED";
+ pDesc = "Data trace value not traced.";
+ break;
+
+ case ETM3_PKT_IGNORE:
+ pName = "IGNORE";
+ pDesc = "Packet ignored.";
+ break;
+
+ case ETM3_PKT_CONTEXT_ID:
+ pName = "CONTEXT_ID";
+ pDesc = "Context ID change.";
+ break;
+
+ case ETM3_PKT_VMID:
+ pName = "VMID";
+ pDesc = "VMID change.";
+ break;
+
+ case ETM3_PKT_EXCEPTION_ENTRY:
+ pName = "EXCEPTION_ENTRY";
+ pDesc = "Exception entry data marker.";
+ break;
+
+ case ETM3_PKT_EXCEPTION_EXIT:
+ pName = "EXCEPTION_EXIT";
+ pDesc = "Exception return.";
+ break;
+
+ case ETM3_PKT_TIMESTAMP:
+ pName = "TIMESTAMP";
+ pDesc = "Timestamp Value.";
+ break;
+
+// internal processing types
+ // case ETM3_PKT_BRANCH_OR_BYPASS_EOT: not externalised
+
+// packet errors
+ case ETM3_PKT_BAD_SEQUENCE:
+ pName = "BAD_SEQUENCE";
+ pDesc = "Invalid sequence for packet type.";
+ break;
+
+ case ETM3_PKT_BAD_TRACEMODE:
+ pName = "BAD_TRACEMODE";
+ pDesc = "Invalid packet type for this trace mode.";
+ break;
+
+ // leave thest unchanged.
+ case ETM3_PKT_RESERVED:
+ default:
+ break;
+
+ }
+
+ if(ppDesc) *ppDesc = pDesc;
+ return pName;
+}
+
+void EtmV3TrcPacket::getBranchAddressStr(std::string &valStr) const
+{
+ std::ostringstream oss;
+ std::string subStr;
+
+ // print address.
+ trcPrintableElem::getValStr(subStr,32,m_pkt_data.addr.valid_bits,
+ m_pkt_data.addr.val,true,m_pkt_data.addr.pkt_bits);
+ oss << "Addr=" << subStr << "; ";
+
+ // current ISA if changed.
+ if(m_pkt_data.curr_isa != m_pkt_data.prev_isa)
+ {
+ getISAStr(subStr);
+ oss << subStr;
+ }
+
+ // S / NS etc if changed.
+ if(m_pkt_data.context.updated)
+ {
+ oss << (m_pkt_data.context.curr_NS ? "NS; " : "S; ");
+ oss << (m_pkt_data.context.curr_Hyp ? "Hyp; " : "");
+ }
+
+ // exception?
+ if(m_pkt_data.exception.bits.present)
+ {
+ getExcepStr(subStr);
+ oss << subStr;
+ }
+ valStr = oss.str();
+}
+
+void EtmV3TrcPacket::getAtomStr(std::string &valStr) const
+{
+ std::ostringstream oss;
+ uint32_t bitpattern = m_pkt_data.atom.En_bits; // arranged LSBit oldest, MSbit newest
+
+ if(!m_pkt_data.cycle_count)
+ {
+ for(int i = 0; i < m_pkt_data.atom.num; i++)
+ {
+ oss << ((bitpattern & 0x1) ? "E" : "N"); // in spec read L->R, oldest->newest
+ bitpattern >>= 1;
+ }
+ }
+ else
+ {
+ switch(m_pkt_data.p_hdr_fmt)
+ {
+ case 1:
+ for(int i = 0; i < m_pkt_data.atom.num; i++)
+ {
+ oss << ((bitpattern & 0x1) ? "WE" : "WN"); // in spec read L->R, oldest->newest
+ bitpattern >>= 1;
+ }
+ break;
+
+ case 2:
+ oss << "W";
+ for(int i = 0; i < m_pkt_data.atom.num; i++)
+ {
+ oss << ((bitpattern & 0x1) ? "E" : "N"); // in spec read L->R, oldest->newest
+ bitpattern >>= 1;
+ }
+ break;
+
+ case 3:
+ for(uint32_t i = 0; i < m_pkt_data.cycle_count; i++)
+ oss << "W";
+ if(m_pkt_data.atom.num)
+ oss << ((bitpattern & 0x1) ? "E" : "N"); // in spec read L->R, oldest->newest
+ break;
+ }
+ oss << "; Cycles=" << m_pkt_data.cycle_count;
+ }
+ valStr = oss.str();
+}
+
+void EtmV3TrcPacket::getISyncStr(std::string &valStr) const
+{
+ std::ostringstream oss;
+ static const char *reason[] = { "Periodic", "Trace Enable", "Restart Overflow", "Debug Exit" };
+
+ // reason.
+ oss << "(" << reason[(int)m_pkt_data.isync_info.reason] << "); ";
+
+ // full address.
+ if(!m_pkt_data.isync_info.no_address)
+ {
+ if(m_pkt_data.isync_info.has_LSipAddress)
+ oss << "Data Instr Addr=0x";
+ else
+ oss << "Addr=0x";
+ oss << std::hex << std::setfill('0') << std::setw(8) << m_pkt_data.addr.val << "; ";
+ }
+
+ oss << (m_pkt_data.context.curr_NS ? "NS; " : "S; ");
+ oss << (m_pkt_data.context.curr_Hyp ? "Hyp; " : " ");
+
+ if(m_pkt_data.context.updated_c)
+ {
+ oss << "CtxtID=" << std::hex << m_pkt_data.context.ctxtID << "; ";
+ }
+
+ if(m_pkt_data.isync_info.no_address)
+ {
+ valStr = oss.str();
+ return; // bail out at this point if a data only ISYNC
+ }
+
+ std::string isaStr;
+ getISAStr(isaStr);
+ oss << isaStr;
+
+ if(m_pkt_data.isync_info.has_cycle_count)
+ {
+ oss << "Cycles=" << std::dec << m_pkt_data.cycle_count << "; ";
+ }
+
+ if(m_pkt_data.isync_info.has_LSipAddress)
+ {
+ std::string addrStr;
+
+ // extract address updata.
+ trcPrintableElem::getValStr(addrStr,32,m_pkt_data.data.addr.valid_bits,
+ m_pkt_data.data.addr.val,true,m_pkt_data.data.addr.pkt_bits);
+ oss << "Curr Instr Addr=" << addrStr << ";";
+ }
+ valStr = oss.str();
+}
+
+void EtmV3TrcPacket::getISAStr(std::string &isaStr) const
+{
+ std::ostringstream oss;
+ oss << "ISA=";
+ switch(m_pkt_data.curr_isa)
+ {
+ case ocsd_isa_arm:
+ oss << "ARM(32); ";
+ break;
+
+ case ocsd_isa_thumb2:
+ oss << "Thumb2; ";
+ break;
+
+ case ocsd_isa_aarch64:
+ oss << "AArch64; ";
+ break;
+
+ case ocsd_isa_tee:
+ oss << "ThumbEE; ";
+ break;
+
+ case ocsd_isa_jazelle:
+ oss << "Jazelle; ";
+ break;
+
+ default:
+ case ocsd_isa_unknown:
+ oss << "Unknown; ";
+ break;
+ }
+ isaStr = oss.str();
+}
+
+void EtmV3TrcPacket::getExcepStr(std::string &excepStr) const
+{
+ static const char *ARv7Excep[] = {
+ "No Exception", "Debug Halt", "SMC", "Hyp",
+ "Async Data Abort", "Jazelle", "Reserved", "Reserved",
+ "PE Reset", "Undefined Instr", "SVC", "Prefetch Abort",
+ "Data Fault", "Generic", "IRQ", "FIQ"
+ };
+
+ static const char *MExcep[] = {
+ "No Exception", "IRQ1", "IRQ2", "IRQ3",
+ "IRQ4", "IRQ5", "IRQ6", "IRQ7",
+ "IRQ0","usage Fault","NMI","SVC",
+ "DebugMonitor", "Mem Manage","PendSV","SysTick",
+ "Reserved","PE Reset","Reserved","HardFault",
+ "Reserved","BusFault","Reserved","Reserved"
+ };
+
+ std::ostringstream oss;
+ oss << "Exception=";
+
+ if(m_pkt_data.exception.bits.cm_type)
+ {
+ if(m_pkt_data.exception.number < 0x18)
+ oss << MExcep[m_pkt_data.exception.number];
+ else
+ oss << "IRQ" << std::dec << (m_pkt_data.exception.number - 0x10);
+ if(m_pkt_data.exception.bits.cm_resume)
+ oss << "; Resume=" << m_pkt_data.exception.bits.cm_resume;
+ if(m_pkt_data.exception.bits.cancel)
+ oss << "; Cancel prev instr";
+ }
+ else
+ {
+ oss << ARv7Excep[m_pkt_data.exception.number] << "; ";
+ if(m_pkt_data.exception.bits.cancel)
+ oss << "; Cancel prev instr";
+ }
+ excepStr = oss.str();
+}
+/* End of File trc_pkt_elem_etmv3.cpp */
diff --git a/decoder/source/etmv3/trc_pkt_proc_etmv3.cpp b/decoder/source/etmv3/trc_pkt_proc_etmv3.cpp
new file mode 100644
index 0000000..7871619
--- /dev/null
+++ b/decoder/source/etmv3/trc_pkt_proc_etmv3.cpp
@@ -0,0 +1,122 @@
+/*
+ * \file trc_pkt_proc_etmv3.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/etmv3/trc_pkt_proc_etmv3.h"
+#include "trc_pkt_proc_etmv3_impl.h"
+#include "common/ocsd_error.h"
+
+#ifdef __GNUC__
+// G++ doesn't like the ## pasting
+#define ETMV3_PKTS_NAME "PKTP_ETMV3"
+#else
+#define ETMV3_PKTS_NAME OCSD_CMPNAME_PREFIX_PKTPROC##"_"##OCSD_BUILTIN_DCD_ETMV3
+#endif
+
+static const uint32_t ETMV3_SUPPORTED_OP_FLAGS = OCSD_OPFLG_PKTPROC_COMMON |
+ ETMV3_OPFLG_UNFORMATTED_SOURCE;
+
+TrcPktProcEtmV3::TrcPktProcEtmV3() : TrcPktProcBase(ETMV3_PKTS_NAME),
+ m_pProcessor(0)
+{
+ m_supported_op_flags = ETMV3_SUPPORTED_OP_FLAGS;
+}
+
+TrcPktProcEtmV3::TrcPktProcEtmV3(int instIDNum) : TrcPktProcBase(ETMV3_PKTS_NAME, instIDNum),
+ m_pProcessor(0)
+{
+ m_supported_op_flags = ETMV3_SUPPORTED_OP_FLAGS;
+}
+
+TrcPktProcEtmV3::~TrcPktProcEtmV3()
+{
+ if(m_pProcessor)
+ delete m_pProcessor;
+ m_pProcessor = 0;
+}
+
+ocsd_err_t TrcPktProcEtmV3::onProtocolConfig()
+{
+ if(m_pProcessor == 0)
+ {
+ m_pProcessor = new (std::nothrow) EtmV3PktProcImpl();
+ if(m_pProcessor == 0)
+ {
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_MEM));
+ return OCSD_ERR_MEM;
+ }
+ m_pProcessor->Initialise(this);
+ }
+ return m_pProcessor->Configure(m_config);
+}
+
+ocsd_datapath_resp_t TrcPktProcEtmV3::processData( const ocsd_trc_index_t index,
+ const uint32_t dataBlockSize,
+ const uint8_t *pDataBlock,
+ uint32_t *numBytesProcessed)
+{
+ if(m_pProcessor)
+ return m_pProcessor->processData(index,dataBlockSize,pDataBlock,numBytesProcessed);
+ return OCSD_RESP_FATAL_NOT_INIT;
+}
+
+ocsd_datapath_resp_t TrcPktProcEtmV3::onEOT()
+{
+ if(m_pProcessor)
+ return m_pProcessor->onEOT();
+ return OCSD_RESP_FATAL_NOT_INIT;
+}
+
+ocsd_datapath_resp_t TrcPktProcEtmV3::onReset()
+{
+ if(m_pProcessor)
+ return m_pProcessor->onReset();
+ return OCSD_RESP_FATAL_NOT_INIT;
+}
+
+ocsd_datapath_resp_t TrcPktProcEtmV3::onFlush()
+{
+ if(m_pProcessor)
+ return m_pProcessor->onFlush();
+ return OCSD_RESP_FATAL_NOT_INIT;
+}
+
+const bool TrcPktProcEtmV3::isBadPacket() const
+{
+ if(m_pProcessor)
+ return m_pProcessor->isBadPacket();
+ return false;
+}
+
+/* End of File trc_pkt_proc_etmv3.cpp */
diff --git a/decoder/source/etmv3/trc_pkt_proc_etmv3_impl.cpp b/decoder/source/etmv3/trc_pkt_proc_etmv3_impl.cpp
new file mode 100644
index 0000000..fc39a5e
--- /dev/null
+++ b/decoder/source/etmv3/trc_pkt_proc_etmv3_impl.cpp
@@ -0,0 +1,1224 @@
+/*
+ * \file trc_pkt_proc_etmv3_impl.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 "trc_pkt_proc_etmv3_impl.h"
+
+EtmV3PktProcImpl::EtmV3PktProcImpl() :
+ m_isInit(false),
+ m_interface(0)
+{
+}
+
+EtmV3PktProcImpl::~EtmV3PktProcImpl()
+{
+}
+
+ocsd_err_t EtmV3PktProcImpl::Configure(const EtmV3Config *p_config)
+{
+ ocsd_err_t err = OCSD_OK;
+ if(p_config != 0)
+ {
+ m_config = *p_config;
+ m_chanIDCopy = m_config.getTraceID();
+ }
+ else
+ {
+ err = OCSD_ERR_INVALID_PARAM_VAL;
+ if(m_isInit)
+ m_interface->LogError(ocsdError(OCSD_ERR_SEV_ERROR,err));
+ }
+ return err;
+}
+
+ocsd_datapath_resp_t EtmV3PktProcImpl::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;
+ m_bytesProcessed = 0;
+
+ while( ( (m_bytesProcessed < dataBlockSize) ||
+ ((m_bytesProcessed == dataBlockSize) && (m_process_state == SEND_PKT)) )
+ && OCSD_DATA_RESP_IS_CONT(resp))
+ {
+ try
+ {
+ switch(m_process_state)
+ {
+ case WAIT_SYNC:
+ if(!m_bStartOfSync)
+ m_packet_index = index + m_bytesProcessed;
+ m_bytesProcessed += waitForSync(dataBlockSize-m_bytesProcessed,pDataBlock+m_bytesProcessed);
+ break;
+
+ case PROC_HDR:
+ m_packet_index = index + m_bytesProcessed;
+ processHeaderByte(pDataBlock[m_bytesProcessed++]);
+ break;
+
+ case PROC_DATA:
+ processPayloadByte(pDataBlock [m_bytesProcessed++]);
+ break;
+
+ case SEND_PKT:
+ resp = outputPacket();
+ break;
+ }
+ }
+ catch(ocsdError &err)
+ {
+ m_interface->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.
+ m_process_state = SEND_PKT;
+ }
+ else
+ {
+ // bail out on any other error.
+ resp = OCSD_RESP_FATAL_INVALID_DATA;
+ }
+ }
+ catch(...)
+ {
+ /// vv bad at this point.
+ resp = OCSD_RESP_FATAL_SYS_ERR;
+ ocsdError fatal = ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_FAIL,m_packet_index,m_chanIDCopy);
+ fatal.setMessage("Unknown System Error decoding trace.");
+ m_interface->LogError(fatal);
+ }
+ }
+
+ *numBytesProcessed = m_bytesProcessed;
+ return resp;
+}
+
+ocsd_datapath_resp_t EtmV3PktProcImpl::onEOT()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ // if we have a partial packet then send to attached sinks
+ if(m_currPacketData.size() != 0)
+ {
+ // TBD: m_curr_packet.updateErrType(ETM4_ETM3_PKT_I_INCOMPLETE_EOT);
+ resp = outputPacket();
+ InitPacketState();
+ }
+ return resp;
+}
+
+ocsd_datapath_resp_t EtmV3PktProcImpl::onReset()
+{
+ InitProcessorState();
+ return OCSD_RESP_CONT;
+}
+
+ocsd_datapath_resp_t EtmV3PktProcImpl::onFlush()
+{
+ // packet processor never holds on to flushable data (may have partial packet,
+ // but any full packets are immediately sent)
+ return OCSD_RESP_CONT;
+}
+
+void EtmV3PktProcImpl::Initialise(TrcPktProcEtmV3 *p_interface)
+{
+ if(p_interface)
+ {
+ m_interface = p_interface;
+ m_isInit = true;
+
+ }
+ InitProcessorState();
+ /* not using pattern matcher for sync at present
+ static const uint8_t a_sync[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 };
+ m_syncMatch.setPattern(a_sync, sizeof(a_sync));*/
+}
+
+void EtmV3PktProcImpl::InitProcessorState()
+{
+ m_bStreamSync = false; // not synced
+ m_process_state = WAIT_SYNC; // waiting for sync
+ m_bStartOfSync = false; // not seen start of sync packet
+ m_curr_packet.ResetState(); // reset intra packet state
+ InitPacketState(); // set curr packet state
+ m_bSendPartPkt = false;
+}
+
+void EtmV3PktProcImpl::InitPacketState()
+{
+ m_bytesExpectedThisPkt = 0;
+ m_BranchPktNeedsException = false;
+ m_bIsync_got_cycle_cnt = false;
+ m_bIsync_get_LSiP_addr = false;
+ m_IsyncInfoIdx = false;
+ m_bExpectingDataAddress = false;
+ m_bFoundDataAddress = false;
+ m_currPacketData.clear();
+ m_currPktIdx = 0; // index into processed bytes in current packet
+ m_curr_packet.Clear();
+
+}
+
+ocsd_datapath_resp_t EtmV3PktProcImpl::outputPacket()
+{
+ ocsd_datapath_resp_t dp_resp = OCSD_RESP_FATAL_NOT_INIT;
+ if(m_isInit)
+ {
+ ocsd_etmv3_pkt_type type = m_curr_packet.getType();
+ if(!m_bSendPartPkt)
+ {
+ dp_resp = m_interface->outputOnAllInterfaces(m_packet_index,&m_curr_packet,&type,m_currPacketData);
+ m_process_state = m_bStreamSync ? PROC_HDR : WAIT_SYNC; // need a header next time, or still waiting to sync.
+ m_currPacketData.clear();
+ }
+ else
+ {
+ // sending part packet, still some data in the main packet
+ dp_resp = m_interface->outputOnAllInterfaces(m_packet_index,&m_curr_packet,&type,m_partPktData);
+ m_process_state = m_post_part_pkt_state;
+ m_packet_index += m_partPktData.size();
+ m_bSendPartPkt = false;
+ m_curr_packet.SetType(m_post_part_pkt_type);
+ }
+ }
+ return dp_resp;
+}
+
+void EtmV3PktProcImpl::setBytesPartPkt(int numBytes, process_state nextState, const ocsd_etmv3_pkt_type nextType)
+{
+ m_partPktData.clear();
+ for(int i=0; i < numBytes; i++)
+ {
+ m_partPktData.push_back(m_currPacketData[i]);
+ }
+ m_currPacketData.erase(m_currPacketData.begin(), m_currPacketData.begin()+numBytes);
+ m_bSendPartPkt = true;
+ m_post_part_pkt_state = nextState;
+ m_post_part_pkt_type = nextType;
+}
+
+uint32_t EtmV3PktProcImpl::waitForSync(const uint32_t dataBlockSize, const uint8_t *pDataBlock)
+{
+ uint8_t currByte;
+ uint32_t bytesProcessed = 0;
+ bool bSendBlock = false;
+
+ // need to wait for the first sync packet
+ while(!bSendBlock && (bytesProcessed < dataBlockSize))
+ {
+ currByte = pDataBlock[bytesProcessed++];
+ // TBD: forced sync point
+
+ if(m_bStartOfSync)
+ {
+ // need to handle consecutive 0 bytes followed by genuine A-SYNC.
+
+ m_currPacketData.push_back(currByte);
+ if((currByte == 0x80) && (m_currPacketData.size() >= 6))
+ {
+ // it is a sync packet possibly with leading zeros
+ bSendBlock = true;
+ if(m_currPacketData.size() > 6)
+ {
+ m_currPacketData.pop_back();
+ bytesProcessed--; // return 0x80 to the input buffer to re-process next pass after stripping 0's
+ setBytesPartPkt(m_currPacketData.size()-5,WAIT_SYNC,ETM3_PKT_NOTSYNC);
+ }
+ else
+ {
+ m_bStreamSync = true;
+ m_curr_packet.SetType(ETM3_PKT_A_SYNC);
+ }
+ }
+ else if(currByte != 0x00)
+ {
+ m_bStartOfSync = false; // not a sync packet
+ }
+ else if(m_currPacketData.size() >= 13) // 13 0's, strip 8 of them...
+ {
+ setBytesPartPkt(8,WAIT_SYNC,ETM3_PKT_NOTSYNC);
+ bSendBlock = true;
+ }
+ }
+ else // not seen a start of sync candidate yet
+ {
+ if(currByte == 0x00) // could be the start of a-sync
+ {
+ if(m_currPacketData.size() == 0)
+ {
+ m_currPacketData.push_back(currByte);
+ m_bStartOfSync = true;
+ }
+ else
+ {
+ bytesProcessed--;
+ bSendBlock = true; // send none sync packet data, re-process this byte next time.
+ m_curr_packet.SetType(ETM3_PKT_NOTSYNC); // send unsynced data packet.
+ }
+ }
+ else
+ {
+ //save a byte - not start of a-sync
+ m_currPacketData.push_back(currByte);
+
+ // done all data in this block, or got 16 unsynced bytes
+ if((bytesProcessed == dataBlockSize) || (m_currPacketData.size() == 16))
+ {
+ bSendBlock = true; // send none sync packet block
+ m_curr_packet.SetType(ETM3_PKT_NOTSYNC); // send unsynced data packet.
+ }
+ }
+ }
+ }
+ if(bSendBlock)
+ SendPacket();
+ return bytesProcessed;
+}
+
+ocsd_err_t EtmV3PktProcImpl::processHeaderByte(uint8_t by)
+{
+ InitPacketState(); // new packet, clear old single packet state (retains intra packet state).
+
+ // save byte
+ m_currPacketData.push_back(by);
+
+ m_process_state = PROC_DATA; // assume next is data packet
+
+ // check for branch address 0bCxxxxxxx1
+ if((by & 0x01) == 0x01 ) {
+ m_curr_packet.SetType(ETM3_PKT_BRANCH_ADDRESS);
+ m_BranchPktNeedsException = false;
+ if((by & 0x80) != 0x80) {
+ // no continuation - 1 byte branch same in alt and std...
+ if((by == 0x01) && (m_interface->getComponentOpMode() & ETMV3_OPFLG_UNFORMATTED_SOURCE))
+ {
+ // TBD: need to fix up for handling bypassed ETM stream at some point.
+ throwUnsupportedErr("Bypassed ETM stream not supported in this version of the decoder.");
+ // could be EOTrace marker from bypassed formatter
+ m_curr_packet.SetType(ETM3_PKT_BRANCH_OR_BYPASS_EOT);
+ }
+ else
+ {
+ OnBranchAddress();
+ SendPacket(); // mark ready to send.
+ }
+ }
+ }
+ // check for p-header - 0b1xxxxxx0
+ else if((by & 0x81) == 0x80) {
+ m_curr_packet.SetType(ETM3_PKT_P_HDR);
+ if(m_curr_packet.UpdateAtomFromPHdr(by,m_config.isCycleAcc()))
+ SendPacket();
+ else
+ throwPacketHeaderErr("Invalid P-Header.");
+ }
+ // check 0b0000xx00 group
+ else if((by & 0xF3) == 0x00) {
+
+ // A-Sync
+ if(by == 0x00) {
+ m_curr_packet.SetType(ETM3_PKT_A_SYNC);
+ }
+ // cycle count
+ else if(by == 0x04) {
+ m_curr_packet.SetType(ETM3_PKT_CYCLE_COUNT);
+ }
+ // I-Sync
+ else if(by == 0x08) {
+ m_curr_packet.SetType(ETM3_PKT_I_SYNC);
+ m_bIsync_got_cycle_cnt = false;
+ m_bIsync_get_LSiP_addr = false;
+ }
+ // trigger
+ else if(by == 0x0C) {
+ m_curr_packet.SetType(ETM3_PKT_TRIGGER);
+ // no payload - just send it.
+ SendPacket();
+ }
+ }
+ // check remaining 0bxxxxxx00 codes
+ else if((by & 0x03 )== 0x00) {
+ // OoO data 0b0xx0xx00
+ if((by & 0x93 )== 0x00) {
+ if(!m_config.isDataValTrace()) {
+ m_curr_packet.SetErrType(ETM3_PKT_BAD_TRACEMODE);
+ throwPacketHeaderErr("Invalid data trace header (out of order data) - not tracing data values.");
+ }
+ m_curr_packet.SetType(ETM3_PKT_OOO_DATA);
+ uint8_t size = ((by & 0x0C) >> 2);
+ // header contains a count of the data to follow
+ // size 3 == 4 bytes, other sizes == size bytes
+ if(size == 0)
+ {
+ m_curr_packet.SetDataOOOTag((by >> 5) & 0x3);
+ m_curr_packet.SetDataValue(0);
+ SendPacket();
+ }
+ else
+ m_bytesExpectedThisPkt = (short)(1 + ((size == 3) ? 4 : size));
+ }
+ // I-Sync + cycle count
+ else if(by == 0x70) {
+ m_curr_packet.SetType(ETM3_PKT_I_SYNC_CYCLE);
+ m_bIsync_got_cycle_cnt = false;
+ m_bIsync_get_LSiP_addr = false;
+ }
+ // store failed
+ else if(by == 0x50) {
+ if(!m_config.isDataValTrace())
+ {
+ m_curr_packet.SetErrType(ETM3_PKT_BAD_TRACEMODE);
+ throwPacketHeaderErr("Invalid data trace header (store failed) - not tracing data values.");
+ }
+ m_curr_packet.SetType(ETM3_PKT_STORE_FAIL);
+ SendPacket();
+ }
+ // OoO placeholder 0b01x1xx00
+ else if((by & 0xD3 )== 0x50) {
+ m_curr_packet.SetType(ETM3_PKT_OOO_ADDR_PLC);
+ if(!m_config.isDataTrace())
+ {
+ m_curr_packet.SetErrType(ETM3_PKT_BAD_TRACEMODE);
+ throwPacketHeaderErr("Invalid data trace header (out of order placeholder) - not tracing data.");
+ }
+ // expecting data address if flagged and address tracing enabled (flag can be set even if address tracing disabled)
+ m_bExpectingDataAddress = ((by & DATA_ADDR_EXPECTED_FLAG) == DATA_ADDR_EXPECTED_FLAG) && m_config.isDataAddrTrace();
+ m_bFoundDataAddress = false;
+ m_curr_packet.SetDataOOOTag((by >> 2) & 0x3);
+ if(!m_bExpectingDataAddress) {
+ SendPacket();
+ }
+ }
+ // vmid 0b00111100
+ else if(by == 0x3c) {
+ m_curr_packet.SetType(ETM3_PKT_VMID);
+ }
+ else
+ {
+ m_curr_packet.SetErrType(ETM3_PKT_RESERVED);
+ throwPacketHeaderErr("Packet header reserved encoding");
+ }
+ }
+ // normal data 0b00x0xx10
+ else if((by & 0xD3 )== 0x02) {
+ uint8_t size = ((by & 0x0C) >> 2);
+ if(!m_config.isDataTrace()) {
+ m_curr_packet.SetErrType(ETM3_PKT_BAD_TRACEMODE);
+ throwPacketHeaderErr("Invalid data trace header (normal data) - not tracing data.");
+ }
+ m_curr_packet.SetType(ETM3_PKT_NORM_DATA);
+ m_bExpectingDataAddress = ((by & DATA_ADDR_EXPECTED_FLAG) == DATA_ADDR_EXPECTED_FLAG) && m_config.isDataAddrTrace();
+ m_bFoundDataAddress = false;
+
+ // set this with the data bytes expected this packet, plus the header byte.
+ m_bytesExpectedThisPkt = (short)( 1 + ((size == 3) ? 4 : size));
+ if(!m_bExpectingDataAddress && (m_bytesExpectedThisPkt == 1)) {
+ // single byte data packet, value = 0;
+ m_curr_packet.SetDataValue(0);
+ SendPacket();
+ }
+
+ }
+ // data suppressed 0b01100010
+ else if(by == 0x62) {
+ if(!m_config.isDataTrace())
+ {
+ m_curr_packet.SetErrType(ETM3_PKT_BAD_TRACEMODE);
+ throwPacketHeaderErr("Invalid data trace header (data suppressed) - not tracing data.");
+ }
+ m_curr_packet.SetType(ETM3_PKT_DATA_SUPPRESSED);
+ SendPacket();
+ }
+ // value not traced 0b011x1010
+ else if((by & 0xEF )== 0x6A) {
+ if(!m_config.isDataTrace()) {
+ m_curr_packet.SetErrType(ETM3_PKT_BAD_TRACEMODE);
+ throwPacketHeaderErr("Invalid data trace header (value not traced) - not tracing data.");
+ }
+ m_curr_packet.SetType(ETM3_PKT_VAL_NOT_TRACED);
+ m_bExpectingDataAddress = ((by & DATA_ADDR_EXPECTED_FLAG) == DATA_ADDR_EXPECTED_FLAG) && m_config.isDataAddrTrace();
+ m_bFoundDataAddress = false;
+ if(!m_bExpectingDataAddress) {
+ SendPacket();
+ }
+ }
+ // ignore 0b01100110
+ else if(by == 0x66) {
+ m_curr_packet.SetType(ETM3_PKT_IGNORE);
+ SendPacket();
+ }
+ // context ID 0b01101110
+ else if(by == 0x6E) {
+ m_curr_packet.SetType(ETM3_PKT_CONTEXT_ID);
+ m_bytesExpectedThisPkt = (short)(1 + m_config.CtxtIDBytes());
+ }
+ // exception return 0b01110110
+ else if(by == 0x76) {
+ m_curr_packet.SetType(ETM3_PKT_EXCEPTION_EXIT);
+ SendPacket();
+ }
+ // exception entry 0b01111110
+ else if(by == 0x7E) {
+ m_curr_packet.SetType(ETM3_PKT_EXCEPTION_ENTRY);
+ SendPacket();
+ }
+ // timestamp packet 0b01000x10
+ else if((by & 0xFB )== 0x42)
+ {
+ m_curr_packet.SetType(ETM3_PKT_TIMESTAMP);
+ }
+ else
+ {
+ m_curr_packet.SetErrType(ETM3_PKT_RESERVED);
+ throwPacketHeaderErr("Packet header reserved encoding.");
+ }
+ return OCSD_OK;
+}
+
+ocsd_err_t EtmV3PktProcImpl::processPayloadByte(uint8_t by)
+{
+ bool bTopBitSet = false;
+ bool packetDone = false;
+
+ // pop byte into buffer
+ m_currPacketData.push_back(by);
+
+ switch(m_curr_packet.getType()) {
+ default:
+ throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_PKT_INTERP_FAIL,m_packet_index,m_chanIDCopy,"Interpreter failed - cannot process payload for unexpected or unsupported packet.");
+ break;
+
+ case ETM3_PKT_BRANCH_ADDRESS:
+ bTopBitSet = (bool)((by & 0x80) == 0x80);
+ if(m_config.isAltBranch()) // etm implements the alternative branch encoding
+ {
+ if(!bTopBitSet) // no continuation
+ {
+ if(!m_BranchPktNeedsException)
+ {
+ if((by & 0xC0) == 0x40)
+ m_BranchPktNeedsException = true;
+ else
+ packetDone = true;
+ }
+ else
+ packetDone = true;
+ }
+ }
+ else
+ {
+ // standard encoding < 5 bytes cannot be exception branch
+ // 5 byte packet
+ if(m_currPacketData.size() == 5) {
+ if((by & 0xC0) == 0x40)
+ // expecting follow up byte(s)
+ m_BranchPktNeedsException = true;
+ else
+ packetDone = true;
+ }
+ // waiting for exception packet
+ else if(m_BranchPktNeedsException){
+ if(!bTopBitSet)
+ packetDone = true;
+ }
+ else {
+ // not exception - end of packets
+ if(!bTopBitSet)
+ packetDone = true;
+ }
+ }
+
+ if(packetDone)
+ {
+ OnBranchAddress();
+ SendPacket();
+ }
+ break;
+
+ case ETM3_PKT_BRANCH_OR_BYPASS_EOT:
+ /*
+ if((by != 0x00) || ( m_currPacketData.size() == ETM3_PKT_BUFF_SIZE)) {
+ if(by == 0x80 && ( m_currPacketData.size() == 7)) {
+ // branch 0 followed by A-sync!
+ m_currPacketData.size() = 1;
+ m_curr_packet.SetType(ETM3_PKT_BRANCH_ADDRESS;
+ SendPacket();
+ memcpy(m_currPacketData, &m_currPacketData[1],6);
+ m_currPacketData.size() = 6;
+ m_curr_packet.SetType(ETM3_PKT_A_SYNC;
+ SendPacket();
+ }
+ else if( m_currPacketData.size() == 2) {
+ // branch followed by another byte
+ m_currPacketData.size() = 1;
+ m_curr_packet.SetType(ETM3_PKT_BRANCH_ADDRESS;
+ SendPacket();
+ ProcessHeaderByte(by);
+ }
+ else if(by == 0x00) {
+ // end of buffer...output something - incomplete / unknown.
+ SendPacket();
+ }
+ else if(by == 0x01) {
+ // 0x01 - 0x00 x N - 0x1
+ // end of buffer...output something
+ m_currPacketData.size()--;
+ SendPacket();
+ ProcessHeaderByte(by);
+ }
+ else {
+ // branch followed by unknown sequence
+ int oldidx = m_currPacketData.size();
+ m_currPacketData.size() = 1;
+ m_curr_packet.SetType(ETM3_PKT_BRANCH_ADDRESS;
+ SendPacket();
+ oldidx--;
+ memcpy(m_currPacketData, &m_currPacketData[1],oldidx);
+ m_currPacketData.size() = oldidx;
+ SendBadPacket("ERROR : unknown sequence");
+ }
+ }*/
+ // just ignore zeros
+ break;
+
+
+
+ case ETM3_PKT_A_SYNC:
+ if(by == 0x00) {
+ if( m_currPacketData.size() > 5) {
+ // extra 0, need to lose one
+
+ // set error type
+ m_curr_packet.SetErrType(ETM3_PKT_BAD_SEQUENCE);
+ // mark extra 0 for sending, retain remaining, restart in A-SYNC processing mode.
+ setBytesPartPkt(1,PROC_DATA,ETM3_PKT_A_SYNC);
+ throwMalformedPacketErr("A-Sync ?: Extra 0x00 in sequence");
+ }
+ }
+ else if((by == 0x80) && ( m_currPacketData.size() == 6)) {
+ SendPacket();
+ m_bStreamSync = true;
+ }
+ else
+ {
+ m_curr_packet.SetErrType(ETM3_PKT_BAD_SEQUENCE);
+ m_bytesProcessed--; // remove the last byte from the number processed to re-try
+ m_currPacketData.pop_back(); // remove the last byte processed from the packet
+ throwMalformedPacketErr("A-Sync ? : Unexpected byte in sequence");
+ }
+ break;
+
+ case ETM3_PKT_CYCLE_COUNT:
+ bTopBitSet = ((by & 0x80) == 0x80);
+ if(!bTopBitSet || ( m_currPacketData.size() >= 6)) {
+ m_currPktIdx = 1;
+ m_curr_packet.SetCycleCount(extractCycleCount());
+ SendPacket();
+ }
+ break;
+
+ case ETM3_PKT_I_SYNC_CYCLE:
+ if(!m_bIsync_got_cycle_cnt) {
+ if(((by & 0x80) != 0x80) || ( m_currPacketData.size() >= 6)) {
+ m_bIsync_got_cycle_cnt = true;
+ }
+ break;
+ }
+ // fall through when we have the first non-cycle count byte
+ case ETM3_PKT_I_SYNC:
+ if(m_bytesExpectedThisPkt == 0) {
+ int cycCountBytes = m_currPacketData.size() - 2;
+ int ctxtIDBytes = m_config.CtxtIDBytes();
+ // bytes expected = header + n x ctxt id + info byte + 4 x addr;
+ if(m_config.isInstrTrace())
+ m_bytesExpectedThisPkt = cycCountBytes + 6 + ctxtIDBytes;
+ else
+ m_bytesExpectedThisPkt = 2 + ctxtIDBytes;
+ m_IsyncInfoIdx = 1 + cycCountBytes + ctxtIDBytes;
+ }
+ if(( m_currPacketData.size() - 1) == (unsigned)m_IsyncInfoIdx) {
+ m_bIsync_get_LSiP_addr = ((m_currPacketData[m_IsyncInfoIdx] & 0x80) == 0x80);
+ }
+
+ // if bytes collected >= bytes expected
+ if( m_currPacketData.size() >= m_bytesExpectedThisPkt) {
+ // if we still need the LSip Addr, then this is not part of the expected
+ // count as we have no idea how long it is
+ if(m_bIsync_get_LSiP_addr) {
+ if((by & 0x80) != 0x80) {
+ OnISyncPacket();
+ }
+ }
+ else {
+ // otherwise, output now
+ OnISyncPacket();
+ }
+ }
+ break;
+
+ case ETM3_PKT_NORM_DATA:
+ if(m_bExpectingDataAddress && !m_bFoundDataAddress) {
+ // look for end of continuation bits
+ if((by & 0x80) != 0x80) {
+ m_bFoundDataAddress = true;
+ // add on the bytes we have found for the address to the expected data bytes
+ m_bytesExpectedThisPkt += ( m_currPacketData.size() - 1);
+ }
+ else
+ break;
+ }
+ // found any data address we were expecting
+ else if(m_bytesExpectedThisPkt == m_currPacketData.size()) {
+ m_currPktIdx = 1;
+ if(m_bExpectingDataAddress)
+ {
+ uint8_t bits = 0, beVal = 0;
+ bool updateBE = false;
+ uint32_t dataAddress = extractDataAddress(bits,updateBE,beVal);
+ m_curr_packet.UpdateDataAddress(dataAddress, bits);
+ if(updateBE)
+ m_curr_packet.UpdateDataEndian(beVal);
+ }
+ m_curr_packet.SetDataValue(extractDataValue((m_currPacketData[0] >> 2) & 0x3));
+ SendPacket();
+ }
+ break;
+
+ case ETM3_PKT_OOO_DATA:
+ if(m_bytesExpectedThisPkt == m_currPacketData.size())
+ {
+ m_currPktIdx = 1;
+ m_curr_packet.SetDataValue(extractDataValue((m_currPacketData[0] >> 2) & 0x3));
+ m_curr_packet.SetDataOOOTag((m_currPacketData[0] >> 5) & 0x3);
+ SendPacket();
+ }
+ if(m_bytesExpectedThisPkt < m_currPacketData.size())
+ throwMalformedPacketErr("Malformed out of order data packet.");
+ break;
+
+ // both these expect an address only.
+ case ETM3_PKT_VAL_NOT_TRACED:
+ case ETM3_PKT_OOO_ADDR_PLC: // we set the tag earlier.
+ if(m_bExpectingDataAddress) {
+ // look for end of continuation bits
+ if((by & 0x80) != 0x80) {
+ uint8_t bits = 0, beVal = 0;
+ bool updateBE = false;
+ m_currPktIdx = 1;
+ uint32_t dataAddress = extractDataAddress(bits,updateBE,beVal);
+ m_curr_packet.UpdateDataAddress(dataAddress, bits);
+ if(updateBE)
+ m_curr_packet.UpdateDataEndian(beVal);
+ SendPacket();
+ }
+ }
+ break;
+
+ case ETM3_PKT_CONTEXT_ID:
+ if(m_bytesExpectedThisPkt == m_currPacketData.size()) {
+ m_currPktIdx = 1;
+ m_curr_packet.UpdateContextID(extractCtxtID());
+ SendPacket();
+ }
+ if(m_bytesExpectedThisPkt < m_currPacketData.size())
+ throwMalformedPacketErr("Malformed context id packet.");
+ break;
+
+ case ETM3_PKT_TIMESTAMP:
+ if((by & 0x80) != 0x80) {
+ uint8_t tsBits = 0;
+ m_currPktIdx = 1;
+ uint64_t tsVal = extractTimestamp(tsBits);
+ m_curr_packet.UpdateTimestamp(tsVal,tsBits);
+ SendPacket();
+ }
+ break;
+
+ case ETM3_PKT_VMID:
+ // single byte payload
+ m_curr_packet.UpdateVMID(by);
+ SendPacket();
+ break;
+ }
+
+ return OCSD_OK;
+}
+
+// extract branch address packet at current location in packet data.
+void EtmV3PktProcImpl::OnBranchAddress()
+{
+ int validBits = 0;
+ ocsd_vaddr_t partAddr = 0;
+
+ partAddr = extractBrAddrPkt(validBits);
+ m_curr_packet.UpdateAddress(partAddr,validBits);
+}
+
+uint32_t EtmV3PktProcImpl::extractBrAddrPkt(int &nBitsOut)
+{
+ static int addrshift[] = {
+ 2, // ARM_ISA
+ 1, // thumb
+ 1, // thumb EE
+ 0 // jazelle
+ };
+
+ static uint8_t addrMask[] = { // byte 5 masks
+ 0x7, // ARM_ISA
+ 0xF, // thumb
+ 0xF, // thumb EE
+ 0x1F // jazelle
+ };
+
+ static int addrBits[] = { // address bits in byte 5
+ 3, // ARM_ISA
+ 4, // thumb
+ 4, // thumb EE
+ 5 // jazelle
+ };
+
+ static ocsd_armv7_exception exceptionTypeARMdeprecated[] = {
+ Excp_Reset,
+ Excp_IRQ,
+ Excp_Reserved,
+ Excp_Reserved,
+ Excp_Jazelle,
+ Excp_FIQ,
+ Excp_AsyncDAbort,
+ Excp_DebugHalt
+ };
+
+ bool CBit = true;
+ int bytecount = 0;
+ int bitcount = 0;
+ int shift = 0;
+ int isa_idx = 0;
+ uint32_t value = 0;
+ uint8_t addrbyte;
+ bool byte5AddrUpdate = false;
+
+ while(CBit && bytecount < 4)
+ {
+ checkPktLimits();
+ addrbyte = m_currPacketData[m_currPktIdx++];
+ CBit = (bool)((addrbyte & 0x80) != 0);
+ shift = bitcount;
+ if(bytecount == 0)
+ {
+ addrbyte &= ~0x81;
+ bitcount+=6;
+ addrbyte >>= 1;
+ }
+ else
+ {
+ // bytes 2-4, no continuation, alt format uses bit 6 to indicate following exception bytes
+ if(m_config.isAltBranch() && !CBit)
+ {
+ // last compressed address byte with exception
+ if((addrbyte & 0x40) == 0x40)
+ extractExceptionData();
+ addrbyte &= 0x3F;
+ bitcount+=6;
+ }
+ else
+ {
+ addrbyte &= 0x7F;
+ bitcount+=7;
+ }
+ }
+ value |= ((uint32_t)addrbyte) << shift;
+ bytecount++;
+ }
+
+ // byte 5 - indicates following exception bytes (or not!)
+ if(CBit)
+ {
+ checkPktLimits();
+ addrbyte = m_currPacketData[m_currPktIdx++];
+
+ // deprecated original byte 5 encoding - ARM state exception only
+ if(addrbyte & 0x80)
+ {
+ uint8_t excep_num = (addrbyte >> 3) & 0x7;
+ m_curr_packet.UpdateISA(ocsd_isa_arm);
+ m_curr_packet.SetException(exceptionTypeARMdeprecated[excep_num], excep_num, (addrbyte & 0x40) ? true : false,m_config.isV7MArch());
+ }
+ else
+ // normal 5 byte branch, or uses exception bytes.
+ {
+ // go grab the exception bits to correctly interpret the ISA state
+ if((addrbyte & 0x40) == 0x40)
+ extractExceptionData();
+
+ if((addrbyte & 0xB8) == 0x08)
+ m_curr_packet.UpdateISA(ocsd_isa_arm);
+ else if ((addrbyte & 0xB0) == 0x10)
+ m_curr_packet.UpdateISA(m_curr_packet.AltISA() ? ocsd_isa_tee : ocsd_isa_thumb2);
+ else if ((addrbyte & 0xA0) == 0x20)
+ m_curr_packet.UpdateISA(ocsd_isa_jazelle);
+ else
+ throwMalformedPacketErr("Malformed Packet - Unknown ISA.");
+ }
+
+ byte5AddrUpdate = true; // need to update the address value from byte 5
+ }
+
+ // figure out the correct ISA shifts for the address bits
+ switch(m_curr_packet.ISA())
+ {
+ case ocsd_isa_thumb2: isa_idx = 1; break;
+ case ocsd_isa_tee: isa_idx = 2; break;
+ case ocsd_isa_jazelle: isa_idx = 3; break;
+ default: break;
+ }
+
+ if(byte5AddrUpdate)
+ {
+ value |= ((uint32_t)(addrbyte & addrMask[isa_idx])) << bitcount;
+ bitcount += addrBits[isa_idx];
+ }
+
+ // finally align according to ISA
+ shift = addrshift[isa_idx];
+ value <<= shift;
+ bitcount += shift;
+
+ nBitsOut = bitcount;
+ return value;
+}
+
+// extract exception data from bytes after address.
+void EtmV3PktProcImpl::extractExceptionData()
+{
+ static const ocsd_armv7_exception exceptionTypesStd[] = {
+ Excp_NoException, Excp_DebugHalt, Excp_SMC, Excp_Hyp,
+ Excp_AsyncDAbort, Excp_Jazelle, Excp_Reserved, Excp_Reserved,
+ Excp_Reset, Excp_Undef, Excp_SVC, Excp_PrefAbort,
+ Excp_SyncDataAbort, Excp_Generic, Excp_IRQ, Excp_FIQ
+ };
+
+ static const ocsd_armv7_exception exceptionTypesCM[] = {
+ Excp_NoException, Excp_CMIRQn, Excp_CMIRQn, Excp_CMIRQn,
+ Excp_CMIRQn, Excp_CMIRQn, Excp_CMIRQn, Excp_CMIRQn,
+ Excp_CMIRQn, Excp_CMUsageFault, Excp_CMNMI, Excp_SVC,
+ Excp_CMDebugMonitor, Excp_CMMemManage, Excp_CMPendSV, Excp_CMSysTick,
+ Excp_Reserved, Excp_Reset, Excp_Reserved, Excp_CMHardFault,
+ Excp_Reserved, Excp_CMBusFault, Excp_Reserved, Excp_Reserved
+ };
+
+ uint16_t exceptionNum = 0;
+ ocsd_armv7_exception excep_type = Excp_Reserved;
+ int resume = 0;
+ int irq_n = 0;
+ bool cancel_prev_instr = 0;
+ bool Byte2 = false;
+
+ checkPktLimits();
+
+ //**** exception info Byte 0
+ uint8_t dataByte = m_currPacketData[m_currPktIdx++];
+
+ m_curr_packet.UpdateNS(dataByte & 0x1);
+ exceptionNum |= (dataByte >> 1) & 0xF;
+ cancel_prev_instr = (dataByte & 0x20) ? true : false;
+ m_curr_packet.UpdateAltISA(((dataByte & 0x40) != 0) ? 1 : 0);
+
+ //** another byte?
+ if(dataByte & 0x80)
+ {
+ checkPktLimits();
+ dataByte = m_currPacketData[m_currPktIdx++];
+
+ if(dataByte & 0x40)
+ Byte2 = true; //** immediate info byte 2, skipping 1
+ else
+ {
+ //**** exception info Byte 1
+ if(m_config.isV7MArch())
+ {
+ exceptionNum |= ((uint16_t)(dataByte & 0x1F)) << 4;
+ }
+ m_curr_packet.UpdateHyp(dataByte & 0x20 ? 1 : 0);
+
+ if(dataByte & 0x80)
+ {
+ checkPktLimits();
+ dataByte = m_currPacketData[m_currPktIdx++];
+ Byte2 = true;
+ }
+ }
+ //**** exception info Byte 2
+ if(Byte2)
+ {
+ resume = dataByte & 0xF;
+ }
+ }
+
+ // set the exception type - according to the number and core profile
+ if(m_config.isV7MArch())
+ {
+ exceptionNum &= 0x1FF;
+ if(exceptionNum < 0x018)
+ excep_type= exceptionTypesCM[exceptionNum];
+ else
+ excep_type = Excp_CMIRQn;
+
+ if(excep_type == Excp_CMIRQn)
+ {
+ if(exceptionNum > 0x018)
+ irq_n = exceptionNum - 0x10;
+ else if(exceptionNum == 0x008)
+ irq_n = 0;
+ else
+ irq_n = exceptionNum;
+ }
+ }
+ else
+ {
+ exceptionNum &= 0xF;
+ excep_type = exceptionTypesStd[exceptionNum];
+ }
+ m_curr_packet.SetException(excep_type, exceptionNum, cancel_prev_instr,m_config.isV7MArch(), irq_n,resume);
+}
+
+void EtmV3PktProcImpl::checkPktLimits()
+{
+ // index running off the end of the packet means a malformed packet.
+ if(m_currPktIdx >= m_currPacketData.size())
+ throwMalformedPacketErr("Malformed Packet - oversized packet.");
+}
+
+uint32_t EtmV3PktProcImpl::extractCtxtID()
+{
+ uint32_t ctxtID = 0;
+ int size = m_config.CtxtIDBytes();
+
+ // check we have enough data
+ if((m_currPktIdx + size) > m_currPacketData.size())
+ throwMalformedPacketErr("Too few bytes to extract context ID.");
+
+ switch(size)
+ {
+ case 1:
+ ctxtID = (uint32_t)m_currPacketData[m_currPktIdx];
+ m_currPktIdx++;
+ break;
+
+ case 2:
+ ctxtID = (uint32_t)m_currPacketData[m_currPktIdx]
+ | ((uint32_t)m_currPacketData[m_currPktIdx+1]) << 8;
+ m_currPktIdx+=2;
+ break;
+
+ case 4:
+ ctxtID = (uint32_t)m_currPacketData[m_currPktIdx]
+ | ((uint32_t)m_currPacketData[m_currPktIdx+1]) << 8
+ | ((uint32_t)m_currPacketData[m_currPktIdx+2]) << 16
+ | ((uint32_t)m_currPacketData[m_currPktIdx+3]) << 24;
+ m_currPktIdx+=4;
+ break;
+ }
+ return ctxtID;
+}
+
+uint64_t EtmV3PktProcImpl::extractTimestamp(uint8_t &tsBits)
+{
+ uint64_t ts = 0;
+ unsigned tsMaxBytes = m_config.TSPkt64() ? 9 : 7;
+ unsigned tsCurrBytes = 0;
+ bool bCont = true;
+ uint8_t mask = 0x7F;
+ uint8_t last_mask = m_config.TSPkt64() ? 0xFF : 0x3F;
+ uint8_t ts_iter_bits = 7;
+ uint8_t ts_last_iter_bits = m_config.TSPkt64() ? 8 : 6;
+ uint8_t currByte;
+ tsBits = 0;
+
+ while((tsCurrBytes < tsMaxBytes) && bCont)
+ {
+ if(m_currPacketData.size() < (m_currPktIdx + tsCurrBytes + 1))
+ throwMalformedPacketErr("Insufficient bytes to extract timestamp.");
+
+ currByte = m_currPacketData[m_currPktIdx+tsCurrBytes];
+ ts |= ((uint64_t)(currByte & mask)) << (7 * tsCurrBytes);
+ tsCurrBytes++;
+ tsBits += ts_iter_bits;
+ bCont = ((0x80 & currByte) == 0x80);
+ if(tsCurrBytes == (tsMaxBytes - 1))
+ {
+ mask = last_mask;
+ ts_iter_bits = ts_last_iter_bits;
+ }
+ }
+ m_currPktIdx += tsCurrBytes;
+ return ts;
+}
+
+
+uint32_t EtmV3PktProcImpl::extractDataAddress(uint8_t &bits, bool &updateBE, uint8_t &beVal)
+{
+ uint32_t dataAddr = 0;
+ int bytesIdx = 0;
+ bool bCont = true;
+ uint8_t currByte = 0;
+
+ updateBE = false;
+ bits = 0;
+
+ while(bCont)
+ {
+ checkPktLimits();
+ currByte = m_currPacketData[m_currPktIdx++] & ((bytesIdx == 4) ? 0x0F : 0x7F);
+ dataAddr |= (((uint32_t)currByte) << (bytesIdx * 7));
+ bCont = ((currByte & 0x80) == 0x80);
+ if(bytesIdx == 4)
+ {
+ bits += 4;
+ updateBE = true;
+ beVal = ((currByte >> 4) & 0x1);
+ bCont = false;
+ }
+ else
+ bits+=7;
+ bytesIdx++;
+ }
+ return dataAddr;
+}
+
+uint32_t EtmV3PktProcImpl::extractDataValue(const int dataByteSize)
+{
+ static int bytesReqTable[] = { 0,1,2,4 };
+
+ uint32_t dataVal = 0;
+ int bytesUsed = 0;
+ int bytesReq = bytesReqTable[dataByteSize & 0x3];
+ while(bytesUsed < bytesReq)
+ {
+ checkPktLimits();
+ dataVal |= (((uint32_t)m_currPacketData[m_currPktIdx++]) << (bytesUsed * 8));
+ bytesUsed++;
+ }
+ return dataVal;
+}
+
+
+uint32_t EtmV3PktProcImpl::extractCycleCount()
+{
+ uint32_t cycleCount = 0;
+ int byteIdx = 0;
+ uint8_t mask = 0x7F;
+ bool bCond = true;
+ uint8_t currByte = 0;
+
+ while(bCond)
+ {
+ checkPktLimits();
+ currByte = m_currPacketData[m_currPktIdx++];
+ cycleCount |= ((uint32_t)(currByte & mask)) << (7 * byteIdx);
+ bCond = ((currByte & 0x80) == 0x80);
+ byteIdx++;
+
+ if(byteIdx == 4)
+ mask = 0x0F;
+
+ if(byteIdx == 5)
+ bCond = false;
+ }
+ return cycleCount;
+}
+
+void EtmV3PktProcImpl::OnISyncPacket()
+{
+ uint8_t iSyncInfoByte = 0;
+ uint32_t instrAddr = 0, LSiPAddr = 0;
+ int LSiPBits = 0;
+ uint8_t T = 0, J = 0, AltISA = 0;
+
+ m_currPktIdx = 1;
+ if(m_bIsync_got_cycle_cnt)
+ {
+ m_curr_packet.SetCycleCount(extractCycleCount());
+ m_curr_packet.SetISyncHasCC();
+ }
+
+ if(m_config.CtxtIDBytes() != 0)
+ {
+ m_curr_packet.UpdateContextID(extractCtxtID());
+ }
+
+ // extract context info
+ iSyncInfoByte = m_currPacketData[m_currPktIdx++];
+ m_curr_packet.SetISyncReason((ocsd_iSync_reason)((iSyncInfoByte >> 5) & 0x3));
+ J = (iSyncInfoByte >> 4) & 0x1;
+ AltISA = m_config.MinorRev() >= 3 ? (iSyncInfoByte >> 2) & 0x1 : 0;
+ m_curr_packet.UpdateNS((iSyncInfoByte >> 3) & 0x1);
+ if(m_config.hasVirtExt())
+ m_curr_packet.UpdateHyp((iSyncInfoByte >> 1) & 0x1);
+
+ // main address value - full 32 bit address value
+ if(m_config.isInstrTrace())
+ {
+ for(int i = 0; i < 4; i++)
+ instrAddr |= ((uint32_t)m_currPacketData[m_currPktIdx++]) << (8*i);
+ T = instrAddr & 0x1; // get the T bit.
+ instrAddr &= ~0x1; // remove from address.
+ m_curr_packet.UpdateAddress(instrAddr,32);
+
+ // enough data now to set the instruction set.
+ ocsd_isa currISA = ocsd_isa_arm;
+ if(J)
+ currISA = ocsd_isa_jazelle;
+ else if(T)
+ currISA = AltISA ? ocsd_isa_tee : ocsd_isa_thumb2;
+ m_curr_packet.UpdateISA(currISA);
+
+ // possible follow up address value - rarely uses unless trace enabled during
+ // load and store instruction executing on top of other instruction.
+ if(m_bIsync_get_LSiP_addr)
+ {
+ LSiPAddr = extractBrAddrPkt(LSiPBits);
+ // follow up address value is compressed relative to the main value
+ // we store this in the data address value temporarily.
+ m_curr_packet.UpdateDataAddress(instrAddr,32);
+ m_curr_packet.UpdateDataAddress(LSiPAddr,LSiPBits);
+ }
+ }
+ else
+ m_curr_packet.SetISyncNoAddr();
+
+ SendPacket(); // mark ready to send
+}
+
+/* End of File trc_pkt_proc_etmv3_impl.cpp */
diff --git a/decoder/source/etmv3/trc_pkt_proc_etmv3_impl.h b/decoder/source/etmv3/trc_pkt_proc_etmv3_impl.h
new file mode 100644
index 0000000..a8e4fd1
--- /dev/null
+++ b/decoder/source/etmv3/trc_pkt_proc_etmv3_impl.h
@@ -0,0 +1,175 @@
+/*
+ * \file trc_pkt_proc_etmv3_impl.h
+ * \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.
+ */
+
+#ifndef ARM_TRC_PKT_PROC_ETMV3_IMPL_H_INCLUDED
+#define ARM_TRC_PKT_PROC_ETMV3_IMPL_H_INCLUDED
+
+#include "opencsd/etmv3/trc_pkt_proc_etmv3.h"
+#include "opencsd/etmv3/trc_cmp_cfg_etmv3.h"
+#include "opencsd/etmv3/trc_pkt_elem_etmv3.h"
+
+#define MAX_PACKET_SIZE 32
+#define ASYNC_SIZE 6
+
+class EtmV3PktProcImpl
+{
+public:
+ EtmV3PktProcImpl();
+ ~EtmV3PktProcImpl();
+
+ void Initialise(TrcPktProcEtmV3 *p_interface);
+
+ ocsd_err_t Configure(const EtmV3Config *p_config);
+
+
+ ocsd_datapath_resp_t processData( const ocsd_trc_index_t index,
+ const uint32_t dataBlockSize,
+ const uint8_t *pDataBlock,
+ uint32_t *numBytesProcessed);
+ ocsd_datapath_resp_t onEOT();
+ ocsd_datapath_resp_t onReset();
+ ocsd_datapath_resp_t onFlush();
+ const bool isBadPacket() const;
+
+protected:
+ typedef enum _process_state {
+ WAIT_SYNC,
+ PROC_HDR,
+ PROC_DATA,
+ SEND_PKT,
+ PROC_ERR,
+ } process_state;
+
+ process_state m_process_state;
+
+
+ void InitPacketState(); // clear current packet state.
+ void InitProcessorState(); // clear all previous process state
+
+ // byte processing
+
+ uint32_t waitForSync(const uint32_t dataBlockSize, const uint8_t *pDataBlock); //!< look for sync, return none-sync bytes processed.
+ ocsd_err_t processHeaderByte(uint8_t by);
+ ocsd_err_t processPayloadByte(uint8_t by);
+
+ // packet handling - main routines
+ void OnBranchAddress();
+ void OnISyncPacket();
+ uint32_t extractCtxtID();
+ uint64_t extractTimestamp(uint8_t &tsBits);
+ uint32_t extractDataAddress(uint8_t &bits, bool &updateBE, uint8_t &beVal);
+ uint32_t extractDataValue(const int dataByteSize);
+ uint32_t extractCycleCount();
+
+ // packet handling - helper routines
+ uint32_t extractBrAddrPkt(int &nBitsOut);
+ void extractExceptionData();
+ void checkPktLimits();
+ void setBytesPartPkt(const int numBytes, const process_state nextState, const ocsd_etmv3_pkt_type nextType); // set first n bytes from current packet to be sent via alt packet.
+
+ // packet output
+ void SendPacket(); // mark state for packet output
+ ocsd_datapath_resp_t outputPacket(); // output a packet
+
+ // bad packets
+ void throwMalformedPacketErr(const char *pszErrMsg);
+ void throwPacketHeaderErr(const char *pszErrMsg);
+ void throwUnsupportedErr(const char *pszErrMsg);
+
+ uint32_t m_bytesProcessed; // bytes processed by the process data routine (index into input buffer)
+ std::vector<uint8_t> m_currPacketData; // raw data
+ uint32_t m_currPktIdx; // index into packet when expanding
+ EtmV3TrcPacket m_curr_packet; // expanded packet
+
+ std::vector<uint8_t> m_partPktData; // raw data when we need to split a packet.
+ bool m_bSendPartPkt; // mark the part packet as the one we send.
+ process_state m_post_part_pkt_state; // state to set after part packet set
+ ocsd_etmv3_pkt_type m_post_part_pkt_type; // reset the packet type.
+
+ // process state
+ bool m_bStreamSync; //!< true if we have synced this stream
+ bool m_bStartOfSync; //!< true if we have a start of sync.
+
+ // packet state
+ uint32_t m_bytesExpectedThisPkt; // used by some of the variable packet length types.
+ bool m_BranchPktNeedsException;
+ bool m_bIsync_got_cycle_cnt;
+ bool m_bIsync_get_LSiP_addr;
+ int m_IsyncInfoIdx;
+ bool m_bExpectingDataAddress;
+ bool m_bFoundDataAddress;
+
+ ocsd_trc_index_t m_packet_index; // index of the start of the current packet
+ ocsd_trc_index_t m_packet_curr_byte_index; // index of the current byte.
+
+ bool m_isInit;
+ TrcPktProcEtmV3 *m_interface; /**< The interface to the other decode components */
+
+ EtmV3Config m_config;
+
+ uint8_t m_chanIDCopy;
+};
+
+
+inline void EtmV3PktProcImpl::SendPacket()
+{
+ m_process_state = SEND_PKT;
+}
+
+inline void EtmV3PktProcImpl::throwMalformedPacketErr(const char *pszErrMsg)
+{
+ throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,m_packet_index,m_chanIDCopy,pszErrMsg);
+}
+
+inline void EtmV3PktProcImpl::throwPacketHeaderErr(const char *pszErrMsg)
+{
+ throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_INVALID_PCKT_HDR,m_packet_index,m_chanIDCopy,pszErrMsg);
+}
+
+inline void EtmV3PktProcImpl::throwUnsupportedErr(const char *pszErrMsg)
+{
+ throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,m_packet_index,m_chanIDCopy,pszErrMsg);
+}
+
+
+inline const bool EtmV3PktProcImpl::isBadPacket() const
+{
+ return m_curr_packet.isBadPacket();
+}
+
+
+#endif // ARM_TRC_PKT_PROC_ETMV3_IMPL_H_INCLUDED
+
+/* End of File trc_pkt_proc_etmv3_impl.h */