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,
};
|