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

Refactoring of registers via wrappers #27

Open
FedericoPonzi opened this issue Feb 4, 2021 · 2 comments
Open

Refactoring of registers via wrappers #27

FedericoPonzi opened this issue Feb 4, 2021 · 2 comments

Comments

@FedericoPonzi
Copy link
Contributor

Context

If you look at serial.rs, this is the current situation:
At the top, we have some const defined

//FIFO enabled.
const IIR_FIFO_BITS: u8 = 0b1100_0000;
const IIR_RDA_BIT: u8 = 0b0000_0100;
const IIR_NONE_BIT: u8 = 0b0000_0001;
const IIR_THR_EMPTY_BIT: u8 = 0b0000_0010;

The pattern is <register>_<field_name>.
An example of usage in the wild is:

    fn add_interrupt(&mut self, interrupt_bits: u8) {
        self.interrupt_identification &= !IIR_NONE_BIT;
        self.interrupt_identification |= interrupt_bits;
    }

Problem

  1. The naming scheme suggests a possible grouping of these consts.
  2. It's not intuitive what's going on with that code, due to manual bit manipulation.

Proposal

First proposal

I know it's not preferable to include external dependencies like bitfield but I think I simple macro will do the trick.

I would propose a macro which will allow the following:

/// Interrupt Identification Register
defreg!(IIR, u8, [
    FIFO[8-7],
    RDA[2-2],
    THR_EMPTY[1-1],
    NONE[0-0],
]);
// Example of usage:

   fn add_interrupt(&mut self, interrupt_bits: u8) {
        self.interrupt_identification.clear_bit(IIR::NONE);
        self.interrupt_identification.set_bit(interrupt_bits);
    }

The parameters are: the struct name, size of the wrapped value, and list of fields and position of those fields (e.g. NONE is one bit long, and it's the lsb).
We could also add another input for a default value (and remove all the DEFAULTconsts).

Second proposal

A simple struct based wrapper. Playground.

#[derive(Debug)]
struct IIR(u8);

impl IIR{
    const FIFO_BITS: u8 = 0b1100_0000;
    const NONE_BIT: u8 = 0b0000_0001;
    const THR_EMPTY_BIT: u8 = 0b0000_0010;
    const RDA_BIT: u8 = 0b0000_0100;
}

impl default::Default for IIR{
    fn default() -> Self{
        Self(IIR::NONE_BIT)
    }
}

We can then define the similar methods as above (clear_bit and set_bit).

@andreeaflorescu
Copy link
Member

Generally grouping the registers together sounds very nice. I think we can go further down and provide abstractions for the main components of the serial console. For example, if we take the interrupts, there are 3 main operations (which have separate defines):

  • enabling interrupts -> corresponds to IER defines
  • adding/deleting an interrupt -> corresponds to the IIR defines
    -trigering the interrupt

A non significant overhead in the serial console comes from handling interrupts. If we can "modularize" working with an interrupt, we get "for free" the separation you are proposing because we can then define the bit shifts in the context of the newly created interface. Does that make sense?

@FedericoPonzi
Copy link
Contributor Author

I'm not sure I understand correctly your proposal, can you maybe show an example of the interface you're referrng to? I thnk you're proposing to not expose the bit masks, but instead to provide methods like "set_bit_x".

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

No branches or pull requests

2 participants