Где-то в моей среде есть большой файл, который содержит (помимо прочего) множество 64-битных структур System Verilog, например.:
typedef struct packed {
logic [63:63] my_field_1;
logic [62:60] my field_2;
...
logic [0:0] my field_n;
} my_struct_1_t;
Мне нужен способ преобразовать это в структуры C/CPP с битовыми полями. например
struct my_struct_1_t {
uint64_t my_field_n:1;//This is the LSB
...
uint64_t my_field_2:3;
uint64_t my_field_1:1;//This is the MSB
};
Я понятия не имею, как это сделать, поэтому буду признателен за любую помощь (на любом языке/скрипте оболочки и т. д.).
Спасибо!
@Lundin - что ты имеешь в виду, говоря, что в C нет четко определенного битового поля? Я работал с ним много лет... И, судя по моему опыту, порядок также четко определен (LSB вверху. MSB внизу). Кроме того, uint64_t существует, если вы добавите #include <inttypes.h>
Это похоже на то, что компилятор verilog должен уметь генерировать, хотя и с метрической тонной макросов...
Раздел о битовых полях в стандарте C просто слишком расплывчат и содержит слишком много аспектов, определяемых реализацией, чтобы быть полезным; компиляторы могут просто реализовывать битовые поля более или менее по своему усмотрению, и это делает их непереносимыми и непредсказуемыми. См. например это. Кроме того, стандарт C охватывает только типы bool
, signed int
и unsigned int
, но uint64_t
вряд ли является одним из них.
@Botje - интересное направление... Хотя я больше склоняюсь к манипулированию текстом (просматриваю исходный файл, манипулирую содержимым и печатаю его в файл .h), но также рассмотрю вашу идею. Есть еще подсказки о том, по каким ключевым словам искать в документации компилятора?
Без понятия. Я был потребителем таких сгенерированных заголовочных файлов, но не участвовал в их производстве.
Спасибо @Botje — попробую спросить у компиляторов из моей компании.
Обратите внимание, что это не должно быть отмечено тегами C и C++ одновременно, поскольку это разные языки. C++, по крайней мере, попытался спасти сломанный стандарт с введением std::bitset
. Судя по всему, C намерен навсегда остаться сломанным.
@Lundin - насчет битового поля - очень интересно, я понятия не имел... Спасибо, что сообщили мне. Но давайте предположим, что я всегда использую один и тот же компилятор (gcc/g++), поэтому меня не беспокоит переносимость. Из прошлого опыта я знаю, что gcc дает детерминированные результаты относительно местоположения битового поля.
@Benny80 Benny80 Если вы сможете найти документацию gcc об «ABI» для конкретной цели и сослаться на нее, вполне возможно создать что-то, что будет работать в этих конкретных условиях. Однако написание кода с использованием битовых масок и битовых сдвигов сделало бы его переносимым, но тогда вам, возможно, придется удалить структуру.
Существует также вопрос, как эти «логические» переменные должны быть представлены аппаратному обеспечению. Можете ли вы написать отдельные биты? Байты? Слова? Четверные слова? Лучше всего придерживаться непрозрачного char[]
blob с атомарной операцией чтения/записи.
@Botje - HW может получить доступ к отдельным битам.
@Лундин - я начинаю думать, что ты прав, а битовые маски и сдвиги более надежны. Но я оставляю вопрос открытым, поскольку, если кто-нибудь предложит хороший способ выполнить преобразование, о котором я просил, - оно подойдет для моих нужд.
А как обновить my_field_2
, состоящий из трех битов? LSB в MSB? MSB в LSB? С середины? Есть ли регистр-защелка, который вам нужно запустить для отправки обновления?
@Botje Аппаратное обеспечение выполняет чтение-изменение-запись. И моей программе на C/C++ просто нужен доступ к этой структуре, чтобы иметь возможность анализировать некоторые необработанные данные (я получаю полные 64-битные данные, и мне нужно знать, какое поле и в каком месте находится).
Вы пытаетесь перевести код SystemVerilog на C/C++ или пытаетесь взаимодействовать с исполняемым кодом SystemVerilog в моделировании?
@ dave_59 - просто переведите структуры с одного языка на другой. Никакого взаимодействия с симуляцией.
Как следует из многих комментариев, использование битовых полей C может быть немного рискованным. Определенного представления в памяти не существует, поэтому приходится экспериментировать с компиляторами и, возможно, с кучей #pragmas, чтобы получить работоспособную комбинацию.
Существуют три варианта.
Вы можете написать код для явного манипулирования данными, чтобы изолировать биты каждого поля, и создать структуру, в которой просто есть int/bools (без битовых полей), чтобы содержать проанализированные данные. Простая функция для изоляции и возврата любой заданной последовательности бит/бит в виде int64 сделала бы это намного проще.
Это технология сериализации, которая имеет несколько форматов проводов. Интерес представляют uPER — правила невыровненного упакованного кодирования. Вы можете относительно легко написать схему ASN.1, которая, используя uPER, сможет генерировать и анализировать ваши данные. Например, в uPER логическое значение превращается в один бит. ЦЕЛОЕ ЧИСЛО (0..15) становится 4-битным. Если у вас был PDU ASN.1, например
MyStruct ::= SET OF
{
my_field_1 [0] BOOLEAN, -- 1 bit
my_field_2 [1] INTEGER (0..7), -- 3 bits as an integer
etc
}
компилятор ASN.1 будет генерировать код C/C++, который анализирует/записывает его в проводном формате uPER, и это будет соответствовать вашей структуре данных. Это немного похоже на вариант 1, за исключением того, что компилятор ASN.1 пишет код, а мы используем спецификацию формата uPER для «приведения в соответствие» с вашими данными.
Этот компилятор ASN.1 , вероятно, справится со своей задачей, и я могу порекомендовать эту веб-страницу для обзора, эту игровую площадку , чтобы попробовать что-то, и книгу Дюбюиссона, доступную здесь бесплатно. Вы также можете преобразовать схему ASN.1 в схему XML (XSD), что дает вам больше возможностей для передачи данных, когда вы и получатель работаете с одной и той же схемой.
В то время как ASN.1 — это «абстрактная синтаксическая нотация №1», CSN.1 — это «конкретная синтаксическая нотация №1».
Целью ASN.1 является определение того, какой информацией необходимо обмениваться, не заботясь о том, как она представлена в сети (отсюда и распространение для нее двоичных и текстовых форматов передачи данных). Целью CSN.1 является определение того, какой информацией необходимо обмениваться, и абсолютно четкое представление о том, как она должна быть представлена в сети.
Таким образом, с помощью CSN.1 можно определить любой произвольный битовый поток, и компилятор автоматически создаст код, который сможет интерпретировать и записывать ваш битовый поток. Однако инструментов для этого гораздо меньше, и что-то часто идет не так. Если вас интересует этот подход, вы, вероятно, смотрите на один из коммерческих инструментов (например, Objective Systems inc, чей компилятор ASN.1 теперь, я думаю, также обрабатывает CSN.1).
Рекомендация: я бы использовал подход ASN.1. Приятно то, что как только вы это заработаете, ваш код C сможет легко повторно создавать данные в различных форматах, включая XML. Это могло бы немного облегчить жизнь, если появятся более совершенные системы для получения данных.
Компилятор ASN.1 от Objective Systems теперь также поддерживает JER (правила кодирования JSON), поэтому он может довольно легко отправлять данные через Интернет, причем получателю не обязательно знать что-либо об ASN.1 как таковом.
Если вам не хочется экспериментировать с ASN.1 uPER, я бы написал код, который бы самостоятельно обрабатывал биты. Это скучный шаблонный код, но он достаточно прост и надежен. Это было бы намного лучше, чем полагаться на компилятор C, который всегда будет располагать битовые поля так, как вы хотите.
Verilog, в отличие от C, вероятно, имеет четко определенные битовые поля, поэтому здесь не обязательно существует перевод 1 к 1. C не нуждается в поддержке битовых полей
uint64_t
, а в случае, если это так, все равно не совсем точно определено, является лиuint64_t my_field_n:1;
битом 63 или битом 0.