const std = @import("std"); var uart_ptr: ?[*]u8 = null; pub fn init(base_addr: usize) void { uart_ptr = @ptrFromInt(base_addr); // Set the word length to 8 bits. Offset 3 is the LCR (line control // register). // // The bottom 2 bits set the word length: // 0 = 5 bits // 1 = 6 bits // 2 = 7 bits // 3 = 8 bits const lcr: u8 = 3 << 0; uart_ptr.?[3] = lcr; // Now enable the FIFO, which is the bottom bit of the FIFO control // register (offset 2) uart_ptr.?[2] = 1 << 0; // Enable receiver buffer interrupts, which is the bottom bit of the IER // (interrupt enable register) uart_ptr.?[1] = 1 << 0; // Per the datasheet, we are to set the clock divisor to: // divisor = ceil(clock_hz/(baud_sps * 16)) // divisor = ceil(22_729_000/(115200 * 16)) = 13 const divisor: u16 = 13; const divisor_least: u8 = divisor & 0xff; const divisor_most: u8 = divisor >> 8; // To write the divisor, we have to open the divisor latch on bit 7 of the // line control register. uart_ptr.?[3] = lcr | 1 << 7; // Now we write the divisor uart_ptr.?[0] = divisor_least; uart_ptr.?[1] = divisor_most; // Now we lock it again uart_ptr.?[3] = lcr; } pub fn get() ?u8 { if (uart_ptr.?[5] & 1 != 0) { return uart_ptr.?[0]; } else { return null; } } pub fn put(c: u8) void { uart_ptr.?[0] = c; } fn drain(_: *std.Io.Writer, data: []const []const u8, splat: usize) !usize { if (uart_ptr == null) return std.Io.Writer.Error.WriteFailed; var written: u32 = 0; for (data, 0..) |item, i| { if (i == data.len - 1) { for (0..splat) |_| for (item) |c| { put(c); written += 1; }; } else { for (item) |c| { put(c); written += 1; } } } return written; } pub var writer: std.Io.Writer = .{ .buffer = &.{}, .vtable = &.{ .drain = drain, }, }; pub var terminal: std.Io.Terminal = .{ .writer = &writer, .mode = .escape_codes, };