1c120c564SAndrew Turner /*
2c120c564SAndrew Turner * \file trc_pkt_decode_ptm.cpp
3c120c564SAndrew Turner * \brief OpenCSD : PTM packet decoder.
4c120c564SAndrew Turner *
5c120c564SAndrew Turner * \copyright Copyright (c) 2016, ARM Limited. All Rights Reserved.
6c120c564SAndrew Turner */
7c120c564SAndrew Turner
8c120c564SAndrew Turner /*
9c120c564SAndrew Turner * Redistribution and use in source and binary forms, with or without modification,
10c120c564SAndrew Turner * are permitted provided that the following conditions are met:
11c120c564SAndrew Turner *
12c120c564SAndrew Turner * 1. Redistributions of source code must retain the above copyright notice,
13c120c564SAndrew Turner * this list of conditions and the following disclaimer.
14c120c564SAndrew Turner *
15c120c564SAndrew Turner * 2. Redistributions in binary form must reproduce the above copyright notice,
16c120c564SAndrew Turner * this list of conditions and the following disclaimer in the documentation
17c120c564SAndrew Turner * and/or other materials provided with the distribution.
18c120c564SAndrew Turner *
19c120c564SAndrew Turner * 3. Neither the name of the copyright holder nor the names of its contributors
20c120c564SAndrew Turner * may be used to endorse or promote products derived from this software without
21c120c564SAndrew Turner * specific prior written permission.
22c120c564SAndrew Turner *
23c120c564SAndrew Turner * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
24c120c564SAndrew Turner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25c120c564SAndrew Turner * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26c120c564SAndrew Turner * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27c120c564SAndrew Turner * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28c120c564SAndrew Turner * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29c120c564SAndrew Turner * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30c120c564SAndrew Turner * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31c120c564SAndrew Turner * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32c120c564SAndrew Turner * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33c120c564SAndrew Turner */
34c120c564SAndrew Turner
35c120c564SAndrew Turner #include <sstream>
36c120c564SAndrew Turner #include "opencsd/ptm/trc_pkt_decode_ptm.h"
37c120c564SAndrew Turner
38c120c564SAndrew Turner #define DCD_NAME "DCD_PTM"
39c120c564SAndrew Turner
TrcPktDecodePtm()40c120c564SAndrew Turner TrcPktDecodePtm::TrcPktDecodePtm()
41c120c564SAndrew Turner : TrcPktDecodeBase(DCD_NAME)
42c120c564SAndrew Turner {
43c120c564SAndrew Turner initDecoder();
44c120c564SAndrew Turner }
45c120c564SAndrew Turner
TrcPktDecodePtm(int instIDNum)46c120c564SAndrew Turner TrcPktDecodePtm::TrcPktDecodePtm(int instIDNum)
47c120c564SAndrew Turner : TrcPktDecodeBase(DCD_NAME,instIDNum)
48c120c564SAndrew Turner {
49c120c564SAndrew Turner initDecoder();
50c120c564SAndrew Turner }
51c120c564SAndrew Turner
~TrcPktDecodePtm()52c120c564SAndrew Turner TrcPktDecodePtm::~TrcPktDecodePtm()
53c120c564SAndrew Turner {
54c120c564SAndrew Turner }
55c120c564SAndrew Turner
56c120c564SAndrew Turner /*********************** implementation packet decoding interface */
57c120c564SAndrew Turner
processPacket()58c120c564SAndrew Turner ocsd_datapath_resp_t TrcPktDecodePtm::processPacket()
59c120c564SAndrew Turner {
60c120c564SAndrew Turner ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
61c120c564SAndrew Turner bool bPktDone = false;
62c120c564SAndrew Turner
63c120c564SAndrew Turner while(!bPktDone)
64c120c564SAndrew Turner {
65c120c564SAndrew Turner switch(m_curr_state)
66c120c564SAndrew Turner {
67c120c564SAndrew Turner case NO_SYNC:
68c120c564SAndrew Turner // no sync - output a no sync packet then transition to wait sync.
69c120c564SAndrew Turner m_output_elem.elem_type = OCSD_GEN_TRC_ELEM_NO_SYNC;
70*b6aadd18SAndrew Turner m_output_elem.unsync_eot_info = m_unsync_info;
71c120c564SAndrew Turner resp = outputTraceElement(m_output_elem);
72c120c564SAndrew Turner m_curr_state = (m_curr_packet_in->getType() == PTM_PKT_A_SYNC) ? WAIT_ISYNC : WAIT_SYNC;
73c120c564SAndrew Turner bPktDone = true;
74c120c564SAndrew Turner break;
75c120c564SAndrew Turner
76c120c564SAndrew Turner case WAIT_SYNC:
77c120c564SAndrew Turner if(m_curr_packet_in->getType() == PTM_PKT_A_SYNC)
78c120c564SAndrew Turner m_curr_state = WAIT_ISYNC;
79c120c564SAndrew Turner bPktDone = true;
80c120c564SAndrew Turner break;
81c120c564SAndrew Turner
82c120c564SAndrew Turner case WAIT_ISYNC:
83c120c564SAndrew Turner if(m_curr_packet_in->getType() == PTM_PKT_I_SYNC)
84c120c564SAndrew Turner m_curr_state = DECODE_PKTS;
85c120c564SAndrew Turner else
86c120c564SAndrew Turner bPktDone = true;
87c120c564SAndrew Turner break;
88c120c564SAndrew Turner
89c120c564SAndrew Turner case DECODE_PKTS:
90c120c564SAndrew Turner resp = decodePacket();
91c120c564SAndrew Turner bPktDone = true;
92c120c564SAndrew Turner break;
93c120c564SAndrew Turner
94c120c564SAndrew Turner default:
95c120c564SAndrew Turner // should only see these after a _WAIT resp - in flush handler
96c120c564SAndrew Turner case CONT_ISYNC:
97c120c564SAndrew Turner case CONT_ATOM:
98c120c564SAndrew Turner bPktDone = true;
99c120c564SAndrew Turner // throw a decoder error
100c120c564SAndrew Turner break;
101c120c564SAndrew Turner }
102c120c564SAndrew Turner }
103c120c564SAndrew Turner return resp;
104c120c564SAndrew Turner }
105c120c564SAndrew Turner
onEOT()106c120c564SAndrew Turner ocsd_datapath_resp_t TrcPktDecodePtm::onEOT()
107c120c564SAndrew Turner {
108c120c564SAndrew Turner ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
109c120c564SAndrew Turner // shouldn't be any packets left to be processed - flush shoudl have done this.
110c120c564SAndrew Turner // just output the end of trace marker
111c120c564SAndrew Turner m_output_elem.setType(OCSD_GEN_TRC_ELEM_EO_TRACE);
112*b6aadd18SAndrew Turner m_output_elem.setUnSyncEOTReason(UNSYNC_EOT);
113c120c564SAndrew Turner resp = outputTraceElement(m_output_elem);
114c120c564SAndrew Turner return resp;
115c120c564SAndrew Turner }
116c120c564SAndrew Turner
onReset()117c120c564SAndrew Turner ocsd_datapath_resp_t TrcPktDecodePtm::onReset()
118c120c564SAndrew Turner {
119c120c564SAndrew Turner ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
120*b6aadd18SAndrew Turner m_unsync_info = UNSYNC_RESET_DECODER;
121c120c564SAndrew Turner resetDecoder();
122c120c564SAndrew Turner return resp;
123c120c564SAndrew Turner }
124c120c564SAndrew Turner
onFlush()125c120c564SAndrew Turner ocsd_datapath_resp_t TrcPktDecodePtm::onFlush()
126c120c564SAndrew Turner {
127c120c564SAndrew Turner ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
128c120c564SAndrew Turner resp = contProcess();
129c120c564SAndrew Turner return resp;
130c120c564SAndrew Turner }
131c120c564SAndrew Turner
132c120c564SAndrew Turner // atom and isync packets can have multiple ouput packets that can be _WAITed mid stream.
contProcess()133c120c564SAndrew Turner ocsd_datapath_resp_t TrcPktDecodePtm::contProcess()
134c120c564SAndrew Turner {
135c120c564SAndrew Turner ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
136c120c564SAndrew Turner switch(m_curr_state)
137c120c564SAndrew Turner {
138c120c564SAndrew Turner case CONT_ISYNC:
139c120c564SAndrew Turner resp = processIsync();
140c120c564SAndrew Turner break;
141c120c564SAndrew Turner
142c120c564SAndrew Turner case CONT_ATOM:
143c120c564SAndrew Turner resp = processAtom();
144c120c564SAndrew Turner break;
145c120c564SAndrew Turner
146c120c564SAndrew Turner case CONT_WPUP:
147c120c564SAndrew Turner resp = processWPUpdate();
148c120c564SAndrew Turner break;
149c120c564SAndrew Turner
150c120c564SAndrew Turner case CONT_BRANCH:
151c120c564SAndrew Turner resp = processBranch();
152c120c564SAndrew Turner break;
153c120c564SAndrew Turner
154c120c564SAndrew Turner default: break; // not a state that requires further processing
155c120c564SAndrew Turner }
156c120c564SAndrew Turner
157c120c564SAndrew Turner if(OCSD_DATA_RESP_IS_CONT(resp) && processStateIsCont())
158c120c564SAndrew Turner m_curr_state = DECODE_PKTS; // continue packet processing - assuming we have not degraded into an unsynced state.
159c120c564SAndrew Turner
160c120c564SAndrew Turner return resp;
161c120c564SAndrew Turner }
162c120c564SAndrew Turner
onProtocolConfig()163c120c564SAndrew Turner ocsd_err_t TrcPktDecodePtm::onProtocolConfig()
164c120c564SAndrew Turner {
165c120c564SAndrew Turner ocsd_err_t err = OCSD_OK;
166c120c564SAndrew Turner if(m_config == 0)
167c120c564SAndrew Turner return OCSD_ERR_NOT_INIT;
168c120c564SAndrew Turner
169c120c564SAndrew Turner // static config - copy of CSID for easy reference
170c120c564SAndrew Turner m_CSID = m_config->getTraceID();
171c120c564SAndrew Turner
172c120c564SAndrew Turner // handle return stack implementation
173c120c564SAndrew Turner if (m_config->hasRetStack())
174c120c564SAndrew Turner {
175c120c564SAndrew Turner m_return_stack.set_active(m_config->enaRetStack());
176c120c564SAndrew Turner #ifdef TRC_RET_STACK_DEBUG
177c120c564SAndrew Turner m_return_stack.set_dbg_logger(this);
178c120c564SAndrew Turner #endif
179c120c564SAndrew Turner }
180c120c564SAndrew Turner
181c120c564SAndrew Turner // config options affecting decode
182c120c564SAndrew Turner m_instr_info.pe_type.profile = m_config->coreProfile();
183c120c564SAndrew Turner m_instr_info.pe_type.arch = m_config->archVersion();
184c120c564SAndrew Turner m_instr_info.dsb_dmb_waypoints = m_config->dmsbWayPt() ? 1 : 0;
185c120c564SAndrew Turner m_instr_info.wfi_wfe_branch = 0;
186c120c564SAndrew Turner return err;
187c120c564SAndrew Turner }
188c120c564SAndrew Turner
189c120c564SAndrew Turner /****************** local decoder routines */
190c120c564SAndrew Turner
initDecoder()191c120c564SAndrew Turner void TrcPktDecodePtm::initDecoder()
192c120c564SAndrew Turner {
193c120c564SAndrew Turner m_CSID = 0;
194c120c564SAndrew Turner m_instr_info.pe_type.profile = profile_Unknown;
195c120c564SAndrew Turner m_instr_info.pe_type.arch = ARCH_UNKNOWN;
196c120c564SAndrew Turner m_instr_info.dsb_dmb_waypoints = 0;
197*b6aadd18SAndrew Turner m_unsync_info = UNSYNC_INIT_DECODER;
198c120c564SAndrew Turner resetDecoder();
199c120c564SAndrew Turner }
200c120c564SAndrew Turner
resetDecoder()201c120c564SAndrew Turner void TrcPktDecodePtm::resetDecoder()
202c120c564SAndrew Turner {
203c120c564SAndrew Turner m_curr_state = NO_SYNC;
204c120c564SAndrew Turner m_need_isync = true; // need context to start.
205c120c564SAndrew Turner
206c120c564SAndrew Turner m_instr_info.isa = ocsd_isa_unknown;
207c120c564SAndrew Turner m_mem_nacc_pending = false;
208c120c564SAndrew Turner
209c120c564SAndrew Turner m_pe_context.ctxt_id_valid = 0;
210c120c564SAndrew Turner m_pe_context.bits64 = 0;
211c120c564SAndrew Turner m_pe_context.vmid_valid = 0;
212c120c564SAndrew Turner m_pe_context.exception_level = ocsd_EL_unknown;
213c120c564SAndrew Turner m_pe_context.security_level = ocsd_sec_secure;
214c120c564SAndrew Turner m_pe_context.el_valid = 0;
215c120c564SAndrew Turner
216c120c564SAndrew Turner m_curr_pe_state.instr_addr = 0x0;
217c120c564SAndrew Turner m_curr_pe_state.isa = ocsd_isa_unknown;
218c120c564SAndrew Turner m_curr_pe_state.valid = false;
219c120c564SAndrew Turner
220c120c564SAndrew Turner m_atoms.clearAll();
221c120c564SAndrew Turner m_output_elem.init();
222c120c564SAndrew Turner }
223c120c564SAndrew Turner
decodePacket()224c120c564SAndrew Turner ocsd_datapath_resp_t TrcPktDecodePtm::decodePacket()
225c120c564SAndrew Turner {
226c120c564SAndrew Turner ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
227c120c564SAndrew Turner switch(m_curr_packet_in->getType())
228c120c564SAndrew Turner {
229c120c564SAndrew Turner // ignore these from trace o/p point of veiw
230c120c564SAndrew Turner case PTM_PKT_NOTSYNC:
231c120c564SAndrew Turner case PTM_PKT_INCOMPLETE_EOT:
232c120c564SAndrew Turner case PTM_PKT_NOERROR:
233c120c564SAndrew Turner break;
234c120c564SAndrew Turner
235c120c564SAndrew Turner // bad / reserved packet - need to wait for next sync point
236c120c564SAndrew Turner case PTM_PKT_BAD_SEQUENCE:
237c120c564SAndrew Turner case PTM_PKT_RESERVED:
238c120c564SAndrew Turner m_curr_state = WAIT_SYNC;
239c120c564SAndrew Turner m_need_isync = true; // need context to re-start.
240c120c564SAndrew Turner m_output_elem.setType(OCSD_GEN_TRC_ELEM_NO_SYNC);
241c120c564SAndrew Turner resp = outputTraceElement(m_output_elem);
242c120c564SAndrew Turner break;
243c120c564SAndrew Turner
244c120c564SAndrew Turner // packets we can ignore if in sync
245c120c564SAndrew Turner case PTM_PKT_A_SYNC:
246c120c564SAndrew Turner case PTM_PKT_IGNORE:
247c120c564SAndrew Turner break;
248c120c564SAndrew Turner
249c120c564SAndrew Turner //
250c120c564SAndrew Turner case PTM_PKT_I_SYNC:
251c120c564SAndrew Turner resp = processIsync();
252c120c564SAndrew Turner break;
253c120c564SAndrew Turner
254c120c564SAndrew Turner case PTM_PKT_BRANCH_ADDRESS:
255c120c564SAndrew Turner resp = processBranch();
256c120c564SAndrew Turner break;
257c120c564SAndrew Turner
258c120c564SAndrew Turner case PTM_PKT_TRIGGER:
259c120c564SAndrew Turner m_output_elem.setType(OCSD_GEN_TRC_ELEM_EVENT);
260c120c564SAndrew Turner m_output_elem.setEvent(EVENT_TRIGGER, 0);
261c120c564SAndrew Turner resp = outputTraceElement(m_output_elem);
262c120c564SAndrew Turner break;
263c120c564SAndrew Turner
264c120c564SAndrew Turner case PTM_PKT_WPOINT_UPDATE:
265c120c564SAndrew Turner resp = processWPUpdate();
266c120c564SAndrew Turner break;
267c120c564SAndrew Turner
268c120c564SAndrew Turner case PTM_PKT_CONTEXT_ID:
269c120c564SAndrew Turner {
270c120c564SAndrew Turner bool bUpdate = true;
271c120c564SAndrew Turner // see if this is a change
272c120c564SAndrew Turner if((m_pe_context.ctxt_id_valid) && (m_pe_context.context_id == m_curr_packet_in->context.ctxtID))
273c120c564SAndrew Turner bUpdate = false;
274c120c564SAndrew Turner if(bUpdate)
275c120c564SAndrew Turner {
276c120c564SAndrew Turner m_pe_context.context_id = m_curr_packet_in->context.ctxtID;
277c120c564SAndrew Turner m_pe_context.ctxt_id_valid = 1;
278c120c564SAndrew Turner m_output_elem.setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT);
279c120c564SAndrew Turner m_output_elem.setContext(m_pe_context);
280c120c564SAndrew Turner resp = outputTraceElement(m_output_elem);
281c120c564SAndrew Turner }
282c120c564SAndrew Turner }
283c120c564SAndrew Turner break;
284c120c564SAndrew Turner
285c120c564SAndrew Turner case PTM_PKT_VMID:
286c120c564SAndrew Turner {
287c120c564SAndrew Turner bool bUpdate = true;
288c120c564SAndrew Turner // see if this is a change
289c120c564SAndrew Turner if((m_pe_context.vmid_valid) && (m_pe_context.vmid == m_curr_packet_in->context.VMID))
290c120c564SAndrew Turner bUpdate = false;
291c120c564SAndrew Turner if(bUpdate)
292c120c564SAndrew Turner {
293c120c564SAndrew Turner m_pe_context.vmid = m_curr_packet_in->context.VMID;
294c120c564SAndrew Turner m_pe_context.vmid_valid = 1;
295c120c564SAndrew Turner m_output_elem.setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT);
296c120c564SAndrew Turner m_output_elem.setContext(m_pe_context);
297c120c564SAndrew Turner resp = outputTraceElement(m_output_elem);
298c120c564SAndrew Turner }
299c120c564SAndrew Turner }
300c120c564SAndrew Turner break;
301c120c564SAndrew Turner
302c120c564SAndrew Turner case PTM_PKT_ATOM:
303c120c564SAndrew Turner if(m_curr_pe_state.valid)
304c120c564SAndrew Turner {
305c120c564SAndrew Turner m_atoms.initAtomPkt(m_curr_packet_in->getAtom(),m_index_curr_pkt);
306c120c564SAndrew Turner resp = processAtom();
307c120c564SAndrew Turner }
308c120c564SAndrew Turner break;
309c120c564SAndrew Turner
310c120c564SAndrew Turner case PTM_PKT_TIMESTAMP:
311c120c564SAndrew Turner m_output_elem.setType(OCSD_GEN_TRC_ELEM_TIMESTAMP);
312c120c564SAndrew Turner m_output_elem.timestamp = m_curr_packet_in->timestamp;
313c120c564SAndrew Turner if(m_curr_packet_in->cc_valid)
314c120c564SAndrew Turner m_output_elem.setCycleCount(m_curr_packet_in->cycle_count);
315c120c564SAndrew Turner resp = outputTraceElement(m_output_elem);
316c120c564SAndrew Turner break;
317c120c564SAndrew Turner
318c120c564SAndrew Turner case PTM_PKT_EXCEPTION_RET:
319c120c564SAndrew Turner m_output_elem.setType(OCSD_GEN_TRC_ELEM_EXCEPTION_RET);
320c120c564SAndrew Turner resp = outputTraceElement(m_output_elem);
321c120c564SAndrew Turner break;
322c120c564SAndrew Turner
323c120c564SAndrew Turner }
324c120c564SAndrew Turner return resp;
325c120c564SAndrew Turner }
326c120c564SAndrew Turner
processIsync()327c120c564SAndrew Turner ocsd_datapath_resp_t TrcPktDecodePtm::processIsync()
328c120c564SAndrew Turner {
329c120c564SAndrew Turner ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
330c120c564SAndrew Turner
331c120c564SAndrew Turner // extract the I-Sync data if not re-entering after a _WAIT
332c120c564SAndrew Turner if(m_curr_state == DECODE_PKTS)
333c120c564SAndrew Turner {
334c120c564SAndrew Turner m_curr_pe_state.instr_addr = m_curr_packet_in->getAddrVal();
335c120c564SAndrew Turner m_curr_pe_state.isa = m_curr_packet_in->getISA();
336c120c564SAndrew Turner m_curr_pe_state.valid = true;
337c120c564SAndrew Turner
338c120c564SAndrew Turner m_i_sync_pe_ctxt = m_curr_packet_in->ISAChanged();
339c120c564SAndrew Turner if(m_curr_packet_in->CtxtIDUpdated())
340c120c564SAndrew Turner {
341c120c564SAndrew Turner m_pe_context.context_id = m_curr_packet_in->getCtxtID();
342c120c564SAndrew Turner m_pe_context.ctxt_id_valid = 1;
343c120c564SAndrew Turner m_i_sync_pe_ctxt = true;
344c120c564SAndrew Turner }
345c120c564SAndrew Turner
346c120c564SAndrew Turner if(m_curr_packet_in->VMIDUpdated())
347c120c564SAndrew Turner {
348c120c564SAndrew Turner m_pe_context.vmid = m_curr_packet_in->getVMID();
349c120c564SAndrew Turner m_pe_context.vmid_valid = 1;
350c120c564SAndrew Turner m_i_sync_pe_ctxt = true;
351c120c564SAndrew Turner }
352c120c564SAndrew Turner m_pe_context.security_level = m_curr_packet_in->getNS() ? ocsd_sec_nonsecure : ocsd_sec_secure;
353c120c564SAndrew Turner
354c120c564SAndrew Turner if(m_need_isync || (m_curr_packet_in->iSyncReason() != iSync_Periodic))
355c120c564SAndrew Turner {
356c120c564SAndrew Turner m_output_elem.setType(OCSD_GEN_TRC_ELEM_TRACE_ON);
357c120c564SAndrew Turner m_output_elem.trace_on_reason = TRACE_ON_NORMAL;
358c120c564SAndrew Turner if(m_curr_packet_in->iSyncReason() == iSync_TraceRestartAfterOverflow)
359c120c564SAndrew Turner m_output_elem.trace_on_reason = TRACE_ON_OVERFLOW;
360c120c564SAndrew Turner else if(m_curr_packet_in->iSyncReason() == iSync_DebugExit)
361c120c564SAndrew Turner m_output_elem.trace_on_reason = TRACE_ON_EX_DEBUG;
362c120c564SAndrew Turner if(m_curr_packet_in->hasCC())
363c120c564SAndrew Turner m_output_elem.setCycleCount(m_curr_packet_in->getCCVal());
364c120c564SAndrew Turner resp = outputTraceElement(m_output_elem);
365c120c564SAndrew Turner }
366c120c564SAndrew Turner else
367c120c564SAndrew Turner {
368c120c564SAndrew Turner // periodic - no output
369c120c564SAndrew Turner m_i_sync_pe_ctxt = false;
370c120c564SAndrew Turner }
371c120c564SAndrew Turner m_need_isync = false; // got 1st Isync - can continue to process data.
372c120c564SAndrew Turner m_return_stack.flush();
373c120c564SAndrew Turner }
374c120c564SAndrew Turner
375c120c564SAndrew Turner if(m_i_sync_pe_ctxt && OCSD_DATA_RESP_IS_CONT(resp))
376c120c564SAndrew Turner {
377c120c564SAndrew Turner m_output_elem.setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT);
378c120c564SAndrew Turner m_output_elem.setContext(m_pe_context);
379c120c564SAndrew Turner m_output_elem.setISA(m_curr_pe_state.isa);
380c120c564SAndrew Turner resp = outputTraceElement(m_output_elem);
381c120c564SAndrew Turner m_i_sync_pe_ctxt = false;
382c120c564SAndrew Turner }
383c120c564SAndrew Turner
384c120c564SAndrew Turner // if wait and still stuff to process....
385c120c564SAndrew Turner if(OCSD_DATA_RESP_IS_WAIT(resp) && ( m_i_sync_pe_ctxt))
386c120c564SAndrew Turner m_curr_state = CONT_ISYNC;
387c120c564SAndrew Turner
388c120c564SAndrew Turner return resp;
389c120c564SAndrew Turner }
390c120c564SAndrew Turner
391c120c564SAndrew Turner // change of address and/or exception in program flow.
392c120c564SAndrew Turner // implies E atom before the branch if none exception.
processBranch()393c120c564SAndrew Turner ocsd_datapath_resp_t TrcPktDecodePtm::processBranch()
394c120c564SAndrew Turner {
395c120c564SAndrew Turner ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
396c120c564SAndrew Turner
397c120c564SAndrew Turner // initial pass - decoding packet.
398c120c564SAndrew Turner if(m_curr_state == DECODE_PKTS)
399c120c564SAndrew Turner {
400c120c564SAndrew Turner // specific behviour if this is an exception packet.
401c120c564SAndrew Turner if(m_curr_packet_in->isBranchExcepPacket())
402c120c564SAndrew Turner {
403c120c564SAndrew Turner // exception - record address and output exception packet.
404c120c564SAndrew Turner m_output_elem.setType(OCSD_GEN_TRC_ELEM_EXCEPTION);
405c120c564SAndrew Turner m_output_elem.exception_number = m_curr_packet_in->excepNum();
406c120c564SAndrew Turner m_output_elem.excep_ret_addr = 0;
407c120c564SAndrew Turner if(m_curr_pe_state.valid)
408c120c564SAndrew Turner {
409c120c564SAndrew Turner m_output_elem.excep_ret_addr = 1;
410c120c564SAndrew Turner m_output_elem.en_addr = m_curr_pe_state.instr_addr;
411c120c564SAndrew Turner }
412c120c564SAndrew Turner // could be an associated cycle count
413c120c564SAndrew Turner if(m_curr_packet_in->hasCC())
414c120c564SAndrew Turner m_output_elem.setCycleCount(m_curr_packet_in->getCCVal());
415c120c564SAndrew Turner
416c120c564SAndrew Turner // output the element
417c120c564SAndrew Turner resp = outputTraceElement(m_output_elem);
418c120c564SAndrew Turner }
419c120c564SAndrew Turner else
420c120c564SAndrew Turner {
421c120c564SAndrew Turner // branch address only - implies E atom - need to output a range element based on the atom.
422c120c564SAndrew Turner if(m_curr_pe_state.valid)
423c120c564SAndrew Turner resp = processAtomRange(ATOM_E,"BranchAddr");
424c120c564SAndrew Turner }
425c120c564SAndrew Turner
426c120c564SAndrew Turner // now set the branch address for the next time.
427c120c564SAndrew Turner m_curr_pe_state.isa = m_curr_packet_in->getISA();
428c120c564SAndrew Turner m_curr_pe_state.instr_addr = m_curr_packet_in->getAddrVal();
429c120c564SAndrew Turner m_curr_pe_state.valid = true;
430c120c564SAndrew Turner }
431c120c564SAndrew Turner
432c120c564SAndrew Turner // atom range may return with NACC pending
433c120c564SAndrew Turner checkPendingNacc(resp);
434c120c564SAndrew Turner
435c120c564SAndrew Turner // if wait and still stuff to process....
436c120c564SAndrew Turner if(OCSD_DATA_RESP_IS_WAIT(resp) && ( m_mem_nacc_pending))
437c120c564SAndrew Turner m_curr_state = CONT_BRANCH;
438c120c564SAndrew Turner
439c120c564SAndrew Turner return resp;
440c120c564SAndrew Turner }
441c120c564SAndrew Turner
442c120c564SAndrew Turner // effectively completes a range prior to exception or after many bytes of trace (>4096)
443c120c564SAndrew Turner //
processWPUpdate()444c120c564SAndrew Turner ocsd_datapath_resp_t TrcPktDecodePtm::processWPUpdate()
445c120c564SAndrew Turner {
446c120c564SAndrew Turner ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
447c120c564SAndrew Turner
448c120c564SAndrew Turner // if we need an address to run from then the WPUpdate will not form a range as
449c120c564SAndrew Turner // we do not have a start point - still waiting for branch or other address packet
450c120c564SAndrew Turner if(m_curr_pe_state.valid)
451c120c564SAndrew Turner {
452c120c564SAndrew Turner // WP update implies atom - use E, we cannot be sure if the instruction passed its condition codes
453c120c564SAndrew Turner // - though it doesn't really matter as it is not a branch so cannot change flow.
454c120c564SAndrew Turner resp = processAtomRange(ATOM_E,"WP update",TRACE_TO_ADDR_INCL,m_curr_packet_in->getAddrVal());
455c120c564SAndrew Turner }
456c120c564SAndrew Turner
457c120c564SAndrew Turner // atom range may return with NACC pending
458c120c564SAndrew Turner checkPendingNacc(resp);
459c120c564SAndrew Turner
460c120c564SAndrew Turner // if wait and still stuff to process....
461c120c564SAndrew Turner if(OCSD_DATA_RESP_IS_WAIT(resp) && ( m_mem_nacc_pending))
462c120c564SAndrew Turner m_curr_state = CONT_WPUP;
463c120c564SAndrew Turner
464c120c564SAndrew Turner return resp;
465c120c564SAndrew Turner }
466c120c564SAndrew Turner
467c120c564SAndrew Turner // a single atom packet can result in multiple range outputs...need to be re-entrant in case we get a wait response.
468c120c564SAndrew Turner // also need to handle nacc response from instruction walking routine
469c120c564SAndrew Turner //
processAtom()470c120c564SAndrew Turner ocsd_datapath_resp_t TrcPktDecodePtm::processAtom()
471c120c564SAndrew Turner {
472c120c564SAndrew Turner ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
473c120c564SAndrew Turner
474c120c564SAndrew Turner // loop to process all the atoms in the packet
475c120c564SAndrew Turner while(m_atoms.numAtoms() && m_curr_pe_state.valid && OCSD_DATA_RESP_IS_CONT(resp))
476c120c564SAndrew Turner {
477c120c564SAndrew Turner resp = processAtomRange(m_atoms.getCurrAtomVal(),"atom");
478c120c564SAndrew Turner if(!m_curr_pe_state.valid)
479c120c564SAndrew Turner m_atoms.clearAll();
480c120c564SAndrew Turner else
481c120c564SAndrew Turner m_atoms.clearAtom();
482c120c564SAndrew Turner }
483c120c564SAndrew Turner
484c120c564SAndrew Turner // bad address may mean a nacc needs sending
485c120c564SAndrew Turner checkPendingNacc(resp);
486c120c564SAndrew Turner
487c120c564SAndrew Turner // if wait and still stuff to process....
488c120c564SAndrew Turner if(OCSD_DATA_RESP_IS_WAIT(resp) && ( m_mem_nacc_pending || m_atoms.numAtoms()))
489c120c564SAndrew Turner m_curr_state = CONT_ATOM;
490c120c564SAndrew Turner
491c120c564SAndrew Turner return resp;
492c120c564SAndrew Turner }
493c120c564SAndrew Turner
checkPendingNacc(ocsd_datapath_resp_t & resp)494c120c564SAndrew Turner void TrcPktDecodePtm::checkPendingNacc(ocsd_datapath_resp_t &resp)
495c120c564SAndrew Turner {
496c120c564SAndrew Turner if(m_mem_nacc_pending && OCSD_DATA_RESP_IS_CONT(resp))
497c120c564SAndrew Turner {
498c120c564SAndrew Turner m_output_elem.setType(OCSD_GEN_TRC_ELEM_ADDR_NACC);
499c120c564SAndrew Turner m_output_elem.st_addr = m_nacc_addr;
500c120c564SAndrew Turner resp = outputTraceElementIdx(m_index_curr_pkt,m_output_elem);
501c120c564SAndrew Turner m_mem_nacc_pending = false;
502c120c564SAndrew Turner }
503c120c564SAndrew Turner }
504c120c564SAndrew Turner
505c120c564SAndrew Turner // given an atom element - walk the code and output a range or mark nacc.
processAtomRange(const ocsd_atm_val A,const char * pkt_msg,const waypoint_trace_t traceWPOp,const ocsd_vaddr_t nextAddrMatch)506c120c564SAndrew Turner 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*/)
507c120c564SAndrew Turner {
508c120c564SAndrew Turner ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
509c120c564SAndrew Turner bool bWPFound = false;
510c120c564SAndrew Turner std::ostringstream oss;
511*b6aadd18SAndrew Turner ocsd_err_t err = OCSD_OK;
512c120c564SAndrew Turner
513c120c564SAndrew Turner m_instr_info.instr_addr = m_curr_pe_state.instr_addr;
514c120c564SAndrew Turner m_instr_info.isa = m_curr_pe_state.isa;
515c120c564SAndrew Turner
516*b6aadd18SAndrew Turner // set type (which resets out-elem) before traceInstrToWP modifies out-elem values
517*b6aadd18SAndrew Turner m_output_elem.setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE);
518*b6aadd18SAndrew Turner
519*b6aadd18SAndrew Turner err = traceInstrToWP(bWPFound,traceWPOp,nextAddrMatch);
520c120c564SAndrew Turner if(err != OCSD_OK)
521c120c564SAndrew Turner {
522c120c564SAndrew Turner if(err == OCSD_ERR_UNSUPPORTED_ISA)
523c120c564SAndrew Turner {
524c120c564SAndrew Turner m_curr_pe_state.valid = false; // need a new address packet
525c120c564SAndrew Turner oss << "Warning: unsupported instruction set processing " << pkt_msg << " packet.";
526c120c564SAndrew Turner LogError(ocsdError(OCSD_ERR_SEV_WARN,err,m_index_curr_pkt,m_CSID,oss.str()));
527c120c564SAndrew Turner // wait for next address
528c120c564SAndrew Turner return OCSD_RESP_WARN_CONT;
529c120c564SAndrew Turner }
530c120c564SAndrew Turner else
531c120c564SAndrew Turner {
532c120c564SAndrew Turner resp = OCSD_RESP_FATAL_INVALID_DATA;
533c120c564SAndrew Turner oss << "Error processing " << pkt_msg << " packet.";
534c120c564SAndrew Turner LogError(ocsdError(OCSD_ERR_SEV_ERROR,err,m_index_curr_pkt,m_CSID,oss.str()));
535c120c564SAndrew Turner return resp;
536c120c564SAndrew Turner }
537c120c564SAndrew Turner }
538c120c564SAndrew Turner
539c120c564SAndrew Turner if(bWPFound)
540c120c564SAndrew Turner {
541c120c564SAndrew Turner // save recorded next instuction address
542c120c564SAndrew Turner ocsd_vaddr_t nextAddr = m_instr_info.instr_addr;
543c120c564SAndrew Turner
544c120c564SAndrew Turner // action according to waypoint type and atom value
545c120c564SAndrew Turner switch(m_instr_info.type)
546c120c564SAndrew Turner {
547c120c564SAndrew Turner case OCSD_INSTR_BR:
548c120c564SAndrew Turner if (A == ATOM_E)
549c120c564SAndrew Turner {
550c120c564SAndrew Turner m_instr_info.instr_addr = m_instr_info.branch_addr;
551c120c564SAndrew Turner if (m_instr_info.is_link)
552c120c564SAndrew Turner m_return_stack.push(nextAddr,m_instr_info.isa);
553c120c564SAndrew Turner }
554c120c564SAndrew Turner break;
555c120c564SAndrew Turner
556c120c564SAndrew Turner // For PTM -> branch addresses imply E atom, N atom does not need address (return stack will require this)
557c120c564SAndrew Turner case OCSD_INSTR_BR_INDIRECT:
558c120c564SAndrew Turner if (A == ATOM_E)
559c120c564SAndrew Turner {
560c120c564SAndrew Turner // atom on indirect branch - either implied E from a branch address packet, or return stack if active.
561c120c564SAndrew Turner
562c120c564SAndrew Turner // indirect branch taken - need new address -if the current packet is a branch address packet this will be sorted.
563c120c564SAndrew Turner m_curr_pe_state.valid = false;
564c120c564SAndrew Turner
565c120c564SAndrew Turner // if return stack and the incoming packet is an atom.
566c120c564SAndrew Turner if (m_return_stack.is_active() && (m_curr_packet_in->getType() == PTM_PKT_ATOM))
567c120c564SAndrew Turner {
568c120c564SAndrew Turner // we have an E atom packet and return stack value - set address from return stack
569c120c564SAndrew Turner m_instr_info.instr_addr = m_return_stack.pop(m_instr_info.next_isa);
570c120c564SAndrew Turner
571c120c564SAndrew Turner if (m_return_stack.overflow())
572c120c564SAndrew Turner {
573c120c564SAndrew Turner resp = OCSD_RESP_FATAL_INVALID_DATA;
574c120c564SAndrew Turner oss << "Return stack error processing " << pkt_msg << " packet.";
575c120c564SAndrew Turner LogError(ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_RET_STACK_OVERFLOW, m_index_curr_pkt, m_CSID, oss.str()));
576c120c564SAndrew Turner return resp;
577c120c564SAndrew Turner }
578c120c564SAndrew Turner else
579c120c564SAndrew Turner m_curr_pe_state.valid = true;
580c120c564SAndrew Turner }
581c120c564SAndrew Turner if(m_instr_info.is_link)
582c120c564SAndrew Turner m_return_stack.push(nextAddr, m_instr_info.isa);
583c120c564SAndrew Turner }
584c120c564SAndrew Turner break;
585c120c564SAndrew Turner }
586c120c564SAndrew Turner
587c120c564SAndrew Turner m_output_elem.setLastInstrInfo((A == ATOM_E),m_instr_info.type, m_instr_info.sub_type,m_instr_info.instr_size);
588c120c564SAndrew Turner m_output_elem.setISA(m_curr_pe_state.isa);
589c120c564SAndrew Turner if(m_curr_packet_in->hasCC())
590c120c564SAndrew Turner m_output_elem.setCycleCount(m_curr_packet_in->getCCVal());
591c120c564SAndrew Turner m_output_elem.setLastInstrCond(m_instr_info.is_conditional);
592c120c564SAndrew Turner resp = outputTraceElementIdx(m_index_curr_pkt,m_output_elem);
593c120c564SAndrew Turner
594c120c564SAndrew Turner m_curr_pe_state.instr_addr = m_instr_info.instr_addr;
595c120c564SAndrew Turner m_curr_pe_state.isa = m_instr_info.next_isa;
596c120c564SAndrew Turner }
597c120c564SAndrew Turner else
598c120c564SAndrew Turner {
599c120c564SAndrew Turner // no waypoint - likely inaccessible memory range.
600c120c564SAndrew Turner m_curr_pe_state.valid = false; // need an address update
601c120c564SAndrew Turner
602c120c564SAndrew Turner if(m_output_elem.st_addr != m_output_elem.en_addr)
603c120c564SAndrew Turner {
604c120c564SAndrew Turner // some trace before we were out of memory access range
605c120c564SAndrew Turner m_output_elem.setLastInstrInfo(true,m_instr_info.type, m_instr_info.sub_type,m_instr_info.instr_size);
606c120c564SAndrew Turner m_output_elem.setISA(m_curr_pe_state.isa);
607c120c564SAndrew Turner m_output_elem.setLastInstrCond(m_instr_info.is_conditional);
608c120c564SAndrew Turner resp = outputTraceElementIdx(m_index_curr_pkt,m_output_elem);
609c120c564SAndrew Turner }
610c120c564SAndrew Turner }
611c120c564SAndrew Turner return resp;
612c120c564SAndrew Turner }
613c120c564SAndrew Turner
traceInstrToWP(bool & bWPFound,const waypoint_trace_t traceWPOp,const ocsd_vaddr_t nextAddrMatch)614c120c564SAndrew Turner ocsd_err_t TrcPktDecodePtm::traceInstrToWP(bool &bWPFound, const waypoint_trace_t traceWPOp /*= TRACE_WAYPOINT*/, const ocsd_vaddr_t nextAddrMatch /*= 0*/)
615c120c564SAndrew Turner {
616c120c564SAndrew Turner uint32_t opcode;
617c120c564SAndrew Turner uint32_t bytesReq;
618c120c564SAndrew Turner ocsd_err_t err = OCSD_OK;
619c120c564SAndrew Turner ocsd_vaddr_t curr_op_address;
620c120c564SAndrew Turner
621c120c564SAndrew Turner ocsd_mem_space_acc_t mem_space = (m_pe_context.security_level == ocsd_sec_secure) ? OCSD_MEM_SPACE_S : OCSD_MEM_SPACE_N;
622c120c564SAndrew Turner
623c120c564SAndrew Turner m_output_elem.st_addr = m_output_elem.en_addr = m_instr_info.instr_addr;
624c120c564SAndrew Turner m_output_elem.num_instr_range = 0;
625c120c564SAndrew Turner
626c120c564SAndrew Turner bWPFound = false;
627c120c564SAndrew Turner
628c120c564SAndrew Turner while(!bWPFound && !m_mem_nacc_pending)
629c120c564SAndrew Turner {
630c120c564SAndrew Turner // start off by reading next opcode;
631c120c564SAndrew Turner bytesReq = 4;
632c120c564SAndrew Turner curr_op_address = m_instr_info.instr_addr; // save the start address for the current opcode
633c120c564SAndrew Turner err = accessMemory(m_instr_info.instr_addr,mem_space,&bytesReq,(uint8_t *)&opcode);
634c120c564SAndrew Turner if(err != OCSD_OK) break;
635c120c564SAndrew Turner
636c120c564SAndrew Turner if(bytesReq == 4) // got data back
637c120c564SAndrew Turner {
638c120c564SAndrew Turner m_instr_info.opcode = opcode;
639c120c564SAndrew Turner err = instrDecode(&m_instr_info);
640c120c564SAndrew Turner if(err != OCSD_OK) break;
641c120c564SAndrew Turner
642c120c564SAndrew Turner // increment address - may be adjusted by direct branch value later
643c120c564SAndrew Turner m_instr_info.instr_addr += m_instr_info.instr_size;
644c120c564SAndrew Turner
645c120c564SAndrew Turner // update the range decoded address in the output packet.
646c120c564SAndrew Turner m_output_elem.en_addr = m_instr_info.instr_addr;
647c120c564SAndrew Turner m_output_elem.num_instr_range++;
648c120c564SAndrew Turner
649c120c564SAndrew Turner m_output_elem.last_i_type = m_instr_info.type;
650c120c564SAndrew Turner // either walking to match the next instruction address or a real waypoint
651c120c564SAndrew Turner if(traceWPOp != TRACE_WAYPOINT)
652c120c564SAndrew Turner {
653c120c564SAndrew Turner if(traceWPOp == TRACE_TO_ADDR_EXCL)
654c120c564SAndrew Turner bWPFound = (m_output_elem.en_addr == nextAddrMatch);
655c120c564SAndrew Turner else
656c120c564SAndrew Turner bWPFound = (curr_op_address == nextAddrMatch);
657c120c564SAndrew Turner }
658c120c564SAndrew Turner else
659c120c564SAndrew Turner bWPFound = (m_instr_info.type != OCSD_INSTR_OTHER);
660c120c564SAndrew Turner }
661c120c564SAndrew Turner else
662c120c564SAndrew Turner {
663c120c564SAndrew Turner // not enough memory accessible.
664c120c564SAndrew Turner m_mem_nacc_pending = true;
665c120c564SAndrew Turner m_nacc_addr = m_instr_info.instr_addr;
666c120c564SAndrew Turner }
667c120c564SAndrew Turner }
668c120c564SAndrew Turner return err;
669c120c564SAndrew Turner }
670c120c564SAndrew Turner
671c120c564SAndrew Turner /* End of File trc_pkt_decode_ptm.cpp */
672