Skip to content

Commit

Permalink
Merge pull request #270 from romancardenas/master
Browse files Browse the repository at this point in the history
Add `Exception` element to RISC-V builder
  • Loading branch information
burrbull authored Aug 20, 2024
2 parents b01c136 + fcce3e5 commit 5989a86
Show file tree
Hide file tree
Showing 8 changed files with 253 additions and 11 deletions.
1 change: 1 addition & 0 deletions svd-encoder/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## Unreleased

- Adapt the `riscv` element to handle `riscv::Exception`.
- Add `riscv` element for configuration parameters related to RISC-V targets.
You must use the `unstable-riscv` feature to enable this exeperimental element.
- Bump MSRV to 1.65.0
Expand Down
27 changes: 26 additions & 1 deletion svd-encoder/src/riscv.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{new_node, Config, Element, Encode, EncodeError, XMLNode};
use crate::svd::riscv::{Hart, Priority, Riscv};
use crate::svd::riscv::{Exception, Hart, Priority, Riscv};

impl Encode for Riscv {
type Error = EncodeError;
Expand All @@ -16,6 +16,15 @@ impl Encode for Riscv {
}
elem.children.push(XMLNode::Element(interrupts));
}
if !self.exceptions.is_empty() {
let mut exceptions = Element::new("exceptions");
for exception in &self.exceptions {
exceptions
.children
.push(exception.encode_node_with_config(config)?);
}
elem.children.push(XMLNode::Element(exceptions));
}
if !self.priorities.is_empty() {
let mut priorities = Element::new("priorities");
for priority in &self.priorities {
Expand All @@ -37,6 +46,22 @@ impl Encode for Riscv {
}
}

impl Encode for Exception {
type Error = EncodeError;

fn encode_with_config(&self, _config: &Config) -> Result<Element, EncodeError> {
let mut children = vec![new_node("name", self.name.clone())];
if let Some(desc) = &self.description {
children.push(new_node("description", desc.clone()));
}
children.push(new_node("value", format!("{}", self.value)));

let mut elem = Element::new("exception");
elem.children = children;
Ok(elem)
}
}

impl Encode for Priority {
type Error = EncodeError;

Expand Down
1 change: 1 addition & 0 deletions svd-parser/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## Unreleased

- Adapt the `riscv` element to handle `riscv::Exception`.
- Add `riscv` element for configuration parameters related to RISC-V targets.
You must use the `unstable-riscv` feature to enable this exeperimental element.
- Bump MSRV to 1.65.0
Expand Down
34 changes: 31 additions & 3 deletions svd-parser/src/riscv.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::*;
use crate::svd::riscv::{Hart, Interrupt, Priority, Riscv};
use crate::svd::riscv::{Exception, Hart, Interrupt, Priority, Riscv};

impl Parse for Riscv {
type Object = Self;
Expand All @@ -22,14 +22,23 @@ impl Parse for Riscv {
builder = builder.core_interrupts(interrupts?);
}

if let Some(exceptions) = tree.get_child("exceptions") {
let exceptions: Result<Vec<_>, _> = exceptions
.children()
.filter(|t| t.is_element() && t.has_tag_name("exception"))
.map(|i| Exception::parse(&i, config))
.collect();
builder = builder.exceptions(exceptions?);
}

if let Some(priorities) = tree.get_child("priorities") {
let priorities: Result<Vec<_>, _> = priorities
.children()
.filter(|t| t.is_element() && t.has_tag_name("priority"))
.map(|i| Priority::parse(&i, config))
.collect();
builder = builder.priorities(priorities?);
};
}

if let Some(harts) = tree.get_child("harts") {
let harts: Result<Vec<_>, _> = harts
Expand All @@ -38,14 +47,33 @@ impl Parse for Riscv {
.map(|i| Hart::parse(&i, config))
.collect();
builder = builder.harts(harts?);
};
}

builder
.build(config.validate_level)
.map_err(|e| SVDError::from(e).at(tree.id()))
}
}

impl Parse for Exception {
type Object = Self;
type Error = SVDErrorAt;
type Config = Config;

fn parse(tree: &Node, config: &Config) -> Result<Self, Self::Error> {
if !tree.has_tag_name("exception") {
return Err(SVDError::NotExpectedTag("exception".to_string()).at(tree.id()));
}

Exception::builder()
.name(tree.get_child_text("name")?)
.description(tree.get_child_text_opt("description")?)
.value(tree.get_child_u32("value")?)
.build(config.validate_level)
.map_err(|e| SVDError::from(e).at(tree.id()))
}
}

impl Parse for Priority {
type Object = Self;
type Error = SVDErrorAt;
Expand Down
1 change: 1 addition & 0 deletions svd-rs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## Unreleased

- Add `riscv::Exception` for custom exception source enumerations.
- Add `riscv` element for configuration parameters related to RISC-V targets.
You must use the `unstable-riscv` feature to enable this exeperimental element.
- Add `DataType`
Expand Down
44 changes: 38 additions & 6 deletions svd-rs/src/riscv.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
pub use super::Interrupt;
use super::{BuildError, SvdError, ValidateLevel};

/// Description of the custom exceptions in the device.
pub mod exception;
pub use exception::Exception;

/// Description of HARTs in the device.
pub mod hart;
pub use hart::Hart;
Expand All @@ -25,6 +29,13 @@ pub struct Riscv {
)]
pub core_interrupts: Vec<Interrupt>,

/// Exception enumeration values
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Vec::is_empty")
)]
pub exceptions: Vec<Exception>,

