summaryrefslogtreecommitdiffstats
path: root/decoder/source/etmv3/trc_pkt_decode_etmv3.cpp
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/etmv3/trc_pkt_decode_etmv3.cpp
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/etmv3/trc_pkt_decode_etmv3.cpp')
-rw-r--r--decoder/source/etmv3/trc_pkt_decode_etmv3.cpp681
1 files changed, 681 insertions, 0 deletions
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 */