Digitrode
цифровая электроника вычислительная техника встраиваемые системы
Verilog. Базовый курс. Часть I
Проектирование схем на ПЛИС представляет собой не менее увлекательное и творческое занятие, чем программирование микроконтроллеров. Поэтому ниже будут показаны основы основ проектирования на языке Verilog, которые, возможно, станут отправной точкой для новичков в этом деле.
Перед началом изучения Verilog читатель должен иметь базовые представления о булевой логике и уметь решать хотя бы простейшие логические выражения. Например, чему будет равна функция F в выражении F = (A • B), если A в лог. «1», а B в лог. «0»? Если читатель знаком с языком C/C++, то ему будет легче понимать некоторые вещи, поскольку Verilog имеет схожий синтаксис. В целом, Verilog достаточно прост в изучении, поэтому поехали…
Итак, что же такое Verilog? Если кратко, то это язык описания аппаратуры (hardware description language или HDL). Но без пояснения этого термина вряд ли новичку будет что-либо понятно. Языки описания аппаратуры используются для формального описания функционирования схемы. Существует несколько языков описания аппаратуры, но популярны лишь два – VHDL и Verilog.
С помощью таких языков мы описываем входы, выходы и поведение схемы. Используя их наряду с ПЛИС мы можем создать огромное количество схем. Можно также использовать эти языки и без привязки к аппаратному средству, просто имитируя поведение цепи и оценивая ее работоспособность.
Перед эпохой ПЛИС FPGA под прототипированием цифровой схемы понималась покупка каждого компонента этой схемы (логические элементы, мультиплексоры и т.д.) и соединение этих элементов между собой зачастую перемычками на макетной плате. Но благодаря Verilog, плате с FPGA, светодиодами и кнопками мы можем быстро и легко проверить работоспособность нашей схемы.
FPGA представляет собой чистый лист для вашей цифровой схемы. Интегрированные среды разработки вроде Xilinx ISE Design Suite преобразуют ваш «высокоуровневый» код на Verilog в поток битов, который и определит поведение FPGA. Поэтому вместо покупки мультиплексоров и прочих элементов мы напишем код и определим, какие выводы FPGA будут входами, а какие выходами.
Verilog-код, который разделяется на модули, описывает, что должно произойти в схеме, а UCF-файл (User Constraint File) сообщает микросхеме, какую функцию несет каждый вывод. FPGA имеет немалое число выводов, которые могут служить входами или выходами, и, чтобы наша задача по проектированию считалась завершенной, мы должны определить те выводы, которые будем использовать. Например, вывод G12 подключен на плате к светодиоду, поэтому будет логично назначить его выходом. Если для работы с этим светодиодом вы создадите переменную LED, то в UCF-файле нужно будет сделать так, что упоминание LED в коде должно сразу отсылать к выводу G12. К придумыванию имен переменных нужно подходить сознательно.
Ваш первый проект на Verilog
Именно проект, а не код! Хотя этот процесс напоминает программирование, в результате мы получаем не программу, а определенную схему. Возможно, вначале будет не совсем понятно, что к чему, но Verilog учится и понимается довольно быстро.
В отношении Verilog нужно сделать несколько замечаний. Этот язык чувствителен к регистру. То есть большие буквы и маленькие буквы – разные вещи. Также следует обращать внимание на отступы, хотя нижеприведенный пример и не демонстрирует этого, но в объемном коде это заметно. Компилятор и среда разработки «проглотят» плохо форматированный код, но плохой стиль будет источником непонимания и возможных ошибок.
Итак, вот «Hello, World» на Verilog:
Далее мы рассмотрим все по порядку.
Это директива, которая определяет единицу модельного времени (первый параметр, 1 нс) и точность модельного времени (второй параметр, 1 пс). Для своего проекта, конечно, вы можете установить другие значения, впрочем для FPGA эта директива не так важна, поскольку в ней нельзя задавать задержки вентилей или таким способом манипулировать с временными параметрами, но при симуляции схемы эта директива важна.
//это комментарий на Verilog
Как и на C++ (потом вы увидите, что синтаксис очень схож с синтаксисом C/C++) комментарий в одну строку начинается с «//». Все после этих двух слешей на текущей строке игнорируется компилятором. Для того, чтобы закомментировать блок, состоящий из нескольких строк, используются «/*» и «*/». Все, что попадет между этими символами, будет закомментировано. Не скупитесь на комментарии, но и не злоупотребляйте ими. Грамотно составленные комментарии облегчат жизнь при отладке.
В языке Verilog module является ключевым словом. Это как в C++ объявление типа, void hello_world(параметры) – находите сходство?
Впрочем, модуль Verilog не возвращает никакого значения (также как и при void в C/C++) и он не является, по сути, функцией, но синтаксис очень похож, и мы можем думать о модуле как об объявлении типов, у него даже есть свое имя – hello_world. Хороший Verilog-код – модульный, то есть каждый функциональный блок должен представлять собой модуль.
В скобках у нас имеется что-то вроде списка параметров. Модуль содержит вход switch[0], еще один вход switch[1] и один выход под названием led. input и output по сути являются типами переменных.
После объявления всех входов и выходов список параметров закрывается скобкой, и ставится точка с запятой. В Verilog, как и в C/C++, можно писать длинные выражения в несколько строк, и только точка с запятой будет означать его окончание.
assign led = switch[0] &
В этой строчке и заключается вся магия. До этого момента в нашем коде были описаны входы и выход, и теперь вы можете манипулировать выходом на основе входов. Здесь мы встречаем еще одно ключевое слово – assign. И оно определяет выходное значение на основе состояния одного или нескольких входов. Это похоже на приравнивание значения определенного выражения определенной переменной, но здесь есть одно «но». Назначение выхода через assign происходит лишь единожды, и в дальнейшем с ним нельзя будет провернуть подобную операцию, но уже с другим выражением, поскольку выход уже аппаратно соответствует именно этому выражению.
Следует помнить, что Verilog – это язык описания аппаратуры, а значит, вы описываете только поведение схемы. На входах switch[0] и switch[1] в разное время могут присутствовать лог. «0» и «1», но состояние выхода led всегда будет определяться выражением «switch[0] &
А что вообще значит это выражение? Что такое switch[0] и switch[1] – понятно. А «&» и «
При описании обычной цифровой схемы мы используем знак «•» для логического умножения «И» (AND), «+» для логического сложения «ИЛИ» (OR) и «⊕» для исключающего ИЛИ (XOR). Чтобы показать инверсию, мы рисуем черточку над переменной или выражением. В Verilog всему этому есть эквивалентные обозначения:
Мы можем группировать вместе выражения, используя скобки. Это особенно полезно для создания вентилей NAND,NOR и XNOR. Для этого можно составить выражение для неивертированной версии, а затем перед ним добавить символ «
». Например, чтобы составить выражение типа «F = A xnor B» следует написать «assign F =
Возвращаясь к «assign led = switch[0] &
switch[1];», можно сказать, что выход led будет равен единице только, когда switch[0] будет равно единице, и switch[1] будет равно нулю нулю.
Окончание модуля Verilog
Это ключевое слово обозначает конец модуля и позволяет компилятору понять, что все что выше этой строки – полезная информация. Хотя среды разработки не особо следят за оформлением, но если у вас будет пустая строка до и пустая строка после строки с endmodule, а сама она не будет иметь отступов, то вы, возможно, сможете избежать некоторых проблем, в первую очередь связанных с пониманием.
Verilog Timescale
Verilog simulation depends on how time is defined because the simulator needs to know what a #1 means in terms of time. The `timescale compiler directive specifies the time unit and precision for the modules that follow it.
Syntax
The time_unit is the measurement of delays and simulation time while the time_precision specifies how delay values are rounded before being used in simulation.
Use the following timescale constructs to use different time units in the same design. Remember that delay specifications in the design are not synthesizable and cannot be converted to hardware logic.
| Character | Unit |
|---|---|
| s | seconds |
| ms | milliseconds |
| us | microseconds |
| ns | nanoseconds |
| ps | picoseconds |
| fs | femtoseconds |
The integers in these specifications can be either 1, 10 or 100 and the character string that specifies the unit can take any value mentioned in the table above.
Example #1: 1ns/1ns
The first delay statement uses #1 which makes the simulator wait for exactly 1 time unit which is specified to be 1ns with `timescale directive. The esecond delay statement uses 0.49 which is less than half a time unit. However the time precision is specified to be 1ns and hence the simulator cannot go smaller than 1 ns which makes it to round the given delay statement and yields 0ns. So the second delay fails to advance the simulation time.
The third delay statement uses exactly half the time unit [hl]#0.5[/lh] and again the simulator will round the value to get #1 which represents one whole time unit. So this gets printed at T=2ns.
The fourth delay statement uses a value more than half the time unit and gets rounded as well making the display statement to be printed at T=3ns.
The simulation runs for 8ns as expected, but notice that the waveform does not have smaller divisions between each nanosecond. This is because the precision of time is the same as the time unit.

