Введение
Verilog имеет встроенные примитивы: вентили, буферы и ключи. Это лишь небольшая часть примитивов, если необходимо, пользователь может создать собственные, более сложные, при помощи UDP (User Defined Primitives). Используя UDP, мы можем моделировать:
- Схемы комбинационной логики
- Схемы последовательной логики [элементы с памятью, триггеры]
Мы можем включать информацию о тайминге в пользовательские примитивы, дополняя библиотеки заказных микросхем.
Синтаксис
Пользовательский примитив UDP начинается с ключевого слова primitive и заканчивается endprimitive. Он должен следовать за объявлением портов или терминалов данного примитива. Таким же образом мы определяем модули. Пользовательский примитив должен определяться за пределами контейнера module ... endmodule.
Verilog Code:
// Пример кода объявления портов вход/выход // и пользовательского примитива primitive udp_syntax ( a, // Port a b, // Port b c, // Port c d // Port d ); output a; input b,c,d; // Код UDP функции endprimitive
В коде, показанном выше, udp_syntax это имя примитива, примитив содержит порты a, b,c и d.
Формальный синтаксис определения пользовательских примитивов показан на следующеем примере:
Verilog Code:
::= primitive ( , <,>* ) ; + ? endprimitive ::= ::= ||= ||= ::= output ; ::= reg ; ::= input <,>* ; ::= initial = ; ::= 1'b0 ||= 1'b1 ||= 1'bx ||= 1 ||= 0 ::= table endtable ::= + ||= + ::= : ; ::= : : ; ::= ||= ::= + ::= * * ::= ( ) ||= ::= ::= ||= -
Правила для портов UDP
- UDP может содержать только один выход и не более 10 входов.
- Выходной порт всегда первый, за ним следуют входные порты.
- Все UDP порты скаляры, векторные порты не допускаются.
- Порты UDP не могут быть двунаправленными.
- Выходные терминалы последовательных UDP требуют дополнительного объявления как регистровый тип.
- Недопустимо объявлять регистром выходной терминал комбинационного UDP.
Тело функции
Функциональность примитива (как последовательного, так и комбинационного) описана в таблице, и описание заканчивается ключевым словом endtable, как показано ниже. Для последовательных UDP, мы можем использовать initial для описания начального состояния выхода.
Verilog Code:
// Код примитива с функцией UDP primitive udp_body ( a, // Port a b, // Port b c // Port c ); output a; input b,c; // Код функции примитива // A = B | C; table // B C : A ? 1 : 1; 1 ? : 1; 0 0 : 0; endtable endprimitive
Примечание: В таблицах пользовательских примитивов не допускается использовать значение Z.
Тест для проверки UDP функции из примера выше
Verilog Code:
`include "udp_body.v" module udp_body_tb(); reg b,c; wire a; udp_body udp (a,b,c); initial begin $monitor(" B = %b C = %b A = %b",b,c,a); b = 0; c = 0; #1 b = 1; #1 b = 0; #1 c = 1; #1 b = 1'bx; #1 c = 0; #1 b = 1; #1 c = 1'bx; #1 b = 0; #1 $finish; end endmodule
Вывод симулятора
Code:
<span style="color: black; font-size: small;"> B = 0 C = 0 A = 0 B = 1 C = 0 A = 1 B = 0 C = 0 A = 0 B = 0 C = 1 A = 1 B = x C = 1 A = 1 B = x C = 0 A = x B = 1 C = 0 A = 1 B = 1 C = x A = 1 B = 0 C = x A = x</span>
Table
table используется для описания функции UDP. Ключевое слово Verilog table обозначает начало таблицы, а ключевое слово endtable обозначает конец таблицы.
Каждая строка в таблице является условием изменения состояния выхода, зависящего от состояния входа. Состояние выхода вычисляется по изменениям входа.
Initial
Инструкция initial используется для инициализации последовательных примитивов. Следующая инструкция должна быть присваиванием, которое назначает битовое значение выходному терминалу типа reg.
Verilog Code:
primitive udp_initial (a,b,c); output a; input b,c; reg a; // a имеет значение 1 при старте симулятора initial a = 1'b1; table // функция примитива udp_initial endtable endprimitive
Символы
В пользовательских примитивах используются специальные символы, такие как передний фронт сигнала и т.д. Следующая таблица показывает их использование в примитивах.
Символ |
Интерпретация |
Пояснение |
? |
0 или 1 или X ? |
Переменная может быть 0 или 1 или X |
b |
0 или 1 |
Аналогично ?, но без включения X |
f |
-10 |
Задний фронт на входе |
r |
-1 |
Передний фронт на входе |
p |
(01) или (0X) или (X1) или (1Z) или (Z1) |
Передний фронт, включая X и Z |
n |
(10) или (1X) или (X0) или (0Z) или (Z0) |
Задний фронт, включая X и Z |
* |
(??) |
Любой переход |
- |
Без изменений |
|