mirror of
https://github.com/italicsjenga/rp-hal-boards.git
synced 2025-01-23 01:36:35 +11:00
Merge pull request #165 from 42-technology-ltd/bootrom_functions_update
Bootrom functions update
This commit is contained in:
commit
dd4a9a8f22
2 changed files with 526 additions and 221 deletions
189
rp2040-hal/examples/rom_funcs.rs
Normal file
189
rp2040-hal/examples/rom_funcs.rs
Normal file
|
@ -0,0 +1,189 @@
|
|||
//! # 'ROM Functions' Example
|
||||
//!
|
||||
//! This application demonstrates how to call functions in the RP2040's boot ROM.
|
||||
//!
|
||||
//! It may need to be adapted to your particular board layout and/or pin assignment.
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
// The macro for our start-up function
|
||||
use cortex_m_rt::entry;
|
||||
|
||||
// Ensure we halt the program on panic (if we don't mention this crate it won't
|
||||
// be linked)
|
||||
use panic_halt as _;
|
||||
|
||||
// Alias for our HAL crate
|
||||
use rp2040_hal as hal;
|
||||
|
||||
// A shorter alias for the Peripheral Access Crate, which provides low-level
|
||||
// register access
|
||||
use hal::pac;
|
||||
|
||||
// Some traits we need
|
||||
use core::fmt::Write;
|
||||
|
||||
/// The linker will place this boot block at the start of our program image. We
|
||||
// need this to help the ROM bootloader get our code up and running.
|
||||
#[link_section = ".boot2"]
|
||||
#[used]
|
||||
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER;
|
||||
|
||||
/// External high-speed crystal on the Raspberry Pi Pico board is 12 MHz. Adjust
|
||||
/// if your board has a different frequency
|
||||
const XTAL_FREQ_HZ: u32 = 12_000_000u32;
|
||||
|
||||
/// Our Cortex-M systick goes from this value down to zero. For our timer maths
|
||||
/// to work, this value must be of the form `2**N - 1`.
|
||||
const SYSTICK_RELOAD: u32 = 0x00FF_FFFF;
|
||||
|
||||
/// Entry point to our bare-metal application.
|
||||
///
|
||||
/// The `#[entry]` macro ensures the Cortex-M start-up code calls this function
|
||||
/// as soon as all global variables are initialised.
|
||||
///
|
||||
/// The function configures the RP2040 peripherals, then writes to the UART in
|
||||
/// an inifinite loop.
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
// Grab our singleton objects
|
||||
let mut pac = pac::Peripherals::take().unwrap();
|
||||
let mut core = pac::CorePeripherals::take().unwrap();
|
||||
|
||||
// Set up the watchdog driver - needed by the clock setup code
|
||||
let mut watchdog = hal::watchdog::Watchdog::new(pac.WATCHDOG);
|
||||
|
||||
// Configure the clocks
|
||||
let clocks = hal::clocks::init_clocks_and_plls(
|
||||
XTAL_FREQ_HZ,
|
||||
pac.XOSC,
|
||||
pac.CLOCKS,
|
||||
pac.PLL_SYS,
|
||||
pac.PLL_USB,
|
||||
&mut pac.RESETS,
|
||||
&mut watchdog,
|
||||
)
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
// The single-cycle I/O block controls our GPIO pins
|
||||
let sio = hal::sio::Sio::new(pac.SIO);
|
||||
|
||||
// Set the pins to their default state
|
||||
let pins = hal::gpio::Pins::new(
|
||||
pac.IO_BANK0,
|
||||
pac.PADS_BANK0,
|
||||
sio.gpio_bank0,
|
||||
&mut pac.RESETS,
|
||||
);
|
||||
|
||||
let mut uart = hal::uart::UartPeripheral::<_, _>::enable(
|
||||
pac.UART0,
|
||||
&mut pac.RESETS,
|
||||
hal::uart::common_configs::_9600_8_N_1,
|
||||
clocks.peripheral_clock.into(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// UART TX (characters sent from RP2040) on pin 1 (GPIO0)
|
||||
let _tx_pin = pins.gpio0.into_mode::<hal::gpio::FunctionUart>();
|
||||
// UART RX (characters reveived by RP2040) on pin 2 (GPIO1)
|
||||
let _rx_pin = pins.gpio1.into_mode::<hal::gpio::FunctionUart>();
|
||||
|
||||
writeln!(uart, "ROM Copyright: {}", hal::rom_data::copyright_string()).unwrap();
|
||||
writeln!(
|
||||
uart,
|
||||
"ROM Git Revision: 0x{:x}",
|
||||
hal::rom_data::git_revision()
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Some ROM functions are exported directly, so we can just call them
|
||||
writeln!(
|
||||
uart,
|
||||
"popcount32(0xF000_0001) = {}",
|
||||
hal::rom_data::popcount32(0xF000_0001)
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Try to hide the numbers from the compiler so it is forced to do the maths
|
||||
let x = hal::rom_data::popcount32(0xFF) as f32; // 8
|
||||
let y = hal::rom_data::popcount32(0xFFF) as f32; // 12
|
||||
|
||||
// Use systick as a count-down timer
|
||||
core.SYST.set_reload(SYSTICK_RELOAD);
|
||||
core.SYST.clear_current();
|
||||
core.SYST.enable_counter();
|
||||
|
||||
// Do some simple sums
|
||||
let start_soft = cortex_m::peripheral::SYST::get_current();
|
||||
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
let soft_result = x * y;
|
||||
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
let end_soft = cortex_m::peripheral::SYST::get_current();
|
||||
|
||||
writeln!(
|
||||
uart,
|
||||
"{} x {} = {} in {} systicks (doing soft-float maths)",
|
||||
x,
|
||||
y,
|
||||
soft_result,
|
||||
calc_delta(start_soft, end_soft)
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Some functions require a look-up in a table. First we do the lookup and
|
||||
// find the function pointer in ROM (you only want to do this once per
|
||||
// function).
|
||||
let fmul = hal::rom_data::float_funcs::fmul();
|
||||
|
||||
// Then we can call the function whenever we want
|
||||
let start_rom = cortex_m::peripheral::SYST::get_current();
|
||||
let rom_result = fmul(x, y);
|
||||
let end_rom = cortex_m::peripheral::SYST::get_current();
|
||||
|
||||
writeln!(
|
||||
uart,
|
||||
"{} x {} = {} in {} systicks (using the ROM)",
|
||||
x,
|
||||
y,
|
||||
rom_result,
|
||||
calc_delta(start_rom, end_rom)
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Now just spin (whilst the UART does its thing)
|
||||
for _ in 0..1_000_000 {
|
||||
cortex_m::asm::nop();
|
||||
}
|
||||
|
||||
// Reboot back into USB mode (no activity, both interfaces enabled)
|
||||
rp2040_hal::rom_data::reset_to_usb_boot(0, 0);
|
||||
|
||||
// In case the reboot fails
|
||||
loop {
|
||||
cortex_m::asm::nop();
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate the number of systicks elapsed between two counter readings.
|
||||
///
|
||||
/// Note: SYSTICK starts at `SYSTICK_RELOAD` and counts down towards zero, so
|
||||
/// these comparisons might appear to be backwards.
|
||||
///
|
||||
/// ```
|
||||
/// assert_eq!(1, calc_delta(SYSTICK_RELOAD, SYSTICK_RELOAD - 1));
|
||||
/// assert_eq!(2, calc_delta(0, SYSTICK_RELOAD - 1));
|
||||
//// ```
|
||||
fn calc_delta(start: u32, end: u32) -> u32 {
|
||||
if start < end {
|
||||
(start.wrapping_sub(end)) & SYSTICK_RELOAD
|
||||
} else {
|
||||
start - end
|
||||
}
|
||||
}
|
||||
|
||||
// End of file
|
|
@ -1,4 +1,12 @@
|
|||
//! Functions and data from the RPI Bootrom.
|
||||
//!
|
||||
//! From the [RP2040 datasheet](https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf), Section 2.8.2.1:
|
||||
//!
|
||||
//! > The Bootrom contains a number of public functions that provide useful
|
||||
//! > RP2040 functionality that might be needed in the absence of any other code
|
||||
//! > on the device, as well as highly optimized versions of certain key
|
||||
//! > functionality that would otherwise have to take up space in most user
|
||||
//! > binaries.
|
||||
|
||||
/// A bootrom function table code.
|
||||
pub type RomFnTableCode = [u8; 2];
|
||||
|
@ -6,15 +14,15 @@ pub type RomFnTableCode = [u8; 2];
|
|||
/// This function searches for (table)
|
||||
type RomTableLookupFn<T> = unsafe extern "C" fn(*const u16, u32) -> T;
|
||||
|
||||
/// The following addresses are described at `2.8.3. Bootrom Contents`
|
||||
/// The following addresses are described at `2.8.2. Bootrom Contents`
|
||||
/// Pointer to the lookup table function supplied by the rom.
|
||||
const ROM_TABLE_LOOKUP_PTR: *const u16 = 0x18 as _;
|
||||
const ROM_TABLE_LOOKUP_PTR: *const u16 = 0x0000_0018 as _;
|
||||
|
||||
/// Pointer to helper functions lookup table.
|
||||
const FUNC_TABLE: *const u16 = 0x14 as _;
|
||||
const FUNC_TABLE: *const u16 = 0x0000_0014 as _;
|
||||
|
||||
/// Pointer to the public data lookup table.
|
||||
const DATA_TABLE: *const u16 = 0x16 as _;
|
||||
const DATA_TABLE: *const u16 = 0x0000_0016 as _;
|
||||
|
||||
/// Retrive rom content from a table using a code.
|
||||
fn rom_table_lookup<T>(table: *const u16, tag: RomFnTableCode) -> T {
|
||||
|
@ -28,6 +36,12 @@ fn rom_table_lookup<T>(table: *const u16, tag: RomFnTableCode) -> T {
|
|||
}
|
||||
}
|
||||
|
||||
/// To save space, the ROM likes to store memory pointers (which are 32-bit on
|
||||
/// the Cortex-M0+) using only the bottom 16-bits. The assumption is that the
|
||||
/// values they point at live in the first 64 KiB of ROM, and the ROM is mapped
|
||||
/// to address `0x0000_0000` and so 16-bits are always sufficient.
|
||||
///
|
||||
/// This functions grabs a 16-bit value from ROM and expands it out to a full 32-bit pointer.
|
||||
unsafe fn rom_hword_as_ptr(rom_address: *const u16) -> *const u32 {
|
||||
let ptr: u16 = *rom_address;
|
||||
ptr as *const u32
|
||||
|
@ -101,8 +115,10 @@ rom_funcs_unsafe! {
|
|||
/// Sets n bytes start at ptr to the value c and returns ptr
|
||||
b"MS" memset(ptr: *mut u8, c: u8, n: u8) -> *mut u8;
|
||||
|
||||
/// Sets n bytes start at ptr to the value c and returns ptr. Note this is a slightly more
|
||||
/// efficient variant of _memset that may only be used if ptr is word aligned.
|
||||
/// Sets n bytes start at ptr to the value c and returns ptr.
|
||||
///
|
||||
/// Note this is a slightly more efficient variant of _memset that may only
|
||||
/// be used if ptr is word aligned.
|
||||
b"M4" memset4(ptr: *mut u32, c: u8, n: u32) -> *mut u32;
|
||||
|
||||
/// Copies n bytes starting at src to dest and returns dest. The results are undefined if the
|
||||
|
@ -110,7 +126,9 @@ rom_funcs_unsafe! {
|
|||
b"MC" memcpy(dest: *mut u8, src: *mut u8, n: u32) -> u8;
|
||||
|
||||
/// Copies n bytes starting at src to dest and returns dest. The results are undefined if the
|
||||
/// regions overlap. Note this is a slightly more efficient variant of _memcpy that may only be
|
||||
/// regions overlap.
|
||||
///
|
||||
/// Note this is a slightly more efficient variant of _memcpy that may only be
|
||||
/// used if dest and src are word aligned.
|
||||
b"C4" memcpy44(dest: *mut u32, src: *mut u32, n: u32) -> *mut u8;
|
||||
|
||||
|
@ -118,6 +136,7 @@ rom_funcs_unsafe! {
|
|||
b"IF" connect_internal_flash() -> ();
|
||||
|
||||
/// First set up the SSI for serial-mode operations, then issue the fixed XIP exit sequence.
|
||||
///
|
||||
/// Note that the bootrom code uses the IO forcing logic to drive the CS pin, which must be
|
||||
/// cleared before returning the SSI to XIP mode (e.g. by a call to _flash_flush_cache). This
|
||||
/// function configures the SSI with a fixed SCK clock divisor of /6.
|
||||
|
@ -130,8 +149,9 @@ rom_funcs_unsafe! {
|
|||
/// 4096 bytes.
|
||||
b"RE" flash_range_erase(addr: u32, count: usize, block_size: u32, block_cmd: u8) -> ();
|
||||
|
||||
/// Program data to a range of flash addresses starting at addr (offset from the start of flash)
|
||||
/// and count bytesin size. addr must be aligned to a 256-byte boundary, and count must be a
|
||||
/// Program data to a range of flash addresses starting at `addr` (and
|
||||
/// offset from the start of flash) and `count` bytes in size. The value
|
||||
/// `addr` must be aligned to a 256-byte boundary, and `count` must be a
|
||||
/// multiple of 256.
|
||||
b"RP" flash_range_program(addr: u32, data: *const u8, count: usize) -> ();
|
||||
|
||||
|
@ -173,15 +193,17 @@ pub fn git_revision() -> u32 {
|
|||
unsafe { *s }
|
||||
}
|
||||
|
||||
/// The start address of the floating point library code and data. This and fplib_end along with the individual
|
||||
/// function pointers in soft_float_table can be used to copy the floating point implementation into RAM if
|
||||
/// desired.
|
||||
/// The start address of the floating point library code and data.
|
||||
///
|
||||
/// This and fplib_end along with the individual function pointers in
|
||||
/// soft_float_table can be used to copy the floating point implementation into
|
||||
/// RAM if desired.
|
||||
pub fn fplib_start() -> *const u8 {
|
||||
rom_table_lookup(DATA_TABLE, *b"FS")
|
||||
}
|
||||
|
||||
/// See Table 181 for the contents of this table.
|
||||
pub fn soft_float_table() -> *const u16 {
|
||||
/// See Table 180 in the RP2040 datasheet for the contents of this table.
|
||||
pub fn soft_float_table() -> *const usize {
|
||||
rom_table_lookup(DATA_TABLE, *b"SF")
|
||||
}
|
||||
|
||||
|
@ -190,12 +212,15 @@ pub fn fplib_end() -> *const u8 {
|
|||
rom_table_lookup(DATA_TABLE, *b"FE")
|
||||
}
|
||||
|
||||
/// This entry is only present in the V2 bootrom. See Table 182 for the contents of this table.
|
||||
pub fn soft_double_table() -> *const u16 {
|
||||
/// This entry is only present in the V2 bootrom. See Table 182 in the RP2040 datasheet for the contents of this table.
|
||||
pub fn soft_double_table() -> *const usize {
|
||||
rom_table_lookup(DATA_TABLE, *b"SD")
|
||||
}
|
||||
|
||||
macro_rules! float_funcs {
|
||||
/// ROM functions using single-precision arithmetic (i.e. 'f32' in Rust terms)
|
||||
pub mod float_funcs {
|
||||
|
||||
macro_rules! make_functions {
|
||||
(
|
||||
$(
|
||||
$(#[$outer:meta])*
|
||||
|
@ -207,106 +232,149 @@ macro_rules! float_funcs {
|
|||
$(
|
||||
$(#[$outer])*
|
||||
pub fn $name() -> extern "C" fn( $( $aname : $aty ),* ) -> $ret {
|
||||
let table: *const *const u16 = rom_table_lookup(DATA_TABLE, *b"SF");
|
||||
let table: *const usize = $crate::rom_data::soft_float_table() as *const usize;
|
||||
unsafe {
|
||||
core::mem::transmute_copy(&table.add($offset))
|
||||
// This is the entry in the table. Our offset is given as a
|
||||
// byte offset, but we want the table index (each pointer in
|
||||
// the table is 4 bytes long)
|
||||
let entry: *const usize = table.offset($offset / 4);
|
||||
// Read the pointer from the table
|
||||
let ptr: usize = core::ptr::read(entry);
|
||||
// Convert the pointer we read into a function
|
||||
core::mem::transmute_copy(&ptr)
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float_funcs! {
|
||||
/// Return a + b.
|
||||
make_functions! {
|
||||
/// Returns a function that will calculate `a + b`
|
||||
0x00 fadd(a: f32, b: f32) -> f32;
|
||||
/// Return a - b.
|
||||
/// Returns a function that will calculate `a - b`
|
||||
0x04 fsub(a: f32, b: f32) -> f32;
|
||||
/// Return a * b.
|
||||
/// Returns a function that will calculate `a * b`
|
||||
0x08 fmul(a: f32, b: f32) -> f32;
|
||||
/// Return a / b.
|
||||
/// Returns a function that will calculate `a / b`
|
||||
0x0c fdiv(a: f32, b: f32) -> f32;
|
||||
/// Return the square root of v or -INFINITY if v is negative.
|
||||
|
||||
// 0x10 and 0x14 are deprecated
|
||||
|
||||
/// Returns a function that will calculate `sqrt(v)` (or return -Infinity if v is negative)
|
||||
0x18 fsqrt(v: f32) -> f32;
|
||||
/// Convert a float to a signed integer, rounding towards -INFINITY, and clamping the result
|
||||
/// to lie within the range -0x80000000 to 0x7FFFFFFF.
|
||||
/// Returns a function that will convert an f32 to a signed integer,
|
||||
/// rounding towards -Infinity, and clamping the result to lie within the
|
||||
/// range `-0x80000000` to `0x7FFFFFFF`
|
||||
0x1c float_to_int(v: f32) -> i32;
|
||||
/// Convert a float to a signed fixed point integer reprsentation where n specifies the
|
||||
/// position of the binary point in the resulting fixed point representation. e.g.
|
||||
/// float_to_fix(0.5, 16) == 0x8000. This method rounds towards -INFINITY, and clamps
|
||||
/// the resulting integer to lie within the range -800000000 to 0x7FFFFFFF.
|
||||
/// Returns a function that will convert an f32 to an signed fixed point
|
||||
/// integer representation where n specifies the position of the binary
|
||||
/// point in the resulting fixed point representation, e.g.
|
||||
/// `f(0.5f, 16) == 0x8000`. This method rounds towards -Infinity,
|
||||
/// and clamps the resulting integer to lie within the range `0x00000000` to
|
||||
/// `0xFFFFFFFF`
|
||||
0x20 float_to_fix(v: f32, n: i32) -> i32;
|
||||
/// Convert a float to an unsigned integer, rounding towards -INFINITY, and clamping the result
|
||||
/// to lie within the range 0x00000000 to 0xFFFFFFFF
|
||||
/// Returns a function that will convert an f32 to an unsigned integer,
|
||||
/// rounding towards -Infinity, and clamping the result to lie within the
|
||||
/// range `0x00000000` to `0xFFFFFFFF`
|
||||
0x24 float_to_uint(v: f32) -> u32;
|
||||
/// Convert a float to an unsigned fixed point integer representation where n specifies the
|
||||
/// position of the binary point in the resulting fixed point representation, e.g.
|
||||
/// float_to_ufix(0.5f, 16) == 0x8000. This method rounds towards -Infinity, and clamps the
|
||||
/// resulting integer to lie within the range 0x00000000 to 0xFFFFFFFF.
|
||||
/// Returns a function that will convert an f32 to an unsigned fixed point
|
||||
/// integer representation where n specifies the position of the binary
|
||||
/// point in the resulting fixed point representation, e.g.
|
||||
/// `f(0.5f, 16) == 0x8000`. This method rounds towards -Infinity,
|
||||
/// and clamps the resulting integer to lie within the range `0x00000000` to
|
||||
/// `0xFFFFFFFF`
|
||||
0x28 float_to_ufix(v: f32, n: i32) -> u32;
|
||||
/// Convert a signed integer to the nearest float value, rounding to even on tie.
|
||||
/// Returns a function that will convert a signed integer to the nearest
|
||||
/// f32 value, rounding to even on tie
|
||||
0x2c int_to_float(v: i32) -> f32;
|
||||
/// Convert a signed fixed point integer representation to the nearest float value, rounding
|
||||
/// to even on tie. n specifies the position of the binary point in fixed point, so
|
||||
/// f = nearest(v/2^n).
|
||||
/// Returns a function that will convert a signed fixed point integer
|
||||
/// representation to the nearest f32 value, rounding to even on tie. `n`
|
||||
/// specifies the position of the binary point in fixed point, so `f =
|
||||
/// nearest(v/(2^n))`
|
||||
0x30 fix_to_float(v: i32, n: i32) -> f32;
|
||||
/// Convert an unsigned integer to the nearest float value, rounding to even on tie.
|
||||
/// Returns a function that will convert an unsigned integer to the nearest
|
||||
/// f32 value, rounding to even on tie
|
||||
0x34 uint_to_float(v: u32) -> f32;
|
||||
/// Convert a unsigned fixed point integer representation to the nearest float value, rounding
|
||||
/// to even on tie. n specifies the position of the binary point in fixed point, so
|
||||
/// f = nearest(v/2^n).
|
||||
/// Returns a function that will convert an unsigned fixed point integer
|
||||
/// representation to the nearest f32 value, rounding to even on tie. `n`
|
||||
/// specifies the position of the binary point in fixed point, so `f =
|
||||
/// nearest(v/(2^n))`
|
||||
0x38 ufix_to_float(v: u32, n: i32) -> f32;
|
||||
/// Return the cosine of angle. angle is in radians, and must be in the range -128 to 128.
|
||||
/// Returns a function that will calculate the cosine of `angle`. The value
|
||||
/// of `angle` is in radians, and must be in the range `-1024` to `1024`
|
||||
0x3c fcos(angle: f32) -> f32;
|
||||
/// Return the sine of angle. angle is in radians, and must be in the range -128 to 128.
|
||||
/// Returns a function that will calculate the sine of `angle`. The value of
|
||||
/// `angle` is in radians, and must be in the range `-1024` to `1024`
|
||||
0x40 fsin(angle: f32) -> f32;
|
||||
/// Return the tangent of angle. angle is in radians, and must be in the range -128 to 128.
|
||||
/// Returns a function that will calculate the tangent of `angle`. The value
|
||||
/// of `angle` is in radians, and must be in the range `-1024` to `1024`
|
||||
0x44 ftan(angle: f32) -> f32;
|
||||
/// Return the exponential value of v, i.e. so e^v.
|
||||
|
||||
// 0x48 is deprecated
|
||||
|
||||
/// Returns a function that will calculate the exponential value of `v`,
|
||||
/// i.e. `e ** v`
|
||||
0x4c fexp(v: f32) -> f32;
|
||||
/// Return the natural logarithm of v. If v <= 0 return -Infinity.
|
||||
/// Returns a function that will calculate the natural logarithm of `v`. If `v <= 0` return -Infinity
|
||||
0x50 fln(v: f32) -> f32;
|
||||
/// Compares two floating point numbers, returning:
|
||||
/// * 0 if a == b
|
||||
/// * -1 if a < b
|
||||
/// * 1 if a > b
|
||||
|
||||
// These are only on BootROM v2 or higher
|
||||
|
||||
/// Returns a function that will compare two floating point numbers, returning:
|
||||
/// • 0 if a == b
|
||||
/// • -1 if a < b
|
||||
/// • 1 if a > b
|
||||
0x54 fcmp(a: f32, b: f32) -> i32;
|
||||
/// Computes the arc tangent of y/x using the signs of arguments to determine the correct quadrant.
|
||||
/// Returns a function that will compute the arc tangent of `y/x` using the
|
||||
/// signs of arguments to determine the correct quadrant
|
||||
0x58 fatan2(y: f32, x: f32) -> f32;
|
||||
/// Convert a signed 64-bit integer to the nearest float value, rounding to even on tie.
|
||||
/// Returns a function that will convert a signed 64-bit integer to the
|
||||
/// nearest f32 value, rounding to even on tie
|
||||
0x5c int64_to_float(v: i64) -> f32;
|
||||
/// Convert a signed fixed point integer representation to the nearest float value, rounding
|
||||
/// to even on tie. n specifies the position of the binary point in fixed point, so
|
||||
/// f = nearest(v/2^n).
|
||||
/// Returns a function that will convert a signed fixed point 64-bit integer
|
||||
/// representation to the nearest f32 value, rounding to even on tie. `n`
|
||||
/// specifies the position of the binary point in fixed point, so `f =
|
||||
/// nearest(v/(2^n))`
|
||||
0x60 fix64_to_float(v: i64, n: i32) -> f32;
|
||||
/// Convert an unsigned 64-bit integer to the nearest float value, rounding to even on tie.
|
||||
/// Returns a function that will convert an unsigned 64-bit integer to the
|
||||
/// nearest f32 value, rounding to even on tie
|
||||
0x64 uint64_to_float(v: u64) -> f32;
|
||||
/// Convert an unsigned fixed point integer representation to the nearest float value, rounding
|
||||
/// to even on tie. n specifies the position of the binary point in fixed point, so
|
||||
/// f = nearest(v/2^n).
|
||||
/// Returns a function that will convert an unsigned fixed point 64-bit
|
||||
/// integer representation to the nearest f32 value, rounding to even on
|
||||
/// tie. `n` specifies the position of the binary point in fixed point, so
|
||||
/// `f = nearest(v/(2^n))`
|
||||
0x68 ufix64_to_float(v: u64, n: i32) -> f32;
|
||||
/// Convert a float to a signed 64-bit integer, rounding towards -Infinity, and clamping
|
||||
/// the result to lie within the range -0x8000000000000000 to 0x7FFFFFFFFFFFFFFF
|
||||
/// Convert an f32 to a signed 64-bit integer, rounding towards -Infinity,
|
||||
/// and clamping the result to lie within the range `-0x8000000000000000` to
|
||||
/// `0x7FFFFFFFFFFFFFFF`
|
||||
0x6c float_to_int64(v: f32) -> i64;
|
||||
/// Convert a float to a signed fixed point 64-bit integer representation where n
|
||||
/// specifies the position of the binary point in the resulting fixed point representation -
|
||||
/// e.g. _float2fix(0.5f, 16) == 0x8000. This method rounds towards -Infinity, and
|
||||
/// clamps the resulting integer to lie within the range -0x8000000000000000 to
|
||||
/// 0x7FFFFFFFFFFFFFF
|
||||
/// Returns a function that will convert an f32 to a signed fixed point
|
||||
/// 64-bit integer representation where n specifies the position of the
|
||||
/// binary point in the resulting fixed point representation - e.g. `f(0.5f,
|
||||
/// 16) == 0x8000`. This method rounds towards -Infinity, and clamps the
|
||||
/// resulting integer to lie within the range `-0x8000000000000000` to
|
||||
/// `0x7FFFFFFFFFFFFFFF`
|
||||
0x70 float_to_fix64(v: f32, n: i32) -> f32;
|
||||
/// Convert a float to an unsigned 64-bit integer, rounding towards -Infinity, and
|
||||
/// clamping the result to lie within the range 0x0000000000000000 to 0xFFFFFFFFFFFFFFFF
|
||||
/// Returns a function that will convert an f32 to an unsigned 64-bit
|
||||
/// integer, rounding towards -Infinity, and clamping the result to lie
|
||||
/// within the range `0x0000000000000000` to `0xFFFFFFFFFFFFFFFF`
|
||||
0x74 float_to_uint64(v: f32) -> u64;
|
||||
/// Convert a float to an unsigned fixed point 64-bit integer representation where n
|
||||
/// specifies the position of the binary point in the resulting fixed point representation,
|
||||
/// e.g. _float2ufix(0.5f, 16) == 0x8000. This method rounds towards -Infinity, and
|
||||
/// clamps the resulting integer to lie within the range 0x0000000000000000 to
|
||||
/// 0xFFFFFFFFFFFFFFFF
|
||||
/// 0x78 float_to_ufix64(v: f32, n: i32) -> u64;
|
||||
/// Converts a float to a double.
|
||||
/// Returns a function that will convert an f32 to an unsigned fixed point
|
||||
/// 64-bit integer representation where n specifies the position of the
|
||||
/// binary point in the resulting fixed point representation, e.g. `f(0.5f,
|
||||
/// 16) == 0x8000`. This method rounds towards -Infinity, and clamps the
|
||||
/// resulting integer to lie within the range `0x0000000000000000` to
|
||||
/// `0xFFFFFFFFFFFFFFFF`
|
||||
0x78 float_to_ufix64(v: f32, n: i32) -> u64;
|
||||
/// Converts an f32 to an f64.
|
||||
0x7c float_to_double(v: f32) -> f64;
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! double_funcs {
|
||||
/// Functions using double-precision arithmetic (i.e. 'f64' in Rust terms)
|
||||
pub mod double_funcs {
|
||||
|
||||
macro_rules! make_double_funcs {
|
||||
(
|
||||
$(
|
||||
$(#[$outer:meta])*
|
||||
|
@ -318,93 +386,141 @@ macro_rules! double_funcs {
|
|||
$(
|
||||
$(#[$outer])*
|
||||
pub fn $name() -> extern "C" fn( $( $aname : $aty ),* ) -> $ret {
|
||||
let table: *const *const u16 = rom_table_lookup(DATA_TABLE, *b"SD");
|
||||
let table: *const usize = $crate::rom_data::soft_double_table() as *const usize;
|
||||
unsafe {
|
||||
core::mem::transmute_copy(&table.add($offset))
|
||||
// This is the entry in the table. Our offset is given as a
|
||||
// byte offset, but we want the table index (each pointer in
|
||||
// the table is 4 bytes long)
|
||||
let entry: *const usize = table.offset($offset / 4);
|
||||
// Read the pointer from the table
|
||||
let ptr: usize = core::ptr::read(entry);
|
||||
// Convert the pointer we read into a function
|
||||
core::mem::transmute_copy(&ptr)
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double_funcs! {
|
||||
/// Return a + b
|
||||
make_double_funcs! {
|
||||
/// Returns a function that will calculate `a + b`
|
||||
0x00 dadd(a: f64, b: f64) -> f64;
|
||||
/// Return a - b
|
||||
/// Returns a function that will calculate `a - b`
|
||||
0x04 dsub(a: f64, b: f64) -> f64;
|
||||
/// Return a * b
|
||||
/// Returns a function that will calculate `a * b`
|
||||
0x08 dmul(a: f64, b: f64) -> f64;
|
||||
/// Return a / b
|
||||
/// Returns a function that will calculate `a / b`
|
||||
0x0c ddiv(a: f64, b: f64) -> f64;
|
||||
/// Return sqrt(v) or -Infinity if v is negative
|
||||
|
||||
// 0x10 and 0x14 are deprecated
|
||||
|
||||
/// Returns a function that will calculate `sqrt(v)` (or return -Infinity if v is negative)
|
||||
0x18 dsqrt(v: f64) -> f64;
|
||||
/// Convert a double to a signed integer, rounding towards -Infinity, and clamping the result to lie
|
||||
/// within the range -0x80000000 to 0x7FFFFFFF
|
||||
/// Returns a function that will convert an f64 to a signed integer,
|
||||
/// rounding towards -Infinity, and clamping the result to lie within the
|
||||
/// range `-0x80000000` to `0x7FFFFFFF`
|
||||
0x1c double_to_int(v: f64) -> i32;
|
||||
/// Convert a double to an unsigned fixed point integer representation where n specifies the
|
||||
/// position of the binary point in the resulting fixed point representation, e.g. _double2ufix(0.5f,
|
||||
/// 16) == 0x8000. This method rounds towards -Infinity, and clamps the resulting integer to lie
|
||||
/// within the range 0x00000000 to 0xFFFFFFFF
|
||||
/// Returns a function that will convert an f64 to an signed fixed point
|
||||
/// integer representation where n specifies the position of the binary
|
||||
/// point in the resulting fixed point representation, e.g.
|
||||
/// `f(0.5f, 16) == 0x8000`. This method rounds towards -Infinity,
|
||||
/// and clamps the resulting integer to lie within the range `0x00000000` to
|
||||
/// `0xFFFFFFFF`
|
||||
0x20 double_to_fix(v: f64, n: i32) -> i32;
|
||||
/// Convert a double to an unsigned integer, rounding towards -Infinity, and clamping the result
|
||||
/// to lie within the range 0x00000000 to 0xFFFFFFFF 0x24 double_to_uint(v: f64) -> u32;
|
||||
/// Returns a function that will convert an f64 to an unsigned integer,
|
||||
/// rounding towards -Infinity, and clamping the result to lie within the
|
||||
/// range `0x00000000` to `0xFFFFFFFF`
|
||||
0x24 double_to_uint(v: f64) -> u32;
|
||||
/// Returns a function that will convert an f64 to an unsigned fixed point
|
||||
/// integer representation where n specifies the position of the binary
|
||||
/// point in the resulting fixed point representation, e.g.
|
||||
/// `f(0.5f, 16) == 0x8000`. This method rounds towards -Infinity,
|
||||
/// and clamps the resulting integer to lie within the range `0x00000000` to
|
||||
/// `0xFFFFFFFF`
|
||||
0x28 double_to_ufix(v: f64, n: i32) -> u32;
|
||||
/// Convert a signed integer to the nearest double value, rounding to even on tie
|
||||
/// Returns a function that will convert a signed integer to the nearest
|
||||
/// double value, rounding to even on tie
|
||||
0x2c int_to_double(v: i32) -> f64;
|
||||
/// Convert a signed fixed point integer representation to the nearest double value, rounding to
|
||||
/// even on tie. n specifies the position of the binary point in fixed point, so f = nearest(v/(2^n))
|
||||
/// Returns a function that will convert a signed fixed point integer
|
||||
/// representation to the nearest double value, rounding to even on tie. `n`
|
||||
/// specifies the position of the binary point in fixed point, so `f =
|
||||
/// nearest(v/(2^n))`
|
||||
0x30 fix_to_double(v: i32, n: i32) -> f64;
|
||||
/// Convert an unsigned integer to the nearest double value, rounding to even on tie
|
||||
/// Returns a function that will convert an unsigned integer to the nearest
|
||||
/// double value, rounding to even on tie
|
||||
0x34 uint_to_double(v: u32) -> f64;
|
||||
/// Convert an unsigned fixed point integer representation to the nearest double value, rounding
|
||||
/// to even on tie. n specifies the position of the binary point in fixed point, so
|
||||
/// f = nearest(v/(2^n))
|
||||
/// Returns a function that will convert an unsigned fixed point integer
|
||||
/// representation to the nearest double value, rounding to even on tie. `n`
|
||||
/// specifies the position of the binary point in fixed point, so f =
|
||||
/// nearest(v/(2^n))
|
||||
0x38 ufix_to_double(v: u32, n: i32) -> f64;
|
||||
/// Return the cosine of angle. angle is in radians, and must be in the range -1024 to 1024
|
||||
/// Returns a function that will calculate the cosine of `angle`. The value
|
||||
/// of `angle` is in radians, and must be in the range `-1024` to `1024`
|
||||
0x3c dcos(angle: f64) -> f64;
|
||||
/// Return the sine of angle. angle is in radians, and must be in the range -1024 to 1024
|
||||
/// Returns a function that will calculate the sine of `angle`. The value of
|
||||
/// `angle` is in radians, and must be in the range `-1024` to `1024`
|
||||
0x40 dsin(angle: f64) -> f64;
|
||||
/// Return the tangent of angle. angle is in radians, and must be in the range -1024 to 1024
|
||||
/// Returns a function that will calculate the tangent of `angle`. The value
|
||||
/// of `angle` is in radians, and must be in the range `-1024` to `1024`
|
||||
0x44 dtan(angle: f64) -> f64;
|
||||
/// Return the exponential value of v, i.e. so
|
||||
|
||||
// 0x48 is deprecated
|
||||
|
||||
/// Returns a function that will calculate the exponential value of `v`,
|
||||
/// i.e. `e ** v`
|
||||
0x4c dexp(v: f64) -> f64;
|
||||
/// Return the natural logarithm of v. If v <= 0 return -Infinity
|
||||
/// Returns a function that will calculate the natural logarithm of v. If v <= 0 return -Infinity
|
||||
0x50 dln(v: f64) -> f64;
|
||||
/// Compares two floating point numbers, returning:
|
||||
|
||||
// These are only on BootROM v2 or higher
|
||||
|
||||
/// Returns a function that will compare two floating point numbers, returning:
|
||||
/// • 0 if a == b
|
||||
/// • -1 if a < b
|
||||
/// • 1 if a > b
|
||||
0x54 dcmp(a: f64, b: f64) -> i32;
|
||||
/// Computes the arc tangent of y/x using the signs of arguments to determine the correct
|
||||
/// quadrant
|
||||
/// Returns a function that will compute the arc tangent of `y/x` using the
|
||||
/// signs of arguments to determine the correct quadrant
|
||||
0x58 datan2(y: f64, x: f64) -> f64;
|
||||
/// Convert a signed 64-bit integer to the nearest double value, rounding to even on tie
|
||||
/// Returns a function that will convert a signed 64-bit integer to the
|
||||
/// nearest double value, rounding to even on tie
|
||||
0x5c int64_to_double(v: i64) -> f64;
|
||||
/// Convert a signed fixed point 64-bit integer representation to the nearest double value,
|
||||
/// rounding to even on tie. n specifies the position of the binary point in fixed point, so
|
||||
/// f = nearest(v/(2^n))
|
||||
/// Returns a function that will convert a signed fixed point 64-bit integer
|
||||
/// representation to the nearest double value, rounding to even on tie. `n`
|
||||
/// specifies the position of the binary point in fixed point, so `f =
|
||||
/// nearest(v/(2^n))`
|
||||
0x60 fix64_to_doubl(v: i64, n: i32) -> f64;
|
||||
/// Convert an unsigned 64-bit integer to the nearest double value, rounding to even on tie
|
||||
/// Returns a function that will convert an unsigned 64-bit integer to the
|
||||
/// nearest double value, rounding to even on tie
|
||||
0x64 uint64_to_double(v: u64) -> f64;
|
||||
/// Convert an unsigned fixed point 64-bit integer representation to the nearest double value,
|
||||
/// rounding to even on tie. n specifies the position of the binary point in fixed point, so
|
||||
/// f = nearest(v/(2^n))
|
||||
/// Returns a function that will convert an unsigned fixed point 64-bit
|
||||
/// integer representation to the nearest double value, rounding to even on
|
||||
/// tie. `n` specifies the position of the binary point in fixed point, so
|
||||
/// `f = nearest(v/(2^n))`
|
||||
0x68 ufix64_to_double(v: u64, n: i32) -> f64;
|
||||
/// Convert a double to a signed 64-bit integer, rounding towards -Infinity, and
|
||||
/// Convert an f64 to a signed 64-bit integer, rounding towards -Infinity,
|
||||
/// and clamping the result to lie within the range `-0x8000000000000000` to
|
||||
/// `0x7FFFFFFFFFFFFFFF`
|
||||
0x6c double_to_int64(v: f64) -> i64;
|
||||
/// Convert a double to a signed fixed point 64-bit integer representation where n specifies the
|
||||
/// position of the binary point in the resulting fixed point representation - e.g. _double2fix(0.5f,
|
||||
/// 16) == 0x8000. This method rounds towards -Infinity, and clamps the resulting integer to lie
|
||||
/// within the range -0x8000000000000000 to 0x7FFFFFFFFFFFFFFF
|
||||
/// Returns a function that will convert an f64 to a signed fixed point
|
||||
/// 64-bit integer representation where n specifies the position of the
|
||||
/// binary point in the resulting fixed point representation - e.g. `f(0.5f,
|
||||
/// 16) == 0x8000`. This method rounds towards -Infinity, and clamps the
|
||||
/// resulting integer to lie within the range `-0x8000000000000000` to
|
||||
/// `0x7FFFFFFFFFFFFFFF`
|
||||
0x70 double_to_fix64(v: f64, n: i32) -> i64;
|
||||
/// Convert a double to an unsigned 64-bit integer, rounding towards -Infinity, and clamping the
|
||||
/// result to lie within the range 0x0000000000000000 to 0xFFFFFFFFFFFFFFFF
|
||||
/// Returns a function that will convert an f64 to an unsigned 64-bit
|
||||
/// integer, rounding towards -Infinity, and clamping the result to lie
|
||||
/// within the range `0x0000000000000000` to `0xFFFFFFFFFFFFFFFF`
|
||||
0x74 double_to_uint64(v: f64) -> u64;
|
||||
/// Convert a double to an unsigned fixed point 64-bit integer representation where n specifies
|
||||
/// the position of the binary point in the resulting fixed point representation, e.g.
|
||||
/// _double2ufix(0.5f, 16) == 0x8000. This method rounds towards -Infinity, and clamps the
|
||||
/// resulting integer to lie within the range 0x0000000000000000 to 0xFFFFFFFFFFFFFFFF
|
||||
/// Returns a function that will convert an f64 to an unsigned fixed point
|
||||
/// 64-bit integer representation where n specifies the position of the
|
||||
/// binary point in the resulting fixed point representation, e.g. `f(0.5f,
|
||||
/// 16) == 0x8000`. This method rounds towards -Infinity, and clamps the
|
||||
/// resulting integer to lie within the range `0x0000000000000000` to
|
||||
/// `0xFFFFFFFFFFFFFFFF`
|
||||
0x78 double_to_ufix64(v: f64, n: i32) -> u64;
|
||||
/// Converts a double to a float
|
||||
/// Returns a function that will convert an f64 to an f32
|
||||
0x7c double_to_float(v: f64) -> f32;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue