Что компилятор C делает с битовыми полями?

Я работаю над встроенным проектом (цель PowerPC, компилятор Freescale Metrowerks Codewarrior), где регистры с отображенной памятью и определяются в хороших битовых полях для создания вертения отдельных битовых флагов легким.

В данный момент мы используем эту функцию для очистки передачи управляющей информации и флагов прерывания. Хотя я еще не заметил ошибок, мне было любопытно, если это безопасно. Есть ли некоторый способ безопасно использовать битовые поля, или сделать я должен перенести каждого в DISABLE_INTERRUPTS... ENABLE_INTERRUPTS?

Разъясниться: заголовок, предоставленный микро, имеет поля как

union {
        vuint16_t R;
        struct {
            vuint16_t MTM:1;        /* message buffer transmission mode */
            vuint16_t CHNLA:1;      /* channel assignement */
            vuint16_t CHNLB:1;      /* channel assignement */
            vuint16_t CCFE:1;       /* cycle counter filter enable */
            vuint16_t CCFMSK:6;     /* cycle counter filter mask */
            vuint16_t CCFVAL:6;     /* cycle counter filter value */
        } B;
    } MBCCFR;

Я предполагаю, что установка немного в битовом поле не является атомарной. Действительно ли это - корректное предположение? Какой код компилятор на самом деле генерирует для битовых полей? Выполнение маски самостоятельно с помощью R (сырые данные), поле могло бы помочь помнить, что операция не является атомарной (легко забыть что присвоение как CAN_A.IMASK1.B.BUF00M = 1 не является атомарным).

Ваш совет ценится.

8
задан Adam Shiemke 21 July 2010 в 13:46
поделиться

6 ответов

Атомарность зависит от цели и компилятора. AVR-GCC, например, пытается определить доступ к биту и выдать инструкцию установки или очистки бита, если это возможно. Проверьте вывод ассемблера, чтобы быть уверенным ...

EDIT: Вот ресурс по атомарным инструкциям на PowerPC прямо из уст лошади:

http://www.ibm.com/developerworks/library/pa-atom/

3
ответ дан 5 December 2019 в 14:00
поделиться

Правильно предположить, что установка битовых полей не атомарна. В стандарте C не совсем ясно, как должны быть реализованы битовые поля, и различные компиляторы используют их по-разному.

Если вас действительно интересуют только ваша целевая архитектура и компилятор, дизассемблируйте некоторый объектный код.

Как правило, ваш код достигает желаемого результата, но он намного менее эффективен, чем код, использующий макросы и сдвиги. Тем не менее, вероятно, более читабельно использовать ваши битовые поля, если вы не заботитесь о производительности здесь.

Вы всегда можете написать функцию-оболочку установщика для атомарных битов, если вас беспокоит, что будущие программисты (включая вас самих) будут сбиты с толку.

3
ответ дан 5 December 2019 в 14:00
поделиться

Да, ваше предположение верно в том смысле, что вы не можете предполагать атомарность. На конкретной платформе вы можете получить его в качестве дополнения, но вы ни в коем случае не можете на него полагаться.

В основном компилятор выполняет маскировку и другие вещи за вас. Он мог бы воспользоваться угловыми случаями или особыми инструкциями. Если вас интересует эффективность, посмотрите на ассемблер, который ваш компилятор производит с этим, обычно это весьма поучительно. Как правило, я бы сказал, что современные компиляторы производят код, который настолько эффективен, насколько это могут быть средние усилия по программированию. По-настоящему глубокая перемотка битов для вашего конкретного компилятора, возможно, может дать вам несколько циклов.

3
ответ дан 5 December 2019 в 14:00
поделиться

Я считаю, что использование битовых полей для моделирования аппаратных регистров - не лучшая идея.

То, как битовые поля обрабатываются компилятором, определяется реализацией (включая то, как обрабатываются поля, охватывающие границы байтов или слов, проблемы с порядком байтов, и как именно реализовано получение, установка и очистка битов). См. C / C ++: Force Bit Field Order and Alignment

Чтобы убедиться, что обращения к регистрам обрабатываются так, как вы могли ожидать или требовать от них обработки, вам необходимо внимательно изучить документацию компилятора и / или посмотреть на выданный код. Я полагаю, что если заголовки, поставляемые с набором инструментов микропроцессора, используют их, можно предположить, что большинство моих проблем решено. Однако я бы предположил, что атомарный доступ не обязательно ...

Я думаю, что лучше всего обрабатывать этот тип доступа на битовом уровне к аппаратным регистрам с помощью функций (или макросов, если необходимо), которые выполняют явные операции чтения / изменения / записи с нужной вам битовой маской, если это то, что вам нужно. процессор требует.

Эти функции могут быть изменены для архитектур, поддерживающих доступ на атомарном битовом уровне (например, адресация ARM Cortex M3 с «полосой битов»). Я не знаю, поддерживает ли PowerPC что-либо подобное - M3 - единственный процессор, с которым я имел дело, который поддерживает его в целом. И даже бит-полосность M3 поддерживает 1-битный доступ; если вы имеете дело с полем шириной 6 бит, вам нужно вернуться к сценарию чтения / изменения / записи.

3
ответ дан 5 December 2019 в 14:00
поделиться

Это полностью зависит от архитектуры и компилятора, являются ли операции битового поля атомарными или нет. Мой личный опыт подсказывает: не используйте битовые поля, если они вам не нужны.

0
ответ дан 5 December 2019 в 14:00
поделиться

Я почти уверен, что на powerpc это не атомарно, но если ваша цель - одноядерная система, то вы можете просто:

void update_reg_from_isr(unsigned * reg_addr, unsigned set, unsigned clear, unsigned toggle) {
   unsigned reg = *reg_addr;
   reg |= set;
   reg &= ~clear;
   reg ^= toggle;
   *reg_addr = reg;
}

void update_reg(unsigned * reg_addr, unsigned set, unsigned clear, unsigned toggle) {
   interrupts_block();
   update_reg_from_isr(reg_addr, set, clear, toggle);
   interrupts_enable();
}

Я не помню, являются ли обработчики прерываний powerpc прерываемыми, но если да, то вы должны просто всегда использовать вторую версию.

Если ваша цель - многопроцессорная система, то вы должны сделать блокировки (spinlocks, которые отключают прерывания на локальном процессоре, а затем ждут, пока другие процессоры закончат с блокировкой), которые защищают доступ к таким вещам, как аппаратные регистры, и получить необходимые блокировки до того, как вы получите доступ к регистру, а затем освободить блокировки сразу после того, как вы закончите обновление регистра (или регистров).

Однажды я читал, как реализовать блокировки в powerpc - это включало в себя указание процессору следить за шиной памяти для определенного адреса, пока вы выполняете некоторые операции, а затем проверять в конце этих операций, был ли записанный адрес другим ядром. Если нет, то операция была успешной, если да, то нужно было повторить операцию. Это было в документе, написанном для разработчиков компиляторов, библиотек и ОС. Я не помню, где я его нашел (возможно, где-то на IBM.com), но если немного поискать, он должен найтись. Вероятно, там также есть информация о том, как выполнять атомарную перестановку битов.

0
ответ дан 5 December 2019 в 14:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: