use crate::types::{trap, Privilege};
use super::unit::{self, Unit};
use super::{util, Decode, Decoder, Error};
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Synchronization<I = unit::ReferenceIOptions, D = unit::ReferenceDOptions> {
Start(Start),
Trap(Trap),
Context(Context),
Support(Support<I, D>),
}
impl<I, D> Synchronization<I, D> {
pub fn branch_not_taken(&self) -> Option<bool> {
match self {
Self::Start(start) => Some(start.branch),
Self::Trap(trap) => Some(trap.branch),
_ => None,
}
}
pub fn as_context(&self) -> Option<&Context> {
match self {
Self::Start(start) => Some(&start.ctx),
Self::Trap(trap) => Some(&trap.ctx),
Self::Context(ctx) => Some(ctx),
_ => None,
}
}
}
impl<I, D> From<Start> for Synchronization<I, D> {
fn from(start: Start) -> Self {
Self::Start(start)
}
}
impl<I, D> From<Trap> for Synchronization<I, D> {
fn from(trap: Trap) -> Self {
Self::Trap(trap)
}
}
impl<I, D> From<Context> for Synchronization<I, D> {
fn from(ctx: Context) -> Self {
Self::Context(ctx)
}
}
impl<I, D> From<Support<I, D>> for Synchronization<I, D> {
fn from(support: Support<I, D>) -> Self {
Self::Support(support)
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Start {
pub branch: bool,
pub ctx: Context,
pub address: u64,
}
impl<U> Decode<'_, '_, U> for Start {
fn decode(decoder: &mut Decoder<U>) -> Result<Self, Error> {
let branch = decoder.read_bit()?;
let ctx = Context::decode(decoder)?;
let address = util::read_address(decoder)?;
Ok(Start {
branch,
ctx,
address,
})
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Trap {
pub branch: bool,
pub ctx: Context,
pub thaddr: bool,
pub address: u64,
pub info: trap::Info,
}
impl<U> Decode<'_, '_, U> for Trap {
fn decode(decoder: &mut Decoder<U>) -> Result<Self, Error> {
let branch = decoder.read_bit()?;
let ctx = Context::decode(decoder)?;
let ecause = decoder.read_bits(decoder.field_widths.ecause.get())?;
let interrupt = decoder.read_bit()?;
let thaddr = decoder.read_bit()?;
let address = util::read_address(decoder)?;
let tval = if interrupt {
None
} else {
Some(decoder.read_bits(decoder.field_widths.iaddress.get())?)
};
Ok(Trap {
branch,
ctx,
thaddr,
address,
info: trap::Info { ecause, tval },
})
}
}
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct Context {
pub privilege: Privilege,
pub time: Option<u64>,
pub context: Option<u64>,
}
impl<U> Decode<'_, '_, U> for Context {
fn decode(decoder: &mut Decoder<U>) -> Result<Self, Error> {
let privilege = decoder
.read_bits::<u8>(decoder.field_widths.privilege.get())?
.try_into()
.map_err(Error::UnknownPrivilege)?;
let time = decoder
.field_widths
.time
.map(|w| decoder.read_bits(w.get()))
.transpose()?;
let context = decoder
.field_widths
.context
.map(|w| decoder.read_bits(w.get()))
.transpose()?;
Ok(Context {
privilege,
time,
context,
})
}
}
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq)]
pub struct Support<I = unit::ReferenceIOptions, D = unit::ReferenceDOptions> {
pub ienable: bool,
pub encoder_mode: EncoderMode,
pub qual_status: QualStatus,
pub ioptions: I,
pub denable: bool,
pub dloss: bool,
pub doptions: D,
}
impl<U: Unit> Decode<'_, '_, U> for Support<U::IOptions, U::DOptions> {
fn decode(decoder: &mut Decoder<U>) -> Result<Self, Error> {
let ienable = decoder.read_bit()?;
let encoder_mode = decoder
.read_bits::<u8>(decoder.unit.encoder_mode_width())?
.try_into()
.map_err(Error::UnknownEncoderMode)?;
let qual_status = QualStatus::decode(decoder)?;
let ioptions = U::decode_ioptions(decoder)?;
let denable = decoder.read_bit()?;
let dloss = decoder.read_bit()?;
let doptions = U::decode_doptions(decoder)?;
Ok(Support {
ienable,
encoder_mode,
qual_status,
ioptions,
denable,
dloss,
doptions,
})
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum QualStatus {
NoChange,
EndedRep,
TraceLost,
EndedNtr,
}
impl Default for QualStatus {
fn default() -> Self {
Self::NoChange
}
}
impl<U> Decode<'_, '_, U> for QualStatus {
fn decode(decoder: &mut Decoder<U>) -> Result<Self, Error> {
Ok(match decoder.read_bits::<u8>(2)? {
0b00 => QualStatus::NoChange,
0b01 => QualStatus::EndedRep,
0b10 => QualStatus::TraceLost,
0b11 => QualStatus::EndedNtr,
_ => unreachable!(),
})
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum EncoderMode {
BranchTrace,
}
impl Default for EncoderMode {
fn default() -> Self {
Self::BranchTrace
}
}
impl TryFrom<u8> for EncoderMode {
type Error = u8;
fn try_from(num: u8) -> Result<Self, Self::Error> {
match num {
0 => Ok(Self::BranchTrace),
e => Err(e),
}
}
}