Skip to content

Commit

Permalink
CSR miselect/mireg: Supervisor indirect register select/alias (#18)
Browse files Browse the repository at this point in the history
Implement external interrupt CSRs miselect/mireg:

- miselect: Machine indirect register select
- mireg: Machine indirect register alias

These CSRs are specified in the RISC-V Advanced Interrupt Architecture
(AIA) (https://github.com/riscv/riscv-aia/releases).
  • Loading branch information
ted-logan authored Feb 16, 2023
1 parent 816df77 commit 93ce7dd
Show file tree
Hide file tree
Showing 3 changed files with 319 additions and 0 deletions.
161 changes: 161 additions & 0 deletions src/register/mireg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
//! mireg register
//!
//! The `mireg` CSR is defined in "The RISC-V Advanced Interrupt
//! Architecture" Version 1.0-RC2
//!
//! Advanced Interrupt Architecture control is specified using an
//! indirect register file. In order to access to the register file,
//! software must:
//!
//! (1) Write to the `miselect` CSR with the index of the register to
//! access
//! (2) Access the `mireg` CSR, which now contains the register to
//! access
//!
//! The functions implemented in this module all write to the `miselect`
//! CSR to select the indirect register, then perform the read, write,
//! or modify operation requested on the `mireg` CSR.
use crate::register::miselect;
use bit_field::BitField;

/// External interrupt delivery enable register
#[derive(Clone, Copy, Debug)]
pub struct Eidelivery {
bits: usize,
}

impl Eidelivery {
/// Returns the contents of the register as raw bits
#[inline]
pub fn bits(&self) -> usize {
self.bits
}

/// Interrupt delivery is enabled
#[inline]
pub fn enabled(&self) -> bool {
self.bits.get_bit(0)
}

/// Interrupt delivery from a PLIC or APLIC is enabled
#[inline]
pub fn plic_enabled(&self) -> bool {
self.bits.get_bit(30)
}
}

/// Read the supervisor external interrupt delivery enable register
pub fn read_eidelivery() -> Eidelivery {
miselect::write(miselect::Register::Eidelivery);
Eidelivery {
bits: unsafe { _read() },
}
}

/// Write the supervisor external interrupt delivery enable register
pub fn write_eidelivery(value: usize) {
miselect::write(miselect::Register::Eidelivery);
unsafe {
_write(value);
}
}

/// Read the supervisor external interrupt threshold register
pub fn read_eithreshold() -> usize {
miselect::write(miselect::Register::Eithreshold);
unsafe { _read() }
}

/// Write the supervisor external interrupt threshold register
pub fn write_eithreshold(value: usize) {
miselect::write(miselect::Register::Eithreshold);
unsafe {
_write(value);
}
}

/// Determine the register offset and bit position for the external
/// interrupt pending and external interrupt enabled registers
#[cfg(riscv32)]
fn int_register_bit(interrupt: usize) -> (usize, usize) {
// On 32-bit RISC-V:
// - Each register is 32 bits wide
// - Even and odd registers both exist
let register = interrupt / 32;
let bit = interrupt % 32;
(register, bit)
}

/// Determine the register offset and bit position for the external
/// interrupt pending and external interrupt enabled registers
#[cfg(not(riscv32))]
fn int_register_bit(interrupt: usize) -> (usize, usize) {
// On 64-bit RISC-V:
// - Each register is 64 bits wide
// - Only the even-numbered registers exist
let register = (interrupt / 64) * 2;
let bit = interrupt % 64;
(register, bit)
}

/// Read the supervisor external interrupt pending bit for the given
/// external interrupt
pub fn read_eip(interrupt: usize) -> bool {
let (register, bit) = int_register_bit(interrupt);
miselect::write_usize(miselect::Register::Eip0 as usize + register);
(unsafe { _read() } >> bit) & 1 == 1
}

/// Set the supervisor external interrupt pending bit for the given
/// external interrupt
pub fn set_eip(interrupt: usize) {
let (register, bit) = int_register_bit(interrupt);
miselect::write_usize(miselect::Register::Eip0 as usize + register);
unsafe {
_set(1 << bit);
}
}

/// Clear the supervisor external interrupt pending bit for the given
/// external interrupt
pub fn clear_eip(interrupt: usize) {
let (register, bit) = int_register_bit(interrupt);
miselect::write_usize(miselect::Register::Eip0 as usize + register);
unsafe {
_clear(1 << bit);
}
}

/// Read the supervisor external interrupt enable bit for the given
/// external interrupt
pub fn read_eie(interrupt: usize) -> bool {
let (register, bit) = int_register_bit(interrupt);
miselect::write_usize(miselect::Register::Eie0 as usize + register);
(unsafe { _read() } >> bit) & 1 == 1
}

/// Set the supervisor external interrupt enable bit for the given
/// external interrupt
pub fn set_eie(interrupt: usize) {
let (register, bit) = int_register_bit(interrupt);
miselect::write_usize(miselect::Register::Eie0 as usize + register);
unsafe {
_set(1 << bit);
}
}

/// Clear the supervisor external interrupt enable bit for the given
/// external interrupt
pub fn clear_eie(interrupt: usize) {
let (register, bit) = int_register_bit(interrupt);
miselect::write_usize(miselect::Register::Eie0 as usize + register);
unsafe {
_clear(1 << bit);
}
}

read_csr!(0x351);
write_csr!(0x351);
set!(0x351);
clear!(0x351);
156 changes: 156 additions & 0 deletions src/register/miselect.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
//! miselect register
//!
//! The `miselect` CSR is defined in "The RISC-V Advanced Interrupt
//! Architecture" Version 1.0-RC2
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Register {
Eidelivery = 0x70,
Eithreshold = 0x72,
Eip0 = 0x80,
Eip1 = 0x81,
Eip2 = 0x82,
Eip3 = 0x83,
Eip4 = 0x84,
Eip5 = 0x85,
Eip6 = 0x86,
Eip7 = 0x87,
Eip8 = 0x88,
Eip9 = 0x89,
Eip10 = 0x8a,
Eip11 = 0x8b,
Eip12 = 0x8c,
Eip13 = 0x8d,
Eip14 = 0x8e,
Eip15 = 0x8f,
Eip16 = 0x90,
Eip17 = 0x91,
Eip18 = 0x92,
Eip19 = 0x93,
Eip20 = 0x94,
Eip21 = 0x95,
Eip22 = 0x96,
Eip23 = 0x97,
Eip24 = 0x98,
Eip25 = 0x99,
Eip26 = 0x9a,
Eip27 = 0x9b,
Eip28 = 0x9c,
Eip29 = 0x9d,
Eip30 = 0x9e,
Eip31 = 0x9f,
Eip32 = 0xa0,
Eip33 = 0xa1,
Eip34 = 0xa2,
Eip35 = 0xa3,
Eip36 = 0xa4,
Eip37 = 0xa5,
Eip38 = 0xa6,
Eip39 = 0xa7,
Eip40 = 0xa8,
Eip41 = 0xa9,
Eip42 = 0xaa,
Eip43 = 0xab,
Eip44 = 0xac,
Eip45 = 0xad,
Eip46 = 0xae,
Eip47 = 0xaf,
Eip48 = 0xb0,
Eip49 = 0xb1,
Eip50 = 0xb2,
Eip51 = 0xb3,
Eip52 = 0xb4,
Eip53 = 0xb5,
Eip54 = 0xb6,
Eip55 = 0xb7,
Eip56 = 0xb8,
Eip57 = 0xb9,
Eip58 = 0xba,
Eip59 = 0xbb,
Eip60 = 0xbc,
Eip61 = 0xbd,
Eip62 = 0xbe,
Eip63 = 0xbf,
Eie0 = 0xc0,
Eie1 = 0xc1,
Eie2 = 0xc2,
Eie3 = 0xc3,
Eie4 = 0xc4,
Eie5 = 0xc5,
Eie6 = 0xc6,
Eie7 = 0xc7,
Eie8 = 0xc8,
Eie9 = 0xc9,
Eie10 = 0xca,
Eie11 = 0xcb,
Eie12 = 0xcc,
Eie13 = 0xcd,
Eie14 = 0xce,
Eie15 = 0xcf,
Eie16 = 0xd0,
Eie17 = 0xd1,
Eie18 = 0xd2,
Eie19 = 0xd3,
Eie20 = 0xd4,
Eie21 = 0xd5,
Eie22 = 0xd6,
Eie23 = 0xd7,
Eie24 = 0xd8,
Eie25 = 0xd9,
Eie26 = 0xda,
Eie27 = 0xdb,
Eie28 = 0xdc,
Eie29 = 0xdd,
Eie30 = 0xde,
Eie31 = 0xdf,
Eie32 = 0xe0,
Eie33 = 0xe1,
Eie34 = 0xe2,
Eie35 = 0xe3,
Eie36 = 0xe4,
Eie37 = 0xe5,
Eie38 = 0xe6,
Eie39 = 0xe7,
Eie40 = 0xe8,
Eie41 = 0xe9,
Eie42 = 0xea,
Eie43 = 0xeb,
Eie44 = 0xec,
Eie45 = 0xed,
Eie46 = 0xee,
Eie47 = 0xef,
Eie48 = 0xf0,
Eie49 = 0xf1,
Eie50 = 0xf2,
Eie51 = 0xf3,
Eie52 = 0xf4,
Eie53 = 0xf5,
Eie54 = 0xf6,
Eie55 = 0xf7,
Eie56 = 0xf8,
Eie57 = 0xf9,
Eie58 = 0xfa,
Eie59 = 0xfb,
Eie60 = 0xfc,
Eie61 = 0xfd,
Eie62 = 0xfe,
Eie63 = 0xff,
}

#[inline]
pub fn write(register: Register) {
unsafe { _write(register as usize) };
}

#[inline]
pub fn write_usize(register: usize) {
unsafe { _write(register) };
}

#[inline]
pub fn read() -> usize {
unsafe { _read() }
}

read_csr!(0x350);
write_csr!(0x350);
2 changes: 2 additions & 0 deletions src/register/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ pub mod mscratch;
pub mod mtval;

// Machine-Level Interrupts
pub mod mireg;
pub mod miselect;
pub mod mtopei;

// Machine Configuration
Expand Down

0 comments on commit 93ce7dd

Please sign in to comment.