Я начинаю взламывать микроконтроллеры, и хотя мне очень удобно работать с побитовыми операторами и говорить прямо с аппаратными средствами, я нахожу полученный код очень многословным и стандартным. Программист более высокого уровня во мне хочет найти эффективный, но действенный способ убрать это.
Например, в регистрах много настроек:
/* Provided by the compiler */
#define SPIE 7
#define SPE 6
#define DORD 5
#define MSTR 5
#define CPOL 4
#define CPHA 3
void init_spi() {
SPCR = (1 << SPE) | (1 << SPIE) | (1 << MSTR) | (1 << SPI2X);
}
К счастью, есть макросы, которые скрывают фактические операции ввода-вывода порта (слева), поэтому это выглядит как простое назначение. Но весь этот синтаксис для меня грязный.
Требования:
- он должен обрабатывать только до 8 бит,
- битовые позиции должны передаваться в любом порядке, а
- должен требовать только передачи установленных битов.
Синтаксис, который мне нужен:
SPCR = биты (SPE, SPIE, MSTR, SPI2X);
Лучшее, что я до сих пор придумал, это комбинированный макрос / функция:
#define bits(...) __pack_bits(__VA_ARGS__, -1)
uint8_t __pack_bits(uint8_t bit, ...) {
uint8_t result = 0;
va_list args;
va_start(args, bit);
result |= (uint8_t) (1 << bit);
for (;;) {
bit = (uint8_t) va_arg(args, int);
if (bit > 7)
break;
result |= (uint8_t) (1 << bit);
}
}
Это компилирует до 32 байтов в моей конкретной архитектуре и требует 61-345 циклов для выполнения (зависит от того, сколько битов было передано).
В идеале это должно быть сделано в препроцессоре, поскольку результат является константой, а машинные инструкции вывода должны быть просто присвоением 8-битного значения регистру.
Можно ли сделать это лучше?