refactor API and add support for more instructions
authorJacob Lifshay <programmerjake@gmail.com>
Thu, 9 Jul 2020 03:26:54 +0000 (20:26 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Thu, 9 Jul 2020 03:26:54 +0000 (20:26 -0700)
src/instr_models.rs
src/lib.rs
src/main.rs
src/python.rs
src/serde_hex.rs
tests/test_power_instruction_analyzer.py

index 4b64aff1170005c0ba1da65b5a00a291db4cd9da..7ce6fef1b3ab00073c28f3e97384844caab2ca2e 100644 (file)
@@ -1,8 +1,36 @@
-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()) {
@@ -18,18 +46,18 @@ pub fn divdeo(inputs: DivInput) -> DivResult {
             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 {
@@ -45,18 +73,18 @@ pub fn divdeuo(inputs: DivInput) -> DivResult {
             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()) {
@@ -66,18 +94,18 @@ pub fn divdo(inputs: DivInput) -> DivResult {
         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 {
@@ -87,18 +115,18 @@ pub fn divduo(inputs: DivInput) -> DivResult {
         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()) {
@@ -114,18 +142,18 @@ pub fn divweo(inputs: DivInput) -> DivResult {
             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 {
@@ -141,18 +169,18 @@ pub fn divweuo(inputs: DivInput) -> DivResult {
             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()) {
@@ -162,18 +190,18 @@ pub fn divwo(inputs: DivInput) -> DivResult {
         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 {
@@ -183,71 +211,69 @@ pub fn divwuo(inputs: DivInput) -> DivResult {
         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()
     }
 }
index d6a8082c4a8a2fa5a08e4c0d635f3e8f9d51d07c..ec31e6ad9194a01cc5810582ef7c77bf8a37126d 100644 (file)
 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 {
@@ -50,13 +155,13 @@ 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,
 }
@@ -64,71 +169,221 @@ pub struct TestDivCase {
 #[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,
                 )+
             ];
         }
@@ -138,51 +393,10 @@ macro_rules! make_div_functions {
             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
                     }
                 }
             )+
@@ -190,23 +404,169 @@ macro_rules! make_div_functions {
     };
 }
 
-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;
index cc16cf0e5a391b94f562b52ef10df353c2b0a225..63044c8e9ca34ca10cbdfb5c48a05281c21d1054 100644 (file)
@@ -1,7 +1,9 @@
 // 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,
@@ -17,17 +19,33 @@ const TEST_VALUES: &[u64] = &[
     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 &dividend 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));
@@ -38,18 +56,18 @@ fn main() {
                     _ => 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();
index 220663e041401b9bb76f39c10322334652f8a062..a1f607191a720883f1b9917b38d4c486d6d554c4 100644 (file)
@@ -3,7 +3,7 @@
 
 #![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};
 
@@ -123,6 +123,7 @@ macro_rules! wrap_type {
         // 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 {
             $(
@@ -154,6 +155,7 @@ macro_rules! wrap_type {
         #[pymethods]
         impl $wrapper {
             #[new]
+            #[args $new_args]
             fn new($($field_name:$field_type),*) -> Self {
                 Self {
                     $value: $wrapped {
@@ -234,57 +236,112 @@ fn power_instruction_analyzer(_py: Python, m: &PyModule) -> PyResult<()> {
         #[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(())
 }
index 17ec8a8b22fe9aaa4d0dad8e7b3fdad0ea8cdbb5..be362c8b02f4d17f5af3da1df3e9cfef8ffd35a7 100644 (file)
@@ -1,7 +1,7 @@
 // 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>;
@@ -10,6 +10,31 @@ pub(crate) trait SerdeHex {
         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 {
index da954a01703ab4da167c78561f692fc482a35e13..3fb483fde60e53f1fc97796dfddb3f860722ac69 100644 (file)
@@ -8,99 +8,138 @@ import power_instruction_analyzer as pia
 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__":