diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 07:24:57 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 07:24:57 +0000 |
commit | 070852d8604cece0c31f28ff3eb8d21d9ba415fb (patch) | |
tree | 9097175a6a5b8b7e37af9a96269ac0b61a0189cd /decoder/source/etmv3/trc_pkt_decode_etmv3.cpp | |
parent | Initial commit. (diff) | |
download | libopencsd-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.cpp | 681 |
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 */ |