14. Specify блоки в Verilog HDL

Описывается блок specify, объявление путей в модуле и назначение этим путям задержек
Содержание

Два типа HDL-конструкций часто используются для описания задержек для структурных моделей, таких как ячейки ASIC. Они следующие:

  • Распределенные задержки, которые определяют время, необходимое для распространения событий через вентили и сети внутри модуля (см. 7.14).
  • Задержки на пути модуля, которые описывают время, необходимое событию в источнике (входной порт или выходной порт) для распространения к месту назначения (выходной или двунаправленный порт).

Этот пункт описывает, как пути задаются в модуле и как задержки назначаются этим путям.

14.1 Объявление specify блока

Блочный оператор, называемый блоком specify, является средством описания путей между источником и пунктом назначения и назначения задержек для этих путей. Синтаксис для блоков specify показан в Синтаксисе 14-1.

specify_block ::= specify { specify_item } endspecify specify_item ::= specparam_declaration | pulsestyle_declaration | showcancelled_declaration | path_declaration | system_timing_check
Синтаксис 14-1-Синтаксис для блока specify

Блок specify должен быть ограничен ключевыми словами specify и endspecify и должен появляться внутри объявления модуля. Блок specify может быть использован для выполнения следующих задач:

  • Опишите различные пути через модуль.
  • Назначьте задержки для этих путей.
  • Выполните проверку временных параметров, чтобы убедиться, что события, происходящие на входах модуля, удовлетворяют временным ограничениям устройства, описываемого модулем (см. п. 15).

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

Например:
specify specparam tRise_clk_q = 150, tFall_clk_q = 200; specparam tSetup = 70; (clk => q) = (tRise_clk_q, tFall_clk_q); $setup(d, posedge clk, tSetup); endspecify

Первые две строки, следующие за ключевым словом specify, объявляют параметры specify, которые рассматриваются в разделе 4.10.3. Строка, следующая за объявлением параметров specify, описывает путь модуля и назначает задержки этому пути модуля. Параметры specify определяют задержку, назначенную пути модуля. Указание путей модулей представлено в разделе 14.2. Назначение задержек путям модулей рассматривается в разделе 14.3. Строка, предшествующая ключевому слову endspecify, объявляет одну из проверок синхронизации системы, которые рассматриваются далее в п. 15.

14.2 Объявление пути к модулю

Для настройки задержек пути модуля в specify блоке необходимо выполнить два шага:

1) Опишите пути модулей.

2) Назначьте задержки для этих путей (см. 14.3).

Синтаксис объявления пути модуля описан в Синтаксис 14-2.

path_declaration ::= simple_path_declaration ; | edge_sensitive_path_declaration ; | state_dependent_path_declaration ;
Синтаксис 14-2-Синтаксис для объявления пути к модулю

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

Например:

На рисунке 14-1 показана схема с задержками на пути модуля. Более одного источника (A, B, C и D) могут иметь модульный путь к одному и тому же месту назначения (Q), и для каждого пути от входа к выходу могут быть заданы различные задержки.

На рисунке 14-1 показана схема с задержками на пути модуля Verilog HDL. Более одного источника (A, B, C и D) могут иметь модульный путь к одному и тому же месту назначения (Q), и для каждого пути от входа к выходу могут быть заданы различные задержки.
Рисунок 14-1 Модульные задержки на пути

14.2.1 Ограничения пути модуля

Пути модулей имеют следующие ограничения:

  • Источник пути модуля должен быть сетью, которая подключена к input или output порту модуля.
  • Место назначения пути модуля должно быть сетью или переменной, которая подключена к output или inout порту модуля.
  • Модуль назначения пути должен иметь только один источник внутри модуля.

14.2.2 Простые пути модулей

Синтаксис для указания простого пути к модулю приведен в Синтаксисе 14-3.

simple_path_declaration ::= parallel_path_description = path_delay_value | full_path_description = path_delay_value parallel_path_description ::= ( specify_input_terminal_descriptor [ polarity_operator ] => specify_output_terminal_descriptor ) full_path_description ::= ( list_of_path_inputs [ polarity_operator ] *> list_of_path_outputs ) list_of_path_inputs ::= specify_input_terminal_descriptor { , specify_input_terminal_descriptor } list_of_path_outputs ::= specify_output_terminal_descriptor { , specify_output_terminal_descriptor } specify_input_terminal_descriptor ::= input_identifier [ [ constant_range_expression ] ] specify_output_terminal_descriptor ::= output_identifier [ [ constant_range_expression ] ] input_identifier ::= input_port_identifier | inout_port_identifier output_identifier ::= output_port_identifier | inout_port_identifier polarity_operator ::= + | -
Синтаксис 14-3 Синтаксис для простого пути модуля

Простые пути могут быть объявлены в одной из двух форм:

  • Источник *> пункт назначения
  • Источник => пункт назначения

Символы *> и => представляют собой различные виды соединения между источником пути модуля и пунктом назначения пути модуля. Оператор *> устанавливает полное соединение между источником и пунктом назначения. Оператор => устанавливает параллельное соединение между источником и пунктом назначения. Описание путей полного и параллельного соединения приведено в разделе 14.2.5.

Например:

Следующие три примера иллюстрируют допустимые простые объявления путей к модулю:
(A => Q) = 10; (B => Q) = (12); (C, D *> Q) = 18;

14.2.3 Пути, чувствительные к фронтам

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

