sylveos

Toy Operating System
Log | Files | Refs

commit af078277eb1cd892c681d040f3a5fa8892a405d9
parent 7ebb5bafd8a4a433d75c6d380efdeed9108e3d14
Author: Sylvia Ivory <git@sivory.net>
Date:   Fri,  6 Feb 2026 22:15:29 -0800

Software UART

Diffstat:
Mboot/root.zig | 4+++-
Api/devices/sw-uart.zig | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mpi/root.zig | 12++++++++++--
Aprograms/sw-uart.zig | 17+++++++++++++++++
4 files changed, 100 insertions(+), 3 deletions(-)

diff --git a/boot/root.zig b/boot/root.zig @@ -30,6 +30,9 @@ export fn kmain() void { uart.write_slice("Setting up stack\n"); pi.setup_stacks(); + uart.write_slice("Setting Cycle Counter\n"); + pi.cycle_counter_init(); + uart.write_slice("Exception Vector:\n"); for (0..16) |i| { const dst: *allowzero u32 = @ptrFromInt(i * @sizeOf(*u32)); @@ -39,7 +42,6 @@ export fn kmain() void { uart.write_slice("Enabling Interrupts\n"); uart.enable_interrupts() catch {}; pi.interrupts.enable_interrupts(); - pi.cycle_counter_init(); uart.write_slice("Entering program\n"); uart.flush(); diff --git a/pi/devices/sw-uart.zig b/pi/devices/sw-uart.zig @@ -0,0 +1,70 @@ +const std = @import("std"); + +const interrupts = @import("../interrupts.zig"); +const mem = @import("../mem.zig"); + +const clock = @import("./clock.zig"); +const gpio = @import("./gpio.zig"); +const pi = @import("../root.zig"); + +pub const Error = error{ AlreadyInitialized, NotInitialized, InvalidBaud } || gpio.Error; + +var initialized = false; +var interrupts_enabled = false; + +pub var delay: u32 = undefined; +var tx: u8 = undefined; +var rx: u8 = undefined; + +pub fn initialize(baud: u32, tx_pin: u8, rx_pin: u8) Error!void { + if (initialized) return Error.AlreadyInitialized; + + try gpio.fn_sel(tx_pin, .output); + // try gpio.set_pull(tx_pin, .Up); + tx = tx_pin; + + try gpio.fn_sel(rx_pin, .input); + // try gpio.set_pull(rx_pin, .Up); + rx = rx_pin; + + try gpio.set_on(tx_pin); + + mem.barrier(.Write); + + // Cycles to delay + delay = (@divFloor(700_000_000, baud)); + if (delay == 0) return Error.InvalidBaud; + + initialized = true; +} + +pub fn write_byte(byte: u8) !void { + if (!initialized) return Error.NotInitialized; + + gpio.set_off(tx) catch {}; + mem.barrier(.Write); + + var deadline = pi.cycle_counter_read() + delay; + pi.cycle_wait_until(deadline); + + for (0..8) |n| { + const state = (byte & (@as(u8, 1) << @truncate(n))) != 0; + gpio.write(tx, state) catch {}; + mem.barrier(.Write); + + deadline += delay; + pi.cycle_wait_until(deadline); + } + + gpio.set_on(tx) catch {}; + mem.barrier(.Write); + + deadline += delay; + pi.cycle_wait_until(deadline); +} + +pub fn write_slice(bytes: []const u8) !void { + for (bytes) |b| { + try write_byte(b); + } +} diff --git a/pi/root.zig b/pi/root.zig @@ -1,3 +1,5 @@ +const std = @import("std"); + pub const Scheduler = @import("scheduler.zig"); pub const PSR = @import("./psr.zig").PSR; @@ -10,15 +12,15 @@ pub const devices = struct { pub const clock = @import("./devices/clock.zig"); pub const gpio = @import("./devices/gpio.zig"); pub const mini_uart = @import("./devices/mini-uart.zig"); + pub const sw_uart = @import("./devices/sw-uart.zig"); pub const timer = @import("./devices/timer.zig"); pub const mailbox = @import("./devices/mailbox.zig"); }; pub inline fn cycle_counter_init() void { - const in: u32 = 1; asm volatile ("MCR p15, 0, %[in], c15, c12, 0" : - : [in] "r" (in), + : [in] "r" (1), ); } @@ -28,6 +30,12 @@ pub inline fn cycle_counter_read() u32 { ); } +pub inline fn cycle_wait_until(deadline: u32) void { + while (cycle_counter_read() < deadline) { + std.mem.doNotOptimizeAway(deadline); + } +} + pub inline fn set_sp(sp: *usize) void { asm volatile ("mov sp, %[value]" : diff --git a/programs/sw-uart.zig b/programs/sw-uart.zig @@ -0,0 +1,17 @@ +const std = @import("std"); +const pi = @import("pi"); + +const mini_uart = pi.devices.mini_uart; +const sw_uart = pi.devices.sw_uart; +const clock = pi.devices.clock; + +pub fn main() !void { + try sw_uart.initialize(115200, 8, 9); + + while (true) { + mini_uart.write_slice("Hello World!\n"); + try sw_uart.write_slice("Hello World!\n"); + + clock.delay_s(1); + } +}