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