для чего предназначен язык verilog

Зачем язык Verilog программисту микроконтроллеров

для чего предназначен язык verilog. Смотреть фото для чего предназначен язык verilog. Смотреть картинку для чего предназначен язык verilog. Картинка про для чего предназначен язык verilog. Фото для чего предназначен язык verilog

Несколько раз начинал писать эту статью и бросал. Бросал потому, что тема, как мне кажется, несколько спорная. Изобретенный мною велосипед может кому-то показаться смешным и нелепым и вообще не совсем корректным. Тем не менее…

Вообще, мне кажется, что в области разработки электронных устройств существует как бы несколько мало пересекающихся миров. Например, существует разработка устройств на базе микроконтроллеров и параллельно существует разработка устройств на базе ПЛИС. Принципы работы этим микросхем принципиально отличаются и точно так же отличаются принципы и методы разработки, используемые языки программирования и отладки. Конечно, выбор элементной базы сильно зависит от поставленной задачи. Однако и так понятно, что эти миры, мир микроконтроллеров и мир ПЛИСов почти не пересекаются. Может быть на стыке технологий что-то есть?

Сам я, в общем, больше предпочитаю ПЛИС и даже участвую в блоге о ПЛИС, однако, недавно наша компания взялась за разработку устройства на базе микроконтроллера STM32. Собственно основные проблемы, которые мы встретили были не совсем технические, а скорее организационные.

Дело в том, что несмотря на заключенный договор о разработке устройства и несмотря на наличие более-менее согласованного ТЗ на устройство так получилось, что каждую неделю заказчик приходил с новыми идеями, требованиями, мыслями и пожеланиями. Можно было бы конечно, послать их куда подальше, но мы решили, что постараемся быть терпеливыми и все же будем выполнять проект.

Самая главная организационная проблема – поступивших запросов на изменение алгоритма управления контроллера было очень много и зачастую они были очень противоречивы. Причем заказчик сам не был уверен, как оно должно работать и даже не очень понимал, как он будет все это проверять. Точнее будет сказать так. Есть менеджеры которые хотят иметь некий контроллер в свой агрегат. Какие конкретно функции должны быть у контроллера и агрегата сами менеджеры точно не знают и требования должен был сформировать единственный инженер, который и должен был проверить работоспособность устройства. Своей методики проверки работоспособности контроллера у инженера нет, так как нет опыта работы с электронными устройствами.

Вот такой пример. В режиме ожидания, когда контроллер просто ждет нажатия кнопки «Пуск», наш контроллер должен раз в сутки включать насос, прокачивающий жидкость, на 10 секунд. Это типа защита от закисания сальников насоса. Когда я спрашиваю; «вы как будете эту функцию проверять» – отвечают, что «никак». Лично я в шоке. Мы, конечно, стараемся писать программы «без ошибок», но думаю принимающая сторона то же как-то должна делить ответственность, проводить свои испытания и т.д…

Далее перейду собственно к технической стороне дела.

Мы решили, что нам нужны свои какие-то тесты программного обеспечения микроконтроллера.

Обычно в мире ПО есть такое понятие юнит-тестирование. И в принципе, эта методика в какой-то мере подходит и для программ микроконтроллера. В настоящее время программы для микроконтроллеров зачастую пишутся на обычном языке Си, так что с юнит тестами, в общем, проблем быть не должно. Хотя… не все можно легко проверить юнит тестами в микроконтроллере.

Все что связано с программированием внутренних аппаратных устройств вроде таймеров, каналов DMA, последовательных портов, прерываний и так далее – с этим есть проблемы. Тут для отладки в пору брать осциллограф и смотреть какие сигналы микроконтроллера получаются на входах-выходах. И вообще померить сколько по времени идет обработка прерывания – дело не лишнее. И это правильно.

Есть еще один нюанс с юнит тестами. Как мне кажется, обычное юнит-тестирование ПО ориентированно на данные. Ну то есть обычно программа юнит-тест подает разные предполагаемые данные на вход проверяемой функции и далее проверяет, что обработанные выходные данные соответствуют требованиям. Все.

