mirror of
https://github.com/MPSU/APS.git
synced 2025-09-15 09:10:10 +00:00
WIP: APS cumulative update (#98)
* WIP: APS cumulative update * Update How FPGA works.md * Перенос раздела "Последовательностная логика" в отдельный док * Исправление картинки * Исправление оформления индексов * Переработка раздела Vivado Basics * Добавление картинки в руководство по созданию проекта * Исправление ссылок в анализе rtl * Обновление изображения в sequential logic * Исправление ссылок в bug hunting * Исправление ссылок * Рефактор руководства по прошивке ПЛИС * Mass update * Update fig_10 * Restore fig_02
This commit is contained in:
committed by
GitHub
parent
78bb01ef95
commit
a28002e681
@@ -7,21 +7,21 @@
|
||||
|
||||
Давайте разберемся что это за присваивания и почему необходимо руководствоваться этими правилами.
|
||||
|
||||
Начать придется издалека. Несмотря на то, что SystemVerilog является **языком описания аппаратуры**, он так же является и языком для верификации описанной аппаратуры (слово `Verilog` является объединением двух слов: `verification` и `logic`). Для целей верификации в языке выделено целое подмножество конструкций, которые не могут быть использованы для описания аппаратуры — так называемое "_несинтезируемое подмножество языка SystemVerilog_". Разумеется, часть языка, которая может быть использована для описания аппаратуры ("_синтезируемое подмножество языка SystemVerilog_") тоже может использоваться в верификации.
|
||||
Начать придется издалека. Несмотря на то, что SystemVerilog является **языком описания аппаратуры**, он так же является и языком для верификации описанной аппаратуры (слово `Verilog` является объединением двух слов: `verification` и `logic` [2, стр. 24]). Для целей верификации в языке выделено целое подмножество конструкций, которые не могут быть использованы для описания аппаратуры — так называемое "_несинтезируемое подмножество языка SystemVerilog_". Разумеется, часть языка, которая может быть использована для описания аппаратуры ("_синтезируемое подмножество языка SystemVerilog_") тоже может использоваться в верификации.
|
||||
|
||||
Давайте для начала разберемся в том, как будут использоваться операторы присваивания при программном моделировании (так называемой симуляции) — одним из инструментов верификации. Разобравшись в поведении операторов во время симуляции будет куда проще объяснить результат использования операторов при синтезе цифровой схемы.
|
||||
Давайте для начала разберемся в том, как будут использоваться операторы присваивания при программном моделировании (так называемой симуляции) — одним из инструментов верификации. Разобравшись в поведении операторов во время симуляции, будет куда проще объяснить результат использования операторов при синтезе цифровой схемы.
|
||||
|
||||
Введем пару сокращений для удобства дальнейшего повествования:
|
||||
|
||||
- под `LHS` (left hand side) мы будем подразумевать "выражение, **которому** присваивают";
|
||||
- под `RHS` (right hand side) мы будем подразумевать "выражение **которое** присваивают".
|
||||
- под `RHS` (right hand side) мы будем подразумевать "выражение, **которое** присваивают".
|
||||
|
||||
В выражении `a = b+c`, `a` является `LHS`, `b+c` является `RHS`.
|
||||
|
||||
два вида присваиваний: **непрерывное** и **процедурное**.
|
||||
Существует два вида присваиваний: **непрерывное** и **процедурное**.
|
||||
|
||||
```SystemVerilog
|
||||
module assignment_example(
|
||||
```Verilog
|
||||
module example_1(
|
||||
input logic a, b
|
||||
output logic c, d
|
||||
);
|
||||
@@ -49,7 +49,7 @@ _Листинг 1. Пример непрерывного и процедурно
|
||||
|
||||
С точки зрения моделирования (не описания аппаратуры), программный блок — это программа (в привычном вам понимании парадигмы программирования), исполняющаяся в отдельном процессе. Программные блоки исполняются независимо друг от друга по определенным событиям.
|
||||
|
||||
Блоки `initial` (их может быть много) исполняются в момент начала моделирования. Блоки `always` исполняются по событиям указанным в **списке чувствительности**:
|
||||
Блоки `initial` (их может быть много) исполняются в момент начала моделирования. Блоки `always` исполняются по событиям, указанным в **списке чувствительности**:
|
||||
|
||||
- `always @(posedge clk)` будет исполняться каждый раз когда произойдет положительный фронт `clk`;
|
||||
- `always @(a,b,c)` будет исполняться каждый раз, когда изменится значение любого из сигналов `a`,`b`,`c`;
|
||||
@@ -89,11 +89,11 @@ _Рисунок 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/8299595). Выполнение отложенных присваиваний происходит в том же порядке, в котором они шли в программном блоке. Подробнее о том как работает событийная симуляция (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/10458102). Выполнение отложенных присваиваний происходит в том же порядке, в котором они шли в программном блоке. Подробнее о том как, работает событийная симуляция (event based simulation) в SystemVerilog, вы можете прочесть в стандарте [IEEE 1800-2023](https://ieeexplore.ieee.org/document/10458102) (раздел 4). Стандарт доступен бесплатно всем желающим по программе "IEEE GET Program".
|
||||
|
||||
Таким образом, если `LHS` **блокирующего** присваивания используется в качестве операнда `RHS` любого другого последующего присваивания, это выражение будет иметь уже обновленное значение, что очень похоже на "_последовательное вычисление_".
|
||||
|
||||
С другой стороны значение, присвоенное `LHS` значение с помощью **неблокирующего** присваивания не может использоваться в качестве операнда `RHS` последующих присваиваний, что создает иллюзию "_параллельного вычисления_" (см. _рис. 3_).
|
||||
С другой стороны значение, присвоенное `LHS` значение с помощью **неблокирующего** присваивания, не может использоваться в качестве операнда `RHS` последующих присваиваний, что создает иллюзию "_параллельного вычисления_" (см. _рис. 3_).
|
||||
|
||||

|
||||
|
||||
@@ -101,20 +101,20 @@ _Рисунок 3. Иллюстрация блокирующих и неблок
|
||||
|
||||
Теперь, понимая как работают присваивания с точки зрения моделирования, посмотрим на то, во что могут синтезироваться подобные операторы.
|
||||
|
||||
Начнем с непрерывного присваивания. Оно превращается в провод, передающий данные от `RHS` к `LHS`. При этом вы должны контролировать что к чему вы присваиваете (не путайте местами `RHS` и `LHS`).
|
||||
Начнем с непрерывного присваивания. Оно превращается в провод, передающий данные от `RHS` к `LHS`. При этом вы должны следить за тем, **что** и **чему** вы присваиваете (не путайте местами `RHS` и `LHS`).
|
||||
|
||||
То во что синтезируются блокирующие и неблокирующие присваивания зависит от описываемой логики, поэтому давайте разберем несколько примеров.
|
||||
То, во что синтезируются блокирующие и неблокирующие присваивания зависит от описываемой логики, поэтому давайте разберём несколько примеров.
|
||||
|
||||
Начнем с исходного примера c цепочкой блокирующих присваиваний, только теперь перепишем его в синтезируемом виде, сохранив изначальную идею.
|
||||
|
||||
```SystemVerilog
|
||||
module example_1(
|
||||
```Verilog
|
||||
module example_2(
|
||||
input logic clk,
|
||||
input logic [31:0] in,
|
||||
output logic [31:0] out
|
||||
);
|
||||
|
||||
logic [31:0] a,b,c;
|
||||
logic [31:0] a, b, c;
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
a = in;
|
||||
@@ -133,7 +133,7 @@ _Листинг 2. Пример описания модуля, использу
|
||||
|
||||
---
|
||||
|
||||
Давайте "прочитаем" эту схему. Мы видим модуль, с входом `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/Регистр_(цифровая_техника)#Сдвигающие_(последовательные)_регистры), представленный на _рис. 4_.
|
||||
|
||||
@@ -151,7 +151,7 @@ _Рисунок 5. Схема, сгенерированная Vivado по опи
|
||||
|
||||
Изучим внимательней поведение цепочки блокирующих присваиваний, представленное на _рис. 1_.
|
||||
|
||||
Каждое последующее присваивание ожидало, пока не выполнится предыдущее, таким образом, `RHS` первого присваивания (`5`) сразу же распространился по всем регистрам. Моделируя _Листинг 2_ мы получим **поведение**, когда на вход каждого регистра будет подаваться сигнал `in`.
|
||||
Каждое последующее присваивание ожидало, пока не выполнится предыдущее, таким образом, `RHS` первого присваивания (`5`) сразу же распространился по всем регистрам. Моделируя _Листинг 2_, мы получим **поведение**, когда на вход каждого регистра будет подаваться сигнал `in`.
|
||||
|
||||
Таким образом на самом деле, мы должны были изобразить нашу схему как на _рис. 6_.
|
||||
|
||||
@@ -159,7 +159,7 @@ _Рисунок 5. Схема, сгенерированная Vivado по опи
|
||||
|
||||
_Рисунок 6. Схема, описанная Листингом 2._
|
||||
|
||||
Но почему тогда на схеме Vivado не осталось регистров `a` и `b`? Посмотрим на них внимательней. Их выходы ни на что не влияют, они висят неподключенные. А значит эти регистры не имеют никакого смысла и если их убрать, ничего не изменится.
|
||||
Но почему тогда на схеме Vivado не осталось регистров `a` и `b`? Посмотрим на них внимательней. Их выходы ни на что не влияют, они ни к чему не подключены. А значит эти регистры не имеют никакого смысла и, если их убрать, ничего не изменится.
|
||||
|
||||
При генерации схемы, Vivado вывел в `Tcl Console` следующие предупреждения:
|
||||
|
||||
@@ -178,8 +178,8 @@ _Рисунок 7. Пример вызова линтера._
|
||||
|
||||
Давайте заменим в _Листинге 2_ блокирующие присваивания на неблокирующие. Напоминаем, что оператор неблокирующего присваивания записывается как `<=`.
|
||||
|
||||
```SystemVerilog
|
||||
module example_2(
|
||||
```Verilog
|
||||
module example_3(
|
||||
input logic clk,
|
||||
input logic [31:0] in,
|
||||
output logic [31:0] out
|
||||
@@ -214,8 +214,8 @@ _Рисунок 8. Схема, сгенерированная Vivado по опи
|
||||
|
||||
Можно ли реализовать сдвиговый регистр, используя блокирующие присваивания? Конечно. Например, можно поменять порядок присваиваний как в _Листинге 4_.
|
||||
|
||||
```SystemVerilog
|
||||
module example_3(
|
||||
```Verilog
|
||||
module example_4(
|
||||
input logic clk,
|
||||
input logic [31:0] in,
|
||||
output logic [31:0] out
|
||||
@@ -244,8 +244,8 @@ _Листинг 4. Цепочка блокирующих присваивани
|
||||
|
||||
Давайте разнесем логику работы каждого регистра по отдельным блокам `always`.
|
||||
|
||||
```SystemVerilog
|
||||
module example_4(
|
||||
```Verilog
|
||||
module example_5(
|
||||
input logic clk,
|
||||
input logic [31:0] in,
|
||||
output logic [31:0] out
|
||||
@@ -292,14 +292,14 @@ _Рисунок 9. Симуляция модуля, описанного Лис
|
||||
|
||||
_Рисунок 10. Моделирование поведения сдвигового регистра._
|
||||
|
||||
Однако, как уже объяснялось ранее, вы не можете рассчитывать на такой результат. Сегодня симулятор смоделировал поведение одним образом — завтра он смоделирует этот же код (в котором не изменилась ни одна строка) по-другому, и будет по прежнему работать в соответствии со стандартом.
|
||||
Однако, как уже объяснялось ранее, вы не можете рассчитывать на такой результат. Сегодня симулятор смоделировал поведение одним образом — завтра он смоделирует этот же код (в котором не изменилась ни одна строка) по-другому, и будет по-прежнему работать в соответствии со стандартом.
|
||||
|
||||
Для того, чтобы получить детерминированный результат, вам необходимо снова воспользоваться неблокирующим присваиванием, поскольку и в этом случае порядок исполнения блоков `always` не влияет на результат присваиваний — сначала вычисляются значения `RHS` всех неблокирующих присваиваний всех программных блоков, и только потом происходит присваивание этих значений `LHS`.
|
||||
|
||||
Рассмотрим еще один пример того, как различие в присваиваниях приведет к описанию двух различных схем:
|
||||
|
||||
```SystemVerilog
|
||||
module example_5(
|
||||
```Verilog
|
||||
module example_6(
|
||||
input logic clk,
|
||||
input logic a, b, c,
|
||||
output logic d
|
||||
@@ -349,8 +349,8 @@ _Рисунок 12. Схема, сгенерированная Vivado по оп
|
||||
|
||||
Рассмотрим зависимость от типа присваивания в комбинационных схемах. Для этого возьмем предыдущий пример, и уберем тактирующий синхроимпульс.
|
||||
|
||||
```SystemVerilog
|
||||
module example_6(
|
||||
```Verilog
|
||||
module example_7(
|
||||
input logic a, b, c,
|
||||
output logic d
|
||||
);
|
||||
@@ -413,12 +413,14 @@ _Рисунок 14. Моделирование цепочки присваива
|
||||
|
||||
Обратите внимание, поведение схем описанных при разных типах присваивания слегка различаются. При блокирующем присваивании все сигналы приняли установившиеся значения за один проход блока `always`, при неблокирующем потребовалось несколько проходов. Однако с точки зрения пользователя, читающего временную диаграмму, в обоих ситуациях сигналы изменили свое значение мгновенно.
|
||||
|
||||
Поэтому не смотря на различия в типах присваиваний схемы получились одинаковыми.
|
||||
Поэтому несмотря на различия в типах присваиваний схемы получились одинаковыми.
|
||||
|
||||
> Получается что для комбинационной логики нет разницы между блокирующим и неблокирующим присваиванием, после переходных процессов результат будет одинаковым?
|
||||
|
||||
И да и нет. С точки зрения синтеза схемы так и есть. Однако есть нюанс в случае моделирования схемы. Поведение комбинационной логики лучше моделирует блокирующее присваивание[[1, стр. 14]](http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf).
|
||||
|
||||
## Итоги главы
|
||||
|
||||
Подведем итоги прочитанному:
|
||||
|
||||
- Блокирующее присваивание блокирует выполнение остальных операций до завершения текущего присваивания. Оно подобно обычному присваиванию в парадигме программирования.
|
||||
@@ -435,7 +437,7 @@ _Рисунок 14. Моделирование цепочки присваива
|
||||
- _Не смешивайте в одном блоке блокирующие и неблокирующие присваивания_ — стандарт допускает подобное описание, но оно затрудняет его чтение. Представьте, что читая описание схемы, вам бы постоянно приходилось держать в голове какие присваивания уже произошли, а какие только произойдут, чтобы понять как эта схема работает.
|
||||
- _Не смешивайте блокирующие и неблокирующие присваивания для одного и того же сигнала_ — стандарт это запрещает (для блоков `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)
|
||||
|
104
Basic Verilog structures/Common mistakes.md
Normal file
104
Basic Verilog structures/Common mistakes.md
Normal file
@@ -0,0 +1,104 @@
|
||||
# Список типичных ошибок в SystemVerilog
|
||||
|
||||
- [Список типичных ошибок в SystemVerilog](#список-типичных-ошибок-в-systemverilog)
|
||||
- [имя сигнала is not a type](#имя-сигнала-is-not-a-type)
|
||||
- [cannot find port on this module](#cannot-find-port-on-this-module)
|
||||
- [Использование сигнала без его объявления (или до его объявления)](#использование-сигнала-без-его-объявления-или-до-его-объявления)
|
||||
- [Объявление выхода модуля его входом](#объявление-выхода-модуля-его-входом)
|
||||
- [](#)
|
||||
|
||||
## имя сигнала is not a type
|
||||
|
||||
Скорее всего, компилятор не распознал присваивание, поскольку оно было записано с ошибками. Вне блоков `always` и `initial` можно выполнять только непрерывное присваивание (через `assign`).
|
||||
|
||||
```Verilog
|
||||
module half_adder(input logic a, input logic b, output logic c);
|
||||
c = a ^ b; // ошибка, для непрерывного присваивания
|
||||
// необходимо ключевое слово assign
|
||||
endmodule
|
||||
```
|
||||
|
||||
_Листинг 1. Пример ошибочного присваивания._
|
||||
|
||||
## cannot find port on this module
|
||||
|
||||
Имя порта, указанного при подключении модуля (после точки) не соответствует ни одному имени сигналов подключаемого модуля
|
||||
|
||||
```Verilog
|
||||
module half_adder(input logic a, input logic b, output logic c);
|
||||
assign c = a ^ b;
|
||||
endmodule
|
||||
|
||||
module testbench();
|
||||
logic A, B, C;
|
||||
|
||||
adder DUT(
|
||||
.A(A), // <- здесь будет ошибка,
|
||||
// т.к. в модуле half_adder нет порта 'A'
|
||||
.b(B),
|
||||
.c(C)
|
||||
);
|
||||
endmodule
|
||||
```
|
||||
|
||||
_Листинг 2. Пример создание экземпляра модуля с ошибкой в описании его входных портов._
|
||||
|
||||
## Использование сигнала без его объявления (или до его объявления)
|
||||
|
||||
Достаточно частая ошибка, когда сигнал забывают объявить, либо объявляют, но потом добавляют код с использованием этого сигнала выше его объявления. Не смотря на то, что в SystemVerilog не важно, в каком порядке были описаны блоки кода, это не касается объявления сигналов — они должны выполняться до их использования. Рассмотрим следующий пример, приведенный в _листинге 3_.
|
||||
|
||||
```Verilog
|
||||
module example(
|
||||
input logic [1:0] a,
|
||||
input logic [1:0] b,
|
||||
output logic [1:0] c
|
||||
);
|
||||
|
||||
assign ab = a | b;
|
||||
// logic [1:0] ab;
|
||||
assign c = ab;
|
||||
endmodule
|
||||
|
||||
module tb_example();
|
||||
logic [1:0] a, b, c;
|
||||
logic [3:0] i = 0;
|
||||
example DUT(.a(a),.b(b),.c(c));
|
||||
assign {a, b} = i;
|
||||
|
||||
initial repeat(15) begin
|
||||
#5;
|
||||
i++;
|
||||
end
|
||||
endmodule
|
||||
```
|
||||
|
||||
_Литсинг 3. Пример присваивания значения сигналу без его объявления._
|
||||
|
||||
Результат моделирования _листинга 3_ приведён на _рисунке 1_.
|
||||
|
||||

|
||||
|
||||
Как вы можете увидеть, код был успешно собрался и был промоделирован, но значения в выделенных синим прямоугольниках не те, что должны были быть. Можно заметить также и то, что значение выхода `c` никогда не превышает единицу.
|
||||
|
||||
Если мы начнем разбираться, и решим вытащить на временную диаграмму внутренний сигнал модуля `ab`, мы увидим, что он почему-то однобитный. Более того, если раскомментировать строчку с объявлением сигнала `ab`, результат никак не изменится.
|
||||
|
||||
Подобное поведение в точности воспроизводит требование стандарта SystemVerilog [1, стр. 108]:
|
||||
|
||||
> - Если идентификатор использовался списке сигналов, подключаемых к модулю, и этот идентификатор не был объявлен в области видимости, которая доступна при этом подключении, то неявно подразумевается однобитный провод.
|
||||
> - Если идентификатор встречается по левую сторону от оператора непрерывного присваивания, и этот идентификатор не был объявлен в той области видимости, которая доступна оператору, то неявно подразумевается однобитный провод.
|
||||
|
||||
Иными словами, если вы присваиваете значение необъявленному сигналу, или пытаетесь подключить необъявленный сигнал к модулю, неявно создается однобитный сигнал с тем же именем (попробуйте удалить объявление сигналов `a`, `b`, `c` в тестбенче _листинга 3_ и посмотрите, как изменится разрядность сигналов тестбенча на временной диаграмме).
|
||||
|
||||
Даже если объявите сигнал с правильной разрядностью после его использования — это уже ничему не поможет, поскольку повторные объявления уже объявленных проводов и регистров стандартом запрещены [1, стр. 91] и в зависимости от САПР будут либо проигнорированы, либо вызовут ошибку.
|
||||
|
||||
Подобная ошибка легко обнаруживается линтером (появился в Vivado начиная с версии 2023.1). Кроме того, при попытке открыть схематик описанной схемы, в TCL-консоли появится сообщение об использовании необъявленного идентификатора:
|
||||
|
||||
```text
|
||||
INFO: [Synth 8-11241] undeclared symbol 'ab', assumed default net type 'wire'
|
||||
```
|
||||
|
||||
## Объявление выхода модуля его входом
|
||||
|
||||
Очень часто в попытке сэкономить себе немного времени студенты выполняют операцию копирования. В частности, копирования строк вида `input logic [7:0]` в процессе описания портов модуля. В случае, если по итогу подобного копирования, выход модуля будет объявлен как его вход (т.е. с помощью ключевого слова `input` вместо `output`).
|
||||
|
||||
##
|
@@ -8,7 +8,7 @@
|
||||
|
||||

|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
|
||||
logic a;
|
||||
logic b;
|
||||
@@ -29,7 +29,7 @@ logic [5:0] e;
|
||||
|
||||
Это можно сделать путем 4 непрерывных присваиваний:
|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
logic a;
|
||||
logic b;
|
||||
logic [7:0] c;
|
||||
@@ -45,7 +45,7 @@ assign e[1:0] = d;
|
||||
|
||||
либо через одно присваивание, использующее конкатенацию:
|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
logic a;
|
||||
logic b;
|
||||
logic [7:0] c;
|
||||
@@ -60,7 +60,7 @@ assign e = {a, b, c[4:3], d};
|
||||
|
||||

|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
logic a;
|
||||
logic b;
|
||||
logic [7:0] c;
|
||||
@@ -76,7 +76,7 @@ assign d = e[1:0];
|
||||
|
||||
Подобную операцию можно так же выполнить в одно выражение через конкатенацию:
|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
logic a;
|
||||
logic b;
|
||||
logic [7:0] c;
|
||||
@@ -89,14 +89,14 @@ assign {a, b, c[4:3], d} = e;
|
||||
|
||||
Кроме того, конкатенация может использоваться при **множественном дублировании** сигналов. Дублирование выполняется выражением:
|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
{a, {число_повторений{повторяемый_сигнал}} ,b}
|
||||
```
|
||||
|
||||
Допустим, мы хотим присвоить какому-то сигналу три копии `[4:3]` битов сигнала `c`, после которых идут сигналы `a` и `b`.
|
||||
Это можно сделать выражением:
|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
logic a;
|
||||
logic b;
|
||||
logic [7:0] c;
|
||||
@@ -105,3 +105,10 @@ logic [7:0] e;
|
||||
|
||||
assign e = { {3{c[4:3]}}, a, b};
|
||||
```
|
||||
|
||||
## Итоги главы
|
||||
|
||||
Оператор конкатенации может быть использован для группировки и репликации сигналов по обе стороны присваивания, а именно:
|
||||
|
||||
- он может быть использован для присваивания сигналу большей разрядности группы сигналов меньшей разрядности
|
||||
- он может быть использован для присваивания группе сигналов меньшей разрядности соответствующих бит сигнала большей разрядности.
|
||||
|
@@ -40,7 +40,7 @@
|
||||
светодиоды являются простейшим устройством вывода. Поэтому, чтобы задание было интересней, для их управления был добавлен регистр, управляющий режимом вывода данных на светодиоды.
|
||||
Рассмотрим прототип модуля, который вам необходимо реализовать:
|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
module led_sb_ctrl(
|
||||
/*
|
||||
Часть интерфейса модуля, отвечающая за подключение к системной шине
|
||||
|
@@ -8,7 +8,7 @@
|
||||
|
||||
Обычно появление защелки в цифровой схеме говорит об ошибке разработки: в случае, если планировалась комбинационная логика, добавление защелки приведет к непредвиденному удержанию предыдущих значений (поскольку защелка сохраняет предыдущее значение до прихода очередной комбинации управляющего сигнала, описанной в блоке `case`). Это особенно плохо, если сигнал, перед которым появилась защелка, чем-то управляет. Представьте, что он управляет сейфом, который должен открываться если ввели правильный пароль:
|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
always_comb begin
|
||||
if(password_is_correct) begin
|
||||
open_the_safe <= 1'b1;
|
||||
@@ -18,7 +18,7 @@ end
|
||||
|
||||
Вроде бы вы все описали правильно: "если ввели правильный пароль — сейф откроется". Однако проблема в том, что это состояние сохранится, и сейф уже не закроется. Именно поэтому у каждого блока `if` должен быть свой блок `else`:
|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
always_comb begin
|
||||
if(password_is_correct) begin
|
||||
open_the_safe <= 1'b1;
|
||||
@@ -33,7 +33,7 @@ end
|
||||
|
||||
Ещё один пример:
|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
module unexpected_d_latch_ex(
|
||||
input logic [1:0] S,
|
||||
input logic D0,
|
||||
|
@@ -12,7 +12,7 @@
|
||||
|
||||

|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
module
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ endmodule
|
||||
|
||||

|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
module box();
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ endmodule
|
||||
|
||||

|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
module box(
|
||||
input logic a,
|
||||
input logic b,
|
||||
@@ -49,7 +49,7 @@ endmodule
|
||||
|
||||

|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
module box(
|
||||
input logic a,
|
||||
input logic b,
|
||||
@@ -62,13 +62,13 @@ module box(
|
||||
endmodule
|
||||
```
|
||||
|
||||
Для объявления провода `c` использовалось ключевое слово (тип) `logic`. Этот тип, подобно стволовым клеткам, может быть в конечном итоге привести к созданию как ячеек памяти (регистров), так и проводов, в зависимости от того, как было описано присваивание объекту этого типа. Поэтому в примере выше говорить о том, что был создан провод не совсем корректно, объект схемы `c` станет проводом, когда будет произведено подключение к этому объекту, соответствующее подключению провода.
|
||||
Для объявления провода `c` использовалось ключевое слово (тип) `logic`. Этот тип может в конечном итоге привести к созданию как ячеек памяти (регистров), так и проводов, в зависимости от того, как было описано присваивание объекту этого типа (подобно тому как стволовые клетки организма могут дифференцироваться в специализированные клетки в зависимости от ситуации). Поэтому в примере выше говорить о том, что был создан провод не совсем корректно, объект схемы `c` станет проводом, когда будет произведено подключение к этому объекту, соответствующее подключению провода.
|
||||
|
||||
Подключим провод `c` ко входу `a`. Для этого используется конструкция `assign c = a;`. Такая конструкция называется **непрерывным присваиванием**. Если очень сильно упростить, то непрерывное присваивание схоже со спайкой двух проводов. После подобного присваивания, провод `c` всегда будет иметь то же значение, что и `a` — как только входной сигнал `a` изменит свое значение, внутренний провод `c` также изменит свое значение (проводу `c` будет **непрерывно присваиваться** значение входа `a`).
|
||||
|
||||

|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
module box(
|
||||
input logic a,
|
||||
input logic b,
|
||||
@@ -95,7 +95,7 @@ endmodule
|
||||
|
||||
Такую схему можно реализовать следующим описанием:
|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
module box(
|
||||
input logic a,
|
||||
input logic b,
|
||||
@@ -114,7 +114,7 @@ endmodule
|
||||
|
||||

|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
module box(
|
||||
input logic a,
|
||||
input logic b,
|
||||
@@ -155,14 +155,18 @@ endmodule
|
||||
|
||||
Используя индекс, можно обратиться к отдельным битам вектора. С помощью диапазона индексов можно получить доступ к диапазону соответствующих битов.
|
||||
|
||||
|фрагмент кода|описание|
|
||||
|-------------|--------|
|
||||
|sum[0]; | Обращение к младшему биту вектора sum, объявленного выше|
|
||||
|sum[7:4]; | Обращение к старшим четырем битам 8-битного вектора sum, объявленного выше|
|
||||
|фрагмент кода|описание |
|
||||
|-------------|-------------------------------------------------------------------------|
|
||||
|sum[0]; | Обращение к младшему биту вектора sum, объявленного выше |
|
||||
|sum[7:5]; | Обращение к старшим трём битам 8-битного вектора sum, объявленного выше |
|
||||
|sum[5+:3]; | Обращение к трём битам, начиная со пятого (т.е. это аналог предыдущего выражения, удобно использовать, когда известен начальный бит и их количество, а конечный нужно считать через них) |
|
||||
|sum[7-:3]; | Обращение к трём битам, заканчивая седьмым (т.е. это аналог предыдущего выражения, удобно использовать, когда известен конечный бит и их количество, а начальный нужно считать через них) |
|
||||
|
||||
Важно понимать, что векторы могут быть использованы и при описании портов модуля:
|
||||
_Таблица 1. Способы обращения как к отдельным битам вектора, так и к диапазонам его бит._
|
||||
|
||||
```SystemVerilog
|
||||
Векторы могут быть использованы и при описании портов модуля:
|
||||
|
||||
```Verilog
|
||||
module vector_ex(
|
||||
input logic [3:0] a, // У данного модуля четырехразрядный вход 'a'
|
||||
output logic [7:0] b // и восьмиразрядный выход 'b'.
|
||||
@@ -186,19 +190,18 @@ endmodule
|
||||
|
||||
Опишем `inv`:
|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
module inv(
|
||||
input logic a,
|
||||
output logic d
|
||||
);
|
||||
|
||||
assign d = ~a;
|
||||
endmodule
|
||||
```
|
||||
|
||||
Опишем `top`:
|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
module top(
|
||||
input logic a,
|
||||
input logic b,
|
||||
@@ -227,17 +230,7 @@ endmodule
|
||||
|
||||
Тогда в нашем описании добавится подключение второго модуля `inv` и провод `c`.
|
||||
|
||||
```SystemVerilog
|
||||
module inv(
|
||||
input logic a,
|
||||
output logic d
|
||||
);
|
||||
|
||||
assign d = ~a;
|
||||
endmodule
|
||||
```
|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
module top(
|
||||
input logic a,
|
||||
input logic b,
|
||||
@@ -274,20 +267,20 @@ endmodule
|
||||
|
||||
___
|
||||
|
||||
## Итоги
|
||||
## Итоги главы
|
||||
|
||||
1. Ключевым блоком в иерархии цифровой схемы, описанной на языке SystemVerilog является **модуль**. Модули позволяют выносить части сложной цифровой схемы в отдельные блоки, из которых потом и будет составлена итоговая схема, что сильно упрощает разработку.
|
||||
2. Условно, модуль можно разделить на следующие части:
|
||||
1. Объявление модуля:
|
||||
1. Ключевые слова `module` / `endmodule` определяющие границы описания модуля.
|
||||
2. Название модуля, следующее за ключевым словом `module`. Описанный модуль представляет собой отдельный тип, имя которого совпадает с названием модуля.
|
||||
3. Указание входов и выходов (портов) модуля, идущих в круглых скобках после названия модуля. Для указания направления порта модуля используются ключевые слова `input` и `output`. После указание направления порта следует указать тип порта (в рамках данного курса типом портов всегда будет logic), его разрядность, а затем имя.
|
||||
3. Указание входов и выходов (портов) модуля, идущих в круглых скобках после названия модуля. Для указания направления порта модуля используются ключевые слова `input` и `output`. После указание направления порта следует указать тип порта (в рамках данного курса типом портов всегда будет `logic`), его разрядность, а затем имя.
|
||||
2. Функциональное описание модуля:
|
||||
1. Объявление внутренних сигналов модуля (будь то проводов или регистров) с помощью ключевого слова `logic`.
|
||||
2. Создание при необходимости объектов других модулей.
|
||||
3. Описание функциональной связи между различными сигналами и объектами внутри описываемого модуля.
|
||||
|
||||
## Проверь себя
|
||||
## Проверьте себя
|
||||
|
||||
Как, по-вашему, описать нижеприведенную схему на языке описания аппаратуры SystemVerilog?
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Описание мультиплексора на языке SystemVerilog
|
||||
# Описание мультиплексоров в SystemVerilog
|
||||
|
||||
**Мультипле́ксор** — устройство, имеющее **несколько сигнальных входов**, **один или более управляющих входов** и **один выход**. Мультиплексор позволяет передавать сигнал **с одного из входов на выход**; при этом выбор желаемого входа осуществляется подачей соответствующей комбинации управляющих сигналов[[1]](https://ru.wikipedia.org/wiki/Мультиплексор_(электроника)).
|
||||
|
||||
@@ -42,7 +42,7 @@ a = b+c >= 5 ? b+c : b+d;
|
||||
Сперва вычисляется первый операнд (выражение `b+c >= 5`). Если это выражение оказалось истинным (равно единице), то переменной `a` будет присвоено значение второго операнда (выражения `b+c`), в противном случае переменной `a` будет присвоено значение третьего операнда (выражения `b+d`).
|
||||
</details>
|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
logic Y;
|
||||
assign Y = S==1 ? D1 : D0;
|
||||
```
|
||||
@@ -61,7 +61,7 @@ assign Y = S==1 ? D1 : D0;
|
||||
|
||||
## Блок always
|
||||
|
||||
Блок `always` — это специальный блок, который позволяет описывать комбинационные и последовательностные схемы, используя более сложные конструкции, такие как `if-else`, `case`. На самом деле, в языке SystemVerilog помимо общего блока `always`, которым можно описать любой вид логики, существует множество специализированных блоков, предназначенных для описания отдельно комбинационной, синхронной и последовательностной асинхронной логики соответственно:
|
||||
Блок `always` — это специальный блок, который позволяет описывать комбинационные и последовательностные схемы (см. документ "[Последовательностная логика](../Introduction/Sequential%20logic.md)"), используя более сложные конструкции, такие как `if-else`, `case`. На самом деле, в языке SystemVerilog помимо общего блока `always`, которым можно описать любой вид логики, существует множество специализированных блоков, предназначенных для описания отдельно комбинационной, синхронной и последовательностной асинхронной логики соответственно:
|
||||
|
||||
- always_comb
|
||||
- always_ff
|
||||
@@ -73,7 +73,7 @@ assign Y = S==1 ? D1 : D0;
|
||||
|
||||
- внутри блока `always_ff` и `always_latch` необходимо использовать оператор неблокирующего присваивания (`<=`);
|
||||
- внутри блока `always_comb` необходимо использовать оператор блокирующего присваивания (`=`).
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
> Остановитесь на выделенном выше фрагменте документа, пока полностью не разберете его. Без освоения всех описанных выше особенностей языка SystemVerilog вы столкнетесь в будущем с множеством ошибок.
|
||||
@@ -88,7 +88,7 @@ assign Y = S==1 ? D1 : D0;
|
||||
|
||||
После, в блоке `else` описывается присваивание сигнала, который должен идти на выход при управляющем сигнале равном нулю (значение после оператора `:` в тернарном операторе).
|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
logic Y;
|
||||
always_comb begin // 1) Используется always_comb, т.к. мы хотим подключить
|
||||
// выход мультиплексора к проводу
|
||||
@@ -104,7 +104,7 @@ end
|
||||
|
||||
Неправильно:
|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
logic Y;
|
||||
always_comb begin
|
||||
if(S==1) begin
|
||||
@@ -135,7 +135,7 @@ end
|
||||
|
||||
Реализация двухвходового мультиплексора с помощью `case` может выглядеть так:
|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
logic Y;
|
||||
always_comb begin
|
||||
case(S) // Описываем блок case, где значение сигнала S
|
||||
@@ -150,9 +150,9 @@ end // (так же как каждый begin должен ок
|
||||
|
||||

|
||||
|
||||
Здесь уже используется мультиплексор 4в1. Управляющий сигнал `S` в данном случае двухбитный. В блоке `case` мы перечисляем всевозможные варианты значений `S` и описываем выход мультиплексора.
|
||||
Здесь уже используется мультиплексор 8в1. Управляющий сигнал `S` в данном случае трёхбитный. В блоке `case` мы перечисляем всевозможные варианты значений `S` и описываем выход мультиплексора.
|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
module case_mux_ex(
|
||||
input logic A,
|
||||
input logic B,
|
||||
@@ -192,7 +192,7 @@ endmodule
|
||||
|
||||
В контексте примера по мультиплексированию 1024 бит использование оператора может быть выполнено следующим образом:
|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
logic [1023:0] bus1024;
|
||||
logic [ 9:0] select;
|
||||
|
||||
@@ -203,7 +203,7 @@ assign one_bit_result = bus1024[select];
|
||||
|
||||
Реализация мультиплексоров через оператор '[]' будет активно применяться вами при реализации различных памятей.
|
||||
|
||||
## Итоги
|
||||
## Итоги главы
|
||||
|
||||
1. Мультиплексор — это **комбинационный** блок, подающий на выход один из нескольких входных сигналов.
|
||||
2. Мультиплексор можно описать множеством способов, среди них:
|
||||
|
@@ -1,8 +1,8 @@
|
||||
# Описание регистра на языке SystemVerilog
|
||||
# Описание регистров в SystemVerilog
|
||||
|
||||
Перед тем, как описывать память, необходимо научиться описывать отдельные регистры. [Регистр](https://ru.wikipedia.org/wiki/Регистр_(цифровая_техника)) — это базовая ячейка памяти, позволяющая хранить состояние, пока на схему подается питание. В современной электронике, регистр чаще всего строится на D-триггерах. В лабораторной работе по АЛУ уже вскользь упоминалось, что как для описания проводов, так и для описания регистров, используется тип `logic`.
|
||||
|
||||
```SystemVerilog
|
||||
```Verilog
|
||||
logic reg_name;
|
||||
```
|
||||
|
||||
@@ -26,16 +26,16 @@ logic reg_name;
|
||||
|
||||
Данной схеме соответствует код:
|
||||
|
||||
```SystemVerilog
|
||||
modulе rеg_ехаmрlе(
|
||||
inрut logic clk,
|
||||
inрut logic dаtа,
|
||||
оutрut logic rеg_dаtа
|
||||
```Verilog
|
||||
module reg_example(
|
||||
input logic clk,
|
||||
input logic data,
|
||||
output logic reg_data
|
||||
);
|
||||
|
||||
logic rеg_nаmе;
|
||||
logic reg_name;
|
||||
|
||||
еndmоdulе
|
||||
endmodule
|
||||
```
|
||||
|
||||
Очевидно, мы хотим подключить сигнал `clk` ко входу тактирующего сигнала регистра, вход `data` ко входу данных, а выход регистра к выходу `reg_data`:
|
||||
@@ -46,16 +46,16 @@ modulе rеg_ехаmрlе(
|
||||
|
||||
Описание регистра, а также указание фронта и тактирующего сигнала происходит в конструкции `always_ff`:
|
||||
|
||||
```SystemVerilog
|
||||
аlwауs_ff @(pоsеdgе clk)
|
||||
```Verilog
|
||||
always @(posedge clk)
|
||||
```
|
||||
|
||||
Далее, внутри данной конструкции необходимо указать, что происходит с содержимым регистра. В нашем случае, происходит запись с входного сигнала `data`
|
||||
|
||||
```SystemVerilog
|
||||
аlwауs_ff @(pоsеdgе clk)
|
||||
rеg_nаmе <= dаtа;
|
||||
еnd
|
||||
```Verilog
|
||||
always @(posedge clk) begin
|
||||
reg_name <= data;
|
||||
end
|
||||
```
|
||||
|
||||
Обратите внимание на оператор `<=`. В данном случае, это не знак "меньше либо равно", а оператор **неблокирующего присваивания**. Существует оператор **блокирующего присваивания** (`=`), который меняет способ построения схемы для такого же выражения справа от оператора, однако в данный момент этот оператор останется за рамками курса. Хоть это и плохая практика в обучении, но пока вам надо просто запомнить, что **при описании записи в регистр всегда используйте оператор неблокирующего присваивания `<=`**.
|
||||
@@ -64,49 +64,49 @@ modulе rеg_ехаmрlе(
|
||||
|
||||
Таким образом, итоговый код описания данной схемы примет вид:
|
||||
|
||||
```SystemVerilog
|
||||
modulе rеg_ехаmрlе(
|
||||
inрut logic сlk,
|
||||
inрut logic dаtа,
|
||||
оutрut logic rеg_dаtа
|
||||
```Verilog
|
||||
module reg_example(
|
||||
input logic clk,
|
||||
input logic data,
|
||||
output logic reg_data
|
||||
);
|
||||
|
||||
logic rеg_nаmе;
|
||||
logic reg_name;
|
||||
|
||||
аlwауs_ff @(pоsеdgе clk) bеgin
|
||||
rеg_nаmе <= dаtа;
|
||||
еnd
|
||||
always @(posedge clk) begin
|
||||
reg_name <= data;
|
||||
end
|
||||
|
||||
аssign reg_data = reg_name;
|
||||
assign reg_data = reg_name;
|
||||
|
||||
еndmоdulе
|
||||
endmodule
|
||||
```
|
||||
|
||||
Предположим, мы хотим добавить управление записью в регистр через сигналы `enable` и `reset`. Это, например, можно сделать следующим образом:
|
||||
|
||||
```SystemVerilog
|
||||
modulе rеg_ехаmрlе(
|
||||
inрut logic сlk,
|
||||
inрut logic dаtа,
|
||||
inрut logic reset,
|
||||
inрut logic enable,
|
||||
оutрut logic rеg_dаtа
|
||||
```Verilog
|
||||
module reg_example(
|
||||
input logic clk,
|
||||
input logic data,
|
||||
input logic reset,
|
||||
input logic enable,
|
||||
output logic reg_data
|
||||
);
|
||||
|
||||
logic rеg_nаmе;
|
||||
logic reg_name;
|
||||
|
||||
аlwауs_ff @(pоsеdgе clk) bеgin
|
||||
if(rеsеt) bеgin
|
||||
rеg_nаmе <= 1'b0;
|
||||
еnd
|
||||
еlse if(enable) bеgin
|
||||
rеg_nаmе <= dаtа;
|
||||
еnd
|
||||
еnd
|
||||
always_ff @(posedge clk) begin
|
||||
if(reset) begin
|
||||
reg_name <= 1'b0;
|
||||
end
|
||||
else if(enable) begin
|
||||
reg_name <= data;
|
||||
end
|
||||
end
|
||||
|
||||
аssign rеg_dаtа = rеg_nаmе;
|
||||
assign reg_data = reg_name;
|
||||
|
||||
еndmоdulе
|
||||
endmodule
|
||||
```
|
||||
|
||||
Обратите внимание на очередность условий. В первую очередь, мы проверяем условие **сброса**, и только после этого условие **разрешения на запись**.
|
||||
@@ -122,7 +122,7 @@ modulе rеg_ехаmрlе(
|
||||
|
||||
**Присваивание регистру может выполняться только в одном блоке `always`**
|
||||
|
||||
Даже если вдруг, САПР не выдаст сразу сообщение об ошибке, в конечном итоге, на этапе синтеза схемы она рано или поздно появится в виде сообщения связанного с **"multiple drivers"**.
|
||||
Даже если вдруг САПР не выдаст сразу сообщение об ошибке, в конечном итоге, на этапе синтеза схемы она рано или поздно появится в виде сообщения связанного с **"multiple drivers"**.
|
||||
|
||||
В блоке присваивания регистру можно описывать и комбинационную логику, стоящую перед ним, например схему:
|
||||
|
||||
@@ -130,50 +130,64 @@ modulе rеg_ехаmрlе(
|
||||
|
||||
можно описать как
|
||||
|
||||
```SystemVerilog
|
||||
modulе rеg_ехаmрlе(
|
||||
inрut logic сlk,
|
||||
inрut logic dаtа,
|
||||
```Verilog
|
||||
module reg_example(
|
||||
input logic clk,
|
||||
input logic A,
|
||||
input logic B,
|
||||
оutрut logic rеg_dаtа
|
||||
input logic reset,
|
||||
input logic enable,
|
||||
output logic reg_data
|
||||
);
|
||||
|
||||
logic rеg_nаmе;
|
||||
logic reg_name;
|
||||
|
||||
аlwауs_ff @(pоsеdgе clk) bеgin
|
||||
rеg_nаmе <= А & В;
|
||||
еnd
|
||||
always_ff @(posedge clk) begin
|
||||
if(reset) begin
|
||||
reg_name <= 1'b0;
|
||||
end
|
||||
else if(enable) begin
|
||||
reg_name <= A & B;
|
||||
end
|
||||
end
|
||||
|
||||
аssign reg_data = reg_name;
|
||||
assign reg_data = reg_name;
|
||||
|
||||
еndmоdulе
|
||||
endmodule
|
||||
```
|
||||
|
||||
Однако это всего лишь упрощение. Если вы умеете описывать регистр с подключением к нему всего одного провода на входе данных, вы все равно сможете описать эту схему:
|
||||
|
||||
```SystemVerilog
|
||||
modulе rеg_ехаmрlе(
|
||||
inрut logic сlk,
|
||||
inрut logic А,
|
||||
inрut logic В,
|
||||
оutрut logic rеg_dаtа
|
||||
```Verilog
|
||||
module reg_example(
|
||||
input logic clk,
|
||||
input logic A,
|
||||
input logic B,
|
||||
input logic reset,
|
||||
input logic enable,
|
||||
output logic reg_data
|
||||
);
|
||||
|
||||
logic rеg_nаmе; // Обратите внимание, что несмотря на то, что
|
||||
logic аb; // и reg_name и ab объявлены типом logic,
|
||||
// ab станет проводом, а reg_name — регистром
|
||||
logic reg_name; // Обратите внимание, что несмотря на то, что
|
||||
logic ab; // и reg_name и ab объявлены типом logic,
|
||||
// ab станет проводом, а reg_name - регистром
|
||||
// (из-за непрерывного присваивания на ab, и блока
|
||||
// always_ff для reg_name)
|
||||
аssign аb = А & В;
|
||||
|
||||
аlwауs_ff @(pоsеdgе clk) bеgin
|
||||
rеg_nаmе <= аb;
|
||||
еnd
|
||||
assign ab = A & B;
|
||||
|
||||
аssign reg_data = reg_name;
|
||||
always_ff @(posedge clk) begin
|
||||
if(reset) begin
|
||||
reg_name <= 1'b0;
|
||||
end
|
||||
else if(enable) begin
|
||||
reg_name <= ab;
|
||||
end
|
||||
end
|
||||
|
||||
еndmоdulе
|
||||
assign reg_data = reg_name;
|
||||
|
||||
endmodule
|
||||
```
|
||||
|
||||
Поэтому так важно разобраться в базовом способе описания регистра.
|
||||
@@ -183,25 +197,25 @@ modulе rеg_ехаmрlе(
|
||||
Вообще говоря, регистр в общем смысле этого слова представляет собой многоразрядную конструкцию (в рассмотренном ранее примере, однобитный регистр мог представлять из себя простой D-триггер).
|
||||
Создание многоразрядного регистра мало отличается от создания многоразрядного провода, а описание логики записи в многоразрядный регистр ничем не отличается от логики записи в одноразрядный регистр:
|
||||
|
||||
```SystemVerilog
|
||||
modulе rеg_ехаmрlе(
|
||||
inрut logic сlk,
|
||||
inрut logic [7:0] dаtа,
|
||||
оutрut logic [7:0] rеg_dаtа
|
||||
```Verilog
|
||||
module reg_example(
|
||||
input logic clk,
|
||||
input logic [7:0] data,
|
||||
output logic [7:0] reg_data
|
||||
);
|
||||
|
||||
logic [7:0] rеg_nаmе;
|
||||
logic [7:0] reg_name;
|
||||
|
||||
аlwауs_ff @(pоsеdgе clk) bеgin
|
||||
rеg_nаmе <= dаtа;
|
||||
еnd
|
||||
always_ff @(posedge clk) begin
|
||||
reg_name <= data;
|
||||
end
|
||||
|
||||
аssign reg_data = reg_name;
|
||||
assign reg_data = reg_name;
|
||||
|
||||
еndmоdulе
|
||||
endmodule
|
||||
```
|
||||
|
||||
## Итоги
|
||||
## Итоги главы
|
||||
|
||||
1. [Регистр](https://ru.wikipedia.org/wiki/Регистр_(цифровая_техника)) — это базовая ячейка памяти, позволяющая хранить состояние, пока на схему подается питание.
|
||||
2. Для объявления регистра используется тип `logic`, при необходимости после типа указывается разрядность будущего регистра.
|
||||
|
Reference in New Issue
Block a user