pub mod encap;
pub mod error;
mod format;
pub mod payload;
pub mod smi;
pub mod sync;
pub mod truncate;
pub mod unit;
mod util;
mod width;
#[cfg(test)]
mod tests;
pub use error::Error;
use core::num::NonZeroUsize;
use core::ops;
use crate::config;
use payload::InstructionTrace;
use truncate::TruncateNum;
#[derive(Clone)]
pub struct Decoder<'d, U> {
data: &'d [u8],
bit_pos: usize,
field_widths: width::Widths,
unit: U,
hart_index_width: u8,
timestamp_width: u8,
trace_type_width: u8,
}
impl<'d, U> Decoder<'d, U> {
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<'_, 'd, U>, Error> {
Decode::decode(self)
}
pub fn decode_smi_packet(&mut self) -> Result<smi::Packet<'_, 'd, U>, Error> {
Decode::decode(self)
}
pub fn decode_payload(&mut self) -> Result<InstructionTrace<U::IOptions, U::DOptions>, Error>
where
U: unit::Unit,
{
Decode::decode(self)
}
pub fn unit(&self) -> &U {
&self.unit
}
fn advance_to_byte(&mut self) {
if self.bit_pos & 0x7 != 0 {
self.bit_pos = (self.bit_pos & !0x7usize) + 8;
}
}
fn remaining_data(&self) -> &'d [u8] {
self.data
.split_at_checked(self.bit_pos >> 3)
.unwrap_or_default()
.1
}
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))
}
}
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)
}
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)
}
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 fn builder() -> Builder<unit::Reference> {
Default::default()
}
#[derive(Copy, Clone, Default)]
pub struct Builder<U = unit::Reference> {
field_widths: width::Widths,
unit: U,
hart_index_width: u8,
timestamp_width: u8,
trace_type_width: u8,
}
impl Builder<unit::Reference> {
pub fn new() -> Self {
Default::default()
}
}
impl<U> Builder<U> {
pub fn with_params(self, params: &config::Parameters) -> Self {
Self {
field_widths: params.into(),
..self
}
}
pub fn for_unit<V>(self, unit: V) -> Builder<V> {
Builder {
field_widths: self.field_widths,
unit,
hart_index_width: self.hart_index_width,
timestamp_width: self.timestamp_width,
trace_type_width: self.trace_type_width,
}
}
pub fn with_hart_index_width(self, hart_index_width: u8) -> Self {
Self {
hart_index_width,
..self
}
}
pub fn with_timestamp_width(self, timestamp_width: u8) -> Self {
Self {
timestamp_width,
..self
}
}
pub fn with_trace_type_width(self, trace_type_width: u8) -> Self {
Self {
trace_type_width,
..self
}
}
pub fn build(self, data: &[u8]) -> Decoder<'_, U> {
Decoder {
data,
bit_pos: 0,
field_widths: self.field_widths,
unit: self.unit,
hart_index_width: self.hart_index_width,
timestamp_width: self.timestamp_width,
trace_type_width: self.trace_type_width,
}
}
}
trait Decode<'a, 'd, U>: Sized {
fn decode(decoder: &'a mut Decoder<'d, U>) -> Result<Self, Error>;
}