Skip to content

Register array in RegisterBlock #121

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Sep 20, 2017

Conversation

kjetilkjeka
Copy link
Contributor

I guess this pull request is dropping a bit out of the sky, but I realized I needed the feature sooner rather than later so decided to just go for it. When it's merged it should fix #114

Some refactoring was done to allow for integration register arrays, the most significant are

  • expand function only takes 1 register instead of slice. This means that the function has to be called for every register that should be expanded. This was done so a register can be conditionaly expanded depending on if it's possible to convert to a Rust array or not.
  • register_to_rust method was factored out from register_block. Mainly so register block wouldn't grow very large with lots of nested control flow.
  • ExpandedRegister was removed, the functions only use Register struct now. This was because if not it would require conversion functions when registers was not expanded. The struct would also need changing as it would only have to support arrays.
  • Since the ExpandedRegisters was dropped the expand function now writes %s(i) (where i is the index) to the names of the expanded registers. This is used later on to resolve name and type.
  • regex is a dependecy, this is used to replace %s(i) with the index. Adding this dependecy might not be desired? and if not I can reimplement it with some logic that iterates over the string.

I've tested with S32K144.svd and it seems to work perfectly with that file.

As mentioned in #114 i do hope that the method of using svd array information instead of unrolling arrays after is acceptable.

@kjetilkjeka kjetilkjeka changed the title Field array Register array in RegisterBlock Jul 5, 2017
@kjetilkjeka
Copy link
Contributor Author

Also have a look at line 399 at generate.rs

I guess that is only valid as long as there are 4 byte (32 bit) registers. However I'm not sure how it can be generalized over register lengths?

Copy link
Member

@japaric japaric left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR, @kjetilkjeka.

It seems reasonable to only translate register arrays to a Rust array in the case of compact (no hole) arrays.

I left several comments about the implementation.

I guess that is only valid as long as there are 4 byte (32 bit) registers. However I'm not sure how it can be generalized over register lengths?

I did not understand this constraint. Why are 4 byte registers special here? Shouldn't the check be register.size == dim_increment? That would check if each array element has reserved space apart from the rergister.

src/generate.rs Outdated
let mut previous = 0;

let get_number_option = |element_option: Option<&String>| -> Option<usize> {element_option
.and_then(|element| match element.parse::<usize>() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this match element.parse() is equivalent to element.parse().ok()

src/generate.rs Outdated
})
};

