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(¶meters);
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}