Files
APS/Basic Verilog structures/Registers.md
Andrei Solodovnikov 9739429d6e Синхронизация с правками публикуемого издания (#101)
* СП. Обновление предисловия

* СП. Обновление введения

* СП. Обновление лаб

* СП. Обновление доп материалов

* СП. Введение

* СП. Введение

* СП. ЛР№4, 15

* СП. Базовые конструкции Verilog

* Update Implementation steps.md

* СП. ЛР 4,5,7,8,14

* СП. ЛР№8

* Синхронизация правок

* СП. Финал

* Исправление ссылки на рисунок

* Обновление схемы

* Синхронизация правок

* Добавление белого фона .drawio-изображениям

* ЛР2. Исправление нумерации рисунка
2025-02-12 17:53:52 +03:00

237 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Описание регистров в SystemVerilog
Перед тем, как описывать память, необходимо научиться описывать отдельные регистры. **Регистр** — устройство для записи, хранения и считывания n-разрядных двоичных данных и выполнения других операций над ними [1, стр. 32]. В современной электронике, регистр чаще всего строится на D-триггерах. В лабораторной работе по АЛУ уже вскользь упоминалось, что как для описания проводов, так и для описания регистров, используется тип `logic`.
```Verilog
logic reg_name;
```
![../.pic/Basic%20Verilog%20structures/registers/fig_01.drawio.svg](../.pic/Basic%20Verilog%20structures/registers/fig_01.drawio.svg)
У регистра может быть несколько входов и один выход. Основных входов, без которых не может существовать регистр два: вход данных и вход тактирующего синхроимпульса. На рисунке они обозначены как `D` и `clk`. Опциональный вход сигнала сброса (`rst`) позволяет обнулять содержимое регистра вне зависимости от входных данных и может работать как с тактовым синхроимпульсом (синхронный сброс), так и без него (асинхронный сброс).
Помимо прочего у регистра также может быть входной сигнал разрешения записи (`enable`), который определяет будут ли записаны данные с входного сигнала данных в регистр или нет, опциональный вход установки (`set`), позволяющий принудительно выставить значение регистра в единицу.
Выход у регистра один. На рисунке выше он обозначен как `Q`.
Важно понимать, что названия приведенных портов не являются чем-то высеченным на камне, они просто описывают функциональное назначение. В процессе описания работы регистра вы будете оперировать только над именем регистра, и сигналами, которые подводите к нему.
Поскольку все сигналы в цифровой схеме передаются по цепям, удобно представлять, что к выходу регистра всегда неявно подключен провод, с именем, совпадающим с именем регистра, поэтому вы можете использовать имя регистра в дальнейшей цифровой логике:
![../.pic/Basic%20Verilog%20structures/registers/fig_02.drawio.svg](../.pic/Basic%20Verilog%20structures/registers/fig_02.drawio.svg)
Итак, мы добавили регистр на холст схемы, но как соединить его с какой-то логикой? Предположим, у нас есть сигнал тактового синхроимпульса и данные, которые мы хотим записать:
![../.pic/Basic%20Verilog%20structures/registers/fig_03.drawio.svg](../.pic/Basic%20Verilog%20structures/registers/fig_03.drawio.svg)
Данной схеме соответствует код:
```Verilog
module reg_example(
input logic clk,
input logic data,
output logic reg_data
);
logic reg_name;
endmodule
```
Очевидно, мы хотим подключить сигнал `clk` ко входу тактирующего сигнала регистра, вход `data` ко входу данных, а выход регистра к выходу `reg_data`:
![../.pic/Basic%20Verilog%20structures/registers/fig_04.drawio.svg](../.pic/Basic%20Verilog%20structures/registers/fig_04.drawio.svg)
Запись в регистр возможна только по фронту тактирующего синхроимпульса. **Фронт** — это переход сигнала из нуля в единицу (**положительный фронт**), либо из единицы в ноль (**отрицательный фронт**).
Описание регистра, а также указание фронта и тактирующего сигнала происходит в конструкции `always_ff`:
```Verilog
always_ff @(posedge clk)
```
Далее, внутри данной конструкции необходимо указать, что происходит с содержимым регистра. В нашем случае, происходит запись с входного сигнала `data`
```Verilog
always_ff @(posedge clk) begin
reg_name <= data;
end
```
> [!IMPORTANT]
> Обратите внимание на оператор `<=`. В данном случае, это не знак "меньше либо равно", а оператор **неблокирующего присваивания**. Существует оператор **блокирующего присваивания** (`=`), который может поменять способ построения схемы для такого же выражения справа от оператора. Хоть это и плохая практика в обучении, но пока вам надо просто запомнить: **при описании записи в регистр всегда используйте оператор неблокирующего присваивания `<=`**. Подробнее о рассказано в документе "[О различиях между блокирующими и неблокирующими присваиваниями](./Assignments.md)".
Помимо прочего, нам необходимо связать выход схемы с выходом регистра. Это можно сделать уже известным вам оператором **непрерывного присваивания** `assign`.
Таким образом, итоговый код описания данной схемы примет вид:
```Verilog
module reg_example(
input logic clk,
input logic data,
output logic reg_data
);
logic reg_name;
always_ff @(posedge clk) begin
reg_name <= data;
end
assign reg_data = reg_name;
endmodule
```
Предположим, мы хотим добавить управление записью в регистр через сигналы `enable` и `reset`. Это, например, можно сделать следующим образом:
```Verilog
module reg_example(
input logic clk,
input logic data,
input logic reset,
input logic enable,
output logic reg_data
);
logic reg_name;
always_ff @(posedge clk) begin
if(reset) begin
reg_name <= 1'b0;
end
else if(enable) begin
reg_name <= data;
end
end
assign reg_data = reg_name;
endmodule
```
Обратите внимание на очередность условий. В первую очередь, мы проверяем условие **сброса**, и только после этого условие **разрешения на запись**.
Если сперва проверить разрешение на запись, а затем в блоке `else` описать логику сброса, то регистр не будет сбрасываться в случае, если `enable` будет равен `1` (запись в регистр будет приоритетней его сброса). Если сброс описать не в блоке `else`, а в отдельном блоке `if`, то может возникнуть неопределенное поведение: нельзя однозначно сказать, что запишется в регистр, если одновременно придут сигналы `reset` и `enable`. Поэтому при наличии сигнала сброса, остальная логика по записи в регистр должна размещаться в блоке `else`.
Кроме того, САПР-ы смотрят на паттерн описания элемента схемы, и когда распознают его, реализуют элемент так как задумывал разработчик. Поэтому при описании регистра всегда сперва описывается сигнал сброса (если он используется) и только затем в блоке `else` описывается вся остальная часть логики записи.
Итоговая схема регистра со сбросом и сигналом разрешения записи:
![../.pic/Basic%20Verilog%20structures/registers/fig_05.drawio.svg](../.pic/Basic%20Verilog%20structures/registers/fig_05.drawio.svg)
Помимо прочего есть еще одно важное правило, которое необходимо знать при описании регистра:
**Присваивание регистру может выполняться только в одном блоке `always`**
Даже если вдруг САПР не выдаст сразу сообщение об ошибке, в конечном итоге, на этапе синтеза схемы она рано или поздно появится в виде сообщения связанного с **"multiple drivers"**.
В блоке присваивания регистру можно описывать и комбинационную логику, стоящую перед ним, например схему:
![../.pic/Basic%20Verilog%20structures/registers/fig_06.drawio.svg](../.pic/Basic%20Verilog%20structures/registers/fig_06.drawio.svg)
можно описать как
```Verilog
module reg_example(
input logic clk,
input logic A,
input logic B,
input logic reset,
input logic enable,
output logic reg_data
);
logic reg_name;
always_ff @(posedge clk) begin
if(reset) begin
reg_name <= 1'b0;
end
else if(enable) begin
reg_name <= A & B;
end
end
assign reg_data = reg_name;
endmodule
```
Однако это всего лишь упрощение. Если вы умеете описывать регистр с подключением к нему всего одного провода на входе данных, вы все равно сможете описать эту схему:
```Verilog
module reg_example(
input logic clk,
input logic A,
input logic B,
input logic reset,
input logic enable,
output logic reg_data
);
logic reg_name; // Обратите внимание, что несмотря на то, что
logic ab; // и reg_name и ab объявлены типом logic,
// ab станет проводом, а reg_name - регистром
// (из-за непрерывного присваивания на ab, и блока
// always_ff для reg_name)
assign ab = A & B;
always_ff @(posedge clk) begin
if(reset) begin
reg_name <= 1'b0;
end
else if(enable) begin
reg_name <= ab;
end
end
assign reg_data = reg_name;
endmodule
```
Поэтому так важно разобраться в базовом способе описания регистра.
Более того, с точки зрения синтезатора данное описание проще для синтеза, т.к. ему не разделять из одного `always` блока комбинационную и синхронные части.
Вообще говоря, регистр в общем смысле этого слова представляет собой многоразрядную конструкцию (в рассмотренном ранее примере, 1-битный регистр мог представлять из себя простой D-триггер).
Создание многоразрядного регистра мало отличается от создания многоразрядного провода, а описание логики записи в многоразрядный регистр ничем не отличается от логики записи в одноразрядный регистр:
```Verilog
module reg_example(
input logic clk,
input logic [7:0] data,
output logic [7:0] reg_data
);
logic [7:0] reg_name;
always_ff @(posedge clk) begin
reg_name <= data;
end
assign reg_data = reg_name;
endmodule
```
## Итоги главы
1. [Регистр](https://ru.wikipedia.org/wiki/Регистр_(цифровая_техника)) — это базовая ячейка памяти, позволяющая хранить состояние, пока на схему подается питание.
2. Для объявления регистра используется тип `logic`, при необходимости после типа указывается разрядность будущего регистра.
3. Для описания логики записи в регистр используется блок `always_ff`, в круглых скобках которого указывается тактирующий сигнал и фронт, по которому будет вестись запись, а также (в случае асинхронного сброса), сигнал сброса.
4. Регистр может иметь различные управляющие сигналы: установки/сброса/разрешения на запись. Логика этих управляющих сигналов является частью логики записи в этот регистр и так же описывается в блоке `always_ff`.
5. При описании логики записи в регистр, необходимо пользоваться оператором **неблокирующего присваивания** `<=`.
6. Нельзя описывать логику записи в регистр более чем в одном блоке `always` (иными словами, операция присваивания для каждого регистра может находиться только в одном блоке always).
## Проверь себя
Как, по-вашему, описать на языке SystemVerilog схему, приведённую ниже?
![../.pic/Basic%20Verilog%20structures/registers/fig_07.drawio.svg](../.pic/Basic%20Verilog%20structures/registers/fig_07.drawio.svg)
## Список источников
1. Ш. Габриелян, Е. Вахтина / Электротехника и электроника. Методические рекомендации. — Ставрополь: Аргус, 2013