Skip to main content

riscv_etrace/packet/
decoder.rs

1// Copyright (C) 2024 - 2026 FZI Forschungszentrum Informatik
2// SPDX-License-Identifier: Apache-2.0
3//! Packet decoder
4
5use core::num::NonZeroUsize;
6use core::ops;
7
8use super::error::Error;
9use super::payload::InstructionTrace;
10use super::truncate::TruncateNum;
11use super::unit::Unit;
12use super::width::Widths;
13use super::{encap, esp32, smi};
14
15/// A decoder for individual packets and/or [payloads][super::payload]
16///
17/// Use this decoder to decode [`encap::Packet`]s or [`smi::Packet`]s.
18///
19/// A decoder is created via a [`Builder`][super::Builder]. From the supplied
20/// data, packets of different formats may be decoded using the corresponding
21/// fns such as [`decode_encap_packet`][Self::decode_encap_packet] or
22/// [`decode_smi_packet`][Self::decode_smi_packet]. After assessing whether a
23/// packet is relevant or not, its [`Payload`][super::payload::Payload] may be
24/// decoded. Multiple packets from different harts may be sequentially decoded
25/// by a single decoder instance.
26///
27/// If a packet could not be decoded due to insufficient data, the decoder will
28/// report this by emitting an [`Error::InsufficientData`] error.
29/// Alternatively, the number of bytes left in the input can be queried via the
30/// fn [`bytes_left`][Self::bytes_left].
31///
32/// # Example
33///
34/// The follwing example demonstrates decoding of trace data in chunks with one
35/// decoder per input, including the recovery from attempting to decode an
36/// incomplete packet. We do not need to clone the [`Builder`][super::Builder]
37/// since it happens to be [`Copy`] in this case.
38///
39/// ```
40/// use riscv_etrace::packet;
41///
42/// # let parameters = Default::default();
43/// # let trace_data = b"\x45\x73\x0a\x00";
44/// # let trace_data_next = b"\x45\x73\x0a\x00\x00\x20\x41\x01";
45/// let builder = packet::builder().with_params(&parameters);
46/// let mut decoder = builder.decoder(trace_data);
47/// loop {
48///     let packet = match decoder.decode_encap_packet() {
49///         Ok(packet) => packet,
50///         Err(packet::Error::InsufficientData(_)) => break,
51///         Err(e) => panic!("{e:?}"),
52///     };
53///     // ...
54/// }
55/// let mut decoder = builder.decoder(trace_data_next);
56/// loop {
57///     let packet = match decoder.decode_encap_packet() {
58///         Ok(packet) => packet,
59///         Err(packet::Error::InsufficientData(_)) => break,
60///         Err(e) => panic!("{e:?}"),
61///     };
62///     // ...
63/// }
64/// ```
65#[derive(Clone)]
66pub struct Decoder<'d, U> {
67    data: &'d [u8],
68    bit_pos: usize,
69    field_widths: Widths,
70    unit: U,
71    hart_index_width: u8,
72    timestamp_width: u8,
73    trace_type_width: u8,
74}
75
76impl<'d, U> Decoder<'d, U> {
77    /// Create a new decoder
78    pub(super) fn new(
79        field_widths: Widths,
80        unit: U,
81        hart_index_width: u8,
82        timestamp_width: u8,
83        trace_type_width: u8,
84    ) -> Self {
85        Self {
86            data: &[],
87            bit_pos: 0,
88            field_widths,
89            unit,
90            hart_index_width,
91            timestamp_width,
92            trace_type_width,
93        }
94    }
95
96    /// Retrieve the number of bytes left in this decoder's data
97    ///
98    /// If the decoder is currently not at a byte boundary, the number returned
99    /// includes the partially decoded byte.
100    pub fn bytes_left(&self) -> usize {
101        self.data.len().saturating_sub(self.bit_pos >> 3)
102    }
103
104    /// Retrieve the current byte position
105    ///
106    /// Returns the zero-based position of the byte which is currently decoded.
107    /// If the current bit position is on a byte boundary, the position of the
108    /// byte after the boundary is returned.
109    ///
110    /// # Example
111    ///
112    /// ```
113    /// use riscv_etrace::packet;
114    ///
115    /// # let trace_data = &[];
116    /// let mut decoder = packet::builder().decoder(trace_data);
117    /// assert_eq!(decoder.byte_pos(), 0);
118    /// ```
119    pub fn byte_pos(&self) -> usize {
120        self.bit_pos >> 3
121    }
122
123    /// Reset the inner data to the given byte slice
124    pub fn reset(&mut self, data: &'d [u8]) {
125        self.bit_pos = 0;
126        self.data = data;
127    }
128
129    /// Decode a single item
130    ///
131    /// Decodes a single item, consuming the associated data from the input and
132    /// sign-extending the input if neccessary. Depending on the item's type and
133    /// [`Decode`] implementation, the decoder may be left at a _bit_ boundary
134    /// following the item after successful operation. A failure may leave the
135    /// decoder in an unspecified state.
136    pub fn decode<T: Decode<'d, U>>(&mut self) -> Result<T, Error> {
137        Decode::decode(self)
138    }
139
140    /// Decode a single [`encap::Packet`]
141    ///
142    /// Decodes a single [`encap::Packet`], consuming the associated data from
143    /// the input. After successful operation, the decoder is left at the byte
144    /// boundary following the packet, ready to decode the next one. A failure
145    /// may leave the decoder in an unspecified state.
146    pub fn decode_encap_packet(&mut self) -> Result<encap::Packet<Self>, Error>
147    where
148        U: Clone,
149    {
150        Decode::decode(self)
151    }
152
153    /// Decode a single [`smi::Packet`] consisting of header and payload
154    ///
155    /// Decodes a single [`smi::Packet`], consuming the associated data from the
156    /// input. After successful operation, the decoder is left at the byte
157    /// boundary following the packet, ready to decode the next one. A failure
158    /// may leave the decoder in an unspecified state.
159    pub fn decode_smi_packet(&mut self) -> Result<smi::Packet<Self>, Error>
160    where
161        U: Clone,
162    {
163        Decode::decode(self)
164    }
165
166    pub fn decode_esp32_packet(&mut self) -> Result<esp32::Packet<Self>, Error>
167    where
168        U: Clone,
169    {
170        Decode::decode(self)
171    }
172
173    /// Decode a single, stand-alone [`InstructionTrace`] payload
174    ///
175    /// Decodes a single [`InstructionTrace`] payload, consuming the associated
176    /// data from the input and sign-extending the input if neccessary. After
177    /// successful operation, the decoder is left at the _bit_ boundary
178    /// following the payload. A failure may leave the decoder in an unspecified
179    /// state.
180    pub fn decode_payload(&mut self) -> Result<InstructionTrace<U::IOptions, U::DOptions>, Error>
181    where
182        U: Unit,
183    {
184        Decode::decode(self)
185    }
186
187    /// Retrieve this decoder's [`Unit`]
188    pub fn unit(&self) -> &U {
189        &self.unit
190    }
191
192    /// Retrieve the payload field widths
193    pub(super) fn widths(&self) -> &Widths {
194        &self.field_widths
195    }
196
197    /// Retrieve the hart index width
198    pub(super) fn hart_index_width(&self) -> u8 {
199        self.hart_index_width
200    }
201
202    /// Retrieve the width of the timestamp used in packet headers
203    pub(super) fn timestamp_width(&self) -> u8 {
204        self.timestamp_width
205    }
206
207    /// Retrieve the trace type width
208    pub(super) fn trace_type_width(&self) -> u8 {
209        self.trace_type_width
210    }
211
212    /// Advance the position to the next byte boundary
213    pub(super) fn advance_to_byte(&mut self) {
214        if self.bit_pos & 0x7 != 0 {
215            self.bit_pos = (self.bit_pos & !0x7usize) + 8;
216        }
217    }
218
219    /// Retrieve the remaining inner data, including the current byte
220    ///
221    /// If the current bit position is at a byte buondary, e.g. after successful
222    /// decoding of a packet, the returned buffer contains only undecoded data.
223    pub fn remaining_data(&self) -> &'d [u8] {
224        self.data
225            .split_at_checked(self.bit_pos >> 3)
226            .unwrap_or_default()
227            .1
228    }
229
230    /// Split off a sub-decoder covering the data to the given position
231    ///
232    /// On success, the inner data will be reset to the portion of the original
233    /// data starting at and including byte `pos` past the current
234    /// [byte position][Self::byte_pos]. A decoder with the original bit
235    /// position covering the first half of the buffer will be returned.
236    pub fn split_off_to(&mut self, pos: usize) -> Result<Self, Error>
237    where
238        U: Clone,
239    {
240        let pos = self.byte_pos().saturating_add(pos);
241        if let Some((data, remaining)) = self.data.split_at_checked(pos) {
242            let mut res = self.clone();
243            res.data = data;
244            self.reset(remaining);
245            Ok(res)
246        } else {
247            let need = pos
248                .checked_sub(self.data.len())
249                .and_then(NonZeroUsize::new)
250                .unwrap_or(NonZeroUsize::MIN);
251            Err(Error::InsufficientData(need))
252        }
253    }
254
255    /// Read a single bit
256    pub(super) fn read_bit(&mut self) -> Result<bool, Error> {
257        let res = (self.get_byte(self.bit_pos >> 3)? >> (self.bit_pos & 0x07)) & 0x1;
258        self.bit_pos += 1;
259        Ok(res != 0)
260    }
261
262    /// Read a single differential bit
263    ///
264    /// The bit's value is considered to be [`true`] if it differs from the
265    /// previous bit and [`false`] if it doesn't.
266    pub(super) fn read_differential_bit(&mut self) -> Result<bool, Error> {
267        let reference_pos = self
268            .bit_pos
269            .checked_sub(1)
270            .ok_or(Error::InsufficientData(NonZeroUsize::MIN))?;
271        let reference_bit = (self.get_byte(reference_pos >> 3)? >> (reference_pos & 0x07)) & 0x1;
272        let raw_bit = (self.get_byte(self.bit_pos >> 3)? >> (self.bit_pos & 0x07)) & 0x1;
273        self.bit_pos += 1;
274        Ok(reference_bit ^ raw_bit != 0)
275    }
276
277    /// Read a number of bits as an integer
278    ///
279    /// Unsigned integers will be left-padded with zeroes, signed integers will
280    /// be sign-extended.
281    ///
282    /// # Safety
283    ///
284    /// May panic if `bit_count` is higher then the bit width of the target
285    /// integer.
286    pub(super) fn read_bits<T>(&mut self, bit_count: u8) -> Result<T, Error>
287    where
288        T: From<u8>
289            + ops::Shl<usize, Output = T>
290            + ops::Shr<usize, Output = T>
291            + ops::BitOrAssign<T>
292            + TruncateNum,
293    {
294        let lowest_bits = self.bit_pos & 0x07;
295        let mut byte_pos = self.bit_pos >> 3;
296        let mut res = T::from(self.get_byte(byte_pos)?) >> lowest_bits;
297        let mut bits_extracted = 8 - lowest_bits;
298
299        while bits_extracted < bit_count.into() {
300            byte_pos += 1;
301            res |= T::from(self.get_byte(byte_pos)?) << bits_extracted;
302            bits_extracted += 8;
303        }
304
305        self.bit_pos += usize::from(bit_count);
306        Ok(res.truncated(bit_count))
307    }
308
309    /// Get the byte at the given byte position
310    ///
311    /// If the byte position is past the end of the current data source, the
312    /// result of a decompression if returned.
313    fn get_byte(&self, pos: usize) -> Result<u8, Error> {
314        if let Some(byte) = self.data.get(pos) {
315            Ok(*byte)
316        } else {
317            self.data
318                .last()
319                .map(|b| if b & 0x80 != 0 { 0xFF } else { 0x00 })
320                .ok_or(Error::InsufficientData(NonZeroUsize::MIN))
321        }
322    }
323}
324
325/// Decodable item
326///
327/// Items implementing this trait may be decoded using an [`Decoder`].
328pub trait Decode<'d, U>: Sized {
329    /// Decode an item of this type
330    fn decode(decoder: &mut Decoder<'d, U>) -> Result<Self, Error>;
331}