-use crate::{DivInput, DivResult, OverflowFlags};
+use crate::{ConditionRegister, InstructionInput, InstructionResult, OverflowFlags};
-pub fn divdeo(inputs: DivInput) -> DivResult {
- let dividend = i128::from(inputs.dividend as i64) << 64;
- let divisor = i128::from(inputs.divisor as i64);
+macro_rules! create_instr_variants {
+ ($fn:ident, $fno:ident, $fn_:ident, $fno_:ident, $iwidth:ident) => {
+ pub fn $fn(inputs: InstructionInput) -> InstructionResult {
+ InstructionResult {
+ overflow: None,
+ ..$fno(inputs)
+ }
+ }
+ pub fn $fn_(inputs: InstructionInput) -> InstructionResult {
+ let mut retval = $fno_(inputs);
+ let mut cr0 = retval.cr0.as_mut().expect("expected cr0 to be set");
+ cr0.so = false;
+ retval.overflow = None;
+ retval
+ }
+ pub fn $fno_(inputs: InstructionInput) -> InstructionResult {
+ let mut retval = $fno(inputs);
+ let result = retval.rt.expect("expected rt to be set");
+ let so = retval.overflow.expect("expected overflow to be set").so;
+ let cr0 = ConditionRegister::from_signed_int(result as $iwidth, so);
+ retval.cr0 = Some(cr0);
+ retval
+ }
+ };
+}
+
+create_instr_variants!(divde, divdeo, divde_, divdeo_, i64);
+
+pub fn divdeo(inputs: InstructionInput) -> InstructionResult {
+ let dividend = i128::from(inputs.ra as i64) << 64;
+ let divisor = i128::from(inputs.rb as i64);
let overflow;
let result;
if divisor == 0 || (divisor == -1 && dividend == i128::min_value()) {
overflow = false;
}
}
- DivResult {
- result,
- overflow: Some(OverflowFlags {
- overflow,
- overflow32: overflow,
- }),
+ InstructionResult {
+ rt: Some(result),
+ overflow: Some(OverflowFlags::from_overflow(overflow)),
+ ..InstructionResult::default()
}
}
-pub fn divdeuo(inputs: DivInput) -> DivResult {
- let dividend = u128::from(inputs.dividend) << 64;
- let divisor = u128::from(inputs.divisor);
+create_instr_variants!(divdeu, divdeuo, divdeu_, divdeuo_, i64);
+
+pub fn divdeuo(inputs: InstructionInput) -> InstructionResult {
+ let dividend = u128::from(inputs.ra) << 64;
+ let divisor = u128::from(inputs.rb);
let overflow;
let result;
if divisor == 0 {
overflow = false;
}
}
- DivResult {
- result,
- overflow: Some(OverflowFlags {
- overflow,
- overflow32: overflow,
- }),
+ InstructionResult {
+ rt: Some(result),
+ overflow: Some(OverflowFlags::from_overflow(overflow)),
+ ..InstructionResult::default()
}
}
-pub fn divdo(inputs: DivInput) -> DivResult {
- let dividend = inputs.dividend as i64;
- let divisor = inputs.divisor as i64;
+create_instr_variants!(divd, divdo, divd_, divdo_, i64);
+
+pub fn divdo(inputs: InstructionInput) -> InstructionResult {
+ let dividend = inputs.ra as i64;
+ let divisor = inputs.rb as i64;
let overflow;
let result;
if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
result = (dividend / divisor) as u64;
overflow = false;
}
- DivResult {
- result,
- overflow: Some(OverflowFlags {
- overflow,
- overflow32: overflow,
- }),
+ InstructionResult {
+ rt: Some(result),
+ overflow: Some(OverflowFlags::from_overflow(overflow)),
+ ..InstructionResult::default()
}
}
-pub fn divduo(inputs: DivInput) -> DivResult {
- let dividend: u64 = inputs.dividend;
- let divisor: u64 = inputs.divisor;
+create_instr_variants!(divdu, divduo, divdu_, divduo_, i64);
+
+pub fn divduo(inputs: InstructionInput) -> InstructionResult {
+ let dividend: u64 = inputs.ra;
+ let divisor: u64 = inputs.rb;
let overflow;
let result;
if divisor == 0 {
result = dividend / divisor;
overflow = false;
}
- DivResult {
- result,
- overflow: Some(OverflowFlags {
- overflow,
- overflow32: overflow,
- }),
+ InstructionResult {
+ rt: Some(result),
+ overflow: Some(OverflowFlags::from_overflow(overflow)),
+ ..InstructionResult::default()
}
}
-pub fn divweo(inputs: DivInput) -> DivResult {
- let dividend = i64::from(inputs.dividend as i32) << 32;
- let divisor = i64::from(inputs.divisor as i32);
+create_instr_variants!(divwe, divweo, divwe_, divweo_, i32);
+
+pub fn divweo(inputs: InstructionInput) -> InstructionResult {
+ let dividend = i64::from(inputs.ra as i32) << 32;
+ let divisor = i64::from(inputs.rb as i32);
let overflow;
let result;
if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
overflow = false;
}
}
- DivResult {
- result,
- overflow: Some(OverflowFlags {
- overflow,
- overflow32: overflow,
- }),
+ InstructionResult {
+ rt: Some(result),
+ overflow: Some(OverflowFlags::from_overflow(overflow)),
+ ..InstructionResult::default()
}
}
-pub fn divweuo(inputs: DivInput) -> DivResult {
- let dividend = u64::from(inputs.dividend as u32) << 32;
- let divisor = u64::from(inputs.divisor as u32);
+create_instr_variants!(divweu, divweuo, divweu_, divweuo_, i32);
+
+pub fn divweuo(inputs: InstructionInput) -> InstructionResult {
+ let dividend = u64::from(inputs.ra as u32) << 32;
+ let divisor = u64::from(inputs.rb as u32);
let overflow;
let result;
if divisor == 0 {
overflow = false;
}
}
- DivResult {
- result,
- overflow: Some(OverflowFlags {
- overflow,
- overflow32: overflow,
- }),
+ InstructionResult {
+ rt: Some(result),
+ overflow: Some(OverflowFlags::from_overflow(overflow)),
+ ..InstructionResult::default()
}
}
-pub fn divwo(inputs: DivInput) -> DivResult {
- let dividend = inputs.dividend as i32;
- let divisor = inputs.divisor as i32;
+create_instr_variants!(divw, divwo, divw_, divwo_, i32);
+
+pub fn divwo(inputs: InstructionInput) -> InstructionResult {
+ let dividend = inputs.ra as i32;
+ let divisor = inputs.rb as i32;
let overflow;
let result;
if divisor == 0 || (divisor == -1 && dividend == i32::min_value()) {
result = (dividend / divisor) as u32 as u64;
overflow = false;
}
- DivResult {
- result,
- overflow: Some(OverflowFlags {
- overflow,
- overflow32: overflow,
- }),
+ InstructionResult {
+ rt: Some(result),
+ overflow: Some(OverflowFlags::from_overflow(overflow)),
+ ..InstructionResult::default()
}
}
-pub fn divwuo(inputs: DivInput) -> DivResult {
- let dividend = inputs.dividend as u32;
- let divisor = inputs.divisor as u32;
+create_instr_variants!(divwu, divwuo, divwu_, divwuo_, i32);
+
+pub fn divwuo(inputs: InstructionInput) -> InstructionResult {
+ let dividend = inputs.ra as u32;
+ let divisor = inputs.rb as u32;
let overflow;
let result;
if divisor == 0 {
result = (dividend / divisor) as u64;
overflow = false;
}
- DivResult {
- result,
- overflow: Some(OverflowFlags {
- overflow,
- overflow32: overflow,
- }),
+ InstructionResult {
+ rt: Some(result),
+ overflow: Some(OverflowFlags::from_overflow(overflow)),
+ ..InstructionResult::default()
}
}
-pub fn modsd(inputs: DivInput) -> DivResult {
- let dividend = inputs.dividend as i64;
- let divisor = inputs.divisor as i64;
+pub fn modsd(inputs: InstructionInput) -> InstructionResult {
+ let dividend = inputs.ra as i64;
+ let divisor = inputs.rb as i64;
let result;
if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
result = 0;
} else {
result = (dividend % divisor) as u64;
}
- DivResult {
- result,
- overflow: None,
+ InstructionResult {
+ rt: Some(result),
+ ..InstructionResult::default()
}
}
-pub fn modud(inputs: DivInput) -> DivResult {
- let dividend: u64 = inputs.dividend;
- let divisor: u64 = inputs.divisor;
+pub fn modud(inputs: InstructionInput) -> InstructionResult {
+ let dividend: u64 = inputs.ra;
+ let divisor: u64 = inputs.rb;
let result;
if divisor == 0 {
result = 0;
} else {
result = dividend % divisor;
}
- DivResult {
- result,
- overflow: None,
+ InstructionResult {
+ rt: Some(result),
+ ..InstructionResult::default()
}
}
-pub fn modsw(inputs: DivInput) -> DivResult {
- let dividend = inputs.dividend as i32;
- let divisor = inputs.divisor as i32;
+pub fn modsw(inputs: InstructionInput) -> InstructionResult {
+ let dividend = inputs.ra as i32;
+ let divisor = inputs.rb as i32;
let result;
if divisor == 0 || (divisor == -1 && dividend == i32::min_value()) {
result = 0;
} else {
result = (dividend % divisor) as u64;
}
- DivResult {
- result,
- overflow: None,
+ InstructionResult {
+ rt: Some(result),
+ ..InstructionResult::default()
}
}
-pub fn moduw(inputs: DivInput) -> DivResult {
- let dividend = inputs.dividend as u32;
- let divisor = inputs.divisor as u32;
+pub fn moduw(inputs: InstructionInput) -> InstructionResult {
+ let dividend = inputs.ra as u32;
+ let divisor = inputs.rb as u32;
let result;
if divisor == 0 {
result = 0;
} else {
result = (dividend % divisor) as u64;
}
- DivResult {
- result,
- overflow: None,
+ InstructionResult {
+ rt: Some(result),
+ ..InstructionResult::default()
}
}
compile_error!("native_instrs feature requires target_arch to be powerpc64");
pub mod instr_models;
-mod python;
mod serde_hex;
use serde::{Deserialize, Serialize};
+use std::{
+ cmp::Ordering,
+ ops::{Index, IndexMut},
+};
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct OverflowFlags {
- pub overflow: bool,
- pub overflow32: bool,
+ pub so: bool,
+ pub ov: bool,
+ pub ov32: bool,
}
impl OverflowFlags {
- pub fn from_xer(xer: u64) -> Self {
+ pub const fn from_xer(xer: u64) -> Self {
Self {
- overflow: (xer & 0x4000_0000) != 0,
- overflow32: (xer & 0x8_0000) != 0,
+ so: (xer & 0x8000_0000) != 0,
+ ov: (xer & 0x4000_0000) != 0,
+ ov32: (xer & 0x8_0000) != 0,
+ }
+ }
+ pub const fn from_overflow(overflow: bool) -> Self {
+ Self {
+ so: overflow,
+ ov: overflow,
+ ov32: overflow,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
-pub struct DivResult {
- #[serde(with = "serde_hex::SerdeHex")]
- pub result: u64,
+pub struct ConditionRegister {
+ pub lt: bool,
+ pub gt: bool,
+ pub eq: bool,
+ pub so: bool,
+}
+
+impl ConditionRegister {
+ pub const fn from_4_bits(bits: u8) -> Self {
+ // assert bits is 4-bits long
+ // can switch to using assert! once rustc feature const_panic is stabilized
+ [0; 0x10][bits as usize];
+
+ Self {
+ lt: (bits & 8) != 0,
+ gt: (bits & 4) != 0,
+ eq: (bits & 2) != 0,
+ so: (bits & 1) != 0,
+ }
+ }
+ pub const CR_FIELD_COUNT: usize = 8;
+ pub const fn from_cr_field(cr: u32, field_index: usize) -> Self {
+ // assert field_index is less than CR_FIELD_COUNT
+ // can switch to using assert! once rustc feature const_panic is stabilized
+ [0; Self::CR_FIELD_COUNT][field_index];
+
+ let reversed_field_index = Self::CR_FIELD_COUNT - field_index - 1;
+ let bits = (cr >> (4 * reversed_field_index)) & 0xF;
+ Self::from_4_bits(bits as u8)
+ }
+ pub fn from_signed_int<T: Ord + Default>(value: T, so: bool) -> Self {
+ let ordering = value.cmp(&T::default());
+ Self {
+ lt: ordering == Ordering::Less,
+ gt: ordering == Ordering::Greater,
+ eq: ordering == Ordering::Equal,
+ so,
+ }
+ }
+}
+
+#[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
+pub struct InstructionResult {
+ #[serde(
+ default,
+ skip_serializing_if = "Option::is_none",
+ with = "serde_hex::SerdeHex"
+ )]
+ pub rt: Option<u64>,
#[serde(default, flatten, skip_serializing_if = "Option::is_none")]
pub overflow: Option<OverflowFlags>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub cr0: Option<ConditionRegister>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub cr1: Option<ConditionRegister>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub cr2: Option<ConditionRegister>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub cr3: Option<ConditionRegister>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub cr4: Option<ConditionRegister>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub cr5: Option<ConditionRegister>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub cr6: Option<ConditionRegister>,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub cr7: Option<ConditionRegister>,
+}
+
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
+pub enum InstructionInputRegister {
+ #[serde(rename = "ra")]
+ Ra,
+ #[serde(rename = "rb")]
+ Rb,
+ #[serde(rename = "rc")]
+ Rc,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
-pub struct DivInput {
+pub struct InstructionInput {
+ #[serde(with = "serde_hex::SerdeHex")]
+ pub ra: u64,
#[serde(with = "serde_hex::SerdeHex")]
- pub dividend: u64,
+ pub rb: u64,
#[serde(with = "serde_hex::SerdeHex")]
- pub divisor: u64,
- #[serde(default, with = "serde_hex::SerdeHex")]
- pub result_prev: u64,
+ pub rc: u64,
+}
+
+impl Index<InstructionInputRegister> for InstructionInput {
+ type Output = u64;
+ fn index(&self, index: InstructionInputRegister) -> &Self::Output {
+ match index {
+ InstructionInputRegister::Ra => &self.ra,
+ InstructionInputRegister::Rb => &self.rb,
+ InstructionInputRegister::Rc => &self.rc,
+ }
+ }
+}
+
+impl IndexMut<InstructionInputRegister> for InstructionInput {
+ fn index_mut(&mut self, index: InstructionInputRegister) -> &mut Self::Output {
+ match index {
+ InstructionInputRegister::Ra => &mut self.ra,
+ InstructionInputRegister::Rb => &mut self.rb,
+ InstructionInputRegister::Rc => &mut self.rc,
+ }
+ }
}
fn is_false(v: &bool) -> bool {
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
-pub struct TestDivCase {
- pub instr: DivInstr,
+pub struct TestCase {
+ pub instr: Instr,
#[serde(flatten)]
- pub inputs: DivInput,
+ pub inputs: InstructionInput,
#[serde(default, skip_serializing_if = "Option::is_none")]
- pub native_outputs: Option<DivResult>,
- pub model_outputs: DivResult,
+ pub native_outputs: Option<InstructionResult>,
+ pub model_outputs: InstructionResult,
#[serde(default, skip_serializing_if = "is_false")]
pub model_mismatch: bool,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct WholeTest {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
- pub test_div_cases: Vec<TestDivCase>,
+ pub test_cases: Vec<TestCase>,
pub any_model_mismatch: bool,
}
-macro_rules! make_div_functions {
+#[cfg(feature = "native_instrs")]
+macro_rules! map_instr_asm_args {
+ ([], [], []) => {
+ ""
+ };
+ ([], [], [$string0:literal $($strings:literal)*]) => {
+ concat!(" ", $string0, $(", ", $strings),*)
+ };
+ ([$($args:ident)*], [rt $($results:ident)*], [$($strings:literal)*]) => {
+ map_instr_asm_args!([$($args)*], [$($results)*], ["$0" $($strings)*])
+ };
+ ([ra $($args:ident)*], [$($results:ident)*], [$($strings:literal)*]) => {
+ map_instr_asm_args!([$($args)*], [$($results)*], ["$3" $($strings)*])
+ };
+ ([rb $($args:ident)*], [$($results:ident)*], [$($strings:literal)*]) => {
+ map_instr_asm_args!([$($args)*], [$($results)*], ["$4" $($strings)*])
+ };
+ ([rc $($args:ident)*], [$($results:ident)*], [$($strings:literal)*]) => {
+ map_instr_asm_args!([$($args)*], [$($results)*], ["$5" $($strings)*])
+ };
+ ([$($args:ident)*], [ov $($results:ident)*], [$($strings:literal)*]) => {
+ map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)*])
+ };
+ ([$($args:ident)*], [cr0 $($results:ident)*], [$($strings:literal)*]) => {
+ map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)*])
+ };
+ ([$($args:ident)*], [cr1 $($results:ident)*], [$($strings:literal)*]) => {
+ map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)*])
+ };
+ ([$($args:ident)*], [cr2 $($results:ident)*], [$($strings:literal)*]) => {
+ map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)*])
+ };
+ ([$($args:ident)*], [cr3 $($results:ident)*], [$($strings:literal)*]) => {
+ map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)*])
+ };
+ ([$($args:ident)*], [cr4 $($results:ident)*], [$($strings:literal)*]) => {
+ map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)*])
+ };
+ ([$($args:ident)*], [cr5 $($results:ident)*], [$($strings:literal)*]) => {
+ map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)*])
+ };
+ ([$($args:ident)*], [cr6 $($results:ident)*], [$($strings:literal)*]) => {
+ map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)*])
+ };
+ ([$($args:ident)*], [cr7 $($results:ident)*], [$($strings:literal)*]) => {
+ map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)*])
+ };
+}
+
+macro_rules! map_instr_input_registers {
+ ([], [$($reg:expr,)*]) => {
+ [$($reg,)*]
+ };
+ ([ra $($args:ident)*], [$($reg:expr,)*]) => {
+ map_instr_input_registers!([$($args)*], [InstructionInputRegister::Ra, $($reg,)*])
+ };
+ ([rb $($args:ident)*], [$($reg:expr,)*]) => {
+ map_instr_input_registers!([$($args)*], [InstructionInputRegister::Rb, $($reg,)*])
+ };
+ ([rc $($args:ident)*], [$($reg:expr,)*]) => {
+ map_instr_input_registers!([$($args)*], [InstructionInputRegister::Rc, $($reg,)*])
+ };
+}
+
+#[cfg(feature = "native_instrs")]
+macro_rules! map_instr_results {
+ ($rt:ident, $xer:ident, $cr:ident, $retval:ident, []) => {};
+ ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [rt $($args:ident)*]) => {
+ $retval.rt = Some($rt);
+ map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
+ };
+ ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [ov $($args:ident)*]) => {
+ $retval.overflow = Some(OverflowFlags::from_xer($xer));
+ map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
+ };
+ ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [cr0 $($args:ident)*]) => {
+ $retval.cr0 = Some(ConditionRegister::from_cr_field($cr, 0));
+ map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
+ };
+ ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [cr1 $($args:ident)*]) => {
+ $retval.cr1 = Some(ConditionRegister::from_cr_field($cr, 1));
+ map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
+ };
+ ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [cr2 $($args:ident)*]) => {
+ $retval.cr2 = Some(ConditionRegister::from_cr_field($cr, 2));
+ map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
+ };
+ ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [cr3 $($args:ident)*]) => {
+ $retval.cr3 = Some(ConditionRegister::from_cr_field($cr, 3));
+ map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
+ };
+ ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [cr4 $($args:ident)*]) => {
+ $retval.cr4 = Some(ConditionRegister::from_cr_field($cr, 4));
+ map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
+ };
+ ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [cr5 $($args:ident)*]) => {
+ $retval.cr5 = Some(ConditionRegister::from_cr_field($cr, 5));
+ map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
+ };
+ ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [cr6 $($args:ident)*]) => {
+ $retval.cr6 = Some(ConditionRegister::from_cr_field($cr, 6));
+ map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
+ };
+ ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [cr7 $($args:ident)*]) => {
+ $retval.cr7 = Some(ConditionRegister::from_cr_field($cr, 7));
+ map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
+ };
+}
+
+#[cfg(feature = "native_instrs")]
+macro_rules! instr {
(
- #[div]
- {
- $($div_enum:ident = $div_fn:ident ($div_instr:literal),)+
+ #[enumerant = $enumerant:ident]
+ fn $fn:ident($($args:ident),*) -> ($($results:ident),*) {
+ $instr:literal
}
- #[rem]
- {
- $($rem_enum:ident = $rem_fn:ident ($rem_instr:literal),)+
+ ) => {
+ pub fn $fn(inputs: InstructionInput) -> InstructionResult {
+ #![allow(unused_variables, unused_assignments)]
+ let InstructionInput {
+ ra,
+ rb,
+ rc,
+ } = inputs;
+ let rt: u64;
+ let xer: u64;
+ let cr: u32;
+ unsafe {
+ llvm_asm!(
+ concat!(
+ "mfxer $1\n",
+ "and $1, $1, $7\n",
+ "mtxer $1\n",
+ $instr, " ",
+ map_instr_asm_args!([$($args)*], [$($results)*], []),
+ "\n",
+ "mfxer $1\n",
+ "mfcr $2\n",
+ )
+ : "=&r"(rt), "=&r"(xer), "=&r"(cr)
+ : "r"(ra), "r"(rb), "r"(rc), "r"(0u64), "r"(!0x8000_0000u64)
+ : "xer", "cr");
+ }
+ let mut retval = InstructionResult::default();
+ map_instr_results!(rt, xer, cr, retval, [$($results)*]);
+ retval
}
+ };
+}
+
+macro_rules! instrs {
+ (
+ $(
+ #[enumerant = $enumerant:ident]
+ fn $fn:ident($($args:ident),*) -> ($($results:ident),*) {
+ $instr:literal
+ }
+ )+
) => {
+ #[cfg(feature = "python")]
+ macro_rules! wrap_all_instr_fns {
+ ($m:ident) => {
+ wrap_instr_fns! {
+ #![pymodule($m)]
+
+ $(fn $fn(inputs: InstructionInput) -> InstructionResult;)*
+ }
+ };
+ }
+
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
- pub enum DivInstr {
+ pub enum Instr {
$(
- #[serde(rename = $div_instr)]
- $div_enum,
- )+
- $(
- #[serde(rename = $rem_instr)]
- $rem_enum,
+ #[serde(rename = $instr)]
+ $enumerant,
)+
}
- impl DivInstr {
+ impl Instr {
#[cfg(feature = "native_instrs")]
- pub fn get_native_fn(self) -> fn(DivInput) -> DivResult {
+ pub fn get_native_fn(self) -> fn(InstructionInput) -> InstructionResult {
match self {
$(
- Self::$div_enum => native_instrs::$div_fn,
- )+
- $(
- Self::$rem_enum => native_instrs::$rem_fn,
+ Self::$enumerant => native_instrs::$fn,
)+
}
}
- pub fn get_model_fn(self) -> fn(DivInput) -> DivResult {
+ pub fn get_model_fn(self) -> fn(InstructionInput) -> InstructionResult {
match self {
$(
- Self::$div_enum => instr_models::$div_fn,
+ Self::$enumerant => instr_models::$fn,
)+
+ }
+ }
+ pub fn get_used_input_registers(self) -> &'static [InstructionInputRegister] {
+ match self {
$(
- Self::$rem_enum => instr_models::$rem_fn,
+ Self::$enumerant => &map_instr_input_registers!([$($args)*], []),
)+
}
}
pub fn name(self) -> &'static str {
match self {
$(
- Self::$div_enum => $div_instr,
- )+
- $(
- Self::$rem_enum => $rem_instr,
+ Self::$enumerant => $instr,
)+
}
}
pub const VALUES: &'static [Self] = &[
$(
- Self::$div_enum,
- )+
- $(
- Self::$rem_enum,
+ Self::$enumerant,
)+
];
}
use super::*;
$(
- pub fn $div_fn(inputs: DivInput) -> DivResult {
- let DivInput {
- dividend,
- divisor,
- result_prev,
- } = inputs;
- let result: u64;
- let xer: u64;
- unsafe {
- llvm_asm!(
- concat!(
- $div_instr,
- " $0, $3, $4\n",
- "mfxer $1"
- )
- : "=&r"(result), "=&r"(xer)
- : "0"(result_prev), "r"(dividend), "r"(divisor)
- : "xer");
- }
- DivResult {
- result,
- overflow: Some(OverflowFlags::from_xer(xer)),
- }
- }
- )+
- $(
- pub fn $rem_fn(inputs: DivInput) -> DivResult {
- let DivInput {
- dividend,
- divisor,
- result_prev,
- } = inputs;
- let result: u64;
- unsafe {
- llvm_asm!(
- concat!(
- $rem_instr,
- " $0, $2, $3"
- )
- : "=&r"(result)
- : "0"(result_prev), "r"(dividend), "r"(divisor));
- }
- DivResult {
- result,
- overflow: None,
+ instr! {
+ #[enumerant = $enumerant]
+ fn $fn($($args),*) -> ($($results),*) {
+ $instr
}
}
)+
};
}
-make_div_functions! {
- #[div]
- {
- DivDEO = divdeo("divdeo"),
- DivDEUO = divdeuo("divdeuo"),
- DivDO = divdo("divdo"),
- DivDUO = divduo("divduo"),
- DivWEO = divweo("divweo"),
- DivWEUO = divweuo("divweuo"),
- DivWO = divwo("divwo"),
- DivWUO = divwuo("divwuo"),
+instrs! {
+ // divde
+ #[enumerant = DivDE]
+ fn divde(ra, rb) -> (rt) {
+ "divde"
+ }
+ #[enumerant = DivDEO]
+ fn divdeo(ra, rb) -> (rt, ov) {
+ "divdeo"
+ }
+ #[enumerant = DivDE_]
+ fn divde_(ra, rb) -> (rt, cr0) {
+ "divde."
+ }
+ #[enumerant = DivDEO_]
+ fn divdeo_(ra, rb) -> (rt, ov, cr0) {
+ "divdeo."
+ }
+
+ // divdeu
+ #[enumerant = DivDEU]
+ fn divdeu(ra, rb) -> (rt) {
+ "divdeu"
+ }
+ #[enumerant = DivDEUO]
+ fn divdeuo(ra, rb) -> (rt, ov) {
+ "divdeuo"
+ }
+ #[enumerant = DivDEU_]
+ fn divdeu_(ra, rb) -> (rt, cr0) {
+ "divdeu."
+ }
+ #[enumerant = DivDEUO_]
+ fn divdeuo_(ra, rb) -> (rt, ov, cr0) {
+ "divdeuo."
+ }
+
+ // divd
+ #[enumerant = DivD]
+ fn divd(ra, rb) -> (rt) {
+ "divd"
+ }
+ #[enumerant = DivDO]
+ fn divdo(ra, rb) -> (rt, ov) {
+ "divdo"
+ }
+ #[enumerant = DivD_]
+ fn divd_(ra, rb) -> (rt, cr0) {
+ "divd."
+ }
+ #[enumerant = DivDO_]
+ fn divdo_(ra, rb) -> (rt, ov, cr0) {
+ "divdo."
+ }
+
+ // divdu
+ #[enumerant = DivDU]
+ fn divdu(ra, rb) -> (rt) {
+ "divdu"
+ }
+ #[enumerant = DivDUO]
+ fn divduo(ra, rb) -> (rt, ov) {
+ "divduo"
+ }
+ #[enumerant = DivDU_]
+ fn divdu_(ra, rb) -> (rt, cr0) {
+ "divdu."
+ }
+ #[enumerant = DivDUO_]
+ fn divduo_(ra, rb) -> (rt, ov, cr0) {
+ "divduo."
+ }
+
+ // divwe
+ #[enumerant = DivWE]
+ fn divwe(ra, rb) -> (rt) {
+ "divwe"
+ }
+ #[enumerant = DivWEO]
+ fn divweo(ra, rb) -> (rt, ov) {
+ "divweo"
+ }
+ #[enumerant = DivWE_]
+ fn divwe_(ra, rb) -> (rt, cr0) {
+ "divwe."
+ }
+ #[enumerant = DivWEO_]
+ fn divweo_(ra, rb) -> (rt, ov, cr0) {
+ "divweo."
+ }
+
+ // divweu
+ #[enumerant = DivWEU]
+ fn divweu(ra, rb) -> (rt) {
+ "divweu"
+ }
+ #[enumerant = DivWEUO]
+ fn divweuo(ra, rb) -> (rt, ov) {
+ "divweuo"
+ }
+ #[enumerant = DivWEU_]
+ fn divweu_(ra, rb) -> (rt, cr0) {
+ "divweu."
+ }
+ #[enumerant = DivWEUO_]
+ fn divweuo_(ra, rb) -> (rt, ov, cr0) {
+ "divweuo."
+ }
+
+ // divw
+ #[enumerant = DivW]
+ fn divw(ra, rb) -> (rt) {
+ "divw"
+ }
+ #[enumerant = DivWO]
+ fn divwo(ra, rb) -> (rt, ov) {
+ "divwo"
+ }
+ #[enumerant = DivW_]
+ fn divw_(ra, rb) -> (rt, cr0) {
+ "divw."
+ }
+ #[enumerant = DivWO_]
+ fn divwo_(ra, rb) -> (rt, ov, cr0) {
+ "divwo."
+ }
+
+ // divwu
+ #[enumerant = DivWU]
+ fn divwu(ra, rb) -> (rt) {
+ "divwu"
}
- #[rem]
- {
- ModSD = modsd("modsd"),
- ModUD = modud("modud"),
- ModSW = modsw("modsw"),
- ModUW = moduw("moduw"),
+ #[enumerant = DivWUO]
+ fn divwuo(ra, rb) -> (rt, ov) {
+ "divwuo"
+ }
+ #[enumerant = DivWU_]
+ fn divwu_(ra, rb) -> (rt, cr0) {
+ "divwu."
+ }
+ #[enumerant = DivWUO_]
+ fn divwuo_(ra, rb) -> (rt, ov, cr0) {
+ "divwuo."
+ }
+
+ // mod*
+ #[enumerant = ModSD]
+ fn modsd(ra, rb) -> (rt) {
+ "modsd"
+ }
+ #[enumerant = ModUD]
+ fn modud(ra, rb) -> (rt) {
+ "modud"
+ }
+ #[enumerant = ModSW]
+ fn modsw(ra, rb) -> (rt) {
+ "modsw"
+ }
+ #[enumerant = ModUW]
+ fn moduw(ra, rb) -> (rt) {
+ "moduw"
}
}
+
+// must be after instrs macro call since it uses a macro definition
+mod python;
// SPDX-License-Identifier: LGPL-2.1-or-later
// See Notices.txt for copyright information
-use power_instruction_analyzer::{DivInput, DivInstr, TestDivCase, WholeTest};
+use power_instruction_analyzer::{
+ Instr, InstructionInput, InstructionInputRegister, TestCase, WholeTest,
+};
const TEST_VALUES: &[u64] = &[
0x0,
0x1234_5678_7FFF_FFFF,
];
+fn call_with_inputs(
+ mut inputs: InstructionInput,
+ input_registers: &[InstructionInputRegister],
+ f: &mut impl FnMut(InstructionInput),
+) {
+ if let Some((&input_register, input_registers)) = input_registers.split_first() {
+ for &i in TEST_VALUES {
+ inputs[input_register] = i;
+ call_with_inputs(inputs, input_registers, f);
+ }
+ } else {
+ f(inputs);
+ }
+}
+
fn main() {
- let mut test_div_cases = Vec::new();
+ let mut test_cases = Vec::new();
let mut any_model_mismatch = false;
- for &instr in DivInstr::VALUES {
- for ÷nd in TEST_VALUES {
- for &divisor in TEST_VALUES {
- let inputs = DivInput {
- dividend,
- divisor,
- result_prev: 0xFECD_BA98_7654_3210,
- };
+ for &instr in Instr::VALUES {
+ call_with_inputs(
+ InstructionInput {
+ ra: 0,
+ rb: 0,
+ rc: 0,
+ },
+ instr.get_used_input_registers(),
+ &mut |inputs| {
let model_outputs = instr.get_model_fn()(inputs);
#[cfg(feature = "native_instrs")]
let native_outputs = Some(instr.get_native_fn()(inputs));
_ => false,
};
any_model_mismatch |= model_mismatch;
- test_div_cases.push(TestDivCase {
+ test_cases.push(TestCase {
instr,
inputs,
native_outputs,
model_outputs,
model_mismatch,
});
- }
- }
+ },
+ );
}
let whole_test = WholeTest {
- test_div_cases,
+ test_cases,
any_model_mismatch,
};
serde_json::to_writer_pretty(std::io::stdout().lock(), &whole_test).unwrap();
#![cfg(feature = "python")]
-use crate::{DivInput, DivResult, OverflowFlags};
+use crate::{ConditionRegister, Instr, InstructionInput, InstructionResult, OverflowFlags};
use pyo3::{prelude::*, wrap_pyfunction, PyObjectProtocol};
use std::{borrow::Cow, cell::RefCell, fmt};
// use tt to work around PyO3 bug fixed in PyO3#832
#[pyclass $($pyclass_args:tt)?]
#[wrapped($value:ident: $wrapped:ident)]
+ #[args $new_args:tt]
$(#[$meta:meta])*
struct $wrapper:ident {
$(
#[pymethods]
impl $wrapper {
#[new]
+ #[args $new_args]
fn new($($field_name:$field_type),*) -> Self {
Self {
$value: $wrapped {
#[pymodule(m)]
#[pyclass(name = OverflowFlags)]
#[wrapped(value: OverflowFlags)]
- #[text_signature = "(overflow, overflow32)"]
+ #[args(so, ov, ov32)]
+ #[text_signature = "(so, ov, ov32)"]
struct PyOverflowFlags {
- #[set = set_overflow]
- overflow: bool,
- #[set = set_overflow32]
- overflow32: bool,
+ #[set = set_so]
+ so: bool,
+ #[set = set_ov]
+ ov: bool,
+ #[set = set_ov32]
+ ov32: bool,
+ }
+ }
+
+ wrap_type! {
+ #[pymodule(m)]
+ #[pyclass(name = ConditionRegister)]
+ #[wrapped(value: ConditionRegister)]
+ #[args(lt, gt, eq, so)]
+ #[text_signature = "(lt, gt, eq, so)"]
+ struct PyConditionRegister {
+ #[set = set_lt]
+ lt: bool,
+ #[set = set_gt]
+ gt: bool,
+ #[set = set_eq]
+ eq: bool,
+ #[set = set_so]
+ so: bool,
}
}
wrap_type! {
#[pymodule(m)]
- #[pyclass(name = DivInput)]
- #[wrapped(value: DivInput)]
- #[text_signature = "(dividend, divisor, result_prev)"]
- struct PyDivInput {
- #[set = set_dividend]
- dividend: u64,
- #[set = set_divisor]
- divisor: u64,
- #[set = set_result_prev]
- result_prev: u64,
+ #[pyclass(name = InstructionInput)]
+ #[wrapped(value: InstructionInput)]
+ #[args(ra, rb, rc)]
+ #[text_signature = "(ra, rb, rc)"]
+ struct PyInstructionInput {
+ #[set = set_ra]
+ ra: u64,
+ #[set = set_rb]
+ rb: u64,
+ #[set = set_rc]
+ rc: u64,
}
}
wrap_type! {
#[pymodule(m)]
- #[pyclass(name = DivResult)]
- #[wrapped(value: DivResult)]
- #[text_signature = "(result, overflow)"]
- struct PyDivResult {
- #[set = set_result]
- result: u64,
+ #[pyclass(name = InstructionResult)]
+ #[wrapped(value: InstructionResult)]
+ #[args(
+ rt="None",
+ overflow="None",
+ cr0="None",
+ cr1="None",
+ cr2="None",
+ cr3="None",
+ cr4="None",
+ cr5="None",
+ cr6="None",
+ cr7="None"
+ )]
+ #[text_signature = "(\
+ rt=None, \
+ overflow=None, \
+ cr0=None, \
+ cr1=None, \
+ cr2=None, \
+ cr3=None, \
+ cr4=None, \
+ cr5=None, \
+ cr6=None, \
+ cr7=None)"
+ ]
+ struct PyInstructionResult {
+ #[set = set_rt]
+ rt: Option<u64>,
#[set = set_overflow]
overflow: Option<OverflowFlags>,
+ #[set = set_cr0]
+ cr0: Option<ConditionRegister>,
+ #[set = set_cr1]
+ cr1: Option<ConditionRegister>,
+ #[set = set_cr2]
+ cr2: Option<ConditionRegister>,
+ #[set = set_cr3]
+ cr3: Option<ConditionRegister>,
+ #[set = set_cr4]
+ cr4: Option<ConditionRegister>,
+ #[set = set_cr5]
+ cr5: Option<ConditionRegister>,
+ #[set = set_cr6]
+ cr6: Option<ConditionRegister>,
+ #[set = set_cr7]
+ cr7: Option<ConditionRegister>,
}
}
- wrap_instr_fns! {
- #![pymodule(m)]
- fn divdeo(inputs: DivInput) -> DivResult;
- fn divdeuo(inputs: DivInput) -> DivResult;
- fn divdo(inputs: DivInput) -> DivResult;
- fn divduo(inputs: DivInput) -> DivResult;
- fn divweo(inputs: DivInput) -> DivResult;
- fn divweuo(inputs: DivInput) -> DivResult;
- fn divwo(inputs: DivInput) -> DivResult;
- fn divwuo(inputs: DivInput) -> DivResult;
- fn modsd(inputs: DivInput) -> DivResult;
- fn modud(inputs: DivInput) -> DivResult;
- fn modsw(inputs: DivInput) -> DivResult;
- fn moduw(inputs: DivInput) -> DivResult;
- }
+ m.setattr(
+ "INSTRS",
+ Instr::VALUES
+ .iter()
+ .map(|&instr| instr.name())
+ .collect::<Vec<_>>(),
+ )?;
+
+ wrap_all_instr_fns!(m);
Ok(())
}
// SPDX-License-Identifier: LGPL-2.1-or-later
// See Notices.txt for copyright information
-use serde::{de, Deserialize, Deserializer, Serializer};
+use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
pub(crate) trait SerdeHex {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>;
Self: Sized;
}
+#[derive(Deserialize, Serialize)]
+struct SerdeHexWrapper<T: SerdeHex>(#[serde(with = "SerdeHex")] T);
+
+fn serialize_ref_helper<T: SerdeHex, S: Serializer>(
+ v: &&T,
+ serializer: S,
+) -> Result<S::Ok, S::Error> {
+ v.serialize(serializer)
+}
+
+#[derive(Serialize)]
+struct SerdeHexRefWrapper<'a, T: SerdeHex>(#[serde(serialize_with = "serialize_ref_helper")] &'a T);
+
+impl<T: SerdeHex> SerdeHex for Option<T> {
+ fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
+ self.as_ref().map(SerdeHexRefWrapper).serialize(serializer)
+ }
+ fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>
+ where
+ Self: Sized,
+ {
+ Ok(Option::<SerdeHexWrapper<T>>::deserialize(deserializer)?.map(|v| v.0))
+ }
+}
+
macro_rules! impl_hex_for_uint {
($ty:ty) => {
impl SerdeHex for $ty {
class TestOverflowFlags(unittest.TestCase):
def test_text_signature(self):
self.assertEqual(pia.OverflowFlags.__text_signature__,
- "(overflow, overflow32)")
+ "(so, ov, ov32)")
def test_fields(self):
- v = pia.OverflowFlags(overflow=False, overflow32=True)
- self.assertEqual(v.overflow, False)
- self.assertEqual(v.overflow32, True)
- v.overflow = True
- self.assertEqual(v.overflow, True)
- v.overflow32 = False
- self.assertEqual(v.overflow32, False)
+ v = pia.OverflowFlags(so=False, ov=False, ov32=True)
+ self.assertEqual(v.so, False)
+ self.assertEqual(v.ov, False)
+ self.assertEqual(v.ov32, True)
+ v.so = True
+ self.assertEqual(v.so, True)
+ v.ov = True
+ self.assertEqual(v.ov, True)
+ v.ov32 = False
+ self.assertEqual(v.ov32, False)
def test_str_repr(self):
- v = pia.OverflowFlags(overflow=False, overflow32=True)
+ v = pia.OverflowFlags(so=False, ov=False, ov32=True)
self.assertEqual(str(v),
- '{"overflow":false,"overflow32":true}')
+ '{"so":false,"ov":false,"ov32":true}')
self.assertEqual(repr(v),
- "OverflowFlags(overflow=False, overflow32=True)")
+ "OverflowFlags(so=False, ov=False, ov32=True)")
-class TestDivInput(unittest.TestCase):
+class TestConditionRegister(unittest.TestCase):
def test_text_signature(self):
- self.assertEqual(pia.DivInput.__text_signature__,
- "(dividend, divisor, result_prev)")
+ self.assertEqual(pia.ConditionRegister.__text_signature__,
+ "(lt, gt, eq, so)")
def test_fields(self):
- v = pia.DivInput(dividend=123, divisor=456, result_prev=789)
- self.assertEqual(v.dividend, 123)
- self.assertEqual(v.divisor, 456)
- self.assertEqual(v.result_prev, 789)
- v.dividend = 1234
- self.assertEqual(v.dividend, 1234)
- v.divisor = 4567
- self.assertEqual(v.divisor, 4567)
- v.result_prev = 7890
- self.assertEqual(v.result_prev, 7890)
+ v = pia.ConditionRegister(lt=False, gt=True, eq=False, so=True)
+ self.assertEqual(v.lt, False)
+ self.assertEqual(v.gt, True)
+ self.assertEqual(v.eq, False)
+ self.assertEqual(v.so, True)
+ v.lt = True
+ self.assertEqual(v.lt, True)
+ v.gt = False
+ self.assertEqual(v.gt, False)
+ v.eq = True
+ self.assertEqual(v.eq, True)
+ v.so = False
+ self.assertEqual(v.so, False)
def test_str_repr(self):
- v = pia.DivInput(dividend=123, divisor=456, result_prev=789)
+ v = pia.ConditionRegister(lt=False, gt=True, eq=False, so=True)
self.assertEqual(str(v),
- '{"dividend":"0x7B","divisor":"0x1C8","result_prev":"0x315"}')
+ '{"lt":false,"gt":true,"eq":false,"so":true}')
self.assertEqual(repr(v),
- "DivInput(dividend=123, divisor=456, result_prev=789)")
+ "ConditionRegister(lt=False, gt=True, eq=False, so=True)")
-class TestDivResult(unittest.TestCase):
+class TestInstructionInput(unittest.TestCase):
def test_text_signature(self):
- self.assertEqual(pia.DivResult.__text_signature__,
- "(result, overflow)")
+ self.assertEqual(pia.InstructionInput.__text_signature__,
+ "(ra, rb, rc)")
def test_fields(self):
- v = pia.DivResult(result=1234,
- overflow=pia.OverflowFlags(overflow=False, overflow32=True))
- self.assertEqual(v.result, 1234)
+ v = pia.InstructionInput(ra=123, rb=456, rc=789)
+ self.assertEqual(v.ra, 123)
+ self.assertEqual(v.rb, 456)
+ self.assertEqual(v.rc, 789)
+ v.ra = 1234
+ self.assertEqual(v.ra, 1234)
+ v.rb = 4567
+ self.assertEqual(v.rb, 4567)
+ v.rc = 7890
+ self.assertEqual(v.rc, 7890)
+
+ def test_str_repr(self):
+ v = pia.InstructionInput(ra=123, rb=456, rc=789)
+ self.assertEqual(str(v),
+ '{"ra":"0x7B","rb":"0x1C8","rc":"0x315"}')
+ self.assertEqual(repr(v),
+ "InstructionInput(ra=123, rb=456, rc=789)")
+
+
+class TestInstructionResult(unittest.TestCase):
+ def test_text_signature(self):
+ self.assertEqual(pia.InstructionResult.__text_signature__,
+ "(rt=None, overflow=None, cr0=None, cr1=None, "
+ + "cr2=None, cr3=None, cr4=None, cr5=None, cr6=None, cr7=None)")
+
+ def test_fields(self):
+ v = pia.InstructionResult(
+ overflow=pia.OverflowFlags(so=False, ov=False, ov32=True))
+ self.assertIsNone(v.rt)
self.assertIsNotNone(v.overflow)
- self.assertEqual(v.overflow.overflow, False)
- self.assertEqual(v.overflow.overflow32, True)
- v.result = 123
- self.assertEqual(v.result, 123)
+ self.assertEqual(v.overflow.so, False)
+ self.assertEqual(v.overflow.ov, False)
+ self.assertEqual(v.overflow.ov32, True)
+ self.assertIsNone(v.cr0)
+ self.assertIsNone(v.cr1)
+ self.assertIsNone(v.cr2)
+ self.assertIsNone(v.cr3)
+ self.assertIsNone(v.cr4)
+ self.assertIsNone(v.cr5)
+ self.assertIsNone(v.cr6)
+ self.assertIsNone(v.cr7)
+ v.rt = 123
+ self.assertEqual(v.rt, 123)
v.overflow = None
self.assertIsNone(v.overflow)
+ v.cr2 = pia.ConditionRegister(lt=False, gt=False, eq=False, so=False)
+ self.assertIsNotNone(v.cr2)
def test_str_repr(self):
- v = pia.DivResult(result=1234,
- overflow=pia.OverflowFlags(overflow=False, overflow32=True))
+ v = pia.InstructionResult(
+ overflow=pia.OverflowFlags(so=False, ov=False, ov32=True),
+ cr0=pia.ConditionRegister(lt=True, gt=True, eq=True, so=True),
+ cr2=pia.ConditionRegister(lt=False, gt=False, eq=False, so=False))
self.assertEqual(str(v),
- '{"result":"0x4D2","overflow":false,"overflow32":true}')
+ '{"so":false,"ov":false,"ov32":true,'
+ + '"cr0":{"lt":true,"gt":true,"eq":true,"so":true},'
+ + '"cr2":{"lt":false,"gt":false,"eq":false,"so":false}}')
self.assertEqual(repr(v),
- "DivResult(result=1234, overflow=OverflowFlags(overflow=False, overflow32=True))")
+ "InstructionResult(rt=None, "
+ + "overflow=OverflowFlags(so=False, ov=False, ov32=True), "
+ + "cr0=ConditionRegister(lt=True, gt=True, eq=True, so=True), "
+ + "cr1=None, "
+ + "cr2=ConditionRegister(lt=False, gt=False, eq=False, so=False), "
+ + "cr3=None, cr4=None, cr5=None, cr6=None, cr7=None)")
class TestDivInstrs(unittest.TestCase):
- cases = [
- ("divdeo", '{"result":"0x0","overflow":true,"overflow32":true}'),
- ("divdeuo", '{"result":"0x0","overflow":true,"overflow32":true}'),
- ("divdo", '{"result":"0x36","overflow":false,"overflow32":false}'),
- ("divduo", '{"result":"0x36","overflow":false,"overflow32":false}'),
- ("divweo", '{"result":"0x0","overflow":true,"overflow32":true}'),
- ("divweuo", '{"result":"0x0","overflow":true,"overflow32":true}'),
- ("divwo", '{"result":"0x36","overflow":false,"overflow32":false}'),
- ("divwuo", '{"result":"0x36","overflow":false,"overflow32":false}'),
- ("modsd", '{"result":"0x10"}'),
- ("modud", '{"result":"0x10"}'),
- ("modsw", '{"result":"0x10"}'),
- ("moduw", '{"result":"0x10"}'),
- ]
-
def test(self):
- v = pia.DivInput(dividend=0x1234, divisor=0x56, result_prev=0x789)
- for fn_name, expected in self.cases:
- with self.subTest(fn_name=fn_name):
+ v = pia.InstructionInput(ra=0x1234, rb=0x56, rc=0x789)
+ for instr in pia.INSTRS:
+ with self.subTest(instr=instr):
+ fn_name = instr.replace(".", "_")
fn = getattr(pia, fn_name)
+ self.assertEqual(fn.__text_signature__, "(inputs)")
results = fn(v)
- self.assertEqual(str(results), expected)
+ self.assertIsInstance(results, pia.InstructionResult)
if __name__ == "__main__":