/// Priority level enumeration values
#[cfg_attr(
feature = "serde",
Expand All @@ -44,6 +55,7 @@ pub struct Riscv {
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct RiscvBuilder {
core_interrupts: Option<Vec<Interrupt>>,
exceptions: Option<Vec<Exception>>,
priorities: Option<Vec<Priority>>,
harts: Option<Vec<Hart>>,
}
Expand All @@ -52,6 +64,7 @@ impl From<Riscv> for RiscvBuilder {
fn from(riscv: Riscv) -> Self {
Self {
core_interrupts: Some(riscv.core_interrupts),
exceptions: Some(riscv.exceptions),
priorities: Some(riscv.priorities),
harts: Some(riscv.harts),
}
Expand All @@ -65,6 +78,12 @@ impl RiscvBuilder {
self
}

/// Set the exception enumeration values
pub fn exceptions(mut self, exceptions: Vec<Exception>) -> Self {
self.exceptions = Some(exceptions);
self
}

/// Set the priority level enumeration values
pub fn priorities(mut self, priorities: Vec<Priority>) -> Self {
self.priorities = Some(priorities);
Expand All @@ -80,12 +99,18 @@ impl RiscvBuilder {
/// Validate and build a [`Riscv`].
pub fn build(self, lvl: ValidateLevel) -> Result<Riscv, SvdError> {
let riscv = Riscv {
core_interrupts: self
.core_interrupts
.ok_or_else(|| BuildError::Uninitialized("core_interrupts".to_string()))?,
priorities: self
.priorities
.ok_or_else(|| BuildError::Uninitialized("priorities".to_string()))?,
core_interrupts: match self.core_interrupts {
Some(core_interrupts) => core_interrupts,
None => Vec::new(),
},
exceptions: match self.exceptions {
Some(exceptions) => exceptions,
None => Vec::new(),
},
priorities: match self.priorities {
Some(priorities) => priorities,
None => Vec::new(),
},
harts: self
.harts
.ok_or_else(|| BuildError::Uninitialized("harts".to_string()))?,
Expand All @@ -110,6 +135,9 @@ impl Riscv {
if let Some(core_interrupts) = builder.core_interrupts {
self.core_interrupts = core_interrupts;
}
if let Some(exceptions) = builder.exceptions {
self.exceptions = exceptions;
}
if let Some(priorities) = builder.priorities {
self.priorities = priorities;
}
Expand All @@ -124,12 +152,16 @@ impl Riscv {
/// # Errors
///
/// - If any of the core interrupt enumeration values are invalid
/// - If any of the exception enumeration values are invalid
/// - If any of the priority level enumeration values are invalid
/// - If any of the HART enumeration values are invalid
pub fn validate(&self, lvl: ValidateLevel) -> Result<(), SvdError> {
for ci in &self.core_interrupts {
ci.validate(lvl)?;
}
for e in &self.exceptions {
e.validate(lvl)?;
}
for p in &self.priorities {
p.validate(lvl)?;
}
Expand Down
114 changes: 114 additions & 0 deletions svd-rs/src/riscv/exception.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
use crate::{BuildError, Description, Name, SvdError, ValidateLevel};

/// Describes a exception source in the device
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub struct Exception {
/// The string represents the exception source name
pub name: String,

/// The string describes the exception source
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub description: Option<String>,

/// Represents the enumeration index value associated to the exception source
pub value: u32,
}

/// Builder for [`Exception`]
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct ExceptionBuilder {
name: Option<String>,
description: Option<String>,
value: Option<u32>,
}

impl From<Exception> for ExceptionBuilder {
fn from(d: Exception) -> Self {
Self {
name: Some(d.name),
description: d.description,
value: Some(d.value),
}
}
}

impl ExceptionBuilder {
/// Set the name of the exception source
pub fn name(mut self, value: String) -> Self {
self.name = Some(value);
self
}
/// Set the description of the exception source
pub fn description(mut self, value: Option<String>) -> Self {
self.description = value;
self
}
/// Set the value of the exception source
pub fn value(mut self, value: u32) -> Self {
self.value = Some(value);
self
}
/// Validate and build an [`Exception`].
pub fn build(self, lvl: ValidateLevel) -> Result<Exception, SvdError> {
let de = Exception {
name: self
.name
.ok_or_else(|| BuildError::Uninitialized("name".to_string()))?,
description: self.description,
value: self
.value
.ok_or_else(|| BuildError::Uninitialized("value".to_string()))?,
};
de.validate(lvl)?;
Ok(de)
}
}

impl Exception {
/// Make a builder for [`Exception`]
pub fn builder() -> ExceptionBuilder {
ExceptionBuilder::default()
}
/// Modify an existing [`Exception`] based on a [builder](ExceptionBuilder).
pub fn modify_from(
&mut self,
builder: ExceptionBuilder,
lvl: ValidateLevel,
) -> Result<(), SvdError> {
if let Some(name) = builder.name {
self.name = name;
}
if builder.description.is_some() {
self.description = builder.description;
}
if let Some(value) = builder.value {
self.value = value;
}
self.validate(lvl)
}
/// Validate the [`Exception`].
///
/// # Notes
///
/// This doesn't do anything.
pub fn validate(&self, _lvl: ValidateLevel) -> Result<(), SvdError> {
Ok(())
}
}

impl Name for Exception {
fn name(&self) -> &str {
&self.name
}
}

impl Description for Exception {
fn description(&self) -> Option<&str> {
self.description.as_deref()
}
}
Loading

0 comments on commit 5989a86

Please sign in to comment.