@@ -33,8 +33,25 @@ pub const InterruptOptions = microzig.utilities.GenerateInterruptOptions(&.{
3333 .{ .InterruptEnum = Interrupt , .HandlerFn = Handler },
3434});
3535
36- /// Allowable `platform` options for microzig.options.
37- pub const CPU_Options = core .CPU_Options ;
36+ /// Allowable `cpu` options for microzig.options.
37+ pub const CPU_Options = struct {
38+ /// If true, interrupt vectors are moved to RAM so handlers can be set at runtime.
39+ ///
40+ /// NOTE: Not supported on cortex_m0.
41+ ram_vector_table : bool = false ,
42+
43+ /// If true, the Cortex-M interrupts will be initialized with a more verbose variant
44+ /// of the interrupt handlers which print the interrupt name.
45+ ///
46+ /// NOTE: This option is enabled in debug builds by default.
47+ verbose_unhandled_irq : bool = (builtin .mode == .Debug ),
48+
49+ /// If true, the FPU will be enabled in the startup code.
50+ ///
51+ /// NOTE: This option is enabled by default if hard float is enabled.
52+ /// NOTE: Not supported on cortex_m0, cortex_m0plus and cortex_m3.
53+ enable_fpu : bool = builtin .abi .float () == .hard ,
54+ };
3855
3956/// External Interrupts
4057/// These are the interrupts generated by the NVIC.
@@ -643,6 +660,37 @@ pub const atomic = struct {
643660 }
644661};
645662
663+ /// Enables the FPU.
664+ ///
665+ /// NOTE: This function is automatically called on cpu startup if the cpu has
666+ /// an fpu and hard float is enabled. HALs also call this in the startup of
667+ /// other cores.
668+ pub inline fn enable_fpu () void {
669+ switch (cortex_m ) {
670+ inline .cortex_m0 ,
671+ .cortex_m0plus ,
672+ .cortex_m3 ,
673+ = > | flavour | @compileError ("FPU not supported on " ++ @tagName (flavour )),
674+ else = > {},
675+ }
676+
677+ // Taken from the rust crate cortex-m-rt.
678+ asm volatile (
679+ \\ldr r0, =0xE000ED88
680+ \\ldr r1, =(0b1111 << 20)
681+ \\ldr r2, [r0]
682+ \\orr r2, r2, r1
683+ \\str r2, [r0]
684+ \\dsb
685+ \\isb
686+ ::: .{
687+ .r0 = true ,
688+ .r1 = true ,
689+ .r2 = true ,
690+ .memory = true ,
691+ });
692+ }
693+
646694/// The RAM vector table used. You can swap interrupt handlers at runtime here.
647695/// Available when using a RAM vector table or a RAM image.
648696pub var ram_vector_table : VectorTable align (256 ) = if (using_ram_vector_table or is_ram_image )
654702pub const startup_logic = struct {
655703 extern fn microzig_main () noreturn ;
656704
657- pub fn ram_image_start () linksection ("microzig_ram_start" ) callconv (.naked ) void {
705+ pub fn ram_image_start () linksection ("microzig_ram_start" ) callconv (.naked ) noreturn {
658706 const eos = comptime microzig .utilities .get_end_of_stack ();
659707 asm volatile (
660708 \\
@@ -672,6 +720,11 @@ pub const startup_logic = struct {
672720 microzig .utilities .initialize_system_memories (.auto );
673721
674722 if (using_ram_vector_table or is_ram_image ) {
723+ switch (cortex_m ) {
724+ .cortex_m0 = > @compileError ("RAM image and RAM vector table are not supported on cortex_m0" ),
725+ else = > {},
726+ }
727+
675728 asm volatile (
676729 \\
677730 // Set VTOR to point to ram table
@@ -684,6 +737,25 @@ pub const startup_logic = struct {
684737 : .{ .memory = true , .r0 = true , .r1 = true });
685738 }
686739
740+ if (fpu_present and microzig .options .cpu .enable_fpu ) {
741+ enable_fpu ();
742+ } else if (! fpu_present and microzig .options .cpu .enable_fpu ) {
743+ @compileError (
744+ \\FPU enable requested though the chip doesn't appear to have an
745+ \\FPU. If your chip does have an FPU please add the `fpu_present`
746+ \\equal to `true` property to your chip file, either manually or via
747+ \\patches. If you want to use patches, you can use something like
748+ \\this:
749+ \\```
750+ \\.{ .set_device_property = .{
751+ \\ .device_name = "CHIP_NAME",
752+ \\ .key = "fpu_present",
753+ \\ .value = "true"
754+ \\} },
755+ \\```
756+ );
757+ }
758+
687759 if (@hasField (types .peripherals .SystemControlBlock , "SHCSR" )) {
688760 // Enable distinction between MemFault, BusFault and UsageFault:
689761 peripherals .scb .SHCSR .modify (.{
@@ -694,7 +766,9 @@ pub const startup_logic = struct {
694766 enable_fault_irq ();
695767 }
696768
697- microzig_main ();
769+ // If the compiler gets too aggressive with inlining we might get some
770+ // floating point operations before the FPU is enabled.
771+ @call (.never_inline , microzig_main , .{});
698772 }
699773
700774 // Validate that the VectorTable type has all the fault handlers that the CPU expects
@@ -970,10 +1044,17 @@ const scb_base = scs_base + core.scb_base_offset;
9701044const mpu_base = scs_base + 0x0D90 ;
9711045const fpu_base = scs_base + 0x0F34 ;
9721046
973- const properties = microzig .chip .properties ;
9741047// TODO: will have to standardize this with regz code generation
975- const mpu_present = @hasDecl (properties , "cpu.mpuPresent" ) and std .mem .eql (u8 , properties .@"cpu.mpuPresent" , "true" );
976- const fpu_present = @hasDecl (properties , "cpu.fpuPresent" ) and std .mem .eql (u8 , properties .@"cpu.fpuPresent" , "true" );
1048+ const mpu_present = @hasDecl (microzig .chip , "properties" ) and
1049+ @hasDecl (microzig .chip .properties , "mpu_present" ) and
1050+ is_property_true (microzig .chip .properties .mpu_present );
1051+ const fpu_present = @hasDecl (microzig .chip , "properties" ) and
1052+ @hasDecl (microzig .chip .properties , "fpu_present" ) and
1053+ is_property_true (microzig .chip .properties .fpu_present );
1054+
1055+ fn is_property_true (value : []const u8 ) bool {
1056+ return std .mem .eql (u8 , value , "true" ) or std .mem .eql (u8 , value , "1" );
1057+ }
9771058
9781059const core = blk : {
9791060 break :blk switch (cortex_m ) {
0 commit comments