使用AVR反转字节中的位

问题描述 投票:0回答:1

我目前正在解决一个问题,希望我建立一个子程序来反转R16中的位。

00000011 => 11000000
or
10101000 => 00010101

对于该类,我们正在使用AVR子集,并且该子例程需要在norfair中工作。

这是我到目前为止所拥有的,任何帮助将不胜感激!

ldi r16,3 ;00000011
function assembly byte avr atmega
1个回答
1
投票

天真的解决方案是使用移位运算符循环遍历各个位并进行检查。但是请注意,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

进行比较
© www.soinside.com 2019 - 2024. All rights reserved.