Skip to content

Commit 5989a86

Browse files
authored
Merge pull request #270 from romancardenas/master
Add `Exception` element to RISC-V builder
2 parents b01c136 + fcce3e5 commit 5989a86

File tree

8 files changed

+253
-11
lines changed

8 files changed

+253
-11
lines changed

svd-encoder/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## Unreleased
99

10+
- Adapt the `riscv` element to handle `riscv::Exception`.
1011
- Add `riscv` element for configuration parameters related to RISC-V targets.
1112
You must use the `unstable-riscv` feature to enable this exeperimental element.
1213
- Bump MSRV to 1.65.0

svd-encoder/src/riscv.rs

+26-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::{new_node, Config, Element, Encode, EncodeError, XMLNode};
2-
use crate::svd::riscv::{Hart, Priority, Riscv};
2+
use crate::svd::riscv::{Exception, Hart, Priority, Riscv};
33

44
impl Encode for Riscv {
55
type Error = EncodeError;
@@ -16,6 +16,15 @@ impl Encode for Riscv {
1616
}
1717
elem.children.push(XMLNode::Element(interrupts));
1818
}
19+
if !self.exceptions.is_empty() {
20+
let mut exceptions = Element::new("exceptions");
21+
for exception in &self.exceptions {
22+
exceptions
23+
.children
24+
.push(exception.encode_node_with_config(config)?);
25+
}
26+
elem.children.push(XMLNode::Element(exceptions));
27+
}
1928
if !self.priorities.is_empty() {
2029
let mut priorities = Element::new("priorities");
2130
for priority in &self.priorities {
@@ -37,6 +46,22 @@ impl Encode for Riscv {
3746
}
3847
}
3948

49+
impl Encode for Exception {
50+
type Error = EncodeError;
51+
52+
fn encode_with_config(&self, _config: &Config) -> Result<Element, EncodeError> {
53+
let mut children = vec![new_node("name", self.name.clone())];
54+
if let Some(desc) = &self.description {
55+
children.push(new_node("description", desc.clone()));
56+
}
57+
children.push(new_node("value", format!("{}", self.value)));
58+
59+
let mut elem = Element::new("exception");
60+
elem.children = children;
61+
Ok(elem)
62+
}
63+
}
64+
4065
impl Encode for Priority {
4166
type Error = EncodeError;
4267

svd-parser/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## Unreleased
99

10+
- Adapt the `riscv` element to handle `riscv::Exception`.
1011
- Add `riscv` element for configuration parameters related to RISC-V targets.
1112
You must use the `unstable-riscv` feature to enable this exeperimental element.
1213
- Bump MSRV to 1.65.0

svd-parser/src/riscv.rs

+31-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::*;
2-
use crate::svd::riscv::{Hart, Interrupt, Priority, Riscv};
2+
use crate::svd::riscv::{Exception, Hart, Interrupt, Priority, Riscv};
33

44
impl Parse for Riscv {
55
type Object = Self;
@@ -22,14 +22,23 @@ impl Parse for Riscv {
2222
builder = builder.core_interrupts(interrupts?);
2323
}
2424

25+
if let Some(exceptions) = tree.get_child("exceptions") {
26+
let exceptions: Result<Vec<_>, _> = exceptions
27+
.children()
28+
.filter(|t| t.is_element() && t.has_tag_name("exception"))
29+
.map(|i| Exception::parse(&i, config))
30+
.collect();
31+
builder = builder.exceptions(exceptions?);
32+
}
33+
2534
if let Some(priorities) = tree.get_child("priorities") {
2635
let priorities: Result<Vec<_>, _> = priorities
2736
.children()
2837
.filter(|t| t.is_element() && t.has_tag_name("priority"))
2938
.map(|i| Priority::parse(&i, config))
3039
.collect();
3140
builder = builder.priorities(priorities?);
32-
};
41+
}
3342

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

4352
builder
4453
.build(config.validate_level)
4554
.map_err(|e| SVDError::from(e).at(tree.id()))
4655
}
4756
}
4857

58+
impl Parse for Exception {
59+
type Object = Self;
60+
type Error = SVDErrorAt;
61+
type Config = Config;
62+
63+
fn parse(tree: &Node, config: &Config) -> Result<Self, Self::Error> {
64+
if !tree.has_tag_name("exception") {
65+
return Err(SVDError::NotExpectedTag("exception".to_string()).at(tree.id()));
66+
}
67+
68+
Exception::builder()
69+
.name(tree.get_child_text("name")?)
70+
.description(tree.get_child_text_opt("description")?)
71+
.value(tree.get_child_u32("value")?)
72+
.build(config.validate_level)
73+
.map_err(|e| SVDError::from(e).at(tree.id()))
74+
}
75+
}
76+
4977
impl Parse for Priority {
5078
type Object = Self;
5179
type Error = SVDErrorAt;

svd-rs/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## Unreleased
99

10+
- Add `riscv::Exception` for custom exception source enumerations.
1011
- Add `riscv` element for configuration parameters related to RISC-V targets.
1112
You must use the `unstable-riscv` feature to enable this exeperimental element.
1213
- Add `DataType`

svd-rs/src/riscv.rs

+38-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
pub use super::Interrupt;
22
use super::{BuildError, SvdError, ValidateLevel};
33

4+
/// Description of the custom exceptions in the device.
5+
pub mod exception;
6+
pub use exception::Exception;
7+
48
/// Description of HARTs in the device.
59
pub mod hart;
610
pub use hart::Hart;
@@ -25,6 +29,13 @@ pub struct Riscv {
2529
)]
2630
pub core_interrupts: Vec<Interrupt>,
2731

