Я пишу приложение, которое взаимодействует с рядом регистров, определенных в VHDL. Регистры имеют ширину 32 бита и распределены по группам. Мне предоставляется базовый адрес группы и 32-битные смещения для каждого члена группы. Вот пример одной группы, регистра внутри группы и структуры регистра.
В настоящее время ввод-вывод обрабатывается с использованием следующей структуры битового поля:
typedef struct
{
uint32_t data0 : 12;
uint32_t data1 : 1;
...
}volatile data_port;
и изменяя поля с помощью указателя на адреса,
data_port *const p_data = (data_port *)0xc006380;
Хотя это может работать на этой платформе, с текущим компилятором меня беспокоит переносимость. Мне было интересно, есть ли лучший способ обработки интерфейса с оборудованием, когда вы вынуждены использовать эти нетрадиционные типы данных?
Одна альтернатива, которую я могу придумать, - это создать еще один уровень между аппаратным обеспечением и структурами регистров, энергозависимый указатель int без знака и использовать структуру битового поля на уровне приложения. Проблема в том, что данные все равно придется копировать из битовых полей, которые могут быть выровнены по-разному на другой платформе, в int, что может быть совершенно другой темой.
Изменить:
Я думаю, что я действительно ищу способ отказаться от использования битовых полей. Отображение структуры с элементами битового поля на оборудование действительно кажется плохим подходом. Итак, чтобы избежать этого, я буду использовать одно из следующих значений вместо указателя на адрес энергозависимой памяти:
#define PeripheralBase ((uint32_t volatile *)BASE)
or
uint32_t volatile *const peripheral_base = (uint32_t *) BASE;
Надеюсь, как только я дойду до этого момента, все будет хорошо выровнено в 32-битном формате. Один из методов, который я придумал для этого, заключался в том, чтобы создать ту же структуру data_port, но удалить упаковку битов, а затем настроить функцию специально для каждого регистра, чтобы сдвинуть биты в беззнаковое int, которое затем можно было бы передать в регистр, используя изменчивый указатель.
Что-то вроде,
static inline uint32_t struct_to_uint(data_port *data)
{
return data->data0
+ ((uint32_t)data->data1 << 12)
+ ((uint32_t)data->data2 << 13)
+ .....;
}
Я не уверен, что синтаксис правильный, но идея состоит в том, чтобы сдвинуть значения, не беспокоясь о компиляторе или платформе. Это так с тех пор? Есть ли проблемы с переносимостью при таком подходе?
data_port *const p_data = (data_port *)0xc006380;
. Если компилятор изменится (например, на архитектуру x64), он может добавить байты заполнения для оптимизации доступа к членам структуры. - person fvdalcin   schedule 10.10.2013volatile
изtypedef
. Поместите это вvolatile data_port *const p_data = (volatile data_port *) 0xc006380;
. Структура является изменчивой только тогда, когда находится по этому специальному адресу, а не когда она скопирована в какое-то другое место. Попробуйтеuint32_t
вместоalt_u32
. - person chux - Reinstate Monica   schedule 10.10.2013uint32_t
позволяет производить выборку / установку всего регистра и сохранять результат в другой энергонезависимой переменной типаdata_port
для последующих операций чтения и записи битового поля. Кстати: я согласен с вашим подходом на другом уровне. - person chux - Reinstate Monica   schedule 10.10.2013