From 6da2c26915064a287bc8df75b081762da7ed5a3b Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Thu, 27 Aug 2020 18:22:21 -0700 Subject: [PATCH] WIP: adding support for carry input/outputs and simplifying python API --- Cargo.lock | 74 +++++++++++++++------------ Cargo.toml | 1 + src/lib.rs | 139 +++++++++++++++++++++++++++++++++++++------------- src/python.rs | 28 ++++++++-- 4 files changed, 169 insertions(+), 73 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 65c6009..604234d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/Cargo.toml b/Cargo.toml index 54b4f5c..d7f17e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 diff --git a/src/lib.rs b/src/lib.rs index 6faa451..a67adf2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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(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, #[serde(default, flatten, skip_serializing_if = "Option::is_none")] pub overflow: Option, + #[serde(default, flatten, skip_serializing_if = "Option::is_none")] + pub carry: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub cr0: Option, #[serde(default, skip_serializing_if = "Option::is_none")] @@ -109,6 +168,17 @@ pub struct InstructionResult { pub cr7: Option, } +#[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 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 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, + #[serde( + default, + skip_serializing_if = "Option::is_none", + with = "serde_hex::SerdeHex" + )] + pub rc: Option, + #[serde(default, skip_serializing_if = "Option::is_none", flatten)] + pub carry: Option, } 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; diff --git a/src/python.rs b/src/python.rs index a1f6071..40153de 100644 --- a/src/python.rs +++ b/src/python.rs @@ -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, #[set = set_rc] - rc: u64, + rc: Option, + #[set = set_carry] + carry: Option, } } -- 2.30.2