diff --git a/svd-encoder/CHANGELOG.md b/svd-encoder/CHANGELOG.md index bbd90e98..cb7d00ec 100644 --- a/svd-encoder/CHANGELOG.md +++ b/svd-encoder/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## Unreleased +- 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 ## [v0.14.3] - 2023-11-15 diff --git a/svd-encoder/Cargo.toml b/svd-encoder/Cargo.toml index fefa7128..cb584e58 100644 --- a/svd-encoder/Cargo.toml +++ b/svd-encoder/Cargo.toml @@ -11,6 +11,9 @@ rust-version = "1.65.0" version = "0.14.4" readme = "README.md" +[features] +unstable-riscv = ["svd-rs/unstable-riscv"] + [dependencies] convert_case = "0.6.0" svd-rs = { version = "0.14.7", path = "../svd-rs" } diff --git a/svd-encoder/src/device.rs b/svd-encoder/src/device.rs index 378e6536..8341f446 100644 --- a/svd-encoder/src/device.rs +++ b/svd-encoder/src/device.rs @@ -34,6 +34,12 @@ impl Encode for Device { elem.children.push(new_node("licenseText", v.clone())); } + #[cfg(feature = "unstable-riscv")] + if let Some(v) = &self.riscv { + elem.children + .push(XMLNode::Element(v.encode_with_config(config)?)); + } + if let Some(v) = &self.cpu { elem.children .push(XMLNode::Element(v.encode_with_config(config)?)); diff --git a/svd-encoder/src/lib.rs b/svd-encoder/src/lib.rs index 7f531426..88d750e3 100644 --- a/svd-encoder/src/lib.rs +++ b/svd-encoder/src/lib.rs @@ -103,5 +103,7 @@ mod readaction; mod register; mod registercluster; mod registerproperties; +#[cfg(feature = "unstable-riscv")] +mod riscv; mod usage; mod writeconstraint; diff --git a/svd-encoder/src/riscv.rs b/svd-encoder/src/riscv.rs new file mode 100644 index 00000000..dfb66f7a --- /dev/null +++ b/svd-encoder/src/riscv.rs @@ -0,0 +1,70 @@ +use super::{new_node, Config, Element, Encode, EncodeError, XMLNode}; +use crate::svd::riscv::{Hart, Priority, Riscv}; + +impl Encode for Riscv { + type Error = EncodeError; + + fn encode_with_config(&self, config: &Config) -> Result { + let mut elem = Element::new("riscv"); + + if !self.core_interrupts.is_empty() { + let mut interrupts = Element::new("coreInterrupts"); + for interrupt in &self.core_interrupts { + interrupts + .children + .push(interrupt.encode_node_with_config(config)?); + } + elem.children.push(XMLNode::Element(interrupts)); + } + if !self.priorities.is_empty() { + let mut priorities = Element::new("priorities"); + for priority in &self.priorities { + priorities + .children + .push(priority.encode_node_with_config(config)?); + } + elem.children.push(XMLNode::Element(priorities)); + } + if !self.harts.is_empty() { + let mut harts = Element::new("harts"); + for hart in &self.harts { + harts.children.push(hart.encode_node_with_config(config)?); + } + elem.children.push(XMLNode::Element(harts)); + } + + Ok(elem) + } +} + +impl Encode for Priority { + type Error = EncodeError; + + fn encode_with_config(&self, _config: &Config) -> Result { + 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("priority"); + elem.children = children; + Ok(elem) + } +} + +impl Encode for Hart { + type Error = EncodeError; + + fn encode_with_config(&self, _config: &Config) -> Result { + 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("hart"); + elem.children = children; + Ok(elem) + } +} diff --git a/svd-parser/CHANGELOG.md b/svd-parser/CHANGELOG.md index 219cad51..a22d267c 100644 --- a/svd-parser/CHANGELOG.md +++ b/svd-parser/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## Unreleased +- 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 ## [v0.14.5] - 2024-01-03 diff --git a/svd-parser/Cargo.toml b/svd-parser/Cargo.toml index b500cdd4..1b45a4ae 100644 --- a/svd-parser/Cargo.toml +++ b/svd-parser/Cargo.toml @@ -17,6 +17,7 @@ readme = "README.md" [features] derive-from = ["svd-rs/derive-from"] expand = ["derive-from"] +unstable-riscv = ["svd-rs/unstable-riscv"] [dependencies] svd-rs = { version = "0.14.7", path = "../svd-rs" } diff --git a/svd-parser/src/device.rs b/svd-parser/src/device.rs index 32ec8d07..701055fc 100644 --- a/svd-parser/src/device.rs +++ b/svd-parser/src/device.rs @@ -1,4 +1,6 @@ use super::*; +#[cfg(feature = "unstable-riscv")] +use crate::svd::riscv::Riscv; use crate::svd::{cpu::Cpu, peripheral::Peripheral, registerproperties::RegisterProperties}; /// Parses a SVD file @@ -31,6 +33,10 @@ impl Parse for Device { .collect(); ps? }); + #[cfg(feature = "unstable-riscv")] + if let Some(riscv) = optional::("riscv", tree, config)? { + device = device.riscv(riscv); + } if let Some(version) = tree.get_child_text_opt("version")? { device = device.version(version) } diff --git a/svd-parser/src/lib.rs b/svd-parser/src/lib.rs index b3d22c6d..e3718ed6 100644 --- a/svd-parser/src/lib.rs +++ b/svd-parser/src/lib.rs @@ -211,6 +211,8 @@ mod readaction; mod register; mod registercluster; mod registerproperties; +#[cfg(feature = "unstable-riscv")] +mod riscv; mod usage; mod writeconstraint; diff --git a/svd-parser/src/riscv.rs b/svd-parser/src/riscv.rs new file mode 100644 index 00000000..fe744e4a --- /dev/null +++ b/svd-parser/src/riscv.rs @@ -0,0 +1,85 @@ +use super::*; +use crate::svd::riscv::{Hart, Interrupt, Priority, Riscv}; + +impl Parse for Riscv { + type Object = Self; + type Error = SVDErrorAt; + type Config = Config; + + fn parse(tree: &Node, config: &Config) -> Result { + if !tree.has_tag_name("riscv") { + return Err(SVDError::NotExpectedTag("riscv".to_string()).at(tree.id())); + } + + let mut builder = Riscv::builder(); + + if let Some(interrupts) = tree.get_child("coreInterrupts") { + let interrupts: Result, _> = interrupts + .children() + .filter(|t| t.is_element() && t.has_tag_name("interrupt")) + .map(|i| Interrupt::parse(&i, config)) + .collect(); + builder = builder.core_interrupts(interrupts?); + } + + if let Some(priorities) = tree.get_child("priorities") { + let priorities: Result, _> = 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, _> = harts + .children() + .filter(|t| t.is_element() && t.has_tag_name("hart")) + .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 Priority { + type Object = Self; + type Error = SVDErrorAt; + type Config = Config; + + fn parse(tree: &Node, config: &Config) -> Result { + if !tree.has_tag_name("priority") { + return Err(SVDError::NotExpectedTag("priority".to_string()).at(tree.id())); + } + + Priority::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 Hart { + type Object = Self; + type Error = SVDErrorAt; + type Config = Config; + + fn parse(tree: &Node, config: &Config) -> Result { + if !tree.has_tag_name("hart") { + return Err(SVDError::NotExpectedTag("hart".to_string()).at(tree.id())); + } + + Hart::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())) + } +} diff --git a/svd-rs/CHANGELOG.md b/svd-rs/CHANGELOG.md index fc66bfc0..4e61645f 100644 --- a/svd-rs/CHANGELOG.md +++ b/svd-rs/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## Unreleased +- 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` ## [v0.14.8] - 2024-02-13 diff --git a/svd-rs/Cargo.toml b/svd-rs/Cargo.toml index 29163403..3f8488b2 100644 --- a/svd-rs/Cargo.toml +++ b/svd-rs/Cargo.toml @@ -15,6 +15,7 @@ readme = "README.md" [features] derive-from = [] +unstable-riscv = [] [dependencies] thiserror = "1.0.31" diff --git a/svd-rs/src/device.rs b/svd-rs/src/device.rs index aa9d4439..d7f9b0a8 100644 --- a/svd-rs/src/device.rs +++ b/svd-rs/src/device.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "unstable-riscv")] +use super::Riscv; use super::{ BuildError, Cpu, Description, EmptyToNone, Name, Peripheral, RegisterProperties, SvdError, ValidateLevel, @@ -105,6 +107,14 @@ pub struct Device { /// Specify the compliant CMSIS-SVD schema version #[cfg_attr(feature = "serde", serde(skip, default = "default_schema_version"))] pub schema_version: String, + + /// Describe the processor included in the device + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] + #[cfg(feature = "unstable-riscv")] + pub riscv: Option, } fn default_xmlns_xs() -> String { @@ -130,6 +140,8 @@ pub struct DeviceBuilder { version: Option, description: Option, license_text: Option, + #[cfg(feature = "unstable-riscv")] + riscv: Option, cpu: Option, header_system_filename: Option, header_definitions_prefix: Option, @@ -152,6 +164,8 @@ impl From for DeviceBuilder { version: Some(d.version), description: Some(d.description), license_text: d.license_text, + #[cfg(feature = "unstable-riscv")] + riscv: d.riscv, cpu: d.cpu, header_system_filename: d.header_system_filename, header_definitions_prefix: d.header_definitions_prefix, @@ -202,6 +216,12 @@ impl DeviceBuilder { self.license_text = value; self } + /// Set the riscv of the device. + #[cfg(feature = "unstable-riscv")] + pub fn riscv(mut self, value: Riscv) -> Self { + self.riscv = Some(value); + self + } /// Set the cpu of the device. pub fn cpu(mut self, value: Option) -> Self { self.cpu = value; @@ -283,6 +303,8 @@ impl DeviceBuilder { }) .ok_or_else(|| BuildError::Uninitialized("description".to_string()))?, license_text: self.license_text, + #[cfg(feature = "unstable-riscv")] + riscv: self.riscv, cpu: self.cpu, header_system_filename: self.header_system_filename, header_definitions_prefix: self.header_definitions_prefix, @@ -341,6 +363,10 @@ impl Device { if builder.license_text.is_some() { self.license_text = builder.license_text.empty_to_none(); } + #[cfg(feature = "unstable-riscv")] + if builder.riscv.is_some() { + self.riscv = builder.riscv; + } if builder.cpu.is_some() { self.cpu = builder.cpu; } diff --git a/svd-rs/src/lib.rs b/svd-rs/src/lib.rs index fe895426..ceaf9e54 100644 --- a/svd-rs/src/lib.rs +++ b/svd-rs/src/lib.rs @@ -94,6 +94,12 @@ pub use self::protection::Protection; pub mod datatype; pub use self::datatype::DataType; +/// Custom objects for the RISC-V ecosystem +#[cfg(feature = "unstable-riscv")] +pub mod riscv; +#[cfg(feature = "unstable-riscv")] +pub use self::riscv::Riscv; + /// Level of validation #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum ValidateLevel { diff --git a/svd-rs/src/riscv.rs b/svd-rs/src/riscv.rs new file mode 100644 index 00000000..7398ec9e --- /dev/null +++ b/svd-rs/src/riscv.rs @@ -0,0 +1,141 @@ +pub use super::Interrupt; +use super::{BuildError, SvdError, ValidateLevel}; + +/// Description of HARTs in the device. +pub mod hart; +pub use hart::Hart; + +/// Description of interrupt priority levels in the device. +pub mod priority; +pub use priority::Priority; + +/// RISC-V specific descriptions. +#[cfg_attr( + feature = "serde", + derive(serde::Deserialize, serde::Serialize), + serde(rename_all = "camelCase") +)] +#[derive(Clone, Debug, PartialEq, Eq)] +#[non_exhaustive] +pub struct Riscv { + /// Core interrupt enumeration values + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] + pub core_interrupts: Vec, + + /// Priority level enumeration values + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] + pub priorities: Vec, + + /// HART enumeration values + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] + pub harts: Vec, +} + +/// Builder for [`Riscv`] +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct RiscvBuilder { + core_interrupts: Option>, + priorities: Option>, + harts: Option>, +} + +impl From for RiscvBuilder { + fn from(riscv: Riscv) -> Self { + Self { + core_interrupts: Some(riscv.core_interrupts), + priorities: Some(riscv.priorities), + harts: Some(riscv.harts), + } + } +} + +impl RiscvBuilder { + /// Set the core interrupt enumeration values + pub fn core_interrupts(mut self, core_interrupts: Vec) -> Self { + self.core_interrupts = Some(core_interrupts); + self + } + + /// Set the priority level enumeration values + pub fn priorities(mut self, priorities: Vec) -> Self { + self.priorities = Some(priorities); + self + } + + /// Set the HART enumeration values + pub fn harts(mut self, harts: Vec) -> Self { + self.harts = Some(harts); + self + } + + /// Validate and build a [`Riscv`]. + pub fn build(self, lvl: ValidateLevel) -> Result { + 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()))?, + harts: self + .harts + .ok_or_else(|| BuildError::Uninitialized("harts".to_string()))?, + }; + riscv.validate(lvl)?; + Ok(riscv) + } +} + +impl Riscv { + /// Make a builder for [`Riscv`] + pub fn builder() -> RiscvBuilder { + RiscvBuilder::default() + } + + /// Modify an existing [`Riscv`] based on a [builder](RiscvBuilder). + pub fn modify_from( + &mut self, + builder: RiscvBuilder, + lvl: ValidateLevel, + ) -> Result<(), SvdError> { + if let Some(core_interrupts) = builder.core_interrupts { + self.core_interrupts = core_interrupts; + } + if let Some(priorities) = builder.priorities { + self.priorities = priorities; + } + if let Some(harts) = builder.harts { + self.harts = harts; + } + self.validate(lvl) + } + + /// Validate the [`Riscv`]. + /// + /// # Errors + /// + /// - If any of the core interrupt 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 p in &self.priorities { + p.validate(lvl)?; + } + for h in &self.harts { + h.validate(lvl)?; + } + Ok(()) + } +} diff --git a/svd-rs/src/riscv/hart.rs b/svd-rs/src/riscv/hart.rs new file mode 100644 index 00000000..27e7ad09 --- /dev/null +++ b/svd-rs/src/riscv/hart.rs @@ -0,0 +1,114 @@ +use crate::{BuildError, Description, Name, SvdError, ValidateLevel}; + +/// Describes a HART ID in the device +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +#[derive(Clone, Debug, PartialEq, Eq)] +#[non_exhaustive] +pub struct Hart { + /// The string represents the HART ID + pub name: String, + + /// The string describes the HART ID + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] + pub description: Option, + + /// Represents the enumeration index value associated to the HART ID + pub value: u32, +} + +/// Builder for [`Hart`] +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct HartBuilder { + name: Option, + description: Option, + value: Option, +} + +impl From for HartBuilder { + fn from(d: Hart) -> Self { + Self { + name: Some(d.name), + description: d.description, + value: Some(d.value), + } + } +} + +impl HartBuilder { + /// Set the name of the HART + pub fn name(mut self, value: String) -> Self { + self.name = Some(value); + self + } + /// Set the description of the HART + pub fn description(mut self, value: Option) -> Self { + self.description = value; + self + } + /// Set the value of the HART + pub fn value(mut self, value: u32) -> Self { + self.value = Some(value); + self + } + /// Validate and build a [`Hart`]. + pub fn build(self, lvl: ValidateLevel) -> Result { + let de = Hart { + 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 Hart { + /// Make a builder for [`Hart`] + pub fn builder() -> HartBuilder { + HartBuilder::default() + } + /// Modify an existing [`Hart`] based on a [builder](HartBuilder). + pub fn modify_from( + &mut self, + builder: HartBuilder, + 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 [`Hart`]. + /// + /// # Notes + /// + /// This doesn't do anything. + pub fn validate(&self, _lvl: ValidateLevel) -> Result<(), SvdError> { + Ok(()) + } +} + +impl Name for Hart { + fn name(&self) -> &str { + &self.name + } +} + +impl Description for Hart { + fn description(&self) -> Option<&str> { + self.description.as_deref() + } +} diff --git a/svd-rs/src/riscv/priority.rs b/svd-rs/src/riscv/priority.rs new file mode 100644 index 00000000..80ab85ac --- /dev/null +++ b/svd-rs/src/riscv/priority.rs @@ -0,0 +1,114 @@ +use crate::{BuildError, Description, Name, SvdError, ValidateLevel}; + +/// Describes a priority level in the device +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +#[derive(Clone, Debug, PartialEq, Eq)] +#[non_exhaustive] +pub struct Priority { + /// The string represents the priority level + pub name: String, + + /// The string describes the priority level + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] + pub description: Option, + + /// Represents the enumeration index value associated to the priority level + pub value: u32, +} + +/// Builder for [`Priority`] +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct PriorityBuilder { + name: Option, + description: Option, + value: Option, +} + +impl From for PriorityBuilder { + fn from(d: Priority) -> Self { + Self { + name: Some(d.name), + description: d.description, + value: Some(d.value), + } + } +} + +impl PriorityBuilder { + /// Set the name of the priority level + pub fn name(mut self, value: String) -> Self { + self.name = Some(value); + self + } + /// Set the description of the priority level + pub fn description(mut self, value: Option) -> Self { + self.description = value; + self + } + /// Set the value of the priority level + pub fn value(mut self, value: u32) -> Self { + self.value = Some(value); + self + } + /// Validate and build a [`Priority`]. + pub fn build(self, lvl: ValidateLevel) -> Result { + let de = Priority { + 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 Priority { + /// Make a builder for [`Priority`] + pub fn builder() -> PriorityBuilder { + PriorityBuilder::default() + } + /// Modify an existing [`Priority`] based on a [builder](PriorityBuilder). + pub fn modify_from( + &mut self, + builder: PriorityBuilder, + 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 [`Priority`]. + /// + /// # Notes + /// + /// This doesn't do anything. + pub fn validate(&self, _lvl: ValidateLevel) -> Result<(), SvdError> { + Ok(()) + } +} + +impl Name for Priority { + fn name(&self) -> &str { + &self.name + } +} + +impl Description for Priority { + fn description(&self) -> Option<&str> { + self.description.as_deref() + } +} diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 9ceb2a9a..8556f80a 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -7,6 +7,9 @@ edition = "2021" version = "0.12.0" publish = false +[features] +unstable-riscv = ["svd-rs/unstable-riscv", "svd-parser/unstable-riscv", "svd-encoder/unstable-riscv"] + [dependencies] svd-rs = { path = "../svd-rs"} svd-parser = { path = "../svd-parser"} diff --git a/tests/src/lib.rs b/tests/src/lib.rs index 68f4a9dd..7e0ed121 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -61,3 +61,6 @@ mod register; //mod registerproperties; mod usage; mod writeconstraint; + +#[cfg(feature = "unstable-riscv")] +mod riscv; diff --git a/tests/src/riscv.rs b/tests/src/riscv.rs new file mode 100644 index 00000000..e4b26d5a --- /dev/null +++ b/tests/src/riscv.rs @@ -0,0 +1,238 @@ +use super::run_test; +use crate::svd::{ + riscv::{Hart, Priority, Riscv}, + Interrupt, ValidateLevel, +}; + +#[test] +fn decode_encode() { + let interrupts = vec![ + Interrupt::builder() + .name("MachineSoft".to_string()) + .description(Some("Machine Software Interrupt".to_string())) + .value(3) + .build(ValidateLevel::Strict) + .unwrap(), + Interrupt::builder() + .name("MachineTimer".to_string()) + .description(Some("Machine Timer Interrupt".to_string())) + .value(7) + .build(ValidateLevel::Strict) + .unwrap(), + Interrupt::builder() + .name("MachineExternal".to_string()) + .description(Some("Machine External Interrupt".to_string())) + .value(11) + .build(ValidateLevel::Strict) + .unwrap(), + ]; + + let priorities = vec![ + Priority::builder() + .name("P0".to_string()) + .description(Some("Priority level 0".to_string())) + .value(0) + .build(ValidateLevel::Strict) + .unwrap(), + Priority::builder() + .name("P1".to_string()) + .description(Some("Priority level 1".to_string())) + .value(1) + .build(ValidateLevel::Strict) + .unwrap(), + Priority::builder() + .name("P2".to_string()) + .description(Some("Priority level 2".to_string())) + .value(2) + .build(ValidateLevel::Strict) + .unwrap(), + Priority::builder() + .name("P3".to_string()) + .description(Some("Priority level 3".to_string())) + .value(3) + .build(ValidateLevel::Strict) + .unwrap(), + Priority::builder() + .name("P4".to_string()) + .description(Some("Priority level 4".to_string())) + .value(4) + .build(ValidateLevel::Strict) + .unwrap(), + Priority::builder() + .name("P5".to_string()) + .description(Some("Priority level 5".to_string())) + .value(5) + .build(ValidateLevel::Strict) + .unwrap(), + Priority::builder() + .name("P6".to_string()) + .description(Some("Priority level 6".to_string())) + .value(6) + .build(ValidateLevel::Strict) + .unwrap(), + Priority::builder() + .name("P7".to_string()) + .description(Some("Priority level 7".to_string())) + .value(7) + .build(ValidateLevel::Strict) + .unwrap(), + ]; + + let harts = vec![Hart::builder() + .name("H0".to_string()) + .description(Some("Hart 0".to_string())) + .value(0) + .build(ValidateLevel::Strict) + .unwrap()]; + + let tests = vec![( + Riscv::builder() + .core_interrupts(interrupts) + .priorities(priorities) + .harts(harts) + .build(ValidateLevel::Strict) + .unwrap(), + " + + + + MachineSoft + Machine Software Interrupt + 3 + + + MachineTimer + Machine Timer Interrupt + 7 + + + MachineExternal + Machine External Interrupt + 11 + + + + + P0 + Priority level 0 + 0 + + + P1 + Priority level 1 + 1 + + + P2 + Priority level 2 + 2 + + + P3 + Priority level 3 + 3 + + + P4 + Priority level 4 + 4 + + + P5 + Priority level 5 + 5 + + + P6 + Priority level 6 + 6 + + + P7 + Priority level 7 + 7 + + + + + H0 + Hart 0 + 0 + + + + ", + " + + + + MachineSoft + Machine Software Interrupt + 3 + + + MachineTimer + Machine Timer Interrupt + 7 + + + MachineExternal + Machine External Interrupt + 11 + + + + + P0 + Priority level 0 + 0 + + + P1 + Priority level 1 + 1 + + + P2 + Priority level 2 + 2 + + + P3 + Priority level 3 + 3 + + + P4 + Priority level 4 + 4 + + + P5 + Priority level 5 + 5 + + + P6 + Priority level 6 + 6 + + + P7 + Priority level 7 + 7 + + + + + H0 + Hart 0 + 0 + + + + ", + )]; + + run_test::(&tests[..], None, None); +}