Для электронного устройства, которое выступает как обработчик входных сигналов принципиально важно понятие «течение времени». Ну то есть требования обычно такие: при возникновении нештатной ситуации и срабатывании аварийного датчика A последовательно с интервалом в N1 секунд выключить исполнительные устройства B, C, а устройство D выключить не позже N2 секунд но не раньше N3 секунд, Что-то вроде этого.

Понятно, что для проверки алгоритма управления программными средствами хорошо бы использовать какой-то симулятор сигналов с учетом течения времени. И такие средства есть в арсенале… у разработчиков систем на ПЛИС.

Разработчик электронных устройств на базе ПЛИС как правило использует язык описания аппаратуры Verilog или VHDL. При этом, кроме кода для ПЛИС пишутся так называемые testbench – это и есть что-то вроде unit-test для обычного программиста на Си.

Я использую Verilog HDL.
Программу тестбенч пишет сам программист и при этом старается симулировать все возможные входные воздействия на микросхему ПЛИС. Выходные сигналы анализируются самим тестбенчем и проверяются в соответствии с ожидаемыми.
При этом, сам симулятор Verilog следит за течением времени в системе.

Рассмотрим простой и совершенно абстрактный пример, что делает программист ПЛИС.
Например, вот модуль, который описывает простой двоичный счетчик с асинхронным сбросом (sample.v):

Думаю такой код поймет любой программист, даже и не знающий языка Verilog HDL. Есть два входных сигнала reset и clk. И есть выходной четырехбитный сигнал [3:0]cnt. Всегда по фронту тактового сигнала значение в счетчике увеличивается. И всегда при появлении единицы на reset счетчик обнуляется.

Этот модуль синтезируемый, то есть его планируется откомпилировать и зашить в ПЛИС.

Теперь, например, программист хочет проверить работоспособность своего модуля. Он пишет программу на Verilog, тестбенч, который будет имитировать входные сигналы для микросхемы (testbench.v):

Этот модуль не синтезируемый, его нельзя откомпилировать и зашить в ПЛИС, но он нужен для симуляции проекта. Обратите внимание на строки

Это в тестбенч вставлен исследуемый экземпляр модуля sample. Получается вот так:

для чего предназначен язык verilog. Смотреть фото для чего предназначен язык verilog. Смотреть картинку для чего предназначен язык verilog. Картинка про для чего предназначен язык verilog. Фото для чего предназначен язык verilog

Очень возможно, что у нас есть критерий работоспособности проекта. Нам нужно, чтобы во время сигнала reset выходные сигналы счетчика были всегда в нуле. То есть мы можем в тестбенче определить сигнал ошибки:

Этот сигнал можно программно мониторить или просто посмотреть глазами на выходных временных диаграммах.

Я часто использую простой свободный симулятор VerilogHDL IcarusVerilog. Его просто установить и работать с ним. Компилирую и запускаю симулятор:

для чего предназначен язык verilog. Смотреть фото для чего предназначен язык verilog. Смотреть картинку для чего предназначен язык verilog. Картинка про для чего предназначен язык verilog. Фото для чего предназначен язык verilog

для чего предназначен язык verilog. Смотреть фото для чего предназначен язык verilog. Смотреть картинку для чего предназначен язык verilog. Картинка про для чего предназначен язык verilog. Фото для чего предназначен язык verilog

Таким образом, самое простое, что может сделать программист ПЛИС – это написать к тестируемому модулю тестбенч и сгенерировать файлы получившихся временных диаграмм и рассматривать их, смотреть правильный ли отклик идет от ПЛИС.

Теперь расскажу, как можно похожую технологию тестирования применить к микроконтроллерам.

Так вот. Оказывается, для симулятора Verilog HDL можно самому дописывать нужные нам системные функции на языке Си. А раз появляется место для языка Си, то появляется место, где код Verilog тестбенча может взаимодействовать с Сишным кодом для микроконтроллера.

Вообще, интерфейс симулятора Verilog к языку Си называется Verilog Procedural Interface (VPI). Рассказывать про него можно долго, это большая отдельная тема. Можно больше почитать, например, вот здесь.

