From 733ba7b4f9158f97ba40a48315278b8d462c4ecf Mon Sep 17 00:00:00 2001 From: RecursiveError Date: Thu, 20 Feb 2025 15:39:32 -0300 Subject: [PATCH] update doc --- core/src/core/experimental.zig | 4 +++ core/src/core/experimental/semihosting.zig | 38 ++++++++++++++++++++-- examples/stmicro/stm32/build.zig | 2 +- 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/core/src/core/experimental.zig b/core/src/core/experimental.zig index ab28ad24..be832cb1 100644 --- a/core/src/core/experimental.zig +++ b/core/src/core/experimental.zig @@ -10,4 +10,8 @@ pub const i2c = @import("experimental/i2c.zig"); pub const Pin = @import("experimental/pin.zig").Pin; pub const spi = @import("experimental/spi.zig"); pub const uart = @import("experimental/uart.zig"); + +///semihosting requires a valid host session, either via a simulator or via a debug probe, otherwise the code will always result in a halt. +///This implementation only supports Arm-M. +///More info: https://github.com/ARM-software/abi-aa/blob/main/semihosting/semihosting.rst pub const ARM_semihosting = @import("experimental/semihosting.zig"); diff --git a/core/src/core/experimental/semihosting.zig b/core/src/core/experimental/semihosting.zig index d36c38d3..c9000981 100644 --- a/core/src/core/experimental/semihosting.zig +++ b/core/src/core/experimental/semihosting.zig @@ -30,6 +30,13 @@ pub const Debug = struct { subcode: usize, }; + pub const MemInfo = extern struct { + heap_base: *anyopaque, + heap_limit: *anyopaque, + stack_base: *anyopaque, + stack_limit: *anyopaque, + }; + //WriteC and Write0 write direct to the Debug terminal, no context need const Writer = std.io.Writer(void, anyerror, writerfn); @@ -66,11 +73,12 @@ pub const Debug = struct { dbg_w.print(fmt, args) catch return; } - //get C errno value + ///get C errno value pub fn get_errno() usize { resume @as(usize, @bitCast(sys_errno())); } - ///get ARGV from the command line. + + ///get data from the command line. /// NOTE: The semihosting implementation might impose limits on the maximum length of the string that can be transferred. /// However, the implementation must be able to support a command-line length of at least 80 bytes. pub fn get_cmd_args(buffer: []u8) anyerror![]const u8 { @@ -82,6 +90,7 @@ pub const Debug = struct { return if (ret == 0) cmd.buffer[0..cmd.len] else error.Fail; } + //currently the semihost specification defines only 2 extensions, where both belong to the same extension byte. pub fn check_extensions(feature_byte: usize, feature_bit: u3) bool { const MAGIC: [4]u8 = .{ 0x53, 0x48, 0x46, 0x42 }; var magic_buffer: [4]u8 = undefined; @@ -121,17 +130,29 @@ pub const Debug = struct { return try fs.open(":tt", .@"A+"); } + pub fn system_memory() MemInfo { + var mem: MemInfo = undefined; + sys_heapinfo(&mem); + return mem; + } + + ///Signals an exception to the debugger + /// NOTE: Not all semihosting client implementations will necessarily trap every corresponding event. + /// NOTE: It is possible for the debugger to request that the application continues by performing an RDI_Execute request or equivalent. pub fn panic(reason: PanicCodes, subcode: usize) void { const data = PanicData{ .reason = @intFromEnum(reason) + 0x20000, .subcode = subcode, }; - //check for EXIT_EXT + //check for EXIT_EXT + //when the exit extension is not implemented on 32bit targets + //sys_exit does not receive "exit code" if (check_extensions(0, 0)) { _ = sys_exit_ext(&data); } else { //ARM-A/M 32bit only + //on 32bit targets sys_exit receives data by value and not by reference _ = sys_exit(@ptrFromInt(data.reason)); } } @@ -330,6 +351,7 @@ pub const Syscalls = enum(usize) { WRITE0 = 0x04, SYS_WRITE = 0x05, SYS_READ = 0x06, + SYS_ISERROR = 0x08, SYS_ISTTY = 0x09, SYS_SEEK = 0x0A, SYS_FLEN = 0x0C, @@ -339,6 +361,7 @@ pub const Syscalls = enum(usize) { SYS_TIME = 0x11, SYS_ERRNO = 0x13, SYS_GET_CMD_LINE = 0x15, + SYS_HEAPINFO = 0x16, SYS_EXIT = 0x18, SYS_EXIT_EXTENDED = 0x20, SYS_ELAPSED = 0x30, @@ -401,6 +424,11 @@ pub inline fn sys_rename(file: [*]const fs.Path) isize { return call(.SYS_RENAME, file); } +//only useful when using syscalls directly +pub inline fn sys_iserror(ret_code: *const isize) bool { + return call(.SYS_ISERROR, ret_code) != 0; +} + pub inline fn sys_istty(file: *const fs.File) isize { return call(.SYS_ISTTY, file); } @@ -421,6 +449,10 @@ pub inline fn sys_cmd_line(args: *Debug.Argv) isize { return call(.SYS_GET_CMD_LINE, args); } +pub inline fn sys_heapinfo(args: *Debug.MemInfo) void { + _ = call(.SYS_HEAPINFO, args); +} + pub inline fn sys_exit(args: *const Debug.PanicData) isize { return call(.SYS_EXIT, args); } diff --git a/examples/stmicro/stm32/build.zig b/examples/stmicro/stm32/build.zig index 101916af..7ea2a11b 100644 --- a/examples/stmicro/stm32/build.zig +++ b/examples/stmicro/stm32/build.zig @@ -15,7 +15,6 @@ pub fn build(b: *std.Build) void { const available_examples = [_]Example{ .{ .target = stm32.chips.STM32F103C8, .name = "STM32F103C8", .file = "src/blinky.zig" }, .{ .target = stm32.boards.stm32f3discovery, .name = "stm32f3discovery", .file = "src/blinky.zig" }, - .{ .target = stm32.chips.STM32F100RB, .name = "STM32F1_semihost", .file = "src/semihosting.zig" }, //set a valid qemu target for test semihosting // TODO: stm32.pins.GlobalConfiguration is not available on those targets // .{ .target = stm32.chips.stm32f303vc, .name = "stm32f303vc", .file = "src/blinky.zig" }, // .{ .target = stm32.chips.stm32f407vg, .name = "stm32f407vg", .file = "src/blinky.zig" }, @@ -23,6 +22,7 @@ pub fn build(b: *std.Build) void { // .{ .target = stm32.boards.stm32f4discovery, .name = "stm32f4discovery", .file = "src/blinky.zig" }, // .{ .target = stm32.boards.stm3240geval, .name = "stm3240geval", .file = "src/blinky.zig" }, // .{ .target = stm32.boards.stm32f429idiscovery, .name = "stm32f429idiscovery", .file = "src/blinky.zig" }, + .{ .target = stm32.chips.STM32F100RB, .name = "STM32F1_semihost", .file = "src/semihosting.zig" }, //QEMU target: stm32vldiscovery }; for (available_examples) |example| {