use core::fmt;
use core::num::NonZeroUsize;
use core::ops;
use super::error::Error;
use super::payload::InstructionTrace;
use super::truncate::TruncateNum;
use super::unit::Unit;
use super::width::Widths;
use super::{encap, smi};
#[derive(Clone)]
pub struct Decoder<'d, U> {
data: &'d [u8],
bit_pos: usize,
field_widths: Widths,
unit: U,
hart_index_width: u8,
timestamp_width: u8,
trace_type_width: u8,
}
impl<'d, U> Decoder<'d, U> {
pub(super) fn new(
field_widths: Widths,
unit: U,
hart_index_width: u8,
timestamp_width: u8,
trace_type_width: u8,
) -> Self {
Self {
data: &[],
bit_pos: 0,
field_widths,
unit,
hart_index_width,
timestamp_width,
trace_type_width,
}
}
pub fn bytes_left(&self) -> usize {
self.data.len().saturating_sub(self.bit_pos >> 3)
}
pub fn byte_pos(&self) -> usize {
self.bit_pos >> 3
}
pub fn reset(&mut self, data: &'d [u8]) {
self.bit_pos = 0;
self.data = data;
}
pub fn decode_encap_packet(&mut self) -> Result<encap::Packet<Scoped<'_, 'd, U>>, Error> {
Decode::decode(self)
}
pub fn decode_smi_packet(&mut self) -> Result<smi::Packet<Scoped<'_, 'd, U>>, Error> {
Decode::decode(self)
}
pub fn decode_payload(&mut self) -> Result<InstructionTrace<U::IOptions, U::DOptions>, Error>
where
U: Unit,
{
Decode::decode(self)
}
pub fn unit(&self) -> &U {
&self.unit
}
pub(super) fn widths(&self) -> &Widths {
&self.field_widths
}
pub(super) fn hart_index_width(&self) -> u8 {
self.hart_index_width
}
pub(super) fn timestamp_width(&self) -> u8 {
self.timestamp_width
}
pub(super) fn trace_type_width(&self) -> u8 {
self.trace_type_width
}
pub(super) fn advance_to_byte(&mut self) {
if self.bit_pos & 0x7 != 0 {
self.bit_pos = (self.bit_pos & !0x7usize) + 8;
}
}
pub fn remaining_data(&self) -> &'d [u8] {
self.data
.split_at_checked(self.bit_pos >> 3)
.unwrap_or_default()
.1
}
pub(super) fn split_data(&mut self, mid: usize) -> Result<&'d [u8], Error> {
if let Some((data, remaining)) = self.data.split_at_checked(mid) {
self.data = data;
Ok(remaining)
} else {
let need = mid
.checked_sub(self.data.len())
.and_then(NonZeroUsize::new)
.unwrap_or(NonZeroUsize::MIN);
Err(Error::InsufficientData(need))
}
}
pub(super) fn read_bit(&mut self) -> Result<bool, Error> {
let res = (self.get_byte(self.bit_pos >> 3)? >> (self.bit_pos & 0x07)) & 0x1;
self.bit_pos += 1;
Ok(res != 0)
}
pub(super) fn read_differential_bit(&mut self) -> Result<bool, Error> {
let reference_pos = self
.bit_pos
.checked_sub(1)
.ok_or(Error::InsufficientData(NonZeroUsize::MIN))?;
let reference_bit = (self.get_byte(reference_pos >> 3)? >> (reference_pos & 0x07)) & 0x1;
let raw_bit = (self.get_byte(self.bit_pos >> 3)? >> (self.bit_pos & 0x07)) & 0x1;
self.bit_pos += 1;
Ok(reference_bit ^ raw_bit != 0)
}
pub(super) fn read_bits<T>(&mut self, bit_count: u8) -> Result<T, Error>
where
T: From<u8>
+ ops::Shl<usize, Output = T>
+ ops::Shr<usize, Output = T>
+ ops::BitOrAssign<T>
+ TruncateNum,
{
let lowest_bits = self.bit_pos & 0x07;
let mut byte_pos = self.bit_pos >> 3;
let mut res = T::from(self.get_byte(byte_pos)?) >> lowest_bits;
let mut bits_extracted = 8 - lowest_bits;
while bits_extracted < bit_count.into() {
byte_pos += 1;
res |= T::from(self.get_byte(byte_pos)?) << bits_extracted;
bits_extracted += 8;
}
self.bit_pos += usize::from(bit_count);
Ok(res.truncated(bit_count))
}
fn get_byte(&self, pos: usize) -> Result<u8, Error> {
if let Some(byte) = self.data.get(pos) {
Ok(*byte)
} else {
self.data
.last()
.map(|b| if b & 0x80 != 0 { 0xFF } else { 0x00 })
.ok_or(Error::InsufficientData(NonZeroUsize::MIN))
}
}
}
pub(super) trait Decode<'a, 'd, U>: Sized {
fn decode(decoder: &'a mut Decoder<'d, U>) -> Result<Self, Error>;
}
pub struct Scoped<'a, 'd, U> {
decoder: &'a mut Decoder<'d, U>,
remaining: &'d [u8],
}
impl<'a, 'd, U> Scoped<'a, 'd, U> {
pub fn new(decoder: &'a mut Decoder<'d, U>, length: usize) -> Result<Self, Error> {
decoder
.split_data(decoder.byte_pos().saturating_add(length))
.map(|remaining| Self { decoder, remaining })
}
pub fn decoder_mut(&mut self) -> &mut Decoder<'d, U> {
self.decoder
}
}
impl<U> fmt::Debug for Scoped<'_, '_, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Scoped")
.field("unaligned_data", &self.decoder.remaining_data())
.finish_non_exhaustive()
}
}
impl<U> PartialEq for Scoped<'_, '_, U> {
fn eq(&self, other: &Self) -> bool {
PartialEq::eq(
self.decoder.remaining_data(),
other.decoder.remaining_data(),
)
}
}
impl<'a, 'd, U> Drop for Scoped<'a, 'd, U> {
fn drop(&mut self) {
self.decoder.reset(self.remaining);
}
}