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:
Andrei Solodovnikov
2024-09-02 10:20:08 +03:00
committed by GitHub
parent 78bb01ef95
commit a28002e681
195 changed files with 3640 additions and 2664 deletions

View File

@@ -1,4 +1,4 @@
# Лабораторная работа 1 "Сумматор"
# Лабораторная работа 1 "Сумматор"
## Цель
@@ -21,7 +21,7 @@
Итогом лабораторной работы будет создание устройства, способного складывать два числа. Но перед тем, как учиться создавать подобное устройство, необходимо немного освоиться в самом процессе складывания чисел.
Давайте начнем с примера и сложим в столбик произвольную пару чисел, например 42 и 79:
Давайте начнём с примера и сложим в столбик произвольную пару чисел, например 42 и 79:
![../../.pic/Labs/lab_01_adder/column_add_dec.drawio.svg](../../.pic/Labs/lab_01_adder/column_add_dec.drawio.svg)
@@ -63,13 +63,13 @@
_Таблица истинности одноразрядного сложения._
`S` — это младший разряд суммы, записываемый в столбце сложения под слагаемыми `a` и `b`. `C` (_carry_, перенос) — это старший разряд суммы, записываемый левее, если произошел перенос разряда. Как мы видим, перенос разряда происходит только в случае, когда оба числа одновременно равны единице. При этом значение `S` обращается в `0`, и результат записывается как `10`, что в двоичной системе означает `2`. Кроме того, значение `S` равно `0` и в случае, когда оба операнда одновременно равны нулю. Вы можете заметить, что `S` равно нулю в тех случаях, когда `а` и `b` равны, и не равно нулю в противоположном случае. Подобным свойством обладает логическая операция **Исключающее ИЛИ** (**eXclusive OR**, **XOR**):
`S` — это младший разряд 2-битного результата суммы, записываемый в столбце сложения под слагаемыми `a` и `b`. `C` (_carry_, перенос) — это старший разряд суммы, записываемый левее, если произошёл перенос разряда. Как мы видим, перенос разряда происходит только в случае, когда оба числа одновременно равны единице. При этом значение `S` обращается в `0`, и результат записывается как `10`, что в двоичной системе означает `2`. Кроме того, значение `S` равно `0` и в случае, когда оба операнда одновременно равны нулю. Вы можете заметить, что `S` равно нулю в тех случаях, когда `а` и `b` равны, и не равно нулю в противоположном случае. Подобным свойством обладает логическая операция **Исключающее ИЛИ** (**eXclusive OR**, **XOR**):
![../../.pic/Labs/lab_01_adder/tt2.png](../../.pic/Labs/lab_01_adder/tt2.png)
_Таблица истинности операции Исключающее ИЛИ (XOR)._
Для бита переноса всё ещё проще — он описывается операцией логическое И:
Для бита переноса всё ещё проще — он описывается операцией **логическое И**:
![../../.pic/Labs/lab_01_adder/tt3.png](../../.pic/Labs/lab_01_adder/tt3.png)
@@ -81,7 +81,7 @@ _Таблица истинности операции И._
_Рисунок 1. Цифровая схема устройства, складывающего два операнда с сохранением переноса (полусумматора)._
Однако, в описании полного 1-битного сумматора сказано, что у него есть три входа, а в наших таблицах истинности и на схеме выше их только два (схема, представленная на рис. 1, реализует так называемый "полусумматор"). На самом деле, на каждом этапе сложения в столбик мы всегда складывали три числа: цифру верхнего числа, цифру нижнего числа, и единицу в случае переноса разряда из предыдущего столбца (если с предыдущего разряда не было переноса, прибавление нуля неявно опускалось).
Однако, в описании полного 1-битного сумматора сказано, что у него есть три входа, а в наших таблицах истинности и на схеме выше их только два (схема, представленная на _рис. 1_, реализует так называемый "полусумматор"). На самом деле, на каждом этапе сложения в столбик мы всегда складывали три числа: цифру верхнего числа, цифру нижнего числа, и единицу в случае переноса разряда из предыдущего столбца (если с предыдущего разряда не было переноса, прибавление нуля неявно опускалось).
Таким образом, таблица истинности немного усложняется:
@@ -107,50 +107,25 @@ _Рисунок 2. Цифровая схема полного 1-битного
## Практика
Реализуем схему полусумматора (рис.1) в виде модуля, описанного на языке SystemVerilog.
Реализуем схему полусумматора (_рис. 1_) в виде модуля, описанного на языке SystemVerilog.
Модуль `half_adder` имеет два входных сигнала и два выходных. Входы `a_i` и `b_i` идут на два логических элемента: Исключающее ИЛИ и И, выходы которых подключены к выходам модуля `sum_o` и `carry_o` соответственно.
<details>
<summary>**Прочти меня перед использованием кода из примера.**</summary>
### Во все примеры кода намеренно вставлены неподдерживаемые символы. Не копируй, одумайся!
Важной частью изучения языка является практика по написанию кода. Даже если перепечатывая пример, вы не до конца его понимаете, вы запоминаете структуру кода и его конструкции. Вы изучаете этот пример для себя, а не для оценки, так что будьте честны с собой и воспроизведите пример самостоятельно.
<details>
<summary>Но мне очень надо.</summary>
![../../.pic/Labs/lab_01_adder/im_watching_you.jpg](../../.pic/Labs/lab_01_adder/im_watching_you.jpg)
</details>
<details>
<summary> — Я переписал пример точь-в-точь, а он все равно не работает!</summary>
Позови преподавателя, он тебе поможет.
</details>
</details>
```systemverilog
```Verilog
module half_adder(
inрut logic a_i, // Входные сигналы
inрut logic b_i,
input logic a_i, // Входные сигналы
input logic b_i,
outрut logic sum_o, // Выходной сигнал
outрut logic carry_o
output logic sum_o, // Выходные сигналы
output logic carry_o
);
);
assign sum_o = a_i ^ b_i;
assign carry_o = a_i & b_i;
assign sum_o = a_i ^ b_i;
assign carry_o = a_i & b_i;
endmodule
endmodule
```
_Листинг 1. SystemVerilog-код модуля half_adder._
@@ -161,19 +136,19 @@ _Листинг 1. SystemVerilog-код модуля half_adder._
_Рисунок 3. Цифровая схема модуля half_adder, сгенерированная САПР Vivado._
Схема похожа на _рис. 1_, но как проверить, что эта схема не содержит ошибок и делает именно то, что от нее ожидается?
Схема похожа на _рис. 1_, но как проверить, что эта схема не содержит ошибок и делает именно то, что от неё ожидается?
Для этого необходимо провести моделирование этой схемы. Во время моделирования на входы подаются тестовые воздействия. Каждое изменение входных сигналов приводит к каскадному изменению состояний внутренних цепей, что в свою очередь приводит к изменению значений на выходных сигналах схемы.
Подаваемые на схему входные воздействия формируются верификационным окружением. Верификационное окружение (в дальнейшем будет использован термин "**тестбенч**") — это особый несинтезируемый модуль, который не имеет входных или выходных сигналов. Ему не нужны входные сигналы, поскольку он сам является генератором всех своих внутренних сигналов, и ему не нужны выходные сигналы, поскольку этот модуль ничего не вычисляет, только подает входные воздействия на проверяемый модуль.
Подаваемые на схему входные воздействия формируются верификационным окружением. Верификационное окружение (в дальнейшем будет использован термин "**тестбенч**") — это особый несинтезируемый модуль, который не имеет входных или выходных сигналов. Ему не нужны входные сигналы, поскольку он сам является генератором всех своих внутренних сигналов, и ему не нужны выходные сигналы, поскольку этот модуль ничего не вычисляет, только подаёт входные воздействия на проверяемый модуль.
Внутри тестбенча можно использовать конструкции из несинтезируемого подмножества языка SystemVerilog, в частности программный блок `initial`, в котором команды выполняются последовательно, что делает этот блок чем-то отдаленно похожим на проверяющую программу. Поскольку изменение внутренних цепей происходит с некоторой задержкой относительно изменений входных сигналов, при моделировании есть возможность делать паузы между командами. Это делается с помощью специального символа #, за которым указывается количество времени симуляции, которое нужно пропустить перед следующей командой.
Перед тем как писать верификационное окружение, необходимо составить план того, как будет проводиться проверка устройства (составить верификационный план). Ввиду предельной простоты устройства, план будет состоять из одного предложения:
> Поскольку устройство не имеет внутреннего состояния, которое могло бы повлиять на результат, а число всех его возможных входных наборов воздействий равно четырем, мы можем проверить его работу, перебрав все возможные комбинации его входных сигналов.
> Поскольку устройство не имеет внутреннего состояния, которое могло бы повлиять на результат, а число всех его возможных входных наборов воздействий равно четырём, мы можем проверить его работу, перебрав все возможные комбинации его входных сигналов.
```SystemVerilog
```Verilog
module testbench(); // <- Не имеет ни входов, ни выходов!
logic a, b, carry, sum;
@@ -224,13 +199,13 @@ _Рисунок 5. Схема 4-битного сумматора._
_Рисунок 6. Схема 4-битного сумматора, сгенерированная САПР Vivado._
Несмотря на запутанность схемы, если присмотреться, вы увидите, как от шин A, B и S отходят линии к каждому из сумматоров, а бит переноса передается от предыдущего сумматора к следующему.
Несмотря на запутанность схемы, если присмотреться, вы увидите, как от шин A, B и S отходят линии к каждому из сумматоров, а бит переноса передаётся от предыдущего сумматора к следующему.
## Задание
Опишите полный 1-битный сумматор, схема которого представлена на _[Рис. 2](../../.pic/Labs/lab_01_adder/fig_02.drawio.svg)_. Прототип модуля следующий:
```SystemVerilog
```Verilog
module fulladder(
input logic a_i,
input logic b_i,
@@ -242,13 +217,13 @@ module fulladder(
Далее, вам необходимо реализовать полный 32-битный сумматор со следующим прототипом:
```systemverilog
```verilog
module fulladder32(
іnput logic [31:0] a_i,
іnput logic [31:0] b_i,
іnput logic carry_i,
оutput logic [31:0] sum_o,
оutput logic carry_o
input logic [31:0] a_i,
input logic [31:0] b_i,
input logic carry_i,
output logic [31:0] sum_o,
output logic carry_o
);
```
@@ -256,7 +231,7 @@ module fulladder32(
Если вы решите делать 4-битный сумматор, то модуль должен быть описан в соответствии со следующим прототипом:
```SystemVerilog
```Verilog
module fulladder4(
input logic [3:0] a_i,
input logic [3:0] b_i,
@@ -271,12 +246,12 @@ module fulladder4(
Создание массива модулей схоже с созданием одного модуля за исключением того, что после имени сущности модуля указывается диапазон, определяющий количество модулей в массиве. При этом подключение сигналов к массиву модулей осуществляется следующим образом:
- если разрядность подключаемого сигнала совпадает с разрядностью порта модуля из массива, этот сигнал подключается к каждому из модулей в массиве;
- если разрядность подключаемого сигнала превосходит разрядность порта модуля из массива в `N` раз (где `N` — количество модулей в массиве), к модулю подключается соответствующий диапазон бит подключаемого сигнала (диапазон младших бит будет подключен к модулю с меньшим индексом в массиве).
- если разрядность подключаемого сигнала превосходит разрядность порта модуля из массива в `N` раз (где `N` — количество модулей в массиве), к модулю подключается соответствующий диапазон бит подключаемого сигнала (диапазон младших бит будет подключён к модулю с меньшим индексом в массиве).
- если разрядность подключаемого сигнала не подходит ни под один из описанных выше пунктов, происходит ошибка синтеза схемы, поскольку в этом случае САПР не способен понять каким образом подключать данный сигнал к каждому модулю из массива.
Далее идет пример того, как можно создать массив модулей:
Далее идёт пример того, как можно создать массив модулей:
```SystemVerilog
```Verilog
module example1(
input logic [3:0] a,
input logic b,
@@ -303,11 +278,11 @@ example1 instance_array[7:0]( // Создается массив из 8 моду
// A[3:0], к instance_array[7] будет подключен
// диапазон A[31:28]).
.b(B) // Поскольку разрядность сигнала B совпадает с
.b(B), // Поскольку разрядность сигнала B совпадает с
// разрядностью входа b, сигнал B будет подключен
// как есть ко всем модулям в массиве.
.c(C[7:0]) // Поскольку разрядность сигнала C не равна
.c(C[7:0]), // Поскольку разрядность сигнала C не равна
// ни разрядности входа c, ни его увосьмиренной
// разрядности, мы должны выбрать такой диапазон
// бит, который будет удовлетворять одному из
@@ -322,36 +297,18 @@ _Листинг 3. Пример создания массива модулей._
### Порядок выполнения задания
1. Создайте проект, согласно [руководству по созданию проекта в Vivado](../../Vivado%20Basics/Vivado%20trainer.md)
2. В `Design Sources` проекта создайте `SystemVerilog`-файл `fulladder`.
3. Опишите в файле модуль `fulladder`, схема которого представлена на _[Рис. 2](../../.pic/Labs/lab_01_adder/fig_02.drawio.svg)_.
4. Проверьте 1-битный сумматор. Для этого:
1. В `Simulation Sources` проекта создайте `SystemVerilog`-файл `tb_fulladder`.
2. Вставьте содержимое файла [`tb_fulladder.sv`](tb_fulladder.sv), расположенного рядом с данным документом.
3. Запустите моделирование. Для запуска симуляции воспользуйтесь [`этой инструкцией`](../../Vivado%20Basics/Run%20Simulation.md).
4. Убедитесь по сигналам временной диаграммы, что модуль работает корректно.
5. В `Design Sources` проекта создайте `SystemVerilog`-файл `fulladder4`.
6. Опишите модуль `fulladder4`, схема которого представлена на _Рис. 5 и 6_, используя [`иерархию модулей`](../../Basic%20Verilog%20structures/Modules.md#%D0%B8%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%8F-%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D0%B5%D0%B9), чтобы в нем выполнялось поразрядное сложение двух 4-битных чисел и входного бита переноса. Некоторые входы и выходы модуля будет необходимо описать в виде [`векторов`](../../Basic%20Verilog%20structures/Modules.md#векторы).
1. Обратите внимание, что входной бит переноса должен подаваться на сумматор, выполняющий сложение нулевого разряда, выходной бит переноса соединяется с выходным битом переноса сумматора, выполняющего сложение 4-го разряда.
7. Проверьте 4-битный сумматор. Для этого:
1. В `Simulation Sources` проекта создайте `SystemVerilog`-файл `tb_fulladder4`.
2. Вставьте содержимое файла [`tb_fulladder4.sv`](tb_fulladder4.sv). Нажмите по нему в окне `Sources` ПКМ и выберите `Set as Top`.
3. Запустите моделирование. Для запуска симуляции воспользуйтесь [`этой инструкцией`](../../Vivado%20Basics/Run%20Simulation.md).
4. Проверьте содержимое TCL-консоли. Убедитесь в появлении сообщения о завершении теста.
5. Убедитесь по сигналам временной диаграммы, что модуль работает корректно.
8. В `Design Sources` проекта создайте `SystemVerilog`-файл `fulladder32`.
9. Опишите модуль `fulladder32` так, чтобы в нем выполнялось поразрядное сложение двух 32-битных чисел и входного бита переноса. Его можно реализовать через последовательное соединение восьми 4-битных сумматоров, либо же можно соединить 32 1-битных сумматора (как вручную, так и с помощью создания массива модулей).
1. Обратите внимание, что входной бит переноса должен подаваться на сумматор, выполняющий сложение нулевого разряда, выходной бит переноса соединяется с выходным битом переноса сумматора, выполняющего сложение 31-го разряда.
10. Проверьте 32-битный сумматор. Для этого:
1. В `Simulation Sources` проекта создайте `SystemVerilog`-файл `tb_fulladder32`.
2. Вставьте содержимое файла [`tb_fulladder32.sv`](tb_fulladder32.sv). Нажмите по нему в окне `Sources` ПКМ и выберите `Set as Top`.
3. Запустите моделирование.
4. Проверьте содержимое TCL-консоли. Убедитесь в появлении сообщения о завершении теста.
5. Если в tcl-консоли были сообщения об ошибках, разберитесь в причине ошибок по временной диаграмме и [исправьте их](../../Vivado%20Basics/Debug%20manual.md).
11. Проверьте работоспособность вашей цифровой схемы в ПЛИС. Для этого:
1. Добавьте файлы из папки [`board files`](https://github.com/MPSU/APS/tree/master/Labs/01.%20Adder/board%20files) в проект.
1. Файл [nexys_adder.sv](https://github.com/MPSU/APS/tree/master/Labs/01.%20Adder/board%20files/nexys_adder.sv) необходимо добавить в `Design Sources` проекта.
2. Файл [nexys_a7_100t.xdc](https://github.com/MPSU/APS/tree/master/Labs/01.%20Adder/board%20files/nexys_a7_100t.xdc) необходимо добавить в `Constraints` проекта.
2. Выберите `nexys_adder` в качестве модуля верхнего уровня (`top-level`) в `Design Sources`.
3. Выполните генерацию битстрима и сконфигурируйте ПЛИС. Для этого воспользуйтесь [следующей инструкцией](../../Vivado%20Basics/How%20to%20program%20an%20fpga%20board.md).
4. Описание логики работы модуля верхнего уровня и связи периферии ПЛИС с реализованным модулем находится в папке [`board files`](https://github.com/MPSU/APS/tree/master/Labs/01.%20Adder/board%20files).
1. Создайте проект, согласно [руководству по созданию проекта в Vivado](../../Vivado%20Basics/01.%20New%20project.md)
2. Опишите модуль `fulladder`, схема которого представлена на _[Рис. 2](../../.pic/Labs/lab_01_adder/fig_02.drawio.svg)_.
1. Модуль необходимо описать с таким же именем и портам, как указано в задании.
3. Проверьте модуль с помощью верификационного окружения, представленного в файле [`lab_01.tb_fulladder.sv`](lab_01.tb_fulladder.sv). Убедитесь по сигналам временной диаграммы, что модуль работает корректно. В случае обнаружения некорректного поведения сигналов суммы и выходного бита переноса, вам необходимо [найти](../../Vivado%20Basics/05.%20Bug%20hunting.md) причину этого поведения, и устранить её.
4. Опишите модуль `fulladder4`, схема которого представлена на _Рис. 5 и 6_, используя [`иерархию модулей`](../../Basic%20Verilog%20structures/Modules.md#%D0%B8%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%8F-%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D0%B5%D0%B9), чтобы в нем выполнялось поразрядное сложение двух 4-битных чисел и входного бита переноса. Некоторые входы и выходы модуля будет необходимо описать в виде [`векторов`](../../Basic%20Verilog%20structures/Modules.md#векторы).
1. Модуль необходимо описать с таким же именем и портам, как указано в задании.
2. Обратите внимание, что входной бит переноса должен подаваться на сумматор, выполняющий сложение нулевого разряда, выходной бит переноса соединяется с выходным битом переноса сумматора, выполняющего сложение 4-го разряда.
5. Проверьте модуль с помощью верификационного окружения, представленного в файле [`lab_01.tb_fulladder4.sv`](lab_01.tb_fulladder4.sv). Убедитесь по сигналам временной диаграммы, что модуль работает корректно. В случае обнаружения некорректного поведения сигналов суммы и выходного бита переноса, вам необходимо [найти](../../Vivado%20Basics/05.%20Bug%20hunting.md) причину этого поведения, и устранить её.
1. Перед запуском моделирования, убедитесь, что у вас выбран корректный модуль верхнего уровня в `Simulation Sources`.
6. Опишите модуль `fulladder32` так, чтобы в нем выполнялось поразрядное сложение двух 32-битных чисел и входного бита переноса. Его можно реализовать через последовательное соединение восьми 4-битных сумматоров, либо же можно соединить 32 1-битных сумматора (как вручную, так и с помощью создания массива модулей).
1. Модуль необходимо описать с таким же именем и портам, как указано в задании.
2. Обратите внимание, что входной бит переноса должен подаваться на сумматор, выполняющий сложение нулевого разряда, выходной бит переноса соединяется с выходным битом переноса сумматора, выполняющего сложение 31-го разряда.
7. Проверьте модуль с помощью верификационного окружения, представленного в файле [`lab_01.tb_fulladder32.sv`](lab_01.tb_fulladder32.sv). В случае, если в TCL-консоли появились сообщения об ошибках, вам необходимо [найти](../../Vivado%20Basics/05.%20Bug%20hunting.md) и исправить их.
1. Перед запуском моделирования, убедитесь, что у вас выбран корректный модуль верхнего уровня в `Simulation Sources`.
8. Проверьте работоспособность вашей цифровой схемы в ПЛИС.

View File

@@ -2,7 +2,7 @@
После того, как вы создали проверили на моделировании 32-разрядный сумматор, вам необходимо проверить его работу на прототипе в ПЛИС.
Инструкция по реализации прототипа описана [здесь](../../../Vivado%20Basics/How%20to%20program%20an%20fpga%20board.md).
Инструкция по реализации прототипа описана [здесь](../../../Vivado%20Basics/07.%20Program%20and%20debug.md).
На _рис. 1_ представлена схема прототипа в ПЛИС.

View File

@@ -9,7 +9,7 @@ See https://github.com/MPSU/APS/blob/master/LICENSE file for licensing details.
* ------------------------------------------------------------------------------
*/
module tb_fulladder();
module lab_01_tb_fulladder();
logic tb_a_i;
logic tb_b_i;

View File

@@ -9,7 +9,7 @@ See https://github.com/MPSU/APS/blob/master/LICENSE file for licensing details.
* ------------------------------------------------------------------------------
*/
module tb_fulladder32();
module lab_01_tb_fulladder32();
logic [31:0] tb_a_i;
logic [31:0] tb_b_i;
@@ -32,7 +32,6 @@ module tb_fulladder32();
initial begin
$display("Test has been started");
$display( "\n\n==========================\nCLICK THE BUTTON 'Run All'\n==========================\n"); $stop();
sequential_add_test();
random_test();
$display("\nTest has been finished\nNumber of errors: %d\n", err_cnt);

View File

@@ -9,7 +9,7 @@ See https://github.com/MPSU/APS/blob/master/LICENSE file for licensing details.
* ------------------------------------------------------------------------------
*/
module tb_fulladder4();
module lab_01_tb_fulladder4();
logic [3:0] tb_a_i;
logic [3:0] tb_b_i;
@@ -30,7 +30,6 @@ module tb_fulladder4();
initial begin
$display("Test has been started");
$display( "\n\n==========================\nCLICK THE BUTTON 'Run All'\n==========================\n"); $stop();
#5ns;
test_case = 9'd0;
repeat(512) begin