背景
在嵌入式开发过程中,我们经常遇到需要返回从第n bit 到 m bit的值,如下:
比如,在我们想判断 MEMWIDTH 的值是多少的时候,我们需要返回 bit[10:8] 的值,如果一个一个bit去判断那就太麻烦了,那么我们如何使用宏来实现这个功能?
宏代码实现
要实现一个宏,用于返回一个32位寄存器从第n
位开始的width
位的值,可以使用位操作。这个宏将会做两件事:
- 首先,将寄存器向右移动
n
位,使得我们感兴趣的那一段位移到寄存器的最低位。 - 然后,使用位掩码来保留低
width
位,同时清除其他所有位。
以下是实现上述操作的宏定义:
#define GET_BITS(reg, n, width) (((reg) >> (n)) & ((1U << (width)) - 1))
这里:
reg
是要从中提取位的32位寄存器。n
是想要开始提取的起始位(从0开始计数)。width
是想要提取的位宽。
这个宏首先通过((reg) >> (n))
将寄存器向右移动n
位,然后用((1U << (width)) - 1)
创建一个width
位全为1的掩码,并与移位后的寄存器进行与操作(&
),从而只保留最低的width
位。
这个方法的关键在于构造掩码。1U << (width)
将数值1无符号左移width
位,这样就在对应的位置创建了一个单个的1,其余位为0。然后从这个数值中减去1,将那个单一的位以下的所有位都变为1,达到了我们想要的掩码效果。
例如,如果有一个寄存器reg
,想要获取从第5位开始的3位,可以这样调用宏:
uint32_t value = GET_BITS(reg, 5, 3);
这将返回reg
从第5位开始的3位的值。