expose methods to python for conversion between SPR values and structs used to repres...
authorJacob Lifshay <programmerjake@gmail.com>
Thu, 3 Sep 2020 22:39:59 +0000 (15:39 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Thu, 3 Sep 2020 22:39:59 +0000 (15:39 -0700)
src/python.rs
tests/test_power_instruction_analyzer.py

index 4370c169a3b1bea9997ed29fa78efdbf921e0a5f..502353cbd6f6032794d0bec04d49f2198c0ceef2 100644 (file)
@@ -6,7 +6,11 @@
 use crate::{
     CarryFlags, ConditionRegister, Instr, InstructionInput, InstructionOutput, OverflowFlags,
 };
-use pyo3::{exceptions::ValueError, prelude::*, wrap_pyfunction, PyObjectProtocol};
+use pyo3::{
+    exceptions::{IndexError, OverflowError, ValueError},
+    prelude::*,
+    wrap_pyfunction, PyObjectProtocol,
+};
 use std::{borrow::Cow, cell::RefCell, fmt};
 
 trait ToPythonRepr {
@@ -251,6 +255,19 @@ fn power_instruction_analyzer(_py: Python, m: &PyModule) -> PyResult<()> {
         }
     }
 
+    #[pymethods]
+    impl PyOverflowFlags {
+        #[text_signature = "(xer)"]
+        #[staticmethod]
+        pub fn from_xer(xer: u64) -> OverflowFlags {
+            OverflowFlags::from_xer(xer)
+        }
+        #[text_signature = "($self)"]
+        pub fn to_xer(&self) -> u64 {
+            self.value.to_xer()
+        }
+    }
+
     wrap_type! {
         #[pymodule(m)]
         #[pyclass(name = CarryFlags)]
@@ -265,6 +282,19 @@ fn power_instruction_analyzer(_py: Python, m: &PyModule) -> PyResult<()> {
         }
     }
 
+    #[pymethods]
+    impl PyCarryFlags {
+        #[text_signature = "(xer)"]
+        #[staticmethod]
+        pub fn from_xer(xer: u64) -> CarryFlags {
+            CarryFlags::from_xer(xer)
+        }
+        #[text_signature = "($self)"]
+        pub fn to_xer(&self) -> u64 {
+            self.value.to_xer()
+        }
+    }
+
     wrap_type! {
         #[pymodule(m)]
         #[pyclass(name = ConditionRegister)]
@@ -283,12 +313,36 @@ fn power_instruction_analyzer(_py: Python, m: &PyModule) -> PyResult<()> {
         }
     }
 
+    #[pymethods]
+    impl PyConditionRegister {
+        #[text_signature = "(bits)"]
+        #[staticmethod]
+        fn from_4_bits(bits: u8) -> PyResult<ConditionRegister> {
+            if bits > 0xF {
+                OverflowError::into("int too big to convert")?;
+            }
+            Ok(ConditionRegister::from_4_bits(bits))
+        }
+        #[text_signature = "(cr, field_index)"]
+        #[staticmethod]
+        fn from_cr_field(cr: u32, mut field_index: isize) -> PyResult<ConditionRegister> {
+            // adjust for python-style indexes
+            if field_index < 0 {
+                field_index += ConditionRegister::CR_FIELD_COUNT as isize;
+            }
+            if field_index < 0 || field_index >= ConditionRegister::CR_FIELD_COUNT as isize {
+                IndexError::into("field_index out of range")?;
+            }
+            Ok(ConditionRegister::from_cr_field(cr, field_index as usize))
+        }
+    }
+
     wrap_type! {
         #[pymodule(m)]
         #[pyclass(name = InstructionInput)]
         #[wrapped(value: InstructionInput)]
         #[args(ra="None", rb="None", rc="None", carry="None", overflow="None")]
-        #[text_signature = "(ra, rb, rc, carry, overflow)"]
+        #[text_signature = "(ra=None, rb=None, rc=None, carry=None, overflow=None)"]
         struct PyInstructionInput {
             #[set = set_ra]
             ra: Option<u64>,
index 43c86b5828a0ed97df262f283902bdef36c81460..15b38540b6f2a13d6f6e48716a76952666153888 100644 (file)
@@ -10,6 +10,16 @@ class TestOverflowFlags(unittest.TestCase):
         self.assertEqual(pia.OverflowFlags.__text_signature__,
                          "(so, ov, ov32)")
 
+    def test_from_to_xer(self):
+        v = pia.OverflowFlags.from_xer(0x186864BDF558B0F6)
+        self.assertEqual(str(v),
+                         '{"so":true,"ov":true,"ov32":true}')
+        self.assertEqual(hex(v.to_xer()), '0xc0080000')
+        v = pia.OverflowFlags.from_xer(0x72242678A4DB14BB)
+        self.assertEqual(str(v),
+                         '{"so":true,"ov":false,"ov32":true}')
+        self.assertEqual(hex(v.to_xer()), '0x80080000')
+
     def test_fields(self):
         v = pia.OverflowFlags(so=False, ov=False, ov32=True)
         self.assertEqual(v.so, False)
@@ -35,6 +45,20 @@ class TestCarryFlags(unittest.TestCase):
         self.assertEqual(pia.CarryFlags.__text_signature__,
                          "(ca, ca32)")
 
+    def test_from_to_xer(self):
+        v = pia.CarryFlags.from_xer(0x186864BDF558B0F6)
+        self.assertEqual(str(v),
+                         '{"ca":true,"ca32":false}')
+        self.assertEqual(hex(v.to_xer()), '0x20000000')
+        v = pia.CarryFlags.from_xer(0xDAF403DEF4ECEBB9)
+        self.assertEqual(str(v),
+                         '{"ca":true,"ca32":true}')
+        self.assertEqual(hex(v.to_xer()), '0x20040000')
+        v = pia.CarryFlags.from_xer(0x7B276724952F507F)
+        self.assertEqual(str(v),
+                         '{"ca":false,"ca32":true}')
+        self.assertEqual(hex(v.to_xer()), '0x40000')
+
     def test_fields(self):
         v = pia.CarryFlags(ca=False, ca32=True)
         self.assertEqual(v.ca, False)
@@ -72,6 +96,39 @@ class TestConditionRegister(unittest.TestCase):
         v.so = False
         self.assertEqual(v.so, False)
 
+    def test_from_4_bits(self):
+        with self.assertRaises(OverflowError):
+            pia.ConditionRegister.from_4_bits(-1)
+        with self.assertRaisesRegex(OverflowError, "int too big to convert"):
+            pia.ConditionRegister.from_4_bits(0x10)
+        v = pia.ConditionRegister.from_4_bits(0xD)
+        self.assertEqual(str(v),
+                         '{"lt":true,"gt":true,"eq":false,"so":true}')
+        v = pia.ConditionRegister.from_4_bits(0x4)
+        self.assertEqual(str(v),
+                         '{"lt":false,"gt":true,"eq":false,"so":false}')
+
+    def test_from_cr_field(self):
+        with self.assertRaisesRegex(IndexError, "^field_index out of range$"):
+            pia.ConditionRegister.from_cr_field(0x0, -9)
+        with self.assertRaisesRegex(IndexError, "^field_index out of range$"):
+            pia.ConditionRegister.from_cr_field(0x0, 8)
+        cr = 0x6C42D586
+        values = [
+            '{"lt":false,"gt":true,"eq":true,"so":false}',
+            '{"lt":true,"gt":true,"eq":false,"so":false}',
+            '{"lt":false,"gt":true,"eq":false,"so":false}',
+            '{"lt":false,"gt":false,"eq":true,"so":false}',
+            '{"lt":true,"gt":true,"eq":false,"so":true}',
+            '{"lt":false,"gt":true,"eq":false,"so":true}',
+            '{"lt":true,"gt":false,"eq":false,"so":false}',
+            '{"lt":false,"gt":true,"eq":true,"so":false}',
+        ]
+        for i in range(-8, 8):
+            with self.subTest(i=i):
+                v = pia.ConditionRegister.from_cr_field(cr, i)
+                self.assertEqual(str(v), values[i])
+
     def test_str_repr(self):
         v = pia.ConditionRegister(lt=False, gt=True, eq=False, so=True)
         self.assertEqual(str(v),