diff --git a/src/register/mireg.rs b/src/register/mireg.rs new file mode 100644 index 00000000..e45c56dc --- /dev/null +++ b/src/register/mireg.rs @@ -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); diff --git a/src/register/miselect.rs b/src/register/miselect.rs new file mode 100644 index 00000000..5a817924 --- /dev/null +++ b/src/register/miselect.rs @@ -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); diff --git a/src/register/mod.rs b/src/register/mod.rs index 296ebeeb..3e0b0f2d 100644 --- a/src/register/mod.rs +++ b/src/register/mod.rs @@ -89,6 +89,8 @@ pub mod mscratch; pub mod mtval; // Machine-Level Interrupts +pub mod mireg; +pub mod miselect; pub mod mtopei; // Machine Configuration