1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
//! Functions and data from the RPI Bootrom. /// A bootrom function table code. 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` /// Pointer to the lookup table function supplied by the rom. const ROM_TABLE_LOOKUP_PTR: *const u16 = 0x18 as _; /// Pointer to helper functions lookup table. const FUNC_TABLE: *const u16 = 0x14 as _; /// Pointer to the public data lookup table. const DATA_TABLE: *const u16 = 0x16 as _; /// Retrive rom content from a table using a code. fn rom_table_lookup<T>(table: *const u16, tag: RomFnTableCode) -> T { unsafe { let rom_table_lookup_ptr: *const u32 = rom_hword_as_ptr(ROM_TABLE_LOOKUP_PTR); let rom_table_lookup: RomTableLookupFn<T> = core::mem::transmute(rom_table_lookup_ptr); rom_table_lookup(rom_hword_as_ptr(table) as *const u16, u16::from_le_bytes(tag) as u32) } } unsafe fn rom_hword_as_ptr(rom_address: *const u16) -> *const u32 { let ptr: u16 = *rom_address; ptr as *const u32 } macro_rules! rom_funcs { ( $( $(#[$outer:meta])* $c:literal $name:ident ( $( $aname:ident : $aty:ty ),* ) -> $ret:ty ; )* ) => { $( $(#[$outer])* pub fn $name($( $aname:$aty ),*) -> $ret{ let func: extern "C" fn( $( $aty ),* ) -> $ret = rom_table_lookup(FUNC_TABLE, *$c); func($( $aname ),*) } )* } } rom_funcs! { /// Return a count of the number of 1 bits in value. b"P3" popcount32(value: u32) -> u32; /// Return the bits of value in the reverse order. b"R3" reverse32(value: u32) -> u32; /// Return the number of consecutive high order 0 bits of value. If value is zero, returns 32. b"L3" clz32(value: u32) -> u32; /// Return the number of consecutive low order 0 bits of value. If value is zero, returns 32. b"T3" ctz32(value: u32) -> u32; /// 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. 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 /// regions overlap. 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 /// used if dest and src are word aligned. b"C4" memcpy44(dest: *mut u32, src: *mut u32, n: u32) -> *mut u8; /// Restore all QSPI pad controls to their default state, and connect the SSI to the QSPI pads. 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. b"EX" flash_exit_xip() -> (); /// Erase a count bytes, starting at addr (offset from start of flash). Optionally, pass a /// block erase command e.g. D8h block erase, and the size of the block erased by this /// command — this function will use the larger block erase where possible, for much higher /// erase speed. addr must be aligned to a 4096-byte sector, and count must be a multiple of /// 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 /// multiple of 256. b"RP" flash_range_program(addr: u32, data: *const u8, count: usize) -> (); /// Flush and enable the XIP cache. Also clears the IO forcing on QSPI CSn, so that the SSI can /// drive the flashchip select as normal. b"FC" flash_flush_cache() -> (); /// Configure the SSI to generate a standard 03h serial read command, with 24 address bits, /// upon each XIP access. This is a very slow XIP configuration, but is very widely supported. /// The debugger calls this function after performing a flash erase/programming operation, so /// that the freshly-programmed code and data is visible to the debug host, without having to /// know exactly what kind of flash device is connected. b"CX" flash_enter_cmd_xip() -> (); /// Resets the RP2040 and uses the watchdog facility to re-start in BOOTSEL mode: /// * gpio_activity_pin_mask is provided to enable an 'activity light' via GPIO attached LED /// for the USB Mass Storage Device: /// * 0 No pins are used as per cold boot. /// * Otherwise a single bit set indicating which GPIO pin should be set to output and /// raised whenever there is mass storage activity from the host. /// * disable_interface_mask may be used to control the exposed USB interfaces: /// * 0 To enable both interfaces (as per cold boot). /// * 1 To disable the USB Mass Storage Interface. /// * 2 to Disable the USB PICOBOOT Interface. b"UB" reset_to_usb_boot(gpio_activity_pin_mask: u32, disable_interface_mask: u32) -> (); /// This is the method that is entered by core 1 on reset to wait to be launched by core 0. /// There are few cases where you should call this method (resetting core 1 is much better). /// This method does not return and should only ever be called on core 1. b"WV" wait_for_vector() -> !; } unsafe fn convert_str(s: *const u8) -> &'static str { let mut end = s; while *end != 0 { end = end.add(1); } let s = core::slice::from_raw_parts(s, end.offset_from(s) as usize); core::str::from_utf8_unchecked(s) } /// The Raspberry Pi Trading Ltd copyright string. pub fn copyright_string() -> &'static str { let s: *const u8 = rom_table_lookup(DATA_TABLE, *b"CR"); unsafe { convert_str(s) } } /// The 8 most significant hex digits of the Bootrom git revision. pub fn git_revision() -> &'static str { let s: *const u8 = rom_table_lookup(DATA_TABLE, *b"GR"); unsafe { convert_str(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. 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 { rom_table_lookup(DATA_TABLE, *b"SF") } /// The end address of the floating point library code and data. 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 { 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 *const u16 = rom_table_lookup(DATA_TABLE, *b"SF"); unsafe { core::mem::transmute_copy(&table.add($offset)) } } )* } } float_funcs! { /// Return a + b. 0x00 fadd(a: f32, b: f32) -> f32; /// Return a - b. 0x04 fsub(a: f32, b: f32) -> f32; /// Return a * b. 0x08 fmul(a: f32, b: f32) -> f32; /// Return a / b. 0x0c fdiv(a: f32, b: f32) -> f32; /// Return the square root of v or -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. 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. 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 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. 0x28 float_to_ufix(v: f32, n: i32) -> u32; /// Convert a signed integer to the nearest float 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). 0x30 fix_to_float(v: i32, n: i32) -> f32; /// Convert an unsigned integer to the nearest float 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). 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. 0x3c fcos(angle: f32) -> f32; /// Return the sine of angle. angle is in radians, and must be in the range -128 to 128. 0x40 fsin(angle: f32) -> f32; /// Return the tangent of angle. angle is in radians, and must be in the range -128 to 128. 0x44 ftan(angle: f32) -> f32; /// Return the exponential value of v, i.e. so e^v. 0x4c fexp(v: f32) -> f32; /// Return 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 0x54 fcmp(a: f32, b: f32) -> i32; /// Computes 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. 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). 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. 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). 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 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 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 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. 0x7c float_to_double(v: f32) -> f64; } 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 *const u16 = rom_table_lookup(DATA_TABLE, *b"SD"); unsafe { core::mem::transmute_copy(&table.add($offset)) } } )* } } double_funcs! { /// Return a + b 0x00 dadd(a: f64, b: f64) -> f64; /// Return a - b 0x04 dsub(a: f64, b: f64) -> f64; /// Return a * b 0x08 dmul(a: f64, b: f64) -> f64; /// Return a / b 0x0c ddiv(a: f64, b: f64) -> f64; /// Return sqrt(v) or -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 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 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; 0x28 double_to_ufix(v: f64, n: i32) -> u32; /// 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)) 0x30 fix_to_double(v: i32, n: i32) -> f64; /// 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)) 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 0x3c dcos(angle: f64) -> f64; /// Return the sine of angle. 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 0x44 dtan(angle: f64) -> f64; /// Return the exponential value of v, i.e. so 0x4c dexp(v: f64) -> f64; /// Return the natural logarithm of v. If v <= 0 return -Infinity 0x50 dln(v: f64) -> f64; /// Compares 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 0x58 datan2(y: f64, x: f64) -> f64; /// 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)) 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 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)) 0x68 ufix64_to_double(v: u64, n: i32) -> f64; /// Convert a double to a signed 64-bit integer, rounding towards -Infinity, and 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 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 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 0x78 double_to_ufix64(v: f64, n: i32) -> u64; /// Converts a double to a float 0x7c double_to_float(v: f64) -> f32; }