diff --git a/CHANGELOG.md b/CHANGELOG.md index be54748..a8ed0cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ * **0.9.2:** * Adds support for more BIOS functions, though not all functions are as clearly documented as I'd like. + * Made much more of the `Fixed` type const friendly. Most ops now have an + inherent method that is `const fn` as well as implementing the `core::ops` + trait (the trait fn just calls the inherent fn). This means that you can't + do `x + y` in a const context, but you can do `x.add(y)`. This is not the + best system, but until const trait impls are stable this is the best middle + ground. * **0.9.1:** * Adds some randomization support directly into the crate. * Added more methods to the `Fixed` type. diff --git a/src/bios.rs b/src/bios.rs index 407fea5..0980bdd 100644 --- a/src/bios.rs +++ b/src/bios.rs @@ -8,11 +8,31 @@ //! of the function ends up inlined). Despite this higher cost, some bios //! functions are useful enough to justify the overhead. -use crate::interrupts::IrqBits; +use crate::{fixed::i16fx14, interrupts::IrqBits}; // Note(Lokathor): All `swi` calls will preserve the flags. You should generally // not use any other inline-asm options with `swi` calls. +/// `0x00`: Software Reset. +/// +/// This clears the BIOS portion of IWRAM (the top `0x200` bytes), resets the +/// SVC, IRQ, and SYS stack pointers to their defaults, then performs a `bx r14` +/// to go to an address based on what's written to the byte at `0x0300_7FFA`: +/// * zero: `0x0800_0000` (ROM) +/// * non-zero: `0x0200_0000` (IWRAM). +/// +/// (Note: the target address is determined *before* clearing the top of IWRAM.) +#[inline] +#[instruction_set(arm::t32)] +pub fn SoftReset() -> ! { + unsafe { + core::arch::asm! { + "swi #0x00", + options(noreturn), + } + }; +} + /// `0x04`: Waits for a specific interrupt type(s) to happen. /// /// Pauses the CPU until any of the interrupt types set in `target_irqs` to @@ -62,6 +82,50 @@ pub fn VBlankIntrWait() { }; } +/// `0x09`: Arc tangent. +/// +/// * **Returns:** The output is in the range +/- `pi/2`, but accuracy is worse +/// outside of +/- `pi/4`. +#[inline] +#[instruction_set(arm::t32)] +pub fn ArcTan(theta: i16fx14) -> i16fx14 { + let mut i = theta.into_raw(); + unsafe { + core::arch::asm! { + "swi #0x09", + inout("r0") i, + out("r1") _, + out("r3") _, + options(pure, nomem, preserves_flags), + } + }; + i16fx14::from_raw(i) +} + +/// `0x0A`: The "2-argument arctangent" ([atan2][wp-atan2]). +/// +/// [wp-atan2]: https://en.wikipedia.org/wiki/Atan2 +/// +/// * **Returns:** The angle of the input vector, with `u16::MAX` being +/// equivalent to `2pi`. +#[inline] +#[instruction_set(arm::t32)] +pub fn ArcTan2(x: i16fx14, y: i16fx14) -> u16 { + let x = x.into_raw(); + let y = y.into_raw(); + let output: u16; + unsafe { + core::arch::asm! { + "swi #0x0A", + inout("r0") x => output, + inout("r1") y => _, + out("r3") _, + options(pure, nomem, preserves_flags), + } + }; + output +} + /// Used to provide info to a call of the [`BitUnPack`] function. #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] diff --git a/src/fixed.rs b/src/fixed.rs index 4906e01..04e5dd4 100644 --- a/src/fixed.rs +++ b/src/fixed.rs @@ -6,6 +6,12 @@ use core::ops::*; #[allow(non_camel_case_types)] pub type i16fx8 = Fixed; +/// `i16` with 14 bits of fixed-point fraction. +/// +/// This is used by the [`ArcTan`] and [`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.