Я же хочу просто схематично проиллюстрировать, как это может быть использовано.
Проект для микроконтроллера может состоять из многих файлов. Наша задача отделить собственно алгоритм управления от аппаратных особенностей конкретного микроконтроллера.

Предположим, проект для микроконтроллера состоит из файлов:

Обработчики прерываний от входных линий микроконтроллера описаны в файле Interrupts.c. Они представляют из себя что-то вроде этого:

Когда сигнал на входной линии микроконтроллера меняется, то происходит прерывание, в нем производится чтение значения на линии и это значение передается функцией Algo_set_val() алгоритму обработки. Весь алгоритм управления описан в файле Algorithm.c.

Файл Algorithm.c одновременно участвует в проекте для микроконтроллера и в проекте для VPI модуля Verilog.

для чего предназначен язык verilog. Смотреть фото для чего предназначен язык verilog. Смотреть картинку для чего предназначен язык verilog. Картинка про для чего предназначен язык verilog. Фото для чего предназначен язык verilog

Примечательно, что мы получаем в свое распоряжение временные диаграммы входных воздействий и откликов. Их можно показать заказчику с целью ознакомления – для их просмотра используется программа GtkWave. Заказчик своими глазами сможет увидеть, как входные воздействия от различных датчиков будут откликаться его алгоритмом управления. Заказчик должен увидеть все возможные комбинации воздействий от входных сигналов и все отклики «черного ящика» под названием микроконтроллер.

По крайней мере, на временных диаграммах можно увидеть, как виртуально включается насос на 10 секунд каждые сутки…

Последний этап – перестаем компилировать VPI модуль для Verilog симулятора (фиолетовый блок) и начинаем компилировать проект микроконтроллера (оранжевый блок).

Теперь функции алгоритма будут вызываться не из виртуальных воздействий симулятора Verilog, а из физических прерываний от входных линий и таймеров.

На всякий случай еще раз замечу, что с помощью нашего Verilog тестбенча мы конечно не проверяем правильность программирования регистров периферийных устройств вроде DMA или таймеров или GPIO. Мы тестируем только «алгоритм управления». На мой взгляд и это очень и очень важно.

Источник

Краткий курс HDL.
Часть 2.1. Описание языка Verilog

Начало описания языка Verilog и немного о VHDL для сравнения

В этом разделе будет дано вступление к описанию языка Verilog. Для сравнения также будет приведена небольшая часть описания языка VHDL. Это сделано для того, чтобы читатель смог оперативно сравнивать конструкции этих двух языков. Для дополнительного изучения можно порекомендовать список литературы.

Для VHDL приняты следующие соглашения об именах, применяемых пользователями в своих проектах:

Зарезервированные слова VHDL приведены в таблице 1.

Verilog

Для Verilog приняты следующие соглашения об именах, применяемых пользователями в своих проектах:

Зарезервированные слова Verilog приведены в таблице 2.

Сигналы или переменные могут быть представлены следующими логическими уровнями:

Операторы

Операторы могут быть трех типов: унитарные, бинарные и тернарные. Унитарные операторы производят действия над единственным операндом. Бинарные операнды производят действия над двумя операндами. Тернарные операторы имеют два оператора, которые делают выбор для трех операндов. Примеры этих операндов:

В языках VHDL и Verilog используются следующие арифметические и битовые операторы:

Операнды (Operands)

Есть несколько типов операндов, которые могут быть определены в выражениях. Самый простой тип — это цепь или регистр, и, если при этом указывается на полную разрядность цепи или регистра, то можно приводить только название цепи или регистра. В этом случае все биты, составляющие цепь или выходы регистра, используются как операнд.

Как цепи, так и регистры могут иметь несколько разрядов. При этом, если используется только единственный бит из вектора цепи или регистра, то необходимо использовать операнд выбора бита. Если при обращении к группе смежных битов в векторной цепи или в регистре используется только часть битов, то необходимо применить операнд выбора части битов из вектора.

На элемент памяти можно сослаться как на операнд. Конкатенация других операндов (включая вложенные конкатенации) может быть определена как операнд. Запрос функции — это тоже операнд.

