Функция для генерации соответствующей маски для битового поля - PullRequest
1 голос
/ 30 сентября 2019

У меня есть 32-битный регистр R с различными битовыми полями, объявленными следующим образом:

typedef union {
  uint32_t raw;
  struct {
    uint32_t F1 : 0x4;
    uint32_t F2 : 0x8;
    uint32_t F3 : 0x8;
    uint32_t F4 : 0xC;
  }
} reg1

У меня также есть макрос regWrite, который читает-изменяет-записывает поле в регистр следующим образом:

#define RegWrite(Reg, Field, Addr, Val) do {
  Reg.raw = read32(Addr);
  Reg.Field = Val;
  write32(Addr, Reg.raw);
} while(0)

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

Например, если я вызову regWrite следующим образом:

regWrite(reg1, F2, 0x12345678, 0xC)

Вывод на печать из макроса должен выглядеть примерно так:

set variable1 [read 32 0x12345678]
set variable1 [ ($variable1 & 0xFFFFF00F) | (0xC << 4) ]
write 32 0x12345678 variable1

Как бы я сгенерировал 0xFFFFF00F, и4 внутри макроса? Спасибо!

Ответы [ 2 ]

1 голос
/ 30 сентября 2019

Что ж, в вашем вопросе отсутствует некоторая важная информация, в том числе:

  • Что вы пытаетесь достичь?
  • Почему вам нужно дать только имя члена структуры в качестве аргумента?

Это может быть XY-проблема .

В любом случае, из буквального требования:

Fn ( X ) должен напечатать из 0x Y и Z .

Вы можете сделать это с помощью макроса:

#include <stdint.h>
#include <stdio.h>

struct F {
    uint32_t F1 : 0x4;
    uint32_t F2 : 0x8;
    uint32_t F3 : 0x8;
    uint32_t F4 : 0xC;
};

#define Fn(Fx) do {                    \
    union {                            \
        struct F f;                    \
        uint32_t u;                    \
    } v;                               \
    v.u = 0;                           \
    v.u = ~v.u;                        \
    v.f.Fx = 0;                        \
    uint32_t m = v.u;                  \
    int b;                             \
    for (b = 0; (v.u & 1) != 0; b++) { \
        v.u >>= 1;                     \
    }                                  \
    (void)printf("0x%0X %d\n", m, b);  \
} while (0)

int main(void) {
    /* Fn(F2) should print out 0xFFFFF00F, and 4. */
    Fn(F2);
    /* Fn(F3) should print out 0xFFF00FFF, and 12. */
    Fn(F3);

    return 0;
}

Некоторые примечания к этому взломанному «решению»:

  • Он использует do { ... } while(0), чтобы убедиться, что макрос не может использоваться как выражение, только какоператор.
  • Нет интерпретации Fx, пока она не будет прочитана компилятором в строке v.f.Fx = 0.
  • Код только для C.
  • Каждыйвремя его использования потребует тактов, и ему нужно пространство кода. Это кажется ненужным для константных выражений.
  • Он работает, определяя объединение, которое может использоваться в качестве структуры или результирующего uint32_t.
  • Маска генерируется путем установки всех битов в1, а затем сбрасывает только данный элемент структуры в 0.
  • Смещение битов получается путем поиска первого 0-разрядного справа.

Обратите внимание, чтоСтандарт не дает никаких обещаний о порядке битовых полей в слове памяти («единица измерения»), даже если они находятся в одном и том же слове памяти. Для получения дополнительной информации см. Главу «Спецификаторы структуры и объединения» версии стандарта, которой соответствует ваш компилятор.

Но если вам нужны значения для других целей, вам следует подумать о своей архитектуре и, конечно же, овозможности стандарта C. Как я уже сказал, по-видимому, вы пытаетесь решить совершенно другую проблему. И для этого показанный источник не является решением .

0 голосов
/ 30 сентября 2019

ОК, я нашел время для поиска более подходящего решения.

#include <stdint.h>
#include <stdio.h>

struct F {
    uint32_t F1 : 0x4;
    uint32_t F2 : 0x8;
    uint32_t F3 : 0x8;
    uint32_t F4 : 0xC;
};

typedef union {
    struct F f;
    uint32_t u;
} Fn_type;

uint32_t Fn_mask_helper(Fn_type v) {
    return ~v.u;
}

#define Fn_mask(Fx) Fn_mask_helper((Fn_type){.u=0, .f.Fx=~0})

int Fn_bit_offset_helper(Fn_type v) {
    v.u = ~v.u;
    int b;
    for (b = 0; (v.u & 1) != 0; b++) {
        v.u >>= 1;
    }
    return b;
}

#define Fn_bit_offset(Fx) Fn_bit_offset_helper((Fn_type){.u=0, .f.Fx=~0})

int main(void) {
    uint32_t m2 = Fn_mask(F2);
    int b2 = Fn_bit_offset(F2);
    (void)printf("0x%0X %d\n", m2, b2);
    uint32_t m3 = Fn_mask(F3);
    int b3 = Fn_bit_offset(F3);
    (void)printf("0x%0X %d\n", m3, b3);

    return 0;
}

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

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

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

Примечание. Вам необходим компилятор, соответствующий как минимум C99.

...