diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f07c87fda..958107ca7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ on: workflow_dispatch: env: - ZIG_VERSION: 0.14.1 + ZIG_VERSION: 0.15.1 jobs: formatting-check: @@ -221,7 +221,7 @@ jobs: - name: Setup Zig uses: mlugg/setup-zig@v2 with: - version: 0.14.1 + version: 0.15.1 - name: Build Website run: zig build working-directory: website diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 2136dbc61..196df1259 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -23,7 +23,7 @@ jobs: - name: Setup Zig uses: mlugg/setup-zig@v2 with: - version: 0.14.1 + version: 0.15.1 - name: Extract version run: echo "MICROZIG_VERSION=$(zig build package -- get-version)" >> $GITHUB_ENV diff --git a/.github/workflows/drivers.yaml b/.github/workflows/drivers.yaml index 3f5938910..7f510ffd8 100644 --- a/.github/workflows/drivers.yaml +++ b/.github/workflows/drivers.yaml @@ -20,7 +20,7 @@ jobs: - name: Setup Zig uses: mlugg/setup-zig@v2 with: - version: 0.14.1 + version: 0.15.1 - name: Run Test Suite working-directory: drivers diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 1ee1e9465..2ee189374 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -20,7 +20,7 @@ jobs: - name: Setup Zig uses: mlugg/setup-zig@v2 with: - version: 0.14.1 + version: 0.15.1 - name: Build linter working-directory: tools/linter @@ -45,8 +45,7 @@ jobs: echo "Lint results:" cat lint_results.json - - - name: Post comments with metadata + - name: Post review with grouped comments uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} @@ -62,58 +61,126 @@ jobs: const content = fs.readFileSync('lint_results.json', 'utf8').trim(); if (!content || content === '[]') { console.log('No lint issues found'); + + // Check if there's an existing review to dismiss + const existingReviews = await github.rest.pulls.listReviews({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number + }); + + const botReview = existingReviews.data.find(review => + review.user.login === 'github-actions[bot]' && + review.body && review.body.includes('') + ); + + if (botReview) { + await github.rest.pulls.dismissReview({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number, + review_id: botReview.id, + message: 'All lint issues have been resolved' + }); + console.log('Dismissed previous lint review - no issues found'); + } return; } const issues = JSON.parse(content); - const existingComments = await github.rest.pulls.listReviewComments({ + // Check for existing bot review + const existingReviews = await github.rest.pulls.listReviews({ owner: context.repo.owner, repo: context.repo.repo, pull_number: context.issue.number }); - const botComments = existingComments.data.filter(comment => - comment.user.login === 'github-actions[bot]' && - comment.body.includes('') ); - const existingHashes = new Set(); - botComments.forEach(comment => { - const match = comment.body.match(//); - if (match) existingHashes.add(match[1]); - }); + // Create hash of current issues to check if review needs updating + const issuesHash = crypto.createHash('md5') + .update(JSON.stringify(issues.map(i => `${i.file}:${i.line}:${i.message}`))) + .digest('hex') + .substring(0, 8); - let postedCount = 0; - let skippedCount = 0; + // Check if existing review has the same issues + if (botReview && botReview.body.includes(``)) { + console.log('Review already exists with same issues, skipping'); + return; + } - for (const issue of issues) { - const issueData = `${issue.file}:${issue.line}:${issue.message}`; - const issueHash = crypto.createHash('md5').update(issueData).digest('hex').substring(0, 8); + // Dismiss existing review if it exists + if (botReview) { + await github.rest.pulls.dismissReview({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number, + review_id: botReview.id, + message: 'Updating with new lint results' + }); + } + + // Prepare review comments + const reviewComments = []; + const issuesByFile = {}; - if (existingHashes.has(issueHash)) { - console.log(`Skipping duplicate issue: ${issueHash}`); - skippedCount++; - continue; + for (const issue of issues) { + if (!issuesByFile[issue.file]) { + issuesByFile[issue.file] = []; } + issuesByFile[issue.file].push(issue); + + reviewComments.push({ + path: issue.file, + line: issue.line, + body: issue.message + }); + } + + // Create review body with summary + const totalIssues = issues.length; + const fileCount = Object.keys(issuesByFile).length; - const commentBody = `${issue.message}\n\n\n`; - console.log(`comment body:`, commentBody); + let reviewBody = `## 🔍 Lint Results\n\n`; + reviewBody += `Found **${totalIssues}** issue${totalIssues !== 1 ? 's' : ''} in **${fileCount}** file${fileCount !== 1 ? 's' : ''}:\n\n`; + for (const [file, fileIssues] of Object.entries(issuesByFile)) { + reviewBody += `- **${file}**: ${fileIssues.length} issue${fileIssues.length !== 1 ? 's' : ''}\n`; + } + + reviewBody += `\n\n`; + + try { + const review = await github.rest.pulls.createReview({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number, + commit_id: context.payload.pull_request.head.sha, + body: reviewBody, + event: 'REQUEST_CHANGES', + comments: reviewComments + }); + + console.log(`Created review with ${reviewComments.length} comments`); + } catch (error) { + console.error(`Failed to create review:`, error.message); + + // Fallback: try to create review without comments if there's an error try { - await github.rest.pulls.createReviewComment({ + await github.rest.pulls.createReview({ owner: context.repo.owner, repo: context.repo.repo, pull_number: context.issue.number, commit_id: context.payload.pull_request.head.sha, - path: issue.file, - line: issue.line, - body: commentBody + body: reviewBody + '\n\n⚠️ Could not attach inline comments due to an error.', + event: 'REQUEST_CHANGES' }); - postedCount++; - } catch (error) { - console.error(`Failed to post comment:`, error.message); + console.log('Created review without inline comments as fallback'); + } catch (fallbackError) { + console.error('Fallback review creation also failed:', fallbackError.message); } } - - console.log(`Posted ${postedCount} new comments, skipped ${skippedCount} duplicates`); diff --git a/.github/workflows/publish-github-pages.yml b/.github/workflows/publish-github-pages.yml index 4f9b947d2..1448fe9b1 100644 --- a/.github/workflows/publish-github-pages.yml +++ b/.github/workflows/publish-github-pages.yml @@ -17,7 +17,7 @@ jobs: - name: Setup Zig uses: mlugg/setup-zig@v2 with: - version: 0.14.1 + version: 0.15.1 - name: Download and install GitHub CLI run: | diff --git a/.github/workflows/sim-aviron.yml b/.github/workflows/sim-aviron.yml index 51693411c..ed71a1fa2 100644 --- a/.github/workflows/sim-aviron.yml +++ b/.github/workflows/sim-aviron.yml @@ -19,7 +19,7 @@ jobs: - name: Setup Zig uses: mlugg/setup-zig@v2 with: - version: 0.14.1 + version: 0.15.1 - name: Build working-directory: sim/aviron diff --git a/.github/workflows/tools-regz-wizard.yml b/.github/workflows/tools-regz-wizard.yml index 1596f79a4..6597dab9b 100644 --- a/.github/workflows/tools-regz-wizard.yml +++ b/.github/workflows/tools-regz-wizard.yml @@ -7,6 +7,7 @@ on: jobs: build: + if: false runs-on: ${{ matrix.os }} strategy: @@ -23,7 +24,7 @@ jobs: - name: Setup Zig uses: mlugg/setup-zig@v2 with: - version: 0.14.1 + version: 0.15.1 - name: Build working-directory: tools/regz-wizard diff --git a/README.md b/README.md index 71511102d..3bb05577c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ## What version of Zig to use -Zig 0.14.1 +Zig 0.15.1 ## Getting Started With MicroZig diff --git a/build.zig b/build.zig index c1b3469d3..2115b2e52 100644 --- a/build.zig +++ b/build.zig @@ -45,13 +45,17 @@ const exe_targets: []const std.Target.Query = &.{ pub fn build(b: *Build) void { const optimize = b.standardOptimizeOption(.{}); - const generate_linker_script_exe = b.addExecutable(.{ - .name = "generate_linker_script", + const generate_linker_script_mod = b.createModule(.{ .root_source_file = b.path("tools/generate_linker_script.zig"), .target = b.graph.host, .optimize = optimize, }); + const generate_linker_script_exe = b.addExecutable(.{ + .name = "generate_linker_script", + .root_module = generate_linker_script_mod, + }); + generate_linker_script_exe.root_module.addImport( "build-internals", b.dependency("build-internals", .{}).module("build-internals"), @@ -366,11 +370,11 @@ pub fn MicroBuild(port_select: PortSelect) type { }; fn serialize_patches(b: *Build, patches: []const regz.patch.Patch) []const u8 { - var buf = std.ArrayList(u8).init(b.allocator); + var buf: std.Io.Writer.Allocating = .init(b.allocator); for (patches) |patch| { - std.json.stringify(patch, .{}, buf.writer()) catch @panic("OOM"); - buf.writer().writeByte('\n') catch @panic("OOM"); + buf.writer.print("{f}", .{std.json.fmt(patch, .{})}) catch @panic("OOM"); + buf.writer.writeByte('\n') catch @panic("OOM"); } return buf.toOwnedSlice() catch @panic("OOM"); @@ -457,7 +461,7 @@ pub fn MicroBuild(port_select: PortSelect) type { regz_run.addArg("--output_path"); // Write to a file const chips_dir = regz_run.addOutputDirectoryArg("chips"); - var patches = std.ArrayList(regz.patch.Patch).init(b.allocator); + var patches: std.array_list.Managed(regz.patch.Patch) = .init(b.allocator); // From chip definition patches.appendSlice(target.chip.patches) catch @panic("OOM"); @@ -488,7 +492,7 @@ pub fn MicroBuild(port_select: PortSelect) type { regz_run.addArg("--output_path"); // Write to a file const chips_dir = regz_run.addOutputDirectoryArg("chips"); - var patches = std.ArrayList(regz.patch.Patch).init(b.allocator); + var patches: std.array_list.Managed(regz.patch.Patch) = .init(b.allocator); // From chip definition patches.appendSlice(target.chip.patches) catch @panic("OOM"); @@ -597,7 +601,7 @@ pub fn MicroBuild(port_select: PortSelect) type { .ram_image = target.ram_image, }; - const args_str = std.json.stringifyAlloc( + const args_str = std.json.Stringify.valueAlloc( b.allocator, generate_linker_script_args, .{}, diff --git a/build.zig.zon b/build.zig.zon index 29c60a3e6..7962cbe6f 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -36,8 +36,8 @@ // used for creating package tarballs .boxzer = .{ - .url = "git+https://github.com/mattnite/boxzer.git#d50d7916b1f850048b2ad7e63a7abf05bd73c0e6", - .hash = "boxzer-0.1.0--ed-MLzlAADinFJMGZncIcYAE07MoAbAr8a2R7Cr-xln", + .url = "git+https://github.com/mattnite/boxzer#d9843a53070b417b281b9616b8d613497fe323d6", + .hash = "boxzer-0.1.0--ed-MNDmAADeDPHt1nPLM6W_ChLmH2YKn-gILlIlE18V", }, }, .paths = .{ diff --git a/core/build.zig b/core/build.zig index 287070952..90d93aa2f 100644 --- a/core/build.zig +++ b/core/build.zig @@ -8,7 +8,10 @@ pub fn build(b: *std.Build) !void { const unit_tests = b.addTest(.{ // We're not using the `start.zig` entrypoint as it overrides too much // configuration - .root_source_file = b.path("src/microzig.zig"), + .root_module = b.createModule(.{ + .root_source_file = b.path("src/microzig.zig"), + .target = b.graph.host, + }), }); const run_unit_tests = b.addRunArtifact(unit_tests); diff --git a/core/build.zig.zon b/core/build.zig.zon index addf114d1..55ad43529 100644 --- a/core/build.zig.zon +++ b/core/build.zig.zon @@ -2,8 +2,12 @@ .name = .mz_core, .fingerprint = 0x2d3edeb5b42fbb10, .version = "0.0.1", + .dependencies = .{ + .@"bounded-array" = .{ + .path = "../modules/bounded-array", + }, + }, .paths = .{ - "thoughts.md", "build.zig", "build.zig.zon", "src", diff --git a/core/src/core/experimental/semihosting.zig b/core/src/core/experimental/semihosting.zig index c9000981f..9baf36e62 100644 --- a/core/src/core/experimental/semihosting.zig +++ b/core/src/core/experimental/semihosting.zig @@ -38,15 +38,39 @@ pub const Debug = struct { }; //WriteC and Write0 write direct to the Debug terminal, no context need - const Writer = std.io.Writer(void, anyerror, writerfn); + pub const Writer = struct { + interface: std.Io.Writer, + }; + + pub fn writer(buffer: []u8) Writer { + return .{ + .interface = .{ + .vtable = &.{ + .drain = drain, + }, + .buffer = buffer, + }, + }; + } pub const Argv = extern struct { buffer: [*]u8, len: usize, }; + fn drain(_: *std.Io.Writer, data: []const []const u8, splat: usize) std.Io.Writer.Error!usize { + _ = splat; + // TODO: implement splat + var ret: usize = 0; + for (data) |d| { + ret += try writerfn({}, d); + } + + return ret; + } + //this is ssssssslow but WriteC is even more slow and Write0 requires '\0' sentinel - fn writerfn(_: void, data: []const u8) anyerror!usize { + fn writerfn(_: void, data: []const u8) std.Io.Writer.Error!usize { var len = data.len; if (len != 1) { @@ -69,8 +93,10 @@ pub const Debug = struct { ///writes to the Debug terminal. ///NOTE: if available, always use `stdout` pub fn print(comptime fmt: []const u8, args: anytype) void { - const dbg_w = Writer{ .context = {} }; - dbg_w.print(fmt, args) catch return; + var buf: [256]u8 = undefined; + var dbg_w = writer(&buf); + dbg_w.interface.print(fmt, args) catch return; + dbg_w.interface.flush() catch return; } ///get C errno value @@ -102,7 +128,9 @@ pub const Debug = struct { const byte_size = ext_file.size() catch return false; if (byte_size < (MAGIC.len + feature_byte + 1)) return false; - _ = ext_file.reader().read(&magic_buffer) catch return false; + var read_buf: [256]u8 = undefined; + var file_reader = ext_file.reader(&read_buf); + _ = file_reader.interface.readSliceShort(&magic_buffer) catch return false; //check the magic number for (magic_buffer, MAGIC) |number, magic| { @@ -112,7 +140,10 @@ pub const Debug = struct { //get feature byte and check feature bit ext_file.seek(feature_byte + 4) catch return false; - const ext_byte = ext_file.reader().readByte() catch return false; + var ext_byte_buf: [1]u8 = undefined; + _ = file_reader.interface.readSliceShort(&ext_byte_buf) catch return false; + const ext_byte = ext_byte_buf[0]; + return (ext_byte & @as(u8, 1) << feature_bit) != 0; } @@ -247,9 +278,18 @@ pub const fs = struct { pub const File = enum(usize) { _, - const Writer = std.io.Writer(File, anyerror, writefn); - const Reader = std.io.Reader(File, anyerror, readfn); - fn writefn(ctx: File, data: []const u8) anyerror!usize { + + pub const Writer = struct { + file: File, + interface: std.Io.Writer, + }; + + pub const Reader = struct { + file: File, + interface: std.Io.Reader, + }; + + fn writefn(ctx: File, data: []const u8) std.Io.Writer.Error!usize { const w_file = RWFile{ .file = ctx, .buf = @constCast(data.ptr), @@ -260,7 +300,7 @@ pub const fs = struct { return data.len - ret; } - fn readfn(ctx: File, out: []u8) anyerror!usize { + fn readfn(ctx: File, out: []u8) std.Io.Reader.Error!usize { var r_file = RWFile{ .file = ctx, .buf = out.ptr, @@ -268,23 +308,69 @@ pub const fs = struct { }; const ret = sys_read(&r_file); - if (ret == -1) return error.ReadFail; + if (ret == -1) return error.ReadFailed; return out.len - @as(usize, @bitCast(ret)); } - pub fn writer(file: File) Writer { - return Writer{ .context = file }; + pub fn writer(file: File, buffer: []u8) Writer { + return .{ + .file = file, + .interface = .{ + .vtable = &.{ + .drain = drain, + }, + .buffer = buffer, + }, + }; + } + + pub fn reader(file: File, buffer: []u8) Reader { + return .{ + .file = file, + .interface = .{ + .vtable = &.{ + .stream = stream, + }, + .buffer = buffer, + .seek = 0, + .end = 0, + }, + }; } - pub fn reader(file: File) Reader { - return Reader{ .context = file }; + fn drain(io_w: *std.Io.Writer, data: []const []const u8, splat: usize) std.Io.Writer.Error!usize { + const w: *Writer = @fieldParentPtr("interface", io_w); + _ = splat; + // TODO: implement splat + var ret: usize = 0; + for (data) |d| { + const n = try writefn(w.file, d); + ret += n; + if (n != d.len) + return ret; + } + + return ret; + } + + fn stream(io_r: *std.Io.Reader, w: *std.Io.Writer, limit: std.Io.Limit) std.Io.Reader.StreamError!usize { + const r: *Reader = @fieldParentPtr("interface", io_r); + // TODO: limit + _ = limit; + + var buf: [256]u8 = undefined; + const n = try r.file.readfn(&buf); + try w.writeAll(buf[0..n]); + return n; } //Write Functions pub fn print(file: File, comptime fmt: []const u8, args: anytype) void { - const wrt = Writer{ .context = file }; - wrt.print(fmt, args) catch return; + var buf: [256]u8 = undefined; + var wrt = file.writer(&buf); + wrt.interface.print(fmt, args) catch return; + wrt.interface.flush() catch return; } //Read Functions @@ -378,8 +464,7 @@ fn call(number: Syscalls, param: *const anyopaque) isize { : [ret] "=r" (-> isize), : [num] "r" (number), [p] "r" (param), - : "memory", "r0", "r1" - ); + : .{ .memory = true, .r0 = true, .r1 = true }); } //WriteC does not have return diff --git a/core/src/core/usb/cdc.zig b/core/src/core/usb/cdc.zig index d55fb44b8..fc111a107 100644 --- a/core/src/core/usb/cdc.zig +++ b/core/src/core/usb/cdc.zig @@ -3,6 +3,8 @@ const std = @import("std"); const types = @import("types.zig"); const utils = @import("utils.zig"); +const utilities = @import("../../utilities.zig"); + const DescType = types.DescType; const bos = utils.BosConfig; @@ -126,7 +128,7 @@ pub const CdcLineCoding = extern struct { }; pub fn CdcClassDriver(comptime usb: anytype) type { - const fifo = std.fifo.LinearFifo(u8, std.fifo.LinearFifoBufferType{ .Static = usb.max_packet_size }); + const FIFO = utilities.CircularBuffer(u8, usb.max_packet_size); return struct { device: ?types.UsbDevice = null, @@ -136,13 +138,13 @@ pub fn CdcClassDriver(comptime usb: anytype) type { line_coding: CdcLineCoding = undefined, - rx: fifo = fifo.init(), - tx: fifo = fifo.init(), + rx: FIFO = .empty, + tx: FIFO = .empty, epin_buf: [usb.max_packet_size]u8 = undefined, pub fn available(self: *@This()) usize { - return self.rx.readableLength(); + return self.rx.get_readable_len(); } pub fn read(self: *@This(), dst: []u8) usize { @@ -152,15 +154,15 @@ pub fn CdcClassDriver(comptime usb: anytype) type { } pub fn write(self: *@This(), data: []const u8) []const u8 { - const write_count = @min(self.tx.writableLength(), data.len); + const write_count = @min(self.tx.get_writable_len(), data.len); if (write_count > 0) { - self.tx.writeAssumeCapacity(data[0..write_count]); + self.tx.write_assume_capacity(data[0..write_count]); } else { return data[0..]; } - if (self.tx.writableLength() == 0) { + if (self.tx.get_writable_len() == 0) { _ = self.write_flush(); } @@ -171,7 +173,7 @@ pub fn CdcClassDriver(comptime usb: anytype) type { if (self.device.?.ready() == false) { return 0; } - if (self.tx.readableLength() == 0) { + if (self.tx.get_readable_len() == 0) { return 0; } const len = self.tx.read(&self.epin_buf); @@ -180,7 +182,7 @@ pub fn CdcClassDriver(comptime usb: anytype) type { } fn prep_out_transaction(self: *@This()) void { - if (self.rx.writableLength() >= usb.max_packet_size) { + if (self.rx.get_writable_len() >= usb.max_packet_size) { // Let endpoint know that we are ready for next packet self.device.?.endpoint_transfer(self.ep_out, &.{}); } @@ -291,7 +293,7 @@ pub fn CdcClassDriver(comptime usb: anytype) type { if (self.write_flush() == 0) { // If there is no data left, a empty packet should be sent if // data len is multiple of EP Packet size and not zero - if (self.tx.readableLength() == 0 and data.len > 0 and data.len == usb.max_packet_size) { + if (self.tx.get_readable_len() == 0 and data.len > 0 and data.len == usb.max_packet_size) { self.device.?.endpoint_transfer(self.ep_in, &.{}); } } diff --git a/core/src/core/usb/utils.zig b/core/src/core/usb/utils.zig index a9b79106c..09da008f4 100644 --- a/core/src/core/usb/utils.zig +++ b/core/src/core/usb/utils.zig @@ -36,7 +36,7 @@ pub const BosConfig = struct { if (cfg_desc_type != @intFromEnum(exp_desc_type)) { return null; } else { - return @constCast(@ptrCast(bos_cfg.ptr)); + return @ptrCast(@constCast(bos_cfg.ptr)); } } diff --git a/core/src/cpus/cortex_m.zig b/core/src/cpus/cortex_m.zig index cb7385315..8e33d9002 100644 --- a/core/src/cpus/cortex_m.zig +++ b/core/src/cpus/cortex_m.zig @@ -576,8 +576,7 @@ pub const startup_logic = struct { : : [_vector_table] "r" (&ram_vector_table), [_VTOR_ADDRESS] "r" (&peripherals.scb.VTOR), - : "memory", "r0", "r1" - ); + : .{ .memory = true, .r0 = true, .r1 = true }); } microzig_main(); diff --git a/core/src/cpus/riscv32.zig b/core/src/cpus/riscv32.zig index 1b36035cb..997ab5f3f 100644 --- a/core/src/cpus/riscv32.zig +++ b/core/src/cpus/riscv32.zig @@ -16,15 +16,15 @@ pub fn wfe() void { pub fn pmp_open_all_space() void { // Config entry0 addr to all 1s to make the range cover all space - asm volatile ("li x6, 0xffffffff" ::: "x6"); + asm volatile ("li x6, 0xffffffff" ::: .{ .x6 = true }); asm volatile ("csrw pmpaddr0, x6"); // Config entry0 cfg to make it NAPOT address mode, and R/W/X okay - asm volatile ("li x6, 0x7f" ::: "x6"); + asm volatile ("li x6, 0x7f" ::: .{ .x6 = true }); asm volatile ("csrw pmpcfg0, x6"); } pub fn switch_m2u_mode() void { - asm volatile ("la x6, 1f " ::: "x6"); + asm volatile ("la x6, 1f " ::: .{ .x6 = true }); asm volatile ("csrw mepc, x6"); asm volatile ("mret"); asm volatile ("1:"); diff --git a/core/src/microzig.zig b/core/src/microzig.zig index e29c3a997..5d0bb57d9 100644 --- a/core/src/microzig.zig +++ b/core/src/microzig.zig @@ -108,7 +108,7 @@ pub fn hang() noreturn { cpu.interrupt.disable_interrupts(); while (true) { // "this loop has side effects, don't optimize the endless loop away please. thanks!" - asm volatile ("" ::: "memory"); + asm volatile ("" ::: .{ .memory = true }); } } diff --git a/core/src/start.zig b/core/src/start.zig index a1ebfe9fd..d543ec9f0 100644 --- a/core/src/start.zig +++ b/core/src/start.zig @@ -49,7 +49,7 @@ export fn microzig_main() noreturn { const return_type = info.@"fn".return_type orelse @compileError(invalid_main_msg); - if (info.@"fn".calling_convention == .@"async") + if (info.@"fn".calling_convention == .async) @compileError("TODO: Embedded event loop not supported yet. Please try again later."); // A hal can export a default init function that runs before main for diff --git a/core/src/utilities.zig b/core/src/utilities.zig index 164a1e34a..308724044 100644 --- a/core/src/utilities.zig +++ b/core/src/utilities.zig @@ -1,4 +1,6 @@ const std = @import("std"); +const assert = std.debug.assert; + const microzig = @import("microzig.zig"); /// Fills .bss with zeroes and *maybe* copies .data from flash into ram. May be @@ -51,7 +53,7 @@ pub inline fn initialize_system_memories(which: enum { /// A helper class that allows operating on a slice of slices /// with similar operations to those of a slice. -pub fn Slice_Vector(comptime Slice: type) type { +pub fn SliceVector(comptime Slice: type) type { const type_info = @typeInfo(Slice); if (type_info != .pointer) @compileError("Slice must have a slice type!"); @@ -304,8 +306,8 @@ pub fn GenerateInterruptOptions(sources: []const Source) type { }); } -test Slice_Vector { - const vec = Slice_Vector([]const u8).init(&.{ +test SliceVector { + const vec = SliceVector([]const u8).init(&.{ "Hello,", " ", "World!", @@ -321,8 +323,8 @@ test Slice_Vector { } } -test "Slice_Vector.init" { - const vec_strip_head = Slice_Vector([]const u8).init(&.{ +test "SliceVector.init" { + const vec_strip_head = SliceVector([]const u8).init(&.{ &.{}, &.{}, &.{}, @@ -332,7 +334,7 @@ test "Slice_Vector.init" { try std.testing.expectEqual(1, vec_strip_head.slices.len); try std.testing.expectEqualStrings("hello", vec_strip_head.slices[0]); - const vec_strip_tail = Slice_Vector([]const u8).init(&.{ + const vec_strip_tail = SliceVector([]const u8).init(&.{ "hello", &.{}, &.{}, @@ -342,7 +344,7 @@ test "Slice_Vector.init" { try std.testing.expectEqual(1, vec_strip_tail.slices.len); try std.testing.expectEqualStrings("hello", vec_strip_tail.slices[0]); - const vec_strip_both = Slice_Vector([]const u8).init(&.{ + const vec_strip_both = SliceVector([]const u8).init(&.{ &.{}, &.{}, "hello", @@ -352,7 +354,7 @@ test "Slice_Vector.init" { try std.testing.expectEqual(1, vec_strip_both.slices.len); try std.testing.expectEqualStrings("hello", vec_strip_both.slices[0]); - const vec_keep_center = Slice_Vector([]const u8).init(&.{ + const vec_keep_center = SliceVector([]const u8).init(&.{ &.{}, "hello", &.{}, @@ -367,8 +369,8 @@ test "Slice_Vector.init" { try std.testing.expectEqualStrings("world", vec_keep_center.slices[3]); } -test "Slice_Vector.iterator" { - const vec = Slice_Vector([]const u8).init(&.{ +test "SliceVector.iterator" { + const vec = SliceVector([]const u8).init(&.{ &.{}, &.{}, "Hello,", @@ -404,11 +406,11 @@ test "Slice_Vector.iterator" { } } -test "Slice_Vector.iterator (mutable)" { +test "SliceVector.iterator (mutable)" { var buffer: [8]u8 = undefined; const expected = "01234567"; - const vec = Slice_Vector([]u8).init(&.{ + const vec = SliceVector([]u8).init(&.{ &.{}, &.{}, buffer[0..3], @@ -431,8 +433,8 @@ test "Slice_Vector.iterator (mutable)" { try std.testing.expectEqualStrings(expected, &buffer); } -test "Slice_Vector.Iterator.next_chunk" { - const vec = Slice_Vector([]const u8).init(&.{ +test "SliceVector.Iterator.next_chunk" { + const vec = SliceVector([]const u8).init(&.{ &.{}, &.{}, "Hello,", @@ -505,3 +507,134 @@ pub fn get_end_of_stack() *const anyopaque { @panic("expected at least one of end_of_stack.address or end_of_stack.symbol_name to be set"); } } + +/// A naive circular buffer implementation. At time of writing, it's intended +/// to fill in where the deleted std.fifo.LinearFifo was used, so the API might +/// seem unfinished. +pub fn CircularBuffer(comptime T: type, comptime len: usize) type { + return struct { + items: [len]T, + start: usize, + end: usize, + full: bool, + + const Self = @This(); + pub const empty: Self = .{ + .items = undefined, + .start = 0, + .end = 0, + .full = false, + }; + + fn assert_valid(buffer: *const Self) void { + assert(buffer.start < len); + assert(buffer.end < len); + } + + pub fn get_writable_len(buffer: *const Self) usize { + buffer.assert_valid(); + return len - buffer.get_readable_len(); + } + + pub fn is_empty(buffer: *const Self) bool { + return !buffer.full and (buffer.start == buffer.end); + } + + pub fn get_readable_len(buffer: *const Self) usize { + buffer.assert_valid(); + + return if (buffer.start <= buffer.end) + buffer.end - buffer.start + else + len - buffer.start - buffer.end; + } + + fn increment_end(buffer: *Self) void { + increment(&buffer.end); + } + + fn increment_start(buffer: *Self) void { + increment(&buffer.start); + } + + fn increment(counter: *usize) void { + if (counter.* >= (len - 1)) { + counter.* = 0; + } else { + counter.* += 1; + } + } + + pub fn write_assume_capacity(buffer: *Self, values: []const T) void { + buffer.assert_valid(); + defer buffer.assert_valid(); + + var first = true; + for (values) |value| { + if (first) { + first = false; + } else { + assert(buffer.start != buffer.end); + } + + buffer.items[buffer.end] = value; + buffer.increment_end(); + } + + if (buffer.start == buffer.end) + buffer.full = true; + } + + pub fn read(buffer: *Self, out: []u8) usize { + buffer.assert_valid(); + defer buffer.assert_valid(); + + var count: usize = 0; + while (!buffer.is_empty() and count < out.len) { + out[count] = buffer.pop().?; + count += 1; + } + + return count; + } + + pub fn write(buffer: *Self, data: []const u8) error{Full}!void { + buffer.assert_valid(); + defer buffer.assert_valid(); + + for (data) |d| { + if (buffer.full) + return error.Full; + + buffer.items[buffer.end] = d; + buffer.increment_end(); + } + } + + /// Pop item from front of buffer. Return null if empty + pub fn pop(buffer: *Self) ?T { + buffer.assert_valid(); + defer buffer.assert_valid(); + + if (buffer.is_empty()) + return null; + + defer { + buffer.increment_start(); + if (buffer.full) { + buffer.full = false; + } + } + return buffer.items[buffer.start]; + } + + pub fn reset(buffer: *Self) void { + buffer.assert_valid(); + defer buffer.assert_valid(); + + buffer.start = 0; + buffer.end = 0; + buffer.full = false; + } + }; +} diff --git a/core/thoughts.md b/core/thoughts.md deleted file mode 100644 index d1979c323..000000000 --- a/core/thoughts.md +++ /dev/null @@ -1,262 +0,0 @@ -# microzig Design Meeting - -## Package structure - -`microzig` package exports all functions and types available in the HAL as well as `microzig.mcu` which will provide access to the MCU. All functions in `microzig` which are not generic will be inline-forwarded to the `board` or `mcu` package. - -``` -root - |- std - |- microzig - | |- mcu (should be specified if "board" does not exit) - | |- build_options (defines if "mcu" and/or "board" exists) - | \- board (must export ".mcu") - | \- mcu - \- mcu (user decision) -``` - -## Minimal Root file - -Declaring `panic` in the root file will cause `builtin` to reference the proper package which will then instantiate microzig which will reference `mcu` package which will instantiate `reset` (or similar) which will invoke `microzig.main()` which will invoke `root.main()`. Oh boy :laughing: - -```zig -const microzig = @import("microzig"); - -pub const panic = microzig.panic; // this will instantiate microzig - -comptime { _ = microzig }; // this should not be necessary - -pub fn main() void { - -} -``` - -## `microzig.mcu` - -`microzig` exports a symbol `mcu` which will provide access to the MCU, CPU and board features - -```zig -// mcu.zig in microzig.zig -const config = @import("build_options"); - -usingnamespace if(config.has_board) - @import("board").mcu -else - @import("mcu"); - -pub const has_board = config.has_board; -pub const board = @import("board"); -``` - -## Interrupt API - -All interrupt handlers are static and will be collected from `root.interrupt_handlers`. Each symbol will be verified if it's a valid interrupt vector. -A symbol can be a function `fn() void`, or a anonymous enum literal `.hang` or `.reset`. - -`microzig.interrupts.enable` and `microzig.interrupts.disable` will allow masking/unmasking those interrupts, `.cli()` and `.sei()` will globally disable/enable interrupts - -`microzig.interrupts` also provides some handling of critical sections - -```zig -pub fn main() void { - microzig.interrupts.enable(.WDT); // enables the WDT interrupt - microzig.interrupts.disable(.WDT); // enables the WDT interrupt - microzig.interrupts.enable(.WTF); // yields compile error "WTF is not a valid interrupt" - microzig.interrupts.enable(.PCINT0); // yields compile error "PCINT0 has no defined interrupt handler" - microzig.interrupts.enable(.NMI); // yields compile error "NMI cannot be masked" - microzig.interrupts.enableAll(); - microzig.interrupts.batchEnable(.{ .NMI, .WDT }); - - microzig.interrupts.cli(); // set interrupt enabled (global enable) - - { // critical section - var crit = microzig.interrupts.enterCriticalSection(); - defer crit.leave(); - } -} - -var TIMER2_OVF_RUNTIME: fn()void = foo; - -pub const interrupt_handlers = struct { - - // AVR - pub fn TIMER2_OVF() void { TIMER2_OVF_RUNTIME(); } - pub fn WDT() void { } - - pub const PCINT1 = .reset; - pub const PCINT2 = .hang; - - // cortex-mX exceptions - pub fn NMI() void { } - pub fn HardFault() void {} - - // LPC 1768 interrupt/irq - pub fn SSP1() void { } -}; -``` - -## Timer API - -microzig should allow having a general purpose timer mechanism - -```zig -pub var cpu_frequency = 16.0 * microzig.clock.mega_hertz; - -pub const sleep_mode = .timer; // timer, busyloop, whatever - -pub fn main() !void { - led.init(); - - while(true) { - led.toggle(); - microzig.sleep(100_000); // sleep 100ms - } -} -``` - -## GPIO API - -`microzig.Pin` parses a pin definition and returns a type that encodes all relevant info and functions to route that pin. -`microzig.Gpio` is a GPIO port/pin configuration that allows modifying pin levels. - -```zig - -// microzig.Pin returns a type containing all relevant pin information -const status_led_pin = microzig.Pin("PA3"); - -// generate a runtime possible pin that cannot be used in all APIs -var generic_pic: microzig.RuntimePin.init(status_led_pin); - -// 4 Bit IEEE-488 bit banging register -const serial_out = microzig.GpioOutputRegister(.{ - microzig.Pin("PA0"), - microzig.Pin("PA1"), - microzig.Pin("PA3"), // whoopsies, i miswired, let the software fix that - microzig.Pin("PA2"), -}); - -pub fn bitBang(nibble: u4) void { - serial_out.write(nibble); -} - -pub fn main() !void { - - // Route all gpio pins from the bit bang register - inline for(serial_out.pins) |pin| { - pin.route(".gpio"); - } - serial_out.init(); - - // route that pin to UART.RXD - status_led_pin.route(.uart0_rxd); - - //var uart_read_dma_channel = microzig.Dma.init(.{.channel = 1}); - - const status_led = microzig.Gpio(status_led_pin, .{ - .mode = .output, // { input, output, input_output, open_drain, generic } - .initial_state = .unspecificed, // { unspecified, low, high, floating, driven } - }); - status_led.init(); - - switch(status_led.mode) { - // only reading API is available - .input => { - _ = status_led.read(); - }, - - // reading and writing is available - .output => { - _ = status_led.read(); - status_led.write(.high); - - // "subvariant" of the write - status_led.toggle(); - status_led.setToHigh(); - status_led.setToLow(); - }, - - // reading, writing and changing direction is available - .input_output => { - status_led.setDirection(.input, undefined); - _ = status_led.read(); - status_led.setDirection(.output, .high); // reqires a defined state after setting the direction - status_led.write(.high); - }, - - // reading and setDive is available - .open_drain => { - status_led.setDrive(.disabled); - _ = status_led.read(); - status_led.setDrive(.enabled); - }, - - // will have all available APIs enabled - .generic => {}, - } - - // AVR: PORTA[3] => "PA3" - // NXP: PORT[1][3] => "P1.3" - // PICO: PORT[1] => "P3" - // STM: PORT[A][3] => "A3" - // ESP32: PORT[1] => "P3" -``` - - -## UART example - -```zig -const std = @import("std"); -const microzig = @import("µzig"); - -// if const it can be comptime-optimized -pub var cpu_frequency = 100.0 * microzig.clock.mega_hertz; - -// if this is enabled, a event loop will run -// in microzig.main() that allows using `async`/`await` "just like that" *grin* -pub const io_mode = .evented; - -pub fn main() !void { - var debug_port = microzig.Uart.init(0, .{ - .baud_rate = 9600, - .stop_bits = .@"2", - .parity = .none, // { none, even, odd, mark, space } - .data_bits = .@"8", // 5, 6, 7, 8, or 9 data bits - //.in_dma_channel = 0, - //.out_dma_channel = 0, - }); - - debug_port.configureDMA(???); - - try debug_port.writer().writeAll("Hello, World!"); - - var line_buffer: [64]u8 = undefined; - const len = try debug_port.reader().readUntilDelimiter(&line_buffer, '\n'); -} -``` - - - - -## Initialization - -somewhere inside microzig.zig -```zig -extern fn reset() noreturn { - if(@hasDecl(mcu, "mcu_reset")) { - mcu.mcu_reset(); - @unreachable(); - } - // zeroing bss, copying .data, setting stack address - - if(@hasDecl(root, "early_main")) // idk about the name - root.early_main(); - else { - mcu.init(); - - if(@hasDecl(root, "main")) - root.main(); - else - @compileError("main or entry_main missing") - } -} -``` diff --git a/drivers/base/Datagram_Device.zig b/drivers/base/Datagram_Device.zig index cdecdf3b6..209f7c915 100644 --- a/drivers/base/Datagram_Device.zig +++ b/drivers/base/Datagram_Device.zig @@ -104,7 +104,7 @@ pub const VTable = struct { /// A device implementation that can be used to write unit tests for datagram devices. pub const Test_Device = struct { arena: std.heap.ArenaAllocator, - packets: std.ArrayList([]u8), + packets: std.array_list.Managed([]u8), // If empty, reads are supported, but don't yield data. // If `null`, reads are not supported. @@ -126,7 +126,7 @@ pub const Test_Device = struct { pub fn init(input: ?[]const []const u8, write_enabled: bool) Test_Device { return Test_Device{ .arena = std.heap.ArenaAllocator.init(std.testing.allocator), - .packets = std.ArrayList([]u8).init(std.testing.allocator), + .packets = std.array_list.Managed([]u8).init(std.testing.allocator), .input_sequence = input, .input_sequence_pos = 0, diff --git a/drivers/base/DateTime.zig b/drivers/base/DateTime.zig index 600f5946e..e2005769b 100644 --- a/drivers/base/DateTime.zig +++ b/drivers/base/DateTime.zig @@ -805,11 +805,11 @@ pub fn days_in_month(year: u16, month: u4) u5 { } fn int_to_string(out_string: []u8, int: u32) usize { - return std.fmt.formatIntBuf(out_string, int, 10, .lower, .{}); + return std.fmt.printInt(out_string, int, 10, .lower, .{}); } fn int_to_string_padded(out_string: []u8, int: u32, width: usize) usize { - return std.fmt.formatIntBuf(out_string, int, 10, .lower, .{ .fill = '0', .width = width }); + return std.fmt.printInt(out_string, int, 10, .lower, .{ .fill = '0', .width = width }); } test "DateTime-Conversion" { diff --git a/drivers/base/I2C_Device.zig b/drivers/base/I2C_Device.zig index 242b2af83..2a26f1d29 100644 --- a/drivers/base/I2C_Device.zig +++ b/drivers/base/I2C_Device.zig @@ -131,7 +131,7 @@ pub const VTable = struct { /// A device implementation that can be used to write unit tests for datagram devices. pub const Test_Device = struct { arena: std.heap.ArenaAllocator, - packets: std.ArrayList([]u8), + packets: std.array_list.Managed([]u8), // If empty, reads are supported, but don't yield data. // If `null`, reads are not supported. @@ -152,7 +152,7 @@ pub const Test_Device = struct { pub fn init(input: ?[]const []const u8, write_enabled: bool) Test_Device { return Test_Device{ .arena = std.heap.ArenaAllocator.init(std.testing.allocator), - .packets = std.ArrayList([]u8).init(std.testing.allocator), + .packets = std.array_list.Managed([]u8).init(std.testing.allocator), .input_sequence = input, .input_sequence_pos = 0, diff --git a/drivers/base/Stream_Device.zig b/drivers/base/Stream_Device.zig index 97275f7af..afac4efb3 100644 --- a/drivers/base/Stream_Device.zig +++ b/drivers/base/Stream_Device.zig @@ -87,7 +87,7 @@ pub const VTable = struct { /// A device implementation that can be used to write unit tests for datagram devices. pub const Test_Device = struct { input: ?std.io.FixedBufferStream([]const u8), - output: ?std.ArrayList(u8), + output: ?std.array_list.Managed(u8), connected: bool, @@ -103,7 +103,7 @@ pub const Test_Device = struct { null, .output = if (write_enabled) - std.ArrayList(u8).init(std.testing.allocator) + std.array_list.Managed(u8).init(std.testing.allocator) else null, }; diff --git a/drivers/build.zig b/drivers/build.zig index 70afe26a1..cc819cb82 100644 --- a/drivers/build.zig +++ b/drivers/build.zig @@ -12,7 +12,7 @@ pub fn build(b: *std.Build) void { const test_suite = b.addTest(.{ .root_module = drivers_mod, - .target = b.graph.host, + .use_llvm = true, }); const run_tests = b.addRunArtifact(test_suite); diff --git a/drivers/display/colors.zig b/drivers/display/colors.zig index cf4c98f9d..9f9f9cd4f 100644 --- a/drivers/display/colors.zig +++ b/drivers/display/colors.zig @@ -8,44 +8,33 @@ pub const BlackWhite = enum(u1) { white = 1, }; -pub const RGB565 = packed struct(u16) { - pub usingnamespace DefaultColors(@This()); - - r: u5, - g: u6, - b: u5, - - pub fn from_rgb(r: u8, g: u8, b: u8) RGB565 { - return RGB565{ - .r = @truncate(r >> 3), - .g = @truncate(g >> 2), - .b = @truncate(b >> 3), - }; - } -}; - -pub const RGB888 = extern struct { - pub usingnamespace DefaultColors(@This()); - - r: u8, - g: u8, - b: u8, - - pub fn from_rgb(r: u8, g: u8, b: u8) RGB888 { - return RGB888{ .r = r, .g = g, .b = b }; - } -}; +pub const RGB565 = Color(.{ u5, u6, u5 }); +pub const RGB888 = Color(.{ u8, u8, u8 }); /// Provides a namespace with the default colors for the given `Color` type. -pub fn DefaultColors(comptime Color: type) type { - return struct { - pub const black = Color.from_rgb(0x00, 0x00, 0x00); - pub const white = Color.from_rgb(0xFF, 0xFF, 0xFF); - pub const red = Color.from_rgb(0xFF, 0x00, 0x00); - pub const green = Color.from_rgb(0x00, 0xFF, 0x00); - pub const blue = Color.from_rgb(0x00, 0x00, 0xFF); - pub const cyan = Color.from_rgb(0x00, 0xFF, 0xFF); - pub const magenta = Color.from_rgb(0xFF, 0x00, 0xFF); - pub const yellow = Color.from_rgb(0xFF, 0xFF, 0x00); +pub fn Color(comptime Ts: [3]type) type { + return packed struct { + const Self = @This(); + + r: Ts[0], + g: Ts[1], + b: Ts[2], + + pub const black: Self = .from_rgb(0x00, 0x00, 0x00); + pub const white: Self = .from_rgb(0xFF, 0xFF, 0xFF); + pub const red: Self = .from_rgb(0xFF, 0x00, 0x00); + pub const green: Self = .from_rgb(0x00, 0xFF, 0x00); + pub const blue: Self = .from_rgb(0x00, 0x00, 0xFF); + pub const cyan: Self = .from_rgb(0x00, 0xFF, 0xFF); + pub const magenta: Self = .from_rgb(0xFF, 0x00, 0xFF); + pub const yellow: Self = .from_rgb(0xFF, 0xFF, 0x00); + + pub fn from_rgb(r: u8, g: u8, b: u8) Self { + return Self{ + .r = @truncate(r >> (8 - @bitSizeOf(Ts[0]))), + .g = @truncate(g >> (8 - @bitSizeOf(Ts[1]))), + .b = @truncate(b >> (8 - @bitSizeOf(Ts[2]))), + }; + } }; } diff --git a/drivers/input/keyboard-matrix.zig b/drivers/input/keyboard-matrix.zig index eec5e8e53..d2edc1f9f 100644 --- a/drivers/input/keyboard-matrix.zig +++ b/drivers/input/keyboard-matrix.zig @@ -160,7 +160,7 @@ inline fn busyloop(comptime N: comptime_int) void { for (0..N) |_| { // wait some cycles so the physics does its magic and convey // the electrons - asm volatile ("" ::: "memory"); + asm volatile ("" ::: .{ .memory = true }); } } diff --git a/drivers/io_expander/pcf8574.zig b/drivers/io_expander/pcf8574.zig index f3b6b7220..b234d3cde 100644 --- a/drivers/io_expander/pcf8574.zig +++ b/drivers/io_expander/pcf8574.zig @@ -65,7 +65,7 @@ pub fn PCF8574(comptime config: PCF8574_Config) type { }; fn read_fn(ctx: *anyopaque) ReadError!State { - const pin_ref: *u8 = @alignCast(@ptrCast(ctx)); + const pin_ref: *u8 = @ptrCast(@alignCast(ctx)); const index = pin_ref.*; const pin_base: *[8]u8 = @ptrFromInt(@intFromPtr(pin_ref) - index); //just 1 byte var PCF_base: *Self = @alignCast(@fieldParentPtr("pin_arr", pin_base)); @@ -74,7 +74,7 @@ pub fn PCF8574(comptime config: PCF8574_Config) type { } fn write_fn(ctx: *anyopaque, state: State) WriteError!void { - const pin_ref: *u8 = @alignCast(@ptrCast(ctx)); + const pin_ref: *u8 = @ptrCast(@alignCast(ctx)); const index = pin_ref.*; const pin_base: *[8]u8 = @ptrFromInt(@intFromPtr(pin_ref) - index); //just 1 byte var PCF_base: *Self = @alignCast(@fieldParentPtr("pin_arr", pin_base)); diff --git a/examples/raspberrypi/rp2xxx/build.zig b/examples/raspberrypi/rp2xxx/build.zig index 90c2cff17..b222eb7e9 100644 --- a/examples/raspberrypi/rp2xxx/build.zig +++ b/examples/raspberrypi/rp2xxx/build.zig @@ -72,7 +72,7 @@ pub fn build(b: *std.Build) void { .{ .name = "mlx90640", .file = "src/mlx90640.zig" }, }; - var available_examples = std.ArrayList(Example).init(b.allocator); + var available_examples: std.array_list.Managed(Example) = .init(b.allocator); available_examples.appendSlice(specific_examples) catch @panic("out of memory"); for (chip_agnostic_examples) |example| { available_examples.append(.{ diff --git a/examples/raspberrypi/rp2xxx/src/mlx90640.zig b/examples/raspberrypi/rp2xxx/src/mlx90640.zig index 349fa3adb..8da4f9700 100644 --- a/examples/raspberrypi/rp2xxx/src/mlx90640.zig +++ b/examples/raspberrypi/rp2xxx/src/mlx90640.zig @@ -61,7 +61,7 @@ pub fn main() !void { } for (0..24) |i| { - std.log.debug("{d:.3}\n", .{x[i]}); + std.log.debug("{any:.3}\n", .{x[i]}); } time.sleep_ms(100); } diff --git a/examples/raspberrypi/rp2xxx/src/rp2040_only/flash_id.zig b/examples/raspberrypi/rp2xxx/src/rp2040_only/flash_id.zig index 499e79d23..894a4b9e5 100644 --- a/examples/raspberrypi/rp2xxx/src/rp2040_only/flash_id.zig +++ b/examples/raspberrypi/rp2xxx/src/rp2040_only/flash_id.zig @@ -30,7 +30,7 @@ pub fn main() !void { while (true) { const serial_number = flash.id(); - const hex_serial_number = std.fmt.fmtSliceHexLower(&serial_number); + const hex_serial_number = std.fmt.bytesToHex(&serial_number, .lower); std.log.info("serial number: {s}", .{hex_serial_number}); time.sleep_ms(1000); } diff --git a/examples/stmicro/stm32/src/stm32f1xx/EXTI.zig b/examples/stmicro/stm32/src/stm32f1xx/EXTI.zig index 67e7ece1d..90c1f231c 100644 --- a/examples/stmicro/stm32/src/stm32f1xx/EXTI.zig +++ b/examples/stmicro/stm32/src/stm32f1xx/EXTI.zig @@ -18,7 +18,7 @@ pub const microzig_options: microzig.Options = .{ }, }; -fn EXTI_handler() callconv(.C) void { +fn EXTI_handler() callconv(.c) void { // we have only one line configured, so we can just clear it // if you have more than one line configured, you should check the pending lines exti.clear_pending(exti.pending()); diff --git a/examples/stmicro/stm32/src/stm32f1xx/advanced_adc.zig b/examples/stmicro/stm32/src/stm32f1xx/advanced_adc.zig index f730ac483..416dd940d 100644 --- a/examples/stmicro/stm32/src/stm32f1xx/advanced_adc.zig +++ b/examples/stmicro/stm32/src/stm32f1xx/advanced_adc.zig @@ -37,7 +37,7 @@ const v25 = 1.43; const avg_slope = 0.0043; //4.3mV/°C var ovf_flag: bool = false; -pub fn watchdog_handler() callconv(.C) void { +pub fn watchdog_handler() callconv(.c) void { ovf_flag = true; adc.clear_flags(adc.read_flags()); //clear all active flags } diff --git a/examples/stmicro/stm32/src/stm32f1xx/rtc.zig b/examples/stmicro/stm32/src/stm32f1xx/rtc.zig index 4a2b2d85e..cab16198a 100644 --- a/examples/stmicro/stm32/src/stm32f1xx/rtc.zig +++ b/examples/stmicro/stm32/src/stm32f1xx/rtc.zig @@ -10,7 +10,7 @@ pub const microzig_options = microzig.Options{ .interrupts = .{ .RTC = .{ .c = rtc_handler } }, }; -pub fn rtc_handler() callconv(.C) void { +pub fn rtc_handler() callconv(.c) void { const events = rtc.read_events(); if (events.second) { led.toggle(); diff --git a/examples/stmicro/stm32/src/stm32f1xx/timer_capture.zig b/examples/stmicro/stm32/src/stm32f1xx/timer_capture.zig index 322e4bfac..a6ce3a216 100644 --- a/examples/stmicro/stm32/src/stm32f1xx/timer_capture.zig +++ b/examples/stmicro/stm32/src/stm32f1xx/timer_capture.zig @@ -38,7 +38,7 @@ var duty_cycle: f32 = 0; //since the timer is reset at each rising edge, //the value of ch2 marks the moment when the signal went from high to low, indicating the duty cycle. //the value of ch1 marks the point when the signal goes back to high before the timer resets, indicating the period. -fn isr_tim2() callconv(.C) void { +fn isr_tim2() callconv(.c) void { const flags = comp.get_interrupt_flags(); if (flags.channel2) { const rev_ch1 = comp.read_ccr(0); diff --git a/examples/stmicro/stm32/src/stm32f1xx/usb_cdc.zig b/examples/stmicro/stm32/src/stm32f1xx/usb_cdc.zig index c7e0108fa..ef74c1286 100644 --- a/examples/stmicro/stm32/src/stm32f1xx/usb_cdc.zig +++ b/examples/stmicro/stm32/src/stm32f1xx/usb_cdc.zig @@ -184,7 +184,7 @@ const SerialState = packed struct(u8) { //=============== USB DATA ================= var USB_RX_BUFFER: [64]u8 = undefined; -var CDC_fifo: std.fifo.LinearFifo(u8, .{ .Static = 64 }) = undefined; +var CDC_fifo: microzig.utilities.CircularBuffer(u8, 64) = .empty; var device_addr: ?u7 = null; var remain_pkg: ?[]const u8 = null; var config: bool = false; @@ -315,9 +315,9 @@ fn ep2_tx(_: EpControl, _: ?*anyopaque) void { fn ep3_rx(epc: EpControl, _: ?*anyopaque) void { const recv = epc.USB_read(.no_change) catch unreachable; - const free_data = CDC_fifo.writableLength(); + const free_data = CDC_fifo.get_writable_len(); const to_write = @min(recv.len, free_data); - CDC_fifo.writeAssumeCapacity(recv[0..to_write]); + CDC_fifo.write_assume_capacity(recv[0..to_write]); } //=============== USB FUNC ================= @@ -392,14 +392,14 @@ fn CDC_write(msg: []const u8) void { } fn CDC_read(buf: []u8, timeout: Timeout) ![]const u8 { - const fifo: *std.fifo.LinearFifo(u8, .{ .Static = 64 }) = &CDC_fifo; + const fifo = &CDC_fifo; var index: usize = 0; reader: for (buf) |*byte| { - while (fifo.readableLength() == 0) { + while (fifo.get_readable_len() == 0) { if (timeout.check_timeout()) break :reader; } - byte.* = fifo.readItem().?; + byte.* = fifo.pop().?; index += 1; } if (index == 0) { @@ -426,7 +426,7 @@ pub fn main() !void { const led = gpio.Pin.from_port(.B, 2); led.set_output_mode(.general_purpose_push_pull, .max_50MHz); - CDC_fifo = std.fifo.LinearFifo(u8, .{ .Static = 64 }).init(); + CDC_fifo.reset(); Counter = timer.counter_device(rcc.get_clock(.TIM2)); //NOTE: the stm32f103 does not have an internal 1.5k pull-up resistor for USB, you must add one externally diff --git a/examples/stmicro/stm32/src/stm32f1xx/usb_remote_hid.zig b/examples/stmicro/stm32/src/stm32f1xx/usb_remote_hid.zig index 785c5fa87..cb2c0f40d 100644 --- a/examples/stmicro/stm32/src/stm32f1xx/usb_remote_hid.zig +++ b/examples/stmicro/stm32/src/stm32f1xx/usb_remote_hid.zig @@ -374,7 +374,7 @@ fn stop_IR_timer() usize { var ir_val: u64 = 0; var ir_index: u6 = 0; -fn IR_handler() callconv(.C) void { +fn IR_handler() callconv(.c) void { const pin_state = IR_pin.read(); if (pin_state == 0) { const val = stop_IR_timer(); @@ -406,7 +406,7 @@ fn IR_handler() callconv(.C) void { var nec_report: NecPkg = undefined; var nec_send: bool = false; -fn IR_timer_handler() callconv(.C) void { +fn IR_timer_handler() callconv(.c) void { const val: u32 = @truncate(ir_val); const nec: NecPkg = @bitCast(val); if (val == 0) { diff --git a/examples/wch/ch32v/src/blinky.zig b/examples/wch/ch32v/src/blinky.zig index 4eafcb88d..4ea8ae75d 100644 --- a/examples/wch/ch32v/src/blinky.zig +++ b/examples/wch/ch32v/src/blinky.zig @@ -41,6 +41,6 @@ inline fn busy_delay(comptime ms: u32) void { var i: u32 = 0; while (i < limit) : (i += 1) { - asm volatile ("" ::: "memory"); + asm volatile ("" ::: .{ .memory = true }); } } diff --git a/examples/wch/ch32v/src/board_blinky.zig b/examples/wch/ch32v/src/board_blinky.zig index 37102a6b2..fc5e875ef 100644 --- a/examples/wch/ch32v/src/board_blinky.zig +++ b/examples/wch/ch32v/src/board_blinky.zig @@ -34,6 +34,6 @@ inline fn busy_delay(comptime ms: u32) void { var i: u32 = 0; while (i < limit) : (i += 1) { - asm volatile ("" ::: "memory"); + asm volatile ("" ::: .{ .memory = true }); } } diff --git a/modules/bounded-array/build.zig b/modules/bounded-array/build.zig new file mode 100644 index 000000000..51921b1d4 --- /dev/null +++ b/modules/bounded-array/build.zig @@ -0,0 +1,12 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + _ = b.addModule("bounded-array", .{ + .root_source_file = b.path("src/bounded_array.zig"), + .target = target, + .optimize = optimize, + }); +} diff --git a/modules/bounded-array/build.zig.zon b/modules/bounded-array/build.zig.zon new file mode 100644 index 000000000..80fd2c6f7 --- /dev/null +++ b/modules/bounded-array/build.zig.zon @@ -0,0 +1,11 @@ +.{ + .name = .bounded_array, + .version = "0.0.1", + .minimum_zig_version = "0.15.1", + .paths = .{ + "build.zig", + "build.zig.zon", + "src", + }, + .fingerprint = 0x7cda5953ee9270c, +} diff --git a/modules/bounded-array/src/bounded_array.zig b/modules/bounded-array/src/bounded_array.zig new file mode 100644 index 000000000..a68b8044c --- /dev/null +++ b/modules/bounded-array/src/bounded_array.zig @@ -0,0 +1,437 @@ +const std = @import("std"); +const assert = std.debug.assert; +const mem = std.mem; +const testing = std.testing; + +/// A structure with an array and a length, that can be used as a slice. +/// +/// Useful to pass around small arrays whose exact size is only known at +/// runtime, but whose maximum size is known at comptime, without requiring +/// an `Allocator`. +/// +/// ```zig +/// var actual_size = 32; +/// var a = try BoundedArray(u8, 64).init(actual_size); +/// var slice = a.slice(); // a slice of the 64-byte array +/// var a_clone = a; // creates a copy - the structure doesn't use any internal pointers +/// ``` +pub fn BoundedArray(comptime T: type, comptime buffer_capacity: usize) type { + return BoundedArrayAligned(T, @alignOf(T), buffer_capacity); +} + +/// A structure with an array, length and alignment, that can be used as a +/// slice. +/// +/// Useful to pass around small explicitly-aligned arrays whose exact size is +/// only known at runtime, but whose maximum size is known at comptime, without +/// requiring an `Allocator`. +/// ```zig +// var a = try BoundedArrayAligned(u8, 16, 2).init(0); +// try a.append(255); +// try a.append(255); +// const b = @ptrCast(*const [1]u16, a.constSlice().ptr); +// try testing.expectEqual(@as(u16, 65535), b[0]); +/// ``` +pub fn BoundedArrayAligned( + comptime T: type, + comptime alignment: u29, + comptime buffer_capacity: usize, +) type { + return struct { + const Self = @This(); + buffer: [buffer_capacity]T align(alignment) = undefined, + len: usize = 0, + + /// Set the actual length of the slice. + /// Returns error.Overflow if it exceeds the length of the backing array. + pub fn init(len: usize) error{Overflow}!Self { + if (len > buffer_capacity) return error.Overflow; + return Self{ .len = len }; + } + + /// View the internal array as a slice whose size was previously set. + pub fn slice(self: anytype) switch (@TypeOf(&self.buffer)) { + *align(alignment) [buffer_capacity]T => []align(alignment) T, + *align(alignment) const [buffer_capacity]T => []align(alignment) const T, + else => unreachable, + } { + return self.buffer[0..self.len]; + } + + /// View the internal array as a constant slice whose size was previously set. + pub fn constSlice(self: *const Self) []align(alignment) const T { + return self.slice(); + } + + /// Adjust the slice's length to `len`. + /// Does not initialize added items if any. + pub fn resize(self: *Self, len: usize) error{Overflow}!void { + if (len > buffer_capacity) return error.Overflow; + self.len = len; + } + + /// Remove all elements from the slice. + pub fn clear(self: *Self) void { + self.len = 0; + } + + /// Copy the content of an existing slice. + pub fn fromSlice(m: []const T) error{Overflow}!Self { + var list = try init(m.len); + @memcpy(list.slice(), m); + return list; + } + + /// Return the element at index `i` of the slice. + pub fn get(self: Self, i: usize) T { + return self.constSlice()[i]; + } + + /// Set the value of the element at index `i` of the slice. + pub fn set(self: *Self, i: usize, item: T) void { + self.slice()[i] = item; + } + + /// Return the maximum length of a slice. + pub fn capacity(self: Self) usize { + return self.buffer.len; + } + + /// Check that the slice can hold at least `additional_count` items. + pub fn ensureUnusedCapacity(self: Self, additional_count: usize) error{Overflow}!void { + if (self.len + additional_count > buffer_capacity) { + return error.Overflow; + } + } + + /// Increase length by 1, returning a pointer to the new item. + pub fn addOne(self: *Self) error{Overflow}!*T { + try self.ensureUnusedCapacity(1); + return self.addOneAssumeCapacity(); + } + + /// Increase length by 1, returning pointer to the new item. + /// Asserts that there is space for the new item. + pub fn addOneAssumeCapacity(self: *Self) *T { + assert(self.len < buffer_capacity); + self.len += 1; + return &self.slice()[self.len - 1]; + } + + /// Resize the slice, adding `n` new elements, which have `undefined` values. + /// The return value is a pointer to the array of uninitialized elements. + pub fn addManyAsArray(self: *Self, comptime n: usize) error{Overflow}!*align(alignment) [n]T { + const prev_len = self.len; + try self.resize(self.len + n); + return self.slice()[prev_len..][0..n]; + } + + /// Resize the slice, adding `n` new elements, which have `undefined` values. + /// The return value is a slice pointing to the uninitialized elements. + pub fn addManyAsSlice(self: *Self, n: usize) error{Overflow}![]align(alignment) T { + const prev_len = self.len; + try self.resize(self.len + n); + return self.slice()[prev_len..][0..n]; + } + + /// Remove and return the last element from the slice, or return `null` if the slice is empty. + pub fn pop(self: *Self) ?T { + if (self.len == 0) return null; + const item = self.get(self.len - 1); + self.len -= 1; + return item; + } + + /// Return a slice of only the extra capacity after items. + /// This can be useful for writing directly into it. + /// Note that such an operation must be followed up with a + /// call to `resize()` + pub fn unusedCapacitySlice(self: *Self) []align(alignment) T { + return self.buffer[self.len..]; + } + + /// Insert `item` at index `i` by moving `slice[n .. slice.len]` to make room. + /// This operation is O(N). + pub fn insert( + self: *Self, + i: usize, + item: T, + ) error{Overflow}!void { + if (i > self.len) { + return error.Overflow; + } + _ = try self.addOne(); + var s = self.slice(); + mem.copyBackwards(T, s[i + 1 .. s.len], s[i .. s.len - 1]); + self.buffer[i] = item; + } + + /// Insert slice `items` at index `i` by moving `slice[i .. slice.len]` to make room. + /// This operation is O(N). + pub fn insertSlice(self: *Self, i: usize, items: []const T) error{Overflow}!void { + try self.ensureUnusedCapacity(items.len); + self.len += items.len; + mem.copyBackwards(T, self.slice()[i + items.len .. self.len], self.constSlice()[i .. self.len - items.len]); + @memcpy(self.slice()[i..][0..items.len], items); + } + + /// Replace range of elements `slice[start..][0..len]` with `new_items`. + /// Grows slice if `len < new_items.len`. + /// Shrinks slice if `len > new_items.len`. + pub fn replaceRange( + self: *Self, + start: usize, + len: usize, + new_items: []const T, + ) error{Overflow}!void { + const after_range = start + len; + var range = self.slice()[start..after_range]; + + if (range.len == new_items.len) { + @memcpy(range[0..new_items.len], new_items); + } else if (range.len < new_items.len) { + const first = new_items[0..range.len]; + const rest = new_items[range.len..]; + @memcpy(range[0..first.len], first); + try self.insertSlice(after_range, rest); + } else { + @memcpy(range[0..new_items.len], new_items); + const after_subrange = start + new_items.len; + for (self.constSlice()[after_range..], 0..) |item, i| { + self.slice()[after_subrange..][i] = item; + } + self.len -= len - new_items.len; + } + } + + /// Extend the slice by 1 element. + pub fn append(self: *Self, item: T) error{Overflow}!void { + const new_item_ptr = try self.addOne(); + new_item_ptr.* = item; + } + + /// Extend the slice by 1 element, asserting the capacity is already + /// enough to store the new item. + pub fn appendAssumeCapacity(self: *Self, item: T) void { + const new_item_ptr = self.addOneAssumeCapacity(); + new_item_ptr.* = item; + } + + /// Remove the element at index `i`, shift elements after index + /// `i` forward, and return the removed element. + /// Asserts the slice has at least one item. + /// This operation is O(N). + pub fn orderedRemove(self: *Self, i: usize) T { + const newlen = self.len - 1; + if (newlen == i) return self.pop().?; + const old_item = self.get(i); + for (self.slice()[i..newlen], 0..) |*b, j| b.* = self.get(i + 1 + j); + self.set(newlen, undefined); + self.len = newlen; + return old_item; + } + + /// Remove the element at the specified index and return it. + /// The empty slot is filled from the end of the slice. + /// This operation is O(1). + pub fn swapRemove(self: *Self, i: usize) T { + if (self.len - 1 == i) return self.pop().?; + const old_item = self.get(i); + self.set(i, self.pop().?); + return old_item; + } + + /// Append the slice of items to the slice. + pub fn appendSlice(self: *Self, items: []const T) error{Overflow}!void { + try self.ensureUnusedCapacity(items.len); + self.appendSliceAssumeCapacity(items); + } + + /// Append the slice of items to the slice, asserting the capacity is already + /// enough to store the new items. + pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void { + const old_len = self.len; + self.len += items.len; + @memcpy(self.slice()[old_len..][0..items.len], items); + } + + /// Append a value to the slice `n` times. + /// Allocates more memory as necessary. + pub fn appendNTimes(self: *Self, value: T, n: usize) error{Overflow}!void { + const old_len = self.len; + try self.resize(old_len + n); + @memset(self.slice()[old_len..self.len], value); + } + + /// Append a value to the slice `n` times. + /// Asserts the capacity is enough. + pub fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void { + const old_len = self.len; + self.len += n; + assert(self.len <= buffer_capacity); + @memset(self.slice()[old_len..self.len], value); + } + + pub const Writer = if (T != u8) + @compileError("The Writer interface is only defined for BoundedArray(u8, ...) " ++ + "but the given type is BoundedArray(" ++ @typeName(T) ++ ", ...)") + else + struct { + ba: *Self, + interface: std.Io.Writer, + //std.io.Writer(*Self, error{Overflow}, appendWrite); + }; + + /// Initializes a writer which will write into the array. + pub fn writer(self: *Self) Writer { + return .{ + .ba = self, + .interface = .{ + .vtable = &.{ + .drain = drain, + }, + .buffer = &.{}, + }, + }; + } + + fn drain(io_w: *std.Io.Writer, data: []const []const u8, splat: usize) std.Io.Writer.Error!usize { + _ = splat; + const w: *Writer = @fieldParentPtr("interface", io_w); + var ret: usize = 0; + for (data) |d| { + const n = w.ba.appendWrite(d) catch return error.WriteFailed; + ret += n; + if (n != d.len) + break; + } + + return ret; + } + + /// Same as `appendSlice` except it returns the number of bytes written, which is always the same + /// as `m.len`. The purpose of this function existing is to match `std.io.Writer` API. + fn appendWrite(self: *Self, m: []const u8) error{Overflow}!usize { + try self.appendSlice(m); + return m.len; + } + }; +} + +test BoundedArray { + var a = try BoundedArray(u8, 64).init(32); + + try testing.expectEqual(a.capacity(), 64); + try testing.expectEqual(a.slice().len, 32); + try testing.expectEqual(a.constSlice().len, 32); + + try a.resize(48); + try testing.expectEqual(a.len, 48); + + const x = [_]u8{1} ** 10; + a = try BoundedArray(u8, 64).fromSlice(&x); + try testing.expectEqualSlices(u8, &x, a.constSlice()); + + var a2 = a; + try testing.expectEqualSlices(u8, a.constSlice(), a2.constSlice()); + a2.set(0, 0); + try testing.expect(a.get(0) != a2.get(0)); + + try testing.expectError(error.Overflow, a.resize(100)); + try testing.expectError(error.Overflow, BoundedArray(u8, x.len - 1).fromSlice(&x)); + + try a.resize(0); + try a.ensureUnusedCapacity(a.capacity()); + (try a.addOne()).* = 0; + try a.ensureUnusedCapacity(a.capacity() - 1); + try testing.expectEqual(a.len, 1); + + const uninitialized = try a.addManyAsArray(4); + try testing.expectEqual(uninitialized.len, 4); + try testing.expectEqual(a.len, 5); + + try a.append(0xff); + try testing.expectEqual(a.len, 6); + try testing.expectEqual(a.pop(), 0xff); + + a.appendAssumeCapacity(0xff); + try testing.expectEqual(a.len, 6); + try testing.expectEqual(a.pop(), 0xff); + + try a.resize(1); + try testing.expectEqual(a.pop(), 0); + try testing.expectEqual(a.pop(), null); + var unused = a.unusedCapacitySlice(); + @memset(unused[0..8], 2); + unused[8] = 3; + unused[9] = 4; + try testing.expectEqual(unused.len, a.capacity()); + try a.resize(10); + + try a.insert(5, 0xaa); + try testing.expectEqual(a.len, 11); + try testing.expectEqual(a.get(5), 0xaa); + try testing.expectEqual(a.get(9), 3); + try testing.expectEqual(a.get(10), 4); + + try a.insert(11, 0xbb); + try testing.expectEqual(a.len, 12); + try testing.expectEqual(a.pop(), 0xbb); + + try a.appendSlice(&x); + try testing.expectEqual(a.len, 11 + x.len); + + try a.appendNTimes(0xbb, 5); + try testing.expectEqual(a.len, 11 + x.len + 5); + try testing.expectEqual(a.pop(), 0xbb); + + a.appendNTimesAssumeCapacity(0xcc, 5); + try testing.expectEqual(a.len, 11 + x.len + 5 - 1 + 5); + try testing.expectEqual(a.pop(), 0xcc); + + try testing.expectEqual(a.len, 29); + try a.replaceRange(1, 20, &x); + try testing.expectEqual(a.len, 29 + x.len - 20); + + try a.insertSlice(0, &x); + try testing.expectEqual(a.len, 29 + x.len - 20 + x.len); + + try a.replaceRange(1, 5, &x); + try testing.expectEqual(a.len, 29 + x.len - 20 + x.len + x.len - 5); + + try a.append(10); + try testing.expectEqual(a.pop(), 10); + + try a.append(20); + const removed = a.orderedRemove(5); + try testing.expectEqual(removed, 1); + try testing.expectEqual(a.len, 34); + + a.set(0, 0xdd); + a.set(a.len - 1, 0xee); + const swapped = a.swapRemove(0); + try testing.expectEqual(swapped, 0xdd); + try testing.expectEqual(a.get(0), 0xee); + + const added_slice = try a.addManyAsSlice(3); + try testing.expectEqual(added_slice.len, 3); + try testing.expectEqual(a.len, 36); + + while (a.pop()) |_| {} + const w = a.writer(); + const s = "hello, this is a test string"; + try w.writeAll(s); + try testing.expectEqualStrings(s, a.constSlice()); +} + +test "BoundedArrayAligned" { + var a = try BoundedArrayAligned(u8, 16, 4).init(0); + try a.append(0); + try a.append(0); + try a.append(255); + try a.append(255); + + const b = @as(*const [2]u16, @ptrCast(a.constSlice().ptr)); + try testing.expectEqual(@as(u16, 0), b[0]); + try testing.expectEqual(@as(u16, 65535), b[1]); +} diff --git a/modules/foundation-libc/build.zig b/modules/foundation-libc/build.zig index aabe36ff5..31ae1c883 100644 --- a/modules/foundation-libc/build.zig +++ b/modules/foundation-libc/build.zig @@ -13,12 +13,14 @@ pub fn build(b: *std.Build) void { b.getInstallStep().dependOn(validation_step); } - const libc = b.addStaticLibrary(.{ + const libc = b.addLibrary(.{ .name = "foundation", - .target = target, - .optimize = optimize, - .root_source_file = b.path("src/libc.zig"), - .single_threaded = single_threaded, + .root_module = b.createModule(.{ + .target = target, + .optimize = optimize, + .root_source_file = b.path("src/libc.zig"), + .single_threaded = single_threaded, + }), }); libc.addIncludePath(b.path("include")); diff --git a/modules/rtt/src/lock.zig b/modules/rtt/src/lock.zig index c1849b889..0551e1816 100644 --- a/modules/rtt/src/lock.zig +++ b/modules/rtt/src/lock.zig @@ -16,7 +16,7 @@ pub fn GenericLock( } fn type_erased_lock(context: *anyopaque) void { - const ptr: *const Context = @alignCast(@ptrCast(context)); + const ptr: *const Context = @ptrCast(@alignCast(context)); return lock_fn(ptr.*); } @@ -25,7 +25,7 @@ pub fn GenericLock( } fn type_erased_unlock(context: *anyopaque) void { - const ptr: *const Context = @alignCast(@ptrCast(context)); + const ptr: *const Context = @ptrCast(@alignCast(context)); return unlock_fn(ptr.*); } @@ -64,8 +64,7 @@ pub const default = struct { \\msr primask, r1 : [val] "=r" (val), : - : "r1", "cc" - ); + : .{ .r1 = true, .cpsr = true }); context.isr_reg_value = val; } @@ -89,8 +88,7 @@ pub const default = struct { \\msr basepri, r1 : [val] "=r" (val), : [MAX_ISR_PRIORITY] "i" (MAX_ISR_PRIORITY), - : "r1", "cc" - ); + : .{ .r1 = true, .cpsr = true }); context.isr_reg_value = val; } @@ -113,8 +111,7 @@ pub const default = struct { \\msr CPSR_C, r1 : [val] "=r" (val), : - : "r1", "cc" - ); + : .{ .r1 = true, .cpsr = true }); context.isr_reg_value = val; } @@ -129,8 +126,7 @@ pub const default = struct { \\msr CPSR_C, r1 : : [val] "r" (val), - : "r0", "r1", "cc" - ); + : .{ .r0 = true, .r1 = true, .cpsr = true }); } }; diff --git a/modules/rtt/src/memory_barrier.zig b/modules/rtt/src/memory_barrier.zig index 60376d389..7d286f1a7 100644 --- a/modules/rtt/src/memory_barrier.zig +++ b/modules/rtt/src/memory_barrier.zig @@ -1,12 +1,12 @@ const std = @import("std"); const builtin = @import("builtin"); -pub const MemoryBarrierFn = fn () callconv(.Inline) void; +pub const MemoryBarrierFn = fn () callconv(.@"inline") void; pub inline fn empty_memory_barrier() void {} inline fn arm_memory_barrier() void { - asm volatile ("DMB" ::: "memory"); + asm volatile ("DMB" ::: .{ .memory = true }); } inline fn error_memory_barrier() void { diff --git a/port/espressif/esp/build.zig b/port/espressif/esp/build.zig index f86265c81..0fdc5de8d 100644 --- a/port/espressif/esp/build.zig +++ b/port/espressif/esp/build.zig @@ -126,10 +126,14 @@ pub fn init(dep: *std.Build.Dependency) Self { pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); + const target = b.standardTargetOptions(.{}); const unit_tests = b.addTest(.{ - .root_source_file = b.path("src/hal.zig"), - .optimize = optimize, + .root_module = b.createModule(.{ + .root_source_file = b.path("src/hal.zig"), + .target = target, + .optimize = optimize, + }), }); const unit_tests_run = b.addRunArtifact(unit_tests); diff --git a/port/espressif/esp/src/hal/drivers.zig b/port/espressif/esp/src/hal/drivers.zig index e855811ee..cb5c1599d 100644 --- a/port/espressif/esp/src/hal/drivers.zig +++ b/port/espressif/esp/src/hal/drivers.zig @@ -73,7 +73,7 @@ pub const I2C_Datagram_Device = struct { pub fn readv(dev: I2C_Datagram_Device, datagrams: []const []u8) !usize { try dev.bus.readv_blocking(dev.address, datagrams, dev.timeout); - return microzig.utilities.Slice_Vector([]u8).init(datagrams).size(); + return microzig.utilities.SliceVector([]u8).init(datagrams).size(); } const vtable = Datagram_Device.VTable{ @@ -175,7 +175,7 @@ pub const I2C_Device = struct { error.CommandNumberExceeded => I2CError.UnknownAbort, else => |e| e, }; - return microzig.utilities.Slice_Vector([]u8).init(chunks).size(); + return microzig.utilities.SliceVector([]u8).init(chunks).size(); } pub fn write_then_read(dev: I2C_Device, address: I2CAddress, src: []const u8, dst: []u8) I2CError!void { diff --git a/port/espressif/esp/src/hal/i2c.zig b/port/espressif/esp/src/hal/i2c.zig index b6d3e50b7..b15f93d52 100644 --- a/port/espressif/esp/src/hal/i2c.zig +++ b/port/espressif/esp/src/hal/i2c.zig @@ -531,7 +531,7 @@ pub const I2C = enum(u1) { pub fn readv_blocking(self: I2C, addr: Address, chunks: []const []u8, timeout: ?mdf.time.Duration) !void { const deadline = mdf.time.Deadline.init_relative(time.get_time_since_boot(), timeout); - const read_vec = microzig.utilities.Slice_Vector([]u8).init(chunks); + const read_vec = microzig.utilities.SliceVector([]u8).init(chunks); var is_first_chunk = true; // Always saving room for the address byte. With a custom iterator we could make sure only the first chunk is 31 (room for address) @@ -618,7 +618,7 @@ pub const I2C = enum(u1) { const deadline = mdf.time.Deadline.init_relative(time.get_time_since_boot(), timeout); // TODO: Write a new utility that does similar but that will coalesce into a specified size - const write_vec = microzig.utilities.Slice_Vector([]const u8).init(chunks); + const write_vec = microzig.utilities.SliceVector([]const u8).init(chunks); if (write_vec.size() == 0) return self.write_operation_blocking(addr, &.{}, start, stop, deadline); diff --git a/port/espressif/esp/src/hal/spi.zig b/port/espressif/esp/src/hal/spi.zig index 38c7b83a5..c428a49c4 100644 --- a/port/espressif/esp/src/hal/spi.zig +++ b/port/espressif/esp/src/hal/spi.zig @@ -1,6 +1,6 @@ const std = @import("std"); const microzig = @import("microzig"); -const Slice_Vector = microzig.utilities.Slice_Vector; +const SliceVector = microzig.utilities.SliceVector; const hal = microzig.hal; const system = hal.system; @@ -163,7 +163,7 @@ pub const SPI_Bus = struct { buffer_vec: []const []const u8, bit_mode: BitMode, ) void { - const vec: Slice_Vector([]const u8) = .init(buffer_vec); + const vec: SliceVector([]const u8) = .init(buffer_vec); var iter = vec.iterator(); var remaining = vec.size(); @@ -200,7 +200,7 @@ pub const SPI_Bus = struct { buffer_vec: []const []u8, bit_mode: BitMode, ) usize { - const vec: Slice_Vector([]u8) = .init(buffer_vec); + const vec: SliceVector([]u8) = .init(buffer_vec); var iter = vec.iterator(); const total_len = vec.size(); @@ -242,9 +242,9 @@ pub const SPI_Bus = struct { write_buffer_vec: []const []const u8, read_buffer_vec: []const []u8, ) void { - const write_vec: Slice_Vector([]const u8) = .init(write_buffer_vec); + const write_vec: SliceVector([]const u8) = .init(write_buffer_vec); var write_iter = write_vec.iterator(); - const read_vec: Slice_Vector([]const u8) = .init(read_buffer_vec); + const read_vec: SliceVector([]const u8) = .init(read_buffer_vec); var read_iter = read_vec.iterator(); var remaining = write_vec.size(); @@ -284,7 +284,7 @@ pub const SPI_Bus = struct { }); } - fn fill_fifo(self: SPI_Bus, iter: *Slice_Vector([]const u8).Iterator, len: usize) void { + fn fill_fifo(self: SPI_Bus, iter: *SliceVector([]const u8).Iterator, len: usize) void { const fifo: *volatile [16]u32 = @ptrCast(&self.regs.W0); var i: usize = 0; @@ -302,7 +302,7 @@ pub const SPI_Bus = struct { } } - fn read_fifo(self: SPI_Bus, iter: *Slice_Vector([]u8).Iterator, len: usize) void { + fn read_fifo(self: SPI_Bus, iter: *SliceVector([]u8).Iterator, len: usize) void { const fifo: *volatile [16]u32 = @ptrCast(&self.regs.W0); var i: usize = 0; diff --git a/port/nordic/nrf5x/build.zig b/port/nordic/nrf5x/build.zig index 938d1a75c..a846763b5 100644 --- a/port/nordic/nrf5x/build.zig +++ b/port/nordic/nrf5x/build.zig @@ -189,10 +189,14 @@ pub fn init(dep: *std.Build.Dependency) Self { pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); + const target = b.standardTargetOptions(.{}); const unit_tests = b.addTest(.{ - .root_source_file = b.path("src/hal.zig"), - .optimize = optimize, + .root_module = b.createModule(.{ + .root_source_file = b.path("src/hal.zig"), + .target = target, + .optimize = optimize, + }), }); const unit_tests_run = b.addRunArtifact(unit_tests); diff --git a/port/nordic/nrf5x/src/hal/drivers.zig b/port/nordic/nrf5x/src/hal/drivers.zig index 2d0367658..f56034dc1 100644 --- a/port/nordic/nrf5x/src/hal/drivers.zig +++ b/port/nordic/nrf5x/src/hal/drivers.zig @@ -72,7 +72,7 @@ pub const I2C_Datagram_Device = struct { pub fn readv(dev: I2C_Datagram_Device, datagrams: []const []u8) !usize { try dev.bus.readv_blocking(dev.address, datagrams, dev.timeout); - return microzig.utilities.Slice_Vector([]u8).init(datagrams).size(); + return microzig.utilities.SliceVector([]u8).init(datagrams).size(); } pub fn writev_then_readv( @@ -204,7 +204,7 @@ pub const I2C_Device = struct { error.Overrun => I2CError.UnknownAbort, else => |e| e, }; - return microzig.utilities.Slice_Vector([]u8).init(chunks).size(); + return microzig.utilities.SliceVector([]u8).init(chunks).size(); } pub fn write_then_read(dev: I2C_Device, address: I2CAddress, src: []const u8, dst: []u8) I2CError!void { @@ -338,7 +338,7 @@ pub const SPI_Device = struct { pub fn readv(dev: SPI_Device, datagrams: []const []const u8) !usize { dev.bus.readv_blocking(u8, datagrams); - return microzig.utilities.Slice_Vector([]u8).init(datagrams).size(); + return microzig.utilities.SliceVector([]u8).init(datagrams).size(); } const vtable = Datagram_Device.VTable{ @@ -373,7 +373,7 @@ pub const SPI_Device = struct { error.Timeout => return ReadError.Timeout, else => return ReadError.Unsupported, }; - return microzig.utilities.Slice_Vector([]u8).init(chunks).size(); + return microzig.utilities.SliceVector([]u8).init(chunks).size(); } }; diff --git a/port/nordic/nrf5x/src/hal/i2c.zig b/port/nordic/nrf5x/src/hal/i2c.zig index 9feb1d054..d9a685572 100644 --- a/port/nordic/nrf5x/src/hal/i2c.zig +++ b/port/nordic/nrf5x/src/hal/i2c.zig @@ -252,7 +252,7 @@ pub const I2C = enum(u1) { pub fn writev_blocking(i2c: I2C, addr: Address, chunks: []const []const u8, timeout: ?mdf.time.Duration) Error!void { try i2c.set_address(addr, .allow_general); - const write_vec = microzig.utilities.Slice_Vector([]const u8).init(chunks); + const write_vec = microzig.utilities.SliceVector([]const u8).init(chunks); if (write_vec.size() == 0) return Error.NoData; @@ -298,7 +298,7 @@ pub const I2C = enum(u1) { pub fn readv_blocking(i2c: I2C, addr: Address, chunks: []const []u8, timeout: ?mdf.time.Duration) Error!void { try i2c.set_address(addr, .dont_allow_reserved); - const read_vec = microzig.utilities.Slice_Vector([]u8).init(chunks); + const read_vec = microzig.utilities.SliceVector([]u8).init(chunks); if (read_vec.size() == 0) return Error.NoData; @@ -360,8 +360,8 @@ pub const I2C = enum(u1) { pub fn writev_then_readv_blocking(i2c: I2C, addr: Address, write_chunks: []const []const u8, read_chunks: []const []u8, timeout: ?mdf.time.Duration) Error!void { try i2c.set_address(addr, .dont_allow_reserved); - const write_vec = microzig.utilities.Slice_Vector([]const u8).init(write_chunks); - const read_vec = microzig.utilities.Slice_Vector([]u8).init(read_chunks); + const write_vec = microzig.utilities.SliceVector([]const u8).init(write_chunks); + const read_vec = microzig.utilities.SliceVector([]u8).init(read_chunks); if (write_vec.size() == 0) return Error.NoData; diff --git a/port/nxp/lpc/build.zig b/port/nxp/lpc/build.zig index b367dbcd4..5495047e8 100644 --- a/port/nxp/lpc/build.zig +++ b/port/nxp/lpc/build.zig @@ -60,10 +60,16 @@ pub fn init(dep: *std.Build.Dependency) Self { } pub fn build(b: *std.Build) void { + const optimize = b.standardOptimizeOption(.{}); + const target = b.standardTargetOptions(.{}); + const lpc176x5x_patch_elf_exe = b.addExecutable(.{ .name = "lpc176x5x-patchelf", - .root_source_file = b.path("src/tools/patchelf.zig"), - .target = b.graph.host, + .root_module = b.createModule(.{ + .root_source_file = b.path("src/tools/patchelf.zig"), + .optimize = optimize, + .target = target, + }), }); b.installArtifact(lpc176x5x_patch_elf_exe); } diff --git a/port/nxp/lpc/src/tools/patchelf.zig b/port/nxp/lpc/src/tools/patchelf.zig index 60736f9b0..e60a9e212 100644 --- a/port/nxp/lpc/src/tools/patchelf.zig +++ b/port/nxp/lpc/src/tools/patchelf.zig @@ -23,9 +23,14 @@ pub fn main() !u8 { var file = try std.fs.cwd().openFile(output_file_name, .{ .mode = .read_write }); defer file.close(); - const header = try std.elf.Header.read(file); + var read_buf: [4096]u8 = undefined; + var write_buf: [4096]u8 = undefined; + var file_reader = file.reader(&read_buf); + var file_writer = file.writer(&write_buf); - var iter = header.program_header_iterator(file); + const header = try std.elf.Header.read(&file_reader.interface); + + var iter = header.iterateProgramHeaders(&file_reader); while (try iter.next()) |phdr| { if (phdr.p_type != std.elf.PT_LOAD) { continue; @@ -48,19 +53,18 @@ pub fn main() !u8 { } try file.seekTo(phdr.p_offset); - var reader = file.reader(); - var writer = file.writer(); var checksum: u32 = 0; var i: usize = 0; while (i < boot_sector_items - 1) : (i += 1) { - const item = try reader.readInt(u32, .little); + const item = try file_reader.interface.takeInt(u32, .little); checksum -%= item; } - try writer.writeInt(u32, checksum, .little); + try file_writer.interface.writeInt(u32, checksum, .little); } + try file_writer.interface.flush(); return 0; } diff --git a/port/raspberrypi/rp2xxx/build.zig b/port/raspberrypi/rp2xxx/build.zig index 0ca3f9bc3..b5b98aad8 100644 --- a/port/raspberrypi/rp2xxx/build.zig +++ b/port/raspberrypi/rp2xxx/build.zig @@ -34,9 +34,14 @@ pub fn init(dep: *std.Build.Dependency) Self { const riscv32_common_dep = b.dependency("microzig/modules/riscv32-common", .{}); const pico_sdk = b.dependency("pico-sdk", .{}); + const bounded_array_dep = b.dependency("bounded-array", .{}); const hal: microzig.HardwareAbstractionLayer = .{ .root_source_file = b.path("src/hal.zig"), + .imports = b.allocator.dupe(std.Build.Module.Import, &.{.{ + .name = "bounded-array", + .module = bounded_array_dep.module("bounded-array"), + }}) catch @panic("OOM"), }; const chip_rp2040: microzig.Target = .{ @@ -268,10 +273,20 @@ pub fn build(b: *std.Build) !void { // TODO: construct all bootroms here and expose them via lazy paths: requires zig 0.14 const optimize = b.standardOptimizeOption(.{}); + const target = b.standardTargetOptions(.{}); + + const bounded_array_dep = b.dependency("bounded-array", .{}); const unit_tests = b.addTest(.{ - .root_source_file = b.path("src/hal.zig"), - .optimize = optimize, + .root_module = b.createModule(.{ + .root_source_file = b.path("src/hal.zig"), + .target = target, + .optimize = optimize, + .imports = &.{.{ + .name = "bounded-array", + .module = bounded_array_dep.module("bounded-array"), + }}, + }), }); unit_tests.addIncludePath(b.path("src/hal/pio/assembler")); @@ -296,9 +311,11 @@ fn get_bootrom(b: *std.Build, target: *const microzig.Target, rom: BootROM) std. zig_target.abi = .eabi; const rom_exe = b.addExecutable(.{ - .name = b.fmt("stage2-{s}", .{@tagName(rom)}), - .optimize = .ReleaseSmall, - .target = b.resolveTargetQuery(zig_target), + .name = b.fmt("stage2-{t}", .{rom}), + .root_module = b.createModule(.{ + .optimize = .ReleaseSmall, + .target = b.resolveTargetQuery(zig_target), + }), }); //rom_exe.linkage = .static; diff --git a/port/raspberrypi/rp2xxx/build.zig.zon b/port/raspberrypi/rp2xxx/build.zig.zon index 80c1f8a79..6de3e3790 100644 --- a/port/raspberrypi/rp2xxx/build.zig.zon +++ b/port/raspberrypi/rp2xxx/build.zig.zon @@ -9,6 +9,7 @@ .url = "https://github.com/raspberrypi/pico-sdk/archive/refs/tags/2.1.1.tar.gz", .hash = "N-V-__8AAPtGbwGQkp_3ej_icp5z6qgvjmwoE1AvAcZlh57Z", }, + .@"bounded-array" = .{ .path = "../../../modules/bounded-array" }, }, .paths = .{ "README.md", diff --git a/port/raspberrypi/rp2xxx/src/hal/clocks/common.zig b/port/raspberrypi/rp2xxx/src/hal/clocks/common.zig index 62e93bd66..903e9c359 100644 --- a/port/raspberrypi/rp2xxx/src/hal/clocks/common.zig +++ b/port/raspberrypi/rp2xxx/src/hal/clocks/common.zig @@ -263,6 +263,8 @@ fn busy_wait_at_least(delay_cycles: u32) void { } : [cycles] "+r" (_cycles), : - : "cc", "memory" - ); + : switch (arch) { + .arm => .{ .cpsr = true, .memory = true }, + .riscv => .{ .memory = true }, + }); } diff --git a/port/raspberrypi/rp2xxx/src/hal/drivers.zig b/port/raspberrypi/rp2xxx/src/hal/drivers.zig index 8ae9ff439..7578e8433 100644 --- a/port/raspberrypi/rp2xxx/src/hal/drivers.zig +++ b/port/raspberrypi/rp2xxx/src/hal/drivers.zig @@ -72,7 +72,7 @@ pub const I2C_Datagram_Device = struct { pub fn readv(dev: I2C_Datagram_Device, datagrams: []const []u8) !usize { try dev.bus.readv_blocking(dev.address, datagrams, dev.timeout); - return microzig.utilities.Slice_Vector([]u8).init(datagrams).size(); + return microzig.utilities.SliceVector([]u8).init(datagrams).size(); } pub fn write_then_read(dev: I2C_Datagram_Device, src: []const u8, dst: []u8) !void { @@ -204,7 +204,7 @@ pub const I2C_Device = struct { error.TxFifoFlushed => I2CError.UnknownAbort, else => |e| e, }; - return microzig.utilities.Slice_Vector([]u8).init(chunks).size(); + return microzig.utilities.SliceVector([]u8).init(chunks).size(); } pub fn write_then_read(dev: I2C_Device, address: I2CAddress, src: []const u8, dst: []u8) I2CError!void { @@ -335,7 +335,7 @@ pub const SPI_Device = struct { pub fn readv(dev: SPI_Device, datagrams: []const []const u8) !usize { dev.bus.readv_blocking(u8, dev.rx_dummy_data, datagrams); - return microzig.utilities.Slice_Vector([]u8).init(datagrams).size(); + return microzig.utilities.SliceVector([]u8).init(datagrams).size(); } const vtable = Datagram_Device.VTable{ @@ -363,7 +363,7 @@ pub const SPI_Device = struct { fn readv_fn(dd: *anyopaque, chunks: []const []u8) ReadError!usize { const dev: *SPI_Device = @ptrCast(@alignCast(dd)); dev.bus.readv_blocking(u8, dev.rx_dummy_data, chunks); - return microzig.utilities.Slice_Vector([]u8).init(chunks).size(); + return microzig.utilities.SliceVector([]u8).init(chunks).size(); } }; diff --git a/port/raspberrypi/rp2xxx/src/hal/flash.zig b/port/raspberrypi/rp2xxx/src/hal/flash.zig index a7128dbf3..983811ba9 100644 --- a/port/raspberrypi/rp2xxx/src/hal/flash.zig +++ b/port/raspberrypi/rp2xxx/src/hal/flash.zig @@ -62,8 +62,7 @@ pub const boot2 = struct { \\blx r0 : : [copyout] "{r0}" (@intFromPtr(©out)), - : "r0", "lr" - ); + : .{ .r0 = true, .r14 = true }); } }; @@ -79,7 +78,7 @@ pub inline fn range_erase(offset: u32, count: u32) void { export fn _range_erase(offset: u32, count: u32) linksection(".ram_text") void { // TODO: add sanity checks, e.g., offset + count < flash size - asm volatile ("" ::: "memory"); // memory barrier + asm volatile ("" ::: .{ .memory = true }); // memory barrier boot2.flash_init(); @@ -103,7 +102,7 @@ pub inline fn range_program(offset: u32, data: []const u8) void { export fn _range_program(offset: u32, data: [*]const u8, len: usize) linksection(".ram_text") void { // TODO: add sanity checks, e.g., offset + count < flash size - asm volatile ("" ::: "memory"); // memory barrier + asm volatile ("" ::: .{ .memory = true }); // memory barrier boot2.flash_init(); @@ -144,7 +143,7 @@ pub inline fn cmd(tx_buf: []const u8, rx_buf: []u8) void { fn _cmd(tx_buf: []const u8, rx_buf: []u8) linksection(".ram_text") void { boot2.flash_init(); - asm volatile ("" ::: "memory"); // memory barrier + asm volatile ("" ::: .{ .memory = true }); // memory barrier rom.connect_internal_flash(); rom.flash_exit_xip(); force_cs(false); diff --git a/port/raspberrypi/rp2xxx/src/hal/hw.zig b/port/raspberrypi/rp2xxx/src/hal/hw.zig index b552df46f..d8990f3c9 100644 --- a/port/raspberrypi/rp2xxx/src/hal/hw.zig +++ b/port/raspberrypi/rp2xxx/src/hal/hw.zig @@ -50,5 +50,5 @@ pub fn xor_alias(ptr: anytype) @TypeOf(ptr) { } pub inline fn tight_loop_contents() void { - asm volatile ("" ::: "memory"); + asm volatile ("" ::: .{ .memory = true }); } diff --git a/port/raspberrypi/rp2xxx/src/hal/i2c.zig b/port/raspberrypi/rp2xxx/src/hal/i2c.zig index ae1a35252..3ab806324 100644 --- a/port/raspberrypi/rp2xxx/src/hal/i2c.zig +++ b/port/raspberrypi/rp2xxx/src/hal/i2c.zig @@ -384,7 +384,7 @@ pub const I2C = enum(u1) { pub fn writev_blocking(i2c: I2C, addr: Address, chunks: []const []const u8, timeout: ?mdf.time.Duration) Error!void { try i2c.set_address(addr, .allow_general); - const write_vec = microzig.utilities.Slice_Vector([]const u8).init(chunks); + const write_vec = microzig.utilities.SliceVector([]const u8).init(chunks); if (write_vec.size() == 0) return Error.NoData; @@ -460,7 +460,7 @@ pub const I2C = enum(u1) { pub fn readv_blocking(i2c: I2C, addr: Address, chunks: []const []u8, timeout: ?mdf.time.Duration) Error!void { try i2c.set_address(addr, .dont_allow_reserved); - const read_vec = microzig.utilities.Slice_Vector([]u8).init(chunks); + const read_vec = microzig.utilities.SliceVector([]u8).init(chunks); if (read_vec.size() == 0) return Error.NoData; @@ -528,8 +528,8 @@ pub const I2C = enum(u1) { pub fn writev_then_readv_blocking(i2c: I2C, addr: Address, write_chunks: []const []const u8, read_chunks: []const []u8, timeout: ?mdf.time.Duration) Error!void { try i2c.set_address(addr, .dont_allow_reserved); - const write_vec = microzig.utilities.Slice_Vector([]const u8).init(write_chunks); - const read_vec = microzig.utilities.Slice_Vector([]u8).init(read_chunks); + const write_vec = microzig.utilities.SliceVector([]const u8).init(write_chunks); + const read_vec = microzig.utilities.SliceVector([]u8).init(read_chunks); if (write_vec.size() == 0) return Error.NoData; diff --git a/port/raspberrypi/rp2xxx/src/hal/pio/assembler.zig b/port/raspberrypi/rp2xxx/src/hal/pio/assembler.zig index 00a9226b4..94cc00dc3 100644 --- a/port/raspberrypi/rp2xxx/src/hal/pio/assembler.zig +++ b/port/raspberrypi/rp2xxx/src/hal/pio/assembler.zig @@ -1,6 +1,9 @@ const std = @import("std"); const assert = std.debug.assert; +const microzig = @import("microzig"); +const BoundedArray = @import("bounded-array").BoundedArray; + const Chip = @import("../chip.zig").Chip; const tokenizer = @import("assembler/tokenizer.zig"); const encoder = @import("assembler/encoder.zig"); @@ -58,16 +61,18 @@ pub const AssembleOptions = struct { }; pub const Diagnostics = struct { - message: std.BoundedArray(u8, 256), + message: BoundedArray(u8, 256), index: u32, pub fn init(index: u32, comptime fmt: []const u8, args: anytype) Diagnostics { var ret = Diagnostics{ - .message = std.BoundedArray(u8, 256).init(0) catch unreachable, + .message = BoundedArray(u8, 256).init(0) catch unreachable, .index = index, }; - ret.message.writer().print(fmt, args) catch unreachable; + var writer = ret.message.writer(); + + writer.interface.print(fmt, args) catch unreachable; return ret; } }; @@ -81,13 +86,13 @@ fn comptime_copy(comptime T: type, comptime slice: []const T) []const T { pub fn assemble_impl(comptime chip: Chip, comptime source: []const u8, diags: *?Diagnostics, options: AssembleOptions) !Output { const tokens = try tokenizer.tokenize(chip, source, diags, options.tokenize); const encoder_output = try encoder.encode(chip, tokens.slice(), diags, options.encode); - var programs = std.BoundedArray(Program, options.encode.max_programs).init(0) catch unreachable; + var programs = BoundedArray(Program, options.encode.max_programs).init(0) catch unreachable; for (encoder_output.programs.slice()) |bounded| try programs.append(bounded.to_exported_program()); return Output{ .defines = blk: { - var tmp = std.BoundedArray(Define, options.encode.max_defines).init(0) catch unreachable; + var tmp = BoundedArray(Define, options.encode.max_defines).init(0) catch unreachable; for (encoder_output.global_defines.slice()) |define| tmp.append(.{ .name = define.name, diff --git a/port/raspberrypi/rp2xxx/src/hal/pio/assembler/Expression.zig b/port/raspberrypi/rp2xxx/src/hal/pio/assembler/Expression.zig index 789fb78a4..0378931fb 100644 --- a/port/raspberrypi/rp2xxx/src/hal/pio/assembler/Expression.zig +++ b/port/raspberrypi/rp2xxx/src/hal/pio/assembler/Expression.zig @@ -16,9 +16,11 @@ const Diagnostics = assembler.Diagnostics; const encoder = @import("encoder.zig"); const DefineWithIndex = encoder.DefineWithIndex; +const BoundedArray = @import("bounded-array").BoundedArray; + const Expression = @This(); -const BoundedOperations = std.BoundedArray(OperationWithIndex, 32); -const BoundedValues = std.BoundedArray(Value, 32); +const BoundedOperations = BoundedArray(OperationWithIndex, 32); +const BoundedValues = BoundedArray(Value, 32); const Value = struct { str: []const u8, @@ -268,7 +270,7 @@ pub fn evaluate( define_lists: []const []const DefineWithIndex, diags: *?Diagnostics, ) !i128 { - var values = std.BoundedArray(EvaluatedValue, 32).init(0) catch unreachable; + var values = BoundedArray(EvaluatedValue, 32).init(0) catch unreachable; // parse/extract values into numbers for (self.values.slice()) |entry| { const value: EvaluatedValue = if (std.fmt.parseInt(i128, entry.str, 0)) |num| .{ diff --git a/port/raspberrypi/rp2xxx/src/hal/pio/assembler/encoder.zig b/port/raspberrypi/rp2xxx/src/hal/pio/assembler/encoder.zig index 4e18084d9..c0c5a8fd3 100644 --- a/port/raspberrypi/rp2xxx/src/hal/pio/assembler/encoder.zig +++ b/port/raspberrypi/rp2xxx/src/hal/pio/assembler/encoder.zig @@ -11,6 +11,8 @@ const Value = tokenizer.Value; const Expression = @import("Expression.zig"); const Chip = @import("../../chip.zig").Chip; +const BoundedArray = @import("bounded-array").BoundedArray; + pub const Options = struct { max_defines: u32 = 16, max_programs: u32 = 16, @@ -56,10 +58,10 @@ pub fn Encoder(comptime chip: Chip, comptime options: Options) type { programs: BoundedPrograms, }; - const BoundedDefines = std.BoundedArray(DefineWithIndex, options.max_defines); - const BoundedPrograms = std.BoundedArray(BoundedProgram, options.max_programs); - const BoundedInstructions = std.BoundedArray(Instruction(chip), 32); - const BoundedLabels = std.BoundedArray(Label, 32); + const BoundedDefines = BoundedArray(DefineWithIndex, options.max_defines); + const BoundedPrograms = BoundedArray(BoundedProgram, options.max_programs); + const BoundedInstructions = BoundedArray(Instruction(chip), 32); + const BoundedLabels = BoundedArray(Label, 32); const Label = struct { name: []const u8, index: u5, @@ -84,7 +86,7 @@ pub fn Encoder(comptime chip: Chip, comptime options: Options) type { return assembler.Program{ .name = &name_const, .defines = blk: { - var tmp = std.BoundedArray(assembler.Define, options.max_defines).init(0) catch unreachable; + var tmp = BoundedArray(assembler.Define, options.max_defines).init(0) catch unreachable; for (bounded.defines.slice()) |define| { comptime var define_name: [define.name.len]u8 = undefined; std.mem.copyForwards(u8, &define_name, define.name); diff --git a/port/raspberrypi/rp2xxx/src/hal/pio/assembler/tokenizer.zig b/port/raspberrypi/rp2xxx/src/hal/pio/assembler/tokenizer.zig index be0533497..0e2a12e30 100644 --- a/port/raspberrypi/rp2xxx/src/hal/pio/assembler/tokenizer.zig +++ b/port/raspberrypi/rp2xxx/src/hal/pio/assembler/tokenizer.zig @@ -7,6 +7,8 @@ const Diagnostics = assembler.Diagnostics; const Expression = @import("Expression.zig"); const Chip = @import("../../chip.zig").Chip; +const BoundedArray = @import("bounded-array").BoundedArray; + pub const Options = struct { capacity: u32 = 256, }; @@ -16,8 +18,8 @@ pub fn tokenize( source: []const u8, diags: *?assembler.Diagnostics, comptime options: Options, -) !std.BoundedArray(Token(chip), options.capacity) { - var tokens = std.BoundedArray(Token(chip), options.capacity).init(0) catch unreachable; +) !BoundedArray(Token(chip), options.capacity) { + var tokens = BoundedArray(Token(chip), options.capacity).init(0) catch unreachable; var tokenizer = Tokenizer(chip).init(source); while (try tokenizer.next(diags)) |token| try tokens.append(token); @@ -34,12 +36,8 @@ pub const Value = union(enum) { pub fn format( value: Value, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, + writer: *std.Io.Writer, ) !void { - _ = fmt; - _ = options; switch (value) { .string => |str| try writer.print("\"{s}\"", .{str}), .expression => |expr| try writer.print("{s}", .{expr}), @@ -72,13 +70,8 @@ pub fn Tokenizer(chip: Chip) type { pub fn format( self: Self, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, + writer: *std.Io.Writer, ) !void { - _ = fmt; - _ = options; - try writer.print( \\parser: \\ index: {} @@ -91,7 +84,7 @@ pub fn Tokenizer(chip: Chip) type { while (line_it.next()) |line| { try writer.print("{s}\n", .{line}); if (!printed_cursor and line_it.index > self.index) { - try writer.writeByteNTimes(' ', line.len - (line_it.index - self.index)); + try writer.splatByteAll(' ', line.len - (line_it.index - self.index)); try writer.writeAll("\x1b[30;42;1m^\x1b[0m\n"); printed_cursor = true; } @@ -617,11 +610,11 @@ pub fn Tokenizer(chip: Chip) type { } /// get the lowercase of a string, returns an error if it's too big - fn lowercase_bounded(comptime max_size: usize, str: []const u8) TokenizeError!std.BoundedArray(u8, max_size) { + fn lowercase_bounded(comptime max_size: usize, str: []const u8) TokenizeError!BoundedArray(u8, max_size) { if (str.len > max_size) return error.TooBig; - var ret = std.BoundedArray(u8, max_size).init(0) catch unreachable; + var ret = BoundedArray(u8, max_size).init(0) catch unreachable; for (str) |c| try ret.append(std.ascii.toLower(c)); @@ -1143,7 +1136,7 @@ pub fn Token(comptime chip: Chip) type { instruction: Instruction, }, - pub const Tag = std.meta.Tag(std.meta.FieldType(Token(chip), .data)); + pub const Tag = std.meta.Tag(@FieldType(Token(chip), "data")); pub const Label = struct { name: []const u8, @@ -1683,7 +1676,7 @@ fn expect_instr_irq(comptime chip: Chip, expected: ExpectedIrqInstr(chip), actua } } -fn bounded_tokenize(comptime chip: Chip, source: []const u8) !std.BoundedArray(Token(chip), 256) { +fn bounded_tokenize(comptime chip: Chip, source: []const u8) !BoundedArray(Token(chip), 256) { var diags: ?assembler.Diagnostics = null; return tokenize(chip, source, &diags, .{}) catch |err| if (diags) |d| blk: { std.log.err("error with chip {s} at index {}: {s}", .{ @tagName(chip), d.index, d.message.slice() }); @@ -2281,7 +2274,7 @@ test "tokenize.instr.comment with no whitespace" { test "format tokenizer" { const test_tokenizer = Tokenizer(.RP2040).init("out 1"); - const string = try std.fmt.allocPrint(std.testing.allocator, "{}", .{test_tokenizer}); + const string = try std.fmt.allocPrint(std.testing.allocator, "{f}", .{test_tokenizer}); defer std.testing.allocator.free(string); try expectEqualStrings( \\parser: diff --git a/port/raspberrypi/rp2xxx/src/hal/rom.zig b/port/raspberrypi/rp2xxx/src/hal/rom.zig index 021cf445b..3c25ca48f 100644 --- a/port/raspberrypi/rp2xxx/src/hal/rom.zig +++ b/port/raspberrypi/rp2xxx/src/hal/rom.zig @@ -59,7 +59,7 @@ pub const chip_specific = switch (chip) { pub fn popcount32(x: u32) u32 { switch (chip) { .RP2040 => { - const f: *const signatures.popcount32 = @alignCast(@ptrCast(lookup_and_cache_function(.popcount32))); + const f: *const signatures.popcount32 = @ptrCast(@alignCast(lookup_and_cache_function(.popcount32))); return f(x); }, // RP2350, supports fast assembly version @@ -71,7 +71,7 @@ pub fn popcount32(x: u32) u32 { pub fn reverse32(x: u32) u32 { switch (chip) { .RP2040 => { - const f: *const signatures.reverse32 = @alignCast(@ptrCast(lookup_and_cache_function(.reverse32))); + const f: *const signatures.reverse32 = @ptrCast(@alignCast(lookup_and_cache_function(.reverse32))); return f(x); }, // RP2350, supports fast assembly version @@ -83,7 +83,7 @@ pub fn reverse32(x: u32) u32 { pub fn clz32(x: u32) u32 { switch (chip) { .RP2040 => { - const f: *const signatures.clz32 = @alignCast(@ptrCast(lookup_and_cache_function(.clz32))); + const f: *const signatures.clz32 = @ptrCast(@alignCast(lookup_and_cache_function(.clz32))); return f(x); }, // RP2350, supports fast assembly version @@ -95,7 +95,7 @@ pub fn clz32(x: u32) u32 { pub fn ctz32(x: u32) u32 { switch (chip) { .RP2040 => { - const f: *const signatures.ctz32 = @alignCast(@ptrCast(lookup_and_cache_function(.ctz32))); + const f: *const signatures.ctz32 = @ptrCast(@alignCast(lookup_and_cache_function(.ctz32))); return f(x); }, // RP2350, supports fast assembly version @@ -111,7 +111,7 @@ pub fn ctz32(x: u32) u32 { pub fn memset(dest: []u8, c: u8) []u8 { switch (chip) { .RP2040 => { - const f: *const signatures.memset = @alignCast(@ptrCast(lookup_and_cache_function(.memset))); + const f: *const signatures.memset = @ptrCast(@alignCast(lookup_and_cache_function(.memset))); return f(dest.ptr, c, dest.len)[0..dest.len]; }, .RP2350 => { @@ -126,7 +126,7 @@ pub fn memcpy(dest: []u8, src: []const u8) []u8 { std.debug.assert(dest.len == src.len); switch (chip) { .RP2040 => { - const f: *const signatures.memcpy = @alignCast(@ptrCast(lookup_and_cache_function(.memcpy))); + const f: *const signatures.memcpy = @ptrCast(@alignCast(lookup_and_cache_function(.memcpy))); return f(dest.ptr, src.ptr, dest.len)[0..dest.len]; }, .RP2350 => { @@ -146,7 +146,7 @@ pub fn memcpy(dest: []u8, src: []const u8) []u8 { /// Restore all QSPI pad controls to their default state, and connect the SSI to /// the QSPI pads pub inline fn connect_internal_flash() void { - const f: *const signatures.connect_internal_flash = @alignCast(@ptrCast(lookup_function(.connect_internal_flash))); + const f: *const signatures.connect_internal_flash = @ptrCast(@alignCast(lookup_function(.connect_internal_flash))); f(); } @@ -157,7 +157,7 @@ pub inline fn connect_internal_flash() void { /// freshly-programmed code and data is visible to the debug host, without /// having to know exactly what kind of flash device is connected. pub inline fn flash_enter_cmd_xip() void { - const f: *const signatures.flash_enter_cmd_xip = @alignCast(@ptrCast(lookup_function(.flash_enter_cmd_xip))); + const f: *const signatures.flash_enter_cmd_xip = @ptrCast(@alignCast(lookup_function(.flash_enter_cmd_xip))); f(); } @@ -167,7 +167,7 @@ pub inline fn flash_enter_cmd_xip() void { /// returning the SSI to XIP mode (e.g. by a call to _flash_flush_cache). This /// function configures the SSI with a fixed SCK clock divisor of /6. pub inline fn flash_exit_xip() void { - const f: *const signatures.flash_exit_xip = @alignCast(@ptrCast(lookup_function(.flash_exit_xip))); + const f: *const signatures.flash_exit_xip = @ptrCast(@alignCast(lookup_function(.flash_exit_xip))); f(); } @@ -175,7 +175,7 @@ pub inline fn flash_exit_xip() void { /// There are few cases where you should call this method (resetting core 1 is much better). /// This method does not return and should only ever be called on core 1. pub inline fn flash_flush_cache() void { - const f: *const signatures.flash_flush_cache = @alignCast(@ptrCast(lookup_function(.flash_flush_cache))); + const f: *const signatures.flash_flush_cache = @ptrCast(@alignCast(lookup_function(.flash_flush_cache))); f(); } @@ -185,7 +185,7 @@ pub inline fn flash_flush_cache() void { /// erase where possible, for much higher erase speed. addr must be aligned to a /// 4096-byte sector, and count must be a multiple of 4096 bytes. pub inline fn flash_range_erase(addr: u32, count: usize, block_size: u32, block_cmd: u8) void { - const f: *const signatures.flash_range_erase = @alignCast(@ptrCast(lookup_function(.flash_range_erase))); + const f: *const signatures.flash_range_erase = @ptrCast(@alignCast(lookup_function(.flash_range_erase))); f(addr, count, block_size, block_cmd); } @@ -193,7 +193,7 @@ pub inline fn flash_range_erase(addr: u32, count: usize, block_size: u32, block_ /// start of flash) and count bytes in size. addr must be aligned to a 256-byte /// boundary, and the length of data must be a multiple of 256. pub inline fn flash_range_program(addr: u32, data: []const u8) void { - const f: *const signatures.flash_range_program = @alignCast(@ptrCast(lookup_function(.flash_range_program))); + const f: *const signatures.flash_range_program = @ptrCast(@alignCast(lookup_function(.flash_range_program))); f(addr, data.ptr, data.len); } @@ -201,13 +201,13 @@ pub inline fn flash_range_program(addr: u32, data: []const u8) void { pub fn reset_to_usb_boot() void { switch (chip) { .RP2040 => { - const f: *const signatures.reset_to_usb_boot = @alignCast(@ptrCast(lookup_function(.reset_to_usb_boot))); + const f: *const signatures.reset_to_usb_boot = @ptrCast(@alignCast(lookup_function(.reset_to_usb_boot))); f(0, 0); }, .RP2350 => { // 0x0002 - reset to bootsel // 0x0100 - block until reset - const f: *const signatures.reboot = @alignCast(@ptrCast(lookup_function(.reboot))); + const f: *const signatures.reboot = @ptrCast(@alignCast(lookup_function(.reboot))); _ = f(0x0002 | 0x0100, 10, 0, 0); unreachable; }, diff --git a/port/raspberrypi/rp2xxx/src/hal/rom/rp2040.zig b/port/raspberrypi/rp2xxx/src/hal/rom/rp2040.zig index 50ec05356..c66fd86da 100644 --- a/port/raspberrypi/rp2xxx/src/hal/rom/rp2040.zig +++ b/port/raspberrypi/rp2xxx/src/hal/rom/rp2040.zig @@ -20,7 +20,7 @@ pub inline fn lookup_float_function(f: SoftFloatFunction) *const anyopaque { @panic("function not available in this bootrom version"); } - const table: [*]const usize = @alignCast(@ptrCast(rom.lookup_and_cache_data(.soft_float_table))); + const table: [*]const usize = @ptrCast(@alignCast(rom.lookup_and_cache_data(.soft_float_table))); return @ptrFromInt(table[@intFromEnum(f) / 4]); } @@ -28,7 +28,7 @@ pub inline fn lookup_double_function(f: SoftDoubleFunction) *const anyopaque { if (rom.get_version_number() < f.min_version()) @panic("function not available in this bootrom version"); - const table: [*]const usize = @alignCast(@ptrCast(rom.lookup_and_cache_data(.soft_double_table))); + const table: [*]const usize = @ptrCast(@alignCast(rom.lookup_and_cache_data(.soft_double_table))); return @ptrFromInt(table[@intFromEnum(f) / 4]); } diff --git a/port/raspberrypi/rp2xxx/src/hal/rom/rp2350.zig b/port/raspberrypi/rp2xxx/src/hal/rom/rp2350.zig index 850952f2f..e3583df1e 100644 --- a/port/raspberrypi/rp2xxx/src/hal/rom/rp2350.zig +++ b/port/raspberrypi/rp2xxx/src/hal/rom/rp2350.zig @@ -8,7 +8,7 @@ pub inline fn lookup_data(data: Data) ?*const anyopaque { ROM_DATA_LOOKUP_A1.* else ROM_DATA_LOOKUP_A2.*); - return @alignCast(@ptrCast(rom_data_lookup_fn(@intFromEnum(data), 0x40))); // 0x40 = data mask + return @ptrCast(@alignCast(rom_data_lookup_fn(@intFromEnum(data), 0x40))); // 0x40 = data mask } /// Asserts that a function with the given code exists in the bootrom. @@ -22,7 +22,7 @@ pub inline fn lookup_function(function: Function) ?*const anyopaque { .arm => if (is_secure_mode()) masks.arm_s else masks.arm_ns, .riscv => masks.riscv, }; - return @alignCast(@ptrCast(rom_table_lookup_fn(@intFromEnum(function), mask))); + return @ptrCast(@alignCast(rom_table_lookup_fn(@intFromEnum(function), mask))); } fn is_secure_mode() bool { diff --git a/port/raspberrypi/rp2xxx/src/hal/spi.zig b/port/raspberrypi/rp2xxx/src/hal/spi.zig index 86b8d0ec3..7c0c7ea5f 100644 --- a/port/raspberrypi/rp2xxx/src/hal/spi.zig +++ b/port/raspberrypi/rp2xxx/src/hal/spi.zig @@ -204,7 +204,7 @@ pub const SPI = enum(u1) { /// Disable SPI, pre-fill the TX FIFO as much as possible, and then re-enable to start transmission. /// Leads to performance gains in thoroughput. Returns how many bytes were consumed from src. - fn prime_tx_fifo(spi: SPI, comptime PacketType: type, src_iter: *microzig.utilities.Slice_Vector([]const PacketType).Iterator) usize { + fn prime_tx_fifo(spi: SPI, comptime PacketType: type, src_iter: *microzig.utilities.SliceVector([]const PacketType).Iterator) usize { const spi_regs = spi.get_regs(); spi_regs.SSPCR1.modify(.{ .SSE = 0, @@ -262,8 +262,8 @@ pub const SPI = enum(u1) { pub fn transceive_vecs_blocking(spi: SPI, comptime PacketType: type, src_vecs: []const []const PacketType, dst_vecs: []const []PacketType) void { comptime validate_bitwidth(PacketType); - const src_data = microzig.utilities.Slice_Vector([]const PacketType).init(src_vecs); - const dst_data = microzig.utilities.Slice_Vector([]PacketType).init(dst_vecs); + const src_data = microzig.utilities.SliceVector([]const PacketType).init(src_vecs); + const dst_data = microzig.utilities.SliceVector([]PacketType).init(dst_vecs); var rx_remaining = src_data.size(); var tx_remaining = dst_data.size(); @@ -317,7 +317,7 @@ pub const SPI = enum(u1) { pub fn writev_blocking(spi: SPI, comptime PacketType: type, src_vec: []const []const PacketType) void { comptime validate_bitwidth(PacketType); - var src_iter = microzig.utilities.Slice_Vector([]const u8).init(src_vec).iterator(); + var src_iter = microzig.utilities.SliceVector([]const u8).init(src_vec).iterator(); _ = spi.prime_tx_fifo(PacketType, &src_iter); @@ -376,7 +376,7 @@ pub const SPI = enum(u1) { pub fn readv_blocking(spi: SPI, comptime PacketType: type, repeated_tx_data: PacketType, dst_vec: []const []PacketType) void { comptime validate_bitwidth(PacketType); - const dst_data = microzig.utilities.Slice_Vector([]PacketType).init(dst_vec); + const dst_data = microzig.utilities.SliceVector([]PacketType).init(dst_vec); const spi_regs = spi.get_regs(); var rx_remaining = dst_data.size(); diff --git a/port/raspberrypi/rp2xxx/src/hal/uart.zig b/port/raspberrypi/rp2xxx/src/hal/uart.zig index 219196922..5e4327565 100644 --- a/port/raspberrypi/rp2xxx/src/hal/uart.zig +++ b/port/raspberrypi/rp2xxx/src/hal/uart.zig @@ -294,7 +294,7 @@ pub const UART = enum(u1) { const uart_regs = uart.get_regs(); const deadline = mdf.time.Deadline.init_relative(time.get_time_since_boot(), timeout); - var iter = microzig.utilities.Slice_Vector([]const u8).init(payloads).iterator(); + var iter = microzig.utilities.SliceVector([]const u8).init(payloads).iterator(); while (iter.next_chunk(null)) |payload| { var offset: usize = uart.prime_tx_fifo(payload); while (offset < payload.len) { @@ -387,7 +387,7 @@ pub const UART = enum(u1) { pub fn readv_blocking(uart: UART, buffers: []const []u8, timeout: ?mdf.time.Duration) ReceiveBlockingError!void { const deadline = mdf.time.Deadline.init_relative(time.get_time_since_boot(), timeout); - var iter = microzig.utilities.Slice_Vector([]u8).init(buffers).iterator(); + var iter = microzig.utilities.SliceVector([]u8).init(buffers).iterator(); while (iter.next_chunk(null)) |buffer| { for (buffer) |*byte| { while (!uart.is_readable()) { diff --git a/port/raspberrypi/rp2xxx/tools/rp2040-flash.zig b/port/raspberrypi/rp2xxx/tools/rp2040-flash.zig index 6e22e077c..7c0cba8db 100644 --- a/port/raspberrypi/rp2xxx/tools/rp2040-flash.zig +++ b/port/raspberrypi/rp2xxx/tools/rp2040-flash.zig @@ -230,7 +230,7 @@ fn auto_detect_pico(allocator: std.mem.Allocator) !?[]const u8 { path: []const u8, }; - var picos = std.ArrayList(Device).init(allocator); + var picos = std.array_list.Managed(Device).init(allocator); defer picos.deinit(); var base_dir = try std.fs.openIterableDirAbsolute("/sys/block/", .{}); diff --git a/port/stmicro/stm32/build.zig b/port/stmicro/stm32/build.zig index 45b1d05cf..32b8625c2 100644 --- a/port/stmicro/stm32/build.zig +++ b/port/stmicro/stm32/build.zig @@ -61,9 +61,11 @@ pub fn build(b: *std.Build) !void { const generate_exe = b.addExecutable(.{ .name = "generate", - .root_source_file = b.path("src/generate.zig"), - .target = b.graph.host, - .optimize = generate_optimize, + .root_module = b.createModule(.{ + .root_source_file = b.path("src/generate.zig"), + .target = b.graph.host, + .optimize = generate_optimize, + }), }); generate_exe.root_module.addImport("regz", regz); diff --git a/port/stmicro/stm32/src/generate.zig b/port/stmicro/stm32/src/generate.zig index 64824f3ee..55c150f69 100644 --- a/port/stmicro/stm32/src/generate.zig +++ b/port/stmicro/stm32/src/generate.zig @@ -30,7 +30,7 @@ pub fn main() !void { var data_dir = try package_dir.openDir("data", .{}); defer data_dir.close(); - var chip_files = std.ArrayList(std.json.Parsed(ChipFile)).init(allocator); + var chip_files = std.array_list.Managed(std.json.Parsed(ChipFile)).init(allocator); defer { for (chip_files.items) |chip_file| chip_file.deinit(); @@ -73,7 +73,9 @@ pub fn main() !void { const chips_file = try std.fs.cwd().createFile("src/Chips.zig", .{}); defer chips_file.close(); - try generate_chips_file(allocator, chips_file.writer(), chip_files.items); + var buf: [4096]u8 = undefined; + var writer = chips_file.writer(&buf); + try generate_chips_file(allocator, &writer.interface, chip_files.items); } // Chip @@ -83,7 +85,7 @@ pub fn main() !void { fn generate_chips_file( allocator: std.mem.Allocator, - writer: anytype, + writer: *std.Io.Writer, chip_files: []const std.json.Parsed(ChipFile), ) !void { try writer.writeAll( @@ -97,7 +99,7 @@ fn generate_chips_file( for (chip_files) |json| { const chip_file = json.value; - try writer.print("{}: *microzig.Target,\n", .{std.zig.fmtId(chip_file.name)}); + try writer.print("{f}: *microzig.Target,\n", .{std.zig.fmtId(chip_file.name)}); } try writer.writeAll( @@ -129,8 +131,8 @@ fn generate_chips_file( } try writer.print( - \\ ret.{} = b.allocator.create(microzig.Target) catch @panic("out of memory"); - \\ ret.{}.* = .{{ + \\ ret.{f} = b.allocator.create(microzig.Target) catch @panic("out of memory"); + \\ ret.{f}.* = .{{ \\ .dep = dep, \\ .preferred_binary_format = .elf, \\ .zig_target = .{{ @@ -174,7 +176,7 @@ fn generate_chips_file( ); { - var chip_memory = try std.ArrayList(ChipFile.Memory).initCapacity(allocator, chip_file.memory.len); + var chip_memory = try std.array_list.Managed(ChipFile.Memory).initCapacity(allocator, chip_file.memory.len); defer chip_memory.deinit(); // Some flash bank regions are not merged so we better do that. @@ -270,4 +272,6 @@ fn generate_chips_file( \\} \\ ); + + try writer.flush(); } diff --git a/port/stmicro/stm32/src/hals/STM32F103/adc.zig b/port/stmicro/stm32/src/hals/STM32F103/adc.zig index b44c82709..449a5213e 100644 --- a/port/stmicro/stm32/src/hals/STM32F103/adc.zig +++ b/port/stmicro/stm32/src/hals/STM32F103/adc.zig @@ -55,7 +55,7 @@ pub const ADC = struct { //wait for calibration to finish while (regs.CR2.read().CAL == 1) { - asm volatile ("" ::: "memory"); + asm volatile ("" ::: .{ .memory = true }); } regs.SR.raw = 0; //clear all status flags @@ -107,7 +107,7 @@ pub const ADC = struct { //wait for conversion to finish while (regs.SR.read().EOC == 0) { - asm volatile ("" ::: "memory"); + asm volatile ("" ::: .{ .memory = true }); } const result: u16 = regs.DR.read().DATA; //read the data registe, this will also clear the EOC flag regs.SR.modify(.{ .STRT = 0 }); //clear the START flag @@ -425,7 +425,7 @@ pub const AdvancedADC = struct { //wait for calibration to finish while (regs.CR2.read().CAL == 1) { - asm volatile ("" ::: "memory"); + asm volatile ("" ::: .{ .memory = true }); } const data = regs.DR.read().DATA; return data; @@ -439,7 +439,7 @@ pub const AdvancedADC = struct { regs.CR2.modify(.{ .RTSCAL = 1 }); //reset calibration //wait for reset to finish while (regs.CR2.read().RTSCAL == 1) { - asm volatile ("" ::: "memory"); + asm volatile ("" ::: .{ .memory = true }); } return regs.DR.read().DATA; //read the calibration data diff --git a/port/stmicro/stm32/src/hals/STM32F103/clocks/clock_stm32f103.zig b/port/stmicro/stm32/src/hals/STM32F103/clocks/clock_stm32f103.zig index c839587cf..1bcd57465 100644 --- a/port/stmicro/stm32/src/hals/STM32F103/clocks/clock_stm32f103.zig +++ b/port/stmicro/stm32/src/hals/STM32F103/clocks/clock_stm32f103.zig @@ -756,13 +756,13 @@ pub const ClockTree = struct { const HSE_Timeoutval = ClockNodeTypes{ .source = .{ .value = if (config.HSE_Timeout) |val| val.get() else 100, - .limit = .{ .max = 4294967295, .min = 1 }, + .limit = .{ .max = 4294967295.0, .min = 1 }, }, }; const LSE_Timeoutval = ClockNodeTypes{ .source = .{ .value = if (config.LSE_Timeout) |val| val.get() else 5000, - .limit = .{ .max = 4294967295, .min = 1 }, + .limit = .{ .max = 4294967295.0, .min = 1 }, }, }; const HSICalibrationValueval = ClockNodeTypes{ diff --git a/port/stmicro/stm32/src/hals/STM32F103/drivers.zig b/port/stmicro/stm32/src/hals/STM32F103/drivers.zig index 7b1756760..edabecfb9 100644 --- a/port/stmicro/stm32/src/hals/STM32F103/drivers.zig +++ b/port/stmicro/stm32/src/hals/STM32F103/drivers.zig @@ -102,7 +102,7 @@ pub const I2C_Datagram_Device = struct { pub fn readv(dev: I2C_Datagram_Device, datagrams: []const []u8, timeout: ?Timeout) !usize { try dev.bus.readv_blocking(dev.address, datagrams, timeout); - return microzig.utilities.Slice_Vector([]u8).init(datagrams).size(); + return microzig.utilities.SliceVector([]u8).init(datagrams).size(); } const vtable = Datagram_Device.VTable{ @@ -245,7 +245,7 @@ pub const I2C_Device = struct { }, else => |e| return e, }; - return microzig.utilities.Slice_Vector([]u8).init(chunks).size(); + return microzig.utilities.SliceVector([]u8).init(chunks).size(); } pub fn write_then_read(dev: I2C_Device, address: I2CAddress, src: []const u8, dst: []u8) I2CError!void { diff --git a/port/stmicro/stm32/src/hals/STM32F103/rcc.zig b/port/stmicro/stm32/src/hals/STM32F103/rcc.zig index d05b3ba59..c896b3ecf 100644 --- a/port/stmicro/stm32/src/hals/STM32F103/rcc.zig +++ b/port/stmicro/stm32/src/hals/STM32F103/rcc.zig @@ -192,13 +192,13 @@ fn set_flash(clock: u32) void { fn secure_enable() void { rcc.CR.modify(.{ .HSION = 1 }); while (rcc.CR.read().HSIRDY != 1) { - asm volatile ("" ::: "memory"); + asm volatile ("" ::: .{ .memory = true }); } rcc.BDCR.raw = 0; rcc.CFGR.raw = 0; while (rcc.CFGR.read().SWS != .HSI) { - asm volatile ("" ::: "memory"); + asm volatile ("" ::: .{ .memory = true }); } rcc.CR.modify(.{ @@ -216,14 +216,14 @@ fn config_HSI(value: usize) void { //wait for the HSI to stabilize for (0..16) |_| { - asm volatile ("" ::: "memory"); + asm volatile ("" ::: .{ .memory = true }); } } fn config_LSI() void { rcc.CSR.modify(.{ .LSION = 1 }); while (rcc.CSR.read().LSIRDY == 0) { - asm volatile ("" ::: "memory"); + asm volatile ("" ::: .{ .memory = true }); } } @@ -235,7 +235,7 @@ fn config_HSE(comptime config: ClockTree.Config) ClockInitError!void { while (rcc.CR.read().HSERDY == 0) { if (ticks == max_wait - 1) return error.HSETimeout; ticks += 1; - asm volatile ("" ::: "memory"); + asm volatile ("" ::: .{ .memory = true }); } } @@ -246,7 +246,7 @@ fn config_LSE(comptime config: ClockTree.Config) ClockInitError!void { while (rcc.BDCR.read().LSERDY == 0) { if (ticks == max_wait - 1) return error.LSETimeout; ticks += 1; - asm volatile ("" ::: "memory"); + asm volatile ("" ::: .{ .memory = true }); } } @@ -323,7 +323,7 @@ fn config_system_clock(comptime config: ClockTree.Config) ClockInitError!void { while (true) { const sws = rcc.CFGR.read().SWS; if (sws == e_val) break; - asm volatile ("" ::: "memory"); + asm volatile ("" ::: .{ .memory = true }); } } } @@ -331,7 +331,7 @@ fn config_system_clock(comptime config: ClockTree.Config) ClockInitError!void { fn init_pll() void { rcc.CR.modify(.{ .PLLON = 1 }); while (rcc.CR.read().PLLRDY == 0) { - asm volatile ("" ::: "memory"); + asm volatile ("" ::: .{ .memory = true }); } } diff --git a/port/stmicro/stm32/src/hals/STM32F103/rtc.zig b/port/stmicro/stm32/src/hals/STM32F103/rtc.zig index 82adcd94b..62398b35b 100644 --- a/port/stmicro/stm32/src/hals/STM32F103/rtc.zig +++ b/port/stmicro/stm32/src/hals/STM32F103/rtc.zig @@ -28,7 +28,7 @@ pub const Events = packed struct(u3) { }; pub fn enter_config_mode() void { - while (rtc.CRL.read().RTOFF == .Ongoing) asm volatile ("" ::: "memory"); + while (rtc.CRL.read().RTOFF == .Ongoing) asm volatile ("" ::: .{ .memory = true }); //enter in config mode rtc.CRL.modify_one("CNF", 1); } @@ -37,7 +37,7 @@ pub fn exit_config_mode() void { //exit config mode rtc.CRL.modify_one("CNF", 0); //wait for the config to finish - while (rtc.CRL.read().RTOFF == .Ongoing) asm volatile ("" ::: "memory"); + while (rtc.CRL.read().RTOFF == .Ongoing) asm volatile ("" ::: .{ .memory = true }); } pub fn apply(config: Config) void { @@ -85,7 +85,7 @@ pub fn apply_interrupts(config: InterruptConfig) void { ///After a reset, reading RTC registers may return unsynchronized or corrupted data. pub fn busy_sync() void { const cr = rtc.CRL.read(); - while (cr.RSF == 0) asm volatile ("" ::: "memory"); + while (cr.RSF == 0) asm volatile ("" ::: .{ .memory = true }); rtc.CRL.modify_one("RSF", 0); } diff --git a/port/stmicro/stm32/src/hals/STM32F103/timer.zig b/port/stmicro/stm32/src/hals/STM32F103/timer.zig index d614a107f..8f8ae7fc6 100644 --- a/port/stmicro/stm32/src/hals/STM32F103/timer.zig +++ b/port/stmicro/stm32/src/hals/STM32F103/timer.zig @@ -535,7 +535,7 @@ pub const Counter = struct { } fn load_and_start(ctx: *const anyopaque, psc: u32, arr: u16) void { - const self: *const GPTimer = @alignCast(@ptrCast(ctx)); + const self: *const GPTimer = @ptrCast(@alignCast(ctx)); const regs = self.regs; regs.CR1.modify(.{ .CEN = 0 }); regs.SR.raw = 0; @@ -546,13 +546,13 @@ pub const Counter = struct { } fn check_event(ctx: *const anyopaque) bool { - const self: *const GPTimer = @alignCast(@ptrCast(ctx)); + const self: *const GPTimer = @ptrCast(@alignCast(ctx)); const regs = self.regs; return regs.SR.read().UIF == 1; } fn busy_wait_fn(ctx: *const anyopaque, time: u64) void { - const self: *const GPTimer = @alignCast(@ptrCast(ctx)); + const self: *const GPTimer = @ptrCast(@alignCast(ctx)); const regs = self.regs; const full_ticks: usize = @intCast(time / std.math.maxInt(u16)); const partial_ticks: u16 = @intCast(time % std.math.maxInt(u16)); diff --git a/port/stmicro/stm32/src/hals/STM32F103/usb_internals/usb_ll.zig b/port/stmicro/stm32/src/hals/STM32F103/usb_internals/usb_ll.zig index 2ad5288e8..7605b22f6 100644 --- a/port/stmicro/stm32/src/hals/STM32F103/usb_internals/usb_ll.zig +++ b/port/stmicro/stm32/src/hals/STM32F103/usb_internals/usb_ll.zig @@ -434,7 +434,7 @@ pub fn default_reset_handler() void { }); } -pub fn usb_handler() callconv(.C) void { +pub fn usb_handler() callconv(.c) void { const event = USB.ISTR.read(); if (event.RESET == 1) { USB.ISTR.modify(.{ .RESET = 0 }); diff --git a/port/stmicro/stm32/src/hals/STM32F303/pins.zig b/port/stmicro/stm32/src/hals/STM32F303/pins.zig index b7211f14c..eae1f0b3b 100644 --- a/port/stmicro/stm32/src/hals/STM32F303/pins.zig +++ b/port/stmicro/stm32/src/hals/STM32F303/pins.zig @@ -103,6 +103,7 @@ pub fn Pins(comptime config: GlobalConfiguration) type { /// PF15: ?PinConfiguration = null, /// } fn PortConfiguration() type { + @setEvalBranchQuota(200000); var fields: []const StructField = &.{}; for ("ABCDEF") |gpio_port_id| { for (0..16) |gpio_pin_number_int| { diff --git a/sim/aviron/README.md b/sim/aviron/README.md index 733c28dea..1ecf080f6 100644 --- a/sim/aviron/README.md +++ b/sim/aviron/README.md @@ -51,7 +51,7 @@ File extensions marked *compile* will be compiled or assembled with the Zig comp //! } const testsuite = @import("testsuite"); -export fn _start() callconv(.C) noreturn { +export fn _start() callconv(.c) noreturn { testsuite.write(.stdout, "hello"); testsuite.write(.stderr, "world"); testsuite.exit(0); diff --git a/sim/aviron/build.zig b/sim/aviron/build.zig index 1bc99f097..2f275dd72 100644 --- a/sim/aviron/build.zig +++ b/sim/aviron/build.zig @@ -66,9 +66,12 @@ pub fn build(b: *Build) !void { // Main emulator executable const aviron_exe = b.addExecutable(.{ .name = "aviron", - .root_source_file = b.path("src/main.zig"), - .target = target, - .optimize = optimize, + .root_module = b.createModule(.{ + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + }), + .use_llvm = true, }); aviron_exe.root_module.addImport("args", args_module); aviron_exe.root_module.addImport("ihex", ihex_module); @@ -88,10 +91,13 @@ pub fn build(b: *Build) !void { for (samples) |sample_name| { const sample = b.addExecutable(.{ .name = sample_name, - .root_source_file = b.path(b.fmt("samples/{s}.zig", .{sample_name})), - .target = avr_target, - .optimize = .ReleaseSmall, - .strip = false, + .root_module = b.createModule(.{ + .root_source_file = b.path(b.fmt("samples/{s}.zig", .{sample_name})), + .target = avr_target, + .optimize = .ReleaseSmall, + .strip = false, + }), + .use_llvm = true, }); sample.bundle_compiler_rt = false; sample.setLinkerScript(b.path("linker.ld")); @@ -120,17 +126,23 @@ fn add_test_suite( aviron_module: *Build.Module, ) !void { const unit_tests = b.addTest(.{ - .root_source_file = b.path("src/main.zig"), - .target = host_target, - .optimize = optimize, + .root_module = b.createModule(.{ + .root_source_file = b.path("src/main.zig"), + .target = host_target, + .optimize = optimize, + }), + .use_llvm = true, }); test_step.dependOn(&b.addRunArtifact(unit_tests).step); const testrunner_exe = b.addExecutable(.{ .name = "aviron-test-runner", - .root_source_file = b.path("src/testrunner.zig"), - .target = host_target, - .optimize = optimize, + .root_module = b.createModule(.{ + .root_source_file = b.path("src/testrunner.zig"), + .target = host_target, + .optimize = optimize, + }), + .use_llvm = true, }); testrunner_exe.root_module.addImport("args", args_module); testrunner_exe.root_module.addImport("aviron", aviron_module); @@ -222,11 +234,14 @@ fn add_test_suite( const test_payload = b.addExecutable(.{ .name = std.fs.path.stem(entry.basename), - .target = custom_target, - .optimize = config.optimize, - .strip = false, - .root_source_file = if (is_zig_test) root_file else null, - .link_libc = false, + .root_module = b.createModule(.{ + .root_source_file = if (is_zig_test) root_file else null, + .target = custom_target, + .optimize = config.optimize, + .strip = false, + .link_libc = false, + }), + .use_llvm = true, }); test_payload.want_lto = false; // AVR has no LTO support! test_payload.verbose_link = true; @@ -305,8 +320,11 @@ fn add_test_suite_update( .cwd_relative = path, } else |_| b.addExecutable(.{ .name = "no-avr-gcc", - .target = b.graph.host, - .root_source_file = b.path("tools/no-avr-gcc.zig"), + .root_module = b.createModule(.{ + .root_source_file = b.path("tools/no-avr-gcc.zig"), + .target = b.graph.host, + }), + .use_llvm = true, }).getEmittedBin(); { @@ -382,18 +400,18 @@ fn add_test_suite_update( } fn parse_test_suite_config(b: *Build, file: std.fs.File) !TestSuiteConfig { - var code = std.ArrayList(u8).init(b.allocator); + var code = std.array_list.Managed(u8).init(b.allocator); defer code.deinit(); - var line_buffer: [4096]u8 = undefined; + var read_buf: [4096]u8 = undefined; + var file_reader = file.reader(&read_buf); + const reader = &file_reader.interface; while (true) { - var fbs = std.io.fixedBufferStream(&line_buffer); - file.reader().streamUntilDelimiter(fbs.writer(), '\n', null) catch |err| switch (err) { + const line = reader.takeDelimiterExclusive('\n') catch |err| switch (err) { error.EndOfStream => break, else => |e| return e, }; - const line = fbs.getWritten(); if (std.mem.startsWith(u8, line, "//!")) { try code.appendSlice(line[3..]); @@ -416,11 +434,21 @@ fn parse_test_suite_config(b: *Build, file: std.fs.File) !TestSuiteConfig { } fn generate_isa_tables(b: *Build, isa_mod: *Build.Module) LazyPath { + const bounded_array_dep = b.dependency("bounded-array", .{}); const generate_tables_exe = b.addExecutable(.{ .name = "aviron-generate-tables", - .root_source_file = b.path("tools/generate-tables.zig"), - .target = b.graph.host, - .optimize = .Debug, + .root_module = b.createModule(.{ + .root_source_file = b.path("tools/generate-tables.zig"), + .target = b.graph.host, + .optimize = .Debug, + .imports = &.{ + .{ + .name = "bounded-array", + .module = bounded_array_dep.module("bounded-array"), + }, + }, + }), + .use_llvm = true, }); generate_tables_exe.root_module.addImport("isa", isa_mod); diff --git a/sim/aviron/build.zig.zon b/sim/aviron/build.zig.zon index e1eb9df48..c7075f7cc 100644 --- a/sim/aviron/build.zig.zon +++ b/sim/aviron/build.zig.zon @@ -4,12 +4,13 @@ .fingerprint = 0xfc536f957aeaeb54, .dependencies = .{ .args = .{ - .url = "git+https://github.com/MasterQ32/zig-args#9425b94c103a031777fdd272c555ce93a7dea581", - .hash = "args-0.0.0-CiLiqv_NAAC97fGpk9hS2K681jkiqPsWP6w3ucb_ctGH", + .url = "git+https://github.com/MasterQ32/zig-args#8ae26b44a884ff20dca98ee84c098e8f8e94902f", + .hash = "args-0.0.0-CiLiqojRAACGzDRO7A9dw7kWSchNk29caJZkXuMCb0Cn", }, + .@"bounded-array" = .{ .path = "../../modules/bounded-array" }, .ihex = .{ - .url = "git+https://github.com/ikskuh/zig-ihex#2c399fc3ab2669df8b0c8a514ca194757f41f826", - .hash = "ihex-0.1.0-1POu20MyAABXXjtXpHXpEZXrNYl34xVCTO8ye1BHOtF_", + .url = "git+https://github.com/mattnite/zig-ihex#9deb291104ecd7dcaab0db27bf05252764600947", + .hash = "ihex-0.1.0-1POu25EyAADaasaxKmaex5A6D_4cohzZkOW4qpn_mav0", }, }, .paths = .{ diff --git a/sim/aviron/samples/hello-world.zig b/sim/aviron/samples/hello-world.zig index d63a6691e..a527a5ed1 100644 --- a/sim/aviron/samples/hello-world.zig +++ b/sim/aviron/samples/hello-world.zig @@ -1,6 +1,6 @@ const testsuite = @import("testsuite"); -export fn _start() callconv(.C) noreturn { +export fn _start() callconv(.c) noreturn { testsuite.write(.stdout, "hello, world!\r\n"); testsuite.exit(0); } diff --git a/sim/aviron/samples/math.zig b/sim/aviron/samples/math.zig index 769d9ff79..2d791cd00 100644 --- a/sim/aviron/samples/math.zig +++ b/sim/aviron/samples/math.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub export fn _start() callconv(.C) noreturn { +pub export fn _start() callconv(.c) noreturn { var a: usize = 1 + 2; for (0..10) |p| { diff --git a/sim/aviron/src/lib/Cpu.zig b/sim/aviron/src/lib/Cpu.zig index 2e9b803a8..2b9d5af9f 100644 --- a/sim/aviron/src/lib/Cpu.zig +++ b/sim/aviron/src/lib/Cpu.zig @@ -111,7 +111,7 @@ pub fn run(cpu: *Cpu, mileage: ?u64) RunError!RunResult { // fmtInstruction(inst), // }); - std.debug.print("TRACE {s} {} [", .{ + std.debug.print("TRACE {s} {f} [", .{ if (skip) "SKIP" else " ", cpu.sreg, }); @@ -122,7 +122,7 @@ pub fn run(cpu: *Cpu, mileage: ?u64) RunError!RunResult { std.debug.print("{X:0>2}", .{reg}); } - std.debug.print("] 0x{X:0>6}: {}\n", .{ + std.debug.print("] 0x{X:0>6}: {f}\n", .{ pc, fmt_instruction(inst), }); @@ -1545,9 +1545,7 @@ pub const SREG = packed struct(u8) { sreg.* = @bitCast(val); } - pub fn format(sreg: SREG, fmt: []const u8, opt: std.fmt.FormatOptions, writer: anytype) !void { - _ = opt; - _ = fmt; + pub fn format(sreg: SREG, writer: *std.Io.Writer) !void { try writer.print("[{c}{c}{c}{c}{c}{c}{c}{c}]", .{ if (sreg.c) @as(u8, 'C') else '-', if (sreg.z) @as(u8, 'Z') else '-', @@ -1661,13 +1659,11 @@ fn decompose16(value: u16) [2]u8 { }; } -fn fmt_instruction(inst: isa.Instruction) std.fmt.Formatter(format_instruction) { +fn fmt_instruction(inst: isa.Instruction) std.fmt.Alt(isa.Instruction, format_instruction) { return .{ .data = inst }; } -fn format_instruction(inst: isa.Instruction, fmt: []const u8, opt: std.fmt.FormatOptions, writer: anytype) !void { - _ = opt; - _ = fmt; +fn format_instruction(inst: isa.Instruction, writer: *std.Io.Writer) !void { try writer.print(" {s: <8}", .{@tagName(inst)}); switch (inst) { @@ -1676,11 +1672,17 @@ fn format_instruction(inst: isa.Instruction, fmt: []const u8, opt: std.fmt.Forma if (T != void) { const info = @typeInfo(T).@"struct"; - inline for (info.fields, 0..) |fld, i| { + inline for (info.fields, 0..) |field, i| { if (i > 0) { try writer.writeAll(", "); } - try writer.print("{s}={}", .{ fld.name, @field(args, fld.name) }); + + const field_info = @typeInfo(field.type); + if (field_info == .int) { + try writer.print("{s}={}", .{ field.name, @field(args, field.name) }); + } else { + try writer.print("{s}={f}", .{ field.name, @field(args, field.name) }); + } } } }, diff --git a/sim/aviron/src/lib/decoder.zig b/sim/aviron/src/lib/decoder.zig index f46d64889..d4bfe3e69 100644 --- a/sim/aviron/src/lib/decoder.zig +++ b/sim/aviron/src/lib/decoder.zig @@ -17,9 +17,9 @@ pub fn decode(inst_val: u16) !Instruction { const opcode = lookup[inst_val]; switch (opcode) { inline else => |tag| { - @setEvalBranchQuota(10_000); + @setEvalBranchQuota(20_000); - const Result = std.meta.FieldType(Instruction, tag); + const Result = @FieldType(Instruction, tag.to_string()); if (Result == void) { return @unionInit(Instruction, @tagName(tag), {}); } diff --git a/sim/aviron/src/main.zig b/sim/aviron/src/main.zig index 4c20f6efb..32740a353 100644 --- a/sim/aviron/src/main.zig +++ b/sim/aviron/src/main.zig @@ -11,12 +11,11 @@ pub fn main() !u8 { defer cli.deinit(); if (cli.options.help or (cli.positionals.len == 0 and !cli.options.info)) { - var stderr = std.io.getStdErr(); - + var stderr_writer = std.fs.File.stderr().writer(&.{}); try args_parser.printHelp( Cli, cli.executable_name orelse "aviron", - stderr.writer(), + &stderr_writer.interface, ); return if (cli.options.help) @as(u8, 0) else 1; @@ -63,13 +62,14 @@ pub fn main() !u8 { io.sreg = &cpu.sreg; if (cli.options.info) { - var stdout = std.io.getStdOut().writer(); - try stdout.print("Information for {s}:\n", .{@tagName(cli.options.mcu)}); - try stdout.print(" Generation: {s: >11}\n", .{@tagName(cpu.instruction_set)}); - try stdout.print(" Code Model: {s: >11}\n", .{@tagName(cpu.code_model)}); - try stdout.print(" Flash: {d: >5} bytes\n", .{cpu.flash.size}); - try stdout.print(" RAM: {d: >5} bytes\n", .{cpu.sram.size}); - try stdout.print(" EEPROM: {d: >5} bytes\n", .{cpu.eeprom.size}); + var stdout = std.fs.File.stdout().writer(&.{}); + try stdout.interface.print("Information for {s}:\n", .{@tagName(cli.options.mcu)}); + try stdout.interface.print(" Generation: {s: >11}\n", .{@tagName(cpu.instruction_set)}); + try stdout.interface.print(" Code Model: {s: >11}\n", .{@tagName(cpu.code_model)}); + try stdout.interface.print(" Flash: {d: >5} bytes\n", .{cpu.flash.size}); + try stdout.interface.print(" RAM: {d: >5} bytes\n", .{cpu.sram.size}); + try stdout.interface.print(" EEPROM: {d: >5} bytes\n", .{cpu.eeprom.size}); + try stdout.interface.flush(); return 0; } @@ -78,12 +78,14 @@ pub fn main() !u8 { var file = try std.fs.cwd().openFile(file_path, .{}); defer file.close(); + var file_buf: [4096]u8 = undefined; + var reader = file.reader(&file_buf); + switch (cli.options.format) { .elf => { - var source = std.io.StreamSource{ .file = file }; - var header = try std.elf.Header.read(&source); + var header = try std.elf.Header.read(&reader.interface); - var pheaders = header.program_header_iterator(&source); + var pheaders = header.iterateProgramHeaders(&reader); while (try pheaders.next()) |phdr| { if (phdr.p_type != std.elf.PT_LOAD) continue; // Header isn't lodead @@ -95,8 +97,8 @@ pub fn main() !u8 { const addr_masked: u24 = @intCast(phdr.p_paddr & 0x007F_FFFF); - try source.seekTo(phdr.p_offset); - try source.reader().readNoEof(dest_mem[addr_masked..][0..phdr.p_filesz]); + try reader.seekTo(phdr.p_offset); + try reader.interface.readSliceAll(dest_mem[addr_masked..][0..phdr.p_filesz]); @memset(dest_mem[addr_masked + phdr.p_filesz ..][0 .. phdr.p_memsz - phdr.p_filesz], 0); } }, @@ -110,7 +112,7 @@ pub fn main() !u8 { @memcpy(flash.data[offset .. offset + data.len], data); } }; - _ = try ihex.parseData(file.reader(), .{ .pedantic = true }, &flash_storage, anyerror, ihex_processor.process); + _ = try ihex.parseData(&reader.interface, .{ .pedantic = true }, &flash_storage, anyerror, ihex_processor.process); }, } } @@ -221,7 +223,12 @@ const IO = struct { const reg: Register = @enumFromInt(addr); return switch (reg) { .exit => 0, - .stdio => std.io.getStdIn().reader().readByte() catch 0xFF, // 0xFF = EOF + .stdio => blk: { + var stdin = std.fs.File.stdin().reader(&.{}); + var buf: [1]u8 = undefined; + stdin.interface.readSliceAll(&buf) catch break :blk 0xFF; // 0xFF = EOF + break :blk buf[0]; + }, .stderr => 0, .scratch_0 => io.scratch_regs[0x0], @@ -256,8 +263,14 @@ const IO = struct { const reg: Register = @enumFromInt(addr); switch (reg) { .exit => std.process.exit(value & mask), - .stdio => std.io.getStdOut().writer().writeByte(value & mask) catch @panic("i/o failure"), - .stderr => std.io.getStdErr().writer().writeByte(value & mask) catch @panic("i/o failure"), + .stdio => { + var stdout = std.fs.File.stdout().writer(&.{}); + stdout.interface.writeByte(value & mask) catch @panic("i/o failure"); + }, + .stderr => { + var stderr = std.fs.File.stderr().writer(&.{}); + stderr.interface.writeByte(value & mask) catch @panic("i/o failure"); + }, .scratch_0 => write_masked(&io.scratch_regs[0x0], mask, value), .scratch_1 => write_masked(&io.scratch_regs[0x1], mask, value), diff --git a/sim/aviron/src/shared/isa.zig b/sim/aviron/src/shared/isa.zig index 0bf594c58..c217d43d7 100644 --- a/sim/aviron/src/shared/isa.zig +++ b/sim/aviron/src/shared/isa.zig @@ -102,6 +102,15 @@ pub const Opcode = enum(u8) { xch, unknown, + + pub fn to_string(opcode: Opcode) []const u8 { + inline for (@typeInfo(Opcode).@"enum".fields) |field| { + if (opcode == @field(Opcode, field.name)) + return field.name; + } + + unreachable; + } }; pub const opinfo = struct { @@ -139,9 +148,7 @@ pub const Register3 = enum(u3) { r22 = 6, r23 = 7, - pub fn format(r: Register3, fmt: []const u8, opt: std.fmt.FormatOptions, writer: anytype) !void { - _ = opt; - _ = fmt; + pub fn format(r: Register3, writer: *std.Io.Writer) !void { try writer.print("r{}", .{ 16 + @as(u32, @intFromEnum(r)), }); @@ -180,9 +187,7 @@ pub const Register4 = enum(u4) { r30 = 14, r31 = 15, - pub fn format(reg4: Register4, fmt: []const u8, opt: std.fmt.FormatOptions, writer: anytype) !void { - _ = opt; - _ = fmt; + pub fn format(reg4: Register4, writer: *std.Io.Writer) !void { try writer.print("r{}", .{ 16 + @as(u32, @intFromEnum(reg4)), }); @@ -221,9 +226,7 @@ pub const Register4_pair = enum(u4) { r29_r28 = 14, r31_r30 = 15, - pub fn format(reg4: Register4_pair, fmt: []const u8, opt: std.fmt.FormatOptions, writer: anytype) !void { - _ = opt; - _ = fmt; + pub fn format(reg4: Register4_pair, writer: *std.Io.Writer) !void { try writer.print("r{}:r{}", .{ @as(u32, @intFromEnum(reg4)) * 2 + 1, @as(u32, @intFromEnum(reg4)) * 2, @@ -279,9 +282,7 @@ pub const Register = enum(u5) { r30 = 30, r31 = 31, - pub fn format(reg5: Register, fmt: []const u8, opt: std.fmt.FormatOptions, writer: anytype) !void { - _ = opt; - _ = fmt; + pub fn format(reg5: Register, writer: *std.Io.Writer) !void { try writer.print("r{}", .{@intFromEnum(reg5)}); } @@ -309,9 +310,7 @@ pub const StatusRegisterBit = enum(u3) { T = 6, I = 7, - pub fn format(bit: StatusRegisterBit, fmt: []const u8, opt: std.fmt.FormatOptions, writer: anytype) !void { - _ = opt; - _ = fmt; + pub fn format(bit: StatusRegisterBit, writer: *std.Io.Writer) !void { try writer.print("{s}", .{@tagName(bit)}); } @@ -329,9 +328,7 @@ pub const StatusRegisterBit = enum(u3) { pub const DataBit = enum(u3) { _, - pub fn format(bit: DataBit, fmt: []const u8, opt: std.fmt.FormatOptions, writer: anytype) !void { - _ = opt; - _ = fmt; + pub fn format(bit: DataBit, writer: anytype) !void { try writer.print("{}", .{@intFromEnum(bit)}); } diff --git a/sim/aviron/src/testconfig.zig b/sim/aviron/src/testconfig.zig index 6011e4c4e..e7dc43447 100644 --- a/sim/aviron/src/testconfig.zig +++ b/sim/aviron/src/testconfig.zig @@ -78,7 +78,7 @@ pub const TestSuiteConfig = struct { }, pub fn to_string(config: TestSuiteConfig, b: *std.Build) []const u8 { - return std.json.stringifyAlloc(b.allocator, config, .{ + return std.json.Stringify.valueAlloc(b.allocator, config, .{ .whitespace = .indent_2, .emit_null_optional_fields = true, .emit_strings_as_arrays = false, @@ -87,10 +87,11 @@ pub const TestSuiteConfig = struct { } pub fn load(allocator: std.mem.Allocator, file: std.fs.File) !TestSuiteConfig { - var reader = std.json.reader(allocator, file.reader()); - defer reader.deinit(); + var buf: [4096]u8 = undefined; + var file_reader = file.reader(&buf); + var json_reader = std.json.Reader.init(allocator, &file_reader.interface); - return try std.json.parseFromTokenSourceLeaky(TestSuiteConfig, allocator, &reader, .{ + return try std.json.parseFromTokenSourceLeaky(TestSuiteConfig, allocator, &json_reader, .{ .allocate = .alloc_always, }); } diff --git a/sim/aviron/src/testrunner.zig b/sim/aviron/src/testrunner.zig index 1921d3925..e14b50469 100644 --- a/sim/aviron/src/testrunner.zig +++ b/sim/aviron/src/testrunner.zig @@ -69,15 +69,15 @@ fn validate_syste_and_exit(exit_mode: ExitMode) noreturn { if (!std.mem.eql(u8, ts.io.stdout.items, ts.config.stdout)) { std.debug.print("stdout mismatch:\n", .{}); - std.debug.print("expected: '{}'\n", .{std.fmt.fmtSliceEscapeLower(ts.config.stdout)}); - std.debug.print("actual: '{}'\n", .{std.fmt.fmtSliceEscapeLower(ts.io.stdout.items)}); + std.debug.print("expected: '{x}'\n", .{ts.config.stdout}); + std.debug.print("actual: '{x}'\n", .{ts.io.stdout.items}); ok = false; } if (!std.mem.eql(u8, ts.io.stderr.items, ts.config.stderr)) { std.debug.print("stderr mismatch:\n", .{}); - std.debug.print("expected: '{}'\n", .{std.fmt.fmtSliceEscapeLower(ts.config.stderr)}); - std.debug.print("actual: '{}'\n", .{std.fmt.fmtSliceEscapeLower(ts.io.stderr.items)}); + std.debug.print("expected: '{x}'\n", .{ts.config.stderr}); + std.debug.print("actual: '{x}'\n", .{ts.io.stderr.items}); ok = false; } @@ -127,10 +127,10 @@ pub fn main() !u8 { if (cli.positionals.len == 0) @panic("usage: aviron [--trace] "); - var stdout = std.ArrayList(u8).init(allocator); + var stdout = std.array_list.Managed(u8).init(allocator); defer stdout.deinit(); - var stderr = std.ArrayList(u8).init(allocator); + var stderr = std.array_list.Managed(u8).init(allocator); defer stderr.deinit(); test_system = SystemState{ @@ -190,10 +190,12 @@ pub fn main() !u8 { var elf_file = try std.fs.cwd().openFile(file_path, .{}); defer elf_file.close(); - var source = std.io.StreamSource{ .file = elf_file }; - var header = try std.elf.Header.read(&source); + var buf: [4096]u8 = undefined; + var file_reader = elf_file.reader(&buf); - var pheaders = header.program_header_iterator(&source); + var header = try std.elf.Header.read(&file_reader.interface); + + var pheaders = header.iterateProgramHeaders(&file_reader); while (try pheaders.next()) |phdr| { if (phdr.p_type != std.elf.PT_LOAD) continue; // Header isn't lodead @@ -206,8 +208,8 @@ pub fn main() !u8 { const addr_masked: u24 = @intCast(phdr.p_vaddr & 0x007F_FFFF); if (phdr.p_filesz > 0) { - try source.seekTo(phdr.p_offset); - try source.reader().readNoEof(dest_mem[addr_masked..][0..phdr.p_filesz]); + try file_reader.seekTo(phdr.p_offset); + try file_reader.interface.readSliceAll(dest_mem[addr_masked..][0..phdr.p_filesz]); } if (phdr.p_memsz > phdr.p_filesz) { @memset(dest_mem[addr_masked + phdr.p_filesz ..][0 .. phdr.p_memsz - phdr.p_filesz], 0); @@ -229,8 +231,8 @@ const IO = struct { sp: u16, sreg: *aviron.Cpu.SREG, - stdout: *std.ArrayList(u8), - stderr: *std.ArrayList(u8), + stdout: *std.array_list.Managed(u8), + stderr: *std.array_list.Managed(u8), stdin: []const u8, diff --git a/sim/aviron/testsuite/lib/write-chan.zig b/sim/aviron/testsuite/lib/write-chan.zig index 02609fb82..7a59cb2e8 100644 --- a/sim/aviron/testsuite/lib/write-chan.zig +++ b/sim/aviron/testsuite/lib/write-chan.zig @@ -4,7 +4,7 @@ //! } const testsuite = @import("testsuite"); -export fn _start() callconv(.C) noreturn { +export fn _start() callconv(.c) noreturn { testsuite.write(.stdout, "hello"); testsuite.write(.stderr, "world"); testsuite.exit(0); diff --git a/sim/aviron/tools/generate-tables.zig b/sim/aviron/tools/generate-tables.zig index 33636b21c..fb7c9d428 100644 --- a/sim/aviron/tools/generate-tables.zig +++ b/sim/aviron/tools/generate-tables.zig @@ -2,6 +2,8 @@ const std = @import("std"); const isa_def = @embedFile("isa.txt"); const isa = @import("isa"); +const BoundedArray = @import("bounded-array").BoundedArray; + fn string_to_enum(comptime T: type, str: []const u8) ?T { inline for (@typeInfo(T).@"enum".fields) |enumField| { if (std.mem.eql(u8, str, enumField.name)) { @@ -22,7 +24,7 @@ pub fn main() !void { var out = try std.fs.cwd().createFile(argv[1], .{}); defer out.close(); - var buf = std.ArrayList(u8).init(allocator); + var buf = std.array_list.Managed(u8).init(allocator); defer buf.deinit(); const writer = buf.writer(); @@ -30,11 +32,11 @@ pub fn main() !void { var lut = [_]isa.Opcode{.unknown} ** (std.math.maxInt(u16) + 1); var base_number_bit_set = std.bit_set.IntegerBitSet(16).initEmpty(); - var unknown_indices = try std.BoundedArray(u8, 16).init(0); + var unknown_indices = try BoundedArray(u8, 16).init(0); var unknown_indices_bit_set = std.bit_set.IntegerBitSet(16).initEmpty(); var result_bit_set = std.bit_set.IntegerBitSet(16).initEmpty(); - var positionals = std.enums.EnumArray(isa.Opcode, std.AutoArrayHashMapUnmanaged(u8, std.BoundedArray(u8, 16))).initFill(.{}); + var positionals = std.enums.EnumArray(isa.Opcode, std.AutoArrayHashMapUnmanaged(u8, BoundedArray(u8, 16))).initFill(.{}); defer for (&positionals.values) |*map| { map.deinit(allocator); }; @@ -62,7 +64,7 @@ pub fn main() !void { else => { const gop = try positionals.getPtr(opcode).getOrPut(allocator, r); if (!gop.found_existing) { - gop.value_ptr.* = try std.BoundedArray(u8, 16).init(0); + gop.value_ptr.* = try BoundedArray(u8, 16).init(0); } try gop.value_ptr.*.append(@intCast(index)); @@ -102,7 +104,7 @@ pub fn main() !void { for (positionals.values, 0..) |map, i| { const opcode = std.enums.EnumIndexer(isa.Opcode).keyForIndex(i); - try writer.print("{}: ", .{std.zig.fmtId(@tagName(opcode))}); + try writer.print("{f}: ", .{std.zig.fmtId(@tagName(opcode))}); const BitSet = struct { name: u8, @@ -114,7 +116,7 @@ pub fn main() !void { } }; - var items = std.ArrayList(BitSet).init(allocator); + var items = std.array_list.Managed(BitSet).init(allocator); defer items.deinit(); var it = map.iterator(); @@ -144,7 +146,7 @@ pub fn main() !void { try writer.writeAll("pub const lookup = [65536]isa.Opcode {"); for (lut, 0..) |v, i| { - try writer.print(".{},", .{std.zig.fmtId(@tagName(v))}); + try writer.print(".{f},", .{std.zig.fmtId(@tagName(v))}); if ((i + 1) % 16 == 0) { try writer.print("\n", .{}); } @@ -153,7 +155,7 @@ pub fn main() !void { try writer.writeAll("};\n\npub const positionals = .{"); for (positionals.values, 0..) |map, i| { - try writer.print(".{} = .{{", .{std.zig.fmtId(@tagName(std.enums.EnumIndexer(isa.Opcode).keyForIndex(i)))}); + try writer.print(".{f} = .{{", .{std.zig.fmtId(@tagName(std.enums.EnumIndexer(isa.Opcode).keyForIndex(i)))}); var it = map.iterator(); while (it.next()) |entry| { try writer.print(".{{'{c}', .{{", .{entry.key_ptr.*}); @@ -186,15 +188,22 @@ pub fn main() !void { var tree = try std.zig.Ast.parse(allocator, txt, .zig); defer tree.deinit(allocator); + var stdout_buf: [4096]u8 = undefined; + var stdout = std.fs.File.stdout(); + var stdout_writer = stdout.writer(&stdout_buf); + + var out_buf: [4096]u8 = undefined; + var out_writer = out.writer(&out_buf); + if (tree.errors.len != 0) { for (tree.errors) |err| { - try tree.renderError(err, std.io.getStdErr().writer()); + try tree.renderError(err, &stdout_writer.interface); } - try out.writer().writeAll(txt); + try out_writer.interface.writeAll(txt); } else { - const render_result = try tree.render(allocator); - defer allocator.free(render_result); - - try out.writer().writeAll(render_result); + const fixups: std.zig.Ast.Render.Fixups = .{}; + try tree.render(allocator, &out_writer.interface, fixups); } + + try out_writer.interface.flush(); } diff --git a/tools/esp-image/build.zig b/tools/esp-image/build.zig index 1471bd5ed..677e44739 100644 --- a/tools/esp-image/build.zig +++ b/tools/esp-image/build.zig @@ -17,29 +17,30 @@ pub const Options = struct { }; pub fn from_elf(dep: *std.Build.Dependency, elf_file: std.Build.LazyPath, options: Options) std.Build.LazyPath { - const elf2image_exe = dep.artifact("elf2image"); + const b = dep.builder; - const run = dep.builder.addRunArtifact(elf2image_exe); + const elf2image_exe = dep.artifact("elf2image"); + const run = b.addRunArtifact(elf2image_exe); run.addFileArg(elf_file); - run.addArg("--chip-id"); - run.addArg(@tagName(options.chip_id)); - - var rev_buf: [5]u8 = undefined; + run.addArgs(&.{ + "--chip-id", + @tagName(options.chip_id), + }); if (options.min_rev) |min_rev| { - const n = std.fmt.formatIntBuf(&rev_buf, min_rev, 10, .lower, .{}); - - run.addArg("--min-rev-full"); - run.addArg(rev_buf[0..n]); + run.addArgs(&.{ + "--min-rev-full", + b.fmt("{}", .{min_rev}), + }); } if (options.max_rev) |max_rev| { - const n = std.fmt.formatIntBuf(&rev_buf, max_rev, 10, .lower, .{}); - - run.addArg("--max-rev-full"); - run.addArg(rev_buf[0..n]); + run.addArgs(&.{ + "--max-rev-full", + b.fmt("{}", .{max_rev}), + }); } if (options.dont_append_digest) |dont_append_digest| { diff --git a/tools/esp-image/build.zig.zon b/tools/esp-image/build.zig.zon index 4716d84de..8fe07d7b4 100644 --- a/tools/esp-image/build.zig.zon +++ b/tools/esp-image/build.zig.zon @@ -4,8 +4,8 @@ .version = "0.1.0", .dependencies = .{ .clap = .{ - .url = "git+https://github.com/Hejsil/zig-clap.git#e47028deaefc2fb396d3d9e9f7bd776ae0b2a43a", - .hash = "clap-0.10.0-oBajB434AQBDh-Ei3YtoKIRxZacVPF1iSwp3IX_ZB8f0", + .url = "git+https://github.com/Hejsil/zig-clap.git#5289e0753cd274d65344bef1c114284c633536ea", + .hash = "clap-0.11.0-oBajB-HnAQDPCKYzwF7rO3qDFwRcD39Q0DALlTSz5H7e", }, }, .paths = .{ diff --git a/tools/esp-image/src/elf2image.zig b/tools/esp-image/src/elf2image.zig index 39314eee4..bd59da979 100644 --- a/tools/esp-image/src/elf2image.zig +++ b/tools/esp-image/src/elf2image.zig @@ -6,6 +6,9 @@ pub const std_options: std.Options = .{ .log_level = .warn, }; +var elf_file_reader_buf: [1024]u8 = undefined; +var output_writer_buf: [1024]u8 = undefined; + pub fn main() !void { var debug_allocator: std.heap.DebugAllocator(.{}) = .init; defer _ = debug_allocator.deinit(); @@ -26,7 +29,10 @@ pub fn main() !void { \\ ); - var diag = clap.Diagnostic{}; + const stderr = std.fs.File.stderr(); + var stderr_writer = stderr.writer(&.{}); + + var diag: clap.Diagnostic = .{}; var res = clap.parse(clap.Help, &args, .{ .u16 = clap.parsers.int(u16, 10), .str = clap.parsers.string, @@ -38,13 +44,14 @@ pub fn main() !void { .diagnostic = &diag, .allocator = allocator, }) catch |err| { - diag.report(std.io.getStdErr().writer(), err) catch {}; + diag.report(&stderr_writer.interface, err) catch {}; return err; }; defer res.deinit(); - if (res.args.help != 0) - return clap.help(std.io.getStdErr().writer(), clap.Help, &args, .{}); + if (res.args.help != 0) { + return clap.help(&stderr_writer.interface, clap.Help, &args, .{}); + } const elf_path = res.positionals[0] orelse return error.MissingInputFile; const output_path = res.args.output orelse return error.MissingOutputFile; @@ -64,28 +71,29 @@ pub fn main() !void { const elf_file = try std.fs.cwd().openFile(elf_path, .{}); defer elf_file.close(); - const elf_header = try std.elf.Header.read(elf_file); + var elf_file_reader = elf_file.reader(&elf_file_reader_buf); + const elf_header = try std.elf.Header.read(&elf_file_reader.interface); const entry_point: u32 = @intCast(elf_header.entry); - var flash_segments: std.ArrayListUnmanaged(Segment) = .empty; + var flash_segments: std.ArrayList(Segment) = .empty; defer flash_segments.deinit(allocator); defer for (flash_segments.items) |segment| { segment.deinit(allocator); }; - var ram_segments: std.ArrayListUnmanaged(Segment) = .empty; + var ram_segments: std.ArrayList(Segment) = .empty; defer ram_segments.deinit(allocator); defer for (ram_segments.items) |segment| { segment.deinit(allocator); }; { - var info_list: std.ArrayListUnmanaged(SegmentInfo) = .empty; + var info_list: std.ArrayList(SegmentInfo) = .empty; defer info_list.deinit(allocator); if (use_segments) { - var it = elf_header.program_header_iterator(elf_file); + var it = elf_header.iterateProgramHeaders(&elf_file_reader); while (try it.next()) |hdr| { if (hdr.p_type == std.elf.PT_LOAD and hdr.p_memsz > 0 and hdr.p_filesz > 0) { try info_list.append(allocator, .{ @@ -96,7 +104,7 @@ pub fn main() !void { } } } else { - var it = elf_header.section_header_iterator(elf_file); + var it = elf_header.iterateSectionHeaders(&elf_file_reader); while (try it.next()) |hdr| { if (hdr.sh_type == std.elf.SHT_PROGBITS and hdr.sh_flags & std.elf.SHF_ALLOC != 0 and hdr.sh_size > 0) { try info_list.append(allocator, .{ @@ -139,7 +147,7 @@ pub fn main() !void { std.log.debug("ram segment at addr 0x{x} of size 0x{x}", .{ segment.addr, segment.size }); } - var segment_data: std.ArrayListUnmanaged(u8) = .empty; + var segment_data: std.ArrayList(u8) = .empty; defer segment_data.deinit(allocator); var segment_count: u8 = 0; @@ -175,12 +183,9 @@ pub fn main() !void { const output_file = try std.fs.cwd().createFile(output_path, .{}); defer output_file.close(); - const output_file_writer = output_file.writer(); + var output_file_writer = output_file.writer(&.{}); - var sha256: Sha256 = .init(.{}); - - var multi_writer = std.io.multiWriter(.{ output_file_writer, sha256.writer() }); - const multi_writer_writer = multi_writer.writer(); + var sha256_hasher = output_file_writer.interface.hashed(Sha256.init(.{}), &output_writer_buf); const file_header: FileHeader = .{ .number_of_segments = segment_count, @@ -199,24 +204,26 @@ pub fn main() !void { .hash = !no_digest, }; - try file_header.write_to(multi_writer_writer); - try extended_file_header.write_to(multi_writer_writer); + try file_header.write_to(&sha256_hasher.writer); + try extended_file_header.write_to(&sha256_hasher.writer); - try multi_writer_writer.writeAll(segment_data.items); + try sha256_hasher.writer.writeAll(segment_data.items); // TODO: Add secure boot option (v1 or v2) and append a signature if enabled. - const position = try output_file.getPos(); - const padding: [16]u8 = @splat(0); - try multi_writer_writer.writeAll(padding[0 .. 15 - position % 16]); - try multi_writer_writer.writeByte(checksum); + try sha256_hasher.writer.flush(); // flush before getting the position + try sha256_hasher.writer.splatByteAll(0, 15 - output_file_writer.pos % 16); + try sha256_hasher.writer.writeByte(checksum); + + try sha256_hasher.writer.flush(); if (!no_digest) { - try output_file_writer.writeAll(&sha256.finalResult()); + try output_file_writer.interface.writeAll(&sha256_hasher.hasher.finalResult()); + try output_file_writer.interface.flush(); } } -fn do_segment_merge(allocator: std.mem.Allocator, segment_list: *std.ArrayListUnmanaged(Segment)) !void { +fn do_segment_merge(allocator: std.mem.Allocator, segment_list: *std.ArrayList(Segment)) !void { if (segment_list.items.len >= 2) { var i: usize = segment_list.items.len - 1; while (i > 0) : (i -= 1) { @@ -292,7 +299,7 @@ const FileHeader = struct { flash_freq: FlashFreq, entry_point: u32, - pub fn write_to(self: FileHeader, writer: anytype) !void { + pub fn write_to(self: FileHeader, writer: *std.Io.Writer) !void { try writer.writeAll(&.{ 0xE9, self.number_of_segments, @@ -315,7 +322,7 @@ const ExtendedFileHeader = struct { max_rev: u16, hash: bool, - pub fn write_to(self: ExtendedFileHeader, writer: anytype) !void { + pub fn write_to(self: ExtendedFileHeader, writer: *std.Io.Writer) !void { try writer.writeByte(@intFromEnum(self.wp)); try writer.writeInt(u24, self.flash_pins_drive_settings, .little); try writer.writeInt(u16, @intFromEnum(self.chip_id), .little); @@ -441,7 +448,7 @@ test "Segment.get_padding_len" { test "do_segment_merge" { var allocator = std.testing.allocator; - var segment_list: std.ArrayListUnmanaged(Segment) = .empty; + var segment_list: std.ArrayList(Segment) = .empty; defer segment_list.deinit(allocator); defer for (segment_list.items) |segment| { segment.deinit(allocator); @@ -480,7 +487,7 @@ test "Segment.write_to" { @memset(segment.data, 'a'); - var segment_data: std.ArrayListUnmanaged(u8) = .empty; + var segment_data: std.ArrayList(u8) = .empty; defer segment_data.deinit(allocator); const writer = segment_data.writer(allocator); diff --git a/tools/generate_linker_script.zig b/tools/generate_linker_script.zig index 8a95b3432..5d17fbe94 100644 --- a/tools/generate_linker_script.zig +++ b/tools/generate_linker_script.zig @@ -12,11 +12,13 @@ pub const Args = struct { ram_image: bool, }; +var writer_buf: [1024]u8 = undefined; + pub fn main() !void { var debug_allocator: std.heap.DebugAllocator(.{}) = .init; defer _ = debug_allocator.deinit(); - var arena = std.heap.ArenaAllocator.init(debug_allocator.allocator()); + var arena: std.heap.ArenaAllocator = .init(debug_allocator.allocator()); defer arena.deinit(); const allocator = arena.allocator(); @@ -38,8 +40,8 @@ pub fn main() !void { const file = try std.fs.cwd().createFile(output_path, .{}); defer file.close(); - const writer = file.writer(); - try writer.print( + var writer = file.writer(&writer_buf); + try writer.interface.print( \\/* \\ * Target CPU: {[cpu]s} \\ * Target Chip: {[chip]s} @@ -69,7 +71,7 @@ pub fn main() !void { } if (parsed_args.generate != .none) { - try writer.writeAll( + try writer.interface.writeAll( \\/* \\ * This section was auto-generated by microzig. \\ */ @@ -81,24 +83,24 @@ pub fn main() !void { for (region_names, parsed_args.memory_regions) |region_name, region| { // flash (rx!w) : ORIGIN = 0x00000000, LENGTH = 512k - try writer.print(" {s} (", .{region_name}); + try writer.interface.print(" {s} (", .{region_name}); - if (region.access.read) try writer.writeAll("r"); - if (region.access.write) try writer.writeAll("w"); - if (region.access.execute) try writer.writeAll("x"); + if (region.access.read) try writer.interface.writeAll("r"); + if (region.access.write) try writer.interface.writeAll("w"); + if (region.access.execute) try writer.interface.writeAll("x"); if (!region.access.read or !region.access.write or !region.access.execute) { - try writer.writeAll("!"); - if (!region.access.read) try writer.writeAll("r"); - if (!region.access.write) try writer.writeAll("w"); - if (!region.access.execute) try writer.writeAll("x"); + try writer.interface.writeAll("!"); + if (!region.access.read) try writer.interface.writeAll("r"); + if (!region.access.write) try writer.interface.writeAll("w"); + if (!region.access.execute) try writer.interface.writeAll("x"); } - try writer.writeAll(")"); + try writer.interface.writeAll(")"); - try writer.print(" : ORIGIN = 0x{X:0>8}, LENGTH = 0x{X:0>8}\n", .{ region.offset, region.length }); + try writer.interface.print(" : ORIGIN = 0x{X:0>8}, LENGTH = 0x{X:0>8}\n", .{ region.offset, region.length }); } - try writer.writeAll("}\n"); + try writer.interface.writeAll("}\n"); } if (parsed_args.generate == .memory_regions_and_sections) { @@ -120,14 +122,14 @@ pub fn main() !void { const options = parsed_args.generate.memory_regions_and_sections; - try writer.writeAll( + try writer.interface.writeAll( \\SECTIONS \\{ \\ ); if (!parsed_args.ram_image) { - try writer.print( + try writer.interface.print( \\ .flash_start : \\ {{ \\ KEEP(*(microzig_flash_start)) @@ -137,7 +139,7 @@ pub fn main() !void { .{flash_region_name}, ); } else { - try writer.print( + try writer.interface.print( \\ .ram_start : \\ {{ \\ KEEP(*(microzig_ram_start)) @@ -148,7 +150,7 @@ pub fn main() !void { ); } - try writer.writeAll( + try writer.interface.writeAll( \\ \\ .text : \\ { @@ -157,27 +159,27 @@ pub fn main() !void { ); if (parsed_args.ram_image) { - try writer.writeAll( + try writer.interface.writeAll( \\ *(.ram_text*) \\ ); } if (options.rodata_location == .flash and !parsed_args.ram_image) { - try writer.writeAll( + try writer.interface.writeAll( \\ *(.srodata*) \\ *(.rodata*) \\ ); } - try writer.print( + try writer.interface.print( \\ }} > {s} \\ , .{if (!parsed_args.ram_image) flash_region_name else ram_region_name}); switch (parsed_args.cpu_arch) { - .arm, .thumb => try writer.print( + .arm, .thumb => try writer.interface.print( \\ \\ .ARM.extab : {{ \\ *(.ARM.extab* .gnu.linkonce.armextab.*) @@ -191,7 +193,7 @@ pub fn main() !void { else => {}, } - try writer.writeAll( + try writer.interface.writeAll( \\ \\ .data : \\ { @@ -202,7 +204,7 @@ pub fn main() !void { ); if (options.rodata_location == .ram or parsed_args.ram_image) { - try writer.writeAll( + try writer.interface.writeAll( \\ *(.srodata*) \\ *(.rodata*) \\ @@ -210,14 +212,14 @@ pub fn main() !void { } if (ram_region.access.execute and !parsed_args.ram_image) { - try writer.writeAll( + try writer.interface.writeAll( // NOTE: should this be `microzig_ram_text`? \\ KEEP(*(.ram_text)) \\ ); } - try writer.print( + try writer.interface.print( \\ microzig_data_end = .; \\ }} > {s} \\ @@ -238,7 +240,7 @@ pub fn main() !void { }); if (!parsed_args.ram_image) { - try writer.print( + try writer.interface.print( \\ \\ .flash_end : \\ {{ @@ -248,24 +250,24 @@ pub fn main() !void { , .{flash_region_name}); } - try writer.writeAll( + try writer.interface.writeAll( \\ \\ microzig_data_load_start = LOADADDR(.data); \\ ); switch (parsed_args.cpu_arch) { - .riscv32, .riscv64 => try writer.writeAll( + .riscv32, .riscv64 => try writer.interface.writeAll( \\ PROVIDE(__global_pointer$ = microzig_data_start + 0x800); \\ ), else => {}, } - try writer.writeAll("}\n"); + try writer.interface.writeAll("}\n"); } if (parsed_args.generate != .none) { - try writer.writeAll( + try writer.interface.writeAll( \\/* \\ * End of auto-generated section. \\ */ @@ -274,6 +276,8 @@ pub fn main() !void { } if (maybe_user_linker_script) |user_linker_script| { - try writer.writeAll(user_linker_script); + try writer.interface.writeAll(user_linker_script); } + + try writer.interface.flush(); } diff --git a/tools/linter/src/main.zig b/tools/linter/src/main.zig index 5f633cfa0..f78ed5543 100644 --- a/tools/linter/src/main.zig +++ b/tools/linter/src/main.zig @@ -16,11 +16,11 @@ pub fn main() !void { const args = try std.process.argsAlloc(allocator); defer std.process.argsFree(allocator, args); - var issues: std.ArrayList(Issue) = .init(allocator); + var issues: std.array_list.Managed(Issue) = .init(allocator); defer issues.deinit(); for (args[1..]) |path| { - const source = std.fs.cwd().readFileAllocOptions(allocator, path, 100 * 1024 * 1024, null, 1, 0) catch |err| { + const source = std.fs.cwd().readFileAllocOptions(allocator, path, 100 * 1024 * 1024, null, .@"1", 0) catch |err| { std.log.err("Failed to read file '{s}': {}", .{ path, err }); return err; }; @@ -67,8 +67,10 @@ pub fn main() !void { } } - const stdout = std.io.getStdOut().writer(); - try std.json.stringify(issues.items, .{}, stdout); + const stdout = std.fs.File.stdout(); + var buf: [4096]u8 = undefined; + var writer = stdout.writer(&buf); + try std.json.Stringify.value(issues.items, .{}, &writer.interface); } const Token = std.zig.Token; @@ -115,7 +117,7 @@ fn camel_to_snake(arena: Allocator, str: []const u8) ![]const u8 { if (str.len == 0) return str; - var ret = std.ArrayList(u8).init(arena); + var ret = std.array_list.Managed(u8).init(arena); errdefer ret.deinit(); if (std.ascii.isUpper(str[0])) { diff --git a/tools/parts_db.zig b/tools/parts_db.zig index 2e6ab4315..aad821c34 100644 --- a/tools/parts_db.zig +++ b/tools/parts_db.zig @@ -19,8 +19,8 @@ pub fn main() !void { const output_path = args[1]; - var chips = std.ArrayList(MicroZig.Chip).init(allocator); - var boards = std.ArrayList(MicroZig.Board).init(allocator); + var chips = std.array_list.Managed(MicroZig.Chip).init(allocator); + var boards = std.array_list.Managed(MicroZig.Board).init(allocator); inline for (port) |port| {} const json_str = std.json.stringifyAlloc(b.allocator, parts_db, .{}) catch @panic("OOM"); diff --git a/tools/printer/build.zig b/tools/printer/build.zig index 8fc39d454..609458c79 100644 --- a/tools/printer/build.zig +++ b/tools/printer/build.zig @@ -79,7 +79,7 @@ pub fn build(b: *std.Build) void { if (b.option(bool, "rebuild-test-elf", "rebuild the test program elf") == true) { const mz_dep = b.lazyDependency("microzig", .{}) orelse return; - const mb = @import("microzig").MicroBuild(.{ + const mb = b.lazyImport(@This(), "microzig").?.MicroBuild(.{ .rp2xxx = true, }).init(b, mz_dep) orelse return; diff --git a/tools/printer/build.zig.zon b/tools/printer/build.zig.zon index cd1402319..d7209a5cf 100644 --- a/tools/printer/build.zig.zon +++ b/tools/printer/build.zig.zon @@ -5,10 +5,10 @@ .minimum_zig_version = "0.14.1", .dependencies = .{ .serial = .{ - .url = "git+https://github.com/ZigEmbeddedGroup/serial#ad338133eda8d86332718bbdc58c641a66307c84", - .hash = "serial-0.0.1-PoeRzI20AABcp4FffI6HXKOL6LcGPKmeqfN4Bna4-YYm", + .url = "git+https://github.com/ZigEmbeddedGroup/serial#fbd7389ff8bbc9fa362aa74081588755b5d028a0", + .hash = "serial-0.0.1-PoeRzF60AAAN8Iu0yXTIX-t3DVzsnmN7vWHKM2HA2Zbq", }, - // use to compile the test program + // used to compile the test program .microzig = .{ .path = "../..", .lazy = true }, }, .paths = .{ diff --git a/tools/printer/examples/rp2xxx_runner.zig b/tools/printer/examples/rp2xxx_runner.zig index 042e87969..f8d8356c2 100644 --- a/tools/printer/examples/rp2xxx_runner.zig +++ b/tools/printer/examples/rp2xxx_runner.zig @@ -2,6 +2,10 @@ const std = @import("std"); const printer = @import("printer"); const serial = @import("serial"); +var elf_file_reader_buf: [1024]u8 = undefined; +var out_stream_buf: [1024]u8 = undefined; +var printer_writer_buf: [512]u8 = undefined; + pub fn main() !void { var debug_allocator: std.heap.DebugAllocator(.{}) = .init; defer _ = debug_allocator.deinit(); @@ -18,21 +22,21 @@ pub fn main() !void { const elf_file = try std.fs.cwd().openFile(elf_path, .{}); defer elf_file.close(); + var elf_file_reader = elf_file.reader(&elf_file_reader_buf); - var elf = try printer.Elf.init(allocator, elf_file); + var elf = try printer.Elf.init(allocator, &elf_file_reader); defer elf.deinit(allocator); var debug_info = try printer.DebugInfo.init(allocator, elf); defer debug_info.deinit(allocator); - var annotator: printer.Annotator = .init; - const serial_device = try std.fs.cwd().openFile(serial_device_path, .{}); defer serial_device.close(); try serial.configureSerialPort(serial_device, .{ .baud_rate = baud_rate, }); try serial.flushSerialPort(serial_device, .both); + var in_stream = serial_device.reader(&.{}); { var flash_cmd: std.process.Child = .init(&.{ @@ -52,13 +56,22 @@ pub fn main() !void { } } - const stdout = std.io.getStdOut(); - const out_stream = stdout.writer(); + const stdout = std.fs.File.stdout(); + var out_stream = stdout.writer(&out_stream_buf); const out_tty_config = std.io.tty.detectConfig(stdout); - var buf: [4096]u8 = undefined; + var printer_writer: printer.Writer = .init( + &printer_writer_buf, + &out_stream.interface, + out_tty_config, + elf, + &debug_info, + ); + while (true) { - const n = try serial_device.read(&buf); - try annotator.process(buf[0..n], elf, &debug_info, out_stream, out_tty_config); + _ = try in_stream.interface.stream(&printer_writer.interface, .unlimited); + + try printer_writer.interface.flush(); + try out_stream.interface.flush(); } } diff --git a/tools/printer/src/DebugInfo.zig b/tools/printer/src/DebugInfo.zig index afc6cf43b..29d5e6073 100644 --- a/tools/printer/src/DebugInfo.zig +++ b/tools/printer/src/DebugInfo.zig @@ -1,6 +1,5 @@ const std = @import("std"); const dwarf = std.dwarf; -const ArrayListUnmanaged = std.ArrayListUnmanaged; const Elf = @import("Elf.zig"); const DebugInfo = @This(); @@ -121,52 +120,52 @@ pub fn query(self: *DebugInfo, address: u64) QueryResult { const Parser = struct { arena: std.mem.Allocator, - directories: ArrayListUnmanaged([]const u8) = .empty, - files: ArrayListUnmanaged(File) = .empty, - loc_list: ArrayListUnmanaged(SourceLocation) = .empty, - compile_unit_names: ArrayListUnmanaged([]const u8) = .empty, - functions: ArrayListUnmanaged(Function) = .empty, + directories: std.ArrayList([]const u8) = .empty, + files: std.ArrayList(File) = .empty, + loc_list: std.ArrayList(SourceLocation) = .empty, + compile_unit_names: std.ArrayList([]const u8) = .empty, + functions: std.ArrayList(Function) = .empty, fn parse_elf(self: *Parser, elf: Elf) !void { - const data = elf.sections.get(.@".debug_info") orelse return bad(); - var reader: std.debug.FixedBufferReader = .{ - .buf = data, - .endian = .little, - }; + const buf = elf.sections.get(.@".debug_info") orelse return bad(); + var reader: std.Io.Reader = .fixed(buf); var current_cu_index: ?usize = null; - while (reader.pos < data.len) { - var length: u64 = try reader.readInt(u32); + while (reader.seek < reader.buffer.len) { + var length: u64 = try reader.takeInt(u32, elf.endian); var dwarf_format: dwarf.Format = .@"32"; if (length == std.math.maxInt(u32)) { - length = try reader.readInt(u64); + length = try reader.takeInt(u64, elf.endian); dwarf_format = .@"64"; } - const version = try reader.readInt(u16); + if (length == 0) break; + + const version = try reader.takeInt(u16, elf.endian); + if (version < 2 or version > 5) return bad(); var address_size: u8 = 0; var abbrev_table_offset: u64 = 0; if (version >= 5) { - const unit_type = try reader.readByte(); + const unit_type = try reader.takeByte(); if (unit_type != dwarf.UT.compile) return bad(); - address_size = try reader.readByte(); - abbrev_table_offset = try reader.readAddress(dwarf_format); + address_size = try reader.takeByte(); + abbrev_table_offset = try read_address(&reader, dwarf_format, elf.endian); } else { - abbrev_table_offset = try reader.readAddress(dwarf_format); - address_size = try reader.readByte(); + abbrev_table_offset = try read_address(&reader, dwarf_format, elf.endian); + address_size = try reader.takeByte(); } - var abbrev_table = try self.get_abbrev_table(elf.sections, abbrev_table_offset); + var abbrev_table = try self.get_abbrev_table(elf, abbrev_table_offset); var depth: usize = 0; while (true) { - const abbrev_code = try reader.readUleb128(u64); + const abbrev_code = try reader.takeLeb128(u64); if (abbrev_code == 0) { - if (depth == 1) { + if (depth <= 1) { break; } depth -= 1; @@ -180,7 +179,7 @@ const Parser = struct { const form_value = try FormValue.parse( &reader, attr.form_id, - elf.format, + elf, dwarf_format, attr.implicit_const_val, ); @@ -255,36 +254,33 @@ const Parser = struct { }.less_than); } - fn get_abbrev_table(self: *Parser, sections: Elf.Sections, offset: usize) !AbbrevTable { - var reader: std.debug.FixedBufferReader = .{ - .buf = sections.get(.@".debug_abbrev") orelse return bad(), - .pos = offset, - .endian = .little, - }; + fn get_abbrev_table(self: *Parser, elf: Elf, offset: usize) !AbbrevTable { + const buf = elf.sections.get(.@".debug_abbrev") orelse return bad(); + var reader: std.Io.Reader = .fixed(buf[offset..]); var abbrev_table: std.AutoHashMapUnmanaged(u64, AbbrevDecl) = .empty; while (true) { - const code = try reader.readUleb128(u64); + const code = try reader.takeLeb128(u64); if (code == 0) { break; } - const tag = try reader.readUleb128(u64); - const has_children = try reader.readByte(); + const tag = try reader.takeLeb128(u64); + const has_children = try reader.takeByte(); - var attrs: ArrayListUnmanaged(AbbrevDecl.Attrib) = .empty; + var attrs: std.ArrayList(AbbrevDecl.Attrib) = .empty; while (true) { - const id = try reader.readUleb128(u64); - const form_id = try reader.readUleb128(u64); + const id = try reader.takeLeb128(u64); + const form_id = try reader.takeLeb128(u64); if (id == 0 and form_id == 0) { break; } var implicit_const_val: ?i64 = null; if (form_id == dwarf.FORM.implicit_const) { - implicit_const_val = try reader.readIleb128(i64); + implicit_const_val = try reader.takeLeb128(i64); } try attrs.append(self.arena, .{ @@ -324,51 +320,48 @@ const Parser = struct { offset: usize, cu_cwd: []const u8, ) !void { - var reader: std.debug.FixedBufferReader = .{ - .buf = elf.sections.get(.@".debug_line") orelse return bad(), - .pos = offset, - .endian = .little, - }; + const buf = elf.sections.get(.@".debug_line") orelse return bad(); + var reader: std.Io.Reader = .fixed(buf[offset..]); - var unit_length: u64 = try reader.readInt(u32); + var unit_length: u64 = try reader.takeInt(u32, elf.endian); var dwarf_format: dwarf.Format = .@"32"; if (unit_length == std.math.maxInt(u32)) { - unit_length = try reader.readInt(u64); + unit_length = try reader.takeInt(u64, elf.endian); dwarf_format = .@"64"; } if (unit_length == 0) { return; } - const next_unit_offset = reader.pos + unit_length; + const next_unit_offset = reader.seek + unit_length; - const version = try reader.readInt(u16); + const version = try reader.takeInt(u16, elf.endian); if (version < 2) return bad(); if (version >= 5) { - _ = try reader.readByte(); // address size - _ = try reader.readByte(); // segment size + _ = try reader.takeByte(); // address size + _ = try reader.takeByte(); // segment size } - const prologue_length = try reader.readAddress(dwarf_format); - const prog_start_offset = reader.pos + prologue_length; + const prologue_length = try read_address(&reader, dwarf_format, elf.endian); + const prog_start_offset = reader.seek + prologue_length; - const minimum_instruction_length = try reader.readByte(); + const minimum_instruction_length = try reader.takeByte(); if (minimum_instruction_length == 0) return bad(); if (version >= 4) { - _ = try reader.readByte(); + _ = try reader.takeByte(); } - const default_is_stmt = (try reader.readByte()) != 0; - const line_base = try reader.readByteSigned(); + const default_is_stmt = (try reader.takeByte()) != 0; + const line_base = try reader.takeByteSigned(); - const line_range = try reader.readByte(); + const line_range = try reader.takeByte(); if (line_range == 0) return bad(); - const opcode_base = try reader.readByte(); + const opcode_base = try reader.takeByte(); - const standard_opcode_lengths = try reader.readBytes(opcode_base - 1); + const standard_opcode_lengths = try reader.take(opcode_base - 1); const dir_index_offset = self.directories.items.len; const file_index_offset = self.files.items.len; @@ -377,17 +370,17 @@ const Parser = struct { try self.directories.append(self.arena, cu_cwd); while (true) { - const dir = try reader.readBytesTo(0); + const dir = try reader.takeSentinel(0); if (dir.len == 0) break; try self.directories.append(self.arena, dir); } while (true) { - const file_name = try reader.readBytesTo(0); + const file_name = try reader.takeSentinel(0); if (file_name.len == 0) break; - const dir_index = try reader.readUleb128(usize); - _ = try reader.readUleb128(u64); // timestamp - _ = try reader.readUleb128(u64); // size + const dir_index = try reader.takeLeb128(usize); + _ = try reader.takeLeb128(u64); // timestamp + _ = try reader.takeLeb128(u64); // size try self.files.append(self.arena, .{ .path = file_name, .dir_index = dir_index_offset + dir_index, @@ -403,17 +396,17 @@ const Parser = struct { }; { - const directory_entry_format_count = try reader.readByte(); + const directory_entry_format_count = try reader.takeByte(); const dir_ent_fmt_buf = try self.arena.alloc(FileEntFmt, directory_entry_format_count); for (dir_ent_fmt_buf[0..directory_entry_format_count]) |*ent_fmt| { ent_fmt.* = .{ - .content_type_code = try reader.readUleb128(u8), - .form_code = try reader.readUleb128(u16), + .content_type_code = try reader.takeLeb128(u8), + .form_code = try reader.takeLeb128(u16), }; } - const directories_count = try reader.readUleb128(usize); + const directories_count = try reader.takeLeb128(usize); for (try self.directories.addManyAsSlice(self.arena, directories_count)) |*e| { e.* = &.{}; @@ -421,7 +414,7 @@ const Parser = struct { const form_value = try FormValue.parse( &reader, ent_fmt.form_code, - elf.format, + elf, dwarf_format, null, ); @@ -435,17 +428,17 @@ const Parser = struct { } { - const file_entry_format_count = try reader.readByte(); + const file_entry_format_count = try reader.takeByte(); const file_ent_fmt_buf = try self.arena.alloc(FileEntFmt, file_entry_format_count); for (file_ent_fmt_buf[0..file_entry_format_count]) |*ent_fmt| { ent_fmt.* = .{ - .content_type_code = try reader.readUleb128(u16), - .form_code = try reader.readUleb128(u16), + .content_type_code = try reader.takeLeb128(u16), + .form_code = try reader.takeLeb128(u16), }; } - const file_names_count = try reader.readUleb128(usize); + const file_names_count = try reader.takeLeb128(usize); for (try self.files.addManyAsSlice(self.arena, file_names_count)) |*e| { e.* = .{ .path = &.{}, .dir_index = 0 }; @@ -453,7 +446,7 @@ const Parser = struct { const form_value = try FormValue.parse( &reader, ent_fmt.form_code, - elf.format, + elf, dwarf_format, null, ); @@ -474,18 +467,18 @@ const Parser = struct { var prog = LineNumberProgram.init(default_is_stmt, version); - try reader.seekTo(prog_start_offset); + reader.seek = prog_start_offset; const LNE = dwarf.LNE; const LNS = dwarf.LNS; - while (reader.pos < next_unit_offset) { - const opcode = try reader.readByte(); + while (reader.seek < next_unit_offset) { + const opcode = try reader.takeByte(); if (opcode == LNS.extended_op) { - const op_size = try reader.readUleb128(u64); + const op_size = try reader.takeLeb128(u64); if (op_size < 1) return bad(); - const sub_op = try reader.readByte(); + const sub_op = try reader.takeByte(); switch (sub_op) { LNE.end_sequence => { // The row being added here is an "end" address, meaning @@ -503,23 +496,23 @@ const Parser = struct { }, LNE.set_address => { const addr = switch (elf.format) { - .@"32" => try reader.readInt(u32), - .@"64" => try reader.readInt(u64), + .@"32" => try reader.takeInt(u32, elf.endian), + .@"64" => try reader.takeInt(u64, elf.endian), }; prog.address = addr; }, LNE.define_file => { - const path = try reader.readBytesTo(0); - const dir_index = try reader.readUleb128(usize); - _ = try reader.readUleb128(u64); - _ = try reader.readUleb128(u64); + const path = try reader.takeSentinel(0); + const dir_index = try reader.takeLeb128(usize); + _ = try reader.takeLeb128(u64); + _ = try reader.takeLeb128(u64); try self.files.append(self.arena, .{ .path = path, .dir_index = dir_index_offset + dir_index, // .timestamp = timestamp, }); }, - else => try reader.seekForward(op_size - 1), + else => reader.toss(op_size - 1), } } else if (opcode >= opcode_base) { // special opcodes @@ -537,19 +530,19 @@ const Parser = struct { prog.basic_block = false; }, LNS.advance_pc => { - const arg = try reader.readUleb128(usize); + const arg = try reader.takeLeb128(usize); prog.address += arg * minimum_instruction_length; }, LNS.advance_line => { - const arg = try reader.readIleb128(i64); + const arg = try reader.takeLeb128(i64); prog.line += arg; }, LNS.set_file => { - const arg = try reader.readUleb128(usize); + const arg = try reader.takeLeb128(usize); prog.file = arg; }, LNS.set_column => { - const arg = try reader.readUleb128(u64); + const arg = try reader.takeLeb128(u64); prog.column = arg; }, LNS.negate_stmt => { @@ -563,13 +556,13 @@ const Parser = struct { prog.address += inc_addr; }, LNS.fixed_advance_pc => { - const arg = try reader.readInt(u16); + const arg = try reader.takeInt(u16, elf.endian); prog.address += arg; }, LNS.set_prologue_end => {}, else => { if (opcode - 1 >= standard_opcode_lengths.len) return bad(); - try reader.seekForward(standard_opcode_lengths[opcode - 1]); + reader.toss(standard_opcode_lengths[opcode - 1]); }, } } @@ -656,9 +649,9 @@ const Parser = struct { rnglistx: u64, fn parse( - reader: anytype, + reader: *std.Io.Reader, form_id: u64, - elf_format: Elf.Format, + elf: Elf, dwarf_format: dwarf.Format, implicit_const_val: ?i64, ) !FormValue { @@ -666,60 +659,60 @@ const Parser = struct { // TODO: check the use of `readAddress` return switch (form_id) { - FORM.addr => .{ .addr = switch (elf_format) { - .@"32" => try reader.readInt(u32), - .@"64" => try reader.readInt(u64), + FORM.addr => .{ .addr = switch (elf.format) { + .@"32" => try reader.takeInt(u32, elf.endian), + .@"64" => try reader.takeInt(u64, elf.endian), } }, - FORM.addrx1 => .{ .addrx = try reader.readInt(u8) }, - FORM.addrx2 => .{ .addrx = try reader.readInt(u16) }, - FORM.addrx3 => .{ .addrx = try reader.readInt(u24) }, - FORM.addrx4 => .{ .addrx = try reader.readInt(u32) }, - FORM.addrx => .{ .addrx = try reader.readUleb128(u64) }, + FORM.addrx1 => .{ .addrx = try reader.takeInt(u8, elf.endian) }, + FORM.addrx2 => .{ .addrx = try reader.takeInt(u16, elf.endian) }, + FORM.addrx3 => .{ .addrx = try reader.takeInt(u24, elf.endian) }, + FORM.addrx4 => .{ .addrx = try reader.takeInt(u32, elf.endian) }, + FORM.addrx => .{ .addrx = try reader.takeLeb128(u64) }, FORM.block1, FORM.block2, FORM.block4, FORM.block, - => .{ .block = try reader.readBytes(switch (form_id) { - FORM.block1 => try reader.readInt(u8), - FORM.block2 => try reader.readInt(u16), - FORM.block4 => try reader.readInt(u32), - FORM.block => try reader.readUleb128(u64), + => .{ .block = try reader.take(switch (form_id) { + FORM.block1 => try reader.takeInt(u8, elf.endian), + FORM.block2 => try reader.takeInt(u16, elf.endian), + FORM.block4 => try reader.takeInt(u32, elf.endian), + FORM.block => try reader.takeLeb128(u64), else => unreachable, }) }, - FORM.data1 => .{ .udata = try reader.readInt(u8) }, - FORM.data2 => .{ .udata = try reader.readInt(u16) }, - FORM.data4 => .{ .udata = try reader.readInt(u32) }, - FORM.data8 => .{ .udata = try reader.readInt(u64) }, - FORM.data16 => .{ .data16 = (try reader.readBytes(16))[0..16] }, - FORM.udata => .{ .udata = try reader.readUleb128(u64) }, - FORM.sdata => .{ .sdata = try reader.readIleb128(i64) }, - FORM.exprloc => .{ .exprloc = try reader.readBytes(try reader.readUleb128(u64)) }, - FORM.flag => .{ .flag = (try reader.readByte()) != 0 }, + FORM.data1 => .{ .udata = try reader.takeInt(u8, elf.endian) }, + FORM.data2 => .{ .udata = try reader.takeInt(u16, elf.endian) }, + FORM.data4 => .{ .udata = try reader.takeInt(u32, elf.endian) }, + FORM.data8 => .{ .udata = try reader.takeInt(u64, elf.endian) }, + FORM.data16 => .{ .data16 = (try reader.take(16))[0..16] }, + FORM.udata => .{ .udata = try reader.takeLeb128(u64) }, + FORM.sdata => .{ .sdata = try reader.takeLeb128(i64) }, + FORM.exprloc => .{ .exprloc = try reader.take(try reader.takeLeb128(u64)) }, + FORM.flag => .{ .flag = (try reader.takeByte()) != 0 }, FORM.flag_present => .{ .flag = true }, - FORM.sec_offset => .{ .sec_offset = try reader.readAddress(dwarf_format) }, - - FORM.ref1 => .{ .ref = try reader.readInt(u8) }, - FORM.ref2 => .{ .ref = try reader.readInt(u16) }, - FORM.ref4 => .{ .ref = try reader.readInt(u32) }, - FORM.ref8 => .{ .ref = try reader.readInt(u64) }, - FORM.ref_udata => .{ .ref = try reader.readUleb128(u64) }, - - FORM.ref_addr => .{ .ref_addr = try reader.readAddress(dwarf_format) }, - FORM.ref_sig8 => .{ .ref = try reader.readInt(u64) }, - - FORM.string => .{ .string = try reader.readBytesTo(0) }, - FORM.strp => .{ .strp = try reader.readAddress(dwarf_format) }, - FORM.strx1 => .{ .strx = try reader.readInt(u8) }, - FORM.strx2 => .{ .strx = try reader.readInt(u16) }, - FORM.strx3 => .{ .strx = try reader.readInt(u24) }, - FORM.strx4 => .{ .strx = try reader.readInt(u32) }, - FORM.strx => .{ .strx = try reader.readUleb128(u64) }, - FORM.line_strp => .{ .line_strp = try reader.readAddress(dwarf_format) }, + FORM.sec_offset => .{ .sec_offset = try read_address(reader, dwarf_format, elf.endian) }, + + FORM.ref1 => .{ .ref = try reader.takeInt(u8, elf.endian) }, + FORM.ref2 => .{ .ref = try reader.takeInt(u16, elf.endian) }, + FORM.ref4 => .{ .ref = try reader.takeInt(u32, elf.endian) }, + FORM.ref8 => .{ .ref = try reader.takeInt(u64, elf.endian) }, + FORM.ref_udata => .{ .ref = try reader.takeLeb128(u64) }, + + FORM.ref_addr => .{ .ref_addr = try read_address(reader, dwarf_format, elf.endian) }, + FORM.ref_sig8 => .{ .ref = try reader.takeInt(u64, elf.endian) }, + + FORM.string => .{ .string = try reader.takeSentinel(0) }, + FORM.strp => .{ .strp = try read_address(reader, dwarf_format, elf.endian) }, + FORM.strx1 => .{ .strx = try reader.takeInt(u8, elf.endian) }, + FORM.strx2 => .{ .strx = try reader.takeInt(u16, elf.endian) }, + FORM.strx3 => .{ .strx = try reader.takeInt(u24, elf.endian) }, + FORM.strx4 => .{ .strx = try reader.takeInt(u32, elf.endian) }, + FORM.strx => .{ .strx = try reader.takeLeb128(u64) }, + FORM.line_strp => .{ .line_strp = try read_address(reader, dwarf_format, elf.endian) }, FORM.implicit_const => .{ .sdata = implicit_const_val orelse return bad() }, - FORM.loclistx => .{ .loclistx = try reader.readUleb128(u64) }, - FORM.rnglistx => .{ .rnglistx = try reader.readUleb128(u64) }, + FORM.loclistx => .{ .loclistx = try reader.takeLeb128(u64) }, + FORM.rnglistx => .{ .rnglistx = try reader.takeLeb128(u64) }, else => { std.log.err("unimplemented form id: 0x{x}", .{form_id}); return unimplemented(); @@ -735,19 +728,11 @@ const Parser = struct { .string => |value| return value, .strp => |offset| { const data = sections.get(.@".debug_str") orelse return bad(); - var reader: std.debug.FixedBufferReader = .{ - .buf = data[offset..], - .endian = .little, - }; - return try reader.readBytesTo(0); + return std.mem.sliceTo(data[offset..], 0); }, .line_strp => |offset| { const data = sections.get(.@".debug_line_str") orelse return bad(); - var reader: std.debug.FixedBufferReader = .{ - .buf = data[offset..], - .endian = .little, - }; - return try reader.readBytesTo(0); + return std.mem.sliceTo(data[offset..], 0); }, .strx => |index| { _ = index; @@ -790,6 +775,13 @@ const Parser = struct { }; } }; + + fn read_address(reader: *std.Io.Reader, dwarf_format: dwarf.Format, endian: std.builtin.Endian) !u64 { + return switch (dwarf_format) { + .@"32" => try reader.takeInt(u32, endian), + .@"64" => try reader.takeInt(u64, endian), + }; + } }; fn bad() error{InvalidDebugInfo} { diff --git a/tools/printer/src/Elf.zig b/tools/printer/src/Elf.zig index a6cb89b67..c466aae79 100644 --- a/tools/printer/src/Elf.zig +++ b/tools/printer/src/Elf.zig @@ -2,6 +2,7 @@ const std = @import("std"); const Elf = @This(); +endian: std.builtin.Endian, format: Format, sections: Sections, loaded_regions: []const Region, @@ -34,18 +35,18 @@ pub const Region = struct { }; }; -pub fn init(allocator: std.mem.Allocator, source: anytype) !Elf { - var elf_header = try std.elf.Header.read(source); +pub fn init(allocator: std.mem.Allocator, file_reader: *std.fs.File.Reader) !Elf { + var elf_header = try std.elf.Header.read(&file_reader.interface); const format: Format = if (elf_header.is_64) .@"64" else .@"32"; const string_table_data = blk: { var shdr: std.elf.Elf64_Shdr = undefined; if (format == .@"32") { - var shdr32: std.elf.Elf32_Shdr = undefined; + // var shdr32: std.elf.Elf32_Shdr = undefined; const offset = elf_header.shoff + @sizeOf(std.elf.Elf32_Shdr) * elf_header.shstrndx; - try source.seekableStream().seekTo(offset); - try source.reader().readNoEof(std.mem.asBytes(&shdr32)); + try file_reader.seekTo(offset); + const shdr32 = try file_reader.interface.takeStruct(std.elf.Elf32_Shdr, elf_header.endian); shdr = .{ .sh_name = shdr32.sh_name, @@ -61,17 +62,12 @@ pub fn init(allocator: std.mem.Allocator, source: anytype) !Elf { }; } else { const offset = elf_header.shoff + @sizeOf(std.elf.Elf64_Shdr) * elf_header.shstrndx; - try source.seekableStream().seekTo(offset); - try source.reader().readNoEof(std.mem.asBytes(&shdr)); + try file_reader.seekTo(offset); + shdr = try file_reader.interface.takeStruct(std.elf.Elf64_Shdr, elf_header.endian); } - const section_data = try allocator.alloc(u8, shdr.sh_size); - errdefer allocator.free(section_data); - - try source.seekableStream().seekTo(shdr.sh_offset); - try source.reader().readNoEof(section_data); - - break :blk section_data; + try file_reader.seekTo(shdr.sh_offset); + break :blk try file_reader.interface.readAlloc(allocator, shdr.sh_size); }; defer allocator.free(string_table_data); @@ -83,26 +79,25 @@ pub fn init(allocator: std.mem.Allocator, source: anytype) !Elf { } } - var section_header_it = elf_header.section_header_iterator(source); + var section_header_it = elf_header.iterateSectionHeaders(file_reader); while (try section_header_it.next()) |shdr| { const name = std.mem.span(@as([*:0]const u8, @ptrCast(string_table_data[shdr.sh_name..]))); inline for (@typeInfo(SectionTypes).@"enum".fields) |section_field| { if (std.mem.eql(u8, name, section_field.name)) { - const section_data = try allocator.alloc(u8, shdr.sh_size); - errdefer allocator.free(section_data); + try file_reader.seekTo(shdr.sh_offset); - try source.seekableStream().seekTo(shdr.sh_offset); - try source.reader().readNoEof(section_data); + const section_data = try file_reader.interface.readAlloc(allocator, shdr.sh_size); + errdefer allocator.free(section_data); sections.put(@enumFromInt(section_field.value), section_data); } } } - var loaded_regions: std.ArrayListUnmanaged(Region) = .empty; + var loaded_regions: std.ArrayList(Region) = .empty; defer loaded_regions.deinit(allocator); - var program_header_iterator = elf_header.program_header_iterator(source); + var program_header_iterator = elf_header.iterateProgramHeaders(file_reader); while (try program_header_iterator.next()) |phdr| { if (phdr.p_type != std.elf.PT_LOAD) continue; @@ -118,6 +113,7 @@ pub fn init(allocator: std.mem.Allocator, source: anytype) !Elf { } return .{ + .endian = elf_header.endian, .format = format, .sections = sections, .loaded_regions = try loaded_regions.toOwnedSlice(allocator), diff --git a/tools/printer/src/main.zig b/tools/printer/src/main.zig index 770287c00..8f52e2616 100644 --- a/tools/printer/src/main.zig +++ b/tools/printer/src/main.zig @@ -1,8 +1,9 @@ const std = @import("std"); const printer = @import("printer"); -const Elf = printer.Elf; -const DebugInfo = printer.DebugInfo; -const Annotator = printer.Annotator; + +var elf_file_reader_buf: [1024]u8 = undefined; +var out_stream_buf: [1024]u8 = undefined; +var printer_writer_buf: [512]u8 = undefined; pub fn main() !void { var debug_allocator: std.heap.DebugAllocator(.{}) = .init; @@ -12,44 +13,46 @@ pub fn main() !void { const args = try std.process.argsAlloc(allocator); defer std.process.argsFree(allocator, args); - if (args.len <= 1) { - try std.io.getStdErr().writeAll("usage: ./printer elf_file [input_file]\n"); + if (args.len < 2) { + try std.fs.File.stderr().writeAll("usage: ./printer elf_file [input_file]\n"); std.process.exit(1); } const elf_file = try std.fs.cwd().openFile(args[1], .{}); defer elf_file.close(); + var elf_file_reader = elf_file.reader(&elf_file_reader_buf); - const input_file = if (args.len <= 2 or std.mem.eql(u8, args[2], "-")) - std.io.getStdIn() - else - try std.fs.cwd().openFile(args[2], .{}); - defer input_file.close(); - - var elf = try Elf.init(allocator, elf_file); + var elf = try printer.Elf.init(allocator, &elf_file_reader); defer elf.deinit(allocator); - var debug_info = try DebugInfo.init(allocator, elf); + var debug_info = try printer.DebugInfo.init(allocator, elf); defer debug_info.deinit(allocator); - const in_stream = input_file.reader(); + const input_file = if (args.len <= 2 or std.mem.eql(u8, args[2], "-")) + std.fs.File.stdin() + else + try std.fs.cwd().openFile(args[2], .{}); + defer input_file.close(); + var in_stream = input_file.reader(&.{}); - const stdout = std.io.getStdOut(); - const out_stream = stdout.writer(); + const stdout = std.fs.File.stdout(); + var out_stream = stdout.writer(&out_stream_buf); const out_tty_config = std.io.tty.detectConfig(stdout); - var buf: [1024]u8 = undefined; - var annotator: Annotator = .init; + var printer_writer: printer.Writer = .init( + &printer_writer_buf, + &out_stream.interface, + out_tty_config, + elf, + &debug_info, + ); while (true) { - const n = try in_stream.read(&buf); - - try annotator.process( - buf[0..n], - elf, - &debug_info, - out_stream, - out_tty_config, - ); + _ = try in_stream.interface.stream(&printer_writer.interface, .unlimited); + + // flush the writers + // TODO: Is there a better way to do this? + try printer_writer.interface.flush(); + try out_stream.interface.flush(); } } diff --git a/tools/printer/src/root.zig b/tools/printer/src/root.zig index 5781e0a00..49f2f2861 100644 --- a/tools/printer/src/root.zig +++ b/tools/printer/src/root.zig @@ -1,10 +1,86 @@ const std = @import("std"); +const Io = std.Io; pub const Elf = @import("Elf.zig"); pub const DebugInfo = @import("DebugInfo.zig"); -/// Takes data and displays it, as well as annotating addresses where it's -/// necessary. +// TODO: defmt +/// Forwards data to the output writer with annotated stack traces. +pub const Writer = struct { + interface: Io.Writer, + + annotator: Annotator = .init, + out_stream: *Io.Writer, + out_tty_config: std.io.tty.Config, + elf: Elf, + debug_info: *DebugInfo, + + pub fn init( + buffer: []u8, + out_stream: *Io.Writer, + out_tty_config: std.io.tty.Config, + elf: Elf, + debug_info: *DebugInfo, + ) Writer { + return .{ + .interface = init_interface(buffer), + .out_stream = out_stream, + .out_tty_config = out_tty_config, + .elf = elf, + .debug_info = debug_info, + }; + } + + pub fn init_interface(buffer: []u8) Io.Writer { + return .{ + .vtable = &.{ + .drain = drain, + .sendFile = Io.Writer.unimplementedSendFile, + }, + .buffer = buffer, + }; + } + + pub fn drain(io_w: *Io.Writer, data: []const []const u8, splat: usize) Io.Writer.Error!usize { + const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w)); + + var len: usize = 0; + + const buffered = io_w.buffered(); + if (buffered.len != 0) { + errdefer _ = io_w.consume(len); + + len += try w.process(buffered); + } + + for (data[0 .. data.len - 1]) |buf| { + if (buf.len == 0) continue; + + errdefer _ = io_w.consume(len); + + len += try w.process(buf); + } + + const pattern = data[data.len - 1]; + if (pattern.len == 0 or splat == 0) return io_w.consume(len); + + for (0..splat) |_| { + errdefer _ = io_w.consume(len); + + len += try w.process(pattern); + } + + return io_w.consume(len); + } + + fn process(w: *Writer, buf: []const u8) Io.Writer.Error!usize { + w.annotator.process(buf, w.out_stream, w.out_tty_config, w.elf, w.debug_info) catch + return error.WriteFailed; + return buf.len; + } +}; + +/// Stack traces annotator. pub const Annotator = struct { state: State, @@ -19,13 +95,14 @@ pub const Annotator = struct { print_address: u64, }; + /// Forwards data to the output writer with annotated stack traces. pub fn process( self: *Annotator, data: []const u8, + out_stream: *Io.Writer, + out_tty_config: std.io.tty.Config, elf: Elf, debug_info: *DebugInfo, - out_stream: anytype, - out_tty_config: std.io.tty.Config, ) !void { var index: usize = 0; @@ -100,7 +177,7 @@ pub const Annotator = struct { }; fn output_location_info( - out_stream: anytype, + out_stream: *Io.Writer, out_tty_config: std.io.tty.Config, address: u64, query_result: DebugInfo.QueryResult, @@ -108,7 +185,7 @@ fn output_location_info( try out_tty_config.setColor(out_stream, .bold); if (query_result.source_location) |src_loc| { - try out_stream.print("{s}:{}:{}", .{ + try out_stream.print("{f}:{}:{}", .{ std.fs.path.fmtJoin(&.{ src_loc.dir_path, src_loc.file_path }), src_loc.line, src_loc.column, @@ -130,7 +207,7 @@ fn output_location_info( } fn output_source_line( - out_stream: anytype, + out_stream: *Io.Writer, out_tty_config: std.io.tty.Config, src_loc: DebugInfo.ResolvedSourceLocation, ) !void { @@ -140,33 +217,37 @@ fn output_source_line( const file = dir.openFile(src_loc.file_path, .{}) catch return; defer file.close(); - var buf_reader = std.io.bufferedReader(file.reader()); - const in_stream = buf_reader.reader(); + var r_buf: [512]u8 = undefined; + var file_reader = file.reader(&r_buf); var line_count: u32 = 1; - var buf: [150]u8 = undefined; + var line_buf: [128]u8 = undefined; const src_line: struct { line: []const u8, too_long: bool, - } = loop: while (true) : (line_count += 1) { - var too_long = false; - - const line = in_stream.readUntilDelimiterOrEof(&buf, '\n') catch |err| switch (err) { - error.StreamTooLong => blk: { - try in_stream.skipUntilDelimiterOrEof('\n'); - too_long = true; - break :blk &buf; + } = while (line_count < src_loc.line) : (line_count += 1) { + _ = file_reader.interface.discardDelimiterInclusive('\n') catch |err| { + if (err == error.EndOfStream) { + return error.InvalidLineNumber; + } else { + return err; + } + }; + } else blk: { + const line = file_reader.interface.takeDelimiterExclusive('\n') catch |err| switch (err) { + error.EndOfStream => return error.InvalidLineNumber, + error.StreamTooLong => break :blk .{ + .line = &line_buf, + .too_long = true, }, else => return err, - } orelse return; + }; - if (src_loc.line == line_count) { - break :loop .{ - .line = line, - .too_long = too_long, - }; - } - } else return; + break :blk .{ + .line = line, + .too_long = false, + }; + }; try out_stream.print("{s}", .{src_line.line}); if (src_line.too_long) { @@ -177,7 +258,7 @@ fn output_source_line( if (src_loc.column > 0) { const space_needed = src_loc.column - 1; - try out_stream.writeByteNTimes(' ', space_needed); + try out_stream.splatByteAll(' ', space_needed); try out_tty_config.setColor(out_stream, .green); try out_stream.writeAll("^"); try out_tty_config.setColor(out_stream, .reset); diff --git a/tools/printer/tests/generate_test_data.zig b/tools/printer/tests/generate_test_data.zig index f74e2992d..f4e7b872c 100644 --- a/tools/printer/tests/generate_test_data.zig +++ b/tools/printer/tests/generate_test_data.zig @@ -29,7 +29,7 @@ pub fn main() !void { var test_data_file = try std.fs.cwd().createFile("tests/test_data.zon", .{}); defer test_data_file.close(); - var all_data: std.ArrayListUnmanaged(common.Data) = .empty; + var all_data: std.ArrayList(common.Data) = .empty; for (elf_paths) |elf_path| { const elf_file = try std.fs.cwd().openFile(elf_path, .{}); @@ -38,7 +38,7 @@ pub fn main() !void { const elf = try printer.Elf.init(allocator, elf_file); var debug_info = try printer.DebugInfo.init(allocator, elf); - var tests: std.ArrayListUnmanaged(common.Test) = .empty; + var tests: std.ArrayList(common.Test) = .empty; for (elf.loaded_regions) |region| { if (!region.flags.exec) continue; diff --git a/tools/printer/tests/test.zig b/tools/printer/tests/test.zig index 54fe1e634..05aef631d 100644 --- a/tools/printer/tests/test.zig +++ b/tools/printer/tests/test.zig @@ -17,7 +17,10 @@ pub fn main() !void { const elf_file = try std.fs.cwd().openFile(data.elf_path, .{}); defer elf_file.close(); - var elf = try printer.Elf.init(allocator, elf_file); + var buf: [4096]u8 = undefined; + var file_reader = elf_file.reader(&buf); + + var elf = try printer.Elf.init(allocator, &file_reader); defer elf.deinit(allocator); var debug_info = try printer.DebugInfo.init(allocator, elf); diff --git a/tools/regz-wizard/src/VirtualFilesystem.zig b/tools/regz-wizard/src/VirtualFilesystem.zig index 44ef01a1f..311a97e58 100644 --- a/tools/regz-wizard/src/VirtualFilesystem.zig +++ b/tools/regz-wizard/src/VirtualFilesystem.zig @@ -35,7 +35,7 @@ pub fn dir(fs: *VirtualFilesystem) Directory { } fn create_file(ctx: *anyopaque, path: []const u8, content: []const u8) Directory.CreateFileError!void { - const fs: *VirtualFilesystem = @alignCast(@ptrCast(ctx)); + const fs: *VirtualFilesystem = @ptrCast(@alignCast(ctx)); const path_copy = try fs.gpa.dupe(u8, path); const content_copy = try fs.gpa.dupe(u8, content); // TODO: clean up collisions diff --git a/tools/regz/build.zig b/tools/regz/build.zig index bc9312feb..58fe782d5 100644 --- a/tools/regz/build.zig +++ b/tools/regz/build.zig @@ -24,9 +24,11 @@ pub fn build(b: *Build) !void { const regz = b.addExecutable(.{ .name = "regz", - .root_source_file = b.path("src/main.zig"), - .target = target, - .optimize = optimize, + .root_module = b.createModule(.{ + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + }), }); regz.linkLibrary(libxml2_dep.artifact("xml2")); regz.root_module.addImport("sqlite", sqlite); @@ -49,8 +51,11 @@ pub fn build(b: *Build) !void { const contextualize_fields = b.addExecutable(.{ .name = "contextualize-fields", - .root_source_file = b.path("src/contextualize-fields.zig"), - .target = b.graph.host, + .root_module = b.createModule(.{ + .root_source_file = b.path("src/contextualize-fields.zig"), + .target = b.graph.host, + }), + .use_llvm = true, }); contextualize_fields.linkLibrary(libxml2_dep.artifact("xml2")); const contextualize_fields_run = b.addRunArtifact(contextualize_fields); @@ -62,8 +67,11 @@ pub fn build(b: *Build) !void { const characterize = b.addExecutable(.{ .name = "characterize", - .root_source_file = b.path("src/characterize.zig"), - .target = b.graph.host, + .root_module = b.createModule(.{ + .root_source_file = b.path("src/characterize.zig"), + .target = b.graph.host, + }), + .use_llvm = true, }); characterize.linkLibrary(libxml2_dep.artifact("xml2")); const characterize_run = b.addRunArtifact(characterize); @@ -71,9 +79,12 @@ pub fn build(b: *Build) !void { characterize_step.dependOn(&characterize_run.step); const tests = b.addTest(.{ - .root_source_file = b.path("src/Database.zig"), - .target = target, - .optimize = optimize, + .root_module = b.createModule(.{ + .root_source_file = b.path("src/Database.zig"), + .target = target, + .optimize = optimize, + }), + .use_llvm = true, }); tests.linkLibrary(libxml2_dep.artifact("xml2")); tests.root_module.addImport("sqlite", sqlite); diff --git a/tools/regz/build.zig.zon b/tools/regz/build.zig.zon index 2239315cf..0ad070686 100644 --- a/tools/regz/build.zig.zon +++ b/tools/regz/build.zig.zon @@ -11,12 +11,12 @@ }, .dependencies = .{ .libxml2 = .{ - .url = "git+https://github.com/mattnite/zig-build-libxml2.git#ab99b56cc3709d2008ebc005b096d85d2a03b462", - .hash = "N-V-__8AAF9angBT74NozogdqB-2vLldsWLcNYJD2TW9xSyF", + .url = "git+https://github.com/mattnite/zig-build-libxml2.git#5474281ad4d173ed298ee789c7dce4f5edb78e10", + .hash = "libxml2-0.0.0-Kr0Y1Ac4ngAiRuFTS2qMO9j-KZsD0PKFKKXoZjynTHLq", }, .sqlite = .{ - .url = "git+https://github.com/mattnite/zig-sqlite.git#4e554ab43095859e153a5652667fd8a4d697b223", - .hash = "sqlite-3.47.2-AAAAACdIpQC782FmpW8DylXC9FX3DNs91fjcoffHjlfZ", + .url = "git+https://github.com/vrischmann/zig-sqlite.git#812e0b51a11812c8ed712462e13c3743fb85f7e9", + .hash = "sqlite-3.48.0-F2R_a52ODgBD8xSs3fcLI3I3Axy3eZ2HmT2V3Giy9ETV", }, }, } diff --git a/tools/regz/src/Database.zig b/tools/regz/src/Database.zig index bdb01b311..fdf5a7d53 100644 --- a/tools/regz/src/Database.zig +++ b/tools/regz/src/Database.zig @@ -358,20 +358,21 @@ pub const StructLayout = enum { }; fn gen_field_list(comptime T: type, opts: struct { prefix: ?[]const u8 = null }) []const u8 { - var buf = std.BoundedArray(u8, 4096).init(0) catch unreachable; - const writer = buf.writer(); + var buf: [4096]u8 = undefined; + var fbs: std.Io.Writer = .fixed(&buf); + inline for (@typeInfo(T).@"struct".fields, 0..) |field, i| { if (i != 0) - writer.writeAll(", ") catch unreachable; + fbs.writeAll(", ") catch unreachable; if (opts.prefix) |prefix| - writer.print("{s}.", .{prefix}) catch unreachable; + fbs.print("{s}.", .{prefix}) catch unreachable; - writer.print("{s}", .{field.name}) catch unreachable; + fbs.print("{s}", .{field.name}) catch unreachable; } const buf_copy = buf; - return buf_copy.slice(); + return buf_copy[0..fbs.buffered().len]; } fn zig_type_to_sql_type(comptime T: type) []const u8 { @@ -393,7 +394,8 @@ fn gen_sql_table(comptime name: []const u8, comptime T: type) []const u8 { } fn gen_sql_table_impl(comptime name: []const u8, comptime T: type) ![]const u8 { - var buf = try std.BoundedArray(u8, 4096).init(0); + var buf: [4096]u8 = undefined; + var fbs: std.Io.Writer = .fixed(&buf); // check that primary key and foreign keys exist var primary_key_found = T.sql_opts.primary_key == null; @@ -408,41 +410,40 @@ fn gen_sql_table_impl(comptime name: []const u8, comptime T: type) ![]const u8 { assert(primary_key_found); - const writer = buf.writer(); - try writer.print("CREATE TABLE {s} (\n", .{name}); + try fbs.print("CREATE TABLE {s} (\n", .{name}); var first = true; inline for (info.@"struct".fields) |field| { if (first) { first = false; } else { - try writer.writeAll(",\n"); + try fbs.writeAll(",\n"); } - try writer.print(" {s}", .{field.name}); - try writer.print(" {s}", .{zig_type_to_sql_type(field.type)}); + try fbs.print(" {s}", .{field.name}); + try fbs.print(" {s}", .{zig_type_to_sql_type(field.type)}); const field_type_info = @typeInfo(field.type); if (field_type_info != .optional) - try writer.writeAll(" NOT NULL"); + try fbs.writeAll(" NOT NULL"); if (T.sql_opts.primary_key) |primary_key| { if (std.mem.eql(u8, primary_key.name, field.name)) { - try writer.writeAll(" PRIMARY KEY"); + try fbs.writeAll(" PRIMARY KEY"); if (primary_key.autoincrement) - try writer.writeAll(" AUTOINCREMENT"); + try fbs.writeAll(" AUTOINCREMENT"); } } } for (T.sql_opts.foreign_keys) |foreign_key| { - try writer.writeAll(",\n"); + try fbs.writeAll(",\n"); const field = for (@typeInfo(T).@"struct".fields) |field| { if (std.mem.eql(u8, field.name, foreign_key.name)) break field; } else unreachable; - try writer.print(" FOREIGN KEY ({s}) REFERENCES {s}(id) ON DELETE {s} ON UPDATE {s}\n", .{ + try fbs.print(" FOREIGN KEY ({s}) REFERENCES {s}(id) ON DELETE {s} ON UPDATE {s}\n", .{ foreign_key.name, (switch (@typeInfo(field.type)) { .optional => |opt| opt.child, @@ -455,10 +456,10 @@ fn gen_sql_table_impl(comptime name: []const u8, comptime T: type) ![]const u8 { // foreign keys - try writer.writeAll(");\n"); + try fbs.writeAll(");\n"); const buf_copy = buf; - return buf_copy.slice(); + return buf_copy[0..fbs.buffered().len]; } const schema: []const []const u8 = &.{ @@ -510,13 +511,8 @@ fn ID(comptime T: type, comptime table_name: []const u8) type { pub fn format( id: @This(), - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, + writer: *std.Io.Writer, ) !void { - _ = fmt; - _ = options; - const ID_Type = @TypeOf(id); try writer.print("{s}({})", .{ ID_Type.table, @intFromEnum(id) }); } @@ -618,7 +614,7 @@ fn exec(db: *Database, comptime query: []const u8, args: anytype) !void { db.sql.execDynamic(query, .{ .diags = &db.diags }, args) catch |err| { std.log.err("Failed Query:\n{s}", .{query}); if (err == error.SQLiteError) - std.log.err("{}", .{db.diags}); + std.log.err("{f}", .{db.diags}); return err; }; @@ -726,7 +722,7 @@ fn get_one(db: *Database, comptime T: type, comptime query: []const u8, args: an return db.sql.one(T, query, .{ .diags = &db.diags }, args) catch |err| { std.log.err("Failed Query:\n{s}", .{query}); if (err == error.SQLiteError) - std.log.err("{}", .{db.diags}); + std.log.err("{f}", .{db.diags}); return err; }; @@ -791,7 +787,7 @@ fn all(db: *Database, comptime T: type, comptime query: []const u8, allocator: A }) catch |err| { if (err == error.SQLiteError) { log.err("query failed: {s}", .{query}); - log.err("{}", .{db.diags}); + log.err("{f}", .{db.diags}); } return err; @@ -803,7 +799,7 @@ fn all(db: *Database, comptime T: type, comptime query: []const u8, allocator: A }, args) catch |err| { if (err == error.SQLiteError) { log.err("query failed: {s}", .{query}); - log.err("{}", .{db.diags}); + log.err("{f}", .{db.diags}); } return err; @@ -950,34 +946,34 @@ fn recursively_calculate_struct_size( /// is calculated to be zero, the nested struct field will not be reported. pub fn get_nested_struct_fields_with_calculated_size( db: *Database, - allocator: Allocator, + gpa: Allocator, struct_id: StructID, ) ![]NestedStructField { - var ret: std.ArrayList(NestedStructField) = .init(allocator); - defer ret.deinit(); + var ret: std.ArrayList(NestedStructField) = .empty; + defer ret.deinit(gpa); - const nested_struct_fields = try db.get_nested_struct_fields(allocator, struct_id); - defer allocator.free(nested_struct_fields); + const nested_struct_fields = try db.get_nested_struct_fields(gpa, struct_id); + defer gpa.free(nested_struct_fields); log.debug("nested_struct_fields.len={} struct_id={}", .{ nested_struct_fields.len, struct_id }); - var size_cache: std.AutoArrayHashMap(StructID, u64) = .init(allocator); + var size_cache: std.AutoArrayHashMap(StructID, u64) = .init(gpa); defer size_cache.deinit(); for (nested_struct_fields) |*nsf| { if (nsf.size_bytes != null) { - try ret.append(nsf.*); + try ret.append(gpa, nsf.*); continue; } var depth: u8 = 0; - const size_bytes = try db.recursively_calculate_struct_size(&depth, &size_cache, allocator, nsf.struct_id); + const size_bytes = try db.recursively_calculate_struct_size(&depth, &size_cache, gpa, nsf.struct_id); std.log.debug("Calculated struct size: struct_id={} size_bytes={}", .{ nsf.struct_id, size_bytes }); nsf.size_bytes = if (size_bytes > 0) size_bytes else continue; - try ret.append(nsf.*); + try ret.append(gpa, nsf.*); } - return ret.toOwnedSlice(); + return ret.toOwnedSlice(gpa); } pub fn get_struct_modes( @@ -1057,7 +1053,7 @@ pub fn get_enum( allocator: Allocator, id: EnumID, ) !Enum { - log.debug("get_enum: id={}", .{id}); + log.debug("get_enum: id={f}", .{id}); const query = std.fmt.comptimePrint("SELECT {s} FROM enums WHERE id = ?", .{ comptime gen_field_list(Enum, .{}), }); @@ -1387,7 +1383,7 @@ pub fn get_enum_by_name( struct_id: StructID, name: []const u8, ) !Enum { - log.debug("get_enum_by_name: struct_id={} name='{s}'", .{ struct_id, name }); + log.debug("get_enum_by_name: struct_id={f} name='{s}'", .{ struct_id, name }); const query = std.fmt.comptimePrint( \\SELECT {s} \\FROM enums @@ -1410,7 +1406,7 @@ pub fn get_enum_by_name( return err; }; - log.debug("get_enum_by_name: parent_id={} name='{s}'", .{ parent_id, name }); + log.debug("get_enum_by_name: parent_id={f} name='{s}'", .{ parent_id, name }); return db.one_alloc(Enum, allocator, query, .{ .struct_id = parent_id, .name = name, @@ -1457,7 +1453,7 @@ fn get_one_alloc( return db.sql.oneAlloc(T, allocator, query, .{ .diags = &db.diags }, args) catch |err| { log.err("Failed query:\n{s}", .{query}); if (err == error.SQLiteError) { - log.err("{}", .{db.diags}); + log.err("{f}", .{db.diags}); } return err; @@ -1513,7 +1509,7 @@ pub fn add_nested_struct_field( .count = opts.count, }); - log.debug("add_nested_struct_field: parent={} name='{s}' struct_id={} offset_bytes={} size_bytes={?} count={?}", .{ + log.debug("add_nested_struct_field: parent={f} name='{s}' struct_id={f} offset_bytes={} size_bytes={?} count={?}", .{ parent, opts.name, opts.struct_id, @@ -1552,7 +1548,7 @@ pub fn create_nested_struct( }); savepoint.commit(); - log.debug("created struct_decl: parent={} struct_id={} name='{s}' description='{?s}' size_bytes={?}", .{ + log.debug("created struct_decl: parent={f} struct_id={f} name='{s}' description='{?s}' size_bytes={?}", .{ parent, struct_id, opts.name, @@ -1607,7 +1603,7 @@ const CreateInterruptOptions = struct { }; pub fn create_interrupt(db: *Database, device_id: DeviceID, opts: CreateInterruptOptions) !InterruptID { - log.debug("create_interrupt: device_id={} name={s} idx={} desc={?s}", .{ + log.debug("create_interrupt: device_id={f} name={s} idx={} desc={?s}", .{ device_id, opts.name, opts.idx, @@ -1661,7 +1657,7 @@ pub fn create_peripheral(db: *Database, opts: CreatePeripheralOptions) !Peripher const peripheral_id: PeripheralID = @enumFromInt(db.sql.getLastInsertRowID()); savepoint.commit(); - log.debug("created {}: struct_id={?} name={s} size_bytes={?} desc={?s}", .{ + log.debug("created {f}: struct_id={f} name={s} size_bytes={?} desc={?s}", .{ peripheral_id, struct_id, opts.name, @@ -1684,7 +1680,7 @@ pub fn create_device_peripheral( device_id: DeviceID, opts: CreateDevicePeripheralOptions, ) !DevicePeripheralID { - log.debug("create_device_peripherals: device_id={} struct_id={} name={s} offset=0x{X} desc={?s}", .{ + log.debug("create_device_peripherals: device_id={f} struct_id={f} name={s} offset=0x{X} desc={?s}", .{ device_id, opts.struct_id, opts.name, @@ -1724,7 +1720,7 @@ pub const CreateModeOptions = struct { pub fn create_mode(db: *Database, parent: StructID, opts: CreateModeOptions) !ModeID { var savepoint = try db.sql.savepoint("create_mode"); defer savepoint.rollback(); - log.debug("create_mode: name={s} parent={}", .{ opts.name, parent }); + log.debug("create_mode: name={s} parent={f}", .{ opts.name, parent }); try db.exec( \\INSERT INTO modes @@ -1743,7 +1739,7 @@ pub fn create_mode(db: *Database, parent: StructID, opts: CreateModeOptions) !Mo savepoint.commit(); log.debug( - "created {}: struct_id={} name='{s}' value='{s}' qualifier='{s}'", + "created {f}: struct_id={f} name='{s}' value='{s}' qualifier='{s}'", .{ mode_id, parent, opts.name, opts.value, opts.qualifier }, ); @@ -1766,7 +1762,7 @@ pub const CreateRegisterOptions = struct { }; pub fn add_register_mode(db: *Database, register_id: RegisterID, mode_id: ModeID) !void { - log.debug("add_register_mode: mode_id={} register_id={}", .{ mode_id, register_id }); + log.debug("add_register_mode: mode_id={f} register_id={f}", .{ mode_id, register_id }); try db.exec( \\INSERT INTO register_modes \\ (register_id, mode_id) @@ -1811,7 +1807,7 @@ pub fn create_register(db: *Database, parent: StructID, opts: CreateRegisterOpti savepoint.commit(); - log.debug("created {}: name='{s}' parent_id={} offset_bytes={} size_bits={}", .{ + log.debug("created {f}: name='{s}' parent_id={f} offset_bytes={} size_bits={}", .{ register_id, opts.name, parent, @@ -1866,7 +1862,7 @@ pub fn add_register_field(db: *Database, parent: RegisterID, opts: AddStructFiel .id = parent, }); - log.debug("{} now has {}", .{ parent, struct_id }); + log.debug("{f} now has {f}", .{ parent, struct_id }); break :blk struct_id; }; @@ -1896,7 +1892,7 @@ pub fn add_struct_field(db: *Database, parent: StructID, opts: AddStructFieldOpt savepoint.commit(); - log.debug("add_struct_field: parent={} name='{s}' offset_bits={} size_bits={} enum_id={?} count={?} stride={?}", .{ + log.debug("add_struct_field: parent={f} name='{s}' offset_bits={} size_bits={} enum_id={?f} count={?} stride={?}", .{ parent, opts.name, opts.offset_bits, @@ -1932,7 +1928,7 @@ pub fn create_enum(db: *Database, struct_id: ?StructID, opts: CreateEnumOptions) const enum_id: EnumID = @enumFromInt(db.sql.getLastInsertRowID()); savepoint.commit(); - log.debug("created {}: struct_id={?} name='{?s}' description='{?s}' size_bits={}", .{ + log.debug("created {f}: struct_id={?f} name='{?s}' description='{?s}' size_bits={}", .{ enum_id, struct_id, opts.name, @@ -1974,7 +1970,7 @@ pub fn create_struct(db: *Database, opts: CreateStructOptions) !StructID { const struct_id: StructID = @enumFromInt(db.sql.getLastInsertRowID()); savepoint.commit(); - log.debug("created {}", .{struct_id}); + log.debug("created {f}", .{struct_id}); return struct_id; } @@ -2111,17 +2107,17 @@ pub fn cleanup_unused_enums(db: *Database) !void { } pub fn apply_patch(db: *Database, ndjson: []const u8) !void { - var list = std.ArrayList(std.json.Parsed(Patch)).init(db.gpa); + var list: std.ArrayList(std.json.Parsed(Patch)) = .empty; defer { for (list.items) |*entry| entry.deinit(); - list.deinit(); + list.deinit(db.gpa); } var line_it = std.mem.tokenizeScalar(u8, ndjson, '\n'); while (line_it.next()) |line| { const p = try Patch.from_json_str(db.gpa, line); errdefer p.deinit(); - try list.append(p); + try list.append(db.gpa, p); } for (list.items) |patch| { diff --git a/tools/regz/src/FS_Directory.zig b/tools/regz/src/FS_Directory.zig index b66ca56a7..69e0bd8e5 100644 --- a/tools/regz/src/FS_Directory.zig +++ b/tools/regz/src/FS_Directory.zig @@ -5,7 +5,7 @@ const vtable = Directory.VTable{ }; pub fn create_file(ctx: *anyopaque, filename: []const u8, contents: []const u8) Directory.CreateFileError!void { - const fs: *FS_Directory = @alignCast(@ptrCast(ctx)); + const fs: *FS_Directory = @ptrCast(@alignCast(ctx)); const file: std.fs.File = if (std.fs.path.dirname(filename)) |dirname| blk: { var dir = fs.dir.makeOpenPath(dirname, .{}) catch return error.System; defer dir.close(); diff --git a/tools/regz/src/arch/arm.zig b/tools/regz/src/arch/arm.zig index 88123f7b8..bb506845c 100644 --- a/tools/regz/src/arch/arm.zig +++ b/tools/regz/src/arch/arm.zig @@ -130,7 +130,7 @@ pub fn write_interrupt_vector( if (interrupt.description) |description| try gen.write_doc_comment(db.gpa, description, writer); - try writer.print("{}: Handler = unhandled,\n", .{ + try writer.print("{f}: Handler = unhandled,\n", .{ std.zig.fmtId(interrupt.name), }); diff --git a/tools/regz/src/arch/arm/nvic.zig b/tools/regz/src/arch/arm/nvic.zig index ee5c94f3c..f31f9a732 100644 --- a/tools/regz/src/arch/arm/nvic.zig +++ b/tools/regz/src/arch/arm/nvic.zig @@ -108,7 +108,7 @@ pub fn load(db: *Database, device_id: EntityId) !void { // TODO: cpu module specific NVIC registers // destroy registers that line up with NVIC registers - var unique_peripherals = std.ArrayList(EntityId).init(db.gpa); + var unique_peripherals = std.array_list.Managed(EntityId).init(db.gpa); defer unique_peripherals.deinit(); for (db.types.peripherals.keys()) |peripheral_id| outer: { diff --git a/tools/regz/src/arch/avr.zig b/tools/regz/src/arch/avr.zig index 174988da3..460eef32b 100644 --- a/tools/regz/src/arch/avr.zig +++ b/tools/regz/src/arch/avr.zig @@ -50,7 +50,7 @@ pub fn write_interrupt_vector( if (interrupt.description) |description| try gen.write_doc_comment(arena, description, writer); - try writer.print("{}: Handler = unhandled,\n", .{ + try writer.print("{f}: Handler = unhandled,\n", .{ std.zig.fmtId(interrupt.name), }); diff --git a/tools/regz/src/arch/riscv.zig b/tools/regz/src/arch/riscv.zig index 81a56323d..654003ac2 100644 --- a/tools/regz/src/arch/riscv.zig +++ b/tools/regz/src/arch/riscv.zig @@ -98,7 +98,7 @@ pub fn write_interrupt_vector( if (interrupt.description) |description| try gen.write_doc_comment(db.gpa, description, writer); - try writer.print("{}: Handler = unhandled,\n", .{ + try writer.print("{f}: Handler = unhandled,\n", .{ std.zig.fmtId(interrupt.name), }); diff --git a/tools/regz/src/atdf.zig b/tools/regz/src/atdf.zig index 073720e8c..004cbf7b3 100644 --- a/tools/regz/src/atdf.zig +++ b/tools/regz/src/atdf.zig @@ -25,7 +25,7 @@ const InterruptGroupEntry = struct { const Context = struct { db: *Database, arena: std.heap.ArenaAllocator, - interrupt_groups: std.StringHashMapUnmanaged(std.ArrayListUnmanaged(InterruptGroupEntry)) = .{}, + interrupt_groups: std.StringHashMapUnmanaged(std.ArrayList(InterruptGroupEntry)) = .empty, inferred_register_group_offsets: std.AutoArrayHashMapUnmanaged(StructID, u64) = .{}, fn init(db: *Database) Context { @@ -270,8 +270,8 @@ fn infer_enum_size(allocator: Allocator, module_node: xml.Node, value_group_node break :blk max_value; }; - var field_sizes = std.ArrayList(u64).init(allocator); - defer field_sizes.deinit(); + var field_sizes: std.ArrayList(u64) = .empty; + defer field_sizes.deinit(allocator); var register_it = module_node.iterate(&.{"register-group"}, &.{"register"}); while (register_it.next()) |register_node| { @@ -282,7 +282,7 @@ fn infer_enum_size(allocator: Allocator, module_node: xml.Node, value_group_node log.debug("found values={s}", .{values}); const mask_str = bitfield_node.get_attribute("mask") orelse continue; const mask = try std.fmt.parseInt(u64, mask_str, 0); - try field_sizes.append(@popCount(mask)); + try field_sizes.append(allocator, @popCount(mask)); // TODO: assert consecutive } } @@ -418,7 +418,7 @@ fn load_register_group_children( var mode_it = node.iterate(&.{}, &.{"mode"}); while (mode_it.next()) |mode_node| load_mode(ctx, mode_node, parent) catch |err| { - log.err("{}: failed to load mode: {}", .{ parent, err }); + log.err("{f}: failed to load mode: {}", .{ parent, err }); return err; }; @@ -438,7 +438,7 @@ fn load_nested_register_group( parent: StructID, ) !void { const db = ctx.db; - log.debug("load_nested_register_group: peripheral={} parent={}", .{ peripheral, parent }); + log.debug("load_nested_register_group: peripheral={f} parent={f}", .{ peripheral, parent }); validate_attrs(node, &.{ "name", @@ -453,9 +453,9 @@ fn load_nested_register_group( const name_in_module = node.get_attribute("name-in-module") orelse return error.MissingNameInModule; const peripheral_struct_id = try db.get_peripheral_struct(peripheral); - log.debug(" peripheral_struct_id={}", .{peripheral_struct_id}); + log.debug(" peripheral_struct_id={f}", .{peripheral_struct_id}); const struct_id = try db.get_struct_decl_id_by_name(peripheral_struct_id, name_in_module); - log.debug(" struct_id={}", .{struct_id}); + log.debug(" struct_id={f}", .{struct_id}); try db.add_nested_struct_field(parent, .{ .name = name, @@ -489,7 +489,7 @@ fn infer_register_group_offset(ctx: *Context, node: xml.Node, struct_id: StructI if (min) |m| { try ctx.inferred_register_group_offsets.put(ctx.arena.allocator(), struct_id, m); - log.debug("inferred offset of {}: {} bytes", .{ struct_id, m }); + log.debug("inferred offset of {f}: {} bytes", .{ struct_id, m }); } } @@ -556,7 +556,7 @@ fn assign_modes_to_register( parent: StructID, mode_names: []const u8, ) !void { - log.debug("assigning mode_names='{s}' to {} from {}", .{ mode_names, register_id, parent }); + log.debug("assigning mode_names='{s}' to {f} from {f}", .{ mode_names, register_id, parent }); const db = ctx.db; const modes = try db.get_struct_modes(ctx.arena.allocator(), parent); @@ -583,7 +583,7 @@ fn load_register( parent: StructID, ) !void { const db = ctx.db; - log.debug("load_register: parent={}", .{parent}); + log.debug("load_register: parent={f}", .{parent}); validate_attrs(node, &.{ "rw", @@ -605,7 +605,7 @@ fn load_register( const name = node.get_attribute("name") orelse return error.MissingRegisterName; const register_group_offset = ctx.inferred_register_group_offsets.get(parent) orelse 0; - log.debug("{} inferred offset: {}", .{ parent, register_group_offset }); + log.debug("{f} inferred offset: {}", .{ parent, register_group_offset }); const register_id = try db.create_register(parent, .{ .name = name, @@ -824,7 +824,7 @@ fn load_enum( .size_bits = size_bits, }); - log.debug("{}: name={s} inferred_size={}", .{ enum_id, name, size_bits }); + log.debug("{f}: name={s} inferred_size={}", .{ enum_id, name, size_bits }); var value_it = node.iterate(&.{}, &.{"value"}); while (value_it.next()) |value_node| @@ -884,7 +884,7 @@ fn load_module_instances( fn peripheral_is_inlined(ctx: *Context, struct_id: StructID) !bool { // inlined peripherals do not have any register groups const struct_decls = try ctx.db.get_struct_decls(ctx.arena.allocator(), struct_id); - log.debug("{} has {} struct decls. Is inlined: {}", .{ struct_id, struct_decls.len, struct_decls.len == 0 }); + log.debug("{f} has {} struct decls. Is inlined: {}", .{ struct_id, struct_decls.len, struct_decls.len == 0 }); return (struct_decls.len == 0); } diff --git a/tools/regz/src/characterize.zig b/tools/regz/src/characterize.zig index 127091882..45959c59a 100644 --- a/tools/regz/src/characterize.zig +++ b/tools/regz/src/characterize.zig @@ -62,7 +62,7 @@ pub fn main() !void { try recursive_characterize(&arena, root_element, &.{}, &found, &results); } - var ordered = std.ArrayList(PrintedResult).init(gpa.allocator()); + var ordered = std.array_list.Managed(PrintedResult).init(gpa.allocator()); defer { for (ordered.items) |*item| item.attrs.deinit(gpa.allocator()); @@ -125,7 +125,7 @@ fn recursive_characterize( results: *Results, ) CharacterizeError!void { const allocator = arena.child_allocator; - var location = std.ArrayList([]const u8).init(allocator); + var location = std.array_list.Managed([]const u8).init(allocator); defer location.deinit(); if (node.name) |name| { diff --git a/tools/regz/src/contextualize-fields.zig b/tools/regz/src/contextualize-fields.zig index 88ec3dd6b..439bc96b7 100644 --- a/tools/regz/src/contextualize-fields.zig +++ b/tools/regz/src/contextualize-fields.zig @@ -20,7 +20,7 @@ pub fn main() !void { if (args.next() != null) return error.TooManyArgs; - var components = std.ArrayList([]const u8).init(gpa.allocator()); + var components = std.array_list.Managed([]const u8).init(gpa.allocator()); defer components.deinit(); { diff --git a/tools/regz/src/embassy.zig b/tools/regz/src/embassy.zig index 037c7282e..2bec6b7db 100644 --- a/tools/regz/src/embassy.zig +++ b/tools/regz/src/embassy.zig @@ -156,11 +156,11 @@ pub fn load_into_db(db: *Database, path: []const u8) !void { const allocator = arena.allocator(); - var chip_files = std.ArrayList(std.json.Parsed(ChipFile)).init(allocator); + var chip_files: std.ArrayList(std.json.Parsed(ChipFile)) = .empty; defer { for (chip_files.items) |chip_file| chip_file.deinit(); - chip_files.deinit(); + chip_files.deinit(allocator); } var register_files = std.StringArrayHashMap(std.json.Parsed(std.json.Value)).init(allocator); @@ -198,7 +198,7 @@ pub fn load_into_db(db: *Database, path: []const u8) !void { }); errdefer chips_file.deinit(); - try chip_files.append(chips_file); + try chip_files.append(allocator, chips_file); } var registers_dir = try data_dir.openDir("registers", .{ .iterate = true }); diff --git a/tools/regz/src/gen.zig b/tools/regz/src/gen.zig index d6a05978c..5b1a9445d 100644 --- a/tools/regz/src/gen.zig +++ b/tools/regz/src/gen.zig @@ -47,7 +47,7 @@ fn write_device_files( } } -fn write_imports(opts: ToZigOptions, types_public: bool, types_path: []const u8, writer: anytype) !void { +fn write_imports(opts: ToZigOptions, types_public: bool, types_path: []const u8, writer: *std.Io.Writer) !void { const public: []const u8 = if (types_public) "pub" else ""; if (opts.for_microzig) { try writer.print( @@ -75,10 +75,9 @@ fn write_device_file( dir: Directory, opts: ToZigOptions, ) !void { - var buffer = std.ArrayList(u8).init(arena); - defer buffer.deinit(); + var buf: std.Io.Writer.Allocating = .init(arena); + const writer = &buf.writer; - const writer = buffer.writer(); if (device.description) |description| { try write_file_comment(arena, description, writer); } @@ -99,7 +98,7 @@ fn write_device_file( if (properties.len > 0) { try writer.writeAll("pub const properties = struct {\n"); for (properties) |prop| { - try writer.print("pub const {} = ", .{ + try writer.print("pub const {f} = ", .{ std.zig.fmtId(prop.key), }); @@ -128,27 +127,31 @@ fn write_device_file( try writer.writeAll("};\n"); } - try buffer.writer().writeByte(0); - var ast = try std.zig.Ast.parse(arena, buffer.items[0 .. buffer.items.len - 1 :0], .zig); + try writer.writeByte(0); + + var ast = try std.zig.Ast.parse(arena, to_zero_sentinel(buf.written()), .zig); defer ast.deinit(arena); if (ast.errors.len > 0) { - log.err("Failed to parse:\n{s}", .{buffer.items}); + log.err("Failed to parse:\n{s}", .{buf.written()}); //try out_writer.writeAll(buffer.items); for (ast.errors) |err| { std.log.err("err: {}", .{err}); - var err_msg = std.ArrayList(u8).init(arena); + var err_msg: std.Io.Writer.Allocating = .init(arena); defer err_msg.deinit(); - try ast.renderError(err, err_msg.writer()); - std.log.err(" {s}", .{err_msg.items}); + try ast.renderError(err, &err_msg.writer); + std.log.err(" {s}", .{err_msg.written()}); } return error.FailedToParse; } - const text = try ast.render(arena); + var rendered_buffer: std.Io.Writer.Allocating = .init(arena); + const fixups: std.zig.Ast.Render.Fixups = .{}; + try ast.render(arena, &rendered_buffer.writer, fixups); + const filename = try std.fmt.allocPrint(arena, "{s}.zig", .{device.name}); - try dir.create_file(filename, text); + try dir.create_file(filename, rendered_buffer.written()); } fn write_types_files(db: *Database, arena: Allocator, dir: Directory, opts: ToZigOptions) !void { @@ -161,12 +164,14 @@ fn write_types_files(db: *Database, arena: Allocator, dir: Directory, opts: ToZi } fn write_peripherals_files(db: *Database, arena: Allocator, dir: Directory, opts: ToZigOptions) !void { - var index_content = std.ArrayList(u8).init(arena); - const index_writer = index_content.writer(); + var index_content: std.Io.Writer.Allocating = .init(arena); + const index_writer = &index_content.writer; + const peripherals = try db.get_peripherals(arena); for (peripherals) |peripheral| { - var periph_content = std.ArrayList(u8).init(arena); - const writer = periph_content.writer(); + var periph_content: std.Io.Writer.Allocating = .init(arena); + const writer = &periph_content.writer; + try write_imports(opts, false, "../../types.zig", writer); write_peripheral(db, arena, &peripheral, writer) catch |err| { log.warn("failed to generate peripheral '{s}': {}", .{ @@ -182,15 +187,18 @@ fn write_peripherals_files(db: *Database, arena: Allocator, dir: Directory, opts }); try writer.writeByte(0); - var ast = try std.zig.Ast.parse(arena, periph_content.items[0 .. periph_content.items.len - 1 :0], .zig); + var ast = try std.zig.Ast.parse(arena, to_zero_sentinel(periph_content.written()), .zig); defer ast.deinit(arena); - const text = try ast.render(arena); - try dir.create_file(path, text); + var rendered_buffer: std.Io.Writer.Allocating = .init(arena); + const fixups: std.zig.Ast.Render.Fixups = .{}; + try ast.render(arena, &rendered_buffer.writer, fixups); + + try dir.create_file(path, rendered_buffer.written()); if (try db.struct_is_zero_sized(arena, peripheral.struct_id)) { try index_writer.print( - \\pub const {} = @import("peripherals/{s}.zig"); + \\pub const {f} = @import("peripherals/{s}.zig"); \\ , .{ std.zig.fmtId(peripheral.name), @@ -198,7 +206,7 @@ fn write_peripherals_files(db: *Database, arena: Allocator, dir: Directory, opts }); } else { try index_writer.print( - \\pub const {} = @import("peripherals/{s}.zig").{}; + \\pub const {f} = @import("peripherals/{s}.zig").{f}; \\ , .{ std.zig.fmtId(peripheral.name), @@ -208,24 +216,25 @@ fn write_peripherals_files(db: *Database, arena: Allocator, dir: Directory, opts } } - try dir.create_file("types/peripherals.zig", index_content.items); + try dir.create_file("types/peripherals.zig", index_content.written()); } -pub fn write_file_comment(allocator: Allocator, comment: []const u8, writer: anytype) !void { +pub fn write_file_comment(allocator: Allocator, comment: []const u8, writer: *std.Io.Writer) !void { try write_comment(allocator, "//!", comment, writer); } -pub fn write_doc_comment(allocator: Allocator, comment: []const u8, writer: anytype) !void { +pub fn write_doc_comment(allocator: Allocator, comment: []const u8, writer: *std.Io.Writer) !void { try write_comment(allocator, "///", comment, writer); } -pub fn write_regular_comment(allocator: Allocator, comment: []const u8, writer: anytype) !void { +pub fn write_regular_comment(allocator: Allocator, comment: []const u8, writer: *std.Io.Writer) !void { try write_comment(allocator, "//", comment, writer); } -fn write_comment(allocator: Allocator, comptime comment_prefix: []const u8, comment: []const u8, writer: anytype) !void { - var tokenized = std.ArrayList(u8).init(allocator); +fn write_comment(allocator: Allocator, comptime comment_prefix: []const u8, comment: []const u8, writer: *std.Io.Writer) !void { + var tokenized: std.Io.Writer.Allocating = .init(allocator); defer tokenized.deinit(); + const tokenized_writer = &tokenized.writer; var first = true; var tok_it = std.mem.tokenizeAny(u8, comment, "\n\r \t"); @@ -233,12 +242,12 @@ fn write_comment(allocator: Allocator, comptime comment_prefix: []const u8, comm if (!first) first = false else - try tokenized.writer().writeByte(' '); + try tokenized_writer.writeByte(' '); - try tokenized.writer().writeAll(token); + try tokenized_writer.writeAll(token); } - const unescaped = try std.mem.replaceOwned(u8, allocator, tokenized.items, "\\n", "\n"); + const unescaped = try std.mem.replaceOwned(u8, allocator, tokenized.written(), "\\n", "\n"); defer allocator.free(unescaped); var line_it = std.mem.tokenizeScalar(u8, unescaped, '\n'); @@ -246,7 +255,7 @@ fn write_comment(allocator: Allocator, comptime comment_prefix: []const u8, comm try writer.print("{s}{s}\n", .{ comment_prefix, line }); } -fn write_string(str: []const u8, writer: anytype) !void { +fn write_string(str: []const u8, writer: *std.Io.Writer) !void { if (std.mem.containsAtLeast(u8, str, 1, "\n")) { try writer.writeByte('\n'); var line_it = std.mem.splitScalar(u8, str, '\n'); @@ -257,11 +266,10 @@ fn write_string(str: []const u8, writer: anytype) !void { } } -fn write_device(db: *Database, arena: Allocator, device: *const Database.Device, out_writer: anytype) !void { - var buffer = std.ArrayList(u8).init(arena); - defer buffer.deinit(); +fn write_device(db: *Database, arena: Allocator, device: *const Database.Device, out_writer: *std.Io.Writer) !void { + var buf: std.Io.Writer.Allocating = .init(arena); + const writer = &buf.writer; - const writer = buffer.writer(); if (device.description) |description| { try write_doc_comment(arena, description, writer); } @@ -306,7 +314,7 @@ fn write_device(db: *Database, arena: Allocator, device: *const Database.Device, try writer.writeAll("};\n"); - try out_writer.writeAll(buffer.items); + try out_writer.writeAll(buf.written()); } const TypeID = union(enum) { @@ -318,8 +326,8 @@ const TypeID = union(enum) { // code. Since this is only used in code generation, just going to stuff it in // the arena allocator fn types_reference(db: *Database, allocator: Allocator, type_id: TypeID) ![]const u8 { - var full_name_components = std.ArrayList([]const u8).init(allocator); - defer full_name_components.deinit(); + var full_name_components: std.ArrayList([]const u8) = .empty; + defer full_name_components.deinit(allocator); var current_id = type_id; @@ -342,7 +350,7 @@ fn types_reference(db: *Database, allocator: Allocator, type_id: TypeID) ![]cons const name_copy = try allocator.dupe(u8, e.name.?); errdefer allocator.free(name_copy); - try full_name_components.insert(0, name_copy); + try full_name_components.insert(allocator, 0, name_copy); }, .@"struct" => |id| if (try db.get_struct_decl(allocator, id)) |struct_decl| { defer struct_decl.deinit(allocator); @@ -351,7 +359,7 @@ fn types_reference(db: *Database, allocator: Allocator, type_id: TypeID) ![]cons const name_copy = try allocator.dupe(u8, struct_decl.name); errdefer allocator.free(name_copy); - try full_name_components.insert(0, name_copy); + try full_name_components.insert(allocator, 0, name_copy); current_id = .{ .@"struct" = struct_decl.parent_id }; } else if (try db.get_peripheral_by_struct_id(allocator, id)) |peripheral| { defer peripheral.deinit(allocator); @@ -359,7 +367,7 @@ fn types_reference(db: *Database, allocator: Allocator, type_id: TypeID) ![]cons const name_copy = try allocator.dupe(u8, peripheral.name); errdefer allocator.free(name_copy); - try full_name_components.insert(0, name_copy); + try full_name_components.insert(allocator, 0, name_copy); break; } else @panic("A struct should have some sort of decl entry"), } @@ -368,31 +376,29 @@ fn types_reference(db: *Database, allocator: Allocator, type_id: TypeID) ![]cons if (full_name_components.items.len == 0) return error.CantReference; - var full_name = std.ArrayList(u8).init(allocator); + var full_name: std.Io.Writer.Allocating = .init(allocator); defer full_name.deinit(); + const writer = &full_name.writer; - const writer = full_name.writer(); try writer.writeAll("types.peripherals"); for (full_name_components.items) |component| - try writer.print(".{}", .{ + try writer.print(".{f}", .{ std.zig.fmtId(component), }); - log.debug("generated type ref: {s}", .{full_name.items}); - return full_name.toOwnedSlice(); + log.debug("generated type ref: {s}", .{full_name.written()}); + return try full_name.toOwnedSlice(); } fn write_interrupt_list( db: *Database, arena: Allocator, device: *const Device, - out_writer: anytype, + out_writer: *std.Io.Writer, ) !void { - var buffer = std.ArrayList(u8).init(arena); - defer buffer.deinit(); - - const writer = buffer.writer(); + var buf: std.Io.Writer.Allocating = .init(arena); + const writer = &buf.writer; const interrupts = try db.get_interrupts(arena, device.id); defer { @@ -449,19 +455,17 @@ fn write_interrupt_list( try writer.writeAll("};\n"); } - try out_writer.writeAll(buffer.items); + try out_writer.writeAll(buf.written()); } fn write_vector_table( db: *Database, arena: Allocator, device: *const Device, - out_writer: anytype, + out_writer: *std.Io.Writer, ) !void { - var buffer = std.ArrayList(u8).init(arena); - defer buffer.deinit(); - - const writer = buffer.writer(); + var buf: std.Io.Writer.Allocating = .init(arena); + const writer = &buf.writer; if (device.arch.is_arm()) try arm.write_interrupt_vector(db, arena, device, writer) @@ -474,7 +478,7 @@ fn write_vector_table( else unreachable; - try out_writer.writeAll(buffer.items); + try out_writer.writeAll(buf.written()); } fn get_device_peripheral_description( @@ -496,13 +500,13 @@ fn write_device_peripheral( db: *Database, arena: Allocator, instance: *const DevicePeripheral, - out_writer: anytype, + out_writer: *std.Io.Writer, ) !void { log.debug("writing periph instance", .{}); - var buffer = std.ArrayList(u8).init(arena); - defer buffer.deinit(); - const writer = buffer.writer(); + var buf: std.Io.Writer.Allocating = .init(arena); + const writer = &buf.writer; + const type_ref = try types_reference(db, arena, .{ .@"struct" = instance.struct_id }); if (try get_device_peripheral_description(db, arena, instance)) |description| @@ -518,14 +522,14 @@ fn write_device_peripheral( else ""; - try writer.print("pub const {}: *volatile {s}{s} = @ptrFromInt(0x{x});\n", .{ + try writer.print("pub const {f}: *volatile {s}{s} = @ptrFromInt(0x{x});\n", .{ std.zig.fmtId(instance.name), array_prefix, type_ref, instance.offset_bytes, }); - try out_writer.writeAll(buffer.items); + try out_writer.writeAll(buf.written()); } fn write_struct( @@ -533,7 +537,7 @@ fn write_struct( arena: Allocator, block_size_bytes: ?u64, struct_id: StructID, - writer: anytype, + writer: *std.Io.Writer, ) anyerror!void { const registers = try db.get_struct_registers(arena, struct_id); const nested_struct_fields = try db.get_nested_struct_fields_with_calculated_size(arena, struct_id); @@ -558,7 +562,7 @@ fn write_struct_body( arena: Allocator, block_size_bytes: ?u64, struct_id: StructID, - writer: anytype, + writer: *std.Io.Writer, ) !void { const registers = try db.get_struct_registers(arena, struct_id); const nested_struct_fields = try db.get_nested_struct_fields_with_calculated_size(arena, struct_id); @@ -601,31 +605,32 @@ fn write_struct_decl( description: ?[]const u8, block_size_bytes: ?u64, struct_id: StructID, - out_writer: anytype, + out_writer: *std.Io.Writer, ) !void { log.debug("writing struct decl: name='{s}'", .{name}); - var buffer = std.ArrayList(u8).init(arena); - defer buffer.deinit(); - const writer = buffer.writer(); + var buf: std.Io.Writer.Allocating = .init(arena); + const writer = &buf.writer; + try writer.writeByte('\n'); if (description) |d| try write_doc_comment(arena, d, writer); - try writer.print("pub const {} = ", .{ + try writer.print("pub const {f} = ", .{ std.zig.fmtId(name), }); try write_struct(db, arena, block_size_bytes, struct_id, writer); try writer.writeAll(";\n"); - try out_writer.writeAll(buffer.items); + + try out_writer.writeAll(buf.written()); } fn write_peripheral( db: *Database, arena: Allocator, peripheral: *const Peripheral, - out_writer: anytype, + out_writer: *std.Io.Writer, ) !void { log.debug("writing peripheral: name='{s}'", .{peripheral.name}); if (try db.struct_is_zero_sized(arena, peripheral.struct_id)) { @@ -649,18 +654,16 @@ fn write_peripheral( } } -fn write_newline_if_written(writer: anytype, written: *bool) !void { +fn write_newline_if_written(writer: *std.Io.Writer, written: *bool) !void { if (written.*) try writer.writeByte('\n') else written.* = true; } -fn write_enum(db: *Database, arena: Allocator, e: *const Enum, out_writer: anytype) !void { - var buffer = std.ArrayList(u8).init(arena); - defer buffer.deinit(); - - const writer = buffer.writer(); +fn write_enum(db: *Database, arena: Allocator, e: *const Enum, out_writer: *std.Io.Writer) !void { + var buf: std.Io.Writer.Allocating = .init(arena); + const writer = &buf.writer; // TODO: handle this instead of assert // assert(std.math.ceilPowerOfTwo(field_set.count()) <= size); @@ -668,21 +671,20 @@ fn write_enum(db: *Database, arena: Allocator, e: *const Enum, out_writer: anyty if (e.description) |description| try write_doc_comment(arena, description, writer); - try writer.print("pub const {} = enum(u{}) {{\n", .{ + try writer.print("pub const {f} = enum(u{}) {{\n", .{ std.zig.fmtId(e.name.?), e.size_bits, }); try write_enum_fields(db, arena, e, writer); try writer.writeAll("};\n"); - try out_writer.writeAll(buffer.items); + try out_writer.writeAll(buf.written()); } -fn write_enum_fields(db: *Database, arena: Allocator, e: *const Enum, out_writer: anytype) !void { - var buffer = std.ArrayList(u8).init(arena); - defer buffer.deinit(); +fn write_enum_fields(db: *Database, arena: Allocator, e: *const Enum, out_writer: *std.Io.Writer) !void { + var buf: std.Io.Writer.Allocating = .init(arena); + const writer = &buf.writer; - const writer = buffer.writer(); const enum_fields = try db.get_enum_fields(arena, e.id, .{ .distinct = true }); for (enum_fields) |enum_field| @@ -692,37 +694,36 @@ fn write_enum_fields(db: *Database, arena: Allocator, e: *const Enum, out_writer if (enum_fields.len < std.math.pow(u64, 2, e.size_bits)) try writer.writeAll("_,\n"); - try out_writer.writeAll(buffer.items); + try out_writer.writeAll(buf.written()); } fn write_enum_field( arena: Allocator, enum_field: *const EnumField, size: u64, - writer: anytype, + writer: *std.Io.Writer, ) !void { // TODO: use size to print the hex value (pad with zeroes accordingly) _ = size; if (enum_field.description) |description| try write_doc_comment(arena, description, writer); - try writer.print("{} = 0x{x},\n", .{ std.zig.fmtId(enum_field.name), enum_field.value }); + try writer.print("{f} = 0x{x},\n", .{ std.zig.fmtId(enum_field.name), enum_field.value }); } fn write_mode_enum_and_fn( db: *Database, arena: Allocator, modes: []const Mode, - out_writer: anytype, + out_writer: *std.Io.Writer, ) !void { - var buffer = std.ArrayList(u8).init(arena); - defer buffer.deinit(); + var buf: std.Io.Writer.Allocating = .init(arena); + const writer = &buf.writer; - const writer = buffer.writer(); try writer.writeAll("pub const Mode = enum {\n"); for (modes) |mode| { - try writer.print("{},\n", .{std.zig.fmtId(mode.name)}); + try writer.print("{f},\n", .{std.zig.fmtId(mode.name)}); } try writer.writeAll( @@ -733,12 +734,12 @@ fn write_mode_enum_and_fn( ); for (modes) |mode| { - var components = std.ArrayList([]const u8).init(db.gpa); - defer components.deinit(); + var components: std.ArrayList([]const u8) = .empty; + defer components.deinit(db.gpa); var tok_it = std.mem.tokenizeScalar(u8, mode.qualifier, '.'); while (tok_it.next()) |token| - try components.append(token); + try components.append(db.gpa, token); const field_name = components.items[components.items.len - 1]; const access_path = try std.mem.join(arena, ".", components.items[1 .. components.items.len - 1]); @@ -754,7 +755,7 @@ fn write_mode_enum_and_fn( const value = try std.fmt.parseInt(u64, token, 0); try writer.print("{},\n", .{value}); } - try writer.print("=> return .{},\n", .{std.zig.fmtId(mode.name)}); + try writer.print("=> return .{f},\n", .{std.zig.fmtId(mode.name)}); try writer.writeAll("else => {},\n"); try writer.writeAll("}\n"); try writer.writeAll("}\n"); @@ -763,7 +764,7 @@ fn write_mode_enum_and_fn( try writer.writeAll("\nunreachable;\n"); try writer.writeAll("}\n"); - try out_writer.writeAll(buffer.items); + try out_writer.writeAll(buf.written()); } fn write_registers_and_nested_structs( @@ -774,7 +775,7 @@ fn write_registers_and_nested_structs( modes: []const Mode, registers: []Register, nested_struct_fields: []NestedStructField, - out_writer: anytype, + out_writer: *std.Io.Writer, ) !void { log.debug("write_registers: modes.len={}", .{modes.len}); if (modes.len > 0) @@ -789,16 +790,16 @@ fn write_registers_with_modes( struct_id: StructID, block_size_bytes: ?u64, modes: []const Mode, - out_writer: anytype, + out_writer: *std.Io.Writer, ) !void { log.debug("write_registers_with_modes", .{}); - var buffer = std.ArrayList(u8).init(arena); - defer buffer.deinit(); - const writer = buffer.writer(); + var buf: std.Io.Writer.Allocating = .init(arena); + const writer = &buf.writer; + for (modes) |mode| { const registers = try db.get_registers_with_mode(arena, struct_id, mode.id); - try writer.print("{}: extern struct {{\n", .{ + try writer.print("{f}: extern struct {{\n", .{ std.zig.fmtId(mode.name), }); @@ -808,7 +809,7 @@ fn write_registers_with_modes( try writer.writeAll("},\n"); } - try out_writer.writeAll(buffer.items); + try out_writer.writeAll(buf.written()); } const StructFieldIterator = struct { @@ -822,7 +823,7 @@ const StructFieldIterator = struct { fn init(registers: []const Register, nested_struct_fields: []const NestedStructField) StructFieldIterator { assert(std.sort.isSorted(Register, registers, {}, Register.less_than)); assert(std.sort.isSorted(NestedStructField, nested_struct_fields, {}, NestedStructField.less_than)); - return StructFieldIterator{ + return .{ .registers = registers, .nested_struct_fields = nested_struct_fields, }; @@ -1025,7 +1026,7 @@ const StructFieldIterator = struct { } }; -fn write_nested_struct_field(db: *Database, arena: Allocator, nsf: *const NestedStructField, writer: anytype) !void { +fn write_nested_struct_field(db: *Database, arena: Allocator, nsf: *const NestedStructField, writer: *std.Io.Writer) !void { if (nsf.description) |description| try write_doc_comment(arena, description, writer); @@ -1034,7 +1035,7 @@ fn write_nested_struct_field(db: *Database, arena: Allocator, nsf: *const Nested try std.fmt.bufPrint(&offset_buf, "offset: 0x{x:0>2}", .{nsf.offset_bytes}); try write_doc_comment(arena, offset_str, writer); - try writer.print("{}: ", .{std.zig.fmtId(nsf.name)}); + try writer.print("{f}: ", .{std.zig.fmtId(nsf.name)}); var array_prefix_buf: [80]u8 = undefined; const array_prefix: []const u8 = if (nsf.count) |count| try std.fmt.bufPrint(&array_prefix_buf, "[{}]", .{count}) @@ -1045,7 +1046,7 @@ fn write_nested_struct_field(db: *Database, arena: Allocator, nsf: *const Nested // TODO: if it's a struct decl then refer to it by name if (try db.get_struct_decl_by_struct_id(arena, nsf.struct_id)) |struct_decl| { // TODO full reference? - try writer.print("{},\n", .{std.zig.fmtId(struct_decl.name)}); + try writer.print("{f},\n", .{std.zig.fmtId(struct_decl.name)}); } else { try write_struct(db, arena, null, nsf.struct_id, writer); try writer.writeAll(",\n"); @@ -1058,15 +1059,14 @@ fn write_registers_and_nested_structs_base( block_size_bytes: ?u64, registers: []Register, nested_struct_fields: []NestedStructField, - out_writer: anytype, + out_writer: *std.Io.Writer, ) !void { log.debug("registers.len={} nested_struct_fields.len={}", .{ registers.len, nested_struct_fields.len }); var it: StructFieldIterator = .init(registers, nested_struct_fields); - var buffer = std.ArrayList(u8).init(arena); - defer buffer.deinit(); + var buf: std.Io.Writer.Allocating = .init(arena); + const writer = &buf.writer; - const writer = buffer.writer(); var minimum_size: u64 = 0; while (it.next()) |entry| { switch (entry) { @@ -1092,20 +1092,20 @@ fn write_registers_and_nested_structs_base( }); } - try out_writer.writeAll(buffer.items); + try out_writer.writeAll(buf.written()); } fn write_register( db: *Database, arena: Allocator, register: *const Register, - out_writer: anytype, + out_writer: *std.Io.Writer, ) !void { log.debug("write_register: {}", .{register.*}); - var buffer = std.ArrayList(u8).init(arena); - defer buffer.deinit(); - const writer = buffer.writer(); + var buf: std.Io.Writer.Allocating = .init(arena); + const writer = &buf.writer; + if (register.description) |description| try write_doc_comment(arena, description, writer); @@ -1124,7 +1124,7 @@ fn write_register( // TODO: named struct type const fields = try db.get_register_fields(arena, register.id, .{}); if (fields.len > 0) { - try writer.print("{}: {s}mmio.Mmio(packed struct(u{}) {{\n", .{ + try writer.print("{f}: {s}mmio.Mmio(packed struct(u{}) {{\n", .{ std.zig.fmtId(register.name), array_prefix, register.size_bits, @@ -1133,14 +1133,14 @@ fn write_register( try write_fields(db, arena, fields, register.size_bits, writer); try writer.writeAll("}),\n"); } else { - try writer.print("{}: {s}u{},\n", .{ + try writer.print("{f}: {s}u{},\n", .{ std.zig.fmtId(register.name), array_prefix, register.size_bits, }); } - try out_writer.writeAll(buffer.items); + try out_writer.writeAll(buf.written()); } /// Determine if a field comes before another, i.e. has a lower bit offset in the register @@ -1154,11 +1154,11 @@ fn write_fields( arena: Allocator, fields: []const Database.StructField, register_size_bits: u64, - out_writer: anytype, + out_writer: *std.Io.Writer, ) !void { // We first expand every 'array field' into its consituent fields, // named e.g. `@OISN[0]`, `@OISN[1]`, etc. for `field.name` OISN. - var expanded_fields = std.ArrayList(Database.StructField).init(arena); + var expanded_fields: std.ArrayList(Database.StructField) = .empty; for (fields) |field| { if (field.count) |count| { var stride = field.stride orelse field.size_bits; @@ -1173,9 +1173,9 @@ fn write_fields( subfield.offset_bits = field.offset_bits + @as(u8, @intCast(stride * i)); subfield.name = try std.fmt.allocPrint(arena, "{s}[{d}]", .{ field.name, i }); subfield.description = try std.fmt.allocPrint(arena, "({d}/{d} of {s}) {s}", .{ i + 1, count, field.name, field.description orelse "" }); - try expanded_fields.append(subfield); + try expanded_fields.append(arena, subfield); } - } else try expanded_fields.append(field); + } else try expanded_fields.append(arena, field); } // the 'count' and 'stride' of each entry of `expanded_fields` are never used below @@ -1185,9 +1185,9 @@ fn write_fields( // where both have stride > size_bits: Above those are appended out of order.) std.sort.insertion(Database.StructField, expanded_fields.items, {}, field_comes_before); - var buffer = std.ArrayList(u8).init(arena); - defer buffer.deinit(); - const writer = buffer.writer(); + var buf: std.Io.Writer.Allocating = .init(arena); + const writer = &buf.writer; + var offset: u64 = 0; for (expanded_fields.items) |field| { @@ -1224,14 +1224,14 @@ fn write_fields( if (field.enum_id) |enum_id| { const e = try db.get_enum(arena, enum_id); if (e.size_bits != field.size_bits) { - log.warn("{}: fails to match the size of {s}, with sizes of {} and {} respectively. Not assigning type.", .{ + log.warn("{f}: fails to match the size of {s}, with sizes of {} and {} respectively. Not assigning type.", .{ enum_id, field.name, e.size_bits, field.size_bits, }); - try writer.print("{}: u{},\n", .{ std.zig.fmtId(field.name), field.size_bits }); + try writer.print("{f}: u{},\n", .{ std.zig.fmtId(field.name), field.size_bits }); } else if (e.name) |enum_name| { if (e.struct_id == null or try db.enum_has_name_collision(enum_id)) { try writer.print( - \\{}: enum(u{}) {{ + \\{f}: enum(u{}) {{ \\ , .{ std.zig.fmtId(field.name), @@ -1242,7 +1242,7 @@ fn write_fields( try writer.writeAll("},\n"); } else { try writer.print( - \\{}: {}, + \\{f}: {f}, \\ , .{ std.zig.fmtId(field.name), @@ -1251,7 +1251,7 @@ fn write_fields( } } else { try writer.print( - \\{}: enum(u{}) {{ + \\{f}: enum(u{}) {{ \\ , .{ std.zig.fmtId(field.name), @@ -1262,7 +1262,7 @@ fn write_fields( try writer.writeAll("},\n"); } } else { - try writer.print("{}: u{},\n", .{ std.zig.fmtId(field.name), field.size_bits }); + try writer.print("{f}: u{},\n", .{ std.zig.fmtId(field.name), field.size_bits }); } log.debug("adding size bits to offset: offset={} field.size_bits={}", .{ offset, field.size_bits }); @@ -1278,7 +1278,11 @@ fn write_fields( log.debug("No padding", .{}); } - try out_writer.writeAll(buffer.items); + try out_writer.writeAll(buf.written()); +} + +fn to_zero_sentinel(buf: []const u8) [:0]const u8 { + return buf[0 .. buf.len - 1 :0]; } const tests = @import("output_tests.zig"); @@ -1548,7 +1552,7 @@ test "gen.StructFieldIterator.one nested struct field and a register" { // var db = try tests.peripheral_instantiation(std.testing.allocator); // defer db.destroy(); // -// var buffer = std.ArrayList(u8).init(std.testing.allocator); +// var buffer = std.array_list.Managed(u8).init(std.testing.allocator); // defer buffer.deinit(); // // try db.to_zig(buffer.writer(), .{ .for_microzig = true }); @@ -1589,7 +1593,7 @@ test "gen.StructFieldIterator.one nested struct field and a register" { // var db = try tests.peripherals_with_shared_type(std.testing.allocator); // defer db.destroy(); // -// var buffer = std.ArrayList(u8).init(std.testing.allocator); +// var buffer = std.array_list.Managed(u8).init(std.testing.allocator); // defer buffer.deinit(); // // try db.to_zig(buffer.writer(), .{ .for_microzig = true }); @@ -1631,7 +1635,7 @@ test "gen.StructFieldIterator.one nested struct field and a register" { // var db = try tests.peripheral_with_modes(std.testing.allocator); // defer db.destroy(); // -// var buffer = std.ArrayList(u8).init(std.testing.allocator); +// var buffer = std.array_list.Managed(u8).init(std.testing.allocator); // defer buffer.deinit(); // // try db.to_zig(buffer.writer(), .{ .for_microzig = true }); @@ -1703,7 +1707,7 @@ test "gen.StructFieldIterator.one nested struct field and a register" { // var db = try tests.peripheral_with_enum(std.testing.allocator); // defer db.destroy(); // -// var buffer = std.ArrayList(u8).init(std.testing.allocator); +// var buffer = std.array_list.Managed(u8).init(std.testing.allocator); // defer buffer.deinit(); // // try db.to_zig(buffer.writer(), .{ .for_microzig = true }); @@ -1739,7 +1743,7 @@ test "gen.StructFieldIterator.one nested struct field and a register" { // var db = try tests.peripheral_with_enum_and_its_exhausted_of_values(std.testing.allocator); // defer db.destroy(); // -// var buffer = std.ArrayList(u8).init(std.testing.allocator); +// var buffer = std.array_list.Managed(u8).init(std.testing.allocator); // defer buffer.deinit(); // // try db.to_zig(buffer.writer(), .{ .for_microzig = true }); @@ -1774,7 +1778,7 @@ test "gen.StructFieldIterator.one nested struct field and a register" { // var db = try tests.field_with_named_enum(std.testing.allocator); // defer db.destroy(); // -// var buffer = std.ArrayList(u8).init(std.testing.allocator); +// var buffer = std.array_list.Managed(u8).init(std.testing.allocator); // defer buffer.deinit(); // // try db.to_zig(buffer.writer(), .{ .for_microzig = true }); @@ -1813,7 +1817,7 @@ test "gen.StructFieldIterator.one nested struct field and a register" { // var db = try tests.field_with_anonymous_enum(std.testing.allocator); // defer db.destroy(); // -// var buffer = std.ArrayList(u8).init(std.testing.allocator); +// var buffer = std.array_list.Managed(u8).init(std.testing.allocator); // defer buffer.deinit(); // // try db.to_zig(buffer.writer(), .{ .for_microzig = true }); @@ -1850,7 +1854,7 @@ test "gen.StructFieldIterator.one nested struct field and a register" { // var db = try tests.namespaced_register_groups(std.testing.allocator); // defer db.destroy(); // -// var buffer = std.ArrayList(u8).init(std.testing.allocator); +// var buffer = std.array_list.Managed(u8).init(std.testing.allocator); // defer buffer.deinit(); // // try db.to_zig(buffer.writer(), .{ .for_microzig = true }); @@ -1904,7 +1908,7 @@ test "gen.StructFieldIterator.one nested struct field and a register" { // var db = try tests.peripheral_with_reserved_register(std.testing.allocator); // defer db.destroy(); // -// var buffer = std.ArrayList(u8).init(std.testing.allocator); +// var buffer = std.array_list.Managed(u8).init(std.testing.allocator); // defer buffer.deinit(); // // try db.to_zig(buffer.writer(), .{ .for_microzig = true }); @@ -1946,7 +1950,7 @@ test "gen.StructFieldIterator.one nested struct field and a register" { // var db = try tests.peripheral_with_count(std.testing.allocator); // defer db.destroy(); // -// var buffer = std.ArrayList(u8).init(std.testing.allocator); +// var buffer = std.array_list.Managed(u8).init(std.testing.allocator); // defer buffer.deinit(); // // try db.to_zig(buffer.writer(), .{ .for_microzig = true }); @@ -1988,7 +1992,7 @@ test "gen.StructFieldIterator.one nested struct field and a register" { // var db = try tests.peripheral_with_count_padding_required(std.testing.allocator); // defer db.destroy(); // -// var buffer = std.ArrayList(u8).init(std.testing.allocator); +// var buffer = std.array_list.Managed(u8).init(std.testing.allocator); // defer buffer.deinit(); // // try db.to_zig(buffer.writer(), .{ .for_microzig = true }); @@ -2031,7 +2035,7 @@ test "gen.StructFieldIterator.one nested struct field and a register" { // var db = try tests.register_with_count(std.testing.allocator); // defer db.destroy(); // -// var buffer = std.ArrayList(u8).init(std.testing.allocator); +// var buffer = std.array_list.Managed(u8).init(std.testing.allocator); // defer buffer.deinit(); // // try db.to_zig(buffer.writer(), .{ .for_microzig = true }); @@ -2073,7 +2077,7 @@ test "gen.StructFieldIterator.one nested struct field and a register" { // var db = try tests.register_with_count_and_fields(std.testing.allocator); // defer db.destroy(); // -// var buffer = std.ArrayList(u8).init(std.testing.allocator); +// var buffer = std.array_list.Managed(u8).init(std.testing.allocator); // defer buffer.deinit(); // // try db.to_zig(buffer.writer(), .{ .for_microzig = true }); @@ -2118,7 +2122,7 @@ test "gen.StructFieldIterator.one nested struct field and a register" { // var db = try tests.field_with_count_width_of_one_offset_and_padding(std.testing.allocator); // defer db.destroy(); // -// var buffer = std.ArrayList(u8).init(std.testing.allocator); +// var buffer = std.array_list.Managed(u8).init(std.testing.allocator); // defer buffer.deinit(); // // try db.to_zig(buffer.writer(), .{ .for_microzig = true }); @@ -2156,7 +2160,7 @@ test "gen.StructFieldIterator.one nested struct field and a register" { // var db = try tests.field_with_count_multi_bit_width_offset_and_padding(std.testing.allocator); // defer db.destroy(); // -// var buffer = std.ArrayList(u8).init(std.testing.allocator); +// var buffer = std.array_list.Managed(u8).init(std.testing.allocator); // defer buffer.deinit(); // // try db.to_zig(buffer.writer(), .{ .for_microzig = true }); @@ -2191,7 +2195,7 @@ test "gen.StructFieldIterator.one nested struct field and a register" { // var db = try tests.interrupts_avr(std.testing.allocator); // defer db.destroy(); // -// var buffer = std.ArrayList(u8).init(std.testing.allocator); +// var buffer = std.array_list.Managed(u8).init(std.testing.allocator); // defer buffer.deinit(); // // try db.to_zig(buffer.writer(), .{ .for_microzig = true }); @@ -2231,7 +2235,7 @@ test "gen.StructFieldIterator.one nested struct field and a register" { // var db = try tests.peripheral_type_with_register_and_field(std.testing.allocator); // defer db.destroy(); // -// var buffer = std.ArrayList(u8).init(std.testing.allocator); +// var buffer = std.array_list.Managed(u8).init(std.testing.allocator); // defer buffer.deinit(); // // try db.to_zig(buffer.writer(), .{ .for_microzig = true }); @@ -2267,7 +2271,7 @@ test "gen.StructFieldIterator.one nested struct field and a register" { // var db = try tests.enums_with_name_collision(std.testing.allocator); // defer db.destroy(); // -// var buffer = std.ArrayList(u8).init(std.testing.allocator); +// var buffer = std.array_list.Managed(u8).init(std.testing.allocator); // defer buffer.deinit(); // // try db.to_zig(buffer.writer(), .{ .for_microzig = true }); @@ -2310,7 +2314,7 @@ test "gen.StructFieldIterator.one nested struct field and a register" { // // try db.backup("value_collision.regz"); // -// var buffer = std.ArrayList(u8).init(std.testing.allocator); +// var buffer = std.array_list.Managed(u8).init(std.testing.allocator); // defer buffer.deinit(); // // try db.to_zig(buffer.writer(), .{ .for_microzig = true }); @@ -2346,7 +2350,7 @@ test "gen.StructFieldIterator.one nested struct field and a register" { // var db = try tests.enum_fields_with_name_collision(std.testing.allocator); // defer db.destroy(); // -// var buffer = std.ArrayList(u8).init(std.testing.allocator); +// var buffer = std.array_list.Managed(u8).init(std.testing.allocator); // defer buffer.deinit(); // // try db.to_zig(buffer.writer(), .{ .for_microzig = true }); @@ -2382,7 +2386,7 @@ test "gen.StructFieldIterator.one nested struct field and a register" { // var db = try tests.register_fields_with_name_collision(std.testing.allocator); // defer db.destroy(); // -// var buffer = std.ArrayList(u8).init(std.testing.allocator); +// var buffer = std.array_list.Managed(u8).init(std.testing.allocator); // defer buffer.deinit(); // // try db.to_zig(buffer.writer(), .{ .for_microzig = true }); @@ -2420,7 +2424,7 @@ test "gen.StructFieldIterator.one nested struct field and a register" { // // try db.backup("nested_struct_field_in_a_peripheral.regz"); // -// var buffer = std.ArrayList(u8).init(std.testing.allocator); +// var buffer = std.array_list.Managed(u8).init(std.testing.allocator); // defer buffer.deinit(); // // try db.to_zig(buffer.writer(), .{ .for_microzig = true }); @@ -2460,7 +2464,7 @@ test "gen.StructFieldIterator.one nested struct field and a register" { // var db = try tests.nested_struct_field_in_a_peripheral_that_has_a_named_type(std.testing.allocator, 0); // defer db.destroy(); // -// var buffer = std.ArrayList(u8).init(std.testing.allocator); +// var buffer = std.array_list.Managed(u8).init(std.testing.allocator); // defer buffer.deinit(); // // try db.to_zig(buffer.writer(), .{ .for_microzig = true }); @@ -2502,7 +2506,7 @@ test "gen.StructFieldIterator.one nested struct field and a register" { // var db = try tests.nested_struct_field_in_a_peripheral(std.testing.allocator, 4); // defer db.destroy(); // -// var buffer = std.ArrayList(u8).init(std.testing.allocator); +// var buffer = std.array_list.Managed(u8).init(std.testing.allocator); // defer buffer.deinit(); // // try db.to_zig(buffer.writer(), .{ .for_microzig = true }); @@ -2544,7 +2548,7 @@ test "gen.StructFieldIterator.one nested struct field and a register" { // var db = try tests.nested_struct_field_in_a_nested_struct_field(std.testing.allocator); // defer db.destroy(); // -// var buffer = std.ArrayList(u8).init(std.testing.allocator); +// var buffer = std.array_list.Managed(u8).init(std.testing.allocator); // defer buffer.deinit(); // // try db.to_zig(buffer.writer(), .{ .for_microzig = true }); @@ -2587,7 +2591,7 @@ test "gen.StructFieldIterator.one nested struct field and a register" { // var db = try tests.nested_struct_field_next_to_register(std.testing.allocator); // defer db.destroy(); // -// var buffer = std.ArrayList(u8).init(std.testing.allocator); +// var buffer = std.array_list.Managed(u8).init(std.testing.allocator); // defer buffer.deinit(); // // try db.to_zig(buffer.writer(), .{ .for_microzig = true }); diff --git a/tools/regz/src/main.zig b/tools/regz/src/main.zig index a223e5ad7..7df2b2da3 100644 --- a/tools/regz/src/main.zig +++ b/tools/regz/src/main.zig @@ -36,7 +36,7 @@ const Arguments = struct { } }; -fn print_usage(writer: anytype) !void { +fn print_usage(writer: *std.Io.Writer) !void { try writer.writeAll( \\regz \\ --help Display this help and exit @@ -48,6 +48,7 @@ fn print_usage(writer: anytype) !void { \\ \\ ); + try writer.flush(); } fn parse_args(allocator: Allocator) !Arguments { @@ -88,7 +89,10 @@ fn parse_args(allocator: Allocator) !Arguments { ret.patch_path = try allocator.dupe(u8, args[i]); } else if (std.mem.startsWith(u8, args[i], "-")) { std.log.err("Unknown argument '{s}'", .{args[i]}); - try print_usage(std.io.getStdErr().writer()); + + var buf: [80]u8 = undefined; + var writer = std.fs.File.stderr().writer(&buf); + try print_usage(&writer.interface); return error.Explained; } else if (ret.input_path != null) { std.log.err("Input path is already set to '{s}', you are trying to set it to '{s}'", .{ @@ -115,7 +119,9 @@ fn main_impl() anyerror!void { defer args.deinit(); if (args.help) { - try print_usage(std.io.getStdOut().writer()); + var buf: [80]u8 = undefined; + var writer = std.fs.File.stdout().writer(&buf); + try print_usage(&writer.interface); return; } diff --git a/tools/regz/src/patch.zig b/tools/regz/src/patch.zig index 983587786..d90ad106d 100644 --- a/tools/regz/src/patch.zig +++ b/tools/regz/src/patch.zig @@ -47,7 +47,7 @@ pub const Patch = union(enum) { /// List for assembling patches in build scripts pub const PatchList = struct { - entries: std.ArrayList(Patch), + entries: std.array_list.Managed(Patch), pub fn append(list: *PatchList, patch: Patch) void { list.append(patch) catch @panic("OOM"); diff --git a/tools/regz/src/svd.zig b/tools/regz/src/svd.zig index 32ab001fd..b9b4b651b 100644 --- a/tools/regz/src/svd.zig +++ b/tools/regz/src/svd.zig @@ -414,7 +414,7 @@ fn load_cluster( while (cluster_it.next()) |cluster_node| try load_cluster(ctx, cluster_node, struct_id); - log.debug("loaded cluster name: {s} description={?s} offset={?s}", .{ name, description, address_offset_str }); + log.debug("loaded cluster name: {s} description={?s} offset={s}", .{ name, description, address_offset_str }); } fn get_name_without_suffix(node: xml.Node, suffix: []const u8) ![]const u8 { @@ -474,7 +474,7 @@ fn load_register_with_dim_element_group(ctx: *Context, node: xml.Node, parent: S DimType.list => blk: { const replacement = try dim_elements.dim_index_value(ctx, i); const new_name = try std.mem.replaceOwned(u8, ctx.arena.allocator(), name, "%s", replacement); - break :blk try std.fmt.allocPrintZ(ctx.arena.allocator(), "{s}", .{new_name}); + break :blk try std.fmt.allocPrintSentinel(ctx.arena.allocator(), "{s}", .{new_name}, 0); }, }, .description = node.get_value("description"), @@ -566,7 +566,7 @@ fn load_field(ctx: *Context, node: xml.Node, register_id: RegisterID) !void { DimType.list => listblk: { const replacement = try elements.dim_index_value(ctx, i); const new_name = try std.mem.replaceOwned(u8, ctx.arena.allocator(), node.get_value("name").?, "%s", replacement); - break :listblk try std.fmt.allocPrintZ(ctx.arena.allocator(), "{s}", .{new_name}); + break :listblk try std.fmt.allocPrintSentinel(ctx.arena.allocator(), "{s}", .{new_name}, 0); }, }; } else try get_name_without_suffix(node, "%s"), @@ -795,10 +795,10 @@ const DimElements = struct { const start_index = iter.next().?; const parse_start = std.fmt.parseInt(usize, start_index, 0); if (parse_start) |start| { - return try std.fmt.allocPrintZ(ctx.arena.allocator(), "{d}", .{start + index}); + return try std.fmt.allocPrintSentinel(ctx.arena.allocator(), "{d}", .{start + index}, 0); } else |_| { if (start_index.len == 1 and std.ascii.isAlphabetic(start_index[0])) { - return std.fmt.allocPrintZ(ctx.arena.allocator(), "{c}", .{start_index[0] + @as(u8, @truncate(index))}); + return std.fmt.allocPrintSentinel(ctx.arena.allocator(), "{c}", .{start_index[0] + @as(u8, @truncate(index))}, 0); } return error.DimIndexInvalid; } @@ -815,7 +815,7 @@ const DimElements = struct { const start_index = iter_value.?; const parse_start = std.fmt.parseInt(usize, start_index, 0); if (parse_start) |start| { - return try std.fmt.allocPrintZ(ctx.arena.allocator(), "{d}", .{start}); + return try std.fmt.allocPrintSentinel(ctx.arena.allocator(), "{d}", .{start}, 0); } else |_| { if (start_index.len == 1 and std.ascii.isAlphabetic(start_index[0])) { return start_index; diff --git a/tools/uf2/build.zig b/tools/uf2/build.zig index 39d02f8e2..077f81ef1 100644 --- a/tools/uf2/build.zig +++ b/tools/uf2/build.zig @@ -36,9 +36,11 @@ pub fn build(b: *std.Build) void { const elf2uf2 = b.addExecutable(.{ .name = "elf2uf2", - .root_source_file = b.path("src/elf2uf2.zig"), - .target = target, - .optimize = optimize, + .root_module = b.createModule(.{ + .root_source_file = b.path("src/elf2uf2.zig"), + .target = target, + .optimize = optimize, + }), }); b.installArtifact(elf2uf2); @@ -47,7 +49,10 @@ pub fn build(b: *std.Build) void { }); const main_tests = b.addTest(.{ - .root_source_file = b.path("src/uf2.zig"), + .root_module = b.createModule(.{ + .root_source_file = b.path("src/uf2.zig"), + .target = b.graph.host, + }), }); const run_main_tests = b.addRunArtifact(main_tests); @@ -56,8 +61,10 @@ pub fn build(b: *std.Build) void { const gen = b.addExecutable(.{ .name = "gen", - .root_source_file = b.path("src/gen.zig"), - .target = b.graph.host, + .root_module = b.createModule(.{ + .root_source_file = b.path("src/gen.zig"), + .target = b.graph.host, + }), }); const gen_run_step = b.addRunArtifact(gen); const gen_step = b.step("gen", "Generate family id enum"); @@ -65,8 +72,10 @@ pub fn build(b: *std.Build) void { const example = b.addExecutable(.{ .name = "example", - .root_source_file = b.path("src/example.zig"), - .target = b.graph.host, + .root_module = b.createModule(.{ + .root_source_file = b.path("src/example.zig"), + .target = b.graph.host, + }), }); b.installArtifact(example); } diff --git a/tools/uf2/src/elf2uf2.zig b/tools/uf2/src/elf2uf2.zig index 41efd4e62..d89426f8f 100644 --- a/tools/uf2/src/elf2uf2.zig +++ b/tools/uf2/src/elf2uf2.zig @@ -34,6 +34,9 @@ fn find_arg(args: []const []const u8, key: []const u8) !?[]const u8 { return value; } +var elf_reader_buf: [1024]u8 = undefined; +var output_writer_buf: [1024]u8 = undefined; + pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); @@ -42,7 +45,8 @@ pub fn main() !void { defer std.process.argsFree(gpa.allocator(), args); for (args) |arg| if (std.mem.eql(u8, "--help", arg)) { - try std.io.getStdOut().writeAll(usage); + var writer = std.fs.File.stdout().writer(&.{}); + try writer.interface.writeAll(usage); return; }; @@ -73,14 +77,18 @@ pub fn main() !void { var archive = uf2.Archive.init(gpa.allocator()); defer archive.deinit(); - try archive.add_elf(elf_path, .{ + const elf_file = try std.fs.cwd().openFile(elf_path, .{}); + defer elf_file.close(); + var elf_reader = elf_file.reader(&elf_reader_buf); + + try archive.add_elf(&elf_reader, .{ .family_id = family_id, }); const dest_file = try std.fs.cwd().createFile(output_path, .{}); defer dest_file.close(); - var buffered = std.io.bufferedWriter(dest_file.writer()); - try archive.write_to(buffered.writer()); - try buffered.flush(); + var writer = dest_file.writer(&output_writer_buf); + try archive.write_to(&writer.interface); + try writer.interface.flush(); } diff --git a/tools/uf2/src/example.zig b/tools/uf2/src/example.zig index df8479693..19597e5af 100644 --- a/tools/uf2/src/example.zig +++ b/tools/uf2/src/example.zig @@ -9,22 +9,32 @@ pub fn main() !void { var archive = uf2.Archive.init(std.heap.page_allocator); defer archive.deinit(); - try archive.add_elf(args[1], .{ + const file = try std.fs.cwd().openFile(args[1], .{}); + defer file.close(); + + var buf: [4096]u8 = undefined; + var reader = file.reader(&buf); + + try archive.add_elf(&reader, .{ .family_id = .RP2040, }); const out_file = try std.fs.cwd().createFile(args[2], .{}); defer out_file.close(); - try archive.write_to(out_file.writer()); + var write_buf: [4096]u8 = undefined; + var writer = out_file.writer(&write_buf); + try archive.write_to(&writer.interface); } else if (args.len == 2) { const file = try std.fs.cwd().openFile(args[1], .{}); defer file.close(); - var blocks = std.ArrayList(uf2.Block).init(std.heap.page_allocator); + var blocks = std.array_list.Managed(uf2.Block).init(std.heap.page_allocator); defer blocks.deinit(); + var buf: [4096]u8 = undefined; + var reader = file.reader(&buf); while (true) { - const block = uf2.Block.from_reader(file.reader()) catch |err| switch (err) { + const block = uf2.Block.from_reader(&reader.interface) catch |err| switch (err) { error.EndOfStream => break, else => return err, }; diff --git a/tools/uf2/src/uf2.zig b/tools/uf2/src/uf2.zig index c6c654960..a8a324d9c 100644 --- a/tools/uf2/src/uf2.zig +++ b/tools/uf2/src/uf2.zig @@ -17,31 +17,28 @@ pub const Options = struct { pub const Archive = struct { allocator: Allocator, blocks: std.ArrayList(Block), - families: std.AutoHashMap(FamilyId, void), + families: std.AutoHashMapUnmanaged(FamilyId, void), // TODO: keep track of contained files const Self = @This(); pub fn init(allocator: std.mem.Allocator) Archive { - return Self{ + return .{ .allocator = allocator, - .blocks = std.ArrayList(Block).init(allocator), - .families = std.AutoHashMap(FamilyId, void).init(allocator), + .blocks = .empty, + .families = .empty, }; } pub fn deinit(self: *Self) void { - self.blocks.deinit(); - self.families.deinit(); + self.blocks.deinit(self.allocator); + self.families.deinit(self.allocator); } - pub fn add_elf(self: *Self, path: []const u8, opts: Options) !void { + pub fn add_elf(self: *Self, reader: *std.fs.File.Reader, opts: Options) !void { // TODO: ensures this reports an error if there is a collision if (opts.family_id) |family_id| - try self.families.putNoClobber(family_id, {}); - - const file = try std.fs.cwd().openFile(path, .{}); - defer file.close(); + try self.families.putNoClobber(self.allocator, family_id, {}); const Segment = struct { addr: u32, @@ -53,15 +50,15 @@ pub const Archive = struct { } }; - var segments = std.ArrayList(Segment).init(self.allocator); - defer segments.deinit(); + var segments: std.ArrayList(Segment) = .empty; + defer segments.deinit(self.allocator); - const header = try std.elf.Header.read(file); - var it = header.program_header_iterator(file); + const header = try std.elf.Header.read(&reader.interface); + var it = header.iterateProgramHeaders(reader); while (try it.next()) |prog_hdr| if (prog_hdr.p_type == std.elf.PT_LOAD and prog_hdr.p_memsz > 0 and prog_hdr.p_filesz > 0) { std.log.debug("segment: {}", .{prog_hdr}); - try segments.append(.{ + try segments.append(self.allocator, .{ .addr = @as(u32, @intCast(prog_hdr.p_paddr)), .file_offset = @as(u32, @intCast(prog_hdr.p_offset)), .size = @as(u32, @intCast(prog_hdr.p_memsz)), @@ -80,7 +77,7 @@ pub const Archive = struct { while (segment_offset < segment.size) { const addr = segment.addr + segment_offset; if (first or addr >= self.blocks.items[self.blocks.items.len - 1].target_addr + prog_page_size) { - try self.blocks.append(.{ + try self.blocks.append(self.allocator, .{ .flags = .{ .not_main_flash = false, .file_container = false, @@ -107,8 +104,8 @@ pub const Archive = struct { const block_offset = addr - block.target_addr; const n_bytes = @min(prog_page_size - block_offset, segment.size - segment_offset); - try file.seekTo(segment.file_offset + segment_offset); - try file.reader().readNoEof(block.data[block_offset..][0..n_bytes]); + try reader.seekTo(segment.file_offset + segment_offset); + try reader.interface.readSliceAll(block.data[block_offset..][0..n_bytes]); segment_offset += n_bytes; } @@ -118,12 +115,13 @@ pub const Archive = struct { @panic("TODO: bundle source in UF2 file"); } - pub fn write_to(self: *Self, writer: anytype) !void { + pub fn write_to(self: *Self, writer: *std.Io.Writer) !void { for (self.blocks.items, 0..) |*block, i| { block.block_number = @as(u32, @intCast(i)); block.total_blocks = @as(u32, @intCast(self.blocks.items.len)); try block.write_to(writer); } + try writer.flush(); } pub fn add_file(self: *Self, path: []const u8) !void { @@ -139,7 +137,7 @@ pub const Archive = struct { var target_addr: u32 = 0; while (true) { - try self.blocks.append(.{ + try self.blocks.append(self.allocator, .{ .flags = .{ .not_main_flash = true, .file_container = true, @@ -233,20 +231,18 @@ pub const Block = extern struct { assert(512 == @sizeOf(Block)); } - pub fn from_reader(reader: anytype) !Block { + pub fn from_reader(reader: *std.Io.Reader) !Block { var block: Block = undefined; inline for (std.meta.fields(Block)) |field| { switch (field.type) { - u32 => @field(block, field.name) = try reader.readInt(u32, .little), + u32 => @field(block, field.name) = try reader.takeInt(u32, .little), [476]u8 => { - const n = try reader.readAll(&@field(block, field.name)); - if (n != @sizeOf(field.type)) - return error.EndOfStream; + try reader.readSliceAll(&@field(block, field.name)); }, else => { assert(4 == @sizeOf(field.type)); @field(block, field.name) = - @as(field.type, @bitCast(try reader.readInt(u32, .little))); + @as(field.type, @bitCast(try reader.takeInt(u32, .little))); }, } } @@ -254,7 +250,7 @@ pub const Block = extern struct { return block; } - pub fn write_to(self: Block, writer: anytype) !void { + pub fn write_to(self: Block, writer: *std.Io.Writer) !void { inline for (std.meta.fields(Block)) |field| { switch (field.type) { u32 => try writer.writeInt(u32, @field(self, field.name), .little), @@ -269,6 +265,8 @@ pub const Block = extern struct { }, } } + + try writer.flush(); } }; @@ -295,7 +293,6 @@ fn expect_equal_block(expected: Block, actual: Block) !void { test "Block loopback" { var buf: [512]u8 = undefined; - var fbs = std.io.fixedBufferStream(&buf); var prng = std.Random.DefaultPrng.init(0xf163bfab); var rand = prng.random(); @@ -312,13 +309,17 @@ test "Block loopback" { }; rand.bytes(&expected.data); - try expected.write_to(fbs.writer()); + { + var writer: std.io.Writer = .fixed(&buf); + try expected.write_to(&writer); + } - // needs to be reset for reader - fbs.reset(); - const actual = try Block.from_reader(fbs.reader()); + { + var reader: std.io.Reader = .fixed(&buf); + const actual = try Block.from_reader(&reader); - try expect_equal_block(expected, actual); + try expect_equal_block(expected, actual); + } } pub const FamilyId = enum(u32) { diff --git a/website/build.zig.zon b/website/build.zig.zon index 0fa079251..12a21d013 100644 --- a/website/build.zig.zon +++ b/website/build.zig.zon @@ -13,8 +13,8 @@ }, .dependencies = .{ .zine = .{ - .url = "git+https://github.com/kristoff-it/zine#ff0b7b1222fe6529fc36e876a71a99379ad761c4", - .hash = "zine-0.9.0-ou6nIEJTFgDwdlQnB6NtTnZneWKgg-qoVPaXyU2PjWF2", + .url = "git+https://github.com/kristoff-it/zine#b96e930630f8237aa4927fe14b9cb227061155d3", + .hash = "zine-0.11.1-ou6nIBB5FgAaYePTyiT2__fkGVNfImMOnpc_xKNXsYpF", }, }, } diff --git a/website/content/docs/getting-started.smd b/website/content/docs/getting-started.smd index 1d18b78fb..83e090f33 100644 --- a/website/content/docs/getting-started.smd +++ b/website/content/docs/getting-started.smd @@ -22,7 +22,7 @@ used for the [2024 SYCL](https://sycl.it) ## Let's Begin -Quickly check that you have Zig `0.14.1` installed by running `zig version`. +Quickly check that you have Zig `0.15.1` installed by running `zig version`. Assuming you've initialized a zig project with `zig init`, or have set one up yourself, you can add microzig as a dependency with the following command: diff --git a/website/content/index.smd b/website/content/index.smd index d7210692f..1ec15f261 100644 --- a/website/content/index.smd +++ b/website/content/index.smd @@ -28,7 +28,7 @@ Zig is an excellent programming language for embedded systems. explicit and even verbose at times. Nullable pointers, pointer casting, integer conversions, etc. -To learn more: [The Zig Language Reference](https://ziglang.org/documentation/0.14.1/) +To learn more: [The Zig Language Reference](https://ziglang.org/documentation/0.15.1/) ## Why MicroZig?