From 4cc9fe68d860b9dd9bc95bb47a428e412335932a Mon Sep 17 00:00:00 2001 From: Fawaz Tirmizi Date: Tue, 11 Oct 2022 15:12:26 -0700 Subject: [PATCH] Reimplement `register::mcause` --- CHANGELOG.md | 2 + src/register/addresses.rs | 1 - src/register/mcause.rs | 115 +++++++++++++++++--------------------- src/register/mod.rs | 2 +- 4 files changed, 54 insertions(+), 66 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e19fb945..8c603949 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] - Disabled all CSR modules (`register::*`) (breaking change) - Replaced CSR macros with new ones using `tock-registers` +- Reimplemeted CSR modules using new base functions: + - `mcause` ## [v0.9.0] - 2022-10-06 diff --git a/src/register/addresses.rs b/src/register/addresses.rs index 10698062..dd841234 100644 --- a/src/register/addresses.rs +++ b/src/register/addresses.rs @@ -216,7 +216,6 @@ pub const CSR_MCOUNTINHIBIT: u16 = 0x320; pub const CSR_MSCRATCH: u16 = 0x340; #[allow(unused)] pub const CSR_MEPC: u16 = 0x341; -#[allow(unused)] pub const CSR_MCAUSE: u16 = 0x342; #[allow(unused)] pub const CSR_MTVAL: u16 = 0x343; diff --git a/src/register/mcause.rs b/src/register/mcause.rs index 705ffff4..6bcf5de0 100644 --- a/src/register/mcause.rs +++ b/src/register/mcause.rs @@ -1,34 +1,75 @@ +// Copyright (c) 2022 by Rivos Inc. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + //! mcause register -/// mcause register -#[derive(Clone, Copy, Debug)] -pub struct Mcause { - bits: usize, +ro_csr!(mcause, usize); + +register_bitfields![usize, + #[cfg(target_pointer_width = "32")] + pub mcause [ + cause OFFSET(0) NUMBITS(31) [], + is_interrupt OFFSET(31) NUMBITS(1) [], + ], + + #[cfg(target_pointer_width = "64")] + pub mcause [ + cause OFFSET(0) NUMBITS(63) [], + is_interrupt OFFSET(63) NUMBITS(1) [], + ], +]; + +/// Get the cause of the latest interrupt +#[inline] +pub fn cause() -> Trap { + let cause: usize = read_field(mcause::cause); + if is_interrupt() { + Trap::Interrupt(Interrupt::from(cause)) + } else { + Trap::Exception(Exception::from(cause)) + } +} + +/// Returns `true` if the last trap was caused by an interrupt, otherwise +/// `false`. +#[inline] +pub fn is_interrupt() -> bool { + is_set(mcause::is_interrupt) } -/// Trap Cause +/// Returns `true` if the last trap was caused by an exception, otherwise +/// `false`. +#[inline] +pub fn is_exception() -> bool { + !is_interrupt() +} + +/// Enum wrapping both potential trap causes #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum Trap { Interrupt(Interrupt), Exception(Exception), } -/// Interrupt +// TODO: Maybe add a feature that changes these enums to use the actual values, +// and the conversion functions to use core::mem::transmute(). Assuming that +// the target platform doesn't use the reserved or custom interrupt lines this +// should be safe. This would only be worthwhile if the compiler doesn't already +// optimize the conversions out. +/// Interrupt causes #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum Interrupt { - UserSoft, SupervisorSoft, MachineSoft, - UserTimer, SupervisorTimer, MachineTimer, - UserExternal, SupervisorExternal, MachineExternal, Unknown, } -/// Exception +/// Exception causes #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum Exception { InstructionMisaligned, @@ -52,13 +93,10 @@ impl Interrupt { #[inline] pub fn from(nr: usize) -> Self { match nr { - 0 => Interrupt::UserSoft, 1 => Interrupt::SupervisorSoft, 3 => Interrupt::MachineSoft, - 4 => Interrupt::UserTimer, 5 => Interrupt::SupervisorTimer, 7 => Interrupt::MachineTimer, - 8 => Interrupt::UserExternal, 9 => Interrupt::SupervisorExternal, 11 => Interrupt::MachineExternal, _ => Interrupt::Unknown, @@ -88,54 +126,3 @@ impl Exception { } } } -impl Mcause { - /// Returns the contents of the register as raw bits - #[inline] - pub fn bits(&self) -> usize { - self.bits - } - - /// Returns the code field - #[inline] - pub fn code(&self) -> usize { - match () { - #[cfg(target_pointer_width = "32")] - () => self.bits & !(1 << 31), - #[cfg(target_pointer_width = "64")] - () => self.bits & !(1 << 63), - #[cfg(target_pointer_width = "128")] - () => self.bits & !(1 << 127), - } - } - - /// Trap Cause - #[inline] - pub fn cause(&self) -> Trap { - if self.is_interrupt() { - Trap::Interrupt(Interrupt::from(self.code())) - } else { - Trap::Exception(Exception::from(self.code())) - } - } - - /// Is trap cause an interrupt. - #[inline] - pub fn is_interrupt(&self) -> bool { - match () { - #[cfg(target_pointer_width = "32")] - () => self.bits & (1 << 31) == 1 << 31, - #[cfg(target_pointer_width = "64")] - () => self.bits & (1 << 63) == 1 << 63, - #[cfg(target_pointer_width = "128")] - () => self.bits & (1 << 127) == 1 << 127, - } - } - - /// Is trap cause an exception. - #[inline] - pub fn is_exception(&self) -> bool { - !self.is_interrupt() - } -} - -read_csr_as!(Mcause, 0x342); diff --git a/src/register/mod.rs b/src/register/mod.rs index d044ae0d..e32ff923 100644 --- a/src/register/mod.rs +++ b/src/register/mod.rs @@ -73,7 +73,7 @@ mod addresses; //pub mod mtvec; // Machine Trap Handling -//pub mod mcause; +pub mod mcause; //pub mod mepc; //pub mod mip; //pub mod mscratch;