Skip to content

Commit 49eeebc

Browse files
committed
Support defining write constraints for newly created fields
This updates `make_field()` to honor a writeConstraint field, the same way that `make_register()` does.
1 parent 118cc58 commit 49eeebc

File tree

2 files changed

+83
-13
lines changed

2 files changed

+83
-13
lines changed

res/add_register/patch.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
_svd: ../add/stm32l4x2.svd
2+
3+
DAC1:
4+
_add:
5+
ANOTHER_REG:
6+
addressOffset: 0x04
7+
size: 32
8+
fields:
9+
MPS:
10+
bitOffset: 0
11+
bitWidth: 5
12+
access: read-write
13+
writeConstraint: [0, 0x1f]

src/patch/mod.rs

Lines changed: 70 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,8 @@ fn make_field(fadd: &Hash, rpath: Option<&RegisterPath>) -> Result<FieldInfoBuil
473473
fadd.get_str("modifiedWriteValues")?
474474
.and_then(ModifiedWriteValues::parse_str),
475475
)
476-
.read_action(fadd.get_str("readAction")?.and_then(ReadAction::parse_str));
476+
.read_action(fadd.get_str("readAction")?.and_then(ReadAction::parse_str))
477+
.write_constraint(get_write_constraint(fadd)?);
477478

478479
if let Some(name) = fadd.get_str("name")? {
479480
fnew = fnew.name(name.into());
@@ -503,6 +504,7 @@ fn make_register(radd: &Hash, path: Option<&BlockPath>) -> Result<RegisterInfoBu
503504
.alternate_group(radd.get_string("alternateGroup")?)
504505
.alternate_register(radd.get_string("alternateRegister")?)
505506
.properties(get_register_properties(radd)?)
507+
.write_constraint(get_write_constraint(radd)?)
506508
.fields(match radd.get_hash("fields")? {
507509
Some(h) => {
508510
let mut fields = Vec::new();
@@ -526,32 +528,35 @@ fn make_register(radd: &Hash, path: Option<&BlockPath>) -> Result<RegisterInfoBu
526528
rnew = rnew.address_offset(address_offset as u32);
527529
}
528530

529-
if let Some(write_constraint) = radd
531+
Ok(rnew)
532+
}
533+
534+
fn get_write_constraint(h: &Hash) -> Result<Option<WriteConstraint>> {
535+
if let Some(write_constraint) = h
530536
.get_yaml("_write_constraint")
531-
.or_else(|| radd.get_yaml("writeConstraint"))
537+
.or_else(|| h.get_yaml("writeConstraint"))
532538
{
533-
let wc = match write_constraint {
539+
match write_constraint {
534540
Yaml::String(s) if s == "none" => {
535541
// Completely remove the existing writeConstraint
536-
None
542+
Ok(None)
537543
}
538544
Yaml::String(s) if s == "enum" => {
539545
// Only allow enumerated values
540-
Some(WriteConstraint::UseEnumeratedValues(true))
546+
Ok(Some(WriteConstraint::UseEnumeratedValues(true)))
541547
}
542548
Yaml::Array(a) => {
543549
// Allow a certain range
544-
Some(WriteConstraint::Range(WriteConstraintRange {
550+
Ok(Some(WriteConstraint::Range(WriteConstraintRange {
545551
min: a[0].i64()? as u64,
546552
max: a[1].i64()? as u64,
547-
}))
553+
})))
548554
}
549-
_ => return Err(anyhow!("Unknown writeConstraint type {write_constraint:?}")),
550-
};
551-
rnew = rnew.write_constraint(wc);
555+
_ => Err(anyhow!("Unknown writeConstraint type {write_constraint:?}")),
556+
}
557+
} else {
558+
Ok(None)
552559
}
553-
554-
Ok(rnew)
555560
}
556561

557562
fn make_cluster(cadd: &Hash, path: Option<&BlockPath>) -> Result<ClusterInfoBuilder> {
@@ -852,3 +857,55 @@ impl Interpolate for FieldPath {
852857
cow
853858
}
854859
}
860+
861+
#[cfg(test)]
862+
mod tests {
863+
use super::*;
864+
use crate::test_utils;
865+
use std::path::Path;
866+
867+
#[test]
868+
fn add_register() -> Result<()> {
869+
let (mut device, yaml) = test_utils::get_patcher(Path::new("add_register")).unwrap();
870+
assert_eq!(device.peripherals.len(), 1);
871+
let registers = device.peripherals[0]
872+
.registers
873+
.as_ref()
874+
.ok_or(anyhow!("no registers"))?;
875+
assert_eq!(registers.len(), 1);
876+
877+
device.process(&yaml, &Default::default()).unwrap();
878+
assert_eq!(device.peripherals.len(), 1);
879+
let periph1 = &device.peripherals[0];
880+
assert_eq!(periph1.name, "DAC1");
881+
let registers = device.peripherals[0]
882+
.registers
883+
.as_ref()
884+
.ok_or(anyhow!("no registers"))?;
885+
assert_eq!(registers.len(), 2);
886+
let reg2 = match &registers[1] {
887+
RegisterCluster::Register(r) => r,
888+
RegisterCluster::Cluster(_) => return Err(anyhow!("expected register, found cluster")),
889+
};
890+
assert_eq!(reg2.name, "ANOTHER_REG");
891+
assert_eq!(reg2.address_offset, 4);
892+
assert_eq!(reg2.properties.size, Some(32));
893+
assert_eq!(reg2.write_constraint, None);
894+
let fields = reg2.fields.as_ref().ok_or(anyhow!("no fields"))?;
895+
assert_eq!(fields.len(), 1);
896+
let field1 = &fields[0];
897+
assert_eq!(field1.name, "MPS");
898+
assert_eq!(field1.bit_offset(), 0);
899+
assert_eq!(field1.bit_width(), 5);
900+
assert_eq!(field1.access, Some(Access::ReadWrite));
901+
assert_eq!(
902+
field1.write_constraint,
903+
Some(WriteConstraint::Range(WriteConstraintRange {
904+
min: 0,
905+
max: 0x1f
906+
}))
907+
);
908+
909+
Ok(())
910+
}
911+
}

0 commit comments

Comments
 (0)