use crate::instruction::{self, Instruction};
use crate::types::{trap, Context};
use super::hart2enc::{CType, IType, JumpType};
use instruction::info::Info;
pub trait Step {
fn address(&self) -> u64;
fn kind(&self) -> Kind;
fn ctype(&self) -> CType;
fn context(&self) -> Context;
fn timestamp(&self) -> Option<u64> {
None
}
fn refine(&mut self, _next: &Self) {}
}
#[derive(Copy, Clone, Debug)]
pub enum Kind {
Retirement {
insn_size: instruction::Size,
},
Trap {
insn_size: Option<instruction::Size>,
info: trap::Info,
},
TrapReturn {
insn_size: instruction::Size,
},
Branch {
insn_size: instruction::Size,
taken: bool,
},
Jump {
insn_size: instruction::Size,
kind: JumpType,
sequentially_inferable: bool,
},
}
impl Kind {
pub fn is_exc_only(self) -> bool {
matches!(
self,
Kind::Trap {
insn_size: None,
..
}
)
}
pub fn is_updiscon(self, infer_sequentially: bool) -> bool {
match self {
Self::TrapReturn { .. } => true,
Self::Jump {
kind,
sequentially_inferable,
..
} => !(kind.is_inferable() || (infer_sequentially && sequentially_inferable)),
_ => false,
}
}
pub fn instruction_size(self) -> Option<instruction::Size> {
match self {
Self::Retirement { insn_size } => Some(insn_size),
Self::Trap { insn_size, .. } => insn_size,
Self::TrapReturn { insn_size } => Some(insn_size),
Self::Branch { insn_size, .. } => Some(insn_size),
Self::Jump { insn_size, .. } => Some(insn_size),
}
}
pub fn from_instruction<I: Info>(
insn: Instruction<I>,
branch_taken: bool,
prev_immediate: Option<I::Register>,
) -> Self {
let insn_size = insn.size;
if insn.is_return_from_trap() {
return Self::TrapReturn { insn_size };
};
if insn.is_branch() {
return Self::Branch {
insn_size,
taken: branch_taken,
};
}
if let Some((target, _)) = insn.uninferable_jump_target() {
let kind = if insn.is_call() {
JumpType::UnferCall
} else if insn.is_return() {
JumpType::Return
} else {
JumpType::UnferOther
};
return Self::Jump {
insn_size,
kind,
sequentially_inferable: Some(target) == prev_immediate,
};
} else if insn.is_inferable_jump() {
let kind = if insn.is_call() {
JumpType::InferCall
} else {
JumpType::InferOther
};
return Self::Jump {
insn_size,
kind,
sequentially_inferable: false,
};
}
Self::Retirement { insn_size }
}
pub fn from_hart(
itype: IType,
ecause: u16,
tval: u64,
insn_size: instruction::Size,
retired: bool,
sequentially_inferable: bool,
) -> Self {
match itype {
IType::Other => Self::Retirement { insn_size },
IType::Exception => Self::Trap {
insn_size: retired.then_some(insn_size),
info: trap::Info {
ecause,
tval: Some(tval),
},
},
IType::Interrupt => Self::Trap {
insn_size: retired.then_some(insn_size),
info: trap::Info { ecause, tval: None },
},
IType::ExReturn => Self::TrapReturn { insn_size },
IType::Branch { taken } => Self::Branch { insn_size, taken },
IType::Jump(kind) => Self::Jump {
insn_size,
kind,
sequentially_inferable,
},
}
}
}