mirror of
https://github.com/MPSU/APS.git
synced 2025-09-15 09:10:10 +00:00
Перенос Implementation steps в Introduction
This commit is contained in:
@@ -1,67 +1,146 @@
|
||||
# Структура папок в проекте Vivado
|
||||
# Окно исходников проекта Vivado
|
||||
|
||||
Вы смотрите на окно `Sources` и ничего не понимаете? Или создали модуль, а он куда–то исчез? Или просто хотите понять, как лучше ориентироваться в созданных модулях? Тогда это для вас.
|
||||
Данный документ расскажет вам об одном из основных окон программы Vivado: `Sources`. Данное оно расположено в левом верхнем углу. Если вы его не видите, данное окно можно активировать через меню: `Window –> Sources`. Окно состоит из следующих вкладок:
|
||||
|
||||
В левом верхнем углу Vivado расположено окно со вкладкой `Sources`. Здесь располагается иерархия модулей вашего проекта. Если у вас нет этой вкладки, открыть её можно так: `Window –> Sources`.
|
||||
1. Hierarchy;
|
||||
2. Libraries;
|
||||
3. Compile Order.
|
||||
|
||||

|
||||
В определенных ситуациях в данном окне может появиться и вкладка `IP Cores`, но в рамках данного курса она нас не интересует.
|
||||
|
||||
Во вкладке `Design Sources` хранятся модули, описывающие ваш дизайн. В `Constrain` лежат файлы, необходимые для работы с конкретной ПЛИС. `Simulation Sources` хранит в себе тестбенчи и обычные модули.
|
||||
Рассмотрим первые три вкладки.
|
||||
|
||||
Допустим, мы создали модуль полного однобитного сумматора `fulladder`, а также создали и планируем описать модуль полного четырехбитного сумматора `fulladder4`, подключив к нему четыре однобитных.
|
||||
## Иерархия модулей проекта
|
||||
|
||||
Итак, раскрываем вкладку `Design Sources` и видим два модуля – `fulladder` и `fulladder4`, которые пока что никак друг с другом не связаны. Двойное нажатие на название модуля приведёт к его открытию.
|
||||
Рассмотрим _рис. 1_.
|
||||
|
||||

|
||||

|
||||
|
||||
Модуль `fulladder4` является модулем верхнего уровня (top-level module), то есть, если мы запустим синтез или имплементацию проекта, именно этот модуль Vivado будет рассматривать. Чтобы сменить модуль верхнего уровня, необходимо нажать на выбранный модуль правой кнопкой мыши, затем на `Set a top`.
|
||||
_Рисунок 1. Окно `Sources`, открытое на вкладке `Hierarchy`._
|
||||
|
||||

|
||||
Данная вкладка состоит из четырех "папок":
|
||||
|
||||
Подключим `fulladder` к `fulladder4` для создания четырехбитного сумматора путём соединения четырех однобитных. Тогда после сохранения окно изменится так:
|
||||
1. Design Sources;
|
||||
2. Constraints;
|
||||
3. Simulation Sources;
|
||||
4. Utility Sources.
|
||||
|
||||

|
||||
В рамках текущего курса лабораторных работ мы будем взаимодействовать только с тремя из них.
|
||||
|
||||
Раскроем вкладку `fulladder4` и увидим 4 подключенных модуля `fulladder`:
|
||||
Помните, что несмотря на использование слова "папка", речь идет не о директориях операционной системы. Папки проекта — это всего лишь удобная абстракция для управления иерархией проекта.
|
||||
|
||||