Синтаксис объявления пути, чувствительного к границам, показан в Синтаксисе 14-4.

edge_sensitive_path_declaration ::= parallel_edge_sensitive_path_description = path_delay_value | full_edge_sensitive_path_description = path_delay_value parallel_edge_sensitive_path_description ::= ( [ edge_identifier ] specify_input_terminal_descriptor => ( specify_output_terminal_descriptor [ polarity_operator ] : data_source_expression ) ) full_edge_sensitive_path_description ::= ( [ edge_identifier ] list_of_path_inputs *> ( list_of_path_outputs [ polarity_operator ] : data_source_expression ) ) data_source_expression ::= expression edge_identifier ::= posedge | negedge
Синтаксис 14-4 — Синтаксис для объявления пути, чувствительного к границам

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

Чувствительный к фронтам путь может быть задан с помощью полных соединений (*>) или параллельных соединений (=>). Для параллельных соединений (=>) пунктом назначения должен быть любой скалярный выход или двунаправленный порт или выборка битов векторного выхода или двунаправленного порта. Для полных соединений (*>) местом назначения должен быть список из одного или нескольких векторных или скалярных портов вывода и ввода, а также битовых выборок или частичных выборок векторных портов вывода и ввода. Описание параллельных путей и путей полного соединения см. в разделе 14.2.5.

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

Например:

Пример 1 Следующий пример демонстрирует объявление пути, чувствительного к фронтам, с оператором положительной полярности:
( posedge clock => ( out +: in ) ) = (10, 8);

В этом примере, при положительном фронте тактового сигнала, путь модуля простирается от тактового сигнала до out, используя задержку нарастания 10 и задержку спада 8. Путь данных идет от in к out, причем in не инвертируется при распространении к out.

Пример 2 — Следующий пример демонстрирует объявление пути, чувствительного к фронтам, с оператором отрицательной полярности:
( negedge clock[0] => ( out -: in ) ) = (10, 8);

В этом примере при отрицательном фронте clock[0] путь модуля простирается от clock[0] до out с задержкой нарастания 10 и задержкой спада 8. Путь данных идет от in к out, причем in инвертируется при распространении к out.

Пример 3 Следующий пример демонстрирует объявление пути, чувствительного к фронтам, без идентификатора фронтов:
( clock => ( out : in ) ) = (10, 8);

В этом примере при любом изменении clock путь модуля простирается от clock до out.

14.2.4 Пути, зависящие от состояния

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

Описание пути, зависящее от состояния, включает следующие элементы:

  • Условное выражение, которое, будучи оцененным как true, включает путь модуля
  • Описание пути к модулю
  • Выражение задержки, которое применяется к пути модуля

Синтаксис объявления пути, зависящего от состояния, показан в Синтаксисе 14-5.

state_dependent_path_declaration ::= if ( module_path_expression ) simple_path_declaration | if ( module_path_expression ) edge_sensitive_path_declaration | ifnone simple_path_declaration
Синтаксис 14-5-Синтаксис для путей, зависящих от состояния

14.2.4.1 Условное выражение

Операнды в условном выражении должны быть построены из следующих элементов:

  • Порты ввода скалярного или векторного модуля или порты вывода или их битовая или частичная выборка
  • Локально определенные переменные или сети или их битовая или частичная выборка
  • Константы времени компиляции (постоянные числа и задающие параметры)

В таблице 14-1 приведен список допустимых операторов, которые могут использоваться в условных выражениях.

Условное выражение должно иметь значение true (1), чтобы пути, зависящему от состояния, было присвоено значение задержки. Если условное выражение оценивается как x или z, оно должно рассматриваться как true. Если условное выражение оценивается в несколько битов, то наименьший значащий бит должен представлять результат. Условное выражение может иметь любое количество операндов и операторов.

Таблица 14-1 Список допустимых операторов в выражении задержки пути в зависимости от состояния
ОператорОписаниеОператорОписание
~побитовое отрицание&сокращение и
&побитовый и|сокращение или
|побитовое или^сокращение xor
^побитовый ксор~&уменьшение n и
^~ ~^побитовый xnor~|сокращение ни
==логическое равенство^~ ~^сокращение кснора
!=логическое неравенство{}конкатенация
&&логичный и{ {} }репликация
||логический или?:условный
!логически не

14.2.4.2 Простые пути, зависящие от состояния

Если описание пути, зависящего от состояния, является простым путем, то он называется простым путем, зависящим от состояния. Описание простого пути рассматривается в разделе 14.2.2.

Например:

Пример 1 — В следующем примере используются пути, зависящие от состояния, для описания времени работы XOR вентиля.
module XORgate (a, b, out); input a, b; output out; xor x1 (out, a, b); specify specparam noninvrise = 1, noninvfall = 2; specparam invertrise = 3, invertfall = 4; if (a) (b => out) = (invertrise, invertfall); if (b) (a => out) = (invertrise, invertfall); if (~a)(b => out) = (noninvrise, noninvfall); if (~b)(a => out) = (noninvrise, noninvfall); endspecify endmodule

В этом примере первые два пути, зависящие от состояния, описывают пару времен задержки нарастания и спада выходного сигнала, когда XOR-вентиль (x1) инвертирует изменяющийся вход. Последние два пути, зависящие от состояния, описывают другую пару времен задержки нарастания и спада выходного сигнала, когда XOR-вентиль буферизирует изменяющийся вход.

