1#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
5#![doc(html_logo_url = "https://docs.espressif.com/projects/rust/esp-rs-grey-bg.svg")]
6#![allow(asm_sub_register, named_asm_labels)]
7#![feature(asm_experimental_arch)]
8#![no_std]
9
10use core::arch::global_asm;
11
12pub use macros::{entry, exception, interrupt, pre_init};
13pub use xtensa_lx;
14
15pub mod exception;
16pub mod interrupt;
17
18#[doc(hidden)]
19#[unsafe(no_mangle)]
20pub unsafe extern "C" fn no_init_hook() {}
21
22unsafe extern "C" {
23 fn __pre_init();
24 fn __post_init();
25
26 fn __zero_bss() -> bool;
27 fn __init_data() -> bool;
28
29 fn main() -> !;
30
31 static _bss_start: u32;
32 static _bss_end: u32;
33
34 static _data_start: u32;
35 static _data_end: u32;
36 static _sidata: u32;
37
38 static _init_start: u32;
39
40 static _stack_start_cpu0: u32;
41}
42
43global_asm!(
44 "
45 .section .rwtext,\"ax\",@progbits
46 .literal sym__pre_init, {__pre_init}
47 .literal sym__post_init, {__post_init}
48 .literal sym__zero_bss, {__zero_bss}
49 .literal sym_main, {main}
50
51 .literal sym_stack_start_cpu0, {_stack_start_cpu0}
52
53 .literal sym_init_start, {_init_start}
54 .literal sym_bss_end, {_bss_end}
55 .literal sym_bss_start, {_bss_start}
56 .literal sym__init_data, {__init_data}
57 .literal sym_data_start, {_data_start}
58 .literal sym_data_end, {_data_end}
59 .literal sym_sidata, {_sidata}
60",
61 __pre_init = sym __pre_init,
62 __post_init = sym __post_init,
63 __zero_bss = sym __zero_bss,
64
65 _stack_start_cpu0 = sym _stack_start_cpu0,
66
67 _bss_end = sym _bss_end,
68 _bss_start = sym _bss_start,
69 __init_data = sym __init_data,
70 _data_start = sym _data_start,
71 _data_end = sym _data_end,
72 _sidata = sym _sidata,
73
74 _init_start = sym _init_start,
75 main = sym main,
76);
77
78cfg_global_asm!(
81 "
82 // _xtensa_lx_rt_zero_fill
83 //
84 // Input arguments:
85 // a2: start address (used as a cursor)
86 // a3: end address
87
88 .section .rwtext,\"ax\",@progbits
89 .global _xtensa_lx_rt_zero_fill
90 .p2align 2
91 .type _xtensa_lx_rt_zero_fill,@function
92_xtensa_lx_rt_zero_fill:
93 entry a1, 0 // Leaf function, no need to reserve stack
94 bgeu a2, a3, .Lfill_done // If start >= end, skip zeroing
95 movi.n a5, 0
96
97.Lfill_loop:
98 s32i.n a5, a2, 0 // Store the zero at the current cursor
99 addi.n a2, a2, 4 // Increment the cursor by 4 bytes
100 bltu a2, a3, .Lfill_loop // If cursor < end, repeat
101.Lfill_done:
102 retw.n
103
104 // _xtensa_lx_rt_copy
105 //
106 // Input arguments:
107 // a2: source address
108 // a3: destination start address (used as a cursor)
109 // a4: destination end address
110
111 .section .rwtext,\"ax\",@progbits
112 .global _xtensa_lx_rt_copy
113 .p2align 2
114 .type _xtensa_lx_rt_copy,@function
115_xtensa_lx_rt_copy:
116 entry a1, 0 // Leaf function, no need to reserve stack
117 bgeu a3, a4, .Lcopy_done // If start >= end, skip copying
118.Lcopy_loop:
119 l32i.n a5, a2, 0 // Load word from source pointer
120 s32i.n a5, a3, 0 // Store word at destination pointer
121 addi.n a3, a3, 4 // Increment destination pointer by 4 bytes
122 addi.n a2, a2, 4 // Increment source pointer by 4 bytes
123 bltu a3, a4, .Lcopy_loop // If cursor < end, repeat
124.Lcopy_done:
125 retw.n
126
127 .section .rwtext,\"ax\",@progbits
128 .global Reset
129 .p2align 2
130 .type Reset,@function
131Reset:
132 entry a1, 0x10 // We're using call4/callx4, reserve 16 bytes for register spill area
133 movi a0, 0 // Trash the return address. Debuggers may use this to stop unwinding.
134
135 wsr.intenable a0 // Disable interrupts
136
137 l32r a2, sym_stack_start_cpu0 // a2 is our temporary value register
138 mov sp, a2 // Set the stack pointer.
139
140 l32r a2, sym__pre_init
141 callx4 a2 // Call the pre-initialization function.
142
143.Linit_bss:
144 l32r a2, sym__zero_bss // Do we need to zero-initialize memory?
145 callx4 a2
146 beqz a6, .Linit_data // No -> skip to copying initialized data
147
148 l32r a6, sym_bss_start // Set input range to .bss
149 l32r a7, sym_bss_end //
150 call4 _xtensa_lx_rt_zero_fill // Zero-fill
151
152.Linit_data:
153 l32r a2, sym__init_data // Do we need to initialize data sections?
154 callx4 a2
155 beqz a6, .Linit_data_done // If not, skip initialization
156
157 l32r a6, sym_sidata // Arguments - source data pointer
158 l32r a7, sym_data_start // - destination pointer
159 l32r a8, sym_data_end // - destination end pointer
160 call4 _xtensa_lx_rt_copy // Copy .data section
161
162.Linit_data_done:
163 memw // Make sure all writes are completed before proceeding. At this point, all static variables have been initialized.
164",
165 #[cfg(XCHAL_HAVE_TIMER0)]
168 "wsr.ccompare0 a0",
169 #[cfg(XCHAL_HAVE_TIMER1)]
170 "wsr.ccompare1 a0",
171 #[cfg(XCHAL_HAVE_TIMER2)]
172 "wsr.ccompare2 a0",
173 #[cfg(XCHAL_HAVE_TIMER3)]
174 "wsr.ccompare3 a0",
175 #[cfg(any(
176 XCHAL_HAVE_TIMER0,
177 XCHAL_HAVE_TIMER1,
178 XCHAL_HAVE_TIMER2,
179 XCHAL_HAVE_TIMER3
180 ))]
181 "isync",
182 "
183 l32r a2, sym_init_start // vector table address
184 wsr.vecbase a2
185
186 l32r a2, sym__post_init
187 callx4 a2
188
189 l32r a2, sym_main // program entry point
190 callx4 a2
191 ",
192);
193
194unsafe extern "C" {
198 #[cfg(XCHAL_HAVE_TIMER0)]
199 pub fn Timer0(save_frame: &mut crate::exception::Context);
200 #[cfg(XCHAL_HAVE_TIMER1)]
201 pub fn Timer1(save_frame: &mut crate::exception::Context);
202 #[cfg(XCHAL_HAVE_TIMER2)]
203 pub fn Timer2(save_frame: &mut crate::exception::Context);
204 #[cfg(XCHAL_HAVE_TIMER3)]
205 pub fn Timer3(save_frame: &mut crate::exception::Context);
206
207 #[cfg(XCHAL_HAVE_PROFILING)]
208 pub fn Profiling(save_frame: &mut crate::exception::Context);
209
210 #[cfg(XCHAL_HAVE_SOFTWARE0)]
211 pub fn Software0(save_frame: &mut crate::exception::Context);
212 #[cfg(XCHAL_HAVE_SOFTWARE1)]
213 pub fn Software1(save_frame: &mut crate::exception::Context);
214
215 #[cfg(XCHAL_HAVE_NMI)]
216 pub fn NMI(save_frame: &mut crate::exception::Context);
217}
218
219#[doc(hidden)]
220#[unsafe(no_mangle)]
221pub extern "C" fn default_mem_hook() -> bool {
222 true }
224
225#[doc(hidden)]
226#[macro_export]
227macro_rules! cfg_asm {
228 (@inner, [$($x:tt)*], [$($opts:tt)*], ) => {
229 asm!($($x)* $($opts)*)
230 };
231 (@inner, [$($x:tt)*], [$($opts:tt)*], #[cfg($meta:meta)] $asm:literal, $($rest:tt)*) => {
232 #[cfg($meta)]
233 cfg_asm!(@inner, [$($x)* $asm,], [$($opts)*], $($rest)*);
234 #[cfg(not($meta))]
235 cfg_asm!(@inner, [$($x)*], [$($opts)*], $($rest)*)
236 };
237 (@inner, [$($x:tt)*], [$($opts:tt)*], $asm:literal, $($rest:tt)*) => {
238 cfg_asm!(@inner, [$($x)* $asm,], [$($opts)*], $($rest)*)
239 };
240 ({$($asms:tt)*}, $($opts:tt)*) => {
241 cfg_asm!(@inner, [], [$($opts)*], $($asms)*)
242 };
243}
244
245#[doc(hidden)]
246#[macro_export]
247macro_rules! cfg_global_asm {
248 {@inner, [$($x:tt)*], } => {
249 global_asm!{$($x)*}
250 };
251 (@inner, [$($x:tt)*], #[cfg($meta:meta)] $asm:literal, $($rest:tt)*) => {
252 #[cfg($meta)]
253 cfg_global_asm!{@inner, [$($x)* $asm,], $($rest)*}
254 #[cfg(not($meta))]
255 cfg_global_asm!{@inner, [$($x)*], $($rest)*}
256 };
257 {@inner, [$($x:tt)*], $asm:literal, $($rest:tt)*} => {
258 cfg_global_asm!{@inner, [$($x)* $asm,], $($rest)*}
259 };
260 {$($asms:tt)*} => {
261 cfg_global_asm!{@inner, [], $($asms)*}
262 };
263}