forked from rust-embedded/riscv
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
CSR miselect/mireg: Supervisor indirect register select/alias (#18)
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
Showing
3 changed files
with
319 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters