WIP: adding support for carry input/outputs and simplifying python API
authorJacob Lifshay <programmerjake@gmail.com>
Fri, 28 Aug 2020 01:22:21 +0000 (18:22 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Fri, 28 Aug 2020 01:22:21 +0000 (18:22 -0700)
Cargo.lock
Cargo.toml
src/lib.rs
src/python.rs

index 65c60093ae3ce456b2148d565752a3d93a0ee850..604234da7488111f60b0df45d3f414a8302e900e 100644 (file)
@@ -73,9 +73,9 @@ checksum = "5b141fdc7836c525d4d594027d318c84161ca17aaf8113ab1f81ab93ae897485"
 
 [[package]]
 name = "inventory"
-version = "0.1.7"
+version = "0.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "621b50c176968fd3b0bd71f821a28a0ea98db2b5aea966b2fbb8bd1b7d310328"
+checksum = "49c68da9c8b1bda33dc6f55b2a9b4f44eca5ba2b2a1a308eab40db9fb7e200cb"
 dependencies = [
  "ctor",
  "ghost",
@@ -84,9 +84,9 @@ dependencies = [
 
 [[package]]
 name = "inventory-impl"
-version = "0.1.7"
+version = "0.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f99a4111304bade76468d05beab3487c226e4fe4c4de1c4e8f006e815762db73"
+checksum = "4143007b389ae51577282e3c95cf5a7ae0c9e06cafa927508300ceedcbc0354c"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -95,15 +95,15 @@ dependencies = [
 
 [[package]]
 name = "itoa"
-version = "0.4.5"
+version = "0.4.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e"
+checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
 
 [[package]]
 name = "libc"
-version = "0.2.71"
+version = "0.2.76"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49"
+checksum = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3"
 
 [[package]]
 name = "lock_api"
@@ -166,19 +166,20 @@ dependencies = [
  "pyo3",
  "serde",
  "serde_json",
+ "serde_plain",
 ]
 
 [[package]]
 name = "proc-macro-hack"
-version = "0.5.16"
+version = "0.5.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4"
+checksum = "99c605b9a0adc77b7211c6b1f722dcb613d68d66859a44f3d485a6da332b0598"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.17"
+version = "1.0.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1502d12e458c49a4c9cbff560d0fe0060c252bc29799ed94ca2ed4bb665a0101"
+checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12"
 dependencies = [
  "unicode-xid",
 ]
@@ -223,24 +224,24 @@ dependencies = [
 
 [[package]]
 name = "quote"
-version = "1.0.6"
+version = "1.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea"
+checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
 dependencies = [
  "proc-macro2",
 ]
 
 [[package]]
 name = "redox_syscall"
-version = "0.1.56"
+version = "0.1.57"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
+checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
 
 [[package]]
 name = "ryu"
-version = "1.0.4"
+version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed3d612bc64430efeb3f7ee6ef26d590dce0c43249217bddc62112540c7941e1"
+checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
 
 [[package]]
 name = "scopeguard"
@@ -250,18 +251,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
 
 [[package]]
 name = "serde"
-version = "1.0.110"
+version = "1.0.115"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99e7b308464d16b56eba9964e4972a3eee817760ab60d88c3f86e1fecb08204c"
+checksum = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.110"
+version = "1.0.115"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "818fbf6bfa9a42d3bfcaca148547aa00c7b915bec71d1757aa2d44ca68771984"
+checksum = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -270,26 +271,35 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.53"
+version = "1.0.57"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "993948e75b189211a9b31a7528f950c6adc21f9720b6438ff80a7fa2f864cea2"
+checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c"
 dependencies = [
  "itoa",
  "ryu",
  "serde",
 ]
 
+[[package]]
+name = "serde_plain"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "625fb0da2b006092b426a94acc1611bec52f2ec27bb27b266a9f93c29ee38eda"
+dependencies = [
+ "serde",
+]
+
 [[package]]
 name = "smallvec"
-version = "1.4.0"
+version = "1.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4"
+checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252"
 
 [[package]]
 name = "syn"
-version = "1.0.27"
+version = "1.0.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ef781e621ee763a2a40721a8861ec519cb76966aee03bb5d00adb6a31dc1c1de"
+checksum = "891d8d6567fe7c7f8835a3a98af4208f3846fba258c1bc3c31d6e506239f11f9"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -298,9 +308,9 @@ dependencies = [
 
 [[package]]
 name = "unicode-xid"
-version = "0.2.0"
+version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
+checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
 
 [[package]]
 name = "unindent"
@@ -310,9 +320,9 @@ checksum = "af41d708427f8fd0e915dcebb2cae0f0e6acb2a939b2d399c265c39a38a18942"
 
 [[package]]
 name = "winapi"
-version = "0.3.8"
+version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
 dependencies = [
  "winapi-i686-pc-windows-gnu",
  "winapi-x86_64-pc-windows-gnu",
index 54b4f5cea79505c091aaf1a52ea5d8713abf1aab..d7f17e6a7940d48d69d4d291bbd89c56520afb56 100644 (file)
@@ -19,4 +19,5 @@ crate-type = ["rlib", "cdylib"]
 [dependencies]
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
+serde_plain = "0.3"
 pyo3 = { version = "0.11", optional = true }
\ No newline at end of file
index 6faa4514fe293acdb86716d255c08f5bf8577b4d..a67adf28726fee7a333005d5cef3b1d5291bbfc6 100644 (file)
@@ -12,24 +12,72 @@ mod serde_hex;
 use serde::{Deserialize, Serialize};
 use std::{
     cmp::Ordering,
+    fmt,
     ops::{Index, IndexMut},
 };
+use serde_plain::forward_display_to_serde;
 
-#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
-pub struct OverflowFlags {
-    pub so: bool,
-    pub ov: bool,
-    pub ov32: bool,
+fn is_default<T: Default + PartialEq>(v: &T) -> bool {
+    T::default() == *v
 }
 
-impl OverflowFlags {
-    pub const fn from_xer(xer: u64) -> Self {
-        Self {
-            so: (xer & 0x8000_0000) != 0,
-            ov: (xer & 0x4000_0000) != 0,
-            ov32: (xer & 0x8_0000) != 0,
+// powerpc bit numbers count from MSB to LSB
+const fn get_xer_bit_mask(powerpc_bit_num: usize) -> u64 {
+    (1 << 63) >> powerpc_bit_num
+}
+
+macro_rules! xer_subset {
+    (
+        $struct_vis:vis struct $struct_name:ident {
+            $(
+                #[bit($powerpc_bit_num:expr, $mask_name:ident)]
+                $field_vis:vis $field_name:ident: bool,
+            )+
         }
+    ) => {
+        #[derive(Default, Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
+        $struct_vis struct $struct_name {
+            $(
+                $field_vis $field_name: bool,
+            )+
+        }
+
+        impl $struct_name {
+            $(
+                $field_vis const $mask_name: u64 = get_xer_bit_mask($powerpc_bit_num);
+            )+
+            pub const fn from_xer(xer: u64) -> Self {
+                Self {
+                    $(
+                        $field_name: (xer & Self::$mask_name) != 0,
+                    )+
+                }
+            }
+            pub const fn to_xer(self) -> u64 {
+                let mut retval = 0u64;
+                $(
+                    if self.$field_name {
+                        retval |= Self::$mask_name;
+                    }
+                )+
+                retval
+            }
+        }
+    };
+}
+
+xer_subset! {
+    pub struct OverflowFlags {
+        #[bit(32, XER_SO_MASK)]
+        pub so: bool,
+        #[bit(33, XER_OV_MASK)]
+        pub ov: bool,
+        #[bit(44, XER_OV32_MASK)]
+        pub ov32: bool,
     }
+}
+
+impl OverflowFlags {
     pub const fn from_overflow(overflow: bool) -> Self {
         Self {
             so: overflow,
@@ -39,6 +87,15 @@ impl OverflowFlags {
     }
 }
 
+xer_subset! {
+    pub struct CarryFlags {
+        #[bit(34, XER_CA_MASK)]
+        pub ca: bool,
+        #[bit(45, XER_CA32_MASK)]
+        pub ca32: bool,
+    }
+}
+
 #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
 pub struct ConditionRegister {
     pub lt: bool,
@@ -91,6 +148,8 @@ pub struct InstructionResult {
     pub rt: Option<u64>,
     #[serde(default, flatten, skip_serializing_if = "Option::is_none")]
     pub overflow: Option<OverflowFlags>,
+    #[serde(default, flatten, skip_serializing_if = "Option::is_none")]
+    pub carry: Option<CarryFlags>,
     #[serde(default, skip_serializing_if = "Option::is_none")]
     pub cr0: Option<ConditionRegister>,
     #[serde(default, skip_serializing_if = "Option::is_none")]
@@ -109,6 +168,17 @@ pub struct InstructionResult {
     pub cr7: Option<ConditionRegister>,
 }
 
+#[derive(Debug)]
+pub struct MissingInstructionInput {
+    pub input: InstructionInputRegister,
+}
+
+impl fmt::Display for MissingInstructionInput {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "missing instruction input: {}", self.input)
+    }
+}
+
 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
 pub enum InstructionInputRegister {
     #[serde(rename = "ra")]
@@ -117,37 +187,30 @@ pub enum InstructionInputRegister {
     Rb,
     #[serde(rename = "rc")]
     Rc,
+    #[serde(rename = "ca")]
+    Carry,
 }
 
+forward_display_to_serde!(InstructionInputRegister);
+
 #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
 pub struct InstructionInput {
     #[serde(with = "serde_hex::SerdeHex")]
     pub ra: u64,
-    #[serde(with = "serde_hex::SerdeHex")]
-    pub rb: u64,
-    #[serde(with = "serde_hex::SerdeHex")]
-    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,
-        }
-    }
+    #[serde(
+        default,
+        skip_serializing_if = "Option::is_none",
+        with = "serde_hex::SerdeHex"
+    )]
+    pub rb: Option<u64>,
+    #[serde(
+        default,
+        skip_serializing_if = "Option::is_none",
+        with = "serde_hex::SerdeHex"
+    )]
+    pub rc: Option<u64>,
+    #[serde(default, skip_serializing_if = "Option::is_none", flatten)]
+    pub carry: Option<CarryFlags>,
 }
 
 fn is_false(v: &bool) -> bool {
@@ -696,3 +759,7 @@ instrs! {
 
 // must be after instrs macro call since it uses a macro definition
 mod python;
+}
+
+// must be after instrs macro call since it uses a macro definition
+mod python;
index a1f607191a720883f1b9917b38d4c486d6d554c4..40153deebec42b0ecaa07ab98f7a63eb6305e9c9 100644 (file)
@@ -3,7 +3,9 @@
 
 #![cfg(feature = "python")]
 
-use crate::{ConditionRegister, Instr, InstructionInput, InstructionResult, OverflowFlags};
+use crate::{
+    CarryFlags, ConditionRegister, Instr, InstructionInput, InstructionResult, OverflowFlags,
+};
 use pyo3::{prelude::*, wrap_pyfunction, PyObjectProtocol};
 use std::{borrow::Cow, cell::RefCell, fmt};
 
@@ -248,6 +250,20 @@ fn power_instruction_analyzer(_py: Python, m: &PyModule) -> PyResult<()> {
         }
     }
 
+    wrap_type! {
+        #[pymodule(m)]
+        #[pyclass(name = CarryFlags)]
+        #[wrapped(value: CarryFlags)]
+        #[args(ca, ca32)]
+        #[text_signature = "(ca, ca32)"]
+        struct PyCarryFlags {
+            #[set = set_ca]
+            ca: bool,
+            #[set = set_ca32]
+            ca32: bool,
+        }
+    }
+
     wrap_type! {
         #[pymodule(m)]
         #[pyclass(name = ConditionRegister)]
@@ -270,15 +286,17 @@ fn power_instruction_analyzer(_py: Python, m: &PyModule) -> PyResult<()> {
         #[pymodule(m)]
         #[pyclass(name = InstructionInput)]
         #[wrapped(value: InstructionInput)]
-        #[args(ra, rb, rc)]
-        #[text_signature = "(ra, rb, rc)"]
+        #[args(ra, rb="None", rc="None", carry="None")]
+        #[text_signature = "(ra, rb, rc, carry)"]
         struct PyInstructionInput {
             #[set = set_ra]
             ra: u64,
             #[set = set_rb]
-            rb: u64,
+            rb: Option<u64>,
             #[set = set_rc]
-            rc: u64,
+            rc: Option<u64>,
+            #[set = set_carry]
+            carry: Option<CarryFlags>,
         }
     }