Операторы и возможность их применения в VHDL или в Verilog приведены в таблице 3. Приоритеты выполнения операторов в Verilog приведены в таблице 4.

Таблица 3. Операторы и возможность их применения в VHDL или в Verilog

Операция

Оператор

Описание

VHDL

Verilog

Арифметические операторы (Arithmetic Operators):

Возведение в степень

Модуль (остаток от деления)

Остаток от деления

Concentration and Replication Operators:

Операторы равенства (Equality Operators):

Битовые логические операторы

(Logical Bit5wise Operators):

unary negation NOT

Поразрядное двоичное «И»

Поразрядное двоичное «ИЛИ»

Поразрядное двоичное «И5НЕ»

Поразрядное двоичное «ИЛИ-НЕ»

Поразрядное двоичное «Исключающее ИЛИ»

Поразрядное двоичное «Исключающее ИЛИ-НЕ»

Операторы логического сравнения

(Logial Comparison Operators):

Поразрядное логическое «НЕ»

Поразрядное логическое «И»

Поразрядное логическое «ИЛИ»

Операторы свертки (Reduction Operators):

less than or equal to

greater than or equal to

Операторы сдвига (Shift Operators):

left logical shift right

arithmetic shift left

arithmetic shift right

logical rotate left

logical rotate right

Логический сдвиг влево

Логический сдвиг вправо

Арифметический сдвиг влево

Арифметический сдвиг вправо

Циклический сдвиг влево

Циклический сдвиг вправо

Приоритет выполнения операторов

Высший приоритет исполнения

Низший приоритет исполнения

Битовые операторы (Bit-Wise Operators)

Битовые операторы позволяют производить побитовые операции над двумя или более операндами (табл. 5–9).

Таблица 5. Поразрядная инверсия

Обратите внимание на то, что необходимо отличать битовые операторы & и | от логических операторов && и ||. Например, если x = 1 и y = 2, то битовая операция x & y в результате даст 0, в то время как x && y — в результате даст 1. Когда операнды имеют неравное число битов, то операнд, имеющий меньшее число битов, будет заполнен нулями в старших разрядах.

Операторы приведения

Операторы приведения выполняют операции побитно над операндом, чтобы произвести результат, имеющий разрядность 1 бит. Первый шаг операции выполняется над первым и вторым битами операнда, в соответствии с таблицами 10–12. Вторые и последующие шаги выполняются аналогично с однобитовым результатом предшествующего шага и следующими битами операнда.

Таблица 10. Оператор приведения по «И» (AND)

Необходимо отметить, что оператор приведения по «И-НЕ» и оператор приведения по «ИЛИ-НЕ» выполняет те же операции, что и операторы приведения по «И» и «ИЛИ» соответственно, но результаты их работы при этом будут инверсными. Результаты работы операторов приведения даны в таблицах 13, 14.

Таблица 13. Результаты работы оператора приведения для «И», «ИЛИ», «И-НЕ» и «ИЛИ-НЕ»

Результат работы оператора приведения для &, |,

Операнд

биты не установлены в

все биты установлены в

часть битов, но не все, установлены в

Таблица 14. Результаты работы оператора приведения для «Исключающего ИЛИ» и «Исключающего ИЛИ-НЕ»

Результат работы оператора приведения для ^ и

Операнд

Значения нечетных битов

Значения четных битов, если они есть

Ограничения синтаксиса

В языке Verilog есть два ограничения синтаксиса, предназначенные для того, чтобы защитить текст описания от ошибки, которая возникает при неправильной записи выражения. Эти ошибки бывает достаточно трудно найти, потому что они возникают из-за неправильного положения пробела и символа в выражении. Для примера можно рассмотреть два выражения. Выражения строк 1 и 2 внешне почти похожи, но дают совершенно разный результат (пример 1).

Пример 1. Тексты описаний, которые почти похожи, но дают совершенно разный результат

Как защитить пользователей от этого типа ошибок? Необходимо использовать круглые скобки для того, чтобы отделить сокращение ИЛИ или И (reduction or or and) оператор от поразрядного ИЛИ или И (bit-wise or or and) оператора. В примере 2 показан синтаксис, который требует круглых скобок.

