我目前正在解决一个问题,希望我建立一个子程序来反转R16中的位。
00000011 => 11000000
or
10101000 => 00010101
对于该类,我们正在使用AVR子集,并且该子例程需要在norfair中工作。
这是我到目前为止所拥有的,任何帮助将不胜感激!
ldi r16,3 ;00000011
天真的解决方案是使用移位运算符循环遍历各个位并进行检查。但是请注意,AVR没有barrel shifter,因此只能移位1 any other shift counts need more than 1 instruction。这是著名的bithacks页面的obvious solution
uint8_t reverse_obvious(uint8_t v)
{
uint8_t r = v & 1; // r will be reversed bits of v; first get LSB of v
uint8_t s = sizeof(v) * CHAR_BIT - 1; // extra shift needed at end
for (v >>= 1; v; v >>= 1)
{
r <<= 1;
r |= v & 1;
s--;
}
r <<= s; // shift when v's highest bits are zero
return r;
}
以上代码段仅使用移位1,但最后一个r <<= s
需要在AVR中循环。您可以通过始终运行8个循环来避免这种情况
uint8_t reverse(uint8_t x)
{
uint8_t mask_up = 0x01;
uint8_t mask_down = 0x80;
uint8_t result = 0;
for (; mask_down; mask_down >>= 1, mask_up <<= 1)
{
if (x & mask_up)
result |= mask_down;
}
return result;
}
另一种偏移量为2的替代方法,但是我想这是不使用查找表的最佳方法。 AVR有足够的可用ROM,因此这种方式应该效率更高]
进行比较uint8_t reverse(uint8_t x) { x = (((x & 0xaaU) >> 1) | ((x & 0x55U) << 1)); x = (((x & 0xccU) >> 2) | ((x & 0x33U) << 2)); x = (((x & 0xf0U) >> 4) | ((x & 0x0fU) << 4)); return x; }
关于反转位,还有很多关于SO的好的答案。尝试将C代码转换为汇编并与result on compiler explorer