Визуальная электроника

Введение

Verilog имеет встроенные примитивы: вентили, буферы и ключи. Это лишь небольшая часть примитивов, если необходимо, пользователь может создать собственные, более сложные, при помощи UDP (User Defined Primitives). Используя UDP, мы можем моделировать:

  • Схемы комбинационной логики
  • Схемы последовательной логики [элементы с памятью, триггеры]

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

Синтаксис

Пользовательский примитив UDP начинается с ключевого слова primitive и заканчивается endprimitive. Он должен следовать за объявлением портов или терминалов данного примитива. Таким же образом мы определяем модули. Пользовательский примитив должен определяться за пределами контейнера module ... endmodule.

Verilog Code:
  1. // Пример кода объявления портов вход/выход
  2. // и пользовательского примитива
  3. primitive udp_syntax (
  4. a, // Port a
  5. b, // Port b
  6. c, // Port c
  7. d // Port d
  8. );
  9. output a;
  10. input b,c,d;
  11.  
  12. // Код UDP функции
  13.  
  14. endprimitive

В коде, показанном выше, udp_syntax это имя примитива, примитив содержит порты a, b,c и d.

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

Verilog Code:
  1. ::= primitive ( ,
  2. <,>* ) ;
  3. +
  4. ?
  5.  
  6. endprimitive
  7.  
  8.  
  9. ::=
  10.  
  11.  
  12. ::=
  13. ||=
  14. ||=
  15.  
  16.  
  17. ::= output ;
  18.  
  19. ::= reg ;
  20.  
  21.  
  22. ::= input <,>* ;
  23.  
  24.  
  25. ::= initial = ;
  26.  
  27.  
  28. ::= 1'b0
  29. ||= 1'b1
  30. ||= 1'bx
  31. ||= 1
  32. ||= 0
  33.  
  34.  
  35. ::= table
  36.  
  37. endtable
  38.  
  39.  
  40. ::= +
  41. ||= +
  42.  
  43.  
  44. ::= : ;
  45.  
  46.  
  47. ::= : : ;
  48.  
  49.  
  50. ::=
  51. ||=
  52.  
  53.  
  54. ::= +
  55.  
  56.  
  57. ::= * *
  58.  
  59.  
  60. ::= ( )
  61. ||=
  62.  
  63.  
  64. ::=
  65.  
  66.  
  67. ::=
  68. ||= -

Правила для портов UDP

  • UDP может содержать только один выход и не более 10 входов.
  • Выходной порт всегда первый, за ним следуют входные порты.
  • Все UDP порты скаляры, векторные порты не допускаются.
  • Порты UDP не могут быть двунаправленными.
  • Выходные терминалы последовательных UDP требуют дополнительного объявления как регистровый тип.
  • Недопустимо объявлять регистром выходной терминал комбинационного UDP.

Тело функции

Функциональность примитива (как последовательного, так и комбинационного) описана в таблице, и описание заканчивается ключевым словом endtable, как показано ниже. Для последовательных UDP, мы можем использовать initial для описания начального состояния выхода.

Verilog Code:
  1. // Код примитива с функцией UDP
  2. primitive udp_body (
  3. a, // Port a
  4. b, // Port b
  5. c // Port c
  6. );
  7. output a;
  8. input b,c;
  9.  
  10. // Код функции примитива
  11. // A = B | C;
  12. table
  13. // B C : A
  14. ? 1 : 1;
  15. 1 ? : 1;
  16. 0 0 : 0;
  17. endtable
  18.  
  19. endprimitive

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

Тест для проверки UDP функции из примера выше

Verilog Code:
  1. `include "udp_body.v"
  2. module udp_body_tb();
  3.  
  4. reg b,c;
  5. wire a;
  6.  
  7. udp_body udp (a,b,c);
  8.  
  9. initial begin
  10. $monitor(" B = %b C = %b A = %b",b,c,a);
  11. b = 0;
  12. c = 0;
  13. #1 b = 1;
  14. #1 b = 0;
  15. #1 c = 1;
  16. #1 b = 1'bx;
  17. #1 c = 0;
  18. #1 b = 1;
  19. #1 c = 1'bx;
  20. #1 b = 0;
  21. #1 $finish;
  22. end
  23.  
  24. endmodule

Вывод симулятора

Code:
  1. <span style="color: black; font-size: small;"> B = 0 C = 0 A = 0
  2. B = 1 C = 0 A = 1
  3. B = 0 C = 0 A = 0
  4. B = 0 C = 1 A = 1
  5. B = x C = 1 A = 1
  6. B = x C = 0 A = x
  7. B = 1 C = 0 A = 1
  8. B = 1 C = x A = 1
  9. B = 0 C = x A = x</span>

Table

table используется для описания функции UDP. Ключевое слово Verilog table обозначает начало таблицы, а ключевое слово endtable обозначает конец таблицы.

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

Initial

Инструкция initial используется для инициализации последовательных примитивов. Следующая инструкция должна быть присваиванием, которое назначает битовое значение выходному терминалу типа reg.

Verilog Code:
  1. primitive udp_initial (a,b,c);
  2. output a;
  3. input b,c;
  4. reg a;
  5. // a имеет значение 1 при старте симулятора
  6. initial a = 1'b1;
  7.  
  8. table
  9. // функция примитива udp_initial
  10. endtable
  11.  
  12. 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

*

(??)

Любой переход

-

Без изменений