let mut index_convertible_temp = match get_number_option(index_iter.next()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this match is equivalent to LHS == Some(0)

src/generate.rs Outdated
for element in index_iter {
if !index_convertible_temp { break; }

index_convertible_temp = match get_number_option(Some(element)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this get_number_option(Some(element)) would be simpler as element.parse().ok()

src/generate.rs Outdated
for element in index_iter {
if !index_convertible_temp { break; }

index_convertible_temp = match get_number_option(Some(element)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the match can probably be replaced by LHS == Some(previous + 1)

src/generate.rs Outdated
match *register {
Register::Single(ref _into) => registers_expanded.push(register.clone()),
Register::Array(ref _into, ref array_info) => {
let index_convertible = if let Some(ref indexes) = array_info.dim_index {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a comment about what this does? It wasn't entirely clear from reading the contents. Is it checking that indexes == 0..info.dim? In that case this may be simpler to write this as indexes.iter().eq(0..info.dim).

src/util.rs Outdated
out
}


pub fn sort_by_offset(mut registers: Vec<Register>) -> Vec<Register> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this routine is complex enough that should be a function.

src/util.rs Outdated
/// the register arrays have been expanded.
pub fn expand(registers: &[Register]) -> Vec<ExpandedRegister> {
/// and turn in into alist of registers where the register arrays have been expanded.
pub fn expand(register: &Register) -> Vec<Register> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that this will now only be used with Register::Array it may be better not to pass &Register but rather the contens of the Register::Array variant

src/util.rs Outdated
info.name.replace("[%s]", "")
for (idx, i) in indices.iter().zip(0..) {
let name = if has_brackets {
info.name.replace("[%s]", format!("%s({})", idx).as_str())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we want to keep the "%s" in this stage? Is it going to be used afterwards? Why not just directly replace it with the formatted idx at this point?

src/util.rs Outdated
} else {
info.name.replace("%s", "")
info.name.replace("%s", format!("%s({})", idx).as_str())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same question as above

src/generate.rs Outdated
|| {
format!("Register {} has no `size` field", register.name)
},
)? * array_info.dim / 8,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I know that it's unrelated to this PR but could you replace the 8 by a BITS_PER_BYTE constant?

@kjetilkjeka
Copy link
Contributor Author

I agree that %s(N) is hacky. But the ExpandedRegister didn't work either as there was no support for array. I made a new struct extending syn::Field (by composition) adding size, offset and description. This makes perfect sense in my head as we're converting from svd::Register to rust fields (which syn::Field represents). Another bonus is the ability to use to_tokens instead of formating manually. Hope you agree with this reasoning? This made some refactoring necessary inside util but I think it makes more sense as it is now.

I guess that is only valid as long as there are 4 byte (32 bit) registers. However I'm not sure how it can be generalized over register lengths?

I did not understand this constraint. Why are 4 byte registers special here? Shouldn't the check be register.size == dim_increment? That would check if each array element has reserved space apart from the rergiste

You're not suppose to understand that, was just me beeing stupid. Should be fixed now.

Most of your comments were considering the conditions for expanding. I've cleaned them up a whole lot. I think it's readable to the point making more comment than the one outside the function unnecessary. But since I wrote the code 2 hours ago I'm quite biased, say if you still want me to add a comment there.

I think I've addressed all the issues you mentioned except "Given that this will now only be used with Register::Array it may be better not to pass &Register but rather the contens of the Register::Array variant". I was a bit reluctant to change this out because:
-The similar function pub fn convert_svd_register(register: &svd::Register) -> syn::Field is used with svd::Register making my mental model of how to use these functions more consistent

  • That expanding a Single register is allowed and gives exactly one registers makes sense (atleast in my head)
  • One more argument gives the ability to make logic errors by passing non corresponding info and array_info
    Anyway It's not a big deal but just think about it, if you still want it changed after, no problem.

@homunkulus
Copy link
Contributor

☔ The latest upstream changes (presumably c7aed0a) made this pull request unmergeable. Please resolve the merge conflicts.

@kjetilkjeka
Copy link
Contributor Author

Rebase onto japaric/master to resolve merge conflicts and include bare_metal features

@homunkulus
Copy link
Contributor

☔ The latest upstream changes (presumably 82ebef2) made this pull request unmergeable. Please resolve the merge conflicts.

…llable on single registers instead of the whole slice
…ly contains numeric indexes and it starts on 0 and contains every element in the range. Then it is convertable to a rust array
… of spliting on [ had a bug when the index was in the middle of the name.
…ork on the new struct RegisterBlockField. Instead of creating a brand new type representing a rust field it's an extension (by composition) of the syn::Field to also give information about offset, size and description. This means that the util extend function now extend to a vector of syn::Field.
… array is that it's packed in memory, not that fields are 32 bits
@kjetilkjeka
Copy link
Contributor Author

Rebased onto 0.11.1 to make mergeable

@kjetilkjeka
Copy link
Contributor Author

@japaric What's the status on svd2rust at them moment? Now that the bare metal changes are adopted will this PR be next in line or should I expect others merged before it?

@kjetilkjeka
Copy link
Contributor Author

@japaric I guess you didn't have the time to look at this PR last time we talked about it.

Do you have an updated estimate of when you will be able to review this PR?

Copy link
Member

@japaric japaric left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for taking so long to come back to this.

I've requested two changes: one is required to have svd2rust not regress in terms of documentation rendering. Please fix them and I'll merge this.

Do you know if any of the devices in the test suite is exercising this change? If none is could you add your SVD file to the test suite?

src/generate.rs Outdated
@@ -461,69 +460,135 @@ pub fn peripheral(
Ok(())
}

struct RegisterBlockField {
field: syn::Field,
description: Ident,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a identifier; it should be a String.

src/generate.rs Outdated
i += 1;
}

let comment = &format!(
"0x{:02x} - {}",
register.offset,
util::respace(&register.info.description)
register.description,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please revert this change or the documentation will have random newlines in it. As in: keep the util::respace.

@kjetilkjeka
Copy link
Contributor Author

Thank you for the review @japaric

I've requested two changes: one is required to have svd2rust not regress in terms of documentation rendering. Please fix them and I'll merge this.

This should be fixed now.

Do you know if any of the devices in the test suite is exercising this change? If none is could you add your SVD file to the test suite?

MK02F12810.svd should exercise this change (amongst other) for this register.

    <register>
      <dim>8</dim>
      <dimIncrement>0x4</dimIncrement>
      <dimIndex>0,1,2,3,4,5,6,7</dimIndex>
      <name>TAGVDW0S%s</name>
      <description>Cache Tag Storage</description>
      <addressOffset>0x100</addressOffset>
      <size>32</size>
      <access>read-write</access>
      <resetValue>0</resetValue>
      <resetMask>0xFFFFFFFF</resetMask>
      <fields>
        <field>
          <name>valid</name>
          <description>1-bit valid for cache entry</description>
          <bitOffset>0</bitOffset>
          <bitWidth>1</bitWidth>
          <access>read-write</access>
        </field>
        <field>
          <name>tag</name>
          <description>14-bit tag for cache entry</description>
          <bitOffset>5</bitOffset>
          <bitWidth>14</bitWidth>
          <access>read-write</access>
        </field>
      </fields>
    </register>
    <register>

The diff for this register (between kjetilkjeka/svd2rust/master and kjetilkjeka/svd2rust/field_array) looks like the following:

12303c12303,12317
<         pub tagvdw0s: [TAGVDW0S; 8],
---
>         pub tagvdw0s0: TAGVDW0S,
>         #[doc = "0x104 - Cache Tag Storage"]
>         pub tagvdw0s1: TAGVDW0S,
>         #[doc = "0x108 - Cache Tag Storage"]
>         pub tagvdw0s2: TAGVDW0S,
>         #[doc = "0x10c - Cache Tag Storage"]
>         pub tagvdw0s3: TAGVDW0S,
>         #[doc = "0x110 - Cache Tag Storage"]
>         pub tagvdw0s4: TAGVDW0S,
>         #[doc = "0x114 - Cache Tag Storage"]
>         pub tagvdw0s5: TAGVDW0S,
>         #[doc = "0x118 - Cache Tag Storage"]
>         pub tagvdw0s6: TAGVDW0S,
>         #[doc = "0x11c - Cache Tag Storage"]
>         pub tagvdw0s7: TAGVDW0S,

This means that the doc string is the same as it used to be for tagvdw0s0. "#[doc = 0x100 - Cache Tag Storage]"

I've also manually inspected the other registers in this file where the new code path is exercised and they are equivalent to the previous example.

The previous example is also equivalent to the .svd file I tested during devlopment S32K144.svd

I can, of course, manually inspect more files? But I've also tested it with the different (allowed) uses of dimIncrement and dimIndex manually. So I believe the next step should be to confirm that all the .svd files in the test suite will be compiled without error.

@japaric
Copy link
Member

japaric commented Sep 19, 2017

Thanks, @kjetilkjeka.

@homunkulus r+

@homunkulus
Copy link
Contributor

📌 Commit 52cf267 has been approved by japaric

@homunkulus
Copy link
Contributor

⌛ Testing commit 52cf267 with merge 1f3542f...

japaric pushed a commit that referenced this pull request Sep 19, 2017
Register array in RegisterBlock

I guess this pull request is dropping a bit out of the sky, but I realized I needed the feature sooner rather than later so decided to just go for it. When it's merged it should fix #114

Some refactoring was done to allow for integration register arrays, the most significant are
- expand function only takes 1 register instead of slice. This means that the function has to be called for every register that should be expanded. This was done so a register can be conditionaly expanded depending on if it's possible to convert to a Rust array or not.
- register_to_rust method was factored out from register_block. Mainly so register block wouldn't grow very large with lots of nested control flow.
- ExpandedRegister was removed, the functions only use Register struct now. This was because if not it would require conversion functions when registers was not expanded. The struct would also need changing as it would only have to support arrays.
- Since the ExpandedRegisters was dropped the expand function now writes ```%s(i)``` (where i is the index) to the names of the expanded registers. This is used later on to resolve name and type.
- regex is a dependecy, this is used to replace ```%s(i)``` with the index. Adding this dependecy might not be desired? and if not I can reimplement it with some logic that iterates over the string.

I've tested with [S32K144.svd](https://github.com/kjetilkjeka/s32k144.rs/blob/master/src/S32K144.svd) and it seems to work perfectly with that file.

As mentioned in #114 i do hope that the method of using svd array information instead of unrolling arrays after is acceptable.
@homunkulus
Copy link
Contributor

☀️ Test successful - status-appveyor, status-travis
Approved by: japaric
Pushing 1f3542f to master...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Merge registers with the same type into an array
3 participants