Обновление введения

This commit is contained in:
Andrei Solodovnikov
2024-06-20 11:52:23 +03:00
parent e0c6df9f66
commit c5bfa29663
19 changed files with 191 additions and 150 deletions

View File

@@ -2,22 +2,32 @@
Для того, чтобы описанное на **языке описания аппаратуры** устройство было реализовано в ПЛИС, необходимо выполнить несколько этапов:
1. Предобработку (elaboration)
2. Синтез (synthesis)
3. Внедрение (implementation)
4. Создание двоичного файла конфигурации (generate bitstream)
1. Elaboration
2. Synthesis
3. Implementation
4. Bitstream generation
Остановимся на каждом шаге подробнее:
В русскоязычной литературе не сложилось устоявшихся терминов для этапов 1 и 3, но **elaboration** можно назвать как "**предобработку**" или "**развертывание**", а **implementation** как "**реализацию**" или "**построение**".
Этапы 2 и 4 переводятся дословно: **синтез** и "**генерация двоичного файла конфигурации** (**битстрима**)".
## Предобработка
Более того, граница между этапами весьма условна и в зависимости от используемой **системы автоматизированного проектирования** (**САПР**), задачи, выполняемые на различных этапах могут перетекать из одного в другой. Описание этапов будет даваться для маршрута проектирования под ПЛИС, однако, с некоторыми оговорками, эти же этапы используются и при проектировании сверхбольших интегральных схем (СБИС).
На этапе предобработки, САПР считывает HDL-описание вашего устройства, производит подстановку значений параметров и блоков generate, устанавливает разрядности сигналов и строит иерархию модулей устройства. Затем, ставит в соответствие отдельным участкам кода соответствующие абстрактные элементы: логические вентили, мультиплексоры, элементы памяти и т.п. Кроме того, производится анализ и оптимизация схемы, например, если какая-то часть логики в конечном итоге не связана ни с одним из выходных сигналов, эта часть логики будет удалена[[1]](https://support.xilinx.com/s/question/0D52E00006iHshoSAC/what-exactly-is-elaborating-a-design?language=en_US).
Итогом предобработки является так называемая **топология межсоединений** (в быту называемая словом **нетлист**). **Нетлист** — это представление цифровой схемы в виде **графа**, где каждый элемент схемы является **узлом**, а **цепи**, соединяющие эти элементы являются ребрами. Нетлист может храниться как в виде каких-то внутренних файлов САПР-а (так хранится нетлист этапа **предобработки**), так и в виде **HDL**-файла, описывающего экземпляры примитивов и связи между ними. Рассмотрим этап предобработки и термин нетлиста на примере.
Остановимся на каждом шаге подробнее.
## Elaboration
На этапе предобработки, САПР разбирает и анализирует HDL-описание вашего устройства, проверяет его на наличие синтаксических ошибок, производит подстановку значений параметров и блоков `generate`, устанавливает разрядности сигналов и строит иерархию модулей устройства.
Затем, ставит в соответствие отдельным участкам кода соответствующие абстрактные элементы: логические вентили, мультиплексоры, элементы памяти и т.п. Кроме того, производится анализ и оптимизация схемы, например, если какая-то часть логики в конечном итоге не связана ни с одним из выходных сигналов, эта часть логики будет удалена[[1]](https://support.xilinx.com/s/question/0D52E00006iHshoSAC/what-exactly-is-elaborating-a-design?language=en_US).
Итогом предобработки является так называемая **топология межсоединений** (в быту называемая словом **нетлист**). **Нетлист** — это представление цифровой схемы в виде **графа**, где каждый элемент схемы является вершиной графа, а **цепи**, соединяющие эти элементы являются его ребрами. Нетлист может храниться как в виде каких-то внутренних файлов САПР-а (так хранится нетлист этапа **предобработки**), так и в виде **HDL**-файла, описывающего экземпляры примитивов и связи между ними. Рассмотрим этап предобработки и термин нетлиста на примере.
Допустим, мы хотим реализовать следующую цифровую схему:
![../.pic/Introduction/Implementation%20steps/fig_01.drawio.svg](../.pic/Introduction/Implementation%20steps/fig_01.drawio.svg)
_Рисунок 1. Пример простой цифровой схемы._
Её можно описать следующим **SystemVerilog**-кодом:
```SystemVerilog
@@ -40,13 +50,15 @@ endmodule
![../.pic/Introduction/Implementation%20steps/fig_02.png](../.pic/Introduction/Implementation%20steps/fig_02.png)
_Рисунок 2. Результат этапа предобработки._
В левом окне мы видим наш нетлист. В нижней части обозначены узлы графа (элементы **ab_i**, **res_i**, **xabc_i**, которые представляют собой **И**, **мультиплексор** и **Исключающее ИЛИ** соответственно. Имена этих элементов схожи с именами проводов, присваиванием которым мы создавали данные элементы)
В верхней части обозначены **ребра графа**, соединяющие элементы схемы. Это входы и выходы нашего модуля, а также созданные нами промежуточные цепи.
Справа вы видите **схематик****графическую схему**, построенную на основе данного **графа** (**нетлиста**).
## Синтез
## Synthesis
На шаге синтеза, САПР берет сгенерированную ранее цифровую схему и реализует элементы этой схемы через примитивы конкретной ПЛИС — в основном через логические ячейки, содержащие таблицы подстановки, полный однобитный сумматор и `D-триггер` (см. [как работает ПЛИС](../Introduction/How%20FPGA%20works.md)).
@@ -58,7 +70,9 @@ endmodule
![../.pic/Introduction/Implementation%20steps/fig_03.png](../.pic/Introduction/Implementation%20steps/fig_03.png)
Мы видим, что между входами/выходами схемы и её внутренней логикой появились новые примитивы — **буферы**. Они нужны, преобразовать уровень напряжения между ножками ПЛИС и внутренней логикой (условно говоря, на вход плис могут приходить сигналы с уровнем `3.3 В`, а внутри ПЛИС примитивы работают с сигналами уровня `1.2 В`).
_Рисунок 3. Результат этапа синтеза._
Мы видим, что между входами/выходами схемы и её внутренней логикой появились новые примитивы — **буферы**. Они нужны, чтобы преобразовать уровень напряжения между входами ПЛИС и внутренней логикой (условно говоря, на вход плис могут приходить сигналы с уровнем `3.3 В`, а внутри ПЛИС примитивы работают с сигналами уровня `1.2 В`).
Сама же логика, как мы и предполагали, свернулась в одну пятивходовую таблицу подстановки.
@@ -108,17 +122,17 @@ endmodule
Таким образом, мы и получаем искомое выражение `EQN=32'hAAAA3CCC`. Если с этой частью возникли сложности, попробуйте составить данную таблицу истинности (без вычисления самих результатов, а затем просмотрите логику быстрого вычисления результата).
</details>
## Внедрение
## Implementation
После построения новой схемы, где в качестве элементов используются ресурсы конкретной ПЛИС, происходит расчёт размещения этой схемы внутри ПЛИС: выбираются конкретные логические ячейки, происходит маршрутизация сигнала между этими ячейками. Например, реализация 32-битного сумматора с ускоренным переносом может потребовать 32 LUT-а и 8 примитивов вычисления быстрого переноса (`CARRY4`). Будет неразумно использовать для этого примитивы, разбросанные по всему кристаллу ПЛИС, ведь тогда придется выполнять сложную маршрутизацию сигнала, да и временные характеристики устройства так же пострадают (сигналу, идущему от предыдущего разряда к следующему придется проходить больший путь). Вместо этого, САПР будет пытаться разместить схему таким образом, чтобы использовались близлежащие примитивы ПЛИС, для получения оптимальных характеристик.
После получения нетлиста, где в качестве элементов используются ресурсы конкретной ПЛИС, происходит **размещение** этой схемы на элементы заданной ПЛИС: выбираются конкретные логические ячейки. Затем происходит **трассировка** (маршрутизация) связей между ними. Для этих процедур часто используется термин **place & route** (размещение и трассировка). Например, реализация 32-битного сумматора с ускоренным переносом может потребовать 32 LUT-а и 8 примитивов вычисления быстрого переноса (`CARRY4`). Будет неразумно использовать для этого примитивы, разбросанные по всему кристаллу ПЛИС, ведь тогда придётся выполнять сложную трассировку сигнала, да и временные характеристики устройства так же пострадают (сигналу, идущему от предыдущего разряда к следующему придётся проходить больший путь). Вместо этого, САПР будет пытаться разместить схему таким образом, чтобы использовались близлежащие примитивы ПЛИС, для получения оптимальных характеристик.
Что именно считается "оптимальным" зависит от двух вещей: настроек САПР и **ограничений** (**constraints**), наложенных на операцию внедрения. Ограничения сужают область возможных решений по размещению примитивов внутри ПЛИС под определенные характеристики (временны́е и физические). Например, можно сказать, внутри ПЛИС схема должна быть размещена таким образом, чтобы время прохождения по **критическому пути** не превышало `20ns`. Это временно́е ограничение. Также нужно сообщить САПР, к какой ножке ПЛИС необходимо подключить входы и выходы нашей схемы — это физическое ограничение.
Что именно считается "оптимальным" зависит от двух вещей: настроек САПР и **ограничений** (**constraints**), учитываемых при построении итоговой схемы в ПЛИС. Ограничения сужают область возможных решений по размещению примитивов внутри ПЛИС под определенные характеристики (временны́е и физические). Например, можно сказать, внутри ПЛИС схема должна быть размещена таким образом, чтобы время прохождения по **критическому пути** не превышало `20ns`. Это временно́е ограничение. Также нужно сообщить САПР, к какой ножке ПЛИС необходимо подключить входы и выходы нашей схемы — это физическое ограничение.
Ограничения описываются не на языке описания аппаратуры, вместо этого используются текстовые файлы специального формата, зависящего от конкретной САПР.
<details>
<summary>
Пример используемых ограничений для лабораторной по АЛУ.
Пример используемых ограничений для лабораторной по АЛУ под отладочную плату `Nexys A7-100T` (для упрощения восприятия, убраны старшие разряды переключателей и светодиодов, т.к. ограничения для каждого из разряда однотипны).
</summary>
Строки, начинающиеся с `#` являются комментариями.
@@ -138,57 +152,23 @@ create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports {CL
# 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
@@ -196,23 +176,29 @@ set_property -dict { PACKAGE_PIN C12 IOSTANDARD LVCMOS33 } [get_ports { resetn
</details>
После выполнения внедрения, нетлист и схема остаются неизменными, однако использованные для реализации схемы примитивы получают свой "адрес" внутри ПЛИС:
После выполнения построения, нетлист и сама цифровая схема остаются неизменными, однако использованные для реализации схемы примитивы получают свой "адрес" внутри ПЛИС:
![cell_add../.pic/Introduction/Implementation%20steps/fig_04.png](../.pic/Introduction/Implementation%20steps/fig_04.png)
Теперь, мы можем посмотреть на "внутренности" нашей ПЛИС `xc7a100tcsg324-1` и то, как через её примитивы будет реализована наша схема. Для этого необходимо отрыть внедрённое устройство: `Implementation -> Open implemented design`. Откроется следующее окно:
_Рисунок 4. "Адрес" конкретного LUT-а в ПЛИС._
Теперь, мы можем посмотреть на "внутренности" нашей ПЛИС `xc7a100tcsg324-1` и то, как через её примитивы будет реализована наша схема. Для этого необходимо открыть построенную схему: `Implementation -> Open implemented design`. Откроется следующее окно:
![../.pic/Introduction/Implementation%20steps/fig_05.png](../.pic/Introduction/Implementation%20steps/fig_05.png)
_Рисунок 5. Окно просмотра реализованного устройства._
Это содержимое ПЛИС. Просто из-за огромного количества содержащихся в ней примитивов, оно показана в таком масштабе, что все сливается в один цветной ковер. Большая часть этого окна неактивна (показана в темно-синих тонах) и это нормально, ведь мы реализовали крошечную цифровую схему, она и не должна занимать значительное количество ресурсов ПЛИС.
Нас интересует "[бледно-голубая точка](https://ru.wikipedia.org/wiki/Pale_Blue_Dot)", расположенная в нижнем левом углу прямоугольника `X0Y1` (выделено красным). Если отмасштабировать эту зону, мы найдем используемый нами LUT:
![../.pic/Introduction/Implementation%20steps/fig_06.png](../.pic/Introduction/Implementation%20steps/fig_06.png)
_Рисунок 6. Расположение выбранного LUT-а внутри ПЛИС._
Кроме того, если поиграться со свойствами этого примитива, мы сможем найти нашу таблицу истинности, инициализирующую этот примитив.
## Generate Bitstream
## Bitstream generation
После того, как САПР определил конкретные примитивы, их режим работы, и пути сигнала между ними, необходимо создать двоичный файл (**bitstream**), который позволит сконфигурировать ПЛИС необходимым нам образом.
Получив этот файл, остается запрограммировать ПЛИС, после чего она воплотит разработанное устройство.
@@ -221,11 +207,20 @@ set_property -dict { PACKAGE_PIN C12 IOSTANDARD LVCMOS33 } [get_ports { resetn
Таким образом, маршрут перехода от HDL-описания устройства до его реализации в ПЛИС выглядит следующим образом:
1. Сперва происходит анализ HDL-описания. В ходе этого анализа выявляются простейшие структуры: регистры, мультиплексоры, вычислительные блоки (сложения/умножения/сдвига и т.п.). Строится граф схемы, построенной с помощью этих структур (**нетлист**). Данный нетлист платформонезависим, т.е. не привязан к конкретной ПЛИС.
2. После происходит этап синтеза нетлиста, полученного на предыдущем этапе в нетлист, использующий имеющиеся ресурсы конкретной ПЛИС. Все, использовавшиеся на предыдущем этапе структуры (регистры, мультиплексоры и прочие блоки) реализуются через примитивы ПЛИС (LUT-ы, D-триггеры, блоки сложения и т.п.).
3. Затем происходит этап внедрения схемы внутрь ПЛИС: если на предыдущем этапе часть схемы была реализована через LUT, то на этом этапе решается **какой именно** LUT будет использован. Область допустимых решений по этому вопросу сужается путем наложения **ограничений** (**constraints**).
4. После размещения остается только сгенерировать двоичный файл (**bitstream**), который во время прошивки сконфигурирует ПЛИС на реализацию нашей схемы.
1. Сперва происходит этап **предобработки** (**elaboration**). В основные задачи этого этапа входит:
1. развертывание иерархии модулей: преобразование иерархической структуры проекта в плоскую, что облегчает дальнейшие этапы обработки;
2. проверка синтаксиса и семантики HDL-кода;
3. разрешение параметров и констант;
4. генерация промежуточного представления проекта, которое затем используется на следующих этапах.
Полученное промежуточное представление проекта использует абстрактные элементы (логические вентили, мультиплексоры, регистры), которые не привязаны к конкретной ПЛИС.
2. Затем выполняется этап **синтеза** (**synthesis**) **нетлиста**, который использует ресурсы конкретной ПЛИС. Все, использовавшиеся на предыдущем этапе структуры (регистры, мультиплексоры и прочие блоки) реализуются через примитивы ПЛИС (LUT-ы, D-триггеры, арифметические блоки и т.п.). Выполняется этап оптимизации логических сетей для минимизации занимаемой площади, уменьшения задержек и энергопотребления.
3. После выполняется этап **построения** (**implementation**) конечной цифровой схемы, выполняющий несколько подэтапов:
1. **Размещение** (**Placement**): определение конкретных местоположений для всех логических элементов в ПЛИС. Если на предыдущем этапе часть схемы была реализована через LUT, то на этом этапе решается **какой именно** LUT будет использован (имеется в виду не его тип, а какой из множества однотипных элементов будет выбран).
2. **Трассировка** (**Routing**): создание соединений между элементами в соответствии с нетлистом.
3. **Временной анализ** (Timing Analysis): Проверка временны́х характеристик для подтверждения, что все сигналы распространяются по цепи в допустимые временны́е рамки.
Область допустимых решений для этапов "**place & route**" сужается путем наложения **физических** и **временны́х** **ограничений** (**constraints**).
4. Последним этапом выполняется **генерация двоичного файла конфигурации** (**bitstream generation**), который во время прошивки сконфигурирует ПЛИС на реализацию построенной схемы.
## Список использованной литературы
1. [Форум Xilinx: what exactly is 'elaborating' a design?](https://support.xilinx.com/s/question/0D52E00006iHshoSAC/what-exactly-is-elaborating-a-design?language=en_US)
1. [Форум Xilinx: what exactly is 'elaborating' a design?](https://support.xilinx.com/s/question/0D52E00006iHshoSAC/what-exactly-is-elaborating-a-design?language=en_US)