svd_rs/
cpu.rs

1use super::{BuildError, Endian, SvdError, ValidateLevel};
2/// CPU describes the processor included in the microcontroller device.
3#[cfg_attr(
4    feature = "serde",
5    derive(serde::Deserialize, serde::Serialize),
6    serde(rename_all = "camelCase")
7)]
8#[derive(Clone, Debug, PartialEq, Eq)]
9#[non_exhaustive]
10pub struct Cpu {
11    /// Processor architecture
12    pub name: String,
13
14    /// Define the HW revision of the processor
15    pub revision: String,
16
17    /// Define the endianness of the processor
18    pub endian: Endian,
19
20    /// Indicate whether the processor is equipped with a memory protection unit (MPU)
21    pub mpu_present: bool,
22
23    /// Indicate whether the processor is equipped with a hardware floating point unit (FPU)
24    pub fpu_present: bool,
25
26    /// Indicate whether the processor is equipped with a double precision floating point unit.
27    /// This element is valid only when `fpu_present` is set to `true`
28    #[cfg_attr(
29        feature = "serde",
30        serde(default, skip_serializing_if = "Option::is_none", rename = "fpuDP")
31    )]
32    pub fpu_double_precision: Option<bool>,
33
34    /// Indicates whether the processor implements the optional SIMD DSP extensions (DSP)
35    #[cfg_attr(
36        feature = "serde",
37        serde(default, skip_serializing_if = "Option::is_none")
38    )]
39    pub dsp_present: Option<bool>,
40
41    /// Indicate whether the processor has an instruction cache
42    #[cfg_attr(
43        feature = "serde",
44        serde(default, skip_serializing_if = "Option::is_none")
45    )]
46    pub icache_present: Option<bool>,
47
48    /// Indicate whether the processor has a data cache
49    #[cfg_attr(
50        feature = "serde",
51        serde(default, skip_serializing_if = "Option::is_none")
52    )]
53    pub dcache_present: Option<bool>,
54
55    /// Indicate whether the processor has an instruction tightly coupled memory
56    #[cfg_attr(
57        feature = "serde",
58        serde(default, skip_serializing_if = "Option::is_none")
59    )]
60    pub itcm_present: Option<bool>,
61
62    /// Indicate whether the processor has a data tightly coupled memory
63    #[cfg_attr(
64        feature = "serde",
65        serde(default, skip_serializing_if = "Option::is_none")
66    )]
67    pub dtcm_present: Option<bool>,
68
69    /// Indicate whether the Vector Table Offset Register (VTOR) is implemented.
70    /// If not specified, then VTOR is assumed to be present
71    #[cfg_attr(
72        feature = "serde",
73        serde(default, skip_serializing_if = "Option::is_none")
74    )]
75    pub vtor_present: Option<bool>,
76
77    /// Define the number of bits available in the Nested Vectored Interrupt Controller (NVIC) for configuring priority
78    #[cfg_attr(feature = "serde", serde(rename = "nvicPrioBits"))]
79    pub nvic_priority_bits: u32,
80
81    /// Indicate whether the processor implements a vendor-specific System Tick Timer
82    #[cfg_attr(feature = "serde", serde(rename = "vendorSystickConfig"))]
83    pub has_vendor_systick: bool,
84
85    /// Add 1 to the highest interrupt number and specify this number in here
86    #[cfg_attr(
87        feature = "serde",
88        serde(default, skip_serializing_if = "Option::is_none")
89    )]
90    pub device_num_interrupts: Option<u32>,
91
92    /// Indicate the amount of regions in the Security Attribution Unit (SAU)
93    #[cfg_attr(
94        feature = "serde",
95        serde(default, skip_serializing_if = "Option::is_none")
96    )]
97    pub sau_num_regions: Option<u32>,
98    // sauRegionsConfig
99}
100
101/// Builder for [`Cpu`]
102#[derive(Clone, Debug, Default, PartialEq, Eq)]
103pub struct CpuBuilder {
104    name: Option<String>,
105    revision: Option<String>,
106    endian: Option<Endian>,
107    mpu_present: Option<bool>,
108    fpu_present: Option<bool>,
109    fpu_double_precision: Option<bool>,
110    dsp_present: Option<bool>,
111    icache_present: Option<bool>,
112    dcache_present: Option<bool>,
113    itcm_present: Option<bool>,
114    dtcm_present: Option<bool>,
115    vtor_present: Option<bool>,
116    nvic_priority_bits: Option<u32>,
117    has_vendor_systick: Option<bool>,
118    device_num_interrupts: Option<u32>,
119    sau_num_regions: Option<u32>,
120}
121
122impl From<Cpu> for CpuBuilder {
123    fn from(c: Cpu) -> Self {
124        Self {
125            name: Some(c.name),
126            revision: Some(c.revision),
127            endian: Some(c.endian),
128            mpu_present: Some(c.mpu_present),
129            fpu_present: Some(c.fpu_present),
130            fpu_double_precision: c.fpu_double_precision,
131            dsp_present: c.dsp_present,
132            icache_present: c.icache_present,
133            dcache_present: c.dcache_present,
134            itcm_present: c.itcm_present,
135            dtcm_present: c.dtcm_present,
136            vtor_present: c.vtor_present,
137            nvic_priority_bits: Some(c.nvic_priority_bits),
138            has_vendor_systick: Some(c.has_vendor_systick),
139            device_num_interrupts: c.device_num_interrupts,
140            sau_num_regions: c.sau_num_regions,
141        }
142    }
143}
144
145impl CpuBuilder {
146    /// Set the name of the cpu.
147    pub fn name(mut self, value: String) -> Self {
148        self.name = Some(value);
149        self
150    }
151    /// Set the revision of the cpu.
152    pub fn revision(mut self, value: String) -> Self {
153        self.revision = Some(value);
154        self
155    }
156    /// Set the endian of the cpu.
157    pub fn endian(mut self, value: Endian) -> Self {
158        self.endian = Some(value);
159        self
160    }
161    /// Set the mpu_present of the cpu.
162    pub fn mpu_present(mut self, value: bool) -> Self {
163        self.mpu_present = Some(value);
164        self
165    }
166    /// Set the fpu_present of the cpu.
167    pub fn fpu_present(mut self, value: bool) -> Self {
168        self.fpu_present = Some(value);
169        self
170    }
171    /// Set the fpu_double_precision of the cpu.
172    pub fn fpu_double_precision(mut self, value: Option<bool>) -> Self {
173        self.fpu_double_precision = value;
174        self
175    }
176    /// Set the dsp_present of the cpu.
177    pub fn dsp_present(mut self, value: Option<bool>) -> Self {
178        self.dsp_present = value;
179        self
180    }
181    /// Set the icache_present of the cpu.
182    pub fn icache_present(mut self, value: Option<bool>) -> Self {
183        self.icache_present = value;
184        self
185    }
186    /// Set the dcache_present of the cpu.
187    pub fn dcache_present(mut self, value: Option<bool>) -> Self {
188        self.dcache_present = value;
189        self
190    }
191    /// Set the itcm_present of the cpu.
192    pub fn itcm_present(mut self, value: Option<bool>) -> Self {
193        self.itcm_present = value;
194        self
195    }
196    /// Set the dtcm_present of the cpu.
197    pub fn dtcm_present(mut self, value: Option<bool>) -> Self {
198        self.dtcm_present = value;
199        self
200    }
201    /// Set the vtor_present of the cpu.
202    pub fn vtor_present(mut self, value: Option<bool>) -> Self {
203        self.vtor_present = value;
204        self
205    }
206    /// Set the nvic_priority_bits of the cpu.
207    pub fn nvic_priority_bits(mut self, value: u32) -> Self {
208        self.nvic_priority_bits = Some(value);
209        self
210    }
211    /// Set the has_vendor_systick of the cpu.
212    pub fn has_vendor_systick(mut self, value: bool) -> Self {
213        self.has_vendor_systick = Some(value);
214        self
215    }
216    /// Set the device_num_interrupts of the cpu.
217    pub fn device_num_interrupts(mut self, value: Option<u32>) -> Self {
218        self.device_num_interrupts = value;
219        self
220    }
221    /// Set the sau_num_regions of the cpu.
222    pub fn sau_num_regions(mut self, value: Option<u32>) -> Self {
223        self.sau_num_regions = value;
224        self
225    }
226    /// Validate and build a [`Cpu`].
227    pub fn build(self, lvl: ValidateLevel) -> Result<Cpu, SvdError> {
228        let cpu = Cpu {
229            name: self
230                .name
231                .ok_or_else(|| BuildError::Uninitialized("name".to_string()))?,
232            revision: self
233                .revision
234                .ok_or_else(|| BuildError::Uninitialized("revision".to_string()))?,
235            endian: self
236                .endian
237                .ok_or_else(|| BuildError::Uninitialized("endian".to_string()))?,
238            mpu_present: self
239                .mpu_present
240                .ok_or_else(|| BuildError::Uninitialized("mpu_present".to_string()))?,
241            fpu_present: self
242                .fpu_present
243                .ok_or_else(|| BuildError::Uninitialized("fpu_present".to_string()))?,
244            fpu_double_precision: self.fpu_double_precision,
245            dsp_present: self.dsp_present,
246            icache_present: self.icache_present,
247            dcache_present: self.dcache_present,
248            itcm_present: self.itcm_present,
249            dtcm_present: self.dtcm_present,
250            vtor_present: self.vtor_present,
251            nvic_priority_bits: self
252                .nvic_priority_bits
253                .ok_or_else(|| BuildError::Uninitialized("nvic_priority_bits".to_string()))?,
254            has_vendor_systick: self
255                .has_vendor_systick
256                .ok_or_else(|| BuildError::Uninitialized("has_vendor_systick".to_string()))?,
257            device_num_interrupts: self.device_num_interrupts,
258            sau_num_regions: self.sau_num_regions,
259        };
260        cpu.validate(lvl)?;
261        Ok(cpu)
262    }
263}
264
265impl Cpu {
266    /// Make a builder for [`Cpu`]
267    pub fn builder() -> CpuBuilder {
268        CpuBuilder::default()
269    }
270    /// Modify an existing [`Cpu`] based on a [builder](CpuBuilder).
271    pub fn modify_from(&mut self, builder: CpuBuilder, lvl: ValidateLevel) -> Result<(), SvdError> {
272        if let Some(name) = builder.name {
273            self.name = name;
274        }
275        if let Some(revision) = builder.revision {
276            self.revision = revision;
277        }
278        if let Some(endian) = builder.endian {
279            self.endian = endian;
280        }
281        if let Some(mpu_present) = builder.mpu_present {
282            self.mpu_present = mpu_present;
283        }
284        if let Some(fpu_present) = builder.fpu_present {
285            self.fpu_present = fpu_present;
286        }
287        if builder.fpu_double_precision.is_some() {
288            self.fpu_double_precision = builder.fpu_double_precision;
289        }
290        if builder.dsp_present.is_some() {
291            self.dsp_present = builder.dsp_present;
292        }
293        if builder.icache_present.is_some() {
294            self.icache_present = builder.icache_present;
295        }
296        if builder.dcache_present.is_some() {
297            self.dcache_present = builder.dcache_present;
298        }
299        if builder.itcm_present.is_some() {
300            self.itcm_present = builder.itcm_present;
301        }
302        if builder.dtcm_present.is_some() {
303            self.dtcm_present = builder.dtcm_present;
304        }
305        if builder.vtor_present.is_some() {
306            self.vtor_present = builder.vtor_present;
307        }
308        if let Some(nvic_priority_bits) = builder.nvic_priority_bits {
309            self.nvic_priority_bits = nvic_priority_bits;
310        }
311        if let Some(has_vendor_systick) = builder.has_vendor_systick {
312            self.has_vendor_systick = has_vendor_systick;
313        }
314        if builder.device_num_interrupts.is_some() {
315            self.device_num_interrupts = builder.device_num_interrupts;
316        }
317        if builder.sau_num_regions.is_some() {
318            self.sau_num_regions = builder.sau_num_regions;
319        }
320        self.validate(lvl)
321    }
322    /// Validate the [`Cpu`]
323    pub fn validate(&self, _lvl: ValidateLevel) -> Result<(), SvdError> {
324        // TODO
325        Ok(())
326    }
327    /// Check if the [`Cpu`] is a Cortex-M
328    pub fn is_cortex_m(&self) -> bool {
329        self.name.starts_with("CM")
330    }
331}