Неправильный синтаксис

Правильный синтаксис

Пример 2. Примеры неправильного и правильного синтаксиса

Операторы сдвига

Операторы сдвига, > выполняют сдвиг операнда, находящегося слева от оператора, влево или вправо на то число позиций двоичного разряда, которое указано справа от оператора сдвига. При сдвиге данных оба оператора производят заполнение освободившихся позиций двоичного числа нулями. Пример 3 иллюстрирует действия, выполняемые этими операциями.

Пример 3. Пример работы операторов сдвига

В 3-м примере 4-битовому регистру start присвоено значение 0001. После сдвига влево на два разряда регистр будет содержать число 0100.

Пример 4. Условный оператор, который имеет три операнда

Условный оператор

Условный оператор имеет три операнда, отделенные двумя операторами, записанными в следующем порядке (пример 4)

Если cond_expr оценивается как ложное — false, то для результата будет использовано выражение false_expr. Если условное выражение истинно — true, то для результата будет использовано выражение true_expr.

Если cond_expr или true_expr и false_expr содержат символы неоднозначности — Х, то для того чтобы вычислить конечный результат, используйте таблицу 15.

Таблица 15. Работа условного оператора

Если разрядность операндов различна, то операнд с меньшей разрядностью будет слева дополнен нулями (старшие разряды) так, чтобы соответствовать разрядности операнда с большей разрядностью.

В примере 5 показано то, как можно использовать условный оператор для того, чтобы выполнить шину с третьим состоянием.

Пример 5. Применение условного оператора для того, чтобы выполнить шину с третьим состоянием

Шина busa управляется сигналом drive_busa. В том случае, когда этот сигнал 1, на шину передаются данные — data, в противном случае шина переключается в третье состояние. Если значение сигнала drive_busa неизвестно, то и значение данных на шине busa тоже неизвестно.

Конкатенация — Concatenation

Конкатенация — объединение битов, находящихся в двух или более выражениях. Для записи конкатенации используются символы фигурных скобок < и >, с запятыми, отделяющими выражения, находящиеся в этих скобках. Пример 6 объединяет четыре выражения.

Пример 6. Применение оператора конкатенации для того, чтобы объединить четыре выражения

Пример 6 эквивалентен другой записи, которая приведена в примере 7.

Пример 7. Применение оператора конкатенации

Постоянные числа, разрядность которых не указана, не должны быть использованы в объединениях, потому что разрядность каждого операнда в конкатенации необходима для того, чтобы вычислить полный размер шины для конкатенации. Конкатенации могут быть записаны при использовании множителя повторения так, как показано в примере 8.

Пример 8. Применение оператора конкатенации с использованием множителя повторения

В примере 9 показаны вложенные конкатенации. Число, указывающее, сколько раз надо повторить конкатенацию, должно быть постоянной величиной.

Пример 9. Применение оператора конкатенации с использованием вложенных конкатенаций

Числа

Постоянные числа могут быть определены в десятичном (d or D), шестнадцатеричном (h or H), восьмеричном (o or O) или в двоичном (b or B) формате.

Они могут произвольно начинаться со знака + или – и могут быть написаны в одном из следующих форматов.

Наиболее простой формат 3 — беззнаковое десятичное число, содержащее, в любом порядке, последовательность цифр от 0 до 9. Хотя пользователь, возможно, не определил размерность написанного числа, Verilog сам вычисляет разрядность числа, примененного в выражении. Обычно в выражениях разрядность примененных в операторах чисел одинакова. И для использования выбирают требуемое число битов, начиная с наименьшего значащего бита.

Формат 1 определяет постоянный размер для разрядности и записывается следующим образом:

Если мы имеем два числа, и одно из них имеет меньшую разрядность, чем другое, то в таком случае для меньшего числа производится заполнение старших разрядов нулями так, чтобы оба числа имели одинаковую разрядность. Если же в числе с большей разрядностью старшие разряды заполнены значениями x или z, то и число с меньшей разрядностью тоже будет заполнено значениями x или z.

