pub trait Multiply<S, U>: Sized {
fn muls(first: S, second: S) -> (S, S);
fn mulu(first: U, second: U) -> (U, U);
fn mulsu(first: S, second: U) -> (S, S);
}
macro_rules! impl_multiply {
($(($signed:ident, $unsigned:ident, * = $bytes:expr) -> ($signed_long:ident, $unsigned_long:ident)),*) => {
$(
impl Multiply<$signed, $unsigned> for $signed {
fn muls(first: $signed, second: $signed) -> ($signed, $signed) {
let result = (first as $signed_long).saturating_mul(second as _);
(result as _, (result >> ($bytes * 8)) as _)
}
fn mulu(first: $unsigned, second: $unsigned) -> ($unsigned, $unsigned) {
let result = (first as $unsigned_long).saturating_mul(second as _);
(result as _, (result >> ($bytes * 8)) as _)
}
fn mulsu(first: $signed, second: $unsigned) -> ($signed, $signed) {
let result = (first as $signed_long).saturating_mul(second as _);
(result as _, (result >> ($bytes * 8)) as _)
}
}
)*
};
}
impl_multiply!{(i32, u32, * = 4) -> (i64, u64), (i64, u64, * = 8) -> (i128, u128)}
#[cfg(target_pointer_width = "32")]
impl_multiply!{(isize, usize, * = 4) -> (i64, u64)}
#[cfg(target_pointer_width = "64")]
impl_multiply!{(isize, usize, * = 8) -> (i128, u128)}
pub trait Integer {
fn add(self, other: Self) -> Self;
fn sub(self, other: Self) -> Self;
fn shl(self, other: Self) -> Self;
fn shr(self, other: Self) -> Self;
fn div(self, other: Self) -> Self;
fn rem(self, other: Self) -> Self;
fn lt(self, other: Self) -> bool;
fn gte(self, other: Self) -> bool;
fn eq(self, other: Self) -> bool;
fn neq(self, other: Self) -> bool;
fn and(self, other: Self) -> Self;
fn or(self, other: Self) -> Self;
fn xor(self, other: Self) -> Self;
fn not(self) -> Self;
}
macro_rules! impl_integer {
($($name:ident(* = $shift:expr, $larger_type:ident)),*) => {
$(
impl Integer for $name {
#[inline(always)]
fn add(self, other: Self) -> Self { $name::wrapping_add(self, other) }
#[inline(always)]
fn sub(self, other: Self) -> Self { $name::wrapping_sub(self, other) }
#[inline(always)]
fn shl(self, other: Self) -> Self { $name::wrapping_shl(self, other as _) }
#[inline(always)]
fn shr(self, other: Self) -> Self { $name::wrapping_shr(self, other as _) }
#[inline(always)]
fn div(self, other: Self) -> Self {
if other == 0 {
-1 as _
} else if self == std::$name::MIN && other == -1 as _ {
self
} else {
self / other
}
}
#[inline(always)]
fn rem(self, other: Self) -> Self {
if other == 0 {
self
} else if self == std::$name::MIN && other == -1 as _ {
0
} else {
self % other
}
}
#[inline(always)]
fn lt(self, other: Self) -> bool { self < other }
#[inline(always)]
fn gte(self, other: Self) -> bool { self >= other }
#[inline(always)]
fn eq(self, other: Self) -> bool { self == other }
#[inline(always)]
fn neq(self, other: Self) -> bool { self != other }
#[inline(always)]
fn and(self, other: Self) -> Self { self & other }
#[inline(always)]
fn or(self, other: Self) -> Self { self | other }
#[inline(always)]
fn xor(self, other: Self) -> Self { self ^ other }
#[inline(always)]
fn not(self) -> Self { !self }
}
)*
};
}
impl_integer! { u32(* = 4, u64), i32(* = 4, i64), u64(* = 8, u128), i64(* = 4, u128), usize(* = 8, usize), isize(* = 8, usize) }
#[derive(Debug, PartialEq, Eq)]
pub enum RegisterWidth {
Bits32,
Bits64
}
pub trait Xlen {
type Signed: Integer + Multiply<Self::Signed, Self::Unsigned> + Copy;
type Unsigned: Integer + Copy;
const WIDTH: RegisterWidth;
fn signed(self) -> Self::Signed;
fn unsigned(self) -> Self::Unsigned;
fn from_signed(from: Self::Signed) -> Self;
fn from_unsigned(from: Self::Unsigned) -> Self;
fn append(self, offset: usize) -> Self::Unsigned;
fn usize(self) -> usize;
}
pub trait Register: Xlen + Sized + Default + Copy {
fn add_signed(self, other: Self) -> Self {
Self::from_signed(self.signed().add(other.signed()))
}
fn add_unsigned(self, other: Self) -> Self {
Self::from_unsigned(self.unsigned().add(other.unsigned()))
}
fn sub_unsigned(self, other: Self) -> Self {
Self::from_unsigned(self.unsigned().sub(other.unsigned()))
}
fn shl(self, other: Self) -> Self {
Self::from_unsigned(self.unsigned().shl(other.unsigned()))
}
fn shr(self, other: Self) -> Self {
Self::from_unsigned(self.unsigned().shr(other.unsigned()))
}
fn sha(self, other: Self) -> Self {
Self::from_signed(self.signed().shr(other.signed()))
}
#[cfg(feature = "ext-m")]
fn mul(self, other: Self) -> Self {
Self::from_signed(Self::Signed::muls(self.signed(), other.signed()).0)
}
#[cfg(feature = "ext-m")]
fn mulh(self, other: Self) -> Self {
Self::from_signed(Self::Signed::muls(self.signed(), other.signed()).1)
}
#[cfg(feature = "ext-m")]
fn mulhu(self, other: Self) -> Self {
Self::from_unsigned(Self::Signed::mulu(self.unsigned(), other.unsigned()).1)
}
#[cfg(feature = "ext-m")]
fn mulhsu(self, other: Self) -> Self {
Self::from_signed(Self::Signed::mulsu(self.signed(), other.unsigned()).1)
}
#[cfg(feature = "ext-m")]
fn div(self, other: Self) -> Self {
Self::from_signed(self.signed().div(other.signed()))
}
#[cfg(feature = "ext-m")]
fn divu(self, other: Self) -> Self {
Self::from_unsigned(self.unsigned().div(other.unsigned()))
}
#[cfg(feature = "ext-m")]
fn rem(self, other: Self) -> Self {
Self::from_signed(self.signed().rem(other.signed()))
}
#[cfg(feature = "ext-m")]
fn remu(self, other: Self) -> Self {
Self::from_unsigned(self.unsigned().rem(other.unsigned()))
}
fn and(self, other: Self) -> Self {
Self::from_unsigned(self.unsigned().and(other.unsigned()))
}
fn or(self, other: Self) -> Self {
Self::from_unsigned(self.unsigned().or(other.unsigned()))
}
fn xor(self, other: Self) -> Self {
Self::from_unsigned(self.unsigned().xor(other.unsigned()))
}
fn not(self) -> Self {
Self::from_unsigned(self.unsigned().not())
}
fn eq(self, other: Self) -> bool {
self.unsigned().eq(other.unsigned())
}
fn neq(self, other: Self) -> bool {
self.unsigned().neq(other.unsigned())
}
fn lt_signed(self, other: Self) -> bool {
self.signed().lt(other.signed())
}
fn lt_unsigned(self, other: Self) -> bool {
self.unsigned().lt(other.unsigned())
}
fn gte_signed(self, other: Self) -> bool {
self.signed().gte(other.signed())
}
fn gte_unsigned(self, other: Self) -> bool {
self.unsigned().gte(other.unsigned())
}
fn sign_extended_byte(byte: u8) -> Self;
fn zero_extended_byte(byte: u8) -> Self;
fn sign_extended_half(half: [u8; 2]) -> Self;
fn zero_extended_half(half: [u8; 2]) -> Self;
fn sign_extended_word(word: [u8; 4]) -> Self;
fn zero_extended_word(word: [u8; 4]) -> Self;
fn sign_extended_double(double: [u8; 8]) -> Self;
fn zero_extended_double(double: [u8; 8]) -> Self;
fn byte(self) -> u8;
fn half(self) -> [u8; 2];
fn word(self) -> [u8; 4];
fn double(self) -> [u8; 8];
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Register32(pub [u8; 4]);
impl Xlen for Register32 {
type Signed = i32;
type Unsigned = u32;
const WIDTH: RegisterWidth = RegisterWidth::Bits32;
fn signed(self) -> i32 {
i32::from_le_bytes(self.0)
}
fn unsigned(self) -> u32 {
u32::from_le_bytes(self.0)
}
fn from_signed(from: i32) -> Self {
Self(from.to_le_bytes())
}
fn from_unsigned(from: u32) -> Self {
Self(from.to_le_bytes())
}
fn append(self, value: usize) -> u32 {
self.unsigned() + value as u32
}
fn usize(self) -> usize {
self.unsigned() as usize
}
}
impl Register for Register32 {
#[inline]
fn sign_extended_byte(byte: u8) -> Self {
let extended = if byte & 0x80 != 0 { 0xFF } else { 0 };
Self([byte, extended, extended, extended])
}
#[inline]
fn zero_extended_byte(byte: u8) -> Self {
Self([byte, 0, 0, 0])
}
#[inline]
fn sign_extended_half(half: [u8; 2]) -> Self {
let extended = if half[1] & 0x80 != 0 { 0xFF } else { 0 };
Self([half[0], half[1], extended, extended])
}
#[inline]
fn zero_extended_half(half: [u8; 2]) -> Self {
Self([half[0], half[1], 0, 0])
}
#[inline(always)]
fn sign_extended_word(word: [u8; 4]) -> Self {
Self(word)
}
#[inline(always)]
fn zero_extended_word(word: [u8; 4]) -> Self {
Self(word)
}
#[inline(always)]
fn sign_extended_double(_: [u8; 8]) -> Self {
panic!("Cannot create a 32 bit register from a 64 bit value")
}
#[inline(always)]
fn zero_extended_double(_: [u8; 8]) -> Self {
panic!("Cannot create a 32 bit register from a 64 bit value")
}
#[inline(always)]
fn byte(self) -> u8 { self.0[0] }
#[inline(always)]
fn half(self) -> [u8; 2] { [self.0[0], self.0[1]] }
#[inline(always)]
fn word(self) -> [u8; 4] { self.0 }
#[inline(always)]
fn double(self) -> [u8; 8] { panic!("Cannot get a 64 bit value from a 32 bit register") }
}
impl Default for Register32 {
fn default() -> Self {
Self([0, 0, 0, 0])
}
}
impl From<u32> for Register32 {
fn from(value: u32) -> Self {
Self::from_unsigned(value)
}
}
impl From<i32> for Register32 {
fn from(value: i32) -> Self {
Self::from_signed(value)
}
}
#[derive(Clone, Copy, Debug)]
pub struct Register64(pub [u8; 8]);
impl Register64 {
pub fn split(self) -> (Register32, Register32) {
(Register32([self.0[0], self.0[1], self.0[2], self.0[3]]), Register32([self.0[4], self.0[5], self.0[6], self.0[7]]))
}
}
impl Xlen for Register64 {
type Signed = i64;
type Unsigned = u64;
const WIDTH: RegisterWidth = RegisterWidth::Bits32;
fn signed(self) -> i64 {
i64::from_le_bytes(self.0)
}
fn unsigned(self) -> u64 {
u64::from_le_bytes(self.0)
}
fn from_signed(from: i64) -> Self {
Self(from.to_le_bytes())
}
fn from_unsigned(from: u64) -> Self {
Self(from.to_le_bytes())
}
fn append(self, value: usize) -> u64 {
self.unsigned() + value as u64
}
fn usize(self) -> usize {
self.unsigned() as usize
}
}
impl Register for Register64 {
#[inline]
fn sign_extended_byte(byte: u8) -> Self {
let extended = if byte & 0x80 != 0 { 0xFF } else { 0 };
Self([byte, extended, extended, extended, extended, extended, extended, extended])
}
#[inline]
fn zero_extended_byte(byte: u8) -> Self {
Self([byte, 0, 0, 0, 0, 0, 0, 0])
}
#[inline]
fn sign_extended_half(half: [u8; 2]) -> Self {
let extended = if half[1] & 0x80 != 0 { 0xFF } else { 0 };
Self([half[0], half[1], extended, extended, extended, extended, extended, extended])
}
#[inline]
fn zero_extended_half(half: [u8; 2]) -> Self {
Self([half[0], half[1], 0, 0, 0, 0, 0, 0])
}
#[inline(always)]
fn sign_extended_word(word: [u8; 4]) -> Self {
let extended = if word[3] & 0x80 != 0 { 0xFF } else { 0 };
Self([word[0], word[1], word[2], word[3], extended, extended, extended, extended])
}
#[inline(always)]
fn zero_extended_word(word: [u8; 4]) -> Self {
Self([word[0], word[1], word[2], word[3], 0, 0, 0, 0])
}
#[inline(always)]
fn sign_extended_double(double: [u8; 8]) -> Self {
Self(double)
}
#[inline(always)]
fn zero_extended_double(double: [u8; 8]) -> Self {
Self(double)
}
#[inline(always)]
fn byte(self) -> u8 { self.0[0] }
#[inline(always)]
fn half(self) -> [u8; 2] { [self.0[0], self.0[1]] }
#[inline(always)]
fn word(self) -> [u8; 4] { [self.0[0], self.0[1], self.0[2], self.0[3]] }
#[inline(always)]
fn double(self) -> [u8; 8] { self.0 }
}
impl Default for Register64 {
fn default() -> Self {
Self([0, 0, 0, 0, 0, 0, 0, 0])
}
}
#[cfg(not(target_pointer_width = "16"))]
#[derive(Clone, Copy, Debug)]
pub struct RegisterSize(pub [u8; std::mem::size_of::<usize>()]);
#[cfg(not(target_pointer_width = "16"))]
impl Xlen for RegisterSize {
type Signed = isize;
type Unsigned = usize;
#[cfg(target_pointer_width = "32")]
const WIDTH: RegisterWidth = RegisterWidth::Bits32;
#[cfg(target_pointer_width = "64")]
const WIDTH: RegisterWidth = RegisterWidth::Bits64;
fn signed(self) -> isize {
isize::from_le_bytes(self.0)
}
fn unsigned(self) -> usize {
usize::from_le_bytes(self.0)
}
fn from_signed(from: isize) -> Self {
Self(from.to_le_bytes())
}
fn from_unsigned(from: usize) -> Self {
Self(from.to_le_bytes())
}
fn append(self, value: usize) -> usize {
self.unsigned() + value as usize
}
fn usize(self) -> usize {
self.unsigned()
}
}
#[cfg(not(target_pointer_width = "16"))]
impl Register for RegisterSize {
#[inline]
fn sign_extended_byte(byte: u8) -> Self {
let extended = if byte & 0x80 != 0 { 0xFF } else { 0 };
#[cfg(target_pointer_width = "32")]
{Self([byte, extended, extended, extended])}
#[cfg(target_pointer_width = "64")]
{Self([byte, extended, extended, extended, extended, extended, extended, extended])}
}
#[inline]
fn zero_extended_byte(byte: u8) -> Self {
#[cfg(target_pointer_width = "32")]
{Self([byte, 0, 0, 0])}
#[cfg(target_pointer_width = "64")]
{Self([byte, 0, 0, 0, 0, 0, 0, 0])}
}
#[inline]
fn sign_extended_half(half: [u8; 2]) -> Self {
let extended = if half[1] & 0x80 != 0 { 0xFF } else { 0 };
#[cfg(target_pointer_width = "32")]
{Self([half[0], half[1], extended, extended])}
#[cfg(target_pointer_width = "64")]
{Self([half[0], half[1], extended, extended, extended, extended, extended, extended])}
}
#[inline]
fn zero_extended_half(half: [u8; 2]) -> Self {
#[cfg(target_pointer_width = "32")]
{Self([half[0], half[1], 0, 0])}
#[cfg(target_pointer_width = "64")]
{Self([half[0], half[1], 0, 0, 0, 0, 0, 0])}
}
#[inline(always)]
fn sign_extended_word(word: [u8; 4]) -> Self {
let extended = if word[3] & 0x80 != 0 { 0xFF } else { 0 };
#[cfg(target_pointer_width = "32")]
{Self(word)}
#[cfg(target_pointer_width = "64")]
{Self([word[0], word[1], word[2], word[3], extended, extended, extended, extended])}
}
#[inline(always)]
fn zero_extended_word(word: [u8; 4]) -> Self {
#[cfg(target_pointer_width = "32")]
{Self(word)}
#[cfg(target_pointer_width = "64")]
{Self([word[0], word[1], word[2], word[3], 0, 0, 0, 0])}
}
#[inline(always)]
fn sign_extended_double(double: [u8; 8]) -> Self {
#[cfg(target_pointer_width = "32")]
{panic!("Cannot create a 32 bit register from a 64 bit value")}
#[cfg(target_pointer_width = "64")]
{Self(double)}
}
#[inline(always)]
fn zero_extended_double(double: [u8; 8]) -> Self {
#[cfg(target_pointer_width = "32")]
{panic!("Cannot create a 32 bit register from a 64 bit value")}
#[cfg(target_pointer_width = "64")]
{Self(double)}
}
#[inline(always)]
fn byte(self) -> u8 { self.0[0] }
#[inline(always)]
fn half(self) -> [u8; 2] { [self.0[0], self.0[1]] }
#[inline(always)]
fn word(self) -> [u8; 4] { [self.0[0], self.0[1], self.0[2], self.0[3]] }
#[inline(always)]
fn double(self) -> [u8; 8] {
#[cfg(not(target_pointer_width = "32"))]
{[self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5], self.0[6], self.0[7]]}
#[cfg(target_pointer_width = "32")]
{panic!("Cannot create a 64 bit value from a 32 bit register")}
}
}
#[cfg(not(target_pointer_width = "16"))]
impl Default for RegisterSize {
fn default() -> Self {
#[cfg(target_pointer_width = "32")]
{Self([0, 0, 0, 0])}
#[cfg(target_pointer_width = "64")]
{Self([0, 0, 0, 0, 0, 0, 0, 0])}
}
}