diff --git a/backup/asm_runtime.rs b/backup/asm_runtime.rs deleted file mode 100644 index 0de3dcf0..00000000 --- a/backup/asm_runtime.rs +++ /dev/null @@ -1,185 +0,0 @@ -// For now, the division fns can just keep living here. - -/// Returns 0 in `r0`, while placing the `numerator` into `r1`. -/// -/// This is written in that slightly strange way so that `div` function and -/// `divmod` functions can share the same code path. -/// -/// See: [__aeabi_idiv0][aeabi-division-by-zero] -/// -/// [aeabi-division-by-zero]: https://github.com/ARM-software/abi-aa/blob/main/rtabi32/rtabi32.rst#division-by-zero -#[naked] -#[no_mangle] -#[instruction_set(arm::a32)] -// this should literally never get called for real, so we leave it in ROM -extern "C" fn __aeabi_idiv0(numerator: i32) -> i32 { - unsafe { - core::arch::asm!( - // this comment stops rustfmt from making this a one-liner - "mov r1, r0", - "mov r0, #0", - "bx lr", - options(noreturn) - ) - } -} - -/// Returns `u32 / u32` -/// -/// This implementation is *not* the fastest possible division, but it is -/// extremely compact. -/// -/// See: [__aeabi_uidiv][aeabi-integer-32-32-division] -/// -/// [aeabi-integer-32-32-division]: -/// https://github.com/ARM-software/abi-aa/blob/main/rtabi32/rtabi32.rst#integer-32-32-32-division-functions -#[naked] -#[no_mangle] -#[instruction_set(arm::a32)] -#[link_section = ".iwram.aeabi.uidiv"] -extern "C" fn __aeabi_uidiv(numerator: u32, denominator: u32) -> u32 { - // Note(Lokathor): Other code in this module relies on being able to call this - // function without affecting r12, so any future implementations of this code - // **must not** destroy r12. - unsafe { - core::arch::asm!( - // Check for divide by 0 - "cmp r1, #0", - "beq {__aeabi_idiv0}", - // r3(shifted_denom) = denom - "mov r3, r1", - // while shifted_denom < (num>>1): shifted_denom =<< 1; - "cmp r3, r0, lsr #1", - "2:", - "lslls r3, r3, #1", - "cmp r3, r0, lsr #1", - "bls 2b", - // r0=quot(init 0), r1=denom, r2=num, r3=shifted_denom - "mov r2, r0", - "mov r0, #0", - // subtraction loop - "3:", - "cmp r2, r3", - "subcs r2, r2, r3", - "adc r0, r0, r0", - "mov r3, r3, lsr #1", - "cmp r3, r1", - "bcs 3b", - "bx lr", - __aeabi_idiv0 = sym __aeabi_idiv0, - options(noreturn) - ) - } -} - -/// Returns `i32 / i32` -/// -/// See: [__aeabi_idiv][aeabi-integer-32-32-division] -/// -/// [aeabi-integer-32-32-division]: -/// https://github.com/ARM-software/abi-aa/blob/main/rtabi32/rtabi32.rst#integer-32-32-32-division-functions -#[naked] -#[no_mangle] -#[instruction_set(arm::a32)] -#[link_section = ".iwram.aeabi.idiv"] -extern "C" fn __aeabi_idiv(numerator: i32, denominator: i32) -> u32 { - unsafe { - core::arch::asm!( - // determine if `numerator` and `denominator` are the same sign - "eor r12, r1, r0", - // convert both values to their unsigned absolute value. - "cmp r0, #0", - "rsblt r0, r0, #0", - "cmp r1, #0", - "rsclt r1, r1, #0", - bracer::with_pushed_registers!("{{lr}}", { - // divide them using `u32` division (this will check for divide by 0) - "bl {__aeabi_uidiv}", - }), - // if they started as different signs, flip the output's sign. - "cmp r12, #0", - "rsblt r0, r0, #0", - "bx lr", - __aeabi_uidiv = sym __aeabi_uidiv, - options(noreturn) - ) - } -} - -/// Returns `(u32 / u32, u32 % u32)` in `(r0, r1)`. -/// -/// The `u64` return value is a mild lie that gets Rust to grab up both the `r0` -/// and `r1` values when the function returns. If you transmute the return value -/// into `[u32; 2]` then you can separate the two parts of the return value, and -/// it will have no runtime cost. -/// -/// See: [__aeabi_uidivmod][aeabi-integer-32-32-division] -/// -/// [aeabi-integer-32-32-division]: -/// https://github.com/ARM-software/abi-aa/blob/main/rtabi32/rtabi32.rst#integer-32-32-32-division-functions -#[naked] -#[no_mangle] -#[instruction_set(arm::a32)] -#[link_section = ".iwram.aeabi.uidivmod"] -extern "C" fn __aeabi_uidivmod(numerator: u32, denominator: u32) -> u64 { - unsafe { - core::arch::asm!( - // We need to save *both* input args until after the uidiv call. One of - // them can be saved in `r12` because we know our uidiv doesn't actually - // touch `r12`, while the other will be pushed onto the stack along with - // `lr`. Since the function's output will be in `r0`, we push/pop `r1`. - "mov r12, r0", - bracer::with_pushed_registers!("{{r1, lr}}", { - "bl {__aeabi_uidiv}", - }), - // Now r0 holds the `quot`, and we use it along with the input args to - // calculate the `rem`. - "mul r2, r0, r1", - "sub r1, r12, r2", - "bx lr", - __aeabi_uidiv = sym __aeabi_uidiv, - options(noreturn) - ) - } -} - -/// Returns `(i32 / i32, i32 % i32)` in `(r0, r1)`. -/// -/// The `u64` return value is a mild lie that gets Rust to grab up both the `r0` -/// and `r1` values when the function returns. If you transmute the return value -/// into `[i32; 2]` then you can separate the two parts of the return value, and -/// it will have no runtime cost. -/// -/// See: [__aeabi_idivmod][aeabi-integer-32-32-division] -/// -/// [aeabi-integer-32-32-division]: -/// https://github.com/ARM-software/abi-aa/blob/main/rtabi32/rtabi32.rst#integer-32-32-32-division-functions -#[naked] -#[no_mangle] -#[instruction_set(arm::a32)] -#[link_section = ".iwram.aeabi.idivmod"] -extern "C" fn __aeabi_idivmod(numerator: i32, denominator: i32) -> u64 { - unsafe { - core::arch::asm!( - bracer::with_pushed_registers!("{{r4, r5, lr}}", { - // store old numerator then make it the unsigned absolute - "movs r4, r0", - "rsblt r0, r0, #0", - // store old denominator then make it the unsigned absolute - "movs r5, r1", - "rsblt r1, r1, #0", - // divmod using unsigned. - "bl {__aeabi_uidivmod}", - // if signs started opposite, quot becomes negative - "eors r12, r4, r5", - "rsblt r0, r0, #0", - // if numerator started negative, rem is negative - "cmp r4, #0", - "rsblt r1, r1, #0", - }), - "bx lr", - __aeabi_uidivmod = sym __aeabi_uidivmod, - options(noreturn) - ) - } -} diff --git a/backup/fixed.rs b/backup/fixed.rs deleted file mode 100644 index f2aa64a9..00000000 --- a/backup/fixed.rs +++ /dev/null @@ -1,358 +0,0 @@ -use core::ops::*; - -/// `i16` with 8 bits of fixed-point fraction. -/// -/// This is used by the affine matrix entries. -#[allow(non_camel_case_types)] -pub type i16fx8 = Fixed; - -/// `i16` with 14 bits of fixed-point fraction. -/// -/// This is used by the [`ArcTan`](crate::bios::ArcTan) and -/// [`ArcTan2`](crate::bios::ArcTan2) BIOS functions. -#[allow(non_camel_case_types)] -pub type i16fx14 = Fixed; - -/// `i32` with 8 bits of fixed-point fraction. -/// -/// This is used by the background reference point entries. -#[allow(non_camel_case_types)] -pub type i32fx8 = Fixed; - -/// A [fixed-point][wp-fp] number. This transparently wraps an integer with a -/// const generic for how many bits are fractional. -/// -/// [wp-fp]: https://en.wikipedia.org/wiki/Fixed-point_arithmetic -/// -/// * This type is generic, but the `I` type is intended to be a signed or -/// unsigned integer of a fixed bit size: `i8`, `i16`, `i32`, `u8`, `u16`, or -/// `u32`. This type is *not* semver supported to work with any other `I` -/// type. If it does work for other types of `I`, that's on accident. -/// * The `B` value is the number of bits that form the fractional part. It -/// should be *less than* the number of bits in the integer's type. Multiply -/// and divide ops need to shift the value by `B`, and so if `B` is greater -/// than or equal to the integer's size the op will panic. -#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[repr(transparent)] -pub struct Fixed(I); - -macro_rules! impl_trait_op_unit { - ($t:ty, $trait:ident, $op:ident) => { - impl $trait for Fixed<$t, B> { - type Output = Self; - #[inline] - #[must_use] - #[cfg_attr(feature = "track_caller", track_caller)] - fn $op(self) -> Self::Output { - Self::$op(self) - } - } - }; -} -macro_rules! impl_trait_op_self_rhs { - ($t:ty, $trait:ident, $op:ident) => { - impl $trait for Fixed<$t, B> { - type Output = Self; - #[inline] - #[must_use] - #[cfg_attr(feature = "track_caller", track_caller)] - fn $op(self, rhs: Self) -> Self::Output { - Self::$op(self, rhs) - } - } - }; -} -macro_rules! impl_trait_op_assign_self_rhs { - ($t:ty, $trait:ident, $op:ident, $op_assign:ident) => { - impl $trait for Fixed<$t, B> { - #[inline] - #[cfg_attr(feature = "track_caller", track_caller)] - fn $op_assign(&mut self, rhs: Self) { - *self = self.$op(rhs); - } - } - }; -} -macro_rules! impl_shift_self_u32 { - ($t:ty, $trait:ident, $op:ident) => { - impl $trait for Fixed<$t, B> { - type Output = Self; - #[inline] - #[must_use] - #[cfg_attr(feature = "track_caller", track_caller)] - fn $op(self, rhs: u32) -> Self::Output { - Self::$op(self, rhs) - } - } - }; -} -macro_rules! impl_shift_assign_self_u32 { - ($t:ty, $trait:ident, $op:ident, $op_assign:ident) => { - impl $trait for Fixed<$t, B> { - #[inline] - #[cfg_attr(feature = "track_caller", track_caller)] - fn $op_assign(&mut self, rhs: u32) { - *self = self.$op(rhs); - } - } - }; -} - -macro_rules! impl_common_fixed_ops { - ($t:ty) => { - impl Fixed<$t, B> { - /// Shifts the value left by `B`, wrapping it into the range of this Fixed - /// type. - #[inline] - #[must_use] - #[cfg_attr(feature = "track_caller", track_caller)] - pub const fn wrapping_from(i: $t) -> Self { - Self(i << B) - } - - /// Makes a `Fixed` directly from a raw inner value (no shift). - #[inline] - #[must_use] - #[cfg_attr(feature = "track_caller", track_caller)] - pub const fn from_raw(i: $t) -> Self { - Self(i) - } - - /// Unwraps the inner value directly into the base type (no shift). - #[inline] - #[must_use] - #[cfg_attr(feature = "track_caller", track_caller)] - pub const fn into_raw(self) -> $t { - self.0 - } - - /// Bitwise Not. - #[inline] - #[must_use] - #[cfg_attr(feature = "track_caller", track_caller)] - pub const fn not(self) -> Self { - Self(!self.0) - } - - /// Addition. - #[inline] - #[must_use] - #[cfg_attr(feature = "track_caller", track_caller)] - pub const fn add(self, rhs: Self) -> Self { - Self(self.0 + rhs.0) - } - - /// Subtraction. - #[inline] - #[must_use] - #[cfg_attr(feature = "track_caller", track_caller)] - pub const fn sub(self, rhs: Self) -> Self { - Self(self.0 - rhs.0) - } - - /// Remainder. - #[inline] - #[must_use] - #[cfg_attr(feature = "track_caller", track_caller)] - pub const fn rem(self, rhs: Self) -> Self { - Self(self.0 % rhs.0) - } - - /// Bitwise AND. - #[inline] - #[must_use] - #[cfg_attr(feature = "track_caller", track_caller)] - pub const fn bitand(self, rhs: Self) -> Self { - Self(self.0 & rhs.0) - } - - /// Bitwise OR. - #[inline] - #[must_use] - #[cfg_attr(feature = "track_caller", track_caller)] - pub const fn bitor(self, rhs: Self) -> Self { - Self(self.0 | rhs.0) - } - - /// Bitwise XOR. - #[inline] - #[must_use] - #[cfg_attr(feature = "track_caller", track_caller)] - pub const fn bitxor(self, rhs: Self) -> Self { - Self(self.0 ^ rhs.0) - } - - /// Bit-shift Left. - #[inline] - #[must_use] - #[cfg_attr(feature = "track_caller", track_caller)] - pub const fn shl(self, rhs: u32) -> Self { - Self(self.0 << rhs) - } - - /// Bit-shift Right. - #[inline] - #[must_use] - #[cfg_attr(feature = "track_caller", track_caller)] - pub const fn shr(self, rhs: u32) -> Self { - Self(self.0 >> rhs) - } - } - impl_trait_op_unit!($t, Not, not); - impl_trait_op_self_rhs!($t, Add, add); - impl_trait_op_self_rhs!($t, Sub, sub); - impl_trait_op_self_rhs!($t, Mul, mul); - impl_trait_op_self_rhs!($t, Div, div); - impl_trait_op_self_rhs!($t, Rem, rem); - impl_trait_op_self_rhs!($t, BitAnd, bitand); - impl_trait_op_self_rhs!($t, BitOr, bitor); - impl_trait_op_self_rhs!($t, BitXor, bitxor); - impl_shift_self_u32!($t, Shl, shl); - impl_shift_self_u32!($t, Shr, shr); - impl_trait_op_assign_self_rhs!($t, AddAssign, add, add_assign); - impl_trait_op_assign_self_rhs!($t, SubAssign, sub, sub_assign); - impl_trait_op_assign_self_rhs!($t, MulAssign, mul, mul_assign); - impl_trait_op_assign_self_rhs!($t, DivAssign, div, div_assign); - impl_trait_op_assign_self_rhs!($t, RemAssign, rem, rem_assign); - impl_trait_op_assign_self_rhs!($t, BitAndAssign, bitand, bitand_assign); - impl_trait_op_assign_self_rhs!($t, BitOrAssign, bitor, bitor_assign); - impl_trait_op_assign_self_rhs!($t, BitXorAssign, bitxor, bitxor_assign); - impl_shift_assign_self_u32!($t, ShlAssign, shl, shl_assign); - impl_shift_assign_self_u32!($t, ShrAssign, shr, shr_assign); - }; -} -impl_common_fixed_ops!(i8); -impl_common_fixed_ops!(i16); -impl_common_fixed_ops!(i32); -impl_common_fixed_ops!(u8); -impl_common_fixed_ops!(u16); -impl_common_fixed_ops!(u32); - -macro_rules! impl_signed_fixed_ops { - ($t:ty, $unsigned:ty) => { - impl Fixed<$t, B> { - /// Negate. - #[inline] - #[must_use] - #[cfg_attr(feature = "track_caller", track_caller)] - pub const fn neg(self) -> Self { - Self(-self.0) - } - - /// If the number is negative or not. - #[inline] - #[must_use] - #[cfg_attr(feature = "track_caller", track_caller)] - pub const fn is_negative(self) -> bool { - self.0 < 0 - } - - /// Multiply. - #[inline] - #[must_use] - #[cfg_attr(feature = "track_caller", track_caller)] - pub const fn mul(self, rhs: Self) -> Self { - let raw = (self.0 as i32) * (rhs.0 as i32); - Self((raw >> B) as $t) - } - - /// Divide. - #[inline] - #[must_use] - #[cfg_attr(feature = "track_caller", track_caller)] - pub const fn div(self, rhs: Self) -> Self { - let m = (self.0 as i32) * (1 << B); - let d = m / (rhs.0 as i32); - Self(d as $t) - } - - /// Fractional part of the value. - #[inline] - #[must_use] - #[cfg_attr(feature = "track_caller", track_caller)] - pub const fn fract(self) -> Self { - let frac_mask = (<$unsigned>::MAX >> (<$t>::BITS - B)); - Self((self.0.unsigned_abs() & frac_mask) as $t) - } - - /// Whole part of the value. - #[inline] - #[must_use] - #[cfg_attr(feature = "track_caller", track_caller)] - pub const fn trunc(self) -> Self { - Self(((self.0.unsigned_abs() >> B) << B) as $t) - } - } - impl_trait_op_unit!($t, Neg, neg); - impl core::fmt::Debug for Fixed<$t, B> { - #[inline] - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - let whole: $t = self.trunc().into_raw() >> B; - let fract: $t = self.fract().into_raw(); - let divisor: $t = 1 << B; - if self.is_negative() { - let whole = whole.unsigned_abs(); - write!(f, "-({whole}+{fract}/{divisor})") - } else { - write!(f, "{whole}+{fract}/{divisor}") - } - } - } - }; -} -impl_signed_fixed_ops!(i8, u8); -impl_signed_fixed_ops!(i16, u16); -impl_signed_fixed_ops!(i32, u32); - -macro_rules! impl_unsigned_fixed_ops { - ($t:ty) => { - impl Fixed<$t, B> { - /// Multiply. - #[inline] - #[must_use] - #[cfg_attr(feature = "track_caller", track_caller)] - pub const fn mul(self, rhs: Self) -> Self { - let raw = (self.0 as u32) * (rhs.0 as u32); - Self((raw >> B) as $t) - } - - /// Divide. - #[inline] - #[must_use] - #[cfg_attr(feature = "track_caller", track_caller)] - pub const fn div(self, rhs: Self) -> Self { - let m = (self.0 as u32) * (1 << B); - let d = m / (rhs.0 as u32); - Self(d as $t) - } - - /// Fractional part of the value. - #[inline] - #[must_use] - #[cfg_attr(feature = "track_caller", track_caller)] - pub const fn fract(self) -> Self { - Self(self.0 & (<$t>::MAX >> (<$t>::BITS - B))) - } - - /// Whole part of the value. - #[inline] - #[must_use] - #[cfg_attr(feature = "track_caller", track_caller)] - pub const fn trunc(self) -> Self { - Self(self.0 & (<$t>::MAX << B)) - } - } - impl core::fmt::Debug for Fixed<$t, B> { - #[inline] - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - let whole: $t = self.trunc().into_raw() >> B; - let fract: $t = self.fract().into_raw(); - let divisor: $t = 1 << B; - write!(f, "{whole}+{fract}/{divisor}") - } - } - }; -} -impl_unsigned_fixed_ops!(u8); -impl_unsigned_fixed_ops!(u16); -impl_unsigned_fixed_ops!(u32); diff --git a/src/lib.rs b/src/lib.rs index 18370350..ebf0047b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,6 +62,7 @@ pub mod obj; pub mod panic_handlers; pub mod per_project_setup; pub mod per_system_setup; +pub mod random; pub mod sample_art; pub mod video; diff --git a/backup/random.rs b/src/random.rs similarity index 93% rename from backup/random.rs rename to src/random.rs index 83e7be2d..4b01eb8c 100644 --- a/backup/random.rs +++ b/src/random.rs @@ -1,6 +1,10 @@ -// Note(Lokathor): We have a generic LCG type below, but for now we can hide the -// process of having to pick what multiplier and increment to use behind a -// newtype that selects some default constants. +//! Randomization routines that will work well enough on the GBA. +//! +//! Randomization is basically about a trade off between time taken to produce +//! each next output and the quality of that output. Most modern randomization +//! libraries do 64-bit randomization and aim to be extremely unpredictable. +//! That's basically overkill on the GBA. The random generators here are 32-bit, +//! and they are relatively simple while maintaining reasonable output. /// A [Linear Congruential Generator][wp-lcg] with 32-bits of output. ///