1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#[macro_export]
macro_rules! write_masked {
($write: expr, $shift: expr, $mask: expr, $val: expr) => {
$write = ($write & !($mask << $shift)) | ($val & $mask) << $shift
}
}
#[macro_export]
macro_rules! read_masked {
($read: expr, $shift: expr, $mask: expr) => {
($read >> $shift) & $mask
}
}
#[macro_export]
macro_rules! field_trait {
(read, $name: ident, $field: tt, $t:ty, $shift: expr) => {
fn $name(&self) -> bool;
};
(write, $name: ident, $field: tt, $t:ty, $shift: expr) => {
fn $name(&mut self, v: bool);
};
(read, $name: ident, $field:tt, $t:ty, $shift:expr, $mask:expr) => {
fn $name(&self) -> $t;
};
(write, $name: ident, $field:tt, $t:ty, $shift:expr, $mask:expr) => {
fn $name(&mut self, v: $t);
}
}
#[macro_export]
macro_rules! field_method {
(read, $name: ident, $field: tt, $t:ty, $shift: expr) => {
fn $name(&self) -> bool {
self.$field & (1 << $shift) != 0
}
};
(write, $name: ident, $field: tt, $t:ty, $shift: expr) => {
fn $name(&mut self, v: bool) {
self.$field = match v {
true => self.$field | (1 << $shift),
false => self.$field & !(1 << $shift),
};
}
};
(read, $name: ident, $field: tt, $t:ty, $shift: expr, $mask: expr) => {
fn $name(&self) -> $t {
read_masked!(self.$field, $shift, $mask)
}
};
(write, $name: ident, $field: tt, $t:ty, $shift: expr, $mask: expr) => {
fn $name(&mut self, v: $t) {
write_masked!(self.$field, $shift, $mask, v);
}
}
}
#[macro_export]
macro_rules! register {
(
$reg:ident, $t:ty, [ $( $op:ident, $name:ident, $field:tt, $type:ty, $( $args:expr ),* );* ;]
) => {
pub trait $reg {
$( field_trait!($op, $name, $field, $type, $( $args ),* ); )*
}
impl $reg for Register<$t> {
$( field_method!($op, $name, $field, $type, $( $args ),* ); )*
}
}
}
#[cfg(test)]
mod tests {
use ::register::Register;
register!(TESTREG1, u16,
[
read, read_bit1, 1, bool, 1;
write, write_bit1, 1, bool, 1;
read, read_var, 1, u16, 2, 0b111;
write, write_var, 1, u16, 2, 0b111;
]
);
#[test]
fn register_traits() {
let mut r = Register::<u16>(0, 0);
assert_eq!(0, r.value());
assert_eq!(false, r.read_bit1());
r.write_bit1(true);
assert_eq!(true, r.read_bit1());
assert_eq!(1 << 1, r.value());
assert_eq!(0, TESTREG1::read_var(&r));
TESTREG1::write_var(&mut r, 3);
assert_eq!(3, TESTREG1::read_var(&r));
assert_eq!(1 << 1 | 3 << 2, r.value());
}
}