| /*! |
| * \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 */ |