Skip to content
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

riscv: add CSR-defining macros #219

Merged
merged 19 commits into from
Oct 18, 2024

Conversation

rmsyn
Copy link
Contributor

@rmsyn rmsyn commented May 30, 2024

Adds helper macros for defining CSR types:

  • read-write:
    • have both getter and setter methods
    • able to read and write the CSR
  • read-only:
    • only has getter methods
    • able to read the CSR
  • write-only:
    • only has setter methods
    • able to write the CSR

Related to: #218

@rmsyn rmsyn requested a review from a team as a code owner May 30, 2024 03:59
@rmsyn rmsyn force-pushed the riscv/csr-macro branch from df39d4e to fd163b1 Compare May 30, 2024 04:07
Comment on lines 1 to 25
read_write_csr! {
"test CSR register type",
Mtest: 0x000,
0b1111_1111,
"test single-bit field",
single: 0,
"setter test single-bit field",
set_single: 0,
}

read_write_csr_field! {
Mtest,
"multiple single-bit field range",
multi_range: 1..=3,
"setter multiple single-bit field range",
set_multi_range: 1..=3,
}

read_write_csr_field!(
Mtest,
"multi-bit field",
multi_field: [4:7],
"setter multi-bit field",
set_multi_field: [4:7],
);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Test calls to the new macros. The above is just a basic compile test.

Still need to add unit tests, and macro calls for the read-only and write-only variants.

@romancardenas
Copy link
Contributor

Thanks! I'll review it ASAP

Copy link
Contributor

@romancardenas romancardenas left a comment

Choose a reason for hiding this comment

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

