On Mon, May 5, 2025 at 4:45 PM Paolo Bonzini <bonz...@gnu.org> wrote:
>
> On 5/5/25 14:26, Manos Pitsidianakis wrote:
> >>     Something I do notice is that there's some inconsistency in
> >>     how we've structured things between the two devices, e.g.:
> >>
> >>     * the pl011 main source file is device.rs, but the hpet one
> >>       is hpet.rs
> >>
> >>     * some places we use the actual names of bits in registers
> >>       (eg Interrupt's OE, BE, etc consts), and some places we
> >>       seem to have renamed them (e.g. pl011 Flags has clear_to_send
> >>       not CTS, etc)
> >>
> >>     * pl011 has defined named fields for its registers, but hpet does
> >>       things like::
> >>
> >>          self.config.get() & (1 << HPET_CFG_LEG_RT_SHIFT) != 0
> >>
> >>     * pl011 has a split between PL011State and PL011Registers,
> >>       but HPET does not. As I mentioned in an email thread a
> >>       little while back, I feel like the State/Registers split
> >>       is something we should either make a more clear deliberate
> >>       formalised separation that's part of how we recommend
> >>       device models should be designed
> >>
> >>     [...]
> >>
> >>     I think it would be good to figure out what we think is the
> >>     right, best style, for writing this kind of thing, and be
> >>     consistent. We have long standing problems in the C device
> >>     models where there are multiple different styles for how
> >>     we write them, and it would be good to try to aim for
> >>     more uniformity on the Rust side.
> >
> > The pl011 stuff was deliberate decisions:
> >
> > - device.rs vs pl011.rs: the device was written as a crate, so it's
> > essentially its own library, plus pl011/src/pl011.rs would be
> > redundant :)
>
> Right, I think Peter's comment was more about moving hpet.rs to
> device.rs, and merging PL011's device_class.rs into its device.rs.
>
> >    That said, it's not important, we can choose either convention. I
> > like the less redundancy and separation of concerns: if pl011 gets
> > converted into a module in a future refactor, it could keep its
> > functionality split into different submodules and `pl011.rs` or
> > `pl011/mod.rs` would be the device module.
>
> I think it's okay to decide that Rust devices will have mini
> directories: it's just the style of the language and Cargo more or less
> relies on having lib.rs.
>
> In a vacuum I would prefer to have hw/char/pl011.rs for what is now
> rust/hw/char/pl011/lib.rs, and place the other files in hw/char/pl011;
> IIRC rustc accepts that style.  However we still rely on Cargo for some
> things(*), and as long as we do there's not much we can do about it.
>
>      (*) notably "cargo fmt".  Everything else is more or less handled
>          by Meson starting with 1.8.0.
>
> > - Using typed registers instead of constants: yes coming from C I can
> > understand it can feel unfamiliar. I specifically wanted to make the
> > register fields typed to avoid making the implementation a "C port",
> > and I think it's worthwhile to use the type system as much as
> > possible.
>
> Peter's comments (especially the second and third) were about two kinds
> of inconsistencies:
>
> 1) HPET not using bilge.  This was because Zhao looked at HPET from the
> opposite direction compared to what you did on pl011, namely avoiding
> unsafe and modeling the BQL properly, and sacrificed a bit the usage of
> idiomatic code like what bilge provides.
>
> I think that you made the right choice for the first device and he made
> the right choice for the second device.  But now someone should look at
> HPET and do the work that you did to adopt bilge.
>
> 2) The choice between bilge on one side, and bitflags or integers on the
> other.  For pl011 you kept interrupt bits as integers for example, and
> this is related to the topic of (non-)availability of const in traits...

Oh right.

>
> >    A straight C port would result into integer constants with integer
> > typed fields everywhere for registers/flags.
> >    Yes, From/Into aren't const, at least yet, but it's not really a
> > hotpath performance wise. I think non-dynamically dispatched trait
> > methods can be inlined by annotating the `fn from(..)` impl with a
> > `#[inline(always)]` hint but I haven't confirmed this, just
> > speculation.
>
> It's not about hot paths, it's more that 1) you cannot use From/Into in
> a "static"'s initializer 2) bilge relies a lot on non-const methods in
> its internal implementation, which makes it quite messy to use it in
> some places.  See for example this thing for which I take all the blame:

Yeah it's not nice that we can't use it in static/const initializers.

>
>      impl Data {
>          // bilge is not very const-friendly, unfortunately
>          pub const BREAK: Self = Self { value: 1 << 10 };
>      }
>
> and the same would be true of interrupt constants and the IRQMASK array.
>
> The separate bilge and bitflags worlds are what bothers me the most in
> the experimental devices.  I can see why they would be very confusing
> for someone who's not had much experience with Rust, and therefore
> doesn't know *why* they are separate.
>
> >    Again, no strong opinions here. I like the "everything is typed"
> > approach and I think it's worth it to explore it because it allows us
> > to "make invalid/illegal states unrepresentable" as one sage article
> > goes.
>
> I agree, and it's why I think you made the right choice using it for
> pl011.  With all the unsafe code that you had to use, strong-typing at
> least showed *something* that Rust could provide compared to C(*).  And
> I like the strong typing too, even if I'm not sure I like bilge's
> *implementation* that much anymore.

It has its pros and cons that's for sure... there are many crates that
let you define typed bitfields, I haven't looked into the current
state of the art lately. We should definitely move on to something
better if it exists now or in the future.

> I'm not really up for rewriting it, but then I've also done more stupid
> rewrites in the past. :)
>
>     (*) when we were discussing safety vs. unsafety last summer, I may
>         have sounded dismissive of this kind of benefit.  My point at the
>         time was that unsafe code was so much more complex than C, that
>         the benefit of strong-typing wasn't enough to *offset* the
>         complexity of unsafe code.  But it is absolutely present.
>
> >> Related to this I have found recently the `attrs crate
> >> <https://docs.rs/attrs/>`__, which provides an easy way to parse the
> >> contents of attributes in a procedural macro.
> >
> > I actually have some WIP patches for this I put a pause on and can
> > continue e.g. 
> > https://gitlab.com/epilys/rust-for-qemu/-/commit/c2c97caaaf03273fabc14aee5a4d1499668ddbe3
>
> The repository is private, but I look forward to seeing it!  If you want
> to post an RFC without even any code, just to show what the device code
> looks like, that would be helpful as it will catch stuff like lack of
> type safety.

Oops, I forgot I had archived it because I moved development to
https://gitlab.com/epilys/qemu . I made it public again. Bear in mind
this was a WIP, basically my git stash but committed.

>
> BTW, if you need it to model reflection better I think it is acceptable
> to assume const_refs_to_static is present.
>
> Paolo

Reply via email to