1use std::marker::PhantomData;
6
7use crate::atomic::AtomicMmio;
8use crate::inject::{GenericVmoMemoryHandler, VmoOpHelper};
9use crate::operand::MmioOperand;
10
11pub struct WriteOneToClear<T>(PhantomData<T>);
19
20impl<T> WriteOneToClear<T> {
21 pub fn new() -> Self {
23 Self(PhantomData)
24 }
25}
26
27impl<T> Default for WriteOneToClear<T> {
28 fn default() -> Self {
29 Self::new()
30 }
31}
32
33impl<T> GenericVmoMemoryHandler for WriteOneToClear<T> {
34 fn load<X: MmioOperand>(&self, op: VmoOpHelper<'_, X>) -> X {
35 assert_eq!(std::mem::size_of::<X>(), std::mem::size_of::<T>(), "incorrect width");
36 op.load()
37 }
38
39 fn store<X: MmioOperand>(&self, op: VmoOpHelper<'_, X>, value: X) {
40 assert_eq!(std::mem::size_of::<X>(), std::mem::size_of::<T>(), "incorrect width");
41 let _: X = op.borrow_region().fetch_and(0, !value);
42 }
43}
44
45#[cfg(test)]
46mod tests {
47 use super::*;
48 use crate::CachedVmoMemory;
49 use crate::inject::VmoMemory;
50 use crate::operand::MmioOperand;
51 use crate::operand::tests::OperandCallable;
52 use mmio::MmioExt as _;
53
54 const VMO_SIZE: usize = 4096;
55
56 #[test]
57 fn test_w1c_all_operand_types() {
58 struct W1CTester;
59
60 impl OperandCallable for W1CTester {
61 fn call<T: MmioOperand>(&mut self) {
62 let handler = WriteOneToClear::<T>::default();
63 let mut mmio = CachedVmoMemory::new_mapped(VMO_SIZE).expect("Failed to map VMO.");
64
65 let initial_val = T::try_from(0xff).unwrap();
67 mmio.store::<T>(0, initial_val);
68
69 let mut mmio = mmio.map(|vmo| VmoMemory::new(handler, vmo));
70 assert_eq!(mmio.load::<T>(0), initial_val);
71
72 let clear_bits = T::try_from(0x0f).unwrap();
74 mmio.store::<T>(0, clear_bits);
75
76 let expected_val = T::try_from(0xf0).unwrap();
78 assert_eq!(mmio.load::<T>(0), expected_val);
79 }
80 }
81
82 W1CTester.call_all();
83 }
84
85 #[fuchsia::test(logging = false)]
86 #[should_panic(expected = "incorrect width")]
87 fn test_w1c_load_incorrect_width_panics() {
88 let handler = WriteOneToClear::<u32>::new();
89 let mmio = CachedVmoMemory::new_mapped(VMO_SIZE)
90 .expect("Failed to map VMO.")
91 .map(|vmo| VmoMemory::new(handler, vmo));
92
93 let _ = mmio.load::<u8>(0);
94 }
95
96 #[fuchsia::test(logging = false)]
97 #[should_panic(expected = "incorrect width")]
98 fn test_w1c_store_incorrect_width_panics() {
99 let mut mmio = CachedVmoMemory::new_mapped(VMO_SIZE)
100 .expect("Failed to map VMO.")
101 .map(|vmo| VmoMemory::new(WriteOneToClear::<u32>::new(), vmo));
102
103 mmio.store::<u8>(0, 0x12);
104 }
105}