Есть ли способ адресовать один бит в C?

Привет, я провел некоторое исследование по бито адресуемым микроконтроллерам. Единственный, что попадалось на моем пути, - это Intel MCS-51 (wiki page), который до сих пор используется очень часто... я было интересно, можете ли вы напрямую обратиться к бит в C, например, на SFR wiki 8051 архитектура памяти.

Биты, которые я адресую в SFR, являются ли они бит адресованы напрямую, или это побитовая операция в битовом поле, которое адресовано байтом, или это что-то еще полностью?

В частности, отсюда: Проверить, установлен ли один бит, похоже, что бит напрямую обрабатывается с помощью MOV, мне интересно, возможно ли это в C (с расширениями) или он выглядит только как побитовая операция, но в фоновом режиме есть некоторые материалы компилятора, которые используют только байты?

В качестве последующего вопроса есть ли какие-либо битовые адресуемые современные процессоры?

Ответ 1

Это не редкость. Например, SDCC (Small Device C Compiler) - популярный компилятор для MCS-51. Здесь вы найдете руководство здесь. Наиболее подходящий раздел - 3.4.1, он описывает языковые расширения для MCS-51:

3.4.1.6 __bit

Это спецификация типа данных и класса хранения. Когда переменная объявленный как бит, он выделяется в адресную память с битами 8051, например:

 __bit test_bit;

Запись 1 в эту переменную генерирует код сборки:

 D2*00 setb _test_bit

Бит-адресная память состоит из 128 бит, которые расположены из 0x20 - 0x2f в памяти данных. Помимо этого 8051 определенного класса хранения большинство архитектур поддерживают бит-поля ANSI-C4. В соответствии с ISO/IEC 9899 биты и битовые поля без явного подписанного модификатора реализованы как unsigned.

Ответ 2

В простой C (без каких-либо расширений, какими бы они ни были), вы можете объявить переменную как поле бит. Он может сэкономить много набранных данных и меньше подвержен ошибкам.

Вот пример программы. Он объявляет бит поле с объединением с обычным типом того же размера.

#include <stdio.h>

int main(int argc, char *argv[])
{
    typedef struct 
    {
        union
        {
            struct {
                int bit0:1;
                int bit1:1;
                int bit2:1;
                int bit3:1;
                int bit4:1;
                int bit5:1;
                int bit6:1;
                int bit7:1;
            };
            unsigned char byte;
        };
    } EigthBits;

    EigthBits b;

    b.byte = 0;
    printf("Will be 0 ==> %d\n", b.byte);

    b.bit4 = 1;
    printf("Will be 16 ==> %d\n", b.byte);
}

Выведет этот вывод:

    Will be 0 ==> 0
    Will be 16 ==> 16

Полезно устанавливать значения для отдельного бита в регистре управления, например. Вы можете установить больше бит (например, int two_bits:2;) в соответствии с вашими потребностями.

Ответ 3

В C вы обычно читаете один байт, а затем замаскируете бит, который хотите, но некоторые компиляторы, специфичные для процессора, предварительно определяют регистры или даже отдельные биты для вас. Например, руководство пользователя Keil Cx51 определяет bit и sfr.

Вы использовали бы тип sfr следующим образом:

sfr P0 = 0x80;    // Port 0 is accessed at address 80h.
P0 = 0x20;        // Write 20h to Port 0.

Чтобы использовать метод byte-at-time, вы сделали бы что-то вроде этого:

#define SFR (* (unsigned char *) 0x80)  // Address of SFR is 0x80.

#define BIT0 0x01  // LSB of any byte
#define BIT1 0x02
#define BIT2 0x04
. . .
#define BIT7 0x80  // MSB of any byte

// Read BIT1 of SFR. sfrBit1 is 1 if BIT1 is set, 0 if not.
unsigned char sfrBit1 = SFR & BIT1  ?  1 : 0;

// Set BIT0 of SFR.
SFR |= BIT0;

