use synth_core::{CortexMVariant, HardwareCapabilities};
pub struct ARMStartupGenerator {
hw_caps: HardwareCapabilities,
}
impl ARMStartupGenerator {
pub fn new(hw_caps: HardwareCapabilities) -> Self {
Self { hw_caps }
}
pub fn generate(&self) -> String {
let mut code = String::new();
code.push_str("/* Startup Code for ARM Cortex-M */\n");
code.push_str("/* Generated by Synth WebAssembly Component Synthesizer */\n\n");
code.push_str("#include <stdint.h>\n\n");
code.push_str("/* Linker-defined symbols */\n");
code.push_str("extern uint32_t _sidata;\n");
code.push_str("extern uint32_t _sdata;\n");
code.push_str("extern uint32_t _edata;\n");
code.push_str("extern uint32_t _sbss;\n");
code.push_str("extern uint32_t _ebss;\n");
code.push_str("extern uint32_t _stack_top;\n\n");
code.push_str("/* Core handlers */\n");
code.push_str("void Reset_Handler(void);\n");
code.push_str("void Default_Handler(void);\n\n");
code.push_str("/* Cortex-M exception handlers */\n");
code.push_str(
"void NMI_Handler(void) __attribute__((weak, alias(\"Default_Handler\")));\n",
);
code.push_str(
"void HardFault_Handler(void) __attribute__((weak, alias(\"Default_Handler\")));\n",
);
code.push_str(
"void MemManage_Handler(void) __attribute__((weak, alias(\"Default_Handler\")));\n",
);
code.push_str(
"void BusFault_Handler(void) __attribute__((weak, alias(\"Default_Handler\")));\n",
);
code.push_str(
"void UsageFault_Handler(void) __attribute__((weak, alias(\"Default_Handler\")));\n",
);
code.push_str(
"void SVC_Handler(void) __attribute__((weak, alias(\"Default_Handler\")));\n",
);
code.push_str(
"void DebugMon_Handler(void) __attribute__((weak, alias(\"Default_Handler\")));\n",
);
code.push_str(
"void PendSV_Handler(void) __attribute__((weak, alias(\"Default_Handler\")));\n",
);
code.push_str(
"void SysTick_Handler(void) __attribute__((weak, alias(\"Default_Handler\")));\n\n",
);
let num_irqs = self.get_irq_count();
if num_irqs > 0 {
code.push_str("/* Device-specific interrupt handlers */\n");
for i in 0..num_irqs {
code.push_str(&format!(
"void IRQ{}_Handler(void) __attribute__((weak, alias(\"Default_Handler\")));\n",
i
));
}
code.push('\n');
}
code.push_str("/* Vector Table */\n");
code.push_str("__attribute__((section(\".isr_vector\")))\n");
code.push_str("const void (*vectors[])(void) = {\n");
code.push_str(" (void (*)(void))(&_stack_top), /* Initial stack pointer */\n");
code.push_str(" Reset_Handler, /* Reset handler */\n");
code.push_str(" NMI_Handler, /* NMI handler */\n");
code.push_str(" HardFault_Handler, /* Hard fault handler */\n");
code.push_str(" MemManage_Handler, /* MPU fault handler */\n");
code.push_str(" BusFault_Handler, /* Bus fault handler */\n");
code.push_str(" UsageFault_Handler, /* Usage fault handler */\n");
code.push_str(" 0, /* Reserved */\n");
code.push_str(" 0, /* Reserved */\n");
code.push_str(" 0, /* Reserved */\n");
code.push_str(" 0, /* Reserved */\n");
code.push_str(" SVC_Handler, /* SVCall handler */\n");
code.push_str(" DebugMon_Handler, /* Debug monitor handler */\n");
code.push_str(" 0, /* Reserved */\n");
code.push_str(" PendSV_Handler, /* PendSV handler */\n");
code.push_str(" SysTick_Handler, /* SysTick handler */\n");
if num_irqs > 0 {
code.push_str("\n /* Device-specific interrupts */\n");
for i in 0..num_irqs {
code.push_str(&format!(" IRQ{}_Handler,\n", i));
}
}
code.push_str("};\n\n");
code.push_str("/* Reset Handler */\n");
code.push_str("void Reset_Handler(void) {\n");
code.push_str(" uint32_t *src, *dest;\n\n");
code.push_str(" /* Copy .data section from flash to RAM */\n");
code.push_str(" src = &_sidata;\n");
code.push_str(" dest = &_sdata;\n");
code.push_str(" while (dest < &_edata) {\n");
code.push_str(" *dest++ = *src++;\n");
code.push_str(" }\n\n");
code.push_str(" /* Zero out .bss section */\n");
code.push_str(" dest = &_sbss;\n");
code.push_str(" while (dest < &_ebss) {\n");
code.push_str(" *dest++ = 0;\n");
code.push_str(" }\n\n");
if self.has_fpu() {
code.push_str(" /* Enable FPU */\n");
code.push_str(" #define SCB_CPACR (*((volatile uint32_t*)0xE000ED88))\n");
code.push_str(
" SCB_CPACR |= (0xF << 20); /* Enable CP10 and CP11 coprocessors */\n",
);
code.push_str(" __asm volatile(\"dsb\\n\\tisb\");\n\n");
}
code.push_str(" /* Call main */\n");
code.push_str(" extern int main(void);\n");
code.push_str(" main();\n\n");
code.push_str(" /* Infinite loop if main returns */\n");
code.push_str(" while (1) {\n");
code.push_str(" __asm volatile(\"wfi\"); /* Wait for interrupt */\n");
code.push_str(" }\n");
code.push_str("}\n\n");
code.push_str("/* Default Handler */\n");
code.push_str("void Default_Handler(void) {\n");
code.push_str(" /* Trap unhandled interrupts */\n");
code.push_str(" while (1) {\n");
code.push_str(" __asm volatile(\"bkpt #0\"); /* Breakpoint */\n");
code.push_str(" }\n");
code.push_str("}\n");
code
}
fn get_irq_count(&self) -> usize {
match &self.hw_caps.arch {
synth_core::TargetArch::ARMCortexM(variant) => match variant {
CortexMVariant::M3 | CortexMVariant::M4 | CortexMVariant::M4F => 48,
CortexMVariant::M7 | CortexMVariant::M7DP => 64,
CortexMVariant::M33 | CortexMVariant::M55 => 64,
},
_ => 0,
}
}
fn has_fpu(&self) -> bool {
self.hw_caps.has_fpu
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_startup_code_generation() {
let hw_caps = HardwareCapabilities::nrf52840();
let generator = ARMStartupGenerator::new(hw_caps);
let startup_code = generator.generate();
println!("\nGenerated Startup Code (excerpt):");
println!(
"{}",
startup_code.lines().take(50).collect::<Vec<_>>().join("\n")
);
assert!(startup_code.contains("Reset_Handler"));
assert!(startup_code.contains("Default_Handler"));
assert!(startup_code.contains("vectors[]"));
assert!(startup_code.contains("_stack_top"));
assert!(startup_code.contains("Copy .data section"));
assert!(startup_code.contains("Zero out .bss"));
assert!(startup_code.contains("main()"));
assert!(startup_code.contains("Enable FPU"));
assert!(startup_code.contains("SCB_CPACR"));
assert!(startup_code.contains("IRQ0_Handler"));
assert!(startup_code.contains("IRQ47_Handler"));
}
#[test]
fn test_startup_code_without_fpu() {
let hw_caps = HardwareCapabilities {
arch: synth_core::TargetArch::ARMCortexM(CortexMVariant::M3),
has_mpu: true,
mpu_regions: 8,
has_pmp: false,
pmp_entries: 0,
has_fpu: false, fpu_precision: None,
has_simd: false,
simd_level: None,
xip_capable: true,
flash_size: 512 * 1024,
ram_size: 128 * 1024,
};
let generator = ARMStartupGenerator::new(hw_caps);
let startup_code = generator.generate();
assert!(!startup_code.contains("Enable FPU"));
}
}