我有 32 位寄存器,其字段定义为位掩码,例如
#define BM_TEST_FIELD 0x000F0000
Run Code Online (Sandbox Code Playgroud)
我需要一个宏,它允许我将寄存器(由其地址定义)的字段(由其位掩码定义)设置为给定值。这是我想出的:
#include <stdio.h>
#include <assert.h>
typedef unsigned int u32;
/*
* Set a given field defined by a bit-mask MASK of a 32-bit register at address
* ADDR to a value VALUE.
*/
#define SET_REGISTER_FIELD(ADDR, MASK, VALUE) \
{ \
u32 mask=(MASK); u32 value=(VALUE); \
u32 mem_reg = *(volatile u32*)(ADDR); /* Get current register value */ \
assert((MASK) != 0); /* Null masks are not supported */ \
while(0 == (mask & 0x01)) /* Shift the value to the left until */ \
{ /* it aligns with the bit field */ \
mask = mask >> 1; value = value << 1; \
} \
mem_reg &= ~(MASK); /* Clear previous register field value */ \
mem_reg |= value; /* Update register field with new value */ \
*(volatile u32*)(ADDR) = mem_reg; /* Update actual register */ \
}
/* Test case */
#define BM_TEST_FIELD 0x000F0000
int main()
{
u32 reg = 0x12345678;
printf("Register before: 0x%.8X\n", reg);/* should be 0x12345678 */
SET_REGISTER_FIELD(®, BM_TEST_FIELD, 0xA);
printf("Register after: 0x%.8X\n", reg); /* should be 0x123A5678 */
return 0;
}
Run Code Online (Sandbox Code Playgroud)
有没有更简单的方法来做到这一点?
编辑:特别是,我正在寻找一种方法来减少运行时计算要求。有没有办法让预处理器计算值所需的左移次数?
编辑:特别是,我正在寻找一种方法来减少运行时计算要求。有没有办法让预处理器计算值所需的左移次数?
是的:
value *= ((MASK) & ~((MASK) << 1))
Run Code Online (Sandbox Code Playgroud)
这乘以 中value的最低设置位MASK。已知乘数在编译时是 2 的常数幂,因此这将被任何远程理智的编译器编译为简单的左移。