mirror of
https://github.com/MPSU/APS.git
synced 2026-06-10 11:13:33 +00:00
English version draft
Assisted-by: Claude:claude-4.6-sonnet
This commit is contained in:
@@ -1,14 +1,14 @@
|
||||
# Описание модулей в SystemVerilog
|
||||
# Describing Modules in SystemVerilog
|
||||
|
||||
Основой цифровых схем в SystemVerilog является модуль. Модуль — это блок SystemVerilog-кода, описывающий цифровую схему какого-то устройства, например пульта телевизора:
|
||||
The fundamental building block of digital circuits in SystemVerilog is the module. A module is a block of SystemVerilog code that describes the digital circuit of some device — for example, a TV remote control:
|
||||
|
||||
<img src="../.pic/Basic%20Verilog%20structures/modules/fig_00.svg" alt="../.pic/Basic%20Verilog%20structures/modules/fig_00.svg" width="300"/>
|
||||
|
||||
У пульта есть входные сигналы: кнопки, нажатие на которые сообщает о нашем намерении изменить громкость или переключить канал. Кроме того, есть выходной сигнал ИК-светодиода, по которому пульт отправляет информацию телевизору.
|
||||
The remote control has input signals — buttons whose presses communicate our intention to change the volume or switch a channel. It also has an output signal from an IR LED, through which the remote sends information to the TV.
|
||||
|
||||
Для создания модуля в языке SystemVerilog используются ключевые слова `module` и `endmodule`, которые определяют начало и конец модуля, обрамляя его. Можно сказать, что эти ключевые слова являются корпусом нашего устройства, отделяют его содержимое от внешнего мира.
|
||||
To create a module in SystemVerilog, the keywords `module` and `endmodule` are used. They define the beginning and end of the module, enclosing it. These keywords can be thought of as the housing of our device, separating its contents from the outside world.
|
||||
|
||||
Определим наш модуль:
|
||||
Let's define our module:
|
||||
|
||||

|
||||
|
||||
@@ -19,7 +19,7 @@ module
|
||||
endmodule
|
||||
```
|
||||
|
||||
У всякого модуля должно быть название. Назовём его `box`. В круглых скобках пишутся имена портов, их направление и типы. Если модуль не имеет ни входов, ни выходов, внутри скобок ничего не пишется. После них всегда ставится точка с запятой.
|
||||
Every module must have a name. Let's call it `box`. Port names, their directions, and types are written inside the parentheses. If a module has neither inputs nor outputs, nothing is written inside the parentheses. A semicolon is always placed after the parentheses.
|
||||
|
||||

|
||||
|
||||
@@ -30,7 +30,7 @@ module box();
|
||||
endmodule
|
||||
```
|
||||
|
||||
Модуль без входов и выходов (портов) — это просто коробка, которая никак не взаимодействует с внешним миром. Подключим к нему два входных сигнала `a, b` и один выходной `q`. Для объявления портов, необходимо указать направление порта (вход это или выход), и тип используемого сигнала. В рамках данного курса лабораторных работ в качестве типа и входов и выходов будет использоваться тип `logic`, о котором будет рассказано чуть позже.
|
||||
A module with no inputs or outputs (ports) is simply a box that does not interact with the outside world in any way. Let's connect two input signals `a, b` and one output signal `q` to it. To declare ports, you must specify the port direction (input or output) and the type of the signal used. Throughout this lab course, the `logic` type will be used for both inputs and outputs — it will be described in more detail shortly.
|
||||
|
||||

|
||||
|
||||
@@ -45,7 +45,7 @@ module box(
|
||||
endmodule
|
||||
```
|
||||
|
||||
Внутри модуля могут быть объявления сигналов, параметров, констант и т.п., о которых другой модуль не узнает. Объявим внутри модуля `box` провод `c`.
|
||||
Inside a module, signals, parameters, constants, etc. can be declared — none of which are visible to other modules. Let's declare an internal wire `c` inside the module `box`.
|
||||
|
||||

|
||||
|
||||
@@ -62,9 +62,9 @@ module box(
|
||||
endmodule
|
||||
```
|
||||
|
||||
Для объявления провода `c` использовалось ключевое слово (тип) `logic`. Этот тип может в конечном итоге привести к созданию как ячеек памяти (регистров), так и проводов, в зависимости от того, как было описано присваивание объекту этого типа (подобно тому как стволовые клетки организма могут дифференцироваться в специализированные клетки в зависимости от ситуации). Поэтому в примере выше говорить о том, что был создан провод не совсем корректно, объект схемы `c` станет проводом, когда будет произведено подключение к этому объекту, соответствующее подключению провода.
|
||||
The keyword (type) `logic` was used to declare wire `c`. This type can ultimately result in either memory elements (registers) or wires, depending on how assignment to an object of this type is described — similar to how stem cells in an organism can differentiate into specialized cells depending on the situation. Therefore, it is not entirely accurate to say that a wire was created in the example above; the circuit object `c` will become a wire once it is connected in a way that corresponds to a wire connection.
|
||||
|
||||
Подключим провод `c` ко входу `a`. Для этого используется конструкция `assign c = a;`. Такая конструкция называется **непрерывным присваиванием**. Если очень сильно упростить, то непрерывное присваивание схоже со спайкой двух проводов. После подобного присваивания, провод `c` всегда будет иметь то же значение, что и `a` — как только входной сигнал `a` изменит своё значение, внутренний провод `c` также изменит своё значение (проводу `c` будет **непрерывно присваиваться** значение входа `a`).
|
||||
Let's connect wire `c` to input `a`. This is done using the construct `assign c = a;`. This construct is called a **continuous assignment**. In simplified terms, a continuous assignment is similar to soldering two wires together. After such an assignment, wire `c` will always have the same value as `a` — whenever input signal `a` changes its value, internal wire `c` will change its value as well (the value of input `a` is **continuously assigned** to wire `c`).
|
||||
|
||||

|
||||
|
||||
@@ -84,19 +84,19 @@ endmodule
|
||||
```
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Обратите внимание, что объявление сигнала типа `logic` нельзя объединять с непрерывным присваиванием этому сигналу. Иными словами, описанный выше сигнал `c` нельзя описать одной строчкой `logic c = a`. Данное выражение не содержит синтаксической ошибки, но оно означает лишь, что в момент создания сигнала `c`, ему будет присвоено значение сигнала `a`. Дальнейшие изменения в значении сигнала `a` никак не отразятся на значении сигнала `c` — именно для этого нужен оператор непрерывного присваивания `assign`.
|
||||
> Note that a `logic` signal declaration cannot be combined with a continuous assignment to that signal. In other words, the signal `c` described above cannot be written in a single line as `logic c = a`. This expression contains no syntax error, but it only means that at the moment signal `c` is created, it will be assigned the value of signal `a`. Any subsequent changes to signal `a` will not be reflected in signal `c` — that is precisely why the continuous assignment operator `assign` is needed.
|
||||
|
||||
Стоит, однако, заметить, что аналогия со спайкой проводов имеет свои недостатки: после неё некоторые студенты начинают думать, что расположение "спаиваемых" сигналов относительно знака равно не имеет значения, однако это не так.
|
||||
It should be noted, however, that the soldering analogy has its drawbacks: some students come away thinking that the position of the "soldered" signals relative to the equals sign does not matter — but it does.
|
||||
|
||||
В непрерывном присваивании участвует две компоненты: выражение-приемник сигнала и выражение-источник сигнала. Обычно, выражением-приемником является провод (либо группа проводов). Выражение-источник сигнала может быть совершенно различным. В примере, приведенном выше, выражением-источником так же был провод, но вместо него мог использоваться и регистр, и выражение, построенное из цепочки арифметических или логических вентилей.
|
||||
A continuous assignment involves two components: the sink expression and the source expression. Typically, the sink expression is a wire (or a group of wires). The source expression can be quite varied. In the example above, the source was also a wire, but it could just as well be a register or an expression built from a chain of arithmetic or logic gates.
|
||||
|
||||
Важно понять, что при непрерывном присваивании слева от знака равно указывается то, **чему мы будем присваивать**, а справа от знака равно указывается то, **что мы будем присваивать**.
|
||||
It is important to understand that in a continuous assignment, the left-hand side of the equals sign specifies **what we are assigning to**, and the right-hand side specifies **what we are assigning**.
|
||||
|
||||
К примеру, мы можем присвоить проводу `с` значение выхода логического вентиля. Пусть нам нужно, чтобы к сигналу `c` был подключен результат операции `a ИЛИ b`.
|
||||
For example, we can assign to wire `c` the output of a logic gate. Suppose we want signal `c` to be connected to the result of the operation `a OR b`.
|
||||
|
||||

|
||||
|
||||
Такую схему можно реализовать следующим описанием:
|
||||
This circuit can be implemented with the following description:
|
||||
|
||||
```Verilog
|
||||
module box(
|
||||
@@ -113,7 +113,7 @@ module box(
|
||||
endmodule
|
||||
```
|
||||
|
||||
Пусть в схеме имеется ещё один логический вентиль - Исключающее ИЛИ. На него подаётся результат операции `a ИЛИ b`, то есть `c`, а также входной сигнал `b`. Результат операции `c Исключающее ИЛИ b` подаётся на выход `q` нашего модуля.
|
||||
Now suppose there is one more logic gate in the circuit — an XOR gate. It receives the result of the `a OR b` operation (i.e., `c`) as well as input signal `b`. The result of the `c XOR b` operation is driven to output `q` of our module.
|
||||
|
||||

|
||||
|
||||
@@ -133,65 +133,65 @@ module box(
|
||||
endmodule
|
||||
```
|
||||
|
||||
Отлично! Мы научились создавать простейшее описание модуля.
|
||||
We have now learned how to write a basic module description.
|
||||
|
||||
Для завершения базового представления о модулях осталось разобраться с таким понятием как **вектор**.
|
||||
To complete the foundational understanding of modules, one more concept remains to be covered: **vectors**.
|
||||
|
||||
## Векторы
|
||||
## Vectors
|
||||
|
||||
В SystemVerilog **вектором** называют группу проводов или регистров, объединенных общим именем, которая может использоваться как для передачи многоразрядных чисел, так и нескольких сигналов, выполняющих общую задачу.
|
||||
In SystemVerilog, a **vector** is a group of wires or registers sharing a common name, which can be used to carry multi-bit numbers or multiple signals that serve a common purpose.
|
||||
|
||||
Синтаксис объявления вектора:
|
||||
Vector declaration syntax:
|
||||
|
||||
<pre>
|
||||
<тип> [<старший индекс>:<младший индекс>] <i>имя_вектора</i>
|
||||
<type> [<most significant index>:<least significant index>] <i>vector_name</i>
|
||||
</pre>
|
||||
|
||||
Несмотря на то, что может использоваться любой диапазон индексов (даже отрицательный), на практике стараются начинать младший индекс с нуля.
|
||||
Although any index range can be used (even negative), in practice the least significant index is typically started at zero.
|
||||
|
||||
Пример:
|
||||
Example:
|
||||
|
||||
<pre>
|
||||
<b>logic</b> [7:0] <i>sum</i>; // Объявляется 8-битный вектор с именем sum типа logic.
|
||||
// Старший индекс равен 7, младший — 0.
|
||||
<b>logic</b> [7:0] <i>sum</i>; // Declares an 8-bit vector named sum of type logic.
|
||||
// Most significant index is 7, least significant is 0.
|
||||
</pre>
|
||||
|
||||
Используя индекс, можно обратиться к отдельным битам вектора. С помощью диапазона индексов можно получить доступ к диапазону соответствующих битов.
|
||||
Using an index, individual bits of a vector can be accessed. Using an index range, a range of corresponding bits can be accessed.
|
||||
|
||||
|фрагмент кода|описание |
|
||||
|-------------|-------------------------------------------------------------------------|
|
||||
|sum[0]; | Обращение к младшему биту вектора sum, объявленного выше |
|
||||
|sum[7:5]; | Обращение к старшим трём битам 8-битного вектора sum, объявленного выше |
|
||||
|sum[5+:3]; | Обращение к трём битам, начиная с пятого (т.е. это аналог предыдущего выражения, удобно использовать, когда известен начальный бит и их количество, а конечный нужно считать через них) |
|
||||
|sum[7-:3]; | Обращение к трём битам, заканчивая седьмым (т.е. это аналог предыдущего выражения, удобно использовать, когда известен конечный бит и их количество, а начальный нужно считать через них) |
|
||||
| Code fragment | Description |
|
||||
|---------------|-----------------------------------------------------------------------------|
|
||||
| sum[0]; | Access to the least significant bit of vector sum declared above |
|
||||
| sum[7:5]; | Access to the three most significant bits of the 8-bit vector sum declared above |
|
||||
| sum[5+:3]; | Access to three bits starting from the fifth (i.e., equivalent to the previous expression; convenient when the starting bit and count are known, and the ending bit is derived from them) |
|
||||
| sum[7-:3]; | Access to three bits ending at the seventh (i.e., equivalent to the previous expression; convenient when the ending bit and count are known, and the starting bit is derived from them) |
|
||||
|
||||
_Таблица 1. Способы обращения как к отдельным битам вектора, так и к диапазонам его бит._
|
||||
_Table 1. Ways to access individual bits of a vector and ranges of its bits._
|
||||
|
||||
Векторы могут быть использованы и при описании портов модуля:
|
||||
Vectors can also be used when describing module ports:
|
||||
|
||||
```Verilog
|
||||
module vector_ex(
|
||||
input logic [3:0] a, // У данного модуля четырехразрядный вход 'a'
|
||||
output logic [7:0] b // и восьмиразрядный выход 'b'.
|
||||
input logic [3:0] a, // This module has a 4-bit input 'a'
|
||||
output logic [7:0] b // and an 8-bit output 'b'.
|
||||
);
|
||||
|
||||
assign b[7:4] = a; // К старшим четырем битам выхода b подключен вход a
|
||||
assign b[3:1] = a[2:0]; // К битам с третьего по первый выхода b подключены
|
||||
// биты со второго по нулевой входа a
|
||||
assign b[0] = a[3]; // к младшему биту b подключен старший бит a;
|
||||
assign b[7:4] = a; // The upper four bits of output b are connected to input a
|
||||
assign b[3:1] = a[2:0]; // Bits three through one of output b are connected to
|
||||
// bits two through zero of input a
|
||||
assign b[0] = a[3]; // The least significant bit of b is connected to the most significant bit of a
|
||||
|
||||
endmodule
|
||||
```
|
||||
|
||||
## Иерархия модулей
|
||||
## Module Hierarchy
|
||||
|
||||
Модули могут содержать другие модули. Реализуя модуль "Пульт ДУ" можно использовать такие цифровые схемы как "Передатчик ИК-сигнала" и "Контроллер нажатия клавиш". Обе эти цифровые схемы могут быть независимыми модулями, которые объединяются в модуле верхнего уровня.
|
||||
Modules can contain other modules. When implementing a "Remote Control" module, you might use digital circuits such as an "IR Signal Transmitter" and a "Key Press Controller". Both of these digital circuits can be independent modules that are combined inside a top-level module.
|
||||
|
||||
Допустим, у нас есть модуль `inv`, который подает на выход инверсию входа, и мы хотим реализовать модуль `top`, который хочет использовать функционал модуля `inv` следующим образом:
|
||||
Suppose we have a module `inv` that drives the inverted value of its input to the output, and we want to implement a module `top` that uses the functionality of module `inv` as follows:
|
||||
|
||||

|
||||
|
||||
Опишем `inv`:
|
||||
Let's describe `inv`:
|
||||
|
||||
```Verilog
|
||||
module inv(
|
||||
@@ -202,7 +202,7 @@ module inv(
|
||||
endmodule
|
||||
```
|
||||
|
||||
Опишем модуль `top`:
|
||||
Let's describe module `top`:
|
||||
|
||||
```Verilog
|
||||
module top(
|
||||
@@ -210,31 +210,31 @@ module top(
|
||||
input logic b,
|
||||
output logic q
|
||||
);
|
||||
// создаём вспомогательный провод c
|
||||
// create auxiliary wire c
|
||||
logic c;
|
||||
|
||||
// подключение модуля
|
||||
inv invertor_1( // подключаем модуль inv и
|
||||
// даём экземпляру этого модуля
|
||||
// имя invertor_1
|
||||
// module instantiation
|
||||
inv invertor_1( // instantiate module inv and
|
||||
// give this instance
|
||||
// the name invertor_1
|
||||
|
||||
.a(a), // вход а модуля inv подключаем ко
|
||||
//входу a модуля top
|
||||
.a(a), // connect input 'a' of module inv to
|
||||
// input 'a' of module top
|
||||
|
||||
.d(c) // выход d модуля inv подключаем к
|
||||
// проводу с модуля top
|
||||
.d(c) // connect output 'd' of module inv to
|
||||
// wire 'c' of module top
|
||||
);
|
||||
|
||||
endmodule
|
||||
```
|
||||
|
||||
Обратите внимание на то, как подключаются сигналы к вложенному модулю: при подключении после `.` пишется имя сигнала подключаемого модуля, затем в скобках пишется имя сигнала подключающего модуля. Для лучшего понимания, посмотрите внимательно на схеме на провод `c` и выход `d` модуля `inv`, а также на SystemVerilog-описание этой схемы.
|
||||
Note how signals are connected to the instantiated module: after the `.` the name of the port of the instantiated module is written, followed by the name of the connecting module's signal in parentheses. For a better understanding, carefully examine wire `c` and output `d` of module `inv` in the schematic, and compare it with the SystemVerilog description of this circuit.
|
||||
|
||||
Мы можем подключить сколько угодно экземпляров одного модуля, поэтому у каждого из экземпляра должно быть своё уникальное имя. Пусть `c` подаётся на логический вентиль И вместе со входом `b`. Результат операции И тоже пойдет на инвертор, а затем на выход `q` модуля top.
|
||||
We can instantiate as many instances of a module as needed, so each instance must have its own unique name. Let `c` be fed into an AND gate together with input `b`. The result of the AND operation is also fed into an inverter, and then to output `q` of module `top`.
|
||||
|
||||

|
||||
|
||||
Тогда в нашем описании добавится подключение второго модуля `inv` и провод `c`.
|
||||
In our description, a second instantiation of module `inv` and wire `c` will be added.
|
||||
|
||||
```Verilog
|
||||
module top(
|
||||
@@ -242,30 +242,30 @@ module top(
|
||||
input logic b,
|
||||
output logic q
|
||||
);
|
||||
// создаём вспомогательный провод c
|
||||
// create auxiliary wire c
|
||||
logic c;
|
||||
|
||||
// подключение модуля 1
|
||||
inv invertor_1( // подключаем модуль inv и даём ему
|
||||
// имя invertor_1
|
||||
// module instantiation 1
|
||||
inv invertor_1( // instantiate module inv and give it
|
||||
// the name invertor_1
|
||||
|
||||
.a(a), // подключаем вход 'а' модуля inv ко
|
||||
// входу 'a' модуля top
|
||||
.a(a), // connect input 'a' of module inv to
|
||||
// input 'a' of module top
|
||||
|
||||
.d(c) // подключаем выход 'd' модуля inv к
|
||||
// проводу 'с' модуля top
|
||||
.d(c) // connect output 'd' of module inv to
|
||||
// wire 'c' of module top
|
||||
);
|
||||
|
||||
// подключение модуля 2
|
||||
inv invertor_2( // подключаем модуль inv и даём ему
|
||||
// имя invertor_2
|
||||
// module instantiation 2
|
||||
inv invertor_2( // instantiate module inv and give it
|
||||
// the name invertor_2
|
||||
|
||||
.a(c & b), // на вход 'а' модуля inv подаём
|
||||
// результат логической операции
|
||||
// "с И b"
|
||||
.a(c & b), // drive the result of the logical
|
||||
// operation "c AND b" to
|
||||
// input 'a' of module inv
|
||||
|
||||
.d(q) // подключаем выход 'd' модуля inv
|
||||
// к выходу q модуля top
|
||||
.d(q) // connect output 'd' of module inv
|
||||
// to output 'q' of module top
|
||||
);
|
||||
|
||||
endmodule
|
||||
@@ -273,23 +273,23 @@ endmodule
|
||||
|
||||
___
|
||||
|
||||
## Итоги главы
|
||||
## Chapter Summary
|
||||
|
||||
1. Ключевым блоком в иерархии цифровой схемы, описанной на языке SystemVerilog является **модуль**. Модули позволяют выносить части сложной цифровой схемы в отдельные блоки, из которых потом и будет составлена итоговая схема, что сильно упрощает разработку.
|
||||
2. Условно, модуль можно разделить на следующие части:
|
||||
1. Объявление модуля:
|
||||
1. Ключевые слова `module` / `endmodule` определяющие границы описания модуля.
|
||||
2. Название модуля, следующее за ключевым словом `module`. Описанный модуль представляет собой отдельный тип, имя которого совпадает с названием модуля.
|
||||
3. Указание входов и выходов (портов) модуля, идущих в круглых скобках после названия модуля. Для указания направления порта модуля используются ключевые слова `input` и `output`. После указание направления порта следует указать тип порта (в рамках данного курса типом портов всегда будет `logic`), его разрядность, а затем имя.
|
||||
2. Функциональное описание модуля:
|
||||
1. Объявление внутренних сигналов модуля (будь то проводов или регистров) с помощью ключевого слова `logic`.
|
||||
2. Создание при необходимости объектов других модулей.
|
||||
3. Описание функциональной связи между различными сигналами и объектами внутри описываемого модуля.
|
||||
1. The key building block in the hierarchy of a digital circuit described in SystemVerilog is the **module**. Modules allow complex digital circuits to be broken into separate blocks, which are then combined to form the final circuit, greatly simplifying development.
|
||||
2. Conceptually, a module can be divided into the following parts:
|
||||
1. Module declaration:
|
||||
1. The keywords `module` / `endmodule` define the boundaries of the module description.
|
||||
2. The module name, which follows the keyword `module`. The described module represents a distinct type whose name matches the module name.
|
||||
3. The specification of the module's inputs and outputs (ports), listed in parentheses after the module name. The keywords `input` and `output` are used to specify port direction. After the direction, the port type must be specified (throughout this course, the port type will always be `logic`), followed by its bit width and name.
|
||||
2. Functional description of the module:
|
||||
1. Declaration of the module's internal signals (whether wires or registers) using the keyword `logic`.
|
||||
2. Instantiation of other modules as needed.
|
||||
3. Description of the functional connections between various signals and objects inside the module being described.
|
||||
|
||||
## Проверьте себя
|
||||
## Check Yourself
|
||||
|
||||
Как, по-вашему, описать нижеприведенную схему на языке описания аппаратуры SystemVerilog?
|
||||
How would you describe the circuit shown below in the SystemVerilog hardware description language?
|
||||
|
||||
Обратите внимание, что вход `a` модуля `top` является двухразрядным: нулевой его бит идёт на вход `a` модуля `or`, первый бит идёт на вход `b` модуля `or`.
|
||||
Note that input `a` of module `top` is two bits wide: its bit 0 goes to input `a` of module `or`, and its bit 1 goes to input `b` of module `or`.
|
||||
|
||||

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