aboutsummaryrefslogtreecommitdiff
path: root/src/riscv.zig
blob: e68b3fb7ba4f307d6f4a7cada5b7cb34cecfe866 (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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// SPDX-FileCopyrightText: 2024 Himbeer <himbeer@disroot.org>
//
// SPDX-License-Identifier: AGPL-3.0-or-later

const std = @import("std");
const interrupts = @import("interrupts.zig");
const paging = @import("paging.zig");

pub const Privilege = enum(u1) {
    user,
    supervisor,
};

pub const ExtensionState = enum(u2) {
    off,
    initial,
    clean,
    dirty,
};

pub const Xlen = enum(u2) {
    rv32 = 1,
    rv64,
    rv128,
};

pub const Sstatus = packed struct(usize) {
    user_interrupt_enable: u1,
    supervisor_interrupt_enable: u1,
    reserved0: u2,
    user_prior_interrupt_enable: u1,
    supervisor_prior_interrupt_enable: u1,
    reserved1: u2,
    previous_privilege: Privilege,
    reserved2: u4,
    floating_point_state: ExtensionState,
    user_extension_state: ExtensionState,
    reserved3: u1,
    supervisor_user_memory_access: u1,
    make_executable_readable: u1,
    reserved4: u12,
    user_xlen: Xlen,
    reserved5: u29,
    need_state_saving: u1, // Read-only.
};

pub const SbiRet = struct {
    err: isize,
    val: isize,
};

pub fn ecall(ext_id: usize, fn_id: usize, a0: usize, a1: usize, a2: usize) SbiRet {
    var ret = SbiRet{ .err = 0, .val = 0 };

    asm volatile (
        \\ ecall
        \\ sw a0, 0(%[err])
        \\ sw a1, 0(%[val])
        :
        : [err] "r" (&ret.err),
          [val] "r" (&ret.val),
          [eid] "{a7}" (ext_id),
          [fid] "{a6}" (fn_id),
          [a0] "{a0}" (a0),
          [a1] "{a1}" (a1),
          [a2] "{a2}" (a2),
    );

    return ret;
}

pub fn stackPointer() usize {
    return asm volatile (""
        : [value] "={sp}" (-> usize),
    );
}

pub const satp = Csr(paging.Satp, "satp");
pub const sstatus = Csr(Sstatus, "sstatus");
pub const sie = Csr(interrupts.Enable, "sie");
pub const sip = Csr(interrupts.Enable, "sip");
pub const sscratch = Csr(usize, "sscratch");
pub const sepc = Csr(usize, "sepc");
pub const stval = Csr(usize, "stval");
pub const time = Csr(usize, "time");

pub fn Csr(comptime T: type, csr: []const u8) type {
    if (csr.len > 8) @compileError("CSR name length exceeds 8 characters");

    return struct {
        pub inline fn read() T {
            comptime var buf = [_]u8{0} ** 23;

            const bits = asm volatile (std.fmt.bufPrint(buf[0..], "csrr %[bits], {s}", .{csr}) catch unreachable
                : [bits] "=r" (-> usize),
            );

            return @bitCast(bits);
        }

        pub inline fn write(value: T) void {
            const bits: usize = @bitCast(value);

            comptime var buf = [_]u8{0} ** 23;

            asm volatile (std.fmt.bufPrint(buf[0..], "csrw {s}, %[bits]", .{csr}) catch unreachable
                :
                : [bits] "r" (bits),
            );
        }
    };
}