Символ подчеркивания может вставляться в числа с любым основанием для того, чтобы улучшить читаемость кода. Но, конечно, символ подчеркивания не может быть первым символом в записи числа. Приведем примеры двоичных чисел: 12’b 0x0x_1101_0zx1 и 12’b 0x0x11010zx1. Как мы видим, первое число читать значительно легче. А это пример неправильной записи: 8’b_0001_1010.

Примеры записи чисел, в которых не определена разрядность:

В примере 10 показаны формы записи чисел, в которых определена разрядность.

Пример 10. Примеры записи чисел, в которых определена разрядность

В примере 11 показаны формы записи чисел со знаком и отрицательных чисел. А в примере 12 показаны формы записи чисел со знаком «?».

Пример 11. Примеры записи чисел со знаком и отрицательных чисел

Пример 12. Примеры записи чисел со знаком «?»

Вещественные числа могут быть записаны в десятичном или научном формате. Если число записано в десятичном формате, оно должно иметь, по крайней мере, одну цифру после десятичной точки (пример 13).

Пример 13. Примеры записи вещественных чисел, которые могут быть записаны в десятичном или научном формате

Преобразование вещественного числа в целое число

Язык Verilog преобразовывает вещественные числа в целые, округляя вещественное число к самому близкому целому числу, а не отбрасывая десятичную часть. Например, вещественные числа 35,7 и 35,5 и округляются до значения 36, а 35,2 становится 35. Неявное преобразование имеет место, когда вы назначаете вещественное число как целое число (real to an integer).

Строки

Строка — это последовательность символов, ограниченная слева и справа кавычками. Они должны быть расположены на одной строке. В строке можно использовать специальные ESC-символы, для чего необходимо применять следующим образом символ «»:

В примере 14 показаны правильная и неправильная формы записи строки.

Пример 14. Примеры записи строки (правильная и неправильная формы записи)

Параметры (Parameters)

В языке Verilog параметры не принадлежат к какому-либо регистру или группе цепей. Параметры не переменные, они — константы. Параметры могут быть как местные, локальные, так и глобальные. Синтаксис для объявлений параметров показан в примере 15.

Пример 15. Синтаксис для объявлений параметров —

Примечание: в некоторых случаях при использовании параметров можно определять диапазон при объявлении параметра.

Пример 16. Объявление параметров

Хотя параметры в Verilog представляют собой константы, они могут быть изменены во время компиляции для того, чтобы принять новые значения, которые отличаются от определенных в назначении объявления. Это позволяет пользователю настраивать инстансы модулей при их установке в проекте. Вы можете изменить параметр утверждением defparam или изменить параметр в утверждении инстанса модуля. Обычно параметры используются для задания значения времени задержки или разрядности (ширины) переменных.

Функции

Определение функции должно начаться с ключевого слова функция — function, сопровождаемого дополнительным ключевым словом автоматическая — automatic и дополнительным указателем signed, диапазоном или типом возвращаемого значения из функции, затем идет само название функции, потом или точка с запятой, или список портов функции, заключенных в круглые скобки, и точка с запятой. И, наконец, определение должно закончиться ключевым словом endfunction. Дополнительно можно использовать параметр range_or_type. Если функция определена по умолчанию, то есть без диапазона или типа, то ее представляют как функцию, возвращающую значение от однобитового регистра. Если используется параметр range_or_type, то необходимо определить, что представляет собой возвращаемое значение функции — реальное, целое число, время, реальное время или значение с диапазоном битов — [n:m]. Функция должна иметь по крайней мере один объявленный вход (одну входную переменную).

Ключевое слово automatic (автоматический) объявляет рекурсивную функцию со всеми функциональными объявлениями, распределенными динамически для каждого рекурсивного обращения. К автоматическим вызовам функции нельзя обратиться при помощи иерархических ссылок. Автоматические функции могут быть вызваны по их иерархическому названию.

Входы функции могут быть объявлены двумя способами. В первом способе необходимо дать название функции, сопровождаемое точкой с запятой. После точки с запятой должны следовать одно или более объявлений входов, которые могут быть произвольно установлены при объявлении тем блока. После объявлений тем для функции должна следовать «начинка» функции, то есть поведенческие утверждения (behavioral statement) и затем ключевое слово endfunction. Пример 17 определяет функцию, названную getbyte, используя при этом спецификацию диапазона.