Пример 2 — Следующий пример моделирует неполный АЛУ. Пути, зависящие от состояния, задают различные задержки для разных операций АЛУ.
module ALU (o1, i1, i2, opcode); input [7:0] i1, i2; input [2:1] opcode; output [7:0] o1; //functional description omitted specify // операция добавления if (opcode == 2'b00) (i1,i2 *> o1) = (25.0, 25.0); // сквозная операция i1 if (opcode == 2'b01) (i1 => o1) = (5.6, 8.0); // сквозная операция i2 if (opcode == 2'b10) (i2 => o1) = (5.6, 8.0); // задержки при изменении opcode (opcode *> o1) = (6.1, 6.5); endspecify endmodule

В предыдущем примере первые три объявления путей объявляют пути, простирающиеся от входов операндов i1 и i2 до выхода o1. Задержки на этих путях назначаются операциям на основе операции, указанной на входах opcode. Последнее объявление пути декларирует путь от входа opcode до выхода o1.

14.2.4.3 Чувствительные к фронтам пути, зависящие от состояния

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

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

  • Фронт, состояние или и то, и другое делают каждую декларацию уникальной.
  • На порт ссылаются одинаково во всех объявлениях путей (весь порт, битовая или частичная выборка).

Например:

Пример 1
if ( !reset && !clear ) ( posedge clock => ( out +: in ) ) = (10, 8) ;

В этом примере, если положительный фронт clock возникает, когда сброс и очистка находятся в низком уровне, путь модуля простирается от clock до out, используя задержку нарастания 10 и задержку спада 8.

Пример 2 — В следующем примере показаны 2 чувствительных к фронтам объявления пути, каждое из которых имеет уникальное ребро:
specify ( posedge clk => ( q[0] : data ) ) = (10, 5); ( negedge clk => ( q[0] : data ) ) = (20, 12); endspecify
Пример 3 — В следующем примере показаны 2 объявления путей чувствительных к фронтам, каждое из которых имеет уникальное условие:
specify if (reset) ( posedge clk => ( q[0] : data ) ) = (15, 8); if (!reset && cntrl) ( posedge clk => ( q[0] : data ) ) = (6, 2); endspecify
Пример 4 — Два объявления пути, зависящие от состояния, показанные ниже, являются неправильными, потому что, хотя они имеют разные условия, пункты назначения указаны по-разному: первый пункт назначения является частичной выборкой, второй — битовой выборкой.
specify if (reset) (posedge clk => (q[3:0]:data)) = (10,5); if (!reset) (posedge clk => (q[0]:data)) = (15,8); endspecif

14.2.4.4 Условие ifnone

Ключевое слово ifnone используется для указания задержки пути, зависящего от состояния, по умолчанию, когда все остальные условия для пути ложны. Условие ifnone должно указывать те же источник и пункт назначения пути модуля, что и зависимые от состояния пути модуля. Следующие правила применяются к модульным путям, указанным с условием ifnone:

  • Только простые пути модулей могут быть описаны с условием ifnone.
  • Пути, зависящие от состояния, которые соответствуют пути ifnone, могут быть либо простыми модульными путями, либо путями, чувствительными к фронтам.
  • Если для пути модуля ifnone нет соответствующих путей модуля, зависящих от состояния, то ifnone путь модуля должен рассматриваться так же, как безусловный простой путь модуля.
  • Запрещено указывать как условие ifnone для пути модуля, так и безусловный простой путь модуля для одного и того же пути модуля.

Например:

Пример 1 Ниже приведены допустимые комбинации путей, зависящие от состояния:
if (C1) (IN => OUT) = (1,1); ifnone (IN => OUT) = (2,2); // операция добавления if (opcode == 2'b00) (i1,i2 *> o1) = (25.0, 25.0); // сквозная операция i1 if (opcode == 2'b01) (i1 => o1) = (5.6, 8.0); // сквозная операция i2 if (opcode == 2'b10) (i2 => o1) = (5.6, 8.0); // для все других операция ifnone (i2 => o1) = (15.0, 15.0); (posedge CLK => (Q +: D)) = (1,1); ifnone (CLK => Q) = (2,2);
Пример 2 — Следующая комбинация описания пути модуля является неправильной, поскольку она объединяет зависимый от состояния путь, использующий условие ifnone, и безусловный путь для того же пути модуля:
if (a) (b => out) = (2,2); if (b) (a => out) = (2,2); ifnone (a => out) = (1,1); (a => out) = (1,1)

14.2.5 Полное и параллельное подключения путей

Оператор *> используется для установления полного соединения между источником и получателем. При полном соединении каждый бит источника должен соединяться с каждым битом места назначения. Источник пути модуля не обязательно должен иметь то же количество битов, что и место назначения пути модуля.

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

  • Для описания пути по модулю между вектором и скаляром
  • Для описания пути по модулю между векторами разных размеров
  • Для описания пути модуля с несколькими источниками или несколькими пунктами назначения в одном операторе (см. 14.2.6)

Оператор => используется для установления параллельного соединения между источником и пунктом назначения. В параллельном соединении каждый бит в источнике должен соединяться с одним соответствующим битом в пункте назначения. Параллельные пути модуля могут быть созданы только между источниками и пунктами назначения, которые содержат одинаковое количество битов.

Параллельные соединения являются более ограничительными, чем полные соединения. Они соединяют только один источник с одним пунктом назначения, где каждый сигнал содержит одинаковое количество битов. Поэтому параллельное соединение может использоваться только для описания пути по модулю между двумя векторами одинакового размера. Поскольку скаляры имеют ширину 1 бит, для установки межбитовых соединений между двумя скалярами можно использовать *> или =>.

Например:

Пример 1Рисунок 14-2 иллюстрирует, чем параллельное соединение отличается от полного соединения между двумя 4-битными векторами.

Рисунок 14-2 иллюстрирует, чем параллельное соединение отличается от полного соединения между двумя 4-битными векторами Verilog HDL
Рисунок 14.2 — Разница между параллельным и полным соединительными путями
Пример 2 — В следующем примере показаны пути модулей для мультиплексора 2:1 с двумя 8-разрядными входами и одним 8-разрядным выходом:
module mux8 (in1, in2, s, q) ; output [7:0] q; input [7:0] in1, in2; input s; // функциональное описание опущено... specify (in1 => q) = (3, 4) ; (in2 => q) = (2, 3) ; (s *> q) = 1; endspecify endmodul

Путь модуля от s до q использует полное соединение (*>), потому что он соединяет скалярный источник — 1-битную линию выбора — с векторным получателем — 8-битной выходной шиной. Модульные пути от обеих входных линий in1 и in2 до q используют параллельное соединение (=>), поскольку устанавливают параллельные соединения между двумя 8-битными шинами.

14.2.6 Объявление нескольких путей к модулю в одном операторе

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

Соединение в объявлении пути к нескольким модулям всегда является полным соединением. Например:
(a, b, c *> q1, q2) = 10;
эквивалентна следующим шести индивидуальным назначениям путей модуля:
(a *> q1) = 10 ; (b *> q1) = 10 ; (c *> q1) = 10 ; (a *> q2) = 10 ; (b *> q2) = 10 ; (c *> q2) = 10 ;

14.2.7 Полярность пути модуля

Полярность пути модуля — это произвольная спецификация, указывающая, инвертируется ли направление перехода сигнала при его распространении от входа к выходу. Это произвольное описание полярности не влияет на фактическое распространение данных или событий через модель. То, как нарастание(восходящий фронт, от 0 к 1) или спад(спадающий фронт, от 1 к 0) сигнала в источнике распространяется к месту назначения, зависит от внутренней логики модуля.

Пути модулей могут задавать любую из трех полярностей:

  • Неизвестная полярность
  • Положительная полярность
  • Отрицательная полярность

14.2.7.1 Неизвестная полярность

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

  • Подъем в источнике может вызвать восходящий, спадающий или отсутствие перехода в пункте назначения.
  • Спад в источнике может вызвать восходящий, спадающий или отсутствие перехода в пункте назначения.

Путь модуля, указанный либо как полное соединение, либо как параллельное соединение, но без оператора полярности + или -, должен рассматриваться как путь модуля с неизвестной полярностью.

Например:
// Неизвестная полярность (In1 => q) = In_to_q ; (s *> q) = s_to_q ;

14.2.7.2 Положительная полярность

Для модульных путей с положительной полярностью любой переход в источнике может вызвать такой же переход в пункте назначения, как показано ниже:

  • Подъем в источнике может вызвать либо восходящий, либо отсутствие перехода в пункте назначения.
  • Спад в источнике может вызвать либо спадающий, либо отсутствие перехода в пункте назначения.
Путь модуля с положительной полярностью задается префиксом оператора полярности + к => или *>. Например:
// Положительная полярность (In1 +=> q) = In_to_q ; (s +*> q) = s_to_q ;

14.2.7.3 Отрицательная полярность

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

  • Подъем в источнике может вызвать либо спадающий, либо отсутствие перехода в пункте назначения.
  • Спад в источнике может вызвать либо повышающий, либо отсутствие перехода в пункте назначения.
Путь модуля с отрицательной полярностью задается префиксом оператора полярности — к => или *>. Например:
// Отрицательная полярность (In1 -=> q) = In_to_q ; (s -*> q) = s_to_q ;

14.3 Назначение задержек для пути модулей

Задержки, возникающие на выходах модуля, где заканчиваются пути, должны быть заданы путем присвоения значений задержки описаниям путей модуля. Синтаксис для объявления значений задержек показан в Синтаксисе 14-6.

path_delay_value ::= list_of_path_delay_expressions | ( list_of_path_delay_expressions ) list_of_path_delay_expressions ::= t_path_delay_expression | trise_path_delay_expression , tfall_path_delay_expression | trise_path_delay_expression , tfall_path_delay_expression , tz_path_delay_expression | t01_path_delay_expression , t10_path_delay_expression , t0z_path_delay_expression , tz1_path_delay_expression , t1z_path_delay_expression , tz0_path_delay_expression | t01_path_delay_expression , t10_path_delay_expression , t0z_path_delay_expression , tz1_path_delay_expression , t1z_path_delay_expression , tz0_path_delay_expression , t0x_path_delay_expression , tx1_path_delay_expression , t1x_path_delay_expression , tx0_path_delay_expression , txz_path_delay_expression , tzx_path_delay_expression t_path_delay_expression ::= path_delay_expression
Синтаксис 14-6 Синтаксис для значения задержки пути

В объявлении задержки пути модуля описание пути модуля (см. 14.2) указывается в левой части, а одно или несколько значений задержки — в правой. Значения задержки могут быть дополнительно заключены в пару круглых скобок. Для пути модуля может быть назначено одно, два, три, шесть или двенадцать значений задержки, как описано в п. 14.3.1. Значения задержки должны быть константными выражениями, содержащими литералы или specparams, и может быть выражение задержки вида min:typ:max.

Например:
specify // Specify параметры specparam tRise_clk_q = 45:150:270, tFall_clk_q=60:200:350; specparam tRise_Control = 35:40:45, tFall_control=40:50:65; // назначение путям модуля (clk => q) = (tRise_clk_q, tFall_clk_q); (clr, pre *> q) = (tRise_control, tFall_control); endspecify

В приведенном примере параметры specify, объявленные после ключевого слова specparam, задают значения задержек пути модуля. Назначения путей модуля присваивают эти задержки путям модуля.

14.3.1 Указание задержек перехода для путях модулей

Каждое выражение задержки пути может быть одним значением, представляющим типичную задержку, или разделенным двоеточием списком из трех значений, представляющих минимальную, типичную и максимальную задержку в таком порядке. Если выражение задержки пути приводит к отрицательному значению, оно должно рассматриваться как ноль. В таблице 14-2 описано, как различные значения задержки пути должны быть связаны с различными переходами. Имена выражений задержки пути соответствуют именам, используемым в синтаксисе 14-6.

Таблица 14-2-Связывание выражений задержки пути с переходами
Переходы/Количество заданных выражений задержки пути123612
0 -> 1ttrisetriset01t01
1 -> 0ttfalltfallt10t10
0 -> zttrisetzt0zt0z
z -> 1ttrisetrisetz1tz1
1 -> zttfalltzt1zt1z
z -> 0ttfalltfalltz0tz0
0 -> x****t0x
x -> 1****tx1
1 -> x****t1x
x -> 0****tx0
x -> z****txz
z -> x****tzx

* См. 14.3.2.

Например:
// одно выражение определяет все переходы (C => Q) = 20; (C => Q) = 10:14:20; // два выражения определяют задержки нарастания и спада specparam tPLH1 = 12, tPHL1 = 25; specparam tPLH2 = 12:16:22, tPHL2 = 16:22:25; (C => Q) = ( tPLH1, tPHL1 ) ; (C => Q) = ( tPLH2, tPHL2 ) ; // три выражения определяют задержки переходов нарастания, спада и z specparam tPLH1 = 12, tPHL1 = 22, tPz1 = 34; specparam tPLH2 = 12:14:30, tPHL2 = 16:22:40, tPz2 = 22:30:34; (C => Q) = (tPLH1, tPHL1, tPz1); (C => Q) = (tPLH2, tPHL2, tPz2); // шесть выражений определяют переходы к/от 0, 1 и z specparam t01 = 12, t10 = 16, t0z = 13, tz1 = 10, t1z = 14, tz0 = 34 ; (C => Q) = ( t01, t10, t0z, tz1, t1z, tz0) ; specparam T01 = 12:14:24, T10 = 16:18:20, T0z = 13:16:30 ; specparam Tz1 = 10:12:16, T1z = 14:23:36, Tz0 = 15:19:34 ; (C => Q) = ( T01, T10, T0z, Tz1, T1z, Tz0) ; // двенадцать выражений указывают все задержки переходов в явном виде specparam t01=10, t10=12, t0z=14, tz1=15, t1z=29, tz0=36, t0x=14, tx1=15, t1x=15, tx0=14, txz=20, tzx=30 ; (C => Q) = (t01, t10, t0z, tz1, t1z, tz0, t0x, tx1, t1x, tx0, txz, tzx) ;

14.3.2 Указание задержек перехода x

Если задержки перехода в x не указаны явно, то расчет значений задержек для перехода в x основывается на следующих двух пессимистических правилах:

  • Переход из известного состояния в x должен происходить как можно быстрее. То есть, для любого перехода в x должна использоваться минимально возможная задержка.
  • Переход из состояния x в известное состояние должен занимать как можно больше времени. То есть, для любого перехода из x должна использоваться как можно большая задержка.

В таблице 14-3 представлен общий алгоритм расчета значений задержки для x-переходов вместе с конкретными примерами. В таблице представлены следующие две группы x-переходов:

1) Переход из известного состояния s в x: s -> x

2) Переход из x в известное состояние s: x -> s

Таблица 14-3 Расчет задержек для x-переходов
X переходЗначение задержки
Общий алгоритм
s -> xминимум (s -> другие известные сигналы)
x -> sмаксимум (другие известные сигналы -> s)
Конкретные переходы
0 -> xминимум (0 -> z задержка, 0 -> 1 задержка)
1 -> xминимум (1 -> z задержка, 1 -> 0 задержка)
z -> xминимум (z -> 1 задержка, z -> 0 задержка)
x -> 0максимум (z -> 0 задержка, 1 -> 0 задержка)
x -> 1максимум (z -> 1 задержка, 0 -> 1 задержка)
x -> zмаксимум (1 -> задержка z, 0 -> задержка z)
Использование: (C => Q) = (5, 12, 17, 10, 6, 22) ;
0 -> xминимум (17, 5) = 5
1 -> xминимум (6, 12) = 6
z -> xминимум (10, 22) = 10
x -> 0максимум (22, 12) = 22
x -> 1максимум (10, 5) = 10
x -> zмаксимум (6, 17) = 17

14.3.3 Выбор задержки

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

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

