Skip to content

Feature Request: Component trait #4

@DavidAntliff

Description

@DavidAntliff

Have you considered a set of trait functions and associated constants on each component, to assist with generic code?

For example, consider the current output emitted for a component:

impl System {
    /// Size in bytes of the underlying memory
    pub const SIZE: usize = 0xC0;

    /// # Safety
    ///
    /// The caller must guarantee that the provided address points to a
    /// hardware register block implementing this interface.
    #[inline(always)]
    #[must_use]
    pub const unsafe fn from_ptr(ptr: *mut ()) -> Self {
        Self {
            ptr: ptr.cast::<u8>(),
        }
    }

    #[inline(always)]
    #[must_use]
    pub const fn as_ptr(&self) -> *mut () {
        self.ptr.cast::<()>()
    }

    // ...

In my system, I have a small hierarchy of components, and it would be useful to split the RDL hierarchy up in a similar way so that components can be handled generically.

For example:

  • Create the root-level RDL and bind it to a mmapped region,
  • Take a clone or reference to some branch of the RDL, for some region,
  • and call as_ptr() to get the base pointer to that region,

In my FPGA design, I have register files of multiple registers, but I also have an external diagnostics API that allows a driver to access registers by index rather than name. Rather than creating a large offset-to-RDL-register map, in this case I'd prefer to allow "table" access, by calculating an aligned read/write offset from the base of any of the register files.

Unfortunately, without this trait, or something similar, it seems I have to hard-code the access to every register file. I can't pass a generic register file around.

If every RDL-generated component implemented a trait, say, Component, that made SIZE, from_ptr() and as_ptr() available, something like:

pub trait Component: Sized {
    const SIZE: usize;

    unsafe fn from_ptr(ptr: *mut ()) -> Self;

    fn as_ptr(&self) -> *mut ();
}

Then my code (and my test code) would be able to do something generic, like this:

fn map_component<C: Component>(base: *mut ()) -> C {
    unsafe { C::from_ptr(base) }
}

fn allocate_buffer<C: Component>() -> Vec<u8> {
    vec![0u8; C::SIZE]
}

I'm not 100% sure this would work, though. I'm interested to know if you've considered it already?

EDIT: Just occurred to me that I can test this out with an extension trait. I'll see where that gets me...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions