diff --git a/.github/SUMMARY.md b/.github/SUMMARY.md index e378e0b..f00a9d0 100644 --- a/.github/SUMMARY.md +++ b/.github/SUMMARY.md @@ -45,7 +45,6 @@ - [Защелки](Basic%20Verilog%20structures/Latches.md) - [О различиях между блокирующими и неблокирующими присваиваниями](Basic%20Verilog%20structures/Assignments.md) - [Контроллеры](Basic%20Verilog%20structures/Controllers.md) -- [Тестовое окружение](Basic%20Verilog%20structures/Testbench.md) --- diff --git a/.pic/Basic Verilog structures/assignments/fig_03.drawio.svg b/.pic/Basic Verilog structures/assignments/fig_03.drawio.svg index db8f9c5..eb3fe20 100644 --- a/.pic/Basic Verilog structures/assignments/fig_03.drawio.svg +++ b/.pic/Basic Verilog structures/assignments/fig_03.drawio.svg @@ -1,4 +1,4 @@ -
a
b
c
in
out
clk
\ No newline at end of file +
module blocking_assignment(
  input  logic a, b
  output logic c, d
);

// непрерывное присваивание
always_ff @(posedge clk) begin
  b = a;

  c = b;  // обновленное значение b

  d = c;  // обновленное значение с
end

endmodule
module nonblocking_assignment(
  input  logic a, b
  output logic c, d
);

// непрерывное присваивание
always_ff @(posedge clk) begin
  b <= a;

  c <= b;  // старое значение b

  d <= c;  // старое значение c
end

endmodule
\ No newline at end of file diff --git a/.pic/Basic Verilog structures/assignments/fig_04.drawio.svg b/.pic/Basic Verilog structures/assignments/fig_04.drawio.svg new file mode 100644 index 0000000..db8f9c5 --- /dev/null +++ b/.pic/Basic Verilog structures/assignments/fig_04.drawio.svg @@ -0,0 +1,4 @@ + + + +
a
b
c
in
out
clk
\ No newline at end of file diff --git a/.pic/Basic Verilog structures/assignments/fig_04.png b/.pic/Basic Verilog structures/assignments/fig_05.png similarity index 100% rename from .pic/Basic Verilog structures/assignments/fig_04.png rename to .pic/Basic Verilog structures/assignments/fig_05.png diff --git a/.pic/Basic Verilog structures/assignments/fig_05.drawio.svg b/.pic/Basic Verilog structures/assignments/fig_06.drawio.svg similarity index 100% rename from .pic/Basic Verilog structures/assignments/fig_05.drawio.svg rename to .pic/Basic Verilog structures/assignments/fig_06.drawio.svg diff --git a/.pic/Basic Verilog structures/assignments/fig_06.png b/.pic/Basic Verilog structures/assignments/fig_06.png deleted file mode 100644 index 93ff309..0000000 Binary files a/.pic/Basic Verilog structures/assignments/fig_06.png and /dev/null differ diff --git a/.pic/Basic Verilog structures/assignments/fig_07.png b/.pic/Basic Verilog structures/assignments/fig_07.png index 3a95c05..93ff309 100644 Binary files a/.pic/Basic Verilog structures/assignments/fig_07.png and b/.pic/Basic Verilog structures/assignments/fig_07.png differ diff --git a/.pic/Basic Verilog structures/assignments/fig_08.png b/.pic/Basic Verilog structures/assignments/fig_08.png index c66be01..3a95c05 100644 Binary files a/.pic/Basic Verilog structures/assignments/fig_08.png and b/.pic/Basic Verilog structures/assignments/fig_08.png differ diff --git a/.pic/Basic Verilog structures/assignments/fig_09.png b/.pic/Basic Verilog structures/assignments/fig_09.png index cbe0d91..c66be01 100644 Binary files a/.pic/Basic Verilog structures/assignments/fig_09.png and b/.pic/Basic Verilog structures/assignments/fig_09.png differ diff --git a/.pic/Basic Verilog structures/assignments/fig_10.png b/.pic/Basic Verilog structures/assignments/fig_10.png index 4a35308..cbe0d91 100644 Binary files a/.pic/Basic Verilog structures/assignments/fig_10.png and b/.pic/Basic Verilog structures/assignments/fig_10.png differ diff --git a/.pic/Basic Verilog structures/assignments/fig_11.png b/.pic/Basic Verilog structures/assignments/fig_11.png index a5c4b8e..4a35308 100644 Binary files a/.pic/Basic Verilog structures/assignments/fig_11.png and b/.pic/Basic Verilog structures/assignments/fig_11.png differ diff --git a/.pic/Basic Verilog structures/assignments/fig_12.png b/.pic/Basic Verilog structures/assignments/fig_12.png index c93ed4d..a5c4b8e 100644 Binary files a/.pic/Basic Verilog structures/assignments/fig_12.png and b/.pic/Basic Verilog structures/assignments/fig_12.png differ diff --git a/.pic/Basic Verilog structures/assignments/fig_13.png b/.pic/Basic Verilog structures/assignments/fig_13.png new file mode 100644 index 0000000..c93ed4d Binary files /dev/null and b/.pic/Basic Verilog structures/assignments/fig_13.png differ diff --git a/.pic/Basic Verilog structures/assignments/fig_13.drawio.svg b/.pic/Basic Verilog structures/assignments/fig_14.drawio.svg similarity index 100% rename from .pic/Basic Verilog structures/assignments/fig_13.drawio.svg rename to .pic/Basic Verilog structures/assignments/fig_14.drawio.svg diff --git a/Basic Verilog structures/Assignments.md b/Basic Verilog structures/Assignments.md index d2c8a45..bf3544b 100644 --- a/Basic Verilog structures/Assignments.md +++ b/Basic Verilog structures/Assignments.md @@ -7,24 +7,43 @@ Давайте разберемся что это за присваивания и почему необходимо руководствоваться этими правилами. -Начать придется издалека. Несмотря на то, что SystemVerilog является **языком описания аппаратуры**, он так же является и языком для верификации описанной аппаратуры (слово `Verilog` является объединением двух слов: `verification` и `logic`). Для целей верификации в языке выделено целое подмножество конструкций, которые не могут быть использованы для описания аппаратуры — так называемое "_несинтезируемое подмножество языка SystemVerilog_". Разумеется, часть языка, которая может быть использована для описания аппаратуры ("_синтезируемое подмножество языка SystemVerilog_") тоже может использоваться в верификации (хотя бы для того, чтобы было что проверять, ведь проверяемая аппаратура описывается этими средствами). +Начать придется издалека. Несмотря на то, что SystemVerilog является **языком описания аппаратуры**, он так же является и языком для верификации описанной аппаратуры (слово `Verilog` является объединением двух слов: `verification` и `logic`). Для целей верификации в языке выделено целое подмножество конструкций, которые не могут быть использованы для описания аппаратуры — так называемое "_несинтезируемое подмножество языка SystemVerilog_". Разумеется, часть языка, которая может быть использована для описания аппаратуры ("_синтезируемое подмножество языка SystemVerilog_") тоже может использоваться в верификации. Давайте для начала разберемся в том, как будут использоваться операторы присваивания при программном моделировании (так называемой симуляции) — одним из инструментов верификации. Разобравшись в поведении операторов во время симуляции будет куда проще объяснить результат использования операторов при синтезе цифровой схемы. -Для начала введем пару сокращений для удобства дальнейшего повествования: +Введем пару сокращений для удобства дальнейшего повествования: -- под `LHS` (left hand side) мы будем подразумевать "выражение, **которому присваивают**"; -- под `RHS` (right hand side) мы будем подразумевать "выражение **которое присваивают**". +- под `LHS` (left hand side) мы будем подразумевать "выражение, **которому** присваивают"; +- под `RHS` (right hand side) мы будем подразумевать "выражение **которое** присваивают". В выражении `a = b+c`, `a` является `LHS`, `b+c` является `RHS`. -Существует два вида присваиваний: **непрерывное** и **процедурное**. + два вида присваиваний: **непрерывное** и **процедурное**. + +```SystemVerilog +module assignment_example( + input logic a, b + output logic c, d +); + +// непрерывное присваивание +assign c = a + b; + +// процедурное присваивание +always_comb begin + d = a + b; +end + +endmodule +``` + +_Листинг 1. Пример непрерывного и процедурного присваивания._ С непрерывным присваиванием вы знакомитесь в самом начале — это оператор `assign`. Непрерывное присваивание постоянно следит за `RHS` этого оператора, и каждый раз, когда любая часть этого выражения меняет своё значение, производит пересчёт значения `RHS`, а затем сразу же передает это значение `LHS`. Если мы произведем `assign a = b+c`, то каждый раз, когда будет меняться значение `b` или `c`, будет пересчитываться результат их суммы, который сразу же будет присвоен выражению `a`. **Непрерывное присваивание может быть использовано только вне программных блоков.** -Под "программными блоками" подразумеваются блоки `always` (всех типов) и `initial`. Есть и другие программные блоки, но в рамках данного курса лабораторных работ вы с ними не столкнетесь. Вообще говоря, синтаксис языка SystemVerilog допускает использование оператора `assign` внутри программного блока, однако в рамках данного курса не существует ни одной ситуации, когда это может потребоваться и со 100% вероятностью будет ошибочно. +Под "программными блоками" подразумеваются блоки `always` (всех типов) и `initial`. Есть и другие программные блоки, но в рамках данного курса лабораторных работ вы с ними не столкнетесь. Вообще говоря, синтаксис языка SystemVerilog допускает использование оператора `assign` внутри программного блока (так называемое "**процедурное непрерывное присваивание**")[[2, стр. 232]](https://ieeexplore.ieee.org/document/8299595), однако в рамках данного курса не существует ни одной ситуации, когда это может потребоваться и со 100% вероятностью будет ошибочно. В отличие от непрерывного присваивания, **процедурное присваивание может быть использовано только в программных блоках**. @@ -70,11 +89,15 @@ _Рисунок 2. Пример цепочки неблокирующих при 2. Затем вычисляется значение `RHS` второго присваивания. Поскольку `a` еще не присвоили значение `5`, результатом `RHS` становится текущее значение `a` — 3. Присваивание этого значения сигналу `b` **откладывается** на потом. 3. Аналогичным образом вычисляется `RHS` третьего присваивания (`2`). Присваивание этого значения также **откладывается** на потом. -Так называемое "**потом**" наступает когда завершается вычисление `RHS` всех неблокирующих присваиваний и завершение присвоений всех блокирующих присваиваний (однако "потом" все равно происходит в тот же момент времени, обратите внимание на значение времени на _рис. 2_). В стандарте SystemVerilog этот момент называется `NBA-region` (сокр. от "Non-Blocking Assignment region") [2, стр. 61]. Выполнение отложенных присваиваний происходит в том же порядке, в котором они шли в программном блоке. Подробнее о том как работает событийная симуляция (event based simulation) в SystemVerilog вы можете прочесть в стандарте [IEEE 1800-2017](https://ieeexplore.ieee.org/document/8299595) (раздел 4). Стандарт доступен бесплатно всем желающим по программе "IEEE GET Program". +Так называемое "**потом**" наступает когда завершается вычисление `RHS` всех неблокирующих присваиваний и завершение присвоений всех блокирующих присваиваний (однако "потом" все равно происходит в тот же момент времени, обратите внимание на значение времени на _рис. 2_). В стандарте SystemVerilog этот момент называется `NBA-region` (сокр. от "Non-Blocking Assignment region") [[2, стр. 61]](https://ieeexplore.ieee.org/document/8299595). Выполнение отложенных присваиваний происходит в том же порядке, в котором они шли в программном блоке. Подробнее о том как работает событийная симуляция (event based simulation) в SystemVerilog вы можете прочесть в стандарте [IEEE 1800-2017](https://ieeexplore.ieee.org/document/8299595) (раздел 4). Стандарт доступен бесплатно всем желающим по программе "IEEE GET Program". -Таким образом, если `LHS` блокирующего присваивания используется в качестве операнда `RHS` любого другого последующего присваивания, результат предыдущего выражения будет передан дальше **в тот же момент времени**, что очень похоже на "_последовательное вычисление_". +Таким образом, если `LHS` **блокирующего** присваивания используется в качестве операнда `RHS` любого другого последующего присваивания, это выражение будет иметь уже обновленное значение, что очень похоже на "_последовательное вычисление_". -С другой стороны `LHS` неблокирующего присваивания не может использоваться в качестве операнда `RHS` последующих присваиваний, что создает иллюзию "_параллельного вычисления_". +С другой стороны значение, присвоенное `LHS` значение с помощью **неблокирующего** присваивания не может использоваться в качестве операнда `RHS` последующих присваиваний, что создает иллюзию "_параллельного вычисления_" (см. _рис. 3_). + +![../.pic/Basic%20Verilog%20structures/assignments/fig_03.drawio.svg](../.pic/Basic%20Verilog%20structures/assignments/fig_03.drawio.svg) + +_Рисунок 3. Иллюстрация блокирующих и неблокирующих присваиваний._ Теперь, понимая как работают присваивания с точки зрения моделирования, посмотрим на то, во что могут синтезироваться подобные операторы. @@ -104,37 +127,37 @@ assign out = c; endmodule ``` -_Листинг 1. Пример описания модуля, использующего цепочку блокирующих присваиваний._ +_Листинг 2. Пример описания модуля, использующего цепочку блокирующих присваиваний._ Если вы уже знакомы с содержимым документа о том, [как описывать регистры](Registers.md), подумайте: какой будет результат синтеза у этой схемы? --- -Давайте "прочитаем" эту схему. Мы видим модуль, с входом `in`, выходом `out` и тактирующим синхроимпульсом `clk`. Так же мы видим три сигнала `a`,`b`,`c`, которые описываются в блоке `always_ff`, предназначенном для описания регистров. Значение `in` по цепочке этих регистров передается до регистра `c`, выход которого подключен к выходу `out`. +Давайте "прочитаем" эту схему. Мы видим модуль, с входом `in`, выходом `out` и тактирующим синхроимпульсом `clk`. Также мы видим три сигнала `a`,`b`,`c`, которые описываются в блоке `always_ff`, предназначенном для описания регистров. Значение `in` по цепочке этих регистров передается до регистра `c`, выход которого подключен к выходу `out`. -Похоже, что здесь был описан [**сдвиговый регистр**](https://ru.wikipedia.org/wiki/Регистр_(цифровая_техника)#Сдвигающие_(последовательные)_регистры), представленный на _рис. 3_. +Похоже, что здесь был описан [**сдвиговый регистр**](https://ru.wikipedia.org/wiki/Регистр_(цифровая_техника)#Сдвигающие_(последовательные)_регистры), представленный на _рис. 4_. -![../.pic/Basic%20Verilog%20structures/assignments/fig_03.drawio.svg](../.pic/Basic%20Verilog%20structures/assignments/fig_03.drawio.svg) +![../.pic/Basic%20Verilog%20structures/assignments/fig_04.drawio.svg](../.pic/Basic%20Verilog%20structures/assignments/fig_04.drawio.svg) -_Рисунок 3. Трехразрядный сдвиговый регистр._ +_Рисунок 4. Трехразрядный сдвиговый регистр._ Давайте откроем цифровую схему, сгенерированную Vivado и убедимся в наших выводах. -![../.pic/Basic%20Verilog%20structures/assignments/fig_04.png](../.pic/Basic%20Verilog%20structures/assignments/fig_04.png) +![../.pic/Basic%20Verilog%20structures/assignments/fig_05.png](../.pic/Basic%20Verilog%20structures/assignments/fig_05.png) -_Рисунок 4. Схема, сгенерированная Vivado по описанию из Листинга 1._ +_Рисунок 5. Схема, сгенерированная Vivado по описанию из Листинга 2._ Произошло что-то странное. Вместо трех регистров Vivado создал только один и судя по названию — это последний регистр `c`. Почему это произошло? Изучим внимательней поведение цепочки блокирующих присваиваний, представленное на _рис. 1_. -Каждое последующее присваивание ожидало, пока не выполнится предыдущее, таким образом, `RHS` первого присваивания (`5`) сразу же (без каких-либо задержек) распространился по всем регистрам. Моделируя _Листинг 1_ мы получим **поведение**, когда на вход каждого регистра будет подаваться сигнал `in`. +Каждое последующее присваивание ожидало, пока не выполнится предыдущее, таким образом, `RHS` первого присваивания (`5`) сразу же распространился по всем регистрам. Моделируя _Листинг 2_ мы получим **поведение**, когда на вход каждого регистра будет подаваться сигнал `in`. -Таким образом на самом деле, мы должны были изобразить нашу схему как на _рис. 5_. +Таким образом на самом деле, мы должны были изобразить нашу схему как на _рис. 6_. -![../.pic/Basic%20Verilog%20structures/assignments/fig_05.drawio.svg](../.pic/Basic%20Verilog%20structures/assignments/fig_05.drawio.svg) +![../.pic/Basic%20Verilog%20structures/assignments/fig_06.drawio.svg](../.pic/Basic%20Verilog%20structures/assignments/fig_06.drawio.svg) -_Рисунок 5. Схема, описанная Листингом 1._ +_Рисунок 6. Схема, описанная Листингом 2._ Но почему тогда на схеме Vivado не осталось регистров `a` и `b`? Посмотрим на них внимательней. Их выходы ни на что не влияют, они висят неподключенные. А значит эти регистры не имеют никакого смысла и если их убрать, ничего не изменится. @@ -149,11 +172,11 @@ Vivado обнаружил, что регистры `a` и `b` ни на что Если вы используете Vivado 2023.1 и новее, вы можете обнаруживать подобные предупреждения более удобным способом — посредством линтера, который можно вызвать из вкладки `RTL ANALYSIS` окна `Flow Navigator`. -![../.pic/Basic%20Verilog%20structures/assignments/fig_06.png](../.pic/Basic%20Verilog%20structures/assignments/fig_06.png) +![../.pic/Basic%20Verilog%20structures/assignments/fig_07.png](../.pic/Basic%20Verilog%20structures/assignments/fig_07.png) -_Рисунок 6. Пример вызова линтера._ +_Рисунок 7. Пример вызова линтера._ -Давайте заменим в _Листинге 1_ блокирующие присваивания на неблокирующие. Напоминаем, что оператор неблокирующего присваивания записывается как `<=`. +Давайте заменим в _Листинге 2_ блокирующие присваивания на неблокирующие. Напоминаем, что оператор неблокирующего присваивания записывается как `<=`. ```SystemVerilog module example_2( @@ -175,21 +198,21 @@ assign out = c; endmodule ``` -_Листинг 2. Пример описания модуля, использующего цепочку неблокирующих присваиваний._ +_Листинг 3. Пример описания модуля, использующего цепочку неблокирующих присваиваний._ Посмотрим, какую схему сгенерирует Vivado в этот раз. -![../.pic/Basic%20Verilog%20structures/assignments/fig_07.png](../.pic/Basic%20Verilog%20structures/assignments/fig_07.png) +![../.pic/Basic%20Verilog%20structures/assignments/fig_08.png](../.pic/Basic%20Verilog%20structures/assignments/fig_08.png) -_Рисунок 7. Схема, сгенерированная Vivado по описанию из Листинга 2._ +_Рисунок 8. Схема, сгенерированная Vivado по описанию из Листинга 3._ -Вряд ли полученный результат стал для вас неожиданным сюжетным поворотом, но давайте разберемся, почему в этот раз сгенерировалась схема, аналогичная представленной на _рис. 3_. +Вряд ли полученный результат стал для вас неожиданным сюжетным поворотом, но давайте разберемся, почему в этот раз сгенерировалась схема, аналогичная представленной на _рис. 4_. -Для этого обратимся к примеру, представленному на _рис. 2_. В данном примере **неблокирующем присваивании** сперва вычислялись значения всех `RHS` (запоминались значения выходов всех регистров) и только потом происходило присваивание новых значений. Подобное **поведение** аналогично поведению сдвиговых регистров. +Для этого обратимся к примеру, представленному на _рис. 2_. В данном примере **неблокирующего присваивания** сперва вычислялись значения всех `RHS` (запоминались значения выходов всех регистров) и только потом происходило присваивание новых значений. Подобное **поведение** аналогично поведению сдвиговых регистров. Слово "_поведение_" было выделено дважды неспроста. Описание схем, которое мы сделали называется "**поведенческим описанием схемы**". -Можно ли реализовать сдвиговый регистр, используя блокирующие присваивания? Конечно. Например, можно поменять порядок присваиваний как в _Листинге 3_. +Можно ли реализовать сдвиговый регистр, используя блокирующие присваивания? Конечно. Например, можно поменять порядок присваиваний как в _Листинге 4_. ```SystemVerilog module example_3( @@ -211,9 +234,9 @@ assign out = c; endmodule ``` -_Листинг 3. Цепочка блокирующих присваиваний в порядке обратном приведенному в Листинге 1._ +_Листинг 4. Цепочка блокирующих присваиваний в порядке обратном приведенному в Листинге 2._ -В этом случае, линтер не сообщит ни о каких ошибках, а Vivado сгенерирует схему, аналогичную _рис. 7_ +В этом случае, линтер не сообщит ни о каких ошибках, а Vivado сгенерирует схему, аналогичную _рис. 8_ Так произошло, поскольку мы разорвали зависимость значений `RHS` последующих присваиваний от значений `LHS` предыдущих (поведение, которое демонстрировала цепочка неблокирующих присваиваний с самого начала). Однако данное решение является скорее хаком, чем примером хорошего проектирования. По сути, мы просто подстроили код, описанный с помощью блокирующих присваиваний таким образом, чтоб он вел себя как код, использующий неблокирующие присваивания. @@ -247,29 +270,29 @@ assign out = c; endmodule ``` -_Листинг 4. Сдвиговый регистр, описанный через блокирующие присваивания в отдельных блоках always._ +_Листинг 5. Сдвиговый регистр, описанный через блокирующие присваивания в отдельных блоках always._ -Сгенерированная в Vivado схема будет аналогична _рис. 7_. Но давайте попробуем промоделировать работу этой схемы, подавая случайные воздействия на вход `in`. - -![../.pic/Basic%20Verilog%20structures/assignments/fig_08.png](../.pic/Basic%20Verilog%20structures/assignments/fig_08.png) - -_Рисунок 8. Симуляция модуля, описанного Листингом 4._ - -Выглядит как-то не по "сдвигово-регистерски". В чем же дело? - -Как уже упоминалось ранее, программные блоки (коими являются блоки `always`) исполняются во время моделирования независимо друг от друга в недетерминированном стандартом порядке. На практике это означает то, что сперва может исполниться второй блок, потом третий, а потом первый — либо в любом другом порядке. Разработчик не может рассчитывать на порядок блоков `always` при описании схемы. - -Конкретно в данной ситуации, симулятор воспроизвел блоки ровно в том порядке, в котором они были описаны. Сперва `a` получил значение `in`, потом `b` получил обновленное значение `a`, затем `c` получил обновленное значение `b`. - -Поскольку поведение недетерминировано, нельзя однозначно сказать, какую схему должен был воспроизвести синтезатор. В данной ситуации, он воспроизвел схему которую мы хотели получить, что, тем не менее, не помогло с моделированием. - -Если заменить порядок `always` подобно тому, как мы изменили порядок в _Листинге 3_, результат на временной диаграмме совпадет с поведением сдвигового регистра. +Сгенерированная в Vivado схема будет аналогична _рис. 8_. Но давайте попробуем промоделировать работу этой схемы, подавая случайные воздействия на вход `in`. ![../.pic/Basic%20Verilog%20structures/assignments/fig_09.png](../.pic/Basic%20Verilog%20structures/assignments/fig_09.png) -_Рисунок 9. Моделирование поведения сдвигового регистра._ +_Рисунок 9. Симуляция модуля, описанного Листингом 5._ -Однако, как уже объяснялось ранее, вы не можете рассчитывать на такой результат. Сегодня симулятор смоделировал поведение одним образом — завтра он смоделирует этот же код, в котором не изменилась ни одна строка, по-другому, и будет по прежнему работать в соответствии со стандартом. +Выглядит как-то не по "сдвигово-регистерски". В чем же дело? + +Как уже упоминалось ранее, программные блоки (коими являются блоки `always`) исполняются во время моделирования независимо друг от друга в недетерминированном стандартом порядке. На практике это означает то, что сперва может исполниться второй блок, потом третий, а потом первый — либо в любом другом порядке. Разработчик не может (и не должен) рассчитывать на порядок блоков `always` при описании схемы. + +Конкретно в данной ситуации, симулятор воспроизвел блоки ровно в том порядке, в котором они были описаны. Сперва `a` получил значение `in`, потом `b` получил обновленное значение `a`, затем `c` получил обновленное значение `b`. + +Поскольку поведение недетерминировано, нельзя однозначно сказать, какую схему должен был воспроизвести синтезатор. В данной ситуации, он воспроизвел схему которую мы хотели получить, но моделирование того же самого модуля демонстрирует поведение вовсе не этой схемы. + +Если заменить порядок `always` подобно тому, как мы изменили порядок в _Листинге 4_, результат на временной диаграмме совпадет с поведением сдвигового регистра. + +![../.pic/Basic%20Verilog%20structures/assignments/fig_10.png](../.pic/Basic%20Verilog%20structures/assignments/fig_10.png) + +_Рисунок 10. Моделирование поведения сдвигового регистра._ + +Однако, как уже объяснялось ранее, вы не можете рассчитывать на такой результат. Сегодня симулятор смоделировал поведение одним образом — завтра он смоделирует этот же код (в котором не изменилась ни одна строка) по-другому, и будет по прежнему работать в соответствии со стандартом. Для того, чтобы получить детерминированный результат, вам необходимо снова воспользоваться неблокирующим присваиванием, поскольку и в этом случае порядок исполнения блоков `always` не влияет на результат присваиваний — сначала вычисляются значения `RHS` всех неблокирующих присваиваний всех программных блоков, и только потом происходит присваивание этих значений `LHS`. @@ -292,17 +315,17 @@ end endmodule ``` -_Листинг 5. Пример цепочки блокирующих присваиваний с комбинационной логикой._ +_Листинг 6. Пример цепочки блокирующих присваиваний с комбинационной логикой._ -Остановитесь на минуту и подумайте, схему с каким поведением описывает _Листинг 5_? +Остановитесь на минуту и подумайте, схему с каким поведением описывает _Листинг 6_? --- Как вы могли догадаться, данный листинг описывает схему с одним регистром `d`, на вход которого подается результат комбинационной логики `c & (a | b)`, поскольку сперва в `temp` попадает результат `a | b` и только после этого вычисляется значение `c & temp`. -![../.pic/Basic%20Verilog%20structures/assignments/fig_10.png](../.pic/Basic%20Verilog%20structures/assignments/fig_10.png) +![../.pic/Basic%20Verilog%20structures/assignments/fig_11.png](../.pic/Basic%20Verilog%20structures/assignments/fig_11.png) -_Рисунок 10. Схема, сгенерированная Vivado по описанию из Листинга 5._ +_Рисунок 11. Схема, сгенерированная Vivado по описанию из Листинга 6._ Попробуйте догадаться о том, что произойдет, если снова заменить блокирующие присваивания на неблокирующие? @@ -310,9 +333,9 @@ _Рисунок 10. Схема, сгенерированная Vivado по оп Результат изменится следующим образом. -![../.pic/Basic%20Verilog%20structures/assignments/fig_11.png](../.pic/Basic%20Verilog%20structures/assignments/fig_11.png) +![../.pic/Basic%20Verilog%20structures/assignments/fig_12.png](../.pic/Basic%20Verilog%20structures/assignments/fig_12.png) -_Рисунок 11. Схема, сгенерированная Vivado по описанию из Листинга 5 после замены блокирующих присваиваний на неблокирующие._ +_Рисунок 12. Схема, сгенерированная Vivado по описанию из Листинга 6 после замены блокирующих присваиваний на неблокирующие._ Из прочтенного может сложиться впечатление, будто бы автор хочет показать, что блокирующее присваивание — это плохо, а неблокирующее — хорошо, однако это не так. Это просто два похожих инструмента, работающих разными способами, о которых должен знать профессионал, использующий эти инструменты. @@ -320,7 +343,7 @@ _Рисунок 11. Схема, сгенерированная Vivado по оп Рассмотрим предыдущий пример еще раз. Нельзя сказать, что одна схема лучше другой — это просто две разные схемы и то, какая из них вам нужна зависит только от вашей задачи. -Однако нельзя не заметить, что при использовании блокирующего присваивания, мы "теряли" регистры. +Однако нельзя не заметить, что при использовании блокирующего присваивания, мы "теряли" регистры. Более того, моделирование **неблокирующих** присваиваний ближе всего по поведению приближено к моделированию регистровой логики [[1, стр. 14]](http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf). Пока что мы рассматривали только синхронные схемы (схемы, работающие по тактовому синхроимпульсу). @@ -342,19 +365,19 @@ end endmodule ``` -_Листинг 6. Пример цепочки блокирующих присваиваний в комбинационной схеме._ +_Листинг 7. Пример цепочки блокирующих присваиваний в комбинационной схеме._ > Обратите внимание на то, что `always_ff` поменялся на `always_comb`. -Как вы думаете, какая схема будет сгенерирована по описанию, представленному _Листинга 6_, и что произойдет с этой схемой, если заменить в нем все блокирующие присваивания на неблокирующие? +Как вы думаете, какая схема будет сгенерирована по описанию, представленному _Листинга 7_, и что произойдет с этой схемой, если заменить в нем все блокирующие присваивания на неблокирующие? --- -Вас может это удивить, но в обоих случаях будет сгенерирована схема, представленная на _рис. 12_. +Вас может это удивить, но в обоих случаях будет сгенерирована схема, представленная на _рис. 13_. -![../.pic/Basic%20Verilog%20structures/assignments/fig_12.png](../.pic/Basic%20Verilog%20structures/assignments/fig_12.png) +![../.pic/Basic%20Verilog%20structures/assignments/fig_13.png](../.pic/Basic%20Verilog%20structures/assignments/fig_13.png) -_Рисунок 12. Схема, сгенерированная Vivado по описанию из Листинга 6._ +_Рисунок 13. Схема, сгенерированная Vivado по описанию из Листинга 7._ > Девочка остолбенела. У неё возникло отчётливое чувство какой-то ужасной несправедливости по отношению к ней. Гарри Поттер был грязным, отвратительным обманщиком и лжецом. Но во время игры все его ответы были верными. [Элиезер Юдковский / Гарри Поттер и методы рационального мышления] @@ -366,15 +389,15 @@ _Рисунок 12. Схема, сгенерированная Vivado по оп Теперь, когда мы стали использовать блок `always_comb`, правила игры изменились. Нет, принцип работы блокирующих и неблокирующих присваиваний остался тем же самым. Изменилось только то, сколько раз будет вызван данный блок. -Начнем со схемы, построенной по блокирующему присваиванию. В общем-то, тут у вас не должно было возникнуть вопросов, логика ровно та же, что была и при построении схемы по _Листингу 5_ (_рис. 10)_, только без выходного регистра. Что логично, ведь мы убрали тактирующий сигнал. +Начнем со схемы, построенной по описанию, использующему блокирующее присваивание. В общем-то, тут у вас не должно было возникнуть вопросов, логика ровно та же, что была и при построении схемы по _Листингу 6_ (_рис. 11)_, только без выходного регистра. Что логично, ведь мы убрали из описания тактирующий сигнал. Вопрос в том, почему это вдруг схема, построенная после замены блокирующих присваиваний на неблокирующие ведет себя точно так же? -Рассмотрим _рис. 13_. +Рассмотрим _рис. 14_. -![../.pic/Basic%20Verilog%20structures/assignments/fig_13.drawio.svg](../.pic/Basic%20Verilog%20structures/assignments/fig_13.drawio.svg) +![../.pic/Basic%20Verilog%20structures/assignments/fig_14.drawio.svg](../.pic/Basic%20Verilog%20structures/assignments/fig_14.drawio.svg) -_Рисунок 13. Моделирование цепочки присваиваний в комбинационном блоке `always`._ +_Рисунок 14. Моделирование цепочки присваиваний в комбинационном блоке `always`._ Комбинационный блок `always` начинает исполняться **каждый раз**, когда операнд любого `RHS` этого блока меняет своё значение. @@ -394,35 +417,23 @@ _Рисунок 13. Моделирование цепочки присваива > Получается что для комбинационной логики нет разницы между блокирующим и неблокирующим присваиванием, после переходных процессов результат будет одинаковым? -И да и нет. С точки зрения синтеза схемы так и есть. Однако есть нюанс в случае моделирования схемы. - -Особенность планировщика событий симуляции такова, что все `RHS` неблокирующих присваиваний будут вычислены после выполнения всех блокирующих присваиваний. - -Чем это может быть удобно? - -Давайте сделаем небольшое лирическое отступление и разберем часто используемую в мире разработки цифровых схем аббревиатуру `RTL`. Она расшифровывается как `Register Transfer Level` — уровень межрегистровых передач. Цифровую схему можно рассматривать на различных уровнях абстракции. Можно рассматривать с физического уровня: как набор проводников, транзисторов, а так же электронов и "дырок", бегающих по ним. Можно рассматривать схему на уровне логических вентилей (gate-level). Одним из таких уровней абстракции является уровень межрегистровых передач, когда мы делим схему на две части: регистры, и комбинационную логику их связующую. - -По каждому такту синхроимпульса, в регистры будет записываться новое значение, пришедшее от комбинационной логики, что приведет к изменению на выходе регистра и начнет цепочку изменений в комбинационной логике, соединяющей регистры. К следующему такту на концах комбинационной логики, являющихся входами регистров должны оказаться установившееся значения, которые будут записаны в регистры и все повторится снова. - -Было бы удобно разделить эти две части: обновление значений в регистрах и обновление значений в комбинационной логике таким образом, чтобы сперва обновлялась комбинационная логика, а потом уже обновлялось значение в регистрах. - -Именно этого можно добиться, если комбинационная логика будет описана посредством блокирующих присваиваний, которые будут выполнены до неблокирующих присваиваний, используемых при описании регистров. +И да и нет. С точки зрения синтеза схемы так и есть. Однако есть нюанс в случае моделирования схемы. Поведение комбинационной логики лучше моделирует блокирующее присваивание[[1, стр. 14]](http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf). Подведем итоги прочитанному: - Блокирующее присваивание блокирует выполнение остальных операций до завершения текущего присваивания. Оно подобно обычному присваиванию в парадигме программирования. -- Неблокирующее присваивание сперва вычисляет `RHS`, давая исполниться остальным операциям до самого присваивания. Причем в случае, если после неблокирующего присваивания выполняется блокирующее, от `LHS` которого зависело `RHS` неблокирующего присваивания — значение `RHS` будет обновлено (в упрощенном виде с некоторыми оговорками это предложение можно читать как: _"неблокирующие присваивания исполняются после выполнения всех блокирующих"_). +- Неблокирующее присваивание сперва вычисляет `RHS`, давая исполниться остальным операциям до самого присваивания. В связи с особенностями поведения блокирующего и неблокирующего присваивания, выведены следующие две максимы: - при описании последовательностной логики (регистров) используйте **неблокирующее** присваивание; - при описании комбинационной логики используйте **блокирующее** присваивание. -Кроме того, существуют следующие рекомендации и требования[1, стр. 5]: +Кроме того, существуют следующие рекомендации и требования[[1, стр. 5]](http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf): - _При описании как последовательностной логики, так и комбинационной в одном блоке `always` используйте неблокирующее присваивание._ -- _Не смешивайте в одном блоке блокирующие и неблокирующие присваивания_ — стандарт допускает подобное описание, но оно затрудняет его чтение. -- _Не смешивайте блокирующие и неблокирующие присваивания для одного и того же сигнала_ — стандарт это запрещает. +- _Не смешивайте в одном блоке блокирующие и неблокирующие присваивания_ — стандарт допускает подобное описание, но оно затрудняет его чтение. Представьте, что читая описание схемы, вам бы постоянно приходилось держать в голове какие присваивания уже произошли, а какие только произойдут, чтобы понять как эта схема работает. +- _Не смешивайте блокирующие и неблокирующие присваивания для одного и того же сигнала_ — стандарт это запрещает (для блоков `always_ff`, `always_comb`, `always_latch`). Использованная литература: