diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 07:24:57 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 07:24:57 +0000 |
commit | 070852d8604cece0c31f28ff3eb8d21d9ba415fb (patch) | |
tree | 9097175a6a5b8b7e37af9a96269ac0b61a0189cd /decoder/source/ptm | |
parent | Initial commit. (diff) | |
download | libopencsd-070852d8604cece0c31f28ff3eb8d21d9ba415fb.tar.xz libopencsd-070852d8604cece0c31f28ff3eb8d21d9ba415fb.zip |
Adding upstream version 1.3.3.upstream/1.3.3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'decoder/source/ptm')
-rw-r--r-- | decoder/source/ptm/trc_cmp_cfg_ptm.cpp | 59 | ||||
-rw-r--r-- | decoder/source/ptm/trc_pkt_decode_ptm.cpp | 671 | ||||
-rw-r--r-- | decoder/source/ptm/trc_pkt_elem_ptm.cpp | 473 | ||||
-rw-r--r-- | decoder/source/ptm/trc_pkt_proc_ptm.cpp | 1218 |
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 */ |