WIP: APS cumulative update (#98)

* WIP: APS cumulative update

* Update How FPGA works.md

* Перенос раздела "Последовательностная логика" в отдельный док

* Исправление картинки

* Исправление оформления индексов

* Переработка раздела Vivado Basics

* Добавление картинки в руководство по созданию проекта

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

* Обновление изображения в sequential logic

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

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

* Рефактор руководства по прошивке ПЛИС

* Mass update

* Update fig_10

* Restore fig_02
This commit is contained in:
Andrei Solodovnikov
2024-09-02 10:20:08 +03:00
committed by GitHub
parent 78bb01ef95
commit a28002e681
195 changed files with 3640 additions and 2664 deletions

View File

@@ -1,4 +1,4 @@
# Лабораторная работа 2. Арифметико-логическое устройство
# Лабораторная работа 2. Арифметико-логическое устройство
Так как основной задачей процессора является обработка цифровых данных, одним из его основных блоков является арифметико-логическое устройство (АЛУ). Задача АЛУ производить над входными данным арифметические и поразрядно логические операции.
@@ -8,7 +8,9 @@
## Материалы для подготовки к лабораторной работе
Освоить [описание мультиплексора на языке SystemVerilog](../../Basic%20Verilog%20structures/Multiplexors.md).
В дополнение к [материалам](../../Basic%20Verilog%20structures/), изученным в ходе предыдущей лабораторной работы, вам рекомендуется ознакомиться с:
- способами описания [мультиплексора](../../Basic%20Verilog%20structures/Multiplexors.md) на языке SystemVerilog.
## Общий ход выполнения работы
@@ -20,7 +22,7 @@
## Теория
Арифметико-логическое устройство (АЛУ, Arithmetic Logic Unit ALU) это блок процессора, выполняющий арифметические и поразрядно логические операции. Разница между арифметическими и логическими операциями в отсутствии у последних бита переноса, так как логические операции происходят между 1-битными числами и дают 1-битный результат, а в случае АЛУ (в рамках данной лабораторной работы) одновременно между 32-мя 1-битными парами чисел. В логических операциях результаты значений отдельных битов друг с другом никак не связаны.
**Арифметико-логическое устройство** (**АЛУ**, Arithmetic Logic Unit ALU) это блок процессора, выполняющий арифметические и поразрядно логические операции. Разница между арифметическими и логическими операциями в отсутствии у последних бита переноса, так как логические операции происходят между 1-битными числами и дают 1-битный результат, а в случае АЛУ (в рамках данной лабораторной работы) одновременно между 32-мя 1-битными парами чисел. В логических операциях результаты значений отдельных битов друг с другом никак не связаны.
Также, кроме результата операций, АЛУ формирует флаги, которые показывают выполняется ли заданное условие. Например, выведет `1`, если один операнд меньше другого.
@@ -32,7 +34,7 @@ _Рисунок 1. Структурное обозначение элемент
На рис. 1 изображен пример АЛУ, используемый в книге "Цифровая схемотехника и архитектура компьютера" Харрис и Харрис. На входы `A` и `B` поступают операнды с разрядностью _N_. На 3-битный вход `F` подается код операции. Например, если туда подать `000`, то на выходе `Y` появится результат операции огическое И_ между битами операндов `A` и `B`. Если на `F` подать `010`, то на выходе появится результат сложения. Это лишь пример, разрядность и коды могут отличаться в зависимости от количества выполняемых операций и архитектуры.
Существует несколько подходов к реализации АЛУ, отличающиеся внутренней организацией. В лабораторных работах применяется повсеместно используемый подход мультиплексирования операций, то есть подключения нескольких операционных устройств (которые выполняют какие-то операции, например сложения, логического И и т.п.) к мультиплексору, который будет передавать результат нужного операционного устройства на выходы АЛУ.
Существует несколько подходов к реализации АЛУ, отличающиеся внутренней организацией. В лабораторных работах применяется повсеместно используемый подход мультиплексирования операций, то есть подключения нескольких операционных устройств (которые выполняют какие-то операции, например сложения, логического ИЛИ и т.п.) к мультиплексору, который будет передавать результат нужного операционного устройства на выходы АЛУ.
Рассмотрим данный подход на примере все того же АЛУ MIPS из книги Харрисов. На рис. 2, в левой его части, изображена внутренняя организация этого АЛУ, справа таблица соответствия кодов операциям. На выходе схемы (внизу) стоит 4-входовой мультиплексор, управляемый двумя из трех битов `F`. К его входам подключены _N_ логических И (побитовое И _N_-битных операндов), _N_ логических ИЛИ, _N_-битный сумматор и Zero Extend устройство, дополняющее слева нулями 1-битное число до N-битного.
@@ -75,40 +77,43 @@ _Рисунок 3. Пример исполнения операции АЛУ._
Пример:
```SystemVerilog
```Verilog
module overflow #(parameter WIDTH = 32)(
input logic [WIDTH-1 : 0] a, b,
output logic overflow
output logic overflow
);
logic [WIDТН : 0] sum;
logic [WIDTH : 0] sum;
ass𝚒gn sum = a + b;
ass𝚒gn overflow = sum[WIDTH];
assign sum = a + b;
assign overflow = sum[WIDTH];
endmodule
```
_Листинг 1. Пример описания параметра в прототипе модуля._
В случае, если параметр не влияет на разрядность портов, его можно объявить в теле модуля:
```SystemVerilog
```Verilog
module toaster(
input logic [31:0] command,
output logic power
)
parameter TOASTER_EN = 32'haf3c5bd0;
assign power = command == TOASTER_EN;
endmodule
```
_Листинг 2. Пример описания параметра в теле модуля._
В случае АЛУ будет удобно использовать параметры для обозначения кодов команд. Во-первых, для того чтобы в `case` не допустить ошибок, а во-вторых чтобы можно было легко менять управляющие коды для повторного использования АЛУ в других проектах.
Сравните сами:
Сравните сами _листинги 3 и 4_:
```SystemVerilog
```Verilog
//parameter SLT = 5'b00011;
//parameter BEQ = 5'b11000;
@@ -121,28 +126,30 @@ always_comb
5'b11000: //... // никуда не годится
```
и
_Листинг 3. Пример описания модуля, использующего "магические" числа._
```SystemVerilog
```Verilog
parameter SLT = 5'b00011;
parameter BEQ = 5'b11000;
//...
аlwауs_comb
always_comb
case(ALUOp)
//...
SLT: //... // очень понятно
BEQ: //... // так лаконично и красиво
```
С параметрами гораздо взрослее, серьезнее и понятнее смотрится. Кстати, сразу на заметку: в SystemVerilog можно объединять группу параметров в **пакет** (package), а затем импортировать его внутрь модуля, позволяя переиспользовать параметры без повторного их прописывания для других модулей.
_Листинг 4. Пример описания модуля, использующего параметры._
С параметрами смотрится гораздо взрослее, серьёзнее и понятнее. Кстати, сразу на заметку: в SystemVerilog можно объединять группу параметров в **пакет** (package), а затем импортировать его внутрь модуля, позволяя переиспользовать параметры без повторного их прописывания для других модулей.
Делается это следующим образом.
Сперва создается SystemVerilog-файл, который будет содержать пакет (к примеру, содержимое файла может быть таким):
```SystemVerilog
```Verilog
package riscv_params_pkg;
parameter ISA_WIDTH = 32;
parameter ANOTHER_EX = 15;
@@ -151,16 +158,17 @@ endpackage
Далее, внутри модуля, которому нужны параметры из этого пакета, необходимо сделать соответствующий импорт этих параметров. Это можно сделать либо для каждого параметра отдельно, либо импортировать все параметры сразу:
```SystemVerilog
module riscv_processor(
```Verilog
module riscv_processor
//import riscv_params_pkg::*;
import riscv_params_pkg::ISA_WIDTH; // Если необходимо импортировать
(
//...Порты
);
import riscv_params_pkg::ISA_WIDTH; // Если необходимо импортировать
import riscv_params_pkg::ANOTHER_EX; // все параметры в пакете,эти две строчки
import riscv_params_pkg::ANOTHER_EX; // все параметры в пакете, эти две строчки
// могут быть заменены закомментированной
// ниже строкой:
//import riscv_params_pkg::*;
// выше строкой:
endmodule
```
@@ -191,14 +199,14 @@ endmodule
Необходимо на языке SystemVerilog реализовать АЛУ в соответствии со следующим прототипом:
```SystemVerilog
```Verilog
module аlu_r𝚒sсv (
𝚒nput logic [31:0] a_i,
𝚒nput logic [31:0] b_i,
𝚒nput logic [4:0] alu_op_i,
оutput logic flag_o,
оutput logic [31:0] result_o
module alu (
input logic [31:0] a_i,
input logic [31:0] b_i,
input logic [4:0] alu_op_i,
output logic flag_o,
output logic [31:0] result_o
);
import alu_opcodes_pkg::*; // импорт параметров, содержащих
@@ -271,8 +279,8 @@ _Таблица 2. Список операций сравнения._
Конструкция `$signed` говорит САПР интерпретировать число, переданное в качестве операнда, как знаковое.
```SystemVerilog
аss𝚒gn Rеsult = $s𝚒gnеd(А) >>> В[4:0];
```Verilog
assign Result = $signed(A) >>> B[4:0];
```
В этом примере некоторому сигналу `Result` присваивают результат сдвига знакового числа `A` на значение количества бит получаемых из младших 5 бит сигнала `B`.
@@ -285,9 +293,8 @@ _Рисунок 4. Пример схемы, реализующей АЛУ._
### Порядок выполнения задания
1. Добавьте в проект файл [`alu_opcodes_pkg.sv`](alu_opcodes_pkg.sv). Этот файл содержит объявление пакета `alu_opcodes_pkg`, в котором прописаны все опкоды АЛУ.
2. В `Design Sources` проекта создайте `SystemVerilog`-файл `аlu_r𝚒sсv.sv`.
3. Опишите в нем модуль АЛУ с таким же именем и портами, как указано в [задании](#задание).
1. Добавьте в `Design Sources` проекта файл [`alu_opcodes_pkg.sv`](alu_opcodes_pkg.sv). Этот файл содержит объявление пакета `alu_opcodes_pkg`, в котором прописаны все опкоды АЛУ.
2. Опишите модуль `alu` с таким же именем и портами, как указано в [задании](#задание).
1. Поскольку у вас два выходных сигнала, зависящих от сигнала `alu_op_i`, вам потребуется описать два разных [мультиплексора](../../Basic%20Verilog%20structures/Multiplexors.md) (их лучше всего описывать через два отдельных блока `case`). При описании, используйте `default` на оставшиеся комбинации сигнала `alu_op_i`.
2. Следите за разрядностью ваших сигналов.
3. Для реализации АЛУ, руководствуйтесь таблицей с операциями, а не схемой в конце задания, которая приведена в качестве референса. Обратите внимание, в одной половине операций `flag_o` должен быть равен нулю, в другой `result_o` (т.е. всегда либо один, либо другой сигнал должен быть равен нулю). Именно поэтому удобней всего будет описывать АЛУ в двух разных блоках `case`.
@@ -296,19 +303,9 @@ _Рисунок 4. Пример схемы, реализующей АЛУ._
1. При подключении сумматора, на входной бит переноса необходимо подать значение `1'b0`. Если не подать значение на входной бит переноса, результат суммы будет не определен (т.к. не определено одно из слагаемых).
2. Выходной бит переноса при подключении сумматора можно не указывать, т.к. он использоваться не будет.
6. При реализации операций сдвига, руководствуйтесь [особенностями реализации сдвигов](#особенности-реализации-сдвига).
4. После реализации модуля АЛУ его нужно будет проверить с помощью тестового окружения.
1. Добавьте файл [`tb_alu.sv`](tb_alu.sv) в `Simulation sources`.
2. Для запуска симуляции воспользуйтесь [`этой инструкцией`](../../Vivado%20Basics/Run%20Simulation.md).
3. Перед запуском симуляции убедитесь, что в качестве top-level модуля выбран модуль `tb_alu`.
4. Убедитесь, что симуляция завершена (об этом будет соответствующее сообщение в консоли). По завершению симуляции, в случае отсутствия ошибок, будет выведено сообщение "SUCCESS", в противном случае будут выведены сообщения об этих ошибках.
5. В случае, если были найдены ошибки, вы должны найти и исправить их. Для этого руководствуйтесь [документом](../../Vivado%20Basics/Debug%20manual.md).
5. Проверьте работоспособность вашей цифровой схемы в ПЛИС. Для этого:
1. Добавьте файлы из папки [`board files`](https://github.com/MPSU/APS/tree/master/Labs/02.%20Arithmetic-logic%20unit/board%20files) в проект.
1. Файл [nexys_alu.sv](https://github.com/MPSU/APS/tree/master/Labs/02.%20Arithmetic-logic%20unit/board%20files/nexys_alu.sv) необходимо добавить в `Design Sources` проекта.
2. Файл [nexys_a7_100t.xdc](https://github.com/MPSU/APS/tree/master/Labs/02.%20Arithmetic-logic%20unit/board%20files/nexys_a7_100t.xdc) необходимо добавить в `Constraints` проекта. В случае, если вы уже добавляли одноименный файл в рамках предыдущих лабораторных работ, его содержимое необходимо заменить содержимым нового файла.
2. Выберите `nexys_alu` в качестве модуля верхнего уровня (`top-level`).
3. Выполните генерацию битстрима и сконфигурируйте ПЛИС. Для этого воспользуйтесь [следующей инструкцией](../../Vivado%20Basics/How%20to%20program%20an%20fpga%20board.md).
4. Описание логики работы модуля верхнего уровня и связи периферии ПЛИС с реализованным модулем находится в папке [`board files`](https://github.com/MPSU/APS/tree/master/Labs/02.%20Arithmetic-logic%20unit/board%20files).
3. Проверьте модуль с помощью верификационного окружения, представленного в файле [`lab_02.tb_alu.sv`](lab_02.tb_alu.sv). В случае, если в TCL-консоли появились сообщения об ошибках, вам необходимо [найти](../../Vivado%20Basics/05.%20Bug%20hunting.md) и исправить их.
1. Перед запуском моделирования, убедитесь, что у вас выбран корректный модуль верхнего уровня в `Simulation Sources`.
4. Проверьте работоспособность вашей цифровой схемы в ПЛИС.
## Список использованной литературы

View File

@@ -2,7 +2,7 @@
После того, как вы проверили на моделировании АЛУ, вам необходимо проверить его работу на прототипе в ПЛИС.
Инструкция по реализации прототипа описана [здесь](../../../Vivado%20Basics/How%20to%20program%20an%20fpga%20board.md).
Инструкция по реализации прототипа описана [здесь](../../../Vivado%20Basics/07.%20Program%20and%20debug.md).
На _рис. 1_ представлена схема прототипа в ПЛИС.

View File

@@ -8,7 +8,7 @@
See https://github.com/MPSU/APS/blob/master/LICENSE file for licensing details.
* ------------------------------------------------------------------------------
*/
module tb_alu();
module lab_02_tb_alu();
import alu_opcodes_pkg::*;
@@ -28,7 +28,7 @@ wire [31:0] result_ref;
wire comparison_result_ref;
alu_riscv DUT
alu DUT
(
.alu_op_i (operator_i ),
.a_i (operand_a_i),
@@ -38,7 +38,7 @@ alu_riscv DUT
.flag_o (comparison_result_dut)
);
alu_riscv_ref REF
alu_ref REF
(
.alu_op_i (operator_i ),
.a_i (operand_a_i),
@@ -54,7 +54,6 @@ reg [8*9:1] operator_type;
initial
begin
$display("Test has been started");
$display( "\n\n==========================\nCLICK THE BUTTON 'Run All'\n==========================\n"); $stop();
//X_test();
result_test();
flag_test();
@@ -141,7 +140,7 @@ task direct_test();
logic [4:0] flag_opcodes_2[3] = {ALU_SLL, ALU_SRL, ALU_SRA};
logic [4:0] flag_opcodes_3[2] = {ALU_ADD, ALU_SUB};
logic [4:0] flag_opcodes_4[5] = {ALU_XOR, ALU_OR, ALU_AND, ALU_EQ, ALU_NE};
repeat(100)
begin
std::randomize(operand_a_i, operand_b_i) with {operand_a_i==operand_b_i;};
@@ -191,14 +190,14 @@ task direct_test();
repeat(100)
begin
std::randomize(operand_a_i) with {operand_a_i > {31{1'b1}};};
std::randomize(operand_a_i) with {operand_a_i > {31{1'b1}};};
std::randomize(operand_b_i) with {operand_b_i > {31{1'b1}};};
foreach(flag_opcodes_3[i]) begin
operator_i = flag_opcodes_3[i];
@(posedge clk);
end
end
repeat(100)
begin
operand_a_i = $urandom();
@@ -256,7 +255,7 @@ parameter HASH_LEN = 1000;
parameter START_CODING = 10366;
parameter START_MUX = START_CODING+100;
module alu_riscv_ref (
module alu_ref (
input logic [ALUOP_W-1:0] alu_op_i,
input logic [OP_W-1:0] a_i,
input logic [OP_W-1:0] b_i,