1 /*!
2  * \file       trc_pkt_decode_etmv3.cpp
3  * \brief      OpenCSD : ETMv3 trace packet decode.
4  *
5  * \copyright  Copyright (c) 2015, ARM Limited. All Rights Reserved.
6  */
7 
8 /*
9  * Redistribution and use in source and binary forms, with or without modification,
10  * are permitted provided that the following conditions are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  *
19  * 3. Neither the name of the copyright holder nor the names of its contributors
20  * may be used to endorse or promote products derived from this software without
21  * specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include "opencsd/etmv3/trc_pkt_decode_etmv3.h"
36 
37 #define DCD_NAME "DCD_ETMV3"
38 
39 TrcPktDecodeEtmV3::TrcPktDecodeEtmV3() :
40     TrcPktDecodeBase(DCD_NAME)
41 {
42     initDecoder();
43 }
44 
45 TrcPktDecodeEtmV3::TrcPktDecodeEtmV3(int instIDNum) :
46     TrcPktDecodeBase(DCD_NAME, instIDNum)
47 {
48     initDecoder();
49 }
50 
51 TrcPktDecodeEtmV3::~TrcPktDecodeEtmV3()
52 {
53 }
54 
55 
56 /* implementation packet decoding interface */
57 ocsd_datapath_resp_t TrcPktDecodeEtmV3::processPacket()
58 {
59     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
60     bool bPktDone = false;
61 
62     if(!m_config)
63         return OCSD_RESP_FATAL_NOT_INIT;
64 
65     // iterate round the state machine, waiting for sync, then decoding packets.
66     while(!bPktDone)
67     {
68         switch(m_curr_state)
69         {
70         case NO_SYNC:
71             // output the initial not synced packet to the sink
72             resp = sendUnsyncPacket();
73             m_curr_state = WAIT_ASYNC;  // immediate wait for ASync and actually check out the packet
74             break;
75 
76         case WAIT_ASYNC:
77             // if async, wait for ISync, but this packet done.
78             if(m_curr_packet_in->getType() == ETM3_PKT_A_SYNC)
79                 m_curr_state = WAIT_ISYNC;
80             bPktDone = true;
81             break;
82 
83         case WAIT_ISYNC:
84             m_bWaitISync = true;    // we are waiting for ISync
85             if((m_curr_packet_in->getType() == ETM3_PKT_I_SYNC) ||
86                 (m_curr_packet_in->getType() == ETM3_PKT_I_SYNC_CYCLE))
87             {
88                 // process the ISync immediately as the first ISync seen.
89                 resp = processISync((m_curr_packet_in->getType() == ETM3_PKT_I_SYNC_CYCLE),true);
90                 m_curr_state = SEND_PKTS;
91                 m_bWaitISync = false;
92             }
93             // something like TS, CC, PHDR+CC, which after ASYNC may be valid prior to ISync
94             else if(preISyncValid(m_curr_packet_in->getType()))
95             {
96                 // decode anything that might be valid - send will be set automatically
97                 resp = decodePacket(bPktDone);
98             }
99             else
100                 bPktDone = true;
101             break;
102 
103         case DECODE_PKTS:
104             resp = decodePacket(bPktDone);
105             break;
106 
107         case SEND_PKTS:
108             resp = m_outputElemList.sendElements();
109             if(OCSD_DATA_RESP_IS_CONT(resp))
110                 m_curr_state = m_bWaitISync ? WAIT_ISYNC : DECODE_PKTS;
111             bPktDone = true;
112             break;
113 
114         default:
115             bPktDone = true;
116             LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_FAIL,m_index_curr_pkt,"Unknown Decoder State"));
117             resetDecoder(); // mark decoder as unsynced - dump any current state.
118             resp = OCSD_RESP_FATAL_SYS_ERR;
119             break;
120         }
121     }
122 
123     return resp;
124 }
125 
126 ocsd_datapath_resp_t TrcPktDecodeEtmV3::onEOT()
127 {
128     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
129     OcsdTraceElement *pElem = 0;
130     try {
131         pElem = GetNextOpElem(resp);
132         pElem->setType(OCSD_GEN_TRC_ELEM_EO_TRACE);
133         m_outputElemList.commitAllPendElem();
134         m_curr_state = SEND_PKTS;
135         resp = m_outputElemList.sendElements();
136         if(OCSD_DATA_RESP_IS_CONT(resp))
137             m_curr_state = DECODE_PKTS;
138     }
139     catch(ocsdError &err)
140     {
141         LogError(err);
142         resetDecoder(); // mark decoder as unsynced - dump any current state.
143     }
144     return resp;
145 }
146 
147 ocsd_datapath_resp_t TrcPktDecodeEtmV3::onReset()
148 {
149     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
150     resetDecoder();
151     return resp;
152 }
153 
154 ocsd_datapath_resp_t TrcPktDecodeEtmV3::onFlush()
155 {
156     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
157     if(m_curr_state == SEND_PKTS)
158     {
159         resp = m_outputElemList.sendElements();
160         if(OCSD_DATA_RESP_IS_CONT(resp))
161             m_curr_state = m_bWaitISync ? WAIT_ISYNC : DECODE_PKTS;
162     }
163     return resp;
164 }
165 
166 ocsd_err_t TrcPktDecodeEtmV3::onProtocolConfig()
167 {
168     ocsd_err_t err = OCSD_OK;
169     if(m_config)
170     {
171         // set some static config elements
172         m_CSID = m_config->getTraceID();
173 
174         // check config compatible with current decoder support level.
175         // at present no data trace;
176         if(m_config->GetTraceMode() != EtmV3Config::TM_INSTR_ONLY)
177         {
178             err = OCSD_ERR_HW_CFG_UNSUPP;
179             LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,"ETMv3 trace decoder : data trace decode not yet supported"));
180         }
181 
182         // need to set up core profile info in follower
183         ocsd_arch_profile_t arch_profile;
184         arch_profile.arch = m_config->getArchVersion();
185         arch_profile.profile = m_config->getCoreProfile();
186         m_code_follower.setArchProfile(arch_profile);
187         m_code_follower.setMemSpaceCSID(m_CSID);
188         m_outputElemList.initCSID(m_CSID);
189     }
190     else
191         err = OCSD_ERR_NOT_INIT;
192     return err;
193 }
194 
195 /* local decode methods */
196 
197 // initialise on creation
198 void TrcPktDecodeEtmV3::initDecoder()
199 {
200     m_CSID = 0;
201     resetDecoder();
202     m_code_follower.initInterfaces(getMemoryAccessAttachPt(),getInstrDecodeAttachPt());
203     m_outputElemList.initSendIf(getTraceElemOutAttachPt());
204 }
205 
206 // reset for first use / re-use.
207 void TrcPktDecodeEtmV3::resetDecoder()
208 {
209     m_curr_state = NO_SYNC; // mark as not synced
210     m_bNeedAddr = true;
211     m_bSentUnknown = false;
212     m_bWaitISync = false;
213     m_outputElemList.reset();
214 }
215 
216 OcsdTraceElement *TrcPktDecodeEtmV3::GetNextOpElem(ocsd_datapath_resp_t &resp)
217 {
218     OcsdTraceElement *pElem = m_outputElemList.getNextElem(m_index_curr_pkt);
219     if(pElem == 0)
220     {
221         resp = OCSD_RESP_FATAL_NOT_INIT;
222         throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_MEM,m_index_curr_pkt,m_CSID,"Memory Allocation Error - fatal");
223     }
224     return pElem;
225 }
226 
227 bool TrcPktDecodeEtmV3::preISyncValid(ocsd_etmv3_pkt_type pkt_type)
228 {
229     bool bValid = false;
230     // its a timestamp
231     if((pkt_type == ETM3_PKT_TIMESTAMP) ||
232         // or we are cycleacc and its a packet that can have CC in it
233         (m_config->isCycleAcc() && ((pkt_type == ETM3_PKT_CYCLE_COUNT) || (pkt_type == ETM3_PKT_P_HDR)))
234         )
235         bValid = true;
236     return bValid;
237 }
238 
239 // simple packet transforms handled here, more complex processing passed on to specific routines.
240 ocsd_datapath_resp_t TrcPktDecodeEtmV3::decodePacket(bool &pktDone)
241 {
242     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
243     bool bISyncHasCC = false;
244     OcsdTraceElement *pElem = 0;
245     pktDone = false;
246 
247     // there may be pended packets that can now be committed.
248     // only the branch address with exception and cancel element can cancel
249     // if not one of those, commit immediately, otherwise defer to branch address handler.
250     if(m_curr_packet_in->getType() != ETM3_PKT_BRANCH_ADDRESS)
251         m_outputElemList.commitAllPendElem();
252 
253     try {
254 
255         switch(m_curr_packet_in->getType())
256         {
257 
258         case ETM3_PKT_NOTSYNC:
259             // mark as not synced - must have lost sync in the packet processor somehow
260             throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,m_index_curr_pkt,m_CSID,"Trace Packet Synchronisation Lost");
261             break;
262 
263             // no action for these packets - ignore and continue
264         case ETM3_PKT_INCOMPLETE_EOT:
265         case ETM3_PKT_A_SYNC:
266         case ETM3_PKT_IGNORE:
267             break;
268 
269     // markers for valid packets
270         case ETM3_PKT_CYCLE_COUNT:
271             pElem = GetNextOpElem(resp);
272             pElem->setType(OCSD_GEN_TRC_ELEM_CYCLE_COUNT);
273             pElem->setCycleCount(m_curr_packet_in->getCycleCount());
274             break;
275 
276         case ETM3_PKT_TRIGGER:
277             pElem = GetNextOpElem(resp);
278             pElem->setType(OCSD_GEN_TRC_ELEM_EVENT);
279             pElem->setEvent(EVENT_TRIGGER,0);
280             break;
281 
282         case ETM3_PKT_BRANCH_ADDRESS:
283             resp = processBranchAddr();
284             break;
285 
286         case ETM3_PKT_I_SYNC_CYCLE:
287             bISyncHasCC = true;
288         case ETM3_PKT_I_SYNC:
289             resp = processISync(bISyncHasCC);
290             break;
291 
292         case ETM3_PKT_P_HDR:
293             resp = processPHdr();
294             break;
295 
296         case ETM3_PKT_CONTEXT_ID:
297             pElem = GetNextOpElem(resp);
298             pElem->setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT);
299             m_PeContext.setCtxtID(m_curr_packet_in->getCtxtID());
300             pElem->setContext(m_PeContext);
301             break;
302 
303         case ETM3_PKT_VMID:
304             pElem = GetNextOpElem(resp);
305             pElem->setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT);
306             m_PeContext.setVMID(m_curr_packet_in->getVMID());
307             pElem->setContext(m_PeContext);
308             break;
309 
310         case ETM3_PKT_EXCEPTION_ENTRY:
311             pElem = GetNextOpElem(resp);
312             pElem->setType(OCSD_GEN_TRC_ELEM_EXCEPTION);
313             pElem->setExcepMarker(); // exception entries are always v7M data markers in ETMv3 trace.
314             break;
315 
316         case ETM3_PKT_EXCEPTION_EXIT:
317             pElem = GetNextOpElem(resp);
318             pElem->setType(OCSD_GEN_TRC_ELEM_EXCEPTION_RET);
319             pendExceptionReturn();
320             break;
321 
322         case ETM3_PKT_TIMESTAMP:
323             pElem = GetNextOpElem(resp);
324             pElem->setType(OCSD_GEN_TRC_ELEM_TIMESTAMP);
325             pElem->setTS(m_curr_packet_in->getTS());
326             break;
327 
328             // data packets - data trace not supported at present
329         case ETM3_PKT_STORE_FAIL:
330         case ETM3_PKT_OOO_DATA:
331         case ETM3_PKT_OOO_ADDR_PLC:
332         case ETM3_PKT_NORM_DATA:
333         case ETM3_PKT_DATA_SUPPRESSED:
334         case ETM3_PKT_VAL_NOT_TRACED:
335         case ETM3_PKT_BAD_TRACEMODE:
336             resp = OCSD_RESP_FATAL_INVALID_DATA;
337             throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,m_index_curr_pkt,m_CSID,"Invalid packet type : Data Tracing decode not supported.");
338             break;
339 
340     // packet errors
341         case ETM3_PKT_BAD_SEQUENCE:
342             resp = OCSD_RESP_FATAL_INVALID_DATA;
343             throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,m_index_curr_pkt,m_CSID,"Bad Packet sequence.");
344             break;
345 
346         default:
347         case ETM3_PKT_RESERVED:
348             resp = OCSD_RESP_FATAL_INVALID_DATA;
349             throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,m_index_curr_pkt,m_CSID,"Reserved or unknown packet ID.");
350             break;
351         }
352         m_curr_state = m_outputElemList.elemToSend() ? SEND_PKTS : DECODE_PKTS;
353         pktDone = !m_outputElemList.elemToSend();
354     }
355     catch(ocsdError &err)
356     {
357         LogError(err);
358         resetDecoder(); // mark decoder as unsynced - dump any current state.
359         pktDone = true;
360     }
361     catch(...)
362     {
363         LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_FAIL,m_index_curr_pkt,m_CSID,"Bad Packet sequence."));
364         resp = OCSD_RESP_FATAL_SYS_ERR;
365         resetDecoder(); // mark decoder as unsynced - dump any current state.
366         pktDone = true;
367     }
368     return resp;
369 }
370 
371 ocsd_datapath_resp_t TrcPktDecodeEtmV3::sendUnsyncPacket()
372 {
373     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
374     OcsdTraceElement *pElem = 0;
375     try {
376         pElem = GetNextOpElem(resp);
377         pElem->setType(OCSD_GEN_TRC_ELEM_NO_SYNC);
378         resp = m_outputElemList.sendElements();
379     }
380     catch(ocsdError &err)
381     {
382         LogError(err);
383         resetDecoder(); // mark decoder as unsynced - dump any current state.
384     }
385     return resp;
386 }
387 
388 void TrcPktDecodeEtmV3::setNeedAddr(bool bNeedAddr)
389 {
390     m_bNeedAddr = bNeedAddr;
391     m_bSentUnknown = false;
392 }
393 
394 ocsd_datapath_resp_t TrcPktDecodeEtmV3::processISync(const bool withCC, const bool firstSync /* = false */)
395 {
396     // map ISync reason to generic reason codes.
397     static trace_on_reason_t on_map[] = { TRACE_ON_NORMAL, TRACE_ON_NORMAL,
398         TRACE_ON_OVERFLOW, TRACE_ON_EX_DEBUG };
399 
400     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
401     bool ctxtUpdate = m_curr_packet_in->isCtxtUpdated();
402     OcsdTraceElement *pElem = 0;
403 
404     try {
405 
406         pElem = GetNextOpElem(resp);
407 
408         if(firstSync || (m_curr_packet_in->getISyncReason() != iSync_Periodic))
409         {
410             pElem->setType(OCSD_GEN_TRC_ELEM_TRACE_ON);
411             pElem->setTraceOnReason(on_map[(int)m_curr_packet_in->getISyncReason()]);
412             pElem =  GetNextOpElem(resp);
413         }
414 
415         // look for context changes....
416         if(ctxtUpdate || firstSync)
417         {
418             // if not first time out, read existing context in output element,
419             // otherwise we are setting it new.
420             if(firstSync)
421                 m_PeContext.resetCtxt();
422 
423             if(m_curr_packet_in->isCtxtIDUpdated())
424                 m_PeContext.setCtxtID(m_curr_packet_in->getCtxtID());
425             if(m_curr_packet_in->isVMIDUpdated())
426                 m_PeContext.setVMID(m_curr_packet_in->getVMID());
427             if(m_curr_packet_in->isCtxtFlagsUpdated())
428             {
429                 m_PeContext.setEL(m_curr_packet_in->isHyp() ? ocsd_EL2 : ocsd_EL_unknown);
430                 m_PeContext.setSecLevel(m_curr_packet_in->isNS() ? ocsd_sec_nonsecure : ocsd_sec_secure);
431             }
432 
433             // prepare the context packet
434             pElem->setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT);
435             pElem->setContext(m_PeContext);
436             pElem->setISA(m_curr_packet_in->ISA());
437 
438             // with cycle count...
439             if(m_curr_packet_in->getISyncHasCC())
440                 pElem->setCycleCount(m_curr_packet_in->getCycleCount());
441 
442         }
443 
444         // set ISync address - if it is a valid I address
445         if(!m_curr_packet_in->getISyncNoAddr())
446         {
447             if(m_curr_packet_in->getISyncIsLSiPAddr())
448             {
449                 // TBD: handle extra data processing instruction for data trace
450                 // need to output E atom relating to the data instruction
451                 // rare - on start-up case.
452 
453                 // main instruction address saved in data address for this packet type.
454                 m_IAddr = m_curr_packet_in->getDataAddr();
455             }
456             else
457             {
458                 m_IAddr = m_curr_packet_in->getAddr();
459             }
460             setNeedAddr(false);    // ready to process atoms.
461         }
462         m_curr_state = m_outputElemList.elemToSend() ? SEND_PKTS : DECODE_PKTS;
463     }
464     catch(ocsdError &err)
465     {
466         LogError(err);
467         resetDecoder(); // mark decoder as unsynced - dump any current state.
468     }
469     return resp;
470 }
471 
472 ocsd_datapath_resp_t TrcPktDecodeEtmV3::processBranchAddr()
473 {
474     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
475     OcsdTraceElement *pElem = 0;
476     bool bUpdatePEContext = false;
477 
478     // might need to cancel something ... if the last output was an instruction range or excep return
479     if(m_curr_packet_in->isExcepCancel())
480         m_outputElemList.cancelPendElem();
481     else
482         m_outputElemList.commitAllPendElem(); // otherwise commit any pending elements.
483 
484     // record the address
485     m_IAddr = m_curr_packet_in->getAddr();
486     setNeedAddr(false);    // no longer need an address.
487 
488     // exception packet - may need additional output
489     if(m_curr_packet_in->isExcepPkt())
490     {
491         // exeception packet may have exception, context change, or both.
492         // check for context change
493         if(m_curr_packet_in->isCtxtUpdated())
494         {
495 
496             ocsd_sec_level sec = m_curr_packet_in->isNS() ? ocsd_sec_nonsecure : ocsd_sec_secure;
497             if(sec != m_PeContext.getSecLevel())
498             {
499                 m_PeContext.setSecLevel(sec);
500                 bUpdatePEContext = true;
501             }
502             ocsd_ex_level pkt_el = m_curr_packet_in->isHyp() ?  ocsd_EL2 : ocsd_EL_unknown;
503             if(pkt_el != m_PeContext.getEL())
504             {
505                 m_PeContext.setEL(pkt_el);
506                 bUpdatePEContext = true;
507             }
508         }
509 
510         // now decide if we need to send any packets out.
511         try {
512 
513             if(bUpdatePEContext)
514             {
515                 pElem = GetNextOpElem(resp);
516                 pElem->setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT);
517                 pElem->setContext(m_PeContext);
518             }
519 
520             // check for exception
521             if(m_curr_packet_in->excepNum() != 0)
522             {
523                 pElem = GetNextOpElem(resp);
524                 pElem->setType(OCSD_GEN_TRC_ELEM_EXCEPTION);
525                 pElem->setExceptionNum(m_curr_packet_in->excepNum());
526             }
527 
528             // finally - do we have anything to send yet?
529             m_curr_state = m_outputElemList.elemToSend() ? SEND_PKTS : DECODE_PKTS;
530         }
531         catch(ocsdError &err)
532         {
533             LogError(err);
534             resetDecoder(); // mark decoder as unsynced - dump any current state.
535         }
536     }
537     return resp;
538 }
539 
540 
541 ocsd_datapath_resp_t TrcPktDecodeEtmV3::processPHdr()
542 {
543     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
544     OcsdTraceElement *pElem = 0;
545     ocsd_isa isa;
546     Etmv3Atoms atoms(m_config->isCycleAcc());
547 
548     atoms.initAtomPkt(m_curr_packet_in,m_index_curr_pkt);
549     isa = m_curr_packet_in->ISA();
550     m_code_follower.setMemSpaceAccess((m_PeContext.getSecLevel() ==  ocsd_sec_secure) ? OCSD_MEM_SPACE_S : OCSD_MEM_SPACE_N);
551 
552     try
553     {
554         do
555         {
556             // if we do not have a valid address then send any cycle count elements
557             // and stop processing
558             if(m_bNeedAddr)
559             {
560                 // output unknown address packet or a cycle count packet
561                 if(!m_bSentUnknown || m_config->isCycleAcc())
562                 {
563                     pElem = GetNextOpElem(resp);
564                     if(m_bSentUnknown || !atoms.numAtoms())
565                         pElem->setType(OCSD_GEN_TRC_ELEM_CYCLE_COUNT);
566                     else
567                         pElem->setType(OCSD_GEN_TRC_ELEM_ADDR_UNKNOWN);
568                     if(m_config->isCycleAcc())
569                         pElem->setCycleCount(atoms.getRemainCC());
570                     m_bSentUnknown = true;
571                 }
572                 atoms.clearAll();   // skip remaining atoms
573             }
574             else    // have an address, can process atoms
575             {
576                 pElem = GetNextOpElem(resp);
577                 pElem->setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE);
578 
579                 // cycle accurate may have a cycle count to use
580                 if(m_config->isCycleAcc())
581                 {
582                     // note: it is possible to have a CC only atom packet.
583                     if(!atoms.numAtoms())   // override type if CC only
584                          pElem->setType(OCSD_GEN_TRC_ELEM_CYCLE_COUNT);
585                     // set cycle count
586                     pElem->setCycleCount(atoms.getAtomCC());
587                 }
588 
589                 // now process the atom
590                 if(atoms.numAtoms())
591                 {
592                     m_code_follower.setISA(isa);
593                     m_code_follower.followSingleAtom(m_IAddr,atoms.getCurrAtomVal());
594 
595                     // valid code range
596                     if(m_code_follower.hasRange())
597                     {
598                         pElem->setAddrRange(m_IAddr,m_code_follower.getRangeEn());
599                         pElem->setLastInstrInfo(atoms.getCurrAtomVal() == ATOM_E,
600                                     m_code_follower.getInstrType(),
601                                     m_code_follower.getInstrSubType());
602                         pElem->setISA(isa);
603                         if(m_code_follower.hasNextAddr())
604                             m_IAddr = m_code_follower.getNextAddr();
605                         else
606                             setNeedAddr(true);
607                     }
608 
609                     // next address has new ISA?
610                     if(m_code_follower.ISAChanged())
611                         isa = m_code_follower.nextISA();
612 
613                     // there is a nacc
614                     if(m_code_follower.isNacc())
615                     {
616                         if(m_code_follower.hasRange())
617                         {
618                             pElem = GetNextOpElem(resp);
619                             pElem->setType(OCSD_GEN_TRC_ELEM_ADDR_NACC);
620                         }
621                         else
622                             pElem->updateType(OCSD_GEN_TRC_ELEM_ADDR_NACC);
623                         pElem->setAddrStart(m_code_follower.getNaccAddr());
624                         setNeedAddr(true);
625                         m_code_follower.clearNacc(); // we have generated some code for the nacc.
626                     }
627                 }
628 
629                 atoms.clearAtom();  // next atom
630             }
631         }
632         while(atoms.numAtoms());
633 
634         // is tha last element an atom?
635         int numElem = m_outputElemList.getNumElem();
636         if(numElem >= 1)
637         {
638             // if the last thing is an instruction range, pend it - could be cancelled later.
639             if(m_outputElemList.getElemType(numElem-1) == OCSD_GEN_TRC_ELEM_INSTR_RANGE)
640                 m_outputElemList.pendLastNElem(1);
641         }
642 
643         // finally - do we have anything to send yet?
644         m_curr_state = m_outputElemList.elemToSend() ? SEND_PKTS : DECODE_PKTS;
645     }
646     catch(ocsdError &err)
647     {
648         LogError(err);
649         resetDecoder(); // mark decoder as unsynced - dump any current state.
650     }
651     return resp;
652 }
653 
654 // if v7M -> pend only ERET, if V7A/R pend ERET and prev instr.
655 void TrcPktDecodeEtmV3::pendExceptionReturn()
656 {
657     int pendElem = 1;
658     if(m_config->getCoreProfile() != profile_CortexM)
659     {
660         int nElem = m_outputElemList.getNumElem();
661         if(nElem > 1)
662         {
663            if(m_outputElemList.getElemType(nElem - 2) == OCSD_GEN_TRC_ELEM_INSTR_RANGE)
664                pendElem = 2;    // need to pend instr+eret for A/R
665         }
666     }
667     m_outputElemList.pendLastNElem(pendElem);
668 }
669 
670 /* End of File trc_pkt_decode_etmv3.cpp */
671