synth_backend/
arm_startup.rs1use synth_core::{CortexMVariant, HardwareCapabilities};
6
7pub struct ARMStartupGenerator {
9 hw_caps: HardwareCapabilities,
10}
11
12impl ARMStartupGenerator {
13 pub fn new(hw_caps: HardwareCapabilities) -> Self {
15 Self { hw_caps }
16 }
17
18 pub fn generate(&self) -> String {
20 let mut code = String::new();
21
22 code.push_str("/* Startup Code for ARM Cortex-M */\n");
23 code.push_str("/* Generated by Synth WebAssembly Component Synthesizer */\n\n");
24 code.push_str("#include <stdint.h>\n\n");
25
26 code.push_str("/* Linker-defined symbols */\n");
28 code.push_str("extern uint32_t _sidata;\n");
29 code.push_str("extern uint32_t _sdata;\n");
30 code.push_str("extern uint32_t _edata;\n");
31 code.push_str("extern uint32_t _sbss;\n");
32 code.push_str("extern uint32_t _ebss;\n");
33 code.push_str("extern uint32_t _stack_top;\n\n");
34
35 code.push_str("/* Core handlers */\n");
37 code.push_str("void Reset_Handler(void);\n");
38 code.push_str("void Default_Handler(void);\n\n");
39
40 code.push_str("/* Cortex-M exception handlers */\n");
42 code.push_str(
43 "void NMI_Handler(void) __attribute__((weak, alias(\"Default_Handler\")));\n",
44 );
45 code.push_str(
46 "void HardFault_Handler(void) __attribute__((weak, alias(\"Default_Handler\")));\n",
47 );
48 code.push_str(
49 "void MemManage_Handler(void) __attribute__((weak, alias(\"Default_Handler\")));\n",
50 );
51 code.push_str(
52 "void BusFault_Handler(void) __attribute__((weak, alias(\"Default_Handler\")));\n",
53 );
54 code.push_str(
55 "void UsageFault_Handler(void) __attribute__((weak, alias(\"Default_Handler\")));\n",
56 );
57 code.push_str(
58 "void SVC_Handler(void) __attribute__((weak, alias(\"Default_Handler\")));\n",
59 );
60 code.push_str(
61 "void DebugMon_Handler(void) __attribute__((weak, alias(\"Default_Handler\")));\n",
62 );
63 code.push_str(
64 "void PendSV_Handler(void) __attribute__((weak, alias(\"Default_Handler\")));\n",
65 );
66 code.push_str(
67 "void SysTick_Handler(void) __attribute__((weak, alias(\"Default_Handler\")));\n\n",
68 );
69
70 let num_irqs = self.get_irq_count();
72 if num_irqs > 0 {
73 code.push_str("/* Device-specific interrupt handlers */\n");
74 for i in 0..num_irqs {
75 code.push_str(&format!(
76 "void IRQ{}_Handler(void) __attribute__((weak, alias(\"Default_Handler\")));\n",
77 i
78 ));
79 }
80 code.push('\n');
81 }
82
83 code.push_str("/* Vector Table */\n");
85 code.push_str("__attribute__((section(\".isr_vector\")))\n");
86 code.push_str("const void (*vectors[])(void) = {\n");
87 code.push_str(" (void (*)(void))(&_stack_top), /* Initial stack pointer */\n");
88 code.push_str(" Reset_Handler, /* Reset handler */\n");
89 code.push_str(" NMI_Handler, /* NMI handler */\n");
90 code.push_str(" HardFault_Handler, /* Hard fault handler */\n");
91 code.push_str(" MemManage_Handler, /* MPU fault handler */\n");
92 code.push_str(" BusFault_Handler, /* Bus fault handler */\n");
93 code.push_str(" UsageFault_Handler, /* Usage fault handler */\n");
94 code.push_str(" 0, /* Reserved */\n");
95 code.push_str(" 0, /* Reserved */\n");
96 code.push_str(" 0, /* Reserved */\n");
97 code.push_str(" 0, /* Reserved */\n");
98 code.push_str(" SVC_Handler, /* SVCall handler */\n");
99 code.push_str(" DebugMon_Handler, /* Debug monitor handler */\n");
100 code.push_str(" 0, /* Reserved */\n");
101 code.push_str(" PendSV_Handler, /* PendSV handler */\n");
102 code.push_str(" SysTick_Handler, /* SysTick handler */\n");
103
104 if num_irqs > 0 {
106 code.push_str("\n /* Device-specific interrupts */\n");
107 for i in 0..num_irqs {
108 code.push_str(&format!(" IRQ{}_Handler,\n", i));
109 }
110 }
111
112 code.push_str("};\n\n");
113
114 code.push_str("/* Reset Handler */\n");
116 code.push_str("void Reset_Handler(void) {\n");
117 code.push_str(" uint32_t *src, *dest;\n\n");
118
119 code.push_str(" /* Copy .data section from flash to RAM */\n");
120 code.push_str(" src = &_sidata;\n");
121 code.push_str(" dest = &_sdata;\n");
122 code.push_str(" while (dest < &_edata) {\n");
123 code.push_str(" *dest++ = *src++;\n");
124 code.push_str(" }\n\n");
125
126 code.push_str(" /* Zero out .bss section */\n");
127 code.push_str(" dest = &_sbss;\n");
128 code.push_str(" while (dest < &_ebss) {\n");
129 code.push_str(" *dest++ = 0;\n");
130 code.push_str(" }\n\n");
131
132 if self.has_fpu() {
134 code.push_str(" /* Enable FPU */\n");
135 code.push_str(" #define SCB_CPACR (*((volatile uint32_t*)0xE000ED88))\n");
136 code.push_str(
137 " SCB_CPACR |= (0xF << 20); /* Enable CP10 and CP11 coprocessors */\n",
138 );
139 code.push_str(" __asm volatile(\"dsb\\n\\tisb\");\n\n");
140 }
141
142 code.push_str(" /* Call main */\n");
143 code.push_str(" extern int main(void);\n");
144 code.push_str(" main();\n\n");
145
146 code.push_str(" /* Infinite loop if main returns */\n");
147 code.push_str(" while (1) {\n");
148 code.push_str(" __asm volatile(\"wfi\"); /* Wait for interrupt */\n");
149 code.push_str(" }\n");
150 code.push_str("}\n\n");
151
152 code.push_str("/* Default Handler */\n");
154 code.push_str("void Default_Handler(void) {\n");
155 code.push_str(" /* Trap unhandled interrupts */\n");
156 code.push_str(" while (1) {\n");
157 code.push_str(" __asm volatile(\"bkpt #0\"); /* Breakpoint */\n");
158 code.push_str(" }\n");
159 code.push_str("}\n");
160
161 code
162 }
163
164 fn get_irq_count(&self) -> usize {
166 match &self.hw_caps.arch {
169 synth_core::TargetArch::ARMCortexM(variant) => match variant {
170 CortexMVariant::M3 | CortexMVariant::M4 | CortexMVariant::M4F => 48,
171 CortexMVariant::M7 | CortexMVariant::M7DP => 64,
172 CortexMVariant::M33 | CortexMVariant::M55 => 64,
173 },
174 _ => 0,
175 }
176 }
177
178 fn has_fpu(&self) -> bool {
180 self.hw_caps.has_fpu
181 }
182}
183
184#[cfg(test)]
185mod tests {
186 use super::*;
187
188 #[test]
189 fn test_startup_code_generation() {
190 let hw_caps = HardwareCapabilities::nrf52840();
191 let generator = ARMStartupGenerator::new(hw_caps);
192
193 let startup_code = generator.generate();
194
195 println!("\nGenerated Startup Code (excerpt):");
197 println!(
198 "{}",
199 startup_code.lines().take(50).collect::<Vec<_>>().join("\n")
200 );
201
202 assert!(startup_code.contains("Reset_Handler"));
204 assert!(startup_code.contains("Default_Handler"));
205 assert!(startup_code.contains("vectors[]"));
206 assert!(startup_code.contains("_stack_top"));
207 assert!(startup_code.contains("Copy .data section"));
208 assert!(startup_code.contains("Zero out .bss"));
209 assert!(startup_code.contains("main()"));
210
211 assert!(startup_code.contains("Enable FPU"));
213 assert!(startup_code.contains("SCB_CPACR"));
214
215 assert!(startup_code.contains("IRQ0_Handler"));
217 assert!(startup_code.contains("IRQ47_Handler"));
218 }
219
220 #[test]
221 fn test_startup_code_without_fpu() {
222 let hw_caps = HardwareCapabilities {
223 arch: synth_core::TargetArch::ARMCortexM(CortexMVariant::M3),
224 has_mpu: true,
225 mpu_regions: 8,
226 has_pmp: false,
227 pmp_entries: 0,
228 has_fpu: false, fpu_precision: None,
230 has_simd: false,
231 simd_level: None,
232 xip_capable: true,
233 flash_size: 512 * 1024,
234 ram_size: 128 * 1024,
235 };
236
237 let generator = ARMStartupGenerator::new(hw_caps);
238 let startup_code = generator.generate();
239
240 assert!(!startup_code.contains("Enable FPU"));
242 }
243}