Синхронизация с правками публикуемого издания (#101)

* СП. Обновление предисловия

* СП. Обновление введения

* СП. Обновление лаб

* СП. Обновление доп материалов

* СП. Введение

* СП. Введение

* СП. ЛР№4, 15

* СП. Базовые конструкции Verilog

* Update Implementation steps.md

* СП. ЛР 4,5,7,8,14

* СП. ЛР№8

* Синхронизация правок

* СП. Финал

* Исправление ссылки на рисунок

* Обновление схемы

* Синхронизация правок

* Добавление белого фона .drawio-изображениям

* ЛР2. Исправление нумерации рисунка
This commit is contained in:
Andrei Solodovnikov
2025-02-12 17:53:52 +03:00
committed by GitHub
parent d251574bbc
commit 9739429d6e
168 changed files with 79781 additions and 961 deletions

View File

@@ -7,7 +7,7 @@
Давайте разберемся что это за присваивания и почему необходимо руководствоваться этими правилами.
Начать придется издалека. Несмотря на то, что SystemVerilog является **языком описания аппаратуры**, он так же является и языком для верификации описанной аппаратуры (слово `Verilog` является объединением двух слов: `verification` и `logic` [2, стр. 24]). Для целей верификации в языке выделено целое подмножество конструкций, которые не могут быть использованы для описания аппаратуры — так называемое "_несинтезируемое подмножество языка SystemVerilog_". Разумеется, часть языка, которая может быть использована для описания аппаратуры ("_синтезируемое подмножество языка SystemVerilog_") тоже может использоваться в верификации.
Начать придется издалека. Несмотря на то, что SystemVerilog является **языком описания аппаратуры**, он так же является и языком для верификации описанной аппаратуры (слово `Verilog` является объединением двух слов: `verification` и `logic` [[2](http://archive.computerhistory.org/resources/access/text/2013/11/102746653-05-01-acc.pdf), стр. 24]). Для целей верификации в языке выделено целое подмножество конструкций, которые не могут быть использованы для описания аппаратуры — так называемое "_несинтезируемое подмножество языка SystemVerilog_". Разумеется, часть языка, которая может быть использована для описания аппаратуры ("_синтезируемое подмножество языка SystemVerilog_") тоже может использоваться в верификации.
Давайте для начала разберемся в том, как будут использоваться операторы присваивания при программном моделировании (так называемой симуляции) — одним из инструментов верификации. Разобравшись в поведении операторов во время симуляции, будет куда проще объяснить результат использования операторов при синтезе цифровой схемы.
@@ -43,7 +43,7 @@ _Листинг 1. Пример непрерывного и процедурно
**Непрерывное присваивание может быть использовано только вне программных блоков.**
Под "программными блоками" подразумеваются блоки `always` (всех типов) и `initial`. Есть и другие программные блоки, но в рамках данного курса лабораторных работ вы с ними не столкнетесь. Вообще говоря, синтаксис языка SystemVerilog допускает использование оператора `assign` внутри программного блока (так называемое "**процедурное непрерывное присваивание**")[[2, стр. 232]](https://ieeexplore.ieee.org/document/8299595), однако в рамках данного курса не существует ни одной ситуации, когда это может потребоваться и со 100% вероятностью будет ошибочно.
Под "программными блоками" подразумеваются блоки `always` (всех типов) и `initial`. Есть и другие программные блоки, но в рамках данного курса лабораторных работ вы с ними не столкнетесь. Вообще говоря, синтаксис языка SystemVerilog допускает использование оператора `assign` внутри программного блока (так называемое "**процедурное непрерывное присваивание**") [[2, стр. 256]](https://ieeexplore.ieee.org/document/10458102), однако в рамках данного курса не существует ни одной ситуации, когда это может потребоваться и со 100% вероятностью будет ошибочно.
В отличие от непрерывного присваивания, **процедурное присваивание может быть использовано только в программных блоках**.
@@ -89,7 +89,7 @@ _Рисунок 2. Пример цепочки неблокирующих при
2. Затем вычисляется значение `RHS` второго присваивания. Поскольку `a` еще не присвоили значение `5`, результатом `RHS` становится текущее значение `a` — 3. Присваивание этого значения сигналу `b` **откладывается** на потом.
3. Аналогичным образом вычисляется `RHS` третьего присваивания (`2`). Присваивание этого значения также **откладывается** на потом.
Так называемое "**потом**" наступает, когда завершается вычисление `RHS` всех неблокирующих присваиваний и завершение присвоений всех блокирующих присваиваний (однако "потом" все равно происходит в тот же момент времени, обратите внимание на значение времени на _рис. 2_). В стандарте SystemVerilog этот момент называется `NBA-region` (сокр. от "Non-Blocking Assignment region") [[2, стр. 61]](https://ieeexplore.ieee.org/document/10458102). Выполнение отложенных присваиваний происходит в том же порядке, в котором они шли в программном блоке. Подробнее о том как, работает событийная симуляция (event based simulation) в SystemVerilog, вы можете прочесть в стандарте [IEEE 1800-2023](https://ieeexplore.ieee.org/document/10458102) (раздел 4). Стандарт доступен бесплатно всем желающим по программе "IEEE GET Program".
Так называемое "**потом**" наступает, когда завершается вычисление `RHS` всех неблокирующих присваиваний и завершение присвоений всех блокирующих присваиваний (однако "потом" все равно происходит в тот же момент времени, обратите внимание на значение времени на _рис. 2_). В стандарте SystemVerilog этот момент называется `NBA-region` (сокр. от "Non-Blocking Assignment region") [[2, стр. 64]](https://ieeexplore.ieee.org/document/10458102). Выполнение отложенных присваиваний происходит в том же порядке, в котором они шли в программном блоке. Подробнее о том как, работает событийная симуляция (event based simulation) в SystemVerilog, вы можете прочесть в стандарте [IEEE 1800-2023](https://ieeexplore.ieee.org/document/10458102) (раздел 4). Стандарт доступен бесплатно всем желающим по программе "IEEE GET Program".
Таким образом, если `LHS` **блокирующего** присваивания используется в качестве операнда `RHS` любого другого последующего присваивания, это выражение будет иметь уже обновленное значение, что очень похоже на "_последовательное вычисление_".
@@ -280,7 +280,7 @@ _Рисунок 9. Симуляция модуля, описанного Лис
Выглядит как-то не по "сдвигово-регистерски". В чем же дело?
Как уже упоминалось ранее, программные блоки (коими являются блоки `always`) исполняются во время моделирования независимо друг от друга в недетерминированном стандартом порядке. На практике это означает то, что сперва может исполниться второй блок, потом третий, а потом первый — либо в любом другом порядке. Разработчик не может (и не должен) рассчитывать на порядок блоков `always` при описании схемы.
Как уже упоминалось ранее, программные блоки (коими являются блоки `always`) исполняются во время моделирования независимо друг от друга в недетерминированном стандартом порядке. На практике это означает, что сперва может исполниться второй блок, потом третий, а потом первый — либо в любом другом порядке. Разработчик не может (и не должен) рассчитывать на порядок блоков `always` при описании схемы.
Конкретно в данной ситуации, симулятор воспроизвел блоки ровно в том порядке, в котором они были описаны. Сперва `a` получил значение `in`, потом `b` получил обновленное значение `a`, затем `c` получил обновленное значение `b`.
@@ -337,7 +337,7 @@ _Рисунок 11. Схема, сгенерированная Vivado по оп
_Рисунок 12. Схема, сгенерированная Vivado по описанию из Листинга 6 после замены блокирующих присваиваний на неблокирующие._
Из прочтенного может сложиться впечатление, будто бы автор хочет показать, что блокирующее присваивание — это плохо, а неблокирующее — хорошо, однако это не так. Это просто два похожих инструмента, работающих разными способами, о которых должен знать профессионал, использующий эти инструменты.
Из прочтённого может сложиться впечатление, будто бы авторы хотят показать, что блокирующее присваивание — это плохо, а неблокирующее — хорошо, однако это не так. Это просто два похожих инструмента, работающих разными способами, о которых должен знать профессионал, использующий эти инструменты.
Одно и тоже описание, использующее разные типы присваиваний может привести к синтезу разных схем.
@@ -417,7 +417,7 @@ _Рисунок 14. Моделирование цепочки присваива
> Получается что для комбинационной логики нет разницы между блокирующим и неблокирующим присваиванием, после переходных процессов результат будет одинаковым?
И да и нет. С точки зрения синтеза схемы так и есть. Однако есть нюанс в случае моделирования схемы. Поведение комбинационной логики лучше моделирует блокирующее присваивание[[1, стр. 14]](http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf).
И да, и нет. С точки зрения синтеза схемы так и есть. Однако есть нюанс в случае моделирования схемы. Поведение комбинационной логики лучше моделирует блокирующее присваивание[[1, стр. 14]](http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf).
## Итоги главы
@@ -434,10 +434,10 @@ _Рисунок 14. Моделирование цепочки присваива
Кроме того, существуют следующие рекомендации и требования[[1, стр. 5]](http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf):
-ри описании как последовательностной логики, так и комбинационной в одном блоке `always` используйте неблокирующее присваивание._
- _Не смешивайте в одном блоке блокирующие и неблокирующие присваивания_ — стандарт допускает подобное описание, но оно затрудняет его чтение. Представьте, что читая описание схемы, вам бы постоянно приходилось держать в голове какие присваивания уже произошли, а какие только произойдут, чтобы понять как эта схема работает.
- _Не смешивайте в одном блоке блокирующие и неблокирующие присваивания_ — стандарт допускает подобное описание, но оно затрудняет его чтение. Представьте, что, читая описание схемы, вам бы постоянно приходилось держать в голове, какие присваивания уже произошли, а какие только произойдут, чтобы понять как эта схема работает.
- _Не смешивайте блокирующие и неблокирующие присваивания для одного и того же сигнала_ — стандарт это запрещает (для блоков `always_ff`, `always_comb`, `always_latch`).
## Список источников
1. [Clifford E. Cummings / Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill](http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf)
2. [1800-2017 - IEEE Standard for SystemVerilog--Unified Hardware Design, Specification, and Verification Language](https://ieeexplore.ieee.org/document/8299595)
2. [1800-2017 - IEEE Standard for SystemVerilog--Unified Hardware Design, Specification, and Verification Language](https://ieeexplore.ieee.org/document/10458102)

View File

@@ -80,14 +80,14 @@ _Литсинг 3. Пример присваивания значения сиг
Как вы можете увидеть, код был успешно собрался и был промоделирован, но значения в выделенных синим прямоугольниках не те, что должны были быть. Можно заметить также и то, что значение выхода `c` никогда не превышает единицу.
Если мы начнем разбираться, и решим вытащить на временную диаграмму внутренний сигнал модуля `ab`, мы увидим, что он почему-то однобитный. Более того, если раскомментировать строчку с объявлением сигнала `ab`, результат никак не изменится.
Если мы начнем разбираться, и решим вытащить на временную диаграмму внутренний сигнал модуля `ab`, мы увидим, что он почему-то 1-битный. Более того, если раскомментировать строчку с объявлением сигнала `ab`, результат никак не изменится.
Подобное поведение в точности воспроизводит требование стандарта SystemVerilog [1, стр. 108]:
> - Если идентификатор использовался списке сигналов, подключаемых к модулю, и этот идентификатор не был объявлен в области видимости, которая доступна при этом подключении, то неявно подразумевается однобитный провод.
> - Если идентификатор встречается по левую сторону от оператора непрерывного присваивания, и этот идентификатор не был объявлен в той области видимости, которая доступна оператору, то неявно подразумевается однобитный провод.
> - Если идентификатор использовался списке сигналов, подключаемых к модулю, и этот идентификатор не был объявлен в области видимости, которая доступна при этом подключении, то неявно подразумевается 1-битный провод.
> - Если идентификатор встречается по левую сторону от оператора непрерывного присваивания, и этот идентификатор не был объявлен в той области видимости, которая доступна оператору, то неявно подразумевается 1-битный провод.
Иными словами, если вы присваиваете значение необъявленному сигналу, или пытаетесь подключить необъявленный сигнал к модулю, неявно создается однобитный сигнал с тем же именем (попробуйте удалить объявление сигналов `a`, `b`, `c` в тестбенче _листинга 3_ и посмотрите, как изменится разрядность сигналов тестбенча на временной диаграмме).
Иными словами, если вы присваиваете значение необъявленному сигналу, или пытаетесь подключить необъявленный сигнал к модулю, неявно создается 1-битный сигнал с тем же именем (попробуйте удалить объявление сигналов `a`, `b`, `c` в тестбенче _листинга 3_ и посмотрите, как изменится разрядность сигналов тестбенча на временной диаграмме).
Даже если объявите сигнал с правильной разрядностью после его использования — это уже ничему не поможет, поскольку повторные объявления уже объявленных проводов и регистров стандартом запрещены [1, стр. 91] и в зависимости от САПР будут либо проигнорированы, либо вызовут ошибку.

View File

@@ -58,7 +58,7 @@ assign e = {a, b, c[4:3], d};
Кроме того, возможна и обратная ситуация. Предположим, мы хотим подать отдельные биты сигнала `e` на различные провода:
![../.pic/Basic%20Verilog%20structures/concatenation/fig_02.drawio.svg](../.pic/Basic%20Verilog%20structures/concatenation/fig_02.drawio.svg)
![../.pic/Basic%20Verilog%20structures/concatenation/fig_03.drawio.svg](../.pic/Basic%20Verilog%20structures/concatenation/fig_03.drawio.svg)
```Verilog
logic a;

View File

@@ -1,10 +1,10 @@
# Защелка
Очень важно при описании мультиплексора с помощью блока `case` описывать оставшиеся комбинации управляющего сигнала с помощью `default` (а при использовании блока `if` — описывать блок `else`) — в противном случае в вашей схеме может появиться [защелка](https://www.build-electronic-circuits.com/d-latch/) (даже несмотря на то, что для описания защелок в SytemVerilog есть отдельный блок `always`: `always_latch`).
Очень важно при описании мультиплексора с помощью блока `case` описывать оставшиеся комбинации управляющего сигнала с помощью `default` (а при использовании блока `if` — описывать блок `else`) — в противном случае в вашей схеме может появиться [защелка](https://www.build-electronic-circuits.com/d-latch/) даже несмотря на то, что для описания защелок в SytemVerilog есть отдельный блок `always`: `always_latch`.
Защелка представляет из себя элемент памяти, причем данные в нее записываются не по тактовому синхроимпульсу, а на протяжении относительно длинного промежутка времени, когда управляющий сигнал "открывает" защелку (в этом случае говорят, что защелка становится "прозрачной"). Из-за этого она не является ни комбинационной, ни синхронной схемой.
Защелка — это всего лишь элемент цифровой схемы и будет неправильно говорить о нем в терминах "плохой" или "хороший". Защелка имеет свои плюсы для [ASIC](https://ru.wikipedia.org/wiki/Интегральная_схема_специальногоазначения)-проектирования. Однако защелка совершенно не подходит при проектировании устройств под ПЛИС.
Защелка — это всего лишь элемент цифровой схемы и будет неправильно говорить о нём в терминах "плохой" или "хороший". Защелка имеет свои плюсы для [ASIC](https://ru.wikipedia.org/wiki/Интегральная_схема_специальногоазначения)-проектирования. Однако защелка совершенно не подходит при проектировании устройств под ПЛИС.
Обычно появление защелки в цифровой схеме говорит об ошибке разработки: в случае, если планировалась комбинационная логика, добавление защелки приведет к непредвиденному удержанию предыдущих значений (поскольку защелка сохраняет предыдущее значение до прихода очередной комбинации управляющего сигнала, описанной в блоке `case`). Это особенно плохо, если сигнал, перед которым появилась защелка, чем-то управляет. Представьте, что он управляет сейфом, который должен открываться если ввели правильный пароль:
@@ -75,6 +75,6 @@ _Рисунок 1. Пример генерации защелки у непол
_Рисунок 2. Пример удержания предыдущих значений защелкой._
Кроме того, защелка усложняет временной анализ и ухудшает временные характеристики, из-за чего схема может работать на меньших частотах, чем могла бы.
Кроме того, защелка усложняет временной анализ и может ухудшить временные характеристики, из-за чего схема может работать на меньших частотах, чем могла бы.
Таким образом, во избежание появления защелки, необходимо описывать все возможные комбинации в блоке `case` (при необходимости покрывая множество оставшихся комбинаций с помощью `default`) и для каждого блока `if` описывать блоки `else`. В случае, если подобная комбинация не планируется к использованию, можно присвоить сигналу значение ноль. Конечно, в этом случае будет создана избыточная логика для присваивания ненужного значения, которое никогда не должно произойти (и существуют способы описания аппаратуры, позволяющие этого избежать), но в данном случае это самый простой способ.

View File

@@ -64,7 +64,7 @@ endmodule
Для объявления провода `c` использовалось ключевое слово (тип) `logic`. Этот тип может в конечном итоге привести к созданию как ячеек памяти (регистров), так и проводов, в зависимости от того, как было описано присваивание объекту этого типа (подобно тому как стволовые клетки организма могут дифференцироваться в специализированные клетки в зависимости от ситуации). Поэтому в примере выше говорить о том, что был создан провод не совсем корректно, объект схемы `c` станет проводом, когда будет произведено подключение к этому объекту, соответствующее подключению провода.
Подключим провод `c` ко входу `a`. Для этого используется конструкция `assign c = a;`. Такая конструкция называется **непрерывным присваиванием**. Если очень сильно упростить, то непрерывное присваивание схоже со спайкой двух проводов. После подобного присваивания, провод `c` всегда будет иметь то же значение, что и `a` — как только входной сигнал `a` изменит свое значение, внутренний провод `c` также изменит свое значение (проводу `c` будет **непрерывно присваиваться** значение входа `a`).
Подключим провод `c` ко входу `a`. Для этого используется конструкция `assign c = a;`. Такая конструкция называется **непрерывным присваиванием**. Если очень сильно упростить, то непрерывное присваивание схоже со спайкой двух проводов. После подобного присваивания, провод `c` всегда будет иметь то же значение, что и `a` — как только входной сигнал `a` изменит своё значение, внутренний провод `c` также изменит своё значение (проводу `c` будет **непрерывно присваиваться** значение входа `a`).
![../.pic/Basic%20Verilog%20structures/modules/fig_05.drawio.svg](../.pic/Basic%20Verilog%20structures/modules/fig_05.drawio.svg)
@@ -110,7 +110,7 @@ module box(
endmodule
```
Пусть в схеме имеется ещё один логический вентиль - Исключающее ИЛИ. На него подаётся результат операции `a ИЛИ b`, то есть `c`, а также входной сигнал `b`. Результат операции `c ИСКЛЮЧАЮЩЕЕ ИЛИ b` подаётся на выход `q` нашего модуля.
Пусть в схеме имеется ещё один логический вентиль - Исключающее ИЛИ. На него подаётся результат операции `a ИЛИ b`, то есть `c`, а также входной сигнал `b`. Результат операции `c Исключающее ИЛИ b` подаётся на выход `q` нашего модуля.
![../.pic/Basic%20Verilog%20structures/modules/fig_07.drawio.svg](../.pic/Basic%20Verilog%20structures/modules/fig_07.drawio.svg)
@@ -227,7 +227,7 @@ endmodule
Обратите внимание на то, как подключаются сигналы к вложенному модулю: при подключении после `.` пишется имя сигнала подключаемого модуля, затем в скобках пишется имя сигнала подключающего модуля. Для лучшего понимания, посмотрите внимательно на схеме на провод `c` и выход `d` модуля `inv`, а также на SystemVerilog-описание этой схемы.
Мы можем подключить сколько угодно экземпляров одного модуля, поэтому у каждого из экземпляра должно быть свое уникальное имя. Пусть `c` подаётся на логический вентиль И вместе со входом `b`. Результат операции И тоже пойдет на инвертор, а затем на выход `q` модуля top.
Мы можем подключить сколько угодно экземпляров одного модуля, поэтому у каждого из экземпляра должно быть своё уникальное имя. Пусть `c` подаётся на логический вентиль И вместе со входом `b`. Результат операции И тоже пойдет на инвертор, а затем на выход `q` модуля top.
![../.pic/Basic%20Verilog%20structures/modules/fig_09.drawio.svg](../.pic/Basic%20Verilog%20structures/modules/fig_09.drawio.svg)
@@ -287,6 +287,6 @@ ___
Как, по-вашему, описать нижеприведенную схему на языке описания аппаратуры SystemVerilog?
Обратите внимание, что вход `a` модуля `top` является двухразрядным: нулевой его бит идет на вход `a` модуля `or`, первый бит идет на вход `b` модуля `or`.
Обратите внимание, что вход `a` модуля `top` является двухразрядным: нулевой его бит идёт на вход `a` модуля `or`, первый бит идёт на вход `b` модуля `or`.
![../.pic/Basic%20Verilog%20structures/modules/fig_10.drawio.svg](../.pic/Basic%20Verilog%20structures/modules/fig_10.drawio.svg)

View File

@@ -22,7 +22,7 @@
- унарный (с одним операндом), пример: `-a`;
- бинарный (с двумя операндами), пример: `a+b`;
- тернарный (с тремя операндами), пример: `cond ? if_true : false`;
- тернарный (с тремя операндами), пример: `cond ? if_true : if_false`;
- и др.
Несмотря на то, что тернарным оператором может быть любой оператор, принимающий три операнда, обычно под ним подразумевается **тернарный условный оператор**, работающий следующим образом:
@@ -129,7 +129,7 @@ end
Мультиплексор также можно описать с использованием **конструкции case**. Блок `case` лучше подходит для описания мультиплексора, когда у того более двух входов (ведь в случае конструкции `if-else` пришлось бы делать вложенное ветвление).
Конструкция `case` представляет собой инструмент множественного ветвления, который сравнивает значение заданного выражения с множеством вариантов, и, в случае первого совпадения, использует соответствующую ветвь. На случай, если ни один из вариантов не совпадет с заданным выражением, конструкция `case` поддерживает вариант `default`. Данная конструкция визуально похожа на оператор `switch-case` в Си, однако вы должны понимать, что используется она не для написания программы, а описания аппаратуры, в частности **мультиплексоров**/**демультиплексоров** и **дешифраторов**.
Конструкция `case` представляет собой инструмент множественного ветвления, который сравнивает значение заданного выражения с множеством вариантов, и, в случае первого совпадения, использует соответствующую ветвь. Как и блок `if-else`, блок `case` должен описывать все возможные комбинации управляющего сигнала.На случай, если ни один из вариантов не совпадет с заданным выражением, конструкция `case` поддерживает вариант `default`. Данная конструкция визуально похожа на оператор `switch-case` в Си, однако вы должны понимать, что используется она не для написания программы, а описания аппаратуры, в частности **мультиплексоров**/**демультиплексоров** и **дешифраторов**.
**Конструкция `case`, наряду с `if-else`, может быть описана только в блоке `always`**.
@@ -150,7 +150,7 @@ end // (так же как каждый begin должен ок
![../.pic/Basic%20Verilog%20structures/multiplexors/fig_04.drawio.svg](../.pic/Basic%20Verilog%20structures/multiplexors/fig_04.drawio.svg)
Здесь уже используется мультиплексор 8в1. Управляющий сигнал `S` в данном случае трёхбитный. В блоке `case` мы перечисляем всевозможные варианты значений `S` и описываем выход мультиплексора.
Здесь уже используется мультиплексор 8в1. Управляющий сигнал `S` в данном случае 3-битный. В блоке `case` мы перечисляем все возможные варианты значений `S` и описываем выход мультиплексора.
```Verilog
module case_mux_ex(
@@ -211,7 +211,7 @@ assign one_bit_result = bus1024[select];
2. использование конструкции [`if-else`](#блок-if-else) внутри блока [`always`](#блок-always);
3. использование конструкции [`case`](#case-блок) внутри блока [`always`](#блок-always);
4. использование [оператора '[]'](#оператор-адресации).
3. Во избежание появления [защелок](Latches.md) при описании мультиплексора, необходимо убедиться что у блоков `if` есть соответствующие им блоки `else`, а у мультиплексоров описаны все комбинации управляющего сигнала (при необходимости, множество оставшихся комбинаций можно покрыть с помощью комбинации `default`). Появление непреднамеренной защелки в дизайне ведет к ухудшению временных характеристик, избыточному использованию ресурсов, а также непредсказуемому поведению схемы из-за возможного удержания сигнала.
3. Во избежание появления [защелок](Latches.md) при описании мультиплексора, необходимо убедиться что у блоков `if` есть соответствующие им блоки `else`, а в блоке `case` описаны все комбинации управляющего сигнала (при необходимости, множество оставшихся комбинаций можно покрыть с помощью комбинации `default`). Появление непреднамеренной защелки в дизайне ведет к ухудшению временных характеристик, избыточному использованию ресурсов, а также непредсказуемому поведению схемы из-за возможного удержания сигнала.
4. Важно отметить, что блоки `if-else` и `case` могут использоваться не только для описания мультиплексоров.
5. Конструкции `if-else` и `case` в рамках данных лабораторных работ можно описывать только внутри блока [`always`](#блок-always). При работе с этим блоком необходимо помнить следующие особенности:
1. Существует несколько типов блока `always`: `always_comb`, `always_ff`, `always_latch`, определяющих то, к чему будет подключена описанная в этом блоке логика: проводу, регистру или защелке соответственно. В данных лабораторных работах вам нужно будет пользоваться блоками `always_ff` и `always_comb`, причем:
@@ -226,3 +226,7 @@ assign one_bit_result = bus1024[select];
Как описать на языке SystemVerilog следующую схему?
![../.pic/Basic%20Verilog%20structures/multiplexors/fig_05.drawio.svg](../.pic/Basic%20Verilog%20structures/multiplexors/fig_05.drawio.svg)
## Список источников
1. [Мультиплексор (электроника)](https://ru.wikipedia.org/wiki/Мультиплексор_(электроника)).

View File

@@ -1,6 +1,6 @@
# Описание регистров в SystemVerilog
Перед тем, как описывать память, необходимо научиться описывать отдельные регистры. [Регистр](https://ru.wikipedia.org/wiki/Регистр_(цифровая_техника)) — это базовая ячейка памяти, позволяющая хранить состояние, пока на схему подается питание. В современной электронике, регистр чаще всего строится на D-триггерах. В лабораторной работе по АЛУ уже вскользь упоминалось, что как для описания проводов, так и для описания регистров, используется тип `logic`.
Перед тем, как описывать память, необходимо научиться описывать отдельные регистры. **Регистр** — устройство для записи, хранения и считывания n-разрядных двоичных данных и выполнения других операций над ними [1, стр. 32]. В современной электронике, регистр чаще всего строится на D-триггерах. В лабораторной работе по АЛУ уже вскользь упоминалось, что как для описания проводов, так и для описания регистров, используется тип `logic`.
```Verilog
logic reg_name;
@@ -47,18 +47,19 @@ endmodule
Описание регистра, а также указание фронта и тактирующего сигнала происходит в конструкции `always_ff`:
```Verilog
always @(posedge clk)
always_ff @(posedge clk)
```
Далее, внутри данной конструкции необходимо указать, что происходит с содержимым регистра. В нашем случае, происходит запись с входного сигнала `data`
```Verilog
always @(posedge clk) begin
always_ff @(posedge clk) begin
reg_name <= data;
end
```
Обратите внимание на оператор `<=`. В данном случае, это не знак "меньше либо равно", а оператор **неблокирующего присваивания**. Существует оператор **блокирующего присваивания** (`=`), который меняет способ построения схемы для такого же выражения справа от оператора, однако в данный момент этот оператор останется за рамками курса. Хоть это и плохая практика в обучении, но пока вам надо просто запомнить, что **при описании записи в регистр всегда используйте оператор неблокирующего присваивания `<=`**.
> [!IMPORTANT]
> Обратите внимание на оператор `<=`. В данном случае, это не знак "меньше либо равно", а оператор **неблокирующего присваивания**. Существует оператор **блокирующего присваивания** (`=`), который может поменять способ построения схемы для такого же выражения справа от оператора. Хоть это и плохая практика в обучении, но пока вам надо просто запомнить: **при описании записи в регистр всегда используйте оператор неблокирующего присваивания `<=`**. Подробнее о рассказано в документе "[О различиях между блокирующими и неблокирующими присваиваниями](./Assignments.md)".
Помимо прочего, нам необходимо связать выход схемы с выходом регистра. Это можно сделать уже известным вам оператором **непрерывного присваивания** `assign`.
@@ -73,7 +74,7 @@ module reg_example(
logic reg_name;
always @(posedge clk) begin
always_ff @(posedge clk) begin
reg_name <= data;
end
@@ -110,7 +111,7 @@ endmodule
```
Обратите внимание на очередность условий. В первую очередь, мы проверяем условие **сброса**, и только после этого условие **разрешения на запись**.
Если сперва проверить разрешение на запись, а затем в блоке `else` описать логику сброса, то регистр не будет сбрасываться в случае, если `enable` будет равен `1` (запись в регистр будет приоритетней его сброса). Если сброс описать не в блоке `else`, а в отдельном блоке `if`, то может возникнуть неопределенное состояние: нельзя однозначно сказать в какой момент придет сигнал `reset` относительно сигнала `enable` и что в итоге запишется в регистр. Поэтому при наличии сигнала сброса, остальная логика по записи в регистр должна размещаться в блоке `else`.
Если сперва проверить разрешение на запись, а затем в блоке `else` описать логику сброса, то регистр не будет сбрасываться в случае, если `enable` будет равен `1` (запись в регистр будет приоритетней его сброса). Если сброс описать не в блоке `else`, а в отдельном блоке `if`, то может возникнуть неопределенное поведение: нельзя однозначно сказать, что запишется в регистр, если одновременно придут сигналы `reset` и `enable`. Поэтому при наличии сигнала сброса, остальная логика по записи в регистр должна размещаться в блоке `else`.
Кроме того, САПР-ы смотрят на паттерн описания элемента схемы, и когда распознают его, реализуют элемент так как задумывал разработчик. Поэтому при описании регистра всегда сперва описывается сигнал сброса (если он используется) и только затем в блоке `else` описывается вся остальная часть логики записи.
@@ -194,7 +195,7 @@ endmodule
Более того, с точки зрения синтезатора данное описание проще для синтеза, т.к. ему не разделять из одного `always` блока комбинационную и синхронные части.
Вообще говоря, регистр в общем смысле этого слова представляет собой многоразрядную конструкцию (в рассмотренном ранее примере, однобитный регистр мог представлять из себя простой D-триггер).
Вообще говоря, регистр в общем смысле этого слова представляет собой многоразрядную конструкцию (в рассмотренном ранее примере, 1-битный регистр мог представлять из себя простой D-триггер).
Создание многоразрядного регистра мало отличается от создания многоразрядного провода, а описание логики записи в многоразрядный регистр ничем не отличается от логики записи в одноразрядный регистр:
```Verilog
@@ -229,3 +230,7 @@ endmodule
Как, по-вашему, описать на языке SystemVerilog схему, приведённую ниже?
![../.pic/Basic%20Verilog%20structures/registers/fig_07.drawio.svg](../.pic/Basic%20Verilog%20structures/registers/fig_07.drawio.svg)
## Список источников
1. Ш. Габриелян, Е. Вахтина / Электротехника и электроника. Методические рекомендации. — Ставрополь: Аргус, 2013