1use mmio::MmioSplit;
29use mmio::region::{MmioRegion, UnsafeMmio};
30use mockall::mock;
31use std::ops::Deref;
32
33mock! {
34 pub MemoryOps {
35 pub fn load8(&self, addr: usize) -> u8;
36 pub fn load16(&self, addr: usize) -> u16;
37 pub fn load32(&self, addr: usize) -> u32;
38 pub fn load64(&self, addr: usize) -> u64;
39
40 pub fn store8(&self, addr: usize, value: u8);
41 pub fn store16(&self, addr: usize, value: u16);
42 pub fn store32(&self, addr: usize, value: u32);
43 pub fn store64(&self, addr: usize, value: u64);
44
45 pub fn write_barrier(&self);
46 }
47}
48
49pub fn new_mock_mmio<O: Deref<Target = MockMemoryOps> + Clone + Send + Sync>(
53 ops: O,
54 len: usize,
55) -> impl MmioSplit + Send + Sync + use<O> {
56 MmioRegion::new(MockMmio { ops, len })
57}
58
59#[derive(Clone)]
60struct MockMmio<O> {
61 ops: O,
62 len: usize,
63}
64
65impl<O: Deref<Target = MockMemoryOps>> UnsafeMmio for MockMmio<O> {
66 fn len(&self) -> usize {
67 self.len
68 }
69
70 fn align_offset(&self, _align: usize) -> usize {
71 0
72 }
73
74 unsafe fn load8_unchecked(&self, offset: usize) -> u8 {
75 self.ops.load8(offset)
76 }
77
78 unsafe fn load16_unchecked(&self, offset: usize) -> u16 {
79 self.ops.load16(offset)
80 }
81
82 unsafe fn load32_unchecked(&self, offset: usize) -> u32 {
83 self.ops.load32(offset)
84 }
85
86 unsafe fn load64_unchecked(&self, offset: usize) -> u64 {
87 self.ops.load64(offset)
88 }
89
90 unsafe fn store8_unchecked(&self, offset: usize, value: u8) {
91 self.ops.store8(offset, value)
92 }
93
94 unsafe fn store16_unchecked(&self, offset: usize, value: u16) {
95 self.ops.store16(offset, value)
96 }
97
98 unsafe fn store32_unchecked(&self, offset: usize, value: u32) {
99 self.ops.store32(offset, value)
100 }
101
102 unsafe fn store64_unchecked(&self, offset: usize, value: u64) {
103 self.ops.store64(offset, value)
104 }
105
106 fn write_barrier(&self) {
107 self.ops.write_barrier();
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114 use mmio::Mmio;
115 use mockall::Sequence;
116 use mockall::predicate::eq;
117
118 #[test]
119 fn test_mock_ops() {
120 let mut ops = MockMemoryOps::new();
121 ops.expect_load8().with(eq(0)).return_const(17);
122
123 let mmio = new_mock_mmio(&ops, 1024);
124 assert_eq!(mmio.load8(0), 17);
125 }
126
127 #[test]
128 fn test_sequence_interleaving() {
129 enum Op {
143 A1,
144 A2,
145 B1,
146 B2,
147 }
148 for interleaving in [
149 [Op::A1, Op::A2, Op::B1, Op::B2],
150 [Op::A1, Op::B1, Op::A2, Op::B2],
151 [Op::A1, Op::B1, Op::B2, Op::A2],
152 [Op::B1, Op::A1, Op::A2, Op::B2],
153 [Op::B1, Op::A1, Op::B2, Op::A2],
154 [Op::B1, Op::B2, Op::A1, Op::A2],
155 ] {
158 let mut ops = MockMemoryOps::new();
159
160 let mut seq1 = Sequence::new();
161 let mut seq2 = Sequence::new();
162
163 ops.expect_load8()
164 .times(1)
165 .in_sequence(&mut seq1)
166 .with(eq(0_usize))
167 .return_const(17_u8);
168 ops.expect_load8()
169 .times(1)
170 .in_sequence(&mut seq1)
171 .with(eq(1_usize))
172 .return_const(36_u8);
173
174 ops.expect_store16()
175 .times(1)
176 .in_sequence(&mut seq2)
177 .with(eq(2_usize), eq(1023_u16))
178 .return_const(());
179 ops.expect_load16()
180 .times(1)
181 .in_sequence(&mut seq2)
182 .with(eq(2_usize))
183 .return_const(1023_u16);
184
185 let mut mmio = new_mock_mmio(&ops, 1024);
186 let r1 = mmio.split_off(2);
187 let mut r2 = mmio.split_off(2);
188
189 for op in interleaving {
190 match op {
191 Op::A1 => assert_eq!(r1.load8(0), 17),
192 Op::A2 => assert_eq!(r1.load8(1), 36),
193 Op::B1 => r2.store16(0, 1023),
194 Op::B2 => assert_eq!(r2.load16(0), 1023),
195 }
196 }
197 }
198 }
199}