updates for zig 0.12.0

wch-ch32v003
Matt Knight 6 months ago
parent 09542f5e98
commit 12ff1b76e4

@ -2,9 +2,11 @@ name: Build
on: on:
push: push:
branches: [main] branches: [main, zig-master]
pull_request: pull_request:
branches: [main] branches: [main]
schedule:
- cron: "0 0 * * *"
jobs: jobs:
build: build:
@ -23,10 +25,27 @@ jobs:
- name: Setup Zig - name: Setup Zig
uses: goto-bus-stop/setup-zig@v2 uses: goto-bus-stop/setup-zig@v2
with: with:
version: master version: 0.12.0
- name: Build - name: Build
run: zig build -Doptimize=ReleaseSmall run: zig build -Doptimize=ReleaseSmall
- name: Unit Test BSPs
run: zig build run-bsp-tests -Doptimize=ReleaseSmall
- name: Dry run packaging - name: Dry run packaging
run: zig build package -- https://example.com if: ${{ matrix.os == 'macos-latest' }}
run: |
MICROZIG_VERSION=$(zig build package -- get-version)
echo microzig version: $MICROZIG_VERSION
zig build package -- http://localhost:8000
python3 -m http.server 8000 --directory boxzer-out &
sleep 1
cd tools/package-test
zig fetch --save=microzig http://localhost:8000/microzig-${MICROZIG_VERSION}.tar.gz
zig build -Doptimize=ReleaseSmall
zig build run-bsp-tests
# clean up server
jobs -p | xargs kill

@ -10,7 +10,7 @@ on:
jobs: jobs:
deploy-packages: deploy-packages:
runs-on: ubuntu-latest runs-on: macos-latest
steps: steps:
- name: Extract tag name - name: Extract tag name
run: echo "TAG_NAME=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV run: echo "TAG_NAME=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
@ -18,27 +18,33 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
fetch-tags: true # required for "git describe"
fetch-depth: 0 fetch-depth: 0
- name: Setup Zig - name: Setup Zig
uses: goto-bus-stop/setup-zig@v2 uses: goto-bus-stop/setup-zig@v2
with: with:
version: master version: 0.12.0
- name: Extract version
run: echo "MICROZIG_VERSION=$(zig build package -- get-version)" >> $GITHUB_ENV
- name: Assemble Packages - name: Assemble Packages
run: zig build package -- "${{ secrets.DOWNLOADS_URL }}" run: zig build package -- "${{ secrets.DOWNLOADS_URL }}"
# TODO: Validation
- name: Deploy - name: Deploy
uses: easingthemes/ssh-deploy@main uses: easingthemes/ssh-deploy@main
with: with:
SSH_PRIVATE_KEY: ${{ secrets.DEPLOY_PRIVATE_KEY }} SSH_PRIVATE_KEY: ${{ secrets.DEPLOY_PRIVATE_KEY }}
ARGS: "-vzrli" ARGS: "-vzrli"
SOURCE: "boxzer-out/${{ env.TAG_NAME }}/" SOURCE: "boxzer-out/"
REMOTE_HOST: ${{ secrets.DEPLOY_HOST }} REMOTE_HOST: ${{ secrets.DEPLOY_HOST }}
REMOTE_USER: ${{ secrets.DEPLOY_USER }} REMOTE_USER: ${{ secrets.DEPLOY_USER }}
REMOTE_PORT: ${{ secrets.DEPLOY_PORT }} REMOTE_PORT: ${{ secrets.DEPLOY_PORT }}
TARGET: "." TARGET: "."
- name: Create Release Draft
uses: ncipollo/release-action@v1
with:
artifactErrorsFailBuild: true
draft: true
generateReleaseNotes: true

@ -1,21 +1,19 @@
MIT License Copyright (c) Zig Embedded Group contributors
Copyright (c) 2022 Zig Embedded Group This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use
of this software.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is granted to anyone to use this software for any purpose, including
of this software and associated documentation files (the "Software"), to deal commercial applications, and to alter it and redistribute it freely, subject to
in the Software without restriction, including without limitation the rights the following restrictions:
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all 1. The origin of this software must not be misrepresented; you must not claim
copies or substantial portions of the Software. that you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is
not required.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2. Altered source versions must be plainly marked as such, and must not be
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, misrepresented as being the original software.
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 3. This notice may not be removed or altered from any source distribution.
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -8,7 +8,7 @@
## What version of Zig to use ## What version of Zig to use
Zig master/nightly Zig 0.12.0
## Getting Started With MicroZig ## Getting Started With MicroZig

@ -1,21 +1,19 @@
MIT License Copyright (c) Zig Embedded Group contributors
Copyright (c) 2022 Zig Embedded Group This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use
of this software.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is granted to anyone to use this software for any purpose, including
of this software and associated documentation files (the "Software"), to deal commercial applications, and to alter it and redistribute it freely, subject to
in the Software without restriction, including without limitation the rights the following restrictions:
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all 1. The origin of this software must not be misrepresented; you must not claim
copies or substantial portions of the Software. that you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is
not required.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2. Altered source versions must be plainly marked as such, and must not be
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, misrepresented as being the original software.
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 3. This notice may not be removed or altered from any source distribution.
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -1,9 +1,5 @@
= ESP MicroZig Package # ESP MicroZig Package
[WIP] [WIP]
SVD is copied from https://github.com/esp-rs/esp-pacs SVD is copied from https://github.com/esp-rs/esp-pacs
== What version of Zig to use
0.11.0

@ -1,8 +1,6 @@
const std = @import("std"); const std = @import("std");
const MicroZig = @import("microzig/build"); const MicroZig = @import("microzig/build");
pub const microzig_board_support = MicroZig.registerBoardSupport(@This());
fn path(comptime suffix: []const u8) std.Build.LazyPath { fn path(comptime suffix: []const u8) std.Build.LazyPath {
return .{ return .{
.cwd_relative = comptime ((std.fs.path.dirname(@src().file) orelse ".") ++ suffix), .cwd_relative = comptime ((std.fs.path.dirname(@src().file) orelse ".") ++ suffix),
@ -11,7 +9,7 @@ fn path(comptime suffix: []const u8) std.Build.LazyPath {
const esp_riscv = .{ const esp_riscv = .{
.name = "Espressif RISC-V", .name = "Espressif RISC-V",
.source_file = path("/src/cpus/espressif-riscv.zig"), .root_source_file = path("/src/cpus/espressif-riscv.zig"),
.target = std.zig.CrossTarget{ .target = std.zig.CrossTarget{
.cpu_arch = .riscv32, .cpu_arch = .riscv32,
.cpu_model = .{ .explicit = &std.Target.riscv.cpu.generic_rv32 }, .cpu_model = .{ .explicit = &std.Target.riscv.cpu.generic_rv32 },
@ -25,7 +23,7 @@ const esp_riscv = .{
}; };
const hal = .{ const hal = .{
.source_file = path("/src/hals/ESP32_C3.zig"), .root_source_file = path("/src/hals/ESP32_C3.zig"),
}; };
pub const chips = struct { pub const chips = struct {
@ -50,32 +48,8 @@ pub const chips = struct {
}; };
}; };
pub const boards = struct { pub const boards = struct {};
// empty right now
};
pub fn build(b: *std.Build) void { pub fn build(b: *std.Build) void {
_ = b; _ = b.step("test", "Run platform agnostic unit tests");
// const optimize = b.standardOptimizeOption(.{});
// var exe = microzig.addEmbeddedExecutable(b, .{
// .name = "esp-bringup",
// .source_file = .{
// .path = "src/example/blinky.zig",
// },
// .backing = .{ .chip = chips.esp32_c3 },
// .optimize = optimize,
// });
// const fw_objcopy = b.addObjCopy(exe.inner.getEmittedBin(), .{
// .format = .bin,
// });
// const fw_bin = fw_objcopy.getOutput();
// const install_fw_bin = b.addInstallFile(fw_bin, "firmware/blinky.bin");
// b.getInstallStep().dependOn(&install_fw_bin.step);
// b.installArtifact(exe.inner);
} }

@ -5,7 +5,11 @@
.@"microzig/build" = .{ .path = "../../../build" }, .@"microzig/build" = .{ .path = "../../../build" },
}, },
.paths = .{ .paths = .{
"LICENSE",
"README.md",
"build.zig", "build.zig",
"build.zig.zon", "build.zig.zon",
"src",
"docs",
}, },
} }

@ -1,4 +1,4 @@
Copyright (c) 2022 Zig Embedded Group Contributors Copyright (c) Zig Embedded Group contributors
This software is provided 'as-is', without any express or implied warranty. In This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use no event will the authors be held liable for any damages arising from the use
@ -9,11 +9,11 @@ commercial applications, and to alter it and redistribute it freely, subject to
the following restrictions: the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim 1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a product, an that you wrote the original software. If you use this software in a product,
acknowledgment in the product documentation would be appreciated but is not an acknowledgment in the product documentation would be appreciated but is
required. not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.

@ -1,6 +0,0 @@
= GigaDevice GD32 Hardware Support Package
== What version of Zig to use
Right now we are following https://ziglang.org/download/[master], but once 0.11.0 is released, we will be switching to the latest stable version of Zig.

@ -0,0 +1 @@
# GigaDevice GD32 Hardware Support Package

@ -2,8 +2,6 @@ const std = @import("std");
const Build = std.Build; const Build = std.Build;
const MicroZig = @import("microzig/build"); const MicroZig = @import("microzig/build");
pub const microzig_board_support = MicroZig.registerBoardSupport(@This());
fn path(comptime suffix: []const u8) std.Build.LazyPath { fn path(comptime suffix: []const u8) std.Build.LazyPath {
return .{ return .{
.cwd_relative = comptime ((std.fs.path.dirname(@src().file) orelse ".") ++ suffix), .cwd_relative = comptime ((std.fs.path.dirname(@src().file) orelse ".") ++ suffix),
@ -11,7 +9,7 @@ fn path(comptime suffix: []const u8) std.Build.LazyPath {
} }
const hal = .{ const hal = .{
.source_file = path("/src/hals/GD32VF103.zig"), .root_source_file = path("/src/hals/GD32VF103.zig"),
}; };
pub const chips = struct { pub const chips = struct {
@ -57,42 +55,12 @@ pub const boards = struct {
.board = .{ .board = .{
.name = "Longan Nano", .name = "Longan Nano",
.url = "https://longan.sipeed.com/en/", .url = "https://longan.sipeed.com/en/",
.source_file = path("/src/boards/longan_nano.zig"), .root_source_file = path("/src/boards/longan_nano.zig"),
}, },
}; };
}; };
}; };
pub fn build(b: *Build) void { pub fn build(b: *Build) void {
_ = b; _ = b.step("test", "Run platform agnostic unit tests");
// const optimize = b.standardOptimizeOption(.{});
// inline for (@typeInfo(boards).Struct.decls) |decl| {
// if (!decl.is_pub)
// continue;
// const exe = microzig.addEmbeddedExecutable(b, .{
// .name = @field(boards, decl.name).name ++ ".minimal",
// .source_file = .{
// .path = "test/programs/minimal.zig",
// },
// .backing = .{ .board = @field(boards, decl.name) },
// .optimize = optimize,
// });
// exe.installArtifact(b);
// }
// inline for (@typeInfo(chips).Struct.decls) |decl| {
// if (!decl.is_pub)
// continue;
// const exe = microzig.addEmbeddedExecutable(b, .{
// .name = @field(chips, decl.name).name ++ ".minimal",
// .source_file = .{
// .path = "test/programs/minimal.zig",
// },
// .backing = .{ .chip = @field(chips, decl.name) },
// .optimize = optimize,
// });
// exe.installArtifact(b);
// }
} }

@ -5,7 +5,11 @@
.@"microzig/build" = .{ .path = "../../../build" }, .@"microzig/build" = .{ .path = "../../../build" },
}, },
.paths = .{ .paths = .{
"LICENSE",
"README.md",
"build.zig", "build.zig",
"build.zig.zon", "build.zig.zon",
"src",
"test",
}, },
} }

@ -1,4 +1,4 @@
Copyright (c) 2022 Zig Embedded Group Contributors Copyright (c) Zig Embedded Group contributors
This software is provided 'as-is', without any express or implied warranty. In This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use no event will the authors be held liable for any damages arising from the use
@ -9,11 +9,11 @@ commercial applications, and to alter it and redistribute it freely, subject to
the following restrictions: the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim 1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a product, an that you wrote the original software. If you use this software in a product,
acknowledgment in the product documentation would be appreciated but is not an acknowledgment in the product documentation would be appreciated but is
required. not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.

@ -1,11 +1,8 @@
const std = @import("std"); const std = @import("std");
const MicroZig = @import("microzig/build"); const MicroZig = @import("microzig/build");
pub const microzig_board_support = MicroZig.registerBoardSupport(@This());
pub fn build(b: *std.Build) void { pub fn build(b: *std.Build) void {
_ = b; _ = b.step("test", "Run platform agnostic unit tests");
// Dummy func to make package manager happy
} }
fn root() []const u8 { fn root() []const u8 {
@ -25,7 +22,7 @@ pub const chips = struct {
.atdf = .{ .path = build_root ++ "/src/chips/ATSAMD51J19A.atdf" }, .atdf = .{ .path = build_root ++ "/src/chips/ATSAMD51J19A.atdf" },
}, },
.memory_regions = &.{ .memory_regions = &.{
.{ .kind = .flash, .offset = 0x00004000, .length = 512 * 1024 }, // Embedded Flash .{ .kind = .flash, .offset = 0x00000000, .length = 512 * 1024 }, // Embedded Flash
.{ .kind = .ram, .offset = 0x20000000, .length = 192 * 1024 }, // Embedded SRAM .{ .kind = .ram, .offset = 0x20000000, .length = 192 * 1024 }, // Embedded SRAM
.{ .kind = .ram, .offset = 0x47000000, .length = 8 * 1024 }, // Backup SRAM .{ .kind = .ram, .offset = 0x47000000, .length = 8 * 1024 }, // Backup SRAM
.{ .kind = .flash, .offset = 0x00804000, .length = 512 }, // NVM User Row .{ .kind = .flash, .offset = 0x00804000, .length = 512 }, // NVM User Row

@ -5,7 +5,10 @@
.@"microzig/build" = .{ .path = "../../../build" }, .@"microzig/build" = .{ .path = "../../../build" },
}, },
.paths = .{ .paths = .{
"LICENSE",
"README.md",
"build.zig", "build.zig",
"build.zig.zon", "build.zig.zon",
"src",
}, },
} }

@ -1,4 +1,4 @@
Copyright (c) 2022 Zig Embedded Group Contributors Copyright (c) Zig Embedded Group contributors
This software is provided 'as-is', without any express or implied warranty. In This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use no event will the authors be held liable for any damages arising from the use
@ -9,11 +9,11 @@ commercial applications, and to alter it and redistribute it freely, subject to
the following restrictions: the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim 1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a product, an that you wrote the original software. If you use this software in a product,
acknowledgment in the product documentation would be appreciated but is not an acknowledgment in the product documentation would be appreciated but is
required. not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.

@ -1,24 +1,18 @@
= Microchip ATmega Hardware Support Package # Microchip ATmega Hardware Support Package
Note: for testing, renode supports arduino nano 33 BLE Note: for testing, renode supports arduino nano 33 BLE
== What version of Zig to use ## FYI: LLVM issues
Right now we are following https://ziglang.org/download/[master], but once 0.11.0 is released, we will be switching to the latest stable version of Zig.
== FYI: LLVM issues
Currently LLVM is having trouble lowering AVR when this is built in debug mode: Currently LLVM is having trouble lowering AVR when this is built in debug mode:
[source] ```
----
LLVM Emit Object... Don't know how to custom lower this! LLVM Emit Object... Don't know how to custom lower this!
UNREACHABLE executed at /Users/mattnite/code/llvm-project-15/llvm/lib/Target/AVR/AVRISelLowering.cpp:842! UNREACHABLE executed at /Users/mattnite/code/llvm-project-15/llvm/lib/Target/AVR/AVRISelLowering.cpp:842!
---- ```
for now always build in release small: for now always build in release small:
[source] ```
----
zig build -Doptimize=ReleaseSmall zig build -Doptimize=ReleaseSmall
---- ```

