Verilog: Лексические конструкции и правила написания кода
Статьи по теме

Лексическая структура языка Verilog
Исходные текстовые файлы языка Verilog представляют собой последовательность лексических элементов, состоящих из одного или нескольких символов. Расположение элементов исходного кода имеет свободный формат, т.е. пробелы, символы табуляции, пустые строки синтаксически безразличны. Однако пробелы и пустые строки очень важны для структурирования исходного кода, что повышает его читабельность.
В языке имеют место следующие лексические элементы:
• Операторы
• Пробелы и комментарии
• Числа
• Строки
• Идентификаторы
• Ключевые слова
Эти лексические элементы будут рассмотрены в этом разделе.
Операторы Verilog
Операторы Verilog HDL могут иметь от одного до трех символов и будут подробно рассмотрены в параграфе 4.2 «Операторы языка Verilog». Операторы могут быть унарными и бинарными, а также есть один оператор который имеет три операнда – условный оператор. Унарные операторы располагаются слева от своего операнда. Бинарные операторы располагаются между операндами. Условный оператор имеет два символа, разделяющие операнды.
Пробелы и комментарии
К пробелам в языке относятся собственно пробелы, символы табуляции, пустые строки. Verilog HDL игнорирует эти символы, кроме случаев, когда они разделяют лексические элементы. Также пробелы и символы табуляции не игнорируются в строках. В языке Verilog приняты две формы для ввода комментариев. Однострочные комментарии начинаются с символов // и заканчиваются концом строки. Многострочные комментарии или иначе блочные комментарии начинаются с символов /* и заканчиваются символами */. Многострочные комментарии не могут быть вложенными, но однострочный комментарий внутри блочного допустим.
Запись чисел в Verilog
Числа или иначе константы могут определяться в десятичном, шестнадцатеричном, восьмеричном или двоичном форматах. В языке Verilog предусмотрены две формы для записи чисел. Первая форма представляет собой простое десятичное число как последовательность цифр от 0 до 9 и опционально может предваряться символами плюса или минуса. Вторая форма представления чисел имеет следующий формат:
1 |
<size> <base_format> <number> |
Поле size содержит десятичные цифры и указывает разрядность константы в битах. Это поле опционально и может опускаться в случаях если разрядность константы заранее определена (Допустим производится присвоение константного значения переменной, разрядность которой задана при ее объявлении). Если разрядность не определена, то разрядность принимается по умолчанию равной 32 (32 в большинстве систем синтеза, в некоторых разрядность по умолчанию может отличаться).
Второе поле base_format содержит букву, определяющую формат представления числа (десятичный, двоичный …). Эта буква предваряется символом одиночной кавычки (‘). Формат представления определяется следующими буквами: d – десятичный; h – шестнадцатиричный; o – восьмеричный и b – двоичный. Допускается вводить эти буквы как прописными, так и строчными.
Последнее поле number содержит цифры допустимые для выбранного формата:
от 0 до 9 для десятичного формата;
от 0 до 7 для восьмеричного;
0 и 1 для двоичного;
от 0 до 9 и буквы a, b, c, d, e, f для шестнадцатеричного.
Буквенные обозначения могут вводится как строчными, так и прописными буквами.
Числа имеющие знаковое представление предваряются опциональными символами плюса и минуса перед полем size. Эти символы перед полем number недопустимы. Запись -8’h5A эквивалентна записи -(8’h5A), а запись 8’h-5A вызовет синтаксическую ошибку.
Помимо указанных цифр в поле numbers могут присутствовать буквы x, X, z, Z и символ (?) (В поле size они недопустимы). Буквы x и X обозначают неизвестное (неопределенное) состояние, т.е. состояние соответствующих битов неизвестно. Буквы z и Z обозначают состояние высокого импеданса – z-состояние или отсутствие источника (драйвера). Символ ? эквивалентен символу z и предназначен для лучшей читабельности кода в случаях когда это состояние безразлично (don’t-care).
Существует возможность сокращать запись числа: например 8’b1 будет эквивалентно записи 8’b11111111, но запись 8’b01 будет эквивалентна записи 8’b00000001. В силу того, что такие сокращенные записи могут мешать читабельности кода, употреблять их без особой надобноси не следует, пожалуй допустимыми можно считать записи 8’b0, 8’b1, 8’bx, можно записать и 16’hx – это эквивалентно 16’hxxxx. В остальных случаях лучше делать подробную запись числа.
Для улучшения читабельности допускаются еще два приема: допускается вставлять пробелы и символы табуляции между полями записи, например 8’hB6 можно записать как 8 ‘h B6. Вставлять пробелы внутри поля number не допускается, но можно вставлять символ подчеркивания (_), для разбиения числа на некоторые группы. Примеры 83465 можно записать как 83_465; 8’b01100111 можно записать как 8’b0110_0111. Символ подчеркивания в поле size или перед полем number недопустим.
Строки в языке Verilog
Строками в языке Verilog являются последовательностями символов, заключенных в двойные кавычки и располагающиеся в одной линии (одной строке исходного кода). Строки могут использоваться в языке как операнды в выражениях представляя собой последовательность 8-и разрядных (байтовых) ASCII-кодов, где один ASCII-символ представляется как одна буква, цифра или специальный символ. Более подробно об использовании строк в языке рассказывается в пункте 4.3.3 “Строки”.
Идентификаторы, ключевые слова, системные имена Verilog
Идентификаторы, ключевые слова и системные имена строятся по одним и тем же правилам, поэтому они и объединены в данный параграф. Общие правила следующие:
• Идентификаторы не должны совпадать с ключевыми словами;
• Идентификаторы не могут начинаться с символов ($) или ( ‘ – апостроф);
• Идентификатор не может начинаться с цифры;
• Длина идентификатора по стандарту не ограничена, но может ограничиваться в конкретном компиляторе;
• Ключевые слова всегда пишутся строчными буквами;
• Системные имена начинаются с символа ($);
• Директивы компилятора начинаются с символа ( ‘ – апостроф);
• Компилятор различает строчные и прописные буквы.
Идентификаторы
Идентификаторы используются в языке Verilog в качестве символических имен для обозначения переменных, констант, модулей, функций, задач и т.д. и могут использоваться для обозначения этих объектов в любом месте описания. Идентификатор представляет собой последовательность из букв, цифр, символов доллара ($) и символов подчеркивания (_) с учетом изложенных выше правил. Другие символы могут использоваться только если идентификатор начинается с символа \ (escaped identifiers) – в этом случае он может содержать все печатные символы. Заканчивается такой идентификатор пробелом, символом табуляции или новой строкой.
Замечание: Обычные идентификаторы могут содержать только буквы латинского алфавита, Для использования букв другого алфавита необходимо идентификатор начинать с символа \. Подобные идентификаторы могут не поддрживаться некоторыми компиляторами.
Поскольку компилятор различает строчные и прописные буквы, можно ввести допустим такой: Module – это слово совпадает по произношению с ключевым словом module, но компилятор ошибки не выдаст, поскольку слово начинается с прописной буквы. Такая возможность есть, но строго не рекомендуется вводить идентификаторы, отличающиеся от ключевых слов только регистром, это потенциально приведет к путанице в будущем и говорит о низкой квалификации разработчика.
Идентификаторы по возможности должны отражать свойства объекта к которому они принадлежат, это повышает самодокументированность кода. Например лучше написать Shifter, чем Sftr: в первом случае понятно, что идет речь о сдвиговом регистре, а что имелось в виду во втором случае не очень. Следует избегать в качестве идентификаторов одиночных букв, особенно a, b, c, d, e, f, x, z, h, b, o – в любом регистре они совпадают с резервированными обозначениями.
К сожалению к языку Verilog не разработано чего-либо похожего на «Венгерскую нотацию» как в языке С, поэтому давать какие-либо общие рекомендации трудно, но есть несколько простых правил, улучшающие читабельность кода:
• Поскольку все ключевые слова прописываются строчными буквами, идентификаторы имен переменных, модулей и т.п. лучше начинать с прописной буквы а продолжать строчными.
• Идентификаторы – имена портов или параметров – лучше писать прописными буквами целиком, в любом месте кода будет понятно с чем мы имеем дело – с портом или с обычной переменной.
• Имена портов или переменных на котором действуют сигналы с активным уровнем в лог.0 лучше начинать со строчной буквы n (negative), это помогает избегать ошибок, связанных с некорректным активным уровнем сигнала (значением переменной). Вместо буквы n можно использовать символ подчеркивания (_).
• Желательно разработать для себя и дополнительные правила, которые помогут вам или другому разработчику легче разбираться в исходном коде.
Ключевые слова
Ключевыми словами начинаются предопределенные идентификаторы, используемые для определения языковых конструкций. Ключевое слово предваряемое символом \ ключевым словом уже не является и компилятором интерпретируется как обычный идентификатор. Использовать этот прием строго не рекомендуется (см. пункт выше). Все ключевые слова прописываются только строчными буквами. В документе ключевые слова прописываются полужирным курсивом. Ниже приведен список ключевых слов языка Verilog.
always | event | or | strong1 |
and | for | output | supply0 |
assign | force | parameter | supply1 |
begin | forever | pmos | table |
buf | fork | posedge | task |
bufif0 | function | primitive | time |
bufif1 | highz0 | pull0 | tran |
case | highz1 | pull1 | tranif0 |
casex | if | pullup | tranif1 |
casez | initial | pulldown | tri |
cmos | inout | rcmos | tri0 |
deassign | input | reg | tri1 |
default | integer | release | triand |
defparam | join | repeat | trior |
disable | large | rnmos | trireg |
edge | macromodule | rpmos | vectored |
else | medium | rtran | wait |
end | module | rtranif0 | wand |
endcase | nand | rtranif1 | weak0 |
endmodule | negedge | scalared | weak1 |
endfunction | nmos | small | while |
endprimitive | nor | specify | wire |
endspecify | not | specparam | wor |
endtable | notif0 | strength | xnor |
endtask | notif1 | strong0 | xor |
Системные имена и директивы компилятора
К системным именам относятся имена системных задач и функций предопределенные в стандарте Verilog HDL. Все системные имена начинаются с символа ($), поэтому спутать с обычным идентификатором их трудно (идентификатор не может содержать этот символ в начале). Полный список системных имен здесь не приводится, поскольку они будут подробно рассмотрены в разделе “Системные функции и задачи”. Системные имена всегда вводятся строчными буквами. В документе системные имена выделяются полужирным шрифтом, например $display. К директивам компилятора относятся предопределенные стандартом идентификаторы, предваряемые символом апострофа (‘). Директивы компилятора вводятся строчными буквами. Директивы компилятора будут подробно рассмотрены в разделе “Директивы компилятора”. В документе они также выделяются полужирным шрифтом, например ‘define, ‘include.