Kind of like it! the mask idea is very nice. I miss two main things:

  • Less repetition in macros. Maybe we could atomize them and leave one "core" macro that creates the struct with bitmask and from_bits/bits, another for the get/set...
  • Using custom types (mainly enums) for setters and getters. That would be awesome (for example XLEN

riscv/src/register/macros.rs Outdated Show resolved Hide resolved
Comment on lines 407 to 736
macro_rules! read_write_csr {
($doc:expr,
$ty:ident: $csr:tt,
$mask:tt,
$(
$field_doc:expr,
$field:ident: $get_bit:literal,
$set_field_doc:expr,
$set_field:ident: $set_bit:literal$(,)?
)+) => {
$crate::read_write_csr!($doc, $ty: $csr, $mask);

$(
$crate::read_write_csr_field!(
$ty,
$field_doc,
$field: $get_bit,
$set_field_doc,
$set_field: $set_bit,
);
)+
};
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Less repetition in macros. Maybe we could atomize them and leave one "core" macro that creates the struct with bitmask and from_bits/bits, another for the get/set...

That's essentially what is there, each of the branches for the various ways to call [read,write]_[only,write]_csr call the internal branch for creating the struct.

Then, the repeated part (in the $(...)+) creates the getters/setters. I guess we could also make read_write_csr_field into another branch of the macro...

Other than that, I'm not sure exactly what you're asking for. What changes would you like to see?

Copy link
Contributor

Choose a reason for hiding this comment

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

What I mean is that, for example, this part of the macro where the register struct is defined appears three times. It would be nice to have it somehow just once in a separate, basic macro and, depending on the macro branches, call this macro

Copy link
Contributor Author

@rmsyn rmsyn Jun 6, 2024

Choose a reason for hiding this comment

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

Ah, I see what you mean. Because each of the macros has this helper branch, make it into its own macro that each one could call.

Alright, I'll work on separating it out. Maybe with a note that you can, but probably don't want to, call this helper macro on its own.

Edit: I added the changes as a fixup commit for easier review. If you like the approach, I'll squash the commit into the previous one.

@rmsyn
Copy link
Contributor Author

rmsyn commented Jun 4, 2024

Using custom types (mainly enums) for setters and getters.

We could add another branch that takes an $var_ty: ident, [$($variant:ident, $variant_val:literal),*]$(,). That would allow to define a custom enum type, and use that enum in the getters/setters.

I can try to work something out.

@rmsyn rmsyn force-pushed the riscv/csr-macro branch from fd163b1 to 37b9403 Compare June 6, 2024 01:23
@rmsyn
Copy link
Contributor Author

rmsyn commented Jun 6, 2024

I can try to work something out.

I added the enum branches, and an extra helper macro.

Let me know what you think.

@romancardenas
Copy link
Contributor

@rmsyn I'm on it, but macros are difficult to review... 😥

Looks great. The only thing now is that I prefer to leave some macros out of the equation, and then let us call the proper sequence of macros according to the CSR. I think this will help us in the future to deal with macros (modular vs monolithic).

Regarding from and into: if we can get help from From and TryFrom traits, I'd go for them instead of maintaining repetitive methods.

Great job!! I'll keep studying all your code 😁

riscv/src/register/macros.rs Outdated Show resolved Hide resolved
Comment on lines 503 to 505
$field:ident: $get_bit:literal,
$set_field_doc:expr,
$set_field:ident: $set_bit:literal$(,)?
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Another thing I would like your opinion on @romancardenas, do you think there are use-cases where users would want to define different bits for the get and set functions?

I couldn't really think of a place where this would be a good idea, so maybe the bit argument could be a single parameter?

Same idea for the range and multi-bit variants.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think these macros should work in the general use cases (i.e., the same bits for getters and setters). For particular cases, we can always just implement them by hand.

@rmsyn
Copy link
Contributor Author

rmsyn commented Sep 14, 2024

Updated the changes onto the latest HEAD commit.

Squashed the previous fixup commit to simplify review.

Added the necessary changes to incorporate the addition of fallible functions, and changed the doc-string arguments.

Let me know if you like the changes.

I still think the bit-field and bit-range macro arguments could be simpler, especially now with four versions of essentially the same macro argument (e.g. $field, $try_field, $set_field, $try_set_field).

Currently, it feels like having the user supply the same argument past the colon all four times is a potential footgun.

Instead, we could change the $field: $field_bit to $field for all four variants, and add a single $bit_arg: $bit at tthe end. Thoughts?

@rmsyn
Copy link
Contributor Author

rmsyn commented Sep 15, 2024

@romancardenas I added some more fixes + improvements to the macro helpers. Reduced some redundancy, and hopefully made the macro invocations more readable.

Please let me know what you think.

More or less, this PR is probably pretty close to "finished"(tm).

Let me know if there are any more changes you would like to see.

@romancardenas
Copy link
Contributor

I'll try to review this later today. Thanks!

@romancardenas
Copy link
Contributor

Looks good, but it is true that having to do something like:

    field: {
        /// Gets the `cycle[h]` inhibit field value.
        cy,
        /// Attempts to get the `cycle[h]` inhibit field value.
        try_cy,
        /// Sets the `cycle[h]` inhibit field value.
        ///
        /// **NOTE**: only updates the in-memory value without touching the CSR.
        set_cy,
        /// Attempts to set the `cycle[h]` inhibit field value.
        ///
        /// **NOTE**: only updates the in-memory value without touching the CSR.
        try_set_cy,
        bit: 0,
    },

is perhaps too verbose. Can't we do something like:

field: {
        /// `cycle[h]` inhibit field value
        cy,
        bit: 0,
    },

And then generate the same code? Just following the try and set notation.

Also, I feel like there are a lot of branches with similar code. Can't we simplify the macros using recursive calls that match patterns, consuming part of the tokens? I think in this way we would have simpler pattern matching and less duplicates.

@rmsyn
Copy link
Contributor Author

rmsyn commented Sep 18, 2024

Looks good, but it is true that having to do something like:

    field: {
        /// Gets the `cycle[h]` inhibit field value.
        cy,
        /// Attempts to get the `cycle[h]` inhibit field value.
        try_cy,
        /// Sets the `cycle[h]` inhibit field value.
        ///
        /// **NOTE**: only updates the in-memory value without touching the CSR.
        set_cy,
        /// Attempts to set the `cycle[h]` inhibit field value.
        ///
        /// **NOTE**: only updates the in-memory value without touching the CSR.
        try_set_cy,
        bit: 0,
    },

is perhaps too verbose. Can't we do something like:

field: {
        /// `cycle[h]` inhibit field value
        cy,
        bit: 0,
    },

And then generate the same code? Just following the try and set notation.

Yes, this is what introducing the paste dependency solves. It requires proc_macros at the very least, and rewriting at least part of the paste crate locally, if we don't import it.

Personally, using the crate dependency is the better option, as it is actively maintained + high code quality.

I really do think the use-case justifies the additional dependency.

I'll add a commit using the paste crate.

Also, I feel like there are a lot of branches with similar code. Can't we simplify the macros using recursive calls that match patterns, consuming part of the tokens? I think in this way we would have simpler pattern matching and less duplicates.

Could you make comments on the specific places where you think they could be refactored into recursive branches?

I have a couple of those branches in the read_only_csr_field and write_only_csr_field to allow for re-use in read_write_csr. Where else can be simplified in a similar way?

Comment on lines 1239 to 928

($ty:ident,
$(#[$field_doc:meta])+
$field:ident: [$bit_start:literal : $bit_end:literal]$(,)?) => {
impl $ty {
paste::paste! {
$(#[$field_doc])+
#[inline]
pub fn $field(&self) -> usize {
self.[<try_ $field>]().unwrap()
}

$(#[$field_doc])+
#[inline]
pub fn [<try_ $field>](&self) -> $crate::result::Result<usize> {
let max_width = core::mem::size_of_val(&self.bits) * 8;

if $bit_end < max_width && $bit_start <= $bit_end {
Ok($crate::bits::bf_extract(self.bits, $bit_start, $bit_end - $bit_start + 1))
} else {
Err($crate::result::Error::IndexOutOfBounds {
index: $bit_start,
min: $bit_start,
max: $bit_end,
})
}
}
}
}
};

($ty:ident,
$(#[$field_doc:meta])+
$field:ident: {
$(#[$field_ty_doc:meta])+
$field_ty:ident {
range: [$field_start:literal : $field_end:literal],
default: $default_variant:ident,
$($variant:ident = $value:expr$(,)?)+
}$(,)?
}$(,)?
) => {
$crate::csr_field_enum!(
$(#[$field_ty_doc])+
$field_ty {
range: [$field_start : $field_end],
default: $default_variant,
$($variant = $value,)+
},
);

$crate::read_only_csr_field!(
$ty,
$(#[$field_doc])*
$field: [$field_start : $field_end],
$field_ty,
);
};

($ty:ident,
$(#[$field_doc:meta])+
$field:ident: [$field_start:literal : $field_end:literal],
$field_ty:ident$(,)?
) => {
impl $ty {
paste::paste! {
$(#[$field_doc])+
#[inline]
pub fn $field(&self) -> $field_ty {
self.[<try_ $field>]().unwrap()
}

$(#[$field_doc])+
#[inline]
pub fn [<try_ $field>](&self) -> $crate::result::Result<$field_ty> {
let max_width = core::mem::size_of_val(&self.bits) * 8;

if $field_end < max_width && $field_start < $field_end {
let value = $crate::bits::bf_extract(
self.bits,
$field_start,
$field_end - $field_start + 1,
);

$field_ty::from_usize(value).ok_or($crate::result::Error::InvalidFieldVariant {
field: stringify!($field),
value,
})
} else {
Err($crate::result::Error::IndexOutOfBounds {
index: $field_start,
min: $field_start,
max: $field_end,
})
}
}
}
}
};
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I rewrote the read_only_csr_field using the paste macro.

Please let me know if you are alright adding the dependency, and I'll rewrite the rest of the macros.

Please be sure about this decision, as it is a lot of work rewriting these macros.

Copy link
Contributor

Choose a reason for hiding this comment

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

Then let's cool this down until we resolve other design decisions. I can say that, as of now, I like how it looks

Comment on lines 3 to 51
read_only_csr! {
/// test CSR register type
Mtest: 0x000,
mask: 0b1111_1111_1111,
/// test single-bit field
single: 0,
}

read_only_csr_field! {
Mtest,
/// multiple single-bit field range
multi_range: 1..=3,
}

read_only_csr_field!(
Mtest,
/// multi-bit field
multi_field: [4:7],
);

read_only_csr_field!(
Mtest,
/// multi-bit field
field_enum: {
/// field enum type with valid field variants
MtestFieldEnum {
range: [7:11],
default: Field1,
Field1 = 1,
Field2 = 2,
Field3 = 3,
Field4 = 15,
}
}
);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

You can see how much the paste crate simplifies macro invocation, it is substantial.

The savings are even greater for the read_write_csr* variants.

@romancardenas
Copy link
Contributor

About reducing code size. Let's take only two pattern branches in read_only_csr_field:

#[macro_export]
macro_rules! read_only_csr {
    ($(#[$doc:meta])+
     $ty:ident: $csr:tt,
     mask: $mask:tt,
     $(
     $(#[$field_doc:meta])+
     $field:ident: $bit:literal$(,)?
     )+
    ) => {
        $crate::csr! { $(#[$doc])+ $ty: $csr, $mask }

        $(
            $crate::read_only_csr_field! {
                $ty,
                $(#[$field_doc])+
                $field: $bit,
            }
        )+

        $crate::read_csr_as!($ty, $csr);
    };

    ($(#[doc:meta])+
     $ty:ident: $csr:tt,
     mask: $mask:tt,
     $(
     $(#[$field_doc:meta])+
     $field:ident: $bit:literal ..= $bit_end:literal$(,)?
     )+) => {
        $crate::csr! { $(#[$doc])+ $ty: $csr, $mask }

        $(
            $crate::read_only_csr_field! {
                $ty,
                $(#[$field_doc])+
                $field: $bit ..= $bit_end,
            }
        )+

        $crate::read_csr_as!($ty, $csr);
    };
    ...
}

Both branches do something like:

        $crate::csr! { $(#[$doc])+ $ty: $csr, $mask }

        $(
            $crate::read_only_csr_field! {
                $ty,
                $(#[$field_doc])+
                <THIS LINE IS THE ONLY THING THAT CHANGES>
            }
        )+

        $crate::read_csr_as!($ty, $csr);

Looking at this specific example, the macro calls other macros (csr, read_csr_as, and read_only_csr_field a few times). So what is the benefit of having a single macro with many pattern branches that just propagate to other macro calls? Why don't we keep it simple and call in the user code to the read_only_csr_field all the times we want? In this way, we keep all macros simpler and users call them as many times as required.

riscv/src/register/macros.rs Show resolved Hide resolved
/// [read_only_csr](crate::read_only_csr), and [write_only_csr](crate::write_only_csr) macros.
#[macro_export]
macro_rules! csr {
($doc:expr, $ty:ident: $csr:literal, $mask:literal) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

We don't need to select the CSR number at this point

Suggested change
($doc:expr, $ty:ident: $csr:literal, $mask:literal) => {
($doc:expr, $ty:ident, $mask:literal) => {

Comment on lines 519 to 735
$crate::read_csr_as!($ty, $csr);
$crate::write_csr_as!($ty, $csr);
$crate::set!($csr);
$crate::clear!($csr);
Copy link
Contributor

Choose a reason for hiding this comment

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

I think I'd leave these macros out and call them as we need them

Suggested change
$crate::read_csr_as!($ty, $csr);
$crate::write_csr_as!($ty, $csr);
$crate::set!($csr);
$crate::clear!($csr);

Copy link
Contributor Author

@rmsyn rmsyn Sep 19, 2024

Choose a reason for hiding this comment

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

I agree about leaving out the set and clear macros, but think the read_csr_as and write_csr_as should still be included.

Would there ever be a case where one would call:

  • read_write_csr, but not read_csr_as and write_csr_as
  • read_only_csr, but not read_csr_as
  • write_only_csr, but not write_csr_as

In my opinion, including these macro calls avoids an author forgetting to include them. If you really think they should be removed, I'll take them out.

riscv/src/register/macros.rs Outdated Show resolved Hide resolved
Comment on lines 503 to 505
$field:ident: $get_bit:literal,
$set_field_doc:expr,
$set_field:ident: $set_bit:literal$(,)?
Copy link
Contributor

Choose a reason for hiding this comment

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

I think these macros should work in the general use cases (i.e., the same bits for getters and setters). For particular cases, we can always just implement them by hand.

riscv/src/register/macros.rs Outdated Show resolved Hide resolved
riscv/src/register/macros.rs Show resolved Hide resolved
Comment on lines 1239 to 928

($ty:ident,
$(#[$field_doc:meta])+
$field:ident: [$bit_start:literal : $bit_end:literal]$(,)?) => {
impl $ty {
paste::paste! {
$(#[$field_doc])+
#[inline]
pub fn $field(&self) -> usize {
self.[<try_ $field>]().unwrap()
}

$(#[$field_doc])+
#[inline]
pub fn [<try_ $field>](&self) -> $crate::result::Result<usize> {
let max_width = core::mem::size_of_val(&self.bits) * 8;

if $bit_end < max_width && $bit_start <= $bit_end {
Ok($crate::bits::bf_extract(self.bits, $bit_start, $bit_end - $bit_start + 1))
} else {
Err($crate::result::Error::IndexOutOfBounds {
index: $bit_start,
min: $bit_start,
max: $bit_end,
})
}
}
}
}
};

($ty:ident,
$(#[$field_doc:meta])+
$field:ident: {
$(#[$field_ty_doc:meta])+
$field_ty:ident {
range: [$field_start:literal : $field_end:literal],
default: $default_variant:ident,
$($variant:ident = $value:expr$(,)?)+
}$(,)?
}$(,)?
) => {
$crate::csr_field_enum!(
$(#[$field_ty_doc])+
$field_ty {
range: [$field_start : $field_end],
default: $default_variant,
$($variant = $value,)+
},
);

$crate::read_only_csr_field!(
$ty,
$(#[$field_doc])*
$field: [$field_start : $field_end],
$field_ty,
);
};

($ty:ident,
$(#[$field_doc:meta])+
$field:ident: [$field_start:literal : $field_end:literal],
$field_ty:ident$(,)?
) => {
impl $ty {
paste::paste! {
$(#[$field_doc])+
#[inline]
pub fn $field(&self) -> $field_ty {
self.[<try_ $field>]().unwrap()
}

$(#[$field_doc])+
#[inline]
pub fn [<try_ $field>](&self) -> $crate::result::Result<$field_ty> {
let max_width = core::mem::size_of_val(&self.bits) * 8;

if $field_end < max_width && $field_start < $field_end {
let value = $crate::bits::bf_extract(
self.bits,
$field_start,
$field_end - $field_start + 1,
);

$field_ty::from_usize(value).ok_or($crate::result::Error::InvalidFieldVariant {
field: stringify!($field),
value,
})
} else {
Err($crate::result::Error::IndexOutOfBounds {
index: $field_start,
min: $field_start,
max: $field_end,
})
}
}
}
}
};
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Then let's cool this down until we resolve other design decisions. I can say that, as of now, I like how it looks

riscv/src/register/macros.rs Outdated Show resolved Hide resolved
riscv/src/register/macros.rs Outdated Show resolved Hide resolved
@romancardenas
Copy link
Contributor

Hi @rmsyn ! I left you a few comments. Let's first figure out how we want to use the macros and then we can explore using the paste crate (which looks great, by the way).

@rmsyn
Copy link
Contributor Author

rmsyn commented Sep 18, 2024

Looking at this specific example, the macro calls other macros (csr, read_csr_as, and read_only_csr_field a few times). So what is the benefit of having a single macro with many pattern branches that just propagate to other macro calls? Why don't we keep it simple and call in the user code to the read_only_csr_field all the times we want? In this way, we keep all macros simpler and users call them as many times as required.

Ah, I see what you mean now. Yes, the code could be simplified by not trying to include field definitions in the type-creation macro.

The main instance where including field definitions in the type-creation macro is when all fields are the same type (bit, range, field-mask, etc.). Otherwise, users will need to invoke the field macros anyway.

I agree simplifying is the way to go here.

@rmsyn
Copy link
Contributor Author

rmsyn commented Sep 19, 2024

Let's first figure out how we want to use the macros and then we can explore using the paste crate (which looks great, by the way).

I've moved the paste work into riscv/csr-macro-paste branch.

When we're settled on the other design work, I can bring that work into this branch.

Copy link
Contributor

@romancardenas romancardenas left a comment

Choose a reason for hiding this comment

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

I have been without an Internet connection, but I had some time to review this PR. Check my comments.

riscv/src/register/macros.rs Show resolved Hide resolved
riscv/src/register/macros.rs Outdated Show resolved Hide resolved
riscv/src/register/macros.rs Outdated Show resolved Hide resolved
riscv/src/register/macros.rs Outdated Show resolved Hide resolved
riscv/src/register/macros.rs Outdated Show resolved Hide resolved
riscv/src/register/macros.rs Outdated Show resolved Hide resolved
riscv/src/register/macros.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@romancardenas romancardenas left a comment

Choose a reason for hiding this comment

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

Ok so... Looks almost there!

What do you think about trying the paste thing so we can shrink even more the macros? The idea would be:

  • For getters of field $field: $field (I think there is no fallible getter?)
  • For setters: try_$field (fallible) and set_$field (infallible)

If you prefer, we can address this in another PR and move on.

assert_eq!(mtest.bits(), 0);

// check that single bit field getter/setters work.
assert_eq!(mtest.single(), false);
Copy link
Contributor

Choose a reason for hiding this comment

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

Clippy complains at my machine about these kinds of assertions. Should look like:

Suggested change
assert_eq!(mtest.single(), false);
assert!(!mtest.single());

Copy link
Contributor

@romancardenas romancardenas left a comment

Choose a reason for hiding this comment

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

I noticed that we may need to re-export paste. @rmsyn , can you confirm this? If not, I think this PR is ready.

riscv/src/register/macros.rs Outdated Show resolved Hide resolved
romancardenas
romancardenas previously approved these changes Sep 27, 2024
Copy link
Contributor

@romancardenas romancardenas left a comment

Choose a reason for hiding this comment

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

LGTM

Let's leave a couple of days in case someone wants to review this and merge it

@romancardenas
Copy link
Contributor

If nobody opposes, I will merge this PR tomorrow by the end of the weekly meeting

@romancardenas
Copy link
Contributor

@rmsyn can you deal with the conflicts? We will merge it to master right after fixing this.

rmsyn and others added 19 commits October 17, 2024 23:58
Adds helper macros for defining CSR types.
Adds the ability to define CSR types using an enum field type.
Adds corrections to CSR creation macros for rebase on commit `a4d69614`.

Includes:

- additions of `try_*` function variants for fallible functions.
- changing doc string macro arguments to idiomatic `///` comments
Replaces repeated field bit and range arguments with a single `bit` or
`range` argument.

Intended to reduce copy-paste, prevent typo errors, and clarify intent.
Adds `try_*` variants for fallible getter functions on read-only CSR
macros.
Adds `try_*` variants for fallible getter functions on write-only CSR
macros.
Modularizes the `read_only_csr_field` and `write_only_csr_field` macro
helpers for re-use in `read_write_only_csr_field`.
Adds the explicit `mask:` field name to CSR helper macros to clarify
intent.
Adds the `field` macro argument label to CSR helper macros to clarify
intent.
Removes field arguments from CSR definition macros.
Removes the unused `csr` number argument from the `csr` macro.
Uses the crate result type for converting a CSR enum type from a
`usize`.
Applies compile-time checks in read-only CSR macros.

Authored-by: rmsyn <github@weathered-steel.dev>
Co-authored-by: romancardenas <rcardenas.rod@gmail.com>
Applies compile-time checks in write-only CSR macros.

Authored-by: rmsyn <github@weathered-steel.dev>
Co-authored-by: romancardenas <rcardenas.rod@gmail.com>
Removes the equality check for range branches in CSR helper macros.

Users who want a single-bit field, i.e. `start == end`, should use the
single-bit branch variants.

Authored-by: rmsyn <github@weathered-steel.dev>
Co-authored-by: romancardenas <rcardenas.rod@gmail.com>
Removes CSR helper macro branches that include field enum type creation.

Leaves the creation of the field enum to the separate `csr_field_enum`
macro, or manual definition of the field enum.

Authored-by: rmsyn <github@weathered-steel.dev>
Co-authored-by: romancardenas <rcardenas.rod@gmail.com>
Uses the [`paste`](https://docs.rs/paste) dependency for concatenating
idents in CSR helper macros.
Re-exports the `paste` macro to allow using CSR helper macros in
external crates.

Authored-by: rmsyn <github@weathered-steel.dev>
Co-authored-by: romancardenas <rcardenas.rod@gmail.com>
@romancardenas romancardenas added this pull request to the merge queue Oct 18, 2024
Merged via the queue into rust-embedded:master with commit a35fde8 Oct 18, 2024
101 checks passed
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.

2 participants