# Описание регистров в 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
