You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
156 lines
4.4 KiB
156 lines
4.4 KiB
use half::f16;
|
|
use num_traits::{float::FloatCore, PrimInt, Unsigned};
|
|
|
|
pub fn bits<T>(word: T, hi: usize, lo: usize) -> T where T: PrimInt + Unsigned {
|
|
assert!(hi >= lo);
|
|
let width = hi - lo + 1;
|
|
(word >> lo) & ((T::one() << width) - T::one())
|
|
}
|
|
|
|
pub fn nth(val: u32, pos: usize) -> u32 {
|
|
(val >> (31 - pos as u32)) & 1
|
|
}
|
|
pub fn f16_lo(val: u32) -> f16 {
|
|
f16::from_bits((val & 0xffff) as u16)
|
|
}
|
|
pub fn f16_hi(val: u32) -> f16 {
|
|
f16::from_bits(((val >> 16) & 0xffff) as u16)
|
|
}
|
|
|
|
pub fn sign_ext(num: u64, bits: usize) -> i64 {
|
|
let mut value = num;
|
|
let is_negative = (value >> (bits - 1)) & 1 != 0;
|
|
if is_negative {
|
|
value |= !0 << bits;
|
|
}
|
|
value as i64
|
|
}
|
|
|
|
pub trait IEEEClass<T> {
|
|
fn exponent(&self) -> T;
|
|
}
|
|
impl IEEEClass<u32> for f32 {
|
|
fn exponent(&self) -> u32 {
|
|
(self.to_bits() & 0b01111111100000000000000000000000) >> 23
|
|
}
|
|
}
|
|
impl IEEEClass<u16> for f16 {
|
|
fn exponent(&self) -> u16 {
|
|
(self.to_bits() & 0b0111110000000000) >> 10
|
|
}
|
|
}
|
|
impl IEEEClass<u64> for f64 {
|
|
fn exponent(&self) -> u64 {
|
|
(self.to_bits() & 0b0111111111110000000000000000000000000000000000000000000000000000) >> 52
|
|
}
|
|
}
|
|
|
|
pub trait VOPModifier<T> {
|
|
fn negate(&self, pos: usize, modifier: usize) -> T;
|
|
fn absolute(&self, pos: usize, modifier: usize) -> T;
|
|
}
|
|
impl<T> VOPModifier<T> for T
|
|
where
|
|
T: FloatCore,
|
|
{
|
|
fn negate(&self, pos: usize, modifier: usize) -> T {
|
|
match (modifier >> pos) & 1 {
|
|
1 => -*self,
|
|
_ => *self,
|
|
}
|
|
}
|
|
fn absolute(&self, pos: usize, modifier: usize) -> T {
|
|
match (modifier >> pos) & 1 {
|
|
1 => self.abs(),
|
|
_ => *self,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn extract_mantissa(x: f64) -> f64 {
|
|
if x.is_infinite() || x.is_nan() {
|
|
return x;
|
|
}
|
|
let bits = x.to_bits();
|
|
let mantissa_mask: u64 = 0x000FFFFFFFFFFFFF;
|
|
let bias: u64 = 1023;
|
|
let normalized_mantissa_bits = (bits & mantissa_mask) | ((bias - 1) << 52);
|
|
return f64::from_bits(normalized_mantissa_bits);
|
|
}
|
|
pub fn ldexp(x: f64, exp: i32) -> f64 {
|
|
x * 2f64.powi(exp)
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
#[test]
|
|
fn test_extract_mantissa() {
|
|
assert_eq!(extract_mantissa(2.0f64), 0.5);
|
|
}
|
|
|
|
#[test]
|
|
fn test_normal_exponent() {
|
|
assert_eq!(2.5f32.exponent(), 128);
|
|
assert_eq!(1.17549435e-38f32.exponent(), 1);
|
|
assert_eq!(f32::INFINITY.exponent(), 255);
|
|
assert_eq!(f32::NEG_INFINITY.exponent(), 255);
|
|
}
|
|
|
|
#[test]
|
|
fn test_denormal_exponent() {
|
|
assert_eq!(1.0e-40f32.exponent(), 0);
|
|
assert_eq!(1.0e-42f32.exponent(), 0);
|
|
assert_eq!(1.0e-44f32.exponent(), 0);
|
|
assert_eq!((1.17549435e-38f32 / 2.0).exponent(), 0);
|
|
}
|
|
|
|
#[test]
|
|
fn test_normal_exponent_f16() {
|
|
assert_eq!(f16::from_f32(3.14f32).exponent(), 16);
|
|
assert_eq!(f16::NEG_INFINITY.exponent(), 31);
|
|
assert_eq!(f16::INFINITY.exponent(), 31);
|
|
}
|
|
|
|
#[test]
|
|
fn test_neg() {
|
|
assert_eq!(0.3_f32.negate(0, 0b001), -0.3_f32);
|
|
assert_eq!(0.3_f32.negate(1, 0b010), -0.3_f32);
|
|
assert_eq!(0.3_f32.negate(2, 0b100), -0.3_f32);
|
|
assert_eq!(0.3_f32.negate(0, 0b110), 0.3_f32);
|
|
assert_eq!(0.3_f32.negate(1, 0b010), -0.3_f32);
|
|
assert_eq!(0.0_f32.negate(0, 0b001).to_bits(), (-0.0f32).to_bits());
|
|
assert_eq!((-0.0_f32).negate(0, 0b001).to_bits(), 0);
|
|
}
|
|
|
|
#[test]
|
|
fn test_sign_ext() {
|
|
assert_eq!(sign_ext(0b000000000000000101000, 21), 40);
|
|
assert_eq!(sign_ext(0b111111111111111011000, 21), -40);
|
|
assert_eq!(sign_ext(0b000000000000000000000, 21), 0);
|
|
assert_eq!(sign_ext(0b111111111111111111111, 21), -1);
|
|
assert_eq!(sign_ext(0b111000000000000000000, 21), -262144);
|
|
assert_eq!(sign_ext(0b000111111111111111111, 21), 262143);
|
|
assert_eq!(sign_ext(7608, 13), -584);
|
|
}
|
|
}
|
|
|
|
use std::sync::LazyLock;
|
|
pub static DEBUG: LazyLock<bool> = LazyLock::new(|| std::env::var("DEBUG").map(|v| v.parse::<usize>().unwrap_or(0) >= 6).unwrap_or(false));
|
|
|
|
pub fn colored(st:&str, color:&str) -> String {
|
|
let ansi_code = match color {
|
|
"green" => format!("\x1b[{};2;39;176;139m", 38),
|
|
"gray" => format!("\x1b[{};2;169;169;169m", 38),
|
|
_ => format!("\x1b[{};2;255;255;255m", 38),
|
|
};
|
|
format!("{}{}{}", ansi_code, st, "\x1b[0m")
|
|
}
|
|
|
|
#[macro_export]
|
|
macro_rules! todo_instr {
|
|
($x:expr) => {{
|
|
println!("{:08X}", $x);
|
|
Err(1)
|
|
}};
|
|
}
|
|
|