use core::fmt;
use super::{payload, unit, Decode, Decoder, Error};
pub struct Packet<'a, 'd, U> {
trace_type: u8,
time_tag: Option<u16>,
hart: u64,
decoder: &'a mut Decoder<'d, U>,
remaining: &'d [u8],
}
impl<U> Packet<'_, '_, U> {
pub fn trace_type(&self) -> Option<TraceType> {
self.raw_trace_type().try_into().ok()
}
pub fn raw_trace_type(&self) -> u8 {
self.trace_type
}
pub fn time_tag(&self) -> Option<u16> {
self.time_tag
}
pub fn hart(&self) -> u64 {
self.hart
}
}
impl<U: unit::Unit> Packet<'_, '_, U> {
pub fn payload(self) -> Result<payload::Payload<U::IOptions, U::DOptions>, Error> {
let trace_type = self
.raw_trace_type()
.try_into()
.map_err(Error::UnknownTraceType)?;
match trace_type {
TraceType::Instruction => {
Decode::decode(self.decoder).map(payload::Payload::InstructionTrace)
}
TraceType::Data => Ok(payload::Payload::DataTrace),
}
}
}
impl<U> fmt::Debug for Packet<'_, '_, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Packet")
.field("trace_type", &self.trace_type)
.field("time_tag", &self.time_tag)
.field("hart", &self.hart)
.field("payload", &self.decoder.remaining_data())
.finish_non_exhaustive()
}
}
impl<U> PartialEq for Packet<'_, '_, U> {
fn eq(&self, other: &Self) -> bool {
PartialEq::eq(
&(
self.trace_type,
self.time_tag,
self.hart,
self.decoder.remaining_data(),
),
&(
other.trace_type,
other.time_tag,
other.hart,
other.decoder.remaining_data(),
),
)
}
}
impl<U> Drop for Packet<'_, '_, U> {
fn drop(&mut self) {
self.decoder.reset(self.remaining);
}
}
impl<'a, 'd, U> Decode<'a, 'd, U> for Packet<'a, 'd, U> {
fn decode(decoder: &'a mut Decoder<'d, U>) -> Result<Self, Error> {
let payload_len: usize = decoder.read_bits(5)?;
let trace_type = decoder.read_bits::<u8>(2)?;
let time_tag = decoder
.read_bit()?
.then(|| decoder.read_bits(16))
.transpose()?;
let hart = decoder.read_bits(decoder.hart_index_width)?;
decoder.advance_to_byte();
decoder
.split_data(decoder.byte_pos() + payload_len)
.map(|remaining| Self {
trace_type,
time_tag,
hart,
decoder,
remaining,
})
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum TraceType {
Instruction,
Data,
}
impl TryFrom<u8> for TraceType {
type Error = u8;
fn try_from(num: u8) -> Result<Self, Self::Error> {
match num {
0b10 => Ok(TraceType::Instruction),
0b11 => Ok(TraceType::Data),
unknown => Err(unknown),
}
}
}
impl PartialEq<u8> for TraceType {
fn eq(&self, other: &u8) -> bool {
Self::try_from(*other).map(|o| *self == o).unwrap_or(false)
}
}
impl fmt::Display for TraceType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Instruction => write!(f, "Instruction"),
Self::Data => write!(f, "Data"),
}
}
}