use rumio::mmio::Lit; use std::{mem::ManuallyDrop, ptr}; struct MmioRegion { ptr: *mut u8, len: usize, cap: usize, } impl MmioRegion { fn new(size: usize) -> (MmioRegion, usize) { let mut region = ManuallyDrop::new(vec![0u8; size]); let (ptr, len, cap) = (region.as_mut_ptr(), region.len(), region.capacity()); (Self { ptr, len, cap }, ptr as usize) } } impl Drop for MmioRegion { fn drop(&mut self) { let _region = unsafe { Vec::from_raw_parts(self.ptr, self.len, self.cap) }; } } rumio::define_mmio_register! { Reg: u16 { rw MODE: 0..1 = enum Mode [ A = 0b00, B = 0b01, C = 0b10, D = 0b11, ], r FOO: 2, rw BAR: 3, rw BAZ: 4, rw FLAGS: 5..8 = flags Flags [ A = 0b0001, B = 0b0010, C = 0b0100, D = 0b1000, ], } } rumio::define_mmio_struct! { pub struct Device { /// foobar (0x00 => one: Reg), (0x08 => two: Reg), (0x0A => lit1: Lit), (0x0E => lit2: Lit), (0x0F => lit3: [Lit; 32]), } } #[test] fn read_write_single_bit() { let (_guard, addr) = MmioRegion::new(16); let mmio = unsafe { Device::new(addr) }; assert!(!mmio.one().FOO().get()); assert!(!mmio.one().BAZ().get()); assert!(!mmio.one().BAR().get()); unsafe { ptr::write_volatile(addr as *mut u8, 0b00010100) }; assert!(mmio.one().FOO().get()); assert!(mmio.one().BAZ().get()); assert!(!mmio.one().BAR().get()); mmio.two().BAR().set(true); assert!(mmio.two().BAR().get()); } #[test] fn read_write_enum() { let (_guard, addr) = MmioRegion::new(16); let mmio = unsafe { Device::new(addr) }; unsafe { ptr::write_volatile(addr as *mut u8, 0b11) }; assert_eq!(mmio.one().MODE().get(), Some(Mode::D)); mmio.one().MODE().set(Mode::A); assert_eq!(mmio.one().MODE().get(), Some(Mode::A)); } #[test] fn read_write_flags() { let (_guard, addr) = MmioRegion::new(16); let mmio = unsafe { Device::new(addr) }; unsafe { ptr::write_volatile(addr as *mut u16, 0b111000000) }; assert_eq!(mmio.one().FLAGS().get(), Flags::B | Flags::C | Flags::D); mmio.one().FLAGS().set(Flags::B | Flags::C); assert_eq!(mmio.one().FLAGS().get(), Flags::B | Flags::C); mmio.two().FLAGS().set(Flags::A | Flags::C); assert_eq!(mmio.two().FLAGS().get(), Flags::A | Flags::C); } #[test] fn read_write_lit() { let (_guard, addr) = MmioRegion::new(16); let mmio = unsafe { Device::new(addr) }; assert_eq!(mmio.lit1().read(), 0); assert_eq!(mmio.lit2().read(), 0); mmio.lit1().write(0xF00D_BABE); mmio.lit2().write(0xAB); assert_eq!(mmio.lit1().read(), 0xF00D_BABE); assert_eq!(mmio.lit2().read(), 0xAB); } #[test] fn read_write_array() { let (_guard, addr) = MmioRegion::new(48); let mmio = unsafe { Device::new(addr) }; for idx in 0..32 { mmio.lit3(idx).write(idx as u8); } for idx in 0..32 { assert_eq!(mmio.lit3(idx).read(), idx as u8); } }