diff --git a/build-internals/build.zig b/build-internals/build.zig index ca7866944..8a157f522 100644 --- a/build-internals/build.zig +++ b/build-internals/build.zig @@ -57,6 +57,9 @@ pub const Target = struct { /// (optional) Provide a custom linker script for the hardware or define a custom generation. linker_script: ?LazyPath = null, + /// (Optional) Explicitly set the entry point + entry: ?Build.Step.Compile.Entry = null, + /// (optional) Post processing step that will patch up and modify the elf file if necessary. patch_elf: ?*const fn (*Build.Dependency, LazyPath) LazyPath = null, @@ -71,6 +74,7 @@ pub const Target = struct { hal: ?HardwareAbstractionLayer = null, board: ?Board = null, linker_script: ?LazyPath = null, + entry: ?Build.Step.Compile.Entry = null, patch_elf: ?*const fn (*Build.Dependency, LazyPath) LazyPath = null, }; @@ -88,6 +92,7 @@ pub const Target = struct { .hal = options.hal orelse from.hal, .board = options.board orelse from.board, .linker_script = options.linker_script orelse from.linker_script, + .entry = options.entry orelse from.entry, .patch_elf = options.patch_elf orelse from.patch_elf, }; return ret; diff --git a/build.zig b/build.zig index 3f031881e..065a20429 100644 --- a/build.zig +++ b/build.zig @@ -332,6 +332,9 @@ pub fn MicroBuild(port_select: PortSelect) type { /// If set, overrides the `linker_script` property of the target. linker_script: ?LazyPath = null, + /// If set, overrides the default `entry` property of the arget. + entry: ?Build.Step.Compile.Entry = null, + /// Strips stack trace info from final executable. strip: bool = false, @@ -538,6 +541,7 @@ pub fn MicroBuild(port_select: PortSelect) type { fw.artifact.link_gc_sections = options.strip_unused_symbols; fw.artifact.link_function_sections = options.strip_unused_symbols; fw.artifact.link_data_sections = options.strip_unused_symbols; + fw.artifact.entry = options.entry orelse target.entry orelse .default; fw.artifact.root_module.addImport("microzig", core_mod); fw.artifact.root_module.addImport("app", app_mod); diff --git a/core/src/cpus/cortex_m.zig b/core/src/cpus/cortex_m.zig index 07953015b..5421da9b6 100644 --- a/core/src/cpus/cortex_m.zig +++ b/core/src/cpus/cortex_m.zig @@ -587,49 +587,68 @@ pub const startup_logic = struct { extern var microzig_bss_end: u8; extern const microzig_data_load_start: u8; + pub fn ram_image_entrypoint() linksection(".entry") callconv(.naked) void { + asm volatile ( + \\ + // Set VTOR to point to ram table + \\mov r0, %[_vector_table] + \\mov r1, %[_VTOR_ADDRESS] + \\str r0, [r1] + // Set up stack and jump to _start + \\ldm r0!, {r1, r2} + \\msr msp, r1 + \\bx r2 + : + : [_vector_table] "r" (&startup_logic._vector_table), + [_VTOR_ADDRESS] "r" (&peripherals.scb.VTOR), + : "memory", "r0", "r1", "r2" + ); + } + pub fn _start() callconv(.c) noreturn { + if (comptime !is_ramimage()) { + // fill .bss with zeroes + { + const bss_start: [*]u8 = @ptrCast(µzig_bss_start); + const bss_end: [*]u8 = @ptrCast(µzig_bss_end); + const bss_len = @intFromPtr(bss_end) - @intFromPtr(bss_start); + + @memset(bss_start[0..bss_len], 0); + } - // fill .bss with zeroes - { - const bss_start: [*]u8 = @ptrCast(µzig_bss_start); - const bss_end: [*]u8 = @ptrCast(µzig_bss_end); - const bss_len = @intFromPtr(bss_end) - @intFromPtr(bss_start); + // load .data from flash + { + const data_start: [*]u8 = @ptrCast(µzig_data_start); + const data_end: [*]u8 = @ptrCast(µzig_data_end); + const data_len = @intFromPtr(data_end) - @intFromPtr(data_start); + const data_src: [*]const u8 = @ptrCast(µzig_data_load_start); - @memset(bss_start[0..bss_len], 0); - } + @memcpy(data_start[0..data_len], data_src[0..data_len]); + } - // load .data from flash - { - const data_start: [*]u8 = @ptrCast(µzig_data_start); - const data_end: [*]u8 = @ptrCast(µzig_data_end); - const data_len = @intFromPtr(data_end) - @intFromPtr(data_start); - const data_src: [*]const u8 = @ptrCast(µzig_data_load_start); + // Move vector table to RAM if requested + if (interrupt.has_ram_vectors()) { + // Copy vector table to RAM and set VTOR to point to it - @memcpy(data_start[0..data_len], data_src[0..data_len]); - } + if (comptime interrupt.has_ram_vectors_section()) { + @export(&ram_vectors, .{ + .name = "_ram_vectors", + .section = "ram_vectors", + .linkage = .strong, + }); + } else { + @export(&ram_vectors, .{ + .name = "_ram_vectors", + .linkage = .strong, + }); + } - // Move vector table to RAM if requested - if (interrupt.has_ram_vectors()) { - // Copy vector table to RAM and set VTOR to point to it - - if (interrupt.has_ram_vectors_section()) { - @export(&ram_vectors, .{ - .name = "_ram_vectors", - .section = "ram_vectors", - .linkage = .strong, - }); - } else { - @export(&ram_vectors, .{ - .name = "_ram_vectors", - .linkage = .strong, - }); - } - - const flash_vector: [*]const usize = @ptrCast(&_vector_table); + const flash_vector: [*]const usize = @ptrCast(&_vector_table); - @memcpy(ram_vectors[0..vector_count], flash_vector[0..vector_count]); + @memcpy(ram_vectors[0..vector_count], flash_vector[0..vector_count]); - peripherals.scb.VTOR = @intFromPtr(&ram_vectors); + peripherals.scb.VTOR = @intFromPtr(&ram_vectors); + } } microzig_main(); @@ -655,14 +674,28 @@ pub const startup_logic = struct { }; }; +fn is_ramimage() bool { + // HACK + // TODO: Use microzig_options? + if (microzig.config.board_name) |board_name| + return std.mem.containsAtLeast(u8, board_name, 1, "ram image"); + return false; +} + pub fn export_startup_logic() void { + if (is_ramimage()) + @export(&startup_logic.ram_image_entrypoint, .{ + .name = "_entry_point", + .linkage = .strong, + }); + @export(&startup_logic._start, .{ .name = "_start", }); @export(&startup_logic._vector_table, .{ .name = "_vector_table", - .section = "microzig_flash_start", + .section = ".isr_vector", .linkage = .strong, }); } diff --git a/examples/raspberrypi/rp2xxx/build.zig b/examples/raspberrypi/rp2xxx/build.zig index 13ce2f48a..4fa403a2d 100644 --- a/examples/raspberrypi/rp2xxx/build.zig +++ b/examples/raspberrypi/rp2xxx/build.zig @@ -12,7 +12,7 @@ pub fn build(b: *std.Build) void { const mz_dep = b.dependency("microzig", .{}); const mb = MicroBuild.init(b, mz_dep) orelse return; - const rp2040_only_examples: []const Example = &.{ + const specific_examples: []const Example = &.{ // RaspberryPi Boards: .{ .target = mb.ports.rp2xxx.boards.raspberrypi.pico, .name = "pico_flash-program", .file = "src/rp2040_only/flash_program.zig" }, .{ .target = mb.ports.rp2xxx.boards.raspberrypi.pico, .name = "pico_flash-id", .file = "src/rp2040_only/flash_id.zig" }, @@ -23,18 +23,15 @@ pub fn build(b: *std.Build) void { .{ .target = mb.ports.rp2xxx.boards.raspberrypi.pico, .name = "pico_hd44780", .file = "src/rp2040_only/hd44780.zig" }, .{ .target = mb.ports.rp2xxx.boards.raspberrypi.pico, .name = "pico_pcf8574", .file = "src/rp2040_only/pcf8574.zig" }, .{ .target = mb.ports.rp2xxx.boards.raspberrypi.pico, .name = "pico_i2c_slave", .file = "src/rp2040_only/i2c_slave.zig" }, + .{ .target = mb.ports.rp2xxx.boards.raspberrypi.pico_flashless, .name = "pico_flashless_blinky", .file = "src/blinky.zig" }, // WaveShare Boards: - .{ .target = mb.ports.rp2xxx.boards.waveshare.rp2040_matrix, .name = "rp2040-matrix_tiles", .file = "src/rp2040_only/tiles.zig" }, + .{ .target = mb.ports.rp2xxx.boards.waveshare.rp2040_matrix, .name = "rp2040_matrix_tiles", .file = "src/rp2040_only/tiles.zig" }, // .{ .target = "board:waveshare/rp2040_eth", .name = "rp2040-eth" }, // .{ .target = "board:waveshare/rp2040_plus_4m", .name = "rp2040-plus-4m" }, // .{ .target = "board:waveshare/rp2040_plus_16m", .name = "rp2040-plus-16m" }, }; - const rp2350_only_examples: []const Example = &.{ - // TODO: No RP2350 feature specific examples to show off yet - }; - const chip_agnostic_examples: []const ChipAgnosticExample = &.{ .{ .name = "adc", .file = "src/adc.zig" }, .{ .name = "i2c-bus-scan", .file = "src/i2c_bus_scan.zig" }, @@ -60,8 +57,7 @@ pub fn build(b: *std.Build) void { }; var available_examples = std.ArrayList(Example).init(b.allocator); - available_examples.appendSlice(rp2040_only_examples) catch @panic("out of memory"); - available_examples.appendSlice(rp2350_only_examples) catch @panic("out of memory"); + available_examples.appendSlice(specific_examples) catch @panic("out of memory"); for (chip_agnostic_examples) |example| { available_examples.append(.{ .target = mb.ports.rp2xxx.boards.raspberrypi.pico, diff --git a/port/raspberrypi/rp2xxx/build.zig b/port/raspberrypi/rp2xxx/build.zig index 113ec6536..b92965d18 100644 --- a/port/raspberrypi/rp2xxx/build.zig +++ b/port/raspberrypi/rp2xxx/build.zig @@ -15,6 +15,7 @@ boards: struct { }, raspberrypi: struct { pico: *const microzig.Target, + pico_flashless: *const microzig.Target, pico2_arm: *const microzig.Target, pico2_riscv: *const microzig.Target, }, @@ -163,6 +164,15 @@ pub fn init(dep: *std.Build.Dependency) Self { .imports = rp2040_bootrom_imports, }, }), + .pico_flashless = chip_rp2040.derive(.{ + .entry = .{ .symbol_name = "_entry_point" }, + .linker_script = b.path("rp2040_ram_image.ld"), + .board = .{ + .name = "RaspberryPi Pico (ram image)", + .url = "https://www.raspberrypi.com/products/raspberry-pi-pico/", + .root_source_file = b.path("src/boards/raspberry_pi_pico2.zig"), + }, + }), .pico2_arm = chip_rp2350_arm.derive(.{ .board = .{ .name = "RaspberryPi Pico 2", diff --git a/port/raspberrypi/rp2xxx/rp2040.ld b/port/raspberrypi/rp2xxx/rp2040.ld index 96bc53f02..1af1e86db 100644 --- a/port/raspberrypi/rp2xxx/rp2040.ld +++ b/port/raspberrypi/rp2xxx/rp2040.ld @@ -26,7 +26,7 @@ SECTIONS .text : { - KEEP(*(microzig_flash_start)) + KEEP(*(.isr_vector)) *(.text*) *(.rodata*) } > flash0 diff --git a/port/raspberrypi/rp2xxx/rp2040_ram_image.ld b/port/raspberrypi/rp2xxx/rp2040_ram_image.ld new file mode 100644 index 000000000..ed36bf7df --- /dev/null +++ b/port/raspberrypi/rp2xxx/rp2040_ram_image.ld @@ -0,0 +1,50 @@ +/* + * Target CPU: ARM Cortex-M0+ + * Target Chip: RP2040 + */ + +MEMORY +{ + entry (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00000100 + ram0 (rwx) : ORIGIN = 0x20000100, LENGTH = 0x0003ff00 +} + +SECTIONS +{ + .entry : + { + KEEP(*(.entry)) + } > entry + + .text : + { + KEEP(*(.isr_vector)) + *(.text*) + *(.rodata*) + } > ram0 + + .ARM.extab : { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > ram0 + + .ARM.exidx : { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > ram0 + + .data : + { + *(.data*) + } > ram0 + + .bss : + { + *(.bss*) + } > ram0 + + /* Unused, but set as extern in startup_logic */ + microzig_data_start = .; + microzig_data_end = .; + microzig_bss_start = .; + microzig_bss_end = .; + microzig_data_load_start = .; +}