Example #2: 10ns/1ns
The only change made in this example compared to the previous one is that the timescale has been changed from 1ns/1ns to 10ns/1ns. So the time unit is 10ns and precision is at 1ns.
Actual simulation time is obtained by multiplying the delay specified using # with the time unit and then it is rounded off based on precision. The first delay statement will then yield 10ns and the second one gives 14.9 which gets rounded to become 15ns.
The third statement similarly adds 5ns (0.5 * 10ns) and the total time becomes 20ns. The fourth one adds another 5ns (0.51 * 10) to advance total time to 25ns.
Note that the base unit in waveform is in tens of nanoseconds with a precision of 1ns.

Example #3: 1ns/1ps
The only change made in this example compared to the previous one is that the timescale has been changed from 1ns/1ns to 1ns/1ps. So the time unit is 1ns and precision is at 1ps.
See that the time units scaled to match the new precision value of 1ps. Also note that time is represented in the smallest resolution which in this case is picoseconds.
Цифровая лаборатория FPGA / DSP
Информационно-учебный проект по цифровой электронике
ЛР4 > Исследование последовательностных логических устройств: Операторы Verilog
Тема: Verilog – время моделирования и временные задержки, операторы Verilog
1. Теоретические сведения.
Краткие теоретические сведения по языку Verilog (продолжение)
При работе с языками описания аппаратуры необходимо всегда помнить одну особенность. Программа, написанная на этом языке (в том числе – на Verilog) выполняется параллельно! В этом главное отличие языка Verilog от таких процедурных языков программирования как C и Pascal. Понять это довольно просто. Ведь с помощью языков HDL описывается схема электрическая принципиальная (т.е. – собственно устройство, в котором электрические сигналы всегда распространяются одновременно).
Для этого в синтаксисе языка Verilog предусмотрены следующие операторы, выполняющиеся параллельно:
• assign;
• always (этот важный оператор мы рассмотрим позже);
Таким образом, если в программе описания модуля используется несколько операторов assign и always, все они будут выполняться параллельно (одновременно).
Понятия моделирования и синтеза
Работу логического устройства, описанного с помощью языков HDL, можно проверить двумя способами: либо на персональном компьютере (моделирование), либо непосредственной реализацией в микросхеме (например – ПЛИС) (синтез). Процесс синтеза намного сложнее моделирования, поскольку предполагает, помимо компиляции кода, еще и синтез логической схемы (т.е. реализацию устройства с помощью доступных компонентов ПЛИС и трассировку проводников в выбранной микросхеме). Поэтому результат применения некоторых конструкций языка Verilog при моделировании и синтезе отличается! Не все операторы языка Verilog являются синтезируемыми!
Обычно для моделирования используются специальные тестовые программы – тестбенчи (testbench), которые предназначены для проверки программы описания модулей (их верификации). Обычно, для выполнения моделирования используется специализированное ПО, например – ModelSim.
Модельное время
Итак, очевидными являются три факта. Во-первых, моделирование логического устройства можно выполнять на ПК. Во-вторых, многие операторы языка Verilog выполняются параллельно. В-третьих, ПК выполняет инструкции строго последовательно. Возникает вопрос, как с помощью компьютера выполнить моделирование событий, которые
выполняются одновременно? Для ответа на этот вопрос необходимо вначале разобраться с
понятиями реального и модельного времени. Естественно, что реальное время отличается от модельного. В реальном времени описываются все изменения, происходящие в моделируемом устройстве. В модельном времени описываются все изменения, происходящие в моделирующей программе. Такое разделение позволяет выполнить на компьютере вначале последовательно все параллельные инструкции, а затем предоставить результат в таком виде, как будто бы они выполнялись одновременно.
Для задания модельного времени в языке Verilog служит конструкция ‘timescale
param1/param2. Param1 задает единицу модельного времени (по умолчанию – 1 нс), а
Param2 – точность модельного времени. Например ‘timescale 1ns/10ps означает, что
единица модельно времени 1 наносекунда. Шаг в 10 единиц модельного времени составит 10 нс. Значение 10 пикосекунд (второй параметр директивы timescale) указывает на точность, с которой будут выполняться вычисления всех изменений за один шаг моделирования. Естественно, что при вычислении задержек в устройстве, время будет округляться с точностью до 10 пикосекунд. С помощью этой конструкции можно задавать точность моделирования.
Временные задержки
Различают временные задержки, связанные с моделированием и синтезом.
Временные задержки при моделировании задаются пользователем с помощью оператора#time (параметр time определяет время задержки в единицах модельного времени). Обычно, такие задержки имитируют конечное время распространения сигналов в реально работающих устройствах. Например, чтобы организовать задержку в 5 наносекунд необходимо записать следующий код:
Временную задержку можно вводить перед оператором присваивания значения сигналу, моделируя время распространения сигнала в реальной схеме:
assign #10 c = a^b;
Данная конструкция описывает элемент «исключающее ИЛИ» (XOR) с задержкой распространения равной 10 (10 единиц модельного времени – первого параметра директивы `timescale, который по умолчанию равен 1 нс). При этом, все задержки в непрерывных присвоениях являются инерциальными. Это значит, что изменения сигнала А на время меньшее 10 нс не приведет к изменениям сигнала С. Для того, чтобы произошло изменение сигнала С требуется, чтобы сигнал А был зафиксирован в новом состоянии на время более 10 нс.
А что же будет при синтезе? Если использовать задержки такого вида при синтезе, то ничего не произойдет! Данный оператор является несинтезируемым, т.е.
он будет игнорироваться. Для формирования задержек в реальном устройстве используются другие методы.
Операторы языка Verilog
Оператор assign
Используется для непрерывного присвоения сигнала переменной типа wire. Синтаксис:
assign var = expression;
Действие оператора: при изменении выражения expression (например, изменилось значение переменной, входящей в expression), вычисляется новое значение выражения и результат присваивается переменной var. В левой части выражения переменная может быть только типа wire, а в правой части – возможна комбинация переменных wire, reg, integer. Все операторыassign в модуле выполняются параллельно.
Оператор always
Один из основных, эффективных операторов языка Verilog. Позволяет задать постоянное выполнение последовательности команд. Указанная последовательность может выполняться либо циклически (в бесконечном цикле), либо только после появления определенного события.
Verilog: Timescales
As we are aware, compiler directive «timescale` in Verilog is a tricky topic and have many discussion around it.
Timescale specifies the time unit and time precision of a module that follow it. The simulation time and delay values are measured using time unit. The precision factor is needed to measure the degree of accuracy of the time unit, in other words how delay values are rounded before being used in simulation.
Let’s have a look into it and see how time units and precision are taken to calculate simulation time.
In the examples, following time scale /time precision combinations are used.
The `rval` changes in different time-steps but due to the differences in timescale directives the simulation time varies.
In the below code, timescale is `timescale 1ps / 1ps.
To find out number of digits taken after decimal, first divide time scale with time precision. The exponent number will be your result.
Check below result to see all simulation time for rval. Also note that simulation ends at 100 PS.
Now, let us check one more example. In `module timescale_check2`, timescale is 1ns / 1ps.
Timescale/Time Precision = 1ns/1ps = 1000 = 10 3 So 3 digits after decimal will be used. In this case 10.566601 becomes 10567 and 21.546604 becomes 21547.
Below examples show simulation results for timescales 100ns/1ns, 1ms / 1us and 10 ms / 10 ns.
ЛР4 > Исследование последовательностных логических устройств: Операторы Verilog
Статьи по теме
Тема: Verilog – время моделирования и временные задержки, операторы Verilog
Структура курса лабораторных работ: Основы Verilog
Скачать Материалы к лабораторной работе по Verilog №4.
1. Теоретические сведения.
Краткие теоретические сведения по языку Verilog (продолжение)
При работе с языками описания аппаратуры необходимо всегда помнить одну особенность. Программа, написанная на этом языке (в том числе – на Verilog) выполняется параллельно! В этом главное отличие языка Verilog от таких процедурных языков программирования как C и Pascal. Понять это довольно просто. Ведь с помощью языков HDL описывается схема электрическая принципиальная (т.е. – собственно устройство, в котором электрические сигналы всегда распространяются одновременно).
Для этого в синтаксисе языка Verilog предусмотрены следующие операторы, выполняющиеся параллельно:
• assign;
• always (этот важный оператор мы рассмотрим позже);
Таким образом, если в программе описания модуля используется несколько операторов assign и always, все они будут выполняться параллельно (одновременно).
Понятия моделирования и синтеза
Работу логического устройства, описанного с помощью языков HDL, можно проверить двумя способами: либо на персональном компьютере (моделирование), либо непосредственной реализацией в микросхеме (например – ПЛИС) (синтез). Процесс синтеза намного сложнее моделирования, поскольку предполагает, помимо компиляции кода, еще и синтез логической схемы (т.е. реализацию устройства с помощью доступных компонентов ПЛИС и трассировку проводников в выбранной микросхеме). Поэтому результат применения некоторых конструкций языка Verilog при моделировании и синтезе отличается! Не все операторы языка Verilog являются синтезируемыми!
Обычно для моделирования используются специальные тестовые программы – тестбенчи (testbench), которые предназначены для проверки программы описания модулей (их верификации). Обычно, для выполнения моделирования используется специализированное ПО, например – ModelSim.
Модельное время
Итак, очевидными являются три факта. Во-первых, моделирование логического устройства можно выполнять на ПК. Во-вторых, многие операторы языка Verilog выполняются параллельно. В-третьих, ПК выполняет инструкции строго последовательно. Возникает вопрос, как с помощью компьютера выполнить моделирование событий, которые
выполняются одновременно? Для ответа на этот вопрос необходимо вначале разобраться с
понятиями реального и модельного времени. Естественно, что реальное время отличается от модельного. В реальном времени описываются все изменения, происходящие в моделируемом устройстве. В модельном времени описываются все изменения, происходящие в моделирующей программе. Такое разделение позволяет выполнить на компьютере вначале последовательно все параллельные инструкции, а затем предоставить результат в таком виде, как будто бы они выполнялись одновременно.
Для задания модельного времени в языке Verilog служит конструкция ‘timescale
param1/param2. Param1 задает единицу модельного времени (по умолчанию – 1 нс), а
Param2 – точность модельного времени. Например ‘timescale 1ns/10ps означает, что
единица модельно времени 1 наносекунда. Шаг в 10 единиц модельного времени составит 10 нс. Значение 10 пикосекунд (второй параметр директивы timescale) указывает на точность, с которой будут выполняться вычисления всех изменений за один шаг моделирования. Естественно, что при вычислении задержек в устройстве, время будет округляться с точностью до 10 пикосекунд. С помощью этой конструкции можно задавать точность моделирования.
Временные задержки
Различают временные задержки, связанные с моделированием и синтезом.
Временные задержки при моделировании задаются пользователем с помощью оператора #time (параметр time определяет время задержки в единицах модельного времени). Обычно, такие задержки имитируют конечное время распространения сигналов в реально работающих устройствах. Например, чтобы организовать задержку в 5 наносекунд необходимо записать следующий код:
Временную задержку можно вводить перед оператором присваивания значения сигналу, моделируя время распространения сигнала в реальной схеме:
assign #10 c = a^b;
Данная конструкция описывает элемент «исключающее ИЛИ» (XOR) с задержкой распространения равной 10 (10 единиц модельного времени – первого параметра директивы `timescale, который по умолчанию равен 1 нс). При этом, все задержки в непрерывных присвоениях являются инерциальными. Это значит, что изменения сигнала А на время меньшее 10 нс не приведет к изменениям сигнала С. Для того, чтобы произошло изменение сигнала С требуется, чтобы сигнал А был зафиксирован в новом состоянии на время более 10 нс.
А что же будет при синтезе? Если использовать задержки такого вида при синтезе, то ничего не произойдет! Данный оператор является несинтезируемым, т.е.
он будет игнорироваться. Для формирования задержек в реальном устройстве используются другие методы.
Операторы языка Verilog
Оператор assign
Используется для непрерывного присвоения сигнала переменной типа wire. Синтаксис:
assign var = expression;
Действие оператора: при изменении выражения expression (например, изменилось значение переменной, входящей в expression), вычисляется новое значение выражения и результат присваивается переменной var. В левой части выражения переменная может быть только типа wire, а в правой части – возможна комбинация переменных wire, reg, integer. Все операторы assign в модуле выполняются параллельно.
Оператор always
Один из основных, эффективных операторов языка Verilog. Позволяет задать постоянное выполнение последовательности команд. Указанная последовательность может выполняться либо циклически (в бесконечном цикле), либо только после появления определенного события.



