summaryrefslogtreecommitdiffstats
path: root/decoder/source/ptm/trc_pkt_decode_ptm.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/ptm/trc_pkt_decode_ptm.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/ptm/trc_pkt_decode_ptm.cpp')
-rw-r--r--decoder/source/ptm/trc_pkt_decode_ptm.cpp671
1 files changed, 671 insertions, 0 deletions
diff --git a/decoder/source/ptm/trc_pkt_decode_ptm.cpp b/decoder/source/ptm/trc_pkt_decode_ptm.cpp
new file mode 100644
index 0000000..7abee84
--- /dev/null
+++ b/decoder/source/ptm/trc_pkt_decode_ptm.cpp
@@ -0,0 +1,671 @@
+/*
+ * \file trc_pkt_decode_ptm.cpp
+ * \brief OpenCSD : PTM packet decoder.
+ *
+ * \copyright Copyright (c) 2016, ARM Limited. All Rights Reserved.
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sstream>
+#include "opencsd/ptm/trc_pkt_decode_ptm.h"
+
+#define DCD_NAME "DCD_PTM"
+
+TrcPktDecodePtm::TrcPktDecodePtm()
+ : TrcPktDecodeBase(DCD_NAME)
+{
+ initDecoder();
+}
+
+TrcPktDecodePtm::TrcPktDecodePtm(int instIDNum)
+ : TrcPktDecodeBase(DCD_NAME,instIDNum)
+{
+ initDecoder();
+}
+
+TrcPktDecodePtm::~TrcPktDecodePtm()
+{
+}
+
+/*********************** implementation packet decoding interface */
+
+ocsd_datapath_resp_t TrcPktDecodePtm::processPacket()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ bool bPktDone = false;
+
+ while(!bPktDone)
+ {
+ switch(m_curr_state)
+ {
+ case NO_SYNC:
+ // no sync - output a no sync packet then transition to wait sync.
+ m_output_elem.elem_type = OCSD_GEN_TRC_ELEM_NO_SYNC;
+ m_output_elem.unsync_eot_info = m_unsync_info;
+ resp = outputTraceElement(m_output_elem);
+ m_curr_state = (m_curr_packet_in->getType() == PTM_PKT_A_SYNC) ? WAIT_ISYNC : WAIT_SYNC;
+ bPktDone = true;
+ break;
+
+ case WAIT_SYNC:
+ if(m_curr_packet_in->getType() == PTM_PKT_A_SYNC)
+ m_curr_state = WAIT_ISYNC;
+ bPktDone = true;
+ break;
+
+ case WAIT_ISYNC:
+ if(m_curr_packet_in->getType() == PTM_PKT_I_SYNC)
+ m_curr_state = DECODE_PKTS;
+ else
+ bPktDone = true;
+ break;
+
+ case DECODE_PKTS:
+ resp = decodePacket();
+ bPktDone = true;
+ break;
+
+ default:
+ // should only see these after a _WAIT resp - in flush handler
+ case CONT_ISYNC:
+ case CONT_ATOM:
+ bPktDone = true;
+ // throw a decoder error
+ break;
+ }
+ }
+ return resp;
+}
+
+ocsd_datapath_resp_t TrcPktDecodePtm::onEOT()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ // shouldn't be any packets left to be processed - flush shoudl have done this.
+ // just output the end of trace marker
+ m_output_elem.setType(OCSD_GEN_TRC_ELEM_EO_TRACE);
+ m_output_elem.setUnSyncEOTReason(UNSYNC_EOT);
+ resp = outputTraceElement(m_output_elem);
+ return resp;
+}
+
+ocsd_datapath_resp_t TrcPktDecodePtm::onReset()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ m_unsync_info = UNSYNC_RESET_DECODER;
+ resetDecoder();
+ return resp;
+}
+
+ocsd_datapath_resp_t TrcPktDecodePtm::onFlush()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ resp = contProcess();
+ return resp;
+}
+
+// atom and isync packets can have multiple ouput packets that can be _WAITed mid stream.
+ocsd_datapath_resp_t TrcPktDecodePtm::contProcess()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ switch(m_curr_state)
+ {
+ case CONT_ISYNC:
+ resp = processIsync();
+ break;
+
+ case CONT_ATOM:
+ resp = processAtom();
+ break;
+
+ case CONT_WPUP:
+ resp = processWPUpdate();
+ break;
+
+ case CONT_BRANCH:
+ resp = processBranch();
+ break;
+
+ default: break; // not a state that requires further processing
+ }
+
+ if(OCSD_DATA_RESP_IS_CONT(resp) && processStateIsCont())
+ m_curr_state = DECODE_PKTS; // continue packet processing - assuming we have not degraded into an unsynced state.
+
+ return resp;
+}
+
+ocsd_err_t TrcPktDecodePtm::onProtocolConfig()
+{
+ ocsd_err_t err = OCSD_OK;
+ if(m_config == 0)
+ return OCSD_ERR_NOT_INIT;
+
+ // static config - copy of CSID for easy reference
+ m_CSID = m_config->getTraceID();
+
+ // handle return stack implementation
+ if (m_config->hasRetStack())
+ {
+ m_return_stack.set_active(m_config->enaRetStack());
+#ifdef TRC_RET_STACK_DEBUG
+ m_return_stack.set_dbg_logger(this);
+#endif
+ }
+
+ // config options affecting decode
+ m_instr_info.pe_type.profile = m_config->coreProfile();
+ m_instr_info.pe_type.arch = m_config->archVersion();
+ m_instr_info.dsb_dmb_waypoints = m_config->dmsbWayPt() ? 1 : 0;
+ m_instr_info.wfi_wfe_branch = 0;
+ return err;
+}
+
+/****************** local decoder routines */
+
+void TrcPktDecodePtm::initDecoder()
+{
+ m_CSID = 0;
+ m_instr_info.pe_type.profile = profile_Unknown;
+ m_instr_info.pe_type.arch = ARCH_UNKNOWN;
+ m_instr_info.dsb_dmb_waypoints = 0;
+ m_unsync_info = UNSYNC_INIT_DECODER;
+ resetDecoder();
+}
+
+void TrcPktDecodePtm::resetDecoder()
+{
+ m_curr_state = NO_SYNC;
+ m_need_isync = true; // need context to start.
+
+ m_instr_info.isa = ocsd_isa_unknown;
+ m_mem_nacc_pending = false;
+
+ m_pe_context.ctxt_id_valid = 0;
+ m_pe_context.bits64 = 0;
+ m_pe_context.vmid_valid = 0;
+ m_pe_context.exception_level = ocsd_EL_unknown;
+ m_pe_context.security_level = ocsd_sec_secure;
+ m_pe_context.el_valid = 0;
+
+ m_curr_pe_state.instr_addr = 0x0;
+ m_curr_pe_state.isa = ocsd_isa_unknown;
+ m_curr_pe_state.valid = false;
+
+ m_atoms.clearAll();
+ m_output_elem.init();
+}
+
+ocsd_datapath_resp_t TrcPktDecodePtm::decodePacket()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ switch(m_curr_packet_in->getType())
+ {
+ // ignore these from trace o/p point of veiw
+ case PTM_PKT_NOTSYNC:
+ case PTM_PKT_INCOMPLETE_EOT:
+ case PTM_PKT_NOERROR:
+ break;
+
+ // bad / reserved packet - need to wait for next sync point
+ case PTM_PKT_BAD_SEQUENCE:
+ case PTM_PKT_RESERVED:
+ m_curr_state = WAIT_SYNC;
+ m_need_isync = true; // need context to re-start.
+ m_output_elem.setType(OCSD_GEN_TRC_ELEM_NO_SYNC);
+ resp = outputTraceElement(m_output_elem);
+ break;
+
+ // packets we can ignore if in sync
+ case PTM_PKT_A_SYNC:
+ case PTM_PKT_IGNORE:
+ break;
+
+ //
+ case PTM_PKT_I_SYNC:
+ resp = processIsync();
+ break;
+
+ case PTM_PKT_BRANCH_ADDRESS:
+ resp = processBranch();
+ break;
+
+ case PTM_PKT_TRIGGER:
+ m_output_elem.setType(OCSD_GEN_TRC_ELEM_EVENT);
+ m_output_elem.setEvent(EVENT_TRIGGER, 0);
+ resp = outputTraceElement(m_output_elem);
+ break;
+
+ case PTM_PKT_WPOINT_UPDATE:
+ resp = processWPUpdate();
+ break;
+
+ case PTM_PKT_CONTEXT_ID:
+ {
+ bool bUpdate = true;
+ // see if this is a change
+ if((m_pe_context.ctxt_id_valid) && (m_pe_context.context_id == m_curr_packet_in->context.ctxtID))
+ bUpdate = false;
+ if(bUpdate)
+ {
+ m_pe_context.context_id = m_curr_packet_in->context.ctxtID;
+ m_pe_context.ctxt_id_valid = 1;
+ m_output_elem.setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT);
+ m_output_elem.setContext(m_pe_context);
+ resp = outputTraceElement(m_output_elem);
+ }
+ }
+ break;
+
+ case PTM_PKT_VMID:
+ {
+ bool bUpdate = true;
+ // see if this is a change
+ if((m_pe_context.vmid_valid) && (m_pe_context.vmid == m_curr_packet_in->context.VMID))
+ bUpdate = false;
+ if(bUpdate)
+ {
+ m_pe_context.vmid = m_curr_packet_in->context.VMID;
+ m_pe_context.vmid_valid = 1;
+ m_output_elem.setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT);
+ m_output_elem.setContext(m_pe_context);
+ resp = outputTraceElement(m_output_elem);
+ }
+ }
+ break;
+
+ case PTM_PKT_ATOM:
+ if(m_curr_pe_state.valid)
+ {
+ m_atoms.initAtomPkt(m_curr_packet_in->getAtom(),m_index_curr_pkt);
+ resp = processAtom();
+ }
+ break;
+
+ case PTM_PKT_TIMESTAMP:
+ m_output_elem.setType(OCSD_GEN_TRC_ELEM_TIMESTAMP);
+ m_output_elem.timestamp = m_curr_packet_in->timestamp;
+ if(m_curr_packet_in->cc_valid)
+ m_output_elem.setCycleCount(m_curr_packet_in->cycle_count);
+ resp = outputTraceElement(m_output_elem);
+ break;
+
+ case PTM_PKT_EXCEPTION_RET:
+ m_output_elem.setType(OCSD_GEN_TRC_ELEM_EXCEPTION_RET);
+ resp = outputTraceElement(m_output_elem);
+ break;
+
+ }
+ return resp;
+}
+
+ocsd_datapath_resp_t TrcPktDecodePtm::processIsync()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+
+ // extract the I-Sync data if not re-entering after a _WAIT
+ if(m_curr_state == DECODE_PKTS)
+ {
+ m_curr_pe_state.instr_addr = m_curr_packet_in->getAddrVal();
+ m_curr_pe_state.isa = m_curr_packet_in->getISA();
+ m_curr_pe_state.valid = true;
+
+ m_i_sync_pe_ctxt = m_curr_packet_in->ISAChanged();
+ if(m_curr_packet_in->CtxtIDUpdated())
+ {
+ m_pe_context.context_id = m_curr_packet_in->getCtxtID();
+ m_pe_context.ctxt_id_valid = 1;
+ m_i_sync_pe_ctxt = true;
+ }
+
+ if(m_curr_packet_in->VMIDUpdated())
+ {
+ m_pe_context.vmid = m_curr_packet_in->getVMID();
+ m_pe_context.vmid_valid = 1;
+ m_i_sync_pe_ctxt = true;
+ }
+ m_pe_context.security_level = m_curr_packet_in->getNS() ? ocsd_sec_nonsecure : ocsd_sec_secure;
+
+ if(m_need_isync || (m_curr_packet_in->iSyncReason() != iSync_Periodic))
+ {
+ m_output_elem.setType(OCSD_GEN_TRC_ELEM_TRACE_ON);
+ m_output_elem.trace_on_reason = TRACE_ON_NORMAL;
+ if(m_curr_packet_in->iSyncReason() == iSync_TraceRestartAfterOverflow)
+ m_output_elem.trace_on_reason = TRACE_ON_OVERFLOW;
+ else if(m_curr_packet_in->iSyncReason() == iSync_DebugExit)
+ m_output_elem.trace_on_reason = TRACE_ON_EX_DEBUG;
+ if(m_curr_packet_in->hasCC())
+ m_output_elem.setCycleCount(m_curr_packet_in->getCCVal());
+ resp = outputTraceElement(m_output_elem);
+ }
+ else
+ {
+ // periodic - no output
+ m_i_sync_pe_ctxt = false;
+ }
+ m_need_isync = false; // got 1st Isync - can continue to process data.
+ m_return_stack.flush();
+ }
+
+ if(m_i_sync_pe_ctxt && OCSD_DATA_RESP_IS_CONT(resp))
+ {
+ m_output_elem.setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT);
+ m_output_elem.setContext(m_pe_context);
+ m_output_elem.setISA(m_curr_pe_state.isa);
+ resp = outputTraceElement(m_output_elem);
+ m_i_sync_pe_ctxt = false;
+ }
+
+ // if wait and still stuff to process....
+ if(OCSD_DATA_RESP_IS_WAIT(resp) && ( m_i_sync_pe_ctxt))
+ m_curr_state = CONT_ISYNC;
+
+ return resp;
+}
+
+// change of address and/or exception in program flow.
+// implies E atom before the branch if none exception.
+ocsd_datapath_resp_t TrcPktDecodePtm::processBranch()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+
+ // initial pass - decoding packet.
+ if(m_curr_state == DECODE_PKTS)
+ {
+ // specific behviour if this is an exception packet.
+ if(m_curr_packet_in->isBranchExcepPacket())
+ {
+ // exception - record address and output exception packet.
+ m_output_elem.setType(OCSD_GEN_TRC_ELEM_EXCEPTION);
+ m_output_elem.exception_number = m_curr_packet_in->excepNum();
+ m_output_elem.excep_ret_addr = 0;
+ if(m_curr_pe_state.valid)
+ {
+ m_output_elem.excep_ret_addr = 1;
+ m_output_elem.en_addr = m_curr_pe_state.instr_addr;
+ }
+ // could be an associated cycle count
+ if(m_curr_packet_in->hasCC())
+ m_output_elem.setCycleCount(m_curr_packet_in->getCCVal());
+
+ // output the element
+ resp = outputTraceElement(m_output_elem);
+ }
+ else
+ {
+ // branch address only - implies E atom - need to output a range element based on the atom.
+ if(m_curr_pe_state.valid)
+ resp = processAtomRange(ATOM_E,"BranchAddr");
+ }
+
+ // now set the branch address for the next time.
+ m_curr_pe_state.isa = m_curr_packet_in->getISA();
+ m_curr_pe_state.instr_addr = m_curr_packet_in->getAddrVal();
+ m_curr_pe_state.valid = true;
+ }
+
+ // atom range may return with NACC pending
+ checkPendingNacc(resp);
+
+ // if wait and still stuff to process....
+ if(OCSD_DATA_RESP_IS_WAIT(resp) && ( m_mem_nacc_pending))
+ m_curr_state = CONT_BRANCH;
+
+ return resp;
+}
+
+// effectively completes a range prior to exception or after many bytes of trace (>4096)
+//
+ocsd_datapath_resp_t TrcPktDecodePtm::processWPUpdate()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+
+ // if we need an address to run from then the WPUpdate will not form a range as
+ // we do not have a start point - still waiting for branch or other address packet
+ if(m_curr_pe_state.valid)
+ {
+ // WP update implies atom - use E, we cannot be sure if the instruction passed its condition codes
+ // - though it doesn't really matter as it is not a branch so cannot change flow.
+ resp = processAtomRange(ATOM_E,"WP update",TRACE_TO_ADDR_INCL,m_curr_packet_in->getAddrVal());
+ }
+
+ // atom range may return with NACC pending
+ checkPendingNacc(resp);
+
+ // if wait and still stuff to process....
+ if(OCSD_DATA_RESP_IS_WAIT(resp) && ( m_mem_nacc_pending))
+ m_curr_state = CONT_WPUP;
+
+ return resp;
+}
+
+// a single atom packet can result in multiple range outputs...need to be re-entrant in case we get a wait response.
+// also need to handle nacc response from instruction walking routine
+//
+ocsd_datapath_resp_t TrcPktDecodePtm::processAtom()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+
+ // loop to process all the atoms in the packet
+ while(m_atoms.numAtoms() && m_curr_pe_state.valid && OCSD_DATA_RESP_IS_CONT(resp))
+ {
+ resp = processAtomRange(m_atoms.getCurrAtomVal(),"atom");
+ if(!m_curr_pe_state.valid)
+ m_atoms.clearAll();
+ else
+ m_atoms.clearAtom();
+ }
+
+ // bad address may mean a nacc needs sending
+ checkPendingNacc(resp);
+
+ // if wait and still stuff to process....
+ if(OCSD_DATA_RESP_IS_WAIT(resp) && ( m_mem_nacc_pending || m_atoms.numAtoms()))
+ m_curr_state = CONT_ATOM;
+
+ return resp;
+}
+
+ void TrcPktDecodePtm::checkPendingNacc(ocsd_datapath_resp_t &resp)
+ {
+ if(m_mem_nacc_pending && OCSD_DATA_RESP_IS_CONT(resp))
+ {
+ m_output_elem.setType(OCSD_GEN_TRC_ELEM_ADDR_NACC);
+ m_output_elem.st_addr = m_nacc_addr;
+ resp = outputTraceElementIdx(m_index_curr_pkt,m_output_elem);
+ m_mem_nacc_pending = false;
+ }
+ }
+
+// given an atom element - walk the code and output a range or mark nacc.
+ocsd_datapath_resp_t TrcPktDecodePtm::processAtomRange(const ocsd_atm_val A, const char *pkt_msg, const waypoint_trace_t traceWPOp /*= TRACE_WAYPOINT*/, const ocsd_vaddr_t nextAddrMatch /*= 0*/)
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ bool bWPFound = false;
+ std::ostringstream oss;
+ ocsd_err_t err = OCSD_OK;
+
+ m_instr_info.instr_addr = m_curr_pe_state.instr_addr;
+ m_instr_info.isa = m_curr_pe_state.isa;
+
+ // set type (which resets out-elem) before traceInstrToWP modifies out-elem values
+ m_output_elem.setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE);
+
+ err = traceInstrToWP(bWPFound,traceWPOp,nextAddrMatch);
+ if(err != OCSD_OK)
+ {
+ if(err == OCSD_ERR_UNSUPPORTED_ISA)
+ {
+ m_curr_pe_state.valid = false; // need a new address packet
+ oss << "Warning: unsupported instruction set processing " << pkt_msg << " packet.";
+ LogError(ocsdError(OCSD_ERR_SEV_WARN,err,m_index_curr_pkt,m_CSID,oss.str()));
+ // wait for next address
+ return OCSD_RESP_WARN_CONT;
+ }
+ else
+ {
+ resp = OCSD_RESP_FATAL_INVALID_DATA;
+ oss << "Error processing " << pkt_msg << " packet.";
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR,err,m_index_curr_pkt,m_CSID,oss.str()));
+ return resp;
+ }
+ }
+
+ if(bWPFound)
+ {
+ // save recorded next instuction address
+ ocsd_vaddr_t nextAddr = m_instr_info.instr_addr;
+
+ // action according to waypoint type and atom value
+ switch(m_instr_info.type)
+ {
+ case OCSD_INSTR_BR:
+ if (A == ATOM_E)
+ {
+ m_instr_info.instr_addr = m_instr_info.branch_addr;
+ if (m_instr_info.is_link)
+ m_return_stack.push(nextAddr,m_instr_info.isa);
+ }
+ break;
+
+ // For PTM -> branch addresses imply E atom, N atom does not need address (return stack will require this)
+ case OCSD_INSTR_BR_INDIRECT:
+ if (A == ATOM_E)
+ {
+ // atom on indirect branch - either implied E from a branch address packet, or return stack if active.
+
+ // indirect branch taken - need new address -if the current packet is a branch address packet this will be sorted.
+ m_curr_pe_state.valid = false;
+
+ // if return stack and the incoming packet is an atom.
+ if (m_return_stack.is_active() && (m_curr_packet_in->getType() == PTM_PKT_ATOM))
+ {
+ // we have an E atom packet and return stack value - set address from return stack
+ m_instr_info.instr_addr = m_return_stack.pop(m_instr_info.next_isa);
+
+ if (m_return_stack.overflow())
+ {
+ resp = OCSD_RESP_FATAL_INVALID_DATA;
+ oss << "Return stack error processing " << pkt_msg << " packet.";
+ LogError(ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_RET_STACK_OVERFLOW, m_index_curr_pkt, m_CSID, oss.str()));
+ return resp;
+ }
+ else
+ m_curr_pe_state.valid = true;
+ }
+ if(m_instr_info.is_link)
+ m_return_stack.push(nextAddr, m_instr_info.isa);
+ }
+ break;
+ }
+
+ m_output_elem.setLastInstrInfo((A == ATOM_E),m_instr_info.type, m_instr_info.sub_type,m_instr_info.instr_size);
+ m_output_elem.setISA(m_curr_pe_state.isa);
+ if(m_curr_packet_in->hasCC())
+ m_output_elem.setCycleCount(m_curr_packet_in->getCCVal());
+ m_output_elem.setLastInstrCond(m_instr_info.is_conditional);
+ resp = outputTraceElementIdx(m_index_curr_pkt,m_output_elem);
+
+ m_curr_pe_state.instr_addr = m_instr_info.instr_addr;
+ m_curr_pe_state.isa = m_instr_info.next_isa;
+ }
+ else
+ {
+ // no waypoint - likely inaccessible memory range.
+ m_curr_pe_state.valid = false; // need an address update
+
+ if(m_output_elem.st_addr != m_output_elem.en_addr)
+ {
+ // some trace before we were out of memory access range
+ m_output_elem.setLastInstrInfo(true,m_instr_info.type, m_instr_info.sub_type,m_instr_info.instr_size);
+ m_output_elem.setISA(m_curr_pe_state.isa);
+ m_output_elem.setLastInstrCond(m_instr_info.is_conditional);
+ resp = outputTraceElementIdx(m_index_curr_pkt,m_output_elem);
+ }
+ }
+ return resp;
+}
+
+ocsd_err_t TrcPktDecodePtm::traceInstrToWP(bool &bWPFound, const waypoint_trace_t traceWPOp /*= TRACE_WAYPOINT*/, const ocsd_vaddr_t nextAddrMatch /*= 0*/)
+{
+ uint32_t opcode;
+ uint32_t bytesReq;
+ ocsd_err_t err = OCSD_OK;
+ ocsd_vaddr_t curr_op_address;
+
+ ocsd_mem_space_acc_t mem_space = (m_pe_context.security_level == ocsd_sec_secure) ? OCSD_MEM_SPACE_S : OCSD_MEM_SPACE_N;
+
+ m_output_elem.st_addr = m_output_elem.en_addr = m_instr_info.instr_addr;
+ m_output_elem.num_instr_range = 0;
+
+ bWPFound = false;
+
+ while(!bWPFound && !m_mem_nacc_pending)
+ {
+ // start off by reading next opcode;
+ bytesReq = 4;
+ curr_op_address = m_instr_info.instr_addr; // save the start address for the current opcode
+ err = accessMemory(m_instr_info.instr_addr,mem_space,&bytesReq,(uint8_t *)&opcode);
+ if(err != OCSD_OK) break;
+
+ if(bytesReq == 4) // got data back
+ {
+ m_instr_info.opcode = opcode;
+ err = instrDecode(&m_instr_info);
+ if(err != OCSD_OK) break;
+
+ // increment address - may be adjusted by direct branch value later
+ m_instr_info.instr_addr += m_instr_info.instr_size;
+
+ // update the range decoded address in the output packet.
+ m_output_elem.en_addr = m_instr_info.instr_addr;
+ m_output_elem.num_instr_range++;
+
+ m_output_elem.last_i_type = m_instr_info.type;
+ // either walking to match the next instruction address or a real waypoint
+ if(traceWPOp != TRACE_WAYPOINT)
+ {
+ if(traceWPOp == TRACE_TO_ADDR_EXCL)
+ bWPFound = (m_output_elem.en_addr == nextAddrMatch);
+ else
+ bWPFound = (curr_op_address == nextAddrMatch);
+ }
+ else
+ bWPFound = (m_instr_info.type != OCSD_INSTR_OTHER);
+ }
+ else
+ {
+ // not enough memory accessible.
+ m_mem_nacc_pending = true;
+ m_nacc_addr = m_instr_info.instr_addr;
+ }
+ }
+ return err;
+}
+
+/* End of File trc_pkt_decode_ptm.cpp */