#macro #embedded #no-std

nightly no-std bitaccess

宏,用于高效且类型检查的访问变量的单个位

4个版本 (破坏性更新)

0.4.0 2021年10月13日
0.3.0 2021年9月26日
0.2.0 2021年9月23日
0.1.0 2021年9月23日

#2024 in 数据结构

每月25次下载

MIT/Apache

12KB
186

Bitaccess

一个小型crate,用于在rust语言中替代缺少位字段访问器。

示例用法

#![feature(asm)]

use bitaccess::{bitaccess, FieldAccess};

#[derive(FieldAccess, Debug)]
#[field_access(u64)]
pub enum Mask {
    Unmasked = 0,
    Masked = 1,
}

#[bitaccess(
    base_type = u64,
    kind = read_write,
    read_via = r#"unsafe { asm!("mrs {}, daif", out(reg) value, options(nostack, nomem)); }"#,
    write_via = r#"unsafe { asm!("msr daif, {}", in(reg) value, options(nostack, nomem)); }"#
)]
pub enum Daif {
    #[bit(9)]
    #[variants(Mask)] D,
    #[bit(8)]
    #[variants(Mask)] A,
    #[bit(7)]
    #[variants(Mask)] I,
    #[bit(6)]
    #[variants(Mask)] F,
}

/// DAIF is an ARM register, so this example is not really suited for running on all machines.
/// It's here just to show power of the macro.
fn alter_daif() {
    println!("Daif IRQ: {:?}", Daif.read(Daif::I).variant());
    Daif.write(Daif::I, Mask::Unmasked);
    println!("Daif IRQ: {:?}", Daif.read(Daif::I).variant());
}

特性

内联寄存器

允许您创建一个存储在常规内存中的对象,无论是栈还是堆(可能通过某些解引用包装器)。

要创建此类结构,您必须创建一个枚举,如下所示

use bitaccess::{bitaccess, FieldAccess};

#[derive(FieldAccess)]
#[field_access(u64)]
enum VariantThird {
    Val1 = 0x1,
    Val2 = 0x3,
    Val3 = 0xf,
}

#[bitaccess(
    base_type = u64,
    kind = read_write
)]
#[repr(C)]
enum MyRegister {
    #[bits(0..=3)]
    FirstDescriptor,
    #[bit(4)]
    #[variants(On => 1, Off => 0)]
    SecondDescriptor,
    #[bitaccess(5..9)]
    #[variants(VariantThird)]
    ThirdDescriptor,
}

Base_type

任何整数类型。

放置除基本整数类型之外的任何类型是不稳定的,但可能有效

Kind

允许选项

  • 只读
  • 只写
  • 读写 | 写读 | 默认

根据选择的选项,生成的代码可能提供ReadBits、WriteBits或两者的实现。字段可以省略,这将生成读写寄存器。

主枚举上的额外属性

bitaccess之后的所有属性都将复制到生成的结构体(是的,这个枚举在底层转换为结构体)

Bits / Bit / Bitaccess

字段属性,声明哪些位是给定字段的组成部分。

接受3种声明形式

显式

#[bits(偏移量 = N, 大小 = S)] 其中N和S都是可评估为base_type的表达式

范围

接受Range和RangeInclusive: 0..4 & 0..=3

单个

对于单个位访问器,允许 #[bit(N)]

变体

字段可以以自动转换的变体形式出现(如上面的VariantThird)。Bitaccess支持两种声明此类访问的方式

内联

由逗号分隔的 标识符 => 对列表。变体将通过枚举访问,其中字段标识符用作名称,例如在上面示例中,我们会调用 SecondDescriptor::On

外部

#[variants(Type)] 中仅指定类型将用于字段访问。类型必须继承 FieldAccess 特性并指定 #[field_access(N)] 属性,其中 N 必须与主枚举中的 base_type 匹配。

全局寄存器

#[derive(FieldAccess)]
#[field_access(u64)]
pub enum ExceptionLevel {
    EL0 = 0b00,
    EL1 = 0b01,
    EL2 = 0b10,
    EL3 = 0b11,
}

#[bitaccess(
    base_type = u64,
    kind = read_only,
    read_via = r#"unsafe { asm!("mrs {}, currentel", out(reg) value, options(nomem, nostack)) }"#
)]
pub enum CurrentEl {
    #[bits(2..4)]
    #[variants(ExceptionLevel)]
    Value,
}

全局寄存器在向位访问宏提供 read_viawrite_via 属性时创建。所有其他属性的行为与 内联寄存器 相同。

Read_via | write_via

字符串中提供的 Rust 指令。有关其他使用示例,请查看测试。

依赖项

~1.5MB
~36K SLoC