summaryrefslogtreecommitdiffstats
path: root/decoder/source/ptm
diff options
context:
space:
mode:
Diffstat (limited to 'decoder/source/ptm')
-rw-r--r--decoder/source/ptm/trc_cmp_cfg_ptm.cpp59
-rw-r--r--decoder/source/ptm/trc_pkt_decode_ptm.cpp671
-rw-r--r--decoder/source/ptm/trc_pkt_elem_ptm.cpp473
-rw-r--r--decoder/source/ptm/trc_pkt_proc_ptm.cpp1218
4 files changed, 2421 insertions, 0 deletions
diff --git a/decoder/source/ptm/trc_cmp_cfg_ptm.cpp b/decoder/source/ptm/trc_cmp_cfg_ptm.cpp
new file mode 100644
index 0000000..74ded02
--- /dev/null
+++ b/decoder/source/ptm/trc_cmp_cfg_ptm.cpp
@@ -0,0 +1,59 @@
+/*
+ * \file trc_cmp_cfg_ptm.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/ptm/trc_cmp_cfg_ptm.h"
+
+PtmConfig::PtmConfig()
+{
+ // defaults set ETMv1.1, V7A
+ m_cfg.arch_ver = ARCH_V7;
+ m_cfg.core_prof = profile_CortexA;
+ m_cfg.reg_ccer = 0;
+ m_cfg.reg_idr = 0x4100F310;
+ m_cfg.reg_ctrl = 0;
+}
+
+PtmConfig::PtmConfig(const ocsd_ptm_cfg *cfg_regs)
+{
+ m_cfg = *cfg_regs;
+}
+
+const int PtmConfig::CtxtIDBytes() const
+{
+ int ctxtIdsizes[] = { 0, 1, 2, 4 };
+ return ctxtIdsizes[(m_cfg.reg_ctrl >> 14) & 0x3];
+}
+
+
+/* End of File trc_cmp_cfg_ptm.cpp */
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 */
diff --git a/decoder/source/ptm/trc_pkt_elem_ptm.cpp b/decoder/source/ptm/trc_pkt_elem_ptm.cpp
new file mode 100644
index 0000000..7c8bcd7
--- /dev/null
+++ b/decoder/source/ptm/trc_pkt_elem_ptm.cpp
@@ -0,0 +1,473 @@
+/*
+ * \file trc_pkt_elem_ptm.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 <sstream>
+#include <iomanip>
+
+#include "opencsd/ptm/trc_pkt_elem_ptm.h"
+
+PtmTrcPacket::PtmTrcPacket()
+{
+}
+
+PtmTrcPacket::~PtmTrcPacket()
+{
+}
+
+PtmTrcPacket &PtmTrcPacket::operator =(const ocsd_ptm_pkt* p_pkt)
+{
+ *dynamic_cast<ocsd_ptm_pkt *>(this) = *p_pkt;
+ return *this;
+}
+
+void PtmTrcPacket::Clear()
+{
+ err_type = PTM_PKT_NOERROR;
+ cycle_count = 0;
+ cc_valid = 0;
+ context.updated = 0;
+ context.updated_c = 0;
+ context.updated_v = 0;
+ ts_update_bits = 0;
+ atom.En_bits = 0;
+ exception.bits.present = 0;
+ prev_isa = curr_isa; // mark ISA as not changed
+}
+
+void PtmTrcPacket::ResetState()
+{
+ type = PTM_PKT_NOTSYNC;
+
+ context.ctxtID = 0;
+ context.VMID = 0;
+ context.curr_alt_isa = 0;
+ context.curr_Hyp = 0;
+ context.curr_NS = 0;
+
+ addr.valid_bits = 0;
+ addr.size = VA_32BIT;
+ addr.val = 0;
+
+ prev_isa = curr_isa = ocsd_isa_unknown;
+
+ timestamp = 0;
+
+ Clear();
+}
+
+void PtmTrcPacket::UpdateAddress(const ocsd_vaddr_t partAddrVal, const int updateBits)
+{
+ ocsd_vaddr_t validMask = OCSD_VA_MASK;
+ validMask >>= OCSD_MAX_VA_BITSIZE-updateBits;
+ addr.pkt_bits = updateBits;
+ addr.val &= ~validMask;
+ addr.val |= (partAddrVal & validMask);
+ if(updateBits > addr.valid_bits)
+ addr.valid_bits = updateBits;
+}
+
+void PtmTrcPacket::UpdateTimestamp(const uint64_t tsVal, const uint8_t updateBits)
+{
+ uint64_t validMask = ~0ULL;
+ validMask >>= 64-updateBits;
+ timestamp &= ~validMask;
+ timestamp |= (tsVal & validMask);
+ ts_update_bits = updateBits;
+}
+
+void PtmTrcPacket::SetCycleAccAtomFromPHdr(const uint8_t pHdr)
+{
+ atom.num = 1;
+ atom.En_bits = (pHdr & 0x2) ? 0x0 : 0x1;
+}
+
+void PtmTrcPacket::SetAtomFromPHdr(const uint8_t pHdr)
+{
+ // how many atoms
+ uint8_t atom_fmt_id = pHdr & 0xF0;
+ if(atom_fmt_id == 0x80)
+ {
+ // format 1 or 2
+ if((pHdr & 0x08) == 0x08)
+ atom.num = 2;
+ else
+ atom.num = 1;
+ }
+ else if(atom_fmt_id == 0x90)
+ {
+ atom.num = 3;
+ }
+ else
+ {
+ if((pHdr & 0xE0) == 0xA0)
+ atom.num = 4;
+ else
+ atom.num = 5;
+ }
+
+ // extract the E/N bits
+ uint8_t atom_mask = 0x2; // start @ bit 1 - newest instruction
+ atom.En_bits = 0;
+ for(int i = 0; i < atom.num; i++)
+ {
+ atom.En_bits <<= 1;
+ if(!(atom_mask & pHdr)) // 0 bit is an E in PTM -> a one in the standard atom bit type
+ atom.En_bits |= 0x1;
+ atom_mask <<= 1;
+ }
+}
+
+ // printing
+void PtmTrcPacket::toString(std::string &str) const
+{
+ std::string temp1, temp2;
+ std::ostringstream oss;
+
+ packetTypeName(type, temp1,temp2);
+ oss << temp1 << " : " << temp2 << "; ";
+
+ // some packets require additional data.
+ switch(type)
+ {
+ case PTM_PKT_BAD_SEQUENCE:
+ packetTypeName(err_type, temp1,temp2);
+ oss << "[" << temp1 << "]; ";
+ break;
+
+ case PTM_PKT_ATOM:
+ getAtomStr(temp1);
+ oss << temp1;
+ break;
+
+ case PTM_PKT_CONTEXT_ID:
+ oss << "CtxtID=0x" << std::hex << std::setw(8) << std::setfill('0') << context.ctxtID << "; ";
+ break;
+
+ case PTM_PKT_VMID:
+ oss << "VMID=0x" << std::hex << std::setw(2) << std::setfill('0') << context.VMID << "; ";
+ break;
+
+ case PTM_PKT_WPOINT_UPDATE:
+ case PTM_PKT_BRANCH_ADDRESS:
+ getBranchAddressStr(temp1);
+ oss << temp1;
+ break;
+
+ case PTM_PKT_I_SYNC:
+ getISyncStr(temp1);
+ oss << temp1;
+ break;
+
+ case PTM_PKT_TIMESTAMP:
+ getTSStr(temp1);
+ oss << temp1;
+ break;
+ }
+
+ str = oss.str();
+}
+
+void PtmTrcPacket::toStringFmt(const uint32_t fmtFlags, std::string &str) const
+{
+ toString(str);
+}
+
+void PtmTrcPacket::getAtomStr(std::string &valStr) const
+{
+ std::ostringstream oss;
+ uint32_t bitpattern = atom.En_bits; // arranged LSBit oldest, MSbit newest
+
+ if(cc_valid) // cycle accurate trace - single atom
+ {
+ std::string subStr;
+ oss << ((bitpattern & 0x1) ? "E" : "N"); // in spec read L->R, oldest->newest
+ oss << "; ";
+ getCycleCountStr(subStr);
+ oss << subStr;
+ }
+ else
+ {
+ // none cycle count
+ for(int i = 0; i < atom.num; i++)
+ {
+ oss << ((bitpattern & 0x1) ? "E" : "N"); // in spec read L->R, oldest->newest
+ bitpattern >>= 1;
+ }
+ oss << "; ";
+ }
+ valStr = oss.str();
+}
+
+void PtmTrcPacket::getBranchAddressStr(std::string &valStr) const
+{
+ std::ostringstream oss;
+ std::string subStr;
+
+ // print address.
+ trcPrintableElem::getValStr(subStr,32,addr.valid_bits,addr.val,true,addr.pkt_bits);
+ oss << "Addr=" << subStr << "; ";
+
+ // current ISA if changed.
+ if(curr_isa != prev_isa)
+ {
+ getISAStr(subStr);
+ oss << subStr;
+ }
+
+ // S / NS etc if changed.
+ if(context.updated)
+ {
+ oss << (context.curr_NS ? "NS; " : "S; ");
+ oss << (context.curr_Hyp ? "Hyp; " : "");
+ }
+
+ // exception?
+ if(exception.bits.present)
+ {
+ getExcepStr(subStr);
+ oss << subStr;
+ }
+
+ if(cc_valid)
+ {
+ getCycleCountStr(subStr);
+ oss << subStr;
+ }
+ valStr = oss.str();
+}
+
+void PtmTrcPacket::getISAStr(std::string &isaStr) const
+{
+ std::ostringstream oss;
+ oss << "ISA=";
+ switch(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 PtmTrcPacket::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"
+ };
+
+ std::ostringstream oss;
+ oss << "Excep=";
+ if(exception.number < 16)
+ oss << ARv7Excep[exception.number];
+ else
+ oss << "Unknown";
+ oss << " [" << std::hex << std::setw(2) << std::setfill('0') << exception.number << "]; ";
+ excepStr = oss.str();
+}
+
+void PtmTrcPacket::getISyncStr(std::string &valStr) const
+{
+ std::ostringstream oss;
+ std::string tmpStr;
+ static const char *reason[] = { "Periodic", "Trace Enable", "Restart Overflow", "Debug Exit" };
+
+ // reason.
+ oss << "(" << reason[(int)i_sync_reason] << "); ";
+
+ // full address.
+ oss << "Addr=0x" << std::hex << std::setfill('0') << std::setw(8) << (uint32_t)addr.val << "; ";
+
+ oss << (context.curr_NS ? "NS; " : "S; ");
+ oss << (context.curr_Hyp ? "Hyp; " : " ");
+
+ if(context.updated_c)
+ {
+ oss << "CtxtID=" << std::hex << std::setw(8) << std::setfill('0') << context.ctxtID << "; ";
+ }
+
+ getISAStr(tmpStr);
+ oss << tmpStr;
+
+ if(cc_valid)
+ {
+ getCycleCountStr(tmpStr);
+ oss << tmpStr;
+ }
+ valStr = oss.str();
+}
+
+void PtmTrcPacket::getTSStr(std::string &valStr) const
+{
+ std::string tmpStr;
+ std::ostringstream oss;
+
+ trcPrintableElem::getValStr(tmpStr,64,64,timestamp,true,ts_update_bits);
+ oss << "TS=" << tmpStr + "(" << std::dec << timestamp << "); ";
+ if(cc_valid)
+ {
+ getCycleCountStr(tmpStr);
+ oss << tmpStr;
+ }
+ valStr = oss.str();
+}
+
+
+void PtmTrcPacket::getCycleCountStr(std::string &subStr) const
+{
+ std::ostringstream oss;
+ oss << "Cycles=" << std::dec << cycle_count << "; ";
+ subStr = oss.str();
+}
+
+
+void PtmTrcPacket::packetTypeName(const ocsd_ptm_pkt_type pkt_type, std::string &name, std::string &desc) const
+{
+ switch(pkt_type)
+ {
+ case PTM_PKT_NOTSYNC: //!< no sync found yet
+ name = "NOTSYNC";
+ desc = "PTM Not Synchronised";
+ break;
+
+ case PTM_PKT_INCOMPLETE_EOT:
+ name = "INCOMPLETE_EOT";
+ desc = "Incomplete packet flushed at end of trace";
+ break;
+
+ case PTM_PKT_NOERROR:
+ name = "NO_ERROR";
+ desc = "Error type not set";
+ break;
+
+ case PTM_PKT_BAD_SEQUENCE:
+ name = "BAD_SEQUENCE";
+ desc = "Invalid sequence in packet";
+ break;
+
+ case PTM_PKT_RESERVED:
+ name = "RESERVED";
+ desc = "Reserved Packet Header";
+ break;
+
+ case PTM_PKT_BRANCH_ADDRESS:
+ name = "BRANCH_ADDRESS";
+ desc = "Branch address packet";
+ break;
+
+ case PTM_PKT_A_SYNC:
+ name = "ASYNC";
+ desc = "Alignment Synchronisation Packet";
+ break;
+
+ case PTM_PKT_I_SYNC:
+ name = "ISYNC";
+ desc = "Instruction Synchronisation packet";
+ break;
+
+ case PTM_PKT_TRIGGER:
+ name = "TRIGGER";
+ desc = "Trigger Event packet";
+ break;
+
+ case PTM_PKT_WPOINT_UPDATE:
+ name = "WP_UPDATE";
+ desc = "Waypoint update packet";
+ break;
+
+ case PTM_PKT_IGNORE:
+ name = "IGNORE";
+ desc = "Ignore packet";
+ break;
+
+ case PTM_PKT_CONTEXT_ID:
+ name = "CTXTID";
+ desc = "Context ID packet";
+ break;
+
+ case PTM_PKT_VMID:
+ name = "VMID";
+ desc = "VM ID packet";
+ break;
+
+ case PTM_PKT_ATOM:
+ name = "ATOM";
+ desc = "Atom packet";
+ break;
+
+ case PTM_PKT_TIMESTAMP:
+ name = "TIMESTAMP";
+ desc = "Timestamp packet";
+ break;
+
+ case PTM_PKT_EXCEPTION_RET:
+ name = "ERET";
+ desc = "Exception return packet";
+ break;
+
+ default:
+ name = "UNKNOWN";
+ desc = "Unknown packet type";
+ break;
+
+ //PTM_PKT_BRANCH_OR_BYPASS_EOT,
+ //PTM_PKT_TPIU_PAD_EOB,
+ }
+}
+
+/* End of File trc_pkt_elem_ptm.cpp */
diff --git a/decoder/source/ptm/trc_pkt_proc_ptm.cpp b/decoder/source/ptm/trc_pkt_proc_ptm.cpp
new file mode 100644
index 0000000..668a14b
--- /dev/null
+++ b/decoder/source/ptm/trc_pkt_proc_ptm.cpp
@@ -0,0 +1,1218 @@
+/*
+ * \file trc_pkt_proc_ptm.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/ptm/trc_pkt_proc_ptm.h"
+#include "opencsd/ptm/trc_cmp_cfg_ptm.h"
+#include "common/ocsd_error.h"
+
+
+#ifdef __GNUC__
+// G++ doesn't like the ## pasting
+#define PTM_PKTS_NAME "PKTP_PTM"
+#else
+// VC++ is OK
+#define PTM_PKTS_NAME OCSD_CMPNAME_PREFIX_PKTPROC##"_PTM"
+#endif
+
+TrcPktProcPtm::TrcPktProcPtm() : TrcPktProcBase(PTM_PKTS_NAME)
+{
+ InitProcessorState();
+ BuildIPacketTable();
+}
+
+TrcPktProcPtm::TrcPktProcPtm(int instIDNum) : TrcPktProcBase(PTM_PKTS_NAME, instIDNum)
+{
+ InitProcessorState();
+ BuildIPacketTable();
+}
+
+TrcPktProcPtm::~TrcPktProcPtm()
+{
+
+}
+
+ocsd_err_t TrcPktProcPtm::onProtocolConfig()
+{
+ ocsd_err_t err = OCSD_ERR_NOT_INIT;
+
+ if(m_config != 0)
+ {
+ m_chanIDCopy = m_config->getTraceID();
+ err = OCSD_OK;
+ }
+ return err;
+}
+
+ocsd_datapath_resp_t TrcPktProcPtm::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;
+ uint8_t currByte = 0;
+
+ m_dataInProcessed = 0;
+
+ if(!checkInit())
+ {
+ resp = OCSD_RESP_FATAL_NOT_INIT;
+ }
+ else
+ {
+ m_pDataIn = pDataBlock;
+ m_dataInLen = dataBlockSize;
+ m_block_idx = index; // index start for current block
+ }
+
+ while( ( ( m_dataInProcessed < dataBlockSize) ||
+ (( m_dataInProcessed == dataBlockSize) && (m_process_state == SEND_PKT)) ) &&
+ OCSD_DATA_RESP_IS_CONT(resp))
+ {
+ try
+ {
+ switch(m_process_state)
+ {
+ case WAIT_SYNC:
+ if(!m_waitASyncSOPkt)
+ {
+ m_curr_pkt_index = m_block_idx + m_dataInProcessed;
+ m_curr_packet.type = PTM_PKT_NOTSYNC;
+ m_bAsyncRawOp = hasRawMon();
+ }
+ resp = waitASync();
+ break;
+
+ case PROC_HDR:
+ m_curr_pkt_index = m_block_idx + m_dataInProcessed;
+ if(readByte(currByte))
+ {
+ m_pIPktFn = m_i_table[currByte].pptkFn;
+ m_curr_packet.type = m_i_table[currByte].pkt_type;
+ }
+ else
+ {
+ // sequencing error - should not get to the point where readByte
+ // fails and m_DataInProcessed < dataBlockSize
+ // throw data overflow error
+ throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_PKT_INTERP_FAIL,m_curr_pkt_index,this->m_chanIDCopy,"Data Buffer Overrun");
+ }
+ m_process_state = PROC_DATA;
+
+ case PROC_DATA:
+ (this->*m_pIPktFn)();
+ break;
+
+ case SEND_PKT:
+ resp = outputPacket();
+ InitPacketState();
+ m_process_state = PROC_HDR;
+ break;
+ }
+ }
+ catch(ocsdError &err)
+ {
+ 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;
+ const ocsdError &fatal = ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_FAIL,m_curr_pkt_index,m_chanIDCopy,"Unknown System Error decoding trace.");
+ LogError(fatal);
+ }
+
+ }
+ *numBytesProcessed = m_dataInProcessed;
+ return resp;
+}
+
+ocsd_datapath_resp_t TrcPktProcPtm::onEOT()
+{
+ ocsd_datapath_resp_t err = OCSD_RESP_FATAL_NOT_INIT;
+ if(checkInit())
+ {
+ err = OCSD_RESP_CONT;
+ if(m_currPacketData.size() > 0)
+ {
+ m_curr_packet.SetErrType(PTM_PKT_INCOMPLETE_EOT);
+ err = outputPacket();
+ }
+ }
+ return err;
+}
+
+ocsd_datapath_resp_t TrcPktProcPtm::onReset()
+{
+ ocsd_datapath_resp_t err = OCSD_RESP_FATAL_NOT_INIT;
+ if(checkInit())
+ {
+ InitProcessorState();
+ err = OCSD_RESP_CONT;
+ }
+ return err;
+}
+
+ocsd_datapath_resp_t TrcPktProcPtm::onFlush()
+{
+ ocsd_datapath_resp_t err = OCSD_RESP_FATAL_NOT_INIT;
+ if(checkInit())
+ {
+ err = OCSD_RESP_CONT;
+ }
+ return err;
+}
+
+const bool TrcPktProcPtm::isBadPacket() const
+{
+ return m_curr_packet.isBadPacket();
+}
+
+void TrcPktProcPtm::InitPacketState()
+{
+ m_curr_packet.Clear();
+
+}
+
+void TrcPktProcPtm::InitProcessorState()
+{
+ m_curr_packet.SetType(PTM_PKT_NOTSYNC);
+ m_pIPktFn = &TrcPktProcPtm::pktReserved;
+ m_process_state = WAIT_SYNC;
+ m_async_0 = 0;
+ m_waitASyncSOPkt = false;
+ m_bAsyncRawOp = false;
+ m_bOPNotSyncPkt = false;
+ m_excepAltISA = 0;
+
+ m_curr_packet.ResetState();
+ InitPacketState();
+}
+
+const bool TrcPktProcPtm::readByte(uint8_t &currByte)
+{
+ bool bValidByte = false;
+
+ if(m_dataInProcessed < m_dataInLen)
+ {
+ currByte = m_pDataIn[m_dataInProcessed++];
+ m_currPacketData.push_back(currByte);
+ bValidByte = true;
+ }
+ return bValidByte;
+}
+
+void TrcPktProcPtm::unReadByte()
+{
+ m_dataInProcessed--;
+ m_currPacketData.pop_back();
+}
+
+ocsd_datapath_resp_t TrcPktProcPtm::outputPacket()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+ resp = outputOnAllInterfaces(m_curr_pkt_index,&m_curr_packet,&m_curr_packet.type,m_currPacketData);
+ m_currPacketData.clear();
+ return resp;
+}
+
+/*** sync and packet functions ***/
+ocsd_datapath_resp_t TrcPktProcPtm::waitASync()
+{
+ ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
+
+ // looking for possible patterns in input buffer:-
+ // a) ASYNC @ start : 00 00 00 00 00 80
+ // b) unsync then async: xx xx xx xx xx xx xx xx 00 00 00 00 00 80
+ // c) unsync (may have 00) xx xx xx xx 00 xx xx 00 00 00 xx xx xx xx
+ // d) unsync then part async: xx xx xx xx xx xx xx xx xx xx xx 00 00 00
+ // e) unsync with prev part async [00 00 00] 00 xx xx xx xx xx xx xx xx [] = byte in previous input buffer
+
+ // bytes to read before throwing an unsynced packet
+ #define UNSYNC_PKT_MAX 16
+ static const uint8_t spare_zeros[] = { 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0 };
+
+ bool doScan = true;
+ bool bSendUnsyncedData = false;
+ bool bHaveASync = false;
+ int unsynced_bytes = 0;
+ int unsync_scan_block_start = 0;
+ int pktBytesOnEntry = m_currPacketData.size(); // did we have part of a potential async last time?
+
+ while(doScan && OCSD_DATA_RESP_IS_CONT(resp))
+ {
+ // may have spotted the start of an async
+ if(m_waitASyncSOPkt == true)
+ {
+ switch(findAsync())
+ {
+ case ASYNC:
+ case ASYNC_EXTRA_0:
+ m_process_state = SEND_PKT;
+ m_waitASyncSOPkt = false;
+ bSendUnsyncedData = true;
+ bHaveASync = true;
+ doScan = false;
+ break;
+
+ case THROW_0:
+ // remove a bunch of 0s
+ unsynced_bytes += ASYNC_PAD_0_LIMIT;
+ m_waitASyncSOPkt = false;
+ m_currPacketData.erase( m_currPacketData.begin(), m_currPacketData.begin()+ASYNC_PAD_0_LIMIT);
+ break;
+
+ case NOT_ASYNC:
+ unsynced_bytes += m_currPacketData.size();
+ m_waitASyncSOPkt = false;
+ m_currPacketData.clear();
+ break;
+
+ case ASYNC_INCOMPLETE:
+ bSendUnsyncedData = true;
+ doScan = false;
+ break;
+ }
+ }
+ else
+ {
+ if(m_pDataIn[m_dataInProcessed++] == 0x00)
+ {
+ m_waitASyncSOPkt = true;
+ m_currPacketData.push_back(0);
+ m_async_0 = 1;
+ }
+ else
+ {
+ unsynced_bytes++;
+ }
+ }
+
+ // may need to send some unsynced data here, either if we have enought to make it worthwhile,
+ // or are at the end of the buffer.
+ if(unsynced_bytes >= UNSYNC_PKT_MAX)
+ bSendUnsyncedData = true;
+
+ if(m_dataInProcessed == m_dataInLen)
+ {
+ bSendUnsyncedData = true;
+ doScan = false; // no more data available - stop the scan
+ }
+
+ // will send any unsynced data
+ if(bSendUnsyncedData && (unsynced_bytes > 0))
+ {
+ if(m_bAsyncRawOp)
+ {
+ // there were some 0's in the packet buyffer from the last pass that are no longer in the raw buffer,
+ // and these turned out not to be an async
+ if(pktBytesOnEntry)
+ {
+ outputRawPacketToMonitor(m_curr_pkt_index,&m_curr_packet,pktBytesOnEntry,spare_zeros);
+ m_curr_pkt_index += pktBytesOnEntry;
+ }
+ outputRawPacketToMonitor(m_curr_pkt_index,&m_curr_packet,unsynced_bytes,m_pDataIn+unsync_scan_block_start);
+ }
+ if (!m_bOPNotSyncPkt)
+ {
+ resp = outputDecodedPacket(m_curr_pkt_index, &m_curr_packet);
+ m_bOPNotSyncPkt = true;
+ }
+ unsync_scan_block_start += unsynced_bytes;
+ m_curr_pkt_index+= unsynced_bytes;
+ unsynced_bytes = 0;
+ bSendUnsyncedData = false;
+ }
+
+ // mark next packet as the ASYNC we are looking for.
+ if(bHaveASync)
+ m_curr_packet.SetType(PTM_PKT_A_SYNC);
+ }
+
+ return resp;
+}
+
+void TrcPktProcPtm::pktASync()
+{
+ if(m_currPacketData.size() == 1) // header byte
+ {
+ m_async_0 = 1;
+ }
+
+ switch(findAsync())
+ {
+ case ASYNC:
+ case ASYNC_EXTRA_0:
+ m_process_state = SEND_PKT;
+ break;
+
+ case THROW_0:
+ case NOT_ASYNC:
+ throwMalformedPacketErr("Bad Async packet");
+ break;
+
+ case ASYNC_INCOMPLETE:
+ break;
+
+ }
+}
+
+TrcPktProcPtm::async_result_t TrcPktProcPtm::findAsync()
+{
+ async_result_t async_res = NOT_ASYNC;
+ bool bFound = false; // found non-zero byte in sequence
+ bool bByteAvail = true;
+ uint8_t currByte;
+
+ while(!bFound && bByteAvail)
+ {
+ if(readByte(currByte))
+ {
+ if(currByte == 0x00)
+ {
+ m_async_0++;
+ if(m_async_0 >= (ASYNC_PAD_0_LIMIT + ASYNC_REQ_0))
+ {
+ bFound = true;
+ async_res = THROW_0;
+ }
+ }
+ else
+ {
+ if(currByte == 0x80)
+ {
+ if(m_async_0 == 5)
+ async_res = ASYNC;
+ else if(m_async_0 > 5)
+ async_res = ASYNC_EXTRA_0;
+ }
+ bFound = true;
+ }
+ }
+ else
+ {
+ bByteAvail = false;
+ async_res = ASYNC_INCOMPLETE;
+ }
+ }
+ return async_res;
+}
+
+void TrcPktProcPtm::pktISync()
+{
+ uint8_t currByte = 0;
+ int pktIndex = m_currPacketData.size() - 1;
+ bool bGotBytes = false, validByte = true;
+
+ if(pktIndex == 0)
+ {
+ m_numCtxtIDBytes = m_config->CtxtIDBytes();
+ m_gotCtxtIDBytes = 0;
+
+ // total bytes = 6 + ctxtID; (perhaps more later)
+ m_numPktBytesReq = 6 + m_numCtxtIDBytes;
+ }
+
+ while(validByte && !bGotBytes)
+ {
+ if(readByte(currByte))
+ {
+ pktIndex = m_currPacketData.size() - 1;
+ if(pktIndex == 5)
+ {
+ // got the info byte
+ int altISA = (currByte >> 2) & 0x1;
+ int reason = (currByte >> 5) & 0x3;
+ m_curr_packet.SetISyncReason((ocsd_iSync_reason)(reason));
+ m_curr_packet.UpdateNS((currByte >> 3) & 0x1);
+ m_curr_packet.UpdateAltISA((currByte >> 2) & 0x1);
+ m_curr_packet.UpdateHyp((currByte >> 1) & 0x1);
+
+ ocsd_isa isa = ocsd_isa_arm;
+ if(m_currPacketData[1] & 0x1)
+ isa = altISA ? ocsd_isa_tee : ocsd_isa_thumb2;
+ m_curr_packet.UpdateISA(isa);
+
+ // check cycle count required - not if reason == 0;
+ m_needCycleCount = (reason != 0) ? m_config->enaCycleAcc() : false;
+ m_gotCycleCount = false;
+ m_numPktBytesReq += (m_needCycleCount ? 1 : 0);
+ m_gotCCBytes = 0;
+
+ }
+ else if(pktIndex > 5)
+ {
+ // cycle count appears first if present
+ if(m_needCycleCount && !m_gotCycleCount)
+ {
+ if(pktIndex == 6)
+ m_gotCycleCount = (bool)((currByte & 0x40) == 0); // no cont bit, got cycle count
+ else
+ m_gotCycleCount = ((currByte & 0x80) == 0) || (pktIndex == 10);
+
+ m_gotCCBytes++; // count the cycle count bytes for later use.
+ if(!m_gotCycleCount) // need more cycle count bytes
+ m_numPktBytesReq++;
+ }
+ // then context ID if present.
+ else if( m_numCtxtIDBytes > m_gotCtxtIDBytes)
+ {
+ m_gotCtxtIDBytes++;
+ }
+ }
+
+ // check if we have enough bytes
+ bGotBytes = (bool)((unsigned)m_numPktBytesReq == m_currPacketData.size());
+ }
+ else
+ validByte = false; // no byte available, exit.
+ }
+
+ if(bGotBytes)
+ {
+ // extract address value, cycle count and ctxt id.
+ uint32_t cycleCount = 0;
+ uint32_t ctxtID = 0;
+ int optIdx = 6; // start index for optional elements.
+
+ // address is always full fixed 32 bit value
+ uint32_t address = ((uint32_t)m_currPacketData[1]) & 0xFE;
+ address |= ((uint32_t)m_currPacketData[2]) << 8;
+ address |= ((uint32_t)m_currPacketData[3]) << 16;
+ address |= ((uint32_t)m_currPacketData[4]) << 24;
+ m_curr_packet.UpdateAddress(address,32);
+
+ if(m_needCycleCount)
+ {
+ extractCycleCount(optIdx,cycleCount);
+ m_curr_packet.SetCycleCount(cycleCount);
+ optIdx+=m_gotCCBytes;
+ }
+
+ if(m_numCtxtIDBytes)
+ {
+ extractCtxtID(optIdx,ctxtID);
+ m_curr_packet.UpdateContextID(ctxtID);
+ }
+ m_process_state = SEND_PKT;
+ }
+}
+
+void TrcPktProcPtm::pktTrigger()
+{
+ m_process_state = SEND_PKT; // no payload
+}
+
+void TrcPktProcPtm::pktWPointUpdate()
+{
+ bool bDone = false;
+ bool bBytesAvail = true;
+ uint8_t currByte = 0;
+ int byteIdx = 0;
+
+ if(m_currPacketData.size() == 1)
+ {
+ m_gotAddrBytes = false; // flag to indicate got all needed address bytes
+ m_numAddrBytes = 0; // number of address bytes so far - in this case header is not part of the address
+
+ m_gotExcepBytes = false; // mark as not got all required exception bytes thus far
+ m_numExcepBytes = 0; // 0 read in
+
+ m_addrPktIsa = ocsd_isa_unknown; // not set by this packet as yet
+ }
+
+ // collect all the bytes needed
+ while(!bDone && bBytesAvail)
+ {
+ if(readByte(currByte))
+ {
+
+ byteIdx = m_currPacketData.size() - 1;
+ if(!m_gotAddrBytes)
+ {
+ // byteIdx for address byte will run from 1 to 5 - first 4 my have continuation or not.
+ if(byteIdx <= 4)
+ {
+ // address bytes 1 - 4;
+ // ISA stays the same
+ if((currByte & 0x80) == 0x00)
+ {
+ // no further bytes
+ m_gotAddrBytes = true;
+ bDone = true;
+ m_gotExcepBytes = true;
+ }
+ }
+ else
+ {
+ // 5th address byte - determine ISA from this.
+ if((currByte & 0x40) == 0x00)
+ m_gotExcepBytes = true; // no exception bytes - mark as done
+ m_gotAddrBytes = true;
+ bDone = m_gotExcepBytes;
+
+ m_addrPktIsa = ocsd_isa_arm; // assume ARM, but then check
+ if((currByte & 0x20) == 0x20) // bit 5 == 1'b1 - jazelle, bits 4 & 3 part of address.
+ m_addrPktIsa = ocsd_isa_jazelle;
+ else if((currByte & 0x30) == 0x10) // bit [5:4] == 2'b01 - thumb, bit 3 part of address.
+ m_addrPktIsa = ocsd_isa_thumb2;
+ }
+ m_numAddrBytes++;
+ }
+ else if(!m_gotExcepBytes)
+ {
+ // excep byte is actually a WP update byte.
+ m_excepAltISA = ((currByte & 0x40) == 0x40) ? 1 : 0;
+ m_gotExcepBytes = true;
+ m_numExcepBytes++;
+ bDone = true;
+ }
+ }
+ else
+ bBytesAvail = false;
+ }
+
+ // analyse the bytes to create the packet
+ if(bDone)
+ {
+ // ISA for the packet
+ if(m_addrPktIsa == ocsd_isa_unknown) // unchanged by trace packet
+ m_addrPktIsa = m_curr_packet.getISA(); // same as prev
+
+ if(m_gotExcepBytes) // may adjust according to alt ISA in exception packet
+ {
+ if((m_addrPktIsa == ocsd_isa_tee) && (m_excepAltISA == 0))
+ m_addrPktIsa = ocsd_isa_thumb2;
+ else if((m_addrPktIsa == ocsd_isa_thumb2) && (m_excepAltISA == 1))
+ m_addrPktIsa = ocsd_isa_tee;
+ }
+ m_curr_packet.UpdateISA(m_addrPktIsa); // mark ISA in packet (update changes current and prev to dectect an ISA change).
+
+ uint8_t total_bits = 0;
+ uint32_t addr_val = extractAddress(1,total_bits);
+ m_curr_packet.UpdateAddress(addr_val,total_bits);
+ m_process_state = SEND_PKT;
+ }
+}
+
+void TrcPktProcPtm::pktIgnore()
+{
+ m_process_state = SEND_PKT; // no payload
+}
+
+void TrcPktProcPtm::pktCtxtID()
+{
+ int pktIndex = m_currPacketData.size() - 1;
+
+ // if at the header, determine how many more bytes we need.
+ if(pktIndex == 0)
+ {
+ m_numCtxtIDBytes = m_config->CtxtIDBytes();
+ m_gotCtxtIDBytes = 0;
+ }
+
+ // read the necessary ctxtID bytes from the stream
+ bool bGotBytes = false, bytesAvail = true;
+ uint32_t ctxtID = 0;
+
+ bGotBytes = m_numCtxtIDBytes == m_gotCtxtIDBytes;
+ while(!bGotBytes & bytesAvail)
+ {
+ bytesAvail = readByte();
+ if(bytesAvail)
+ m_gotCtxtIDBytes++;
+ bGotBytes = m_numCtxtIDBytes == m_gotCtxtIDBytes;
+ }
+
+ if(bGotBytes)
+ {
+ if(m_numCtxtIDBytes)
+ {
+ extractCtxtID(1,ctxtID);
+ }
+ m_curr_packet.UpdateContextID(ctxtID);
+ m_process_state = SEND_PKT;
+ }
+}
+
+void TrcPktProcPtm::pktVMID()
+{
+ uint8_t currByte;
+
+ // just need a single payload byte...
+ if(readByte(currByte))
+ {
+ m_curr_packet.UpdateVMID(currByte);
+ m_process_state = SEND_PKT;
+ }
+}
+
+void TrcPktProcPtm::pktAtom()
+{
+ uint8_t pHdr = m_currPacketData[0];
+
+ if(!m_config->enaCycleAcc())
+ {
+ m_curr_packet.SetAtomFromPHdr(pHdr);
+ m_process_state = SEND_PKT;
+ }
+ else
+ {
+ bool bGotAllPktBytes = false, byteAvail = true;
+ uint8_t currByte = 0; // cycle accurate tracing -> atom + cycle count
+
+ if(!(pHdr & 0x40))
+ {
+ // only the header byte present
+ bGotAllPktBytes = true;
+ }
+ else
+ {
+ // up to 4 additional bytes of count data.
+ while(byteAvail && !bGotAllPktBytes)
+ {
+ if(readByte(currByte))
+ {
+ if(!(currByte & 0x80) || (m_currPacketData.size() == 5))
+ bGotAllPktBytes = true;
+ }
+ else
+ byteAvail = false;
+ }
+ }
+
+ // we have all the bytes for a cycle accurate packet.
+ if(bGotAllPktBytes)
+ {
+ uint32_t cycleCount = 0;
+ extractCycleCount(0,cycleCount);
+ m_curr_packet.SetCycleCount(cycleCount);
+ m_curr_packet.SetCycleAccAtomFromPHdr(pHdr);
+ m_process_state = SEND_PKT;
+ }
+ }
+}
+
+void TrcPktProcPtm::pktTimeStamp()
+{
+ uint8_t currByte = 0;
+ int pktIndex = m_currPacketData.size() - 1;
+ bool bGotBytes = false, byteAvail = true;
+
+ if(pktIndex == 0)
+ {
+ m_gotTSBytes = false;
+ m_needCycleCount = m_config->enaCycleAcc();
+ m_gotCCBytes = 0;
+
+ // max byte buffer size for full ts packet
+ m_tsByteMax = m_config->TSPkt64() ? 10 : 8;
+ }
+
+ while(byteAvail && !bGotBytes)
+ {
+ if(readByte(currByte))
+ {
+ if(!m_gotTSBytes)
+ {
+ if(((currByte & 0x80) == 0) || (m_currPacketData.size() == (unsigned)m_tsByteMax))
+ {
+ m_gotTSBytes = true;
+ if(!m_needCycleCount)
+ bGotBytes = true;
+ }
+ }
+ else
+ {
+ uint8_t cc_cont_mask = 0x80;
+ // got TS bytes, collect cycle count
+ if(m_gotCCBytes == 0)
+ cc_cont_mask = 0x40;
+ if((currByte & cc_cont_mask) == 0)
+ bGotBytes = true;
+ m_gotCCBytes++;
+ if(m_gotCCBytes == 5)
+ bGotBytes = true;
+ }
+ }
+ else
+ byteAvail = false;
+ }
+
+ if(bGotBytes)
+ {
+ uint64_t tsVal = 0;
+ uint32_t cycleCount = 0;
+ uint8_t tsUpdateBits = 0;
+ int ts_end_idx = extractTS(tsVal,tsUpdateBits);
+ if(m_needCycleCount)
+ {
+ extractCycleCount(ts_end_idx,cycleCount);
+ m_curr_packet.SetCycleCount(cycleCount);
+ }
+ m_curr_packet.UpdateTimestamp(tsVal,tsUpdateBits);
+ m_process_state = SEND_PKT;
+ }
+}
+
+void TrcPktProcPtm::pktExceptionRet()
+{
+ m_process_state = SEND_PKT; // no payload
+}
+
+void TrcPktProcPtm::pktBranchAddr()
+{
+ uint8_t currByte = m_currPacketData[0];
+ bool bDone = false;
+ bool bBytesAvail = true;
+ int byteIdx = 0;
+
+ if(m_currPacketData.size() == 1)
+ {
+ m_gotAddrBytes = false; // flag to indicate got all needed address bytes
+ m_numAddrBytes = 1; // number of address bytes so far
+
+ m_needCycleCount = m_config->enaCycleAcc(); // check if we have a cycle count
+ m_gotCCBytes = 0; // number of cc bytes read in so far.
+
+ m_gotExcepBytes = false; // mark as not got all required exception bytes thus far
+ m_numExcepBytes = 0; // 0 read in
+
+ m_addrPktIsa = ocsd_isa_unknown; // not set by this packet as yet
+
+ // header is also 1st address byte
+ if((currByte & 0x80) == 0) // could be single byte packet
+ {
+ m_gotAddrBytes = true;
+ if(!m_needCycleCount)
+ bDone = true; // all done if no cycle count
+ m_gotExcepBytes = true; // cannot have exception bytes following single byte packet
+ }
+
+ }
+
+ // collect all the bytes needed
+ while(!bDone && bBytesAvail)
+ {
+ if(readByte(currByte))
+ {
+ byteIdx = m_currPacketData.size() - 1;
+ if(!m_gotAddrBytes)
+ {
+ if(byteIdx < 4)
+ {
+ // address bytes 2 - 4;
+ // ISA stays the same
+ if((currByte & 0x80) == 0x00)
+ {
+ // no further bytes
+ if((currByte & 0x40) == 0x00)
+ m_gotExcepBytes = true; // no exception bytes - mark as done
+ m_gotAddrBytes = true;
+ bDone = m_gotExcepBytes && !m_needCycleCount;
+ }
+ }
+ else
+ {
+ // 5th address byte - determine ISA from this.
+ if((currByte & 0x40) == 0x00)
+ m_gotExcepBytes = true; // no exception bytes - mark as done
+ m_gotAddrBytes = true;
+ bDone = m_gotExcepBytes && !m_needCycleCount;
+
+ m_addrPktIsa = ocsd_isa_arm; // assume ARM, but then check
+ if((currByte & 0x20) == 0x20) // bit 5 == 1'b1 - jazelle, bits 4 & 3 part of address.
+ m_addrPktIsa = ocsd_isa_jazelle;
+ else if((currByte & 0x30) == 0x10) // bit [5:4] == 2'b01 - thumb, bit 3 part of address.
+ m_addrPktIsa = ocsd_isa_thumb2;
+ }
+ m_numAddrBytes++;
+ }
+ else if(!m_gotExcepBytes)
+ {
+ // may need exception bytes
+ if(m_numExcepBytes == 0)
+ {
+ if((currByte & 0x80) == 0x00)
+ m_gotExcepBytes = true;
+ m_excepAltISA = ((currByte & 0x40) == 0x40) ? 1 : 0;
+ }
+ else
+ m_gotExcepBytes = true;
+ m_numExcepBytes++;
+
+ if(m_gotExcepBytes && !m_needCycleCount)
+ bDone = true;
+
+ }
+ else if(m_needCycleCount)
+ {
+ // not done after exception bytes, collect cycle count
+ if(m_gotCCBytes == 0)
+ {
+ bDone = ((currByte & 0x40) == 0x00 );
+ }
+ else
+ {
+ // done if no more or 5th byte
+ bDone = (((currByte & 0x80) == 0x00 ) || (m_gotCCBytes == 4));
+ }
+ m_gotCCBytes++;
+ }
+ else
+ // this should never be reached.
+ throwMalformedPacketErr("sequencing error analysing branch packet");
+ }
+ else
+ bBytesAvail = false;
+ }
+
+ // analyse the bytes to create the packet
+ if(bDone)
+ {
+ // ISA for the packet
+ if(m_addrPktIsa == ocsd_isa_unknown) // unchanged by trace packet
+ m_addrPktIsa = m_curr_packet.getISA(); // same as prev
+
+ if(m_gotExcepBytes) // may adjust according to alt ISA in exception packet
+ {
+ if((m_addrPktIsa == ocsd_isa_tee) && (m_excepAltISA == 0))
+ m_addrPktIsa = ocsd_isa_thumb2;
+ else if((m_addrPktIsa == ocsd_isa_thumb2) && (m_excepAltISA == 1))
+ m_addrPktIsa = ocsd_isa_tee;
+ }
+ m_curr_packet.UpdateISA(m_addrPktIsa); // mark ISA in packet (update changes current and prev to dectect an ISA change).
+
+
+
+ // we know the ISA, we can correctly interpret the address.
+ uint8_t total_bits = 0;
+ uint32_t addr_val = extractAddress(0,total_bits);
+ m_curr_packet.UpdateAddress(addr_val,total_bits);
+
+ if(m_numExcepBytes > 0)
+ {
+ uint8_t E1 = m_currPacketData[m_numAddrBytes];
+ uint16_t ENum = (E1 >> 1) & 0xF;
+ ocsd_armv7_exception excep = Excp_Reserved;
+
+ m_curr_packet.UpdateNS(E1 & 0x1);
+ if(m_numExcepBytes > 1)
+ {
+ uint8_t E2 = m_currPacketData[m_numAddrBytes+1];
+ m_curr_packet.UpdateHyp((E2 >> 5) & 0x1);
+ ENum |= ((uint16_t)(E2 & 0x1F) << 4);
+ }
+
+ if(ENum <= 0xF)
+ {
+ static ocsd_armv7_exception v7ARExceptions[16] = {
+ Excp_NoException, Excp_DebugHalt, Excp_SMC, Excp_Hyp,
+ Excp_AsyncDAbort, Excp_ThumbEECheckFail, Excp_Reserved, Excp_Reserved,
+ Excp_Reset, Excp_Undef, Excp_SVC, Excp_PrefAbort,
+ Excp_SyncDataAbort, Excp_Generic, Excp_IRQ, Excp_FIQ
+ };
+ excep = v7ARExceptions[ENum];
+ }
+ m_curr_packet.SetException(excep,ENum);
+ }
+
+ if(m_needCycleCount)
+ {
+ int countIdx = m_numAddrBytes + m_numExcepBytes;
+ uint32_t cycleCount = 0;
+ extractCycleCount(countIdx,cycleCount);
+ m_curr_packet.SetCycleCount(cycleCount);
+ }
+ m_process_state = SEND_PKT;
+ }
+}
+
+void TrcPktProcPtm::pktReserved()
+{
+ m_process_state = SEND_PKT; // no payload
+}
+
+void TrcPktProcPtm::extractCtxtID(int idx, uint32_t &ctxtID)
+{
+ ctxtID = 0;
+ int shift = 0;
+ for(int i=0; i < m_numCtxtIDBytes; i++)
+ {
+ if((size_t)idx+i >= m_currPacketData.size())
+ throwMalformedPacketErr("Insufficient packet bytes for Context ID value.");
+ ctxtID |= ((uint32_t)m_currPacketData[idx+i]) << shift;
+ shift+=8;
+ }
+}
+
+void TrcPktProcPtm::extractCycleCount(int offset, uint32_t &cycleCount)
+{
+ bool bCont = true;
+ cycleCount = 0;
+ int by_idx = 0;
+ uint8_t currByte;
+ int shift = 4;
+
+ while(bCont)
+ {
+ if((size_t)by_idx+offset >= m_currPacketData.size())
+ throwMalformedPacketErr("Insufficient packet bytes for Cycle Count value.");
+
+ currByte = m_currPacketData[offset+by_idx];
+ if(by_idx == 0)
+ {
+ bCont = (currByte & 0x40) != 0;
+ cycleCount = (currByte >> 2) & 0xF;
+ }
+ else
+ {
+
+ bCont = (currByte & 0x80) != 0;
+ if(by_idx == 4)
+ bCont = false;
+ cycleCount |= (((uint32_t)(currByte & 0x7F)) << shift);
+ shift += 7;
+ }
+ by_idx++;
+ }
+}
+
+int TrcPktProcPtm::extractTS(uint64_t &tsVal,uint8_t &tsUpdateBits)
+{
+ bool bCont = true;
+ int tsIdx = 1; // start index;
+ uint8_t byteVal;
+ bool b64BitVal = m_config->TSPkt64();
+ int shift = 0;
+
+ tsVal = 0;
+ tsUpdateBits = 0;
+
+ while(bCont)
+ {
+ if((size_t)tsIdx >= m_currPacketData.size())
+ throwMalformedPacketErr("Insufficient packet bytes for Timestamp value.");
+
+ byteVal = m_currPacketData[tsIdx];
+
+ if(b64BitVal)
+ {
+ if(tsIdx < 9)
+ {
+ bCont = ((byteVal & 0x80) == 0x80);
+ byteVal &= 0x7F;
+ tsUpdateBits += 7;
+ }
+ else
+ {
+ bCont = false;
+ tsUpdateBits += 8;
+ }
+ }
+ else
+ {
+ if(tsIdx < 7)
+ {
+ bCont = ((byteVal & 0x80) == 0x80);
+ byteVal &= 0x7F;
+ tsUpdateBits += 7;
+ }
+ else
+ {
+ byteVal &=0x3F;
+ bCont = false;
+ tsUpdateBits += 6;
+ }
+ }
+ tsVal |= (((uint64_t)byteVal) << shift);
+ tsIdx++;
+ shift += 7;
+ }
+ return tsIdx; // return next byte index in packet.
+}
+
+uint32_t TrcPktProcPtm::extractAddress(const int offset, uint8_t &total_bits)
+{
+ // we know the ISA, we can correctly interpret the address.
+ uint32_t addr_val = 0;
+ uint8_t mask = 0x7E; // first byte mask (always);
+ uint8_t num_bits = 0x7; // number of bits in the 1st byte (thumb);
+ int shift = 0;
+ int next_shift = 0;
+
+ total_bits = 0;
+
+ for(int i = 0; i < m_numAddrBytes; i++)
+ {
+ if(i == 4)
+ {
+ // 5th byte mask
+ mask = 0x0f; // thumb mask;
+ num_bits = 4;
+ if(m_addrPktIsa == ocsd_isa_jazelle)
+ {
+ mask = 0x1F;
+ num_bits = 5;
+ }
+ else if(m_addrPktIsa == ocsd_isa_arm)
+ {
+ mask = 0x07;
+ num_bits = 3;
+ }
+ }
+ else if(i > 0)
+ {
+ mask = 0x7F;
+ num_bits = 7;
+ // check for last byte but not 1st or 5th byte mask
+ if(i == m_numAddrBytes-1)
+ {
+ mask = 0x3F;
+ num_bits = 6;
+ }
+ }
+
+ // extract data
+ shift = next_shift;
+ addr_val |= ((uint32_t)(m_currPacketData[i+offset] & mask) << shift);
+ total_bits += num_bits;
+
+ // how much we shift the next value
+ if(i == 0)
+ {
+ if(m_addrPktIsa == ocsd_isa_jazelle)
+ {
+ addr_val >>= 1;
+ next_shift = 6;
+ total_bits--; // adjust bits for jazelle offset
+ }
+ else
+ {
+ next_shift = 7;
+ }
+ }
+ else
+ {
+ next_shift += 7;
+ }
+ }
+
+ if(m_addrPktIsa == ocsd_isa_arm)
+ {
+ addr_val <<= 1; // shift one extra bit for ARM address alignment.
+ total_bits++;
+ }
+ return addr_val;
+}
+
+
+void TrcPktProcPtm::BuildIPacketTable()
+{
+ // initialise all to branch, atom or reserved packet header
+ for(unsigned i = 0; i < 256; i++)
+ {
+ // branch address packets all end in 8'bxxxxxxx1
+ if((i & 0x01) == 0x01)
+ {
+ m_i_table[i].pkt_type = PTM_PKT_BRANCH_ADDRESS;
+ m_i_table[i].pptkFn = &TrcPktProcPtm::pktBranchAddr;
+ }
+ // atom packets are 8'b1xxxxxx0
+ else if((i & 0x81) == 0x80)
+ {
+ m_i_table[i].pkt_type = PTM_PKT_ATOM;
+ m_i_table[i].pptkFn = &TrcPktProcPtm::pktAtom;
+ }
+ else
+ {
+ // set all the others to reserved for now
+ m_i_table[i].pkt_type = PTM_PKT_RESERVED;
+ m_i_table[i].pptkFn = &TrcPktProcPtm::pktReserved;
+ }
+ }
+
+ // pick out the other packet types by individual codes.
+
+ // A-sync 8'b00000000
+ m_i_table[0x00].pkt_type = PTM_PKT_A_SYNC;
+ m_i_table[0x00].pptkFn = &TrcPktProcPtm::pktASync;
+
+ // I-sync 8'b00001000
+ m_i_table[0x08].pkt_type = PTM_PKT_I_SYNC;
+ m_i_table[0x08].pptkFn = &TrcPktProcPtm::pktISync;
+
+ // waypoint update 8'b01110010
+ m_i_table[0x72].pkt_type = PTM_PKT_WPOINT_UPDATE;
+ m_i_table[0x72].pptkFn = &TrcPktProcPtm::pktWPointUpdate;
+
+ // trigger 8'b00001100
+ m_i_table[0x0C].pkt_type = PTM_PKT_TRIGGER;
+ m_i_table[0x0C].pptkFn = &TrcPktProcPtm::pktTrigger;
+
+ // context ID 8'b01101110
+ m_i_table[0x6E].pkt_type = PTM_PKT_CONTEXT_ID;
+ m_i_table[0x6E].pptkFn = &TrcPktProcPtm::pktCtxtID;
+
+ // VMID 8'b00111100
+ m_i_table[0x3C].pkt_type = PTM_PKT_VMID;
+ m_i_table[0x3C].pptkFn = &TrcPktProcPtm::pktVMID;
+
+ // Timestamp 8'b01000x10
+ m_i_table[0x42].pkt_type = PTM_PKT_TIMESTAMP;
+ m_i_table[0x42].pptkFn = &TrcPktProcPtm::pktTimeStamp;
+ m_i_table[0x46].pkt_type = PTM_PKT_TIMESTAMP;
+ m_i_table[0x46].pptkFn = &TrcPktProcPtm::pktTimeStamp;
+
+ // Exception return 8'b01110110
+ m_i_table[0x76].pkt_type = PTM_PKT_EXCEPTION_RET;
+ m_i_table[0x76].pptkFn = &TrcPktProcPtm::pktExceptionRet;
+
+ // Ignore 8'b01100110
+ m_i_table[0x66].pkt_type = PTM_PKT_IGNORE;
+ m_i_table[0x66].pptkFn = &TrcPktProcPtm::pktIgnore;
+}
+
+/* End of File trc_pkt_proc_ptm.cpp */