Thanks for using Compiler Explorer
Sponsors
Jakt
C++
Ada
Algol68
Analysis
Android Java
Android Kotlin
Assembly
C
C3
Carbon
C with Coccinelle
C++ with Coccinelle
C++ (Circle)
CIRCT
Clean
CMake
CMakeScript
COBOL
C++ for OpenCL
MLIR
Cppx
Cppx-Blue
Cppx-Gold
Cpp2-cppfront
Crystal
C#
CUDA C++
D
Dart
Elixir
Erlang
Fortran
F#
GLSL
Go
Haskell
HLSL
Hook
Hylo
IL
ispc
Java
Julia
Kotlin
LLVM IR
LLVM MIR
Modula-2
Mojo
Nim
Numba
Nix
Objective-C
Objective-C++
OCaml
Odin
OpenCL C
Pascal
Pony
PTX
Python
Racket
Raku
Ruby
Rust
Sail
Snowball
Scala
Slang
Solidity
Spice
SPIR-V
Swift
LLVM TableGen
Toit
Triton
TypeScript Native
V
Vala
Visual Basic
Vyper
WASM
Zig
Javascript
GIMPLE
Ygen
sway
zig source #2
Output
Compile to binary object
Link to binary
Execute the code
Intel asm syntax
Demangle identifiers
Verbose demangling
Filters
Unused labels
Library functions
Directives
Comments
Horizontal whitespace
Debug intrinsics
Compiler
zig 0.10.0
zig 0.11.0
zig 0.12.0
zig 0.12.1
zig 0.13.0
zig 0.14.0
zig 0.14.1
zig 0.15.1
zig 0.2.0
zig 0.3.0
zig 0.4.0
zig 0.5.0
zig 0.6.0
zig 0.7.0
zig 0.7.1
zig 0.8.0
zig 0.9.0
zig trunk
Options
Source code
// simple nonsense example for a memory mapped io register const TimerCtrl = packed struct(u32) { read_only: Field(u8, .read), threshold: Field(u16, .readwrite), enabled: Field(u1, .readwrite), _reserved: Field(u2, .reserved), // field can be timer_mode: Field( enum(u2) { one_pulse = 0, pwm = 1, }, .readwrite, ), _reserved2: Field(u3, .reserved), }; export fn main(timer_ctrl: * volatile Register(TimerCtrl) ) void { // the following line causes a compile error, ensuring the // read_only bit field is not modified // timer_ctrl.modify(.{.read_only = 0}); // configuring some or all of the timer registers in a single call timer_ctrl.modify(.{.timer_mode=.pwm, .threshold=127}); // In order to ensure that the enable bit is set after the // configuration bits, we have make a second modification. timer_ctrl.modify(.{.enabled = 1}); _ = timer_ctrl.read(); // Reading the value returns the bit fields numerical values only //std.debug.print("CTRL: {any}\n", .{timer_ctrl.read()}); // Accessing the timer struct directly also reveals bit field access restrictions //std.debug.print("\nTimer register representation:\n{any}\n", .{timer_ctrl.*.reg}); } pub fn Register(Description: type) type { return packed struct(u32){ reg: Description, pub fn read(self: * volatile @This()) RegisterValue(@TypeOf(self.reg)) { const raw_value: u32 = @as(u32, @bitCast(self.reg)); return @as(RegisterValue(@TypeOf(self.reg)), @bitCast(raw_value)); } // inlining reduces the binary size significantly pub inline fn modify(self: * volatile @This(), mod: RegisterModifier(@TypeOf(self.reg))) void { var value = self.reg; const mod_info = @typeInfo(@TypeOf(mod)); // probably not very efficient, as it iterates through all fields, even though only a single one // might be modified. Then again, the accessed fields are known at compile time, so the // compiler should be able to on optimize away unnecessary field accesses. inline for(mod_info.@"struct".fields) |field| { const val = @field(mod, field.name); if(val != null) { @field(value, field.name).bits = val.?; } } self.reg = value; } }; } // Please, don't look any further! // Please! noo... const Restriction = enum { reserved, read, write, readwrite }; fn Field(bits: type, access: Restriction) type { // access restrictions are encoded into zero sized declarations. switch (access) { .read => return packed struct { const read: u0 = undefined; bits: bits, }, .write => return packed struct { const write: u0 = undefined; bits: bits, }, .readwrite => return packed struct { const readwrite: u0 = undefined; bits: bits, }, .reserved => return packed struct { const reserved: u0 = undefined; bits: bits, }, } } fn RegisterValue(register: type) type { const register_type = @typeInfo(register); const rstrct_fields = register_type.@"struct".fields; var bare_fields: [rstrct_fields.len]Type.StructField = undefined; var struct_with_bare_fields = register_type; struct_with_bare_fields.@"struct".fields = &bare_fields; for (&bare_fields, rstrct_fields) |*bare, rstrct| { const rstrct_struct_fields = @typeInfo(rstrct.type).@"struct".fields; if (rstrct_struct_fields.len != 1) @compileError(err_msg_fields); if (!std.mem.eql(u8, rstrct_struct_fields[0].name, "bits")) @compileError(err_msg_fields); const original_field_type = rstrct_struct_fields[0].type; bare.* = rstrct; bare.*.type = original_field_type; } return @Type(struct_with_bare_fields); } fn RegisterModifier(register: type) type { const register_type = @typeInfo(register); const rstrct_fields = register_type.@"struct".fields; var bare_fields: [rstrct_fields.len]Type.StructField = undefined; var struct_with_bare_fields = register_type; struct_with_bare_fields.@"struct".layout = .auto; struct_with_bare_fields.@"struct".backing_integer = null; var counter: usize = 0; for (rstrct_fields) |rstrct| { if (@hasDecl(rstrct.type, "write") or @hasDecl(rstrct.type, "readwrite")) { const rstrct_struct_info = @typeInfo(rstrct.type); if (rstrct_struct_info != Type.@"struct") @compileError(err_msg_fields); if (rstrct_struct_info.@"struct".fields.len != 1) @compileError(err_msg_fields); if (!std.mem.eql(u8, rstrct_struct_info.@"struct".fields[0].name, "bits")) @compileError(err_msg_fields); const original_field_type = rstrct_struct_info.@"struct".fields[0].type; bare_fields[counter] = rstrct; bare_fields[counter].type = @Type(Type{.optional = .{ .child = original_field_type }}); bare_fields[counter].default_value_ptr = @as(* const bare_fields[counter].type, &null); counter += 1; } } if(counter == 0){ const msg = std.fmt.comptimePrint("The register '{s}' does not have any fields with write access.", .{@typeName(register)}); @compileError(msg); } struct_with_bare_fields.@"struct".fields = bare_fields[0..counter]; return @Type(struct_with_bare_fields); } const err_msg = "Can only build modifier for packed structs."; const err_msg_fields = "All register fields must be of type 'Field'."; const std = @import("std"); const Type = std.builtin.Type;
Become a Patron
Sponsor on GitHub
Donate via PayPal
Compiler Explorer Shop
Source on GitHub
Mailing list
Installed libraries
Wiki
Report an issue
How it works
Contact the author
CE on Mastodon
CE on Bluesky
Statistics
Changelog
Version tree