1use crate::atomic::AtomicMmio;
6use crate::operand::MmioOperand;
7use mmio::{IndexedRegister, Mmio, MmioExt, Register};
8
9pub struct FakeMmioDevice<M>(M);
16
17impl<M> FakeMmioDevice<M> {
18 pub fn new(m: M) -> Self {
20 Self(m)
21 }
22}
23
24impl<M: Mmio> FakeMmioDevice<M> {
25 pub fn read<R: Register>(&self) -> R {
27 R::from_raw(self.0.load::<R::Value>(R::OFFSET))
28 }
29
30 pub fn write<R: Register>(&mut self, v: R) {
32 self.0.store::<R::Value>(R::OFFSET, v.to_raw())
33 }
34
35 pub fn clear_bits<R: Register>(&mut self, v: R::Value) {
37 self.0.masked_modify(R::OFFSET, v, !v)
38 }
39
40 pub fn set_bits<R: Register>(&mut self, v: R::Value) {
42 self.0.masked_modify(R::OFFSET, v, v)
43 }
44
45 pub fn read_indexed<R: IndexedRegister>(&self, index: usize) -> R {
47 R::from_raw(self.0.load::<R::Value>(R::BASE_OFFSET + index * R::STRIDE))
48 }
49
50 pub fn write_indexed<R: IndexedRegister>(&mut self, index: usize, v: R) {
52 self.0.store::<R::Value>(R::BASE_OFFSET + index * R::STRIDE, v.to_raw())
53 }
54}
55
56impl<M: AtomicMmio> FakeMmioDevice<M> {
57 pub fn swap<R: Register<Value: MmioOperand>>(&self, v: R) -> R {
60 R::from_raw(self.0.swap(R::OFFSET, v.to_raw()))
61 }
62
63 pub fn take<R: Register<Value: MmioOperand> + Default>(&self) -> R {
66 self.swap(R::default())
67 }
68
69 pub fn fetch_or<R: Register<Value: MmioOperand>>(&self, v: R) -> R {
72 R::from_raw(self.0.fetch_or(R::OFFSET, v.to_raw()))
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79 use crate::CachedVmoMemory;
80
81 const VMO_SIZE: usize = 4096;
82
83 mmio::register! {
84 #[register(offset = 0x0, mode = RW)]
85 pub struct TestReg32(u32);
86
87 #[register(offset = 0x8, mode = RW)]
88 pub struct TestReg8(u8);
89
90 #[indexed_register(offset = 0x10, stride = 4, count = 4, mode = RW)]
91 pub struct TestIndexedReg32(u32);
92 }
93
94 #[test]
95 fn test_read_write() {
96 let mmio = CachedVmoMemory::new_mapped(VMO_SIZE).expect("Failed to map VMO.");
97 let mut dev = FakeMmioDevice::new(mmio);
98
99 let reg32 = TestReg32::from_raw(0x1234_5678);
100 dev.write(reg32);
101 assert_eq!(dev.read::<TestReg32>(), reg32);
102
103 let reg8 = TestReg8::from_raw(0xab);
104 dev.write(reg8);
105 assert_eq!(dev.read::<TestReg8>(), reg8);
106 }
107
108 #[test]
109 fn test_set_and_clear_bits() {
110 let mmio = CachedVmoMemory::new_mapped(VMO_SIZE).expect("Failed to map VMO.");
111 let mut dev = FakeMmioDevice::new(mmio);
112
113 dev.write(TestReg32::from_raw(0xf0f0_f0f0));
114
115 dev.clear_bits::<TestReg32>(0xa0a0_a0a0);
116 assert_eq!(dev.read::<TestReg32>(), TestReg32::from_raw(0x5050_5050));
117
118 dev.set_bits::<TestReg32>(0x0505_0505);
119 assert_eq!(dev.read::<TestReg32>(), TestReg32::from_raw(0x5555_5555));
120 }
121
122 #[test]
123 fn test_indexed_read_write() {
124 let mmio = CachedVmoMemory::new_mapped(VMO_SIZE).expect("Failed to map VMO.");
125 let mut dev = FakeMmioDevice::new(mmio);
126
127 let reg0 = TestIndexedReg32::from_raw(0x1111_1111);
128 let reg1 = TestIndexedReg32::from_raw(0x2222_2222);
129 let reg2 = TestIndexedReg32::from_raw(0x3333_3333);
130
131 dev.write_indexed(0, reg0);
132 dev.write_indexed(1, reg1);
133 dev.write_indexed(2, reg2);
134
135 assert_eq!(dev.read_indexed::<TestIndexedReg32>(0), reg0);
136 assert_eq!(dev.read_indexed::<TestIndexedReg32>(1), reg1);
137 assert_eq!(dev.read_indexed::<TestIndexedReg32>(2), reg2);
138 }
139
140 #[test]
141 fn test_atomic_swap() {
142 let mmio = CachedVmoMemory::new_mapped(VMO_SIZE).expect("Failed to map VMO.");
143 let dev = FakeMmioDevice::new(mmio);
144
145 let new_val = TestReg32::from_raw(0xdead_beef);
146 let old = dev.swap(new_val);
147 assert_eq!(old, TestReg32::from_raw(0));
148 assert_eq!(dev.read::<TestReg32>(), new_val);
149 }
150
151 #[test]
152 fn test_atomic_take() {
153 let mmio = CachedVmoMemory::new_mapped(VMO_SIZE).expect("Failed to map VMO.");
154 let dev = FakeMmioDevice::new(mmio);
155
156 let val = TestReg32::from_raw(0xcafe_babe);
157 let _ = dev.swap(val);
158 let taken = dev.take::<TestReg32>();
159 assert_eq!(taken, val);
160 assert_eq!(dev.read::<TestReg32>(), TestReg32::default());
161 }
162
163 #[test]
164 fn test_atomic_fetch_or() {
165 let mmio = CachedVmoMemory::new_mapped(VMO_SIZE).expect("Failed to map VMO.");
166 let dev = FakeMmioDevice::new(mmio);
167
168 let initial = TestReg32::from_raw(0x0000_ffff);
169 let _ = dev.swap(initial);
170 let old = dev.fetch_or(TestReg32::from_raw(0xffff_0000));
171 assert_eq!(old, initial);
172 assert_eq!(dev.read::<TestReg32>(), TestReg32::from_raw(0xffff_ffff));
173 }
174}