После определения активных уточняющих путей необходимо выбрать задержку среди них. Это делается путем сравнения правильной задержки для конкретного запланированного перехода из каждого specify пути и выбора наименьшей.

Например:

Пример 1
(A => Y) = (6, 9); (B => Y) = (5, 11);

Для перехода Y от 0 к 1, если A перешел позже, чем B, будет выбрана задержка 6. Но если B перешел более позже, чем A, то будет выбрана задержка 5. А если при последнем переходе A и B сделали это одновременно, то будет выбрана наименьшая из двух задержек нарастания, то есть задержка нарастания от B, равная 5. Задержка спада от A, равная 9, будет выбрана, если Y вместо этого перейдет от 1 к 0.

Пример 2
if (MODE < 5) (A => Y) = (5, 9); if (MODE < 4) (A => Y) = (4, 8); if (MODE < 3) (A => Y) = (6, 5); if (MODE < 2) (A => Y) = (3, 2); if (MODE < 1) (A => Y) = (7, 7);

В зависимости от значения MODE могут быть активны от нуля до пяти из этих specify путей. Например, когда MODE равен 2, активны первые три задающих пути. Для перехода по нарастанию будет выбрана задержка 4, так как это наименьшая задержка нарастания среди первых трех. Переход на спад выберет задержку 5, так как это наименьшая задержка спада среди первых трех.

14.4 Смешивание задержек пути модуля и распределенных задержек

Если модуль содержит задержки на пути модуля и распределенные задержки (задержки на примитивных экземплярах внутри модуля), то для каждого пути используется большая из двух задержек.

Например:

Пример 1Рисунок 14-3 иллюстрирует простую схему, смоделированную с помощью комбинации распределенных задержек и задержек пути (показан только путь от входа D до выхода Q). Здесь задержка на пути модуля от входа D до выхода Q равна 22, а сумма распределенных задержек равна 0 + 1 = 1. Поэтому переход на Q, вызванный переходом на D, произойдет через 22 единицы времени после перехода на D.

Рисунок 14-3 иллюстрирует простую схему Verilog HDL, смоделированную с помощью комбинации распределенных задержек и задержек пути (показан только путь от входа D до выхода Q)
Рисунок 14-3 Задержки на пути к модулю больше, чем распределенные задержки

Пример 2 На рисунке 14-4 задержка на пути модуля от D до Q равна 22, но распределенные задержки вдоль этого пути модуля теперь составляют 10 + 20 = 30. Поэтому событие на Q, вызванное событием на D, произойдет через 30 единиц времени после события на D.

На рисунке 14-4 задержка на пути модуля от D до Q равна 22, но распределенные задержки вдоль этого пути модуля теперь составляют 10 + 20 = 30. Поэтому событие на Q, вызванное событием на D, произойдет через 30 единиц времени после события на D
Рисунок 14-4 Задержки на пути к модулю меньше, чем распределенные задержки

14.5 Управление проводной логикой

Выходные сети пути модуля не должны иметь более одного драйвера в пределах модуля. Поэтому проводная логика на выходах тракта модуля не допускается.

На рисунке 14-5 показано нарушение этого правила проводного вывода и метод, позволяющий избежать нарушения правила.

На рисунке 14-5 показано нарушение этого правила проводного вывода и метод, позволяющий избежать нарушения правила Verilog HDL
Рисунок 14-5 Законные и незаконные пути модулей

На рисунке 14-5 (a) любой путь модуля к S является неправильным, потому что конечный пункт пути имеет два источника.

Предполагая, что сигнал S на рисунке 14-5 (a) является проводным, это ограничение можно обойти, заменив проводную логику на стробируемую логику, чтобы создать один источник на выходе. На рисунке 14-5 (b) показано, как добавление третьего вентиля. Заштрихованный вентиль — решает проблему для модуля на рисунке 14-5 (a).

Пример на рисунке 14-6 также является неправильным. В этом примере, когда выходы Q и R соединены вместе, создается ситуация, когда оба пути имеют несколько источников из одного модуля.

Пример на рисунке 14-6 также является неправильным. В этом примере, когда выходы Q и R соединены вместе, создается ситуация, когда оба пути имеют несколько источников из одного модуля
Рисунок 14-6 Пути модулей расставлены неправильно

Хотя несколько выходных источников к месту назначения пути запрещены внутри одного модуля, они разрешены вне модуля. Пример на рисунке 14-7 является законным, потому что Q и R имеют только по одному источнику в пределах модуля, в котором указаны пути модуля.

Пример на рисунке 14-7 является законным, потому что Q и R имеют только по одному источнику в пределах модуля, в котором указаны пути модуля
Рисунок 14-7-Пути к законному модулю

14.6 Детальное управление поведением импульсной фильтрации. Пределы ошибки и отклонения

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

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

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

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

На рисунке 14-8 задержка нарастания от входа A до выхода Y равна 7, а задержка спада — 9. По умолчанию предел ошибки и предел отклонения для задержки нарастания равны 7. Предел ошибки и предел отклонения для задержки спада оба равны 9. Пределы импульса, связанные с задержкой, формирующей задний фронт импульса, определяют, следует ли фильтровать импульс и каким образом. Форма волны Y’ показывает форму волны, полученную в результате отсутствия фильтрации импульса. Ширина импульса равна 2, что меньше предела отбраковки для задержки нарастания 7. Поэтому импульс фильтруется, как показано на форме волны Y.

