-
Notifications
You must be signed in to change notification settings - Fork 3
Description
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...