@ -2,8 +2,6 @@ const std = @import("std");
const Build = std.Build; const Build = std.Build;
const MicroZig = @import("microzig/build"); const MicroZig = @import("microzig/build");
pub const microzig_board_support = MicroZig.registerBoardSupport(@This());
fn path(comptime suffix: []const u8) Build.LazyPath { fn path(comptime suffix: []const u8) Build.LazyPath {
return .{ return .{
.cwd_relative = comptime ((std.fs.path.dirname(@src().file) orelse ".") ++ suffix), .cwd_relative = comptime ((std.fs.path.dirname(@src().file) orelse ".") ++ suffix),
@ -11,7 +9,7 @@ fn path(comptime suffix: []const u8) Build.LazyPath {
} }
const hal = .{ const hal = .{
.source_file = path("/src/hals/ATmega328P.zig"), .root_source_file = path("/src/hals/ATmega328P.zig"),
}; };
pub const chips = struct { pub const chips = struct {
@ -42,7 +40,7 @@ pub const boards = struct {
.board = .{ .board = .{
.name = "Arduino Nano", .name = "Arduino Nano",
.url = "https://docs.arduino.cc/hardware/nano", .url = "https://docs.arduino.cc/hardware/nano",
.source_file = path("/src/boards/arduino_nano.zig"), .root_source_file = path("/src/boards/arduino_nano.zig"),
}, },
}; };
@ -53,36 +51,12 @@ pub const boards = struct {
.board = .{ .board = .{
.name = "Arduino Uno", .name = "Arduino Uno",
.url = "https://docs.arduino.cc/hardware/uno-rev3", .url = "https://docs.arduino.cc/hardware/uno-rev3",
.source_file = path("/src/boards/arduino_uno.zig"), .root_source_file = path("/src/boards/arduino_uno.zig"),
}, },
}; };
}; };
}; };
pub fn build(b: *Build) void { pub fn build(b: *Build) void {
_ = b; _ = b.step("test", "Run platform agnostic unit tests");
// const optimize = b.standardOptimizeOption(.{});
// inline for (@typeInfo(boards).Struct.decls) |decl| {
// const exe = microzig.addEmbeddedExecutable(b, .{
// .name = @field(boards, decl.name).name ++ ".minimal",
// .source_file = .{
// .path = "test/programs/minimal.zig",
// },
// .backing = .{ .board = @field(boards, decl.name) },
// .optimize = optimize,
// });
// exe.installArtifact(b);
// }
// inline for (@typeInfo(chips).Struct.decls) |decl| {
// const exe = microzig.addEmbeddedExecutable(b, .{
// .name = @field(chips, decl.name).name ++ ".minimal",
// .source_file = .{
// .path = "test/programs/minimal.zig",
// },
// .backing = .{ .chip = @field(chips, decl.name) },
// .optimize = optimize,
// });
// exe.installArtifact(b);
// }
} }

@ -5,7 +5,10 @@
.@"microzig/build" = .{ .path = "../../../build" }, .@"microzig/build" = .{ .path = "../../../build" },
}, },
.paths = .{ .paths = .{
"LICENSE",
"README.md",
"build.zig", "build.zig",
"build.zig.zon", "build.zig.zon",
"src",
}, },
} }

@ -0,0 +1,19 @@
Copyright (c) Zig Embedded Group contributors
This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use
of this software.
Permission is granted to anyone to use this software for any purpose, including
commercial applications, and to alter it and redistribute it freely, subject to
the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is
not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

@ -1,11 +0,0 @@
= Nordic nrf5x
HALs and register definitions for nrf5x devices
== What version of Zig to use
Right now we are following https://ziglang.org/download/[master], but once 0.11.0 is released, we will be switching to the latest stable version of Zig.
== Renode supports:
- nrf52840 development kit

@ -0,0 +1,7 @@
# Nordic nrf5x
HALs and register definitions for nrf5x devices
## Renode supports:
- nrf52840 development kit

@ -2,8 +2,6 @@ const std = @import("std");
const Build = std.Build; const Build = std.Build;
const MicroZig = @import("microzig/build"); const MicroZig = @import("microzig/build");
pub const microzig_board_support = MicroZig.registerBoardSupport(@This());
fn path(comptime suffix: []const u8) std.Build.LazyPath { fn path(comptime suffix: []const u8) std.Build.LazyPath {
return .{ return .{
.cwd_relative = comptime ((std.fs.path.dirname(@src().file) orelse ".") ++ suffix), .cwd_relative = comptime ((std.fs.path.dirname(@src().file) orelse ".") ++ suffix),
@ -51,19 +49,17 @@ pub const chips = struct {
}; };
pub const boards = struct { pub const boards = struct {
pub const nordic = struct { pub const nordic_nRF52840_Dongle = MicroZig.Target{
pub const nRF52840_Dongle = MicroZig.Target{ .preferred_format = .elf,
.preferred_format = .elf, .chip = chips.nrf52840.chip,
.chip = chips.nrf52840.chip, .board = .{
.board = .{ .name = "nRF52840 Dongle",
.name = "nRF52840 Dongle", .url = "https://www.nordicsemi.com/Products/Development-hardware/nrf52840-dongle",
.url = "https://www.nordicsemi.com/Products/Development-hardware/nrf52840-dongle", .root_source_file = path("/src/boards/nrf52840-dongle.zig"),
.source_file = path("/src/boards/nrf52840-dongle.zig"), },
},
};
}; };
}; };
pub fn build(b: *Build) void { pub fn build(b: *Build) void {
_ = b; _ = b.step("test", "Run platform agnostic unit tests");
} }

@ -5,8 +5,12 @@
.@"microzig/build" = .{ .path = "../../../build" }, .@"microzig/build" = .{ .path = "../../../build" },
}, },
.paths = .{ .paths = .{
"LICENSE",
"README.md",
"build.zig", "build.zig",
"build.zig.zon", "build.zig.zon",
"src",
"test",
}, },
} }

@ -1,4 +1,4 @@
Copyright (c) 2022 Zig Embedded Group Contributors Copyright (c) Zig Embedded Group contributors
This software is provided 'as-is', without any express or implied warranty. In This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use no event will the authors be held liable for any damages arising from the use
@ -9,11 +9,11 @@ commercial applications, and to alter it and redistribute it freely, subject to
the following restrictions: the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim 1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a product, an that you wrote the original software. If you use this software in a product,
acknowledgment in the product documentation would be appreciated but is not an acknowledgment in the product documentation would be appreciated but is
required. not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.

@ -1,7 +0,0 @@
= NXP LPC Hardware Support Package
Please see https://github.com/ZigEmbeddedGroup/lpcboot[lpcboot] as well
== What version of Zig to use
Right now we are following https://ziglang.org/download/[master], but once 0.11.0 is released, we will be switching to the latest stable version of Zig.

@ -0,0 +1,3 @@
# NXP LPC Hardware Support Package
Please see [lpcboot](https://github.com/ZigEmbeddedGroup/lpcboot) as well

@ -1,8 +1,6 @@
const std = @import("std"); const std = @import("std");
const MicroZig = @import("microzig/build"); const MicroZig = @import("microzig/build");
pub const microzig_board_support = MicroZig.registerBoardSupport(@This());
fn path(comptime suffix: []const u8) std.Build.LazyPath { fn path(comptime suffix: []const u8) std.Build.LazyPath {
return .{ return .{
.cwd_relative = comptime ((std.fs.path.dirname(@src().file) orelse ".") ++ suffix), .cwd_relative = comptime ((std.fs.path.dirname(@src().file) orelse ".") ++ suffix),
@ -10,7 +8,7 @@ fn path(comptime suffix: []const u8) std.Build.LazyPath {
} }
const hal = .{ const hal = .{
.source_file = path("/src/hals/LPC176x5x.zig"), .root_source_file = path("/src/hals/LPC176x5x.zig"),
}; };
pub const chips = struct { pub const chips = struct {
@ -43,7 +41,7 @@ pub const boards = struct {
.board = .{ .board = .{
.name = "mbed LPC1768", .name = "mbed LPC1768",
.url = "https://os.mbed.com/platforms/mbed-LPC1768/", .url = "https://os.mbed.com/platforms/mbed-LPC1768/",
.source_file = path("/src/boards/mbed_LPC1768.zig"), .root_source_file = path("/src/boards/mbed_LPC1768.zig"),
}, },
.binary_post_process = postprocess, .binary_post_process = postprocess,
}; };
@ -65,35 +63,5 @@ fn postprocess(b: *std.Build, input: std.Build.LazyPath) std.Build.LazyPath {
} }
pub fn build(b: *std.Build) void { pub fn build(b: *std.Build) void {
_ = b; _ = b.step("test", "Run platform agnostic unit tests");
// const optimize = b.standardOptimizeOption(.{});
// inline for (@typeInfo(boards).Struct.decls) |decl| {
// if (!decl.is_pub)
// continue;
// const exe = microzig.addEmbeddedExecutable(b, .{
// .name = @field(boards, decl.name).name ++ ".minimal",
// .source_file = .{
// .path = "test/programs/minimal.zig",
// },
// .backing = .{ .board = @field(boards, decl.name) },
// .optimize = optimize,
// });
// exe.installArtifact(b);
// }
// inline for (@typeInfo(chips).Struct.decls) |decl| {
// if (!decl.is_pub)
// continue;
// const exe = microzig.addEmbeddedExecutable(b, .{
// .name = @field(chips, decl.name).name ++ ".minimal",
// .source_file = .{
// .path = "test/programs/minimal.zig",
// },
// .backing = .{ .chip = @field(chips, decl.name) },
// .optimize = optimize,
// });
// exe.installArtifact(b);
// }
} }

@ -5,7 +5,11 @@
.@"microzig/build" = .{ .path = "../../../build" }, .@"microzig/build" = .{ .path = "../../../build" },
}, },
.paths = .{ .paths = .{
"LICENSE",
"README.md",
"build.zig", "build.zig",
"build.zig.zon", "build.zig.zon",
"src",
"test",
}, },
} }

@ -1,11 +1,19 @@
Copyright (c) 2022 Zig Embedded Group contributors Copyright (c) Zig Embedded Group contributors
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use
of this software.
Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: Permission is granted to anyone to use this software for any purpose, including
commercial applications, and to alter it and redistribute it freely, subject to
the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is
not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.

@ -1,17 +0,0 @@
= raspberrypi-rp2040
HAL and register definitions for the RP2040.
== What version of Zig to use
0.11.0
== Supported devices ==
- Raspberry Pi RP2040 (`chips.rp2040`)
- Raspberry Pi Pico (`boards.raspberry_pi.pico`)
- (*experimental*) Waveshare RP2040-Plus (4M Flash) (`boards.waveshare.rp2040_plus_4m`)
- (*experimental*) Waveshare RP2040-Plus (16M Flash) (`boards.waveshare.rp2040_plus_16m`)
- (*experimental*) Waveshare RP2040-ETH Mini (`boards.waveshare.rp2040_eth`)
- (*experimental*) Waveshare RP2040-Matrix (`boards.waveshare.rp2040_matrix`)

@ -0,0 +1,7 @@
# raspberrypi-rp2040
HAL and register definitions for the RP2040.
## What version of Zig to use
0.12.0

@ -11,8 +11,14 @@ fn root() []const u8 {
const build_root = root(); const build_root = root();
pub fn build(b: *Build) !void { pub fn build(b: *Build) !void {
// Dummy func to make package manager happy const unit_tests = b.addTest(.{
_ = b; .root_source_file = .{ .path = "src/hal.zig" },
});
unit_tests.addIncludePath(.{ .path = "src/hal/pio/assembler" });
const unit_tests_run = b.addRunArtifact(unit_tests);
const test_step = b.step("test", "Run platform agnostic unit tests");
test_step.dependOn(&unit_tests_run.step);
} }
pub const chips = struct { pub const chips = struct {
@ -35,7 +41,7 @@ pub const boards = struct {
.linker_script = linker_script, .linker_script = linker_script,
.board = .{ .board = .{
.name = "RaspberryPi Pico", .name = "RaspberryPi Pico",
.source_file = .{ .cwd_relative = build_root ++ "/src/boards/raspberry_pi_pico.zig" }, .root_source_file = .{ .cwd_relative = build_root ++ "/src/boards/raspberry_pi_pico.zig" },
.url = "https://www.raspberrypi.com/products/raspberry-pi-pico/", .url = "https://www.raspberrypi.com/products/raspberry-pi-pico/",
}, },
.configure = rp2040_configure(.w25q080), .configure = rp2040_configure(.w25q080),
@ -50,7 +56,7 @@ pub const boards = struct {
.linker_script = linker_script, .linker_script = linker_script,
.board = .{ .board = .{
.name = "Waveshare RP2040-Plus (4M Flash)", .name = "Waveshare RP2040-Plus (4M Flash)",
.source_file = .{ .cwd_relative = build_root ++ "/src/boards/waveshare_rp2040_plus_4m.zig" }, .root_source_file = .{ .cwd_relative = build_root ++ "/src/boards/waveshare_rp2040_plus_4m.zig" },
.url = "https://www.waveshare.com/rp2040-plus.htm", .url = "https://www.waveshare.com/rp2040-plus.htm",
}, },
.configure = rp2040_configure(.w25q080), .configure = rp2040_configure(.w25q080),
@ -63,7 +69,7 @@ pub const boards = struct {
.linker_script = linker_script, .linker_script = linker_script,
.board = .{ .board = .{
.name = "Waveshare RP2040-Plus (16M Flash)", .name = "Waveshare RP2040-Plus (16M Flash)",
.source_file = .{ .cwd_relative = build_root ++ "/src/boards/waveshare_rp2040_plus_16m.zig" }, .root_source_file = .{ .cwd_relative = build_root ++ "/src/boards/waveshare_rp2040_plus_16m.zig" },
.url = "https://www.waveshare.com/rp2040-plus.htm", .url = "https://www.waveshare.com/rp2040-plus.htm",
}, },
.configure = rp2040_configure(.w25q080), .configure = rp2040_configure(.w25q080),
@ -76,7 +82,7 @@ pub const boards = struct {
.linker_script = linker_script, .linker_script = linker_script,
.board = .{ .board = .{
.name = "Waveshare RP2040-ETH Mini", .name = "Waveshare RP2040-ETH Mini",
.source_file = .{ .cwd_relative = build_root ++ "/src/boards/waveshare_rp2040_eth.zig" }, .root_source_file = .{ .cwd_relative = build_root ++ "/src/boards/waveshare_rp2040_eth.zig" },
.url = "https://www.waveshare.com/rp2040-eth.htm", .url = "https://www.waveshare.com/rp2040-eth.htm",
}, },
.configure = rp2040_configure(.w25q080), .configure = rp2040_configure(.w25q080),
@ -89,7 +95,7 @@ pub const boards = struct {
.linker_script = linker_script, .linker_script = linker_script,
.board = .{ .board = .{
.name = "Waveshare RP2040-Matrix", .name = "Waveshare RP2040-Matrix",
.source_file = .{ .cwd_relative = build_root ++ "/src/boards/waveshare_rp2040_matrix.zig" }, .root_source_file = .{ .cwd_relative = build_root ++ "/src/boards/waveshare_rp2040_matrix.zig" },
.url = "https://www.waveshare.com/rp2040-matrix.htm", .url = "https://www.waveshare.com/rp2040-matrix.htm",
}, },
.configure = rp2040_configure(.w25q080), .configure = rp2040_configure(.w25q080),
@ -117,7 +123,7 @@ const linker_script = .{
}; };
const hal = .{ const hal = .{
.source_file = .{ .cwd_relative = build_root ++ "/src/hal.zig" }, .root_source_file = .{ .cwd_relative = build_root ++ "/src/hal.zig" },
}; };
const chip = .{ const chip = .{
@ -125,7 +131,7 @@ const chip = .{
.url = "https://www.raspberrypi.com/products/rp2040/", .url = "https://www.raspberrypi.com/products/rp2040/",
.cpu = MicroZig.cpus.cortex_m0plus, .cpu = MicroZig.cpus.cortex_m0plus,
.register_definition = .{ .register_definition = .{
.json = .{ .cwd_relative = build_root ++ "/src/chips/RP2040.json" }, .svd = .{ .cwd_relative = build_root ++ "/src/chips/rp2040.svd" },
}, },
.memory_regions = &.{ .memory_regions = &.{
.{ .kind = .flash, .offset = 0x10000100, .length = (2048 * 1024) - 256 }, .{ .kind = .flash, .offset = 0x10000100, .length = (2048 * 1024) - 256 },
@ -181,11 +187,10 @@ pub fn get_bootrom(mz: *MicroZig, rom: BootROM) Stage2Bootloader {
.target = mz.host_build.resolveTargetQuery(target), .target = mz.host_build.resolveTargetQuery(target),
.root_source_file = null, .root_source_file = null,
}); });
rom_exe.linkage = .static; //rom_exe.linkage = .static;
// rom_exe.pie = false;
// rom_exe.force_pic = false;
rom_exe.setLinkerScript(.{ .path = build_root ++ "/src/bootroms/shared/stage2.ld" }); rom_exe.setLinkerScript(.{ .path = build_root ++ "/src/bootroms/shared/stage2.ld" });
rom_exe.addAssemblyFile(.{ .path = rom_path }); rom_exe.addAssemblyFile(.{ .path = rom_path });
rom_exe.entry = .{ .symbol_name = "_stage2_boot" };
break :blk rom_exe; break :blk rom_exe;
}, },
@ -201,66 +206,3 @@ pub fn get_bootrom(mz: *MicroZig, rom: BootROM) Stage2Bootloader {
.elf = rom_exe.getEmittedBin(), .elf = rom_exe.getEmittedBin(),
}; };
} }
/////////////////////////////////////////
// MicroZig Legacy Interface //
/////////////////////////////////////////
// // this build script is mostly for testing and verification of this
// // package. In an attempt to modularize -- designing for a case where a
// // project requires multiple HALs, it accepts microzig as a param
// pub fn build(b: *Build) !void {
// const optimize = b.standardOptimizeOption(.{});
// const args_dep = b.dependency("args", .{});
// const args_mod = args_dep.module("args");
// var examples = Examples.init(b, optimize);
// examples.install(b);
// const pio_tests = b.addTest(.{
// .root_source_file = .{
// .path = "src/hal.zig",
// },
// .optimize = optimize,
// });
// pio_tests.addIncludePath(.{ .path = "src/hal/pio/assembler" });
// const test_step = b.step("test", "run unit tests");
// test_step.dependOn(&b.addRunArtifact(pio_tests).step);
// {
// const flash_tool = b.addExecutable(.{
// .name = "rp2040-flash",
// .optimize = .Debug,
// .target = .{},
// .root_source_file = .{ .path = "tools/rp2040-flash.zig" },
// });
// flash_tool.addModule("args", args_mod);
// b.installArtifact(flash_tool);
// }
// // Install all bootroms for debugging and CI
// inline for (comptime std.enums.values(std.meta.Tag(BootROM))) |rom| {
// if (rom == .artifact or rom == .blob) {
// continue;
// }
// if (rom == .is25lp080) {
// // TODO: https://github.com/ZigEmbeddedGroup/raspberrypi-rp2040/issues/79
// // is25lp080.o:(text+0x16): has non-ABS relocation R_ARM_THM_CALL against symbol 'read_flash_sreg'
// continue;
// }
// const files = get_bootrom(b, rom);
// if (files.elf) |elf| {
// b.getInstallStep().dependOn(
// &b.addInstallFileWithDir(elf, .{ .custom = "stage2" }, b.fmt("{s}.elf", .{@tagName(rom)})).step,
// );
// }
// b.getInstallStep().dependOn(
// &b.addInstallFileWithDir(files.bin, .{ .custom = "stage2" }, b.fmt("{s}.bin", .{@tagName(rom)})).step,
// );
// }
// }

@ -7,6 +7,12 @@
}, },
}, },
.paths = .{ .paths = .{
"LICENSE",
"README.md",
"build.zig.zon", "build.zig.zon",
"build.zig",
"src",
"tools",
"rp2040.ld",
}, },
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -39,19 +39,19 @@ pub const IrqLevel = enum(u2) {
pub const IrqCallback = fn (gpio: u32, events: u32) callconv(.C) void; pub const IrqCallback = fn (gpio: u32, events: u32) callconv(.C) void;
pub const Override = enum { pub const Override = enum(u2) {
normal, normal,
invert, invert,
low, low,
high, high,
}; };
pub const SlewRate = enum { pub const SlewRate = enum(u1) {
slow, slow,
fast, fast,
}; };
pub const DriveStrength = enum { pub const DriveStrength = enum(u2) {
@"2mA", @"2mA",
@"4mA", @"4mA",
@"8mA", @"8mA",

@ -392,7 +392,7 @@ pub fn Pins(comptime config: GlobalConfiguration) type {
return @Type(.{ return @Type(.{
.Struct = .{ .Struct = .{
.layout = .Auto, .layout = .auto,
.is_tuple = false, .is_tuple = false,
.fields = fields, .fields = fields,
.decls = &.{}, .decls = &.{},

@ -10,7 +10,7 @@ const PIO1 = microzig.chip.peripherals.PIO1;
const gpio = @import("gpio.zig"); const gpio = @import("gpio.zig");
const resets = @import("resets.zig"); const resets = @import("resets.zig");
const hw = @import("hw.zig"); const hw = @import("hw.zig");
const assembler = @import("pio/assembler.zig"); pub const assembler = @import("pio/assembler.zig");
const encoder = @import("pio/assembler/encoder.zig"); const encoder = @import("pio/assembler/encoder.zig");
// global state for keeping track of used things // global state for keeping track of used things

@ -86,9 +86,9 @@ pub fn assemble_impl(comptime source: []const u8, diags: *?Diagnostics, options:
.name = define.name, .name = define.name,
.value = define.value, .value = define.value,
}) catch unreachable; }) catch unreachable;
break :blk tmp.slice(); break :blk tmp.constSlice();
}, },
.programs = programs.slice(), .programs = programs.constSlice(),
}; };
} }

@ -1,4 +0,0 @@
= PIO example programs for testing
These were all taken from https://github.com/raspberrypi/pico-examples[the official pico examples repo].
The headers are generated using `pioasm`.

@ -0,0 +1,4 @@
# PIO example programs for testing
These were all taken from [the official pico examples repo](https://github.com/raspberrypi/pico-examples).
The headers are generated using `pioasm`.

@ -78,22 +78,25 @@ pub fn Encoder(comptime options: Options) type {
pub fn to_exported_program(comptime bounded: BoundedProgram) assembler.Program { pub fn to_exported_program(comptime bounded: BoundedProgram) assembler.Program {
comptime var program_name: [bounded.name.len]u8 = undefined; comptime var program_name: [bounded.name.len]u8 = undefined;
std.mem.copyForwards(u8, &program_name, bounded.name); std.mem.copyForwards(u8, &program_name, bounded.name);
const name_const = program_name;
return assembler.Program{ return assembler.Program{
.name = &program_name, .name = &name_const,
.defines = blk: { .defines = blk: {
var tmp = std.BoundedArray(assembler.Define, options.max_defines).init(0) catch unreachable; var tmp = std.BoundedArray(assembler.Define, options.max_defines).init(0) catch unreachable;
for (bounded.defines.slice()) |define| { for (bounded.defines.slice()) |define| {
comptime var define_name: [define.name.len]u8 = undefined; comptime var define_name: [define.name.len]u8 = undefined;
std.mem.copyForwards(u8, &define_name, define.name); std.mem.copyForwards(u8, &define_name, define.name);
const const_def_name = define_name;
tmp.append(.{ tmp.append(.{
.name = &define_name, .name = &const_def_name,
.value = @as(i64, @intCast(define.value)), .value = @as(i64, @intCast(define.value)),
}) catch unreachable; }) catch unreachable;
} }
break :blk tmp.slice(); const defines_const = tmp;
break :blk defines_const.constSlice();
}, },
.instructions = @as([]const u16, @ptrCast(bounded.instructions.slice())), .instructions = @as([]const u16, @ptrCast(bounded.instructions.constSlice())),
.origin = bounded.origin, .origin = bounded.origin,
.side_set = bounded.side_set, .side_set = bounded.side_set,
.wrap_target = bounded.wrap_target, .wrap_target = bounded.wrap_target,

@ -1151,7 +1151,7 @@ const DirectiveTag = @typeInfo(Token.Directive).Union.tag_type.?;
const PayloadTag = @typeInfo(Token.Instruction.Payload).Union.tag_type.?; const PayloadTag = @typeInfo(Token.Instruction.Payload).Union.tag_type.?;
fn expect_program(expected: []const u8, actual: Token) !void { fn expect_program(expected: []const u8, actual: Token) !void {
try expectEqual(Token.Tag.program, actual.data); try expectEqual(Token.Tag.program, @as(Token.Tag, actual.data));
try expectEqualStrings(expected, actual.data.program); try expectEqualStrings(expected, actual.data.program);
} }
@ -1173,7 +1173,7 @@ fn expect_opt_value(expected: ?Value, actual: ?Value) !void {
} }
fn expect_define(expected: Token.Define, actual: Token) !void { fn expect_define(expected: Token.Define, actual: Token) !void {
try expectEqual(Token.Tag.define, actual.data); try expectEqual(Token.Tag.define, @as(Token.Tag, actual.data));
const define = actual.data.define; const define = actual.data.define;
try expectEqualStrings(expected.name, define.name); try expectEqualStrings(expected.name, define.name);
@ -1181,12 +1181,12 @@ fn expect_define(expected: Token.Define, actual: Token) !void {
} }
fn expect_origin(expected: Value, actual: Token) !void { fn expect_origin(expected: Value, actual: Token) !void {
try expectEqual(Token.Tag.origin, actual.data); try expectEqual(Token.Tag.origin, @as(Token.Tag, actual.data));
try expect_value(expected, actual.data.origin); try expect_value(expected, actual.data.origin);
} }
fn expect_side_set(expected: Token.SideSet, actual: Token) !void { fn expect_side_set(expected: Token.SideSet, actual: Token) !void {
try expectEqual(Token.Tag.side_set, actual.data); try expectEqual(Token.Tag.side_set, @as(Token.Tag, actual.data));
const side_set = actual.data.side_set; const side_set = actual.data.side_set;
try expect_value(expected.count, side_set.count); try expect_value(expected.count, side_set.count);
@ -1195,15 +1195,15 @@ fn expect_side_set(expected: Token.SideSet, actual: Token) !void {
} }
fn expect_wrap_target(actual: Token) !void { fn expect_wrap_target(actual: Token) !void {
try expectEqual(Token.Tag.wrap_target, actual.data); try expectEqual(Token.Tag.wrap_target, @as(Token.Tag, actual.data));
} }
fn expect_wrap(actual: Token) !void { fn expect_wrap(actual: Token) !void {
try expectEqual(Token.Tag.wrap, actual.data); try expectEqual(Token.Tag.wrap, @as(Token.Tag, actual.data));
} }
fn expect_lang_opt(expected: Token.LangOpt, actual: Token) !void { fn expect_lang_opt(expected: Token.LangOpt, actual: Token) !void {
try expectEqual(Token.Tag.lang_opt, actual.data); try expectEqual(Token.Tag.lang_opt, @as(Token.Tag, actual.data));
const lang_opt = actual.data.lang_opt; const lang_opt = actual.data.lang_opt;
try expectEqualStrings(expected.lang, lang_opt.lang); try expectEqualStrings(expected.lang, lang_opt.lang);
@ -1212,12 +1212,12 @@ fn expect_lang_opt(expected: Token.LangOpt, actual: Token) !void {
} }
fn expect_word(expected: Value, actual: Token) !void { fn expect_word(expected: Value, actual: Token) !void {
try expectEqual(Token.Tag.word, actual.data); try expectEqual(Token.Tag.word, @as(Token.Tag, actual.data));
try expect_value(expected, actual.data.word); try expect_value(expected, actual.data.word);
} }
fn expect_label(expected: Token.Label, actual: Token) !void { fn expect_label(expected: Token.Label, actual: Token) !void {
try expectEqual(Token.Tag.label, actual.data); try expectEqual(Token.Tag.label, @as(Token.Tag, actual.data));
const label = actual.data.label; const label = actual.data.label;
try expectEqual(expected.public, label.public); try expectEqual(expected.public, label.public);
@ -1230,8 +1230,8 @@ const ExpectedNopInstr = struct {
}; };
fn expect_instr_nop(expected: ExpectedNopInstr, actual: Token) !void { fn expect_instr_nop(expected: ExpectedNopInstr, actual: Token) !void {
try expectEqual(Token.Tag.instruction, actual.data); try expectEqual(Token.Tag.instruction, @as(Token.Tag, actual.data));
try expectEqual(PayloadTag.nop, actual.data.instruction.payload); try expectEqual(PayloadTag.nop, @as(PayloadTag, actual.data.instruction.payload));
const instr = actual.data.instruction; const instr = actual.data.instruction;
try expect_opt_value(expected.delay, instr.delay); try expect_opt_value(expected.delay, instr.delay);
@ -1246,8 +1246,8 @@ const ExpectedSetInstr = struct {
}; };
fn expect_instr_set(expected: ExpectedSetInstr, actual: Token) !void { fn expect_instr_set(expected: ExpectedSetInstr, actual: Token) !void {
try expectEqual(Token.Tag.instruction, actual.data); try expectEqual(Token.Tag.instruction, @as(Token.Tag, actual.data));
try expectEqual(PayloadTag.set, actual.data.instruction.payload); try expectEqual(PayloadTag.set, @as(PayloadTag, actual.data.instruction.payload));
const instr = actual.data.instruction; const instr = actual.data.instruction;
try expect_opt_value(expected.delay, instr.delay); try expect_opt_value(expected.delay, instr.delay);
@ -1266,8 +1266,8 @@ const ExpectedJmpInstr = struct {
}; };
fn expect_instr_jmp(expected: ExpectedJmpInstr, actual: Token) !void { fn expect_instr_jmp(expected: ExpectedJmpInstr, actual: Token) !void {
try expectEqual(Token.Tag.instruction, actual.data); try expectEqual(Token.Tag.instruction, @as(Token.Tag, actual.data));
try expectEqual(PayloadTag.jmp, actual.data.instruction.payload); try expectEqual(PayloadTag.jmp, @as(PayloadTag, actual.data.instruction.payload));
const instr = actual.data.instruction; const instr = actual.data.instruction;
try expect_opt_value(expected.delay, instr.delay); try expect_opt_value(expected.delay, instr.delay);
@ -1289,8 +1289,8 @@ const ExpectedWaitInstr = struct {
}; };
fn expect_instr_wait(expected: ExpectedWaitInstr, actual: Token) !void { fn expect_instr_wait(expected: ExpectedWaitInstr, actual: Token) !void {
try expectEqual(Token.Tag.instruction, actual.data); try expectEqual(Token.Tag.instruction, @as(Token.Tag, actual.data));
try expectEqual(PayloadTag.wait, actual.data.instruction.payload); try expectEqual(PayloadTag.wait, @as(PayloadTag, actual.data.instruction.payload));
const instr = actual.data.instruction; const instr = actual.data.instruction;
try expect_opt_value(expected.delay, instr.delay); try expect_opt_value(expected.delay, instr.delay);
@ -1310,8 +1310,8 @@ const ExpectedInInstr = struct {
}; };
fn expect_instr_in(expected: ExpectedInInstr, actual: Token) !void { fn expect_instr_in(expected: ExpectedInInstr, actual: Token) !void {
try expectEqual(Token.Tag.instruction, actual.data); try expectEqual(Token.Tag.instruction, @as(Token.Tag, actual.data));
try expectEqual(PayloadTag.in, actual.data.instruction.payload); try expectEqual(PayloadTag.in, @as(PayloadTag, actual.data.instruction.payload));
const instr = actual.data.instruction; const instr = actual.data.instruction;
try expect_opt_value(expected.delay, instr.delay); try expect_opt_value(expected.delay, instr.delay);
@ -1330,8 +1330,8 @@ const ExpectedOutInstr = struct {
}; };
fn expect_instr_out(expected: ExpectedOutInstr, actual: Token) !void { fn expect_instr_out(expected: ExpectedOutInstr, actual: Token) !void {
try expectEqual(Token.Tag.instruction, actual.data); try expectEqual(Token.Tag.instruction, @as(Token.Tag, actual.data));
try expectEqual(PayloadTag.out, actual.data.instruction.payload); try expectEqual(PayloadTag.out, @as(PayloadTag, actual.data.instruction.payload));
const instr = actual.data.instruction; const instr = actual.data.instruction;
try expect_opt_value(expected.delay, instr.delay); try expect_opt_value(expected.delay, instr.delay);
@ -1350,8 +1350,8 @@ const ExpectedPushInstr = struct {
}; };
fn expect_instr_push(expected: ExpectedPushInstr, actual: Token) !void { fn expect_instr_push(expected: ExpectedPushInstr, actual: Token) !void {
try expectEqual(Token.Tag.instruction, actual.data); try expectEqual(Token.Tag.instruction, @as(Token.Tag, actual.data));
try expectEqual(PayloadTag.push, actual.data.instruction.payload); try expectEqual(PayloadTag.push, @as(PayloadTag, actual.data.instruction.payload));
const instr = actual.data.instruction; const instr = actual.data.instruction;
try expect_opt_value(expected.delay, instr.delay); try expect_opt_value(expected.delay, instr.delay);
@ -1370,8 +1370,8 @@ const ExpectedPullInstr = struct {
}; };
fn expect_instr_pull(expected: ExpectedPullInstr, actual: Token) !void { fn expect_instr_pull(expected: ExpectedPullInstr, actual: Token) !void {
try expectEqual(Token.Tag.instruction, actual.data); try expectEqual(Token.Tag.instruction, @as(Token.Tag, actual.data));
try expectEqual(PayloadTag.pull, actual.data.instruction.payload); try expectEqual(PayloadTag.pull, @as(PayloadTag, actual.data.instruction.payload));
const instr = actual.data.instruction; const instr = actual.data.instruction;
try expect_opt_value(expected.delay, instr.delay); try expect_opt_value(expected.delay, instr.delay);
@ -1391,8 +1391,8 @@ const ExpectedMovInstr = struct {
}; };
fn expect_instr_mov(expected: ExpectedMovInstr, actual: Token) !void { fn expect_instr_mov(expected: ExpectedMovInstr, actual: Token) !void {
try expectEqual(Token.Tag.instruction, actual.data); try expectEqual(Token.Tag.instruction, @as(Token.Tag, actual.data));
try expectEqual(PayloadTag.mov, actual.data.instruction.payload); try expectEqual(PayloadTag.mov, @as(PayloadTag, actual.data.instruction.payload));
const instr = actual.data.instruction; const instr = actual.data.instruction;
try expect_opt_value(expected.delay, instr.delay); try expect_opt_value(expected.delay, instr.delay);
@ -1414,8 +1414,8 @@ const ExpectedIrqInstr = struct {
}; };
fn expect_instr_irq(expected: ExpectedIrqInstr, actual: Token) !void { fn expect_instr_irq(expected: ExpectedIrqInstr, actual: Token) !void {
try expectEqual(Token.Tag.instruction, actual.data); try expectEqual(Token.Tag.instruction, @as(Token.Tag, actual.data));
try expectEqual(PayloadTag.irq, actual.data.instruction.payload); try expectEqual(PayloadTag.irq, @as(PayloadTag, actual.data.instruction.payload));
const instr = actual.data.instruction; const instr = actual.data.instruction;
try expect_opt_value(expected.delay, instr.delay); try expect_opt_value(expected.delay, instr.delay);

@ -1,21 +1,19 @@
MIT License Copyright (c) Zig Embedded Group contributors
Copyright (c) 2022 Zig Embedded Group This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use
of this software.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is granted to anyone to use this software for any purpose, including
of this software and associated documentation files (the "Software"), to deal commercial applications, and to alter it and redistribute it freely, subject to
in the Software without restriction, including without limitation the rights the following restrictions:
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all 1. The origin of this software must not be misrepresented; you must not claim
copies or substantial portions of the Software. that you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is
not required.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2. Altered source versions must be plainly marked as such, and must not be
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, misrepresented as being the original software.
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 3. This notice may not be removed or altered from any source distribution.
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -1,14 +0,0 @@
= stm32
HALs and register definitions for stm32 (STMicro) devices
== What version of Zig to use
Right now we are following https://ziglang.org/download/[master], but once 0.11.0 is released, we will be switching to the latest stable version of Zig.
== stm32 boards that renode supports:
- blue pill (stm32f103)
- nucleo 64 (stm32f103)
- f4 discovery
- f7 discovery

@ -0,0 +1,10 @@
# stm32
HALs and register definitions for stm32 (STMicro) devices
## stm32 boards that renode supports:
- blue pill (stm32f103)
- nucleo 64 (stm32f103)
- f4 discovery
- f7 discovery

@ -1,8 +1,6 @@
const std = @import("std"); const std = @import("std");
const MicroZig = @import("microzig/build"); const MicroZig = @import("microzig/build");
pub const microzig_board_support = MicroZig.registerBoardSupport(@This());
fn root() []const u8 { fn root() []const u8 {
return comptime (std.fs.path.dirname(@src().file) orelse "."); return comptime (std.fs.path.dirname(@src().file) orelse ".");
} }
@ -10,13 +8,8 @@ const build_root = root();
const KiB = 1024; const KiB = 1024;
////////////////////////////////////////
// MicroZig Gen 2 Interface //
////////////////////////////////////////
pub fn build(b: *std.Build) !void { pub fn build(b: *std.Build) !void {
_ = b; _ = b.step("test", "Run platform agnostic unit tests");
// Dummy func to make package manager happy
} }
pub const chips = struct { pub const chips = struct {
@ -34,7 +27,7 @@ pub const chips = struct {
}, },
}, },
.hal = .{ .hal = .{
.source_file = .{ .cwd_relative = build_root ++ "/src/hals/STM32F103/hal.zig" }, .root_source_file = .{ .cwd_relative = build_root ++ "/src/hals/STM32F103/hal.zig" },
}, },
}; };
@ -194,7 +187,7 @@ pub const boards = struct {
.chip = chips.stm32f303vc.chip, .chip = chips.stm32f303vc.chip,
.board = .{ .board = .{
.name = "STM32F3DISCOVERY", .name = "STM32F3DISCOVERY",
.source_file = .{ .path = build_root ++ "/src/boards/STM32F3DISCOVERY.zig" }, .root_source_file = .{ .path = build_root ++ "/src/boards/STM32F3DISCOVERY.zig" },
}, },
}; };
@ -203,7 +196,7 @@ pub const boards = struct {
.chip = chips.stm32f407vg.chip, .chip = chips.stm32f407vg.chip,
.board = .{ .board = .{
.name = "STM32F4DISCOVERY", .name = "STM32F4DISCOVERY",
.source_file = .{ .path = build_root ++ "/src/boards/STM32F4DISCOVERY.zig" }, .root_source_file = .{ .path = build_root ++ "/src/boards/STM32F4DISCOVERY.zig" },
}, },
}; };
@ -212,7 +205,7 @@ pub const boards = struct {
.chip = chips.stm32f407vg.chip, .chip = chips.stm32f407vg.chip,
.board = .{ .board = .{
.name = "STM3240G_EVAL", .name = "STM3240G_EVAL",
.source_file = .{ .path = build_root ++ "/src/boards/STM3240G_EVAL.zig" }, .root_source_file = .{ .path = build_root ++ "/src/boards/STM3240G_EVAL.zig" },
}, },
}; };
@ -221,7 +214,7 @@ pub const boards = struct {
.chip = chips.stm32f429zit6u.chip, .chip = chips.stm32f429zit6u.chip,
.board = .{ .board = .{
.name = "STM32F429IDISCOVERY", .name = "STM32F429IDISCOVERY",
.source_file = .{ .path = build_root ++ "/src/boards/STM32F429IDISCOVERY.zig" }, .root_source_file = .{ .path = build_root ++ "/src/boards/STM32F429IDISCOVERY.zig" },
}, },
}; };
}; };
@ -235,7 +228,7 @@ pub const boards = struct {
// const exe = microzig.addEmbeddedExecutable(b, .{ // const exe = microzig.addEmbeddedExecutable(b, .{
// .name = @field(boards, decl.name).name ++ ".minimal", // .name = @field(boards, decl.name).name ++ ".minimal",
// .source_file = .{ // .root_source_file = .{
// .path = "test/programs/minimal.zig", // .path = "test/programs/minimal.zig",
// }, // },
// .backing = .{ .board = @field(boards, decl.name) }, // .backing = .{ .board = @field(boards, decl.name) },
@ -250,7 +243,7 @@ pub const boards = struct {
// const exe = microzig.addEmbeddedExecutable(b, .{ // const exe = microzig.addEmbeddedExecutable(b, .{
// .name = @field(chips, decl.name).name ++ ".minimal", // .name = @field(chips, decl.name).name ++ ".minimal",
// .source_file = .{ // .root_source_file = .{
// .path = "test/programs/minimal.zig", // .path = "test/programs/minimal.zig",
// }, // },
// .backing = .{ .chip = @field(chips, decl.name) }, // .backing = .{ .chip = @field(chips, decl.name) },

@ -5,7 +5,11 @@
.@"microzig/build" = .{ .path = "../../../build" }, .@"microzig/build" = .{ .path = "../../../build" },
}, },
.paths = .{ .paths = .{
"LICENSE",
"README.md",
"build.zig", "build.zig",
"build.zig.zon", "build.zig.zon",
"src",
"test",
}, },
} }

@ -111,7 +111,7 @@ pub fn Pins(comptime config: GlobalConfiguration) type {
return @Type(.{ return @Type(.{
.Struct = .{ .Struct = .{
.layout = .Auto, .layout = .auto,
.is_tuple = false, .is_tuple = false,
.fields = fields, .fields = fields,
.decls = &.{}, .decls = &.{},

@ -1,20 +1,8 @@
const std = @import("std"); const std = @import("std");
const Build = std.Build;
const MicroZig = @import("build/definitions");
// TODO: fix this issue with AVR. For some reason we fail wasi assertions?
//
// error: the following command failed with 1 compilation errors:
//Users/mattnite/zig/0.12.0-dev.3097+5c0766b6c/files/zig build-exe -freference-trace=256 -OReleaseSmall -target avr-freestanding-eabi -mcpu avr5 --dep app --dep microzig -Mroot=/Users/mattnite/code/microzig/core/src/start.zig --dep microzig -Mapp=/Users/mattnite/code/microzig/examples/microchip/avr/src/blinky.zig --dep config --dep chip --dep cpu --dep hal --dep board -Mmicrozig=/Users/mattnite/code/microzig/core/src/microzig.zig -Mconfig=/Users/mattnite/code/microzig/zig-cache/c/303c67fccae4ec4bb03ec2180082b67b/options.zig --dep microzig -Mchip=/Users/mattnite/code/microzig/zig-cache/o/2c86b0de714a8b4409eb761d16297c00/chip.zig --dep microzig -Mcpu=/Users/mattnite/code/microzig/core/src/cpus/avr5.zig --dep microzig -Mhal=/Users/mattnite/code/microzig/bsp/microchip/avr/src/hals/ATmega328P.zig --dep microzig -Mboard=/Users/mattnite/code/microzig/bsp/microchip/avr/src/boards/arduino_uno.zig --cache-dir /Users/mattnite/code/microzig/zig-cache --global-cache-dir /Users/mattnite/.cache/zig --name arduino-nano_blinky -static -fcompiler-rt --script /Users/mattnite/code/microzig/zig-cache/o/2c186d936508aa71bea517796451c3f9/linker.ld --listen=-
//install
//mq install
// mq install generated to arduino-nano_blinky.hex
// mq objcopy generated
// mq zig build-exe arduino-nano_blinky ReleaseSmall avr-freestanding-eabi 1 errors
///Users/mattnite/zig/0.12.0-dev.3097+5c0766b6c/files/lib/std/debug.zig:403:14: error: reached unreachable code
// if (!ok) unreachable; // assertion failure
// ^~~~~~~~~~~
///Users/mattnite/zig/0.12.0-dev.3097+5c0766b6c/files/lib/std/os/wasi.zig:12:11: note: called from here
// assert(@alignOf(i16) == 2);
// ~~~~~~^~~~~~~~~~~~~~~~~~~~
const example_dep_names: []const []const u8 = &.{ const example_dep_names: []const []const u8 = &.{
"examples/nordic/nrf5x", "examples/nordic/nrf5x",
"examples/nxp/lpc", "examples/nxp/lpc",
@ -22,11 +10,22 @@ const example_dep_names: []const []const u8 = &.{
//"examples/microchip/avr", //"examples/microchip/avr",
"examples/gigadevice/gd32", "examples/gigadevice/gd32",
"examples/stmicro/stm32", "examples/stmicro/stm32",
"examples/espressif/esp", //"examples/espressif/esp",
"examples/raspberrypi/rp2040", "examples/raspberrypi/rp2040",
}; };
pub fn build(b: *std.Build) void { const bsps = .{
.{ "bsp/nordic/nrf5x", @import("bsp/nordic/nrf5x") },
.{ "bsp/nxp/lpc", @import("bsp/nxp/lpc") },
.{ "bsp/microchip/atsam", @import("bsp/microchip/atsam") },
.{ "bsp/microchip/avr", @import("bsp/microchip/avr") },
.{ "bsp/gigadevice/gd32", @import("bsp/gigadevice/gd32") },
.{ "bsp/stmicro/stm32", @import("bsp/stmicro/stm32") },
.{ "bsp/espressif/esp", @import("bsp/espressif/esp") },
.{ "bsp/raspberrypi/rp2040", @import("bsp/raspberrypi/rp2040") },
};
pub fn build(b: *Build) void {
const optimize = b.standardOptimizeOption(.{}); const optimize = b.standardOptimizeOption(.{});
// Build all examples // Build all examples
@ -47,4 +46,97 @@ pub fn build(b: *std.Build) void {
const package_step = b.step("package", "Package monorepo using boxzer"); const package_step = b.step("package", "Package monorepo using boxzer");
package_step.dependOn(&boxzer_run.step); package_step.dependOn(&boxzer_run.step);
//const website_dep = b.dependency("website", .{});
//const website_step = b.step("website", "Build website");
//website_step.dependOn(website_dep.builder.getInstallStep());
const parts_db = generate_parts_db(b) catch @panic("OOM");
const parts_db_json = b.addInstallFile(parts_db, "parts-db.json");
package_step.dependOn(&parts_db_json.step);
const test_bsps_step = b.step("run-bsp-tests", "Run all platform agnostic tests for BSPs");
inline for (bsps) |bsp| {
const bsp_dep = b.dependency(bsp[0], .{});
test_bsps_step.dependOn(&bsp_dep.builder.top_level_steps.get("test").?.step);
}
}
const PartsDb = struct {
chips: []const Chip,
boards: []const Board,
const Chip = struct {
identifier: []const u8,
bsp_package: []const u8,
url: ?[]const u8,
cpu: []const u8,
has_hal: bool,
memory: struct {
flash: u64,
ram: u64,
},
output_format: ?[]const u8,
};
const Board = struct {
identifier: []const u8,
bsp_package: []const u8,
chip_idx: u32,
url: ?[]const u8,
output_format: ?[]const u8,
};
};
fn generate_parts_db(b: *Build) !Build.LazyPath {
var chips = std.ArrayList(PartsDb.Chip).init(b.allocator);
var boards = std.ArrayList(PartsDb.Board).init(b.allocator);
inline for (bsps) |bsp| {
const chips_start_idx = chips.items.len;
inline for (@typeInfo(@field(bsp[1], "chips")).Struct.decls) |decl| {
const target = @field(@field(bsp[1], "chips"), decl.name);
try chips.append(.{
.identifier = decl.name,
.bsp_package = bsp[0],
.url = target.chip.url,
.cpu = target.chip.cpu.name,
.has_hal = target.hal != null,
.memory = .{
.flash = 0,
.ram = 0,
},
.output_format = null,
});
}
inline for (@typeInfo(@field(bsp[1], "boards")).Struct.decls) |decl| {
const target = @field(@field(bsp[1], "boards"), decl.name);
_ = target;
_ = chips_start_idx;
//const chip_idx = inline for (@typeInfo(@field(bsp[1], "chips")).Struct.decls, 0..) |chip_decl, idx| {
// const chip = @field(@field(bsp[1], "chips"), chip_decl.name);
// if (std.mem.eql(u8, chip.chip.name, target.chip.name))
// break chips_start_idx + idx;
//} else @compileError("failed to get chip_idx");
try boards.append(.{
.identifier = decl.name,
.bsp_package = bsp[0],
.chip_idx = 0,
.url = "",
.output_format = null,
});
}
}
const parts_db = PartsDb{
.chips = chips.items,
.boards = boards.items,
};
const parts_db_str = try std.json.stringifyAlloc(b.allocator, parts_db, .{
.whitespace = .indent_4,
});
const write_file_step = b.addWriteFiles();
return write_file_step.add("parts-db.json", parts_db_str);
} }

@ -1,11 +1,11 @@
.{ .{
.name = "microzig", .name = "microzig",
.version = "0.0.0", .version = "0.12.0",
.dependencies = .{ .dependencies = .{
// packages within the monorepo so that others can reach them // packages within the monorepo so that others can reach them
.@"build" = .{ .path = "build" }, .build = .{ .path = "build" },
.@"build/definitions" = .{ .path = "build/definitions" }, .@"build/definitions" = .{ .path = "build/definitions" },
.@"core" = .{ .path = "core" }, .core = .{ .path = "core" },
.@"tools/regz" = .{ .path = "tools/regz" }, .@"tools/regz" = .{ .path = "tools/regz" },
.@"tools/uf2" = .{ .path = "tools/uf2" }, .@"tools/uf2" = .{ .path = "tools/uf2" },
.@"bsp/nordic/nrf5x" = .{ .path = "bsp/nordic/nrf5x" }, .@"bsp/nordic/nrf5x" = .{ .path = "bsp/nordic/nrf5x" },
@ -29,8 +29,8 @@
// used for creating package tarballs // used for creating package tarballs
.boxzer = .{ .boxzer = .{
.url = "https://github.com/mattnite/boxzer/archive/b9f08b4c9b1db709af03763ace69761a6482238c.tar.gz", .url = "https://github.com/mattnite/boxzer/archive/74f17daa97f6861c31b30a5070136216c08eb39b.tar.gz",
.hash = "12204fdd9914a6d99abb55366b3a664395a6038d7e6308178c0664158eff9418e188", .hash = "1220a14c01a66c023d8944dc672edd5121f98f82196fefbc09a13bcadb96e1c8e7f1",
}, },
}, },
@ -39,5 +39,7 @@
"build.zig", "build.zig",
"build.zig.zon", "build.zig.zon",
"LICENSE", "LICENSE",
"design",
"docs",
}, },
} }

@ -1,21 +1,19 @@
MIT License Copyright (c) Zig Embedded Group contributors
Copyright (c) 2022 Zig Embedded Group This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use
of this software.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is granted to anyone to use this software for any purpose, including
of this software and associated documentation files (the "Software"), to deal commercial applications, and to alter it and redistribute it freely, subject to
in the Software without restriction, including without limitation the rights the following restrictions:
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all 1. The origin of this software must not be misrepresented; you must not claim
copies or substantial portions of the Software. that you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is
not required.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2. Altered source versions must be plainly marked as such, and must not be
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, misrepresented as being the original software.
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 3. This notice may not be removed or altered from any source distribution.
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -117,7 +117,7 @@ pub fn add_firmware(
config.addOption(?[]const u8, "board_name", if (maybe_board) |brd| brd.name else null); config.addOption(?[]const u8, "board_name", if (maybe_board) |brd| brd.name else null);
config.addOption([]const u8, "chip_name", chip.name); config.addOption([]const u8, "chip_name", chip.name);
config.addOption([]const u8, "cpu_name", chip.name); config.addOption([]const u8, "cpu_name", chip.cpu.name);
config.addOption(usize, "end_of_stack", first_ram.offset + first_ram.length); config.addOption(usize, "end_of_stack", first_ram.offset + first_ram.length);
const fw: *Firmware = host_build.allocator.create(Firmware) catch @panic("out of memory"); const fw: *Firmware = host_build.allocator.create(Firmware) catch @panic("out of memory");
@ -133,9 +133,7 @@ pub fn add_firmware(
}), }),
.target = options.target, .target = options.target,
.output_files = Firmware.OutputFileMap.init(host_build.allocator), .output_files = Firmware.OutputFileMap.init(host_build.allocator),
.config = config, .config = config,
.modules = .{ .modules = .{
.microzig = micro_build.createModule(.{ .microzig = micro_build.createModule(.{
.root_source_file = .{ .cwd_relative = mz.microzig_core.builder.pathFromRoot("src/microzig.zig") }, .root_source_file = .{ .cwd_relative = mz.microzig_core.builder.pathFromRoot("src/microzig.zig") },
@ -146,13 +144,10 @@ pub fn add_firmware(
}, },
}, },
}), }),
.cpu = undefined, .cpu = undefined,
.chip = undefined, .chip = undefined,
.board = null, .board = null,
.hal = null, .hal = null,
.app = undefined, .app = undefined,
}, },
}; };
@ -167,7 +162,7 @@ pub fn add_firmware(
fw.modules.microzig.addImport("chip", fw.modules.chip); fw.modules.microzig.addImport("chip", fw.modules.chip);
fw.modules.cpu = micro_build.createModule(.{ fw.modules.cpu = micro_build.createModule(.{
.root_source_file = chip.cpu.source_file, .root_source_file = chip.cpu.root_source_file,
.imports = &.{ .imports = &.{
.{ .name = "microzig", .module = fw.modules.microzig }, .{ .name = "microzig", .module = fw.modules.microzig },
}, },
@ -176,7 +171,7 @@ pub fn add_firmware(
if (maybe_hal) |hal| { if (maybe_hal) |hal| {
fw.modules.hal = micro_build.createModule(.{ fw.modules.hal = micro_build.createModule(.{
.root_source_file = hal.source_file, .root_source_file = hal.root_source_file,
.imports = &.{ .imports = &.{
.{ .name = "microzig", .module = fw.modules.microzig }, .{ .name = "microzig", .module = fw.modules.microzig },
}, },
@ -186,7 +181,7 @@ pub fn add_firmware(
if (maybe_board) |brd| { if (maybe_board) |brd| {
fw.modules.board = micro_build.createModule(.{ fw.modules.board = micro_build.createModule(.{
.root_source_file = brd.source_file, .root_source_file = brd.root_source_file,
.imports = &.{ .imports = &.{
.{ .name = "microzig", .module = fw.modules.microzig }, .{ .name = "microzig", .module = fw.modules.microzig },
}, },
@ -195,7 +190,7 @@ pub fn add_firmware(
} }
fw.modules.app = host_build.createModule(.{ fw.modules.app = host_build.createModule(.{
.root_source_file = options.source_file, .root_source_file = options.root_source_file,
.imports = &.{ .imports = &.{
.{ .name = "microzig", .module = fw.modules.microzig }, .{ .name = "microzig", .module = fw.modules.microzig },
}, },
@ -345,7 +340,7 @@ pub const FirmwareOptions = struct {
optimize: std.builtin.OptimizeMode, optimize: std.builtin.OptimizeMode,
/// The root source file for the application. This is your `src/main.zig` file. /// The root source file for the application. This is your `src/main.zig` file.
source_file: LazyPath, root_source_file: LazyPath,
// Overrides: // Overrides:
@ -488,9 +483,9 @@ pub const Firmware = struct {
/// Adds a regular dependency to your application. /// Adds a regular dependency to your application.
pub fn add_app_import(fw: *Firmware, name: []const u8, module: *std.Build.Module, options: AppDependencyOptions) void { pub fn add_app_import(fw: *Firmware, name: []const u8, module: *std.Build.Module, options: AppDependencyOptions) void {
if (options.depend_on_microzig) { if (options.depend_on_microzig) {
module.dependencies.put("microzig", fw.modules.microzig) catch @panic("OOM"); module.addImport("microzig", fw.modules.microzig);
} }
fw.modules.app.dependencies.put(name, module) catch @panic("OOM"); fw.modules.app.addImport(name, module);
} }
pub fn add_include_path(fw: *Firmware, path: LazyPath) void { pub fn add_include_path(fw: *Firmware, path: LazyPath) void {
@ -505,14 +500,8 @@ pub const Firmware = struct {
fw.artifact.addCSourceFile(source); fw.artifact.addCSourceFile(source);
} }
pub fn add_options(fw: *Firmware, module_name: []const u8, options: *std.Build.OptionsStep) void { pub fn add_options(fw: *Firmware, module_name: []const u8, options: *std.Build.Step.Options) void {
fw.artifact.addOptions(module_name, options); fw.modules.app.addOptions(module_name, options);
fw.modules.app.dependencies.put(
module_name,
fw.host_build.createModule(.{
.source_file = options.getOutput(),
}),
) catch @panic("OOM");
} }
pub fn add_object_file(fw: *Firmware, source: LazyPath) void { pub fn add_object_file(fw: *Firmware, source: LazyPath) void {

@ -1,21 +1,19 @@
MIT License Copyright (c) Zig Embedded Group contributors
Copyright (c) 2022 Zig Embedded Group This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use
of this software.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is granted to anyone to use this software for any purpose, including
of this software and associated documentation files (the "Software"), to deal commercial applications, and to alter it and redistribute it freely, subject to
in the Software without restriction, including without limitation the rights the following restrictions:
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all 1. The origin of this software must not be misrepresented; you must not claim
copies or substantial portions of the Software. that you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is
not required.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2. Altered source versions must be plainly marked as such, and must not be
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, misrepresented as being the original software.
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 3. This notice may not be removed or altered from any source distribution.
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -14,7 +14,7 @@ pub const Cpu = struct {
name: []const u8, name: []const u8,
/// Source file providing startup code and memory initialization routines. /// Source file providing startup code and memory initialization routines.
source_file: LazyPath, root_source_file: LazyPath,
/// The compiler target we use to compile all the code. /// The compiler target we use to compile all the code.
target: std.Target.Query, target: std.Target.Query,
@ -53,7 +53,7 @@ pub const Chip = struct {
/// Defines a hardware abstraction layer. /// Defines a hardware abstraction layer.
pub const HardwareAbstractionLayer = struct { pub const HardwareAbstractionLayer = struct {
/// Root source file for this HAL. /// Root source file for this HAL.
source_file: LazyPath, root_source_file: LazyPath,
}; };
/// Provides a description of a board. /// Provides a description of a board.
@ -69,7 +69,7 @@ pub const BoardDefinition = struct {
url: ?[]const u8 = null, url: ?[]const u8 = null,
/// Provides the root file for the board definition. /// Provides the root file for the board definition.
source_file: LazyPath, root_source_file: LazyPath,
}; };
/// A descriptor for memory regions in a microcontroller. /// A descriptor for memory regions in a microcontroller.

@ -1,11 +1,19 @@
Copyright (c) 2022 Matthew Knight, Felix Queißner and Maciej Kuliński Copyright (c) Zig Embedded Group contributors
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use
of this software.
Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: Permission is granted to anyone to use this software for any purpose, including
commercial applications, and to alter it and redistribute it freely, subject to
the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is
not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.

@ -1,162 +0,0 @@
:imagesdir: design
:toc: macro
image::logo-text-auto.svg[]
image::https://img.shields.io/discord/824493524413710336.svg?logo=discord[link=https://discord.gg/ShUWykk38X]
[NOTE]
This is in development; breaks in the API are bound to happen.
toc::[]
== What version of Zig to use
0.11.0
== Contributing
Please see the https://github.com/orgs/ZigEmbeddedGroup/projects/1/views/1[project page], it's used as a place to brainstorm and organize work in ZEG. There will be issues marked as `good first issue` or drafts for larger ideas that need scoping/breaking ground on.
== Introduction
This repo contains the infrastructure for getting started in an embedded Zig project; it "gets you to main()". Specifically, it offers:
* a single easy-to-use builder function that:
** generates your linker script
** sets up packages and startup code
* generalized interfaces for common devices, such as UART.
* device drivers for interacting with external hardware
* an uncomplicated method to define xref:interrupts[interrupts]
== Getting Started
Visit https://github.com/ZigEmbeddedGroup/microzig-examples to find examples for your specific board.
== Design
For MicroZig internals please see the xref:docs/design.adoc[Design Document].
== Does MicroZig support X hardware?
MicroZig is designed to cover as wide a swath of hardware as possible. The https://github.com/ZigEmbeddedGroup[Zig Embedded Group] has some repositories that contain hardware-specific code. You will find them with the `hardware-support-package` label. If you can't find your specific device, it doesn't mean that you can't run Zig on it, it's likely you're just the first! In that case, see xref:#getting-microzig-on-new-hardware[Getting MicroZig on New Hardware].
Start with an empty Zig project by running `zig init-exe`, and add the hardware support package as a submodule. We'll use `microchip-atmega` in our example:
[source,zig]
----
const std = @import("std");
const atmega = @import("deps/microchip-atmega/build.zig");
// the hardware support package should have microzig as a dependency
const microzig = @import("deps/hardware_support_package/deps/microzig/build.zig");
pub fn build(b: *std.build.Builder) !void {
const optimize = b.standardOptimizeOption(.{});
var exe = microzig.addEmbeddedExecutable( b, .{
.name = "my-executable",
.source_file = .{
.path = "src/main.zig",
},
.backing = .{
.board = atmega.boards.arduino_nano,
// instead of a board, you can use the raw chip as well
// .chip = atmega.chips.atmega328p,
},
.optimize = optimize,
});
exe.installArtifact(b);
}
----
`zig build` and now you have an executable for an Arduino Nano. In your application you can import `microzig` in order to interact with the hardware:
[source,zig]
----
const microzig = @import("microzig");
// `microzig.config`: comptime access to configuration
// `microzig.chip`: access to register definitions, generated code
// `microzig.board`: access to board information
// `microzig.hal`: access to hand-written code for interacting with the hardware
// `microzig.cpu`: access to AVR5 specific functions
pub fn main() !void {
// your program here
}
----
== Getting MicroZig on New Hardware
If you have a board/chip that isn't defined in microzig, you can set it up yourself! You need to have:
* SVD or ATDF file defining registers
* flash and ram address and sizes
First, use https://github.com/ZigEmbeddedGroup/regz[Regz] to generate the register definitions for your chip and save them to a file. Then define the chip:
[source,zig]
----
const nrf52832 = Chip{
.name = "nRF52832",
.source = .{
.path = "path/to/generated/file.zig",
},
.cpu = cpus.cortex_m4,
.memory_regions = &.{
MemoryRegion{ .offset = 0x00000000, .length = 0x80000, .kind = .flash },
MemoryRegion{ .offset = 0x20000000, .length = 0x10000, .kind = .ram },
},
};
const backing = .{
.chip = nrf52832,
};
----
It's important that the chip name actually matches one of the entries under `devices` in the generated code.
=== Optional: JSON Register Schema
You can also invoke `regz` to generate a JSON representation of the hardware:
[source]
----
regz --json <path to svd/atdf>
----
This file could then be used by tooling. You can add it to a `Chip` like so:
[source,zig]
----
const nrf52832 = Chip{
.name = "nRF52832",
.json_register_schema = .{
.path = "path/to.json",
},
// ...
};
----
== Interrupts
The currently supported architectures for interrupt vector generation are ARM and AVR. To define the Interrupt Service Routine (ISR) for a given interrupt, you create a function with the same name in an `interrupts` namespace, which is nested in a `microzig_options` namespace:
[source,zig]
----
pub const microzig_options = struct {
pub const interrupts = struct {
pub fn PCINT0() void {
// interrupt handling code
}
};
}
pub fn main() !void {
// my application
}
----
We're using compile-time checks along with the generated code to determine the list of interrupts. If a function is defined whose name is not in this list, you'll get a compiler error with the list of interrupts/valid names.

@ -18,7 +18,7 @@ pub fn build(b: *std.Build) !void {
pub const cpus = struct { pub const cpus = struct {
pub const avr5 = MicroZig.Cpu{ pub const avr5 = MicroZig.Cpu{
.name = "AVR5", .name = "AVR5",
.source_file = .{ .path = build_root ++ "/src/cpus/avr5.zig" }, .root_source_file = .{ .path = build_root ++ "/src/cpus/avr5.zig" },
.target = std.zig.CrossTarget{ .target = std.zig.CrossTarget{
.cpu_arch = .avr, .cpu_arch = .avr,
.cpu_model = .{ .explicit = &std.Target.avr.cpu.avr5 }, .cpu_model = .{ .explicit = &std.Target.avr.cpu.avr5 },
@ -29,7 +29,7 @@ pub const cpus = struct {
pub const cortex_m0 = MicroZig.Cpu{ pub const cortex_m0 = MicroZig.Cpu{
.name = "ARM Cortex-M0", .name = "ARM Cortex-M0",
.source_file = .{ .path = build_root ++ "/src/cpus/cortex-m.zig" }, .root_source_file = .{ .path = build_root ++ "/src/cpus/cortex-m.zig" },
.target = std.zig.CrossTarget{ .target = std.zig.CrossTarget{
.cpu_arch = .thumb, .cpu_arch = .thumb,
.cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m0 }, .cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m0 },
@ -40,7 +40,7 @@ pub const cpus = struct {
pub const cortex_m0plus = MicroZig.Cpu{ pub const cortex_m0plus = MicroZig.Cpu{
.name = "ARM Cortex-M0+", .name = "ARM Cortex-M0+",
.source_file = .{ .path = build_root ++ "/src/cpus/cortex-m.zig" }, .root_source_file = .{ .path = build_root ++ "/src/cpus/cortex-m.zig" },
.target = std.zig.CrossTarget{ .target = std.zig.CrossTarget{
.cpu_arch = .thumb, .cpu_arch = .thumb,
.cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m0plus }, .cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m0plus },
@ -51,7 +51,7 @@ pub const cpus = struct {
pub const cortex_m3 = MicroZig.Cpu{ pub const cortex_m3 = MicroZig.Cpu{
.name = "ARM Cortex-M3", .name = "ARM Cortex-M3",
.source_file = .{ .path = build_root ++ "/src/cpus/cortex-m.zig" }, .root_source_file = .{ .path = build_root ++ "/src/cpus/cortex-m.zig" },
.target = std.zig.CrossTarget{ .target = std.zig.CrossTarget{
.cpu_arch = .thumb, .cpu_arch = .thumb,
.cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m3 }, .cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m3 },
@ -62,7 +62,7 @@ pub const cpus = struct {
pub const cortex_m4 = MicroZig.Cpu{ pub const cortex_m4 = MicroZig.Cpu{
.name = "ARM Cortex-M4", .name = "ARM Cortex-M4",
.source_file = .{ .path = build_root ++ "/src/cpus/cortex-m.zig" }, .root_source_file = .{ .path = build_root ++ "/src/cpus/cortex-m.zig" },
.target = std.zig.CrossTarget{ .target = std.zig.CrossTarget{
.cpu_arch = .thumb, .cpu_arch = .thumb,
.cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m4 }, .cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m4 },
@ -73,7 +73,7 @@ pub const cpus = struct {
pub const riscv32_imac = MicroZig.Cpu{ pub const riscv32_imac = MicroZig.Cpu{
.name = "RISC-V 32-bit", .name = "RISC-V 32-bit",
.source_file = .{ .path = build_root ++ "/src/cpus/riscv32.zig" }, .root_source_file = .{ .path = build_root ++ "/src/cpus/riscv32.zig" },
.target = std.zig.CrossTarget{ .target = std.zig.CrossTarget{
.cpu_arch = .riscv32, .cpu_arch = .riscv32,
.cpu_model = .{ .explicit = &std.Target.riscv.cpu.sifive_e21 }, .cpu_model = .{ .explicit = &std.Target.riscv.cpu.sifive_e21 },

@ -5,7 +5,11 @@
.@"microzig/build/definitions" = .{ .path = "../build/definitions" }, .@"microzig/build/definitions" = .{ .path = "../build/definitions" },
}, },
.paths = .{ .paths = .{
"LICENSE",
"thoughts.md",
"build.zig", "build.zig",
"build.zig.zon", "build.zig.zon",
"src",
"test",
}, },
} }

@ -0,0 +1,112 @@
/// Describes a device. This is the most broad description in USB and is
/// typically the first thing the host asks for.
pub const Device = extern struct {
/// Version of the device descriptor / USB protocol, in binary-coded
/// decimal. This is typically `0x01_10` for USB 1.1.
bcdUSB: u16,
/// Class of device, giving a broad functional area.
bDeviceClass: u8,
/// SubClass of device, refining the class.
bDeviceSubClass: u8,
/// Protocol within the subclass.
bDeviceProtocol: u8,
/// Maximum unit of data this device can move.
bMaxPacketSize0: u8,
/// ID of product vendor.
idVendor: u16,
/// ID of product.
idProduct: u16,
/// Device version number, as BCD again.
bcdDevice: u16,
/// Index of manufacturer name in string descriptor table.
iManufacturer: u8,
/// Index of product name in string descriptor table.
iPRoduct: u8,
/// Index of serial number in string descriptor table.
iSerialNumber: u8,
/// Number of configurations supported by this device.
bNumConfigurations: u8,
};
pub const Interface = extern struct {
bInterfaceNumber: u8,
bAlternateSetting: u8,
bNumEndpoints: u8,
bInterfaceClass: u8,
bInterfaceSubClass: u8,
bInterfaceProtocol: u8,
iInterface: u8,
};
/// Description of a single available device configuration.
pub const Configuration = extern struct {
/// Total length of all descriptors in this configuration, concatenated.
/// This will include this descriptor, plus at least one interface
/// descriptor, plus each interface descriptor's endpoint descriptors.
wTotalLength: u16,
/// Number of interface descriptors in this configuration.
bNumInterfaces: u8,
/// Number to use when requesting this configuration via a
/// `SetConfiguration` request.
bConfigurationValue: u8,
/// Index of this configuration's name in the string descriptor table.
iConfiguration: u8,
/// Bit set of device attributes:
///
/// - Bit 7 should be set (indicates that device can be bus powered in USB
/// 1.0).
/// - Bit 6 indicates that the device can be self-powered.
/// - Bit 5 indicates that the device can signal remote wakeup of the host
/// (like a keyboard).
/// - The rest are reserved and should be zero.
bmAttributes: u8,
/// Maximum device power consumption in units of 2mA.
bMaxPower: u8,
};
pub const InterfaceAssociation = extern struct {
bFirstInterface: u8,
bInterfaceCount: u8,
bFunctionClass: u8,
bFunctionSubClass: u8,
bFunctionProtocol: u8,
iFunction: u8,
};
/// Describes an endpoint within an interface
pub const Endpoint = extern struct {
/// Address of this endpoint, where the bottom 4 bits give the endpoint
/// number (0..15) and the top bit distinguishes IN (1) from OUT (0).
bEndpointAddress: u8,
/// Endpoint attributes; the most relevant part is the bottom 2 bits, which
/// control the transfer type using the values from `TransferType`.
bmAttributes: u8,
/// Maximum packet size this endpoint can accept/produce.
wMaxPacketSize: u16,
/// Interval for polling interrupt/isochronous endpoints (which we don't
/// currently support) in milliseconds.
bInterval: u8,
};
pub const BOS = extern struct {
/// The number of bytes in this descriptor and all of its subordinate
/// descriptors
wTotalLength: u16,
/// The numbre of device capability descriptors subordinate to this BOS
/// descriptor
bNumDeviceCaps: u8,
};
pub const Utf16Le = struct {
bytes: []const u8,
};
/// For string descriptor zero: an array of one or more language identifier
/// codes, for other string descriptors, a unicode UTF-16LE string
pub const String = extern struct {
string_or_lang: union {
bSTRING: Utf16Le,
wLANGID: []const u8,
};
};

@ -119,7 +119,7 @@ fn is_valid_field(field_name: []const u8) bool {
const VectorTable = microzig.chip.VectorTable; const VectorTable = microzig.chip.VectorTable;
// will be imported by microzig.zig to allow system startup. // will be imported by microzig.zig to allow system startup.
pub var vector_table: VectorTable = blk: { pub const vector_table: VectorTable = blk: {
var tmp: VectorTable = .{ var tmp: VectorTable = .{
.initial_stack_pointer = microzig.config.end_of_stack, .initial_stack_pointer = microzig.config.end_of_stack,
.Reset = .{ .C = microzig.cpu.startup_logic._start }, .Reset = .{ .C = microzig.cpu.startup_logic._start },

@ -36,7 +36,7 @@ blk: {
break :blk @Type(.{ break :blk @Type(.{
.Struct = .{ .Struct = .{
.fields = &fields, .fields = &fields,
.layout = .Auto, .layout = .auto,
.decls = &.{}, .decls = &.{},
.is_tuple = false, .is_tuple = false,
}, },
@ -97,7 +97,7 @@ comptime {
const export_opts = .{ const export_opts = .{
.name = "vector_table", .name = "vector_table",
.section = "microzig_flash_start", .section = "microzig_flash_start",
.linkage = .Strong, .linkage = .strong,
}; };
if ((microzig.board != void and @hasDecl(microzig.board, "vector_table"))) if ((microzig.board != void and @hasDecl(microzig.board, "vector_table")))

@ -1,3 +0,0 @@
= MicroZig Test Area
These are minimal tests to validate MicroZig behavior.

@ -1,103 +0,0 @@
= MicroZig Design
:imagesdir: images
:toc: macro
toc::[]
== Dependency Tree
The build portion of MicroZig sets up a dependency graph like the following.
image::deps.svg[]
Your application lives in `app`; that's where `main()` resides. `root` contains the entry point and will set up [zero-initialized data] and [uninitialized data]. This is all encapsulated in an `EmbeddedExecutable` object. It has methods to add dependencies acquired from the package manager.
The `microzig` module has different namespaces, some are static, but the nodes you see in the diagram above are switched out according to your configured hardware.
== Configurable Modules under `microzig`
The configurable modules, with the exception of `config`, are able to import `microzig`. This exists so that one module may access another through `microzig`. This allows us to have patterns like the `hal` grabbing the frequency of an external crystal oscillator from `board`. Information stays where it's relevant. Circular dependencies of declarations will result in a compile error.
=== `cpu`
This module models your specific CPU and is important for initializing memory. Generally, you shouldn't need to define this yourself, it's likely that MicroZig will have the definition for you.
Further research is needed for SOCs with multiple, heterogeneous CPUs. Likely it means patching together multiple `EmbeddedExecutable`s.
=== `chip`
This module is intended for generated code from https://github.com/ZigEmbeddedGroup/regz[Regz]. You can handwrite this code if you like, but needs to be structured as follows:
[source,zig]
----
pub const types = struct {
// type definitions for peripherals here
};
pub const devices = struct {
pub const chip_name = struct {
// peripherals and interrupt table here ...
};
};
----
This code generation has a `devices` namespace where your specific hardware will reside. When defining a `Chip`, which is ultimately used in the creation of an `EmbeddedExecutable`, the name must exactly match the name under the `devices` namespace. It's okay if the name has whitespace, for that we can use `@""` notation.
Let's say we had a device with the name `STM32F103`. We'd define our chip as:
[source,zig]
----
pub const stm32f103 = microzig.Chip{
.name = "STM32F103",
.cpu = microzig.cpus.cortex_m3,
.source = .{
.path = "path/to/generated.zig",
},
.json_register_schema = .{
.path = "path/to/generated.json",
},
.hal = .{
.path = "path/to/hal.zig",
},
.memory_regions = &.{
MemoryRegion{ .offset = 0x08000000, .length = 64 * 1024, .kind = .flash },
MemoryRegion{ .offset = 0x20000000, .length = 20 * 1024, .kind = .ram },
},
};
----
As discussed, the `name` must match a namespace under `devices` in the `chip` source.
TODO
When making a package that defines chips for others, see xref:hardware_support_packages.adoc[Hardware Support Packages] and xref:tricks.adoc#packaging-and-paths[Packaging and Paths].
=== `hal`
This module contains hand-written code for interacting with the chip.
TODO
=== `board`
TODO
=== `config`
TODO
== Static Namespaces under `microzig`
TODO
== Linkerscript Generation
TODO
== JSON register schema
TODO
== Interrupts
TODO

@ -0,0 +1,112 @@
G MicroZig Design
## Dependency Tree
The build portion of MicroZig sets up a dependency graph like the following.
![](images/deps.svg)
Your application lives in `app`; that's where `main()` resides. `root` contains
the entry point and will set up [zero-initialized data] and [uninitialized
data]. This is all encapsulated in an `EmbeddedExecutable` object. It has
methods to add dependencies acquired from the package manager.
The `microzig` module has different namespaces, some are static, but the nodes
you see in the diagram above are switched out according to your configured
hardware.
## Configurable Modules under `microzig`
The configurable modules, with the exception of `config`, are able to import
`microzig`. This exists so that one module may access another through
`microzig`. This allows us to have patterns like the `hal` grabbing the
frequency of an external crystal oscillator from `board`. Information stays
where it's relevant. Circular dependencies of declarations will result in a
compile error.
### `cpu`
This module models your specific CPU and is important for initializing memory.
Generally, you shouldn't need to define this yourself, it's likely that MicroZig
will have the definition for you.
Further research is needed for SOCs with multiple, heterogeneous CPUs. Likely it
means patching together multiple `EmbeddedExecutable`s.
### `chip`
This module is intended for generated code from
(Regz)[https://github.com/ZigEmbeddedGroup/microzig/tree/main/tools/regz]. You
can hand write this code if you like, but needs to be structured as follows:
```zig
pub const types = struct {
// type definitions for peripherals here
};
pub const devices = struct {
pub const chip_name = struct {
// peripherals and interrupt table here ...
};
};
```
This code generation has a `devices` namespace where your specific hardware will
reside. When defining a `Chip`, which is ultimately used in the creation of an
`EmbeddedExecutable`, the name must exactly match the name under the `devices`
namespace. It's okay if the name has white space, for that we can use `@""`
notation.
Let's say we had a device with the name `STM32F103`. We'd define our chip as:
```zig
pub const stm32f103 = microzig.Chip{
.name = "STM32F103",
.cpu = microzig.cpus.cortex_m3,
.source = .{
.path = "path/to/generated.zig",
},
.json_register_schema = .{
.path = "path/to/generated.json",
},
.hal = .{
.path = "path/to/hal.zig",
},
.memory_regions = &.{
MemoryRegion{ .offset = 0x08000000, .length = 64 * 1024, .kind = .flash },
MemoryRegion{ .offset = 0x20000000, .length = 20 * 1024, .kind = .ram },
},
};
```
As discussed, the `name` must match a namespace under `devices` in the `chip` source.
### `hal`
This module contains hand-written code for interacting with the chip.
TODO
### `board`
TODO
### `config`
TODO
## Static Namespaces under `microzig`
TODO
## Linkerscript Generation
TODO
## JSON register schema
TODO
## Interrupts
TODO

@ -1,7 +0,0 @@
= Hardware Support Packages
:imagesdir: images
:toc: macro
toc::[]
This document goes over the _suggested_ way to structure a hardware support package. At the end of the day, MicroZig is designed for flexibility, we do not require all "supported" hardware be defined in one monorepo. Instead, we make it so that you can define your hardware locally if that best suits your project.

@ -1,3 +0,0 @@
= Tips and Tricks
This document has some `build.zig` tricks for other pages to reference.

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2022 Zig Embedded Group
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -1,3 +0,0 @@
# microzig-examples
Examples for embedded zig!

@ -0,0 +1,19 @@
Copyright (c) Zig Embedded Group contributors
This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use
of this software.
Permission is granted to anyone to use this software for any purpose, including
commercial applications, and to alter it and redistribute it freely, subject to
the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is
not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

@ -20,7 +20,7 @@ pub fn build(b: *std.Build) void {
.name = example.name, .name = example.name,
.target = example.target, .target = example.target,
.optimize = optimize, .optimize = optimize,
.source_file = .{ .path = example.file }, .root_source_file = .{ .path = example.file },
}); });
// `installFirmware()` is the MicroZig pendant to `Build.installArtifact()` // `installFirmware()` is the MicroZig pendant to `Build.installArtifact()`

@ -7,7 +7,10 @@
}, },
.paths = .{ .paths = .{
"LICENSE",
"README.md",
"build.zig", "build.zig",
"build.zig.zon", "build.zig.zon",
"src",
}, },
} }

@ -0,0 +1,19 @@
Copyright (c) Zig Embedded Group contributors
This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use
of this software.
Permission is granted to anyone to use this software for any purpose, including
commercial applications, and to alter it and redistribute it freely, subject to
the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is
not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

@ -22,7 +22,7 @@ pub fn build(b: *std.Build) void {
.name = example.name, .name = example.name,
.target = example.target, .target = example.target,
.optimize = optimize, .optimize = optimize,
.source_file = .{ .path = example.file }, .root_source_file = .{ .path = example.file },
}); });
// `install_firmware()` is the MicroZig pendant to `Build.installArtifact()` // `install_firmware()` is the MicroZig pendant to `Build.installArtifact()`

@ -7,7 +7,9 @@
}, },
.paths = .{ .paths = .{
"LICENSE",
"build.zig", "build.zig",
"build.zig.zon", "build.zig.zon",
"src",
}, },
} }

@ -0,0 +1,19 @@
Copyright (c) Zig Embedded Group contributors
This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use
of this software.
Permission is granted to anyone to use this software for any purpose, including
commercial applications, and to alter it and redistribute it freely, subject to
the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is
not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

@ -20,7 +20,7 @@ pub fn build(b: *std.Build) void {
.name = example.name, .name = example.name,
.target = example.target, .target = example.target,
.optimize = optimize, .optimize = optimize,
.source_file = .{ .path = example.file }, .root_source_file = .{ .path = example.file },
}); });
// `install_firmware()` is the MicroZig pendant to `Build.installArtifact()` // `install_firmware()` is the MicroZig pendant to `Build.installArtifact()`

@ -7,7 +7,9 @@
}, },
.paths = .{ .paths = .{
"LICENSE",
"build.zig", "build.zig",
"build.zig.zon", "build.zig.zon",
"src",
}, },
} }

@ -0,0 +1,19 @@
Copyright (c) Zig Embedded Group contributors
This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use
of this software.
Permission is granted to anyone to use this software for any purpose, including
commercial applications, and to alter it and redistribute it freely, subject to
the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is
not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

@ -21,7 +21,7 @@ pub fn build(b: *std.Build) void {
.name = example.name, .name = example.name,
.target = example.target, .target = example.target,
.optimize = optimize, .optimize = optimize,
.source_file = .{ .path = example.file }, .root_source_file = .{ .path = example.file },
}); });
// `install_firmware()` is the MicroZig pendant to `Build.installArtifact()` // `install_firmware()` is the MicroZig pendant to `Build.installArtifact()`

@ -7,7 +7,9 @@
}, },
.paths = .{ .paths = .{
"LICENSE",
"build.zig", "build.zig",
"build.zig.zon", "build.zig.zon",
"src",
}, },
} }

@ -0,0 +1,19 @@
Copyright (c) Zig Embedded Group contributors
This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use
of this software.
Permission is granted to anyone to use this software for any purpose, including
commercial applications, and to alter it and redistribute it freely, subject to
the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is
not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

@ -1,11 +0,0 @@
= Nordic nrf5x
HALs and register definitions for nrf5x devices
== What version of Zig to use
Right now we are following https://ziglang.org/download/[master], but once 0.11.0 is released, we will be switching to the latest stable version of Zig.
== Renode supports:
- nrf52840 development kit

@ -0,0 +1,7 @@
# Nordic nrf5x
HALs and register definitions for nrf5x devices
## Renode supports:
- nrf52840 development kit

@ -4,7 +4,7 @@ const MicroZig = @import("microzig/build");
const nrf5x = @import("microzig/bsp/nordic/nrf5x"); const nrf5x = @import("microzig/bsp/nordic/nrf5x");
const available_examples = [_]Example{ const available_examples = [_]Example{
.{ .target = nrf5x.boards.nordic.nRF52840_Dongle, .name = "nrf52480-dongle_blinky", .file = "src/blinky.zig" }, .{ .target = nrf5x.boards.nordic_nRF52840_Dongle, .name = "nrf52480-dongle_blinky", .file = "src/blinky.zig" },
}; };
pub fn build(b: *Build) void { pub fn build(b: *Build) void {
@ -21,7 +21,7 @@ pub fn build(b: *Build) void {
.name = example.name, .name = example.name,
.target = example.target, .target = example.target,
.optimize = optimize, .optimize = optimize,
.source_file = .{ .path = example.file }, .root_source_file = .{ .path = example.file },
}); });
// `install_firmware()` is the MicroZig pendant to `Build.installArtifact()` // `install_firmware()` is the MicroZig pendant to `Build.installArtifact()`

@ -7,7 +7,10 @@
}, },
.paths = .{ .paths = .{
"LICENSE",
"README.md",
"build.zig", "build.zig",
"build.zig.zon", "build.zig.zon",
"src",
}, },
} }

@ -0,0 +1,19 @@
Copyright (c) Zig Embedded Group contributors
This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use
of this software.
Permission is granted to anyone to use this software for any purpose, including
commercial applications, and to alter it and redistribute it freely, subject to
the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is
not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

@ -20,7 +20,7 @@ pub fn build(b: *std.Build) void {
.name = example.name, .name = example.name,
.target = example.target, .target = example.target,
.optimize = optimize, .optimize = optimize,
.source_file = .{ .path = example.file }, .root_source_file = .{ .path = example.file },
}); });
// `install_firmware()` is the MicroZig pendant to `Build.installArtifact()` // `install_firmware()` is the MicroZig pendant to `Build.installArtifact()`

@ -7,7 +7,10 @@
}, },
.paths = .{ .paths = .{
"LICENSE",
"README.md",
"build.zig", "build.zig",
"build.zig.zon", "build.zig.zon",
"src",
}, },
} }

@ -0,0 +1,19 @@
Copyright (c) Zig Embedded Group contributors
This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use
of this software.
Permission is granted to anyone to use this software for any purpose, including
commercial applications, and to alter it and redistribute it freely, subject to
the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is
not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

@ -41,7 +41,7 @@ pub fn build(b: *std.Build) void {
.name = example.name, .name = example.name,
.target = example.target, .target = example.target,
.optimize = optimize, .optimize = optimize,
.source_file = .{ .path = example.file }, .root_source_file = .{ .path = example.file },
}); });
// `install_firmware()` is the MicroZig pendant to `Build.installArtifact()` // `install_firmware()` is the MicroZig pendant to `Build.installArtifact()`

@ -7,7 +7,11 @@
}, },
.paths = .{ .paths = .{
"LICENSE",
"README.md",
"build.zig", "build.zig",
"build.zig.zon", "build.zig.zon",
"src",
"scripts",
}, },
} }

@ -0,0 +1,19 @@
Copyright (c) Zig Embedded Group contributors
This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use
of this software.
Permission is granted to anyone to use this software for any purpose, including
commercial applications, and to alter it and redistribute it freely, subject to
the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is
not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

@ -27,7 +27,7 @@ pub fn build(b: *std.Build) void {
.name = example.name, .name = example.name,
.target = example.target, .target = example.target,
.optimize = optimize, .optimize = optimize,
.source_file = .{ .path = example.file }, .root_source_file = .{ .path = example.file },
}); });
// `install_firmware()` is the MicroZig pendant to `Build.installArtifact()` // `install_firmware()` is the MicroZig pendant to `Build.installArtifact()`

@ -7,7 +7,9 @@
}, },
.paths = .{ .paths = .{
"LICENSE",
"build.zig", "build.zig",
"build.zig.zon", "build.zig.zon",
"src",
}, },
} }

@ -1,747 +0,0 @@
#!/usr/bin/env python3
#
# Prepares a full deployment of MicroZig.
# Creates all packages into ${repo}/microzig-deploy with the final folder structure.
#
# Just invoke this script to create a deployment structure for MicroZig.
#
import io, sys, os, datetime, re, shutil, json, hashlib, html
from pathlib import Path, PurePosixPath
from dataclasses import dataclass, field
from dataclasses_json import dataclass_json, config as dcj_config, Exclude as JsonExclude
from semver import Version
from marshmallow import fields
from enum import Enum as StrEnum
from argparse import ArgumentParser, BooleanOptionalAction
import pathspec
import stat
import tarfile
from marshmallow import fields as mm_fields
from typing import Optional, Any
from lib.common import execute_raw, execute, slurp, check_zig_version, check_required_tools
import lib.common as common
DEFAULT_DEPLOYMENT_BASE="https://download.microzig.tech/packages"
DEBUG_DEPLOYMENT_BASE="http://localhost:8080"
LEGAL_PACKAGE_NAME = re.compile("^[A-Za-z]$")
VERBOSE = False
ALL_FILES_DIR=".data"
REQUIRED_TOOLS = [
"zig",
"git",
"tar",
"gzip",
]
REQUIRED_ZIG_VERSION="0.11.0"
REPO_ROOT = Path(__file__).parent.parent
assert REPO_ROOT.is_dir()
common.VERBOSE = VERBOSE
class PackageType(StrEnum):
build = "build"
core = "core"
board_support = "board-support"
example = "example"
@dataclass_json
@dataclass
class Archive:
size: str
sha256sum: str
@dataclass_json
@dataclass
class Package:
hash: str
files: list[str] = field(default_factory=lambda:[])
@dataclass_json
@dataclass
class ExternalDependency:
url: str
hash: str
@dataclass_json
@dataclass
class Timestamp:
unix: str
iso: str
@dataclass_json
@dataclass
class PackageConfiguration:
package_name: str
package_type: PackageType
version: Optional[Version] = field(default=None, metadata=dcj_config(decoder=Version.parse, encoder=Version.__str__, mm_field=fields.String()))
external_dependencies: dict[str,ExternalDependency] = field(default_factory=lambda:dict())
inner_dependencies: set[str] = field(default_factory=lambda:set())
archive: Optional[Archive] = field(default = None)
created: Optional[Timestamp] = field(default = None)
package: Optional[Package] = field(default= None)
download_url: Optional[str] = field(default=None)
microzig: Optional[Any] = field(default=None) # optional configuration field with microzig-specific options
# inner fields:
# package_dir: Path = field(default=None, metadata = dcj_config(exclude=JsonExclude.ALWAYS))
@dataclass_json
@dataclass
class PackageDesc:
name: str
type: PackageType
version: str # semver
metadata: str # url to json
download: str # url to tar.gz
@dataclass_json
@dataclass
class PackageIndex:
last_update: Timestamp
packages: list[PackageDesc]
PackageIndexSchema = PackageIndex.schema()
PackageSchema = Package.schema()
PackageConfigurationSchema = PackageConfiguration.schema()
def file_digest(path: Path, hashfunc) -> bytes:
BUF_SIZE = 65536
digest = hashfunc()
with path.open('rb') as f:
while True:
data = f.read(BUF_SIZE)
if not data:
break
digest.update(data)
return digest.digest()
FILE_STAT_MAP = {
stat.S_IFDIR: "directory",
stat.S_IFCHR: "character device",
stat.S_IFBLK: "block device",
stat.S_IFREG: "regular",
stat.S_IFIFO: "fifo",
stat.S_IFLNK: "link",
stat.S_IFSOCK: "socket",
}
def file_type(path: Path) -> str:
return FILE_STAT_MAP[stat.S_IFMT( path.stat().st_mode)]
def build_zig_tools():
# ensure we have our tools available:
execute("zig", "build", "tools", cwd=REPO_ROOT)
archive_info = REPO_ROOT / "zig-out/tools/archive-info"
create_pkg_descriptor = REPO_ROOT / "zig-out/tools/create-pkg-descriptor"
assert archive_info.is_file()
assert create_pkg_descriptor.is_file()
return {
"archive_info": archive_info,
"create_pkg_descriptor": create_pkg_descriptor,
}
# Determines the correct version:
def get_version_from_git() -> str:
raw_git_out = slurp("git", "describe", "--match", "*.*.*", "--tags", "--abbrev=9", cwd=REPO_ROOT, allow_failure=True).strip().decode()
if len(raw_git_out) == 0:
print("failed to get version from git, using 'development'", file=sys.stderr)
return f"{REQUIRED_ZIG_VERSION}-development"
def render_version(major,minor,patch,counter,hash):
return f"{major}.{minor}.{patch}-{counter}-{hash}"
full_version = re.match('^([0-9]+)\.([0-9]+)\.([0-9]+)\-([0-9]+)\-([a-z0-9]+)$', raw_git_out)
if full_version:
return render_version(*full_version.groups())
base_version = re.match('^([0-9]+)\.([0-9]+)\.([0-9]+)$', raw_git_out)
if base_version:
commit_hash = slurp("git", "rev-parse", "--short=9", "HEAD")
return render_version(*base_version.groups(), 0, commit_hash)
raise RuntimeError(f"Bad result '{raw_git_out}' from git describe.")
def create_output_directory(repo_root: Path) -> Path:
deploy_target=repo_root / "microzig-deploy"
if deploy_target.is_dir():
shutil.rmtree(deploy_target)
assert not deploy_target.exists()
deploy_target.mkdir()
return deploy_target
def resolve_dependency_order(packages: dict[PackageConfiguration]) -> list[PackageConfiguration]:
open_list = list(packages.values())
closed_set = set()
closed_list = []
while len(open_list) > 0:
head = open_list.pop(0)
all_resolved = True
for dep_name in head.inner_dependencies:
dep = packages[dep_name]
if dep.package_name not in closed_set:
all_resolved = False
break
if all_resolved:
closed_set.add(head.package_name)
closed_list.append(head)
else:
open_list.append(head)
return closed_list
def get_batch_timestamp():
render_time = datetime.datetime.now()
return Timestamp(
unix=str(int(render_time.timestamp())),
iso=render_time.isoformat(),
)
def list_of_str(arg):
return arg.split(',')
def main():
arg_parser = ArgumentParser()
arg_parser.add_argument("--base-url", type=str, required=False, default=DEFAULT_DEPLOYMENT_BASE, help="Sets the download URL for the packages.")
arg_parser.add_argument("--debug", action="store_true", required=False, default=False, help="Creates a deployment for local development, hosted by localhost:8080")
arg_parser.add_argument("--examples", action=BooleanOptionalAction, required=False, default=True, help="Build the examples")
arg_parser.add_argument("--boards", type=list_of_str, help='list of boards to build', default=[])
cli_args = arg_parser.parse_args()
base_url = cli_args.base_url if not cli_args.debug else DEBUG_DEPLOYMENT_BASE
check_required_tools(REQUIRED_TOOLS)
check_zig_version(REQUIRED_ZIG_VERSION)
print("preparing environment...")
deploy_target = create_output_directory(REPO_ROOT)
# Some generic meta information:
batch_timestamp = get_batch_timestamp()
version = get_version_from_git()
tools = build_zig_tools()
# After building the tools, zig-cache should exist, so we can tap into it for our own caching purposes:
cache_root = REPO_ROOT / "zig-cache"
assert cache_root.is_dir()
cache_dir = cache_root / "microzig"
cache_dir.mkdir(exist_ok=True)
detail_files_dir = deploy_target / ALL_FILES_DIR
detail_files_dir.mkdir(exist_ok=True)
# Prepare `.gitignore` pattern matcher:
global_ignore_spec = pathspec.PathSpec.from_lines(
pathspec.patterns.GitWildMatchPattern,
(REPO_ROOT / ".gitignore").read_text().splitlines(),
)
# also insert a pattern to exclude
global_ignore_spec.patterns.append(
pathspec.patterns.GitWildMatchPattern("microzig-package.json")
)
# Fetch and find all packages:
print("validating packages...")
packages = {}
validation_ok = True
PACKAGES_ROOT = PurePosixPath("packages")
EXAMPLES_ROOT = PurePosixPath("examples")
for meta_path in REPO_ROOT.rglob("microzig-package.json"):
assert meta_path.is_file()
pkg_dir = meta_path.parent
pkg_dict = json.loads(meta_path.read_bytes())
pkg = PackageConfigurationSchema.load(pkg_dict)
# Skip examples or non enabled boards
if any([
pkg.package_type == PackageType.example and not cli_args.examples,
pkg.package_type == PackageType.board_support and cli_args.boards and pkg.package_name not in cli_args.boards
]):
continue
pkg.version = version
pkg.created = batch_timestamp
pkg.package_dir = pkg_dir
if pkg.package_type == PackageType.build:
pkg.out_rel_dir = PACKAGES_ROOT
pkg.out_basename = pkg.package_name
elif pkg.package_type == PackageType.core:
pkg.out_rel_dir = PACKAGES_ROOT
pkg.out_basename = pkg.package_name
# Implicit dependencies:
pkg.inner_dependencies.add("microzig-build") # core requires the build types
elif pkg.package_type == PackageType.board_support:
parsed_pkg_name = PurePosixPath( pkg.package_name)
pkg.out_rel_dir = PACKAGES_ROOT / "board-support" / parsed_pkg_name.parent
pkg.out_basename = parsed_pkg_name.name
# Implicit dependencies:
pkg.inner_dependencies.add("microzig-build") # BSPs also require build types
pkg.inner_dependencies.add("microzig-core") # but also the core types (?)
elif pkg.package_type == PackageType.example:
parsed_pkg_name = PurePosixPath( pkg.package_name)
pkg.package_name = "examples:" + pkg.package_name # patch the name so we can use the same name for BSP and Example
pkg.out_rel_dir = EXAMPLES_ROOT / parsed_pkg_name.parent
pkg.out_basename = parsed_pkg_name.name
# Implicit dependencies:
pkg.inner_dependencies.add("microzig-build") # BSPs also require build types
pkg.inner_dependencies.add("microzig-core") # but also the core types (?)
else:
assert False
download_path = pkg.out_rel_dir / ALL_FILES_DIR / f"{pkg.out_basename}-{version}.tar.gz"
pkg.download_url = f"{base_url}/{download_path}"
buildzig_path = pkg_dir / "build.zig"
buildzon_path = pkg_dir / "build.zig.zon"
if not buildzig_path.is_file():
print("")
print(f"The package at {meta_path} is missing its build.zig file: {buildzig_path}")
print("Please create a build.zig for that package!")
validation_ok = False
if buildzon_path.is_file():
print("")
print(f"The package at {meta_path} has a build.zig.zon: {buildzon_path}")
print("Please remove that file and merge it into microzig-package.json!")
validation_ok = False
if pkg.package_name not in packages:
packages[pkg.package_name] = pkg
else:
print("")
print(f"The package at {meta_path} has a duplicate package name {pkg.package_name}")
print("Please remove that file and merge it into microzig-package.json!")
validation_ok = False
if not validation_ok:
print("Not all packages are valid. Fix the packages and try again!" )
exit(1)
print("loaded packages:")
for key in packages:
print(f" * {key}")
print("resolving inner dependencies...")
evaluation_ordered_packages = resolve_dependency_order(packages)
# bundle everything:
index = PackageIndex(
last_update = batch_timestamp,
packages = [],
)
print("creating packages...")
for pkg in evaluation_ordered_packages:
print(f"bundling {pkg.package_name}...")
pkg_dir = pkg.package_dir
pkg_cache_dir = cache_dir / hashlib.md5(pkg.package_name.encode()).hexdigest()
pkg_cache_dir.mkdir(exist_ok=True)
meta_path = pkg_dir / "microzig-package.json"
pkg_zon_file = pkg_cache_dir / pkg_dir.name / "build.zig.zon"
out_rel_dir: PurePosixPath = pkg.out_rel_dir
out_basename: str = pkg.out_basename
if pkg.package_type == PackageType.board_support:
bsp_info = slurp(
"zig", "build-exe",
f"{REPO_ROOT}/tools/extract-bsp-info.zig" ,
"--cache-dir", f"{REPO_ROOT}/zig-cache",
"--deps", "bsp,microzig-build",
"--mod", f"bsp:microzig-build:{pkg_dir}/build.zig",
"--mod", f"microzig-build:uf2:{REPO_ROOT}/build/build.zig",
"--mod", f"uf2::{REPO_ROOT}/tools/lib/dummy_uf2.zig",
"--name", "extract-bsp-info",
cwd=pkg_cache_dir,
)
extra_json_str=slurp(pkg_cache_dir/"extract-bsp-info")
pkg.microzig = json.loads(extra_json_str)
assert out_rel_dir is not None
assert out_basename is not None
# File names:
out_file_name_tar = f"{out_basename}-{version}.tar"
out_file_name_compr = f"{out_file_name_tar}.gz"
out_file_name_meta = f"{out_basename}-{version}.json"
out_symlink_pkg_name = f"{out_basename}.tar.gz"
out_symlink_meta_name = f"{out_basename}.json"
# Directories_:
out_base_dir = deploy_target / out_rel_dir
out_data_dir = out_base_dir / ALL_FILES_DIR
# paths:
out_file_tar = out_data_dir / out_file_name_tar
out_file_targz = out_data_dir / out_file_name_compr
out_file_meta = out_data_dir / out_file_name_meta
out_symlink_pkg = out_base_dir / out_symlink_pkg_name
out_symlink_meta = out_base_dir / out_symlink_meta_name
# ensure the directories exist:
out_base_dir.mkdir(parents = True, exist_ok=True)
out_data_dir.mkdir(parents = True, exist_ok=True)
# find files that should be packaged:
package_files = [*global_ignore_spec.match_tree(pkg_dir,negate = True )]
# package_files = [
# file.relative_to(pkg_dir)
# for file in pkg_dir.rglob("*")
# if not global_ignore_spec.match_file(str(file))
# if file.name !=
# ]
if VERBOSE:
print("\n".join(f" * {str(f)} ({file_type(pkg_dir / f)})" for f in package_files))
print()
# tar -cf "${out_tar}" $(git ls-files -- . ':!:microzig-package.json')
execute("tar", "-cf", out_file_tar, "--hard-dereference", *( f"{pkg_dir.name}/{file}" for file in package_files), cwd=pkg_dir.parent)
zon_data = slurp(
tools["create_pkg_descriptor"],
pkg.package_name,
input=PackageConfigurationSchema.dumps(evaluation_ordered_packages, many=True ).encode(),
)
pkg_zon_file.parent.mkdir(exist_ok=True)
with pkg_zon_file.open("wb") as f:
f.write(zon_data)
slurp("zig", "fmt", pkg_zon_file) # slurp the message away
execute("tar", "-rf", out_file_tar, "--hard-dereference", f"{pkg_zon_file.parent.name}/{pkg_zon_file.name}", cwd=pkg_zon_file.parent.parent)
# tar --list --file "${out_tar}" > "${pkg_cache_dir}/contents.list"
zig_pkg_info_str = slurp(tools["archive_info"], out_file_tar)
pkg.package = PackageSchema.loads(zig_pkg_info_str)
# explicitly use maximum compression level here as we're shipping to potentially many people
execute("gzip", "-f9", out_file_tar)
assert not out_file_tar.exists()
assert out_file_targz.is_file()
del out_file_tar
pkg.archive = Archive(
sha256sum = file_digest(out_file_targz, hashlib.sha256).hex(),
size = str(out_file_targz.stat().st_size),
)
with out_file_meta.open("w") as f:
f.write(PackageConfigurationSchema.dumps(pkg))
out_symlink_pkg.symlink_to(out_file_targz.relative_to(out_symlink_pkg.parent))
out_symlink_meta.symlink_to(out_file_meta.relative_to(out_symlink_meta.parent))
index.packages.append(PackageDesc(
name = pkg.package_name,
type = pkg.package_type,
version = version,
metadata = pkg.download_url.removesuffix(".tar.gz") + ".json",
download = pkg.download_url,
))
with (deploy_target / "index.json").open("w") as f:
f.write(PackageIndexSchema.dumps(index))
with (detail_files_dir / "chip-families.svg").open("w") as f:
ICON_YES = TableIcon(
glyph="",
path="M10,17L5,12L6.41,10.58L10,14.17L17.59,6.58L19,8M19,3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3Z",
color="#0f0",
)
ICON_NO = TableIcon(
glyph="",
path="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z",
color="#f44336",
)
ICON_WIP = TableIcon(
glyph="🛠",
path="M13.78 15.3L19.78 21.3L21.89 19.14L15.89 13.14L13.78 15.3M17.5 10.1C17.11 10.1 16.69 10.05 16.36 9.91L4.97 21.25L2.86 19.14L10.27 11.74L8.5 9.96L7.78 10.66L6.33 9.25V12.11L5.63 12.81L2.11 9.25L2.81 8.55H5.62L4.22 7.14L7.78 3.58C8.95 2.41 10.83 2.41 12 3.58L9.89 5.74L11.3 7.14L10.59 7.85L12.38 9.63L14.2 7.75C14.06 7.42 14 7 14 6.63C14 4.66 15.56 3.11 17.5 3.11C18.09 3.11 18.61 3.25 19.08 3.53L16.41 6.2L17.91 7.7L20.58 5.03C20.86 5.5 21 6 21 6.63C21 8.55 19.45 10.1 17.5 10.1Z",
color="#82aec0",
)
ICON_EXPERIMENTAL = TableIcon(
glyph="🧪",
path="M7,2V4H8V18A4,4 0 0,0 12,22A4,4 0 0,0 16,18V4H17V2H7M11,16C10.4,16 10,15.6 10,15C10,14.4 10.4,14 11,14C11.6,14 12,14.4 12,15C12,15.6 11.6,16 11,16M13,12C12.4,12 12,11.6 12,11C12,10.4 12.4,10 13,10C13.6,10 14,10.4 14,11C14,11.6 13.6,12 13,12M14,7H10V4H14V7Z",
color="#2ac9b4"
)
ICON_UNKNOWN = TableIcon(
glyph="",
path="M10,19H13V22H10V19M12,2C17.35,2.22 19.68,7.62 16.5,11.67C15.67,12.67 14.33,13.33 13.67,14.17C13,15 13,16 13,17H10C10,15.33 10,13.92 10.67,12.92C11.33,11.92 12.67,11.33 13.5,10.67C15.92,8.43 15.32,5.26 12,5A3,3 0 0,0 9,8H6A6,6 0 0,1 12,2Z",
color="#ed4034"
)
def bsp_info(bsp: PackageConfiguration):
targets = bsp.microzig["board-support"]["targets"]
num_chips = len([
1
for tgt
in targets
if tgt["board"] is None
])
num_boards = len(targets) - num_chips
any_hal = any(
tgt["features"]["hal"]
for tgt
in targets
)
all_hal = all(
tgt["features"]["hal"]
for tgt
in targets
)
hal_support = ICON_NO
if all_hal:
hal_support = ICON_YES
elif any_hal:
hal_support = ICON_WIP
examples = packages.get(f"examples:{bsp.package_name}", None)
return [
bsp.package_name, # Chip Family
num_chips, # Chips
num_boards, # Boards
hal_support, # HAL
TableLink(href=f"https://downloads.microzig.tech/examples/{bsp.package_name}.tar.gz", content="Download") if examples is not None else "", # Examples
]
render_table(
target=f,
columns=[
TableColumn(title="Chip Family", width=200),
TableColumn(title="Chips", width=70),
TableColumn(title="Boards", width=70),
TableColumn(title="HAL", width=50),
TableColumn(title="Examples", width=100),
# TableColumn(title="Abstractions", width=120),
],
rows = [
bsp_info(bsp)
for key, bsp
in sorted(packages.items())
if bsp.package_type == PackageType.board_support
],
)
@dataclass
class TableLink:
href: str
content: any
@dataclass
class TableIcon:
glyph: str
path: str
color: str = field(default="#fff")
@dataclass
class TableColumn:
title: str
width: int
def render_table(target: io.IOBase, columns: list[TableColumn], rows: list[list[str]]):
cell_height = 25
total_width = sum(col.width for col in columns)
total_height = cell_height * (1 + len(rows))
target.write('<?xml version="1.0" encoding="UTF-8" standalone="no"?>')
target.write('<svg')
target.write(' width="%s"' % (total_width))
target.write(' height="%s"' % (total_height))
target.write(' viewBox="0 0 %s %s"' % (total_width, total_height))
target.write(' version="1.1"')
target.write(' xmlns="http://www.w3.org/2000/svg">')
target.write("""<style>
svg {
background-color: #0d1117;
}
rect {
fill: none;
stroke: #30363d;
stroke-width: 1;
stroke-linecap: round;
stroke-linejoin: round;
stroke-opacity: 1;
}
rect.odd {
fill: #161b22;
}
text {
font-style: normal;
font-variant: normal;
font-weight: normal;
font-stretch: normal;
font-size: 20;
line-height:1.25;
font-family: sans-serif;
font-variant-ligatures: normal;
font-variant-caps: normal;
font-variant-numeric: normal;
stroke-width: 1;
fill: #e6edf3;
}
text.heading {
font-weight: bold;
}
a {
fill: #2c81f7;
}
</style>""")
target.write('<g>')
x = 0
y = 0
def valueout(content: any):
if isinstance(content, TableLink):
target.write(f'<a target="_blank" href="{content.href}">')
valueout(content.content)
target.write('</a>')
elif isinstance(content, TableIcon):
target.write(content.glyph)
else:
target.write(html.escape(str(content)))
def cellout(col: TableColumn, content: any, is_heading: bool = False):
nonlocal x, y
target.write('<rect')
target.write(f' width="{col.width}"')
target.write(f' height="{cell_height}"')
target.write(f' x="{x}"')
target.write(f' y="{y}"')
target.write('/>')
target.write('<text')
if is_heading:
target.write(' class="heading"')
target.write(f' space="preserve"')
target.write(f' x="{x+5}"')
target.write(f' y="{y+cell_height-5}"')
target.write('>')
valueout(content)
target.write("</text>")
x += col.width
def endrow():
nonlocal x, y
x = 0
y += cell_height
for col in columns:
cellout(col, col.title, is_heading=True)
endrow()
for row in rows:
for col, cell in zip(columns, row):
cellout(col, cell)
endrow()
target.write(""" </g>
</svg>
""")
if __name__ == "__main__":
main()

@ -1,162 +0,0 @@
//!
//! Creates a `build.zig.zon` based on a JSON array of `microzig-package.json` files.
//!
//! Usage: create-pkg-descriptor <package-name> < all-packages.json > build.zig.zon
//!
//! Searches for a package called `<package-name>` in the `microzig-package.json` descriptors
//! passed in on stdin.
//!
//! Those package descriptors must have `version`, `package_name`, `external_dependencies` and `inner_dependencies` set,
//! The inner dependencies must also have `download_url` and `package.hash` available.
//!
//! This program is intended for the use from the `tools/bundly.py` bundler. See this script for more usage information.
//!
const std = @import("std");
const eggzon = @import("eggzon");
const fmtEscapes = std.zig.fmtEscapes;
const fmtId = std.zig.fmtId;
const Archive = struct {
sha256sum: []const u8,
size: []const u8,
};
const Package = struct {
hash: []const u8,
files: []const []const u8,
};
const Timestamp = struct {
iso: []const u8,
unix: []const u8,
};
const MetaData = struct {
const Type = enum(u32) {
// we "abuse" the enum value here to map our keys to a priority mapping:
// Zig 0.11 must have dependencies with inner dependencies in the right order,
// otherwise the build system won't find the dependencies:
build = 0, // must always be first
core = 300,
@"board-support" = 500,
example = 900,
};
package_name: []const u8,
package_type: Type,
version: []const u8,
inner_dependencies: [][]const u8 = &.{},
external_dependencies: std.json.Value = .null,
archive: ?Archive = null,
package: ?Package = null,
created: ?Timestamp = null,
download_url: ?[]const u8 = null,
microzig: std.json.Value = .null,
};
fn findPackage(packages: []const MetaData, name: []const u8) ?*const MetaData {
return for (packages) |*pkg| {
if (std.mem.eql(u8, pkg.package_name, name))
return pkg;
} else null;
}
fn renderDep(writer: anytype, name: []const u8, url: []const u8, hash: []const u8) !void {
try writer.print(" .{} = .{{\n", .{fmtId(name)});
try writer.print(" .url = \"{}\",\n", .{fmtEscapes(url)});
try writer.print(" .hash = \"{}\",\n", .{fmtEscapes(hash)});
try writer.writeAll(" },\n");
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var arena_impl = std.heap.ArenaAllocator.init(allocator);
defer arena_impl.deinit();
const arena = arena_impl.allocator();
const argv = try std.process.argsAlloc(arena);
if (argv.len != 2) {
@panic("version and/or relpath missing!");
}
// build inputs:
const pkg_name = argv[1];
const json_input = try std.io.getStdIn().readToEndAlloc(arena, 1 << 20);
errdefer std.log.err("failed to parse json from {s}", .{json_input});
const all_packages = try std.json.parseFromSliceLeaky([]MetaData, arena, json_input, .{});
const package = findPackage(all_packages, pkg_name).?;
const version = try std.SemanticVersion.parse(package.version);
var buffered_stdout = std.io.bufferedWriter(std.io.getStdOut().writer());
const stdout = buffered_stdout.writer();
{
try stdout.writeAll(".{\n");
try stdout.print(" .name = \"{}\",\n", .{fmtEscapes(package.package_name)});
try stdout.print(" .version = \"{}\",\n", .{version});
try stdout.writeAll(" .dependencies = .{\n");
if (package.external_dependencies != .null) {
const deps = &package.external_dependencies.object;
for (deps.keys(), deps.values()) |key, value| {
const dep: *const std.json.ObjectMap = &value.object;
try renderDep(
stdout,
key,
dep.get("url").?.string,
dep.get("hash").?.string,
);
}
}
std.sort.block([]const u8, package.inner_dependencies, all_packages, orderPackagesByPriority);
// Add all other dependencies:
for (package.inner_dependencies) |dep_name| {
const dep = findPackage(all_packages, dep_name).?;
try renderDep(
stdout,
dep_name,
dep.download_url.?,
dep.package.?.hash,
);
}
try stdout.writeAll(" },\n");
try stdout.writeAll("}\n");
}
try buffered_stdout.flush();
}
fn orderPackagesByPriority(mt: []MetaData, lhs_name: []const u8, rhs_name: []const u8) bool {
const rhs = findPackage(mt, rhs_name).?;
const lhs = findPackage(mt, lhs_name).?;
const rhs_prio = @intFromEnum(rhs.package_type);
const lhs_prio = @intFromEnum(lhs.package_type);
if (lhs_prio < rhs_prio)
return true;
if (lhs_prio > rhs_prio)
return false;
return std.ascii.lessThanIgnoreCase(lhs_name, rhs_name);
}

@ -1,100 +0,0 @@
//!
//! A tool that extracs which chips and boards are available from a board support package
//! and validates that the declarations conform
//!
const std = @import("std");
const bsp = @import("bsp");
const microzig = @import("microzig/build");
// Fake build_runner.zig api:
pub const dependencies = struct {
pub const imports = struct {};
};
const JsonTarget = struct {
id: []const u8,
output_format: ?[]const u8,
features: struct {
hal: bool,
},
memory: struct {
flash: u64,
ram: u64,
},
cpu: []const u8,
chip: []const u8,
chip_url: ?[]const u8,
board: ?[]const u8,
board_url: ?[]const u8,
};
fn renderMicroZigTarget(stream: anytype, key: []const u8, target: microzig.Target) !void {
var jtarget = JsonTarget{
.id = key,
.output_format = if (target.preferred_format) |fmt| @tagName(fmt) else null,
.features = .{
.hal = (target.hal != null),
},
.cpu = @tagName(target.chip.cpu),
.chip = target.chip.name,
.chip_url = target.chip.url,
.board = null,
.board_url = null,
.memory = .{
.flash = 0,
.ram = 0,
},
};
if (target.board) |brd| {
jtarget.board = brd.name;
jtarget.board_url = brd.url;
}
for (target.chip.memory_regions) |reg| {
switch (reg.kind) {
.flash => jtarget.memory.flash += reg.length,
.ram => jtarget.memory.ram += reg.length,
else => {},
}
}
try std.json.stringify(jtarget, .{}, stream);
}
fn renderTargetArray(stream: anytype, targets: []const microzig.BoardSupportPackageDefinition.TargetDefinition) !void {
for (targets, 0..) |target_def, i| {
if (i > 0) try stream.writeAll(",");
try renderMicroZigTarget(
stream,
target_def.id,
target_def.target,
);
}
}
pub fn main() !void {
const info = bsp.microzig_board_support;
var stdout = std.io.getStdOut().writer();
try stdout.writeAll("{ \"board-support\": {");
try stdout.writeAll("\"targets\":[");
try renderTargetArray(stdout, info.targets);
try stdout.writeAll("]}}");
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save