На рисунке 14-8 задержка нарастания от входа A до выхода Y равна 7, а задержка спада - 9
Рисунок 14-8 Пример импульсной фильтрации

Существует три способа изменить пределы импульсов по сравнению с их значениями по умолчанию. Во-первых, язык Verilog предоставляет параметр PATHPULSE$ specparam для изменения пределов импульсов по сравнению с их значениями по умолчанию. Во-вторых, в опциях вызова можно указать проценты, применяемые ко всем задержкам пути модуля для формирования соответствующих пределов ошибок и пределов отклонения. В-третьих, аннотация SDF может индивидуально аннотировать предел ошибки и предел отклонения для каждой задержки перехода по пути модуля.

14.6.1 Specify блочного управления предельными значениями импульсов

Предельные значения импульсов могут быть заданы из блока specify с помощью параметра PATHPULSE$ specparam. Синтаксис для использования PATHPULSE$ для задания предельных значений отклонения и ошибки приведен в Синтаксисе 14-7.

pulse_control_specparam ::= PATHPULSE$ = ( reject_limit_value [ , error_limit_value ] ) | PATHPULSE$specify_input_terminal_descriptor$specify_output_terminal_descriptor = ( reject_limit_value [ , error_limit_value ] ) error_limit_value ::= limit_value reject_limit_value ::= limit_value limit_value ::= constant_mintypmax_expression
Синтаксис 14-7-Синтаксис для управления импульсами PATHPULSE$

Если указано только значение предела ошибки, оно должно применяться как к пределу отклонения, так и к пределу ошибки.

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

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

Если в объявлении пути модуля объявлено несколько путей, параметр PATHPULSE$ должен быть указан только для первого входного порта пути и первого выходного порта пути. Указанные предел отказа и предел ошибки должны применяться ко всем остальным путям в объявлении нескольких путей. Параметр PATHPULSE$, указывающий что-либо, кроме входного и выходного портов первого пути, игнорируется.

Например:

В следующем примере путь (clk=>q) получает предел отклонения 2 и предел ошибки 9, как определено первой декларацией PATHPULSE$. Пути (clr*>q) и (pre*>q) получают предел отклонения 0 и предел ошибки 4, как определено второй декларацией PATHPULSE$. Путь (data=>q) не определен явно ни в одном из объявлений PATHPULSE$. Поэтому он получает предел отказа и предел ошибки 3, как определено последним объявлением PATHPULSE$.
specify (clk => q) = 12; (data => q) = 10; (clr, pre *> q) = 4; specparam PATHPULSE$clk$q = (2,9), PATHPULSE$clr$q = (0,4), PATHPULSE$ = 3; endspecify

14.6.2 Глобальное управление предельными значениями импульсов

Два параметра вызова могут задавать проценты, применяемые глобально ко всем задержкам перехода пути модуля. Опция вызова error limit задает процент от каждой задержки перехода пути модуля, используемый для предельного значения ошибки. Опция вызова reject limit задает процент от каждой задержки перехода пути модуля, используемый для предельного значения отказа. Процентные значения должны быть целым числом от 0 до 100.

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

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

Когда присутствуют оба параметра вызова PATHPULSE$ и глобальный предел импульса, PATHPULSE$ значения имеют приоритет.

14.6.3 SDF аннотация предельных значений импульсов

Аннотация SDF может быть использована для указания предельных значений импульсов задержек перехода между путями модуля. Более подробно это описано в пункте 16.

При наличии PATHPULSE$, глобальных опций вызова пределов импульса и аннотации SDF значений пределов импульса, значения аннотации SDF имеют приоритет.

14.6.4 Подробные возможности управления импульсами

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

14.6.4.1 Фильтрация импульсов по событию(on-event) в сравнении с фильтрацией по обнаружению(on-detect)

Когда выходной импульс должен быть отфильтрован на X, больший пессимизм может быть выражен, если выход тракта модуля переходит сразу на X (on-detect), а не в уже запланированное время перехода по переднему фронту импульса (on-event).

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

Как и метод on-event, метод фильтрации импульсов по обнаружению изменяет передний фронт импульса на переход к X и задний фронт на переход от X, но время переднего фронта изменяется таким образом, что он возникает сразу после обнаружения импульса.

Рисунок 14-9 иллюстрирует это поведение на примере простого буфера с асимметричным временем нарастания/спада, где пределы отклонения и ошибки равны 0. Показана форма выходного сигнала для подходов «по обнаружению» и «по событию».

Рисунок 14-9 иллюстрирует это поведение на примере простого буфера с асимметричным временем нарастания/спада, где пределы отклонения и ошибки равны 0
Рисунок 14-9 Обнаружение в сравнении с событием

Поведение при обнаружении или при событии может быть выбрано двумя различными способами. Во-первых, один из них может быть выбран глобально для всех выходов тракта модуля с помощью опции вызова on-detect или on-event. Во-вторых, один из вариантов может быть выбран локально с помощью объявления стиля импульса блока specify.

Синтаксис объявления pulsestyle показан в Синтаксисе 14-8.

pulsestyle_declaration ::= pulsestyle_onevent list_of_path_outputs ; | pulsestyle_ondetect list_of_path_outputs ;
Синтаксис 14-8 Синтаксис для объявления стиля импульса(pulsestyle)

Если вывод пути модуля появляется в объявлении стиля импульса после того, как он уже появился в объявлении пути модуля, это ошибка.

Опции вызова pulsestyle имеют приоритет над объявлениями блоков specify pulsestyle.

14.6.4.2 Обнаружение отрицательного импульса

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

Отрицательные импульсы могут быть обозначены состоянием X с помощью стиля поведения showcancelled. Когда задний фронт импульса должен быть запланирован перед передним фронтом, этот стиль заставляет передний фронт быть запланированным на X, а задний фронт — на X. При стиле импульса on-event расписание на X заменяет расписание переднего фронта. При стиле импульса по обнаружению расписание на X составляется сразу после обнаружения отрицательного импульса.

Поведение showcancelled может быть включено двумя различными способами. Во-первых, оно может быть включено глобально для всех выходов путей модуля с помощью опций showcancelled и noshowcancelled invocation. Во-вторых, оно может быть включено локально с помощью объявлений блока specify showcancelled.

Синтаксис для деклараций showcancelled показан в Синтаксисе 14-9.

showcancelled_declaration ::= showcancelled list_of_path_outputs ; | noshowcancelled list_of_path_outputs ;
Синтаксис 14-9 — Синтаксис для деклараций с показателями

Ошибкой является появление вывода пути модуля в объявлении showcancelled после того, как он уже появился в объявлении пути модуля. Опции вызовов showcancelled имеют приоритет над объявлениями блоков specify showcancelled.

Показное поведение проиллюстрировано на рисунке 14-10, где показан узкий импульс, поданный на вход буфера с неравными задержками нарастания/спада. Это приводит к тому, что задний фронт импульса планируется раньше, чем передний фронт. Передний фронт входного импульса планирует выходное событие на 6 единиц позже в точке, обозначенной A. Задний фронт импульса происходит на одну единицу времени позже, что планирует выходное событие на 4 единицы позже, обозначенное точкой B. Это второе расписание на выходе происходит на время, предшествующее уже существующему расписанию для переднего фронта выходного импульса.

Форма выходного сигнала показана для трех различных режимов работы. Первая осциллограмма показывает поведение по умолчанию с не включенной функцией showcancelled и стилем on-event по умолчанию. Вторая форма волны показывает поведение с showcancelled в сочетании со стилем on-event. Последняя форма волны показывает поведение с showcancelled в сочетании со стилем on-detect.

Показное поведение, где показан узкий импульс, поданный на вход буфера с неравными задержками нарастания/спада
Рисунок 14-10 Проблема отмены текущего события и ее исправление

Такая же ситуация может возникнуть при почти одновременном переходе на вход, который определяется как переход двух входов ближе друг к другу по времени, чем разница в их соответствующих задержках до выхода. На рисунке 14-11 показаны осциллограммы для двухвходового NAND-вентиля, где первоначально A имеет высокий уровень, а B — низкий. B переходит 0->1 в момент времени 10, вызывая график выхода 1->0 в момент времени 24. A переходит 1->0 в момент времени 12, вызывая график 0->1 в момент времени 22. Стрелками отмечены переходы на выходе, вызванные переходами на входах A и B.

Форма выходного сигнала показана для трех различных режимов работы. Первая осциллограмма показывает поведение по умолчанию с не включенной функцией showcancelled и стилем on-event по умолчанию. Вторая показывает поведение с showcancelled в сочетании со стилем on-event. Третий показывает поведение с showcancelled в сочетании с включением обнаружения.

На рисунке 14-11 показаны осциллограммы для двухвходового NAND-вентиля, где первоначально A имеет высокий уровень, а B - низкий
Рисунок 14-11 — NAND-вентиля с почти одновременным переключением входов, когда одно событие запланировано до другого, которое еще не наступило

Один из недостатков стиля on-event с показным поведением заключается в том, что по мере сближения фронтов выходных импульсов, длительность результирующего состояния X становится меньше. Рисунок 14-12 иллюстрирует, как стиль on-detect решает эту проблему.

Один из недостатков стиля on-event с показным поведением заключается в том, что по мере сближения фронтов выходных импульсов, длительность результирующего состояния X становится меньше. Рисунок иллюстрирует, как стиль on-detect решает эту проблему
Рисунок 14-12 — NAND-вентиля с почти одновременным переключением входа и выходным событием, запланированным на одно и то же время

Например:

Пример 1
specify (a=>out)=(2,3); (b =>out)=(3,4); endspecify

Поскольку в блоке specify нет объявлений pulsestyle или showcancelled, компилятор применяет режимы по умолчанию on-event и noshowcancelled.

Пример 2
specify (a=>out)=(2,3); showcancelled out; (b =>out)=(3,4); endspecify

Это объявление showcancelled является ошибочным, потому что оно следует за использованием out объявлении пути модуля. Противоречиво, если бы out имел поведение noshowcancelled от входа a, но showcancelled от входа b.

Пример 3 — Оба этих блока specify дают одинаковый результат. Выходы out и out_b объявлены как showcancelled и on-detect.
specify showcancelled out; pulsestyle_ondetect out; (a => out) = (2,3); (b => out) = (4,5); showcancelled out_b; pulsestyle_ondetect out_b; (a => out_b) = (3,4); (b => out_b) = (5,6); endspecify specify showcancelled out,out_b; pulsestyle_ondetect out,out_b; (a => out) = (2,3); (b => out) = (4,5); (a => out_b) = (3,4); (b => out_b) = (5,6); endspecify