2个版本
使用旧的Rust 2015
0.1.1 | 2017年3月29日 |
---|---|
0.1.0 | 2017年3月29日 |
#13 in #volatile
22KB
377 行
volatile内存操作。
此库包含原始指针的包装以执行volatile内存操作。这对于内存映射I/O非常有用。写入外围内存地址通常会被编译器优化掉。类型Volatile
通过包装内存地址以执行volatile操作来强制编译器保持这些内存访问和存储。
Volatile
指针的创建通常是不安全的,但您可以在其上执行的实际操作被认为是安全的。这是因为实际的内存操作是通过定义为由Rust标准定义的safe方法的Deref
和DerefMut
特质来执行的。重要的是要记住,Volatile
指针几乎与原始指针相同,因此对它的所有解引用操作都应被视为不安全的(即使编译器没有强制执行)。
示例
use volatile::Volatile;
const IO_ADDR: *const u32 = 0x4000_4400 as *const _;
unsafe {
let mut io_ptr = Volatile::new(IO_ADDR);
// Some bit that we need to set for an IO operation
*io_ptr |= 0b1 << 5;
}
在某些嵌入式设备上,您可能希望执行某些操作,例如等待由某些tick计数的量度经过的一定时间。
// Some tick counter that may be updated by a hardware interrupt
static mut TICKS: usize = 0;
while unsafe { TICKS < 10 } {/* wait for ticks to change */}
通常,Rust编译器会将这种类型的操作优化为无限循环loop
,因为在单线程环境中,TICKS
的值不能改变,但TICKS
可能会被某些硬件中断更新,所以我们希望不断重新加载该值以检查它。因此,为了解决这个问题,我们可以使用Volatile
指针来强制编译器在每次循环中重新加载该值。
use volatile::Volatile;
static mut TICKS: usize = 0;
unsafe {
let ticks_ptr = Volatile::new(&TICKS);
while *ticks_ptr < 10 {/* wait for ticks to change */}
}
现在,在每次循环中都会重新加载TICKS
的值。
当与内存映射外围设备一起工作时,您通常有一个包含控制、状态和数据寄存器的内存块,这些寄存器用于某些硬件外围设备。这些通常最好表示为具有每个寄存器作为字段的struct,但在没有volatile操作的情况下,对这些内存地址的加载和存储通常会被编译器优化掉。为了解决这个问题,您可以使用Volatile
指针指向映射的地址,并将其表示为正确的类型的struct。
use volatile::Volatile;
const USART_ADDR: *const Usart = 0x4000_4400 as *const _;
// For transmitting and receiving data over serial
#[repr(C)]
struct Usart {
control_reg: u32,
status_reg: u32,
tx_data_reg: u32,
rx_data_reg: u32,
}
let recieved = unsafe {
let mut usart_block = Volatile::new(USART_ADDR);
// Set some bits, these will be hardware specific
usart_block.control_reg |= 0b11 << 5;
while usart_block.status_reg & 0b1 << 7 == 0 {/*wait for hardware to set a bit*/}
// Transmit some data
usart_block.tx_data_reg = 100;
while usart_block.status_reg & 0b1 << 6 == 0 {/*wait for hardware to set some other bit*/}
// Receive some data
usart_block.rx_data_reg
};
指向结构的每个字段访问都将被视为易变,因此编译器不会优化掉。
与原始指针一样,可以从有效的引用安全地创建Volatile
指针,尽管它们的使用仍然应该被视为不安全的。
use volatile::Volatile;
let x: u32 = 0;
let ptr = Volatile::from(&x);