use core::fmt;
use crate::types::branch;
use super::decoder::{Decode, Decoder};
use super::encoder::{Encode, Encoder};
use super::{Error, ext, sync, unit, util};
#[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,
}
}
pub fn as_support(&self) -> Option<&sync::Support<I, D>> {
self.as_instruction_trace()
.and_then(InstructionTrace::as_support)
}
}
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),
}
}
}
impl<I: unit::IOptions, D> fmt::Display for Payload<I, D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InstructionTrace(i) => fmt::Display::fmt(i, f),
Self::DataTrace => write!(f, "DATA"),
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum InstructionTrace<I = unit::ReferenceIOptions, D = unit::ReferenceDOptions> {
Extension(ext::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> {
match decoder.read_bits::<u8>(2)? {
0b00 => ext::Extension::decode(decoder).map(Into::into),
0b01 => Branch::decode(decoder).map(Into::into),
0b10 => AddressInfo::decode(decoder).map(Into::into),
0b11 => sync::Synchronization::decode(decoder).map(Into::into),
_ => unreachable!(),
}
}
}
impl<'d, U> Encode<'d, U> for InstructionTrace<U::IOptions, U::DOptions>
where
U: unit::Unit,
U::IOptions: Encode<'d, U>,
U::DOptions: Encode<'d, U>,
{
fn encode(&self, encoder: &mut Encoder<'d, U>) -> Result<(), Error> {
match self {
Self::Extension(ext) => {
encoder.write_bits(0b00u8, 2)?;
encoder.encode(ext)
}
Self::Branch(branch) => {
encoder.write_bits(0b01u8, 2)?;
encoder.encode(branch)
}
Self::Address(addr) => {
encoder.write_bits(0b10u8, 2)?;
encoder.encode(addr)
}
Self::Synchronization(sync) => {
encoder.write_bits(0b11u8, 2)?;
encoder.encode(sync)
}
}
}
}
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(e) => e.get_address_info(),
_ => 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(e) => e.implicit_return_depth(),
_ => None,
}
}
pub fn as_support(&self) -> Option<&sync::Support<I, D>> {
match self {
Self::Synchronization(sync) => sync.as_support(),
_ => None,
}
}
}
impl<I, D> From<ext::Extension> for InstructionTrace<I, D> {
fn from(ex: ext::Extension) -> Self {
Self::Extension(ex)
}
}
impl<I, D> From<ext::BranchCount> for InstructionTrace<I, D> {
fn from(count: ext::BranchCount) -> Self {
Self::Extension(ext::Extension::BranchCount(count))
}
}
impl<I, D> From<ext::JumpTargetIndex> for InstructionTrace<I, D> {
fn from(idx: ext::JumpTargetIndex) -> Self {
Self::Extension(ext::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())
}
}
impl<I: unit::IOptions, D> fmt::Display for InstructionTrace<I, D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Extension(e) => fmt::Display::fmt(e, f),
Self::Branch(b) => write!(f, "BRANCH {b}"),
Self::Address(a) => write!(f, "ADDR {a}"),
Self::Synchronization(s) => fmt::Display::fmt(s, f),
}
}
}
#[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),
})
}
}
}
impl<U> Encode<'_, U> for Branch {
fn encode(&self, encoder: &mut Encoder<U>) -> Result<(), Error> {
if let Some(address) = self.address.as_ref() {
let count = util::BranchCount(self.branch_map.count());
encoder.encode(&count)?;
encoder.write_bits(self.branch_map.raw_map(), count.field_length())?;
encoder.encode(address)
} else {
encoder.encode(&util::BranchCount(0))?;
encoder.write_bits(self.branch_map.raw_map(), 31)
}
}
}
impl fmt::Display for Branch {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.branch_map, f)?;
if let Some(address) = self.address {
write!(f, ", {address}")?;
}
Ok(())
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct AddressInfo {
pub address: i64,
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,
})
}
}
impl<U> Encode<'_, U> for AddressInfo {
fn encode(&self, encoder: &mut Encoder<U>) -> Result<(), Error> {
util::write_address(encoder, self.address)?;
encoder.write_differential_bit(self.notify)?;
encoder.write_differential_bit(self.updiscon)?;
util::write_implicit_return(encoder, self.irdepth)
}
}
impl fmt::Display for AddressInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "address: {:0x}", self.address as u64)?;
if self.address < 0
&& let Some(addr) = self.address.checked_neg()
{
write!(f, " (-{addr:x})")?;
}
if self.notify {
write!(f, ", notify")?;
}
if self.updiscon {
write!(f, ", updiscon")?;
}
if let Some(irdepth) = self.irdepth {
write!(f, ", irdepth: {irdepth}")?;
}
Ok(())
}
}