`rumio`
=======
[![Crates.io](https://img.shields.io/crates/v/rumio.svg)](https://crates.io/crates/rumio)
[![Documentation](https://img.shields.io/badge/documentation-docs.rs-blue.svg)](https://docs.rs/rumio)

**Control your MMIO and CPU registers without pain.**

[Documentation][docs-rs] | [Crate][crates-io] | [Examples][examples]

This crate provides various macros to generate a nice API for [MMIO][mmio] blocks
and CPU registers. It's mainly meant as a replacement for the [`register`][regs-rs] crate
to provide a better API and make the work easier.

# Usage

For more updated and larger examples take a look at the [tests][examples].

## Defining CPU registers

The CPU registers are only useful for control registers which store their data using
bitfields. For example the Control-Status-Register of the RISC-V architecture.

```rust
#![feature(asm)]

mod mstatus {
  use rumio::cpu::{RegisterRead, RegisterWrite};

  // first we need to define a register, and a way to read/write to it.
  // we will use the `mstatus` CSR from the RISC-V architecture as an example
  struct Mstatus;

  // the `usize` argument indicates the underyling value of the register.
  impl RegisterRead<usize> for Mstatus {
      #[inline]
      fn read() -> usize {
          let reg;
          unsafe { asm!("csrr {}, mstatus", out(reg) reg) }
          reg
      }
  }

  impl RegisterWrite<usize> for Mstatus {
      #[inline]
      fn write(val: usize) {
          unsafe { asm!("csrw mstatus, {}", in(reg) val) }
      }

      #[inline]
      fn set(mask: usize) {
          // `impl_cpu_set` and `impl_cpu_clear` can generated `set` and `clear`
          // by performing a read, setting the bits and then write the value again.
          rumio::impl_cpu_set!(Self, mask);
      }

      #[inline]
      fn clear(mask: usize) {
          rumio::impl_cpu_clear!(Self, mask);
      }
  }

  // now define the different bits and fields of this register
  rumio::define_cpu_register! { Mstatus as usize =>
    /// Globally enables interrupts in U-Mode.
    rw UIE: 0,
    /// Globally enables interrupts in S-Mode.
    rw SIE: 1,
    /// Globally enables interrupts in M-Mode.
    rw MIE: 3,

    /// The privilege mode a trap in M-Mode was taken from.
    r MPP: 11..12 = enum PrivilegeMode [
      User = 0b00,
      Supervisor = 0b01,
      Machine = 0b11,
    ],

    /// This is not an actual flag of the `mstatus` register, but
    /// we add it here for showing the usage of `flags`
    rw FLAGS: 13..16 = flags CpuFlags [
      A = 0b0001,
      B = 0b0010,
      C = 0b0100,
      D = 0b1000,
    ],
  }
}

// the generated api then can be used like this.
// to explore the full api generated by this macro, check the `example_generated`
// module on docs.rs, and check the examples (the tests are the examples)

mstatus::modify(mstatus::UIE::SET | mstatus::SIE::SET | mstatus::MIE::SET);
println!("Trap was taken from {:?}", mstatus::MPP::get());
```

## Defining MMIO registers

```rust
// define one MMIO register whose base type is `u16` and name is `Reg`.
rumio::define_mmio_register! {
    Reg: u16 {
        rw MODE: 0..1 = enum Mode [
            A = 0b00,
            B = 0b01,
            C = 0b10,
            D = 0b11,
        ],

        r FOO: 2,

        rw BAR: 3,
        rw BAZ: 4,

        rw FLAGS: 5..8 = flags Flags [
            A = 0b0001,
            B = 0b0010,
            C = 0b0100,
            D = 0b1000,
        ],
    }
}

rumio::define_mmio_struct! {
    pub struct Device {
        0x00 => one: Reg,
        0x08 => two: Reg,
    }
}

// create a new `Device` at address `0xF00D_BABE
let mmio = unsafe { Device::new(0xF00D_BABE) };

// access the `one` register
let one = mmio.one();

// now `one` can be used similarly to the cpu register
one.MODE().set(Mode::B);
one.FLAGS().set(Flags::B | Flags::C);

one.modify(Mode::A | BAR::SET);
```

### License

Licensed under either [Apache License][apache] or the [MIT][mit] license.


[docs-rs]: https://docs.rs/rumio
[crates-io]: https://crates.io/crates/ruumio
[examples]: https://github.com/Stupremee/rumio/tree/main/tests
[apache]: https://github.com/Stupremee/rumio/tree/main/LICENSE-APACHE
[mit]: https://github.com/Stupremee/rumio/tree/main/LICENSE-MIT
[mmio]: https://en.wikipedia.org/wiki/Memory-mapped_I/O
[regs-rs]: https://docs.rs/register
