use crate::types::branch;
use super::{format, sync, unit, util, Decode, Decoder, Error};
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Payload<I = unit::ReferenceIOptions, D = unit::ReferenceDOptions> {
InstructionTrace(InstructionTrace<I, D>),
DataTrace,
}
impl<I, D> Payload<I, D> {
pub fn as_instruction_trace(&self) -> Option<&InstructionTrace<I, D>> {
match self {
Payload::InstructionTrace(p) => Some(p),
_ => None,
}
}
}
impl<I, D> From<InstructionTrace<I, D>> for Payload<I, D> {
fn from(p: InstructionTrace<I, D>) -> Self {
Self::InstructionTrace(p)
}
}
impl<I, D> TryFrom<Payload<I, D>> for InstructionTrace<I, D> {
type Error = Payload<I, D>;
fn try_from(payload: Payload<I, D>) -> Result<Self, Self::Error> {
match payload {
Payload::InstructionTrace(p) => Ok(p),
p => Err(p),
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum BranchFmt {
NoAddr = 0,
Addr = 2,
AddrFail = 3,
}
impl<U> Decode<'_, '_, U> for BranchFmt {
fn decode(decoder: &mut Decoder<U>) -> Result<Self, Error> {
match decoder.read_bits::<u8>(2)? {
0b00 => Ok(BranchFmt::NoAddr),
0b01 => Err(Error::BadBranchFmt),
0b10 => Ok(BranchFmt::Addr),
0b11 => Ok(BranchFmt::AddrFail),
_ => unreachable!(),
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum InstructionTrace<I = unit::ReferenceIOptions, D = unit::ReferenceDOptions> {
Extension(Extension),
Branch(Branch),
Address(AddressInfo),
Synchronization(sync::Synchronization<I, D>),
}
impl<U: unit::Unit> Decode<'_, '_, U> for InstructionTrace<U::IOptions, U::DOptions> {
fn decode(decoder: &mut Decoder<U>) -> Result<Self, Error> {
format::Format::decode(decoder)?.decode_payload(decoder)
}
}
impl<I, D> InstructionTrace<I, D> {
pub fn get_address_info(&self) -> Option<&AddressInfo> {
match self {
Self::Address(addr) => Some(addr),
Self::Branch(branch) => branch.address.as_ref(),
Self::Extension(Extension::BranchCount(branch_count)) => branch_count.address.as_ref(),
_ => None,
}
}
pub fn implicit_return_depth(&self) -> Option<usize> {
match self {
Self::Address(a) => a.irdepth,
Self::Branch(b) => b.address.and_then(|a| a.irdepth),
Self::Extension(Extension::BranchCount(b)) => b.address.and_then(|a| a.irdepth),
Self::Extension(Extension::JumpTargetIndex(j)) => j.irdepth,
_ => None,
}
}
}
impl<I, D> From<Extension> for InstructionTrace<I, D> {
fn from(ex: Extension) -> Self {
Self::Extension(ex)
}
}
impl<I, D> From<BranchCount> for InstructionTrace<I, D> {
fn from(count: BranchCount) -> Self {
Self::Extension(Extension::BranchCount(count))
}
}
impl<I, D> From<JumpTargetIndex> for InstructionTrace<I, D> {
fn from(idx: JumpTargetIndex) -> Self {
Self::Extension(Extension::JumpTargetIndex(idx))
}
}
impl<I, D> From<Branch> for InstructionTrace<I, D> {
fn from(branch: Branch) -> Self {
Self::Branch(branch)
}
}
impl<I, D> From<AddressInfo> for InstructionTrace<I, D> {
fn from(addr: AddressInfo) -> Self {
Self::Address(addr)
}
}
impl<I, D> From<sync::Synchronization<I, D>> for InstructionTrace<I, D> {
fn from(sync: sync::Synchronization<I, D>) -> Self {
Self::Synchronization(sync)
}
}
impl<I, D> From<sync::Start> for InstructionTrace<I, D> {
fn from(start: sync::Start) -> Self {
Self::Synchronization(start.into())
}
}
impl<I, D> From<sync::Trap> for InstructionTrace<I, D> {
fn from(trap: sync::Trap) -> Self {
Self::Synchronization(trap.into())
}
}
impl<I, D> From<sync::Context> for InstructionTrace<I, D> {
fn from(ctx: sync::Context) -> Self {
Self::Synchronization(ctx.into())
}
}
impl<I, D> From<sync::Support<I, D>> for InstructionTrace<I, D> {
fn from(support: sync::Support<I, D>) -> Self {
Self::Synchronization(support.into())
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Extension {
BranchCount(BranchCount),
JumpTargetIndex(JumpTargetIndex),
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct BranchCount {
pub branch_count: u32,
pub branch_fmt: BranchFmt,
pub address: Option<AddressInfo>,
}
impl<U> Decode<'_, '_, U> for BranchCount {
fn decode(decoder: &mut Decoder<U>) -> Result<Self, Error> {
let branch_count = decoder.read_bits::<u32>(32)? - 31;
let branch_fmt = BranchFmt::decode(decoder)?;
let address = if branch_fmt == BranchFmt::NoAddr {
None
} else {
Some(AddressInfo::decode(decoder)?)
};
Ok(BranchCount {
branch_count,
address,
branch_fmt,
})
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct JumpTargetIndex {
pub index: usize,
pub branch_map: branch::Map,
pub irdepth: Option<usize>,
}
impl<U> Decode<'_, '_, U> for JumpTargetIndex {
fn decode(decoder: &mut Decoder<U>) -> Result<Self, Error> {
let index = decoder.read_bits(decoder.field_widths.cache_index)?;
let branch_map = util::BranchCount::decode(decoder)?.read_branch_map(decoder)?;
let irdepth = util::read_implicit_return(decoder)?;
Ok(JumpTargetIndex {
index,
branch_map,
irdepth,
})
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Branch {
pub branch_map: branch::Map,
pub address: Option<AddressInfo>,
}
impl<U> Decode<'_, '_, U> for Branch {
fn decode(decoder: &mut Decoder<U>) -> Result<Self, Error> {
use util::BranchCount;
let count = BranchCount::decode(decoder)?;
if count.is_zero() {
let branch_map = BranchCount::FULL.read_branch_map(decoder)?;
Ok(Branch {
branch_map,
address: None,
})
} else {
let branch_map = count.read_branch_map(decoder)?;
let address = AddressInfo::decode(decoder)?;
Ok(Branch {
branch_map,
address: Some(address),
})
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct AddressInfo {
pub address: u64,
pub notify: bool,
pub updiscon: bool,
pub irdepth: Option<usize>,
}
impl<U> Decode<'_, '_, U> for AddressInfo {
fn decode(decoder: &mut Decoder<U>) -> Result<Self, Error> {
let address = util::read_address(decoder)?;
let notify = decoder.read_differential_bit()?;
let updiscon = decoder.read_differential_bit()?;
let irdepth = util::read_implicit_return(decoder)?;
Ok(AddressInfo {
address,
notify,
updiscon,
irdepth,
})
}
}