Пример 17. Определение функции getbyte при использовании спецификации диапазона

Пример 18. Определение функции getbyte при использовании перечисления портов в скобках

По второму способу (пример 18) необходимо дать название функции, сопровождаемое открывающей скобкой, и одним или более входными объявлениями, которые отделяются запятыми. После всех объявлений входов должна быть закрывающая круглая скобка и точка с запятой. После точки с запятой могут идти объявления тем блока, сопровождаемые поведенческими утверждениями и затем ключевым словом endfunction.

Значения, возвращаемые из функции

Определение функции неявно объявляет и переменную, которая используется в проекте. Переменная должна иметь то же самое название, что и функция. По умолчанию, эта переменная имеет то же самое значение, что и 1-битовый регистр. Или, в общем случае, переменная имеет то же самое значение, что и тип, определенный в объявлении функции. Определение функции устанавливает возвращаемое из функции значение, результат работы этой функции на внутренней переменной будет иметь то же самое название, что и функция. Попытка объявить другой объект с таким же названием, как у уже объявленной функции, и в тех пределах, где данная функция уже объявлена, приведет к ошибке. То же самое происходит и в пределах функции. В каждой функции есть своя переменная с названием функции, которая может использоваться в выражениях. Поэтому и в пределах данной функции неправильно объявлять другой объект с тем же самым названием, как и данная функция.

В следующем примере иллюстрируется это понятие. Для функции getbyte, определенной в примере 18, возвращаемое значение будет выглядеть следующим образом:

В примере 18, использующем ту же функцию getbyte, создается новое слово, представляющее собой конкатенацию результатов двух вызовов функции:

Правила работы с функциями

При использовании функции имеют больше ограничений, чем задачи. Сформулируем шесть правил использования функций:

В примере 19 показано определение функции с именем factorial, которая возвращает целочисленное значение. Функция factorial вызывается итерационно, и результаты ее работы выводятся на монитор.

Пример 19. Пример вызова функции factorial

Результаты симуляции будут следующие:

0 factorial=1
1 factorial=1
2 factorial=2
3 factorial=6
4 factorial=24
5 factorial=120
6 factorial=720
7 factorial=5040

Использование постоянных функций (constant functions)

Вызовы функций постоянных значений (Constant function calls) используются для того, чтобы поддержать возможность проведения вычислений значений параметров во время разработки. Вызов функций постоянных значений должен быть вызовом функции для вычисления постоянного значения, которое находится локально в том модуле, где выполнен вызов, и аргументы функции представляют собой также постоянные выражения.

Функции постоянных значений представляют собой подмножество нормальных функций Verilog, которые должны иметь следующие ограничения:

Пример 20. Определение функции, названной clogb2, которая возвращает целое число, равное округленному в бо′льшую сторону значению логарифма по основанию 2

Цепи, регистры, память, представление чисел и времени (Wire Registers, Memories, Integers and Time)

Цепь — wire

Цепи на схеме соответствуют физическим проводам, которые подключаются ко всем компонентам схемы. Разрядность цепей по умолчанию — один бит. Цепи не хранят значения сигнала, и для того чтобы состояние сигнала в цепи было определено, какой-либо источник сигнала должен непрерывно управлять ею. Если цепь имеет несколько источников сигнала — драйверов (например, два выхода вентилей подключены к одной цепи), то значение результирующего сигнала в цепи имеет значение, согласно тому, какой тип цепи используется. Названия цепей и выполняемые ими функции приведены в таблице 16.

Таблица 16. Названия цепей и выполняемые ими функции

Название

Функция

Описание

Для этой цепи, если все драйверы имеют одно и то же значение, тогда wire принимает это же значение. Если все драйверы, кроме одного, имеют значение Z, тогда wire принимает значение того драйвера, который имеет значение выходного сигнала, не равное Z. Если два или больше не-Z драйвера имеют различную мощность выходного каскада, то wire принимает значение более сильного драйвера. Если два драйвера равной силы имеют различные значения, то wire принимает значение x.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *