diff --git a/androscalpel/src/instructions.rs b/androscalpel/src/instructions.rs index f147717..6384334 100644 --- a/androscalpel/src/instructions.rs +++ b/androscalpel/src/instructions.rs @@ -3,11 +3,31 @@ //! Instruction at a sligthly higher level than //! -use crate::{DexString, IdField, IdType, Result}; +use crate::{DexString, IdField, IdMethod, IdMethodType, IdType, MethodHandle, Result}; use anyhow::anyhow; use pyo3::prelude::*; +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct CallSite; // TODO + +#[pymethods] +impl CallSite { + #[new] + pub fn new() -> Self { + Self + } + + pub fn __str__(&self) -> String { + todo!() + } + + pub fn __repr__(&self) -> String { + todo!() + } +} + /// Waste a cycle. #[pyclass] #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -2959,3 +2979,4452 @@ impl SPutShort { ) } } + +/// Call a normal virtual method. +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct InvokeVirtual { + pub method: IdMethod, + pub args: Vec, +} + +#[pymethods] +impl InvokeVirtual { + #[new] + pub fn new(method: IdMethod, args: Vec) -> Result { + let invoke = Self { method, args }; + invoke.sanity_check()?; + Ok(invoke) + } + + pub fn sanity_check(&self) -> Result<()> { + let mut last = None; + let mut consec = true; + let mut four_bites = true; + let len = self.args.len(); + for r in self.args { + if let Some(last) = last { + if r != last + 1 { + consec = false; + } + } + if r & 0b1111_0000 != 0 { + four_bites = false; + } + last = Some(r); + } + if four_bites && len <= 5 { + Ok(()) + } else if consec && len <= 255 { + Ok(()) + } else { + Err(anyhow!( + "invoke-virtual instruction must either use 5 or \ + less register indexed on 4 bites or less than 255 \ + consecutive registers" + )) + } + } + + pub fn __str__(&self) -> String { + let args = if self.args.len() >= 5 { + format!("{} .. {}", self.args[0], self.args[self.args.len() - 1]) + } else { + self.args + .iter() + .map(|v| format!("{v}")) + .collect::>() + .join(" ") + }; + format!("invoke-virtual {{{}}} {}", args, self.method.__str__()) + } + + pub fn __repr__(&self) -> String { + let args = if self.args.len() >= 5 { + format!("{} .. {}", self.args[0], self.args[self.args.len() - 1]) + } else { + self.args + .iter() + .map(|v| format!("{v}")) + .collect::>() + .join(" ") + }; + format!( + "Instruction(InvokeVirtual({}, {}))", + args, + self.method.__str__() + ) + } +} + +/// Call the closest superclass's virtual method of a non interface class. +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct InvokeSuper { + pub method: IdMethod, + pub args: Vec, +} + +#[pymethods] +impl InvokeSuper { + #[new] + pub fn new(method: IdMethod, args: Vec) -> Result { + let invoke = Self { method, args }; + invoke.sanity_check()?; + Ok(invoke) + } + + pub fn sanity_check(&self) -> Result<()> { + let mut last = None; + let mut consec = true; + let mut four_bites = true; + let len = self.args.len(); + for r in self.args { + if let Some(last) = last { + if r != last + 1 { + consec = false; + } + } + if r & 0b1111_0000 != 0 { + four_bites = false; + } + last = Some(r); + } + if four_bites && len <= 5 { + Ok(()) + } else if consec && len <= 255 { + Ok(()) + } else { + Err(anyhow!( + "invoke-super instruction must either use 5 or \ + less register indexed on 4 bites or less than 255 \ + consecutive registers" + )) + } + } + + pub fn __str__(&self) -> String { + let args = if self.args.len() >= 5 { + format!("{} .. {}", self.args[0], self.args[self.args.len() - 1]) + } else { + self.args + .iter() + .map(|v| format!("{v}")) + .collect::>() + .join(" ") + }; + format!("invoke-super {{{}}} {}", args, self.method.__str__()) + } + + pub fn __repr__(&self) -> String { + let args = if self.args.len() >= 5 { + format!("{} .. {}", self.args[0], self.args[self.args.len() - 1]) + } else { + self.args + .iter() + .map(|v| format!("{v}")) + .collect::>() + .join(" ") + }; + format!( + "Instruction(InvokeSuper({}, {}))", + args, + self.method.__str__() + ) + } +} + +/// Call a direct method (non static non overridable, like private). +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct InvokeDirect { + pub method: IdMethod, + pub args: Vec, +} + +#[pymethods] +impl InvokeDirect { + #[new] + pub fn new(method: IdMethod, args: Vec) -> Result { + let invoke = Self { method, args }; + invoke.sanity_check()?; + Ok(invoke) + } + + pub fn sanity_check(&self) -> Result<()> { + let mut last = None; + let mut consec = true; + let mut four_bites = true; + let len = self.args.len(); + for r in self.args { + if let Some(last) = last { + if r != last + 1 { + consec = false; + } + } + if r & 0b1111_0000 != 0 { + four_bites = false; + } + last = Some(r); + } + if four_bites && len <= 5 { + Ok(()) + } else if consec && len <= 255 { + Ok(()) + } else { + Err(anyhow!( + "invoke-direct instruction must either use 5 or \ + less register indexed on 4 bites or less than 255 \ + consecutive registers" + )) + } + } + + pub fn __str__(&self) -> String { + let args = if self.args.len() >= 5 { + format!("{} .. {}", self.args[0], self.args[self.args.len() - 1]) + } else { + self.args + .iter() + .map(|v| format!("{v}")) + .collect::>() + .join(" ") + }; + format!("invoke-direct {{{}}} {}", args, self.method.__str__()) + } + + pub fn __repr__(&self) -> String { + let args = if self.args.len() >= 5 { + format!("{} .. {}", self.args[0], self.args[self.args.len() - 1]) + } else { + self.args + .iter() + .map(|v| format!("{v}")) + .collect::>() + .join(" ") + }; + format!( + "Instruction(InvokeDirect({}, {}))", + args, + self.method.__str__() + ) + } +} + +/// Call a static method. +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct InvokeStatic { + pub method: IdMethod, + pub args: Vec, +} + +#[pymethods] +impl InvokeStatic { + #[new] + pub fn new(method: IdMethod, args: Vec) -> Result { + let invoke = Self { method, args }; + invoke.sanity_check()?; + Ok(invoke) + } + + pub fn sanity_check(&self) -> Result<()> { + let mut last = None; + let mut consec = true; + let mut four_bites = true; + let len = self.args.len(); + for r in self.args { + if let Some(last) = last { + if r != last + 1 { + consec = false; + } + } + if r & 0b1111_0000 != 0 { + four_bites = false; + } + last = Some(r); + } + if four_bites && len <= 5 { + Ok(()) + } else if consec && len <= 255 { + Ok(()) + } else { + Err(anyhow!( + "invoke-static instruction must either use 5 or \ + less register indexed on 4 bites or less than 255 \ + consecutive registers" + )) + } + } + + pub fn __str__(&self) -> String { + let args = if self.args.len() >= 5 { + format!("{} .. {}", self.args[0], self.args[self.args.len() - 1]) + } else { + self.args + .iter() + .map(|v| format!("{v}")) + .collect::>() + .join(" ") + }; + format!("invoke-static {{{}}} {}", args, self.method.__str__()) + } + + pub fn __repr__(&self) -> String { + let args = if self.args.len() >= 5 { + format!("{} .. {}", self.args[0], self.args[self.args.len() - 1]) + } else { + self.args + .iter() + .map(|v| format!("{v}")) + .collect::>() + .join(" ") + }; + format!( + "Instruction(InvokeStatic({}, {}))", + args, + self.method.__str__() + ) + } +} + +/// Call a interface method (method from an interface on an object whose class is unknown) +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct InvokeInterface { + pub method: IdMethod, + pub args: Vec, +} + +#[pymethods] +impl InvokeInterface { + #[new] + pub fn new(method: IdMethod, args: Vec) -> Result { + let invoke = Self { method, args }; + invoke.sanity_check()?; + Ok(invoke) + } + + pub fn sanity_check(&self) -> Result<()> { + let mut last = None; + let mut consec = true; + let mut four_bites = true; + let len = self.args.len(); + for r in self.args { + if let Some(last) = last { + if r != last + 1 { + consec = false; + } + } + if r & 0b1111_0000 != 0 { + four_bites = false; + } + last = Some(r); + } + if four_bites && len <= 5 { + Ok(()) + } else if consec && len <= 255 { + Ok(()) + } else { + Err(anyhow!( + "invoke-interface instruction must either use 5 or \ + less register indexed on 4 bites or less than 255 \ + consecutive registers" + )) + } + } + + pub fn __str__(&self) -> String { + let args = if self.args.len() >= 5 { + format!("{} .. {}", self.args[0], self.args[self.args.len() - 1]) + } else { + self.args + .iter() + .map(|v| format!("{v}")) + .collect::>() + .join(" ") + }; + format!("invoke-interface {{{}}} {}", args, self.method.__str__()) + } + + pub fn __repr__(&self) -> String { + let args = if self.args.len() >= 5 { + format!("{} .. {}", self.args[0], self.args[self.args.len() - 1]) + } else { + self.args + .iter() + .map(|v| format!("{v}")) + .collect::>() + .join(" ") + }; + format!( + "Instruction(InvokeInterface({}, {}))", + args, + self.method.__str__() + ) + } +} + +/// Put -val in dest. +/// +/// `dest` and `val` are registered indexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct NegInt { + dest: u8, + val: u8, +} + +#[pymethods] +impl NegInt { + #[new] + pub fn new(dest: u8, val: u8) -> Result { + let ins = Self { dest, val }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "neg-int uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.val & 0b1111_0000 != 0 { + Err(anyhow!( + "neg-int uses registers indexed on 4 bits, found {}", + self.val + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("neg-int {} {}", self.dest, self.val) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(NegInt({}, {}))", self.dest, self.val) + } +} + +/// Put ~val in dest +/// +/// `dest` and `val` are registered indexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct NotInt { + dest: u8, + val: u8, +} + +#[pymethods] +impl NotInt { + #[new] + pub fn new(dest: u8, val: u8) -> Result { + let ins = Self { dest, val }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "not-int uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.val & 0b1111_0000 != 0 { + Err(anyhow!( + "not-int uses registers indexed on 4 bits, found {}", + self.val + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("not-int {} {}", self.dest, self.val) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(NotInt({}, {}))", self.dest, self.val) + } +} + +/// Put -val in dest. dest and val are pair registers. +/// +/// `dest` and `val` are registered indexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct NegLong { + dest: u8, + val: u8, +} + +#[pymethods] +impl NegLong { + #[new] + pub fn new(dest: u8, val: u8) -> Result { + let ins = Self { dest, val }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "neg-long uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.val & 0b1111_0000 != 0 { + Err(anyhow!( + "neg-long uses registers indexed on 4 bits, found {}", + self.val + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("neg-long {} {}", self.dest, self.val) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(NegLong({}, {}))", self.dest, self.val) + } +} + +/// Put ~val in dest. dest and val are pair registers. +/// +/// `dest` and `val` are registered indexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct NotLong { + dest: u8, + val: u8, +} + +#[pymethods] +impl NotLong { + #[new] + pub fn new(dest: u8, val: u8) -> Result { + let ins = Self { dest, val }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "not-long uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.val & 0b1111_0000 != 0 { + Err(anyhow!( + "not-long uses registers indexed on 4 bits, found {}", + self.val + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("not-long {} {}", self.dest, self.val) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(NotLong({}, {}))", self.dest, self.val) + } +} + +/// Put -val in dest. +/// +/// `dest` and `val` are registered indexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct NegFloat { + dest: u8, + val: u8, +} + +#[pymethods] +impl NegFloat { + #[new] + pub fn new(dest: u8, val: u8) -> Result { + let ins = Self { dest, val }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "neg-float uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.val & 0b1111_0000 != 0 { + Err(anyhow!( + "neg-float uses registers indexed on 4 bits, found {}", + self.val + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("neg-float {} {}", self.dest, self.val) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(NegFloat({}, {}))", self.dest, self.val) + } +} + +/// Put -val in dest. +/// +/// `dest` and `val` are registered indexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct NegDouble { + dest: u8, + val: u8, +} + +#[pymethods] +impl NegDouble { + #[new] + pub fn new(dest: u8, val: u8) -> Result { + let ins = Self { dest, val }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "neg-double uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.val & 0b1111_0000 != 0 { + Err(anyhow!( + "neg-double uses registers indexed on 4 bits, found {}", + self.val + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("neg-double {} {}", self.dest, self.val) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(NegDouble({}, {}))", self.dest, self.val) + } +} + +/// Convert copy val to dest an convert to long. +/// +/// TODO: dest is probably a pair register, but is val to? +/// +/// `dest` and `val` are registered indexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct IntToLong { + dest: u8, + val: u8, +} + +#[pymethods] +impl IntToLong { + #[new] + pub fn new(dest: u8, val: u8) -> Result { + let ins = Self { dest, val }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "int-to-long uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.val & 0b1111_0000 != 0 { + Err(anyhow!( + "int-to-long uses registers indexed on 4 bits, found {}", + self.val + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("int-to-long {} {}", self.dest, self.val) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(IntToLong({}, {}))", self.dest, self.val) + } +} + +/// Copy val to dest and convert the integer value to a float. +/// +/// `dest` and `val` are registered indexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct IntToFloat { + dest: u8, + val: u8, +} + +#[pymethods] +impl IntToFloat { + #[new] + pub fn new(dest: u8, val: u8) -> Result { + let ins = Self { dest, val }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "int-to-float uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.val & 0b1111_0000 != 0 { + Err(anyhow!( + "int-to-float uses registers indexed on 4 bits, found {}", + self.val + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("int-to-float {} {}", self.dest, self.val) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(IntToFloat({}, {}))", self.dest, self.val) + } +} + +/// Copy val to dest and convert the integer value to a double +/// +/// TODO: dest is probably a pair register, but is val to? +/// +/// `dest` and `val` are registered indexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct IntToDouble { + dest: u8, + val: u8, +} + +#[pymethods] +impl IntToDouble { + #[new] + pub fn new(dest: u8, val: u8) -> Result { + let ins = Self { dest, val }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "int-to-double uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.val & 0b1111_0000 != 0 { + Err(anyhow!( + "int-to-double uses registers indexed on 4 bits, found {}", + self.val + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("int-to-double {} {}", self.dest, self.val) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(IntToDouble({}, {}))", self.dest, self.val) + } +} + +/// Copy val to dest and convert the long value to an integer. +/// +/// TODO: val is probably a pair register, but is dest to? +/// +/// `dest` and `val` are registered indexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct LongToInt { + dest: u8, + val: u8, +} + +#[pymethods] +impl LongToInt { + #[new] + pub fn new(dest: u8, val: u8) -> Result { + let ins = Self { dest, val }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "long-to-int uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.val & 0b1111_0000 != 0 { + Err(anyhow!( + "long-to-int uses registers indexed on 4 bits, found {}", + self.val + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("long-to-int {} {}", self.dest, self.val) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(LongToInt({}, {}))", self.dest, self.val) + } +} + +/// Copy val to dest and convert the long value to a float. +/// +/// TODO: val is probably a pair register, but is dest to? +/// +/// `dest` and `val` are registered indexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct LongToFloat { + dest: u8, + val: u8, +} + +#[pymethods] +impl LongToFloat { + #[new] + pub fn new(dest: u8, val: u8) -> Result { + let ins = Self { dest, val }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "long-to-float uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.val & 0b1111_0000 != 0 { + Err(anyhow!( + "long-to-float uses registers indexed on 4 bits, found {}", + self.val + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("long-to-float {} {}", self.dest, self.val) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(LongToFloat({}, {}))", self.dest, self.val) + } +} + +/// Copy val to dest and convert the long value to a double. +/// +/// dest and val are pair registers. +/// +/// `dest` and `val` are registered indexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct LongToDouble { + dest: u8, + val: u8, +} + +#[pymethods] +impl LongToDouble { + #[new] + pub fn new(dest: u8, val: u8) -> Result { + let ins = Self { dest, val }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "long-to-double uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.val & 0b1111_0000 != 0 { + Err(anyhow!( + "long-to-double uses registers indexed on 4 bits, found {}", + self.val + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("long-to-double {} {}", self.dest, self.val) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(LongToDouble({}, {}))", self.dest, self.val) + } +} + +/// Copy val to dest and convert the float value to an integer. +/// +/// `dest` and `val` are registered indexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct FloatToInt { + dest: u8, + val: u8, +} + +#[pymethods] +impl FloatToInt { + #[new] + pub fn new(dest: u8, val: u8) -> Result { + let ins = Self { dest, val }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "float-to-int uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.val & 0b1111_0000 != 0 { + Err(anyhow!( + "float-to-int uses registers indexed on 4 bits, found {}", + self.val + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("float-to-int {} {}", self.dest, self.val) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(FloatToInt({}, {}))", self.dest, self.val) + } +} + +/// Copy val to dest and convert the float value to a long. +/// +/// TODO: dest is probably a pair register, but is val too? +/// +/// `dest` and `val` are registered indexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct FloatToLong { + dest: u8, + val: u8, +} + +#[pymethods] +impl FloatToLong { + #[new] + pub fn new(dest: u8, val: u8) -> Result { + let ins = Self { dest, val }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "float-to-long uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.val & 0b1111_0000 != 0 { + Err(anyhow!( + "float-to-long uses registers indexed on 4 bits, found {}", + self.val + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("float-to-long {} {}", self.dest, self.val) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(FloatToLong({}, {}))", self.dest, self.val) + } +} + +/// Copy val to dest and convert the float value to a double. +/// +/// TODO: dest is probably a pair register, but is val too? +/// +/// `dest` and `val` are registered indexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct FloatToDouble { + dest: u8, + val: u8, +} + +#[pymethods] +impl FloatToDouble { + #[new] + pub fn new(dest: u8, val: u8) -> Result { + let ins = Self { dest, val }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "float-to-double uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.val & 0b1111_0000 != 0 { + Err(anyhow!( + "float-to-double uses registers indexed on 4 bits, found {}", + self.val + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("float-to-double {} {}", self.dest, self.val) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(FloatToDouble({}, {}))", self.dest, self.val) + } +} + +/// Copy val to dest and convert the double value to an integer. +/// +/// TODO: val is probably a pair register, but is dest too? +/// +/// `dest` and `val` are registered indexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DoubleToInt { + dest: u8, + val: u8, +} + +#[pymethods] +impl DoubleToInt { + #[new] + pub fn new(dest: u8, val: u8) -> Result { + let ins = Self { dest, val }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "double-to-int uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.val & 0b1111_0000 != 0 { + Err(anyhow!( + "double-to-int uses registers indexed on 4 bits, found {}", + self.val + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("double-to-int {} {}", self.dest, self.val) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(DoubleToInt({}, {}))", self.dest, self.val) + } +} + +/// Copy val to dest and convert the double value to a long. +/// +/// val and dest are pair registers. +/// +/// `dest` and `val` are registered indexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DoubleToLong { + dest: u8, + val: u8, +} + +#[pymethods] +impl DoubleToLong { + #[new] + pub fn new(dest: u8, val: u8) -> Result { + let ins = Self { dest, val }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "double-to-long uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.val & 0b1111_0000 != 0 { + Err(anyhow!( + "double-to-long uses registers indexed on 4 bits, found {}", + self.val + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("double-to-long {} {}", self.dest, self.val) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(DoubleToLong({}, {}))", self.dest, self.val) + } +} + +/// Copy val to dest and convert the double value to a float. +/// +/// TODO: val is probably a pair register, but is dest too? +/// +/// `dest` and `val` are registered indexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DoubleToFloat { + dest: u8, + val: u8, +} + +#[pymethods] +impl DoubleToFloat { + #[new] + pub fn new(dest: u8, val: u8) -> Result { + let ins = Self { dest, val }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "double-to-float uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.val & 0b1111_0000 != 0 { + Err(anyhow!( + "double-to-float uses registers indexed on 4 bits, found {}", + self.val + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("double-to-float {} {}", self.dest, self.val) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(DoubleToFloat({}, {}))", self.dest, self.val) + } +} + +/// Copy val to dest and convert the integer value to a byte. +/// +/// `dest` and `val` are registered indexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct IntToByte { + dest: u8, + val: u8, +} + +#[pymethods] +impl IntToByte { + #[new] + pub fn new(dest: u8, val: u8) -> Result { + let ins = Self { dest, val }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "int-to-byte uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.val & 0b1111_0000 != 0 { + Err(anyhow!( + "int-to-byte uses registers indexed on 4 bits, found {}", + self.val + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("int-to-byte {} {}", self.dest, self.val) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(IntToByte({}, {}))", self.dest, self.val) + } +} + +/// Copy val to dest and convert the integer value to a char. +/// +/// `dest` and `val` are registered indexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct IntToChar { + dest: u8, + val: u8, +} + +#[pymethods] +impl IntToChar { + #[new] + pub fn new(dest: u8, val: u8) -> Result { + let ins = Self { dest, val }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "int-to-char uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.val & 0b1111_0000 != 0 { + Err(anyhow!( + "int-to-char uses registers indexed on 4 bits, found {}", + self.val + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("int-to-char {} {}", self.dest, self.val) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(IntToChar({}, {}))", self.dest, self.val) + } +} + +/// Copy val to dest and convert the integer value to a short. +/// +/// `dest` and `val` are registered indexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct IntToShort { + dest: u8, + val: u8, +} + +#[pymethods] +impl IntToShort { + #[new] + pub fn new(dest: u8, val: u8) -> Result { + let ins = Self { dest, val }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "int-to-short uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.val & 0b1111_0000 != 0 { + Err(anyhow!( + "int-to-short uses registers indexed on 4 bits, found {}", + self.val + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("int-to-short {} {}", self.dest, self.val) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(IntToShort({}, {}))", self.dest, self.val) + } +} + +/// Put a + b in dest. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AddInt { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl AddInt { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("add-int {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(AddInt({}, {}, {}))", self.dest, self.b, self.c) + } +} + +/// Put a - b in dest. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct SubInt { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl SubInt { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("sub-int {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(SubInt({}, {}, {}))", self.dest, self.b, self.c) + } +} + +/// Put a * b in dest. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct MulInt { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl MulInt { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("mul-int {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(MulInt({}, {}, {}))", self.dest, self.b, self.c) + } +} + +/// Put a / b in dest. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DivInt { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl DivInt { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("div-int {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(DivInt({}, {}, {}))", self.dest, self.b, self.c) + } +} + +/// Put a % b in dest. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct RemInt { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl RemInt { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("rem-int {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(RemInt({}, {}, {}))", self.dest, self.b, self.c) + } +} + +/// Put a & b in dest. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AndInt { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl AndInt { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("and-int {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(AndInt({}, {}, {}))", self.dest, self.b, self.c) + } +} + +/// Put a | b in dest. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct OrInt { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl OrInt { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("or-int {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(OrInt({}, {}, {}))", self.dest, self.b, self.c) + } +} + +/// Put a ^ b in dest. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct XorInt { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl XorInt { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("xor-int {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(XorInt({}, {}, {}))", self.dest, self.b, self.c) + } +} + +/// Put a << b in dest. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ShlInt { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl ShlInt { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("shl-int {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(ShlInt({}, {}, {}))", self.dest, self.b, self.c) + } +} + +/// Put a >> b (signed) in dest. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ShrInt { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl ShrInt { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("shr-int {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(ShrInt({}, {}, {}))", self.dest, self.b, self.c) + } +} + +/// Put a >> b in dest. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct UshrInt { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl UshrInt { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("ushr-int {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(UshrInt({}, {}, {}))", + self.dest, self.b, self.c + ) + } +} + +/// Put a + b in dest. +/// +/// dest, b and c are register pairs +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AddLong { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl AddLong { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("add-long {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(AddLong({}, {}, {}))", + self.dest, self.b, self.c + ) + } +} + +/// Put a - b in dest. +/// +/// dest, b and c are register pairs +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct SubLong { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl SubLong { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("sub-long {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(SubLong({}, {}, {}))", + self.dest, self.b, self.c + ) + } +} + +/// Put a * b in dest. +/// +/// dest, b and c are register pairs +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct MulLong { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl MulLong { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("mul-long {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(MulLong({}, {}, {}))", + self.dest, self.b, self.c + ) + } +} + +/// Put a / b in dest. +/// +/// dest, b and c are register pairs +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DivLong { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl DivLong { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("div-long {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(DivLong({}, {}, {}))", + self.dest, self.b, self.c + ) + } +} + +/// Put a % b in dest. +/// +/// dest, b and c are register pairs +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct RemLong { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl RemLong { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("rem-long {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(RemLong({}, {}, {}))", + self.dest, self.b, self.c + ) + } +} + +/// Put a & b in dest. +/// +/// dest, b and c are register pairs +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AndLong { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl AndLong { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("and-long {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(AndLong({}, {}, {}))", + self.dest, self.b, self.c + ) + } +} + +/// Put a | b in dest. +/// +/// dest, b and c are register pairs +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct OrLong { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl OrLong { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("or-long {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(OrLong({}, {}, {}))", self.dest, self.b, self.c) + } +} + +/// Put a ^ b in dest. +/// +/// dest, b and c are register pairs +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct XorLong { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl XorLong { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("xor-long {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(XorLong({}, {}, {}))", + self.dest, self.b, self.c + ) + } +} + +/// Put a << b in dest. +/// +/// dest, and b are register pairs, and c is a single register +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ShlLong { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl ShlLong { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("shl-long {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(ShlLong({}, {}, {}))", + self.dest, self.b, self.c + ) + } +} + +/// Put a >> b (signed) in dest. +/// +/// dest, and b are register pairs, and c is a single register +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ShrLong { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl ShrLong { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("shr-long {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(ShrLong({}, {}, {}))", + self.dest, self.b, self.c + ) + } +} + +/// Put a >> b in dest. +/// +/// dest, and b are register pairs, and c is a single register +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct UshrLong { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl UshrLong { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("ushr-long {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(UshrLong({}, {}, {}))", + self.dest, self.b, self.c + ) + } +} + +/// Put a + b in dest. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AddFloat { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl AddFloat { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("add-float {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(AddFloat({}, {}, {}))", + self.dest, self.b, self.c + ) + } +} + +/// Put a - b in dest. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct SubFloat { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl SubFloat { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("sub-float {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(SubFloat({}, {}, {}))", + self.dest, self.b, self.c + ) + } +} + +/// Put a * b in dest. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct MulFloat { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl MulFloat { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("mul-float {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(MulFloat({}, {}, {}))", + self.dest, self.b, self.c + ) + } +} + +/// Put a / b in dest. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DivFloat { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl DivFloat { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("div-float {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(DivFloat({}, {}, {}))", + self.dest, self.b, self.c + ) + } +} + +/// Put a % b in dest. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct RemFloat { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl RemFloat { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("rem-float {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(RemFloat({}, {}, {}))", + self.dest, self.b, self.c + ) + } +} + +/// Put a + b in dest. +/// +/// dest, b and c are register pairs +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AddDouble { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl AddDouble { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("add-double {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(AddDouble({}, {}, {}))", + self.dest, self.b, self.c + ) + } +} + +/// Put a - b in dest. +/// +/// dest, b and c are register pairs +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct SubDouble { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl SubDouble { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("sub-double {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(SubDouble({}, {}, {}))", + self.dest, self.b, self.c + ) + } +} + +/// Put a * b in dest. +/// +/// dest, b and c are register pairs +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct MulDouble { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl MulDouble { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("mul-double {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(MulDouble({}, {}, {}))", + self.dest, self.b, self.c + ) + } +} + +/// Put a / b in dest. +/// +/// dest, b and c are register pairs +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DivDouble { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl DivDouble { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("div-double {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(DivDouble({}, {}, {}))", + self.dest, self.b, self.c + ) + } +} + +/// Put a % b in dest. +/// +/// dest, b and c are register pairs +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct RemDouble { + dest: u8, + b: u8, + c: u8, +} + +#[pymethods] +impl RemDouble { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("rem-double {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(RemDouble({}, {}, {}))", + self.dest, self.b, self.c + ) + } +} + +/// Put dest + b in dest. +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AddInt2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl AddInt2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "add-int/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "add-int/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("add-int/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(AddInt2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest - b in dest. +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct SubInt2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl SubInt2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "sub-int/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "sub-int/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("sub-int/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(SubInt2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest * b in dest. +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct MulInt2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl MulInt2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "mul-int/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "mul-int/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("mul-int/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(MulInt2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest / b in dest. +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DivInt2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl DivInt2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "div-int/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "div-int/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("div-int/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(DivInt2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest % b in dest. +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct RemInt2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl RemInt2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "rem-int/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "rem-int/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("rem-int/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(RemInt2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest & b in dest. +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AndInt2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl AndInt2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "and-int/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "and-int/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("and-int/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(AndInt2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest | b in dest. +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct OrInt2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl OrInt2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "or-int/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "or-int/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("or-int/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(OrInt2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest ^ b in dest. +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct XorInt2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl XorInt2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "xor-int/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "xor-int/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("xor-int/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(XorInt2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest << b in dest. +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ShlInt2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl ShlInt2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "shl-int/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "shl-int/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("shl-int/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(ShlInt2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest >> b (signed) in dest. +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ShrInt2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl ShrInt2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "shr-int/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "shr-int/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("shr-int/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(ShrInt2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest >> b in dest. +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct UshrInt2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl UshrInt2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "ushr-int/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "ushr-int/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("ushr-int/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(UshrInt2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest + b in dest. +/// +/// dest and b are register pairs +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AddLong2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl AddLong2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "add-long/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "add-long/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("add-long/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(AddLong2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest - b in dest. +/// +/// dest and b are register pairs +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct SubLong2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl SubLong2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "sub-long/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "sub-long/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("sub-long/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(SubLong2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest * b in dest. +/// +/// dest and b are register pairs +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct MulLong2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl MulLong2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "mul-long/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "mul-long/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("mul-long/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(MulLong2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest / b in dest. +/// +/// dest and b are register pairs +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DivLong2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl DivLong2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "div-long/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "div-long/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("div-long/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(DivLong2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest % b in dest. +/// +/// dest and b are register pairs +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct RemLong2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl RemLong2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "rem-long/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "rem-long/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("rem-long/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(RemLong2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest & b in dest. +/// +/// dest and b are register pairs +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AndLong2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl AndLong2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "and-long/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "and-long/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("and-long/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(AndLong2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest | b in dest. +/// +/// dest and b are register pairs +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct OrLong2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl OrLong2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "or-long/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "or-long/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("or-long/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(OrLong2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest ^ b in dest. +/// +/// dest and b are register pairs +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct XorLong2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl XorLong2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "xor-long/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "xor-long/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("xor-long/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(XorLong2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest << b in dest. +/// +/// dest is a register pair, and b is a single register +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ShlLong2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl ShlLong2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "shl-long/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "shl-long/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("shl-long/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(ShlLong2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest >> b (signed) in dest. +/// +/// dest is a register pair, and b is a single register +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ShrLong2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl ShrLong2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "shr-long/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "shr-long/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("shr-long/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(ShrLong2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest >> b in dest. +/// +/// dest is a register pair, and b is a single register +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct UshrLong2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl UshrLong2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "ushr-long/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "ushr-long/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("ushr-long/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(UshrLong2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest + b in dest. +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AddFloat2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl AddFloat2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "add-float/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "add-float/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("add-float/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(AddFloat2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest - b in dest. +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct SubFloat2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl SubFloat2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "sub-float/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "sub-float/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("sub-float/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(SubFloat2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest * b in dest. +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct MulFloat2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl MulFloat2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "mul-float/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "mul-float/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("mul-float/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(MulFloat2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest / b in dest. +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DivFloat2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl DivFloat2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "div-float/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "div-float/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("div-float/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(DivFloat2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest % b in dest. +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct RemFloat2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl RemFloat2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "rem-float/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "rem-float/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("rem-float/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(RemFloat2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest + b in dest. +/// +/// dest and b are register pairs +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AddDouble2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl AddDouble2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "add-double/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "add-double/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("add-double/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(AddDouble2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest - b in dest. +/// +/// dest and b are register pairs +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct SubDouble2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl SubDouble2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "sub-double/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "sub-double/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("sub-double/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(SubDouble2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest * b in dest. +/// +/// dest and b are register pairs +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct MulDouble2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl MulDouble2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "mul-double/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "mul-double/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("mul-double/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(MulDouble2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest / b in dest. +/// +/// dest and b are register pairs +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DivDouble2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl DivDouble2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "div-double/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "div-double/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("div-double/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(DivDouble2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put dest % b in dest. +/// +/// dest and b are register pairs +/// +/// `dest` and `b` are registers indexed on 4 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct RemDouble2Addr { + dest: u8, + b: u8, +} + +#[pymethods] +impl RemDouble2Addr { + #[new] + pub fn new(dest: u8, b: u8) -> Result { + let ins = Self { dest, b }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.dest & 0b1111_0000 != 0 { + Err(anyhow!( + "rem-double/2addr uses registers indexed on 4 bits, found {}", + self.dest + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "rem-double/2addr uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("rem-double/2addr {} {}", self.dest, self.b) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(RemDouble2Addr({}, {}))", self.dest, self.b) + } +} + +/// Put b + lit in dest. +/// +/// Either `dest` and `b` are registers indexed on 4 bits and lit is encoded in 16 bits +/// or `dest` and `b` are registers indexed on 8 bits and lit is encoded in 8 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AddIntLit { + dest: u8, + b: u8, + lit: i16, +} + +#[pymethods] +impl AddIntLit { + #[new] + pub fn new(dest: u8, b: u8, lit: i16) -> Result { + let ins = Self { dest, b, lit }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + let mut reg_on_4_bit = true; + let lit_on_8_bits = true; + if self.dest & 0b1111_0000 != 0 { + reg_on_4_bit = false; + } + if self.b & 0b1111_0000 != 0 { + reg_on_4_bit = false; + } + if self.lit < -128 || self.lit > 127 { + lit_on_8_bits = false; + } + if !reg_on_4_bit && !lit_on_8_bits { + Err(anyhow!( + "add-int/lit uses either registers indexed on 4 bits, and a literal \ + encoded on 16 bits (add-int/lit16), or registers indexed on 8 bits and \ + a literal encoded on 8 bits (add-int/lit8). Found reg {} and {}, and lit \ + {}", + self.dest, + self.b, + self.lit + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("add-int/lit {} {} {}", self.dest, self.b, self.lit) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(AddInt2Addr({}, {}, {}))", + self.dest, self.b, self.lit + ) + } +} + +/// Put lit - b in dest. +/// +/// Either `dest` and `b` are registers indexed on 4 bits and lit is encoded in 16 bits +/// or `dest` and `b` are registers indexed on 8 bits and lit is encoded in 8 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct RsubIntLit { + dest: u8, + b: u8, + lit: i16, +} + +#[pymethods] +impl RsubIntLit { + #[new] + pub fn new(dest: u8, b: u8, lit: i16) -> Result { + let ins = Self { dest, b, lit }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + let mut reg_on_4_bit = true; + let lit_on_8_bits = true; + if self.dest & 0b1111_0000 != 0 { + reg_on_4_bit = false; + } + if self.b & 0b1111_0000 != 0 { + reg_on_4_bit = false; + } + if self.lit < -128 || self.lit > 127 { + lit_on_8_bits = false; + } + if !reg_on_4_bit && !lit_on_8_bits { + Err(anyhow!( + "rsub-int/lit uses either registers indexed on 4 bits, and a literal \ + encoded on 16 bits (rsub-int/lit16), or registers indexed on 8 bits and \ + a literal encoded on 8 bits (rsub-int/lit8). Found reg {} and {}, and lit \ + {}", + self.dest, + self.b, + self.lit + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("rsub-int/lit {} {} {}", self.dest, self.b, self.lit) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(RsubInt2Addr({}, {}, {}))", + self.dest, self.b, self.lit + ) + } +} + +/// Put b * lit in dest. +/// +/// Either `dest` and `b` are registers indexed on 4 bits and lit is encoded in 16 bits +/// or `dest` and `b` are registers indexed on 8 bits and lit is encoded in 8 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct MulIntLit { + dest: u8, + b: u8, + lit: i16, +} + +#[pymethods] +impl MulIntLit { + #[new] + pub fn new(dest: u8, b: u8, lit: i16) -> Result { + let ins = Self { dest, b, lit }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + let mut reg_on_4_bit = true; + let lit_on_8_bits = true; + if self.dest & 0b1111_0000 != 0 { + reg_on_4_bit = false; + } + if self.b & 0b1111_0000 != 0 { + reg_on_4_bit = false; + } + if self.lit < -128 || self.lit > 127 { + lit_on_8_bits = false; + } + if !reg_on_4_bit && !lit_on_8_bits { + Err(anyhow!( + "mul-int/lit uses either registers indexed on 4 bits, and a literal \ + encoded on 16 bits (mul-int/lit16), or registers indexed on 8 bits and \ + a literal encoded on 8 bits (mul-int/lit8). Found reg {} and {}, and lit \ + {}", + self.dest, + self.b, + self.lit + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("mul-int/lit {} {} {}", self.dest, self.b, self.lit) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(MulInt2Addr({}, {}, {}))", + self.dest, self.b, self.lit + ) + } +} + +/// Put b / lit in dest. +/// +/// Either `dest` and `b` are registers indexed on 4 bits and lit is encoded in 16 bits +/// or `dest` and `b` are registers indexed on 8 bits and lit is encoded in 8 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DivIntLit { + dest: u8, + b: u8, + lit: i16, +} + +#[pymethods] +impl DivIntLit { + #[new] + pub fn new(dest: u8, b: u8, lit: i16) -> Result { + let ins = Self { dest, b, lit }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + let mut reg_on_4_bit = true; + let lit_on_8_bits = true; + if self.dest & 0b1111_0000 != 0 { + reg_on_4_bit = false; + } + if self.b & 0b1111_0000 != 0 { + reg_on_4_bit = false; + } + if self.lit < -128 || self.lit > 127 { + lit_on_8_bits = false; + } + if !reg_on_4_bit && !lit_on_8_bits { + Err(anyhow!( + "div-int/lit uses either registers indexed on 4 bits, and a literal \ + encoded on 16 bits (div-int/lit16), or registers indexed on 8 bits and \ + a literal encoded on 8 bits (div-int/lit8). Found reg {} and {}, and lit \ + {}", + self.dest, + self.b, + self.lit + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("div-int/lit {} {} {}", self.dest, self.b, self.lit) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(DivInt2Addr({}, {}, {}))", + self.dest, self.b, self.lit + ) + } +} + +/// Put b % lit in dest. +/// +/// Either `dest` and `b` are registers indexed on 4 bits and lit is encoded in 16 bits +/// or `dest` and `b` are registers indexed on 8 bits and lit is encoded in 8 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct RemIntLit { + dest: u8, + b: u8, + lit: i16, +} + +#[pymethods] +impl RemIntLit { + #[new] + pub fn new(dest: u8, b: u8, lit: i16) -> Result { + let ins = Self { dest, b, lit }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + let mut reg_on_4_bit = true; + let lit_on_8_bits = true; + if self.dest & 0b1111_0000 != 0 { + reg_on_4_bit = false; + } + if self.b & 0b1111_0000 != 0 { + reg_on_4_bit = false; + } + if self.lit < -128 || self.lit > 127 { + lit_on_8_bits = false; + } + if !reg_on_4_bit && !lit_on_8_bits { + Err(anyhow!( + "rem-int/lit uses either registers indexed on 4 bits, and a literal \ + encoded on 16 bits (rem-int/lit16), or registers indexed on 8 bits and \ + a literal encoded on 8 bits (rem-int/lit8). Found reg {} and {}, and lit \ + {}", + self.dest, + self.b, + self.lit + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("rem-int/lit {} {} {}", self.dest, self.b, self.lit) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(RemInt2Addr({}, {}, {}))", + self.dest, self.b, self.lit + ) + } +} + +/// Put b & lit in dest. +/// +/// Either `dest` and `b` are registers indexed on 4 bits and lit is encoded in 16 bits +/// or `dest` and `b` are registers indexed on 8 bits and lit is encoded in 8 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AndIntLit { + dest: u8, + b: u8, + lit: i16, +} + +#[pymethods] +impl AndIntLit { + #[new] + pub fn new(dest: u8, b: u8, lit: i16) -> Result { + let ins = Self { dest, b, lit }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + let mut reg_on_4_bit = true; + let lit_on_8_bits = true; + if self.dest & 0b1111_0000 != 0 { + reg_on_4_bit = false; + } + if self.b & 0b1111_0000 != 0 { + reg_on_4_bit = false; + } + if self.lit < -128 || self.lit > 127 { + lit_on_8_bits = false; + } + if !reg_on_4_bit && !lit_on_8_bits { + Err(anyhow!( + "and-int/lit uses either registers indexed on 4 bits, and a literal \ + encoded on 16 bits (and-int/lit16), or registers indexed on 8 bits and \ + a literal encoded on 8 bits (and-int/lit8). Found reg {} and {}, and lit \ + {}", + self.dest, + self.b, + self.lit + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("and-int/lit {} {} {}", self.dest, self.b, self.lit) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(AndInt2Addr({}, {}, {}))", + self.dest, self.b, self.lit + ) + } +} + +/// Put b | lit in dest. +/// +/// Either `dest` and `b` are registers indexed on 4 bits and lit is encoded in 16 bits +/// or `dest` and `b` are registers indexed on 8 bits and lit is encoded in 8 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct OrIntLit { + dest: u8, + b: u8, + lit: i16, +} + +#[pymethods] +impl OrIntLit { + #[new] + pub fn new(dest: u8, b: u8, lit: i16) -> Result { + let ins = Self { dest, b, lit }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + let mut reg_on_4_bit = true; + let lit_on_8_bits = true; + if self.dest & 0b1111_0000 != 0 { + reg_on_4_bit = false; + } + if self.b & 0b1111_0000 != 0 { + reg_on_4_bit = false; + } + if self.lit < -128 || self.lit > 127 { + lit_on_8_bits = false; + } + if !reg_on_4_bit && !lit_on_8_bits { + Err(anyhow!( + "or-int/lit uses either registers indexed on 4 bits, and a literal \ + encoded on 16 bits (or-int/lit16), or registers indexed on 8 bits and \ + a literal encoded on 8 bits (or-int/lit8). Found reg {} and {}, and lit \ + {}", + self.dest, + self.b, + self.lit + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("or-int/lit {} {} {}", self.dest, self.b, self.lit) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(OrInt2Addr({}, {}, {}))", + self.dest, self.b, self.lit + ) + } +} + +/// Put b ^ lit in dest. +/// +/// Either `dest` and `b` are registers indexed on 4 bits and lit is encoded in 16 bits +/// or `dest` and `b` are registers indexed on 8 bits and lit is encoded in 8 bits +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct XorIntLit { + dest: u8, + b: u8, + lit: i16, +} + +#[pymethods] +impl XorIntLit { + #[new] + pub fn new(dest: u8, b: u8, lit: i16) -> Result { + let ins = Self { dest, b, lit }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + let mut reg_on_4_bit = true; + let lit_on_8_bits = true; + if self.dest & 0b1111_0000 != 0 { + reg_on_4_bit = false; + } + if self.b & 0b1111_0000 != 0 { + reg_on_4_bit = false; + } + if self.lit < -128 || self.lit > 127 { + lit_on_8_bits = false; + } + if !reg_on_4_bit && !lit_on_8_bits { + Err(anyhow!( + "xor-int/lit uses either registers indexed on 4 bits, and a literal \ + encoded on 16 bits (xor-int/lit16), or registers indexed on 8 bits and \ + a literal encoded on 8 bits (xor-int/lit8). Found reg {} and {}, and lit \ + {}", + self.dest, + self.b, + self.lit + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("xor-int/lit {} {} {}", self.dest, self.b, self.lit) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(XorInt2Addr({}, {}, {}))", + self.dest, self.b, self.lit + ) + } +} + +/// Put b << lit in dest. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ShlIntLit { + dest: u8, + b: u8, + lit: i8, +} + +#[pymethods] +impl ShlIntLit { + #[new] + pub fn new(dest: u8, b: u8, lit: i8) -> Self { + Self { dest, b, lit } + } + + pub fn __str__(&self) -> String { + format!("shl-int/lit {} {} {}", self.dest, self.b, self.lit) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(ShlIntLit({}, {}, {}))", + self.dest, self.b, self.lit + ) + } +} + +/// Put b >> lit (signed) in dest. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ShrIntLit { + dest: u8, + b: u8, + lit: i8, +} + +#[pymethods] +impl ShrIntLit { + #[new] + pub fn new(dest: u8, b: u8, lit: i8) -> Self { + Self { dest, b, lit } + } + + pub fn __str__(&self) -> String { + format!("shr-int/lit {} {} {}", self.dest, self.b, self.lit) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(ShrIntLit({}, {}, {}))", + self.dest, self.b, self.lit + ) + } +} + +/// Put b >> lit in dest. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct UshrIntLit { + dest: u8, + b: u8, + lit: i8, +} + +#[pymethods] +impl UshrIntLit { + #[new] + pub fn new(dest: u8, b: u8, lit: i8) -> Self { + Self { dest, b, lit } + } + + pub fn __str__(&self) -> String { + format!("ushr-int/lit {} {} {}", self.dest, self.b, self.lit) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(UshrIntLit({}, {}, {}))", + self.dest, self.b, self.lit + ) + } +} + +/// Call a polymorphic method. +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct InvokePolymorphic { + pub method: IdMethod, + pub proto: IdMethodType, + pub args: Vec, +} + +#[pymethods] +impl InvokePolymorphic { + #[new] + pub fn new(method: IdMethod, proto: IdMethodType, args: Vec) -> Result { + let invoke = Self { + method, + proto, + args, + }; + invoke.sanity_check()?; + Ok(invoke) + } + + pub fn sanity_check(&self) -> Result<()> { + let mut last = None; + let mut consec = true; + let mut four_bites = true; + let len = self.args.len(); + for r in self.args { + if let Some(last) = last { + if r != last + 1 { + consec = false; + } + } + if r & 0b1111_0000 != 0 { + four_bites = false; + } + last = Some(r); + } + if four_bites && len <= 5 { + Ok(()) + } else if consec && len <= 255 { + Ok(()) + } else { + Err(anyhow!( + "invoke-polymorphic instruction must either use 5 or \ + less register indexed on 4 bites or less than 255 \ + consecutive registers" + )) + } + } + + pub fn __str__(&self) -> String { + let args = if self.args.len() >= 5 { + format!("{} .. {}", self.args[0], self.args[self.args.len() - 1]) + } else { + self.args + .iter() + .map(|v| format!("{v}")) + .collect::>() + .join(" ") + }; + format!( + "invoke-polymorphic {{{}}} {} {}", + args, + self.method.__str__(), + self.proto.__str__() + ) + } + + pub fn __repr__(&self) -> String { + let args = if self.args.len() >= 5 { + format!("{} .. {}", self.args[0], self.args[self.args.len() - 1]) + } else { + self.args + .iter() + .map(|v| format!("{v}")) + .collect::>() + .join(" ") + }; + format!( + "Instruction(InvokePolymorphic({}, {}, {}))", + args, + self.method.__str__(), + self.proto.__str__() + ) + } +} + +/// Invoke a method from a call site. +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct InvokeCustom { + pub call_site: CallSite, + pub args: Vec, +} + +#[pymethods] +impl InvokeCustom { + #[new] + pub fn new(call_site: CallSite, args: Vec) -> Result { + let invoke = Self { call_site, args }; + invoke.sanity_check()?; + Ok(invoke) + } + + pub fn sanity_check(&self) -> Result<()> { + let mut last = None; + let mut consec = true; + let mut four_bites = true; + let len = self.args.len(); + for r in self.args { + if let Some(last) = last { + if r != last + 1 { + consec = false; + } + } + if r & 0b1111_0000 != 0 { + four_bites = false; + } + last = Some(r); + } + if four_bites && len <= 5 { + Ok(()) + } else if consec && len <= 255 { + Ok(()) + } else { + Err(anyhow!( + "invoke-custom instruction must either use 5 or \ + less register indexed on 4 bites or less than 255 \ + consecutive registers" + )) + } + } + + pub fn __str__(&self) -> String { + let args = if self.args.len() >= 5 { + format!("{} .. {}", self.args[0], self.args[self.args.len() - 1]) + } else { + self.args + .iter() + .map(|v| format!("{v}")) + .collect::>() + .join(" ") + }; + format!("invoke-custom {{{}}} {}", args, self.call_site.__str__(),) + } + + pub fn __repr__(&self) -> String { + let args = if self.args.len() >= 5 { + format!("{} .. {}", self.args[0], self.args[self.args.len() - 1]) + } else { + self.args + .iter() + .map(|v| format!("{v}")) + .collect::>() + .join(" ") + }; + format!( + "Instruction(InvokeCustom({}, {}))", + args, + self.call_site.__str__(), + ) + } +} + +/// Put contents reference to the method handle in the register. +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ConstMethodHandle { + pub handle: MethodHandle, + pub to: u8, +} + +#[pymethods] +impl ConstMethodHandle { + #[new] + pub fn new(to: u8, handle: MethodHandle) -> Self { + Self { to, handle } + } + + pub fn __str__(&self) -> String { + format!("const-method-handle {} {}", self.to, self.handle.__str__()) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(ConstMethodHandle({}, {}))", + self.to, + self.handle.__repr__() + ) + } +} + +/// Put contents reference to the prototype in the register. +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ConstMethodType { + pub proto: IdMethodType, + pub to: u8, +} + +#[pymethods] +impl ConstMethodType { + #[new] + pub fn new(to: u8, proto: IdMethodType) -> Self { + Self { to, proto } + } + + pub fn __str__(&self) -> String { + format!("const-method-type {} {}", self.to, self.proto.__str__()) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(ConstMethodHandle ConstMethodType({}, {}))", + self.to, + self.proto.__repr__() + ) + } +} diff --git a/androscalpel/src/method_handle.rs b/androscalpel/src/method_handle.rs index 29563b0..dc3e1fe 100644 --- a/androscalpel/src/method_handle.rs +++ b/androscalpel/src/method_handle.rs @@ -603,6 +603,21 @@ impl MethodHandle { } } + // Not exposed to python, but meh, let's keep it coherent + pub fn __repr__(&self) -> String { + match self { + Self::StaticPut(val) => val.__repr__(), + Self::StaticGet(val) => val.__repr__(), + Self::InstancePut(val) => val.__repr__(), + Self::InstanceGet(val) => val.__repr__(), + Self::InvokeStatic(val) => val.__repr__(), + Self::InvokeInstance(val) => val.__repr__(), + Self::InvokeConstructor(val) => val.__str__(), + Self::InvokeDirect(val) => val.__repr__(), + Self::InvokeInterface(val) => val.__repr__(), + } + } + /// Return all strings referenced in the Handle. pub fn get_all_strings(&self) -> HashSet { match self {