use core::fmt;
use crate::types::branch;
use super::decoder::{Decode, Decoder};
use super::encoder::{Encode, Encoder};
use super::payload::AddressInfo;
use super::{Error, util};
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Extension {
BranchCount(BranchCount),
JumpTargetIndex(JumpTargetIndex),
}
impl Extension {
pub fn get_address_info(&self) -> Option<&AddressInfo> {
match self {
Self::BranchCount(b) => b.kind.address_info(),
_ => None,
}
}
pub fn implicit_return_depth(&self) -> Option<usize> {
match self {
Self::BranchCount(b) => b.kind.address_info().and_then(|a| a.irdepth),
Self::JumpTargetIndex(j) => j.irdepth,
}
}
}
impl<U> Decode<'_, U> for Extension {
fn decode(decoder: &mut Decoder<U>) -> Result<Self, Error> {
match decoder.read_bits(decoder.widths().format0_subformat)? {
0 => BranchCount::decode(decoder).map(Self::BranchCount),
1 => JumpTargetIndex::decode(decoder).map(Self::JumpTargetIndex),
s => Err(Error::UnknownFmt(0, Some(s))),
}
}
}
impl<U> Encode<'_, U> for Extension {
fn encode(&self, encoder: &mut Encoder<U>) -> Result<(), Error> {
match self {
Self::BranchCount(branch) => encoder.encode(branch),
Self::JumpTargetIndex(jti) => encoder.encode(jti),
}
}
}
impl fmt::Display for Extension {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::BranchCount(b) => write!(f, "BRANCH COUNT {b}"),
Self::JumpTargetIndex(j) => write!(f, "JTI {j}"),
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct BranchCount {
pub branch_count: u32,
pub kind: BranchKind,
}
impl<U> Decode<'_, U> for BranchCount {
fn decode(decoder: &mut Decoder<U>) -> Result<Self, Error> {
let branch_count = decoder.read_bits(32)?;
let kind = BranchKind::decode(decoder)?;
Ok(BranchCount { branch_count, kind })
}
}
impl<U> Encode<'_, U> for BranchCount {
fn encode(&self, encoder: &mut Encoder<U>) -> Result<(), Error> {
encoder.write_bits(self.branch_count, 32)?;
encoder.encode(&self.kind)
}
}
impl fmt::Display for BranchCount {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} branches predicted correctly", self.branch_count)?;
match self.kind {
BranchKind::NoAddr => Ok(()),
BranchKind::Addr(info) => write!(f, ", including branch at {info}"),
BranchKind::AddrFail(info) => write!(f, ", excluding branch at {info}"),
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum BranchKind {
NoAddr,
Addr(AddressInfo),
AddrFail(AddressInfo),
}
impl BranchKind {
pub fn address_info(&self) -> Option<&AddressInfo> {
match self {
Self::Addr(a) => Some(a),
Self::AddrFail(a) => Some(a),
_ => None,
}
}
}
impl<U> Decode<'_, U> for BranchKind {
fn decode(decoder: &mut Decoder<U>) -> Result<Self, Error> {
match decoder.read_bits::<u8>(2)? {
0b00 => Ok(Self::NoAddr),
0b01 => Err(Error::BadBranchFmt),
0b10 => decoder.decode().map(Self::Addr),
0b11 => decoder.decode().map(Self::AddrFail),
_ => unreachable!(),
}
}
}
impl<U> Encode<'_, U> for BranchKind {
fn encode(&self, encoder: &mut Encoder<U>) -> Result<(), Error> {
match self {
Self::NoAddr => encoder.write_bits(0b00u8, 2),
Self::Addr(info) => {
encoder.write_bits(0b10u8, 2)?;
encoder.encode(info)
}
Self::AddrFail(info) => {
encoder.write_bits(0b11u8, 2)?;
encoder.encode(info)
}
}
}
}
#[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.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,
})
}
}
impl<U> Encode<'_, U> for JumpTargetIndex {
fn encode(&self, encoder: &mut Encoder<U>) -> Result<(), Error> {
encoder.write_bits(self.index, encoder.widths().cache_index)?;
let count = util::BranchCount(self.branch_map.count());
encoder.encode(&count)?;
encoder.write_bits(self.branch_map.raw_map(), count.field_length())?;
util::write_implicit_return(encoder, self.irdepth)
}
}
impl fmt::Display for JumpTargetIndex {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "index: {}, {}", self.index, self.branch_map)?;
if let Some(irdepth) = self.irdepth {
write!(f, ", irdepth: {irdepth}")?;
}
Ok(())
}
}