From 603ad0d9f9d05ec792140a19549395c7a2b74d6c Mon Sep 17 00:00:00 2001 From: Tenkai Kariya Date: Sat, 26 Oct 2024 21:26:35 -0700 Subject: [PATCH 1/2] cleanup and added example in res --- res/expand_cluster/mspm0g350x.svd | 136 ++++++++++++++++++++++++++++++ res/expand_cluster/patch.yml | 7 ++ src/patch/peripheral.rs | 91 ++++++++++++++++++++ 3 files changed, 234 insertions(+) create mode 100644 res/expand_cluster/mspm0g350x.svd create mode 100644 res/expand_cluster/patch.yml diff --git a/res/expand_cluster/mspm0g350x.svd b/res/expand_cluster/mspm0g350x.svd new file mode 100644 index 00000000..a6fceef1 --- /dev/null +++ b/res/expand_cluster/mspm0g350x.svd @@ -0,0 +1,136 @@ + + + MSPM0G350x + + + GPIOB + GPIOB + 1.0 + PERIPHERALREGION + 0x400A2000 + + 0x0 + 0x1F00 + registers + + + + 1 + 24 + 0 + GPIOB_GPRCM[%s] + + 0x800 + + GPIOB_PWREN + Power enable + 0x0 + 32 + read-write + + + ENABLE + Enable the power + 0x0 + 0x1 + + + DISABLE + Disable Power + 0x0 + + + ENABLE + Enable Power + 0x1 + + + + + + + GPIOB_RSTCTL + Reset Control + 0x4 + 32 + write-only + + + RESETSTKYCLR + Clear the RESETSTKY bit in the STAT register + 0x1 + 0x1 + write-only + + + NOP + Writing 0 has no effect + 0x0 + + + CLR + Clear reset sticky bit + 0x1 + + + + + RESETASSERT + Assert reset to the peripheral + 0x0 + 0x1 + write-only + + + NOP + Writing 0 has no effect + 0x0 + + + ASSERT + Assert reset + 0x1 + + + + + + + GPIOB_STAT + Status Register + 0x14 + 32 + read-only + + + RESETSTKY + This bit indicates, if the peripheral was reset, since this bit was + cleared + by RESETSTKYCLR in the RSTCTL register + 0x10 + 0x1 + read-only + + + NORES + The peripheral has not been reset since this bit was last cleared + by + RESETSTKYCLR in the RSTCTL register + 0x0 + + + RESET + The peripheral was reset since the last bit clear + 0x1 + + + + + + + + + + diff --git a/res/expand_cluster/patch.yml b/res/expand_cluster/patch.yml new file mode 100644 index 00000000..36d45746 --- /dev/null +++ b/res/expand_cluster/patch.yml @@ -0,0 +1,7 @@ +_svd: "./mspm0g350x.svd" + +# Alter top-level information and peripherals for this device +"GPIO*": + _expand_cluster: + - "GPIO?_GPRCM*" + _strip: "GPIO?_" diff --git a/src/patch/peripheral.rs b/src/patch/peripheral.rs index cc789455..edbedc5e 100644 --- a/src/patch/peripheral.rs +++ b/src/patch/peripheral.rs @@ -513,6 +513,73 @@ pub(crate) trait RegisterBlockExt: Name { } } + fn get_cluster_registers( + &self, + cspec: &str, + bpath: &BlockPath, + ) -> anyhow::Result)>> { + // ) -> anyhow::Result<(Vec, ClusterInfo)> { + let (cspec, ignore) = cspec.spec(); + println!("Expanding cluster {0}", cspec); + + let present = self.present_clusters().clone(); + Ok(self + .clstrs() + .matched(cspec) + .map(|ctag| { + let regs = ctag + .clone() + .all_registers() + .map(|reg| { + RegisterCluster::Register(::clone(reg).single()) + }) + .collect::>(); + if regs.is_empty() && !ignore { + return Err(anyhow!( + "Could not find cluster `{bpath}:{cspec}. Present clusters: {present}.`" + )); + } + Ok((std::ops::Deref::deref(ctag), regs)) + }) + .flatten() + .collect::>()) + } + /// Expand register cluster + fn expand_cluster(&mut self, cspec: &str, bpath: &BlockPath) -> PatchResult { + let mut info_and_regs = Vec::new(); + + let mut clusters_to_delete = Vec::new(); + // some fancy footwork to satisfy the borrow checker gods + for (ci, rc) in self.get_cluster_registers(cspec, bpath)? { + let mut regs = Vec::new(); + for reg in rc { + regs.push(::clone(®)); + } + info_and_regs.push((ci.clone(), regs)); + } + + if let Some(regs) = self.children_mut() { + for (_cinfo, cluster_registers) in info_and_regs { + let mut found = false; + for reg in cluster_registers { + found = true; + println!("Adding register {0}", reg.name()); + regs.push(reg.clone()) + } + if !found { + return Err(anyhow!("No registers found in cluster {:?}", cspec)); + } else { + clusters_to_delete.push(cspec) + } + } + } + for cspec in clusters_to_delete { + self.delete_cluster(cspec) + .with_context(|| format!("Deleting clusters matched to `{cspec}`"))?; + } + Ok(()) + } + /// Expand register array fn expand_array(&mut self, rspec: &str, _rmod: &Hash, _config: &Config) -> PatchResult { if let Some(regs) = self.children_mut() { @@ -749,6 +816,27 @@ impl PeripheralExt for Peripheral { } } + if let Some(expand_cluster) = pmod.get_yaml("_expand_cluster") { + match expand_cluster { + Yaml::String(cspec) => { + self.expand_cluster(cspec, &ppath) + .with_context(|| format!("During expand of `{cspec}` cluster"))?; + } + Yaml::Array(clusters) => { + for cspec in clusters { + let cspec = cspec.str()?; + self.expand_cluster(cspec, &ppath) + .with_context(|| format!("During expand of `{cspec}` cluster"))?; + } + } + _ => { + return Err(anyhow!( + "`_expand_cluster` requires string value or array of strings" + )) + } + } + } + // Handle any copied peripherals for (rname, rcopy) in pmod.hash_iter("_copy") { let rname = rname.str()?; @@ -889,6 +977,7 @@ impl PeripheralExt for Peripheral { // Handle registers or clusters for (rcspec, rcmod) in pmod { let rcspec = rcspec.str()?; + println!("Processing {0}", rcspec); if Self::KEYWORDS.contains(&rcspec) { continue; } @@ -1153,6 +1242,7 @@ impl ClusterExt for Cluster { .with_context(|| format!("According to `{rcspec}`"))?; } + println!("post process"); self.post_process(cmod, parent, config) } @@ -1504,6 +1594,7 @@ fn collect_in_cluster( ) }; cluster.pre_process(cmod, path, &config)?; + println!("cluster post process"); cluster.post_process(cmod, path, &config)?; regs.insert(place, RegisterCluster::Cluster(cluster)); Ok(()) From 1d9454a0b03ea66dbc929df9286b43fe3a9c535f Mon Sep 17 00:00:00 2001 From: Tenkai Kariya Date: Wed, 6 Nov 2024 21:58:03 -0800 Subject: [PATCH 2/2] expand_cluster implementation --- README.md | 23 + res/expand_cluster/expected.svd | 1187 +++++++++++++++++++++++++++++ res/expand_cluster/mspm0g350x.svd | 488 ++++++++++++ res/expand_cluster/patch.yml | 21 +- src/patch/peripheral.rs | 370 +++++++-- src/patch/yaml_ext.rs | 87 ++- 6 files changed, 2101 insertions(+), 75 deletions(-) create mode 100644 res/expand_cluster/expected.svd diff --git a/README.md b/README.md index 562cc292..fd8e8ed5 100644 --- a/README.md +++ b/README.md @@ -266,6 +266,29 @@ _rebase: FIRST_REG: {} SECOND_REG: {} + # clusters can be expanded into individual registers. The name of the resulting register will be the cluster name, concatenated with the register name. + + _expand_cluster: + - CLUSTER_ONE* + - CLUSTER_TWO* + + # When expanding clusters containing more than one element (as specified by ), each register will have substutute [%] in the cluster name with its index number. If the cluster has a dimIndex element, a %s in the cluster name will be replaced by dimIndex element. [%] is not compatible with dimIndex, as according to SVD 1.3.10 + # The SVD 1.3.10 does not specify a delimiter for expansion, so passing the following parameters to the cluster as a hash will allow you to set the delimiter before and after the index is applied (the default delimiters are "_". You can also force the cluster to apply a zero index to a cluster with a single element by passing in the _zeroindex: true parameter + + _expand_cluster: + CLUSTER_ONE*: + CLUSTER_TWO*: + _preindex: "_" + _postindex: "_" + _zeroindex: true + + + # if you pass the _noprefix: true parameter to a cluster, the cluster name will not be prefixed with the peripheral name. This is only valid for single element clusters. + + _expand_cluster: + CLUSTER_ONE*: + _noprefix: true + # A register on this peripheral, matches an SVD tag MODER: # As in the peripheral scope, rename or redescribe a field. diff --git a/res/expand_cluster/expected.svd b/res/expand_cluster/expected.svd new file mode 100644 index 00000000..c553d0e8 --- /dev/null +++ b/res/expand_cluster/expected.svd @@ -0,0 +1,1187 @@ + + + MSPM0G350x + 1.0 + + 8 + 32 + + + GPIOB + 1.0 + PERIPHERALREGION + GPIOB + 0x400A2000 + + 0x0 + 0x1F00 + registers + + + + FSUB_0 + Subsciber Port 0 + 0x400 + 0x20 + read-write + 0x00000000 + + + CHANID + 0 = disconnected. + 1-15 = connected to channelID = CHANID. + 0 + 4 + + + UNCONNECTED + A value of 0 specifies that the event is not connected + 0 + + + + + + + PWREN + Power enable + 0x800 + 0x20 + read-write + + + ENABLE + Enable the power + 0 + 1 + + + DISABLE + Disable Power + 0 + + + ENABLE + Enable Power + 1 + + + + + + + RSTCTL + Reset Control + 0x804 + 0x20 + write-only + + + RESETSTKYCLR + Clear the RESETSTKY bit in the STAT register + 1 + 1 + write-only + + + NOP + Writing 0 has no effect + 0 + + + CLR + Clear reset sticky bit + 1 + + + + + RESETASSERT + Assert reset to the peripheral + 0 + 1 + write-only + + + NOP + Writing 0 has no effect + 0 + + + ASSERT + Assert reset + 1 + + + + + + + STAT + Status Register + 0x814 + 0x20 + read-only + + + RESETSTKY + This bit indicates, if the peripheral was reset, since this bit was + cleared + by RESETSTKYCLR in the RSTCTL register + 16 + 1 + read-only + + + NORES + The peripheral has not been reset since this bit was last cleared + by + RESETSTKYCLR in the RSTCTL register + 0 + + + RESET + The peripheral was reset since the last bit clear + 1 + + + + + + + TEST_REG_0 + Reg Description + 0x800 + 0x20 + read-write + + + ENABLE + Enable the reg + 0 + 1 + + + DISABLE + Disable regster + 0 + + + ENABLE + Enable register + 1 + + + + + + + 3 + 0x18 + X,Y,Z + + TEST_NESTED_CLUSTER_0[%s] + 0x1000 + + TEST_NC_REG + Reg Description + 0x0 + 0x20 + read-write + + + ENABLE + Enable the reg + 0 + 1 + + + DISABLE + Disable regster + 0 + + + ENABLE + Enable register + 1 + + + + + + + + TEST_REG_1 + Reg Description + 0x818 + 0x20 + read-write + + + ENABLE + Enable the reg + 0 + 1 + + + DISABLE + Disable regster + 0 + + + ENABLE + Enable register + 1 + + + + + + + 3 + 0x18 + X,Y,Z + + TEST_NESTED_CLUSTER_1[%s] + 0x1018 + + TEST_NC_REG + Reg Description + 0x0 + 0x20 + read-write + + + ENABLE + Enable the reg + 0 + 1 + + + DISABLE + Disable regster + 0 + + + ENABLE + Enable register + 1 + + + + + + + + TEST_REG_2 + Reg Description + 0x830 + 0x20 + read-write + + + ENABLE + Enable the reg + 0 + 1 + + + DISABLE + Disable regster + 0 + + + ENABLE + Enable register + 1 + + + + + + + 3 + 0x18 + X,Y,Z + + TEST_NESTED_CLUSTER_2[%s] + 0x1030 + + TEST_NC_REG + Reg Description + 0x0 + 0x20 + read-write + + + ENABLE + Enable the reg + 0 + 1 + + + DISABLE + Disable regster + 0 + + + ENABLE + Enable register + 1 + + + + + + + + TEST_REG_3 + Reg Description + 0x848 + 0x20 + read-write + + + ENABLE + Enable the reg + 0 + 1 + + + DISABLE + Disable regster + 0 + + + ENABLE + Enable register + 1 + + + + + + + 3 + 0x18 + X,Y,Z + + TEST_NESTED_CLUSTER_3[%s] + 0x1048 + + TEST_NC_REG + Reg Description + 0x0 + 0x20 + read-write + + + ENABLE + Enable the reg + 0 + 1 + + + DISABLE + Disable regster + 0 + + + ENABLE + Enable register + 1 + + + + + + + + TEST_REG_A + Reg Description + 0x800 + 0x20 + read-write + + + ENABLE + Enable the reg + 0 + 1 + + + DISABLE + Disable regster + 0 + + + ENABLE + Enable register + 1 + + + + + + + 3 + 0x18 + X,Y,Z + + TEST_NESTED_CLUSTER_A[%s] + 0x1000 + + TEST_NC_REG + Reg Description + 0x0 + 0x20 + read-write + + + ENABLE + Enable the reg + 0 + 1 + + + DISABLE + Disable regster + 0 + + + ENABLE + Enable register + 1 + + + + + + + + TEST_REG_B + Reg Description + 0x818 + 0x20 + read-write + + + ENABLE + Enable the reg + 0 + 1 + + + DISABLE + Disable regster + 0 + + + ENABLE + Enable register + 1 + + + + + + + 3 + 0x18 + X,Y,Z + + TEST_NESTED_CLUSTER_B[%s] + 0x1018 + + TEST_NC_REG + Reg Description + 0x0 + 0x20 + read-write + + + ENABLE + Enable the reg + 0 + 1 + + + DISABLE + Disable regster + 0 + + + ENABLE + Enable register + 1 + + + + + + + + TEST_REG_C + Reg Description + 0x830 + 0x20 + read-write + + + ENABLE + Enable the reg + 0 + 1 + + + DISABLE + Disable regster + 0 + + + ENABLE + Enable register + 1 + + + + + + + 3 + 0x18 + X,Y,Z + + TEST_NESTED_CLUSTER_C[%s] + 0x1030 + + TEST_NC_REG + Reg Description + 0x0 + 0x20 + read-write + + + ENABLE + Enable the reg + 0 + 1 + + + DISABLE + Disable regster + 0 + + + ENABLE + Enable register + 1 + + + + + + + + TEST_REG_D + Reg Description + 0x848 + 0x20 + read-write + + + ENABLE + Enable the reg + 0 + 1 + + + DISABLE + Disable regster + 0 + + + ENABLE + Enable register + 1 + + + + + + + 3 + 0x18 + X,Y,Z + + TEST_NESTED_CLUSTER_D[%s] + 0x1048 + + TEST_NC_REG + Reg Description + 0x0 + 0x20 + read-write + + + ENABLE + Enable the reg + 0 + 1 + + + DISABLE + Disable regster + 0 + + + ENABLE + Enable register + 1 + + + + + + + + + + DAC0 + 1.0 + PERIPHERALREGION + DAC + 0x40018000 + + 0x0 + 0x1F00 + registers + + + + DAC0_IIDX_0 + Interrupt index + 0x1020 + 0x20 + read-only + 0x00000000 + + + STAT + Interrupt index status + 0 + 4 + read-only + + + NO_INTR + No pending interrupt + 0 + + + MODRDYIFG + Module ready interrupt + 2 + + + FIFOFULLIFG + FIFO full interrupt + 9 + + + FIFO1B4IFG + FIFO one fourth empty interrupt + 10 + + + FIFO1B2IFG + FIFO half empty interrupt + 11 + + + FIFO3B4IFG + FIFO three fourth empty interrupt + 12 + + + FIFOEMPTYIFG + FIFO empty interrupt + 13 + + + FIFOURUNIFG + FIFO underrun interrupt + 14 + + + DMADONEIFG + DMA done interrupt + 15 + + + + + + + DAC0_IMASK_0 + Interrupt mask + 0x1028 + 0x20 + read-write + 0x00000000 + + + MODRDYIFG + Masks MODRDYIFG + 1 + 1 + + + CLR + Interrupt is masked out + 0 + + + SET + Interrupt will request an interrupt service routine and + corresponding bit in MIS will be set + 1 + + + + + FIFO1B2IFG + Masks FIFO1B2IFG + 10 + 1 + + + CLR + Interrupt is masked out + 0 + + + SET + Interrupt will request an interrupt service routine and + corresponding bit in MIS will be set + 1 + + + + + FIFOEMPTYIFG + Masks FIFOEMPTYIFG + 12 + 1 + + + CLR + Interrupt is masked out + 0 + + + SET + Interrupt will request an interrupt service routine and + corresponding bit in MIS will be set + 1 + + + + + FIFO1B4IFG + Masks FIFO1B4IFG + 9 + 1 + + + CLR + Interrupt is masked out + 0 + + + SET + Interrupt will request an interrupt service routine and + corresponding bit in MIS will be set + 1 + + + + + FIFO3B4IFG + Masks FIFO3B4IFG + 11 + 1 + + + CLR + Interrupt is masked out + 0 + + + SET + Interrupt will request an interrupt service routine and + corresponding bit in MIS will be set + 1 + + + + + FIFOFULLIFG + Masks FIFOFULLIFG + 8 + 1 + + + CLR + Interrupt is masked out + 0 + + + SET + Interrupt will request an interrupt service routine and + corresponding bit in MIS will be set + 1 + + + + + FIFOURUNIFG + Masks FIFOURUNIFG + 13 + 1 + + + CLR + Interrupt is masked out + 0 + + + SET + Interrupt will request an interrupt service routine and + corresponding bit in MIS will be set + 1 + + + + + DMADONEIFG + Masks DMADONEIFG + 14 + 1 + + + CLR + Interrupt is masked out + 0 + + + SET + Interrupt will request an interrupt service routine and + corresponding bit in MIS will be set + 1 + + + + + + + DAC0_IIDX_1 + Interrupt index + 0x104C + 0x20 + read-only + 0x00000000 + + + STAT + Interrupt index status + 0 + 4 + read-only + + + NO_INTR + No pending interrupt + 0 + + + MODRDYIFG + Module ready interrupt + 2 + + + FIFOFULLIFG + FIFO full interrupt + 9 + + + FIFO1B4IFG + FIFO one fourth empty interrupt + 10 + + + FIFO1B2IFG + FIFO half empty interrupt + 11 + + + FIFO3B4IFG + FIFO three fourth empty interrupt + 12 + + + FIFOEMPTYIFG + FIFO empty interrupt + 13 + + + FIFOURUNIFG + FIFO underrun interrupt + 14 + + + DMADONEIFG + DMA done interrupt + 15 + + + + + + + DAC0_IMASK_1 + Interrupt mask + 0x1054 + 0x20 + read-write + 0x00000000 + + + MODRDYIFG + Masks MODRDYIFG + 1 + 1 + + + CLR + Interrupt is masked out + 0 + + + SET + Interrupt will request an interrupt service routine and + corresponding bit in MIS will be set + 1 + + + + + FIFO1B2IFG + Masks FIFO1B2IFG + 10 + 1 + + + CLR + Interrupt is masked out + 0 + + + SET + Interrupt will request an interrupt service routine and + corresponding bit in MIS will be set + 1 + + + + + FIFOEMPTYIFG + Masks FIFOEMPTYIFG + 12 + 1 + + + CLR + Interrupt is masked out + 0 + + + SET + Interrupt will request an interrupt service routine and + corresponding bit in MIS will be set + 1 + + + + + FIFO1B4IFG + Masks FIFO1B4IFG + 9 + 1 + + + CLR + Interrupt is masked out + 0 + + + SET + Interrupt will request an interrupt service routine and + corresponding bit in MIS will be set + 1 + + + + + FIFO3B4IFG + Masks FIFO3B4IFG + 11 + 1 + + + CLR + Interrupt is masked out + 0 + + + SET + Interrupt will request an interrupt service routine and + corresponding bit in MIS will be set + 1 + + + + + FIFOFULLIFG + Masks FIFOFULLIFG + 8 + 1 + + + CLR + Interrupt is masked out + 0 + + + SET + Interrupt will request an interrupt service routine and + corresponding bit in MIS will be set + 1 + + + + + FIFOURUNIFG + Masks FIFOURUNIFG + 13 + 1 + + + CLR + Interrupt is masked out + 0 + + + SET + Interrupt will request an interrupt service routine and + corresponding bit in MIS will be set + 1 + + + + + DMADONEIFG + Masks DMADONEIFG + 14 + 1 + + + CLR + Interrupt is masked out + 0 + + + SET + Interrupt will request an interrupt service routine and + corresponding bit in MIS will be set + 1 + + + + + + + + + CRC + 1.0 + PERIPHERALREGION + CRC + 0x40440000 + + 0x0 + 0x2000 + registers + + + + 1 + 0x18 + + TEST_CLUSTER_WITH_REG_ARRAY_MEMBER[%s] + 0x800 + + CRC_PWREN + Power enable + 0x0 + 0x20 + read-write + 0x00000000 + + + ENABLE + Enable the power + 0 + 1 + read-write + + + DISABLE + Disable Power + 0 + + + ENABLE + Enable Power + 1 + + + + + + + 512 + 0x4 + 0-511 + TEST_REGISTER_ARRAY_IN_CLUSTER_%s + CRC Input Data Array Register + 0x1800 + 0x20 + write-only + 0x00000000 + 0xFFFFFFFF + + + DATA + Input Data + 0 + 32 + write-only + + + + + + + + \ No newline at end of file diff --git a/res/expand_cluster/mspm0g350x.svd b/res/expand_cluster/mspm0g350x.svd index a6fceef1..16211556 100644 --- a/res/expand_cluster/mspm0g350x.svd +++ b/res/expand_cluster/mspm0g350x.svd @@ -16,6 +16,173 @@ registers + + GPIOB_FSUB_0 + Subsciber Port 0 + 0x400 + 32 + read-write + 0x00000000 + + + CHANID + 0 = disconnected. + 1-15 = connected to channelID = CHANID. + 0x0 + 0x4 + + + UNCONNECTED + A value of 0 specifies that the event is not connected + 0x0 + + + + + + + 4 + 24 + + TEST_CLUSTER_NO_INDEX[%s] + + 0x800 + + TEST_REG + Reg Description + 0x0 + 32 + read-write + + + ENABLE + Enable the reg + 0x0 + 0x1 + + + DISABLE + Disable regster + 0x0 + + + ENABLE + Enable register + 0x1 + + + + + + + 3 + 24 + X,Y,Z + + TEST_NESTED_CLUSTER%s + + 0x800 + + TEST_NC_REG + Reg Description + 0x0 + 32 + read-write + + + ENABLE + Enable the reg + 0x0 + 0x1 + + + DISABLE + Disable regster + 0x0 + + + ENABLE + Enable register + 0x1 + + + + + + + + + 4 + 24 + A,B,C,D + + TEST_CLUSTER_WITH_INDEX%s + + 0x800 + + TEST_REG + Reg Description + 0x0 + 32 + read-write + + + ENABLE + Enable the reg + 0x0 + 0x1 + + + DISABLE + Disable regster + 0x0 + + + ENABLE + Enable register + 0x1 + + + + + + + 3 + 24 + X,Y,Z + + TEST_NESTED_CLUSTER[%s] + + 0x800 + + TEST_NC_REG + Reg Description + 0x0 + 32 + read-write + + + ENABLE + Enable the reg + 0x0 + 0x1 + + + DISABLE + Disable regster + 0x0 + + + ENABLE + Enable register + 0x1 + + + + + + + 1 24 @@ -132,5 +299,326 @@ + + DAC0 + DAC + 1.0 + PERIPHERALREGION + 0x40018000 + + 0x0 + 0x1F00 + registers + + + + 2 + 44 + 0,1 + DAC0_INT_EVENT[%s] + + 0x1020 + + DAC0_IIDX + Interrupt index + 0x0 + 32 + read-only + 0x00000000 + + + STAT + Interrupt index status + 0x0 + 0x4 + read-only + + + NO_INTR + No pending interrupt + 0x0 + + + MODRDYIFG + Module ready interrupt + 0x2 + + + FIFOFULLIFG + FIFO full interrupt + 0x9 + + + FIFO1B4IFG + FIFO one fourth empty interrupt + 0xA + + + FIFO1B2IFG + FIFO half empty interrupt + 0xB + + + FIFO3B4IFG + FIFO three fourth empty interrupt + 0xC + + + FIFOEMPTYIFG + FIFO empty interrupt + 0xD + + + FIFOURUNIFG + FIFO underrun interrupt + 0xE + + + DMADONEIFG + DMA done interrupt + 0xF + + + + + + + DAC0_IMASK + Interrupt mask + 0x8 + 32 + read-write + 0x00000000 + + + MODRDYIFG + Masks MODRDYIFG + 0x1 + 0x1 + + + CLR + Interrupt is masked out + 0x0 + + + SET + Interrupt will request an interrupt service routine and + corresponding bit in MIS will be set + 0x1 + + + + + FIFO1B2IFG + Masks FIFO1B2IFG + 0xA + 0x1 + + + CLR + Interrupt is masked out + 0x0 + + + SET + Interrupt will request an interrupt service routine and + corresponding bit in MIS will be set + 0x1 + + + + + FIFOEMPTYIFG + Masks FIFOEMPTYIFG + 0xC + 0x1 + + + CLR + Interrupt is masked out + 0x0 + + + SET + Interrupt will request an interrupt service routine and + corresponding bit in MIS will be set + 0x1 + + + + + FIFO1B4IFG + Masks FIFO1B4IFG + 0x9 + 0x1 + + + CLR + Interrupt is masked out + 0x0 + + + SET + Interrupt will request an interrupt service routine and + corresponding bit in MIS will be set + 0x1 + + + + + FIFO3B4IFG + Masks FIFO3B4IFG + 0xB + 0x1 + + + CLR + Interrupt is masked out + 0x0 + + + SET + Interrupt will request an interrupt service routine and + corresponding bit in MIS will be set + 0x1 + + + + + FIFOFULLIFG + Masks FIFOFULLIFG + 0x8 + 0x1 + + + CLR + Interrupt is masked out + 0x0 + + + SET + Interrupt will request an interrupt service routine and + corresponding bit in MIS will be set + 0x1 + + + + + FIFOURUNIFG + Masks FIFOURUNIFG + 0xD + 0x1 + + + CLR + Interrupt is masked out + 0x0 + + + SET + Interrupt will request an interrupt service routine and + corresponding bit in MIS will be set + 0x1 + + + + + DMADONEIFG + Masks DMADONEIFG + 0xE + 0x1 + + + CLR + Interrupt is masked out + 0x0 + + + SET + Interrupt will request an interrupt service routine and + corresponding bit in MIS will be set + 0x1 + + + + + + + + + + CRC + CRC + 1.0 + PERIPHERALREGION + 0x40440000 + + 0x0 + 0x2000 + registers + + + + 1 + 24 + 0 + TEST_CLUSTER_WITH_REG_ARRAY_MEMBER[%s] + + 0x800 + + CRC_PWREN + Power enable + 0x0 + 32 + read-write + 0x00000000 + + + ENABLE + Enable the power + 0x0 + 0x1 + read-write + + + DISABLE + Disable Power + 0x0 + + + ENABLE + Enable Power + 0x1 + + + + + + + 512 + 4 + + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511 + TEST_REGISTER_ARRAY_IN_CLUSTER_%s + CRC Input Data Array Register + 0x1800 + 32 + write-only + 0x00000000 + 0xffffffff + + + DATA + Input Data + 0x0 + 0x20 + write-only + + + + + + diff --git a/res/expand_cluster/patch.yml b/res/expand_cluster/patch.yml index 36d45746..e3f282e0 100644 --- a/res/expand_cluster/patch.yml +++ b/res/expand_cluster/patch.yml @@ -2,6 +2,23 @@ _svd: "./mspm0g350x.svd" # Alter top-level information and peripherals for this device "GPIO*": - _expand_cluster: - - "GPIO?_GPRCM*" _strip: "GPIO?_" + _clusters: + "*": + _strip: "GPIO?_" + _expand_cluster: + GPRCM*: + _preindex: "_" + _postindex: "_" + _zeroindex: false + _noprefix: true + TEST_CLUSTER*: + +"DAC*": + _strip: "DAC?_" + _clusters: + "INT_EVENT*": + _strip: "DAC?_" + _expand_cluster: + - "?~missing_cluster" + - "INT_EVENT*" diff --git a/src/patch/peripheral.rs b/src/patch/peripheral.rs index edbedc5e..a5f8cd4a 100644 --- a/src/patch/peripheral.rs +++ b/src/patch/peripheral.rs @@ -182,13 +182,24 @@ pub(crate) trait RegisterBlockExt: Name { } } - /// Delete clusters matched by cspec inside ptag fn delete_cluster(&mut self, cspec: &str) -> PatchResult { + let (cspec, ignore) = cspec.spec(); + if let Some(children) = self.children_mut() { - children.retain( - |rc| !matches!(rc, RegisterCluster::Cluster(c) if matchname(&c.name, cspec)), - ); - Ok(()) + let mut deleted = false; + children.retain(|rc| { + let retain = + !matches!(rc, RegisterCluster::Cluster(c) if matchname(&c.name, cspec)); + if !retain { + deleted = true; + } + retain + }); + if !deleted && !ignore { + Err(anyhow!("No matching clusters found")) + } else { + Ok(()) + } } else { Err(anyhow!("No registers or clusters")) } @@ -468,6 +479,21 @@ pub(crate) trait RegisterBlockExt: Name { } } } + for ctag in self.clstrs_mut() { + if glob.is_match(&ctag.name) { + ctag.name.drain(..len); + } + if let Some(dname) = ctag.header_struct_name.as_mut() { + if glob.is_match(dname.as_str()) { + dname.drain(..len); + } + } + if let Some(name) = ctag.alternate_cluster.as_mut() { + if glob.is_match(name.as_str()) { + name.drain(..len); + } + } + } Ok(()) } @@ -495,6 +521,24 @@ pub(crate) trait RegisterBlockExt: Name { } } } + for ctag in self.clstrs_mut() { + if glob.is_match(&ctag.name) { + let nlen = ctag.name.len(); + ctag.name.truncate(nlen - len); + } + if let Some(dname) = ctag.header_struct_name.as_mut() { + if glob.is_match(dname.as_str()) { + let nlen = dname.len(); + dname.truncate(nlen - len); + } + } + if let Some(name) = ctag.alternate_cluster.as_mut() { + if glob.is_match(name.as_str()) { + let nlen = name.len(); + name.truncate(nlen - len); + } + } + } Ok(()) } @@ -516,70 +560,229 @@ pub(crate) trait RegisterBlockExt: Name { fn get_cluster_registers( &self, cspec: &str, - bpath: &BlockPath, - ) -> anyhow::Result)>> { - // ) -> anyhow::Result<(Vec, ClusterInfo)> { - let (cspec, ignore) = cspec.spec(); - println!("Expanding cluster {0}", cspec); - - let present = self.present_clusters().clone(); - Ok(self - .clstrs() - .matched(cspec) - .map(|ctag| { - let regs = ctag - .clone() - .all_registers() - .map(|reg| { - RegisterCluster::Register(::clone(reg).single()) - }) - .collect::>(); - if regs.is_empty() && !ignore { - return Err(anyhow!( - "Could not find cluster `{bpath}:{cspec}. Present clusters: {present}.`" - )); + ) -> Vec<(&ClusterInfo, DimElement, Vec)> { + let (cspec, _) = cspec.spec(); + self.clstrs() + .filter(|ctag| matchname(&ctag.name, cspec)) + .filter_map(|ctag| match ctag.clone() { + svd_rs::MaybeArray::Array(cluster, dim) => { + let mut clusters_and_registers = cluster + .registers() + .map(|reg| reg.clone().into()) + .collect::>(); + clusters_and_registers.extend( + cluster + .clusters() + .map(|reg| reg.clone().into()) + .collect::>(), + ); + Some((std::ops::Deref::deref(ctag), dim, clusters_and_registers)) } - Ok((std::ops::Deref::deref(ctag), regs)) + _ => None, }) - .flatten() - .collect::>()) + .collect::>() } - /// Expand register cluster - fn expand_cluster(&mut self, cspec: &str, bpath: &BlockPath) -> PatchResult { - let mut info_and_regs = Vec::new(); + /// Expand register cluster + fn expand_cluster( + &mut self, + cspec: &str, + bpath: &BlockPath, + pre_index_delim: Option<&str>, + post_index_delim: Option<&str>, + zeroindex: Option, + noprefix: Option, + ) -> PatchResult { + let mut clusters_to_expand_with_info = Vec::new(); let mut clusters_to_delete = Vec::new(); + + let (_, ignore) = cspec.spec(); + // some fancy footwork to satisfy the borrow checker gods - for (ci, rc) in self.get_cluster_registers(cspec, bpath)? { + let cluster_data = self.get_cluster_registers(cspec); + if cluster_data.is_empty() && !ignore { + let present = self.present_clusters().clone(); + return Err(anyhow!( + "Could not find cluster `{bpath}:{cspec}. Present clusters: {present}.`" + )); + } + + for (ci, dim, rc) in cluster_data { let mut regs = Vec::new(); for reg in rc { regs.push(::clone(®)); } - info_and_regs.push((ci.clone(), regs)); + clusters_to_expand_with_info.push((ci.clone(), dim, regs)); } if let Some(regs) = self.children_mut() { - for (_cinfo, cluster_registers) in info_and_regs { + for (ctag, dim, cluster_registers) in clusters_to_expand_with_info.clone() { let mut found = false; - for reg in cluster_registers { - found = true; - println!("Adding register {0}", reg.name()); - regs.push(reg.clone()) + let cluster_offset = ctag.address_offset; + log::info!( + "Expanding {} element cluster {} for peripheral {}", + dim.dim, + ctag.name, + bpath + ); + // iterate through each dim to expand each dim of a cluster + for n_dim in 0..dim.dim { + let prefix = Self::expand_cluster_register_name_prefix( + n_dim, + ctag.clone(), + bpath, + dim.clone(), + pre_index_delim, + post_index_delim, + zeroindex, + noprefix, + )?; + for reg in cluster_registers.clone() { + let reg = match reg { + RegisterCluster::Register(mut register) => { + register.address_offset += cluster_offset; + register.address_offset += n_dim * dim.dim_increment; + register.name = format!("{}{}", prefix, register.name); + RegisterCluster::Register(register) + } + RegisterCluster::Cluster(mut cluster) => { + cluster.address_offset += cluster_offset; + cluster.address_offset += n_dim * dim.dim_increment; + cluster.name = format!("{}{}", prefix, cluster.name); + RegisterCluster::Cluster(cluster) + } + }; + found = true; + log::info!( + "Adding register at offset 0x{:08x}: {}", + reg.address_offset(), + reg.name(), + ); + regs.push(reg.clone()) + } } if !found { return Err(anyhow!("No registers found in cluster {:?}", cspec)); } else { - clusters_to_delete.push(cspec) + clusters_to_delete.push(ctag.name); } } - } - for cspec in clusters_to_delete { - self.delete_cluster(cspec) - .with_context(|| format!("Deleting clusters matched to `{cspec}`"))?; - } + } else { + return Err(anyhow!("No registers or clusters")); + }; + + self.delete_cluster(cspec) + .with_context(|| format!("Deleting clusters matched to `{cspec}`"))?; + Ok(()) } + /// get the prefix to apply to a register name in a cluster that is being expanded + #[allow(clippy::too_many_arguments)] + fn expand_cluster_register_name_prefix( + n_dim: u32, + ctag: ClusterInfo, + bpath: &BlockPath, + dim: DimElement, + pre_index_delim: Option<&str>, + post_index_delim: Option<&str>, + zeroindex: Option, + noprefix: Option, + ) -> anyhow::Result { + let pre_index_delim = pre_index_delim.unwrap_or("_").to_string(); + let post_index_delim = post_index_delim.unwrap_or("_").to_string(); + + let has_bracket_delim = ctag.name.find(r#"[%s]"#); + let has_nobracket_delim = ctag.name.find(r#"[%s]"#); + let prefix = if dim.dim > 1 || matches!(zeroindex, Some(true)) { + if let Some(true) = noprefix { + return Err(anyhow!( + "Cannot expand cluster {}:{} with multiple elements with noprefix", + bpath, + ctag.name + )); + } + match ( + dim.dim_index.clone(), + has_bracket_delim, + has_nobracket_delim, + ) { + (Some(_), Some(_), _) => { + return Err(anyhow!("Cannot expand cluster {}:{} with multiple elements that uses dim_index and [%s] substitution https://open-cmsis-pack.github.io/svd-spec/main/elem_registers.html", bpath, ctag.name)); + } + (Some(dim_index), None, Some(_)) => { + if dim_index.len() != dim.dim as usize { + return Err(anyhow!("Cannot expand cluster {}:{} with multiple elements that has a dim_index with a number of elements unequal to dim length. _modify cluster dim or index before expanding cluster", bpath, ctag.name)); + } else { + format!( + "{}{}", + &ctag.name.replace( + "%s", + &format!( + "{}{}", + pre_index_delim, + &dim_index[n_dim as usize].to_string() + ) + ), + post_index_delim + ) + } + } + (Some(dim_index), None, None) => { + if dim_index.len() != dim.dim as usize { + return Err(anyhow!("Cannot expand cluster {}:{} with multiple elements that has a dim_index with a number of elements unequal to dim length. _modify cluster dim or index before expanding cluster ", bpath, ctag.name)); + } else { + format!( + "{}{}", + &ctag.name.replace( + r#"%s"#, + &format!( + "{}{}", + pre_index_delim, + &dim_index[n_dim as usize].to_string() + ) + ), + post_index_delim + ) + } + } + (None, Some(_), _) => { + format!( + "{}{}", + &ctag.name.replace( + r#"[%s]"#, + &format!("{}{}", pre_index_delim, &n_dim.to_string()) + ), + post_index_delim + ) + } + (None, None, _) => { + format!( + "{}{}{}{}", + ctag.name, pre_index_delim, n_dim, post_index_delim + ) + } + } + } else { + if let Some(true) = noprefix { + return Ok("".to_string()); + } + // the cluster is a single element and zeroindex is false, so we will skip adding an index + match (has_bracket_delim, has_nobracket_delim) { + (Some(_), _) => { + format!("{}{}", &ctag.name.replace(r#"[%s]"#, ""), post_index_delim) + } + (None, Some(_)) => { + format!("{}{}", &ctag.name.replace(r#"%s"#, ""), post_index_delim) + } + (None, None) => { + format!("{}{}", &ctag.name, post_index_delim) + } + } + }; + Ok(prefix) + } + /// Expand register array fn expand_array(&mut self, rspec: &str, _rmod: &Hash, _config: &Config) -> PatchResult { if let Some(regs) = self.children_mut() { @@ -816,27 +1019,6 @@ impl PeripheralExt for Peripheral { } } - if let Some(expand_cluster) = pmod.get_yaml("_expand_cluster") { - match expand_cluster { - Yaml::String(cspec) => { - self.expand_cluster(cspec, &ppath) - .with_context(|| format!("During expand of `{cspec}` cluster"))?; - } - Yaml::Array(clusters) => { - for cspec in clusters { - let cspec = cspec.str()?; - self.expand_cluster(cspec, &ppath) - .with_context(|| format!("During expand of `{cspec}` cluster"))?; - } - } - _ => { - return Err(anyhow!( - "`_expand_cluster` requires string value or array of strings" - )) - } - } - } - // Handle any copied peripherals for (rname, rcopy) in pmod.hash_iter("_copy") { let rname = rname.str()?; @@ -977,7 +1159,6 @@ impl PeripheralExt for Peripheral { // Handle registers or clusters for (rcspec, rcmod) in pmod { let rcspec = rcspec.str()?; - println!("Processing {0}", rcspec); if Self::KEYWORDS.contains(&rcspec) { continue; } @@ -1012,6 +1193,57 @@ impl PeripheralExt for Peripheral { .with_context(|| format!("According to `{cspec}`"))?; } + // Handle cluster expansions + if let Some(expand_cluster) = pmod.get_yaml("_expand_cluster") { + match expand_cluster { + Yaml::String(cspec) => { + self.expand_cluster(cspec, &ppath, None, None, None, None) + .with_context(|| format!("During expand of `{cspec}` cluster"))?; + } + Yaml::Array(cspec) => { + for cname in cspec { + let cname = cname.str()?; + self.expand_cluster(cname, &ppath, None, None, None, None) + .with_context(|| format!("During expand of `{cname}` cluster"))?; + } + } + Yaml::Hash(cspec) => { + for (cname, cspec) in cspec { + let cspec = cspec.hash().ok(); + let cname = cname.str()?; + let mut preindex = None; + let mut postindex = None; + let mut zeroindex = None; + let mut noprefix = None; + if let Some(cspec) = cspec { + for (key, val) in cspec { + match key.str()? { + "_preindex" => preindex = Some(val.str()?), + "_postindex" => postindex = Some(val.str()?), + "_zeroindex" => zeroindex = Some(val.bool()?), + "_noprefix" => noprefix = Some(val.bool()?), + _ => { + return Err(anyhow!( + "`_expand_cluster` requires string value or array of strings" + )) + } + } + } + }; + self.expand_cluster( + cname, &ppath, preindex, postindex, zeroindex, noprefix, + ) + .with_context(|| format!("During expand of `{cname}` cluster"))?; + } + } + _ => { + return Err(anyhow!( + "`_expand_cluster` requires string value or array of strings" + )) + } + } + } + Ok(()) } } @@ -1242,7 +1474,6 @@ impl ClusterExt for Cluster { .with_context(|| format!("According to `{rcspec}`"))?; } - println!("post process"); self.post_process(cmod, parent, config) } @@ -1594,7 +1825,6 @@ fn collect_in_cluster( ) }; cluster.pre_process(cmod, path, &config)?; - println!("cluster post process"); cluster.post_process(cmod, path, &config)?; regs.insert(place, RegisterCluster::Cluster(cluster)); Ok(()) diff --git a/src/patch/yaml_ext.rs b/src/patch/yaml_ext.rs index c4ae7ff1..3bbb0d7d 100644 --- a/src/patch/yaml_ext.rs +++ b/src/patch/yaml_ext.rs @@ -208,10 +208,16 @@ pub trait GetVal { } } fn str_vec_iter<'a>(&'a self, k: &str) -> Result>> { - Ok(OptIter::new(match self.get_yaml(k) { + let yaml = self.get_yaml(k); + Ok(OptIter::new(match yaml { None => None, - Some(y) if matches!(y, Yaml::String(_) | Yaml::Array(_)) => { - Some(OverStringIter(y, None)) + Some(Yaml::String(_)) => Some(OverStringIter(yaml.unwrap(), None)), + Some(Yaml::Array(y)) => { + if y.iter().all(|x| x.as_str().is_some()) { + Some(OverStringIter(yaml.unwrap(), None)) + } else { + return Err(anyhow!("`{k}` requires string value or array of strings")); + } } _ => return Err(anyhow!("`{k}` requires string value or array of strings")), })) @@ -224,3 +230,78 @@ impl GetVal for Hash { self.get(&k.to_yaml()) } } + +#[cfg(test)] +mod tests { + use crate::patch::yaml_ext::GetVal; + use yaml_rust::YamlLoader; + + #[test] + fn test_str_vec_iter_string_value() { + let yaml_str = r#" + key: "value" + "#; + let docs = YamlLoader::load_from_str(yaml_str).unwrap(); + let hash = docs[0].as_hash().unwrap(); + + let result = hash.str_vec_iter("key"); + assert!(result.is_ok()); + let mut iter = result.unwrap(); + assert_eq!(iter.next().unwrap(), "value"); + assert!(iter.next().is_none()); + } + + #[test] + fn test_str_vec_iter_array_of_strings() { + let yaml_str = r#" + key: ["value1", "value2", "value3"] + "#; + let docs = YamlLoader::load_from_str(yaml_str).unwrap(); + let hash = docs[0].as_hash().unwrap(); + + let result = hash.str_vec_iter("key"); + assert!(result.is_ok()); + let mut iter = result.unwrap(); + assert_eq!(iter.next().unwrap(), "value1"); + assert_eq!(iter.next().unwrap(), "value2"); + assert_eq!(iter.next().unwrap(), "value3"); + assert!(iter.next().is_none()); + } + + #[test] + fn test_str_vec_iter_invalid_type() { + let yaml_str = r#" + key: 123 + "#; + let docs = YamlLoader::load_from_str(yaml_str).unwrap(); + let hash = docs[0].as_hash().unwrap(); + + let result = hash.str_vec_iter("key"); + assert!(result.is_err()); + } + + #[test] + fn test_str_vec_iter_hash_type() { + let yaml_str = r#" + key: + subkey: "value" + "#; + let docs = YamlLoader::load_from_str(yaml_str).unwrap(); + let hash = docs[0].as_hash().unwrap(); + + let result = hash.str_vec_iter("key"); + assert!(result.is_err()); + } + + #[test] + fn test_str_vec_iter_array_with_hash() { + let yaml_str = r#" + key: ["value1", "value2", {subkey: "value"}] + "#; + let docs = YamlLoader::load_from_str(yaml_str).unwrap(); + let hash = docs[0].as_hash().unwrap(); + + let result = hash.str_vec_iter("key"); + assert!(result.is_err()); + } +}