use crate::exception::ADDRESS_ERROR;
use crate::instruction::Size;
use std::num::Wrapping;
use std::ops::{BitAnd, BitOr, BitXor, Shl};
#[inline(always)]
pub const fn bit(data: u16, bit: u16) -> bool {
data & (1 << bit) != 0
}
#[inline(always)]
pub const fn bits(d: u16, beg: u16, end: u16) -> u16 {
let mask = (1 << (end + 1 - beg)) - 1;
d >> beg & mask
}
pub trait IsEven : Sized {
fn is_even(self) -> bool;
fn even(self) -> Result<Self, u8>;
}
impl IsEven for u32 {
#[inline(always)]
fn is_even(self) -> bool {
self & 1 == 0
}
#[inline(always)]
fn even(self) -> Result<Self, u8> {
if self.is_even() {
Ok(self)
} else {
Err(ADDRESS_ERROR)
}
}
}
impl IsEven for Wrapping<u32> {
#[inline(always)]
fn is_even(self) -> bool {
self.0 & 1 == 0
}
#[inline(always)]
fn even(self) -> Result<Self, u8> {
if self.is_even() {
Ok(self)
} else {
Err(ADDRESS_ERROR)
}
}
}
impl IsEven for usize {
#[inline(always)]
fn is_even(self) -> bool {
self & 1 == 0
}
#[inline(always)]
fn even(self) -> Result<Self, u8> {
if self.is_even() {
Ok(self)
} else {
Err(ADDRESS_ERROR)
}
}
}
pub trait SliceAs {
fn u32_be(self) -> u32;
fn i32_be_sized(self, size: Size) -> i32;
fn get_next_word(&mut self) -> u16;
}
impl SliceAs for &[u16] {
fn u32_be(self) -> u32 {
(self[0] as u32) << 16 | self[1] as u32
}
fn i32_be_sized(self, size: Size) -> i32 {
match size {
Size::Byte => self[0] as i8 as i32,
Size::Word => self[0] as i16 as i32,
Size::Long => self.u32_be() as i32,
}
}
fn get_next_word(&mut self) -> u16 {
let d = self[0];
*self = &self[1..];
d
}
}
pub trait CarryingOps<S, U> : Sized + Integer {
fn carryingadd(self, rhs: Self, carry: bool) -> (Self, bool);
fn borrowingsub(self, rhs: Self, borrow: bool) -> (Self, bool);
fn signed_carrying_add(self, rhs: Self, carry: bool) -> (S, bool);
fn unsigned_carrying_add(self, rhs: Self, carry: bool) -> (U, bool);
fn signed_borrowing_sub(self, rhs: Self, carry: bool) -> (S, bool);
fn unsigned_borrowing_sub(self, rhs: Self, carry: bool) -> (U, bool);
}
macro_rules! impl_carrying_ops_signed {
($t:ty, $st:ty, $ut:ty) => {
impl CarryingOps<$st, $ut> for $t {
fn carryingadd(self, rhs: Self, carry: bool) -> (Self, bool) {
let (a, b) = self.overflowing_add(rhs);
let (c, d) = a.overflowing_add(carry as $t);
(c, b != d)
}
fn borrowingsub(self, rhs: Self, borrow: bool) -> (Self, bool) {
let (a, b) = self.overflowing_sub(rhs);
let (c, d) = a.overflowing_sub(borrow as $t);
(c, b != d)
}
fn signed_carrying_add(self, rhs: Self, carry: bool) -> ($st, bool) {
(self as $st).carryingadd(rhs as $st, carry)
}
fn unsigned_carrying_add(self, rhs: Self, carry: bool) -> ($ut, bool) {
(self as $ut).carryingadd(rhs as $ut, carry)
}
fn signed_borrowing_sub(self, rhs: Self, carry: bool) -> ($st, bool) {
(self as $st).borrowingsub(rhs as $st, carry)
}
fn unsigned_borrowing_sub(self, rhs: Self, carry: bool) -> ($ut, bool) {
(self as $ut).borrowingsub(rhs as $ut, carry)
}
}
};
}
macro_rules! impl_carrying_ops_unsigned {
($t:ty, $st:ty, $ut:ty) => {
impl CarryingOps<$st, $ut> for $t {
fn carryingadd(self, rhs: Self, carry: bool) -> (Self, bool) {
let (a, b) = self.overflowing_add(rhs);
let (c, d) = a.overflowing_add(carry as $t);
(c, b || d)
}
fn borrowingsub(self, rhs: Self, borrow: bool) -> (Self, bool) {
let (a, b) = self.overflowing_sub(rhs);
let (c, d) = a.overflowing_sub(borrow as $t);
(c, b || d)
}
fn signed_carrying_add(self, rhs: Self, carry: bool) -> ($st, bool) {
(self as $st).carryingadd(rhs as $st, carry)
}
fn unsigned_carrying_add(self, rhs: Self, carry: bool) -> ($ut, bool) {
(self as $ut).carryingadd(rhs as $ut, carry)
}
fn signed_borrowing_sub(self, rhs: Self, carry: bool) -> ($st, bool) {
(self as $st).borrowingsub(rhs as $st, carry)
}
fn unsigned_borrowing_sub(self, rhs: Self, carry: bool) -> ($ut, bool) {
(self as $ut).borrowingsub(rhs as $ut, carry)
}
}
};
}
impl_carrying_ops_signed!(i8, i8, u8);
impl_carrying_ops_unsigned!(u8, i8, u8);
impl_carrying_ops_signed!(i16, i16, u16);
impl_carrying_ops_unsigned!(u16, i16, u16);
impl_carrying_ops_signed!(i32, i32, u32);
impl_carrying_ops_unsigned!(u32, i32, u32);
pub trait Integer : Copy + PartialEq + PartialOrd +
BitAnd<Output = Self> + BitOr<Output = Self> + BitXor<Output = Self> +
Shl<Output = Self> {
const ZERO: Self;
const SIGN_BIT_MASK: Self;
}
macro_rules! impl_integer {
($t:ty, $sign:expr) => {
impl Integer for $t {
const ZERO: Self = 0;
const SIGN_BIT_MASK: Self = $sign;
}
};
}
impl_integer!(i8, -0x80);
impl_integer!(u8, 0x80);
impl_integer!(i16, -0x8000);
impl_integer!(u16, 0x8000);
impl_integer!(i32, -0x8000_0000);
impl_integer!(u32, 0x8000_0000);