| /* |
| * \file trc_pkt_decode_stm.cpp |
| * \brief OpenCSD : STM packet decoder - output generic SW trace packets. |
| * |
| * \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 "opencsd/stm/trc_pkt_decode_stm.h" |
| #define DCD_NAME "DCD_STM" |
| |
| TrcPktDecodeStm::TrcPktDecodeStm() |
| : TrcPktDecodeBase(DCD_NAME) |
| { |
| initDecoder(); |
| } |
| |
| TrcPktDecodeStm::TrcPktDecodeStm(int instIDNum) |
| : TrcPktDecodeBase(DCD_NAME, instIDNum) |
| { |
| initDecoder(); |
| } |
| |
| TrcPktDecodeStm::~TrcPktDecodeStm() |
| { |
| if(m_payload_buffer) |
| delete [] m_payload_buffer; |
| m_payload_buffer = 0; |
| } |
| |
| /* implementation packet decoding interface */ |
| ocsd_datapath_resp_t TrcPktDecodeStm::processPacket() |
| { |
| ocsd_datapath_resp_t resp = OCSD_RESP_CONT; |
| bool bPktDone = false; |
| |
| m_decode_pass1 = true; |
| |
| while(!bPktDone) |
| { |
| switch(m_curr_state) |
| { |
| case NO_SYNC: |
| m_output_elem.setType(OCSD_GEN_TRC_ELEM_NO_SYNC); |
| m_output_elem.setUnSyncEOTReason(m_unsync_info); |
| resp = outputTraceElement(m_output_elem); |
| m_curr_state = WAIT_SYNC; |
| break; |
| |
| case WAIT_SYNC: |
| if(m_curr_packet_in->getPktType() == STM_PKT_ASYNC) |
| m_curr_state = DECODE_PKTS; |
| bPktDone = true; |
| break; |
| |
| case DECODE_PKTS: |
| resp = decodePacket(bPktDone); |
| break; |
| } |
| } |
| return resp; |
| } |
| |
| ocsd_datapath_resp_t TrcPktDecodeStm::onEOT() |
| { |
| ocsd_datapath_resp_t resp = OCSD_RESP_CONT; |
| 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 TrcPktDecodeStm::onReset() |
| { |
| ocsd_datapath_resp_t resp = OCSD_RESP_CONT; |
| m_unsync_info = UNSYNC_RESET_DECODER; |
| resetDecoder(); |
| return resp; |
| } |
| |
| ocsd_datapath_resp_t TrcPktDecodeStm::onFlush() |
| { |
| ocsd_datapath_resp_t resp = OCSD_RESP_CONT; |
| // don't currently save unsent packets so nothing to flush |
| return resp; |
| } |
| |
| ocsd_err_t TrcPktDecodeStm::onProtocolConfig() |
| { |
| if(m_config == 0) |
| return OCSD_ERR_NOT_INIT; |
| |
| // static config - copy of CSID for easy reference |
| m_CSID = m_config->getTraceID(); |
| return OCSD_OK; |
| } |
| |
| void TrcPktDecodeStm::initDecoder() |
| { |
| m_payload_buffer = 0; |
| m_num_pkt_correlation = 1; // fixed at single packet payload correlation - add feature later |
| m_CSID = 0; |
| |
| // base decoder state - STM requires no memory and instruction decode. |
| setUsesMemAccess(false); |
| setUsesIDecode(false); |
| m_unsync_info = UNSYNC_INIT_DECODER; |
| resetDecoder(); |
| } |
| |
| void TrcPktDecodeStm::resetDecoder() |
| { |
| m_curr_state = NO_SYNC; |
| m_payload_size = 0; |
| m_payload_used = 0; |
| m_payload_odd_nibble = false; |
| m_output_elem.init(); |
| m_swt_packet_info.swt_flag_bits = 0; // zero out everything |
| initPayloadBuffer(); |
| } |
| |
| void TrcPktDecodeStm::initPayloadBuffer() |
| { |
| // set up the payload buffer. If we are correlating indentical packets then |
| // need a buffer that is a multiple of 64bit packets. |
| // otherwise a single packet length will do. |
| if(m_payload_buffer) |
| delete [] m_payload_buffer; |
| m_payload_buffer = new (std::nothrow) uint8_t[m_num_pkt_correlation * sizeof(uint64_t)]; |
| } |
| |
| ocsd_datapath_resp_t TrcPktDecodeStm::decodePacket(bool &bPktDone) |
| { |
| ocsd_datapath_resp_t resp = OCSD_RESP_CONT; |
| bool bSendPacket = false; // flag to indicate output required. |
| |
| bPktDone = true; // assume complete unless 2nd pass required. |
| m_output_elem.setType(OCSD_GEN_TRC_ELEM_SWTRACE); |
| clearSWTPerPcktInfo(); |
| |
| switch (m_curr_packet_in->getPktType()) |
| { |
| case STM_PKT_BAD_SEQUENCE: /**< Incorrect protocol sequence */ |
| case STM_PKT_RESERVED: |
| resp = OCSD_RESP_FATAL_INVALID_DATA; |
| m_unsync_info = UNSYNC_BAD_PACKET; |
| case STM_PKT_NOTSYNC: |
| resetDecoder(); |
| break; |
| |
| case STM_PKT_VERSION: /**< Version packet - not relevant to generic (versionless) o/p */ |
| case STM_PKT_ASYNC: /**< Alignment synchronisation packet */ |
| case STM_PKT_INCOMPLETE_EOT: /**< Incomplete packet flushed at end of trace. */ |
| // no action required. |
| break; |
| |
| /* markers for valid packets*/ |
| case STM_PKT_NULL: /**< Null packet */ |
| if(m_curr_packet_in->isTSPkt()) |
| bSendPacket = true; // forward NULL packet if associated timestamp. |
| break; |
| |
| case STM_PKT_FREQ: /**< Frequency packet */ |
| m_swt_packet_info.swt_frequency = 1; |
| updatePayload(bSendPacket); |
| break; |
| |
| case STM_PKT_TRIG: /**< Trigger event packet. */ |
| m_swt_packet_info.swt_trigger_event = 1; |
| updatePayload(bSendPacket); |
| break; |
| |
| case STM_PKT_GERR: /**< Global error packet - protocol error but unknown which master had error */ |
| m_swt_packet_info.swt_master_id = m_curr_packet_in->getMaster(); |
| m_swt_packet_info.swt_channel_id = m_curr_packet_in->getChannel(); |
| m_swt_packet_info.swt_global_err = 1; |
| m_swt_packet_info.swt_id_valid = 0; |
| updatePayload(bSendPacket); |
| break; |
| |
| case STM_PKT_MERR: /**< Master error packet - current master detected an error (e.g. dropped trace) */ |
| m_swt_packet_info.swt_channel_id = m_curr_packet_in->getChannel(); |
| m_swt_packet_info.swt_master_err = 1; |
| updatePayload(bSendPacket); |
| break; |
| |
| case STM_PKT_M8: /**< Set current master */ |
| m_swt_packet_info.swt_master_id = m_curr_packet_in->getMaster(); |
| m_swt_packet_info.swt_channel_id = m_curr_packet_in->getChannel(); // forced to 0 |
| m_swt_packet_info.swt_id_valid = 1; |
| break; |
| |
| case STM_PKT_C8: /**< Set lower 8 bits of current channel - packet proc hadnles this */ |
| case STM_PKT_C16: /**< Set current channel */ |
| m_swt_packet_info.swt_channel_id = m_curr_packet_in->getChannel(); |
| break; |
| |
| case STM_PKT_FLAG: /**< Flag packet */ |
| m_swt_packet_info.swt_marker_packet = 1; |
| bSendPacket = true; // send 0 payload marker packet./ |
| break; |
| |
| |
| case STM_PKT_D4: /**< 4 bit data payload packet */ |
| case STM_PKT_D8: /**< 8 bit data payload packet */ |
| case STM_PKT_D16: /**< 16 bit data payload packet */ |
| case STM_PKT_D32: /**< 32 bit data payload packet */ |
| case STM_PKT_D64: /**< 64 bit data payload packet */ |
| updatePayload(bSendPacket); |
| break; |
| |
| } |
| |
| if(bSendPacket) |
| { |
| if(m_curr_packet_in->isTSPkt()) |
| { |
| m_output_elem.setTS(m_curr_packet_in->getTSVal()); |
| m_swt_packet_info.swt_has_timestamp = 1; |
| } |
| m_output_elem.setSWTInfo(m_swt_packet_info); |
| resp = outputTraceElement(m_output_elem); |
| } |
| |
| return resp; |
| } |
| |
| void TrcPktDecodeStm::clearSWTPerPcktInfo() |
| { |
| m_swt_packet_info.swt_flag_bits &= (uint32_t)(0x0 | SWT_ID_VALID_MASK); // clear flags and current payload size (save id valid flag). |
| } |
| |
| void TrcPktDecodeStm::updatePayload(bool &bSendPacket) |
| { |
| // without buffering similar packets - this function is quite simple |
| bSendPacket = true; |
| m_swt_packet_info.swt_payload_num_packets = 1; |
| |
| switch(m_curr_packet_in->getPktType()) |
| { |
| case STM_PKT_D4: /**< 4 bit data payload packet */ |
| m_swt_packet_info.swt_payload_pkt_bitsize = 4; |
| *(uint8_t *)m_payload_buffer = m_curr_packet_in->getD4Val(); |
| break; |
| |
| case STM_PKT_D8: /**< 8 bit data payload packet */ |
| case STM_PKT_TRIG: /**< Trigger event packet - 8 bits. */ |
| case STM_PKT_GERR: /**< error packet - 8 bits. */ |
| case STM_PKT_MERR: /**< error packet - 8 bits. */ |
| m_swt_packet_info.swt_payload_pkt_bitsize = 8; |
| *(uint8_t *)m_payload_buffer = m_curr_packet_in->getD8Val(); |
| break; |
| |
| case STM_PKT_D16: /**< 16 bit data payload packet */ |
| m_swt_packet_info.swt_payload_pkt_bitsize = 16; |
| *(uint16_t *)m_payload_buffer = m_curr_packet_in->getD16Val(); |
| break; |
| |
| case STM_PKT_D32: /**< 32 bit data payload packet */ |
| case STM_PKT_FREQ: /**< Frequency packet */ |
| m_swt_packet_info.swt_payload_pkt_bitsize = 32; |
| *(uint32_t *)m_payload_buffer = m_curr_packet_in->getD32Val(); |
| break; |
| |
| |
| case STM_PKT_D64: /**< 64 bit data payload packet */ |
| m_swt_packet_info.swt_payload_pkt_bitsize = 64; |
| *(uint64_t *)m_payload_buffer = m_curr_packet_in->getD64Val(); |
| break; |
| } |
| m_output_elem.setExtendedDataPtr(m_payload_buffer); |
| if (m_curr_packet_in->isMarkerPkt()) |
| m_swt_packet_info.swt_marker_packet = 1; |
| |
| } |
| |
| /* End of File trc_pkt_decode_stm.cpp */ |