1#![doc = document_features::document_features!()]
5#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")]
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
78global_asm!(
79 "
80 // _xtensa_lx_rt_zero_fill
81 //
82 // Input arguments:
83 // a2: start address (used as a cursor)
84 // a3: end address
85
86 .section .rwtext,\"ax\",@progbits
87 .global _xtensa_lx_rt_zero_fill
88 .p2align 2
89 .type _xtensa_lx_rt_zero_fill,@function
90_xtensa_lx_rt_zero_fill:
91 entry a1, 0
92 bgeu a2, a3, .Lfill_done // If start >= end, skip zeroing
93 movi.n a5, 0
94
95.Lfill_loop:
96 s32i.n a5, a2, 0 // Store the zero at the current cursor
97 addi.n a2, a2, 4 // Increment the cursor by 4 bytes
98 bltu a2, a3, .Lfill_loop // If cursor < end, repeat
99.Lfill_done:
100 retw.n
101
102 // _xtensa_lx_rt_copy
103 //
104 // Input arguments:
105 // a2: source address
106 // a3: destination start address (used as a cursor)
107 // a4: destination end address
108
109 .section .rwtext,\"ax\",@progbits
110 .global _xtensa_lx_rt_copy
111 .p2align 2
112 .type _xtensa_lx_rt_copy,@function
113_xtensa_lx_rt_copy:
114 entry a1, 0
115 bgeu a3, a4, .Lcopy_done // If start >= end, skip copying
116.Lcopy_loop:
117 l32i.n a5, a2, 0 // Load word from source pointer
118 s32i.n a5, a3, 0 // Store word at destination pointer
119 addi.n a3, a3, 4 // Increment destination pointer by 4 bytes
120 addi.n a2, a2, 4 // Increment source pointer by 4 bytes
121 bltu a3, a4, .Lcopy_loop // If cursor < end, repeat
122.Lcopy_done:
123 retw.n
124
125 .section .rwtext,\"ax\",@progbits
126 .global Reset
127 .p2align 2
128 .type Reset,@function
129Reset:
130 entry a1, 0
131 movi a0, 0 // Trash the return address. Debuggers may use this to stop unwinding.
132
133 wsr.intenable a0 // Disable interrupts
134
135 l32r a5, sym_stack_start_cpu0 // a5 is our temporary value register
136 mov sp, a5 // Set the stack pointer.
137
138 l32r a5, sym__pre_init
139 callx8 a5 // Call the pre-initialization function.
140
141.Linit_bss:
142 l32r a5, sym__zero_bss // Do we need to zero-initialize memory?
143 callx8 a5
144 beqz a10, .Linit_data // No -> skip to copying initialized data
145
146 l32r a10, sym_bss_start // Set input range to .bss
147 l32r a11, sym_bss_end //
148 call8 _xtensa_lx_rt_zero_fill // Zero-fill
149
150.Linit_data:
151 l32r a5, sym__init_data // Do we need to initialize data sections?
152 callx8 a5
153 beqz a10, .Linit_data_done // If not, skip initialization
154
155 l32r a10, sym_sidata // Arguments - source data pointer
156 l32r a11, sym_data_start // - destination pointer
157 l32r a12, sym_data_end // - destination end pointer
158 call8 _xtensa_lx_rt_copy // Copy .data section
159
160.Linit_data_done:
161 memw // Make sure all writes are completed before proceeding. At this point, all static variables have been initialized.
162"
163);
164
165#[cfg(any(
168 XCHAL_HAVE_TIMER0,
169 XCHAL_HAVE_TIMER1,
170 XCHAL_HAVE_TIMER2,
171 XCHAL_HAVE_TIMER3
172))]
173cfg_global_asm!(
174 #[cfg(XCHAL_HAVE_TIMER0)]
175 "wsr.ccompare0 a0",
176 #[cfg(XCHAL_HAVE_TIMER1)]
177 "wsr.ccompare1 a0",
178 #[cfg(XCHAL_HAVE_TIMER2)]
179 "wsr.ccompare2 a0",
180 #[cfg(XCHAL_HAVE_TIMER3)]
181 "wsr.ccompare3 a0",
182 "isync",
183);
184
185global_asm!(
186 "
187 l32r a5, sym_init_start // vector table address
188 wsr.vecbase a5
189
190 l32r a5, sym__post_init
191 callx8 a5
192
193 l32r a5, sym_main // program entry point
194 callx8 a5
195 ",
196);
197
198unsafe extern "C" {
202 #[cfg(XCHAL_HAVE_TIMER0)]
203 pub fn Timer0(save_frame: &mut crate::exception::Context);
204 #[cfg(XCHAL_HAVE_TIMER1)]
205 pub fn Timer1(save_frame: &mut crate::exception::Context);
206 #[cfg(XCHAL_HAVE_TIMER2)]
207 pub fn Timer2(save_frame: &mut crate::exception::Context);
208 #[cfg(XCHAL_HAVE_TIMER3)]
209 pub fn Timer3(save_frame: &mut crate::exception::Context);
210
211 #[cfg(XCHAL_HAVE_PROFILING)]
212 pub fn Profiling(save_frame: &mut crate::exception::Context);
213
214 #[cfg(XCHAL_HAVE_SOFTWARE0)]
215 pub fn Software0(save_frame: &mut crate::exception::Context);
216 #[cfg(XCHAL_HAVE_SOFTWARE1)]
217 pub fn Software1(save_frame: &mut crate::exception::Context);
218
219 #[cfg(XCHAL_HAVE_NMI)]
220 pub fn NMI(save_frame: &mut crate::exception::Context);
221}
222
223#[doc(hidden)]
224#[unsafe(no_mangle)]
225pub extern "C" fn default_mem_hook() -> bool {
226 true }
228
229#[doc(hidden)]
230#[macro_export]
231macro_rules! cfg_asm {
232 (@inner, [$($x:tt)*], [$($opts:tt)*], ) => {
233 asm!($($x)* $($opts)*)
234 };
235 (@inner, [$($x:tt)*], [$($opts:tt)*], #[cfg($meta:meta)] $asm:literal, $($rest:tt)*) => {
236 #[cfg($meta)]
237 cfg_asm!(@inner, [$($x)* $asm,], [$($opts)*], $($rest)*);
238 #[cfg(not($meta))]
239 cfg_asm!(@inner, [$($x)*], [$($opts)*], $($rest)*)
240 };
241 (@inner, [$($x:tt)*], [$($opts:tt)*], $asm:literal, $($rest:tt)*) => {
242 cfg_asm!(@inner, [$($x)* $asm,], [$($opts)*], $($rest)*)
243 };
244 ({$($asms:tt)*}, $($opts:tt)*) => {
245 cfg_asm!(@inner, [], [$($opts)*], $($asms)*)
246 };
247}
248
249#[doc(hidden)]
250#[macro_export]
251macro_rules! cfg_global_asm {
252 {@inner, [$($x:tt)*], } => {
253 global_asm!{$($x)*}
254 };
255 (@inner, [$($x:tt)*], #[cfg($meta:meta)] $asm:literal, $($rest:tt)*) => {
256 #[cfg($meta)]
257 cfg_global_asm!{@inner, [$($x)* $asm,], $($rest)*}
258 #[cfg(not($meta))]
259 cfg_global_asm!{@inner, [$($x)*], $($rest)*}
260 };
261 {@inner, [$($x:tt)*], $asm:literal, $($rest:tt)*} => {
262 cfg_global_asm!{@inner, [$($x)* $asm,], $($rest)*}
263 };
264 {$($asms:tt)*} => {
265 cfg_global_asm!{@inner, [], $($asms)*}
266 };
267}