mirror of
https://github.com/MPSU/APS.git
synced 2026-04-18 10:25:33 +00:00
Compare commits
4 Commits
english_ve
...
896f7fccda
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
896f7fccda | ||
|
|
40074bcb25 | ||
|
|
b480505e11 | ||
|
|
59b569a1e4 |
@@ -1,279 +1,281 @@
|
|||||||
# What is an FPGA and How Does It Work
|
# Что такое ПЛИС и как она работает
|
||||||
|
|
||||||
- [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)
|
- [Таблицы подстановки (Look-Up Tables, LUTs)](#Таблицы-подстановки-look-up-tables-luts)
|
||||||
- [D Flip-Flops](#d-flip-flops)
|
- [D-триггеры](#d-триггеры)
|
||||||
- [Arithmetic](#arithmetic)
|
- [Арифметика](#Арифметика)
|
||||||
- [Logic Blocks](#logic-blocks)
|
- [Логические блоки](#Логические-блоки)
|
||||||
- [Interconnect Network](#interconnect-network)
|
- [Сеть межсоединений](#Сеть-межсоединений)
|
||||||
- [Chapter Summary](#chapter-summary)
|
- [Итоги главы](#Итоги-главы)
|
||||||
- [References](#references)
|
- [Список источников](#Список-источников)
|
||||||
|
|
||||||
> 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.
|
> Параграфы "Цифровые схемы и логические вентили" и "Таблицы подстановки" во многом используют материалы статьи "[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/).
|
||||||
|
|
||||||
## History of FPGAs
|
## История появления ПЛИС
|
||||||
|
|
||||||
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.
|
До появления интегральных схем электронные устройства строились на базе вакуумных ламп, которые выполняли функции усиления и переключения. Эти лампы были громоздкими, энергозатратными и недолговечными. Затем их заменили на транзисторы, которые стали основой современных электронных схем. Поначалу транзисторы, как и лампы, использовались в виде отдельных компонентов, и схемы собирались из них, как модель из кубиков Lego. В случае ошибки её можно было исправить ручной корректировкой соединений между элементами, подобно исправлению ошибки при сборке модели Lego.
|
||||||
|
|
||||||
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.
|
С развитием технологий произошла миниатюризация транзисторов, что позволило разместить их вместе с соединениями на одном кристалле. Так появились интегральные схемы — электронные схемы, выполненные на полупроводниковой подложке и заключённые в неразборный корпус. Этот переход стал революционным шагом в развитии электроники, открыв путь к созданию компактных и производительных устройств.
|
||||||
|
|
||||||
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.
|
В большинстве случаев, исправить ошибку, допущенную при разработке и изготовлении интегральной схемы, невозможно. С учетом того, что изготовление прототипа интегральной схемы является долгим и затратным мероприятием (от десятков тысяч до миллионов долларов), возникла необходимость в гибком, быстром и дешёвом способе изготовления прототипа, и проверки на нём схемы до её изготовления. Так появились **программируемые логические интегральные схемы** (**ПЛИС**). В связи с повсеместным использованием англоязычной литературы, имеет смысл дать и англоязычное название этого класса устройств: **programmable logic devices** (**PLD**).
|
||||||
It should be noted that this book mainly focuses on a specific type of PLD known as an 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.
|
Стоит оговориться, что в данной книге под термином ПЛИС будет подразумеваться конкретный тип программируемых схем: **FPGA** (**field-programmable gate array**, **программируемая пользователем вентильная матрица**, **ППВМ**).
|
||||||
|
|
||||||
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.
|
### Цифровые схемы
|
||||||
|
|
||||||
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.
|
**Цифровая схема** — это **абстрактная модель** вычислений, которая оперирует двумя дискретными состояниями, обычно обозначаемыми как `0` и `1`. Важно понимать, что эти состояния не привязаны к конкретным физическим величинам, таким как напряжение в электрической цепи. Вместо этого они представляют собой обобщенные логические значения, которые могут быть реализованы на любой технологии, способной различать два дискретных состояния.
|
||||||
|
|
||||||
Of course, when designing efficient digital circuits, the underlying technology must be taken into account.
|
Благодаря этой абстракции цифровые схемы могут быть реализованы не только с помощью традиционных электронных компонентов, но и на совершенно иных платформах, например на [пневматических системах](https://habr.com/ru/companies/ruvds/articles/692236/), [из картона и шариков](https://habr.com/ru/articles/399391/), [красной пыли](https://minecraft.fandom.com/wiki/Tutorials/Redstone_computers) в игре Майнкрафт или даже с использованием человеческого взаимодействия, подобно тому, как это описано в романе Лю Цысиня "Задача трёх тел" (эффективность подобных схем — это уже другой вопрос). Основная идея заключается в том, что цифровая схема отвязывается от физической реализации, фокусируясь лишь на логике взаимодействия состояний `0` и `1`, что делает её универсальной и независимой от конкретной технологии.
|
||||||
|
|
||||||
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.
|
Разумеется, при проектировании эффективных цифровых схем необходимо оглядываться на технологию, по которой эти схемы будут работать.
|
||||||
|
|
||||||
These basic building blocks are called **logic gates**.
|
В электронике словом "цифровая" описывают схемы, которые абстрагируются от непрерывных (аналоговых) значений напряжений, вместо этого используются только два дискретных значения: `0` и `1`. На данном уровне абстракции нас не интересуют конкретные значения напряжений и пороги этих значений, что позволяет нам разрабатывать схему в идеальном мире, где у напряжения может быть всего два значения: `0` и `1`. А обеспечением этих условий будут заниматься базовые блоки, из которых мы будем строить цифровые схемы.
|
||||||
|
|
||||||
### 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.
|
Существует множество логических вентилей, мы рассмотрим четыре из них: **И**, **ИЛИ**, **Исключающее ИЛИ**, **НЕ**. Каждый из этих элементов принимает на вход **цифровое значение** (см. [**цифровая схема**](#Цифровые-схемы)), выполняет определенную **логическую функцию** над входами и подает на выход результат этой функции в виде **цифрового значения**.
|
||||||
|
|
||||||
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-4_ иллюстрируются условными графическими обозначениями (**УГО**), взятыми из двух стандартов: **ANSI** и **ГОСТ**. Ввиду повсеместного использования в литературе первого варианта, в дальнейшем в книге будет использован он.
|
||||||
|
|
||||||
|
Логический вентиль **И** принимает два входа и выдает на выход значение `1` только в том случае, если оба входа равны `1`. Если хотя бы один из входов `0`, то на выходе будет `0`. На схемах логический вентиль **И** отображается следующим образом:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 1. Schematic symbol of the **AND** gate._
|
_Рисунок 1. УГО логического вентиля **И**._
|
||||||
|
|
||||||
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:
|
Логический вентиль **ИЛИ** принимает два входа и выдает на выход значение `1` в случае, если хотя бы один из входов равен `1`. Если оба входа равны `0`, то на выходе будет `0`. На схемах логический вентиль **ИЛИ** отображается следующим образом:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 2. Schematic symbol of the **OR** gate._
|
_Рисунок 2. УГО логического вентиля **ИЛИ**._
|
||||||
|
|
||||||
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:
|
Логический вентиль **Исключающее ИЛИ** принимает два входа и выдает на выход значение `1` в случае, если значения входов не равны между собой (один из них равен `1`, а другой `0`). Если значения входов равны между собой (оба равны `0` или оба равны `1`), то на выходе будет `0`. На схемах логический вентиль **Исключающее ИЛИ** отображается следующим образом:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 3. Schematic symbol of the **XOR** gate._
|
_Рисунок 3. УГО логического вентиля **Исключающее ИЛИ**._
|
||||||
|
|
||||||
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:
|
Логический вентиль **НЕ** — самый простой. Он принимает один вход и подает на выход его инверсию. Если на вход пришло значение `0`, то на выходе будет `1`, если на вход пришло значение `1`, то на выходе будет `0`. Он обозначается на схемах следующим образом:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 4. Schematic symbol of the **NOT** gate._
|
_Рисунок 4. УГО логического вентиля **НЕ**._
|
||||||
|
|
||||||
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.
|
Логические вентили могут быть построены из **транзисторов**. **Транзистор** — это элемент, который может пропускать/блокировать ток в зависимости от поданного напряжения на его управляющий вход.
|
||||||
|
|
||||||
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**-типа (**Комплементарная Металл-Оксид-Полупроводниковая**, **КМОП** логика). Для данного типа транзисторов оказалось эффективнее реализовать операции **И-НЕ** и **ИЛИ-НЕ**.
|
||||||
|
|
||||||
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.
|
С точки зрения построения цифровых схем МОП-транзисторы (**P**- и **N**-типа) можно воспринимать как выключатели, которые замыкают или размыкают связь между двумя выводами. Разница между **P**- и **N** типами заключается в значении напряжения на управляющем входе, при котором транзистор "открыт" (вход и выход замкнуты) или "закрыт" (связь разорвана). _Рис. 5_ иллюстрирует данное различие.
|
||||||
|
|
||||||
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!
|
Выводы, между которыми образуется связь называются "**сток**" (**drain**, **d**) и "**исток**" (**source**, **s**), а управляющий вход — "**затвор**" (**gate**, **g**). Обратите внимание, что логический вентиль (**logic gate**) и затвор транзистора (просто **gate**) — это разные сущности!
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 5. P-type and N-type MOS transistors._
|
_Рисунок 5. МОП-транзисторы P и N типа._
|
||||||
|
|
||||||
_Fig. 6_ shows how **NAND** and **NOR** gates are constructed using **CMOS** technology. Let us walk through the operation of the **NAND** gate.
|
На _рис. 6_ показан способ построения логических вентилей **И-НЕ**, **ИЛИ-НЕ** по **КМОП** технологии. Рассмотрим принцип работы вентиля **И-НЕ**.
|
||||||
|
|
||||||
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.
|
Подача значения `1` на вход **А** или **B** открывает соответствующий этому входу n-канальный транзистор (обозначен на _рис. 6_ красным цветом) и закрывает дополняющий его (комплементарный ему) p-канальный транзистор (обозначен синим цветом). Подача на оба входа `1` закрывает оба p-канальных транзистора (верхняя часть схемы разомкнута, что для значения на выходе означает, что её будто и нет) и открывает оба n-канальных транзистора. В результате чего выход замыкается на "землю" (чёрный треугольник внизу схемы), что эквивалентно `0` в контексте цифровых значений.
|
||||||
|
|
||||||
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.
|
В случае, если хотя бы на одном из входов **А** или **B** будет значение `0`, откроется один из параллельно соединенных p-канальных транзисторов (в то время как соединение с "землей" будет разорвано) и выход будет подключен к питанию (две перпендикулярные линии вверху схемы), что эквивалентно `1` в контексте цифровых значений.
|
||||||
|
|
||||||
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**.
|
Как вы видите, напряжение на выход подается от **источников постоянного питания** или **земли**, а не от входов вентиля, именно этим и обеспечивается постоянное обновление напряжения и устойчивость **цифровых схем** к помехам.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 6. Schematic of **NAND** and **NOR** gates built from CMOS transistors._
|
_Рисунок 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_.
|
Как правило, при необходимости инвертировать вход или выход логического элемента на схеме, на нем рисуют кружок вместо добавления логического вентиля **НЕ** в том виде, котором он изображён на _рис. 4_. К примеру, логический элемент **И-НЕ** обозначают в виде, представленном на _рис. 6_.
|
||||||
|
|
||||||
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._
|
_Рисунок 7. Схема логического вентиля **НЕ**, построенного на КМОП транзисторах._
|
||||||
|
|
||||||
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**.
|
Мультиплексор — это устройство, которое в зависимости от значения **управляющего сигнала** подает на выход значение одного из входных сигналов.
|
||||||
|
|
||||||
The schematic symbol of a multiplexer is shown in _Figure 8_.
|
УГО мультиплексора представлено на _рисунке 8_.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 8. Multiplexer symbol._
|
_Рисунок 8. Обозначение Мультиплексора._
|
||||||
|
|
||||||
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.
|
Символ `/` на линии `sel` указывает на то, что данный сигнал является многоразрядным, а число ниже указывает на то, что разрядность сигнала составляет 6 бит.
|
||||||
|
|
||||||
A multiplexer can have any number of inputs, but always has exactly one output.
|
Число входов мультиплексора может быть различным, но выход у него всегда один.
|
||||||
|
|
||||||
**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.
|
**Способ, которым кодируется значение управляющего сигнала может также различаться**. Простейшая цифровая схема мультиплексора получится, если использовать [**унитарное**](https://ru.wikipedia.org/wiki/Унитарный_код) (**one-hot**) кодирование. При таком кодировании, значение **многоразрядного** управляющего сигнала **всегда** содержит **ровно одну** `1`. Информация, которую несёт закодированный таким образом сигнал содержится в положении этой `1` внутри управляющего сигнала.
|
||||||
|
|
||||||
Let us see how a multiplexer with a one-hot-encoded select signal can be implemented using only **AND** and **OR** gates:
|
Посмотрим, как можно реализовать мультиплексор с управляющим сигналом, использующим one-hot-кодирование, при помощи одних лишь логических вентилей **И**, **ИЛИ**:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 9. Multiplexer implementation using one-hot encoding._
|
_Рисунок 9. Реализация мультиплексора, использующего one-hot кодирование._
|
||||||
|
|
||||||
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`.
|
Если мы выставим значение управляющего сигнала, равное `000010`, означающее, что только **первый** бит этого сигнала (**счет ведется с нуля**) будет равен **единице** (`sel[1] = 1`), то увидим, что на один из входов каждого логического вентиля **И** будет подано значение `0`. Исключением будет логический вентиль **И** для входа `b`, на вход которого будет подано значение `1`. Это означает, что все логические вентили **И** (кроме первого, на который подается вход `b`) будут выдавать на выход `0` (см. [Логические вентили](#Логические-вентили)) вне зависимости от того, что было подано на входы a,c,d,e и f. Единственным входом, который будет влиять на работу схемы, окажется вход `b`. Когда он равен `1`, на выходе соответствующего логического вентиля **И** окажется значение `1`. Когда он равен `0` на выходе **И** окажется значение `0`. Иными словами, выход **И** будет повторять значение `b`.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 10. Multiplexer implementation using one-hot encoding._
|
_Рисунок 10. Реализация мультиплексора, использующего one-hot кодирование._
|
||||||
|
|
||||||
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:
|
Логический вентиль **ИЛИ** на данной схеме имеет больше двух входов. Подобный вентиль может быть создан в виде каскада логических вентилей **ИЛИ**:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 11. Multi-input **OR** gate implementation._
|
_Рисунок 11. Реализация многоходового логического **ИЛИ**._
|
||||||
|
|
||||||
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`.
|
**Многовходовой вентиль ИЛИ** ведет себя ровно так же, как двухвходовой: он выдает на выход значение `1`, когда хотя бы один из входов равен `1`. В случае, если все входы равны `0`, на выход **ИЛИ** пойдет `0`.
|
||||||
|
|
||||||
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`).
|
Для нашей схемы мультиплексора гарантируется, что каждый вход **ИЛИ** кроме одного будет равняться `0` (поскольку выход каждого **И** кроме одного будет равен `0`). Это означает, что выход **многовходового ИЛИ** будет зависеть только от **одного** входа (в случае, когда `sel = 000010` — от входа `b`).
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 12. Multiplexer implementation using one-hot encoding._
|
_Рисунок 12. Реализация мультиплексора, использующего one-hot кодирование._
|
||||||
|
|
||||||
By changing the value of `sel`, we can control which multiplexer input is routed to the output.
|
Меняя значение `sel`, мы можем управлять тем, какой из входов мультиплексора будет идти на его выход.
|
||||||
|
|
||||||
### Programmable Memory
|
### Программируемая память
|
||||||
|
|
||||||
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 представлена схема простейшей ячейки статической памяти, состоящей из транзистора и двух инверторов (т.е. суммарно состоящей из 5 транзисторов, поэтому она называется **5T** SRAM). Данная ячейка реализует 1 бит программируемой памяти, являвшейся одним из основных компонентов самой первой ПЛИС.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 13. Programmable memory cell of the Xilinx XC2064 FPGA [[2, p. 2-63](https://archive.org/details/programmablegate00xili/page/n93/mode/2up)]._
|
_Рисунок 13. Программируемая ячейка памяти ПЛИС Xilinx XC2064[[2, стр. 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)
|
||||||
|
|
||||||
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**).
|
Представьте мультиплексор с четырьмя входными сигналами и двухбитным управляющим сигналом (обратите внимание, что теперь это сигнал использует обычное двоичное кодирование). Но теперь, вместо того чтобы выставлять входные сигналы во внешний мир, давайте подключим их к программируемой памяти. Это означает, что мы можем "запрограммировать" каждый из входов на какое-то константное значение. Поместим то, что у нас получилось, в отдельный блок и вот, мы получили двухвходовую **Таблицу подстановки** (**Look-Up Tables**, далее **LUT**).
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 14. Look-Up Table (LUT) implementation._
|
_Рисунок 14. Реализация таблицы подстановки (Look-Up Table, 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**.
|
Эти два входа **LUT** являются битами управляющего сигнала мультиплексора, спрятанного внутри **LUT**. Программируя входы мультиплексора (точнее, программируя память, к которой подключены входы мультиплексора), мы можем реализовать на базе **LUT** **любую(!)** логическую функцию, принимающую два входа и возвращающую один выход.
|
||||||
|
|
||||||
For example, suppose we want to implement **logical AND**. To do so, we need to write the following content into the memory:
|
Допустим, мы хотим получить **логическое И**. Для этого, нам потребуется записать в память следующее содержимое:
|
||||||
|
|
||||||
| Address ({x, y}) | Value (f) |
|
|Адрес ({x, y}) | Значение (f)|
|
||||||
|------------------|-----------|
|
|---------------|-------------|
|
||||||
| 00 | 0 |
|
| 00 | 0 |
|
||||||
| 01 | 0 |
|
| 01 | 0 |
|
||||||
| 10 | 0 |
|
| 10 | 0 |
|
||||||
| 11 | 1 |
|
| 11 | 1 |
|
||||||
|
|
||||||
This is the simplest example — in practice, **LUT**s typically have more inputs, allowing them to implement more complex logic.
|
Это простейший пример — обычно **LUT**-ы имеют больше входов, что позволяет им реализовывать более сложную логику.
|
||||||
|
|
||||||
## D Flip-Flops
|
## D-триггеры
|
||||||
|
|
||||||
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.
|
Как вы уже поняли, используя неограниченное количество LUT-ов, вы можете построить цифровую схему, реализующую логическую функцию любой сложности. Однако цифровые схемы не ограничиваются реализацией одних только логических функций (цифровые схемы, реализующие логическую функцию, называются **комбинационными**, поскольку выход зависит только от комбинации входов). Например, так не построить цифровую схему, реализующую процессор. Для таких схем нужны элементы памяти. Заметим, что речь идет не о программируемой памяти, задавая значения которой мы управляем тем, какие логические функции будут реализовывать LUT-ы. Речь идет о ячейках памяти, которые будут использоваться логикой самой схемы.
|
||||||
|
|
||||||
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 flip-flop**). Из D-триггеров можно собирать другие ячейки памяти, например **регистры** (а из регистров можно собрать **память с произвольным доступом** (**random access memory**, **RAM**)), **сдвиговые регистры** и т.п.
|
||||||
|
|
||||||
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:
|
**D-триггер** — это цифровой элемент, способный хранить один бит информации. В базовом варианте у этого элемента есть два входа и один выход. Один из входов подает значение, которое будет записано в **D-триггер**, второй вход управляет записью (обычно он называется `clk` или `clock` и подключается к тактирующему синхроимпульсу схемы). Когда управляющий сигнал меняет своё значение с `0` на `1` (либо с `1` на `0`, зависит от схемы), в **D-триггер** записывается значение сигнала данных. Обычно, описывая **D-триггер**, говорится, что он строится из двух **триггеров-защелок** (**D-latch**), которые, в свою очередь, строятся из **RS-триггеров**. Однако в конечном итоге, все эти элементы могут быть построены на базе логических вентилей **И**/**ИЛИ**, **НЕ**:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 15. D flip-flop implementation._
|
_Рисунок 15. Реализация D-триггера._
|
||||||
|
|
||||||
## Arithmetic
|
## Арифметика
|
||||||
|
|
||||||
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.
|
Помимо описанных выше блоков (мультиплексоров и построенных на их основе LUT-ов и регистров) выделяется еще один тип блоков, настолько часто используемый в цифровых схемах, что его заранее размещают в ПЛИС в больших количествах: это арифметические блоки. Эти блоки используются при сложении, вычитании, сравнении чисел, реализации счётчиков. В разных ПЛИС могут быть предустановлены разные блоки: где-то это может быть 1-битный сумматор, а где-то блок вычисления ускоренного переноса (`carry-chain`).
|
||||||
|
|
||||||
All of these blocks can be implemented using logic gates. For example, here is how a full adder can be implemented:
|
Все эти блоки могут быть реализованы через логические вентили, например так можно реализовать сумматор:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 16. Full 1-bit adder implementation._
|
_Рисунок 16. Реализация полного однобитного сумматора._
|
||||||
|
|
||||||
## Logic Blocks
|
## Логические блоки
|
||||||
|
|
||||||
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.
|
В предыдущих параграфах, были рассмотрены отдельные виды цифровых блоков: таблицы подстановок, регистры, арифметические блоки. Для удобства структурирования, эти блоки объединены в ПЛИС в виде **логических блоков**. Обычно, логические блоки современных ПЛИС состоят из **логических ячеек** (или **логических элементов**), но для простоты повествования, мы объединим все эти термины.
|
||||||
|
|
||||||
|
Логический блок может содержать одну или несколько **LUT**, **арифметический блок**, и один или несколько **D-триггеров**, которые соединены между собой некоторым количеством мультиплексоров. На _рисунке 17_ представлена схема того, как может выглядеть логический блок:
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 17. Logic cell schematic [[2]](https://en.wikipedia.org/wiki/Field-programmable_gate_array)._
|
_Рисунок 17. Схема логической ячейки[[2]](https://en.wikipedia.org/wiki/Field-programmable_gate_array)._
|
||||||
|
|
||||||
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.
|
Логический блок представляет собой цепочку операций: `логическая функция, реализованная через LUT -> арифметическая операция -> Запись в D-триггер`. Каждый из мультиплексоров определяет то, будет ли пропущен какой-либо из этих этапов.
|
||||||
By configuring a logic block, the following variations of a circuit fragment can be obtained:
|
Таким образом, конфигурируя логический блок, можно получить следующие вариации кусочка цифровой схемы:
|
||||||
|
|
||||||
1. Combinational circuit (logical function implemented in a LUT)
|
1. Комбинационная схема (логическая функция, реализованная в LUT)
|
||||||
2. Arithmetic operation
|
2. Арифметическая операция
|
||||||
3. Write data to a D flip-flop
|
3. Запись данных в D-триггер
|
||||||
4. Combinational circuit with the result written to a D flip-flop
|
4. Комбинационная схема с записью результата в D-триггер
|
||||||
5. Arithmetic operation with the result written to a D flip-flop
|
5. Арифметическая операция с записью результата в D-триггер
|
||||||
6. Combinational circuit followed by an arithmetic operation
|
6. Комбинационная схема с последующей арифметической операцией
|
||||||
7. Combinational circuit followed by an arithmetic operation and a write to a D flip-flop
|
7. Комбинационная схема с последующей арифметической операцией и записью в 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_ приведён реальный пример использования логического блока в ПЛИС `xc7a100tcsg324-1` при реализации Арифметико-логического устройства (АЛУ), подключенного к периферии отладочной платы `Nexys-7`. На этом рисунке вы можете увидеть использование LUT-ов, арифметического блока (ускоренного расчета переноса), и одного из D-триггеров. D-триггеры, обозначенные серым цветом, не используются.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 18. Example of logic cell usage._
|
_Рисунок 18. Пример использования логической ячейки._
|
||||||
|
|
||||||
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
|
## Сеть межсоединений
|
||||||
|
|
||||||
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, входящий в патент на ПЛИС[[4](https://patents.google.com/patent/US4870302A)].
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_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)]._
|
_Рисунок 19. Содержимое ПЛИС в виде межсоединения логических блоков и блоков ввода-вывода[[5](http://www.righto.com/2020/09/reverse-engineering-first-fpga-chip.html)]._
|
||||||
|
|
||||||
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)].
|
Синим показано 9 логических блоков, желтым — 12 блоков ввода-вывода. Все эти блоки окружены **сетью межсоединений** (interconnect net), представляющей собой решётку из горизонтальных и вертикальных соединительных линий — межсоединений общего назначения (general purpose interconnect) [[2, 2-66](https://archive.org/details/programmablegate00xili/page/n97/mode/2up)].
|
||||||
|
|
||||||
The diagonal marks at line crossings represent **programmable interconnect points** (**PIPs**): transistors whose gates are connected to programmable memory.
|
Косыми чертами в местах пересечения линий обозначены **программируемые точки межсоединений** (**programmable interconnect points**, **PIP**s), представляющие собой транзисторы, затвор которых подключен к программируемой памяти.
|
||||||
|
|
||||||
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. Using elements such as **transistors**, it is possible to build **logic gates**: **AND**, **OR**, **NOT**, and so on.
|
1. Используя такие элементы, как **транзисторы**, можно собирать **логические вентили**: элементы **И**, **ИЛИ**, **НЕ** и т.п.
|
||||||
2. Using **logic gates**, it is possible to create circuits that implement both **logical functions** (**combinational circuits**) and complex logic with memory (**sequential circuits**).
|
2. Используя **логические вентили**, можно создавать схемы, реализующие как **логические функции** (**комбинационные схемы**), так и сложную логику с памятью (**последовательностные схемы**).
|
||||||
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.
|
3. Из логических вентилей строится и такая важная комбинационная схема, как **мультиплексор**: цифровой блок, который в зависимости от значения управляющего сигнала подаёт на выход один из входных сигналов.
|
||||||
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.
|
4. Кроме того, подключив вход бистабильной ячейки (представляющую собой петлю из двух инверторов) к транзистору, можно получить 1 бит **программируемой памяти**.
|
||||||
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.
|
5. Подключив входные сигналы мультиплексора к программируемой памяти, можно получить **Таблицу подстановок** (**Look-Up Table**, **LUT**), которая может реализовывать простейшие логические функции. LUT-ы позволяют заменить логические вентили И/ИЛИ/НЕ, и удобны тем, что их можно динамически изменять. Логические вентили в свою очередь исполняются на заводе и уже не могут быть изменены после создания.
|
||||||
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).
|
6. Из логических вентилей также можно собрать базовую ячейку памяти: **D-триггер**, и такую комбинационную схему как **полный 1-битный сумматор** (или любой другой часто используемый арифметический блок).
|
||||||
7. Combining a LUT, an arithmetic block, and a D flip-flop yields the FPGA structure known as a **logic block**.
|
7. Объединив LUT, арифметический блок и D-триггер получается структура в ПЛИС, которая называется **логический блок**.
|
||||||
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.
|
8. Логический блок (а также другие **примитивы**, такие как **блочная память** или **умножители**) — это множество блоков, которые заранее физически размещаются в кристалле ПЛИС, их количество строго определено конкретной ПЛИС и не может быть изменено.
|
||||||
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**).
|
9. Подключая программируемую память к транзисторам, расположенных в узлах **сети межсоединений**, можно управлять расположением разрывов в сети, а значит можно оставить только маршрут, по которому сигнал пойдет туда, куда нам нужно (**трассировать сигнал**).
|
||||||
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).
|
10. **Конфигурируя примитивы** и **трассируя сигнал** между ними (см. п.4), можно получить **практически любую цифровую схему** (с учетом ограничения ёмкости ПЛИС).
|
||||||
|
|
||||||
## References
|
## Список источников
|
||||||
|
|
||||||
1. Alchitry, Ell C / [How Does an FPGA Work?](https://learn.sparkfun.com/tutorials/how-does-an-fpga-work/all)
|
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)
|
2. Xilinx / [The Programmable Gate Array Data Book](https://archive.org/details/programmablegate00xili)
|
||||||
|
|||||||
@@ -1,31 +1,34 @@
|
|||||||
# 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
|
1. Elaboration
|
||||||
2. Synthesis
|
2. Synthesis
|
||||||
3. Implementation
|
3. Implementation
|
||||||
4. Bitstream generation
|
4. Bitstream generation
|
||||||
|
|
||||||
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.
|
В русскоязычной литературе не сложилось устоявшихся терминов для этапов 1 и 3, но **elaboration** можно назвать как "**предобработку**" или "**развертывание**", а **implementation** как "**реализацию**" или "**построение**".
|
||||||
|
Этапы 2 и 4 переводятся дословно: **синтез** и "**генерация двоичного файла конфигурации** (**битстрима**)".
|
||||||
|
|
||||||
Let us examine each step in detail.
|
Более того, граница между этапами весьма условна и в зависимости от используемой **системы автоматизированного проектирования** (**САПР**), задачи, выполняемые на различных этапах, могут перетекать из одного в другой. Описание этапов будет даваться для маршрута проектирования под ПЛИС, однако, с некоторыми оговорками, эти же этапы используются и при проектировании ASIC.
|
||||||
|
|
||||||
|
Остановимся на каждом шаге подробнее.
|
||||||
|
|
||||||
## Elaboration
|
## Elaboration
|
||||||
|
|
||||||
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.
|
На этапе предобработки, САПР разбирает и анализирует HDL-описание вашего устройства, проверяет его на наличие синтаксических ошибок, производит подстановку значений параметров, развёртывает конструкции, использующиеся для повторяющихся или параметризуемых частей кода, устанавливает разрядности сигналов и строит иерархию модулей устройства.
|
||||||
|
|
||||||
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).
|
Затем, ставит в соответствие отдельным участкам кода соответствующие абстрактные элементы: логические вентили, мультиплексоры, элементы памяти и т.п. Кроме того, производится анализ и оптимизация схемы, например, если какая-то часть логики в конечном итоге не связана ни с одним из выходных сигналов, она будет удалена[[1]](https://support.xilinx.com/s/question/0D52E00006iHshoSAC/what-exactly-is-elaborating-a-design?language=en_US).
|
||||||
|
|
||||||
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.
|
Итогом предобработки является так называемая **топология межсоединений** (в быту называемая словом **нетлист**). **Нетлист** — это представление цифровой схемы в виде **графа**, где каждый элемент схемы является вершиной графа, а **цепи**, соединяющие эти элементы являются его ребрами. Нетлист может храниться как в виде каких-то внутренних файлов САПР-а (так хранится нетлист этапа **предобработки**), так и в виде **HDL**-файла, описывающего экземпляры примитивов и связи между ними. Рассмотрим этап предобработки и термин нетлиста на примере.
|
||||||
|
|
||||||
Suppose we want to implement the circuit shown in _Figure 1_.
|
Допустим, мы хотим реализовать схему, представленную на _рисунке 1_.
|
||||||
|
|
||||||

|

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

|

|
||||||
|
|
||||||
_Figure 2. Result of the elaboration step._
|
_Рисунок 2. Результат этапа предобработки._
|
||||||
|
|
||||||
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).
|
В левом окне мы видим наш нетлист. В нижней части обозначены узлы графа (элементы **ab_i**, **res_i**, **xabc_i**, которые представляют собой **И**, **мультиплексор** и **Исключающее ИЛИ** соответственно. Имена этих элементов схожи с именами проводов, присваиванием которым мы создавали данные элементы)
|
||||||
|
|
||||||
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
|
## Synthesis
|
||||||
|
|
||||||
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)).
|
На шаге синтеза, САПР берет сгенерированную ранее цифровую схему и реализует элементы этой схемы через примитивы конкретной ПЛИС — в основном через логические ячейки, содержащие таблицы подстановки, полный 1-битный сумматор и `D-триггер` (см. [как работает ПЛИС](../Introduction/How%20FPGA%20works.md)).
|
||||||
|
|
||||||
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.
|
Поскольку в примере схема чисто **комбинационная**, результат её работы можно рассчитать и выразить в виде **таблицы истинности**, а значит для её реализации лучше всего подойдут **Таблицы Подстановки** (**LUT**-ы). Более того, в ПЛИС `xc7a100tcsg324-1` есть пятивходовые LUT-ы, а у нашей схемы именно столько входов. Это означает, работу всей этой схемы можно заменить **всего одной таблицей подстановки** внутри ПЛИС.
|
||||||
|
|
||||||
Let us continue with our example and perform the synthesis step. To do this, click the `Run Synthesis` button.
|
Итак, продолжим рассматривать наш пример и выполним этап синтеза. Для этого нажмем на кнопку `Run Synthesis`.
|
||||||
|
|
||||||
After synthesis completes, we will be able to open the new schematic shown in Figure 3.
|
После выполнения синтеза у нас появится возможность открыть новую схему, представленную на рисунке I.4-3.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 3. Result of the synthesis step._
|
_Рисунок 3. Результат этапа синтеза._
|
||||||
|
|
||||||
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`).
|
Мы видим, что между входами/выходами схемы и её внутренней логикой появились новые примитивы — **буферы**. Они нужны, чтобы преобразовать уровень напряжения между входами ПЛИС и внутренней логикой (условно говоря, на вход плис могут приходить сигналы с уровнем `3.3 В`, а внутри ПЛИС примитивы работают с сигналами уровня `1.2 В`).
|
||||||
|
|
||||||
The logic itself, as we expected, has been folded into a single five-input look-up table.
|
Сама же логика, как мы и предполагали, свернулась в одну пятивходовую таблицу подстановки.
|
||||||
|
|
||||||
The line `EQN=32'hAAAA3CCC` means that the look-up table will be initialized with the following 32-bit value: `0xAAAA3CCC`.
|
строка `EQN=32'hAAAA3CCC` означает, что таблица подстановки будет инициализирована следующим 32-битным значением: `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.
|
Поскольку у схемы 5 входов, у нас может быть 2<sup>5</sup>=32 возможных комбинаций входных сигналов и для каждого нужно свое значение результата.
|
||||||
|
|
||||||
Is it possible to verify this 32-bit value without computing all 32 combinations by hand?
|
Можно ли как-то проверить данное 32-битное значение без просчитывания всех 32 комбинаций сигналов "на бумажке"?
|
||||||
<details>
|
<details>
|
||||||
<summary>
|
<summary>
|
||||||
Yes, it is.
|
Да, можно.
|
||||||
</summary>
|
</summary>
|
||||||
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:
|
Сперва надо понять в каком именно порядке будут идти эти комбинации. Мы видим, что сигналы подключены к таблице подстановки в следующем порядке: `d, c, b, a, sel`. Это означает, что сама таблица примет вид:
|
||||||
|
|
||||||
```ascii
|
```ascii
|
||||||
|sel| a | b | c | d | |res|
|
|sel| a | b | c | d | |res|
|
||||||
@@ -96,9 +99,9 @@ First, we need to understand the exact order in which these combinations appear.
|
|||||||
| 1 | 1 | 1 | 1 | 1 | | 1 |
|
| 1 | 1 | 1 | 1 | 1 | | 1 |
|
||||||
```
|
```
|
||||||
|
|
||||||
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.
|
Давайте посмотрим на логику исходной схемы и данную таблицу истинности: когда `sel==1`, на выход идет `d`, это означает, что мы знаем все значения для нижней половины таблицы истинности, в нижней половине таблице истинности самый левый входной сигнал (`sel`) равен только единице, значит результат будет совпадать с сигналом `d`, который непрерывно меняется с `0` на `1` и оканчивается значением `1`. Это означает, что если читать значения результатов снизу-вверх (от старших значений к младшим), то сначала у нас будет 16 цифр, представляющих 8 пар `10`:`101010101010`, что эквивалентно записи `AAAA` в шестнадцатеричной форме.
|
||||||
|
|
||||||
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:
|
Рассчитывать оставшиеся 16 вариантов тоже не обязательно, если посмотреть на схему, то можно заметить, что когда `sel!=1`, ни `sel`, ни `d` больше не участвуют в управлении выходом. Выход будет зависеть от операции XOR, которая дает `1` только когда её входы не равны между собой. Верхний вход XOR (выход И) , будет равен единице только когда входы `a` и `b` равны единице, причем в данный момент, нас интересуют только ситуации, когда `sel!=1`. Принимая во внимание, что в таблице истинности значения входов записываются чередующимися степенями двойки (единицами, парами, четверками, восьмерками) единиц и нулей, мы понимаем, что интересующая нас часть таблицы истинности будет выглядеть следующим образом:
|
||||||
|
|
||||||
```ascii
|
```ascii
|
||||||
...
|
...
|
||||||
@@ -113,31 +116,31 @@ Computing the remaining 16 cases is also unnecessary. Looking at the circuit, we
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
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.
|
Только в этой части таблицы истинности мы получим `1` на выходе **И**, при этом в старшей части, вход `c` также равен `1`. Это значит, что входы **Исключающего ИЛИ** будут равны и на выходе будет `0`. Значит результат этой таблицы истинности будет равен `0011` или `3` в шестнадцатеричной записи.
|
||||||
|
|
||||||
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`.
|
Ниже данной части таблицы истинности располагается та часть, где `sel==1`, выше та часть, где выход **И** будет равен `0`. Это означает, что оставшаяся младшая часть будет повторять значения `c`, которое сменяется парами нулей и единиц: `00-11-00-11..`. Эта оставшаяся последовательность будет записана в шестнадцатеричном виде как `0xCCC`.
|
||||||
|
|
||||||
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.
|
Таким образом, мы и получаем искомое выражение `EQN=32'hAAAA3CCC`. Если с этой частью возникли сложности, попробуйте составить данную таблицу истинности (без вычисления самих результатов, а затем просмотрите логику быстрого вычисления результата).
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## Implementation
|
## Implementation
|
||||||
|
|
||||||
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.
|
После получения нетлиста, где в качестве элементов используются ресурсы конкретной ПЛИС, происходит **размещение** этой схемы на элементы заданной ПЛИС: выбираются конкретные логические ячейки. Затем происходит **трассировка** (маршрутизация) связей между ними. Для этих процедур часто используется термин **place & route** (размещение и трассировка). Например, реализация 32-битного сумматора с ускоренным переносом может потребовать 32 LUT-а и 8 примитивов вычисления быстрого переноса (`CARRY4`). Будет неразумно использовать для этого примитивы, разбросанные по всему кристаллу ПЛИС, ведь тогда придётся выполнять сложную трассировку сигнала, да и временные характеристики устройства также пострадают (сигналу, идущему от предыдущего разряда к следующему, придётся проходить больший путь). Вместо этого, САПР будет пытаться разместить схему таким образом, чтобы использовались близлежащие примитивы ПЛИС, для получения оптимальных характеристик.
|
||||||
|
|
||||||
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**), учитываемых при построении итоговой схемы в ПЛИС. Ограничения сужают область возможных решений по размещению примитивов внутри ПЛИС под определенные характеристики (временны́е и физические). Например, можно сказать, внутри ПЛИС схема должна быть размещена таким образом, чтобы время прохождения по **критическому пути** не превышало `20ns`. Это временно́е ограничение. Также нужно сообщить САПР, к какой ножке ПЛИС необходимо подключить входы и выходы нашей схемы — это физическое ограничение.
|
||||||
|
|
||||||
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>
|
<details>
|
||||||
<summary>
|
<summary>
|
||||||
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).
|
Пример используемых ограничений для лабораторной по АЛУ под отладочную плату `Nexys A7-100T` (для упрощения восприятия, убраны старшие разряды переключателей и светодиодов, т.к. ограничения для каждого из разряда однотипны).
|
||||||
</summary>
|
</summary>
|
||||||
|
|
||||||
Lines beginning with `#` are comments.
|
Строки, начинающиеся с `#` являются комментариями.
|
||||||
|
|
||||||
Lines beginning with `set_property` are physical constraints that bind the inputs and outputs of our circuit to specific FPGA pins.
|
Строки, начинающиеся с `set_property` являются физическими ограничениями, связывающими входы и выходы нашей схемы с конкретными входами и выходами ПЛИС.
|
||||||
|
|
||||||
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).
|
Строка `create_clock...` задает временны́е ограничения, описывая целевую тактовую частоту тактового сигнала и его [скважность](https://ru.wikipedia.org/wiki/%D0%A1%D0%BA%D0%B2%D0%B0%D0%B6%D0%BD%D0%BE%D1%81%D1%82%D1%8C).
|
||||||
|
|
||||||
```xdc
|
```xdc
|
||||||
## This file is a general .xdc for the Nexys A7-100T
|
## This file is a general .xdc for the Nexys A7-100T
|
||||||
@@ -174,51 +177,51 @@ set_property -dict { PACKAGE_PIN C12 IOSTANDARD LVCMOS33 } [get_ports { resetn
|
|||||||
|
|
||||||
</details>
|
</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:
|
После выполнения построения, нетлист и сама цифровая схема остаются неизменными, однако использованные для реализации схемы примитивы получают свой "адрес" внутри ПЛИС:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 4. The "address" of a specific LUT inside the FPGA._
|
_Рисунок 4. "Адрес" конкретного LUT-а в ПЛИС._
|
||||||
|
|
||||||
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.
|
Теперь, мы можем посмотреть на "внутренности" нашей ПЛИС `xc7a100tcsg324-1` и то, как через её примитивы будет реализована наша схема. Для этого необходимо открыть построенную схему: `Implementation -> Open implemented design`. Откроется окно, представленное на _рис. 5_.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 5. The implemented design viewer window._
|
_Рисунок 5. Окно просмотра реализованного устройства._
|
||||||
|
|
||||||
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.
|
Это содержимое ПЛИС. Просто из-за огромного количества содержащихся в ней примитивов, оно показана в таком масштабе, что всё сливается в один цветной ковёр. Большая часть этого окна неактивна (показана в тёмно-синих тонах) и это нормально, ведь мы реализовали крошечную цифровую схему, она и не должна занимать значительное количество ресурсов ПЛИС.
|
||||||
|
|
||||||
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:
|
Нас интересует "[бледно-голубая точка](https://ru.wikipedia.org/wiki/Pale_Blue_Dot)", расположенная в нижнем левом углу прямоугольника `X0Y1` (выделено красным). Если отмасштабировать эту зону, мы найдем используемый нами LUT:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 6. Location of the selected LUT inside the FPGA._
|
_Рисунок 6. Расположение выбранного LUT-а внутри ПЛИС._
|
||||||
|
|
||||||
Furthermore, by examining the properties of this primitive, we can find the truth table used to initialize it.
|
Кроме того, если поиграться со свойствами этого примитива, мы сможем найти нашу таблицу истинности, инициализирующую этот примитив.
|
||||||
|
|
||||||
## Bitstream generation
|
## Bitstream generation
|
||||||
|
|
||||||
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.
|
После того, как САПР определил конкретные примитивы, их режим работы, и пути сигнала между ними, необходимо создать двоичный файл (**bitstream**), который позволит сконфигурировать ПЛИС необходимым нам образом.
|
||||||
Once this file is obtained, all that remains is to program the FPGA, after which it will implement the designed device.
|
Получив этот файл, остается запрограммировать ПЛИС, после чего она воплотит разработанное устройство.
|
||||||
|
|
||||||
## Chapter Summary
|
## Итоги главы
|
||||||
|
|
||||||
The flow from an HDL description of a device to its implementation on an FPGA is as follows:
|
Таким образом, маршрут перехода от HDL-описания устройства до его реализации в ПЛИС выглядит следующим образом:
|
||||||
|
|
||||||
1. First, the **elaboration** step takes place. Its main tasks include:
|
1. Сперва происходит этап **предобработки** (**elaboration**). В основные задачи этого этапа входит:
|
||||||
1. flattening the module hierarchy: converting the hierarchical project structure into a flat one, which simplifies subsequent processing steps;
|
1. развертывание иерархии модулей: преобразование иерархической структуры проекта в плоскую, что облегчает дальнейшие этапы обработки;
|
||||||
2. syntax and semantic checking of the HDL code;
|
2. проверка синтаксиса и семантики HDL-кода;
|
||||||
3. resolving parameters and constants;
|
3. разрешение параметров и констант;
|
||||||
4. generating an intermediate project representation used in subsequent steps.
|
4. генерация промежуточного представления проекта, которое затем используется на следующих этапах.
|
||||||
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.
|
2. Затем выполняется этап **синтеза** (**synthesis**) **нетлиста**, который использует ресурсы конкретной ПЛИС. Все, использовавшиеся на предыдущем этапе структуры (регистры, мультиплексоры и прочие блоки) реализуются через примитивы ПЛИС (LUT-ы, D-триггеры, арифметические блоки и т.п.). Выполняется этап оптимизации логических сетей для минимизации занимаемой площади, уменьшения задержек и энергопотребления.
|
||||||
3. Then the **implementation** step builds the final digital circuit, consisting of several sub-steps:
|
3. После выполняется этап **построения** (**implementation**) конечной цифровой схемы, выполняющий несколько подэтапов:
|
||||||
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).
|
1. **Размещение** (**Placement**): определение конкретных местоположений для всех логических элементов в ПЛИС. Если на предыдущем этапе часть схемы была реализована через LUT, то на этом этапе решается **какой именно** LUT будет использован (имеется в виду не его тип, а какой из множества однотипных элементов будет выбран).
|
||||||
2. **Routing**: creating connections between elements in accordance with the netlist.
|
2. **Трассировка** (**Routing**): создание соединений между элементами в соответствии с нетлистом.
|
||||||
3. **Timing Analysis**: verifying timing characteristics to confirm that all signals propagate through the circuit within acceptable timing margins.
|
3. **Временной анализ** (Timing Analysis): Проверка временны́х характеристик для подтверждения, что все сигналы распространяются по цепи в допустимые временны́е рамки.
|
||||||
The solution space for the **place & route** steps is constrained by applying **physical** and **timing** **constraints**.
|
Область допустимых решений для этапов "**place & route**" сужается путем наложения **физических** и **временны́х** **ограничений** (**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.
|
4. Последним этапом выполняется **генерация двоичного файла конфигурации** (**bitstream generation**), который во время прошивки сконфигурирует ПЛИС на реализацию построенной схемы.
|
||||||
|
|
||||||
## References
|
## Список источников
|
||||||
|
|
||||||
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. [Форум Xilinx: 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.
|
В противоположность комбинационной, существует также и **последовательностная логика**, или "логика с памятью" — цифровая логика, выходы которой зависят не только от её входов, но и от её внутреннего состояния.
|
||||||
|
|
||||||
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 (а)_). Эта комбинационная схема всегда будет давать `0`, если оба её входа равны, в противном случае, она выдаст `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.
|
Предположим теперь, что в качестве одного из входов исключающего ИЛИ стоит некая ячейка памяти, которая запоминает предыдущее значение, выданное этим логическим вентилем (_рис. 1 (б)_). Теперь, выходы схемы зависят не только от того, что мы подадим на вход, но и от того, что находится в данной ячейке памяти, а самое главное — теперь, подавая на вход одно и тоже воздействие, мы можем получить разные результаты.
|
||||||
|
|
||||||
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.
|
Будем исходить из того, что изначально ячейка памяти проинициализирована нулём. Сперва подадим на вход этой схемы `0`. Поскольку оба входа равны `0`, на выход схемы подаётся `0`, и значение в ячейке памяти остаётся прежним. Затем, подадим на вход `1` — теперь на выход схемы идёт значение `1` и оно же сохраняется в ячейке памяти. После, мы снова подаём на вход `0`, однако, в отличие от первого раза, на выход схемы пойдёт `1`, т.к. входы исключающего ИЛИ не равны. Выставив на вход `1` ещё раз, мы получим на выходе `0`.
|
||||||
|
|
||||||
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]
|
> [!Info]
|
||||||
> 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].
|
> В некоторых источниках синхронной логикой могут называть и ту, что работает по уровню (а не фронту) единого источника тактового синхроимпульса [[1, стр. 164](https://reader.lanbook.com/book/241166?lms=d92e0036d4c90623ffd0a8ecc34dee72)].
|
||||||
|
|
||||||
## Bistable Cells
|
## Бистабильные ячейки
|
||||||
|
|
||||||
A **bistable cell** is a static memory element capable of holding one of two stable states corresponding to the digital values "0" or "1".
|
**Бистабильная ячейка** — это элемент статической памяти, способный принимать одно из двух устойчивых состояний, соответствующих цифровым значениям "0" или "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).
|
**Статическая память** — это тип памяти, который сохраняет данные в течении неопределённого времени, пока его питание остаётся включённым, без необходимости регенерации (в отличие от **динамической памяти**, использующей для хранения конденсаторы, требующие для хранения регулярного обновления данных).
|
||||||
|
|
||||||
Consider the simplest static memory cell shown in _fig. 2_, which is capable of storing 1 bit of information.
|
Рассмотрим простейшую ячейку статической памяти, представленную на _рис. 2_, которая способна хранить 1 бит информации.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 2. The simplest static memory cell._
|
_Рисунок 2. Простейшая ячейка статической памяти._
|
||||||
|
|
||||||
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).
|
Для того, чтобы добавить в эту ячейку входы с возможностью записи данных, можно поставить перед инверторами логические элементы ИЛИ (которые совместно с инверторами образуют элементы ИЛИ-НЕ).
|
||||||
|
|
||||||
The result is an **RS latch** — the bistable cell shown in _fig. 3_.
|
В результате получится **RS-триггер** — бистабильная ячейка, представленная на _рис. 3_.
|
||||||
|
|
||||||
## RS latch
|
## RS-триггер
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 3. Circuit and truth table of the RS latch. X indicates that the result in that row is independent of the stored value._
|
_Рисунок 3. Схема и таблица истинности RS-триггера. X означает, что в этой строке результат не зависит от хранимого значения._
|
||||||
|
|
||||||
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:
|
RS-триггер — это бистабильная ячейка, имеющая два управляющих входа: `R` (reset) и `S` (set), и два выхода: `Q` и `Q̅`. `Q̅` является инверсией `Q`. 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.
|
1. Если вход `R=1`, а `S=0`, то выход верхнего элемента ИЛИ-НЕ (а значит и выход `Q`) равен `0` вне зависимости от второго его входа. Этот выход поступает вместе с входом `S` на нижний элемент ИЛИ-НЕ, который выдаёт `1` (на выход `Q̅`), поскольку оба его входа равны `0`. Эта единица подаётся на второй вход верхнего элемента ИЛИ-НЕ и теперь, даже если вход `R` станет равным `0`, `1` на втором его входе сможет воспроизвести тоже самое поведение, запирая внутри триггера стабильное состояние `Q=0`.
|
||||||
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.
|
2. Если вход `R=0`, а `S=1`, схема работает противоположным образом: поскольку на нижний элемент подаётся `1` с входа `S`, выход `Q̅` равен `0` вне зависимости от второго входа нижнего элемента ИЛИ-НЕ. Этот ноль подаётся на второй вход верхнего элемента ИЛИ-НЕ, и поскольку оба его входа равны `0`, на выходе этого элемента (на выход `Q`) подаётся `1`, которая возвращается обратно на вход нижнего элемента ИЛИ-НЕ, запирая внутри триггера стабильное состояние `Q=1`.
|
||||||
3. Therefore, when both inputs are simultaneously `0`, the RS latch retains its previous value.
|
3. Таким образом, если на оба входа одновременно равны `0`, RS-триггер хранит своё предыдущее значение.
|
||||||
|
|
||||||
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:
|
Проблемой данного триггера является то, что он имеет **запрещённую** комбинацию входов. В случае RS-триггера, построенного на элементах ИЛИ-НЕ, таковой комбинацией входов является `R=1` и `S=1`. Даже с точки зрения функционального назначения, данная комбинация не имеет смысла: кому потребуется одновременно и сбрасывать 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`.
|
4. Если оба входа одновременно равны `1`, то оба выхода Q и Q̅ будут равны `0`, что нарушает логику работы триггера, поскольку выход Q̅ должен быть инверсией выхода Q. При этом, если после этого перевести оба входа в `0`, RS-триггер окажется в неустойчивом состоянии (в состоянии гонки), а выходы могут начать неопределённо долго инвертироваться. Пока RS-триггер был в запрещённом состоянии, выходы `Q` и `Q̅`, равные `0`, подавались на входы обоих элементов ИЛИ-НЕ, а если после этого **одновременно** перевести входы `R` и `S` в состояние `0`, то на входах обоих вентилей будут `0`, что побудит их выдать на выходы `1`, которые пойдут обратно на входы этих вентилей, после чего те подадут на выход `0`, и так будет продолжаться до тех пор, пока один из сигналов в петле обратной связи не выиграет гонку, и RS-триггер не окажется в стабильном состоянии `0` либо `1`.
|
||||||
|
|
||||||
To eliminate the forbidden state of the RS latch, the D latch was devised.
|
Для того чтобы избавиться от запрещённого состояния RS-триггера, была придумана D-защёлка (gated D-latch).
|
||||||
|
|
||||||
## D Latch
|
## 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-защёлка — это бистабильная ячейка памяти, имеющая входы `D` (Data) и `E` (enable). Иногда вход enable называют clk (clock) или G (gated), что никак не сказывается на его функциональном назначении. Когда сигнал `E` равен `1`, D-защёлка "захватывает" данные с входа `D`. Когда сигнал `E` равен `0`, D-защёлка сохраняет уже захваченные данные.
|
||||||
|
|
||||||
A D latch can be built on top of an RS latch by adding logic that prevents the forbidden state from occurring (_fig. 4_).
|
D-защёлка может быть построена на базе RS-триггера, к которому добавляется логика, исключающая возможность появления запрещённого состояния (_рис. 4_).
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 4. Circuit and truth table of the D latch._
|
_Рисунок 4. Схема и таблица истинности D-защёлки._
|
||||||
|
|
||||||
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-защёлки заключается в следующем. Когда сигнал `E` равен `0`, логические вентили И подают на выход `0` вне зависимости от второго входа, и RS-триггер переходит в состояние хранения текущего значения. В такой ситуации говорят, что D-защёлка "закрыта", или "перешла в непрозрачное состояние". Когда сигнал `E` равен `1`, логические элементы И, добавленные перед входами RS-триггера передают на выход значение со второго их входа. При этом на второй вход этих элементов подаются противоположные сигналы: `!D` и `D`, что исключает возможность одновременного появления `1` на входах `R` и `S`. В этом случае в RS-триггер попадает значение с входа `D`, а про D-защёлку говорят, что она "открыта" (перешла в "прозрачное" состояние). Пока защёлка "прозрачна", данные со входа `D` идут напрямую на выход `Q`.
|
||||||
|
|
||||||
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-защёлка устраняет главный недостаток RS-триггера, она тоже является не самой надёжной бистабильной ячейкой памяти. Дело в том, что D-защёлка пропускает на выход данные со входа `D` всё то время, пока она "прозрачна". Это значит, что она будет пропускать через себя все возможные переходные процессы сигнала `D`. Это значит, что она будет распространять переходные процессы сигналов со входа D, на которые будут реагировать последующие участки цифровой схемы. Из-за этого, через всю цифровую схему, начиная со входов, будут распространяться переходные процессы. В результате определить моменты времени, в которых на выходе схемы будет корректный результат обработки входного сигнала, станет практически невозможно. Было бы гораздо удобней, если бы могли сохранять данные одномоментно, когда на входе `D` уже находится установившееся значение, отсекая тем самым на каждом элементе памяти переходные процессы всех предыдущих участков цифровой схемы. Таким элементом памяти, является D-триггер (D flip-flop).
|
||||||
|
|
||||||
## D Flip-Flop
|
## D-триггер
|
||||||
|
|
||||||
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.
|
D-триггер — это элемент статической памяти, который сохраняет данные со входа `D` **в момент перехода управляющего сигнала из нуля в единицу** (либо в момент перехода из единицы в ноль). Данный сигнал называется **сигналом синхронизации** (или **синхроимпульсом**) и обозначается как clk (clock).
|
||||||
|
|
||||||
_Figure 5_ shows how a D flip-flop is constructed from two D latches.
|
На _рис. 5_ показан способ построения D-триггера из двух D-защёлок.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 5. Circuit and truth table of the D flip-flop._
|
_Рисунок 5. Схема и таблица истинности D-триггера._
|
||||||
|
|
||||||
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-триггера, схема которого представлена на _рис. 5_ заключается в том, что управляющий сигнал `E` одной защёлки является инверсией управляющего сигнала `E` другой защёлки. Это значит, что пока одна защёлка "прозрачна" и принимает данные со входа — другая "непрозрачна" и данные не принимает. В момент, когда тактовый синхроимпульс меняет своё значение с `0` на `1`, ведущая защёлка становится "непрозрачной" для новых данных с входа `D`, и "запертые" в ней данные попадают в только что открывшуюся ведомую защёлку. Несмотря на то, что ведомая защёлка "прозрачна" всё то время, пока сигнал `clk = 1`, данные в ней остаются стабильными, поскольку выход ведущей защёлки больше не может измениться.
|
||||||
|
|
||||||
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_.
|
Описанные схемы бистабильных ячеек представляют собой скорее математическое описание элементов памяти — так проще объяснить принцип их работы. Если ваша технология позволяет реализовать элементы И, ИЛИ и НЕ — значит вы точно можете реализовать подобные элементы. При этом, используя особенности конкретной технологии, данные схемы можно реализовывать более эффективно. D-защёлку, к примеру, можно реализовать схемой, представленной на _рис. 6_.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 6. Configurable memory cell of the Xilinx XC2064 FPGA [[2, p. 2-63](https://archive.org/details/programmablegate00xili/page/n93/mode/2up)]._
|
_Рисунок 6. Конфигурируемая ячейка памяти ПЛИС Xilinx XC2064 [[2, стр. 2-63](https://archive.org/details/programmablegate00xili/page/n93/mode/2up)]._
|
||||||
|
|
||||||
## Metastability
|
## Метастабильность
|
||||||
|
|
||||||
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_. На _рис. 7 (а)_ показана передаточная функция U<sub>вых</sub> = T(U<sub>вх</sub>) некоторого инвертора. По оси абсцисс откладывается входное напряжение, подаваемое на инвертор, а по оси ординат — его выходное напряжение. Если подать на вход инвертора, описываемого подобной передаточной функцией напряжение, равное 0В (соответствует цифровому значению `0`), на выходе будет напряжение равное 3В (соответствует цифровому значению `1`), и наоборот: если подать на вход значение 3В, мы получим на выходе значение приблизительно равное 0В.
|
||||||
|
|
||||||
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 (б)_. Точки пересечения кривых на этом графике являются точками равновесия, в которых входные и выходные напряжения обоих инверторов являются согласованными.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 7. Transfer functions for: a) a single CMOS inverter; b) a pair of inverters connected in a bistable loop [3, p. 497]._
|
_Рисунок 7. Передаточные функции для: а) одиночного КМОП-инвертора; б) пары инверторов, объединённых в бистабильную петлю [3, стр. 497]._
|
||||||
|
|
||||||
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.
|
Как вы можете заметить, таких точек почему-то не две, а три. Две эти точки обозначены как **стабильные** и соответствуют привычным цифровым значениям 1 (для 3В) и 0 (для 0В). Третья точка равновесия обозначена как **метастабильная** и расположена примерно посередине между этими двумя значениями. И действительно, согласно графику, если подать на вход приблизительно 1.5В, на выходе будет точно такое же напряжение, которое затем будет подано на вход второго инвертора и т.д., благодаря чему петля будет находиться в подобном состоянии неопределённый промежуток времени. Подобное состояние называется **метастабильным состоянием** и присуще любой бистабильной ячейке, реализованной на электронной компонентной базе.
|
||||||
|
|
||||||
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_). Предположим, шарик находится у подножия левого склона холма. Если приложить к нему достаточную силу, направленную вправо — шарик перекатится через холм, и он окажется на противоположном склоне (для удобства аналогии, на склонах холма стоят стенки, чтобы шарик останавливался всегда в одной и той же точке этого склона). Если приложить недостаточно силы — шарик поднимется немного вверх по холму, и скатится обратно, остановившись в той же точке, откуда и начал. Однако, если вы будете достаточно "удачливы" и "точны", вы можете приложить ровно столько силы, чтобы шарик поднялся на вершину холма, но не смог с неё скатиться. Этот шарик может оставаться в таком положении неопределённое количество времени, но любое малейшее возмущение (будь то лёгкое дуновение ветерка, вызванное взмахом крыла пролетевшей рядом бабочки, или далёкое землетрясение, можете придумать свою экстравагантную причину) может заставить шарик скатиться в любую сторону.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 8. A mechanical analogy for metastability [3, p. 498]._
|
_Рисунок 8. Механическая аналогия явлению метастабильности [3, стр. 498]._
|
||||||
|
|
||||||
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.
|
Вернёмся к _рис. 7_ (б). Предположим, что инвертор находится в метастабильном состоянии и в цепи возникла случайная наводка, слегка отклонившая напряжение на входе одного из инверторов. Это отклонение усилится на выходе инвертора и попадёт на вход второго инвертора, усилившись на котором оно вернётся на вход первого инвертора и т.д. пока в конечном итоге не остановится в верхней равновесной точке.
|
||||||
|
|
||||||
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.
|
Если же возмущение произойдёт, пока бистабильная ячейка была в стабильном состоянии — её состояние не изменится. Предположим, что бистабильная ячейка хранит значение `1`, т.е. на вход первого инвертора подаётся значение 0В, и пришло возмущение, отклонившее это напряжение до 1В (а для подобной цифровой схемы это очень экстремальное отклонение, за пределами допустимых режимов работы). Проведём вертикальную линию до точки пересечения с черной кривой — это значение на выходе первого инвертора, и входа второго инвертора. Из этой точки, проведём горизонтальную линию до пересечения с синей кривой — это значение на выходе второго инвертора и входе первого. В общем-то, уже на этом этапе, на вход первого инвертора снова подаётся околонулевое напряжение. Именно поэтому крайние две точки пересечения называются **стабильными** — пока на схему подаётся питание, ячейка будет находиться в этом состоянии бесконечно долго до тех пор, пока не произойдёт существенного воздействия, чтобы она могла изменить это состояние.
|
||||||
|
|
||||||
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."
|
В случае метастабильного состояния — мы не можем предсказать, конкретное значение того, как долго ячейка будет находиться в этом состоянии — это случайная величина, для которой может быть оценено значение вероятности. Например, можно сделать оценку вроде: "вероятность того, что бистабильная ячейка выйдет из метастабильного состояния через 100мс много выше вероятности, что она выйдет из этого состояния через 100 секунд"
|
||||||
|
|
||||||
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.
|
Таким образом, метастабильность — это явление, возникающее в ходе нарушения условий работы цифровых элементов. В обычных случаях это явление является нежелательным (если только вы не планируете использовать свою схему в качестве генератора случайных чисел) и важно знать, как его избежать.
|
||||||
|
|
||||||
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:
|
Любые бистабильные ячейки имеют специальные временны́е параметры (ограничения), несоблюдение которых может привести к появлению метастабильности. В рамках этого курса, вы будете работать в основном с бистабильными ячейками, представленными в виде D-триггеров. Для 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>setup</sub> (**setup time**) — **время предустановки**. Это интервал времени, в течение которого сигнал на входе `D` должен оставаться неизменным перед наступлением фронта тактового сигнала.
|
||||||
- T<sub>hold</sub> (**hold time**) — the interval during which the signal at input `D` must remain stable after the clock edge arrives.
|
- T<sub>hold</sub> (**hold time**) — **время удержания**. Это интервал времени, в течение которого сигнал на входе `D` должен оставаться неизменным после наступления фронта тактового сигнала.
|
||||||
|
|
||||||
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 в непосредственной близости от фронта клока, но какое именно — неизвестно. Однако иногда "звёзды сойдутся", и триггер окажется в метастабильном состоянии. Вероятность этого крайне мала (о таком событии можно сказать, что оно "одно на миллиард"), однако не стоит относиться к нему с пренебрежением. Если схема работает на частоте в 1ГГц, триггер будет обновлять своё состояние миллиард раз в секунду, а сама схема может содержать миллионы триггеров. В таком контексте, фраза "одно на миллиард" означает не "ничего страшного, скорее при моей жизни этого не произойдёт", а "чёрт, кажется, что поэтому у меня ничего не работает".
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 9. Example of D flip-flop timing parameter violations [[4](https://habr.com/ru/articles/254869/)]._
|
_Рисунок 9. Пример нарушения временны́х параметров D-триггера [[4](https://habr.com/ru/articles/254869/)]._
|
||||||
|
|
||||||
_Figure 9_ shows three possible outcomes of a timing violation:
|
На _рис. 9_ показано три различных исхода нарушения временных ограничений:
|
||||||
|
|
||||||
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.
|
1. Выход триггера Q<sub>1</sub> принял новое значение сигнала D, которое было установлено во временном промежутке T<sub>setup</sub>.
|
||||||
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.
|
2. Выход триггера Q<sub>2</sub> принял старое значение сигнала D, которое было установлено на входе до начала T<sub>setup</sub>. На следующем положительном фронте clk на входе D находится уже установившееся значение, которое без проблем записывается в триггер.
|
||||||
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.
|
3. Перемена в уровне во время T<sub>setup</sub> привело к тому, что на триггер было подано напряжение, равное половине уровня логической единицы, и тот оказался в метастабильном состоянии. Спустя некоторое время, триггер оказался в одном из стабильных состояний, но в каком — никто заранее предсказать не может (заштрихованная область, где триггер принял значение либо 0, либо 1). На следующем положительном фронте clk на входе D находится уже установившееся значение, которое без проблем записывается в триггер.
|
||||||
|
|
||||||
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>setup</sub>.
|
||||||
|
|
||||||
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> происходит, когда у схемы есть пути с задержкой распространения сигнала до элементов последовательностной логики, которая меньше минимально допустимой. Данные пути напрямую не влияют на значение максимальной частоты, но требуют добавления элементов задержки на кратчайшие пути. Такие пути, как правило, являются значительной проблемой при проектировании интегральных схем специального назначения (application-specific integrated circuit, **ASIC**).
|
||||||
|
|
||||||
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.
|
Допустим в схеме есть два регистра А и Б, задержка распространения сигнала между которыми меньше допустимой. В этом случае, в момент фронта синхроимпульса с выхода регистра А может начать распространяться изменение в уровне сигнала. Это изменение достигнет входа регистра Б в этом же такте, пока у того не завершилось время удержания T<sub>hold</sub>.
|
||||||
|
|
||||||
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.
|
Для того чтобы определить, способна ли проектируемая схема работать на целевой частоте, выполняется **статический временной анализ** (**static timing analysis**, **STA**). В процессе STA, САПР рассчитывает задержки всех временных путей схемы и определяет критический путь. Итогом статического временного анализа является оценка запаса по времени (или времени простоя, англ.: slack) для каждого временного пути, когда схема работает на заданной частоте. Если slack положительный — это значит, что задержка критического пути схемы меньше предельно допустимой, и возможно увеличение частоты схемы (например, при небольшом снижении напряжения питания) в пределах данной величины. Если slack отрицательный — это значит, что задержка по критическому пути уже превысила допустимую, и для корректной работы схемы необходимо либо изменить критический путь таким образом, чтобы сократилась его задержка распространения сигнала, либо уменьшить тактовую частоту.
|
||||||
|
|
||||||
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".
|
К сожалению, соблюсти временны́е ограничения триггеров не всегда возможно, поскольку в некоторых случаях, вход данных может по своей природе быть асинхронен (т.е. никаким образом не зависеть от входного тактового сигнала). К примеру, данные на вход триггера подаются со входа цифровой схемы, который подключён к кнопке, нажатие на которую никак не привязано к тактовому синхроимпульсу. В других случаях, необходимо передать данные, синхронизированные с одним тактовым сигналом, в область схемы, работающей от другого тактового сигнала. Подобная ситуация называется **пересечением тактовых доменов**, или **clock domain crossing** (**CDC**). В зависимости от конкретного сценария, существуют различные схемы синхронизации, самой простой из которых является установка дополнительного триггера там, где прогнозируется возникновение метастабильного состояния (рис. 10). В высокой долей вероятности в течении 1-2 тактов на выходе синхронизирующего триггера окажется стабильное состояние, которое подавалось на вход Din. Неопределённость в количестве тактов появляется из-за того, что мы не знаем, в какую сторону "свалится" состояние первого регистра в цепи.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 10. Circuit and timing diagram of the simplest synchronizer._
|
_Рисунок 10. Схема и временная диаграмма простейшего синхронизатора._
|
||||||
|
|
||||||
## Chapter Summary
|
## Итоги главы
|
||||||
|
|
||||||
1. Digital logic is divided into **combinational** and **sequential** logic.
|
1. Цифровая логика делится на **комбинационную** и **последовательностную**.
|
||||||
1. **Combinational** logic is memoryless logic whose outputs depend only on its inputs.
|
1. **Комбинационной** называют логику без памяти, выходы которой зависят только от её входов.
|
||||||
2. **Sequential** logic is logic with memory whose outputs depend not only on its inputs but also on its internal state.
|
2. **последовательностной** называют логику с памятью, выходы которой зависят не только от её входов, но и от её внутреннего состояния.
|
||||||
2. Digital circuits are also divided into **synchronous** and **asynchronous**.
|
2. Кроме того, цифровые схемы делят на **синхронные** и **асинхронные**.
|
||||||
1. **Synchronous** circuits are sequential circuits whose state changes synchronously with the clock edge.
|
1. **Синхронными** называют последовательностные схемы, состояние которых меняется синхронно фронту тактового сигнала.
|
||||||
2. **Asynchronous** circuits include both combinational circuits and sequential circuits whose state can change independently of the clock edge.
|
2. **Асинхронными** называют как комбинационные схемы, так и последовательностные схемы, изменение состояния которых может происходить без привязки к фронту тактового сигнала.
|
||||||
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. Существуют синхронные схемы с асинхронными сигналами предустановки/сброса. В большинстве случаев, они рассматриваются как обычные синхронные схемы, но их асинхронная логика предустановки/сброса, должна учитываться при расчёте **критического пути**.
|
||||||
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.
|
3. **Критический путь** — это часть цифровой схемы с наибольшей задержкой распространения сигнала, на пути которой не встречаются элементы синхронной логики.
|
||||||
4. **Static memory** is a type of memory that retains data indefinitely as long as power is supplied, without requiring refresh cycles.
|
4. **Статическая память** — это тип памяти, который сохраняет данные в течение неопределённого времени, пока его питание остаётся включённым, без необходимости регенерации.
|
||||||
5. **Dynamic memory** is a type of memory that uses capacitors for storage, requiring periodic refresh of memory contents to prevent data loss.
|
5. **Динамическая память** — это тип памяти, использующий для хранения конденсаторы, что приводит к необходимости в регулярном обновлении содержимого памяти для того, чтобы не утратить данные.
|
||||||
6. The foundation of static memory is the **bistable cell**.
|
6. Основой статической памяти является **бистабильная ячейка**.
|
||||||
7. A **bistable cell** is an element capable of holding one of two stable states corresponding to the digital values "0" or "1".
|
7. **Бистабильная ячейка** — элемент, способный сохранять одно из двух устойчивых состояний, соответствующих цифровым значениям «0» или «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**.
|
8. Простейшей бистабильной ячейкой является петля из двух инверторов. Недостатком данной реализации является отсутствие возможности подать данные в эту ячейку извне. Этот недостаток решается преобразованием цепи в **RS-триггер**.
|
||||||
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**.
|
9. **RS-триггер** — это бистабильная ячейка, имеющая два входа: сброс (reset, R) и установка (set, S). Данная ячейка может быть построена на паре логических вентилей ИЛИ-НЕ или И-НЕ. Недостатком данной бистабильной ячейки является наличие запрещённой комбинации входных сигналов, которая может привести к непредсказуемому поведению. Данный недостаток может быть разрешён путём добавления в схему дополнительной логики, из которой получается **D-защёлка**.
|
||||||
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.
|
10. **D-защёлка** — это бистабильная ячейка, имеющая два входа: сигнал разрешения записи (`E` / `clk`), и сигнал входных данных (D). Пока сигнал `E` активен, данные со входа `D` сохраняются в D-защёлку и идут на её выход (в таких случаях говорят, что защёлка "прозрачна"). Несмотря на то, что D-защёлка разрешает проблему запрещённого состояния RS-триггера, всё то время, пока она "прозрачна", она пропускает через себя все переходные процессы входных сигналов.
|
||||||
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:
|
11. **D-триггер** — это бистабильная ячейка, которая подобно D-защёлке имеет входы `clk` и `D`, но который сохраняет данные только в момент одного из фронтов тактового синхроимпульса (положительного или отрицательного фронта). Как и любые бистабильные ячейки, D-триггер подвержен явлению **метастабильности**. Метастабильность в D-триггере может возникнуть, если данные на входе `D` меняются во временном окне, расположенном в окрестностях фронта тактового синхроимпульса, определяемом следующими двумя параметрами:
|
||||||
1. T<sub>setup</sub> (**setup time**) — the interval during which the input signal must remain stable before the clock edge arrives.
|
1. T<sub>setup</sub> (**setup time**) — **время предустановки**. Это интервал, в течение которого сигнал на входе должен оставаться неизменным перед наступлением фронта тактового сигнала.
|
||||||
2. T<sub>hold</sub> (**hold time**) — the interval during which the input signal must remain stable after the clock edge arrives.
|
2. T<sub>hold</sub> (**hold time**) — **время удержания**. Это интервал, в течение которого сигнал на входе должен оставаться стабильным после наступления фронта тактового сигнала.
|
||||||
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`.
|
12. **Метастабильное состояние** — это состояние бистабильной ячейки, при котором та не находится ни в одном из стабильных цифровых состояниях `0`/`1`, находясь при этом примерно посередине между ними. Через неопределённый промежуток времени (длину которого можно оценить с точки зрения вероятностей) бистабильная ячейка может выйти из этого состояния, приняв любое из значений `0`/`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.
|
13. В большинстве случаев метастабильность является нежелательным явлением в цифровой схеме. Причиной такого явления может стать работа схемы на частоте, не подходящей для имеющегося у данной схемы критического пути. Для того, чтобы узнать, сможет ли схема работать на заданной частоте, проводится **статический временной анализ** (**static timing analysis**, **STA**).
|
||||||
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**).
|
14. Метастабильность может возникнуть и в случае, если сигнал данных по своей природе является асинхронным тактовому сигналу бистабильной ячейки: он может передаваться по событиям из внешнего мира, или с выхода бистабильных ячеек, работающих от других тактовых синхроимпульсов (подобная ситуация называется **пересечением тактовых доменов**, **clock domain crossing**, **CDC**).
|
||||||
|
|
||||||
## References
|
## Список источников
|
||||||
|
|
||||||
1. D.M. Harris, S.L. Harris / Digital Design and Computer Architecture. RISC-V Edition, 2021;
|
1. [Д.М. Харрис, С.Л. Харрис / Цифровая схемотехника и архитектура компьютера: RISC-V / пер. с англ. В. С. Яценков, А. Ю. Романов; под. ред. А. Ю. Романова / М.: ДМК Пресс, 2021](https://e.lanbook.com/book/241166);
|
||||||
2. Xilinx / [The Programmable Gate Array Data Book](https://archive.org/details/programmablegate00xili);
|
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;
|
3. J. Wakerly, Digital Design: Principles and Practices (5th Edition). Pearson, 2017;
|
||||||
4. [Flip-flop metastability and clock domain synchronization](https://habr.com/ru/articles/254869/).
|
4. [Метастабильность триггера и межтактовая синхронизация](https://habr.com/ru/articles/254869/).
|
||||||
|
|||||||
@@ -1,83 +1,83 @@
|
|||||||
# What is a Hardware Description Language (HDL)
|
# Что такое язык описания аппаратуры (HDL)
|
||||||
|
|
||||||
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.
|
На заре появления цифровой электроники, [цифровые схемы](How%20FPGA%20works.md#Цифровые-схемы) в виде диаграммы на бумаге были маленькими, а их реализация в виде физической аппаратуры — большой. В процессе развития электроники (и её преобразования в микроэлектронику) цифровые схемы на бумаге становились всё больше, а относительный размер их реализации в виде физических микросхем — всё меньше. На _рис. 1_, вы можете увидеть цифровую схему устройства Intel 4004, выпущенного в 1971 году.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 1. Digital circuit of the Intel 4004 processor at the transistor level [[1]](https://www.4004.com/mcs4-masks-schematics-sim.html)._
|
_Рисунок 1. Цифровая схема процессора Intel 4004 на уровне транзисторов[[1]](https://www.4004.com/mcs4-masks-schematics-sim.html)._
|
||||||
|
|
||||||
This chip contains 2,300 transistors [[2]](https://en.wikipedia.org/wiki/Intel_4004).
|
Данная микросхема состоит из 2300 транзисторов[[2]](https://en.wikipedia.org/wiki/Intel_4004).
|
||||||
|
|
||||||
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.
|
За прошедшие полсотни лет сложность цифровых схем выросла колоссально. Современные процессоры для настольных компьютеров состоят из десятков миллиардов транзисторов. Диаграмма выше при печати в оригинальном размере займет прямоугольник размером 115х140 см с площадью около 1.6 м<sup>2</sup>. Предполагая, что площадь печати имеет прямо пропорциональную зависимость от количества транзисторов, получим, что распечатка схемы современного процессора из 23 млрд транзисторов заняла бы площадь в 16млн м<sup>2</sup>, что эквивалентно квадрату со стороной в 4км.
|
||||||
|
|
||||||
<img src="../.pic/Introduction/What%20is%20HDL/ancient_city.png" alt="Ancient city" width="400"/>
|
<img src="../.pic/Introduction/What%20is%20HDL/ancient_city.png" alt="Старый город" width="400"/>
|
||||||
|
|
||||||
_Figure 2. The scale that digital circuit diagrams of modern processors would reach if printed on paper._
|
_Рисунок 2. Масштаб размеров, которых могли бы достигать цифровые схемы современных процессоров, если бы они печатались на бумаге._
|
||||||
|
|
||||||
As you might guess, at some point between 1971 and 2024, engineers stopped designing digital circuits by drawing them on paper.
|
Как вы можете догадаться, в какой-то момент между 1971-м и 2024-м годами инженеры перестали разрабатывать цифровые схемы, рисуя их на бумаге.
|
||||||
|
|
||||||
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.
|
Разумеется, разрабатывая устройство, не обязательно вырисовывать на схеме каждый транзистор — можно управлять сложностью, переходя с одного уровня абстракции на другой. Например, начинать разработку схемы с уровня функциональных блоков, а затем рисовать схему для каждого отдельного блока.
|
||||||
|
|
||||||
For instance, the Intel 4004 circuit can be represented as follows:
|
К примеру, схему Intel 4004 можно представить в следующем виде:
|
||||||
|
|
||||||
<img src="../.pic/Introduction/What%20is%20HDL/4004_arch.png" alt="../.pic/Introduction/What%20is%20HDL/4004_arch.png" width="500"/>
|
<img src="../.pic/Introduction/What%20is%20HDL/4004_arch.png" alt="../.pic/Introduction/What%20is%20HDL/4004_arch.png" width="500"/>
|
||||||
|
|
||||||
_Figure 3. Digital circuit of the Intel 4004 processor at the functional block level [[2]](https://en.wikipedia.org/wiki/Intel_4004)._
|
_Рисунок 3. Цифровая схема процессора Intel 4004 на уровне функциональных блоков[[2]](https://en.wikipedia.org/wiki/Intel_4004)._
|
||||||
|
|
||||||
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:
|
Однако несмотря на это, даже отдельные блоки порой бывают довольно сложны. Возьмем блок аппаратного шифрования по алгоритму AES[[3]](https://csrc.nist.gov/files/pubs/fips/197/final/docs/fips-197.pdf) на рисунке 4:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 4. Digital circuit of a hardware AES encryption block [[4]](https://iis-people.ee.ethz.ch/~kgf/acacia/acacia_thesis.pdf)._
|
_Рисунок 4. Цифровая схема блока аппаратного шифрования по алгоритму AES[[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:
|
Как можно описать цифровую схему текстом? Рассмотрим цифровую схему полусумматора:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 5. Digital circuit of a half-adder at the logic gate level._
|
_Рисунок 5. Цифровая схема полусумматора на уровне логических вентилей._
|
||||||
|
|
||||||
This **module** (_half-adder_) has two **inputs**: _a_ and _b_, and two **outputs**: _sum_ and _carry_.
|
Это **устройство** (_полусумматор_) имеет два **входа**: _a_ и _b_, а также два **выхода**: _sum_ и _carry_.
|
||||||
The _sum_ output is the **result** of the logical **XOR** operation on operands _a_ and _b_.
|
Выход _sum_ является **результатом** логической операции **Исключающее ИЛИ** от операндов _a_ и _b_.
|
||||||
The _carry_ output is the **result** of the logical **AND** operation on operands _a_ and _b_.
|
Выход _carry_ является **результатом** логической операции **И** от операндов _a_ и _b_.
|
||||||
|
|
||||||
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):
|
Текст выше и является тем описанием, по которому можно воссоздать эту цифровую схему. Если стандартизировать описание схемы, то в нем можно будет оставить только слова, выделенные жирным и курсивом. Пример того, как можно было бы описать эту схему по стандарту IEEE 1364-2005 (язык описания аппаратуры (Hardware Description Language — HDL) Verilog):
|
||||||
|
|
||||||
```Verilog
|
```Verilog
|
||||||
module half_sum( // module half-adder with
|
module half_sum( // устройство полусумматор cо
|
||||||
input a, // input a,
|
input a, // входом a,
|
||||||
input b, // input b,
|
input b, // входом b,
|
||||||
output sum, // output sum and
|
output sum, // выходом sum и
|
||||||
output carry // output carry.
|
output carry // выходом carry.
|
||||||
);
|
);
|
||||||
|
|
||||||
assign sum = a ^ b; // Where output sum is the result of XOR of a and b,
|
assign sum = a ^ b; // Где выход sum является результатом Исключающего ИЛИ от a и b,
|
||||||
assign carry = a & b; // and output carry is the result of logical AND of a and b.
|
assign carry = a & b; // а выход carry является результатом логического И от a и b.
|
||||||
|
|
||||||
endmodule
|
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
|
``` Verilog
|
||||||
module half_sum(input a, b, output sum, carry);
|
module half_sum(input a, b, output sum, carry);
|
||||||
assign sum = a ^ b;
|
assign sum = a ^ b;
|
||||||
assign carry = a & b;
|
assign carry = a & b;
|
||||||
endmodule
|
endmodule
|
||||||
```
|
```
|
||||||
|
|
||||||
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**.
|
Важно отметить, что код на языке Verilog описывает устройство целиком, одномоментно. Это **описание схемы** выше, а **не построчное выполнение программы**.
|
||||||
|
|
||||||
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.
|
С практикой описание схемы в текстовом виде становится намного проще и не требует графического представления. Для описания достаточно только спецификации: формальной записи того, как должно работать устройство. По ней разрабатывается алгоритм, который затем претворяется в описание на HDL.
|
||||||
|
|
||||||
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.
|
Занятный факт: ранее было высказано предположение о том, что инженеры перестали разрабатывать устройства, рисуя цифровые схемы в промежуток времени между 1971-м и 2024-м годами. Так вот, первая конференция, посвящённая языкам описания аппаратуры состоялась в 1973-м году[[5, стр. 8]](https://dl.acm.org/doi/pdf/10.1145/3386337). Таким образом, Intel 4004 можно считать одним из последних цифровых устройств, разработанных без использования языков описания аппаратуры.
|
||||||
|
|
||||||
## References
|
## Список источников
|
||||||
|
|
||||||
1. [Intel 4004 — 50th Anniversary Project](https://www.4004.com/mcs4-masks-schematics-sim.html);
|
1. [Intel 4004 — 50th Anniversary Project](https://www.4004.com/mcs4-masks-schematics-sim.html);
|
||||||
2. [Wikipedia page on Intel 4004](https://en.wikipedia.org/wiki/Intel_4004);
|
2. [Страница википедии по 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);
|
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);
|
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).
|
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,119 +1,121 @@
|
|||||||
# Lab 1 "Adder"
|
# Лабораторная работа №1 "Сумматор"
|
||||||
|
|
||||||
## Goal
|
## Цель
|
||||||
|
|
||||||
Get familiar with the Vivado EDA tool and learn how to implement basic circuit modules using SystemVerilog language constructs.
|
Познакомиться с САПР Vivado и научиться реализовывать в нём простейшие схемотехнические модули с помощью конструкций языка SystemVerilog.
|
||||||
|
|
||||||
## Preparation Materials
|
## Материал для подготовки к лабораторной работе
|
||||||
|
|
||||||
[Describing modules in SystemVerilog](../../Basic%20Verilog%20structures/Modules.md).
|
[Описание модулей на языке SystemVerilog](../../Basic%20Verilog%20structures/Modules.md).
|
||||||
|
|
||||||
## Workflow
|
## Ход работы
|
||||||
|
|
||||||
1. Study the 1-bit adder;
|
1. Изучение 1-битного сумматора;
|
||||||
2. Reproduce the example of implementing and verifying a half adder.
|
2. Воспроизведение примера по реализации и проверке полусумматора.
|
||||||
3. Implement and verify a full 1-bit adder
|
3. Реализация и проверка полного 1-битного сумматора
|
||||||
4. Study the 4-bit adder;
|
4. Изучение 4-битного сумматора;
|
||||||
5. Implement and verify a full 4-bit adder;
|
5. Реализация и проверка полного 4-битного сумматора;
|
||||||
6. Implement and verify a full 32-bit adder.
|
6. Реализация и проверка полного 32-битного сумматора.
|
||||||
|
|
||||||
## 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.
|
Итогом лабораторной работы будет создание устройства, способного складывать два числа. Но перед тем, как учиться создавать подобное устройство, необходимо немного освоиться в самом процессе складывания чисел.
|
||||||
|
|
||||||
Let's start with an example and add a pair of numbers in column format, say 42 and 79:
|
Давайте начнём с примера и сложим в столбик произвольную пару чисел, например 42 и 79:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
```text
|
```text
|
||||||
2 + 9 = 11 ➨ write 1, carry 1
|
2 + 9 = 11 ➨ 1 пишем, 1 "в уме"
|
||||||
4 + 7 + carry 1 = 12 ➨ write 2, carry 1
|
4 + 7 + "1 в уме" = 12 ➨ 2 пишем, 1 "в уме"
|
||||||
0 + 0 + carry 1 = 1
|
0 + 0 + "1 в уме" = 1
|
||||||
```
|
```
|
||||||
|
|
||||||
Total: 121.
|
Итого, 121.
|
||||||
|
|
||||||
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.
|
Назовём то, что мы звали "1 в уме", переносом разряда.
|
||||||
|
|
||||||
|
Теперь попробуем сделать то же самое, только в двоичной системе исчисления. К примеру, над числами 3 и 5. Три в двоичной системе записывается как 011. Пять записывается как 101.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
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.
|
Поскольку в двоичной системе всего две цифры: 0 и 1, один разряд не может превысить 1. Складывая числа 1 и 1, вы получаете 2, что не умещается в один разряд, поэтому мы пишем 0 и держим 1 "в уме". Это снова перенос разряда. Поскольку в двоичной арифметике разряд называют битом, перенос разряда можно назвать переносом бита, а сам разряд, который перенесли — битом переноса.
|
||||||
|
|
||||||
### Full 1-bit Adder
|
### Полный 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.
|
Полный 1-битный сумматор — это цифровое устройство, которое выполняет сложение двух 1-битных чисел и учитывает входной бит переноса. Это устройство имеет три входа: два слагаемых и входной бит переноса, а также два выхода: 1-битный результат суммы и выходной бит переноса.
|
||||||
|
|
||||||
What is the carry-in? Let's recall the second step of adding 42 and 79:
|
Что такое входной бит переноса? Давайте вспомним второй этап сложения чисел 42 и 79:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
4 + 7 + carry 1 = 12 ➨ write 2, carry 1
|
4 + 7 + "1 в уме" = 12 ➨ 2 пишем, 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.
|
Входной бит переноса — это бит, перенесённый с предыдущего этапа сложения двоичных чисел. Имея этот сигнал, мы можем складывать многоразрядные двоичные числа путём последовательного соединения нескольких 1-битных сумматоров: выходной бит переноса сумматора младшего разряда передастся на входной бит переноса сумматора старшего разряда.
|
||||||
|
|
||||||
### 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` 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".
|
`S` — это младший разряд 2-битного результата суммы, записываемый в столбце сложения под слагаемыми `a` и `b`. `C` (_carry_, перенос) — это старший разряд суммы, записываемый левее, если произошёл перенос разряда. Как мы видим, перенос разряда происходит только в случае, когда оба числа одновременно равны единице. При этом значение `S` обращается в `0`, и результат записывается как `10`, что в двоичной системе означает `2`. Кроме того, значение `S` равно `0` и в случае, когда оба операнда одновременно равны нулю. Вы можете заметить, что `S` равно нулю в тех случаях, когда `а` и `b` равны, и не равно нулю в противоположном случае. Подобным свойством обладает логическая операция **Исключающее ИЛИ** (**eXclusive OR**, **XOR**), именно поэтому одно из других названий этой операции — сумма по модулю 2.
|
||||||
|
|
||||||

|

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

|

|
||||||
|
|
||||||
_Truth table for the AND operation._
|
_Таблица истинности операции И._
|
||||||
|
|
||||||
_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. Цифровая схема устройства, складывающего два операнда с сохранением переноса (полусумматора)._
|
||||||
|
|
||||||
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).
|
Однако, в описании полного 1-битного сумматора сказано, что у него есть три входа, а в наших таблицах истинности и на схеме выше их только два (схема, представленная на _рис. 1_, реализует так называемый "полусумматор"). На самом деле, на каждом этапе сложения в столбик мы всегда складывали три числа: цифру верхнего числа, цифру нижнего числа, и единицу в случае переноса разряда из предыдущего столбца (если с предыдущего разряда не было переноса, прибавление нуля неявно опускалось).
|
||||||
|
|
||||||
Therefore, the truth table becomes slightly more complex:
|
Таким образом, таблица истинности немного усложняется:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Truth table for a full 1-bit adder._
|
_Таблица истинности сигналов полного 1-битного сумматора._
|
||||||
|
|
||||||
Since we now have both a carry-in and a carry-out, suffixes "in" and "out" are added to distinguish them.
|
Поскольку теперь у нас есть и входной и выходной биты переноса, для их различия добавлены суффиксы "in" и "out".
|
||||||
|
|
||||||
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.
|
Как в таком случае описать S? Например, как сумму по модулю 2 этих трёх слагаемых: `а ⊕ b ⊕ Cіn`. Давайте сравним такую операцию с таблицей истинности. Сумма по модуля 2 — это ассоциативная операция [`(a⊕b)⊕c = a⊕(b⊕с)`], т.е. порядок сложения не влияет на результат. Предположим, что Cin равен нулю. Сумма по модулю 2 с нулём даёт второй операнд (`a⊕0=a`), значит `(a⊕b)⊕0 = a⊕b`. Это соответствует верхней половине таблицы истинности для сигнала S, когда Cin равен нулю.
|
||||||
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.
|
Предположим, что Cin равен единице. Сумма по модулю 2 с единицей даёт нам отрицание второго операнда (`a⊕1=!a`), значит `(a⊕b) ⊕1=!(a⊕b)`. Это соответствует нижней половине таблицы истинности, когда Cin равен единице.
|
||||||
|
|
||||||
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:
|
Для выходного бита переноса всё гораздо проще. Он равен единице, когда хотя бы два из трех операндов равны единице, это значит, что необходимо попарно сравнить все операнды, и если найдется хоть одна такая пара, он равен единице. Это утверждение можно записать следующим образом:
|
||||||
|
|
||||||
`Cout = (a&b) | (a&Cin) | (b&Cin)`, where `&` is logical AND, `|` is logical OR.
|
`Cоut = (a&b) | (а&Cіn) | (b&Cіn)`, где `&` — логическое И, `|` — логическое ИЛИ.
|
||||||
|
|
||||||
The digital circuit with this described behavior looks as follows:
|
Цифровая схема устройства с описанным поведением выглядит следующим образом:
|
||||||
|
|
||||||

|

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

|

|
||||||
|
|
||||||
_Figure 3. Digital circuit of the half_adder module generated by the Vivado EDA tool._
|
_Рисунок 3. Цифровая схема модуля half_adder, сгенерированная САПР Vivado._
|
||||||
|
|
||||||
The circuit resembles _Fig. 1_, but how do we verify that this circuit is error-free and behaves as expected?
|
Схема похожа на _рис. 1_, но как проверить, что эта схема не содержит ошибок и делает именно то, что от неё ожидается?
|
||||||
|
|
||||||
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.
|
Подаваемые на схему входные воздействия формируются верификационным окружением. Верификационное окружение (в дальнейшем будет использован термин "**тестбенч**") — это особый несинтезируемый модуль, который не имеет входных или выходных сигналов. Эти сигналы ему не нужны, потому что он сам является генератором всех своих внутренних сигналов, и данный модуль не передаёт ничего вовне — только проверяет тестируемый модуль внутри себя.
|
||||||
|
|
||||||
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.
|
Внутри тестбенча можно использовать конструкции из несинтезируемого подмножества языка SystemVerilog, в частности программный блок `initial`, в котором команды выполняются последовательно, что делает этот блок чем-то отдалённо похожим на проверяющую программу. Поскольку изменение внутренних цепей происходит с некоторой задержкой относительно изменений входных сигналов, при моделировании есть возможность делать паузы между командами. Это делается с помощью специального символа #, за которым указывается количество времени симуляции, которое нужно пропустить перед следующей командой.
|
||||||
|
|
||||||
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
|
```Verilog
|
||||||
module testbench(); // <- Has neither inputs nor outputs!
|
module testbench(); // <- Не имеет ни входов, ни выходов!
|
||||||
logic a, b, carry, sum;
|
logic a, b, carry, sum;
|
||||||
|
|
||||||
half_adder DUT( // <- Connect the design under test
|
half_adder DUT( // <- Подключаем проверяемый модуль
|
||||||
.a_i (a ),
|
.a_i (a ),
|
||||||
.b_i (b ),
|
.b_i (b ),
|
||||||
.carry_o(carry),
|
.carry_o(carry),
|
||||||
@@ -155,50 +157,50 @@ module testbench(); // <- Has neither inputs nor outputs!
|
|||||||
);
|
);
|
||||||
|
|
||||||
initial begin
|
initial begin
|
||||||
a = 1'b0; b = 1'b0; // <- Apply test stimuli to the module
|
a = 1'b0; b = 1'b0; // <- Подаём на входы модуля тестовые
|
||||||
#10ns; // inputs
|
#10ns; // воздействия
|
||||||
a = 1'b0; b = 1'b1;
|
a = 1'b0; b = 1'b1;
|
||||||
#10ns; // <- Pause for ten nanoseconds before
|
#10ns; // <- Делаем паузу в десять наносекунд
|
||||||
a = 1'b1; b = 1'b0; // the next input signal change
|
a = 1'b1; b = 1'b0; // перед очередным изменением
|
||||||
#10ns;
|
#10ns; // входных сигналов
|
||||||
a = 1'b1; b = 1'b1;
|
a = 1'b1; b = 1'b1;
|
||||||
end
|
end
|
||||||
endmodule
|
endmodule
|
||||||
```
|
```
|
||||||
|
|
||||||
_Listing 2. SystemVerilog code for the half_adder testbench._
|
_Листинг 2. SystemVerilog-код тестбенча для модуля half_adder._
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 4. Timing diagram simulating the operation of the circuit from Fig. 3._
|
_Рисунок 4. Временная диаграмма, моделирующая работу схемы с рис. 3._
|
||||||
|
|
||||||
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).
|
В данной лабораторной работе вам предстоит реализовать схему полного 1-битного сумматора (_рис. 2_). Модуль полусумматора, код которого представлен в _листинге 1_ не используется в лабораторной работе (он был дан только в качестве примера).
|
||||||
|
|
||||||
### Full 4-bit Adder
|
### Полный 4-битный сумматор
|
||||||
|
|
||||||
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.
|
До этого мы реализовали сложение в столбик только для одного разряда, теперь мы хотим реализовать всю операцию сложения в столбик. Как это сделать? Сделать ровно то, что делается при сложении в столбик: сначала сложить младший разряд, получить бит переноса для следующего разряда, сложить следующий и т.д.
|
||||||
|
|
||||||
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).
|
Давайте посмотрим, как это будет выглядеть на схеме (для простоты, внутренняя логика 1-битного сумматора скрыта, но вы должны помнить, что каждый прямоугольник — это та же самая схема с рис. 2).
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 5. 4-bit adder circuit._
|
_Рисунок 5. Схема 4-битного сумматора._
|
||||||
|
|
||||||
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.
|
Фиолетовой линией на схеме показаны провода, соединяющие выходной бит переноса сумматора предыдущего разряда с входным битом переноса сумматора следующего разряда.
|
||||||
|
|
||||||
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.
|
Как же реализовать модуль, состоящий из цепочки других модулей? Половину этой задачи мы уже сделали, когда писали тестбенч к 1-битному полусумматору в _Листинге 2_ — мы создавали модуль внутри другого модуля и подключали к нему провода. Теперь надо сделать то же самое, только с чуть большим числом модулей.
|
||||||
|
|
||||||
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.
|
Описание 4-битного сумматора, сводится к описанию межсоединения четырёх экземпляров 1-битного сумматора. Подробнее о том, как описывать создание экземпляров модулей рассказано в главе [Описание модулей на языке SystemVerilog](../../Basic%20Verilog%20structures/Modules.md#Иерархия-модулей), который вы изучали перед лабораторной работой.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 6. 4-bit adder circuit generated by the Vivado EDA tool._
|
_Рисунок 6. Схема 4-битного сумматора, сгенерированная САПР Vivado._
|
||||||
|
|
||||||
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_).
|
Несмотря на запутанность схемы, если присмотреться, вы увидите, как от шин A, B и S отходят линии к каждому из сумматоров, а бит переноса передаётся от предыдущего сумматора к следующему. Для передачи битов переноса от одного сумматора к другому, потребуется создать вспомогательные провода, которые можно сгруппировать в один [вектор](../../Basic%20Verilog%20structures/Modules.md#Векторы) (см. сигналы c[0]-c[2] на _рис. 5_).
|
||||||
|
|
||||||
## Assignment
|
## Задание
|
||||||
|
|
||||||
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:
|
Опишите полный 1-битный сумматор, схема которого представлена на _[Рис. 2](../../.pic/Labs/lab_01_adder/fig_02.drawio.svg)_. Прототип модуля следующий:
|
||||||
|
|
||||||
```Verilog
|
```Verilog
|
||||||
module fulladder(
|
module fulladder(
|
||||||
@@ -210,7 +212,7 @@ module fulladder(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
Next, implement a full 32-bit adder with the following prototype:
|
Далее, вам необходимо реализовать полный 32-битный сумматор со следующим прототипом:
|
||||||
|
|
||||||
```verilog
|
```verilog
|
||||||
module fulladder32(
|
module fulladder32(
|
||||||
@@ -222,9 +224,9 @@ module fulladder32(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
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.
|
Соединять вручную 32 однотипных модуля чревато усталостью и ошибками, поэтому можно сначала создать 4-битный сумматор, а затем из набора 4-битных сумматоров сделать 32-битный.
|
||||||
|
|
||||||
If you choose to build a 4-bit adder, the module must follow this prototype:
|
Если вы решите делать 4-битный сумматор, то модуль должен быть описан в соответствии со следующим прототипом:
|
||||||
|
|
||||||
```Verilog
|
```Verilog
|
||||||
module fulladder4(
|
module fulladder4(
|
||||||
@@ -236,15 +238,15 @@ module fulladder4(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
Alternatively, you can create an array of 1-bit adders.
|
Либо же можно создать массив 1-битных сумматоров.
|
||||||
|
|
||||||
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:
|
Создание массива модулей схоже с созданием одного модуля за исключением того, что после имени экземпляра модуля указывается диапазон, определяющий количество модулей в массиве. При этом подключение сигналов к массиву модулей осуществляется следующим образом:
|
||||||
|
|
||||||
- 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);
|
- если разрядность подключаемого сигнала превосходит разрядность порта модуля из массива в `N` раз (где `N` — количество модулей в массиве), к модулю подключается соответствующий диапазон бит подключаемого сигнала (диапазон младших бит будет подключён к модулю с меньшим индексом в массиве).
|
||||||
- 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.
|
- если разрядность подключаемого сигнала не подходит ни под один из описанных выше пунктов, происходит ошибка синтеза схемы, поскольку в этом случае САПР не способен понять каким образом подключать данный сигнал к каждому модулю из массива.
|
||||||
|
|
||||||
_Listing 3_ shows an example of how to create a module array.
|
В _листинге 3_ представлен пример того, как можно создать массив модулей.
|
||||||
|
|
||||||
```Verilog
|
```Verilog
|
||||||
module example1(
|
module example1(
|
||||||
@@ -265,52 +267,54 @@ module example2(
|
|||||||
output logic [ 8:0] C
|
output logic [ 8:0] C
|
||||||
);
|
);
|
||||||
|
|
||||||
example1 instance_array[7:0]( // Creates an array of 8 example1 modules
|
example1 instance_array[7:0]( // Создается массив из 8 модулей example1
|
||||||
.a(A), // Since the width of signal A is 8 times greater
|
.a(A), // Поскольку разрядность сигнала A в 8 раз больше
|
||||||
// than the width of port a, each module in the array
|
// разрядности входа a, к каждому модулю в массиве
|
||||||
// is connected to its own bit range of signal A
|
// будет подключен свой диапазон бит сигнала A
|
||||||
// (instance_array[0] is connected to A[3:0],
|
// (к instance_array[0] будет подключен диапазон
|
||||||
// instance_array[7] is connected to A[31:28]).
|
// A[3:0], к instance_array[7] будет подключен
|
||||||
|
// диапазон A[31:28]).
|
||||||
|
|
||||||
.b(B), // Since the width of signal B matches the width
|
.b(B), // Поскольку разрядность сигнала B совпадает с
|
||||||
// of port b, signal B is connected as-is to
|
// разрядностью входа b, сигнал B будет подключен
|
||||||
// all modules in the array.
|
// как есть ко всем модулям в массиве.
|
||||||
|
|
||||||
.c(C[7:0]), // Since the width of signal C does not equal
|
.c(C[7:0]), // Поскольку разрядность сигнала C не равна
|
||||||
// either the port width of c or eight times
|
// ни разрядности входа c, ни его увосьмерённой
|
||||||
// that width, we must select a bit range that
|
// разрядности, мы должны выбрать такой диапазон
|
||||||
// satisfies one of the requirements.
|
// бит, который будет удовлетворять одному из
|
||||||
|
// этих требований.
|
||||||
|
|
||||||
.d(C[8]) // Same as the previous case.
|
.d(C[8]) // Аналогично предыдущему.
|
||||||
);
|
);
|
||||||
endmodule
|
endmodule
|
||||||
```
|
```
|
||||||
|
|
||||||
_Listing 3. Example of creating a module array._
|
_Листинг 3. Пример создания массива модулей._
|
||||||
|
|
||||||
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:
|
Реализация массива сумматоров будет осложнена тем, что вам потребуется каким-то образом организовать передачу выходного бита переноса предыдущего разряда до входного бита переноса следующего разряда. Для этого рекомендуется создать два 32-битных вектора:
|
||||||
|
|
||||||
- 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. Create a project following the [Vivado project creation guide](../../Vivado%20Basics/01.%20New%20project.md).
|
1. Создайте проект, согласно [руководству по созданию проекта в Vivado](../../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)_.
|
2. Опишите модуль `fulladder`, схема которого представлена на _[Рис. 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.
|
1. Модуль необходимо описать с таким же именем и портами, как указано в задании.
|
||||||
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.
|
3. Проверьте модуль с помощью верификационного окружения, представленного в файле [`lab_01.tb_fulladder.sv`](lab_01.tb_fulladder.sv). Убедитесь по сигналам временной диаграммы, что модуль работает корректно. В случае обнаружения некорректного поведения сигналов суммы и выходного бита переноса, вам необходимо [найти](../../Vivado%20Basics/05.%20Bug%20hunting.md) причину этого поведения, и устранить её.
|
||||||
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).
|
4. Опишите модуль `fulladder4`, схема которого представлена на _Рис. 5 и 6_, используя [`иерархию модулей`](../../Basic%20Verilog%20structures/Modules.md#Иерархия-модулей), чтобы в нем выполнялось поразрядное сложение двух 4-битных чисел и входного бита переноса. Некоторые входы и выходы модуля будет необходимо описать в виде [`векторов`](../../Basic%20Verilog%20structures/Modules.md#Векторы).
|
||||||
1. The module must be described with the same name and ports as specified in the assignment.
|
1. Модуль необходимо описать с таким же именем и портами, как указано в задании.
|
||||||
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.
|
2. Обратите внимание, что входной бит переноса должен подаваться на сумматор, выполняющий сложение нулевого разряда, выходной бит переноса соединяется с выходным битом переноса сумматора, выполняющего сложение 4-го разряда. Промежуточные биты переноса передаются с помощью вспомогательных проводов, которые необходимо создать самостоятельно.
|
||||||
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.
|
5. Проверьте модуль с помощью верификационного окружения, представленного в файле [`lab_01.tb_fulladder4.sv`](lab_01.tb_fulladder4.sv). Убедитесь по сигналам временной диаграммы, что модуль работает корректно. В случае обнаружения некорректного поведения сигналов суммы и выходного бита переноса, вам необходимо [найти](../../Vivado%20Basics/05.%20Bug%20hunting.md) причину этого поведения, и устранить её.
|
||||||
1. Before launching simulation, make sure the correct top-level module is selected in `Simulation Sources`.
|
1. Перед запуском моделирования убедитесь, что у вас выбран корректный модуль верхнего уровня в `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).
|
6. Опишите модуль `fulladder32` так, чтобы в нем выполнялось поразрядное сложение двух 32-битных чисел и входного бита переноса. Его можно реализовать через последовательное соединение восьми 4-битных сумматоров, либо же можно соединить 32 1-битных сумматора (как вручную, так и с помощью создания массива модулей).
|
||||||
1. The module must be described with the same name and ports as specified in the assignment.
|
1. Модуль необходимо описать с таким же именем и портами, как указано в задании.
|
||||||
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.
|
2. Обратите внимание, что входной бит переноса должен подаваться на сумматор, выполняющий сложение нулевого разряда, выходной бит переноса соединяется с выходным битом переноса сумматора, выполняющего сложение 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.
|
7. Проверьте модуль с помощью верификационного окружения, представленного в файле [`lab_01.tb_fulladder32.sv`](lab_01.tb_fulladder32.sv). В случае, если в TCL-консоли появились сообщения об ошибках, вам необходимо [найти](../../Vivado%20Basics/05.%20Bug%20hunting.md) и исправить их.
|
||||||
1. Before launching simulation, make sure the correct top-level module is selected in `Simulation Sources`.
|
1. Перед запуском моделирования убедитесь, что у вас выбран корректный модуль верхнего уровня в `Simulation Sources`.
|
||||||
8. [Verify](./board%20files) the operation of your digital circuit on the FPGA.
|
8. [Проверьте](./board%20files) работоспособность вашей цифровой схемы в ПЛИС.
|
||||||
|
|||||||
@@ -1,73 +1,73 @@
|
|||||||
# Lab 2. Arithmetic Logic Unit
|
# Лабораторная работа №2. Арифметико-логическое устройство
|
||||||
|
|
||||||
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
|
## Цель
|
||||||
|
|
||||||
Using multiplexer description skills, describe an arithmetic logic unit (ALU) module in SystemVerilog.
|
Используя навыки по описанию мультиплексоров, описать блок арифметико-логического устройства (АЛУ) на языке SystemVerilog.
|
||||||
|
|
||||||
## Preparation Materials
|
## Материалы для подготовки к лабораторной работе
|
||||||
|
|
||||||
In addition to the [materials](../../Basic%20Verilog%20structures/) covered in the previous lab, you are encouraged to review:
|
В дополнение к [материалам](../../Basic%20Verilog%20structures/), изученным в ходе предыдущей лабораторной работы, вам рекомендуется ознакомиться с:
|
||||||
|
|
||||||
- how to describe a [multiplexer](../../Basic%20Verilog%20structures/Multiplexors.md) in SystemVerilog.
|
- способами описания [мультиплексора](../../Basic%20Verilog%20structures/Multiplexors.md) на языке SystemVerilog.
|
||||||
|
|
||||||
## General Workflow
|
## Ход работы
|
||||||
|
|
||||||
1. Study the structure and operating principle of an ALU (see [#theory](#theory))
|
1. Изучить устройство и принцип работы АЛУ (раздел [#теория](#Теория))
|
||||||
2. Study the SystemVerilog language constructs for implementing an ALU (see [#tools](#Tools))
|
2. Изучить языковые конструкции SystemVerilog для реализации АЛУ (раздел [#инструменты](#Инструменты))
|
||||||
3. Read the assignment carefully (see [#assignment](#Assignment))
|
3. Внимательно ознакомиться с заданием (раздел [#задание](#Задание))
|
||||||
4. Describe the ALU module and verify it using the provided verification environment.
|
4. Описать модуль АЛУ, проверить его предоставленным верификационным окружением.
|
||||||
5. Test the ALU on the FPGA.
|
5. Проверить работу АЛУ в ПЛИС.
|
||||||
|
|
||||||
## Theory
|
## Теория
|
||||||
|
|
||||||
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.
|
**Арифметико-логическое устройство** (**АЛУ**, Arithmetic Logic Unit – ALU) – это блок процессора, выполняющий арифметические и поразрядно логические операции. Разница между арифметическими и логическими операциями в отсутствии у последних бита переноса, так как логические операции происходят между 1-битными числами и дают 1-битный результат, а в случае АЛУ (в рамках данной лабораторной работы) одновременно между 32-мя 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.
|
Также, кроме результата операций, АЛУ может формировать специальные сигналы-флаги, которые показывают выполняется ли заданное условие. Например, выводить `1`, если один операнд меньше другого, или если в результате суммы произошло переполнение.
|
||||||
|
|
||||||
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.
|
Обычно АЛУ представляет собой комбинационную схему (то есть не имеет элементов памяти), на входы которой поступают информационные (операнды) и управляющие (код операции) сигналы, в ответ на что на выходе появляется результат заданной операции. АЛУ может быть реализовано и в виде последовательностной логики, но это скорее исключение.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 1. Block diagram symbol of an ALU [1, p. 247]._
|
_Рисунок 1. Структурное обозначение элемента АЛУ[[1, стр. 304]](https://reader.lanbook.com/book/241166?lms=1b8d65a957786d4b32b8201bd30e97f3)._
|
||||||
|
|
||||||
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.
|
На рис. 1 изображено структурное обозначение АЛУ, используемое в книге "Цифровая схемотехника и архитектура компьютера RISC-V" Харрис и Харрис. На входы `A` и `B` поступают операнды с разрядностью _N_. На 2-битный вход `ALUControl` подается код операции. Например, если туда подать `10`, то на выходе `Y` появится результат операции _логическое И_ между битами операндов `A` и `B`. Если же подать `00`, то на выходе появится результат сложения. Это лишь пример, разрядность и коды могут отличаться в зависимости от количества выполняемых операций и архитектуры.
|
||||||
|
|
||||||
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.
|
Существует несколько подходов к реализации АЛУ, отличающиеся внутренней организацией. В лабораторных работах применяется повсеместно используемый подход мультиплексирования операций, то есть подключения нескольких операционных устройств (которые выполняют какие-то операции, например сложения, логического ИЛИ и т.п.) к мультиплексору, который будет передавать результат нужного операционного устройства на выходы АЛУ.
|
||||||
|
|
||||||
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, в левой его части, изображена внутренняя организация этого АЛУ, справа – таблица соответствия кодов операциям. На выходе схемы (внизу) стоит 4-входовой мультиплексор, управляемый 2-битным сигналом `ALUControl`. Ко входам мультиплексора подключены выходы `N` логических И (побитовое И N-битных операндов), `N` логических ИЛИ, а выход N-битного сумматора подключён дважды, позволяя выбирать его результат для двух кодов операции.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 2. ALU block diagram [1, p. 247]._
|
_Рисунок 2. Структурная схема АЛУ [[1, стр. 305]](https://reader.lanbook.com/book/241166?lms=1b8d65a957786d4b32b8201bd30e97f3)._
|
||||||
|
|
||||||
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`.
|
Вход `A` подключается напрямую ко входам этих операционных устройств. Вход `B` тоже — за исключением подключения к сумматору. На вход второго операнда сумматора подаётся результат мультиплексирования сигналов `B` и `~B`. Управляющим сигналом этого мультиплексора является младший бит управляющего сигнала `ALUControl`. Кроме того, этот же младший бит подаётся и на сумматор в качестве входного бита переноса. Это означает, что когда `ALUControl[0] = 0`, вычисляется сумма `A + B + 0`, а когда `ALUControl[0] = 1`, вычисляется сумма `A + ~B + 1`, что (с учётом [дополнительного кода](https://ru.wikipedia.org/wiki/Дополнительный_код) ) эквивалентно `A – B`.
|
||||||
|
|
||||||
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.
|
Преимущество такой организации АЛУ в простоте его модификации, настройке под нужные коды операций, читаемости кода и масштабируемости. Можно легко добавить или убрать требуемые операции. Подумайте, как бы вы обновили данную схему, если бы от вас потребовалось расширить её функционал операциями XOR (Исключающее ИЛИ) и (SGE операция "больше либо равно")?
|
||||||
|
|
||||||
## Tools
|
## Инструменты
|
||||||
|
|
||||||
As mentioned above, an ALU can be implemented by [multiplexing](../../Basic%20Verilog%20structures/Multiplexors.md) the results of several functional units.
|
Как было сказано выше, АЛУ можно реализовать, [мультиплексируя](../../Basic%20Verilog%20structures/Multiplexors.md) результаты нескольких операционных устройств.
|
||||||
|
|
||||||
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).
|
При описании очередной комбинации управляющего сигнала, выходу мультиплексора можно сразу присваивать необходимое логическое выражение (например результат побитового ИЛИ можно подать на выход сразу в виде выражения: `a | b`, однако в некоторых случаях выражения будут сложнее из-за различных особенностей реализации, о которых будет рассказано в задании).
|
||||||
|
|
||||||
### Parameters
|
### Параметры
|
||||||
|
|
||||||
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.
|
Очень удобным на практике оказывается использование параметров. Параметры добавляют модулю гибкости, позволяя убрать ["магические"](https://ru.wikipedia.org/wiki/Магическое_число_(программирование)#Плохая_практика_программирования) константы из описания модулей, подставляя вместо них выразительное символьное имя. Параметры отдаленно схожи с макросами `#define` в языке Си, однако стоит понимать, что это не одно и то же. Дефайны представляют собой специальные текстовые макросы, которые автоматически заменяются на этапе препроцессора (как если бы вы прошлись по всем файлам своего кода и вручную заменили бы макросы на их значения). Например, с помощью дефайнов можно писать целые куски кода, а не просто одно какое-то число. При этом у дефайнов глобальная область видимости (объявив их в одном месте, этот макрос будет доступен во всем последующем коде). Параметр в свою очередь может хранить только значение какого-то конкретного типа (т.е. в параметр нельзя поместить фрагмент кода) а область видимости параметра ограничена тем модулем, где он был объявлен.
|
||||||
|
|
||||||
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.
|
Допустим, ваше устройство должно включить тостер, если на вход ему придет сигнал `32'haf3c5bd0`. Человек, не знакомый с устройством, при прочтении этого кода будет недоумевать, что это за число и почему используется именно оно. Однако, скрыв его за параметром `TOASTER_EN`, читающий поймет, что это код включения тостера. Кроме того, если некоторая константа должна использоваться в нескольких местах кода, то определив её в виде параметра, можно будет менять её в одном месте, и она тут же поменяется везде.
|
||||||
|
|
||||||
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.
|
- в теле описания модуля.
|
||||||
|
|
||||||
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.
|
В первом случае после имени модуля ставится символ `#`, затем в круглых скобках указывается ключевое слово `parameter`. Далее идет тип параметра (по умолчанию — знаковое 32-битное число), после чего задаются его имя и, при необходимости, значение по умолчанию.
|
||||||
|
|
||||||
Example:
|
Пример:
|
||||||
|
|
||||||
```Verilog
|
```Verilog
|
||||||
module overflow #(parameter WIDTH = 32)(
|
module overflow #(parameter WIDTH = 32)(
|
||||||
@@ -83,9 +83,9 @@ module overflow #(parameter WIDTH = 32)(
|
|||||||
endmodule
|
endmodule
|
||||||
```
|
```
|
||||||
|
|
||||||
_Listing 1. Example of declaring a parameter in the module prototype._
|
_Листинг 1. Пример описания параметра в прототипе модуля._
|
||||||
|
|
||||||
If the parameter does not affect port widths, it can be declared in the module body:
|
В случае, если параметр не влияет на разрядность портов, его можно объявить в теле модуля:
|
||||||
|
|
||||||
```Verilog
|
```Verilog
|
||||||
module toaster(
|
module toaster(
|
||||||
@@ -99,11 +99,11 @@ module toaster(
|
|||||||
endmodule
|
endmodule
|
||||||
```
|
```
|
||||||
|
|
||||||
_Listing 2. Example of declaring a parameter in the module body._
|
_Листинг 2. Пример описания параметра в теле модуля._
|
||||||
|
|
||||||
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.
|
В случае АЛУ будет удобно использовать параметры для обозначения кодов команд. Во-первых, для того чтобы в `case` не допустить ошибок, а во-вторых – чтобы можно было легко менять управляющие коды для повторного использования АЛУ в других проектах.
|
||||||
|
|
||||||
Compare _listings 3 and 4_ yourself:
|
Сравните сами _листинги 3 и 4_:
|
||||||
|
|
||||||
```Verilog
|
```Verilog
|
||||||
//parameter ADD = 5'b00000;
|
//parameter ADD = 5'b00000;
|
||||||
@@ -114,11 +114,11 @@ Compare _listings 3 and 4_ yourself:
|
|||||||
always_comb
|
always_comb
|
||||||
case(ALUOp)
|
case(ALUOp)
|
||||||
//...
|
//...
|
||||||
5'b00011: //... // completely unclear
|
5'b00011: //... // вообще же ничего не понятно
|
||||||
5'b11000: //... // unacceptable
|
5'b11000: //... // никуда не годится
|
||||||
```
|
```
|
||||||
|
|
||||||
_Listing 3. Example of a module description using "magic" numbers._
|
_Листинг 3. Пример описания модуля, использующего "магические" числа._
|
||||||
|
|
||||||
```Verilog
|
```Verilog
|
||||||
parameter ADD = 5'b00000;
|
parameter ADD = 5'b00000;
|
||||||
@@ -129,17 +129,17 @@ parameter SUB = 5'b01000;
|
|||||||
always_comb
|
always_comb
|
||||||
case(ALUOp)
|
case(ALUOp)
|
||||||
//...
|
//...
|
||||||
ADD: //... // very clear
|
ADD: //... // очень понятно
|
||||||
SUB: //... // concise and clean
|
SUB: //... // так лаконично и красиво
|
||||||
```
|
```
|
||||||
|
|
||||||
_Listing 4. Example of a module description using parameters._
|
_Листинг 4. Пример описания модуля, использующего параметры._
|
||||||
|
|
||||||
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.
|
С параметрами смотрится гораздо взрослее, серьёзнее и понятнее. Кстати, сразу на заметку: в SystemVerilog можно объединять группу параметров в **пакет** (package), а затем импортировать его внутрь модуля, позволяя переиспользовать параметры без повторного их прописывания для других модулей.
|
||||||
|
|
||||||
This is done as follows.
|
Делается это следующим образом.
|
||||||
|
|
||||||
First, create a SystemVerilog file that contains the package (for example, the file might contain):
|
Сперва создается SystemVerilog-файл, который будет содержать пакет (к примеру, содержимое файла может быть таким):
|
||||||
|
|
||||||
```Verilog
|
```Verilog
|
||||||
package riscv_params_pkg;
|
package riscv_params_pkg;
|
||||||
@@ -148,70 +148,71 @@ package riscv_params_pkg;
|
|||||||
endpackage
|
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
|
```Verilog
|
||||||
module riscv_processor
|
module riscv_processor
|
||||||
//import riscv_params_pkg::*;
|
//import riscv_params_pkg::*;
|
||||||
import riscv_params_pkg::ISA_WIDTH; // If you need to import
|
import riscv_params_pkg::ISA_WIDTH; // Если необходимо импортировать
|
||||||
(
|
(
|
||||||
//...Ports
|
//...Порты
|
||||||
);
|
);
|
||||||
|
|
||||||
import riscv_params_pkg::ANOTHER_EX; // all parameters in the package, these two lines
|
import riscv_params_pkg::ANOTHER_EX; // все параметры в пакете, эти две строчки
|
||||||
// can be replaced by the commented-out line above:
|
// могут быть заменены закомментированной
|
||||||
|
// выше строкой:
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
```
|
```
|
||||||
|
|
||||||
### Bit Shifts
|
### Битовые сдвиги
|
||||||
|
|
||||||
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**.
|
Реализуемое в данной лабораторной работе АЛУ использует операции битового сдвига. **Битовый сдвиг** — это операция, при которой все биты числа смещаются на заданное количество позиций. Сдвиг числа на _N_ бит эквивалентен _N_ сдвигам на 1 бит. В архитектуре RISC-V используются два типа сдвигов: **логический** и **арифметический**.
|
||||||
|
|
||||||
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.
|
При **логическом сдвиге** биты сдвигаются влево или вправо, а освободившиеся позиции заполняются нулями. При этом разряды, "вытолкнутые" за пределы разрядной сетки числа, пропадают. Например, если выполнить логический сдвиг двоичного числа _1<ins>0011010</ins>_ на один бит влево, получится _<ins>0011010</ins>0_. Обратите внимание, что старшая единица была вытолкнута за границу и исчезла.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 3. Illustration of a binary number transformation under a logical shift._
|
_Рисунок 3. Иллюстрация преобразования двоичного числа при логическом сдвиге._
|
||||||
|
|
||||||
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:
|
При арифметическом сдвиге заполнение освобождённых битов выполняется так, чтобы сохранился знак числа. В дополнительном коде знак определяется старшим битом, поэтому:
|
||||||
|
|
||||||
- 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>_;
|
- при **арифметическом сдвиге вправо** освободившиеся позиции заполняются значением старшего бита исходного числа. Это позволяет сохранить знак. Например, арифметический сдвиг на два бита вправо числа _<ins>100110</ins>10_ даёт _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.
|
- **арифметический сдвиг влево** эквивалентен логическому, так как заполнение младших битов нулями не влияет на знак числа.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 4. Illustration of a binary number transformation under an arithmetic shift._
|
_Рисунок 4. Иллюстрация преобразования двоичного числа при арифметическом сдвиге._
|
||||||
|
|
||||||
Bit shifts have an important arithmetic meaning — they correspond to multiplication or division of a number by a power of two:
|
Битовый сдвиг имеет важный арифметический смысл — он соответствует умножению или делению числа на степень двойки:
|
||||||
|
|
||||||
- a left shift by _N_ bits is equivalent to multiplication by _2<sup>N</sup>_,
|
- сдвиг влево на _N_ бит эквивалентен умножению на _2<sup>N</sup>_,
|
||||||
- a right shift by _N_ bits is equivalent to integer division by _2<sup>N</sup>_.
|
- сдвиг вправо на _N_ бит эквивалентен целочисленному делению на _2<sup>N</sup>_.
|
||||||
|
|
||||||
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.
|
Этот приём знаком должен быть знаком вам при работе с десятичной системой: умножая число на 10, мы просто дописываем справа ноль. То же самое работает и для деления: если отрезать последний разряд у числа <ins>4</ins>2, получится 4, что соответствует целочисленному делению на 10. В двоичной системе добавление (стирание) нуля справа эквивалентно умножению (делению) на 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.
|
Арифметический сдвиг важен тем, что сохраняет это свойство для знаковых чисел, представленных в дополнительном коде. Логический сдвиг вправо изменяет и знак, и модуль отрицательного числа в дополнительном коде, поэтому не может использоваться для деления знаковых чисел.
|
||||||
|
|
||||||
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.
|
Операции умножения и деления — это очень «дорогие» операции как с точки зрения элементов схемы (если эти операции реализуются аппаратно), так и с точки зрения времени их вычисления. Поэтому выполнение сдвигов в качестве замены умножения применяется повсеместно. Например, написав в коде языка C++ выражение `var * 8`, после компиляции вы наверняка получите операцию сдвига влево на 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++
|
```C++
|
||||||
X = X | (1 << N); // Set the N-th bit
|
X = X | (1 << N); // Установка N-го бита
|
||||||
X = X & ~(1 << N); // Clear the N-th bit
|
X = X & ~(1 << N); // Очистка N-го бита
|
||||||
Y = (X & (1 << N)) != 0; // Read the N-th bit
|
Y = (X & (1 << N)) != 0; // Чтение N-го бита
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Shift Implementation Notes
|
#### Особенности реализации сдвига
|
||||||
|
|
||||||
> [!IMPORTANT]
|
> [!IMPORTANT]
|
||||||
> According to the RISC-V specification, **ALL** shift operations use only the 5 least significant bits of operand B [2, pp. 26–27].
|
> По спецификации RISC-V, для **ВСЕХ** операций сдвига используются только 5 младших бит операнда B[2, стр. 26-27].
|
||||||
|
|
||||||
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.
|
Сами посмотрите: выполнять операцию сдвига более чем на 31 для 32-битных чисел не имеет смысла, число полностью заполнится нулями (единицами). Т.е. сдвигая на любое число, большее 31, вы получите один и тот же результат. Для того чтобы закодировать 31 требуется минимум 5 бит, отсюда и это требование. Оно обязательно, поскольку старшие биты в дальнейшем будут использоваться по другому назначению и, если вы упустите это, ваш будущий процессор станет работать неправильно.
|
||||||
|
|
||||||
## Assignment
|
## Задание
|
||||||
|
|
||||||
Implement an ALU in SystemVerilog according to the following prototype:
|
Необходимо на языке SystemVerilog реализовать АЛУ в соответствии со следующим прототипом:
|
||||||
|
|
||||||
```Verilog
|
```Verilog
|
||||||
|
|
||||||
@@ -223,112 +224,112 @@ module alu (
|
|||||||
output logic [31:0] result_o
|
output logic [31:0] result_o
|
||||||
);
|
);
|
||||||
|
|
||||||
import alu_opcodes_pkg::*; // import of parameters containing
|
import alu_opcodes_pkg::*; // импорт параметров, содержащих
|
||||||
// operation codes for the ALU
|
// коды операций для АЛУ
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
```
|
```
|
||||||
|
|
||||||
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.
|
Для стандартного набора целочисленных операций архитектуры RISC-V требуется выполнять 16 различных операций. Для кодирования 16 операций было бы достаточно 4 бит, но в лабораторной работе предлагается использовать 5-битный код, что связано с особенностями кодирования инструкций. Старший бит кода операции указывает на то, является ли операция вычислительной или это операция сравнения.
|
||||||
|
|
||||||
For readability, the instruction list is split into two tables.
|
Для удобства чтения, список инструкций разбит на две таблицы.
|
||||||
|
|
||||||
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.**
|
В первой таблице перечислены операции, вычисляющие значение сигнала `result_o`. **При получении АЛУ любого кода операции, не входящего в эту таблицу, сигнал `result_o` должен быть равен нулю**.
|
||||||
|
|
||||||
| Operation | ={cmp, mod, opcode} | Expression | Action |
|
|Операция|={cmp, mod, opcode}|Выражение | Действие |
|
||||||
|-----------|---------------------|-------------------------|-------------------------------------------------------|
|
|--------|-------------------|-----------------------|-------------------------------------------------------|
|
||||||
| ADD | 0 0 000 | result_o = a_i + b_i | Addition |
|
| ADD | 0 0 000 |result_o = a_i + b_i | Сложение |
|
||||||
| SUB | 0 1 000 | result_o = a_i – b_i | Subtraction |
|
| SUB | 0 1 000 |result_o = a_i – b_i | Вычитание |
|
||||||
| SLL | 0 0 001 | result_o = a_i << b_i | Left shift |
|
| SLL | 0 0 001 |result_o = a_i << b_i | Сдвиг влево |
|
||||||
| SLTS | 0 0 010 | result_o = a_i < b_i | **Signed** comparison |
|
| SLTS | 0 0 010 |result_o = a_i < b_i | **Знаковое** сравнение |
|
||||||
| SLTU | 0 0 011 | result_o = a_i < b_i | **Unsigned** comparison |
|
| SLTU | 0 0 011 |result_o = a_i < b_i | **Беззнаковое** сравнение |
|
||||||
| XOR | 0 0 100 | result_o = a_i ^ b_i | Bitwise exclusive **OR** |
|
| XOR | 0 0 100 |result_o = a_i ^ b_i | Побитовое исключающее **ИЛИ** |
|
||||||
| SRL | 0 0 101 | result_o = a_i >> b_i | Right shift |
|
| SRL | 0 0 101 |result_o = a_i >> b_i | Сдвиг вправо |
|
||||||
| SRA | 0 1 101 | result_o = a_i >>> b_i | Arithmetic right shift (`a_i` operand is signed) |
|
| SRA | 0 1 101 |result_o = a_i >>> b_i | Арифметический сдвиг вправо (операнд `a_i` — знаковый)|
|
||||||
| OR | 0 0 110 | result_o = a_i \| b_i | Bitwise logical **OR** |
|
| OR | 0 0 110 |result_o = a_i \| b_i | Побитовое логическое **ИЛИ** |
|
||||||
| AND | 0 0 111 | result_o = a_i & b_i | Bitwise logical **AND** |
|
| AND | 0 0 111 |result_o = a_i & b_i | Побитовое логическое **И** |
|
||||||
|
|
||||||
_Table 1. List of computational operations._
|
_Таблица 1. Список вычислительных операций._
|
||||||
|
|
||||||
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.**
|
Во второй таблице перечислены операции, вычисляющие значение сигнала `flag_o`. **При получении АЛУ любого кода операции, не входящего в эту таблицу, сигнал `flag_o` должен быть равен нулю**.
|
||||||
|
|
||||||
| Operation | ={cmp, mod, opcode} | Expression | Action |
|
|Операция|={cmp, mod, opcode}| Выражение | Действие |
|
||||||
|-----------|---------------------|------------------------|--------------------------------------|
|
|--------|-------------------|----------------------|-----------------------------------|
|
||||||
| EQ | 1 1 000 | flag_o = (a_i == b_i) | Set flag if operands are **equal** |
|
| EQ | 1 1 000 | flag_o = (a_i == b_i)| Выставить флаг, если **равны** |
|
||||||
| NE | 1 1 001 | flag_o = (a_i != b_i) | Set flag if operands are **unequal** |
|
| NE | 1 1 001 | flag_o = (a_i != b_i)| Выставить флаг, если **не равны** |
|
||||||
| LTS | 1 1 100 | flag_o = a_i < b_i | **Signed** comparison **<** |
|
| LTS | 1 1 100 | flag_o = a_i < b_i | **Знаковое** сравнение **<** |
|
||||||
| GES | 1 1 101 | flag_o = a_i ≥ b_i | **Signed** comparison **≥** |
|
| GES | 1 1 101 | flag_o = a_i ≥ b_i | **Знаковое** сравнение **≥** |
|
||||||
| LTU | 1 1 110 | flag_o = a_i < b_i | **Unsigned** comparison **<** |
|
| LTU | 1 1 110 | flag_o = a_i < b_i | **Беззнаковое** сравнение **<** |
|
||||||
| GEU | 1 1 111 | flag_o = a_i ≥ b_i | **Unsigned** comparison **≥** |
|
| GEU | 1 1 111 | flag_o = a_i ≥ b_i | **Беззнаковое** сравнение **≥** |
|
||||||
|
|
||||||
_Table 2. List of comparison operations._
|
_Таблица 2. Список операций сравнения._
|
||||||
|
|
||||||
**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.**
|
**Выражения в этих двух таблицах приведены для примера. Не все из них можно просто переписать — часть этих выражений надо дополнить. Чтобы вы не копировали выражения, в них вставлены неподдерживаемые символы.**
|
||||||
|
|
||||||
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:
|
Несмотря на разделение на вычислительные операции, и операции сравнения, в _Таблице 1_ (вычислительных операций) оказалось две операции: `SLTS` и `SLTU`, которые выполняют сравнения. В итоге у нас есть две похожие пары инструкций:
|
||||||
|
|
||||||
- `LTS`
|
- `LTS`
|
||||||
- `LTU`
|
- `LTU`
|
||||||
- `SLTS`
|
- `SLTS`
|
||||||
- `SLTU`
|
- `SLTU`
|
||||||
|
|
||||||
The first pair computes a "branch" result. The operation result is placed on the `flag_o` output and used directly for branching.
|
Первая пара инструкций вычисляет "ветвительный" результат. Результат операции будет подан на выходной сигнал `flag_o` и использован непосредственно при ветвлении.
|
||||||
|
|
||||||
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.
|
Вторые две инструкции используются для получения "вычислительного" результата. Т.е. результат сравнения будет подан на выходной сигнал `result_o` так же, как подается результат операции `ADD`, и будет использован в неких вычислениях, избегая при этом условного перехода.
|
||||||
|
|
||||||
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:
|
К примеру, нам необходимо пройтись по массиву из миллиона элементов и убедиться, что все они были неотрицательны. Об этом будет сигнализировать переменная `num_of_err`, значение которой должно быть равно числу элементов массива, меньших нуля. Вычислить значение этой переменной можно двумя способами:
|
||||||
|
|
||||||
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).
|
1. В каждой итерации цикла сделать ветвление: в одном случае инкрементировать переменную, в другом случае — нет (для ветвления использовать "ветвительную" операцию `LTS`).
|
||||||
2. In each loop iteration, add the result of the "computational" operation `SLTS` to the current value of the variable.
|
2. В каждой итерации цикла складывать текущее значение переменной с результатом "вычислительной" операции `SLTS`.
|
||||||
|
|
||||||
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.
|
Операции ветвления очень сильно влияют (в худшую сторону) на производительность конвейерного процессора. В первом случае мы получим миллион операций ветвления, во втором — ни одной! Разумеется, потом переменную `num_of_err` скорее всего сравнят с нулем что приведет к ветвлению, но при вычислении значения этой переменной ветвления можно будет избежать.
|
||||||
|
|
||||||
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`).
|
Различие между `SLTS` и `SLTU` (или `LTS` и `LTU`) заключается в том, как мы интерпретируем операнды: как знаковые числа (операции `STLS` и `LTS`) или как беззнаковые (операции `SLTU` и `LTU`).
|
||||||
|
|
||||||
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`.
|
Предположим, мы сравниваем два двоичных числа: `1011` и `0100`. Если интерпретировать эти числа как беззнаковые, то это `11` и `4`, результат: `11 > 4`. Однако если интерпретировать эти числа как знаковые, то теперь это числа `-5` и `4` и в этом случае `-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**.
|
Как мы видим, результат одной и той же операции над одними и теми же двоичными числами может зависеть от того, каким образом мы интерпретируем эти двоичные числа. Для большинства операций в АЛУ это не важно: например, сложение будет работать одинаково в обоих случаях, благодаря свойствам дополнительного кода, а побитовые операции работают с отдельными битами двоичного числа. А вот для операции арифметического сдвига это важно — **операнд А в арифметическом сдвиге должен интерпретироваться как знаковый**.
|
||||||
|
|
||||||
By default, SystemVerilog interprets all signals as unsigned. To change this behavior, use the `$signed` construct.
|
По умолчанию SystemVerilog интерпретирует все сигналы как беззнаковые, если мы хотим изменить это поведение, необходимо воспользоваться конструкцией `$signed`.
|
||||||
|
|
||||||
The `$signed` construct tells the synthesis tool to interpret the value passed as an operand as a signed number.
|
Конструкция `$signed` говорит САПР интерпретировать число, переданное в качестве операнда, как знаковое.
|
||||||
|
|
||||||
```Verilog
|
```Verilog
|
||||||
assign Result = $signed(A) / 10;
|
assign Result = $signed(A) / 10;
|
||||||
```
|
```
|
||||||
|
|
||||||
In this example, signal `Result` is assigned the result of dividing the **signed** number `A` by `10`.
|
В этом примере некоторому сигналу `Result` присваивают результат деления **знакового** числа `A` на `10`.
|
||||||
|
|
||||||
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.
|
Так как используются не все возможные комбинации управляющего сигнала АЛУ, то **при описании через `case` не забывайте использовать `default`**. Если описать АЛУ как задумано, то получится что-то похожее на _рис. 5_. Но не обязательно, зависит от вашего описания.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
_Figure 5. Example circuit implementing the ALU._
|
_Рисунок 5. Пример схемы, реализующей АЛУ._
|
||||||
|
|
||||||
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.
|
Обратите внимание на то, что сумматор на _рис. 5_ отличается от всех остальных блоков. Для того, чтобы спроектированный в ЛР№1 32-разрядный сумматор был создан не зазря, а также для закрепления навыков по созданию экземпляров модулей внутри других модулей, вам предлагается использовать его при реализации АЛУ.
|
||||||
|
|
||||||
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.
|
Другие блоки распознаны Vivado на основе представленных в описании АЛУ арифметических или логических выражений и в процессе синтеза будут реализованы через те компоненты ПЛИС, которые позволят лучше всего удовлетворить временным и физическим ограничениям проекта (см. главу "Этапы реализации проекта в ПЛИС"). Сумматор же будет реализован так, как это описали мы, поскольку вместо использования абстрактной операции "+" в описании АЛУ было сказано разместить конкретный модуль, реализующий конкретную схему. Такая реализация сумматора не является эффективной ни в плане временных характеристик, ни в плане количества затраченных на реализацию ресурсов ПЛИС. Но как уже упоминалось в ЛР№1, цель этой реализации — воспроизвести простоту логики рассуждений о том, как спроектировать сумматор.
|
||||||
|
|
||||||
### Assignment Steps
|
### Порядок выполнения задания
|
||||||
|
|
||||||
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. Добавьте в `Design Sources` проекта файл [`alu_opcodes_pkg.sv`](alu_opcodes_pkg.sv). Этот файл содержит объявление пакета `alu_opcodes_pkg`, в котором прописаны все опкоды АЛУ.
|
||||||
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.
|
1. Поскольку данный файл не содержит описания модулей, он не отобразится во вкладке `Hierarchy` окна `Sources` Vivado (исключением может быть ситуация, когда в проекте вообще нет ни одного модуля). Добавленный файл можно будет найти во вкладках `Libraries` и `Compile Order`.
|
||||||
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_.
|
2. Обратите внимание, что имена параметров кодов операций АЛУ, объявленных в добавляемом пакете, имеют префикс `ALU_`, которого не было в _таблицах 1 и 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.
|
3. В случае, если вы добавили пакет в проект и импортировали его в модуле АЛУ, однако Vivado выдает ошибку о том, что используемые параметры не объявлены, попробуйте сперва исправить все остальные синтаксические ошибки и сохранить файл. Если и это не помогло, можно перейти на вкладку `Compile Order`, нажать правой кнопкой мыши по файлу `alu_opcodes_pkg.sv` и выбрать `Move to Top`. Таким образом, мы сообщаем Vivado, что при компиляции проекта, этот файл всегда необходимо собирать в первую очередь. Это вариант "последней надежды" и должен использоваться только в самом крайнем случае. Когда в проекте нет никаких проблем, Vivado всегда может самостоятельно определить правильный порядок компиляции файлов. Тот факт, что вам приходится менять этот порядок означает, что в проекте есть какие-то проблемы, не позволяющие Vivado определить правильный порядок самостоятельно.
|
||||||
2. Describe the `alu` module with the same name and ports as specified in the [assignment](#Assignment).
|
2. Опишите модуль `alu` с таким же именем и портами, как указано в [задании](#Задание).
|
||||||
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`.
|
1. Поскольку у вас два выходных сигнала, зависящих от сигнала `alu_op_i`, вам потребуется описать два разных [мультиплексора](../../Basic%20Verilog%20structures/Multiplexors.md) (их лучше всего описывать через два отдельных блока `case`). При описании, используйте `default` на оставшиеся комбинации сигнала `alu_op_i`.
|
||||||
2. Pay attention to the bit widths of your signals.
|
2. Следите за разрядностью ваших сигналов.
|
||||||
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.
|
3. Для реализации АЛУ, руководствуйтесь таблицей с операциями, а не схемой в конце задания, которая приведена в качестве референса. Обратите внимание, в одной половине операций `flag_o` должен быть равен нулю, в другой `result_o` (т.е. всегда либо один, либо другой сигнал должен быть равен нулю). Именно поэтому удобней всего будет описывать АЛУ в двух разных блоках `case`.
|
||||||
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.
|
4. Вам не нужно переписывать опкоды из таблицы в качестве вариантов для блока `case`. Вместо этого используйте символьные имена с помощью параметров, импортированных из пакета `alu_opcodes_pkg`.
|
||||||
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.
|
5. Описывая операцию сложения вы **должны** использовать ваш 32-битный сумматор из первой лабораторной. При описании вычитания сумматор использовать не надо, можно использовать оператор `-`.
|
||||||
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).
|
1. При подключении сумматора, на входной бит переноса необходимо подать значение `1'b0`. Если не подать значение на входной бит переноса, результат суммы будет не определен (т.к. не определено одно из слагаемых).
|
||||||
2. The carry-out can be left unconnected, as it will not be used.
|
2. Выходной бит переноса при подключении сумматора можно не указывать, т.к. он использоваться не будет.
|
||||||
6. When implementing shift operations, follow the [shift implementation notes](#Shift-Implementation-Notes).
|
6. При реализации операций сдвига, руководствуйтесь [особенностями реализации сдвигов](#Особенности-реализации-сдвига).
|
||||||
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.
|
3. Проверьте модуль с помощью верификационного окружения, представленного в файле [`lab_02.tb_alu.sv`](lab_02.tb_alu.sv). В случае, если в TCL-консоли появились сообщения об ошибках, вам необходимо [найти](../../Vivado%20Basics/05.%20Bug%20hunting.md) и исправить их.
|
||||||
1. Before running the simulation, make sure the correct top-level module is selected in `Simulation Sources`.
|
1. Перед запуском моделирования убедитесь, что у вас выбран корректный модуль верхнего уровня в `Simulation Sources`.
|
||||||
4. [Verify](./board%20files) that your digital circuit works correctly on the FPGA.
|
4. [Проверьте](./board%20files) работоспособность вашей цифровой схемы в ПЛИС.
|
||||||
|
|
||||||
## References
|
## Список использованной литературы
|
||||||
|
|
||||||
1. D.M. Harris, S.L. Harris / Digital Design and Computer Architecture. RISC-V Edition, 2021;
|
1. [Д.М. Харрис, С.Л. Харрис / Цифровая схемотехника и архитектура компьютера: RISC-V / пер. с англ. В. С. Яценков, А. Ю. Романов; под. ред. А. Ю. Романова / М.: ДМК Пресс, 2021](https://e.lanbook.com/book/241166);
|
||||||
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).
|
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).
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
1. Описать модуль контроллера прерываний.
|
1. Описать модуль контроллера прерываний.
|
||||||
2. Описать модуль контроллера регистров статуса и контроля (**CSR**-контроллер).
|
2. Описать модуль контроллера регистров статуса и контроля (**CSR**-контроллер).
|
||||||
|
|
||||||
## Ход выполнения
|
## Ход работы
|
||||||
|
|
||||||
1. Изучение теории по прерываниям и исключениям в архитектуре RISC-V, включая работу с регистрами статуса и контроля (**CSR**) и механизмы реализации прерываний.
|
1. Изучение теории по прерываниям и исключениям в архитектуре RISC-V, включая работу с регистрами статуса и контроля (**CSR**) и механизмы реализации прерываний.
|
||||||
2. Реализация схемы обработки прерывания для устройства на основе RISC-V
|
2. Реализация схемы обработки прерывания для устройства на основе RISC-V
|
||||||
|
|||||||
Reference in New Issue
Block a user