aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-rp/src/rom_data.rs115
1 files changed, 54 insertions, 61 deletions
diff --git a/embassy-rp/src/rom_data.rs b/embassy-rp/src/rom_data.rs
index 757a27114..805c1f09f 100644
--- a/embassy-rp/src/rom_data.rs
+++ b/embassy-rp/src/rom_data.rs
@@ -56,56 +56,32 @@ macro_rules! declare_rom_function {
56 fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty 56 fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty
57 $lookup:block 57 $lookup:block
58 ) => { 58 ) => {
59 #[doc = r"Additional access for the `"] 59 declare_rom_function!{
60 #[doc = stringify!($name)] 60 __internal ,
61 #[doc = r"` ROM function."] 61 $(#[$outer])*
62 pub mod $name { 62 fn $name( $($argname: $ty),* ) -> $ret
63 /// Retrieve a function pointer. 63 $lookup
64 #[cfg(not(feature = "rom-func-cache"))]
65 pub fn ptr() -> extern "C" fn( $($argname: $ty),* ) -> $ret {
66 let p: *const u32 = $lookup;
67 unsafe {
68 let func : extern "C" fn( $($argname: $ty),* ) -> $ret = core::mem::transmute(p);
69 func
70 }
71 }
72
73 /// Retrieve a function pointer.
74 #[cfg(feature = "rom-func-cache")]
75 pub fn ptr() -> extern "C" fn( $($argname: $ty),* ) -> $ret {
76 use core::sync::atomic::{AtomicU16, Ordering};
77
78 // All pointers in the ROM fit in 16 bits, so we don't need a
79 // full width word to store the cached value.
80 static CACHED_PTR: AtomicU16 = AtomicU16::new(0);
81 // This is safe because the lookup will always resolve
82 // to the same value. So even if an interrupt or another
83 // core starts at the same time, it just repeats some
84 // work and eventually writes back the correct value.
85 let p: *const u32 = match CACHED_PTR.load(Ordering::Relaxed) {
86 0 => {
87 let raw: *const u32 = $lookup;
88 CACHED_PTR.store(raw as u16, Ordering::Relaxed);
89 raw
90 },
91 val => val as *const u32,
92 };
93 unsafe {
94 let func : extern "C" fn( $($argname: $ty),* ) -> $ret = core::mem::transmute(p);
95 func
96 }
97 }
98 } 64 }
65 };
99 66
100 $(#[$outer])* 67 (
101 pub extern "C" fn $name( $($argname: $ty),* ) -> $ret { 68 $(#[$outer:meta])*
102 $name::ptr()($($argname),*) 69 unsafe fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty
70 $lookup:block
71 ) => {
72 declare_rom_function!{
73 __internal unsafe ,
74 $(#[$outer])*
75 fn $name( $($argname: $ty),* ) -> $ret
76 $lookup
103 } 77 }
104 }; 78 };
105 79
106 ( 80 (
81 __internal
82 $( $maybe_unsafe:ident )? ,
107 $(#[$outer:meta])* 83 $(#[$outer:meta])*
108 unsafe fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty 84 fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty
109 $lookup:block 85 $lookup:block
110 ) => { 86 ) => {
111 #[doc = r"Additional access for the `"] 87 #[doc = r"Additional access for the `"]
@@ -114,43 +90,58 @@ macro_rules! declare_rom_function {
114 pub mod $name { 90 pub mod $name {
115 /// Retrieve a function pointer. 91 /// Retrieve a function pointer.
116 #[cfg(not(feature = "rom-func-cache"))] 92 #[cfg(not(feature = "rom-func-cache"))]
117 pub fn ptr() -> unsafe extern "C" fn( $($argname: $ty),* ) -> $ret { 93 pub fn ptr() -> $( $maybe_unsafe )? extern "C" fn( $($argname: $ty),* ) -> $ret {
118 let p: *const u32 = $lookup; 94 let p: *const u32 = $lookup;
119 unsafe { 95 unsafe {
120 let func : unsafe extern "C" fn( $($argname: $ty),* ) -> $ret = core::mem::transmute(p); 96 let func : $( $maybe_unsafe )? extern "C" fn( $($argname: $ty),* ) -> $ret
97 = core::mem::transmute(p);
121 func 98 func
122 } 99 }
123 } 100 }
124 101
102 #[cfg(feature = "rom-func-cache")]
103 // unlike rp2040-hal we store a full word, containing the full function pointer.
104 // rp2040-hal saves two bytes by storing only the rom offset, at the cost of
105 // having to do an indirection and an atomic operation on every rom call.
106 static mut CACHE: $( $maybe_unsafe )? extern "C" fn( $($argname: $ty),* ) -> $ret
107 = trampoline;
108
109 #[cfg(feature = "rom-func-cache")]
110 $( $maybe_unsafe )? extern "C" fn trampoline( $($argname: $ty),* ) -> $ret {
111 use core::sync::atomic::{compiler_fence, Ordering};
112
113 let p: *const u32 = $lookup;
114 #[allow(unused_unsafe)]
115 unsafe {
116 CACHE = core::mem::transmute(p);
117 compiler_fence(Ordering::Release);
118 CACHE($($argname),*)
119 }
120 }
121
125 /// Retrieve a function pointer. 122 /// Retrieve a function pointer.
126 #[cfg(feature = "rom-func-cache")] 123 #[cfg(feature = "rom-func-cache")]
127 pub fn ptr() -> unsafe extern "C" fn( $($argname: $ty),* ) -> $ret { 124 pub fn ptr() -> $( $maybe_unsafe )? extern "C" fn( $($argname: $ty),* ) -> $ret {
128 use core::sync::atomic::{AtomicU16, Ordering}; 125 use core::sync::atomic::{compiler_fence, Ordering};
129 126
130 // All pointers in the ROM fit in 16 bits, so we don't need a
131 // full width word to store the cached value.
132 static CACHED_PTR: AtomicU16 = AtomicU16::new(0);
133 // This is safe because the lookup will always resolve 127 // This is safe because the lookup will always resolve
134 // to the same value. So even if an interrupt or another 128 // to the same value. So even if an interrupt or another
135 // core starts at the same time, it just repeats some 129 // core starts at the same time, it just repeats some
136 // work and eventually writes back the correct value. 130 // work and eventually writes back the correct value.
137 let p: *const u32 = match CACHED_PTR.load(Ordering::Relaxed) { 131 //
138 0 => { 132 // We easily get away with using only compiler fences here
139 let raw: *const u32 = $lookup; 133 // because RP2040 SRAM is not cached. If it were we'd need
140 CACHED_PTR.store(raw as u16, Ordering::Relaxed); 134 // to make sure updates propagate quickly, or just take the
141 raw 135 // hit and let each core resolve every function once.
142 }, 136 compiler_fence(Ordering::Acquire);
143 val => val as *const u32,
144 };
145 unsafe { 137 unsafe {
146 let func : unsafe extern "C" fn( $($argname: $ty),* ) -> $ret = core::mem::transmute(p); 138 CACHE
147 func
148 } 139 }
149 } 140 }
150 } 141 }
151 142
152 $(#[$outer])* 143 $(#[$outer])*
153 pub unsafe extern "C" fn $name( $($argname: $ty),* ) -> $ret { 144 pub $( $maybe_unsafe )? extern "C" fn $name( $($argname: $ty),* ) -> $ret {
154 $name::ptr()($($argname),*) 145 $name::ptr()($($argname),*)
155 } 146 }
156 }; 147 };
@@ -369,6 +360,7 @@ pub fn fplib_start() -> *const u8 {
369} 360}
370 361
371/// See Table 180 in the RP2040 datasheet for the contents of this table. 362/// See Table 180 in the RP2040 datasheet for the contents of this table.
363#[cfg_attr(feature = "rom-func-cache", inline(never))]
372pub fn soft_float_table() -> *const usize { 364pub fn soft_float_table() -> *const usize {
373 rom_table_lookup(DATA_TABLE, *b"SF") 365 rom_table_lookup(DATA_TABLE, *b"SF")
374} 366}
@@ -379,6 +371,7 @@ pub fn fplib_end() -> *const u8 {
379} 371}
380 372
381/// This entry is only present in the V2 bootrom. See Table 182 in the RP2040 datasheet for the contents of this table. 373/// This entry is only present in the V2 bootrom. See Table 182 in the RP2040 datasheet for the contents of this table.
374#[cfg_attr(feature = "rom-func-cache", inline(never))]
382pub fn soft_double_table() -> *const usize { 375pub fn soft_double_table() -> *const usize {
383 if rom_version_number() < 2 { 376 if rom_version_number() < 2 {
384 panic!( 377 panic!(