From 990c2343356c331dea09475e6309a33af9885fa0 Mon Sep 17 00:00:00 2001 From: Kibels <98838009+kibels@users.noreply.github.com> Date: Sun, 18 Jan 2026 18:43:23 -0700 Subject: [PATCH] feat: use atomic immediate instructions for interrupt enable/disable --- modules/riscv32-common/src/riscv32_common.zig | 118 ++++++++++++++---- port/wch/ch32v/src/cpus/main.zig | 14 +-- 2 files changed, 103 insertions(+), 29 deletions(-) diff --git a/modules/riscv32-common/src/riscv32_common.zig b/modules/riscv32-common/src/riscv32_common.zig index 50800d448..df24bab64 100644 --- a/modules/riscv32-common/src/riscv32_common.zig +++ b/modules/riscv32-common/src/riscv32_common.zig @@ -136,9 +136,42 @@ pub const csr = struct { pub const mconfigptr = Csr(0xF15, u32); pub const mstatus = Csr(0x300, packed struct { - reserved0: u3, - mie: u1, - reserved1: u28, + pub const XS = enum(u2) { + /// Extension unit status + off = 0b00, + initial = 0b01, + clean = 0b10, + dirty = 0b11, + pub const zero = .off; + pub const mask = .dirty; + }; + pub const FS = XS; + pub const VS = XS; + pub const MPP = enum(u2) { + user = 0b00, + supervisor = 0b01, + hypervisor = 0b10, + machine = 0b11, + pub const zero = .user; + pub const mask = .machine; + }; + + reserved0: u1 = 0, + sie: u1 = 0, + reserved2: u1 = 0, + mie: u1 = 0, + reserved4: u1 = 0, + spie: u1 = 0, + ube: u1 = 0, + mpie: u1 = 0, + spp: u1 = 0, + vs: VS = .zero, + mpp: MPP = .zero, + fs: FS = .zero, + xs: XS = .zero, + mprv: u1 = 0, + reserved18: u13 = 0, + sd: u1 = 0, }); pub const misa = Csr(0x301, u32); pub const medeleg = Csr(0x302, u32); @@ -150,8 +183,8 @@ pub const csr = struct { vectored = 0b01, }; - mode: Mode, - base: u30, + mode: Mode = .direct, + base: u30 = 0, }); pub const mcounteren = Csr(0x306, u32); pub const mstatush = Csr(0x310, u32); @@ -384,6 +417,15 @@ pub const csr = struct { return struct { const Self = @This(); + /// Convert from basic types to CSR packed struct + pub inline fn from_val(val: anytype) T { + switch (@typeInfo(@TypeOf(val))) { + .comptime_int => return @bitCast(@as(u32, val)), + .int => return @bitCast(val), + else => @compileError("unsupported type"), + } + } + pub inline fn read_raw() u32 { return asm volatile ("csrr %[value], " ++ ident : [value] "=r" (-> u32), @@ -394,11 +436,18 @@ pub const csr = struct { return @bitCast(read_raw()); } - pub inline fn write_raw(value: u32) void { - asm volatile ("csrw " ++ ident ++ ", %[value]" - : - : [value] "r" (value), - ); + pub inline fn write_raw(bits: u32) void { + if (is_comptime(bits) and comptime (bits & std.math.maxInt(u5) == bits)) { + asm volatile ("csrwi " ++ ident ++ ", %[bits]" + : + : [bits] "i" (bits), + ); + } else { + asm volatile ("csrw " ++ ident ++ ", %[bits]" + : + : [bits] "r" (bits), + ); + } } pub inline fn write(value: T) void { @@ -420,25 +469,39 @@ pub const csr = struct { } pub inline fn set_raw(bits: u32) void { - asm volatile ("csrs " ++ ident ++ ", %[bits]" - : - : [bits] "r" (bits), - ); + if (is_comptime(bits) and comptime (bits & std.math.maxInt(u5) == bits)) { + asm volatile ("csrsi " ++ ident ++ ", %[bits]" + : + : [bits] "i" (bits), + ); + } else { + asm volatile ("csrs " ++ ident ++ ", %[bits]" + : + : [bits] "r" (bits), + ); + } } - pub inline fn set(fields: anytype) void { - set_raw(get_bits(fields)); + pub inline fn set(fields: T) void { + set_raw(@bitCast(fields)); } pub inline fn clear_raw(bits: u32) void { - asm volatile ("csrc " ++ ident ++ ", %[bits]" - : - : [bits] "r" (bits), - ); + if (is_comptime(bits) and comptime (bits & std.math.maxInt(u5) == bits)) { + asm volatile ("csrci " ++ ident ++ ", %[bits]" + : + : [bits] "i" (bits), + ); + } else { + asm volatile ("csrc " ++ ident ++ ", %[bits]" + : + : [bits] "r" (bits), + ); + } } - pub inline fn clear(fields: anytype) void { - clear_raw(get_bits(fields)); + pub inline fn clear(fields: T) void { + clear_raw(@bitCast(fields)); } pub inline fn read_set_raw(bits: u32) u32 { @@ -476,6 +539,17 @@ pub const csr = struct { else => @compileError("unsupported type"), }; } + + inline fn is_comptime(x: anytype) bool { + // Voodoo to determine whether x is comptime known + return comptime check: { + // For anonymous tuple types, + // if the value of a field is comptime known, + // then the corresponding field in that tuple's type is comptime. + const field = @typeInfo(@TypeOf(.{x})).@"struct".fields[0]; + break :check field.is_comptime; + }; + } }; } }; diff --git a/port/wch/ch32v/src/cpus/main.zig b/port/wch/ch32v/src/cpus/main.zig index 593ac98d2..11aa90d1e 100644 --- a/port/wch/ch32v/src/cpus/main.zig +++ b/port/wch/ch32v/src/cpus/main.zig @@ -421,7 +421,7 @@ pub const csr = struct { /// Machine Mode Status Register pub const mstatus = Csr(0x300, packed struct(u32) { - pub const Fs = enum(u2) { + pub const FS = enum(u2) { /// Floating-point unit status off = 0b00, initial = 0b01, @@ -432,11 +432,11 @@ pub const csr = struct { /// [2:0] Reserved reserved0: u3 = 0, /// [3] Machine mode interrupt enable - mie: u1, + mie: u1 = 0, /// [6:4] Reserved reserved4: u3 = 0, /// [7] Interrupt enable state before entering interrupt - mpie: u1, + mpie: u1 = 0, /// [10:8] Reserved reserved8: u3 = 0, /// [12:11] Privileged mode before entering break @@ -444,7 +444,7 @@ pub const csr = struct { /// [14:13] Floating-point unit status /// Valid only for WCH-V4F /// NOTE: reserved on other chips - fs: Fs = .off, + fs: FS = .off, /// [31:15] Reserved reserved15: u17 = 0, }); @@ -459,16 +459,16 @@ pub const csr = struct { /// Interrupt or exception entry address mode selection. /// 0: Use of the uniform entry address. /// 1: Address offset based on interrupt number *4. - mode0: u1, + mode0: u1 = 0, /// [1] Mode 1 /// Interrupt vector table identifies patterns. /// 0: Identification by jump instruction, /// limited range, support for non-jump 0 instructions. /// 1: Identify by absolute address, support /// full range, but must jump. - mode1: u1, + mode1: u1 = 0, /// [31:2] Base address of the interrupt vector table - base: u30, + base: u30 = 0, }); pub const mscratch = riscv32_common.csr.mscratch;