32+
/// Exception enumeration values
33+
#[cfg_attr(
34+
feature = "serde",
35+
serde(default, skip_serializing_if = "Vec::is_empty")
36+
)]
37+
pub exceptions: Vec<Exception>,
38+
2839
/// Priority level enumeration values
2940
#[cfg_attr(
3041
feature = "serde",
@@ -44,6 +55,7 @@ pub struct Riscv {
4455
#[derive(Clone, Debug, Default, PartialEq, Eq)]
4556
pub struct RiscvBuilder {
4657
core_interrupts: Option<Vec<Interrupt>>,
58+
exceptions: Option<Vec<Exception>>,
4759
priorities: Option<Vec<Priority>>,
4860
harts: Option<Vec<Hart>>,
4961
}
@@ -52,6 +64,7 @@ impl From<Riscv> for RiscvBuilder {
5264
fn from(riscv: Riscv) -> Self {
5365
Self {
5466
core_interrupts: Some(riscv.core_interrupts),
67+
exceptions: Some(riscv.exceptions),
5568
priorities: Some(riscv.priorities),
5669
harts: Some(riscv.harts),
5770
}
@@ -65,6 +78,12 @@ impl RiscvBuilder {
6578
self
6679
}
6780

81+
/// Set the exception enumeration values
82+
pub fn exceptions(mut self, exceptions: Vec<Exception>) -> Self {
83+
self.exceptions = Some(exceptions);
84+
self
85+
}
86+
6887
/// Set the priority level enumeration values
6988
pub fn priorities(mut self, priorities: Vec<Priority>) -> Self {
7089
self.priorities = Some(priorities);
@@ -80,12 +99,18 @@ impl RiscvBuilder {
8099
/// Validate and build a [`Riscv`].
81100
pub fn build(self, lvl: ValidateLevel) -> Result<Riscv, SvdError> {
82101
let riscv = Riscv {
83-
core_interrupts: self
84-
.core_interrupts
85-
.ok_or_else(|| BuildError::Uninitialized("core_interrupts".to_string()))?,
86-
priorities: self
87-
.priorities
88-
.ok_or_else(|| BuildError::Uninitialized("priorities".to_string()))?,
102+
core_interrupts: match self.core_interrupts {
103+
Some(core_interrupts) => core_interrupts,
104+
None => Vec::new(),
105+
},
106+
exceptions: match self.exceptions {
107+
Some(exceptions) => exceptions,
108+
None => Vec::new(),
109+
},
110+
priorities: match self.priorities {
111+
Some(priorities) => priorities,
112+
None => Vec::new(),
113+
},
89114
harts: self
90115
.harts
91116
.ok_or_else(|| BuildError::Uninitialized("harts".to_string()))?,
@@ -110,6 +135,9 @@ impl Riscv {
110135
if let Some(core_interrupts) = builder.core_interrupts {
111136
self.core_interrupts = core_interrupts;
112137
}
138+
if let Some(exceptions) = builder.exceptions {
139+
self.exceptions = exceptions;
140+
}
113141
if let Some(priorities) = builder.priorities {
114142
self.priorities = priorities;
115143
}
@@ -124,12 +152,16 @@ impl Riscv {
124152
/// # Errors
125153
///
126154
/// - If any of the core interrupt enumeration values are invalid
155+
/// - If any of the exception enumeration values are invalid
127156
/// - If any of the priority level enumeration values are invalid
128157
/// - If any of the HART enumeration values are invalid
129158
pub fn validate(&self, lvl: ValidateLevel) -> Result<(), SvdError> {
130159
for ci in &self.core_interrupts {
131160
ci.validate(lvl)?;
132161
}
162+
for e in &self.exceptions {
163+
e.validate(lvl)?;
164+
}
133165
for p in &self.priorities {
134166
p.validate(lvl)?;
135167
}

svd-rs/src/riscv/exception.rs

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
use crate::{BuildError, Description, Name, SvdError, ValidateLevel};
2+
3+
/// Describes a exception source in the device
4+
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
5+
#[derive(Clone, Debug, PartialEq, Eq)]
6+
#[non_exhaustive]
7+
pub struct Exception {
8+
/// The string represents the exception source name
9+
pub name: String,
10+
11+
/// The string describes the exception source
12+
#[cfg_attr(
13+
feature = "serde",
14+
serde(default, skip_serializing_if = "Option::is_none")
15+
)]
16+
pub description: Option<String>,
17+
18+
/// Represents the enumeration index value associated to the exception source
19+
pub value: u32,
20+
}
21+
22+
/// Builder for [`Exception`]
23+
#[derive(Clone, Debug, Default, PartialEq, Eq)]
24+
pub struct ExceptionBuilder {
25+
name: Option<String>,
26+
description: Option<String>,
27+
value: Option<u32>,
28+
}
29+
30+
impl From<Exception> for ExceptionBuilder {
31+
fn from(d: Exception) -> Self {
32+
Self {
33+
name: Some(d.name),
34+
description: d.description,
35+
value: Some(d.value),
36+
}
37+
}
38+
}
39+
40+
impl ExceptionBuilder {
41+
/// Set the name of the exception source
42+
pub fn name(mut self, value: String) -> Self {
43+
self.name = Some(value);
44+
self
45+
}
46+
/// Set the description of the exception source
47+
pub fn description(mut self, value: Option<String>) -> Self {
48+
self.description = value;
49+
self
50+
}
51+
/// Set the value of the exception source
52+
pub fn value(mut self, value: u32) -> Self {
53+
self.value = Some(value);
54+
self
55+
}
56+
/// Validate and build an [`Exception`].
57+
pub fn build(self, lvl: ValidateLevel) -> Result<Exception, SvdError> {
58+
let de = Exception {
59+
name: self
60+
.name
61+
.ok_or_else(|| BuildError::Uninitialized("name".to_string()))?,
62+
description: self.description,
63+
value: self
64+
.value
65+
.ok_or_else(|| BuildError::Uninitialized("value".to_string()))?,
66+
};
67+
de.validate(lvl)?;
68+
Ok(de)
69+
}
70+
}
71+
72+
impl Exception {
73+
/// Make a builder for [`Exception`]
74+
pub fn builder() -> ExceptionBuilder {
75+
ExceptionBuilder::default()
76+
}
77+
/// Modify an existing [`Exception`] based on a [builder](ExceptionBuilder).
78+
pub fn modify_from(
79+
&mut self,
80+
builder: ExceptionBuilder,
81+
lvl: ValidateLevel,
82+
) -> Result<(), SvdError> {
83+
if let Some(name) = builder.name {
84+
self.name = name;
85+
}
86+
if builder.description.is_some() {
87+
self.description = builder.description;
88+
}
89+
if let Some(value) = builder.value {
90+
self.value = value;
91+
}
92+
self.validate(lvl)
93+
}
94+
/// Validate the [`Exception`].
95+
///
96+
/// # Notes
97+
///
98+
/// This doesn't do anything.
99+
pub fn validate(&self, _lvl: ValidateLevel) -> Result<(), SvdError> {
100+
Ok(())
101+
}
102+
}
103+
104+
impl Name for Exception {
105+
fn name(&self) -> &str {
106+
&self.name
107+
}
108+
}
109+
110+
impl Description for Exception {
111+
fn description(&self) -> Option<&str> {
112+
self.description.as_deref()
113+
}
114+
}

0 commit comments

Comments
 (0)