summaryrefslogtreecommitdiff
path: root/src/uart.zig
blob: 661084c914223f111d613107c5c31d7c7627f082 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
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,
};