From 7a05b8f3a75251d7ad4827a4857abbdf47164244 Mon Sep 17 00:00:00 2001 From: "Jonathan Pallant (42 Technology)" Date: Mon, 11 Oct 2021 15:45:34 +0100 Subject: [PATCH 1/9] Fix the ROM function table code. The floating point table lookup was incorrect. --- rp2040-hal/src/rom_data.rs | 52 +++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/rp2040-hal/src/rom_data.rs b/rp2040-hal/src/rom_data.rs index 77afe98..f01a3ce 100644 --- a/rp2040-hal/src/rom_data.rs +++ b/rp2040-hal/src/rom_data.rs @@ -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 = 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(table: *const u16, tag: RomFnTableCode) -> T { @@ -28,6 +36,12 @@ fn rom_table_lookup(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 @@ -180,8 +194,8 @@ 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,8 +204,8 @@ 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") } @@ -207,9 +221,16 @@ 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) } } )* @@ -318,9 +339,16 @@ 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) } } )* From f56369e1c7c90d67cf3bbe5d0e306c40c6d9c502 Mon Sep 17 00:00:00 2001 From: "Jonathan Pallant (42 Technology)" Date: Mon, 11 Oct 2021 15:45:44 +0100 Subject: [PATCH 2/9] Add example which uses the ROM functions --- rp2040-hal/examples/rom_funcs.rs | 179 +++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 rp2040-hal/examples/rom_funcs.rs diff --git a/rp2040-hal/examples/rom_funcs.rs b/rp2040-hal/examples/rom_funcs.rs new file mode 100644 index 0000000..aa1b5fb --- /dev/null +++ b/rp2040-hal/examples/rom_funcs.rs @@ -0,0 +1,179 @@ +//! # '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. +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::(); + // UART RX (characters reveived by RP2040) on pin 2 (GPIO1) + let _rx_pin = pins.gpio1.into_mode::(); + + 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::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(); + } +} + +fn calc_delta(start: u32, end: u32) -> u32 { + if start < end { + (start.wrapping_sub(end)) & SYSTICK_RELOAD + } else { + start - end + } +} + +// End of file From 64207a62e5159554d4b55cbdcbe5b7117e7d735b Mon Sep 17 00:00:00 2001 From: "Jonathan Pallant (42 Technology)" Date: Mon, 11 Oct 2021 16:22:11 +0100 Subject: [PATCH 3/9] Add comment to `calc_delta` function as it's non-obvious. --- rp2040-hal/examples/rom_funcs.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/rp2040-hal/examples/rom_funcs.rs b/rp2040-hal/examples/rom_funcs.rs index aa1b5fb..d241420 100644 --- a/rp2040-hal/examples/rom_funcs.rs +++ b/rp2040-hal/examples/rom_funcs.rs @@ -36,7 +36,8 @@ pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; /// 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. +/// 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. @@ -168,6 +169,15 @@ fn main() -> ! { } } +/// 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 From ae66ac4cb62da0b0803d80fbd75ccc739b1f6bab Mon Sep 17 00:00:00 2001 From: "Jonathan Pallant (42 Technology)" Date: Mon, 11 Oct 2021 16:22:35 +0100 Subject: [PATCH 4/9] Tweak doc comments. --- rp2040-hal/src/rom_data.rs | 268 ++++++++++++++++++++++--------------- 1 file changed, 161 insertions(+), 107 deletions(-) diff --git a/rp2040-hal/src/rom_data.rs b/rp2040-hal/src/rom_data.rs index f01a3ce..48c5df3 100644 --- a/rp2040-hal/src/rom_data.rs +++ b/rp2040-hal/src/rom_data.rs @@ -238,92 +238,115 @@ macro_rules! float_funcs { } float_funcs! { - /// Return a + b. + /// 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. + /// 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. + /// 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 + /// 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 a 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; } @@ -356,83 +379,114 @@ macro_rules! double_funcs { } double_funcs! { - /// Return a + b + /// 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 + /// 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 + /// 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: + /// 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 a f32 0x7c double_to_float(v: f64) -> f32; } From e1afb70bd244b9c076c33c6821576857fc128142 Mon Sep 17 00:00:00 2001 From: "Jonathan Pallant (42 Technology)" Date: Mon, 11 Oct 2021 16:37:16 +0100 Subject: [PATCH 5/9] Moved float and double functions into modules. Makes the docs cleaner. --- rp2040-hal/examples/rom_funcs.rs | 2 +- rp2040-hal/src/rom_data.rs | 572 ++++++++++++++++--------------- 2 files changed, 300 insertions(+), 274 deletions(-) diff --git a/rp2040-hal/examples/rom_funcs.rs b/rp2040-hal/examples/rom_funcs.rs index d241420..d81e925 100644 --- a/rp2040-hal/examples/rom_funcs.rs +++ b/rp2040-hal/examples/rom_funcs.rs @@ -138,7 +138,7 @@ fn main() -> ! { // 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::fmul(); + 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(); diff --git a/rp2040-hal/src/rom_data.rs b/rp2040-hal/src/rom_data.rs index 48c5df3..200cda8 100644 --- a/rp2040-hal/src/rom_data.rs +++ b/rp2040-hal/src/rom_data.rs @@ -209,284 +209,310 @@ pub fn soft_double_table() -> *const usize { rom_table_lookup(DATA_TABLE, *b"SD") } -macro_rules! float_funcs { - ( - $( - $(#[$outer:meta])* - $offset:literal $name:ident ( - $( $aname:ident : $aty:ty ),* - ) -> $ret:ty; - )* - ) => { - $( - $(#[$outer])* - pub fn $name() -> extern "C" fn( $( $aname : $aty ),* ) -> $ret { - let table: *const usize = $crate::rom_data::soft_float_table() as *const usize; - unsafe { - // 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) +/// ROM functions using single-precision arithmetic (i.e. 'f64' in Rust terms) +pub mod float_funcs { + + macro_rules! make_functions { + ( + $( + $(#[$outer:meta])* + $offset:literal $name:ident ( + $( $aname:ident : $aty:ty ),* + ) -> $ret:ty; + )* + ) => { + $( + $(#[$outer])* + pub fn $name() -> extern "C" fn( $( $aname : $aty ),* ) -> $ret { + let table: *const usize = $crate::rom_data::soft_float_table() as *const usize; + unsafe { + // 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) + } } - } - )* + )* + } + } + + make_functions! { + /// Returns a function that will calculate `a + b` + 0x00 fadd(a: f32, b: f32) -> f32; + /// Returns a function that will calculate `a - b` + 0x04 fsub(a: f32, b: f32) -> f32; + /// Returns a function that will calculate `a * b` + 0x08 fmul(a: f32, b: f32) -> f32; + /// Returns a function that will calculate `a / b` + 0x0c fdiv(a: f32, b: f32) -> f32; + + // 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; + /// 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; + /// 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; + /// 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; + /// 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; + /// 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; + /// 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; + /// 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; + /// 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; + /// 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; + /// 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; + /// 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; + + // 0x48 is deprecated + + /// Returns a function that will calculate the exponential value of `v`, + /// i.e. `e ** v` + 0x4c fexp(v: f32) -> f32; + /// Returns a function that will calculate the natural logarithm of `v`. If `v <= 0` return -Infinity + 0x50 fln(v: f32) -> f32; + + // 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; + /// 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; + /// 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; + /// 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; + /// 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; + /// 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 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; + /// 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; + /// 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; + /// 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; } } -float_funcs! { - /// Returns a function that will calculate `a + b` - 0x00 fadd(a: f32, b: f32) -> f32; - /// Returns a function that will calculate `a - b` - 0x04 fsub(a: f32, b: f32) -> f32; - /// Returns a function that will calculate `a * b` - 0x08 fmul(a: f32, b: f32) -> f32; - /// Returns a function that will calculate `a / b` - 0x0c fdiv(a: f32, b: f32) -> f32; - /// Returns a function that will calculate `sqrt(v)` (or return -Infinity if v is negative) - 0x18 fsqrt(v: f32) -> f32; - /// 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; - /// 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; - /// 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; - /// 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; - /// 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; - /// 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; - /// 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; - /// 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; - /// 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; - /// 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; - /// 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; - /// Returns a function that will calculate the exponential value of `v`, - /// i.e. `e ** v` - 0x4c fexp(v: f32) -> f32; - /// Returns a function that will calculate the natural logarithm of `v`. If `v <= 0` return -Infinity - 0x50 fln(v: f32) -> f32; - /// 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; - /// 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; - /// 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; - /// 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; - /// 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; - /// 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 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; - /// Returns a function that will convert a 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; - /// 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; - /// 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; -} +/// Functions using double-precision arithmetic (i.e. 'f64' in Rust terms) +pub mod double_funcs { -macro_rules! double_funcs { - ( - $( - $(#[$outer:meta])* - $offset:literal $name:ident ( - $( $aname:ident : $aty:ty ),* - ) -> $ret:ty; - )* - ) => { - $( - $(#[$outer])* - pub fn $name() -> extern "C" fn( $( $aname : $aty ),* ) -> $ret { - let table: *const usize = $crate::rom_data::soft_double_table() as *const usize; - unsafe { - // 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) + macro_rules! make_double_funcs { + ( + $( + $(#[$outer:meta])* + $offset:literal $name:ident ( + $( $aname:ident : $aty:ty ),* + ) -> $ret:ty; + )* + ) => { + $( + $(#[$outer])* + pub fn $name() -> extern "C" fn( $( $aname : $aty ),* ) -> $ret { + let table: *const usize = $crate::rom_data::soft_double_table() as *const usize; + unsafe { + // 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) + } } - } - )* + )* + } + } + + make_double_funcs! { + /// Returns a function that will calculate `a + b` + 0x00 dadd(a: f64, b: f64) -> f64; + /// Returns a function that will calculate `a - b` + 0x04 dsub(a: f64, b: f64) -> f64; + /// Returns a function that will calculate `a * b` + 0x08 dmul(a: f64, b: f64) -> f64; + /// Returns a function that will calculate `a / b` + 0x0c ddiv(a: f64, b: f64) -> f64; + + // 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; + /// 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; + /// 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; + /// 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; + /// 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; + /// 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; + /// 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; + /// 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; + /// 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; + /// 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; + /// 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; + + // 0x48 is deprecated + + /// Returns a function that will calculate the exponential value of `v`, + /// i.e. `e ** v` + 0x4c dexp(v: f64) -> f64; + /// Returns a function that will calculate the natural logarithm of v. If v <= 0 return -Infinity + 0x50 dln(v: f64) -> f64; + + // 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; + /// 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; + /// 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; + /// 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; + /// 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; + /// 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 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; + /// 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; + /// 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; + /// 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; + /// Returns a function that will convert an f64 to an f32 + 0x7c double_to_float(v: f64) -> f32; } } - -double_funcs! { - /// Returns a function that will calculate `a + b` - 0x00 dadd(a: f64, b: f64) -> f64; - /// Returns a function that will calculate `a - b` - 0x04 dsub(a: f64, b: f64) -> f64; - /// Returns a function that will calculate `a * b` - 0x08 dmul(a: f64, b: f64) -> f64; - /// Returns a function that will calculate `a / b` - 0x0c ddiv(a: f64, b: f64) -> f64; - /// Returns a function that will calculate `sqrt(v)` (or return -Infinity if v is negative) - 0x18 dsqrt(v: f64) -> f64; - /// 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; - /// 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; - /// 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; - /// 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; - /// 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; - /// 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; - /// 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; - /// 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; - /// 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; - /// 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; - /// Returns a function that will calculate the exponential value of `v`, - /// i.e. `e ** v` - 0x4c dexp(v: f64) -> f64; - /// Returns a function that will calculate the natural logarithm of v. If v <= 0 return -Infinity - 0x50 dln(v: f64) -> f64; - /// 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; - /// 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; - /// 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; - /// 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; - /// 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; - /// 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 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; - /// 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; - /// 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; - /// 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; - /// Returns a function that will convert an f64 to a f32 - 0x7c double_to_float(v: f64) -> f32; -} From 5c55af76d23de229b0d26bcaf58f29c77c14a501 Mon Sep 17 00:00:00 2001 From: "Jonathan Pallant (42 Technology)" Date: Mon, 11 Oct 2021 16:37:50 +0100 Subject: [PATCH 6/9] Typo --- rp2040-hal/src/rom_data.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rp2040-hal/src/rom_data.rs b/rp2040-hal/src/rom_data.rs index 200cda8..7c8ea46 100644 --- a/rp2040-hal/src/rom_data.rs +++ b/rp2040-hal/src/rom_data.rs @@ -209,7 +209,7 @@ pub fn soft_double_table() -> *const usize { rom_table_lookup(DATA_TABLE, *b"SD") } -/// ROM functions using single-precision arithmetic (i.e. 'f64' in Rust terms) +/// ROM functions using single-precision arithmetic (i.e. 'f32' in Rust terms) pub mod float_funcs { macro_rules! make_functions { From 2423e42eb9ca3ec9f8fb25f3def9531b3567a867 Mon Sep 17 00:00:00 2001 From: "Jonathan Pallant (42 Technology)" Date: Mon, 11 Oct 2021 16:39:12 +0100 Subject: [PATCH 7/9] Clean up comments. --- rp2040-hal/src/rom_data.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/rp2040-hal/src/rom_data.rs b/rp2040-hal/src/rom_data.rs index 7c8ea46..4dd6111 100644 --- a/rp2040-hal/src/rom_data.rs +++ b/rp2040-hal/src/rom_data.rs @@ -144,8 +144,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) -> (); From 74ea262f654633f2431018d03ce45899fb9cd6d2 Mon Sep 17 00:00:00 2001 From: "Jonathan Pallant (42 Technology)" Date: Mon, 11 Oct 2021 16:40:23 +0100 Subject: [PATCH 8/9] Cleaning up the comment summaries. --- rp2040-hal/src/rom_data.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/rp2040-hal/src/rom_data.rs b/rp2040-hal/src/rom_data.rs index 4dd6111..8d63280 100644 --- a/rp2040-hal/src/rom_data.rs +++ b/rp2040-hal/src/rom_data.rs @@ -115,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 @@ -124,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; @@ -132,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. @@ -188,9 +193,11 @@ 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") } From 6a4a4fd247a421ad7af4e1d403e7b559c78f5153 Mon Sep 17 00:00:00 2001 From: "Jonathan Pallant (42 Technology)" Date: Mon, 11 Oct 2021 16:41:51 +0100 Subject: [PATCH 9/9] Formatting. --- rp2040-hal/src/rom_data.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rp2040-hal/src/rom_data.rs b/rp2040-hal/src/rom_data.rs index 8d63280..02aa014 100644 --- a/rp2040-hal/src/rom_data.rs +++ b/rp2040-hal/src/rom_data.rs @@ -127,7 +127,7 @@ rom_funcs_unsafe! { /// 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 /// used if dest and src are word aligned. b"C4" memcpy44(dest: *mut u32, src: *mut u32, n: u32) -> *mut u8; @@ -136,7 +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.