use bitflags::bitflags;
use super::globals::MAX_OP_COUNT;
pub const INVALID_PHYS_ID: u8 = 0xFF;
bitflags! {
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
pub struct CpuRwFlags: u32 {
const NONE = 0x0000_0000;
const OF = 0x0000_0001;
const CF = 0x0000_0002;
const ZF = 0x0000_0004;
const SF = 0x0000_0008;
const X86_CF = Self::CF.bits();
const X86_OF = Self::OF.bits();
const X86_SF = Self::SF.bits();
const X86_ZF = Self::ZF.bits();
const X86_AF = 0x0000_0100;
const X86_PF = 0x0000_0200;
const X86_DF = 0x0000_0400;
const X86_IF = 0x0000_0800;
const X86_AC = 0x0000_1000;
const X86_C0 = 0x0001_0000;
const X86_C1 = 0x0002_0000;
const X86_C2 = 0x0004_0000;
const X86_C3 = 0x0008_0000;
const A64_V = Self::OF.bits();
const A64_C = Self::CF.bits();
const A64_Z = Self::ZF.bits();
const A64_N = Self::SF.bits();
const A64_Q = 0x0000_0100;
const A64_GE = 0x0000_0200;
const RISCV_FFLAGS = 0x0000_0100;
const RISCV_FRM = 0x0000_0200;
const RISCV_VXSAT = 0x0000_0400;
}
}
bitflags! {
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
pub struct OpRwFlags: u32 {
const NONE = 0;
const READ = 0x0000_0001;
const WRITE = 0x0000_0002;
const RW = Self::READ.bits() | Self::WRITE.bits();
const REG_MEM = 0x0000_0004;
const CONSECUTIVE = 0x0000_0008;
const ZEXT = 0x0000_0010;
const UNIQUE = 0x0000_0080;
const REG_PHYS_ID = 0x0000_0100;
const MEM_PHYS_ID = 0x0000_0200;
const MEM_FAKE = 0x0000_0400;
const MEM_BASE_READ = 0x0000_1000;
const MEM_BASE_WRITE = 0x0000_2000;
const MEM_BASE_RW = Self::MEM_BASE_READ.bits() | Self::MEM_BASE_WRITE.bits();
const MEM_INDEX_READ = 0x0000_4000;
const MEM_INDEX_WRITE = 0x0000_8000;
const MEM_INDEX_RW = Self::MEM_INDEX_READ.bits() | Self::MEM_INDEX_WRITE.bits();
const MEM_BASE_PRE_MODIFY = 0x0001_0000;
const MEM_BASE_POST_MODIFY = 0x0002_0000;
}
}
bitflags! {
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
pub struct InstRwFlags: u32 {
const NONE = 0x0000_0000;
const MOV_OP = 0x0000_0001;
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct OpRwInfo {
pub op_flags: OpRwFlags,
pub phys_id: u8,
pub rm_size: u8,
pub consecutive_lead_count: u8,
pub read_byte_mask: u64,
pub write_byte_mask: u64,
pub extend_byte_mask: u64,
}
impl Default for OpRwInfo {
fn default() -> Self {
Self::new()
}
}
impl OpRwInfo {
pub const fn new() -> Self {
Self {
op_flags: OpRwFlags::NONE,
phys_id: INVALID_PHYS_ID,
rm_size: 0,
consecutive_lead_count: 0,
read_byte_mask: 0,
write_byte_mask: 0,
extend_byte_mask: 0,
}
}
pub fn reset(&mut self, op_flags: OpRwFlags, register_size: u32, phys_id: u8) {
self.op_flags = op_flags;
self.phys_id = phys_id;
self.rm_size = if op_flags.contains(OpRwFlags::REG_MEM) {
register_size as u8
} else {
0
};
self.consecutive_lead_count = 0;
let mask = u64::MAX >> (64 - register_size.min(64));
self.read_byte_mask = if op_flags.contains(OpRwFlags::READ) {
mask
} else {
0
};
self.write_byte_mask = if op_flags.contains(OpRwFlags::WRITE) {
mask
} else {
0
};
self.extend_byte_mask = 0;
}
pub const fn is_read(&self) -> bool {
self.op_flags.contains(OpRwFlags::READ)
}
pub const fn is_write(&self) -> bool {
self.op_flags.contains(OpRwFlags::WRITE)
}
pub const fn is_read_write(&self) -> bool {
self.op_flags.contains(OpRwFlags::RW)
}
pub const fn is_read_only(&self) -> bool {
!self.is_write()
}
pub const fn is_write_only(&self) -> bool {
!self.is_read()
}
}
#[derive(Clone, Copy, Debug)]
pub struct InstRwInfo {
pub inst_flags: InstRwFlags,
pub read_flags: CpuRwFlags,
pub write_flags: CpuRwFlags,
pub op_count: u8,
pub rm_feature: u8,
pub extra_reg: OpRwInfo,
pub operands: [OpRwInfo; MAX_OP_COUNT],
}
impl Default for InstRwInfo {
fn default() -> Self {
Self::new()
}
}
impl InstRwInfo {
pub const fn new() -> Self {
Self {
inst_flags: InstRwFlags::NONE,
read_flags: CpuRwFlags::NONE,
write_flags: CpuRwFlags::NONE,
op_count: 0,
rm_feature: 0,
extra_reg: OpRwInfo::new(),
operands: [OpRwInfo::new(); MAX_OP_COUNT],
}
}
pub const fn is_mov_op(&self) -> bool {
self.inst_flags.contains(InstRwFlags::MOV_OP)
}
pub fn operands(&self) -> &[OpRwInfo] {
&self.operands[..self.op_count as usize]
}
pub fn operands_mut(&mut self) -> &mut [OpRwInfo] {
&mut self.operands[..self.op_count as usize]
}
pub fn operand(&self, index: usize) -> Option<&OpRwInfo> {
self.operands().get(index)
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
#[repr(u8)]
pub enum InstControlFlow {
#[default]
Regular = 0,
Jump = 1,
Branch = 2,
Call = 3,
Return = 4,
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
#[repr(u8)]
pub enum InstSameRegHint {
#[default]
None = 0,
RO = 1,
WO = 2,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn op_rw_flags_layout() {
assert_eq!(OpRwFlags::READ.bits(), 0x1);
assert_eq!(OpRwFlags::WRITE.bits(), 0x2);
assert_eq!(OpRwFlags::RW.bits(), 0x3);
assert_eq!(OpRwFlags::REG_MEM.bits(), 0x4);
}
#[test]
fn reset_computes_masks() {
let mut info = OpRwInfo::new();
info.reset(OpRwFlags::RW, 8, INVALID_PHYS_ID);
assert!(info.is_read_write());
assert_eq!(info.read_byte_mask, 0xFF);
assert_eq!(info.write_byte_mask, 0xFF);
assert_eq!(info.extend_byte_mask, 0);
info.reset(OpRwFlags::WRITE | OpRwFlags::REG_MEM, 16, 3);
assert!(info.is_write_only());
assert_eq!(info.rm_size, 16);
assert_eq!(info.phys_id, 3);
assert_eq!(info.write_byte_mask, 0xFFFF);
assert_eq!(info.read_byte_mask, 0);
}
}