svd_rs/
register.rs

1use super::{
2    array::{descriptions, names},
3    Access, BuildError, DataType, Description, DimElement, EmptyToNone, Field, MaybeArray,
4    ModifiedWriteValues, Name, ReadAction, RegisterProperties, SvdError, ValidateLevel,
5    WriteConstraint,
6};
7use std::ops::Deref;
8
9/// A single register or array of registers. A register is a named, programmable resource that belongs to a [peripheral](crate::Peripheral).
10pub type Register = MaybeArray<RegisterInfo>;
11
12/// Errors from [`RegisterInfo::validate`]
13#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
14pub enum Error {
15    /// Register had no fields, but specified a `<fields>` tag.
16    #[error("Register have `fields` tag, but it is empty")]
17    EmptyFields,
18}
19
20/// A register is a named, programmable resource that belongs to a [peripheral](crate::Peripheral).
21#[cfg_attr(
22    feature = "serde",
23    derive(serde::Deserialize, serde::Serialize),
24    serde(rename_all = "camelCase")
25)]
26#[derive(Clone, Debug, PartialEq, Eq)]
27#[non_exhaustive]
28pub struct RegisterInfo {
29    /// String to identify the register.
30    /// Register names are required to be unique within the scope of a peripheral
31    pub name: String,
32
33    /// Specifies a register name without the restrictions of an ANSI C identifier.
34    #[cfg_attr(
35        feature = "serde",
36        serde(default, skip_serializing_if = "Option::is_none")
37    )]
38    pub display_name: Option<String>,
39
40    /// String describing the details of the register
41    #[cfg_attr(
42        feature = "serde",
43        serde(default, skip_serializing_if = "Option::is_none")
44    )]
45    pub description: Option<String>,
46
47    /// Specifies a group name associated with all alternate register that have the same name
48    #[cfg_attr(
49        feature = "serde",
50        serde(default, skip_serializing_if = "Option::is_none")
51    )]
52    pub alternate_group: Option<String>,
53
54    /// This tag can reference a register that has been defined above to
55    /// current location in the description and that describes the memory location already
56    #[cfg_attr(
57        feature = "serde",
58        serde(default, skip_serializing_if = "Option::is_none")
59    )]
60    pub alternate_register: Option<String>,
61
62    /// Define the address offset relative to the enclosing element
63    pub address_offset: u32,
64
65    /// Specifies register size, access permission and reset value
66    #[cfg_attr(feature = "serde", serde(flatten))]
67    pub properties: RegisterProperties,
68
69    /// Register data type
70    #[cfg_attr(
71        feature = "serde",
72        serde(default, skip_serializing_if = "Option::is_none")
73    )]
74    pub datatype: Option<DataType>,
75
76    /// Specifies the write side effects
77    #[cfg_attr(
78        feature = "serde",
79        serde(default, skip_serializing_if = "Option::is_none")
80    )]
81    pub modified_write_values: Option<ModifiedWriteValues>,
82
83    /// Specifies the subset of allowed write values
84    #[cfg_attr(
85        feature = "serde",
86        serde(default, skip_serializing_if = "Option::is_none")
87    )]
88    pub write_constraint: Option<WriteConstraint>,
89
90    /// If set, it specifies the side effect following a read operation.
91    /// If not set, the register is not modified
92    #[cfg_attr(
93        feature = "serde",
94        serde(default, skip_serializing_if = "Option::is_none")
95    )]
96    pub read_action: Option<ReadAction>,
97
98    /// `None` indicates that the `<fields>` node is not present
99    #[cfg_attr(
100        feature = "serde",
101        serde(default, skip_serializing_if = "Option::is_none")
102    )]
103    pub fields: Option<Vec<Field>>,
104
105    /// Specify the register name from which to inherit data.
106    /// Elements specified subsequently override inherited values
107    #[cfg_attr(
108        feature = "serde",
109        serde(default, skip_serializing_if = "Option::is_none")
110    )]
111    pub derived_from: Option<String>,
112}
113
114/// Return iterator over address offsets of each register in array
115pub fn address_offsets<'a>(
116    info: &'a RegisterInfo,
117    dim: &'a DimElement,
118) -> impl Iterator<Item = u32> + 'a {
119    (0..dim.dim).map(move |i| info.address_offset + i * dim.dim_increment)
120}
121
122/// Extract `RegisterInfo` items from array
123pub fn expand<'a>(
124    info: &'a RegisterInfo,
125    dim: &'a DimElement,
126) -> impl Iterator<Item = RegisterInfo> + 'a {
127    dim.indexes()
128        .zip(names(info, dim))
129        .zip(descriptions(info, dim))
130        .zip(address_offsets(info, dim))
131        .map(|(((idx, name), description), address_offset)| {
132            let mut info = info.clone();
133            info.name = name;
134            info.description = description;
135            info.address_offset = address_offset;
136            info.display_name = info
137                .display_name
138                .map(|d| d.replace("[%s]", &idx).replace("%s", &idx));
139            info
140        })
141}
142
143/// Builder for [`RegisterInfo`]
144#[derive(Clone, Debug, Default, PartialEq, Eq)]
145pub struct RegisterInfoBuilder {
146    name: Option<String>,
147    display_name: Option<String>,
148    description: Option<String>,
149    alternate_group: Option<String>,
150    alternate_register: Option<String>,
151    address_offset: Option<u32>,
152    properties: RegisterProperties,
153    datatype: Option<DataType>,
154    modified_write_values: Option<ModifiedWriteValues>,
155    write_constraint: Option<WriteConstraint>,
156    read_action: Option<ReadAction>,
157    fields: Option<Vec<Field>>,
158    derived_from: Option<String>,
159}
160
161impl From<RegisterInfo> for RegisterInfoBuilder {
162    fn from(r: RegisterInfo) -> Self {
163        Self {
164            name: Some(r.name),
165            display_name: r.display_name,
166            description: r.description,
167            alternate_group: r.alternate_group,
168            alternate_register: r.alternate_register,
169            address_offset: Some(r.address_offset),
170            properties: r.properties,
171            datatype: r.datatype,
172            modified_write_values: r.modified_write_values,
173            write_constraint: r.write_constraint,
174            read_action: r.read_action,
175            fields: r.fields,
176            derived_from: r.derived_from,
177        }
178    }
179}
180
181impl RegisterInfoBuilder {
182    /// Set the name of the register.
183    pub fn name(mut self, value: String) -> Self {
184        self.name = Some(value);
185        self
186    }
187    /// Set the display name of the register.
188    pub fn display_name(mut self, value: Option<String>) -> Self {
189        self.display_name = value;
190        self
191    }
192    /// Set the description of the register.
193    pub fn description(mut self, value: Option<String>) -> Self {
194        self.description = value;
195        self
196    }
197    /// Set the alternate group of the register.
198    pub fn alternate_group(mut self, value: Option<String>) -> Self {
199        self.alternate_group = value;
200        self
201    }
202    /// Set the alternate register of the register.
203    pub fn alternate_register(mut self, value: Option<String>) -> Self {
204        self.alternate_register = value;
205        self
206    }
207    /// Set the address offset of the register.
208    pub fn address_offset(mut self, value: u32) -> Self {
209        self.address_offset = Some(value);
210        self
211    }
212    /// Set the properties of the register.
213    pub fn properties(mut self, value: RegisterProperties) -> Self {
214        self.properties = value;
215        self
216    }
217    /// Set the datatype of the register.
218    pub fn datatype(mut self, value: Option<DataType>) -> Self {
219        self.datatype = value;
220        self
221    }
222    /// Set the size of the register.
223    pub fn size(mut self, value: Option<u32>) -> Self {
224        self.properties.size = value;
225        self
226    }
227    /// Set the access of the register.
228    pub fn access(mut self, value: Option<Access>) -> Self {
229        self.properties.access = value;
230        self
231    }
232    /// Set the reset value of the register.
233    pub fn reset_value(mut self, value: Option<u64>) -> Self {
234        self.properties.reset_value = value;
235        self
236    }
237    /// Set the reset mask of the register.
238    pub fn reset_mask(mut self, value: Option<u64>) -> Self {
239        self.properties.reset_mask = value;
240        self
241    }
242    /// Set the modified write values of the register.
243    pub fn modified_write_values(mut self, value: Option<ModifiedWriteValues>) -> Self {
244        self.modified_write_values = value;
245        self
246    }
247    /// Set the write constraint of the register.
248    pub fn write_constraint(mut self, value: Option<WriteConstraint>) -> Self {
249        self.write_constraint = value;
250        self
251    }
252    /// Set the read action of the register.
253    pub fn read_action(mut self, value: Option<ReadAction>) -> Self {
254        self.read_action = value;
255        self
256    }
257    /// Set the fields of the register.
258    pub fn fields(mut self, value: Option<Vec<Field>>) -> Self {
259        self.fields = value;
260        self
261    }
262    /// Set the derived_from attribute of the register.
263    pub fn derived_from(mut self, value: Option<String>) -> Self {
264        self.derived_from = value;
265        self
266    }
267    /// Validate and build a [`RegisterInfo`].
268    pub fn build(self, lvl: ValidateLevel) -> Result<RegisterInfo, SvdError> {
269        let reg = RegisterInfo {
270            name: self
271                .name
272                .ok_or_else(|| BuildError::Uninitialized("name".to_string()))?,
273            display_name: self.display_name,
274            description: self.description,
275            alternate_group: self.alternate_group,
276            alternate_register: self.alternate_register,
277            address_offset: self
278                .address_offset
279                .ok_or_else(|| BuildError::Uninitialized("address_offset".to_string()))?,
280            properties: self.properties.build(lvl)?,
281            datatype: self.datatype,
282            modified_write_values: self.modified_write_values,
283            write_constraint: self.write_constraint,
284            read_action: self.read_action,
285            fields: self.fields,
286            derived_from: self.derived_from,
287        };
288        reg.validate(lvl)?;
289        Ok(reg)
290    }
291}
292
293impl RegisterInfo {
294    /// Make a builder for [`RegisterInfo`]
295    pub fn builder() -> RegisterInfoBuilder {
296        RegisterInfoBuilder::default()
297    }
298    /// Construct single [`Register`]
299    pub const fn single(self) -> Register {
300        Register::Single(self)
301    }
302    /// Construct [`Register`] array
303    pub const fn array(self, dim: DimElement) -> Register {
304        Register::Array(self, dim)
305    }
306    /// Construct single [`Register`] or array
307    pub fn maybe_array(self, dim: Option<DimElement>) -> Register {
308        if let Some(dim) = dim {
309            self.array(dim)
310        } else {
311            self.single()
312        }
313    }
314    /// Modify an existing [`RegisterInfo`] based on a [builder](RegisterInfoBuilder).
315    pub fn modify_from(
316        &mut self,
317        builder: RegisterInfoBuilder,
318        lvl: ValidateLevel,
319    ) -> Result<(), SvdError> {
320        if let Some(name) = builder.name {
321            self.name = name;
322        }
323        if builder.display_name.is_some() {
324            self.display_name = builder.display_name.empty_to_none();
325        }
326        if builder.description.is_some() {
327            self.description = builder.description.empty_to_none();
328        }
329        if builder.alternate_group.is_some() {
330            self.alternate_group = builder.alternate_group.empty_to_none();
331        }
332        if builder.alternate_register.is_some() {
333            self.alternate_register = builder.alternate_register.empty_to_none();
334        }
335        if let Some(address_offset) = builder.address_offset {
336            self.address_offset = address_offset;
337        }
338        if builder.derived_from.is_some() {
339            self.derived_from = builder.derived_from;
340            self.fields = None;
341            self.properties = RegisterProperties::default();
342            self.datatype = None;
343            self.modified_write_values = None;
344            self.write_constraint = None;
345        } else {
346            self.properties.modify_from(builder.properties, lvl)?;
347            if builder.datatype.is_some() {
348                self.datatype = builder.datatype;
349            }
350            if builder.modified_write_values.is_some() {
351                self.modified_write_values = builder.modified_write_values;
352            }
353            if builder.write_constraint.is_some() {
354                self.write_constraint = builder.write_constraint;
355            }
356            if builder.read_action.is_some() {
357                self.read_action = builder.read_action;
358            }
359            if builder.fields.is_some() {
360                self.fields = builder.fields.empty_to_none();
361            }
362        }
363        self.validate(lvl)
364    }
365    /// Validate the [`RegisterInfo`]
366    pub fn validate(&self, lvl: ValidateLevel) -> Result<(), SvdError> {
367        if !lvl.is_disabled() {
368            if lvl.is_strict() {
369                super::check_dimable_name(&self.name, "name")?;
370                if let Some(name) = self.alternate_group.as_ref() {
371                    super::check_name(name, "alternateGroup")?;
372                }
373                if let Some(name) = self.alternate_register.as_ref() {
374                    super::check_dimable_name(name, "alternateRegister")?;
375                }
376            }
377            if let Some(name) = self.derived_from.as_ref() {
378                if lvl.is_strict() {
379                    super::check_derived_name(name, "derivedFrom")?;
380                }
381            } else if let Some(fields) = self.fields.as_ref() {
382                if fields.is_empty() && lvl.is_strict() {
383                    return Err(Error::EmptyFields.into());
384                }
385            }
386        }
387        Ok(())
388    }
389    /// Validate the [`RegisterInfo`] recursively
390    pub fn validate_all(&self, lvl: ValidateLevel) -> Result<(), SvdError> {
391        self.properties.validate(lvl)?;
392        for f in self.fields() {
393            f.validate_all(lvl)?;
394        }
395        self.validate(lvl)
396    }
397
398    /// Returns iterator over child fields
399    pub fn fields(&self) -> std::slice::Iter<Field> {
400        match &self.fields {
401            Some(fields) => fields.iter(),
402            None => [].iter(),
403        }
404    }
405
406    /// Returns mutable iterator over child fields
407    pub fn fields_mut(&mut self) -> std::slice::IterMut<Field> {
408        match &mut self.fields {
409            Some(fields) => fields.iter_mut(),
410            None => [].iter_mut(),
411        }
412    }
413
414    /// Get field by name
415    pub fn get_field(&self, name: &str) -> Option<&Field> {
416        self.fields().find(|f| f.name == name)
417    }
418
419    /// Get mutable field by name
420    pub fn get_mut_field(&mut self, name: &str) -> Option<&mut Field> {
421        self.fields_mut().find(|f| f.name == name)
422    }
423
424    /// Get bits which is affected by register fields
425    pub fn bitmask(&self) -> u64 {
426        self.fields().fold(0, |mask, f| mask | f.bitmask())
427    }
428}
429
430impl Register {
431    /// Validate the [`Register`] recursively
432    pub fn validate_all(&self, lvl: ValidateLevel) -> Result<(), SvdError> {
433        if let Self::Array(_, dim) = self {
434            dim.validate(lvl)?;
435        }
436        self.deref().validate_all(lvl)
437    }
438}
439
440impl Name for RegisterInfo {
441    fn name(&self) -> &str {
442        &self.name
443    }
444}
445
446impl Description for RegisterInfo {
447    fn description(&self) -> Option<&str> {
448        self.description.as_deref()
449    }
450}