|
||||
В папке `Design Sources` строится иерархия проектируемых модулей (реальных схем, которые в будущем могут быть воспроизведены в ПЛИС или заказной микросхеме).
|
||||
|
||||
Папка `Constraints` содержит файлы ограничений, помогающих реализовать проект на конкретной ПЛИС (см. ["Этапы реализации проекта в ПЛИС"](../Introduction/Implementation%20steps.md#implementation)).
|
||||
|
||||
`Simulation Sources` хранит в себе иерархию верификационного окружения, включая модули из папки `Design Sources` — т.е. все модули (как синтезируемые, так и не синтезируемые), которые будут использованы пр моделировании.
|
||||
|
||||
> Обратите внимание на то, вкладка `Hierarchy` не содержит файлов. Здесь отображается иерархия модулей проекта. Один модуль может быть использован несколько раз — и в этом случае он будет столько же раз отображён в иерархии, хотя файл, хранящий описание этого модуля останется один (см. _рис. 5_).
|
||||
|
||||
Допустим, мы создали модуль полного однобитного сумматора `fulladder`, а также создали модуль полного четырехбитного сумматора `fulladder4`, содержимое которого мы только планируем описать, подключив внутри него четыре однобитных сумматора.
|
||||
|
||||
Раскрыв папку `Design Sources` мы увидим два модуля – `fulladder` и `fulladder4`, которые пока что никак друг с другом не связаны. Двойное нажатие на название модуля приведёт к открытию файла, содержащего описание этого модуля.
|
||||
|
||||

|
||||
|
||||
_Рисунок 2. Содержимое папки `Design Sources`._
|
||||
|
||||
Модуль `fulladder4` является модулем верхнего уровня (top-level module). Это значит, что при попытке запуска моделирования или синтеза, Vivado будет работать именно с этим модулем. Чтобы сменить модуль верхнего уровня, необходимо нажать правой кнопкой мыши на интересующий модуль и выбрать `Set a top`.
|
||||
|
||||

|
||||
|
||||
_Рисунок 3. Пример смены модуля верхнего уровня._
|
||||
|
||||
Опишем логику работы четырехбитного сумматора таким образом, чтобы тот содержал четыре однобитных сумматора. После сохранения окно изменится так:
|
||||
|
||||

|
||||
|
||||
_Рисунок 4. Обновленное содержимое папки `Design Sources`._
|
||||
|
||||
После раскрытия ветки `fulladder4` будет отображено 4 подключенных модуля `fulladder`.
|
||||
|
||||

|
||||
|
||||
_Рисунок 5. Иерархия проекта с четырьмя копиями модуля `fulladder`._
|
||||
|
||||
В `Simulation Sources` мы видим один файл тестбенча, к которому что-то подключено, и модуль `fulladder4` с подключенными к нему другими модулями:
|
||||
|
||||

|
||||

|
||||
|
||||
Модули из `Design Sources` автоматически попадают в `Simulation Sources`, так как эти файлы нужны для симуляции. Они не являются копиями модулей, а просто дублируются для удобства. Каждый раз, когда вы меняете что-то в своём дизайне, это отражается как во вкладке `Design Sources`, так и в `Simulation Sources`. Раскроем вкладку с модулем `tb`:
|
||||
_Рисунок 6. Иерархия модулей `Simulation Sources`.
|
||||
|
||||

|
||||
Модули из `Design Sources` автоматически попадают в `Simulation Sources`, так как эти модули используются при моделировании.
|
||||
|
||||
Помните, что здесь отображается иерархия модулей. В реальности модуль `fulladder` описан всего один раз.
|
||||
|
||||
Каждый раз, когда вы меняете что-то в модулях разрабатываемого устройства, это отражается как во вкладке `Design Sources`, так и в `Simulation Sources`. Раскроем вкладку с модулем `tb`:
|
||||
|
||||

|
||||
|
||||
_Рисунок 7. Пример иерархии с отсутствующим модулем._
|
||||
|
||||
Такая картина говорит нам о попытке подключить модуль, которого нет в проекте. Часто это связано с неправильным указанием подключаемого модуля. В данном случае мы хотим подключить модуль `half_adder` и Vivado не может его найти.
|
||||
|
||||
```Verilog
|
||||
```SystemVerilog
|
||||
module tb();
|
||||
...
|
||||
|
||||
//...
|
||||
|
||||
half_adder DUT(
|
||||
.A (a),
|
||||
.B (b),
|
||||
.P (p),
|
||||
.S (s)
|
||||
);
|
||||
...
|
||||
|
||||
// ...
|
||||
|
||||
endmodule
|
||||
```
|
||||
|
||||
Переименуем название подключаемого модуля на `fulladder4` и сохраним.
|
||||
|
||||
```Verilog
|
||||
```SystemVerilog
|
||||
module tb();
|
||||
...
|
||||
|
||||
//...
|
||||
|
||||
fulladder4 DUT(
|
||||
.A (a),
|
||||
.B (b),
|
||||
.P (p),
|
||||
.S (s)
|
||||
);
|
||||
...
|
||||
|
||||
// ...
|
||||
|
||||
endmodule
|
||||
```
|
||||
|
||||
После обновления в окне `Sources` модуль `fulladder4` "спрячется" под `tb`. Если раскрыть вкладку, будет видно, что `fulladder4` подключен к `tb`, а четыре модуля `fulladder` – к `fulladder4`. Также отметим, что `tb` является модулем верхнего уровня, значит, если мы захотим запустить симуляцию, то Vivado выполнит симуляцию именно для модуля `tb`. Изменить модуль верхнего уровня можно так же, как было описано ранее.
|
||||
|
||||

|
||||

|
||||
|
||||
_Рисунок 8. Пример исправленной иерархии верификационного окружения._
|
||||
|
||||
После каждого сохранения файла проекта, иерархия проекта будет какое-то время обновляться. Это можно заметить по надписи `Updating` вверху окна (см. _рис 9_). Во время обновления иерархии не стоит выполнять операции синтеза или моделирования — это приведет к ошибке.
|
||||
|
||||

|
||||
|
||||
_Рисунок 9. Окно `Sources` во время обновления иерархии проекта._
|
||||
|
||||
Одной из частой ошибок студентов бывает прикрепление файла не к той папке. Например, создание модуля проекта в папке `Simulation Sources` (из-за чего тот не появится в папке `Design Sources`), или создание модуля верификационного окружения в папке `Design Sources` (он же наоборот — окажется и в папке `Simulation Sources`, но при этом в папке Design Sources окажется несинтезируемый модуль, который может оказаться еще и модулем верхнего уровня, что приведет к ошибке).
|
||||
|
||||
В случае, если произошла такая ошибка, она может быть легко исправлена нажатием правой кнопкой мыши по неправильно расположеному модулю и выбору кнопки: "Move to Design[или Simulation] sources".
|
||||
|
||||
## Библиотеки проекта
|
||||
|
||||
В данной вкладке находятся файлы проекта, сгруппированные по библиотекам. Обычно данная вкладка практически не используется.
|
||||
|
||||
## Порядок компиляции сущностей проекта
|
||||
|
||||
Обычно Vivado сам определяет порядок компиляции по иерархии проекта. Однако, в некоторых ситуациях он может определить что-то неправильно. На данной вкладке вы можете исправить порядок компиляции (скорее всего, вам может потребоваться эта вкладка, для указания порядка компиляции пакетов SystemVerilog).
|
||||
|
||||
## Дополнительные материалы
|
||||
|
||||
Более подробную информацию по окну `Sources` вы можете найти в руководстве пользователя Vivado: ["Vivado Design Suite User Guide: Using the Vivado IDE (UG893)"](https://docs.xilinx.com/r/en-US/ug893-vivado-ide/Using-the-Sources-Window) (раздел "Using the Sources Window").
|
||||
|
@@ -1,227 +0,0 @@
|
||||
# Шаги реализации разработанного устройства в ПЛИС
|
||||
|
||||
Для того, чтобы описанное на **языке описания аппаратуры** устройство было реализовано в ПЛИС, необходимо выполнить несколько этапов:
|
||||
|
||||
1. Элаборацию (elaboration)
|
||||
2. Синтез (synthesis)
|
||||
3. Имплементацию (implementation)
|
||||
4. Генерацию битстрима (generate bitstream)
|
||||
|
||||
Остановимся на каждом шаге подробнее:
|
||||
|
||||
## Elaboration
|
||||
|
||||
На шаге **элаборации**, САПР строит цифровую схему по её **HDL**-описанию. Построенная схема не привязана к конкретной ПЛИС и использует абстрактные элементы: логические вентили, мультиплексоры, элементы памяти и т.п.
|
||||
На самом деле САПР генерирует не схему (картинку, схематик), а так называемый **нетлист**. **Нетлист** — это представление цифровой схемы в виде **графа**, где каждый элемент схемы является **узлом**, а **цепи**, соединяющие эти элементы являются ребрами. **Нетлист** может храниться как в виде каких-то внутренних файлов САПР-а (в случае **нетлиста** для этапа **элаборации**), так и в виде **HDL**-файла, описывающего экземпляры примитивов и связи между ними. Рассмотрим этап **элаборации** и термин **нетлиста** на примере.
|
||||
|
||||
Допустим, мы хотим реализовать следующую цифровую схему:
|
||||
|
||||

|
||||
|
||||
Её можно описать следующим **SystemVerilog**-кодом:
|
||||
|
||||
```SystemVerilog
|
||||
module sample(
|
||||
input logic a, b, c, d, sel,
|
||||
output logic res
|
||||
);
|
||||
|
||||
logic ab = a & b;
|
||||
logic xabc = ab ^ c;
|
||||
|
||||
assign res = sel? d : xabc;
|
||||
|
||||
endmodule
|
||||
```
|
||||
|
||||
Выполним этап **элаборации**. Для этого в **Vivado** на вкладке `RTL Analysis` выберем `Schematic`.
|
||||
|
||||
Откроются следующие окна:
|
||||
|
||||

|
||||
|
||||
В левом окне мы видим наш нетлист. В нижней части обозначены узлы графа (элементы **ab_i**, **res_i**, **xabc_i**, которые представляют собой **И**, **мультиплексор** и **Исключающее ИЛИ** соответственно. Имена этих элементов схожи с именами проводов, присваиванием которым мы создавали данные элементы)
|
||||
|
||||
В верхней части обозначены **ребра графа**, соединяющие элементы схемы. Это входы и выходы нашего модуля, а также созданные нами промежуточные цепи.
|
||||
|
||||
Справа вы видите **схематик** — **графическую схему**, построенную на основе данного **графа** (**нетлиста**).
|
||||
|
||||
## Synthesis
|
||||
|
||||
На шаге синтеза, САПР берет сгенерированную ранее цифровую схему и реализует элементы этой схемы через примитивы конкретной ПЛИС — в основном через логические ячейки, содержащие таблицы подстановки, полный однобитный сумматор и `D-триггер` (см. [как работает ПЛИС](../Introduction/How%20FPGA%20works.md)).
|
||||
|
||||
В рамках нашего примера, САПР смотрит на построенный на этапе **элаборации** **нетлист** и решает, какими средствами (**примитивами**) ПЛИС можно его реализовать. Поскольку схема чисто **комбинационная**, результат её работы можно рассчитать и выразить в виде **таблицы истинности**, а значит для её реализации лучше всего подойдут **Таблицы Подстановки** (**LUT**-ы). Более того, в ПЛИС `xc7a100tcsg324-1` есть пятивходовые LUT-ы, а у нашей схемы именно столько входов. Это означает, работу всей этой схемы можно заменить **всего одной таблицей подстановки** внутри ПЛИС.
|
||||
|
||||
Итак, продолжим рассматривать наш пример и выполним этап синтеза. Для этого нажмем на кнопку `Run Synthesis`.
|
||||
|
||||
После выполнения синтеза у нас появится возможность открыть новый схематик, сделаем это.
|
||||
|
||||

|
||||
|
||||
Мы видим, что между входами/выходами схемы и её внутренней логикой появились новые примитивы — **буферы**. Они нужны, преобразовать уровень напряжения между ножками ПЛИС и внутренней логикой (условно говоря, на вход плис могут приходить сигналы с уровнем `3.3 В`, а внутри ПЛИС примитивы работают с сигналами уровня `1.2 В`).
|
||||
|
||||
Сама же логика, как мы и предполагали, свернулась в одну пятивходовую таблицу подстановки.
|
||||
|
||||
строка `EQN=32'hAAAA3CCC` означает, что таблица подстановки будет инициализирована следующим 32-битным значением: `0xAAAA3CCC`.
|
||||
Поскольку у схемы 5 входов, у нас может быть 2<sup>5</sup>=32 возможных комбинаций входных сигналов и для каждого нужно свое значение результата.
|
||||
|
||||
Можно ли как-то проверить данное 32-битное значение без просчитывания всех 32 комбинаций сигналов "на бумажке"?
|
||||
<details>
|
||||
<summary>
|
||||
Да, можно.
|
||||
</summary>
|
||||
Сперва надо понять в каком именно порядке будут идти эти комбинации. Мы видим, что сигналы подключены к таблице подстановки в следующем порядке: `d, c, b, a, sel`. Это означает, что сама таблица примет вид:
|
||||
|
||||
```ascii
|
||||
|sel| a | b | c | d | |res|
|
||||
|---|---|---|---|---| |---|
|
||||
| 0 | 0 | 0 | 0 | 0 | | 0 |
|
||||
| 0 | 0 | 0 | 0 | 1 | | 0 |
|
||||
| 0 | 0 | 0 | 1 | 0 | | 1 |
|
||||
| 0 | 0 | 0 | 1 | 1 | | 1 |
|
||||
| 0 | 0 | 1 | 0 | 0 | | 0 |
|
||||
....
|
||||
| 1 | 1 | 1 | 1 | 1 | | 1 |
|
||||
```
|
||||
|
||||
Давайте посмотрим на логику исходной схемы и данную таблицу истинности: когда `sel==1`, на выход идет `d`, это означает, что мы знаем все значения для нижней половины таблицы истинности, в нижней половине таблице истинности самый левый входной сигнал (`sel`) равен только единице, значит результат будет совпадать с сигналом `d`, который непрерывно меняется с `0` на `1` и оканчивается значением `1`. Это означает, что если читать значения результатов снизу-вверх (от старших значений к младшим), то сначала у нас будет 16 цифр, представляющих 8 пар `10`:`101010101010`, что эквивалентно записи `AAAA` в шестнадцатиричной записи.
|
||||
|
||||
Рассчитывать оставшиеся 16 вариантов тоже не обязательно, если посмотреть на схему, то можно заметить, что когда `sel!=1`, ни `sel`, ни `d` больше не участвуют в управлении выходом. Выход будет зависеть от операции xor, которая дает `1` только когда её входы не равны между собой. Верхний вход xor (выход И) , будет равен единице только когда входы `a` и `b` равны единице, причем в данный момент, нас интересуют только ситуации, когда `sel!=1`. Принимая во внимание, что в таблице истинности значения входов записываются чередующимися степенями двойки (единицами, парами, четверками, восьмерками) единиц и нулей, мы понимаем, что интересующая нас часть таблицы истинности будет выглядеть следующим образом:
|
||||
|
||||
```ascii
|
||||
...
|
||||
|
||||
| a | b | c |
|
||||
. |---|---|---| .
|
||||
. | 1 | 1 | 0 | .
|
||||
. | 1 | 1 | 0 | .
|
||||
| 1 | 1 | 1 |
|
||||
| 1 | 1 | 1 |
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
Только в этой части таблицы истинности мы получим `1` на выходе **И**, при этом в старшей части, вход `c` так же равен `1`. Это значит, что входы **Исключающего ИЛИ** будут равны и на выходе будет `0`. Значит результат этой таблицы истинности будет равен `0011` или `3` в шестнадцатиричной записи.
|
||||
|
||||
Ниже данной части таблицы истинности располагается та часть, где `sel==1`, выше та часть, где выход **И** будет равен `0`. Это означает, что оставшаяся младшая часть будет повторять значения `c`, которое сменяется парами нулей и единиц: `00-11-00-11..`. Эта оставшаяся последовательность будет записана в шестнадцатиричном виде как `0xCCC`.
|
||||
|
||||
Таким образом, мы и получаем искомое выражение `EQN=32'hAAAA3CCC`. Если с этой частью возникли сложности, попробуйте составить данную таблицу истинности (без вычисления самих результатов, а затем просмотрите логику быстрого вычисления результата).
|
||||
</details>
|
||||
|
||||
## Implementation
|
||||
|
||||
После построения новой схемы, где в качестве элементов используются ресурсы конкретной ПЛИС, происходит расчёт размещения этой схемы внутри ПЛИС: выбираются конкретные логические ячейки, происходит маршрутизация сигнала между этими ячейками. Например, реализация 32-битного сумматора с ускоренным переносом может потребовать 32 LUT-а и 8 примитивов вычисления быстрого переноса (`CARRY4`). Будет неразумно использовать для этого примитивы, разбросанные по всему кристаллу ПЛИС, ведь тогда придется выполнять сложную маршрутизацию сигнала, да и временные характеристики устройства так же пострадают (сигналу идущему от предыдущего разряда к следующему придется проходить больший путь). Вместо этого, САПР будет пытаться разместить схему таким образом, чтобы использовались близлежащие примитивы ПЛИС, для получения оптимальных характеристик.
|
||||
|
||||
Что именно считается "оптимальным" зависит от двух вещей: настроек САПР и **ограничений** (**constraints**), наложенных на имплементацию. Ограничения сужают область возможных решений по размещению примитивов внутри ПЛИС под определенные характеристики (временны́е и физические). Например, можно сказать, внутри ПЛИС схема должна быть размещена таким образом, чтобы время прохождения по **критическому пути** не превышало `20ns`. Это временно́е ограничение. Также нужно сообщить САПР, к какой ножке ПЛИС необходимо подключить входы и выходы нашей схемы — это физическое ограничение.
|
||||
|
||||
Ограничения описываются не на языке описания аппаратуры, вместо этого используются текстовые файлы специального формата, зависящего от конкретной САПР.
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
Пример используемых ограничений для лабораторной по АЛУ.
|
||||
</summary>
|
||||
|
||||
Строки, начинающиеся с `#` являются комментариями.
|
||||
|
||||
Строки, начинающиеся с `set_property` являются физическими ограничениями, связывающими входы и выходы нашей схемы с конкретными входами и выходами ПЛИС.
|
||||
|
||||
Строка `create_clock...` задает временны́е ограничения, описывая целевую тактовую частоту тактового сигнала и его [скважность](https://ru.wikipedia.org/wiki/%D0%A1%D0%BA%D0%B2%D0%B0%D0%B6%D0%BD%D0%BE%D1%81%D1%82%D1%8C).
|
||||
|
||||
```xdc
|
||||
## This file is a general .xdc for the Nexys A7-100T
|
||||
|
||||
# Clock signal
|
||||
|
||||
set_property -dict { PACKAGE_PIN E3 IOSTANDARD LVCMOS33 } [get_ports { CLK100 }]; #IO_L12P_T1_MRCC_35 Sch=clk100mhz
|
||||
create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports {CLK100}];
|
||||
|
||||
# Switches
|
||||
set_property -dict { PACKAGE_PIN J15 IOSTANDARD LVCMOS33 } [get_ports { SW[0] }]; #IO_L24N_T3_RS0_15 Sch=sw[0]
|
||||
set_property -dict { PACKAGE_PIN L16 IOSTANDARD LVCMOS33 } [get_ports { SW[1] }]; #IO_L3N_T0_DQS_EMCCLK_14 Sch=sw[1]
|
||||
set_property -dict { PACKAGE_PIN M13 IOSTANDARD LVCMOS33 } [get_ports { SW[2] }]; #IO_L6N_T0_D08_VREF_14 Sch=sw[2]
|
||||
set_property -dict { PACKAGE_PIN R15 IOSTANDARD LVCMOS33 } [get_ports { SW[3] }]; #IO_L13N_T2_MRCC_14 Sch=sw[3]
|
||||
set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports { SW[4] }]; #IO_L12N_T1_MRCC_14 Sch=sw[4]
|
||||
set_property -dict { PACKAGE_PIN T18 IOSTANDARD LVCMOS33 } [get_ports { SW[5] }]; #IO_L7N_T1_D10_14 Sch=sw[5]
|
||||
set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { SW[6] }]; #IO_L17N_T2_A13_D29_14 Sch=sw[6]
|
||||
set_property -dict { PACKAGE_PIN R13 IOSTANDARD LVCMOS33 } [get_ports { SW[7] }]; #IO_L5N_T0_D07_14 Sch=sw[7]
|
||||
set_property -dict { PACKAGE_PIN T8 IOSTANDARD LVCMOS18 } [get_ports { SW[8] }]; #IO_L24N_T3_34 Sch=sw[8]
|
||||
set_property -dict { PACKAGE_PIN U8 IOSTANDARD LVCMOS18 } [get_ports { SW[9] }]; #IO_25_34 Sch=sw[9]
|
||||
set_property -dict { PACKAGE_PIN R16 IOSTANDARD LVCMOS33 } [get_ports { SW[10] }]; #IO_L15P_T2_DQS_RDWR_B_14 Sch=sw[10]
|
||||
set_property -dict { PACKAGE_PIN T13 IOSTANDARD LVCMOS33 } [get_ports { SW[11] }]; #IO_L23P_T3_A03_D19_14 Sch=sw[11]
|
||||
set_property -dict { PACKAGE_PIN H6 IOSTANDARD LVCMOS33 } [get_ports { SW[12] }]; #IO_L24P_T3_35 Sch=sw[12]
|
||||
set_property -dict { PACKAGE_PIN U12 IOSTANDARD LVCMOS33 } [get_ports { SW[13] }]; #IO_L20P_T3_A08_D24_14 Sch=sw[13]
|
||||
set_property -dict { PACKAGE_PIN U11 IOSTANDARD LVCMOS33 } [get_ports { SW[14] }]; #IO_L19N_T3_A09_D25_VREF_14 Sch=sw[14]
|
||||
set_property -dict { PACKAGE_PIN V10 IOSTANDARD LVCMOS33 } [get_ports { SW[15] }]; #IO_L21P_T3_DQS_14 Sch=sw[15]
|
||||
|
||||
### LEDs
|
||||
|
||||
set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { LED[0] }]; #IO_L18P_T2_A24_15 Sch=led[0]
|
||||
set_property -dict { PACKAGE_PIN K15 IOSTANDARD LVCMOS33 } [get_ports { LED[1] }]; #IO_L24P_T3_RS1_15 Sch=led[1]
|
||||
set_property -dict { PACKAGE_PIN J13 IOSTANDARD LVCMOS33 } [get_ports { LED[2] }]; #IO_L17N_T2_A25_15 Sch=led[2]
|
||||
set_property -dict { PACKAGE_PIN N14 IOSTANDARD LVCMOS33 } [get_ports { LED[3] }]; #IO_L8P_T1_D11_14 Sch=led[3]
|
||||
set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { LED[4] }]; #IO_L7P_T1_D09_14 Sch=led[4]
|
||||
set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { LED[5] }]; #IO_L18N_T2_A11_D27_14 Sch=led[5]
|
||||
set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports { LED[6] }]; #IO_L17P_T2_A14_D30_14 Sch=led[6]
|
||||
set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports { LED[7] }]; #IO_L18P_T2_A12_D28_14 Sch=led[7]
|
||||
set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { LED[8] }]; #IO_L16N_T2_A15_D31_14 Sch=led[8]
|
||||
set_property -dict { PACKAGE_PIN T15 IOSTANDARD LVCMOS33 } [get_ports { LED[9] }]; #IO_L14N_T2_SRCC_14 Sch=led[9]
|
||||
set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports { LED[10] }]; #IO_L22P_T3_A05_D21_14 Sch=led[10]
|
||||
set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports { LED[11] }]; #IO_L15N_T2_DQS_DOUT_CSO_B_14 Sch=led[11]
|
||||
set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { LED[12] }]; #IO_L16P_T2_CSI_B_14 Sch=led[12]
|
||||
set_property -dict { PACKAGE_PIN V14 IOSTANDARD LVCMOS33 } [get_ports { LED[13] }]; #IO_L22N_T3_A04_D20_14 Sch=led[13]
|
||||
set_property -dict { PACKAGE_PIN V12 IOSTANDARD LVCMOS33 } [get_ports { LED[14] }]; #IO_L20N_T3_A07_D23_14 Sch=led[14]
|
||||
set_property -dict { PACKAGE_PIN V11 IOSTANDARD LVCMOS33 } [get_ports { LED[15] }]; #IO_L21N_T3_DQS_A06_D22_14 Sch=led[15]
|
||||
|
||||
## 7 segment display
|
||||
set_property -dict { PACKAGE_PIN T10 IOSTANDARD LVCMOS33 } [get_ports { CA }]; #IO_L24N_T3_A00_D16_14 Sch=ca
|
||||
set_property -dict { PACKAGE_PIN R10 IOSTANDARD LVCMOS33 } [get_ports { CB }]; #IO_25_14 Sch=cb
|
||||
set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { CC }]; #IO_25_15 Sch=cc
|
||||
set_property -dict { PACKAGE_PIN K13 IOSTANDARD LVCMOS33 } [get_ports { CD }]; #IO_L17P_T2_A26_15 Sch=cd
|
||||
set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33 } [get_ports { CE }]; #IO_L13P_T2_MRCC_14 Sch=ce
|
||||
set_property -dict { PACKAGE_PIN T11 IOSTANDARD LVCMOS33 } [get_ports { CF }]; #IO_L19P_T3_A10_D26_14 Sch=cf
|
||||
set_property -dict { PACKAGE_PIN L18 IOSTANDARD LVCMOS33 } [get_ports { CG }]; #IO_L4P_T0_D04_14 Sch=cg
|
||||
# set_property -dict { PACKAGE_PIN H15 IOSTANDARD LVCMOS33 } [get_ports { DP }]; #IO_L19N_T3_A21_VREF_15 Sch=dp
|
||||
set_property -dict { PACKAGE_PIN J17 IOSTANDARD LVCMOS33 } [get_ports { AN[0] }]; #IO_L23P_T3_FOE_B_15 Sch=an[0]
|
||||
set_property -dict { PACKAGE_PIN J18 IOSTANDARD LVCMOS33 } [get_ports { AN[1] }]; #IO_L23N_T3_FWE_B_15 Sch=an[1]
|
||||
set_property -dict { PACKAGE_PIN T9 IOSTANDARD LVCMOS33 } [get_ports { AN[2] }]; #IO_L24P_T3_A01_D17_14 Sch=an[2]
|
||||
set_property -dict { PACKAGE_PIN J14 IOSTANDARD LVCMOS33 } [get_ports { AN[3] }]; #IO_L19P_T3_A22_15 Sch=an[3]
|
||||
set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { AN[4] }]; #IO_L8N_T1_D12_14 Sch=an[4]
|
||||
set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { AN[5] }]; #IO_L14P_T2_SRCC_14 Sch=an[5]
|
||||
set_property -dict { PACKAGE_PIN K2 IOSTANDARD LVCMOS33 } [get_ports { AN[6] }]; #IO_L23P_T3_35 Sch=an[6]
|
||||
set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { AN[7] }]; #IO_L23N_T3_A02_D18_14 Sch=an[7]
|
||||
|
||||
## Buttons
|
||||
set_property -dict { PACKAGE_PIN C12 IOSTANDARD LVCMOS33 } [get_ports { resetn }]; #IO_L3P_T0_DQS_AD1P_15 Sch=cpu_resetn
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
После выполнения имплементации, нетлист и схема остаются неизменными, однако использованные для реализации схемы примитивы получают свой "адрес" внутри ПЛИС:
|
||||
|
||||

|
||||
|
||||
Теперь, мы можем посмотреть на "внутренности" нашей ПЛИС `xc7a100tcsg324-1` и то, как через её примитивы будет реализована наша схема. Для этого, необходимо отрыть имплементированное устройство: `Implementation -> Open implemented design`. Откроется следующее окно:
|
||||
|
||||

|
||||
|
||||
Может показаться очень страшным и непонятным, но это содержимое ПЛИС. Просто из-за огромного количества содержащихся в ней примитивов, она показана в таком масштабе, что все сливается в один цветной ковер. Большая часть этого окна неактивна (показана в темно-синих тонах) и это нормально, ведь мы реализовали крошечную цифровую схему, она и не должна занимать значительное количество ресурсов ПЛИС.
|
||||
|
||||
Нас интересует "[бледно-голубая точка](https://ru.wikipedia.org/wiki/Pale_Blue_Dot)", расположенная в нижнем левом углу прямоугольника `X0Y1` (выделено красным). Если отмасштабировать эту зону, мы найдем используемый нами LUT:
|
||||
|
||||

|
||||
|
||||
Кроме того, если поиграться со свойствами этого примитива, мы сможем найти нашу таблицу истинности, инициализирующую этот примитив.
|
||||
|
||||
## Generate Bitstream
|
||||
|
||||
После того, как САПР определил конкретные примитивы, их режим работы, и пути сигнала между ними, необходимо создать двоичный файл (**bitstream**), который позволит сконфигурировать ПЛИС необходимым нам образом.
|
||||
Получив этот файл, остается запрограммировать ПЛИС, после чего она воплотит разработанное устройство.
|
||||
|
||||
## Выводы
|
||||
|
||||
Таким образом, маршрут перехода от HDL-описания устройства до его реализации в ПЛИС выглядит следующим образом:
|
||||
|
||||
1. Сперва происходит анализ HDL-описания. В ходе этого анализа выявляются простейшие структуры: регистры, мультиплексоры, вычислительные блоки (сложения/умножения/сдвига и т.п.). Строится граф схемы, построенной с помощью этих структур (**нетлист**). Данный нетлист платформонезависим, т.е. не привязан к конкретной ПЛИС.
|
||||
2. После происходит этап синтеза нетлиста, полученного на предыдущем этапе в нетлист, использующий имеющиеся ресурсы конкретной ПЛИС. Все, использовавшиеся на предыдущем этапе структуры (регистры, мультиплексоры и прочие блоки) реализуются через примитивы ПЛИС (LUT-ы, D-триггеры, блоки сложения и т.п.).
|
||||
3. Затем происходит этап размещения схемы внутри ПЛИС: если на предыдущем этапе часть схемы была реализована через LUT, то на этом этапе решается **какой именно** LUT будет использован. Область допустимых решений по этому вопросу сужается путем наложения **ограничений** (**constraints**).
|
||||
4. После размещения остается только сгенерировать двоичный файл (**bitstream**), который во время прошивки сконфигурирует ПЛИС на реализацию нашей схемы.
|
@@ -1,17 +1,19 @@
|
||||
# Основа работы с Vivado
|
||||
|
||||
Цикл лабораторных работ создан, чтобы вы могли на практике отработать полученные знания по архитектурам процессорных систем, увидеть "изнутри", как "бегают нолики и единицы", подобно тому, как они бегают и в ваших компьютерах.
|
||||
Для эффективного погружения в лабораторные работы используется САПР **Vivado**. Это довольно сложный инструмент, на одно только осваивание которого требуется порядочное количество времени.
|
||||
Дабы сократить порог вхождения в освоение этого инструмента, был написан ряд материалов по описанию базовых сценариев использования, который представлен в данной папке.
|
||||
Цикл лабораторных работ создан, чтобы вы могли на практике отработать полученные знания по архитектурам процессорных систем, увидеть "изнутри", как "бегают нолики и единицы", подобно тому, как они бегают и в ваших компьютерах.
|
||||
|
||||
Для эффективного погружения в лабораторные работы используется САПР **Vivado**. Это довольно сложный инструмент, на одно только осваивание которого требуется порядочное количество времени.
|
||||
|
||||
Дабы сократить порог вхождения в освоение этого инструмента, был написан ряд материалов по описанию базовых сценариев использования, который представлен в данной папке.
|
||||
|
||||
Здесь находятся инструкции о том как:
|
||||
|
||||
1. [Установить Vivado](Install%20Vivado.md)
|
||||
2. [Создать демо-проект под отладочный стенд Nexys-7](Vivado%20trainer.md)
|
||||
3. [Загрузить сделанную лабу в ПЛИС](Program%20nexys%20a7.md)
|
||||
4. [Понять структуру папок в проекте Vivado](Folder%20Structure%20In%20The%20Project.md)
|
||||
5. [Открыть логическую схему написанного вами модуля](How%20to%20open%20a%20schematic.md)
|
||||
6. [Запустить симуляцию](Run%20Simulation.md)
|
||||
7. [Разобраться с ошибками, при попытке открыть схему / запустить симуляцию](Elaboration%20failed.md)
|
||||
8. [Находить и исправлять ошибки дизайна, найденные тестовым окружением](Debug%20manual.md)
|
||||
9. [Добавить заголовочный файл в проект Vivado](Verilog%20Header.md)
|
||||
10. [Понять как работают этапы элаборации/синтеза/имплементации](Implementation%20steps.md)
|
||||
1. [установить Vivado](Install%20Vivado.md);
|
||||
2. [создать демо-проект под отладочный стенд Nexys-7](Vivado%20trainer.md);
|
||||
3. [загрузить сделанную лабу в ПЛИС](Program%20nexys%20a7.md);
|
||||
4. [разобраться в структуре папок проекта Vivado](Folder%20Structure%20In%20The%20Project.md);
|
||||
5. [открыть логическую схему написанного вами модуля](How%20to%20open%20a%20schematic.md);
|
||||
6. [запустить симуляцию](Run%20Simulation.md);
|
||||
7. [разобраться с ошибками, при попытке открыть схему / запустить симуляцию](Elaboration%20failed.md);
|
||||
8. [находить и исправлять ошибки дизайна, найденные тестовым окружением](Debug%20manual.md);
|
||||
9. [добавить заголовочный файл в проект Vivado](Verilog%20Header.md).
|
||||
|
Reference in New Issue
Block a user