Реверсивные биты в байте с AVR - PullRequest
0 голосов
/ 13 апреля 2020

В настоящее время я работаю над проблемой, которая требует, чтобы я создал подпрограмму, которая обратит биты в R16.

00000011 => 11000000
or
10101000 => 00010101

Для класса мы используем подмножество AVR, и подпрограмма должна работать в norfair.

Это то, что я имею до сих пор, любая помощь будет оценена!

ldi r16,3 ;00000011

1 Ответ

3 голосов
/ 14 апреля 2020

Наивным решением является l oop через биты с оператором сдвига и проверка. Но имейте в виду, что AVR не имеет бочкообразного переключателя , поэтому он может сдвигаться только на 1, , для любого другого сдвига требуется более 1 инструкции . Вот одно очевидное решение со страницы знаменитых битхаков

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 требуется oop. Вы можете избежать этого, всегда выполняя 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 имеет много доступного ПЗУ для таблицы, поэтому он должен быть намного более эффективным:

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;
}

Некоторые компиляторы также имеют встроенные модули для инвертирования битов. Например, Clang имеет __builtin_bitreverse8(), а G CC имеет __builtin_avr_insert_bits(), которые можно использовать для инвертирования битов:

// reverse the bit order of bits
__builtin_avr_insert_bits (0x01234567, bits, 0)

К сожалению их ужасные результаты


На SO также есть много вопросов с хорошими ответами о реверсировании битов. Попробуйте преобразовать код C в сборку и сравнить с результатом в проводнике компилятора

...