itm_decode/
lib.rs

1//! A decoder for the ITM and DWT packet protocol as specifed in the
2//! [ARMv7-M architecture reference manual, Appendix
3//! D4](https://developer.arm.com/documentation/ddi0403/ed/). Any
4//! references in this code base refers to this document.
5//!
6//! Common abbreviations:
7//!
8//! - ITM: instrumentation trace macrocell;
9//! - PC: program counter;
10//! - DWT: data watchpoint and trace unit;
11//! - MSB: most significant bit;
12//! - BE: big-endian;
13
14use bitmatch::bitmatch;
15use bitvec::prelude::*;
16use std::convert::TryInto;
17
18#[cfg(feature = "serde")]
19use serde_crate::{Deserialize, Serialize};
20
21/// Re-exports for exception types of the `cortex-m` crate for `serde`
22/// purposes.
23pub mod cortex_m {
24    /// Denotes the exception type (interrupt event) of the processor.
25    /// (Table B1-4)
26    pub use cortex_m::peripheral::scb::{Exception, VectActive};
27
28    /// Verbatim copy of used `cortex_m` enums for serde functionality.
29    /// Should not be used directly. Public because serde requires it.
30    /// See <https://serde.rs/remote-derive.html>
31    #[cfg(feature = "serde")]
32    pub mod serde {
33        use super::{Exception, VectActive};
34        use serde_crate::{Deserialize, Serialize};
35
36        #[derive(Serialize, Deserialize)]
37        #[serde(crate = "serde_crate", remote = "Exception")]
38        pub enum ExceptionDef {
39            NonMaskableInt,
40            HardFault,
41            MemoryManagement,
42            BusFault,
43            UsageFault,
44            SecureFault,
45            SVCall,
46            DebugMonitor,
47            PendSV,
48            SysTick,
49        }
50
51        #[derive(Serialize, Deserialize)]
52        #[serde(crate = "serde_crate", remote = "VectActive")]
53        pub enum VectActiveDef {
54            ThreadMode,
55            Exception(#[serde(with = "ExceptionDef")] Exception),
56            Interrupt { irqn: u8 },
57        }
58    }
59}
60
61/// The set of valid packet types that can be decoded.
62#[derive(Debug, Clone, PartialEq)]
63#[cfg_attr(
64    feature = "serde",
65    derive(Serialize, Deserialize),
66    serde(crate = "serde_crate")
67)]
68pub enum TracePacket {
69    // Synchronization packet category (Appendix D4, p. 782)
70    /// A synchronization packet is a unique pattern in the bitstream.
71    /// It is identified and used to provide the alignment of other
72    /// packet bytes in the bitstream. (Appendix D4.2.1)
73    Sync,
74
75    // Protocol packet category (Appendix D4, p. 782)
76    /// Found in the bitstream if
77    ///
78    /// - Software has written to an ITM stimulus port register when the
79    /// stimulus port output buffer is full.
80    /// - The DWT attempts to generate a hardware source packet when the
81    /// DWT output buffer is full.
82    /// - The local timestamp counter overflows.
83    ///
84    /// See (Appendix D4.2.3).
85    Overflow,
86
87    /// A delta timestamp that measures the interval since the
88    /// generation of the last local timestamp and its relation to the
89    /// corresponding ITM/DWT data packets. (Appendix D4.2.4)
90    LocalTimestamp1 {
91        /// Timestamp value.
92        ts: u64,
93
94        /// Indicates the relationship between the generation of `ts`
95        /// and the corresponding ITM or DWT data packet.
96        data_relation: TimestampDataRelation,
97    },
98
99    /// A derivative of `LocalTimestamp1` for timestamp values between
100    /// 1-6. Always synchronous to te associated ITM/DWT data. (Appendix D4.2.4)
101    LocalTimestamp2 {
102        /// Timestamp value.
103        ts: u8,
104    },
105
106    /// An absolute timestamp based on the global timestamp clock that
107    /// contain the timestamp's lower-order bits. (Appendix D4.2.5)
108    GlobalTimestamp1 {
109        /// Lower-order bits of the timestamp; bits\[25:0\].
110        ts: u64,
111
112        /// Set if higher order bits output by the last GTS2 have
113        /// changed.
114        wrap: bool,
115
116        /// Set if the system has asserted a clock change input to the
117        /// processor since the last generated global timestamp.
118        clkch: bool,
119    },
120
121    /// An absolute timestamp based on the global timestamp clock that
122    /// contain the timestamp's higher-order bits. (Appendix D4.2.5)
123    GlobalTimestamp2 {
124        /// Higher-order bits of the timestamp value; bits\[63:26\] or
125        /// bits\[47:26\] depending on implementation.
126        ts: u64,
127    },
128
129    /// A packet that provides additional information about the
130    /// identified source (one of two possible, theoretically). On
131    /// ARMv7-M this packet is only used to denote on which ITM stimulus
132    /// port a payload was written. (Appendix D4.2.6)
133    Extension {
134        /// Source port page number.
135        page: u8,
136    },
137
138    // Source packet category
139    /// Contains the payload written to the ITM stimulus ports.
140    Instrumentation {
141        /// Stimulus port number.
142        port: u8,
143
144        /// Instrumentation data written to the stimulus port. MSB, BE.
145        payload: Vec<u8>,
146    },
147
148    /// One or more event counters have wrapped. (Appendix D4.3.1)
149    EventCounterWrap {
150        /// POSTCNT wrap (see Appendix C1, p. 732).
151        cyc: bool,
152        /// FOLDCNT wrap (see Appendix C1, p. 734).
153        fold: bool,
154        /// LSUCNT wrap (see Appendix C1, p. 734).
155        lsu: bool,
156        /// SLEEPCNT wrap (see Appendix C1, p. 734).
157        sleep: bool,
158        /// EXCCNT wrap (see Appendix C1, p. 734).
159        exc: bool,
160        /// CPICNT wrap (see Appendix C1, p. 734).
161        cpi: bool,
162    },
163
164    /// The processor has entered, exit, or returned to an exception.
165    /// (Appendix D4.3.2)
166    ExceptionTrace {
167        #[cfg_attr(feature = "serde", serde(with = "cortex_m::serde::VectActiveDef"))]
168        exception: cortex_m::VectActive,
169        action: ExceptionAction,
170    },
171
172    /// Periodic PC sample. (Appendix D4.3.3)
173    PCSample {
174        /// The value of the PC. `None` if periodic PC sleep packet.
175        pc: Option<u32>,
176    },
177
178    /// A DWT comparator matched a PC value. (Appendix D4.3.4)
179    DataTracePC {
180        /// The comparator number that generated the data.
181        comparator: u8,
182
183        /// The PC value for the instruction that caused the successful
184        /// address comparison.
185        pc: u32,
186    },
187
188    /// A DWT comparator matched an address. (Appendix D4.3.4)
189    DataTraceAddress {
190        /// The comparator number that generated the data.
191        comparator: u8,
192
193        /// Data address content; bits\[15:0\]. MSB, BE.
194        data: Vec<u8>,
195    },
196
197    /// A data trace packet with a value. (Appendix D4.3.4)
198    DataTraceValue {
199        /// The comparator number that generated the data.
200        comparator: u8,
201
202        /// Whether the data was read or written.
203        access_type: MemoryAccessType,
204
205        /// The data value. MSB, BE.
206        value: Vec<u8>,
207    },
208}
209
210/// Denotes the action taken by the processor by a given exception. (Table D4-6)
211#[derive(Debug, Clone, PartialEq)]
212#[cfg_attr(
213    feature = "serde",
214    derive(Serialize, Deserialize),
215    serde(crate = "serde_crate")
216)]
217pub enum ExceptionAction {
218    /// Exception was entered.
219    Entered,
220
221    /// Exception was exited.
222    Exited,
223
224    /// Exception was returned to.
225    Returned,
226}
227
228/// Denotes the type of memory access.
229#[derive(Debug, Clone, PartialEq)]
230#[cfg_attr(
231    feature = "serde",
232    derive(Serialize, Deserialize),
233    serde(crate = "serde_crate")
234)]
235pub enum MemoryAccessType {
236    /// Memory was read.
237    Read,
238
239    /// Memory was written.
240    Write,
241}
242
243/// Indicates the relationship between the generation of the local
244/// timestamp packet and the corresponding ITM or DWT data packet.
245/// (Appendix D4.2.4)
246#[derive(Debug, Clone, PartialEq)]
247#[cfg_attr(
248    feature = "serde",
249    derive(Serialize, Deserialize),
250    serde(crate = "serde_crate")
251)]
252pub enum TimestampDataRelation {
253    /// The local timestamp value is synchronous to the corresponding
254    /// ITM or DWT data. The value in the TS field is the timestamp
255    /// counter value when the ITM or DWT packet is generated.
256    Sync,
257
258    /// The local timestamp value is delayed relative to the ITM or DWT
259    /// data. The value in the TS field is the timestamp counter value
260    /// when the Local timestamp packet is generated.
261    ///
262    /// Note: the local timestamp value corresponding to the previous
263    /// ITM or DWT packet is unknown, but must be between the previous
264    /// and the current local timestamp values.
265    UnknownDelay,
266
267    /// Output of the ITM or DWT packet corresponding to this Local
268    /// timestamp packet is delayed relative to the associated event.
269    /// The value in the TS field is the timestamp counter value when
270    /// the ITM or DWT packets is generated.
271    ///
272    /// This encoding indicates that the ITM or DWT packet was delayed
273    /// relative to other trace output packets.
274    AssocEventDelay,
275
276    /// Output of the ITM or DWT packet corresponding to this Local
277    /// timestamp packet is delayed relative to the associated event,
278    /// and this Local timestamp packet is delayed relative to the ITM
279    /// or DWT data. This is a combined condition of `UnknownDelay` and
280    /// `AssocEventDelay`.
281    UnknownAssocEventDelay,
282}
283
284/// A header or payload byte failed to be decoded.
285#[derive(Debug, Clone, PartialEq, thiserror::Error)]
286#[cfg_attr(
287    feature = "serde",
288    derive(Serialize, Deserialize),
289    serde(crate = "serde_crate")
290)]
291pub enum MalformedPacket {
292    /// Header is invalid and cannot be decoded.
293    #[error("Header is invalid and cannot be decoded: {}", format!("{:#b}", .0))]
294    InvalidHeader(u8),
295
296    /// The type discriminator ID in the hardware source packet header
297    /// is invalid or the associated payload is of wrong size.
298    #[error("Hardware source packet type discriminator ID ({disc_id}) or payload length ({}) is invalid", .payload.len())]
299    InvalidHardwarePacket {
300        /// The discriminator ID. Potentially invalid.
301        disc_id: u8,
302
303        /// Associated payload. Potentially invalid length. MSB, BE.
304        payload: Vec<u8>,
305    },
306
307    /// The type discriminator ID in the hardware source packet header
308    /// is invalid.
309    #[error("Hardware source packet discriminator ID is invalid: {disc_id}")]
310    InvalidHardwareDisc {
311        /// The discriminator ID. Potentially invalid.
312        disc_id: u8,
313
314        /// Associated payload length.
315        size: usize,
316    },
317
318    /// An exception trace packet refers to an invalid action or an
319    /// invalid exception number.
320    #[error("IRQ number {exception} and/or action {function} is invalid")]
321    InvalidExceptionTrace {
322        /// The exception number.
323        exception: u16,
324
325        /// Numerical representation of the function associated with the
326        /// exception number.
327        function: u8,
328    },
329
330    /// The payload length of a PCSample packet is invalid.
331    #[error("Payload length of PC sample is invalid: {}", .payload.len())]
332    InvalidPCSampleSize {
333        /// The payload constituting the PC value, of invalid size. MSB, BE.
334        payload: Vec<u8>,
335    },
336
337    /// The GlobalTimestamp2 packet does not contain a 48-bit or 64-bit
338    /// timestamp.
339    #[error("GlobalTimestamp2 packet does not contain a 48-bit or 64-bit timestamp")]
340    InvalidGTS2Size {
341        /// The payload constituting the timestamp, of invalid size. MSB, BE.
342        payload: Vec<u8>,
343    },
344
345    /// The number of zeroes in the Synchronization packet is less than
346    /// 47.
347    #[error(
348        "The number of zeroes in the Synchronization packet is less than expected: {0} < {}",
349        SYNC_MIN_ZEROS
350    )]
351    InvalidSync(usize),
352
353    /// A source packet (from software or hardware) contains an invalid
354    /// expected payload size.
355    #[error(
356        "A source packet (from software or hardware) contains an invalid expected payload size"
357    )]
358    InvalidSourcePayload {
359        /// The header which contains the invalid payload size.
360        header: u8,
361
362        /// The invalid payload size. See (Appendix D4.2.8, Table D4-4).
363        size: u8,
364    },
365}
366
367const SYNC_MIN_ZEROS: usize = 47;
368
369/// The decoder's possible states. The default decoder state is `Header`
370/// and will always return there after a maximum of two steps. (E.g. if
371/// the current state is `Syncing` or `HardwareSource`, the next state
372/// is `Header` again.)
373enum PacketStub {
374    /// Next zero bits will be assumed to be part of a a Synchronization
375    /// packet until a set bit is encountered.
376    Sync(usize),
377
378    /// Next bytes will be assumed to be part of an Instrumentation
379    /// packet, until `payload` contains `expected_size` bytes.
380    Instrumentation { port: u8, expected_size: usize },
381
382    /// Next bytes will be assumed to be part of a Hardware source
383    /// packet, until `payload` contains `expected_size` bytes.
384    HardwareSource { disc_id: u8, expected_size: usize },
385
386    /// Next bytes will be assumed to be part of a LocalTimestamp{1,2}
387    /// packet, until the MSB is set.
388    LocalTimestamp {
389        data_relation: TimestampDataRelation,
390    },
391
392    /// Next bytes will be assumed to be part of a GlobalTimestamp1
393    /// packet, until the MSB is set.
394    GlobalTimestamp1,
395
396    /// Next bytes will be assumed to be part of a GlobalTimestamp2
397    /// packet, until the MSB is set.
398    GlobalTimestamp2,
399}
400
401/// Combined timestamp generated from local and global timestamp
402/// packets. Field values relate to the target's global timestamp clock.
403/// See (Appendix C1, page 713).
404#[derive(Debug, Clone, PartialEq)]
405#[cfg_attr(
406    feature = "serde",
407    derive(Serialize, Deserialize),
408    serde(crate = "serde_crate")
409)]
410pub struct Timestamp {
411    /// A base timestamp upon which to apply the delta. `Some(base)` if
412    /// both a GTS1 and GTS2 packets where received.
413    pub base: Option<usize>,
414
415    /// A monotonically increasing local timestamp counter which apply
416    /// on the base timestamp. The value is the sum of all local
417    /// timestamps since the last global timestamp. `Some(delta)` if at
418    /// least one LTS1/LTS2 where received; or, if global timestamps are
419    /// enabled, if at least one LTS1/LTS2 where received since the last
420    /// global timestamp.
421    ///
422    /// Will be `None` if [DecoderOptions::only_gts] is set.
423    pub delta: Option<usize>,
424
425    /// In what manner this timestamp relate to the associated data
426    /// packets, if known.
427    pub data_relation: Option<TimestampDataRelation>,
428
429    /// An overflow packet was recieved, which may have been caused by a
430    /// local timestamp counter overflow. See (Appendix D4.2.3). The
431    /// timestamp in this structure is now potentially diverged from the
432    /// true timestamp by the maximum value of the local timestamp
433    /// counter (implementation defined), and will be considered such
434    /// until the next global timestamp.
435    pub diverged: bool,
436}
437
438impl Default for Timestamp {
439    fn default() -> Self {
440        Timestamp {
441            base: None,
442            delta: None,
443            data_relation: None,
444            diverged: false,
445        }
446    }
447}
448
449/// A context in which to record the current timestamp between calls to [Decoder::pull_with_timestamp].
450struct TimestampedContext {
451    /// Data packets associated with [TimestampedContext::ts] in this structure.
452    pub packets: Vec<TracePacket>,
453
454    /// Malformed packets associated with [TimestampedContext::ts] in this structure.
455    pub malformed_packets: Vec<MalformedPacket>,
456
457    /// The potentially received [TracePacket::GlobalTimestamp1] packet.
458    /// Used in combination with [TimestampedContext::gts2] to update
459    /// [Timestamp::base].
460    pub gts1: Option<usize>,
461
462    /// The potentially received [TracePacket::GlobalTimestamp2] packet.
463    /// Used in combination with [TimestampedContext::gts1] to update
464    /// [Timestamp::base].
465    pub gts2: Option<usize>,
466
467    /// The current timestamp.
468    pub ts: Timestamp,
469
470    /// Number of ITM packets consumed thus far.
471    pub packets_consumed: usize,
472}
473
474impl Default for TimestampedContext {
475    fn default() -> Self {
476        TimestampedContext {
477            packets: vec![],
478            malformed_packets: vec![],
479            gts1: None,
480            gts2: None,
481            ts: Timestamp::default(),
482            packets_consumed: 0,
483        }
484    }
485}
486
487pub struct DecoderOptions {
488    /// Whether to only process global timestamps in the bitstream on
489    /// [Decoder::pull_with_timestamps].
490    pub only_gts: bool,
491}
492
493impl Default for DecoderOptions {
494    fn default() -> Self {
495        Self { only_gts: false }
496    }
497}
498
499/// ITM and DWT packet protocol decoder.
500pub struct Decoder {
501    /// Decoder options
502    options: DecoderOptions,
503
504    /// The incoming bytes to the decoder.
505    incoming: BitVec,
506
507    /// Whether the decoder is in a state of synchronization.
508    sync: Option<usize>,
509
510    /// Timestamp context. Used exclusively in
511    /// [Decoder::pull_with_timestamp] for bookkeeping purposes.
512    ts_ctx: TimestampedContext,
513}
514
515/// Association between a set of [TracePacket]s and their Timestamp.
516#[derive(Debug, Clone, PartialEq)]
517#[cfg_attr(
518    feature = "serde",
519    derive(Serialize, Deserialize),
520    serde(crate = "serde_crate")
521)]
522pub struct TimestampedTracePackets {
523    ///  Timestamp of [packets] and [malformed_packets].
524    pub timestamp: Timestamp,
525    pub packets: Vec<TracePacket>,
526    pub malformed_packets: Vec<MalformedPacket>,
527
528    /// Number of ITM packets consumed to create this structure.
529    pub packets_consumed: usize,
530}
531
532enum HeaderVariant {
533    Packet(TracePacket),
534    Stub(PacketStub),
535}
536
537impl Decoder {
538    pub fn new(options: DecoderOptions) -> Self {
539        Decoder {
540            options,
541            incoming: BitVec::new(),
542            sync: None,
543            ts_ctx: TimestampedContext::default(),
544        }
545    }
546
547    /// Push trace data into the decoder.
548    pub fn push(&mut self, data: &[u8]) {
549        // To optimize the performance in pull, we must reverse the
550        // input bitstream and prepend it. This is a costly operation,
551        // but is better done here than elsewhere.
552        let mut bv = BitVec::<LocalBits, _>::from_vec(data.to_vec());
553        bv.reverse();
554        bv.append(&mut self.incoming);
555        self.incoming.append(&mut bv);
556    }
557
558    /// Decode the next [TracePacket].
559    pub fn pull(&mut self) -> Result<Option<TracePacket>, MalformedPacket> {
560        if self.sync.is_some() {
561            return self.handle_sync();
562        }
563        assert!(self.sync.is_none());
564
565        if self.incoming.len() < 8 {
566            // No header to decode, nothing to do
567            return Ok(None);
568        }
569
570        self.ts_ctx.packets_consumed = self.ts_ctx.packets_consumed + 1;
571        match Self::decode_header(self.pull_byte())? {
572            HeaderVariant::Packet(p) => Ok(Some(p)),
573            HeaderVariant::Stub(s) => self.process_stub(&s),
574        }
575    }
576
577    /// Pull the next set of ITM data packets (not timestamps) from the
578    /// decoder and associates a [Timestamp]. **Assumes that local
579    /// timestamps will be found in the bitstream.**
580    ///
581    /// According to (Appendix C1.7.1, page 710-711), a local timestamp
582    /// relating to a single, or to a stream of back-to-back packets, is
583    /// generated and sent after the data packets in question in the
584    /// bitstream.
585    ///
586    /// This function thus [Decoder::pull]s packets until a local
587    /// timestamp is read (by default), and opportunely calculates an
588    /// associated [Timestamp]: local timestamps monotonically increase
589    /// an internal delta counter; upon a global timestamps the base is
590    /// updated, and the delta is reset.
591    pub fn pull_with_timestamp(&mut self) -> Option<TimestampedTracePackets> {
592        // Common functionality for LTS{1,2}
593        fn assoc_packets_with_lts(
594            packets: Vec<TracePacket>,
595            malformed_packets: Vec<MalformedPacket>,
596            ts: &mut Timestamp,
597            lts: usize,
598            data_relation: TimestampDataRelation,
599            packets_consumed: &mut usize,
600        ) -> TimestampedTracePackets {
601            if let Some(ref mut delta) = ts.delta {
602                *delta += lts as usize;
603            } else {
604                ts.delta = Some(lts);
605            }
606            ts.data_relation = Some(data_relation);
607            let ttp = TimestampedTracePackets {
608                timestamp: ts.clone(),
609                packets,
610                malformed_packets,
611                packets_consumed: *packets_consumed,
612            };
613            *packets_consumed = 0;
614            ttp
615        }
616
617        loop {
618            match self.pull() {
619                // No packets remaining
620                Ok(None) => return None,
621
622                // A local timestamp: packets received after the last
623                // local timestamp (all self.ts_ctx.packets) relate to
624                // this local timestamp. Return the packets and
625                // timestamp.
626                Ok(Some(TracePacket::LocalTimestamp1 { ts, data_relation }))
627                    if !self.options.only_gts =>
628                {
629                    return Some(assoc_packets_with_lts(
630                        self.ts_ctx.packets.drain(..).collect(),
631                        self.ts_ctx.malformed_packets.drain(..).collect(),
632                        &mut self.ts_ctx.ts,
633                        ts as usize,
634                        data_relation,
635                        &mut self.ts_ctx.packets_consumed,
636                    ));
637                }
638                Ok(Some(TracePacket::LocalTimestamp2 { ts })) if !self.options.only_gts => {
639                    return Some(assoc_packets_with_lts(
640                        self.ts_ctx.packets.drain(..).collect(),
641                        self.ts_ctx.malformed_packets.drain(..).collect(),
642                        &mut self.ts_ctx.ts,
643                        ts as usize,
644                        TimestampDataRelation::Sync,
645                        &mut self.ts_ctx.packets_consumed,
646                    ));
647                }
648
649                // A global timestamp: store until we have both the
650                // upper (GTS2) and lower bits (GTS1).
651                Ok(Some(TracePacket::GlobalTimestamp1 { ts, wrap, clkch })) => {
652                    self.ts_ctx.gts1 = Some(ts as usize);
653                    if wrap {
654                        // upper bits have changed; GTS2 incoming
655                        self.ts_ctx.gts2 = None;
656                    }
657                    if clkch {
658                        // changed input clock to ITM; full GTS incoming
659                        self.ts_ctx.gts1 = None;
660                        self.ts_ctx.gts2 = None;
661                    }
662                }
663                Ok(Some(TracePacket::GlobalTimestamp2 { ts })) => {
664                    self.ts_ctx.gts2 = Some(ts as usize)
665                }
666
667                // An overflow: the local timestamp may potentially have
668                // wrapped around, but this is not necessarily the case.
669                // We can in any case no longer generate an accurate
670                // Timestamp.
671                Ok(Some(TracePacket::Overflow)) => {
672                    self.ts_ctx.ts.diverged = true;
673                    self.ts_ctx.packets.push(TracePacket::Overflow);
674                }
675
676                // A packet that doesn't relate to the timestamp: stash
677                // it until the next local timestamp.
678                Ok(Some(packet)) if !self.options.only_gts => self.ts_ctx.packets.push(packet),
679
680                Err(malformed) => self.ts_ctx.malformed_packets.push(malformed),
681
682                // As above, but with local timestamps considered data: return the packet directly.
683                Ok(Some(packet)) if self.options.only_gts => {
684                    return Some(TimestampedTracePackets {
685                        timestamp: self.ts_ctx.ts.clone(),
686                        packets: vec![packet],
687                        malformed_packets: vec![],
688                        packets_consumed: 1,
689                    });
690                }
691                _ => unreachable!(),
692            }
693
694            // Do we have enough info two calculate a new base for the timestamp?
695            if let (Some(lower), Some(upper)) = (self.ts_ctx.gts1, self.ts_ctx.gts2) {
696                // XXX Should we move this calc into some Timestamp::from()?
697                const GTS2_TS_SHIFT: usize = 26; // see (Appendix D4.2.5).
698                self.ts_ctx.ts = Timestamp::default();
699                self.ts_ctx.ts.base = Some((upper << GTS2_TS_SHIFT) | lower);
700                self.ts_ctx.gts1 = None;
701                self.ts_ctx.gts2 = None;
702            }
703        }
704    }
705
706    /// Read zeros from the bitstream until the first bit is set. This
707    /// realigns the incoming bitstream for further processing, which
708    /// may not be 8-bit aligned.
709    fn handle_sync(&mut self) -> Result<Option<TracePacket>, MalformedPacket> {
710        if let Some(mut count) = self.sync {
711            while let Some(bit) = self.incoming.pop() {
712                if !bit && count < SYNC_MIN_ZEROS {
713                    count += 1;
714                    continue;
715                } else if bit && count >= SYNC_MIN_ZEROS {
716                    self.sync = None;
717                    return Ok(Some(TracePacket::Sync));
718                } else {
719                    self.sync = None;
720                    return Err(MalformedPacket::InvalidSync(count));
721                }
722            }
723        }
724
725        Ok(None)
726    }
727
728    /// Pulls a single byte from the incoming buffer.
729    fn pull_byte(&mut self) -> u8 {
730        let mut b: u8 = 0;
731        for i in 0..8 {
732            b |= (self.incoming.pop().unwrap() as u8) << i;
733        }
734
735        b
736    }
737
738    /// Pulls `cnt` bytes from the incoming buffer, if `cnt` bytes are
739    /// available.
740    fn pull_bytes(&mut self, cnt: usize) -> Option<Vec<u8>> {
741        if self.incoming.len() < cnt * 8 {
742            return None;
743        }
744
745        let mut payload = vec![];
746        for _ in 0..cnt {
747            payload.push(self.pull_byte());
748        }
749        Some(payload)
750    }
751
752    /// Pulls bytes from the incoming buffer until the continuation-bit
753    /// is not set. All [PacketStub]s follow follow this payload schema.
754    /// (e.g. Appendix D4, Fig. D4-4)
755    fn pull_payload(&mut self) -> Option<Vec<u8>> {
756        let mut iter = self.incoming.rchunks(8);
757        let mut cnt = 0;
758        loop {
759            cnt = cnt + 1;
760            match iter.next() {
761                None => return None,
762                Some(b) if b.len() < 8 => return None,
763                Some(b) => match b.first_zero() {
764                    // bit 7 is not set: we have reached the end of the
765                    // payload
766                    //
767                    // TODO replace with Option::contains when stable
768                    Some(0) => break,
769                    _ => continue,
770                },
771            }
772        }
773
774        Some(self.pull_bytes(cnt).unwrap())
775    }
776
777    fn process_stub(&mut self, stub: &PacketStub) -> Result<Option<TracePacket>, MalformedPacket> {
778        match stub {
779            PacketStub::Sync(count) => {
780                self.sync = Some(*count);
781                self.handle_sync()
782            }
783
784            PacketStub::HardwareSource {
785                disc_id,
786                expected_size,
787            } => {
788                if let Some(payload) = self.pull_bytes(*expected_size) {
789                    Self::handle_hardware_source(*disc_id, payload).map(|p| Some(p))
790                } else {
791                    Ok(None)
792                }
793            }
794            PacketStub::LocalTimestamp { data_relation } => {
795                if let Some(payload) = self.pull_payload() {
796                    Ok(Some(TracePacket::LocalTimestamp1 {
797                        data_relation: data_relation.clone(),
798                        ts: Decoder::extract_timestamp(payload, 27),
799                    }))
800                } else {
801                    Ok(None)
802                }
803            }
804            PacketStub::GlobalTimestamp1 => {
805                if let Some(payload) = self.pull_payload() {
806                    Ok(Some(TracePacket::GlobalTimestamp1 {
807                        ts: Decoder::extract_timestamp(payload.clone(), 25),
808                        clkch: (payload.last().unwrap() & (1 << 5)) >> 5 == 1,
809                        wrap: (payload.last().unwrap() & (1 << 6)) >> 6 == 1,
810                    }))
811                } else {
812                    Ok(None)
813                }
814            }
815            PacketStub::GlobalTimestamp2 => {
816                if let Some(payload) = self.pull_payload() {
817                    Ok(Some(TracePacket::GlobalTimestamp2 {
818                        ts: Decoder::extract_timestamp(
819                            payload.to_vec(),
820                            match payload.len() {
821                                4 => 47 - 26, // 48 bit timestamp
822                                6 => 63 - 26, // 64 bit timestamp
823                                _ => {
824                                    return Err(MalformedPacket::InvalidGTS2Size {
825                                        payload: payload.to_vec(),
826                                    })
827                                }
828                            },
829                        ),
830                    }))
831                } else {
832                    Ok(None)
833                }
834            }
835            PacketStub::Instrumentation {
836                port,
837                expected_size,
838            } => {
839                if let Some(payload) = self.pull_bytes(*expected_size) {
840                    Ok(Some(TracePacket::Instrumentation {
841                        port: *port,
842                        payload: payload.to_vec(),
843                    }))
844                } else {
845                    Ok(None)
846                }
847            }
848        }
849    }
850
851    // TODO template this for u32, u64?
852    fn extract_timestamp(payload: Vec<u8>, max_len: u64) -> u64 {
853        // Decode the first N - 1 payload bytes
854        let (rtail, head) = payload.split_at(payload.len() - 1);
855        let mut ts: u64 = 0;
856        for (i, b) in rtail.iter().enumerate() {
857            ts |= ((b & !(1 << 7)) as u64) // mask out continuation bit
858                << (7 * i);
859        }
860
861        // Mask out the timestamp's MSBs and shift them into the final
862        // value.
863        let shift = 7 - (max_len % 7);
864        let mask: u8 = 0xFFu8.wrapping_shl(shift.try_into().unwrap()) >> shift;
865        ts | (((head[0] & mask) as u64) << (7 * rtail.len()))
866    }
867
868    /// Decodes the payload of a hardware source packet.
869    #[bitmatch]
870    fn handle_hardware_source(
871        disc_id: u8,
872        payload: Vec<u8>,
873    ) -> Result<TracePacket, MalformedPacket> {
874        match disc_id {
875            0 => {
876                // event counter wrap
877
878                if payload.len() != 1 {
879                    return Err(MalformedPacket::InvalidHardwarePacket { disc_id, payload });
880                }
881
882                let b = payload[0];
883                Ok(TracePacket::EventCounterWrap {
884                    cyc: b & (1 << 5) != 0,
885                    fold: b & (1 << 4) != 0,
886                    lsu: b & (1 << 3) != 0,
887                    sleep: b & (1 << 2) != 0,
888                    exc: b & (1 << 1) != 0,
889                    cpi: b & (1 << 0) != 0,
890                })
891            }
892            1 => {
893                // exception trace
894
895                if payload.len() != 2 {
896                    return Err(MalformedPacket::InvalidHardwarePacket { disc_id, payload });
897                }
898
899                let function = (payload[1] >> 4) & 0b11;
900                let exception_number = ((payload[1] as u16 & 1) << 8) | payload[0] as u16;
901                let exception_number: u8 = if let Ok(nr) = exception_number.try_into() {
902                    nr
903                } else {
904                    return Err(MalformedPacket::InvalidExceptionTrace {
905                        exception: exception_number,
906                        function,
907                    });
908                };
909
910                return Ok(TracePacket::ExceptionTrace {
911                    exception: if let Some(exception) = cortex_m::VectActive::from(exception_number)
912                    {
913                        exception
914                    } else {
915                        return Err(MalformedPacket::InvalidExceptionTrace {
916                            exception: exception_number.into(),
917                            function,
918                        });
919                    },
920                    action: match function {
921                        0b01 => ExceptionAction::Entered,
922                        0b10 => ExceptionAction::Exited,
923                        0b11 => ExceptionAction::Returned,
924                        _ => {
925                            return Err(MalformedPacket::InvalidExceptionTrace {
926                                exception: exception_number.into(),
927                                function,
928                            })
929                        }
930                    },
931                });
932            }
933            2 => {
934                // PC sample
935                match payload.len() {
936                    1 if payload[0] == 0 => Ok(TracePacket::PCSample { pc: None }),
937                    4 => Ok(TracePacket::PCSample {
938                        pc: Some(u32::from_le_bytes(payload.try_into().unwrap())),
939                    }),
940                    _ => Err(MalformedPacket::InvalidPCSampleSize { payload }),
941                }
942            }
943            8..=23 => {
944                // data trace
945                #[bitmatch]
946                let "???t_tccd" = disc_id; // we have already masked out bit[2:0]
947                let comparator = c;
948
949                match (t, d, payload.len()) {
950                    (0b01, 0, 4) => {
951                        // PC value packet
952                        Ok(TracePacket::DataTracePC {
953                            comparator,
954                            pc: u32::from_le_bytes(payload.try_into().unwrap()),
955                        })
956                    }
957                    (0b01, 1, 2) => {
958                        // address packet
959                        Ok(TracePacket::DataTraceAddress {
960                            comparator,
961                            data: payload,
962                        })
963                    }
964                    (0b10, d, _) => {
965                        // data value packet
966                        Ok(TracePacket::DataTraceValue {
967                            comparator,
968                            access_type: if d == 0 {
969                                MemoryAccessType::Read
970                            } else {
971                                MemoryAccessType::Write
972                            },
973                            value: payload,
974                        })
975                    }
976                    _ => Err(MalformedPacket::InvalidHardwarePacket { disc_id, payload }),
977                }
978            }
979            _ => unreachable!(), // we already verify the discriminator when we decode the header
980        }
981    }
982
983    /// Decodes the first byte of a packet, the header, into a complete packet or a packet stub.
984    #[bitmatch]
985    fn decode_header(header: u8) -> Result<HeaderVariant, MalformedPacket> {
986        fn translate_ss(ss: u8) -> Option<usize> {
987            // See (Appendix D4.2.8, Table D4-4)
988            Some(
989                match ss {
990                    0b01 => 2,
991                    0b10 => 3,
992                    0b11 => 5,
993                    _ => return None,
994                } - 1, // ss would include the header byte, but it has already been processed
995            )
996        }
997
998        let stub = |s| Ok(HeaderVariant::Stub(s));
999        let packet = |p| Ok(HeaderVariant::Packet(p));
1000
1001        #[bitmatch]
1002        match header {
1003            // Synchronization packet category
1004            "0000_0000" => stub(PacketStub::Sync(8)),
1005
1006            // Protocol packet category
1007            "0111_0000" => packet(TracePacket::Overflow),
1008            "11rr_0000" => {
1009                // Local timestamp, format 1 (LTS1)
1010                let tc = r; // relationship with corresponding data
1011
1012                stub(PacketStub::LocalTimestamp {
1013                    data_relation: match tc {
1014                        0b00 => TimestampDataRelation::Sync,
1015                        0b01 => TimestampDataRelation::UnknownDelay,
1016                        0b10 => TimestampDataRelation::AssocEventDelay,
1017                        0b11 => TimestampDataRelation::UnknownAssocEventDelay,
1018                        _ => unreachable!(),
1019                    },
1020                })
1021            }
1022            "0ttt_0000" => {
1023                // Local timestamp, format 2 (LTS2)
1024                packet(TracePacket::LocalTimestamp2 { ts: t })
1025            }
1026            "1001_0100" => {
1027                // Global timestamp, format 1 (GTS1)
1028                stub(PacketStub::GlobalTimestamp1)
1029            }
1030            "1011_0100" => {
1031                // Global timestamp, format 2(GTS2)
1032                stub(PacketStub::GlobalTimestamp2)
1033            }
1034            "0ppp_1000" => {
1035                // Extension packet
1036                packet(TracePacket::Extension { page: p })
1037            }
1038
1039            // Source packet category
1040            "aaaa_a0ss" => {
1041                // Instrumentation packet
1042                stub(PacketStub::Instrumentation {
1043                    port: a,
1044                    expected_size: if let Some(s) = translate_ss(s) {
1045                        s
1046                    } else {
1047                        return Err(MalformedPacket::InvalidSourcePayload { header, size: s });
1048                    },
1049                })
1050            }
1051            "aaaa_a1ss" => {
1052                // Hardware source packet
1053                let disc_id = a;
1054
1055                if !(0..=2).contains(&disc_id) && !(8..=23).contains(&disc_id) {
1056                    return Err(MalformedPacket::InvalidHardwareDisc {
1057                        disc_id,
1058                        size: s.into(),
1059                    });
1060                }
1061
1062                stub(PacketStub::HardwareSource {
1063                    disc_id,
1064                    expected_size: if let Some(s) = translate_ss(s) {
1065                        s
1066                    } else {
1067                        return Err(MalformedPacket::InvalidSourcePayload { header, size: s });
1068                    },
1069                })
1070            }
1071            "hhhh_hhhh" => Err(MalformedPacket::InvalidHeader(h)),
1072        }
1073    }
1074}
1075
1076#[cfg(test)]
1077mod tests {
1078    use super::*;
1079
1080    #[test]
1081    fn pull_bytes() {
1082        let mut decoder = Decoder::new(DecoderOptions::default());
1083        let payload = vec![0b1000_0000, 0b1010_0000, 0b1000_0100, 0b0110_0000];
1084        decoder.push(&payload);
1085        assert_eq!(decoder.pull_bytes(3).unwrap().len(), 3);
1086    }
1087
1088    #[test]
1089    fn pull_payload() {
1090        let mut decoder = Decoder::new(DecoderOptions::default());
1091        let payload = vec![0b1000_0000, 0b1010_0000, 0b1000_0100, 0b0110_0000];
1092        #[rustfmt::skip]
1093        decoder.push(&payload);
1094        assert_eq!(decoder.pull_payload(), Some(payload));
1095    }
1096
1097    #[test]
1098    fn extract_timestamp() {
1099        #[rustfmt::skip]
1100        let ts: Vec<u8> = [
1101            0b1000_0000,
1102            0b1000_0000,
1103            0b1000_0000,
1104            0b0000_0000,
1105        ].to_vec();
1106
1107        assert_eq!(Decoder::extract_timestamp(ts, 25), 0);
1108
1109        #[rustfmt::skip]
1110        let ts: Vec<u8> = [
1111            0b1000_0001,
1112            0b1000_0111,
1113            0b1001_1111,
1114            0b0111_1111
1115        ].to_vec();
1116
1117        assert_eq!(
1118            Decoder::extract_timestamp(ts, 27),
1119            0b1111111_0011111_0000111_0000001,
1120        );
1121
1122        #[rustfmt::skip]
1123        let ts: Vec<u8> = [
1124            0b1000_0001,
1125            0b1000_0111,
1126            0b1001_1111,
1127            0b1111_1111
1128        ].to_vec();
1129
1130        assert_eq!(
1131            Decoder::extract_timestamp(ts, 25),
1132            0b11111_0011111_0000111_0000001,
1133        );
1134    }
1135}