mirror of
https://github.com/MPSU/APS.git
synced 2026-04-18 10:25:33 +00:00
Compare commits
15 Commits
eaa9c22f08
...
english_ve
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
047d4e65a6 | ||
|
|
ca0ae579f3 | ||
|
|
98db9682dd | ||
|
|
93a68c25eb | ||
|
|
efee883c35 | ||
|
|
54d19b7798 | ||
|
|
7ebed1ded9 | ||
|
|
0b9d7fb3bc | ||
|
|
145b19dccb | ||
|
|
3871c41cda | ||
|
|
c9fa090383 | ||
|
|
581ef9ff48 | ||
|
|
097863cf65 | ||
|
|
a78e4a8ab0 | ||
|
|
0168dc0d65 |
@@ -226,7 +226,3 @@ assign one_bit_result = bus1024[select];
|
||||
Как описать на языке SystemVerilog следующую схему?
|
||||
|
||||

|
||||
|
||||
## Список источников
|
||||
|
||||
1. [Мультиплексор (электроника)](https://ru.wikipedia.org/wiki/Мультиплексор_(электроника)).
|
||||
|
||||
@@ -1,281 +1,279 @@
|
||||
# Что такое ПЛИС и как она работает
|
||||
# What is an FPGA and How Does It Work
|
||||
|
||||
- [Что такое ПЛИС и как она работает](#Что-такое-ПЛИС-и-как-она-работает)
|
||||
- [История появления ПЛИС](#История-появления-ПЛИС)
|
||||
- [Цифровые схемы и логические вентили](#Цифровые-схемы-и-логические-вентили)
|
||||
- [Цифровые схемы](#Цифровые-схемы)
|
||||
- [Логические вентили](#Логические-вентили)
|
||||
- [Мультиплексоры](#Мультиплексоры)
|
||||
- [Программируемая память](#Программируемая-память)
|
||||
- [Таблицы подстановки (Look-Up Tables, LUTs)](#Таблицы-подстановки-look-up-tables-luts)
|
||||
- [D-триггеры](#d-триггеры)
|
||||
- [Арифметика](#Арифметика)
|
||||
- [Логические блоки](#Логические-блоки)
|
||||
- [Сеть межсоединений](#Сеть-межсоединений)
|
||||
- [Итоги главы](#Итоги-главы)
|
||||
- [Список источников](#Список-источников)
|
||||
- [What is an FPGA and How Does It Work](#what-is-an-fpga-and-how-does-it-work)
|
||||
- [History of FPGAs](#history-of-fpgas)
|
||||
- [Digital Circuits and Logic Gates](#digital-circuits-and-logic-gates)
|
||||
- [Digital Circuits](#digital-circuits)
|
||||
- [Logic Gates](#logic-gates)
|
||||
- [Multiplexers](#multiplexers)
|
||||
- [Programmable Memory](#programmable-memory)
|
||||
- [Look-Up Tables (LUTs)](#look-up-tables-luts)
|
||||
- [D Flip-Flops](#d-flip-flops)
|
||||
- [Arithmetic](#arithmetic)
|
||||
- [Logic Blocks](#logic-blocks)
|
||||
- [Interconnect Network](#interconnect-network)
|
||||
- [Chapter Summary](#chapter-summary)
|
||||
- [References](#references)
|
||||
|
||||
> Параграфы "Цифровые схемы и логические вентили" и "Таблицы подстановки" во многом используют материалы статьи "[How Does an FPGA Work?[1]](https://learn.sparkfun.com/tutorials/how-does-an-fpga-work/all)" за авторством `Alchitry, Ell C`, распространяемой по лицензии [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/).
|
||||
> The sections "Digital Circuits and Logic Gates" and "Look-Up Tables" draw heavily from the article "[How Does an FPGA Work?[1]](https://learn.sparkfun.com/tutorials/how-does-an-fpga-work/all)" by `Alchitry, Ell C`, distributed under the [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) license.
|
||||
|
||||
## История появления ПЛИС
|
||||
## History of FPGAs
|
||||
|
||||
До появления интегральных схем электронные устройства строились на базе вакуумных ламп, которые выполняли функции усиления и переключения. Эти лампы были громоздкими, энергозатратными и недолговечными. Затем их заменили на транзисторы, которые стали основой современных электронных схем. Поначалу транзисторы, как и лампы, использовались в виде отдельных компонентов, и схемы собирались из них, как модель из кубиков Lego. В случае ошибки её можно было исправить ручной корректировкой соединений между элементами, подобно исправлению ошибки при сборке модели Lego.
|
||||
Before integrated circuits existed, electronic devices were built using vacuum tubes, which performed amplification and switching functions. These tubes were bulky, power-hungry, and short-lived. They were later replaced by transistors, which became the foundation of modern electronic circuits. Initially, transistors were used as discrete components just like tubes, and circuits were assembled from them like a Lego model. If a mistake was made, it could be corrected by manually reworking the connections between components, much like fixing an error when building a Lego model.
|
||||
|
||||
С развитием технологий произошла миниатюризация транзисторов, что позволило разместить их вместе с соединениями на одном кристалле. Так появились интегральные схемы — электронные схемы, выполненные на полупроводниковой подложке и заключённые в неразборный корпус. Этот переход стал революционным шагом в развитии электроники, открыв путь к созданию компактных и производительных устройств.
|
||||
As technology advanced, transistors were miniaturized, making it possible to place them together with their interconnections on a single die. This gave rise to integrated circuits — electronic circuits fabricated on a semiconductor substrate and enclosed in a sealed package. This transition was a revolutionary step in the development of electronics, paving the way for compact and high-performance devices.
|
||||
|
||||
В большинстве случаев, исправить ошибку, допущенную при разработке и изготовлении интегральной схемы, невозможно. С учетом того, что изготовление прототипа интегральной схемы является долгим и затратным мероприятием (от десятков тысяч до миллионов долларов), возникла необходимость в гибком, быстром и дешёвом способе изготовления прототипа, и проверки на нём схемы до её изготовления. Так появились **программируемые логические интегральные схемы** (**ПЛИС**). В связи с повсеместным использованием англоязычной литературы, имеет смысл дать и англоязычное название этого класса устройств: **programmable logic devices** (**PLD**).
|
||||
In most cases, it is impossible to correct a mistake made during the design and manufacture of an integrated circuit. Given that fabricating a prototype integrated circuit is a lengthy and expensive process (costing tens of thousands to millions of dollars), there arose a need for a flexible, fast, and inexpensive way to prototype and verify a circuit before committing to fabrication. This is how **programmable logic devices** (**PLDs**) came about.
|
||||
It should be noted that this book mainly focuses on a specific type of PLD known as an FPGA (field-programmable gate array).
|
||||
|
||||
Стоит оговориться, что в данной книге под термином ПЛИС будет подразумеваться конкретный тип программируемых схем: **FPGA** (**field-programmable gate array**, **программируемая пользователем вентильная матрица**, **ППВМ**).
|
||||
An FPGA contains a finite set of basic building blocks (primitives), primitive interconnect blocks, and input/output blocks. By applying a specific set of configuration data to an FPGA (**programming** it), the primitives, their interconnections with each other, and with the I/O blocks can be configured to implement a desired digital circuit. The advantage of an FPGA is that if an error is found in a prototype implemented on the FPGA, the digital circuit can be corrected and the FPGA reprogrammed.
|
||||
|
||||
ПЛИС содержит некоторое конечное множество базовых блоков (примитивов), блоки межсоединений примитивов и блоки ввода-вывода. Подав определенный набор воздействий на ПЛИС (**запрограммировав** её), можно настроить примитивы, их межсоединения между собой и блоками ввода-вывода, чтобы получить требуемую цифровую схему. Удобство ПЛИС заключается в том, что в случае обнаружения ошибки на прототипе, исполненном в ПЛИС, вы можете исправить свою цифровую схему и повторно запрограммировать ПЛИС.
|
||||
In addition, FPGAs can be used effectively not only as a low-cost prototyping tool, but also as the final implementation vehicle for low-volume products (it is cheaper to buy and program an off-the-shelf batch of FPGAs than to fabricate a custom batch of chips).
|
||||
|
||||
Кроме того, эффективно использовать ПЛИС не как средство дешевого прототипирования, но и как средство реализации конечного продукта в случае малого тиража (дешевле купить и запрограммировать готовую партию ПЛИС, чем изготовить партию собственных микросхем).
|
||||
Let us take a closer look at what this device is and how it works internally, but first we need to cover some basics of digital circuits and logic gates.
|
||||
|
||||
Давайте разберемся, что же это за устройство и как оно работает изнутри, но перед этим необходимо провести ликбез по цифровым схемам и логическим вентилям.
|
||||
## Digital Circuits and Logic Gates
|
||||
|
||||
## Цифровые схемы и логические вентили
|
||||
### Digital Circuits
|
||||
|
||||
### Цифровые схемы
|
||||
A **digital circuit** is an **abstract model** of computation that operates on two discrete states, commonly denoted as `0` and `1`. It is important to understand that these states are not tied to specific physical quantities such as voltage in an electrical circuit. Instead, they represent generalized logical values that can be implemented on any technology capable of distinguishing two discrete states.
|
||||
|
||||
**Цифровая схема** — это **абстрактная модель** вычислений, которая оперирует двумя дискретными состояниями, обычно обозначаемыми как `0` и `1`. Важно понимать, что эти состояния не привязаны к конкретным физическим величинам, таким как напряжение в электрической цепи. Вместо этого они представляют собой обобщенные логические значения, которые могут быть реализованы на любой технологии, способной различать два дискретных состояния.
|
||||
Thanks to this abstraction, digital circuits can be implemented not only using traditional electronic components, but also on entirely different platforms — for example, using [pneumatic systems](https://habr.com/ru/companies/ruvds/articles/692236/), [cardboard and marbles](https://habr.com/ru/articles/399391/), [redstone dust](https://minecraft.fandom.com/wiki/Tutorials/Redstone_computers) in Minecraft, or even through human interaction, as described in Liu Cixin's novel "The Three-Body Problem" (the efficiency of such implementations is another matter entirely). The core idea is that a digital circuit is decoupled from its physical implementation, focusing solely on the logic of interactions between the states `0` and `1`, which makes it universal and technology-independent.
|
||||
|
||||
Благодаря этой абстракции цифровые схемы могут быть реализованы не только с помощью традиционных электронных компонентов, но и на совершенно иных платформах, например на [пневматических системах](https://habr.com/ru/companies/ruvds/articles/692236/), [из картона и шариков](https://habr.com/ru/articles/399391/), [красной пыли](https://minecraft.fandom.com/wiki/Tutorials/Redstone_computers) в игре Майнкрафт или даже с использованием человеческого взаимодействия, подобно тому, как это описано в романе Лю Цысиня "Задача трёх тел" (эффективность подобных схем — это уже другой вопрос). Основная идея заключается в том, что цифровая схема отвязывается от физической реализации, фокусируясь лишь на логике взаимодействия состояний `0` и `1`, что делает её универсальной и независимой от конкретной технологии.
|
||||
Of course, when designing efficient digital circuits, the underlying technology must be taken into account.
|
||||
|
||||
Разумеется, при проектировании эффективных цифровых схем необходимо оглядываться на технологию, по которой эти схемы будут работать.
|
||||
In electronics, the word "digital" describes circuits that abstract away from continuous (analog) voltage values, using only two discrete values: `0` and `1`. At this level of abstraction, we are not concerned with specific voltage levels or their thresholds, which allows us to design circuits in an idealized world where voltage can have only two values: `0` and `1`. Ensuring these conditions is the responsibility of the basic building blocks from which digital circuits are constructed.
|
||||
|
||||
В электронике словом "цифровая" описывают схемы, которые абстрагируются от непрерывных (аналоговых) значений напряжений, вместо этого используются только два дискретных значения: `0` и `1`. На данном уровне абстракции нас не интересуют конкретные значения напряжений и пороги этих значений, что позволяет нам разрабатывать схему в идеальном мире, где у напряжения может быть всего два значения: `0` и `1`. А обеспечением этих условий будут заниматься базовые блоки, из которых мы будем строить цифровые схемы.
|
||||
These basic building blocks are called **logic gates**.
|
||||
|
||||
Эти базовые блоки называются **логическими вентилями**.
|
||||
### Logic Gates
|
||||
|
||||
### Логические вентили
|
||||
There are many types of logic gates; we will consider four of them: **AND**, **OR**, **XOR**, and **NOT**. Each of these elements accepts a **digital value** as input (see [**Digital Circuits**](#digital-circuits)), performs a specific **logical function** on its inputs, and produces the result of that function as a **digital value** on its output.
|
||||
|
||||
Существует множество логических вентилей, мы рассмотрим четыре из них: **И**, **ИЛИ**, **Исключающее ИЛИ**, **НЕ**. Каждый из этих элементов принимает на вход **цифровое значение** (см. [**цифровая схема**](#Цифровые-схемы)), выполняет определенную **логическую функцию** над входами и подает на выход результат этой функции в виде **цифрового значения**.
|
||||
The logic gates in _Figs. 1–4_ are illustrated using standard schematic symbols from two standards: **ANSI** and **GOST**. Since the ANSI variant is widely used in the literature, it will be used throughout this book.
|
||||
|
||||
Логические вентили на _рис. 1-4_ иллюстрируются условными графическими обозначениями (**УГО**), взятыми из двух стандартов: **ANSI** и **ГОСТ**. Ввиду повсеместного использования в литературе первого варианта, в дальнейшем в книге будет использован он.
|
||||
|
||||
Логический вентиль **И** принимает два входа и выдает на выход значение `1` только в том случае, если оба входа равны `1`. Если хотя бы один из входов `0`, то на выходе будет `0`. На схемах логический вентиль **И** отображается следующим образом:
|
||||
The **AND** gate takes two inputs and outputs a value of `1` only when both inputs are `1`. If at least one input is `0`, the output is `0`. The **AND** gate is represented on schematics as follows:
|
||||
|
||||

|
||||
|
||||
_Рисунок 1. УГО логического вентиля **И**._
|
||||
_Figure 1. Schematic symbol of the **AND** gate._
|
||||
|
||||
Логический вентиль **ИЛИ** принимает два входа и выдает на выход значение `1` в случае, если хотя бы один из входов равен `1`. Если оба входа равны `0`, то на выходе будет `0`. На схемах логический вентиль **ИЛИ** отображается следующим образом:
|
||||
The **OR** gate takes two inputs and outputs a value of `1` if at least one input equals `1`. If both inputs are `0`, the output is `0`. The **OR** gate is represented on schematics as follows:
|
||||
|
||||

|
||||
|
||||
_Рисунок 2. УГО логического вентиля **ИЛИ**._
|
||||
_Figure 2. Schematic symbol of the **OR** gate._
|
||||
|
||||
Логический вентиль **Исключающее ИЛИ** принимает два входа и выдает на выход значение `1` в случае, если значения входов не равны между собой (один из них равен `1`, а другой `0`). Если значения входов равны между собой (оба равны `0` или оба равны `1`), то на выходе будет `0`. На схемах логический вентиль **Исключающее ИЛИ** отображается следующим образом:
|
||||
The **XOR** (Exclusive OR) gate takes two inputs and outputs a value of `1` when the input values are not equal to each other (one is `1` and the other is `0`). If both inputs are equal (both `0` or both `1`), the output is `0`. The **XOR** gate is represented on schematics as follows:
|
||||
|
||||

|
||||
|
||||
_Рисунок 3. УГО логического вентиля **Исключающее ИЛИ**._
|
||||
_Figure 3. Schematic symbol of the **XOR** gate._
|
||||
|
||||
Логический вентиль **НЕ** — самый простой. Он принимает один вход и подает на выход его инверсию. Если на вход пришло значение `0`, то на выходе будет `1`, если на вход пришло значение `1`, то на выходе будет `0`. Он обозначается на схемах следующим образом:
|
||||
The **NOT** gate is the simplest. It takes a single input and outputs its inverse. If the input is `0`, the output is `1`; if the input is `1`, the output is `0`. It is represented on schematics as follows:
|
||||
|
||||

|
||||
|
||||
_Рисунок 4. УГО логического вентиля **НЕ**._
|
||||
_Figure 4. Schematic symbol of the **NOT** gate._
|
||||
|
||||
Также существуют вариации базовых вентилей, такие как **И-НЕ**, **ИЛИ-НЕ**, **Исключающее ИЛИ-НЕ**, отличающиеся от исходных тем, что результат операции инвертирован относительно результата аналогичной операции без **-НЕ**.
|
||||
There are also variations of the basic gates, such as **NAND**, **NOR**, and **XNOR**, which differ from their base counterparts in that the result of the operation is inverted relative to the result of the corresponding operation without the inversion.
|
||||
|
||||
Логические вентили строятся из **транзисторов**. **Транзистор** — это элемент, который может пропускать/блокировать ток в зависимости от поданного напряжения на его управляющий вход.
|
||||
Logic gates can be built from **transistors**. A **transistor** is a device that can pass or block current depending on the voltage applied to its control terminal.
|
||||
|
||||
Особенностью современных интегральных схем является то, что они строятся на основе комплементарной (взаимодополняющей) пары транзисторов **P** и **N**-типа (**Комплементарная Металл-Оксид-Полупроводниковая**, **КМОП** логика). Для данного типа транзисторов оказалось эффективнее реализовать операции **И-НЕ** и **ИЛИ-НЕ**.
|
||||
A key feature of modern integrated circuits is that they are built using complementary (**P**- and **N**-type) transistor pairs — **Complementary Metal-Oxide-Semiconductor** (**CMOS**) logic. For this type of transistor, it turns out to be more efficient to implement **NAND** and **NOR** operations.
|
||||
|
||||
С точки зрения построения цифровых схем МОП-транзисторы (**P**- и **N**-типа) можно воспринимать как выключатели, которые замыкают или размыкают связь между двумя выводами. Разница между **P**- и **N** типами заключается в значении напряжения на управляющем входе, при котором транзистор "открыт" (вход и выход замкнуты) или "закрыт" (связь разорвана). _Рис. 5_ иллюстрирует данное различие.
|
||||
From the perspective of building digital circuits, MOS transistors (**P**- and **N**-type) can be thought of as switches that either connect or disconnect two terminals. The difference between **P**- and **N**-type transistors lies in the voltage at the control terminal that causes the transistor to be "on" (terminals connected) or "off" (connection broken). _Fig. 5_ illustrates this difference.
|
||||
|
||||
Выводы, между которыми образуется связь называются "**сток**" (**drain**, **d**) и "**исток**" (**source**, **s**), а управляющий вход — "**затвор**" (**gate**, **g**). Обратите внимание, что логический вентиль (**logic gate**) и затвор транзистора (просто **gate**) — это разные сущности!
|
||||
The terminals between which the connection is formed are called the "**drain**" (**d**) and "**source**" (**s**), and the control terminal is called the "**gate**" (**g**). Note that a **logic gate** and a transistor **gate** are different things!
|
||||
|
||||

|
||||
|
||||
_Рисунок 5. МОП-транзисторы P и N типа._
|
||||
_Figure 5. P-type and N-type MOS transistors._
|
||||
|
||||
На _рис. 6_ показан способ построения логических вентилей **И-НЕ**, **ИЛИ-НЕ** по **КМОП** технологии. Рассмотрим принцип работы вентиля **И-НЕ**.
|
||||
_Fig. 6_ shows how **NAND** and **NOR** gates are constructed using **CMOS** technology. Let us walk through the operation of the **NAND** gate.
|
||||
|
||||
Подача значения `1` на вход **А** или **B** открывает соответствующий этому входу n-канальный транзистор (обозначен на _рис. 6_ красным цветом) и закрывает дополняющий его (комплементарный ему) p-канальный транзистор (обозначен синим цветом). Подача на оба входа `1` закрывает оба p-канальных транзистора (верхняя часть схемы разомкнута, что для значения на выходе означает, что её будто и нет) и открывает оба n-канальных транзистора. В результате чего выход замыкается на "землю" (чёрный треугольник внизу схемы), что эквивалентно `0` в контексте цифровых значений.
|
||||
Applying a value of `1` to input **A** or **B** turns on the corresponding N-channel transistor (shown in red in _Fig. 6_) and turns off its complementary P-channel transistor (shown in blue). Applying `1` to both inputs turns off both P-channel transistors (the upper portion of the circuit is open, effectively removing it from the output) and turns on both N-channel transistors. As a result, the output is connected to "ground" (the black triangle at the bottom of the circuit), which is equivalent to `0` in terms of digital values.
|
||||
|
||||
В случае, если хотя бы на одном из входов **А** или **B** будет значение `0`, откроется один из параллельно соединенных p-канальных транзисторов (в то время как соединение с "землей" будет разорвано) и выход будет подключен к питанию (две перпендикулярные линии вверху схемы), что эквивалентно `1` в контексте цифровых значений.
|
||||
If at least one of the inputs **A** or **B** is `0`, one of the parallel-connected P-channel transistors turns on (while the connection to "ground" is broken), and the output is connected to the supply voltage (the two perpendicular lines at the top of the circuit), which is equivalent to `1` in terms of digital values.
|
||||
|
||||
Как вы видите, напряжение на выход подается от **источников постоянного питания** или **земли**, а не от входов вентиля, именно этим и обеспечивается постоянное обновление напряжения и устойчивость **цифровых схем** к помехам.
|
||||
As you can see, the output voltage is driven from the **power supply** or **ground**, not from the gate inputs themselves. This is precisely what ensures continuous voltage refresh and noise immunity of **digital circuits**.
|
||||
|
||||

|
||||
|
||||
_Рисунок 6. Схема логических вентилей **И-НЕ**, **ИЛИ-НЕ**, построенных на КМОП транзисторах._
|
||||
_Figure 6. Schematic of **NAND** and **NOR** gates built from CMOS transistors._
|
||||
|
||||
Как правило, при необходимости инвертировать вход или выход логического элемента на схеме, на нем рисуют кружок вместо добавления логического вентиля **НЕ** в том виде, котором он изображён на _рис. 4_. К примеру, логический элемент **И-НЕ** обозначают в виде, представленном на _рис. 6_.
|
||||
As a rule, when it is necessary to invert an input or output of a logic element in a schematic, a small circle is drawn on it rather than adding an explicit **NOT** gate as shown in _Fig. 4_. For example, the **NAND** gate is represented in the form shown in _Fig. 6_.
|
||||
|
||||
При желании, из логического элемента **И-НЕ** можно легко получить логический элемент **И** (как и элемент **ИЛИ** из **ИЛИ-НЕ**). Для этого необходимо поставить на выходе **И-НЕ** инвертор, собираемый из двух МОП-транзисторов по схеме, представленной на _рис. 7_.
|
||||
If desired, a **NAND** gate can easily be converted into an **AND** gate (just as a **NOR** gate can be converted into an **OR** gate) by placing an inverter at the output of **NAND**, built from two MOS transistors as shown in _Fig. 7_.
|
||||
|
||||

|
||||
|
||||
_Рисунок 7. Схема логического вентиля **НЕ**, построенного на КМОП транзисторах._
|
||||
_Figure 7. Schematic of a **NOT** gate built from CMOS transistors._
|
||||
|
||||
КМОП логика далеко не единственный способ построения цифровых элементов, ранее достаточно широко применялись другие варианты построения схем, например только на одном типе транзисторов. Однако наиболее эффективным оказалось использование именно комплементарных пар, и на сегодня такой подход для цифровых схем является доминирующим.
|
||||
CMOS logic is far from the only way to build digital elements; other approaches were widely used in the past, such as circuits built using only one type of transistor. However, the use of complementary pairs has proven to be the most efficient, and today this approach dominates digital circuit design.
|
||||
|
||||
Используя одни лишь описанные выше логические вентили можно построить **любую(!)** цифровую схему.
|
||||
Using only the logic gates described above, it is possible to build **any(!)** digital circuit.
|
||||
|
||||
Однако, при описании цифровых схем, некоторые цифровые блоки используются настолько часто, что для них ввели отдельные обозначения (**сумматоры**, **умножители**, **мультиплексоры** т.п.), используемые при описании более сложных схем. Рассмотрим один из фундаментальных строительных блоков в ПЛИС — **мультиплексор**.
|
||||
However, when describing digital circuits, certain digital blocks are used so frequently that dedicated symbols have been introduced for them — **adders**, **multipliers**, **multiplexers**, etc. — which are used when describing more complex circuits. Let us look at one of the fundamental building blocks in an FPGA: the **multiplexer**.
|
||||
|
||||
### Мультиплексоры
|
||||
### Multiplexers
|
||||
|
||||
Мультиплексор — это устройство, которое в зависимости от значения **управляющего сигнала** подает на выход значение одного из входных сигналов.
|
||||
A multiplexer is a device that routes one of its input signals to the output, depending on the value of a **select signal**.
|
||||
|
||||
УГО мультиплексора представлено на _рисунке 8_.
|
||||
The schematic symbol of a multiplexer is shown in _Figure 8_.
|
||||
|
||||

|
||||
|
||||
_Рисунок 8. Обозначение Мультиплексора._
|
||||
_Figure 8. Multiplexer symbol._
|
||||
|
||||
Символ `/` на линии `sel` указывает на то, что данный сигнал является многоразрядным, а число ниже указывает на то, что разрядность сигнала составляет 6 бит.
|
||||
The `/` symbol on the `sel` line indicates that this signal is multi-bit, and the number below specifies that the signal width is 6 bits.
|
||||
|
||||
Число входов мультиплексора может быть различным, но выход у него всегда один.
|
||||
A multiplexer can have any number of inputs, but always has exactly one output.
|
||||
|
||||
**Способ, которым кодируется значение управляющего сигнала может также различаться**. Простейшая цифровая схема мультиплексора получится, если использовать [**унитарное**](https://ru.wikipedia.org/wiki/Унитарный_код) (**one-hot**) кодирование. При таком кодировании, значение **многоразрядного** управляющего сигнала **всегда** содержит **ровно одну** `1`. Информация, которую несёт закодированный таким образом сигнал содержится в положении этой `1` внутри управляющего сигнала.
|
||||
**The way in which the select signal is encoded can also vary.** The simplest digital multiplexer circuit results from using [**one-hot**](https://en.wikipedia.org/wiki/One-hot) encoding. With this encoding, the value of the **multi-bit** select signal **always** contains **exactly one** `1`. The information carried by such an encoded signal is contained in the position of that `1` within the select signal.
|
||||
|
||||
Посмотрим, как можно реализовать мультиплексор с управляющим сигналом, использующим one-hot-кодирование, при помощи одних лишь логических вентилей **И**, **ИЛИ**:
|
||||
Let us see how a multiplexer with a one-hot-encoded select signal can be implemented using only **AND** and **OR** gates:
|
||||
|
||||

|
||||
|
||||
_Рисунок 9. Реализация мультиплексора, использующего one-hot кодирование._
|
||||
_Figure 9. Multiplexer implementation using one-hot encoding._
|
||||
|
||||
Если мы выставим значение управляющего сигнала, равное `000010`, означающее, что только **первый** бит этого сигнала (**счет ведется с нуля**) будет равен **единице** (`sel[1] = 1`), то увидим, что на один из входов каждого логического вентиля **И** будет подано значение `0`. Исключением будет логический вентиль **И** для входа `b`, на вход которого будет подано значение `1`. Это означает, что все логические вентили **И** (кроме первого, на который подается вход `b`) будут выдавать на выход `0` (см. [Логические вентили](#Логические-вентили)) вне зависимости от того, что было подано на входы a,c,d,e и f. Единственным входом, который будет влиять на работу схемы, окажется вход `b`. Когда он равен `1`, на выходе соответствующего логического вентиля **И** окажется значение `1`. Когда он равен `0` на выходе **И** окажется значение `0`. Иными словами, выход **И** будет повторять значение `b`.
|
||||
If we set the select signal to `000010`, meaning that only the **first** bit of this signal (**counting from zero**) equals **one** (`sel[1] = 1`), we can see that a value of `0` is applied to one input of each **AND** gate. The exception is the **AND** gate for input `b`, which receives a value of `1`. This means that all **AND** gates (except the one connected to input `b`) will output `0` (see [Logic Gates](#logic-gates)) regardless of what is applied to inputs a, c, d, e, and f. The only input that will affect the circuit's output is `b`. When it is `1`, the corresponding **AND** gate outputs `1`. When it is `0`, the **AND** gate outputs `0`. In other words, the **AND** gate's output mirrors the value of `b`.
|
||||
|
||||

|
||||
|
||||
_Рисунок 10. Реализация мультиплексора, использующего one-hot кодирование._
|
||||
_Figure 10. Multiplexer implementation using one-hot encoding._
|
||||
|
||||
Логический вентиль **ИЛИ** на данной схеме имеет больше двух входов. Подобный вентиль может быть создан в виде каскада логических вентилей **ИЛИ**:
|
||||
The **OR** gate in this circuit has more than two inputs. Such a gate can be constructed as a cascade of two-input **OR** gates:
|
||||
|
||||

|
||||
|
||||
_Рисунок 11. Реализация многоходового логического **ИЛИ**._
|
||||
_Figure 11. Multi-input **OR** gate implementation._
|
||||
|
||||
**Многовходовой вентиль ИЛИ** ведет себя ровно так же, как двухвходовой: он выдает на выход значение `1`, когда хотя бы один из входов равен `1`. В случае, если все входы равны `0`, на выход **ИЛИ** пойдет `0`.
|
||||
A **multi-input OR gate** behaves exactly like a two-input one: it outputs `1` when at least one input is `1`. If all inputs are `0`, the output is `0`.
|
||||
|
||||
Для нашей схемы мультиплексора гарантируется, что каждый вход **ИЛИ** кроме одного будет равняться `0` (поскольку выход каждого **И** кроме одного будет равен `0`). Это означает, что выход **многовходового ИЛИ** будет зависеть только от **одного** входа (в случае, когда `sel = 000010` — от входа `b`).
|
||||
In our multiplexer circuit, it is guaranteed that every input of the **OR** gate except one will be `0` (since every **AND** gate output except one will be `0`). This means the output of the **multi-input OR** gate depends on only **one** input (when `sel = 000010`, it depends on input `b`).
|
||||
|
||||

|
||||
|
||||
_Рисунок 12. Реализация мультиплексора, использующего one-hot кодирование._
|
||||
_Figure 12. Multiplexer implementation using one-hot encoding._
|
||||
|
||||
Меняя значение `sel`, мы можем управлять тем, какой из входов мультиплексора будет идти на его выход.
|
||||
By changing the value of `sel`, we can control which multiplexer input is routed to the output.
|
||||
|
||||
### Программируемая память
|
||||
### Programmable Memory
|
||||
|
||||
Из транзисторов можно построить не только логические элементы, но и элементы памяти. На рис. 13 представлена схема простейшей ячейки статической памяти, состоящей из транзистора и двух инверторов (т.е. суммарно состоящей из 5 транзисторов, поэтому она называется **5T** SRAM). Данная ячейка реализует 1 бит программируемой памяти, являвшейся одним из основных компонентов самой первой ПЛИС.
|
||||
Transistors can be used to build not only logic elements, but also memory elements. Fig. 13 shows a schematic of the simplest static memory cell, consisting of one transistor and two inverters (totaling 5 transistors, which is why it is called **5T** SRAM). This cell implements 1 bit of programmable memory and was one of the core components of the very first FPGA.
|
||||
|
||||

|
||||
|
||||
_Рисунок 13. Программируемая ячейка памяти ПЛИС Xilinx XC2064[[2, стр. 2-63](https://archive.org/details/programmablegate00xili/page/n93/mode/2up)]._
|
||||
_Figure 13. Programmable memory cell of the Xilinx XC2064 FPGA [[2, p. 2-63](https://archive.org/details/programmablegate00xili/page/n93/mode/2up)]._
|
||||
|
||||
Данная память представляет собой **бистабильную ячейку** — петлю из двух инверторов, в которых "заперто" хранимое значение. Дважды инвертированный сигнал совпадает по значению с исходным, при этом, проходя через каждый из инверторов, сигнал обновляет свое значение напряжения, что не позволяет ему угаснуть из-за сопротивления цепи.
|
||||
This memory is a **bistable cell** — a loop of two inverters in which the stored value is "latched". A signal inverted twice returns to its original value, and as it passes through each inverter, the signal's voltage level is refreshed, preventing it from decaying due to circuit resistance.
|
||||
|
||||
Для того чтобы поместить в бистабильную ячейку новое значение, к её входу подключается еще один транзистор, замыкающий или размыкающий её с напряжением питания/земли.
|
||||
To write a new value into the bistable cell, an additional transistor is connected to its input, which connects or disconnects it from the supply voltage or ground.
|
||||
|
||||
## Таблицы подстановки (Look-Up Tables, LUTs)
|
||||
## Look-Up Tables (LUTs)
|
||||
|
||||
Представьте мультиплексор с четырьмя входными сигналами и двухбитным управляющим сигналом (обратите внимание, что теперь это сигнал использует обычное двоичное кодирование). Но теперь, вместо того чтобы выставлять входные сигналы во внешний мир, давайте подключим их к программируемой памяти. Это означает, что мы можем "запрограммировать" каждый из входов на какое-то константное значение. Поместим то, что у нас получилось, в отдельный блок и вот, мы получили двухвходовую **Таблицу подстановки** (**Look-Up Tables**, далее **LUT**).
|
||||
Imagine a multiplexer with four input signals and a two-bit select signal (note that this signal now uses standard binary encoding). But instead of exposing the input signals to the outside world, let us connect them to programmable memory. This means we can "program" each input to hold a constant value. If we enclose the result in a separate block, we obtain a two-input **Look-Up Table** (**LUT**).
|
||||
|
||||

|
||||
|
||||
_Рисунок 14. Реализация таблицы подстановки (Look-Up Table, LUT)._
|
||||
_Figure 14. Look-Up Table (LUT) implementation._
|
||||
|
||||
Эти два входа **LUT** являются битами управляющего сигнала мультиплексора, спрятанного внутри **LUT**. Программируя входы мультиплексора (точнее, программируя память, к которой подключены входы мультиплексора), мы можем реализовать на базе **LUT** **любую(!)** логическую функцию, принимающую два входа и возвращающую один выход.
|
||||
The two inputs of the **LUT** are the bits of the select signal of the multiplexer hidden inside the **LUT**. By programming the multiplexer inputs (more precisely, by programming the memory to which the multiplexer inputs are connected), we can implement **any(!)** logical function with two inputs and one output on top of the **LUT**.
|
||||
|
||||
Допустим, мы хотим получить **логическое И**. Для этого, нам потребуется записать в память следующее содержимое:
|
||||
For example, suppose we want to implement **logical AND**. To do so, we need to write the following content into the memory:
|
||||
|
||||
|Адрес ({x, y}) | Значение (f)|
|
||||
|---------------|-------------|
|
||||
| Address ({x, y}) | Value (f) |
|
||||
|------------------|-----------|
|
||||
| 00 | 0 |
|
||||
| 01 | 0 |
|
||||
| 10 | 0 |
|
||||
| 11 | 1 |
|
||||
|
||||
Это простейший пример — обычно **LUT**-ы имеют больше входов, что позволяет им реализовывать более сложную логику.
|
||||
This is the simplest example — in practice, **LUT**s typically have more inputs, allowing them to implement more complex logic.
|
||||
|
||||
## D-триггеры
|
||||
## D Flip-Flops
|
||||
|
||||
Как вы уже поняли, используя неограниченное количество LUT-ов, вы можете построить цифровую схему, реализующую логическую функцию любой сложности. Однако цифровые схемы не ограничиваются реализацией одних только логических функций (цифровые схемы, реализующие логическую функцию, называются **комбинационными**, поскольку выход зависит только от комбинации входов). Например, так не построить цифровую схему, реализующую процессор. Для таких схем нужны элементы памяти. Заметим, что речь идет не о программируемой памяти, задавая значения которой мы управляем тем, какие логические функции будут реализовывать LUT-ы. Речь идет о ячейках памяти, которые будут использоваться логикой самой схемы.
|
||||
As you have already seen, using an unlimited number of LUTs, you can build a digital circuit that implements a logical function of any complexity. However, digital circuits are not limited to implementing logical functions only (circuits that implement logical functions are called **combinational circuits**, because the output depends only on the current combination of inputs). For example, a digital circuit implementing a processor cannot be built this way. Such circuits require memory elements. Note that we are not talking about the programmable memory used to configure the logic functions implemented by the LUTs — we are talking about memory cells used by the circuit's own logic.
|
||||
|
||||
Такой базовой ячейкой памяти является **D-триггер** (**D flip-flop**). Из D-триггеров можно собирать другие ячейки памяти, например **регистры** (а из регистров можно собрать **память с произвольным доступом** (**random access memory**, **RAM**)), **сдвиговые регистры** и т.п.
|
||||
The fundamental memory element is the **D flip-flop**. D flip-flops can be used to build other memory elements, such as **registers** (and registers can be used to build **random access memory** (**RAM**)), **shift registers**, and so on.
|
||||
|
||||
**D-триггер** — это цифровой элемент, способный хранить один бит информации. В базовом варианте у этого элемента есть два входа и один выход. Один из входов подает значение, которое будет записано в **D-триггер**, второй вход управляет записью (обычно он называется `clk` или `clock` и подключается к тактирующему синхроимпульсу схемы). Когда управляющий сигнал меняет своё значение с `0` на `1` (либо с `1` на `0`, зависит от схемы), в **D-триггер** записывается значение сигнала данных. Обычно, описывая **D-триггер**, говорится, что он строится из двух **триггеров-защелок** (**D-latch**), которые, в свою очередь, строятся из **RS-триггеров**. Однако в конечном итоге, все эти элементы могут быть построены на базе логических вентилей **И**/**ИЛИ**, **НЕ**:
|
||||
A **D flip-flop** is a digital element capable of storing one bit of information. In its basic form, it has two inputs and one output. One input receives the value to be stored in the **D flip-flop**; the other controls the write operation (typically called `clk` or `clock`, and connected to the circuit's clock signal). When the control signal transitions from `0` to `1` (or from `1` to `0`, depending on the design), the data signal's value is captured into the **D flip-flop**. It is commonly said that a **D flip-flop** is built from two **D latches**, which in turn are built from **SR latches**. Ultimately, however, all of these elements can be implemented using **AND**/**OR** and **NOT** gates:
|
||||
|
||||

|
||||
|
||||
_Рисунок 15. Реализация D-триггера._
|
||||
_Figure 15. D flip-flop implementation._
|
||||
|
||||
## Арифметика
|
||||
## Arithmetic
|
||||
|
||||
Помимо описанных выше блоков (мультиплексоров и построенных на их основе LUT-ов и регистров) выделяется еще один тип блоков, настолько часто используемый в цифровых схемах, что его заранее размещают в ПЛИС в больших количествах: это арифметические блоки. Эти блоки используются при сложении, вычитании, сравнении чисел, реализации счётчиков. В разных ПЛИС могут быть предустановлены разные блоки: где-то это может быть 1-битный сумматор, а где-то блок вычисления ускоренного переноса (`carry-chain`).
|
||||
In addition to the blocks described above (multiplexers and the LUTs and registers built on top of them), there is another type of block so frequently used in digital circuits that it is pre-placed in FPGAs in large quantities: **arithmetic blocks**. These blocks are used for addition, subtraction, comparison, and counter implementations. Different FPGAs may include different arithmetic primitives: some include a 1-bit adder, others a carry-chain block.
|
||||
|
||||
Все эти блоки могут быть реализованы через логические вентили, например так можно реализовать сумматор:
|
||||
All of these blocks can be implemented using logic gates. For example, here is how a full adder can be implemented:
|
||||
|
||||

|
||||
|
||||
_Рисунок 16. Реализация полного однобитного сумматора._
|
||||
_Figure 16. Full 1-bit adder implementation._
|
||||
|
||||
## Логические блоки
|
||||
## Logic Blocks
|
||||
|
||||
В предыдущих параграфах, были рассмотрены отдельные виды цифровых блоков: таблицы подстановок, регистры, арифметические блоки. Для удобства структурирования, эти блоки объединены в ПЛИС в виде **логических блоков**. Обычно, логические блоки современных ПЛИС состоят из **логических ячеек** (или **логических элементов**), но для простоты повествования, мы объединим все эти термины.
|
||||
|
||||
Логический блок может содержать одну или несколько **LUT**, **арифметический блок**, и один или несколько **D-триггеров**, которые соединены между собой некоторым количеством мультиплексоров. На _рисунке 17_ представлена схема того, как может выглядеть логический блок:
|
||||
The previous sections covered individual types of digital blocks: look-up tables, registers, and arithmetic blocks. For structural convenience, these blocks are grouped together inside an FPGA as **logic blocks**. Typically, logic blocks in modern FPGAs consist of **logic cells** (or **logic elements**), but for simplicity we will use these terms interchangeably.
|
||||
|
||||
A logic block can contain one or more **LUT**s, an **arithmetic block**, and one or more **D flip-flops**, connected to each other through a number of multiplexers. _Figure 17_ shows what a logic block may look like:
|
||||
|
||||

|
||||
|
||||
_Рисунок 17. Схема логической ячейки[[2]](https://en.wikipedia.org/wiki/Field-programmable_gate_array)._
|
||||
_Figure 17. Logic cell schematic [[2]](https://en.wikipedia.org/wiki/Field-programmable_gate_array)._
|
||||
|
||||
Логический блок представляет собой цепочку операций: `логическая функция, реализованная через LUT -> арифметическая операция -> Запись в D-триггер`. Каждый из мультиплексоров определяет то, будет ли пропущен какой-либо из этих этапов.
|
||||
Таким образом, конфигурируя логический блок, можно получить следующие вариации кусочка цифровой схемы:
|
||||
A logic block represents a chain of operations: `logical function implemented in LUT → arithmetic operation → write to D flip-flop`. Each multiplexer determines whether any of these stages is bypassed.
|
||||
By configuring a logic block, the following variations of a circuit fragment can be obtained:
|
||||
|
||||
1. Комбинационная схема (логическая функция, реализованная в LUT)
|
||||
2. Арифметическая операция
|
||||
3. Запись данных в D-триггер
|
||||
4. Комбинационная схема с записью результата в D-триггер
|
||||
5. Арифметическая операция с записью результата в D-триггер
|
||||
6. Комбинационная схема с последующей арифметической операцией
|
||||
7. Комбинационная схема с последующей арифметической операцией и записью в D-триггер
|
||||
1. Combinational circuit (logical function implemented in a LUT)
|
||||
2. Arithmetic operation
|
||||
3. Write data to a D flip-flop
|
||||
4. Combinational circuit with the result written to a D flip-flop
|
||||
5. Arithmetic operation with the result written to a D flip-flop
|
||||
6. Combinational circuit followed by an arithmetic operation
|
||||
7. Combinational circuit followed by an arithmetic operation and a write to a D flip-flop
|
||||
|
||||
На _рисунке 18_ приведён реальный пример использования логического блока в ПЛИС `xc7a100tcsg324-1` при реализации Арифметико-логического устройства (АЛУ), подключенного к периферии отладочной платы `Nexys-7`. На этом рисунке вы можете увидеть использование LUT-ов, арифметического блока (ускоренного расчета переноса), и одного из D-триггеров. D-триггеры, обозначенные серым цветом, не используются.
|
||||
_Figure 18_ shows a real example of logic block usage in the `xc7a100tcsg324-1` FPGA when implementing an Arithmetic Logic Unit (ALU) connected to the peripherals of the `Nexys-7` development board. In this figure, you can see the use of LUTs, an arithmetic block (carry-lookahead), and one of the D flip-flops. D flip-flops shown in grey are unused.
|
||||
|
||||

|
||||
|
||||
_Рисунок 18. Пример использования логической ячейки._
|
||||
_Figure 18. Example of logic cell usage._
|
||||
|
||||
Располагая большим наборов таких логических блоков, и имея возможность межсоединять их нужным вам образом, вы получаете широчайшие возможности по реализации практически любой цифровой схемы (ограничением является только ёмкость ПЛИС, т.е. количество подобных логических блоков, входов выходов и т.п.).
|
||||
With a large set of such logic blocks and the ability to interconnect them as needed, you have extensive capabilities for implementing virtually any digital circuit (the only limitation is the FPGA's capacity — i.e., the number of logic blocks, I/O pins, and so on).
|
||||
|
||||
Помимо логических блоков в ПЛИС есть и другие примитивы: **блочная память**, **блоки умножителей** и т.п.
|
||||
In addition to logic blocks, FPGAs also include other primitives: **block RAM**, **multiplier blocks**, and so on.
|
||||
|
||||
## Сеть межсоединений
|
||||
## Interconnect Network
|
||||
|
||||
Для того чтобы разобраться, как управлять межсоединением логических блоков, рассмотрим рис. 19, входящий в патент на ПЛИС[[4](https://patents.google.com/patent/US4870302A)].
|
||||
To understand how the interconnection of logic blocks is controlled, let us look at Fig. 19, taken from the FPGA patent [[4](https://patents.google.com/patent/US4870302A)].
|
||||
|
||||

|
||||
|
||||
_Рисунок 19. Содержимое ПЛИС в виде межсоединения логических блоков и блоков ввода-вывода[[5](http://www.righto.com/2020/09/reverse-engineering-first-fpga-chip.html)]._
|
||||
_Figure 19. FPGA contents showing the interconnection of logic blocks and I/O blocks [[5](http://www.righto.com/2020/09/reverse-engineering-first-fpga-chip.html)]._
|
||||
|
||||
Синим показано 9 логических блоков, желтым — 12 блоков ввода-вывода. Все эти блоки окружены **сетью межсоединений** (interconnect net), представляющей собой решётку из горизонтальных и вертикальных соединительных линий — межсоединений общего назначения (general purpose interconnect) [[2, 2-66](https://archive.org/details/programmablegate00xili/page/n97/mode/2up)].
|
||||
Nine logic blocks are shown in blue, and twelve I/O blocks in yellow. All of these blocks are surrounded by an **interconnect network**, which consists of a grid of horizontal and vertical wiring lines — the general purpose interconnect [[2, 2-66](https://archive.org/details/programmablegate00xili/page/n97/mode/2up)].
|
||||
|
||||
Косыми чертами в местах пересечения линий обозначены **программируемые точки межсоединений** (**programmable interconnect points**, **PIP**s), представляющие собой транзисторы, затвор которых подключен к программируемой памяти.
|
||||
The diagonal marks at line crossings represent **programmable interconnect points** (**PIPs**): transistors whose gates are connected to programmable memory.
|
||||
|
||||
Управляя значением в подключенной к затвору транзистора памяти, можно управлять тем, что из себя будет представлять транзистор в данной точке: разрыв, или цепь. А значит, можно удалять "лишние" участки сети, оставляя только используемые логические блоки, соединенные между собой.
|
||||
By controlling the value stored in the memory connected to a transistor's gate, it is possible to determine whether that transistor acts as an open connection or a closed switch at that point in the grid. This allows "unused" segments of the network to be removed, leaving only the routes needed to connect the logic blocks to each other.
|
||||
|
||||
## Итоги главы
|
||||
## Chapter Summary
|
||||
|
||||
1. Используя такие элементы, как **транзисторы**, можно собирать **логические вентили**: элементы **И**, **ИЛИ**, **НЕ** и т.п.
|
||||
2. Используя **логические вентили**, можно создавать схемы, реализующие как **логические функции** (**комбинационные схемы**), так и сложную логику с памятью (**последовательностные схемы**).
|
||||
3. Из логических вентилей строится и такая важная комбинационная схема, как **мультиплексор**: цифровой блок, который в зависимости от значения управляющего сигнала подаёт на выход один из входных сигналов.
|
||||
4. Кроме того, подключив вход бистабильной ячейки (представляющую собой петлю из двух инверторов) к транзистору, можно получить 1 бит **программируемой памяти**.
|
||||
5. Подключив входные сигналы мультиплексора к программируемой памяти, можно получить **Таблицу подстановок** (**Look-Up Table**, **LUT**), которая может реализовывать простейшие логические функции. LUT-ы позволяют заменить логические вентили И/ИЛИ/НЕ, и удобны тем, что их можно динамически изменять. Логические вентили в свою очередь исполняются на заводе и уже не могут быть изменены после создания.
|
||||
6. Из логических вентилей также можно собрать базовую ячейку памяти: **D-триггер**, и такую комбинационную схему как **полный 1-битный сумматор** (или любой другой часто используемый арифметический блок).
|
||||
7. Объединив LUT, арифметический блок и D-триггер получается структура в ПЛИС, которая называется **логический блок**.
|
||||
8. Логический блок (а также другие **примитивы**, такие как **блочная память** или **умножители**) — это множество блоков, которые заранее физически размещаются в кристалле ПЛИС, их количество строго определено конкретной ПЛИС и не может быть изменено.
|
||||
9. Подключая программируемую память к транзисторам, расположенных в узлах **сети межсоединений**, можно управлять расположением разрывов в сети, а значит можно оставить только маршрут, по которому сигнал пойдет туда, куда нам нужно (**трассировать сигнал**).
|
||||
10. **Конфигурируя примитивы** и **трассируя сигнал** между ними (см. п.4), можно получить **практически любую цифровую схему** (с учетом ограничения ёмкости ПЛИС).
|
||||
1. Using elements such as **transistors**, it is possible to build **logic gates**: **AND**, **OR**, **NOT**, and so on.
|
||||
2. Using **logic gates**, it is possible to create circuits that implement both **logical functions** (**combinational circuits**) and complex logic with memory (**sequential circuits**).
|
||||
3. Logic gates can also be used to build the important combinational circuit known as the **multiplexer**: a digital block that routes one of its input signals to the output based on the value of a select signal.
|
||||
4. Furthermore, by connecting the input of a bistable cell (a loop of two inverters) to a transistor, one bit of **programmable memory** can be obtained.
|
||||
5. By connecting the input signals of a multiplexer to programmable memory, a **Look-Up Table** (**LUT**) is obtained, which can implement simple logical functions. LUTs can replace AND/OR/NOT gates and have the advantage of being dynamically reconfigurable. Logic gates, by contrast, are fixed at fabrication and cannot be changed afterwards.
|
||||
6. Logic gates can also be used to build the basic memory element — the **D flip-flop** — and the combinational circuit known as the **full 1-bit adder** (or any other commonly used arithmetic block).
|
||||
7. Combining a LUT, an arithmetic block, and a D flip-flop yields the FPGA structure known as a **logic block**.
|
||||
8. A logic block (as well as other **primitives**, such as **block RAM** or **multipliers**) represents a set of blocks that are physically pre-placed in the FPGA die; their quantity is fixed by the specific FPGA and cannot be changed.
|
||||
9. By connecting programmable memory to transistors located at the nodes of the **interconnect network**, the placement of breaks in the network can be controlled, making it possible to leave only the routing paths that carry signals where they are needed (**signal routing**).
|
||||
10. By **configuring primitives** and **routing signals** between them (see item 4), **virtually any digital circuit** can be implemented (subject to the FPGA's capacity constraints).
|
||||
|
||||
## Список источников
|
||||
## References
|
||||
|
||||
1. Alchitry, Ell C / [How Does an FPGA Work?](https://learn.sparkfun.com/tutorials/how-does-an-fpga-work/all)
|
||||
2. Xilinx / [The Programmable Gate Array Data Book](https://archive.org/details/programmablegate00xili)
|
||||
|
||||
@@ -1,34 +1,31 @@
|
||||
# Этапы реализации проекта в ПЛИС
|
||||
# FPGA Implementation Steps
|
||||
|
||||
Для того, чтобы описанное на **языке описания аппаратуры** устройство было реализовано в ПЛИС, необходимо выполнить несколько этапов:
|
||||
In order to implement a device described in a **hardware description language** on an FPGA, several steps must be completed:
|
||||
|
||||
1. Elaboration
|
||||
2. Synthesis
|
||||
3. Implementation
|
||||
4. Bitstream generation
|
||||
|
||||
В русскоязычной литературе не сложилось устоявшихся терминов для этапов 1 и 3, но **elaboration** можно назвать как "**предобработку**" или "**развертывание**", а **implementation** как "**реализацию**" или "**построение**".
|
||||
Этапы 2 и 4 переводятся дословно: **синтез** и "**генерация двоичного файла конфигурации** (**битстрима**)".
|
||||
The boundary between steps is quite conditional, and depending on the **electronic design automation** (**EDA**) tool used, the tasks performed at different steps may overlap. The description of the steps will be given for the FPGA design flow; however, with some caveats, the same steps are used in ASIC design as well.
|
||||
|
||||
Более того, граница между этапами весьма условна и в зависимости от используемой **системы автоматизированного проектирования** (**САПР**), задачи, выполняемые на различных этапах, могут перетекать из одного в другой. Описание этапов будет даваться для маршрута проектирования под ПЛИС, однако, с некоторыми оговорками, эти же этапы используются и при проектировании ASIC.
|
||||
|
||||
Остановимся на каждом шаге подробнее.
|
||||
Let us examine each step in detail.
|
||||
|
||||
## Elaboration
|
||||
|
||||
На этапе предобработки, САПР разбирает и анализирует HDL-описание вашего устройства, проверяет его на наличие синтаксических ошибок, производит подстановку значений параметров, развёртывает конструкции, использующиеся для повторяющихся или параметризуемых частей кода, устанавливает разрядности сигналов и строит иерархию модулей устройства.
|
||||
During the elaboration step, the EDA tool parses and analyzes the HDL description of your device, checks it for syntax errors, substitutes parameter values, expands constructs used for repetitive or parameterizable parts of the code, resolves signal widths, and builds the module hierarchy of the device.
|
||||
|
||||
Затем, ставит в соответствие отдельным участкам кода соответствующие абстрактные элементы: логические вентили, мультиплексоры, элементы памяти и т.п. Кроме того, производится анализ и оптимизация схемы, например, если какая-то часть логики в конечном итоге не связана ни с одним из выходных сигналов, она будет удалена[[1]](https://support.xilinx.com/s/question/0D52E00006iHshoSAC/what-exactly-is-elaborating-a-design?language=en_US).
|
||||
It then maps individual sections of code to the corresponding abstract elements: logic gates, multiplexers, memory elements, and so on. Additionally, the circuit is analyzed and optimized — for example, if some part of the logic is ultimately not connected to any output signal, it will be removed[[1]](https://support.xilinx.com/s/question/0D52E00006iHshoSAC/what-exactly-is-elaborating-a-design?language=en_US).
|
||||
|
||||
Итогом предобработки является так называемая **топология межсоединений** (в быту называемая словом **нетлист**). **Нетлист** — это представление цифровой схемы в виде **графа**, где каждый элемент схемы является вершиной графа, а **цепи**, соединяющие эти элементы являются его ребрами. Нетлист может храниться как в виде каких-то внутренних файлов САПР-а (так хранится нетлист этапа **предобработки**), так и в виде **HDL**-файла, описывающего экземпляры примитивов и связи между ними. Рассмотрим этап предобработки и термин нетлиста на примере.
|
||||
The result of elaboration is the so-called **netlist**. A **netlist** is a representation of a digital circuit as a **graph**, where each circuit element is a node of the graph, and the **nets** connecting these elements are its edges. A netlist can be stored either as internal EDA tool files (as is the case for the elaboration netlist) or as an **HDL** file describing primitive instances and the connections between them. Let us examine the elaboration step and the concept of a netlist using an example.
|
||||
|
||||
Допустим, мы хотим реализовать схему, представленную на _рисунке 1_.
|
||||
Suppose we want to implement the circuit shown in _Figure 1_.
|
||||
|
||||

|
||||
|
||||
_Рисунок 1. Пример простой цифровой схемы._
|
||||
_Figure 1. Example of a simple digital circuit._
|
||||
|
||||
Её можно описать следующим **SystemVerilog**-кодом:
|
||||
It can be described with the following **SystemVerilog** code:
|
||||
|
||||
```SystemVerilog
|
||||
module sample(
|
||||
@@ -45,47 +42,47 @@ assign res = sel? d : xabc;
|
||||
endmodule
|
||||
```
|
||||
|
||||
Выполним этап предобработки. Для этого в **Vivado** на вкладке `RTL Analysis` выберем `Schematic`.
|
||||
Let us perform the elaboration step. To do this, in **Vivado**, under the `RTL Analysis` tab, select `Schematic`.
|
||||
|
||||
Откроются следующие окна:
|
||||
The following windows will open:
|
||||
|
||||

|
||||
|
||||
_Рисунок 2. Результат этапа предобработки._
|
||||
_Figure 2. Result of the elaboration step._
|
||||
|
||||
В левом окне мы видим наш нетлист. В нижней части обозначены узлы графа (элементы **ab_i**, **res_i**, **xabc_i**, которые представляют собой **И**, **мультиплексор** и **Исключающее ИЛИ** соответственно. Имена этих элементов схожи с именами проводов, присваиванием которым мы создавали данные элементы)
|
||||
In the left window we can see our netlist. The lower section shows the graph nodes (elements **ab_i**, **res_i**, **xabc_i**, which represent **AND**, a **multiplexer**, and **XOR** respectively; the names of these elements correspond to the names of the wires whose assignments created them).
|
||||
|
||||
В верхней части обозначены **ребра графа**, соединяющие элементы схемы. Это входы и выходы нашего модуля, а также созданные нами промежуточные цепи.
|
||||
The upper section shows the **graph edges** connecting the circuit elements. These are the inputs and outputs of our module, as well as the intermediate nets we created.
|
||||
|
||||
Справа вы видите **схематик** — **графическую схему**, построенную на основе данного **графа** (**нетлиста**).
|
||||
On the right, you see the **schematic** — a **graphical diagram** built from this **graph** (**netlist**).
|
||||
|
||||
## Synthesis
|
||||
|
||||
На шаге синтеза, САПР берет сгенерированную ранее цифровую схему и реализует элементы этой схемы через примитивы конкретной ПЛИС — в основном через логические ячейки, содержащие таблицы подстановки, полный 1-битный сумматор и `D-триггер` (см. [как работает ПЛИС](../Introduction/How%20FPGA%20works.md)).
|
||||
During the synthesis step, the EDA tool takes the previously generated digital circuit and implements its elements using the primitives of the specific FPGA — primarily through logic cells containing look-up tables, a full 1-bit adder, and a `D flip-flop` (see [how an FPGA works](../Introduction/How%20FPGA%20works.md)).
|
||||
|
||||
Поскольку в примере схема чисто **комбинационная**, результат её работы можно рассчитать и выразить в виде **таблицы истинности**, а значит для её реализации лучше всего подойдут **Таблицы Подстановки** (**LUT**-ы). Более того, в ПЛИС `xc7a100tcsg324-1` есть пятивходовые LUT-ы, а у нашей схемы именно столько входов. Это означает, работу всей этой схемы можно заменить **всего одной таблицей подстановки** внутри ПЛИС.
|
||||
Since the circuit in the example is purely **combinational**, its behavior can be calculated and expressed as a **truth table**, meaning **Look-Up Tables** (**LUTs**) are the best fit for its implementation. Moreover, the `xc7a100tcsg324-1` FPGA contains five-input LUTs, and our circuit has exactly that many inputs. This means the entire circuit's behavior can be replaced by **a single look-up table** inside the FPGA.
|
||||
|
||||
Итак, продолжим рассматривать наш пример и выполним этап синтеза. Для этого нажмем на кнопку `Run Synthesis`.
|
||||
Let us continue with our example and perform the synthesis step. To do this, click the `Run Synthesis` button.
|
||||
|
||||
После выполнения синтеза у нас появится возможность открыть новую схему, представленную на рисунке I.4-3.
|
||||
After synthesis completes, we will be able to open the new schematic shown in Figure 3.
|
||||
|
||||

|
||||
|
||||
_Рисунок 3. Результат этапа синтеза._
|
||||
_Figure 3. Result of the synthesis step._
|
||||
|
||||
Мы видим, что между входами/выходами схемы и её внутренней логикой появились новые примитивы — **буферы**. Они нужны, чтобы преобразовать уровень напряжения между входами ПЛИС и внутренней логикой (условно говоря, на вход плис могут приходить сигналы с уровнем `3.3 В`, а внутри ПЛИС примитивы работают с сигналами уровня `1.2 В`).
|
||||
We can see that new primitives — **buffers** — have appeared between the circuit's inputs/outputs and its internal logic. These are needed to convert voltage levels between the FPGA pins and its internal logic (loosely speaking, signals arriving at FPGA inputs may have a level of `3.3 V`, while the primitives inside the FPGA operate with signals at `1.2 V`).
|
||||
|
||||
Сама же логика, как мы и предполагали, свернулась в одну пятивходовую таблицу подстановки.
|
||||
The logic itself, as we expected, has been folded into a single five-input look-up table.
|
||||
|
||||
строка `EQN=32'hAAAA3CCC` означает, что таблица подстановки будет инициализирована следующим 32-битным значением: `0xAAAA3CCC`.
|
||||
Поскольку у схемы 5 входов, у нас может быть 2<sup>5</sup>=32 возможных комбинаций входных сигналов и для каждого нужно свое значение результата.
|
||||
The line `EQN=32'hAAAA3CCC` means that the look-up table will be initialized with the following 32-bit value: `0xAAAA3CCC`.
|
||||
Since the circuit has 5 inputs, there are 2<sup>5</sup>=32 possible input signal combinations, and each one requires its own result value.
|
||||
|
||||
Можно ли как-то проверить данное 32-битное значение без просчитывания всех 32 комбинаций сигналов "на бумажке"?
|
||||
Is it possible to verify this 32-bit value without computing all 32 combinations by hand?
|
||||
<details>
|
||||
<summary>
|
||||
Да, можно.
|
||||
Yes, it is.
|
||||
</summary>
|
||||
Сперва надо понять в каком именно порядке будут идти эти комбинации. Мы видим, что сигналы подключены к таблице подстановки в следующем порядке: `d, c, b, a, sel`. Это означает, что сама таблица примет вид:
|
||||
First, we need to understand the exact order in which these combinations appear. We can see that the signals are connected to the look-up table in the following order: `d, c, b, a, sel`. This means the table takes the following form:
|
||||
|
||||
```ascii
|
||||
|sel| a | b | c | d | |res|
|
||||
@@ -99,9 +96,9 @@ _Рисунок 3. Результат этапа синтеза._
|
||||
| 1 | 1 | 1 | 1 | 1 | | 1 |
|
||||
```
|
||||
|
||||
Давайте посмотрим на логику исходной схемы и данную таблицу истинности: когда `sel==1`, на выход идет `d`, это означает, что мы знаем все значения для нижней половины таблицы истинности, в нижней половине таблице истинности самый левый входной сигнал (`sel`) равен только единице, значит результат будет совпадать с сигналом `d`, который непрерывно меняется с `0` на `1` и оканчивается значением `1`. Это означает, что если читать значения результатов снизу-вверх (от старших значений к младшим), то сначала у нас будет 16 цифр, представляющих 8 пар `10`:`101010101010`, что эквивалентно записи `AAAA` в шестнадцатеричной форме.
|
||||
Let us look at the logic of the original circuit and this truth table: when `sel==1`, the output is `d`, which means we already know all values for the lower half of the truth table. In the lower half, the leftmost input signal (`sel`) is always `1`, so the result will match signal `d`, which continuously alternates between `0` and `1` and ends with `1`. This means that reading the result values from bottom to top (from most significant to least significant), we first have 16 digits representing 8 pairs of `10`: `101010101010`, which is equivalent to `AAAA` in hexadecimal.
|
||||
|
||||
Рассчитывать оставшиеся 16 вариантов тоже не обязательно, если посмотреть на схему, то можно заметить, что когда `sel!=1`, ни `sel`, ни `d` больше не участвуют в управлении выходом. Выход будет зависеть от операции XOR, которая дает `1` только когда её входы не равны между собой. Верхний вход XOR (выход И) , будет равен единице только когда входы `a` и `b` равны единице, причем в данный момент, нас интересуют только ситуации, когда `sel!=1`. Принимая во внимание, что в таблице истинности значения входов записываются чередующимися степенями двойки (единицами, парами, четверками, восьмерками) единиц и нулей, мы понимаем, что интересующая нас часть таблицы истинности будет выглядеть следующим образом:
|
||||
Computing the remaining 16 cases is also unnecessary. Looking at the circuit, we can notice that when `sel!=1`, neither `sel` nor `d` play any role in controlling the output. The output depends on the XOR operation, which produces `1` only when its inputs differ. The upper XOR input (the AND output) equals one only when both `a` and `b` are one, and at this point we are only interested in cases where `sel!=1`. Given that the truth table lists input values in alternating powers of two (ones, pairs, fours, eights), we understand that the portion of the truth table we are interested in looks as follows:
|
||||
|
||||
```ascii
|
||||
...
|
||||
@@ -116,31 +113,31 @@ _Рисунок 3. Результат этапа синтеза._
|
||||
...
|
||||
```
|
||||
|
||||
Только в этой части таблицы истинности мы получим `1` на выходе **И**, при этом в старшей части, вход `c` также равен `1`. Это значит, что входы **Исключающего ИЛИ** будут равны и на выходе будет `0`. Значит результат этой таблицы истинности будет равен `0011` или `3` в шестнадцатеричной записи.
|
||||
Only in this part of the truth table do we get `1` at the AND output, and in the upper part of this section, input `c` is also `1`. This means the XOR inputs are equal and the output is `0`. Therefore, the result for this portion of the truth table is `0011`, or `3` in hexadecimal.
|
||||
|
||||
Ниже данной части таблицы истинности располагается та часть, где `sel==1`, выше та часть, где выход **И** будет равен `0`. Это означает, что оставшаяся младшая часть будет повторять значения `c`, которое сменяется парами нулей и единиц: `00-11-00-11..`. Эта оставшаяся последовательность будет записана в шестнадцатеричном виде как `0xCCC`.
|
||||
Below this section of the truth table is the part where `sel==1`, and above it is the part where the AND output equals `0`. This means the remaining lower portion will repeat the values of `c`, which alternates in pairs of zeros and ones: `00-11-00-11..`. This remaining sequence is written in hexadecimal as `0xCCC`.
|
||||
|
||||
Таким образом, мы и получаем искомое выражение `EQN=32'hAAAA3CCC`. Если с этой частью возникли сложности, попробуйте составить данную таблицу истинности (без вычисления самих результатов, а затем просмотрите логику быстрого вычисления результата).
|
||||
Thus, we arrive at the expression `EQN=32'hAAAA3CCC`. If this section was difficult to follow, try constructing the full truth table (without computing the actual results), and then review the logic for the fast result derivation.
|
||||
</details>
|
||||
|
||||
## Implementation
|
||||
|
||||
После получения нетлиста, где в качестве элементов используются ресурсы конкретной ПЛИС, происходит **размещение** этой схемы на элементы заданной ПЛИС: выбираются конкретные логические ячейки. Затем происходит **трассировка** (маршрутизация) связей между ними. Для этих процедур часто используется термин **place & route** (размещение и трассировка). Например, реализация 32-битного сумматора с ускоренным переносом может потребовать 32 LUT-а и 8 примитивов вычисления быстрого переноса (`CARRY4`). Будет неразумно использовать для этого примитивы, разбросанные по всему кристаллу ПЛИС, ведь тогда придётся выполнять сложную трассировку сигнала, да и временные характеристики устройства также пострадают (сигналу, идущему от предыдущего разряда к следующему, придётся проходить больший путь). Вместо этого, САПР будет пытаться разместить схему таким образом, чтобы использовались близлежащие примитивы ПЛИС, для получения оптимальных характеристик.
|
||||
After obtaining the netlist in which the elements are the primitives of the specific FPGA, the circuit is **placed** onto the FPGA's logic elements: specific logic cells are selected. Then **routing** of the connections between them is performed. These procedures are commonly referred to as **place & route**. For example, implementing a 32-bit carry-lookahead adder may require 32 LUTs and 8 fast carry computation primitives (`CARRY4`). It would be inefficient to use primitives scattered across the entire FPGA die, as this would require complex signal routing and would degrade the timing characteristics of the device (signals travelling from one bit to the next would have to traverse longer paths). Instead, the EDA tool attempts to place the circuit such that nearby FPGA primitives are used, in order to achieve optimal characteristics.
|
||||
|
||||
Что именно считается "оптимальным" зависит от двух вещей: настроек САПР и **ограничений** (**constraints**), учитываемых при построении итоговой схемы в ПЛИС. Ограничения сужают область возможных решений по размещению примитивов внутри ПЛИС под определенные характеристики (временны́е и физические). Например, можно сказать, внутри ПЛИС схема должна быть размещена таким образом, чтобы время прохождения по **критическому пути** не превышало `20ns`. Это временно́е ограничение. Также нужно сообщить САПР, к какой ножке ПЛИС необходимо подключить входы и выходы нашей схемы — это физическое ограничение.
|
||||
What exactly is considered "optimal" depends on two things: the EDA tool settings and the **constraints** applied when building the final circuit on the FPGA. Constraints narrow the solution space for primitive placement inside the FPGA to meet specific characteristics (timing and physical). For example, you can specify that the circuit must be placed such that the **critical path** delay does not exceed `20 ns`. This is a timing constraint. You also need to tell the EDA tool which FPGA pin the inputs and outputs of your circuit should be connected to — this is a physical constraint.
|
||||
|
||||
Ограничения описываются не на языке описания аппаратуры, вместо этого используются текстовые файлы специального формата, зависящего от конкретной САПР.
|
||||
Constraints are not described in a hardware description language; instead, plain text files in a special format specific to the EDA tool are used.
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
Пример используемых ограничений для лабораторной по АЛУ под отладочную плату `Nexys A7-100T` (для упрощения восприятия, убраны старшие разряды переключателей и светодиодов, т.к. ограничения для каждого из разряда однотипны).
|
||||
Example constraints used for the ALU lab targeting the <code>Nexys A7-100T</code> development board (higher-order switch and LED bits are omitted for clarity, as the constraints for each bit are identical).
|
||||
</summary>
|
||||
|
||||
Строки, начинающиеся с `#` являются комментариями.
|
||||
Lines beginning with `#` are comments.
|
||||
|
||||
Строки, начинающиеся с `set_property` являются физическими ограничениями, связывающими входы и выходы нашей схемы с конкретными входами и выходами ПЛИС.
|
||||
Lines beginning with `set_property` are physical constraints that bind the inputs and outputs of our circuit to specific FPGA pins.
|
||||
|
||||
Строка `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).
|
||||
The `create_clock...` line defines timing constraints, specifying the target clock frequency and its [duty cycle](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
|
||||
@@ -177,51 +174,51 @@ set_property -dict { PACKAGE_PIN C12 IOSTANDARD LVCMOS33 } [get_ports { resetn
|
||||
|
||||
</details>
|
||||
|
||||
После выполнения построения, нетлист и сама цифровая схема остаются неизменными, однако использованные для реализации схемы примитивы получают свой "адрес" внутри ПЛИС:
|
||||
After implementation completes, the netlist and the digital circuit itself remain unchanged; however, the primitives used to realize the circuit are assigned their "address" inside the FPGA:
|
||||
|
||||

|
||||
|
||||
_Рисунок 4. "Адрес" конкретного LUT-а в ПЛИС._
|
||||
_Figure 4. The "address" of a specific LUT inside the FPGA._
|
||||
|
||||
Теперь, мы можем посмотреть на "внутренности" нашей ПЛИС `xc7a100tcsg324-1` и то, как через её примитивы будет реализована наша схема. Для этого необходимо открыть построенную схему: `Implementation -> Open implemented design`. Откроется окно, представленное на _рис. 5_.
|
||||
Now we can look at the "internals" of our FPGA `xc7a100tcsg324-1` and see how our circuit is implemented through its primitives. To do this, open the implemented design: `Implementation -> Open implemented design`. The window shown in _Fig. 5_ will open.
|
||||
|
||||

|
||||
|
||||
_Рисунок 5. Окно просмотра реализованного устройства._
|
||||
_Figure 5. The implemented design viewer window._
|
||||
|
||||
Это содержимое ПЛИС. Просто из-за огромного количества содержащихся в ней примитивов, оно показана в таком масштабе, что всё сливается в один цветной ковёр. Большая часть этого окна неактивна (показана в тёмно-синих тонах) и это нормально, ведь мы реализовали крошечную цифровую схему, она и не должна занимать значительное количество ресурсов ПЛИС.
|
||||
This is the contents of the FPGA. Due to the enormous number of primitives it contains, it is displayed at a scale where everything blends into a single colored mosaic. Most of this window is inactive (shown in dark blue tones), and that is expected — we implemented a tiny digital circuit that should not occupy a significant amount of FPGA resources.
|
||||
|
||||
Нас интересует "[бледно-голубая точка](https://ru.wikipedia.org/wiki/Pale_Blue_Dot)", расположенная в нижнем левом углу прямоугольника `X0Y1` (выделено красным). Если отмасштабировать эту зону, мы найдем используемый нами LUT:
|
||||
We are interested in the "[pale blue dot](https://en.wikipedia.org/wiki/Pale_Blue_Dot)" located in the lower-left corner of the rectangle `X0Y1` (highlighted in red). Zooming into that area, we will find the LUT we are using:
|
||||
|
||||

|
||||
|
||||
_Рисунок 6. Расположение выбранного LUT-а внутри ПЛИС._
|
||||
_Figure 6. Location of the selected LUT inside the FPGA._
|
||||
|
||||
Кроме того, если поиграться со свойствами этого примитива, мы сможем найти нашу таблицу истинности, инициализирующую этот примитив.
|
||||
Furthermore, by examining the properties of this primitive, we can find the truth table used to initialize it.
|
||||
|
||||
## Bitstream generation
|
||||
|
||||
После того, как САПР определил конкретные примитивы, их режим работы, и пути сигнала между ними, необходимо создать двоичный файл (**bitstream**), который позволит сконфигурировать ПЛИС необходимым нам образом.
|
||||
Получив этот файл, остается запрограммировать ПЛИС, после чего она воплотит разработанное устройство.
|
||||
After the EDA tool has determined the specific primitives, their operating modes, and the signal paths between them, a binary file (**bitstream**) must be generated. This file will configure the FPGA in the required way.
|
||||
Once this file is obtained, all that remains is to program the FPGA, after which it will implement the designed device.
|
||||
|
||||
## Итоги главы
|
||||
## Chapter Summary
|
||||
|
||||
Таким образом, маршрут перехода от HDL-описания устройства до его реализации в ПЛИС выглядит следующим образом:
|
||||
The flow from an HDL description of a device to its implementation on an FPGA is as follows:
|
||||
|
||||
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. First, the **elaboration** step takes place. Its main tasks include:
|
||||
1. flattening the module hierarchy: converting the hierarchical project structure into a flat one, which simplifies subsequent processing steps;
|
||||
2. syntax and semantic checking of the HDL code;
|
||||
3. resolving parameters and constants;
|
||||
4. generating an intermediate project representation used in subsequent steps.
|
||||
The resulting intermediate representation uses abstract elements (logic gates, multiplexers, registers) that are not tied to any specific FPGA.
|
||||
2. Next, the **synthesis** step is performed, producing a **netlist** that uses the resources of the specific FPGA. All structures used in the previous step (registers, multiplexers, and other blocks) are implemented through FPGA primitives (LUTs, D flip-flops, arithmetic blocks, etc.). A logic network optimization step is performed to minimize area, reduce delays, and lower power consumption.
|
||||
3. Then the **implementation** step builds the final digital circuit, consisting of several sub-steps:
|
||||
1. **Placement**: determining the specific locations of all logic elements within the FPGA. If part of the circuit was implemented using LUTs in the previous step, this step decides **which specific** LUT will be used (not its type, but which of the many identical elements will be selected).
|
||||
2. **Routing**: creating connections between elements in accordance with the netlist.
|
||||
3. **Timing Analysis**: verifying timing characteristics to confirm that all signals propagate through the circuit within acceptable timing margins.
|
||||
The solution space for the **place & route** steps is constrained by applying **physical** and **timing** **constraints**.
|
||||
4. The final step is **bitstream generation**, which produces the binary configuration file that will configure the FPGA to implement the built circuit when programmed.
|
||||
|
||||
## Список источников
|
||||
## References
|
||||
|
||||
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 Forum: what exactly is 'elaborating' a design?](https://support.xilinx.com/s/question/0D52E00006iHshoSAC/what-exactly-is-elaborating-a-design?language=en_US)
|
||||
|
||||
@@ -1,188 +1,188 @@
|
||||
# Последовательностная логика
|
||||
# Sequential Logic
|
||||
|
||||
## Классификация цифровой логики
|
||||
## Classification of Digital Logic
|
||||
|
||||
Цифровая логика делится на **комбинационную** и **последовательностную**.
|
||||
Digital logic is divided into **combinational** and **sequential** logic.
|
||||
|
||||
**Комбинационная логика** (или "логика без памяти") — это цифровая логика, выходы которой зависят только от её входов. Один и тот же набор входных воздействий на эту логику всегда будет давать один и тот же результат. Комбинационную логику можно всегда представить в виде таблицы истинности (или логической функции) всех её выходов от её входов.
|
||||
**Combinational logic** (or "memoryless logic") is digital logic whose outputs depend only on its inputs. The same set of input stimuli will always produce the same result. Combinational logic can always be represented as a truth table (or a logic function) of all its outputs in terms of its inputs.
|
||||
|
||||
В противоположность комбинационной, существует также и **последовательностная логика**, или "логика с памятью" — цифровая логика, выходы которой зависят не только от её входов, но и от её внутреннего состояния.
|
||||
In contrast to combinational logic, there also exists **sequential logic**, or "logic with memory" — digital logic whose outputs depend not only on its inputs, but also on its internal state.
|
||||
|
||||
Простейшим примером комбинационной логики может быть любой логический вентиль, например исключающее ИЛИ (_рис. 1 (а)_). Эта комбинационная схема всегда будет давать `0`, если оба её входа равны, в противном случае, она выдаст `1`.
|
||||
The simplest example of combinational logic is any logic gate, such as XOR (_fig. 1 (a)_). This combinational circuit will always output `0` when both of its inputs are equal, and `1` otherwise.
|
||||
|
||||

|
||||
|
||||
_Рисунок 1. Пример комбинационной (а), и последовательностной (б) схем._
|
||||
_Figure 1. Example of a combinational (a) and a sequential (b) circuit._
|
||||
|
||||
Предположим теперь, что в качестве одного из входов исключающего ИЛИ стоит некая ячейка памяти, которая запоминает предыдущее значение, выданное этим логическим вентилем (_рис. 1 (б)_). Теперь, выходы схемы зависят не только от того, что мы подадим на вход, но и от того, что находится в данной ячейке памяти, а самое главное — теперь, подавая на вход одно и тоже воздействие, мы можем получить разные результаты.
|
||||
Now suppose that one of the XOR inputs is a memory cell that stores the previous value produced by that gate (_fig. 1 (b)_). The circuit's outputs now depend not only on what we apply to the input, but also on what is currently held in the memory cell — and most importantly, applying the same input stimulus can now yield different results.
|
||||
|
||||
Будем исходить из того, что изначально ячейка памяти проинициализирована нулём. Сперва подадим на вход этой схемы `0`. Поскольку оба входа равны `0`, на выход схемы подаётся `0`, и значение в ячейке памяти остаётся прежним. Затем, подадим на вход `1` — теперь на выход схемы идёт значение `1` и оно же сохраняется в ячейке памяти. После, мы снова подаём на вход `0`, однако, в отличие от первого раза, на выход схемы пойдёт `1`, т.к. входы исключающего ИЛИ не равны. Выставив на вход `1` ещё раз, мы получим на выходе `0`.
|
||||
Assume the memory cell is initially set to zero. First, we apply `0` to the input. Since both inputs are equal to `0`, the output is `0` and the memory cell retains its value. Next, we apply `1` — the output becomes `1` and is stored in the memory cell. We then apply `0` again; unlike the first time, the output is now `1`, because the XOR inputs are unequal. Applying `1` once more yields `0` at the output.
|
||||
|
||||
Как вы видите, результат последовательностной логики зависит от **последовательности** произведённых входных воздействий, в то время как комбинационная логика зависит от **комбинации** её текущих входных воздействий.
|
||||
As you can see, the result of sequential logic depends on the **sequence** of input stimuli applied, whereas combinational logic depends on the **combination** of its current inputs.
|
||||
|
||||
Последовательностная логика делится на **синхронную** и **асинхронную**.
|
||||
Sequential logic is divided into **synchronous** and **asynchronous**.
|
||||
|
||||
**Синхронной логикой** называется такая логика, которая обновляет своё состояние (содержимое ячеек памяти) одновременно (**синхронно**) с фронтом тактового сигнала*. В свою очередь **асинхронная последовательностная логика** — это логика, которая может обновлять своё состояние **асинхронно** (т.е. без привязки к фронту тактового синхроимпульса). Бывает также и синхронная логика с асинхронными сигналами предустановки/сброса.
|
||||
**Synchronous logic** is logic that updates its state (the contents of its memory cells) simultaneously (**synchronously**) with the edge of a clock signal\*. **Asynchronous sequential logic**, in turn, is logic that can update its state **asynchronously** (i.e., independently of a clock edge). There also exist synchronous circuits with asynchronous preset/reset signals.
|
||||
|
||||
Комбинационная логика по своей природе является асинхронной, поэтому в зависимости от контекста под "асинхронной логикой" может подразумеваться как комбинационная логика, так и последовательностная логика, которая может обновлять значение не по фронту тактового синхроимпульса.
|
||||
Combinational logic is inherently asynchronous; therefore, depending on context, "asynchronous logic" may refer either to combinational logic or to sequential logic whose state can change without being tied to a clock edge.
|
||||
|
||||
> [!Info]
|
||||
> В некоторых источниках синхронной логикой могут называть и ту, что работает по уровню (а не фронту) единого источника тактового синхроимпульса [[1, стр. 164](https://reader.lanbook.com/book/241166?lms=d92e0036d4c90623ffd0a8ecc34dee72)].
|
||||
> Some sources also refer to logic that operates on the level (rather than the edge) of a single clock source as synchronous logic [1, p. 119].
|
||||
|
||||
## Бистабильные ячейки
|
||||
## Bistable Cells
|
||||
|
||||
**Бистабильная ячейка** — это элемент статической памяти, способный принимать одно из двух устойчивых состояний, соответствующих цифровым значениям "0" или "1".
|
||||
A **bistable cell** is a static memory element capable of holding one of two stable states corresponding to the digital values "0" or "1".
|
||||
|
||||
**Статическая память** — это тип памяти, который сохраняет данные в течении неопределённого времени, пока его питание остаётся включённым, без необходимости регенерации (в отличие от **динамической памяти**, использующей для хранения конденсаторы, требующие для хранения регулярного обновления данных).
|
||||
**Static memory** is a type of memory that retains data indefinitely as long as power is supplied, without requiring refresh cycles (unlike **dynamic memory**, which uses capacitors for storage and requires periodic data refresh to prevent loss).
|
||||
|
||||
Рассмотрим простейшую ячейку статической памяти, представленную на _рис. 2_, которая способна хранить 1 бит информации.
|
||||
Consider the simplest static memory cell shown in _fig. 2_, which is capable of storing 1 bit of information.
|
||||
|
||||

|
||||
|
||||
_Рисунок 2. Простейшая ячейка статической памяти._
|
||||
_Figure 2. The simplest static memory cell._
|
||||
|
||||
Данная ячейка представляет собой петлю из двух инверторов, в которых "заперто" хранимое значение. Дважды инвертированный сигнал совпадает по значению с исходным, при этом проходя через каждый из инверторов, сигнал обновляет своё значение напряжения, поддерживая тем самым уровни напряжения логических значений. Главной проблемой подобной ячейки является то, что она требует дополнительной аппаратуры для записи в эту ячейку хранимой информации.
|
||||
This cell consists of a loop of two inverters in which the stored value is "latched". A signal inverted twice equals its original value, and as it passes through each inverter the voltage level is refreshed, thereby maintaining the voltage levels that represent the logic values. The main drawback of such a cell is that it requires additional hardware to write new data into it.
|
||||
|
||||
Для того, чтобы добавить в эту ячейку входы с возможностью записи данных, можно поставить перед инверторами логические элементы ИЛИ (которые совместно с инверторами образуют элементы ИЛИ-НЕ).
|
||||
To add write capability, OR gates can be placed before the inverters (which, together with the inverters, form NOR gates).
|
||||
|
||||
В результате получится **RS-триггер** — бистабильная ячейка, представленная на _рис. 3_.
|
||||
The result is an **RS latch** — the bistable cell shown in _fig. 3_.
|
||||
|
||||
## RS-триггер
|
||||
## RS latch
|
||||
|
||||

|
||||
|
||||
_Рисунок 3. Схема и таблица истинности RS-триггера. X означает, что в этой строке результат не зависит от хранимого значения._
|
||||
_Figure 3. Circuit and truth table of the RS latch. X indicates that the result in that row is independent of the stored value._
|
||||
|
||||
RS-триггер — это бистабильная ячейка, имеющая два управляющих входа: `R` (reset) и `S` (set), и два выхода: `Q` и `Q̅`. `Q̅` является инверсией `Q`. RS-триггер, построенный на логических элементах ИЛИ-НЕ, работает следующим образом:
|
||||
An RS latch is a bistable cell with two control inputs: `R` (reset) and `S` (set), and two outputs: `Q` and `Q̅`. `Q̅` is the complement of `Q`. An RS latch built from NOR gates operates as follows:
|
||||
|
||||
1. Если вход `R=1`, а `S=0`, то выход верхнего элемента ИЛИ-НЕ (а значит и выход `Q`) равен `0` вне зависимости от второго его входа. Этот выход поступает вместе с входом `S` на нижний элемент ИЛИ-НЕ, который выдаёт `1` (на выход `Q̅`), поскольку оба его входа равны `0`. Эта единица подаётся на второй вход верхнего элемента ИЛИ-НЕ и теперь, даже если вход `R` станет равным `0`, `1` на втором его входе сможет воспроизвести тоже самое поведение, запирая внутри триггера стабильное состояние `Q=0`.
|
||||
2. Если вход `R=0`, а `S=1`, схема работает противоположным образом: поскольку на нижний элемент подаётся `1` с входа `S`, выход `Q̅` равен `0` вне зависимости от второго входа нижнего элемента ИЛИ-НЕ. Этот ноль подаётся на второй вход верхнего элемента ИЛИ-НЕ, и поскольку оба его входа равны `0`, на выходе этого элемента (на выход `Q`) подаётся `1`, которая возвращается обратно на вход нижнего элемента ИЛИ-НЕ, запирая внутри триггера стабильное состояние `Q=1`.
|
||||
3. Таким образом, если на оба входа одновременно равны `0`, RS-триггер хранит своё предыдущее значение.
|
||||
1. If `R=1` and `S=0`, the output of the upper NOR gate (and therefore output `Q`) is `0` regardless of its second input. This output, together with input `S`, drives the lower NOR gate, which produces `1` (at output `Q̅`) since both of its inputs are `0`. This `1` is fed back to the second input of the upper NOR gate, so that even if `R` returns to `0`, the `1` on its second input reproduces the same behaviour, locking the stable state `Q=0` inside the flip-flop.
|
||||
2. If `R=0` and `S=1`, the circuit operates in the opposite manner: since `1` from input `S` drives the lower gate, output `Q̅` is `0` regardless of the lower NOR gate's second input. This `0` is applied to the second input of the upper NOR gate, and since both of its inputs are `0`, the output of that gate (output `Q`) is `1`, which feeds back to the lower NOR gate's input, locking the stable state `Q=1` inside the flip-flop.
|
||||
3. Therefore, when both inputs are simultaneously `0`, the RS latch retains its previous value.
|
||||
|
||||
Проблемой данного триггера является то, что он имеет **запрещённую** комбинацию входов. В случае RS-триггера, построенного на элементах ИЛИ-НЕ, таковой комбинацией входов является `R=1` и `S=1`. Даже с точки зрения функционального назначения, данная комбинация не имеет смысла: кому потребуется одновременно и сбрасывать RS-триггер в 0 и устанавливать его в 1? Тем не менее, вот что произойдет, если использовать эту комбинацию:
|
||||
The drawback of this flip-flop is that it has a **forbidden** input combination. For an RS latch built from NOR gates, this forbidden combination is `R=1` and `S=1`. Even from a functional standpoint, this combination makes no sense: who would want to simultaneously reset an RS latch to 0 and set it to 1? Nevertheless, here is what happens when this combination is used:
|
||||
|
||||
4. Если оба входа одновременно равны `1`, то оба выхода Q и Q̅ будут равны `0`, что нарушает логику работы триггера, поскольку выход Q̅ должен быть инверсией выхода Q. При этом, если после этого перевести оба входа в `0`, RS-триггер окажется в неустойчивом состоянии (в состоянии гонки), а выходы могут начать неопределённо долго инвертироваться. Пока RS-триггер был в запрещённом состоянии, выходы `Q` и `Q̅`, равные `0`, подавались на входы обоих элементов ИЛИ-НЕ, а если после этого **одновременно** перевести входы `R` и `S` в состояние `0`, то на входах обоих вентилей будут `0`, что побудит их выдать на выходы `1`, которые пойдут обратно на входы этих вентилей, после чего те подадут на выход `0`, и так будет продолжаться до тех пор, пока один из сигналов в петле обратной связи не выиграет гонку, и RS-триггер не окажется в стабильном состоянии `0` либо `1`.
|
||||
4. If both inputs are simultaneously `1`, both outputs Q and Q̅ will be `0`, which violates the latch logic since Q̅ should be the complement of Q. Moreover, if both inputs are then **simultaneously** returned to `0`, the RS latch enters an unstable (racing) state, and the outputs may oscillate indefinitely. While the RS latch was in the forbidden state, outputs `Q` and `Q̅`, both equal to `0`, were fed back to the inputs of both NOR gates. If both `R` and `S` are simultaneously returned to `0`, both gate inputs become `0`, causing both gates to output `1`, which feeds back to their inputs, after which they output `0`, and this continues until one of the signals in the feedback loop wins the race and the RS latch settles into a stable state of `0` or `1`.
|
||||
|
||||
Для того чтобы избавиться от запрещённого состояния RS-триггера, была придумана D-защёлка (gated D-latch).
|
||||
To eliminate the forbidden state of the RS latch, the D latch was devised.
|
||||
|
||||
## D-защелка
|
||||
## D Latch
|
||||
|
||||
D-защёлка — это бистабильная ячейка памяти, имеющая входы `D` (Data) и `E` (enable). Иногда вход enable называют clk (clock) или G (gated), что никак не сказывается на его функциональном назначении. Когда сигнал `E` равен `1`, D-защёлка "захватывает" данные с входа `D`. Когда сигнал `E` равен `0`, D-защёлка сохраняет уже захваченные данные.
|
||||
A D latch is a bistable memory cell with inputs `D` (Data) and `E` (enable). The enable input is sometimes called clk (clock) or G (gated), which does not affect its functional role. When `E` is `1`, the D latch "captures" data from input `D`. When `E` is `0`, the D latch holds the previously captured data.
|
||||
|
||||
D-защёлка может быть построена на базе RS-триггера, к которому добавляется логика, исключающая возможность появления запрещённого состояния (_рис. 4_).
|
||||
A D latch can be built on top of an RS latch by adding logic that prevents the forbidden state from occurring (_fig. 4_).
|
||||
|
||||

|
||||
|
||||
_Рисунок 4. Схема и таблица истинности D-защёлки._
|
||||
_Figure 4. Circuit and truth table of the D latch._
|
||||
|
||||
Логика работы D-защёлки заключается в следующем. Когда сигнал `E` равен `0`, логические вентили И подают на выход `0` вне зависимости от второго входа, и RS-триггер переходит в состояние хранения текущего значения. В такой ситуации говорят, что D-защёлка "закрыта", или "перешла в непрозрачное состояние". Когда сигнал `E` равен `1`, логические элементы И, добавленные перед входами RS-триггера передают на выход значение со второго их входа. При этом на второй вход этих элементов подаются противоположные сигналы: `!D` и `D`, что исключает возможность одновременного появления `1` на входах `R` и `S`. В этом случае в RS-триггер попадает значение с входа `D`, а про D-защёлку говорят, что она "открыта" (перешла в "прозрачное" состояние). Пока защёлка "прозрачна", данные со входа `D` идут напрямую на выход `Q`.
|
||||
The D latch operates as follows. When `E` is `0`, the AND gates drive their outputs to `0` regardless of the second input, and the RS latch transitions to its hold state. In this situation the D latch is said to be "closed", or "opaque". When `E` is `1`, the AND gates placed before the RS latch inputs pass the value of their second input to the output. The complementary signals `!D` and `D` are applied to the second inputs of these gates, which prevents both `R` and `S` from being `1` simultaneously. In this case the value from input `D` enters the RS latch, and the D latch is said to be "open" (it transitions to the "transparent" state). While the latch is transparent, data from input `D` passes directly to output `Q`.
|
||||
|
||||
Несмотря на то, что D-защёлка устраняет главный недостаток RS-триггера, она тоже является не самой надёжной бистабильной ячейкой памяти. Дело в том, что D-защёлка пропускает на выход данные со входа `D` всё то время, пока она "прозрачна". Это значит, что она будет пропускать через себя все возможные переходные процессы сигнала `D`. Это значит, что она будет распространять переходные процессы сигналов со входа D, на которые будут реагировать последующие участки цифровой схемы. Из-за этого, через всю цифровую схему, начиная со входов, будут распространяться переходные процессы. В результате определить моменты времени, в которых на выходе схемы будет корректный результат обработки входного сигнала, станет практически невозможно. Было бы гораздо удобней, если бы могли сохранять данные одномоментно, когда на входе `D` уже находится установившееся значение, отсекая тем самым на каждом элементе памяти переходные процессы всех предыдущих участков цифровой схемы. Таким элементом памяти, является D-триггер (D flip-flop).
|
||||
Although the D latch eliminates the main drawback of the RS latch, it is not the most reliable bistable memory cell too. The problem is that the D latch passes data from input `D` to the output for the entire time it is transparent. This means it propagates all transient glitches on the `D` signal, which subsequent portions of the digital circuit will react to. As a result, transients originating at the circuit inputs propagate throughout the entire design, making it practically impossible to determine at what moments in time the circuit output contains a valid result. It would be far more convenient to capture data instantaneously, at the moment when input `D` has already settled to a stable value, thereby cutting off transients from all preceding stages at each memory element. The D flip-flop (D flip-flop) is exactly such a memory element.
|
||||
|
||||
## D-триггер
|
||||
## D Flip-Flop
|
||||
|
||||
D-триггер — это элемент статической памяти, который сохраняет данные со входа `D` **в момент перехода управляющего сигнала из нуля в единицу** (либо в момент перехода из единицы в ноль). Данный сигнал называется **сигналом синхронизации** (или **синхроимпульсом**) и обозначается как clk (clock).
|
||||
A D flip-flop is a static memory element that captures data from input `D` **at the moment the control signal transitions from zero to one** (or from one to zero). This signal is called the **clock signal** (or **clock**) and is denoted clk.
|
||||
|
||||
На _рис. 5_ показан способ построения D-триггера из двух D-защёлок.
|
||||
_Figure 5_ shows how a D flip-flop is constructed from two D latches.
|
||||
|
||||

|
||||
|
||||
_Рисунок 5. Схема и таблица истинности D-триггера._
|
||||
_Figure 5. Circuit and truth table of the D flip-flop._
|
||||
|
||||
Принцип работы D-триггера, схема которого представлена на _рис. 5_ заключается в том, что управляющий сигнал `E` одной защёлки является инверсией управляющего сигнала `E` другой защёлки. Это значит, что пока одна защёлка "прозрачна" и принимает данные со входа — другая "непрозрачна" и данные не принимает. В момент, когда тактовый синхроимпульс меняет своё значение с `0` на `1`, ведущая защёлка становится "непрозрачной" для новых данных с входа `D`, и "запертые" в ней данные попадают в только что открывшуюся ведомую защёлку. Несмотря на то, что ведомая защёлка "прозрачна" всё то время, пока сигнал `clk = 1`, данные в ней остаются стабильными, поскольку выход ведущей защёлки больше не может измениться.
|
||||
The D flip-flop shown in _fig. 5_ operates on the principle that the enable signal `E` of one latch is the complement of the enable signal `E` of the other. This means that while one latch is transparent and accepting data from the input, the other is opaque and not accepting data. At the moment the clock transitions from `0` to `1`, the master latch becomes opaque to new data from input `D`, and the data "latched" inside it passes into the slave latch that has just opened. Although the slave latch remains transparent for the entire time `clk = 1`, the data inside it remains stable because the master latch output can no longer change.
|
||||
|
||||
Описанные схемы бистабильных ячеек представляют собой скорее математическое описание элементов памяти — так проще объяснить принцип их работы. Если ваша технология позволяет реализовать элементы И, ИЛИ и НЕ — значит вы точно можете реализовать подобные элементы. При этом, используя особенности конкретной технологии, данные схемы можно реализовывать более эффективно. D-защёлку, к примеру, можно реализовать схемой, представленной на _рис. 6_.
|
||||
The bistable cell circuits described above are more of a mathematical model of memory elements — they serve to explain the operating principle more clearly. If your technology allows you to implement AND, OR, and NOT gates, you can certainly implement such elements. Moreover, by exploiting the characteristics of a specific technology, these circuits can be implemented more efficiently. A D latch, for example, can be implemented as the circuit shown in _fig. 6_.
|
||||
|
||||

|
||||
|
||||
_Рисунок 6. Конфигурируемая ячейка памяти ПЛИС Xilinx XC2064 [[2, стр. 2-63](https://archive.org/details/programmablegate00xili/page/n93/mode/2up)]._
|
||||
_Figure 6. Configurable memory cell of the Xilinx XC2064 FPGA [[2, p. 2-63](https://archive.org/details/programmablegate00xili/page/n93/mode/2up)]._
|
||||
|
||||
## Метастабильность
|
||||
## Metastability
|
||||
|
||||
Как ранее упоминалось, при проектировании эффективных цифровых схем, необходимо оглядываться на аналоговые особенности технологии, по которой эти схемы будут реализованы. Выполним анализ простейшей бистабильной ячейки, построенной на двух инверторах. Для этого рассмотрим _рис. 7_. На _рис. 7 (а)_ показана передаточная функция U<sub>вых</sub> = T(U<sub>вх</sub>) некоторого инвертора. По оси абсцисс откладывается входное напряжение, подаваемое на инвертор, а по оси ординат — его выходное напряжение. Если подать на вход инвертора, описываемого подобной передаточной функцией напряжение, равное 0В (соответствует цифровому значению `0`), на выходе будет напряжение равное 3В (соответствует цифровому значению `1`), и наоборот: если подать на вход значение 3В, мы получим на выходе значение приблизительно равное 0В.
|
||||
As mentioned earlier, designing efficient digital circuits requires consideration of the analog characteristics of the technology in which those circuits will be implemented. Let us analyze the simplest bistable cell built from two inverters by examining _fig. 7_. _Figure 7 (a)_ shows the transfer function U<sub>out</sub> = T(U<sub>in</sub>) of an inverter. The horizontal axis represents the input voltage applied to the inverter, and the vertical axis represents its output voltage. Applying 0 V (corresponding to digital value `0`) to the input of an inverter described by such a transfer function yields 3 V (corresponding to digital value `1`) at the output, and vice versa: applying 3 V yields approximately 0 V at the output.
|
||||
|
||||
Поскольку в бистабильной ячейке выход одного инвертора подаётся на вход второго, оказывается удобным наложить графики передаточной функции обоих таким образом, чтобы входное напряжение одного инвертора оказалось на той же оси, где откладывается выходное напряжение другого инвертора, как представлено на _рис. 7 (б)_. Точки пересечения кривых на этом графике являются точками равновесия, в которых входные и выходные напряжения обоих инверторов являются согласованными.
|
||||
Since in a bistable cell the output of one inverter drives the input of the other, it is convenient to superimpose the transfer function plots of both inverters so that the input voltage of one inverter shares the same axis as the output voltage of the other, as shown in _fig. 7 (b)_. The intersection points of the curves on this plot are equilibrium points at which the input and output voltages of both inverters are mutually consistent.
|
||||
|
||||

|
||||
|
||||
_Рисунок 7. Передаточные функции для: а) одиночного КМОП-инвертора; б) пары инверторов, объединённых в бистабильную петлю [3, стр. 497]._
|
||||
_Figure 7. Transfer functions for: a) a single CMOS inverter; b) a pair of inverters connected in a bistable loop [3, p. 497]._
|
||||
|
||||
Как вы можете заметить, таких точек почему-то не две, а три. Две эти точки обозначены как **стабильные** и соответствуют привычным цифровым значениям 1 (для 3В) и 0 (для 0В). Третья точка равновесия обозначена как **метастабильная** и расположена примерно посередине между этими двумя значениями. И действительно, согласно графику, если подать на вход приблизительно 1.5В, на выходе будет точно такое же напряжение, которое затем будет подано на вход второго инвертора и т.д., благодаря чему петля будет находиться в подобном состоянии неопределённый промежуток времени. Подобное состояние называется **метастабильным состоянием** и присуще любой бистабильной ячейке, реализованной на электронной компонентной базе.
|
||||
As you can see, there are three intersection points rather than two. Two of these are labeled as **stable** and correspond to the familiar digital values 1 (at 3 V) and 0 (at 0 V). The third equilibrium point is labeled **metastable** and lies approximately midway between the two stable values. Indeed, according to the plot, applying approximately 1.5 V to the input produces exactly the same voltage at the output, which is then applied to the second inverter's input, and so on, causing the loop to remain in this state for an indeterminate period. This condition is called the **metastable state** and is an inherent property of any bistable cell implemented in electronic hardware.
|
||||
|
||||
Традиционно, для объяснения явления метастабильности используется аналогия с шариком на холме (_рис. 8_). Предположим, шарик находится у подножия левого склона холма. Если приложить к нему достаточную силу, направленную вправо — шарик перекатится через холм, и он окажется на противоположном склоне (для удобства аналогии, на склонах холма стоят стенки, чтобы шарик останавливался всегда в одной и той же точке этого склона). Если приложить недостаточно силы — шарик поднимется немного вверх по холму, и скатится обратно, остановившись в той же точке, откуда и начал. Однако, если вы будете достаточно "удачливы" и "точны", вы можете приложить ровно столько силы, чтобы шарик поднялся на вершину холма, но не смог с неё скатиться. Этот шарик может оставаться в таком положении неопределённое количество времени, но любое малейшее возмущение (будь то лёгкое дуновение ветерка, вызванное взмахом крыла пролетевшей рядом бабочки, или далёкое землетрясение, можете придумать свою экстравагантную причину) может заставить шарик скатиться в любую сторону.
|
||||
Metastability is traditionally explained using the analogy of a ball on a hill (_fig. 8_). Suppose the ball is resting at the bottom of the left slope. Applying sufficient force to the right will cause the ball to roll over the hill and come to rest on the opposite slope (walls are placed at the bottom of each slope for convenience, so the ball always stops at the same point). Applying insufficient force causes the ball to roll partway up the hill and roll back to its starting position. However, if you are sufficiently "lucky" and "precise", you can apply exactly enough force to push the ball to the top of the hill without it rolling off. The ball may remain at the top for an indeterminate amount of time, but any slight disturbance — a gentle breeze from the wing of a passing butterfly, a distant earthquake, or any other exotic cause you care to imagine — can send the ball rolling in either direction.
|
||||
|
||||

|
||||
|
||||
_Рисунок 8. Механическая аналогия явлению метастабильности [3, стр. 498]._
|
||||
_Figure 8. A mechanical analogy for metastability [3, p. 498]._
|
||||
|
||||
Вернёмся к _рис. 7_ (б). Предположим, что инвертор находится в метастабильном состоянии и в цепи возникла случайная наводка, слегка отклонившая напряжение на входе одного из инверторов. Это отклонение усилится на выходе инвертора и попадёт на вход второго инвертора, усилившись на котором оно вернётся на вход первого инвертора и т.д. пока в конечном итоге не остановится в верхней равновесной точке.
|
||||
Returning to _fig. 7 (b)_: suppose the inverter is in the metastable state and a random noise event slightly perturbs the voltage at the input of one of the inverters. This perturbation is amplified at the inverter's output and applied to the second inverter's input, where it is amplified again and fed back to the first inverter's input, and so on, until the loop ultimately settles at the upper equilibrium point.
|
||||
|
||||
Если же возмущение произойдёт, пока бистабильная ячейка была в стабильном состоянии — её состояние не изменится. Предположим, что бистабильная ячейка хранит значение `1`, т.е. на вход первого инвертора подаётся значение 0В, и пришло возмущение, отклонившее это напряжение до 1В (а для подобной цифровой схемы это очень экстремальное отклонение, за пределами допустимых режимов работы). Проведём вертикальную линию до точки пересечения с черной кривой — это значение на выходе первого инвертора, и входа второго инвертора. Из этой точки, проведём горизонтальную линию до пересечения с синей кривой — это значение на выходе второго инвертора и входе первого. В общем-то, уже на этом этапе, на вход первого инвертора снова подаётся околонулевое напряжение. Именно поэтому крайние две точки пересечения называются **стабильными** — пока на схему подаётся питание, ячейка будет находиться в этом состоянии бесконечно долго до тех пор, пока не произойдёт существенного воздействия, чтобы она могла изменить это состояние.
|
||||
If the disturbance occurs while the bistable cell is in a stable state, its state will not change. Suppose the bistable cell is storing the value `1`, meaning 0 V is applied to the first inverter's input, and a disturbance shifts this voltage to 1 V (an extremely large deviation for such a digital circuit, well outside the normal operating range). Drawing a vertical line to its intersection with the black curve gives the output voltage of the first inverter and the input voltage of the second. Drawing a horizontal line from that point to its intersection with the blue curve gives the output voltage of the second inverter and the input voltage of the first. By that point the first inverter's input has already returned to near-zero voltage. This is precisely why the two outer intersection points are called **stable**: as long as power is applied, the cell remains in that state indefinitely until a sufficiently large disturbance occurs to cause a transition.
|
||||
|
||||
В случае метастабильного состояния — мы не можем предсказать, конкретное значение того, как долго ячейка будет находиться в этом состоянии — это случайная величина, для которой может быть оценено значение вероятности. Например, можно сделать оценку вроде: "вероятность того, что бистабильная ячейка выйдет из метастабильного состояния через 100мс много выше вероятности, что она выйдет из этого состояния через 100 секунд"
|
||||
In the metastable case, we cannot predict the specific duration for which the cell will remain in that state — it is a random variable for which only probabilistic estimates can be made. For example, one might say: "the probability that the bistable cell will exit the metastable state within 100 ms is far greater than the probability that it will still be in that state after 100 seconds."
|
||||
|
||||
Таким образом, метастабильность — это явление, возникающее в ходе нарушения условий работы цифровых элементов. В обычных случаях это явление является нежелательным (если только вы не планируете использовать свою схему в качестве генератора случайных чисел) и важно знать, как его избежать.
|
||||
Thus, metastability is a phenomenon that arises when the operating conditions of digital elements are violated. In normal circumstances it is an undesirable effect (unless you intend to use your circuit as a random number generator), and it is important to know how to avoid it.
|
||||
|
||||
Любые бистабильные ячейки имеют специальные временны́е параметры (ограничения), несоблюдение которых может привести к появлению метастабильности. В рамках этого курса, вы будете работать в основном с бистабильными ячейками, представленными в виде D-триггеров. Для D-триггеров таковыми временными параметрами являются:
|
||||
All bistable cells have specific timing parameters (constraints) whose violation can lead to metastability. In this course, you will primarily work with bistable cells in the form of D flip-flops. For D flip-flops, these timing parameters are:
|
||||
|
||||
- T<sub>setup</sub> (**setup time**) — **время предустановки**. Это интервал времени, в течение которого сигнал на входе `D` должен оставаться неизменным перед наступлением фронта тактового сигнала.
|
||||
- T<sub>hold</sub> (**hold time**) — **время удержания**. Это интервал времени, в течение которого сигнал на входе `D` должен оставаться неизменным после наступления фронта тактового сигнала.
|
||||
- T<sub>setup</sub> (**setup time**) — the interval during which the signal at input `D` must remain stable before the clock edge arrives.
|
||||
- T<sub>hold</sub> (**hold time**) — the interval during which the signal at input `D` must remain stable after the clock edge arrives.
|
||||
|
||||
Эти два параметра образуют временное окно вокруг фронта тактового сигнала, в течение которого входной сигнал должен оставаться стабильным. Несоблюдение данных требований приводит к неопределённому поведению триггера (см. _рис. 9_). В простейшем случае он сохранит либо "старое", либо "новое" значение, пришедшее на вход данных D в непосредственной близости от фронта клока, но какое именно — неизвестно. Однако иногда "звёзды сойдутся", и триггер окажется в метастабильном состоянии. Вероятность этого крайне мала (о таком событии можно сказать, что оно "одно на миллиард"), однако не стоит относиться к нему с пренебрежением. Если схема работает на частоте в 1ГГц, триггер будет обновлять своё состояние миллиард раз в секунду, а сама схема может содержать миллионы триггеров. В таком контексте, фраза "одно на миллиард" означает не "ничего страшного, скорее при моей жизни этого не произойдёт", а "чёрт, кажется, что поэтому у меня ничего не работает".
|
||||
These two parameters define a timing window around the clock edge during which the input signal must remain stable. Violating these requirements leads to undefined flip-flop behaviour (see _fig. 9_). In the simplest case, the flip-flop will capture either the "old" or the "new" value that arrived at data input D in the vicinity of the clock edge, but which one is unknown. However, sometimes "the stars align" and the flip-flop enters a metastable state. The probability of this is extremely low (the kind of event described as "one in a billion"), yet it should not be dismissed. If a circuit operates at 1 GHz, the flip-flop updates its state one billion times per second, and the circuit itself may contain millions of flip-flops. In that context, "one in a billion" does not mean "nothing to worry about, it probably won't happen in my lifetime" — it means "damn, that's apparently why nothing works."
|
||||
|
||||

|
||||
|
||||
_Рисунок 9. Пример нарушения временны́х параметров D-триггера [[4](https://habr.com/ru/articles/254869/)]._
|
||||
_Figure 9. Example of D flip-flop timing parameter violations [[4](https://habr.com/ru/articles/254869/)]._
|
||||
|
||||
На _рис. 9_ показано три различных исхода нарушения временных ограничений:
|
||||
_Figure 9_ shows three possible outcomes of a timing violation:
|
||||
|
||||
1. Выход триггера Q<sub>1</sub> принял новое значение сигнала D, которое было установлено во временном промежутке T<sub>setup</sub>.
|
||||
2. Выход триггера Q<sub>2</sub> принял старое значение сигнала D, которое было установлено на входе до начала T<sub>setup</sub>. На следующем положительном фронте clk на входе D находится уже установившееся значение, которое без проблем записывается в триггер.
|
||||
3. Перемена в уровне во время T<sub>setup</sub> привело к тому, что на триггер было подано напряжение, равное половине уровня логической единицы, и тот оказался в метастабильном состоянии. Спустя некоторое время, триггер оказался в одном из стабильных состояний, но в каком — никто заранее предсказать не может (заштрихованная область, где триггер принял значение либо 0, либо 1). На следующем положительном фронте clk на входе D находится уже установившееся значение, которое без проблем записывается в триггер.
|
||||
1. Flip-flop output Q<sub>1</sub> captured the new value of signal D that was established within the T<sub>setup</sub> window.
|
||||
2. Flip-flop output Q<sub>2</sub> captured the old value of signal D that was established before T<sub>setup</sub> began. On the next positive clock edge, input D already holds a settled value, which is captured without issue.
|
||||
3. A signal transition during T<sub>setup</sub> caused a voltage equal to half the logic-high level to reach the flip-flop, pushing it into a metastable state. After some time the flip-flop settled into one of the stable states, but which one cannot be predicted in advance (shown as the hatched region where the flip-flop took either 0 or 1). On the next positive clock edge, input D already holds a settled value, which is captured without issue.
|
||||
|
||||
Нарушение по T<sub>setup</sub> обычно происходит, когда схема работает на частоте, не подходящей для имеющегося у схемы критического пути. Критический путь — это комбинационная часть цифровой схемы с наибольшей задержкой распространения сигнала. Время прохождения сигнала по этому пути характеризует минимально возможный период тактового сигнала и, соответственно, максимальную тактовую частоту работы всей схемы.
|
||||
A T<sub>setup</sub> violation typically occurs when the circuit is clocked at a frequency incompatible with the circuit's critical path. The critical path is the combinational portion of the digital circuit with the greatest signal propagation delay. The propagation time along this path determines the minimum achievable clock period and, consequently, the maximum operating frequency of the entire circuit.
|
||||
|
||||
Если подать на схему частоту, превышающую ограничение, определяемое критическим путём, сигнал может не принять установившееся значение на конце критического пути и, если на этом конце находится вход триггера — будут нарушено его ограничение по времени предустановки T<sub>setup</sub>.
|
||||
If the circuit is driven at a frequency that exceeds the constraint imposed by the critical path, the signal may not have settled at the end of the critical path, and if a flip-flop input is located there, its T<sub>setup</sub> constraint will be violated.
|
||||
|
||||
Нарушение по T<sub>hold</sub> происходит, когда у схемы есть пути с задержкой распространения сигнала до элементов последовательностной логики, которая меньше минимально допустимой. Данные пути напрямую не влияют на значение максимальной частоты, но требуют добавления элементов задержки на кратчайшие пути. Такие пути, как правило, являются значительной проблемой при проектировании интегральных схем специального назначения (application-specific integrated circuit, **ASIC**).
|
||||
A T<sub>hold</sub> violation occurs when the circuit contains paths with a signal propagation delay to sequential logic elements that is shorter than the minimum permissible value. Such paths do not directly limit the maximum operating frequency, but they require the insertion of delay elements on the shortest paths. These paths are typically a significant concern in the design of application-specific integrated circuits (**ASICs**).
|
||||
|
||||
Допустим в схеме есть два регистра А и Б, задержка распространения сигнала между которыми меньше допустимой. В этом случае, в момент фронта синхроимпульса с выхода регистра А может начать распространяться изменение в уровне сигнала. Это изменение достигнет входа регистра Б в этом же такте, пока у того не завершилось время удержания T<sub>hold</sub>.
|
||||
Suppose a circuit contains two registers A and B whose signal propagation delay is shorter than the minimum allowed. In this case, at the moment of the clock edge, a level transition may begin propagating from the output of register A. This transition reaches the input of register B within the same clock cycle, before B's T<sub>hold</sub> interval has expired.
|
||||
|
||||
Для того чтобы определить, способна ли проектируемая схема работать на целевой частоте, выполняется **статический временной анализ** (**static timing analysis**, **STA**). В процессе STA, САПР рассчитывает задержки всех временных путей схемы и определяет критический путь. Итогом статического временного анализа является оценка запаса по времени (или времени простоя, англ.: slack) для каждого временного пути, когда схема работает на заданной частоте. Если slack положительный — это значит, что задержка критического пути схемы меньше предельно допустимой, и возможно увеличение частоты схемы (например, при небольшом снижении напряжения питания) в пределах данной величины. Если slack отрицательный — это значит, что задержка по критическому пути уже превысила допустимую, и для корректной работы схемы необходимо либо изменить критический путь таким образом, чтобы сократилась его задержка распространения сигнала, либо уменьшить тактовую частоту.
|
||||
To determine whether a circuit under design is capable of operating at the target frequency, **static timing analysis** (**STA**) is performed. During STA, the EDA tool calculates the propagation delays of all timing paths and identifies the critical path. The result of static timing analysis is the timing slack for each path when the circuit operates at the specified frequency. A positive slack indicates that the critical path delay is below the maximum allowed value, meaning the circuit frequency could potentially be increased (for example, by slightly reducing the supply voltage) by up to that margin. A negative slack indicates that the critical path delay already exceeds the allowed limit, and correct circuit operation requires either modifying the critical path to reduce its propagation delay or reducing the clock frequency.
|
||||
|
||||
К сожалению, соблюсти временны́е ограничения триггеров не всегда возможно, поскольку в некоторых случаях, вход данных может по своей природе быть асинхронен (т.е. никаким образом не зависеть от входного тактового сигнала). К примеру, данные на вход триггера подаются со входа цифровой схемы, который подключён к кнопке, нажатие на которую никак не привязано к тактовому синхроимпульсу. В других случаях, необходимо передать данные, синхронизированные с одним тактовым сигналом, в область схемы, работающей от другого тактового сигнала. Подобная ситуация называется **пересечением тактовых доменов**, или **clock domain crossing** (**CDC**). В зависимости от конкретного сценария, существуют различные схемы синхронизации, самой простой из которых является установка дополнительного триггера там, где прогнозируется возникновение метастабильного состояния (рис. 10). В высокой долей вероятности в течении 1-2 тактов на выходе синхронизирующего триггера окажется стабильное состояние, которое подавалось на вход Din. Неопределённость в количестве тактов появляется из-за того, что мы не знаем, в какую сторону "свалится" состояние первого регистра в цепи.
|
||||
Unfortunately, it is not always possible to meet flip-flop timing constraints, because in some cases the data input is inherently asynchronous (i.e., completely independent of the clock signal). For example, data may arrive at a flip-flop input from an external pin connected to a button press, which bears no relation to the clock. In other cases, data synchronized to one clock domain must be transferred to a region of the circuit operating from a different clock. This situation is called a **clock domain crossing** (**CDC**). Depending on the specific scenario, various synchronization circuits exist; the simplest is the insertion of an extra flip-flop at the point where a metastable state is anticipated (_fig. 10_). With high probability the synchronizing flip-flop output will settle to a valid state within 1–2 clock cycles. The uncertainty in the number of cycles arises because we do not know in which direction the first register in the chain will "fall".
|
||||
|
||||

|
||||
|
||||
_Рисунок 10. Схема и временная диаграмма простейшего синхронизатора._
|
||||
_Figure 10. Circuit and timing diagram of the simplest synchronizer._
|
||||
|
||||
## Итоги главы
|
||||
## Chapter Summary
|
||||
|
||||
1. Цифровая логика делится на **комбинационную** и **последовательностную**.
|
||||
1. **Комбинационной** называют логику без памяти, выходы которой зависят только от её входов.
|
||||
2. **последовательностной** называют логику с памятью, выходы которой зависят не только от её входов, но и от её внутреннего состояния.
|
||||
2. Кроме того, цифровые схемы делят на **синхронные** и **асинхронные**.
|
||||
1. **Синхронными** называют последовательностные схемы, состояние которых меняется синхронно фронту тактового сигнала.
|
||||
2. **Асинхронными** называют как комбинационные схемы, так и последовательностные схемы, изменение состояния которых может происходить без привязки к фронту тактового сигнала.
|
||||
3. Существуют синхронные схемы с асинхронными сигналами предустановки/сброса. В большинстве случаев, они рассматриваются как обычные синхронные схемы, но их асинхронная логика предустановки/сброса, должна учитываться при расчёте **критического пути**.
|
||||
3. **Критический путь** — это часть цифровой схемы с наибольшей задержкой распространения сигнала, на пути которой не встречаются элементы синхронной логики.
|
||||
4. **Статическая память** — это тип памяти, который сохраняет данные в течение неопределённого времени, пока его питание остаётся включённым, без необходимости регенерации.
|
||||
5. **Динамическая память** — это тип памяти, использующий для хранения конденсаторы, что приводит к необходимости в регулярном обновлении содержимого памяти для того, чтобы не утратить данные.
|
||||
6. Основой статической памяти является **бистабильная ячейка**.
|
||||
7. **Бистабильная ячейка** — элемент, способный сохранять одно из двух устойчивых состояний, соответствующих цифровым значениям «0» или «1».
|
||||
8. Простейшей бистабильной ячейкой является петля из двух инверторов. Недостатком данной реализации является отсутствие возможности подать данные в эту ячейку извне. Этот недостаток решается преобразованием цепи в **RS-триггер**.
|
||||
9. **RS-триггер** — это бистабильная ячейка, имеющая два входа: сброс (reset, R) и установка (set, S). Данная ячейка может быть построена на паре логических вентилей ИЛИ-НЕ или И-НЕ. Недостатком данной бистабильной ячейки является наличие запрещённой комбинации входных сигналов, которая может привести к непредсказуемому поведению. Данный недостаток может быть разрешён путём добавления в схему дополнительной логики, из которой получается **D-защёлка**.
|
||||
10. **D-защёлка** — это бистабильная ячейка, имеющая два входа: сигнал разрешения записи (`E` / `clk`), и сигнал входных данных (D). Пока сигнал `E` активен, данные со входа `D` сохраняются в D-защёлку и идут на её выход (в таких случаях говорят, что защёлка "прозрачна"). Несмотря на то, что D-защёлка разрешает проблему запрещённого состояния RS-триггера, всё то время, пока она "прозрачна", она пропускает через себя все переходные процессы входных сигналов.
|
||||
11. **D-триггер** — это бистабильная ячейка, которая подобно D-защёлке имеет входы `clk` и `D`, но который сохраняет данные только в момент одного из фронтов тактового синхроимпульса (положительного или отрицательного фронта). Как и любые бистабильные ячейки, D-триггер подвержен явлению **метастабильности**. Метастабильность в D-триггере может возникнуть, если данные на входе `D` меняются во временном окне, расположенном в окрестностях фронта тактового синхроимпульса, определяемом следующими двумя параметрами:
|
||||
1. T<sub>setup</sub> (**setup time**) — **время предустановки**. Это интервал, в течение которого сигнал на входе должен оставаться неизменным перед наступлением фронта тактового сигнала.
|
||||
2. T<sub>hold</sub> (**hold time**) — **время удержания**. Это интервал, в течение которого сигнал на входе должен оставаться стабильным после наступления фронта тактового сигнала.
|
||||
12. **Метастабильное состояние** — это состояние бистабильной ячейки, при котором та не находится ни в одном из стабильных цифровых состояниях `0`/`1`, находясь при этом примерно посередине между ними. Через неопределённый промежуток времени (длину которого можно оценить с точки зрения вероятностей) бистабильная ячейка может выйти из этого состояния, приняв любое из значений `0`/`1`.
|
||||
13. В большинстве случаев метастабильность является нежелательным явлением в цифровой схеме. Причиной такого явления может стать работа схемы на частоте, не подходящей для имеющегося у данной схемы критического пути. Для того, чтобы узнать, сможет ли схема работать на заданной частоте, проводится **статический временной анализ** (**static timing analysis**, **STA**).
|
||||
14. Метастабильность может возникнуть и в случае, если сигнал данных по своей природе является асинхронным тактовому сигналу бистабильной ячейки: он может передаваться по событиям из внешнего мира, или с выхода бистабильных ячеек, работающих от других тактовых синхроимпульсов (подобная ситуация называется **пересечением тактовых доменов**, **clock domain crossing**, **CDC**).
|
||||
1. Digital logic is divided into **combinational** and **sequential** logic.
|
||||
1. **Combinational** logic is memoryless logic whose outputs depend only on its inputs.
|
||||
2. **Sequential** logic is logic with memory whose outputs depend not only on its inputs but also on its internal state.
|
||||
2. Digital circuits are also divided into **synchronous** and **asynchronous**.
|
||||
1. **Synchronous** circuits are sequential circuits whose state changes synchronously with the clock edge.
|
||||
2. **Asynchronous** circuits include both combinational circuits and sequential circuits whose state can change independently of the clock edge.
|
||||
3. Synchronous circuits with asynchronous preset/reset signals exist. In most cases they are treated as ordinary synchronous circuits, but their asynchronous preset/reset logic must be taken into account when calculating the **critical path**.
|
||||
3. The **critical path** is the portion of a digital circuit with the greatest signal propagation delay along which no synchronous logic elements are encountered.
|
||||
4. **Static memory** is a type of memory that retains data indefinitely as long as power is supplied, without requiring refresh cycles.
|
||||
5. **Dynamic memory** is a type of memory that uses capacitors for storage, requiring periodic refresh of memory contents to prevent data loss.
|
||||
6. The foundation of static memory is the **bistable cell**.
|
||||
7. A **bistable cell** is an element capable of holding one of two stable states corresponding to the digital values "0" or "1".
|
||||
8. The simplest bistable cell is a loop of two inverters. Its drawback is the absence of any means to write data from outside. This drawback is resolved by converting the circuit into an **RS latch**.
|
||||
9. An **RS latch** is a bistable cell with two inputs: reset (R) and set (S). It can be built from a pair of NOR or NAND gates. The drawback of this bistable cell is the existence of a forbidden input combination that can lead to unpredictable behaviour. This drawback can be resolved by adding extra logic to obtain a **D latch**.
|
||||
10. A **D latch** is a bistable cell with two inputs: a write-enable signal (`E` / `clk`) and a data input (D). While signal `E` is active, data from input `D` is stored in the D latch and appears at its output (the latch is said to be "transparent"). Although the D latch eliminates the forbidden state of the RS latch, it propagates all transients on the input signals for the entire time it is transparent.
|
||||
11. A **D flip-flop** is a bistable cell that, like a D latch, has `clk` and `D` inputs, but captures data only at one of the clock edges (positive or negative). Like all bistable cells, the D flip-flop is susceptible to **metastability**. Metastability in a D flip-flop can occur if the data at input `D` changes within the timing window around the clock edge defined by the following two parameters:
|
||||
1. T<sub>setup</sub> (**setup time**) — the interval during which the input signal must remain stable before the clock edge arrives.
|
||||
2. T<sub>hold</sub> (**hold time**) — the interval during which the input signal must remain stable after the clock edge arrives.
|
||||
12. The **metastable state** is a state of a bistable cell in which it is not in either stable digital state `0`/`1`, but instead sits approximately midway between them. After an indeterminate period of time (whose duration can only be estimated probabilistically), the bistable cell may exit this state and settle to either `0` or `1`.
|
||||
13. In most cases metastability is an undesirable phenomenon in a digital circuit. It can be caused by operating the circuit at a frequency incompatible with the circuit's critical path. To determine whether the circuit can operate at a given frequency, **static timing analysis** (**STA**) is performed.
|
||||
14. Metastability can also occur when the data signal is inherently asynchronous to the bistable cell's clock: it may be driven by external-world events or by bistable cells operating from different clocks (a situation called a **clock domain crossing**, **CDC**).
|
||||
|
||||
## Список источников
|
||||
## References
|
||||
|
||||
1. [Д.М. Харрис, С.Л. Харрис / Цифровая схемотехника и архитектура компьютера: RISC-V / пер. с англ. В. С. Яценков, А. Ю. Романов; под. ред. А. Ю. Романова / М.: ДМК Пресс, 2021](https://e.lanbook.com/book/241166);
|
||||
1. D.M. Harris, S.L. Harris / Digital Design and Computer Architecture. RISC-V Edition, 2021;
|
||||
2. Xilinx / [The Programmable Gate Array Data Book](https://archive.org/details/programmablegate00xili);
|
||||
3. J. Wakerly, Digital Design: Principles and Practices (5th Edition). Pearson, 2017;
|
||||
4. [Метастабильность триггера и межтактовая синхронизация](https://habr.com/ru/articles/254869/).
|
||||
4. [Flip-flop metastability and clock domain synchronization](https://habr.com/ru/articles/254869/).
|
||||
|
||||
@@ -1,65 +1,65 @@
|
||||
# Что такое язык описания аппаратуры (HDL)
|
||||
# What is a Hardware Description Language (HDL)
|
||||
|
||||
На заре появления цифровой электроники, [цифровые схемы](How%20FPGA%20works.md#Цифровые-схемы) в виде диаграммы на бумаге были маленькими, а их реализация в виде физической аппаратуры — большой. В процессе развития электроники (и её преобразования в микроэлектронику) цифровые схемы на бумаге становились всё больше, а относительный размер их реализации в виде физических микросхем — всё меньше. На _рис. 1_, вы можете увидеть цифровую схему устройства Intel 4004, выпущенного в 1971 году.
|
||||
In the early days of digital electronics, [digital circuits](How%20FPGA%20works.md#Digital-circuits) drawn on paper were small, while their physical hardware implementations were large. As electronics evolved into microelectronics, the paper diagrams grew increasingly complex, while the physical size of their chip implementations shrank dramatically. In _Fig. 1_, you can see the digital circuit of the Intel 4004 processor, released in 1971.
|
||||
|
||||

|
||||
|
||||
_Рисунок 1. Цифровая схема процессора Intel 4004 на уровне транзисторов[[1]](https://www.4004.com/mcs4-masks-schematics-sim.html)._
|
||||
_Figure 1. Digital circuit of the Intel 4004 processor at the transistor level [[1]](https://www.4004.com/mcs4-masks-schematics-sim.html)._
|
||||
|
||||
Данная микросхема состоит из 2300 транзисторов[[2]](https://en.wikipedia.org/wiki/Intel_4004).
|
||||
This chip contains 2,300 transistors [[2]](https://en.wikipedia.org/wiki/Intel_4004).
|
||||
|
||||
За прошедшие полсотни лет сложность цифровых схем выросла колоссально. Современные процессоры для настольных компьютеров состоят из десятков миллиардов транзисторов. Диаграмма выше при печати в оригинальном размере займет прямоугольник размером 115х140 см с площадью около 1.6 м<sup>2</sup>. Предполагая, что площадь печати имеет прямо пропорциональную зависимость от количества транзисторов, получим, что распечатка схемы современного процессора из 23 млрд транзисторов заняла бы площадь в 16млн м<sup>2</sup>, что эквивалентно квадрату со стороной в 4км.
|
||||
Over the past fifty years, the complexity of digital circuits has grown enormously. Modern desktop processors contain tens of billions of transistors. If printed at its original scale, the diagram above would occupy a rectangle of 115×140 cm, with an area of about 1.6 m<sup>2</sup>. Assuming that the print area scales linearly with the transistor count, printing the circuit of a modern processor with 23 billion transistors would require an area of 16 million m<sup>2</sup> — equivalent to a square with a side length of 4 km.
|
||||
|
||||
<img src="../.pic/Introduction/What%20is%20HDL/ancient_city.png" alt="Старый город" width="400"/>
|
||||
<img src="../.pic/Introduction/What%20is%20HDL/ancient_city.png" alt="Ancient city" width="400"/>
|
||||
|
||||
_Рисунок 2. Масштаб размеров, которых могли бы достигать цифровые схемы современных процессоров, если бы они печатались на бумаге._
|
||||
_Figure 2. The scale that digital circuit diagrams of modern processors would reach if printed on paper._
|
||||
|
||||
Как вы можете догадаться, в какой-то момент между 1971-м и 2024-м годами инженеры перестали разрабатывать цифровые схемы, рисуя их на бумаге.
|
||||
As you might guess, at some point between 1971 and 2024, engineers stopped designing digital circuits by drawing them on paper.
|
||||
|
||||
Разумеется, разрабатывая устройство, не обязательно вырисовывать на схеме каждый транзистор — можно управлять сложностью, переходя с одного уровня абстракции на другой. Например, начинать разработку схемы с уровня функциональных блоков, а затем рисовать схему для каждого отдельного блока.
|
||||
Of course, when designing a device, it is not necessary to draw every transistor on a schematic — complexity can be managed by moving between levels of abstraction. For example, one can start designing at the level of functional blocks, and then draw the schematic for each individual block.
|
||||
|
||||
К примеру, схему Intel 4004 можно представить в следующем виде:
|
||||
For instance, the Intel 4004 circuit can be represented as follows:
|
||||
|
||||
<img src="../.pic/Introduction/What%20is%20HDL/4004_arch.png" alt="../.pic/Introduction/What%20is%20HDL/4004_arch.png" width="500"/>
|
||||
|
||||
_Рисунок 3. Цифровая схема процессора Intel 4004 на уровне функциональных блоков[[2]](https://en.wikipedia.org/wiki/Intel_4004)._
|
||||
_Figure 3. Digital circuit of the Intel 4004 processor at the functional block level [[2]](https://en.wikipedia.org/wiki/Intel_4004)._
|
||||
|
||||
Однако несмотря на это, даже отдельные блоки порой бывают довольно сложны. Возьмем блок аппаратного шифрования по алгоритму AES[[3]](https://csrc.nist.gov/files/pubs/fips/197/final/docs/fips-197.pdf) на рисунке 4:
|
||||
However, even individual blocks can sometimes be quite complex. Consider the hardware AES encryption block [[3]](https://csrc.nist.gov/files/pubs/fips/197/final/docs/fips-197.pdf) shown in Figure 4:
|
||||
|
||||

|
||||
|
||||
_Рисунок 4. Цифровая схема блока аппаратного шифрования по алгоритму AES[[4]](https://iis-people.ee.ethz.ch/~kgf/acacia/acacia_thesis.pdf)._
|
||||
_Figure 4. Digital circuit of a hardware AES encryption block [[4]](https://iis-people.ee.ethz.ch/~kgf/acacia/acacia_thesis.pdf)._
|
||||
|
||||
Заметьте, что даже этот блок не представлен на уровне отдельных транзисторов. Каждая операция Исключающего ИЛИ, умножения, мультиплексирования сигнала и таблицы подстановки — это отдельные блоки, функционал которых ещё надо реализовать.
|
||||
В какой-то момент инженеры поняли, что проще описать цифровую схему в текстовом представлении, нежели в графическом.
|
||||
Note that even this block is not shown at the individual transistor level. Each XOR operation, multiplication, signal multiplexing, and substitution table is a separate block whose functionality still needs to be implemented.
|
||||
At some point, engineers realized it was simpler to describe a digital circuit in textual form rather than graphical form.
|
||||
|
||||
Как можно описать цифровую схему текстом? Рассмотрим цифровую схему полусумматора:
|
||||
How can a digital circuit be described in text? Let us consider the digital circuit of a half-adder:
|
||||
|
||||

|
||||

|
||||
|
||||
_Рисунок 5. Цифровая схема полусумматора на уровне логических вентилей._
|
||||
_Figure 5. Digital circuit of a half-adder at the logic gate level._
|
||||
|
||||
Это **устройство** (_полусумматор_) имеет два **входа**: _a_ и _b_, а также два **выхода**: _sum_ и _carry_.
|
||||
Выход _sum_ является **результатом** логической операции **Исключающее ИЛИ** от операндов _a_ и _b_.
|
||||
Выход _carry_ является **результатом** логической операции **И** от операндов _a_ и _b_.
|
||||
This **module** (_half-adder_) has two **inputs**: _a_ and _b_, and two **outputs**: _sum_ and _carry_.
|
||||
The _sum_ output is the **result** of the logical **XOR** operation on operands _a_ and _b_.
|
||||
The _carry_ output is the **result** of the logical **AND** operation on operands _a_ and _b_.
|
||||
|
||||
Текст выше и является тем описанием, по которому можно воссоздать эту цифровую схему. Если стандартизировать описание схемы, то в нем можно будет оставить только слова, выделенные жирным и курсивом. Пример того, как можно было бы описать эту схему по стандарту IEEE 1364-2005 (язык описания аппаратуры (Hardware Description Language — HDL) Verilog):
|
||||
The text above is precisely the description from which this digital circuit can be reconstructed. If the description is standardized, only the words in bold and italics need to be retained. The following is an example of how this circuit could be described according to the IEEE 1364-2005 standard (the Verilog Hardware Description Language — HDL):
|
||||
|
||||
```Verilog
|
||||
module half_sum( // устройство полусумматор cо
|
||||
input a, // входом a,
|
||||
input b, // входом b,
|
||||
output sum, // выходом sum и
|
||||
output carry // выходом carry.
|
||||
module half_sum( // module half-adder with
|
||||
input a, // input a,
|
||||
input b, // input b,
|
||||
output sum, // output sum and
|
||||
output carry // output carry.
|
||||
);
|
||||
|
||||
assign sum = a ^ b; // Где выход sum является результатом Исключающего ИЛИ от a и b,
|
||||
assign carry = a & b; // а выход carry является результатом логического И от a и b.
|
||||
assign sum = a ^ b; // Where output sum is the result of XOR of a and b,
|
||||
assign carry = a & b; // and output carry is the result of logical AND of a and b.
|
||||
|
||||
endmodule
|
||||
```
|
||||
|
||||
На первый взгляд такое описание выглядит даже больше, чем записанное естественным языком, однако видимый объем получен только за счёт переноса строк и некоторой избыточности в описании входов и выходов, которая была добавлена для повышения читаемости. То же самое описание можно было записать и в виде:
|
||||
At first glance, this description appears even longer than the natural-language version. However, the extra length comes only from line breaks and some redundancy in the port declarations, which was added to improve readability. The same description could also be written as:
|
||||
|
||||
```Verilog
|
||||
module half_sum(input a, b, output sum, carry);
|
||||
@@ -68,16 +68,16 @@ module half_sum(input a, b, output sum, carry);
|
||||
endmodule
|
||||
```
|
||||
|
||||
Важно отметить, что код на языке Verilog описывает устройство целиком, одномоментно. Это **описание схемы** выше, а **не построчное выполнение программы**.
|
||||
It is important to note that Verilog code describes the device as a whole, all at once. It's a **description of a circuit**, not **line-by-line program execution**.
|
||||
|
||||
С практикой описание схемы в текстовом виде становится намного проще и не требует графического представления. Для описания достаточно только спецификации: формальной записи того, как должно работать устройство. По ней разрабатывается алгоритм, который затем претворяется в описание на HDL.
|
||||
With practice, describing a circuit in text becomes much easier and requires no graphical representation. A specification — a formal statement of how the device should behave — is sufficient. From it, an algorithm is developed, which is then expressed as an HDL description.
|
||||
|
||||
Занятный факт: ранее было высказано предположение о том, что инженеры перестали разрабатывать устройства, рисуя цифровые схемы в промежуток времени между 1971-м и 2024-м годами. Так вот, первая конференция, посвящённая языкам описания аппаратуры состоялась в 1973-м году[[5, стр. 8]](https://dl.acm.org/doi/pdf/10.1145/3386337). Таким образом, Intel 4004 можно считать одним из последних цифровых устройств, разработанных без использования языков описания аппаратуры.
|
||||
An interesting fact: it was mentioned earlier that engineers stopped designing devices by drawing digital circuits sometime between 1971 and 2024. The first conference dedicated to hardware description languages was held in 1973 [[5, p. 8]](https://dl.acm.org/doi/pdf/10.1145/3386337). Thus, the Intel 4004 can be considered one of the last digital devices designed without the use of hardware description languages.
|
||||
|
||||
## Список источников
|
||||
## References
|
||||
|
||||
1. [Intel 4004 — 50th Anniversary Project](https://www.4004.com/mcs4-masks-schematics-sim.html);
|
||||
2. [Страница википедии по Intel 4004](https://en.wikipedia.org/wiki/Intel_4004);
|
||||
3. [F.Ka˘gan. Gürkaynak / Side Channel Attack Secure Cryptographic Accelerators](https://iis-people.ee.ethz.ch/~kgf/acacia/acacia_thesis.pdf);
|
||||
4. [FIPS 197, Advanced Encryption Standart (AES)](https://csrc.nist.gov/files/pubs/fips/197/final/docs/fips-197.pdf);
|
||||
2. [Wikipedia page on Intel 4004](https://en.wikipedia.org/wiki/Intel_4004);
|
||||
3. [F. Kağan Gürkaynak / Side Channel Attack Secure Cryptographic Accelerators](https://iis-people.ee.ethz.ch/~kgf/acacia/acacia_thesis.pdf);
|
||||
4. [FIPS 197, Advanced Encryption Standard (AES)](https://csrc.nist.gov/files/pubs/fips/197/final/docs/fips-197.pdf);
|
||||
5. [P. Flake, P. Moorby, S. Golson, A. Salz, S. Davidmann / Verilog HDL and Its Ancestors and Descendants](https://dl.acm.org/doi/pdf/10.1145/3386337).
|
||||
|
||||
@@ -1,121 +1,119 @@
|
||||
# Лабораторная работа №1 "Сумматор"
|
||||
# Lab 1 "Adder"
|
||||
|
||||
## Цель
|
||||
## Goal
|
||||
|
||||
Познакомиться с САПР Vivado и научиться реализовывать в нём простейшие схемотехнические модули с помощью конструкций языка SystemVerilog.
|
||||
Get familiar with the Vivado EDA tool and learn how to implement basic circuit modules using SystemVerilog language constructs.
|
||||
|
||||
## Материал для подготовки к лабораторной работе
|
||||
## Preparation Materials
|
||||
|
||||
[Описание модулей на языке SystemVerilog](../../Basic%20Verilog%20structures/Modules.md).
|
||||
[Describing modules in SystemVerilog](../../Basic%20Verilog%20structures/Modules.md).
|
||||
|
||||
## Ход работы
|
||||
## Workflow
|
||||
|
||||
1. Изучение 1-битного сумматора;
|
||||
2. Воспроизведение примера по реализации и проверке полусумматора.
|
||||
3. Реализация и проверка полного 1-битного сумматора
|
||||
4. Изучение 4-битного сумматора;
|
||||
5. Реализация и проверка полного 4-битного сумматора;
|
||||
6. Реализация и проверка полного 32-битного сумматора.
|
||||
1. Study the 1-bit adder;
|
||||
2. Reproduce the example of implementing and verifying a half adder.
|
||||
3. Implement and verify a full 1-bit adder
|
||||
4. Study the 4-bit adder;
|
||||
5. Implement and verify a full 4-bit adder;
|
||||
6. Implement and verify a full 32-bit adder.
|
||||
|
||||
## Теория
|
||||
## Theory
|
||||
|
||||
Итогом лабораторной работы будет создание устройства, способного складывать два числа. Но перед тем, как учиться создавать подобное устройство, необходимо немного освоиться в самом процессе складывания чисел.
|
||||
The outcome of this lab will be a device capable of adding two numbers. But before learning how to build such a device, it is necessary to get comfortable with the addition process itself.
|
||||
|
||||
Давайте начнём с примера и сложим в столбик произвольную пару чисел, например 42 и 79:
|
||||
Let's start with an example and add a pair of numbers in column format, say 42 and 79:
|
||||
|
||||

|
||||
|
||||
```text
|
||||
2 + 9 = 11 ➨ 1 пишем, 1 "в уме"
|
||||
4 + 7 + "1 в уме" = 12 ➨ 2 пишем, 1 "в уме"
|
||||
0 + 0 + "1 в уме" = 1
|
||||
2 + 9 = 11 ➨ write 1, carry 1
|
||||
4 + 7 + carry 1 = 12 ➨ write 2, carry 1
|
||||
0 + 0 + carry 1 = 1
|
||||
```
|
||||
|
||||
Итого, 121.
|
||||
Total: 121.
|
||||
|
||||
Назовём то, что мы звали "1 в уме", переносом разряда.
|
||||
|
||||
Теперь попробуем сделать то же самое, только в двоичной системе исчисления. К примеру, над числами 3 и 5. Три в двоичной системе записывается как 011. Пять записывается как 101.
|
||||
Now let's do the same thing in binary. For example, with the numbers 3 and 5. Three in binary is 011. Five is 101.
|
||||
|
||||

|
||||
|
||||
Поскольку в двоичной системе всего две цифры: 0 и 1, один разряд не может превысить 1. Складывая числа 1 и 1, вы получаете 2, что не умещается в один разряд, поэтому мы пишем 0 и держим 1 "в уме". Это снова перенос разряда. Поскольку в двоичной арифметике разряд называют битом, перенос разряда можно назвать переносом бита, а сам разряд, который перенесли — битом переноса.
|
||||
Since binary has only two digits — 0 and 1 — a single bit cannot exceed 1. When adding 1 and 1, you get 2, which does not fit in one bit, so we write 0 and carry 1. This is again a carry. Since binary digits are called bits, the carry is called a carry bit.
|
||||
|
||||
### Полный 1-битный сумматор
|
||||
### Full 1-bit Adder
|
||||
|
||||
Полный 1-битный сумматор — это цифровое устройство, которое выполняет сложение двух 1-битных чисел и учитывает входной бит переноса. Это устройство имеет три входа: два слагаемых и входной бит переноса, а также два выхода: 1-битный результат суммы и выходной бит переноса.
|
||||
A full 1-bit adder is a digital device that adds two 1-bit numbers and accounts for an incoming carry bit. It has three inputs — two operands and a carry-in — and two outputs: a 1-bit sum result and a carry-out.
|
||||
|
||||
Что такое входной бит переноса? Давайте вспомним второй этап сложения чисел 42 и 79:
|
||||
What is the carry-in? Let's recall the second step of adding 42 and 79:
|
||||
|
||||
```text
|
||||
4 + 7 + "1 в уме" = 12 ➨ 2 пишем, 1 "в уме"
|
||||
4 + 7 + carry 1 = 12 ➨ write 2, carry 1
|
||||
```
|
||||
|
||||
**+ "1 в уме"** — это прибавление разряда, перенесённого с предыдущего этапа сложения.
|
||||
**+ carry 1** — this is the addition of the carry bit propagated from the previous step.
|
||||
|
||||
Входной бит переноса — это бит, перенесённый с предыдущего этапа сложения двоичных чисел. Имея этот сигнал, мы можем складывать многоразрядные двоичные числа путём последовательного соединения нескольких 1-битных сумматоров: выходной бит переноса сумматора младшего разряда передастся на входной бит переноса сумматора старшего разряда.
|
||||
The carry-in is the bit propagated from the previous stage of binary addition. With this signal, we can add multi-bit binary numbers by chaining multiple 1-bit adders: the carry-out of the lower-order adder is fed into the carry-in of the higher-order adder.
|
||||
|
||||
### Реализация одноразрядного сложения
|
||||
### Single-bit Addition Implementation
|
||||
|
||||
Можно ли как-то описать сложение двух одноразрядных двоичных чисел с помощью логических операций? Давайте посмотрим на таблицу истинности подобной операции:
|
||||
Can single-bit binary addition be described using logical operations? Let's look at the truth table for this operation:
|
||||
|
||||

|
||||
|
||||
_Таблица истинности одноразрядного сложения._
|
||||
_Truth table for single-bit addition._
|
||||
|
||||
`S` — это младший разряд 2-битного результата суммы, записываемый в столбце сложения под слагаемыми `a` и `b`. `C` (_carry_, перенос) — это старший разряд суммы, записываемый левее, если произошёл перенос разряда. Как мы видим, перенос разряда происходит только в случае, когда оба числа одновременно равны единице. При этом значение `S` обращается в `0`, и результат записывается как `10`, что в двоичной системе означает `2`. Кроме того, значение `S` равно `0` и в случае, когда оба операнда одновременно равны нулю. Вы можете заметить, что `S` равно нулю в тех случаях, когда `а` и `b` равны, и не равно нулю в противоположном случае. Подобным свойством обладает логическая операция **Исключающее ИЛИ** (**eXclusive OR**, **XOR**), именно поэтому одно из других названий этой операции — сумма по модулю 2.
|
||||
`S` is the least significant bit of the 2-bit sum result, written in the sum column below operands `a` and `b`. `C` (_carry_) is the most significant bit of the sum, written to the left when a carry occurs. As we can see, a carry occurs only when both numbers are simultaneously equal to one. In this case, `S` becomes `0` and the result is written as `10`, which equals `2` in binary. Additionally, `S` equals `0` when both operands are simultaneously zero. You may notice that `S` is zero when `a` and `b` are equal, and non-zero otherwise. This property belongs to the **Exclusive OR** (**XOR**) logical operation, which is why another name for this operation is "sum modulo 2".
|
||||
|
||||

|
||||
|
||||
_Таблица истинности операции Исключающее ИЛИ (XOR)._
|
||||
_Truth table for the Exclusive OR (XOR) operation._
|
||||
|
||||
Для бита переноса всё ещё проще — он описывается операцией **логическое И**:
|
||||
The carry bit is even simpler — it is described by the **logical AND** operation:
|
||||
|
||||

|
||||
|
||||
_Таблица истинности операции И._
|
||||
_Truth table for the AND operation._
|
||||
|
||||
На _рис. 1_ представлена цифровая схема, связывающая входные и выходные сигналы с помощью логических элементов, соответствующих ожидаемому поведению.
|
||||
_Fig. 1_ shows the digital circuit connecting inputs and outputs through logic gates that match the expected behavior.
|
||||
|
||||

|
||||
|
||||
_Рисунок 1. Цифровая схема устройства, складывающего два операнда с сохранением переноса (полусумматора)._
|
||||
_Figure 1. Digital circuit of a device that adds two operands with carry preservation (half adder)._
|
||||
|
||||
Однако, в описании полного 1-битного сумматора сказано, что у него есть три входа, а в наших таблицах истинности и на схеме выше их только два (схема, представленная на _рис. 1_, реализует так называемый "полусумматор"). На самом деле, на каждом этапе сложения в столбик мы всегда складывали три числа: цифру верхнего числа, цифру нижнего числа, и единицу в случае переноса разряда из предыдущего столбца (если с предыдущего разряда не было переноса, прибавление нуля неявно опускалось).
|
||||
However, the description of a full 1-bit adder states that it has three inputs, while our truth tables and the circuit above only have two (the circuit in _Fig. 1_ implements a so-called "half adder"). In fact, at every step of column addition we always add three numbers: the digit of the top number, the digit of the bottom number, and one in case of a carry from the previous column (if there was no carry from the previous digit, adding zero was implicitly omitted).
|
||||
|
||||
Таким образом, таблица истинности немного усложняется:
|
||||
Therefore, the truth table becomes slightly more complex:
|
||||
|
||||

|
||||
|
||||
_Таблица истинности сигналов полного 1-битного сумматора._
|
||||
_Truth table for a full 1-bit adder._
|
||||
|
||||
Поскольку теперь у нас есть и входной и выходной биты переноса, для их различия добавлены суффиксы "in" и "out".
|
||||
Since we now have both a carry-in and a carry-out, suffixes "in" and "out" are added to distinguish them.
|
||||
|
||||
Как в таком случае описать S? Например, как сумму по модулю 2 этих трёх слагаемых: `а ⊕ b ⊕ Cіn`. Давайте сравним такую операцию с таблицей истинности. Сумма по модуля 2 — это ассоциативная операция [`(a⊕b)⊕c = a⊕(b⊕с)`], т.е. порядок сложения не влияет на результат. Предположим, что Cin равен нулю. Сумма по модулю 2 с нулём даёт второй операнд (`a⊕0=a`), значит `(a⊕b)⊕0 = a⊕b`. Это соответствует верхней половине таблицы истинности для сигнала S, когда Cin равен нулю.
|
||||
Предположим, что Cin равен единице. Сумма по модулю 2 с единицей даёт нам отрицание второго операнда (`a⊕1=!a`), значит `(a⊕b) ⊕1=!(a⊕b)`. Это соответствует нижней половине таблицы истинности, когда Cin равен единице.
|
||||
How do we express S in this case? For example, as the sum modulo 2 of the three operands: `a ⊕ b ⊕ Cin`. Let's verify this against the truth table. Sum modulo 2 is an associative operation [`(a⊕b)⊕c = a⊕(b⊕c)`], meaning the order of addition does not affect the result. Assume Cin is zero. Sum modulo 2 with zero gives the second operand (`a⊕0=a`), so `(a⊕b)⊕0 = a⊕b`. This corresponds to the upper half of the truth table for signal S when Cin is zero.
|
||||
Assume Cin is one. Sum modulo 2 with one gives the negation of the second operand (`a⊕1=!a`), so `(a⊕b)⊕1=!(a⊕b)`. This corresponds to the lower half of the truth table when Cin is one.
|
||||
|
||||
Для выходного бита переноса всё гораздо проще. Он равен единице, когда хотя бы два из трех операндов равны единице, это значит, что необходимо попарно сравнить все операнды, и если найдется хоть одна такая пара, он равен единице. Это утверждение можно записать следующим образом:
|
||||
For the carry-out, things are simpler. It equals one when at least two of the three operands equal one, meaning we need to compare all pairs of operands and if any such pair is found, it equals one. This can be written as:
|
||||
|
||||
`Cоut = (a&b) | (а&Cіn) | (b&Cіn)`, где `&` — логическое И, `|` — логическое ИЛИ.
|
||||
`Cout = (a&b) | (a&Cin) | (b&Cin)`, where `&` is logical AND, `|` is logical OR.
|
||||
|
||||
Цифровая схема устройства с описанным поведением выглядит следующим образом:
|
||||
The digital circuit with this described behavior looks as follows:
|
||||
|
||||

|
||||
|
||||
_Рисунок 2. Цифровая схема полного 1-битного сумматора._
|
||||
_Figure 2. Digital circuit of a full 1-bit adder._
|
||||
|
||||
## Практика
|
||||
## Practice
|
||||
|
||||
Реализуем схему полусумматора (_рис. 1_) в виде модуля, описанного на языке SystemVerilog.
|
||||
Let's implement the half adder circuit (_Fig. 1_) as a module described in SystemVerilog.
|
||||
|
||||
Модуль `half_adder` имеет два входных сигнала и два выходных. Входы `a_i` и `b_i` идут на два логических элемента: Исключающее ИЛИ и И, выходы которых подключены к выходам модуля `sum_o` и `carry_o` соответственно.
|
||||
The `half_adder` module has two input signals and two output signals. Inputs `a_i` and `b_i` feed into two logic elements: Exclusive OR and AND, whose outputs are connected to module outputs `sum_o` and `carry_o` respectively.
|
||||
|
||||
```Verilog
|
||||
module half_adder(
|
||||
input logic a_i, // Входные сигналы
|
||||
input logic a_i, // Input signals
|
||||
input logic b_i,
|
||||
|
||||
output logic sum_o, // Выходные сигналы
|
||||
output logic sum_o, // Output signals
|
||||
output logic carry_o
|
||||
);
|
||||
|
||||
@@ -125,31 +123,31 @@ assign carry_o = a_i & b_i;
|
||||
endmodule
|
||||
```
|
||||
|
||||
_Листинг 1. SystemVerilog-код модуля half_adder._
|
||||
_Listing 1. SystemVerilog code for the half_adder module._
|
||||
|
||||
По данному коду, САПР может реализовать схему, представленную на рисунке 3.
|
||||
From this code, the EDA tool can implement the circuit shown in Figure 3.
|
||||
|
||||

|
||||
|
||||
_Рисунок 3. Цифровая схема модуля half_adder, сгенерированная САПР Vivado._
|
||||
_Figure 3. Digital circuit of the half_adder module generated by the Vivado EDA tool._
|
||||
|
||||
Схема похожа на _рис. 1_, но как проверить, что эта схема не содержит ошибок и делает именно то, что от неё ожидается?
|
||||
The circuit resembles _Fig. 1_, but how do we verify that this circuit is error-free and behaves as expected?
|
||||
|
||||
Для этого необходимо провести моделирование этой схемы. Во время моделирования на входы подаются тестовые воздействия. Каждое изменение входных сигналов приводит к каскадному изменению состояний внутренних цепей, что в свою очередь приводит к изменению значений на выходных сигналах схемы.
|
||||
To do this, we need to simulate the circuit. During simulation, test stimuli are applied to the inputs. Each change in input signals causes a cascading change in the states of internal nets, which in turn causes changes in the output signal values.
|
||||
|
||||
Подаваемые на схему входные воздействия формируются верификационным окружением. Верификационное окружение (в дальнейшем будет использован термин "**тестбенч**") — это особый несинтезируемый модуль, который не имеет входных или выходных сигналов. Эти сигналы ему не нужны, потому что он сам является генератором всех своих внутренних сигналов, и данный модуль не передаёт ничего вовне — только проверяет тестируемый модуль внутри себя.
|
||||
The test stimuli applied to the circuit are generated by the verification environment. The verification environment (hereafter referred to as a "**testbench**") is a special non-synthesizable module that has no input or output signals. It does not need them because it generates all its internal signals itself, and this module does not pass anything to the outside world — it only tests the design under test (DUT) internally.
|
||||
|
||||
Внутри тестбенча можно использовать конструкции из несинтезируемого подмножества языка SystemVerilog, в частности программный блок `initial`, в котором команды выполняются последовательно, что делает этот блок чем-то отдалённо похожим на проверяющую программу. Поскольку изменение внутренних цепей происходит с некоторой задержкой относительно изменений входных сигналов, при моделировании есть возможность делать паузы между командами. Это делается с помощью специального символа #, за которым указывается количество времени симуляции, которое нужно пропустить перед следующей командой.
|
||||
Inside the testbench, constructs from the non-synthesizable subset of SystemVerilog can be used, in particular the `initial` procedural block, in which statements execute sequentially, making this block somewhat similar to a test program. Since changes in internal nets occur with some delay relative to input signal changes, it is possible to insert pauses between statements during simulation. This is done using the special `#` symbol followed by the amount of simulation time to skip before the next statement.
|
||||
|
||||
Перед тем как писать верификационное окружение, необходимо составить план того, как будет проводиться проверка устройства (составить верификационный план). Ввиду предельной простоты устройства, план будет состоять из одного предложения:
|
||||
Before writing the verification environment, it is necessary to draft a plan for how the device will be verified (a verification plan). Given the extreme simplicity of the device, the plan consists of a single statement:
|
||||
|
||||
> Поскольку устройство не имеет внутреннего состояния, которое могло бы повлиять на результат, а число всех его возможных входных наборов воздействий равно четырём, мы можем проверить его работу, перебрав все возможные комбинации его входных сигналов.
|
||||
> Since the device has no internal state that could affect the result, and the total number of all possible input stimulus combinations equals four, we can verify its operation by exhausting all possible combinations of its input signals.
|
||||
|
||||
```Verilog
|
||||
module testbench(); // <- Не имеет ни входов, ни выходов!
|
||||
module testbench(); // <- Has neither inputs nor outputs!
|
||||
logic a, b, carry, sum;
|
||||
|
||||
half_adder DUT( // <- Подключаем проверяемый модуль
|
||||
half_adder DUT( // <- Connect the design under test
|
||||
.a_i (a ),
|
||||
.b_i (b ),
|
||||
.carry_o(carry),
|
||||
@@ -157,50 +155,50 @@ module testbench(); // <- Не имеет ни входов, ни
|
||||
);
|
||||
|
||||
initial begin
|
||||
a = 1'b0; b = 1'b0; // <- Подаём на входы модуля тестовые
|
||||
#10ns; // воздействия
|
||||
a = 1'b0; b = 1'b0; // <- Apply test stimuli to the module
|
||||
#10ns; // inputs
|
||||
a = 1'b0; b = 1'b1;
|
||||
#10ns; // <- Делаем паузу в десять наносекунд
|
||||
a = 1'b1; b = 1'b0; // перед очередным изменением
|
||||
#10ns; // входных сигналов
|
||||
#10ns; // <- Pause for ten nanoseconds before
|
||||
a = 1'b1; b = 1'b0; // the next input signal change
|
||||
#10ns;
|
||||
a = 1'b1; b = 1'b1;
|
||||
end
|
||||
endmodule
|
||||
```
|
||||
|
||||
_Листинг 2. SystemVerilog-код тестбенча для модуля half_adder._
|
||||
_Listing 2. SystemVerilog code for the half_adder testbench._
|
||||
|
||||

|
||||
|
||||
_Рисунок 4. Временная диаграмма, моделирующая работу схемы с рис. 3._
|
||||
_Figure 4. Timing diagram simulating the operation of the circuit from Fig. 3._
|
||||
|
||||
В данной лабораторной работе вам предстоит реализовать схему полного 1-битного сумматора (_рис. 2_). Модуль полусумматора, код которого представлен в _листинге 1_ не используется в лабораторной работе (он был дан только в качестве примера).
|
||||
In this lab, you will implement the full 1-bit adder circuit (_Fig. 2_). The half adder module whose code is shown in _Listing 1_ is not used in this lab (it was provided as an example only).
|
||||
|
||||
### Полный 4-битный сумматор
|
||||
### Full 4-bit Adder
|
||||
|
||||
До этого мы реализовали сложение в столбик только для одного разряда, теперь мы хотим реализовать всю операцию сложения в столбик. Как это сделать? Сделать ровно то, что делается при сложении в столбик: сначала сложить младший разряд, получить бит переноса для следующего разряда, сложить следующий и т.д.
|
||||
So far, we have implemented column addition for only one digit. Now we want to implement the full column addition operation. How? By doing exactly what column addition does: first add the least significant bit, obtain the carry for the next bit, add the next, and so on.
|
||||
|
||||
Давайте посмотрим, как это будет выглядеть на схеме (для простоты, внутренняя логика 1-битного сумматора скрыта, но вы должны помнить, что каждый прямоугольник — это та же самая схема с рис. 2).
|
||||
Let's look at how this appears as a circuit (for simplicity, the internal logic of the 1-bit adder is hidden, but remember that each rectangle is the same circuit from Fig. 2).
|
||||
|
||||

|
||||
|
||||
_Рисунок 5. Схема 4-битного сумматора._
|
||||
_Figure 5. 4-bit adder circuit._
|
||||
|
||||
Фиолетовой линией на схеме показаны провода, соединяющие выходной бит переноса сумматора предыдущего разряда с входным битом переноса сумматора следующего разряда.
|
||||
The purple lines in the circuit show the wires connecting the carry-out of one adder stage to the carry-in of the next stage.
|
||||
|
||||
Как же реализовать модуль, состоящий из цепочки других модулей? Половину этой задачи мы уже сделали, когда писали тестбенч к 1-битному полусумматору в _Листинге 2_ — мы создавали модуль внутри другого модуля и подключали к нему провода. Теперь надо сделать то же самое, только с чуть большим числом модулей.
|
||||
How do we implement a module composed of a chain of other modules? We already did half of this when we wrote the testbench for the 1-bit half adder in _Listing 2_ — we created a module inside another module and connected wires to it. Now we need to do the same thing, just with a slightly larger number of modules.
|
||||
|
||||
Описание 4-битного сумматора, сводится к описанию межсоединения четырёх экземпляров 1-битного сумматора. Подробнее о том, как описывать создание экземпляров модулей рассказано в главе [Описание модулей на языке SystemVerilog](../../Basic%20Verilog%20structures/Modules.md#Иерархия-модулей), который вы изучали перед лабораторной работой.
|
||||
Describing a 4-bit adder reduces to describing the interconnection of four instances of a 1-bit adder. More details on how to instantiate modules are covered in the chapter [Describing modules in SystemVerilog](../../Basic%20Verilog%20structures/Modules.md#Module-hierarchy), which you studied before this lab.
|
||||
|
||||

|
||||
|
||||
_Рисунок 6. Схема 4-битного сумматора, сгенерированная САПР Vivado._
|
||||
_Figure 6. 4-bit adder circuit generated by the Vivado EDA tool._
|
||||
|
||||
Несмотря на запутанность схемы, если присмотреться, вы увидите, как от шин A, B и S отходят линии к каждому из сумматоров, а бит переноса передаётся от предыдущего сумматора к следующему. Для передачи битов переноса от одного сумматора к другому, потребуется создать вспомогательные провода, которые можно сгруппировать в один [вектор](../../Basic%20Verilog%20structures/Modules.md#Векторы) (см. сигналы c[0]-c[2] на _рис. 5_).
|
||||
Despite how complex the circuit looks, if you look closely, you can see lines running from buses A, B, and S to each of the adders, with the carry bit propagating from one adder to the next. To transfer the carry bits from one adder to the next, auxiliary wires need to be created; these can be grouped into a single [vector](../../Basic%20Verilog%20structures/Modules.md#Vectors) (see signals c[0]–c[2] in _Fig. 5_).
|
||||
|
||||
## Задание
|
||||
## Assignment
|
||||
|
||||
Опишите полный 1-битный сумматор, схема которого представлена на _[Рис. 2](../../.pic/Labs/lab_01_adder/fig_02.drawio.svg)_. Прототип модуля следующий:
|
||||
Describe a full 1-bit adder whose circuit is shown in _[Fig. 2](../../.pic/Labs/lab_01_adder/fig_02.drawio.svg)_. The module prototype is as follows:
|
||||
|
||||
```Verilog
|
||||
module fulladder(
|
||||
@@ -212,7 +210,7 @@ module fulladder(
|
||||
);
|
||||
```
|
||||
|
||||
Далее, вам необходимо реализовать полный 32-битный сумматор со следующим прототипом:
|
||||
Next, implement a full 32-bit adder with the following prototype:
|
||||
|
||||
```verilog
|
||||
module fulladder32(
|
||||
@@ -224,9 +222,9 @@ module fulladder32(
|
||||
);
|
||||
```
|
||||
|
||||
Соединять вручную 32 однотипных модуля чревато усталостью и ошибками, поэтому можно сначала создать 4-битный сумматор, а затем из набора 4-битных сумматоров сделать 32-битный.
|
||||
Manually connecting 32 identical modules is tedious and error-prone, so it is recommended to first build a 4-bit adder and then combine four 4-bit adders into a 32-bit one.
|
||||
|
||||
Если вы решите делать 4-битный сумматор, то модуль должен быть описан в соответствии со следующим прототипом:
|
||||
If you choose to build a 4-bit adder, the module must follow this prototype:
|
||||
|
||||
```Verilog
|
||||
module fulladder4(
|
||||
@@ -238,15 +236,15 @@ module fulladder4(
|
||||
);
|
||||
```
|
||||
|
||||
Либо же можно создать массив 1-битных сумматоров.
|
||||
Alternatively, you can create an array of 1-bit adders.
|
||||
|
||||
Создание массива модулей схоже с созданием одного модуля за исключением того, что после имени экземпляра модуля указывается диапазон, определяющий количество модулей в массиве. При этом подключение сигналов к массиву модулей осуществляется следующим образом:
|
||||
Creating a module array is similar to instantiating a single module, except that a range defining the number of modules in the array is specified after the instance name. Signal connections to a module array work as follows:
|
||||
|
||||
- если разрядность подключаемого сигнала совпадает с разрядностью порта модуля из массива, этот сигнал подключается к каждому из модулей в массиве;
|
||||
- если разрядность подключаемого сигнала превосходит разрядность порта модуля из массива в `N` раз (где `N` — количество модулей в массиве), к модулю подключается соответствующий диапазон бит подключаемого сигнала (диапазон младших бит будет подключён к модулю с меньшим индексом в массиве).
|
||||
- если разрядность подключаемого сигнала не подходит ни под один из описанных выше пунктов, происходит ошибка синтеза схемы, поскольку в этом случае САПР не способен понять каким образом подключать данный сигнал к каждому модулю из массива.
|
||||
- if the width of the connected signal matches the port width of the module in the array, that signal is connected to every module in the array;
|
||||
- if the width of the connected signal is `N` times the port width of the array module (where `N` is the number of modules in the array), the corresponding bit range of the signal is connected to each module (the lower bit range is connected to the module with the smaller index in the array);
|
||||
- if the width of the connected signal does not match either of the above cases, a synthesis error occurs, because the EDA tool cannot determine how to connect the signal to each module in the array.
|
||||
|
||||
В _листинге 3_ представлен пример того, как можно создать массив модулей.
|
||||
_Listing 3_ shows an example of how to create a module array.
|
||||
|
||||
```Verilog
|
||||
module example1(
|
||||
@@ -267,54 +265,52 @@ module example2(
|
||||
output logic [ 8:0] C
|
||||
);
|
||||
|
||||
example1 instance_array[7:0]( // Создается массив из 8 модулей example1
|
||||
.a(A), // Поскольку разрядность сигнала A в 8 раз больше
|
||||
// разрядности входа a, к каждому модулю в массиве
|
||||
// будет подключен свой диапазон бит сигнала A
|
||||
// (к instance_array[0] будет подключен диапазон
|
||||
// A[3:0], к instance_array[7] будет подключен
|
||||
// диапазон A[31:28]).
|
||||
example1 instance_array[7:0]( // Creates an array of 8 example1 modules
|
||||
.a(A), // Since the width of signal A is 8 times greater
|
||||
// than the width of port a, each module in the array
|
||||
// is connected to its own bit range of signal A
|
||||
// (instance_array[0] is connected to A[3:0],
|
||||
// instance_array[7] is connected to A[31:28]).
|
||||
|
||||
.b(B), // Поскольку разрядность сигнала B совпадает с
|
||||
// разрядностью входа b, сигнал B будет подключен
|
||||
// как есть ко всем модулям в массиве.
|
||||
.b(B), // Since the width of signal B matches the width
|
||||
// of port b, signal B is connected as-is to
|
||||
// all modules in the array.
|
||||
|
||||
.c(C[7:0]), // Поскольку разрядность сигнала C не равна
|
||||
// ни разрядности входа c, ни его увосьмерённой
|
||||
// разрядности, мы должны выбрать такой диапазон
|
||||
// бит, который будет удовлетворять одному из
|
||||
// этих требований.
|
||||
.c(C[7:0]), // Since the width of signal C does not equal
|
||||
// either the port width of c or eight times
|
||||
// that width, we must select a bit range that
|
||||
// satisfies one of the requirements.
|
||||
|
||||
.d(C[8]) // Аналогично предыдущему.
|
||||
.d(C[8]) // Same as the previous case.
|
||||
);
|
||||
endmodule
|
||||
```
|
||||
|
||||
_Листинг 3. Пример создания массива модулей._
|
||||
_Listing 3. Example of creating a module array._
|
||||
|
||||
Реализация массива сумматоров будет осложнена тем, что вам потребуется каким-то образом организовать передачу выходного бита переноса предыдущего разряда до входного бита переноса следующего разряда. Для этого рекомендуется создать два 32-битных вектора:
|
||||
Implementing the adder array will be complicated by the need to propagate the carry-out of each stage to the carry-in of the next. To do this, it is recommended to create two 32-bit vectors:
|
||||
|
||||
- вектор входных битов переноса;
|
||||
- вектор выходных битов переноса.
|
||||
- a vector of carry-in bits;
|
||||
- a vector of carry-out bits.
|
||||
|
||||
Далее, с помощью оператора непрерывного присваивания соединить разряды вектора выходных битов переноса с соответствующими разрядами вектора входных битов переноса. Кроме того, вам потребуется связать входной и выходной биты переноса модуля с младшим и старшим разрядом соответствующих векторов.
|
||||
Then use continuous assignment to connect the bits of the carry-out vector to the corresponding bits of the carry-in vector. In addition, you will need to connect the module-level carry-in and carry-out to the least significant and most significant bits of the corresponding vectors.
|
||||
|
||||
После того, как векторы бит переноса будут готовы, создание массива модулей уже не будет представлять сложности.
|
||||
Once the carry bit vectors are ready, creating the module array will be straightforward.
|
||||
|
||||
### Порядок выполнения задания
|
||||
### Step-by-Step Instructions
|
||||
|
||||
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#Иерархия-модулей), чтобы в нем выполнялось поразрядное сложение двух 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. [Проверьте](./board%20files) работоспособность вашей цифровой схемы в ПЛИС.
|
||||
1. Create a project following the [Vivado project creation guide](../../Vivado%20Basics/01.%20New%20project.md).
|
||||
2. Describe the `fulladder` module whose circuit is shown in _[Fig. 2](../../.pic/Labs/lab_01_adder/fig_02.drawio.svg)_.
|
||||
1. The module must be described with the same name and ports as specified in the assignment.
|
||||
3. Verify the module using the verification environment provided in the file [`lab_01.tb_fulladder.sv`](lab_01.tb_fulladder.sv). Check the waveform signals to confirm that the module operates correctly. If incorrect behavior is observed on the sum or carry-out signals, you must [find](../../Vivado%20Basics/05.%20Bug%20hunting.md) the cause and fix it.
|
||||
4. Describe the `fulladder4` module whose circuit is shown in _Figs. 5 and 6_, using [module hierarchy](../../Basic%20Verilog%20structures/Modules.md#Module-hierarchy) to perform bit-by-bit addition of two 4-bit numbers and a carry-in. Some inputs and outputs of the module will need to be described as [vectors](../../Basic%20Verilog%20structures/Modules.md#Vectors).
|
||||
1. The module must be described with the same name and ports as specified in the assignment.
|
||||
2. Note that the carry-in must be fed to the adder that processes bit 0, and the carry-out must be connected to the carry-out of the adder processing bit 3. Intermediate carry bits are passed using auxiliary wires that you must create yourself.
|
||||
5. Verify the module using the verification environment provided in the file [`lab_01.tb_fulladder4.sv`](lab_01.tb_fulladder4.sv). Check the waveform signals to confirm that the module operates correctly. If incorrect behavior is observed on the sum or carry-out signals, you must [find](../../Vivado%20Basics/05.%20Bug%20hunting.md) the cause and fix it.
|
||||
1. Before launching simulation, make sure the correct top-level module is selected in `Simulation Sources`.
|
||||
6. Describe the `fulladder32` module to perform bit-by-bit addition of two 32-bit numbers and a carry-in. It can be implemented by chaining eight 4-bit adders, or by connecting 32 1-bit adders (either manually or by creating a module array).
|
||||
1. The module must be described with the same name and ports as specified in the assignment.
|
||||
2. Note that the carry-in must be fed to the adder that processes bit 0, and the carry-out must be connected to the carry-out of the adder processing bit 31.
|
||||
7. Verify the module using the verification environment provided in the file [`lab_01.tb_fulladder32.sv`](lab_01.tb_fulladder32.sv). If error messages appear in the TCL console, you must [find](../../Vivado%20Basics/05.%20Bug%20hunting.md) and fix them.
|
||||
1. Before launching simulation, make sure the correct top-level module is selected in `Simulation Sources`.
|
||||
8. [Verify](./board%20files) the operation of your digital circuit on the FPGA.
|
||||
|
||||
@@ -1,73 +1,73 @@
|
||||
# Лабораторная работа №2. Арифметико-логическое устройство
|
||||
# Lab 2. Arithmetic Logic Unit
|
||||
|
||||
Так как основной задачей процессора является обработка цифровых данных, одним из его основных блоков является арифметико-логическое устройство (АЛУ). Задача АЛУ производить над входными данными арифметические и поразрядно логические операции.
|
||||
Since the primary purpose of a processor is to process digital data, one of its core components is the arithmetic logic unit (ALU). The ALU performs arithmetic and bitwise logical operations on input data.
|
||||
|
||||
## Цель
|
||||
## Goal
|
||||
|
||||
Используя навыки по описанию мультиплексоров, описать блок арифметико-логического устройства (АЛУ) на языке SystemVerilog.
|
||||
Using multiplexer description skills, describe an arithmetic logic unit (ALU) module in SystemVerilog.
|
||||
|
||||
## Материалы для подготовки к лабораторной работе
|
||||
## Preparation Materials
|
||||
|
||||
В дополнение к [материалам](../../Basic%20Verilog%20structures/), изученным в ходе предыдущей лабораторной работы, вам рекомендуется ознакомиться с:
|
||||
In addition to the [materials](../../Basic%20Verilog%20structures/) covered in the previous lab, you are encouraged to review:
|
||||
|
||||
- способами описания [мультиплексора](../../Basic%20Verilog%20structures/Multiplexors.md) на языке SystemVerilog.
|
||||
- how to describe a [multiplexer](../../Basic%20Verilog%20structures/Multiplexors.md) in SystemVerilog.
|
||||
|
||||
## Общий ход выполнения работы
|
||||
## General Workflow
|
||||
|
||||
1. Изучить устройство и принцип работы АЛУ (раздел [#теория](#Теория))
|
||||
2. Изучить языковые конструкции SystemVerilog для реализации АЛУ (раздел [#инструменты](#Инструменты))
|
||||
3. Внимательно ознакомиться с заданием (раздел [#задание](#Задание))
|
||||
4. Описать модуль АЛУ, проверить его предоставленным верификационным окружением.
|
||||
5. Проверить работу АЛУ в ПЛИС.
|
||||
1. Study the structure and operating principle of an ALU (see [#theory](#theory))
|
||||
2. Study the SystemVerilog language constructs for implementing an ALU (see [#tools](#Tools))
|
||||
3. Read the assignment carefully (see [#assignment](#Assignment))
|
||||
4. Describe the ALU module and verify it using the provided verification environment.
|
||||
5. Test the ALU on the FPGA.
|
||||
|
||||
## Теория
|
||||
## Theory
|
||||
|
||||
**Арифметико-логическое устройство** (**АЛУ**, Arithmetic Logic Unit – ALU) – это блок процессора, выполняющий арифметические и поразрядно логические операции. Разница между арифметическими и логическими операциями в отсутствии у последних бита переноса, так как логические операции происходят между 1-битными числами и дают 1-битный результат, а в случае АЛУ (в рамках данной лабораторной работы) одновременно между 32-мя 1-битными парами чисел. В логических операциях результаты значений отдельных битов друг с другом никак не связаны.
|
||||
An **arithmetic logic unit** (**ALU**) is a processor block that performs arithmetic and bitwise logical operations. The difference between arithmetic and logical operations is that logical operations have no carry bit — logical operations are performed between 1-bit numbers and produce a 1-bit result, whereas in the ALU (within the scope of this lab) they operate simultaneously on 32 pairs of 1-bit numbers. In logical operations, the result of individual bits are entirely independent of one another.
|
||||
|
||||
Также, кроме результата операций, АЛУ может формировать специальные сигналы-флаги, которые показывают выполняется ли заданное условие. Например, выводить `1`, если один операнд меньше другого, или если в результате суммы произошло переполнение.
|
||||
In addition to the operation result, the ALU can generate special flag signals that indicate whether a given condition holds. For example, it can output `1` if one operand is less than another, or if an addition resulted in overflow.
|
||||
|
||||
Обычно АЛУ представляет собой комбинационную схему (то есть не имеет элементов памяти), на входы которой поступают информационные (операнды) и управляющие (код операции) сигналы, в ответ на что на выходе появляется результат заданной операции. АЛУ может быть реализовано и в виде последовательностной логики, но это скорее исключение.
|
||||
An ALU is typically a combinational circuit (i.e., it has no memory elements). Its inputs receive data (operands) and control (operation code) signals, and its output produces the result of the specified operation. An ALU can also be implemented as sequential logic, but this is the exception rather than the rule.
|
||||
|
||||

|
||||
|
||||
_Рисунок 1. Структурное обозначение элемента АЛУ[[1, стр. 304]](https://reader.lanbook.com/book/241166?lms=1b8d65a957786d4b32b8201bd30e97f3)._
|
||||
_Figure 1. Block diagram symbol of an ALU [1, p. 247]._
|
||||
|
||||
На рис. 1 изображено структурное обозначение АЛУ, используемое в книге "Цифровая схемотехника и архитектура компьютера RISC-V" Харрис и Харрис. На входы `A` и `B` поступают операнды с разрядностью _N_. На 2-битный вход `ALUControl` подается код операции. Например, если туда подать `10`, то на выходе `Y` появится результат операции _логическое И_ между битами операндов `A` и `B`. Если же подать `00`, то на выходе появится результат сложения. Это лишь пример, разрядность и коды могут отличаться в зависимости от количества выполняемых операций и архитектуры.
|
||||
Fig. 1 shows the ALU block diagram symbol used in the book "Digital Design and Computer Architecture: RISC-V Edition" by Harris & Harris. Inputs `A` and `B` receive N-bit operands. The 2-bit `ALUControl` input carries the operation code. For example, supplying `10` causes output `Y` to produce the bitwise AND of operands `A` and `B`. Supplying `00` produces the addition result. This is just an example — the bit widths and codes may vary depending on the number of operations and the architecture.
|
||||
|
||||
Существует несколько подходов к реализации АЛУ, отличающиеся внутренней организацией. В лабораторных работах применяется повсеместно используемый подход мультиплексирования операций, то есть подключения нескольких операционных устройств (которые выполняют какие-то операции, например сложения, логического ИЛИ и т.п.) к мультиплексору, который будет передавать результат нужного операционного устройства на выходы АЛУ.
|
||||
There are several approaches to implementing an ALU, differing in their internal organization. In these labs we use the widely adopted operation-multiplexing approach: multiple functional units (each performing a specific operation such as addition, bitwise OR, etc.) are connected to a multiplexer, which forwards the result of the selected unit to the ALU outputs.
|
||||
|
||||
Рассмотрим данный подход на примере всё того же АЛУ из книги Харрисов. На рис. 2, в левой его части, изображена внутренняя организация этого АЛУ, справа – таблица соответствия кодов операциям. На выходе схемы (внизу) стоит 4-входовой мультиплексор, управляемый 2-битным сигналом `ALUControl`. Ко входам мультиплексора подключены выходы `N` логических И (побитовое И N-битных операндов), `N` логических ИЛИ, а выход N-битного сумматора подключён дважды, позволяя выбирать его результат для двух кодов операции.
|
||||
Let us examine this approach using the same ALU from the Harris & Harris book. In Fig. 2, the left side shows the internal organization of this ALU; the right side shows the operation code table. At the output of the circuit (bottom) is a 4-input multiplexer controlled by the 2-bit `ALUControl` signal. The multiplexer inputs are connected to the outputs of `N` AND gates (bitwise AND of N-bit operands), `N` OR gates, and the output of an N-bit adder — connected twice, allowing the adder result to be selected for two different operation codes.
|
||||
|
||||

|
||||
|
||||
_Рисунок 2. Структурная схема АЛУ [[1, стр. 305]](https://reader.lanbook.com/book/241166?lms=1b8d65a957786d4b32b8201bd30e97f3)._
|
||||
_Figure 2. ALU block diagram [1, p. 247]._
|
||||
|
||||
Вход `A` подключается напрямую ко входам этих операционных устройств. Вход `B` тоже — за исключением подключения к сумматору. На вход второго операнда сумматора подаётся результат мультиплексирования сигналов `B` и `~B`. Управляющим сигналом этого мультиплексора является младший бит управляющего сигнала `ALUControl`. Кроме того, этот же младший бит подаётся и на сумматор в качестве входного бита переноса. Это означает, что когда `ALUControl[0] = 0`, вычисляется сумма `A + B + 0`, а когда `ALUControl[0] = 1`, вычисляется сумма `A + ~B + 1`, что (с учётом [дополнительного кода](https://ru.wikipedia.org/wiki/Дополнительный_код) ) эквивалентно `A – B`.
|
||||
Input `A` connects directly to the inputs of all functional units. Input `B` does as well — except for the adder connection. The second operand input of the adder receives the result of multiplexing `B` and `~B`. The control signal for this multiplexer is the least significant bit of `ALUControl`. Furthermore, that same least significant bit (LSB) is supplied to the adder as its carry-in. This means that when `ALUControl[0] = 0`, the sum `A + B + 0` is computed, and when `ALUControl[0] = 1`, the sum `A + ~B + 1` is computed — which (due to the properties of [two's complement](https://en.wikipedia.org/wiki/Two%27s_complement)) is equivalent to `A – B`.
|
||||
|
||||
Преимущество такой организации АЛУ в простоте его модификации, настройке под нужные коды операций, читаемости кода и масштабируемости. Можно легко добавить или убрать требуемые операции. Подумайте, как бы вы обновили данную схему, если бы от вас потребовалось расширить её функционал операциями XOR (Исключающее ИЛИ) и (SGE операция "больше либо равно")?
|
||||
The advantage of this ALU organization is its ease of modification, flexibility in assigning operation codes, code readability, and scalability. Operations can easily be added or removed. Consider how you would update this circuit if you needed to extend its functionality with XOR (exclusive OR) and SGE (greater-than-or-equal) operations.
|
||||
|
||||
## Инструменты
|
||||
## Tools
|
||||
|
||||
Как было сказано выше, АЛУ можно реализовать, [мультиплексируя](../../Basic%20Verilog%20structures/Multiplexors.md) результаты нескольких операционных устройств.
|
||||
As mentioned above, an ALU can be implemented by [multiplexing](../../Basic%20Verilog%20structures/Multiplexors.md) the results of several functional units.
|
||||
|
||||
При описании очередной комбинации управляющего сигнала, выходу мультиплексора можно сразу присваивать необходимое логическое выражение (например результат побитового ИЛИ можно подать на выход сразу в виде выражения: `a | b`, однако в некоторых случаях выражения будут сложнее из-за различных особенностей реализации, о которых будет рассказано в задании).
|
||||
When describing each combination of the control signal, you can directly assign the required logical expression to the multiplexer output (for example, the result of a bitwise OR can be expressed directly as `a | b`, though some cases require more complex expressions due to implementation specifics discussed in the assignment).
|
||||
|
||||
### Параметры
|
||||
### Parameters
|
||||
|
||||
Очень удобным на практике оказывается использование параметров. Параметры добавляют модулю гибкости, позволяя убрать ["магические"](https://ru.wikipedia.org/wiki/Магическое_число_(программирование)#Плохая_практика_программирования) константы из описания модулей, подставляя вместо них выразительное символьное имя. Параметры отдаленно схожи с макросами `#define` в языке Си, однако стоит понимать, что это не одно и то же. Дефайны представляют собой специальные текстовые макросы, которые автоматически заменяются на этапе препроцессора (как если бы вы прошлись по всем файлам своего кода и вручную заменили бы макросы на их значения). Например, с помощью дефайнов можно писать целые куски кода, а не просто одно какое-то число. При этом у дефайнов глобальная область видимости (объявив их в одном месте, этот макрос будет доступен во всем последующем коде). Параметр в свою очередь может хранить только значение какого-то конкретного типа (т.е. в параметр нельзя поместить фрагмент кода) а область видимости параметра ограничена тем модулем, где он был объявлен.
|
||||
Parameters are very useful in practice. They add flexibility to a module by replacing ["magic"](https://en.wikipedia.org/wiki/Magic_number_(programming)#Numeric_literal) constants in module descriptions with meaningful symbolic names. Parameters are loosely similar to `#define` macros in C, but they are not the same thing. Defines are special text macros that are automatically substituted at the preprocessor stage (as if you had manually replaced every occurrence in your source files). For example, defines can expand into entire code fragments, not just single values. Defines also have global scope (once declared, the macro is available throughout all subsequent code). A parameter, by contrast, can only hold a value of a specific type (you cannot store a code fragment in a parameter), and its scope is limited to the module in which it is declared.
|
||||
|
||||
Допустим, ваше устройство должно включить тостер, если на вход ему придет сигнал `32'haf3c5bd0`. Человек, не знакомый с устройством, при прочтении этого кода будет недоумевать, что это за число и почему используется именно оно. Однако, скрыв его за параметром `TOASTER_EN`, читающий поймет, что это код включения тостера. Кроме того, если некоторая константа должна использоваться в нескольких местах кода, то определив её в виде параметра, можно будет менять её в одном месте, и она тут же поменяется везде.
|
||||
Suppose your device must turn on a toaster when it receives the signal `32'haf3c5bd0`. A reader unfamiliar with the design would be puzzled by that number. However, hiding it behind a parameter named `TOASTER_EN` immediately communicates that it is the toaster enable code. Furthermore, if the same constant is used in multiple places, defining it as a parameter means you only need to change it in one location for the change to propagate everywhere.
|
||||
|
||||
Параметры позволяют влиять на структуру модуля. К примеру, описывая сумматор, можно параметризовать его разрядность и использовать этот параметр при описании модуля (например, в качестве диапазона массива модулей). В этом случае вы сможете создавать множество сумматоров различных разрядностей, подставляя при создании нужное вам значение параметра.
|
||||
Parameters can also influence the structure of a module. For example, when describing an adder, you can parameterize its bit width and use that parameter throughout the module description (e.g., as the range of a module array). This lets you instantiate adders of different widths simply by supplying a different parameter value at instantiation time.
|
||||
|
||||
Параметр может быть объявлен в модуле двумя способами:
|
||||
A parameter can be declared in a module in two ways:
|
||||
|
||||
- в прототипе модуля;
|
||||
- в теле описания модуля.
|
||||
- in the module prototype;
|
||||
- in the module body.
|
||||
|
||||
В первом случае после имени модуля ставится символ `#`, затем в круглых скобках указывается ключевое слово `parameter`. Далее идет тип параметра (по умолчанию — знаковое 32-битное число), после чего задаются его имя и, при необходимости, значение по умолчанию.
|
||||
In the first case, a `#` symbol is placed after the module name, followed by the keyword `parameter` in parentheses. Next comes the parameter type (default is a signed 32-bit integer), then the name, and optionally a default value.
|
||||
|
||||
Пример:
|
||||
Example:
|
||||
|
||||
```Verilog
|
||||
module overflow #(parameter WIDTH = 32)(
|
||||
@@ -83,9 +83,9 @@ module overflow #(parameter WIDTH = 32)(
|
||||
endmodule
|
||||
```
|
||||
|
||||
_Листинг 1. Пример описания параметра в прототипе модуля._
|
||||
_Listing 1. Example of declaring a parameter in the module prototype._
|
||||
|
||||
В случае, если параметр не влияет на разрядность портов, его можно объявить в теле модуля:
|
||||
If the parameter does not affect port widths, it can be declared in the module body:
|
||||
|
||||
```Verilog
|
||||
module toaster(
|
||||
@@ -99,11 +99,11 @@ module toaster(
|
||||
endmodule
|
||||
```
|
||||
|
||||
_Листинг 2. Пример описания параметра в теле модуля._
|
||||
_Listing 2. Example of declaring a parameter in the module body._
|
||||
|
||||
В случае АЛУ будет удобно использовать параметры для обозначения кодов команд. Во-первых, для того чтобы в `case` не допустить ошибок, а во-вторых – чтобы можно было легко менять управляющие коды для повторного использования АЛУ в других проектах.
|
||||
For the ALU, it is convenient to use parameters to denote operation codes. First, this avoids errors in the `case` statement; second, it makes it easy to change control codes when reusing the ALU in other projects.
|
||||
|
||||
Сравните сами _листинги 3 и 4_:
|
||||
Compare _listings 3 and 4_ yourself:
|
||||
|
||||
```Verilog
|
||||
//parameter ADD = 5'b00000;
|
||||
@@ -114,11 +114,11 @@ _Листинг 2. Пример описания параметра в теле
|
||||
always_comb
|
||||
case(ALUOp)
|
||||
//...
|
||||
5'b00011: //... // вообще же ничего не понятно
|
||||
5'b11000: //... // никуда не годится
|
||||
5'b00011: //... // completely unclear
|
||||
5'b11000: //... // unacceptable
|
||||
```
|
||||
|
||||
_Листинг 3. Пример описания модуля, использующего "магические" числа._
|
||||
_Listing 3. Example of a module description using "magic" numbers._
|
||||
|
||||
```Verilog
|
||||
parameter ADD = 5'b00000;
|
||||
@@ -129,17 +129,17 @@ parameter SUB = 5'b01000;
|
||||
always_comb
|
||||
case(ALUOp)
|
||||
//...
|
||||
ADD: //... // очень понятно
|
||||
SUB: //... // так лаконично и красиво
|
||||
ADD: //... // very clear
|
||||
SUB: //... // concise and clean
|
||||
```
|
||||
|
||||
_Листинг 4. Пример описания модуля, использующего параметры._
|
||||
_Listing 4. Example of a module description using parameters._
|
||||
|
||||
С параметрами смотрится гораздо взрослее, серьёзнее и понятнее. Кстати, сразу на заметку: в SystemVerilog можно объединять группу параметров в **пакет** (package), а затем импортировать его внутрь модуля, позволяя переиспользовать параметры без повторного их прописывания для других модулей.
|
||||
Using parameters looks far more professional, serious, and readable. As a side note: in SystemVerilog you can group parameters into a **package** and then import it into a module, allowing you to reuse parameters without redeclaring them in each module.
|
||||
|
||||
Делается это следующим образом.
|
||||
This is done as follows.
|
||||
|
||||
Сперва создается SystemVerilog-файл, который будет содержать пакет (к примеру, содержимое файла может быть таким):
|
||||
First, create a SystemVerilog file that contains the package (for example, the file might contain):
|
||||
|
||||
```Verilog
|
||||
package riscv_params_pkg;
|
||||
@@ -148,71 +148,70 @@ package riscv_params_pkg;
|
||||
endpackage
|
||||
```
|
||||
|
||||
Далее, внутри модуля, которому нужны параметры из этого пакета, необходимо сделать соответствующий импорт этих параметров. Это можно сделать либо для каждого параметра отдельно, либо импортировать все параметры сразу:
|
||||
Then, inside the module that needs parameters from this package, import them. You can import each parameter individually or import all of them at once:
|
||||
|
||||
```Verilog
|
||||
module riscv_processor
|
||||
//import riscv_params_pkg::*;
|
||||
import riscv_params_pkg::ISA_WIDTH; // Если необходимо импортировать
|
||||
import riscv_params_pkg::ISA_WIDTH; // If you need to import
|
||||
(
|
||||
//...Порты
|
||||
//...Ports
|
||||
);
|
||||
|
||||
import riscv_params_pkg::ANOTHER_EX; // все параметры в пакете, эти две строчки
|
||||
// могут быть заменены закомментированной
|
||||
// выше строкой:
|
||||
import riscv_params_pkg::ANOTHER_EX; // all parameters in the package, these two lines
|
||||
// can be replaced by the commented-out line above:
|
||||
|
||||
endmodule
|
||||
```
|
||||
|
||||
### Битовые сдвиги
|
||||
### Bit Shifts
|
||||
|
||||
Реализуемое в данной лабораторной работе АЛУ использует операции битового сдвига. **Битовый сдвиг** — это операция, при которой все биты числа смещаются на заданное количество позиций. Сдвиг числа на _N_ бит эквивалентен _N_ сдвигам на 1 бит. В архитектуре RISC-V используются два типа сдвигов: **логический** и **арифметический**.
|
||||
The ALU implemented in this lab uses bit shift operations. A **bit shift** is an operation in which all bits of a number are moved by a specified number of positions. Shifting a number by _N_ bits is equivalent to performing _N_ single-bit shifts. RISC-V uses two types of shifts: **logical** and **arithmetic**.
|
||||
|
||||
При **логическом сдвиге** биты сдвигаются влево или вправо, а освободившиеся позиции заполняются нулями. При этом разряды, "вытолкнутые" за пределы разрядной сетки числа, пропадают. Например, если выполнить логический сдвиг двоичного числа _1<ins>0011010</ins>_ на один бит влево, получится _<ins>0011010</ins>0_. Обратите внимание, что старшая единица была вытолкнута за границу и исчезла.
|
||||
In a **logical shift**, bits are moved left or right and the vacated positions are filled with zeros. Bits that are shifted beyond the bit-width of the number are discarded. For example, a logical left shift of the binary number _1<ins>0011010</ins>_ by one bit yields _<ins>0011010</ins>0_. Note that the leading one was pushed out and lost.
|
||||
|
||||

|
||||
|
||||
_Рисунок 3. Иллюстрация преобразования двоичного числа при логическом сдвиге._
|
||||
_Figure 3. Illustration of a binary number transformation under a logical shift._
|
||||
|
||||
При арифметическом сдвиге заполнение освобождённых битов выполняется так, чтобы сохранился знак числа. В дополнительном коде знак определяется старшим битом, поэтому:
|
||||
In an **arithmetic shift**, vacated bit positions are filled in a way that preserves the sign of the number. In two's complement, the sign is determined by the most significant bit, therefore:
|
||||
|
||||
- при **арифметическом сдвиге вправо** освободившиеся позиции заполняются значением старшего бита исходного числа. Это позволяет сохранить знак. Например, арифметический сдвиг на два бита вправо числа _<ins>100110</ins>10_ даёт _11<ins>100110</ins>_;
|
||||
- **арифметический сдвиг влево** эквивалентен логическому, так как заполнение младших битов нулями не влияет на знак числа.
|
||||
- in an **arithmetic right shift**, vacated positions are filled with the value of the original MSB. This preserves the sign. For example, an arithmetic right shift by two bits of _<ins>100110</ins>10_ yields _11<ins>100110</ins>_;
|
||||
- an **arithmetic left shift** is equivalent to a logical left shift, since filling the lower bits with zeros does not affect the sign of the number.
|
||||
|
||||

|
||||
|
||||
_Рисунок 4. Иллюстрация преобразования двоичного числа при арифметическом сдвиге._
|
||||
_Figure 4. Illustration of a binary number transformation under an arithmetic shift._
|
||||
|
||||
Битовый сдвиг имеет важный арифметический смысл — он соответствует умножению или делению числа на степень двойки:
|
||||
Bit shifts have an important arithmetic meaning — they correspond to multiplication or division of a number by a power of two:
|
||||
|
||||
- сдвиг влево на _N_ бит эквивалентен умножению на _2<sup>N</sup>_,
|
||||
- сдвиг вправо на _N_ бит эквивалентен целочисленному делению на _2<sup>N</sup>_.
|
||||
- a left shift by _N_ bits is equivalent to multiplication by _2<sup>N</sup>_,
|
||||
- a right shift by _N_ bits is equivalent to integer division by _2<sup>N</sup>_.
|
||||
|
||||
Этот приём знаком должен быть знаком вам при работе с десятичной системой: умножая число на 10, мы просто дописываем справа ноль. То же самое работает и для деления: если отрезать последний разряд у числа <ins>4</ins>2, получится 4, что соответствует целочисленному делению на 10. В двоичной системе добавление (стирание) нуля справа эквивалентно умножению (делению) на 2.
|
||||
You may be familiar with this principle from the decimal system: multiplying a number by 10 simply appends a zero on the right. The same applies to division: dropping the last digit of <ins>4</ins>2 gives 4, which is integer division by 10. In binary, appending (or removing) a zero on the right is equivalent to multiplying (or dividing) by 2.
|
||||
|
||||
Арифметический сдвиг важен тем, что сохраняет это свойство для знаковых чисел, представленных в дополнительном коде. Логический сдвиг вправо изменяет и знак, и модуль отрицательного числа в дополнительном коде, поэтому не может использоваться для деления знаковых чисел.
|
||||
Arithmetic shift is important because it preserves this property for signed numbers represented in two's complement. A logical right shift changes both the sign and the magnitude of a negative number in two's complement, so it cannot be used for dividing signed numbers.
|
||||
|
||||
Операции умножения и деления — это очень «дорогие» операции как с точки зрения элементов схемы (если эти операции реализуются аппаратно), так и с точки зрения времени их вычисления. Поэтому выполнение сдвигов в качестве замены умножения применяется повсеместно. Например, написав в коде языка C++ выражение `var * 8`, после компиляции вы наверняка получите операцию сдвига влево на 3.
|
||||
Multiplication and division are very "expensive" operations both in terms of circuit area (when implemented in hardware) and computation time. As a result, using shifts as a substitute for multiplication is widespread. For example, writing `var * 8` in C++ code will almost certainly be compiled to a left shift by 3.
|
||||
|
||||
Ещё одно применение сдвигов: установка и очищение флагов управляющих регистров. Дело в том, что обычно процессоры не имеют доступа к отдельным битам многоразрядных регистров — их значения читаются записываются целиком. Вот как можно реализовать битовые операции с помощью сдвигов:
|
||||
Another application of shifts is setting and clearing bits in control registers. Since processors typically cannot access individual bits of wide registers — their values are read and written as a whole — bit manipulation is achieved using shifts:
|
||||
|
||||
```C++
|
||||
X = X | (1 << N); // Установка N-го бита
|
||||
X = X & ~(1 << N); // Очистка N-го бита
|
||||
Y = (X & (1 << N)) != 0; // Чтение N-го бита
|
||||
X = X | (1 << N); // Set the N-th bit
|
||||
X = X & ~(1 << N); // Clear the N-th bit
|
||||
Y = (X & (1 << N)) != 0; // Read the N-th bit
|
||||
```
|
||||
|
||||
#### Особенности реализации сдвига
|
||||
#### Shift Implementation Notes
|
||||
|
||||
> [!IMPORTANT]
|
||||
> По спецификации RISC-V, для **ВСЕХ** операций сдвига используются только 5 младших бит операнда B[2, стр. 26-27].
|
||||
> According to the RISC-V specification, **ALL** shift operations use only the 5 least significant bits of operand B [2, pp. 26–27].
|
||||
|
||||
Сами посмотрите: выполнять операцию сдвига более чем на 31 для 32-битных чисел не имеет смысла, число полностью заполнится нулями (единицами). Т.е. сдвигая на любое число, большее 31, вы получите один и тот же результат. Для того чтобы закодировать 31 требуется минимум 5 бит, отсюда и это требование. Оно обязательно, поскольку старшие биты в дальнейшем будут использоваться по другому назначению и, если вы упустите это, ваш будущий процессор станет работать неправильно.
|
||||
Consider why: shifting a 32-bit number by more than 31 positions makes no sense — the result is simply all zeros (or all ones). That is, shifting by any value greater than 31 always produces the same result. Encoding 31 requires at least 5 bits, hence this requirement. It is mandatory: the upper bits will be used for other purposes later, and ignoring this will cause your future processor to behave incorrectly.
|
||||
|
||||
## Задание
|
||||
## Assignment
|
||||
|
||||
Необходимо на языке SystemVerilog реализовать АЛУ в соответствии со следующим прототипом:
|
||||
Implement an ALU in SystemVerilog according to the following prototype:
|
||||
|
||||
```Verilog
|
||||
|
||||
@@ -224,112 +223,112 @@ module alu (
|
||||
output logic [31:0] result_o
|
||||
);
|
||||
|
||||
import alu_opcodes_pkg::*; // импорт параметров, содержащих
|
||||
// коды операций для АЛУ
|
||||
import alu_opcodes_pkg::*; // import of parameters containing
|
||||
// operation codes for the ALU
|
||||
|
||||
endmodule
|
||||
```
|
||||
|
||||
Для стандартного набора целочисленных операций архитектуры RISC-V требуется выполнять 16 различных операций. Для кодирования 16 операций было бы достаточно 4 бит, но в лабораторной работе предлагается использовать 5-битный код, что связано с особенностями кодирования инструкций. Старший бит кода операции указывает на то, является ли операция вычислительной или это операция сравнения.
|
||||
The standard integer instruction set of RISC-V requires 16 distinct operations. While 4 bits would suffice to encode 16 operations, this lab uses a 5-bit code, which is related to the instruction encoding scheme. The MSB of the operation code indicates whether the operation is a computational operation or a comparison.
|
||||
|
||||
Для удобства чтения, список инструкций разбит на две таблицы.
|
||||
For readability, the instruction list is split into two tables.
|
||||
|
||||
В первой таблице перечислены операции, вычисляющие значение сигнала `result_o`. **При получении АЛУ любого кода операции, не входящего в эту таблицу, сигнал `result_o` должен быть равен нулю**.
|
||||
The first table lists the operations that compute the value of the `result_o` signal. **If the ALU receives any operation code not listed in this table, the `result_o` signal must be zero.**
|
||||
|
||||
|Операция|={cmp, mod, opcode}|Выражение | Действие |
|
||||
|--------|-------------------|-----------------------|-------------------------------------------------------|
|
||||
| ADD | 0 0 000 |result_o = a_i + b_i | Сложение |
|
||||
| SUB | 0 1 000 |result_o = a_i – b_i | Вычитание |
|
||||
| SLL | 0 0 001 |result_o = a_i << b_i | Сдвиг влево |
|
||||
| SLTS | 0 0 010 |result_o = a_i < b_i | **Знаковое** сравнение |
|
||||
| SLTU | 0 0 011 |result_o = a_i < b_i | **Беззнаковое** сравнение |
|
||||
| XOR | 0 0 100 |result_o = a_i ^ b_i | Побитовое исключающее **ИЛИ** |
|
||||
| SRL | 0 0 101 |result_o = a_i >> b_i | Сдвиг вправо |
|
||||
| SRA | 0 1 101 |result_o = a_i >>> b_i | Арифметический сдвиг вправо (операнд `a_i` — знаковый)|
|
||||
| OR | 0 0 110 |result_o = a_i \| b_i | Побитовое логическое **ИЛИ** |
|
||||
| AND | 0 0 111 |result_o = a_i & b_i | Побитовое логическое **И** |
|
||||
| Operation | ={cmp, mod, opcode} | Expression | Action |
|
||||
|-----------|---------------------|-------------------------|-------------------------------------------------------|
|
||||
| ADD | 0 0 000 | result_o = a_i + b_i | Addition |
|
||||
| SUB | 0 1 000 | result_o = a_i – b_i | Subtraction |
|
||||
| SLL | 0 0 001 | result_o = a_i << b_i | Left shift |
|
||||
| SLTS | 0 0 010 | result_o = a_i < b_i | **Signed** comparison |
|
||||
| SLTU | 0 0 011 | result_o = a_i < b_i | **Unsigned** comparison |
|
||||
| XOR | 0 0 100 | result_o = a_i ^ b_i | Bitwise exclusive **OR** |
|
||||
| SRL | 0 0 101 | result_o = a_i >> b_i | Right shift |
|
||||
| SRA | 0 1 101 | result_o = a_i >>> b_i | Arithmetic right shift (`a_i` operand is signed) |
|
||||
| OR | 0 0 110 | result_o = a_i \| b_i | Bitwise logical **OR** |
|
||||
| AND | 0 0 111 | result_o = a_i & b_i | Bitwise logical **AND** |
|
||||
|
||||
_Таблица 1. Список вычислительных операций._
|
||||
_Table 1. List of computational operations._
|
||||
|
||||
Во второй таблице перечислены операции, вычисляющие значение сигнала `flag_o`. **При получении АЛУ любого кода операции, не входящего в эту таблицу, сигнал `flag_o` должен быть равен нулю**.
|
||||
The second table lists the operations that compute the value of the `flag_o` signal. **If the ALU receives any operation code not listed in this table, the `flag_o` signal must be zero.**
|
||||
|
||||
|Операция|={cmp, mod, opcode}| Выражение | Действие |
|
||||
|--------|-------------------|----------------------|-----------------------------------|
|
||||
| EQ | 1 1 000 | flag_o = (a_i == b_i)| Выставить флаг, если **равны** |
|
||||
| NE | 1 1 001 | flag_o = (a_i != b_i)| Выставить флаг, если **не равны** |
|
||||
| LTS | 1 1 100 | flag_o = a_i < b_i | **Знаковое** сравнение **<** |
|
||||
| GES | 1 1 101 | flag_o = a_i ≥ b_i | **Знаковое** сравнение **≥** |
|
||||
| LTU | 1 1 110 | flag_o = a_i < b_i | **Беззнаковое** сравнение **<** |
|
||||
| GEU | 1 1 111 | flag_o = a_i ≥ b_i | **Беззнаковое** сравнение **≥** |
|
||||
| Operation | ={cmp, mod, opcode} | Expression | Action |
|
||||
|-----------|---------------------|------------------------|--------------------------------------|
|
||||
| EQ | 1 1 000 | flag_o = (a_i == b_i) | Set flag if operands are **equal** |
|
||||
| NE | 1 1 001 | flag_o = (a_i != b_i) | Set flag if operands are **unequal** |
|
||||
| LTS | 1 1 100 | flag_o = a_i < b_i | **Signed** comparison **<** |
|
||||
| GES | 1 1 101 | flag_o = a_i ≥ b_i | **Signed** comparison **≥** |
|
||||
| LTU | 1 1 110 | flag_o = a_i < b_i | **Unsigned** comparison **<** |
|
||||
| GEU | 1 1 111 | flag_o = a_i ≥ b_i | **Unsigned** comparison **≥** |
|
||||
|
||||
_Таблица 2. Список операций сравнения._
|
||||
_Table 2. List of comparison operations._
|
||||
|
||||
**Выражения в этих двух таблицах приведены для примера. Не все из них можно просто переписать — часть этих выражений надо дополнить. Чтобы вы не копировали выражения, в них вставлены неподдерживаемые символы.**
|
||||
**The expressions in these two tables are provided as examples. Not all of them can simply be transcribed — some must be supplemented. To prevent copy-pasting, the expressions contain unsupported characters.**
|
||||
|
||||
Несмотря на разделение на вычислительные операции, и операции сравнения, в _Таблице 1_ (вычислительных операций) оказалось две операции: `SLTS` и `SLTU`, которые выполняют сравнения. В итоге у нас есть две похожие пары инструкций:
|
||||
Despite the separation into computational operations and comparison operations, _Table 1_ (computational operations) includes two operations — `SLTS` and `SLTU` — that perform comparisons. This gives us two similar pairs of instructions:
|
||||
|
||||
- `LTS`
|
||||
- `LTU`
|
||||
- `SLTS`
|
||||
- `SLTU`
|
||||
|
||||
Первая пара инструкций вычисляет "ветвительный" результат. Результат операции будет подан на выходной сигнал `flag_o` и использован непосредственно при ветвлении.
|
||||
The first pair computes a "branch" result. The operation result is placed on the `flag_o` output and used directly for branching.
|
||||
|
||||
Вторые две инструкции используются для получения "вычислительного" результата. Т.е. результат сравнения будет подан на выходной сигнал `result_o` так же, как подается результат операции `ADD`, и будет использован в неких вычислениях, избегая при этом условного перехода.
|
||||
The second pair is used to obtain a "computational" result. That is, the comparison result is placed on the `result_o` output in the same way as the result of the `ADD` operation, and is used in further computations — avoiding a conditional branch.
|
||||
|
||||
К примеру, нам необходимо пройтись по массиву из миллиона элементов и убедиться, что все они были неотрицательны. Об этом будет сигнализировать переменная `num_of_err`, значение которой должно быть равно числу элементов массива, меньших нуля. Вычислить значение этой переменной можно двумя способами:
|
||||
For example, suppose we need to iterate over an array of one million elements and check that all of them are non-negative. This is tracked by the variable `num_of_err`, whose value should equal the count of elements less than zero. The variable can be computed in two ways:
|
||||
|
||||
1. В каждой итерации цикла сделать ветвление: в одном случае инкрементировать переменную, в другом случае — нет (для ветвления использовать "ветвительную" операцию `LTS`).
|
||||
2. В каждой итерации цикла складывать текущее значение переменной с результатом "вычислительной" операции `SLTS`.
|
||||
1. In each loop iteration, perform a branch: in one case increment the variable, in the other do not (use the "branch" operation `LTS` for branching).
|
||||
2. In each loop iteration, add the result of the "computational" operation `SLTS` to the current value of the variable.
|
||||
|
||||
Операции ветвления очень сильно влияют (в худшую сторону) на производительность конвейерного процессора. В первом случае мы получим миллион операций ветвления, во втором — ни одной! Разумеется, потом переменную `num_of_err` скорее всего сравнят с нулем что приведет к ветвлению, но при вычислении значения этой переменной ветвления можно будет избежать.
|
||||
Branch operations have a strong (negative) impact on the performance of a pipelined processor. In the first case we get one million branch operations; in the second — none! Of course, `num_of_err` will likely be compared to zero at some point, causing a branch, but during the computation of that variable's value the branch can be avoided entirely.
|
||||
|
||||
Различие между `SLTS` и `SLTU` (или `LTS` и `LTU`) заключается в том, как мы интерпретируем операнды: как знаковые числа (операции `STLS` и `LTS`) или как беззнаковые (операции `SLTU` и `LTU`).
|
||||
The difference between `SLTS` and `SLTU` (or `LTS` and `LTU`) lies in how we interpret the operands: as signed numbers (operations `SLTS` and `LTS`) or as unsigned (operations `SLTU` and `LTU`).
|
||||
|
||||
Предположим, мы сравниваем два двоичных числа: `1011` и `0100`. Если интерпретировать эти числа как беззнаковые, то это `11` и `4`, результат: `11 > 4`. Однако если интерпретировать эти числа как знаковые, то теперь это числа `-5` и `4` и в этом случае `-5 < 4`.
|
||||
Suppose we compare two binary numbers: `1011` and `0100`. Interpreted as unsigned, these are `11` and `4`, giving `11 > 4`. Interpreted as signed, they are `-5` and `4`, giving `-5 < 4`.
|
||||
|
||||
Как мы видим, результат одной и той же операции над одними и теми же двоичными числами может зависеть от того, каким образом мы интерпретируем эти двоичные числа. Для большинства операций в АЛУ это не важно: например, сложение будет работать одинаково в обоих случаях, благодаря свойствам дополнительного кода, а побитовые операции работают с отдельными битами двоичного числа. А вот для операции арифметического сдвига это важно — **операнд А в арифметическом сдвиге должен интерпретироваться как знаковый**.
|
||||
As we can see, the result of the same operation on the same binary numbers can depend on how those numbers are interpreted. For most ALU operations this does not matter — for example, addition works identically in both cases due to the properties of two's complement, and bitwise operations work on individual bits. However, for arithmetic right shift it does matter — **the operand A in an arithmetic shift must be interpreted as signed**.
|
||||
|
||||
По умолчанию SystemVerilog интерпретирует все сигналы как беззнаковые, если мы хотим изменить это поведение, необходимо воспользоваться конструкцией `$signed`.
|
||||
By default, SystemVerilog interprets all signals as unsigned. To change this behavior, use the `$signed` construct.
|
||||
|
||||
Конструкция `$signed` говорит САПР интерпретировать число, переданное в качестве операнда, как знаковое.
|
||||
The `$signed` construct tells the synthesis tool to interpret the value passed as an operand as a signed number.
|
||||
|
||||
```Verilog
|
||||
assign Result = $signed(A) / 10;
|
||||
```
|
||||
|
||||
В этом примере некоторому сигналу `Result` присваивают результат деления **знакового** числа `A` на `10`.
|
||||
In this example, signal `Result` is assigned the result of dividing the **signed** number `A` by `10`.
|
||||
|
||||
Так как используются не все возможные комбинации управляющего сигнала АЛУ, то **при описании через `case` не забывайте использовать `default`**. Если описать АЛУ как задумано, то получится что-то похожее на _рис. 5_. Но не обязательно, зависит от вашего описания.
|
||||
Since not all possible combinations of the ALU control signal are used, **when describing the logic with `case`, do not forget to include a `default` branch**. If the ALU is described as intended, the result will look something like _Fig. 5_ — though it may differ depending on your description.
|
||||
|
||||

|
||||
|
||||
_Рисунок 5. Пример схемы, реализующей АЛУ._
|
||||
_Figure 5. Example circuit implementing the ALU._
|
||||
|
||||
Обратите внимание на то, что сумматор на _рис. 5_ отличается от всех остальных блоков. Для того, чтобы спроектированный в ЛР№1 32-разрядный сумматор был создан не зазря, а также для закрепления навыков по созданию экземпляров модулей внутри других модулей, вам предлагается использовать его при реализации АЛУ.
|
||||
Note that the adder in _Fig. 5_ differs from all other blocks. To make the 32-bit adder designed in Lab 1 worthwhile, and to reinforce module instantiation skills, you are expected to use it when implementing the ALU.
|
||||
|
||||
Другие блоки распознаны Vivado на основе представленных в описании АЛУ арифметических или логических выражений и в процессе синтеза будут реализованы через те компоненты ПЛИС, которые позволят лучше всего удовлетворить временным и физическим ограничениям проекта (см. главу "Этапы реализации проекта в ПЛИС"). Сумматор же будет реализован так, как это описали мы, поскольку вместо использования абстрактной операции "+" в описании АЛУ было сказано разместить конкретный модуль, реализующий конкретную схему. Такая реализация сумматора не является эффективной ни в плане временных характеристик, ни в плане количества затраченных на реализацию ресурсов ПЛИС. Но как уже упоминалось в ЛР№1, цель этой реализации — воспроизвести простоту логики рассуждений о том, как спроектировать сумматор.
|
||||
The other blocks are recognized by Vivado from the arithmetic or logical expressions in the ALU description and will be synthesized using the FPGA primitives that best satisfy the project's timing and physical constraints (see "FPGA Design Flow"). The adder, however, will be implemented exactly as described, because instead of using the abstract `+` operator, the ALU description instantiates a specific module implementing a specific circuit. This adder implementation is not efficient — neither in terms of timing characteristics nor in terms of FPGA resource utilization. But as mentioned in Lab 1, the goal of this implementation is to illustrate the simplicity of the design reasoning behind the adder.
|
||||
|
||||
### Порядок выполнения задания
|
||||
### Assignment Steps
|
||||
|
||||
1. Добавьте в `Design Sources` проекта файл [`alu_opcodes_pkg.sv`](alu_opcodes_pkg.sv). Этот файл содержит объявление пакета `alu_opcodes_pkg`, в котором прописаны все опкоды АЛУ.
|
||||
1. Поскольку данный файл не содержит описания модулей, он не отобразится во вкладке `Hierarchy` окна `Sources` Vivado (исключением может быть ситуация, когда в проекте вообще нет ни одного модуля). Добавленный файл можно будет найти во вкладках `Libraries` и `Compile Order`.
|
||||
2. Обратите внимание, что имена параметров кодов операций АЛУ, объявленных в добавляемом пакете, имеют префикс `ALU_`, которого не было в _таблицах 1 и 2_.
|
||||
3. В случае, если вы добавили пакет в проект и импортировали его в модуле АЛУ, однако Vivado выдает ошибку о том, что используемые параметры не объявлены, попробуйте сперва исправить все остальные синтаксические ошибки и сохранить файл. Если и это не помогло, можно перейти на вкладку `Compile Order`, нажать правой кнопкой мыши по файлу `alu_opcodes_pkg.sv` и выбрать `Move to Top`. Таким образом, мы сообщаем Vivado, что при компиляции проекта, этот файл всегда необходимо собирать в первую очередь. Это вариант "последней надежды" и должен использоваться только в самом крайнем случае. Когда в проекте нет никаких проблем, Vivado всегда может самостоятельно определить правильный порядок компиляции файлов. Тот факт, что вам приходится менять этот порядок означает, что в проекте есть какие-то проблемы, не позволяющие Vivado определить правильный порядок самостоятельно.
|
||||
2. Опишите модуль `alu` с таким же именем и портами, как указано в [задании](#Задание).
|
||||
1. Поскольку у вас два выходных сигнала, зависящих от сигнала `alu_op_i`, вам потребуется описать два разных [мультиплексора](../../Basic%20Verilog%20structures/Multiplexors.md) (их лучше всего описывать через два отдельных блока `case`). При описании, используйте `default` на оставшиеся комбинации сигнала `alu_op_i`.
|
||||
2. Следите за разрядностью ваших сигналов.
|
||||
3. Для реализации АЛУ, руководствуйтесь таблицей с операциями, а не схемой в конце задания, которая приведена в качестве референса. Обратите внимание, в одной половине операций `flag_o` должен быть равен нулю, в другой `result_o` (т.е. всегда либо один, либо другой сигнал должен быть равен нулю). Именно поэтому удобней всего будет описывать АЛУ в двух разных блоках `case`.
|
||||
4. Вам не нужно переписывать опкоды из таблицы в качестве вариантов для блока `case`. Вместо этого используйте символьные имена с помощью параметров, импортированных из пакета `alu_opcodes_pkg`.
|
||||
5. Описывая операцию сложения вы **должны** использовать ваш 32-битный сумматор из первой лабораторной. При описании вычитания сумматор использовать не надо, можно использовать оператор `-`.
|
||||
1. При подключении сумматора, на входной бит переноса необходимо подать значение `1'b0`. Если не подать значение на входной бит переноса, результат суммы будет не определен (т.к. не определено одно из слагаемых).
|
||||
2. Выходной бит переноса при подключении сумматора можно не указывать, т.к. он использоваться не будет.
|
||||
6. При реализации операций сдвига, руководствуйтесь [особенностями реализации сдвигов](#Особенности-реализации-сдвига).
|
||||
3. Проверьте модуль с помощью верификационного окружения, представленного в файле [`lab_02.tb_alu.sv`](lab_02.tb_alu.sv). В случае, если в TCL-консоли появились сообщения об ошибках, вам необходимо [найти](../../Vivado%20Basics/05.%20Bug%20hunting.md) и исправить их.
|
||||
1. Перед запуском моделирования убедитесь, что у вас выбран корректный модуль верхнего уровня в `Simulation Sources`.
|
||||
4. [Проверьте](./board%20files) работоспособность вашей цифровой схемы в ПЛИС.
|
||||
1. Add the file [`alu_opcodes_pkg.sv`](alu_opcodes_pkg.sv) to the project's `Design Sources`. This file contains the declaration of the `alu_opcodes_pkg` package, which defines all ALU operation codes.
|
||||
1. Since this file contains no module declarations, it will not appear in the `Hierarchy` tab of the Vivado `Sources` window (the exception is when the project contains no modules at all). The added file can be found in the `Libraries` and `Compile Order` tabs.
|
||||
2. Note that the ALU operation code parameter names declared in the added package have the prefix `ALU_`, which was not present in _Tables 1 and 2_.
|
||||
3. If you have added the package to the project and imported it in the ALU module but Vivado reports an error saying the used parameters are undeclared, first try fixing all other syntax errors and saving the file. If that does not help, go to the `Compile Order` tab, right-click on `alu_opcodes_pkg.sv`, and select `Move to Top`. This tells Vivado to always compile this file first. This is a last-resort option and should only be used as a final measure. When the project has no issues, Vivado is always able to determine the correct compilation order on its own. The fact that you need to change this order indicates there are problems in the project preventing Vivado from determining the correct order automatically.
|
||||
2. Describe the `alu` module with the same name and ports as specified in the [assignment](#Assignment).
|
||||
1. Since you have two output signals that depend on `alu_op_i`, you will need to describe two separate [multiplexers](../../Basic%20Verilog%20structures/Multiplexors.md) (best described using two separate `case` blocks). Use `default` to cover the remaining combinations of `alu_op_i`.
|
||||
2. Pay attention to the bit widths of your signals.
|
||||
3. When implementing the ALU, follow the operations table rather than the reference schematic at the end of the assignment. Note that in one half of the operations `flag_o` must be zero, and in the other half `result_o` must be zero (i.e., at all times, one or the other signal must be zero). This is why it is most convenient to describe the ALU using two separate `case` blocks.
|
||||
4. You do not need to copy operation codes from the table as `case` values. Instead, use the symbolic names from the parameters imported from the `alu_opcodes_pkg` package.
|
||||
5. When describing the addition operation, you **must** use your 32-bit adder from Lab 1. For subtraction, you do not need to use the adder — you may use the `-` operator.
|
||||
1. When connecting the adder, supply `1'b0` to the carry-in input. If the carry-in is left undriven, the sum result will be undefined (since one of the addends is undefined).
|
||||
2. The carry-out can be left unconnected, as it will not be used.
|
||||
6. When implementing shift operations, follow the [shift implementation notes](#Shift-Implementation-Notes).
|
||||
3. Verify the module using the verification environment provided in the file [`lab_02.tb_alu.sv`](lab_02.tb_alu.sv). If error messages appear in the TCL console, [find](../../Vivado%20Basics/05.%20Bug%20hunting.md) and fix them.
|
||||
1. Before running the simulation, make sure the correct top-level module is selected in `Simulation Sources`.
|
||||
4. [Verify](./board%20files) that your digital circuit works correctly on the FPGA.
|
||||
|
||||
## Список использованной литературы
|
||||
## References
|
||||
|
||||
1. [Д.М. Харрис, С.Л. Харрис / Цифровая схемотехника и архитектура компьютера: RISC-V / пер. с англ. В. С. Яценков, А. Ю. Романов; под. ред. А. Ю. Романова / М.: ДМК Пресс, 2021](https://e.lanbook.com/book/241166);
|
||||
1. D.M. Harris, S.L. Harris / Digital Design and Computer Architecture. RISC-V Edition, 2021;
|
||||
2. [The RISC-V Instruction Set Manual Volume I: Unprivileged ISA, Document Version 20240411, Editors Andrew Waterman and Krste Asanović, RISC-V Foundation, April 2024](https://github.com/riscv/riscv-isa-manual/releases/download/20240411/unpriv-isa-asciidoc.pdf).
|
||||
|
||||
@@ -328,7 +328,7 @@ module register_file(
|
||||
|
||||
```
|
||||
|
||||
По адресу `0` должно всегда считываться значение `0` вне зависимости от того, какое значение в этой ячейке памяти, и есть ли она вообще. Такая особенность обусловлена тем, что при выполнении операций очень часто используется ноль (сравнение с нулём, инициализация переменных нулевым значением, копирование значения одного регистра в другой посредством сложения с нулём и записи результата и т.п.). Эту особенность регистрового файла можно реализовать несколькими способами:
|
||||
По спецификации RISC-V, нулевой регистр регистрового файла является аппаратным нулём [[2](https://github.com/riscv/riscv-isa-manual/releases/download/20240411/unpriv-isa-asciidoc.pdf), стр. 21]. Это значит, что по адресу `0` должно всегда считываться значение `0` вне зависимости от того, какое значение в этой ячейке памяти, и есть ли она вообще. Такая особенность обусловлена тем, что при выполнении операций очень часто используется ноль (сравнение с нулём, инициализация переменных нулевым значением, копирование значения одного регистра в другой посредством сложения с нулём и записи результата и т.п.). Эту особенность регистрового файла можно реализовать несколькими способами:
|
||||
|
||||
- с помощью мультиплексора, управляющим сигналом которого является результат сравнения адреса на чтение с нулём;
|
||||
- либо же можно проинициализировать нулевую ячейку памяти нулём с запретом записи в неё каких-либо значений. В этом случае в ячейке всегда будет ноль, а значит и считываться с нулевого адреса будет только он.
|
||||
|
||||
@@ -101,7 +101,7 @@ module lab_15_tb_system();
|
||||
end
|
||||
|
||||
|
||||
system DUT(
|
||||
processor_system DUT(
|
||||
.clk_i (clk_i ),
|
||||
.resetn_i (!rst_i ),
|
||||
.rx_i (flashing_is_done ? tb_rx : flash_rx ),
|
||||
|
||||
@@ -210,6 +210,15 @@ _Листинг 4. Код функции `uart_send_char`._
|
||||
|
||||
### Компиляция
|
||||
|
||||
> «Я нашёл этому поистине чудесное доказательство, но поля книги слишком узки для него».
|
||||
> — Пьер де Ферма
|
||||
|
||||
Репозиторий CoreMark содержит встроенную систему сборки, основанную на утилите `make`, с возможностью добавления пользовательских платформ. При корректной интеграции платформы программу можно было бы собрать, запрограммировать ею микроконтроллер и получить результат выполнения одной командой.
|
||||
|
||||
Однако для описания такого подхода потребовалась бы отдельная глава, посвящённая системе сборки, утилите `make` и Python-скрипту, отвечающему за программирование микроконтроллера. Поэтому в данном параграфе авторы выбрали более простой путь — заменили исходную систему сборки собственной, упрощённой реализацией, поддерживающей только нашу платформу.
|
||||
|
||||
Ознакомиться с корректным способом интеграции можно в репозитории [github.com/MPSU/APS-coremark](https://github.com/MPSU/APS-coremark).
|
||||
|
||||
Для компиляции программы, вам потребуются предоставленные файлы [Makefile](Makefile) и [linker_script.ld](linker_script.ld), а также файл [startup.S](../14.%20Programming/startup.S) из ЛР№14. Эти файлы необходимо скопировать с заменой в корень папки с программой.
|
||||
|
||||
`Makefile` написан из расчёта, что кросс-компилятор расположен по пути `C:/riscv_cc/`. В случае, если это не так, измените первую строчку данного файла в соответствии с расположением кросс-компилятора.
|
||||
|
||||
Submodule Lectures/Presentations updated: b030af68d1...dd6e7f205f
@@ -29,7 +29,7 @@
|
||||
|
||||
## Дэвид М. Харрис и Сара Л. Харрис: Цифровая схемотехника и архитектура компьютера: RISC-V
|
||||
|
||||
Потрясающая книга, являющаяся более доступным вариантом изложения и иллюстрации книги "Архитектура компьютера и проектирование компьютерных систем", Паттерсона и Хеннесси. На примере архитектуры **RISC-V** рассказывается как построить процессор начиная с вопросов работы транзистора. Рассматриваются базовые конструкции языков описания аппаратуры **SystemVerilog** и **VHDL**. Эту книгу на чистом энтузиазме перевели на русский язык группа ученых и инженеров из стран бывшего СССР с подачи [Юрия Панчула](http://panchul.com/about_ru/). Электронный вариант для архитектуры **MIPS** распространяется бесплатно и абсолютно легально. Обязательна к ознакомлению каждому! Гораздо удобнее использовать печатный вариант, на этот случай ее можно приобрести [тут](https://dmkpress.com/catalog/electronics/circuit_design/978-5-97060-961-3/). Электронный вариант с архитектурой **MIPS** доступен в облаке и [электронной библотеке](https://e.lanbook.com/book/241166).
|
||||
Потрясающая книга, являющаяся более доступным вариантом изложения и иллюстрации книги "Архитектура компьютера и проектирование компьютерных систем", Паттерсона и Хеннесси. На примере архитектуры **RISC-V** рассказывается как построить процессор начиная с вопросов работы транзистора. Рассматриваются базовые конструкции языков описания аппаратуры **SystemVerilog** и **VHDL**. Эту книгу на чистом энтузиазме перевели на русский язык группа ученых и инженеров из стран бывшего СССР с подачи [Юрия Панчула](http://panchul.com/about_ru/). Электронный вариант для архитектуры **MIPS** распространяется бесплатно и абсолютно легально. Обязательна к ознакомлению каждому! Гораздо удобнее использовать печатный вариант, на этот случай ее можно приобрести [тут](https://dmkpress.com/catalog/electronics/circuit_design/978-5-97060-961-3/). Электронный вариант с архитектурой **RISC-V** доступен в [электронной библотеке](https://e.lanbook.com/book/241166).
|
||||
|
||||

|
||||
|
||||
|
||||
Reference in New Issue
Block a user