sylveos

Toy Operating System
Log | Files | Refs

commit 5ba71952a6169b411f1f32f66dd3ed1920bb0fe1
parent 69f6f54a28a74691db0c34c7e1cdabf9b78a0563
Author: Sylvia Ivory <git@sivory.net>
Date:   Wed, 14 Jan 2026 22:10:09 -0800

Add fake-pi

Diffstat:
Mbuild.zig | 39+++++++++++++++++++++++++++++++++++++--
Afake-pi/device.zig | 5+++++
Afake-pi/devices/gpio.zig | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Afake-pi/main.zig | 9+++++++++
Afake-pi/root.zig | 42++++++++++++++++++++++++++++++++++++++++++
Msrc/main.zig | 10+++++++++-
Msrc/root.zig | 4++--
Msrc/util.zig | 28+++++++++++++++-------------
Mstart.s | 16+++++++++++++++-
9 files changed, 212 insertions(+), 19 deletions(-)

diff --git a/build.zig b/build.zig @@ -1,6 +1,35 @@ const std = @import("std"); const config = @import("build.zig.zon"); +fn add_exe_fake_pi(exe_name: []const u8, path: std.Build.LazyPath, b: *std.Build) !*std.Build.Step.Compile { + const pi = b.createModule(.{ + .root_source_file = path, + .target = b.graph.host, + .optimize = .ReleaseSafe, + }); + + const fake_pi = b.createModule(.{ + .root_source_file = b.path("fake-pi/main.zig"), + .target = b.graph.host, + .optimize = .ReleaseSafe, + }); + + fake_pi.addImport("pi", pi); + + const exe_name_fake = try std.fmt.allocPrint(b.allocator, "{s}-fake-pi", .{exe_name}); + defer b.allocator.free(exe_name_fake); + + const exe = b.addExecutable(.{ + .name = exe_name_fake, + .linkage = .static, + .root_module = fake_pi, + }); + + b.installArtifact(exe); + + return exe; +} + fn add_exe(exe_name: []const u8, path: std.Build.LazyPath, b: *std.Build) !*std.Build.Step.Compile { var cpu_features = std.Target.arm.cpu.arm1176jzf_s.features; cpu_features.addFeatureSet(std.Target.arm.featureSet(&[_]std.Target.arm.Feature{.strict_align})); @@ -54,7 +83,7 @@ fn lab(name: []const u8, units: []const []const u8, b: *std.Build) !void { const template = \\ const lab = @import("{s}"); \\ export fn abort() void {{ while(true) {{}} }} - \\ export fn main() void {{ _ = lab.{s}() catch {{}}; }} + \\ pub export fn kmain() void {{ _ = lab.{s}() catch {{}}; }} ; const root_src = try std.fmt.allocPrint(b.allocator, template, .{ lab_path, unit }); @@ -96,10 +125,16 @@ fn handle_lab(name: []const u8, b: *std.Build) !void { } pub fn build(b: *std.Build) !void { + const fake_pi = b.option(bool, "fake-pi", "build with fake-pi"); const lab_opt = b.option([]const u8, "lab", "compile specific lab"); + if (lab_opt) |lab_name| { try handle_lab(lab_name, b); } - _ = try add_exe(@tagName(config.name), b.path("src/root.zig"), b); + if (fake_pi orelse false) { + _ = try add_exe_fake_pi(@tagName(config.name), b.path("src/root.zig"), b); + } else { + _ = try add_exe(@tagName(config.name), b.path("src/root.zig"), b); + } } diff --git a/fake-pi/device.zig b/fake-pi/device.zig @@ -0,0 +1,5 @@ +pub const Error = error{ + InvalidAddress, + IllegalWrite, + IllegalRead, +}; diff --git a/fake-pi/devices/gpio.zig b/fake-pi/devices/gpio.zig @@ -0,0 +1,78 @@ +const std = @import("std"); + +const device = @import("../device.zig"); + +// TODO; these constants should come from src/devices/gpio.zig +pub const START_OFFSET: usize = 0x0020_0000; +pub const END_OFFSET: usize = 0x0020_00B0; + +const GPFSEL0_OFFSET: usize = START_OFFSET + 0x0000; +const GPSET0_OFFSET: usize = START_OFFSET + 0x001C; +const GPCLR0_OFFSET: usize = START_OFFSET + 0x0028; +const GPLEV0_OFFSET: usize = START_OFFSET + 0x0034; +var base_address: u32 = 0; + +var gpfsel0 = ~@as(u32, 0); +var gpfsel1 = ~@as(u32, 0); +var gpfsel2 = ~@as(u32, 0); +var gpfsel3 = ~@as(u32, 0); +var gpfsel4 = ~@as(u32, 0); +var gpfsel5 = ~@as(u32, 0); + +var gpset0: u32 = 0; +var gpset1: u32 = 0; + +var gpclr0: u32 = 0; +var gpclr1: u32 = 0; + +var gplev0: u32 = 0; +var gplev1: u32 = 0; + +pub const Error = error{ + ReadGPFSEL, + ReadGPCLR, + WriteGPLEV, +} || device.Error; + +pub fn initialize(base_addr: u32) void { + base_address = base_addr; +} + +pub fn read_u32(address: *u32) Error!u32 { + std.log.info("GPFSEL_OFFSET = 0x{X} to 0x{X}, address = 0x{X}", .{ GPFSEL0_OFFSET, GPFSEL0_OFFSET + @sizeOf(u32) * 5, @intFromPtr(address) - base_address }); + + switch (@intFromPtr(address) - base_address) { + GPFSEL0_OFFSET + @sizeOf(u32) * 0 => return gpfsel0, + GPFSEL0_OFFSET + @sizeOf(u32) * 1 => return gpfsel1, + GPFSEL0_OFFSET + @sizeOf(u32) * 2 => return gpfsel2, + GPFSEL0_OFFSET + @sizeOf(u32) * 3 => return gpfsel3, + GPFSEL0_OFFSET + @sizeOf(u32) * 4 => return gpfsel4, + GPFSEL0_OFFSET + @sizeOf(u32) * 5 => return gpfsel5, + + GPSET0_OFFSET...(GPSET0_OFFSET + @sizeOf(u32)) => return Error.ReadGPFSEL, + GPCLR0_OFFSET...(GPCLR0_OFFSET + @sizeOf(u32)) => return Error.ReadGPCLR, + + GPLEV0_OFFSET...(GPLEV0_OFFSET + @sizeOf(u32)) => return std.crypto.random.int(u32), + else => return Error.IllegalRead, + } +} + +pub fn put_u32(address: *u32, value: u32) Error!void { + switch (@intFromPtr(address) - base_address) { + GPFSEL0_OFFSET + @sizeOf(u32) * 0 => gpfsel0 = value, + GPFSEL0_OFFSET + @sizeOf(u32) * 1 => gpfsel1 = value, + GPFSEL0_OFFSET + @sizeOf(u32) * 2 => gpfsel2 = value, + GPFSEL0_OFFSET + @sizeOf(u32) * 3 => gpfsel3 = value, + GPFSEL0_OFFSET + @sizeOf(u32) * 4 => gpfsel4 = value, + GPFSEL0_OFFSET + @sizeOf(u32) * 5 => gpfsel5 = value, + + GPSET0_OFFSET => gpset0 = value, + GPSET0_OFFSET + @sizeOf(u32) => gpset0 = value, + + GPCLR0_OFFSET => gpclr0 = value, + GPCLR0_OFFSET + @sizeOf(u32) => gpclr1 = value, + + GPLEV0_OFFSET...(GPLEV0_OFFSET + @sizeOf(u32)) => return Error.WriteGPLEV, + else => return Error.IllegalWrite, + } +} diff --git a/fake-pi/main.zig b/fake-pi/main.zig @@ -0,0 +1,9 @@ +const std = @import("std"); +const pi = @import("pi"); + +const root = @import("root.zig"); + +pub fn main() void { + root.initialize(); + pi.kmain(); +} diff --git a/fake-pi/root.zig b/fake-pi/root.zig @@ -0,0 +1,42 @@ +const std = @import("std"); + +const gpio = @import("devices/gpio.zig"); + +const BASE_ADDRESS: u32 = 0x2000_0000; + +pub fn initialize() void { + std.log.info("fake-pi initialized", .{}); + gpio.initialize(BASE_ADDRESS); +} + +export fn get_u32(address: *u32) u32 { + switch (@intFromPtr(address)) { + (BASE_ADDRESS + gpio.START_OFFSET)...(BASE_ADDRESS + gpio.END_OFFSET) => { + std.log.info("read_u32(0x{X}): gpio subsystem", .{@intFromPtr(address)}); + + return gpio.read_u32(address) catch |e| { + std.log.err("read_u32 gpio error: {t}", .{e}); + return std.crypto.random.int(u32); + }; + }, + else => { + std.log.err("read_u32: illegal read", .{}); + return std.crypto.random.int(u32); + }, + } +} + +export fn put_u32(address: *u32, value: u32) void { + switch (@intFromPtr(address)) { + (BASE_ADDRESS + gpio.START_OFFSET)...(BASE_ADDRESS + gpio.END_OFFSET) => { + std.log.info("put_u32(0x{X}, 0x{X}): gpio subsystem", .{ @intFromPtr(address), value }); + + gpio.put_u32(address, value) catch |e| { + std.log.err("put_u32 gpio error: {t}", .{e}); + }; + }, + else => { + std.log.err("put_u32: illegal write", .{}); + }, + } +} diff --git a/src/main.zig b/src/main.zig @@ -1 +1,9 @@ -pub fn main() void {} +const gpio = @import("devices/gpio.zig"); + +const BASE_ADDRESS: u32 = 0x2000_0000; + +pub fn main() !void { + gpio.initialize(BASE_ADDRESS); + + try gpio.set_output(21); +} diff --git a/src/root.zig b/src/root.zig @@ -6,8 +6,8 @@ export fn abort() noreturn { while (true) {} } -export fn main() void { - _ = fake_main(); +pub export fn kmain() void { + _ = fake_main() catch {}; } fn panic_handler(msg: []const u8, trace_addr: ?usize) noreturn { diff --git a/src/util.zig b/src/util.zig @@ -1,19 +1,21 @@ pub extern fn nop() void; +pub extern fn get_u32(address: *u32) u32; +pub extern fn put_u32(address: *u32, value: u32) void; -pub inline fn get_u32(address: *u32) u32 { - return asm volatile ("ldr %[result], [%[address]]" - : [result] "=r" (-> u32), - : [address] "r" (address), - ); -} +// pub inline fn get_u32(address: *u32) u32 { +// return asm volatile ("ldr %[result], [%[address]]" +// : [result] "=r" (-> u32), +// : [address] "r" (address), +// ); +// } -pub inline fn put_u32(address: *u32, value: u32) void { - asm volatile ("str %[value], [%[address]]" - : - : [address] "r" (address), - [value] "r" (value), - ); -} +// pub inline fn put_u32(address: *u32, value: u32) void { +// asm volatile ("str %[value], [%[address]]" +// : +// : [address] "r" (address), +// [value] "r" (value), +// ); +// } pub noinline fn delay_cycles(ticks: usize) void { var counter = ticks; diff --git a/start.s b/start.s @@ -3,7 +3,7 @@ .align 8 _start: mov sp, 0x800000 - bl main + bl kmain bl abort .global nop @@ -11,3 +11,17 @@ _start: .align 8 nop: bx lr + +.global put_32 +.type _start, function +.align 8 +put_32: + str r1,[r0] + bx lr + +.global get_32 +.type _start, function +.align 8 +get_32: + ldr r0,[r0] + bx lr