// Clear BIT2 of SFR.
SFR &= ~BIT2;

Для удобства вы можете определить макросы утилиты для установки и очистки отдельных битов:

#define SET(reg, bit) reg |=  (1 << bit)  // Sets a bit in reg.
#define CLR(reg, bit) reg &= ~(1 << bit)  // Clears a bit in reg.

SET(SFR, 1); // Set BIT1 
CLR(SFR, 2); // Clear BIT2

Ответ 4

Процессор 8051 определяет несколько инструкций, чтобы адресовать один бит для очистки до 0, установить значение 1 или проверить значение, за которым следует условная ветвь, чтобы обходить следующий код, если бит был установлен или очищен.

Эти инструкции очень эффективны, используя только 2 байта. Первый байт определяет инструкцию, а второй - операнд, который идентифицирует, какой бит использовать, из 256 бит.

Первые 128 бит ссылаются на 16 SFR-байтов (бит 0-7 на адрес 0x80 для P0, бит 8-15 для SFR в addreess 0x88 для P1 и т.д. до бит 120 до 127 для SFR 0xF8).

Следующие 128 бит, как описано выше Хансом Пассантом, ссылаются на 16 байт внутренней памяти между 0x20 и 0x2F.

8051 фактически считывает весь байт, тестирует, устанавливает или очищает указанный бит и записывает все 8 бит обратно в одно и то же место (кроме теста). Помимо эффективности, эта инструкция также не модифицирует какой-либо регистр, такой как R0-R7, аккумулятор и т.д.

Компилятор C может легко принять более 128 "__бит" переменных и заменить эффективный код ассемблера, упомянутый выше, на классические операции маскирования, описанные большинством людей. Тем не менее, самым простым решением, реализованным компилятором Keil, является объявление ошибки при использовании более 128 битных переменных.

Есть некоторые DSP и графические процессоры, которые могут адресовать определенное количество бит. Это может быть очень полезно при написании эффективного алгоритма сжатия, некоторой процедуры рисования и т.д. Например, TMS34010 от Texas Instruments может определять две группы регистров, используя различное количество бит для каждого доступа к памяти. Цикл может читать, например, 3 бит за раз, используя регистр из первой группы и записывать 11 бит, используя регистр во второй группе. Внутренне контроллер памяти все еще читал 16 бит и записывал 16 бит и изменял только указанное количество бит внутри каждого 16-битного слова. Все операции с памятью ссылаются на бит, а не на слово. Например, счетчик программ увеличивается на 16 при выполнении каждой команды. Аппаратное обеспечение создало бы исключение, если бы нижние биты были бы не равны нулю, но для выполнения какого-либо типа запутывания Техасскому прибору было бы легко сделать чип, который согласился бы прочитать код операции с некоторым сдвигом бит.

Изобретатели языка C предсказывали, что в один прекрасный день может быть какой-то процессор, который может быть адресован по битам. Они объяснили, что текущее ограничение чтения/записи целого слова при использовании битовых структур (как описано Ixe013) может быть снято в будущем. К сожалению, процессоры с битовыми адресами не получили большого внимания в мире программного обеспечения.

Ответ 5

В "C (с расширениями) все возможно", потому что C с расширениями может быть любым диалектом, принося вам программный эквивалент пирога в небе.

В стандарте ISO C наименьшей индивидуально адресуемой единицей хранения является байт, представленный типами символов.

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

Если процессор может адресовать биты, возможно, один из способов получить это через встроенный ассемблерный язык компилятора C, если он имеет такую ​​вещь. Или связанные с внешним языком ассемблерные процедуры.

Ответ 6

Это зависит от того, что вы подразумеваете под "способом обращения". Нет никаких проблем при написании функций set_bit(address, bit, value), get_bit(address, bit, value), которые будут выполнять такие действия. Однако get_bit вернет вам char, по крайней мере, который является байтом.

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