Initial commit

This commit is contained in:
Andrei Solodovnikov
2023-09-07 17:04:37 +03:00
commit f4c0960704
334 changed files with 36105 additions and 0 deletions

View File

@@ -0,0 +1,83 @@
# Список основных терминов (must know!)
Ниже приводится перечень основных терминов, понимание которых является обязательным, без чего нельзя заключить вывод о том, что акт передачи знаний студенту совершен! В противном случае, из непонимания какого-то термина следует непонимание тех разделов дисциплины, в которых на него опираются. Некоторые из них имеют критически высокий уровень значимости. К таковым, например, относятся *процессор*, *архитектура*, *система команд.* Непонимание выпускником технической специальности смысла этих слов сравнимо со врачом непонимающим, что такое иммунитет. Это неприемлемо!
Главное не заучить определения, а именно понимать смысл. Если не ошибаюсь, это сказал Эйнштейн: «если ты не можешь что-то объяснить школьнику, значит ты сам это не понимаешь». На экзамене, в беседе, мы будем проверять понимание нижеизложенного.
Отдельно подчеркну: нижеизложенное является необходимым, но недостаточным для успешной сдачи экзамена.
**Процессор** это программно-управляемое устройство, как правило, выполненное на одной интегральной схеме, осуществляющее цифровую обработку информации и управление этим процессом.
**Микроконтроллер** это устройство, конструктивно выполненное на базе одной интегральной схемы и содержащее в себе процессор, оперативное и постоянное запоминающие устройства, а также различные периферийные устройства (например: АЦП, ЦАП, контроллеры интерфейсов, таймеры, модули ШИМ и т.д.).
**Интегрированный процессор** это специализированный процессор, функциональные возможности которого отражают специфику решаемых с его помощью задач.
**Процессор цифровой обработки сигналов** (ПЦОС, Digital Signal Processor, DSP) это специализированный процессор, ориентированный на реализацию процедур, обеспечивающих преобразование аналоговых сигналов, представленных в цифровой форме.
**Инструкция** (Команда) это отдельная операция процессора, определенная системой команд и, которая, содержит в себе закодированную информацию о том, какое действие необходимо совершить и, если это требуется, над какими данными.
**Программа** это комбинация инструкций и данных, позволяющая аппаратному обеспечению вычислительной системы выполнять вычисления или функции управления.
**Слово** это определяемая архитектурой величина, измеряемая в битах или байтах и равная разрядности регистров процессора и\или шины данных.
**Арифметико-логическое устройство** (АЛУ) это устройство, предназначенное для выполнения арифметических и поразрядно-логических операций над многоразрядными словами.
**Критический путь** это самый длинный путь прохождения сигнала в комбинационной схеме (характеризует максимальное время распространения сигнала в этой комбинационной схеме: от начала изменений значений на входах, до момента, когда все выходы достигнут установившихся значений).
**Архитектура** абстрактная модель совокупности функциональных возможностей процессора.
**Микроархитектура** это структурная организация процессора, описывающая, как именно расположены и соединены друг с другом его функциональные узлы (регистры, АЛУ, конечные автоматы, блоки памяти и другие блоки, необходимые для реализации архитектуры).
**Архитектура системы команд** (Instruction Set Architecture, ISA) часть архитектуры, определяющая программируемую часть процессора, то есть средства вычислительной машины, которые видны и доступны программисту (система команд, поддерживаемые форматы данных, системы регистров, способы адресации, модели памяти и т.д.).
**Система команд** это совокупность команд (инструкций), выполнение которых на аппаратном уровне поддерживает процессор.
**Устройство управления** блок процессора, организующий последовательную выборку команд из памяти, их дешифрацию и формирование соответствующих управляющих сигналов для всех блоков процессора.
**Конвейер команд** (Вычислительный конвейер) это способ временного распараллеливания исполняемых команд, при котором выполнение команд разделяется на несколько более простых операций (называемых ступенями), под каждую из которых выделен свой блок аппаратуры и организована передача данных между ними, благодаря чему можно одновременно выполнять несколько команд на разных стадиях конвейера.
**Конфликты конвейера** это ситуации, которые препятствуют выполнению очередной команды из потока команд в предназначенном для нее такте, по причине нехватки ресурсов (структурный конфликт), зависимости от данных, получаемых в еще незавершенной команде (конфликт по данным) или из-за неопределенности какую команду загружать после команды условного перехода, до того, как истинность условия стала известной (конфликт по управлению).
**Прерывание** это автоматическое изменение хода выполнения программы (запуск подпрограммы обработчика прерывания), вызванное событием (программным или аппаратным) или совокупностью событий, возникших в некоторой части вычислительной системы.
**Вектор прерывания** адрес начала подпрограммы обработчика прерывания, который загружается в счетчик команд (Program counter) при возникновении соответствующего прерывания.
**Исключения** это нештатные ситуации, возникающие при ошибках в работе процессора, либо ошибках при работе с памятью.
**Стек** способ организации памяти, при котором слово данных, записанное последним, при считывании будет доступно первым (Last In, First Out, LIFO).
**Ассоциативная память** это способ организации памяти, при котором поиск требуемых данных происходит не по адресу местоположения в памяти, а по уникальным признакам (тегам), хранящимся вместе с соответствующими данными.
**Локальность по обращению** это понятие, отражающее закономерность обращений программ к памяти и, с высокой вероятностью, проявляющееся в повторном использовании данных, к которым недавно уже обращались (временная локальность данных), и в использовании в ближайшем будущем данных, находящихся по соседним адресам (пространственная локальность программ и данных).
**Кэш-память** память малого объема, работающая значительно быстрее основной памяти на частоте ядра процессора, и, храня в себе одновременно лишь малую часть основной памяти, призвана повысить скорость доступа к данным за счет их временной и пространственной локальности.
**Виртуальная память** это способ автоматического управления иерархической памятью, при котором для нескольких ее уровней организуется единое адресное пространство, благодаря чему можно создать для программиста видимость памяти большого объема, а перемещая данные между уровнями (согласно локальности по обращению) для большинства обращений к памяти обеспечивать скорость доступа, равную скорости более быстрых типов памяти.
**Транзакция** операция на шине.
**Шина** это группа сигнальных линий, предназначенных для выполнения определенной функции в программно-управляемом процессе передачи данных.
**Интерфейс** совокупность механических, электрических и программных средств, с помощью которых компоненты системы объединяются для решения задачи обмена информации.
**Арбитр магистрали** это устройство, контролирующее соблюдение правил предоставления общей шины одному из запросивших ее устройств, другими словами, арбитр выбирает какому устройству и на сколько время предоставить управление шиной для передачи информации, вместе с тем контролирует присутствие на общей шине строго не более одного ведущего устройства в любой момент времени.
**Совмещенное адресное пространство** это способ построения систем ввода\вывода, при котором определенная область адресов памяти отводится для адресации регистров устройств ввода\вывода.
**Выделенное адресное пространство** это способ построения систем ввода\вывода, при котором система памяти и система ввода\вывода имеют собственные, отдельные системы адресов, с изолированными, раздельными линиями адреса, в связи с чем, для управления вводом\выводом используются специальные инструкции.
**Принстонская архитектура** это способ организации памяти, при котором для хранения программ и данных используется единая (общая) память с разделенным по времени доступом (по очереди) к командам, либо данным, по общей шине процессор-память.
**Гарвардская архитектура** это способ организации памяти, при котором используют отдельную память для хранения программ, и отдельную память для данных, каждая из которых соединена с процессором собственной шиной.
**CISC** (Complex Instruction Set Computer) это архитектура с полным набором команд, изначально ориентированная на уменьшении рутины при программировании, она характеризуется наличием большого (около тысяча и более) количества разнообразных простых и сложных команд и множеством различных способов адресации операндов, благодаря чему коды инструкций имеют переменную длину, а в качестве операндов могут использоваться ячейки основной памяти.
**RISC** (Reduced Instruction Set Computer) это архитектура с сокращенным набором команд, которая ориентирована на простоту реализации, из-за чего поддерживает, в основном, не более сотни команд, кодируемых словами фиксированной длины, и использующей всего несколько способов адресации операндов, но выполнять операции можно только с данными из регистрового файла, в связи с чем необходимо применять специальные команды пересылки данных между основной памятью и процессором.
**VLIW** (Very Long Instruction Word) это архитектура со сверхдлинным командным словом, характеризующаяся увеличенным количеством исполнительных устройств, а сверхдлинная команда, является, по сути, склейкой нескольких выполняющихся одновременно RISC-инструкций, каждая из которых управляет определенным исполнительным устройством, что предоставляет программисту все возможности параллельной обработки.
**Скалярный процессор** это процессор, в каждый момент времени осуществляющий работу только над одной порцией данных.
**Суперскалярный процессор** это процессор, который одновременно выполняет более чем одну скалярную команду.
**Суперскалярная архитектура** это архитектура с увеличенным количеством исполнительных устройств, в которой параллельная обработка достигается за счет выборки сразу нескольких инструкций за раз, динамически распределяя между исполнительными устройствами с целью их максимальной загрузки.

149
Other/FAQ.md Normal file
View File

@@ -0,0 +1,149 @@
# Список типичных ошибок при работе с Vivado и Verilog
## Содержание
1. [Ошибки, связанные с САПР Vivado](#ошибки-связанные-с-сапр-vivado)
1.1 [Не запускается симуляция: FATAL_ERROR: PrivateChannel: Error creating client socket](#не-запускается-симуляция-fatal_error-privatechannel-error-creating-client-socket)
1.2 [Не запускается симуляция: boot::filesystem::remove: Процесс не может получить доступ к файлу, т.к. этот файл занят другим процессом](#не-запускается-симуляция-boot-filesystem-remove-процесс-не-может-получить-доступ-к-файлу)
1.3 [Вылетает Vivado при попытке открыть схему](#вылетает-vivado-при-попытке-открыть-схему)
1.4 [Не устанавливается Vivado: The following fatal error encountered while installing files: Unable to open archive](#не-устанавливается-vivado-unable-to-open-archive)
2. [Ошибки синтаксиса языка Verilog](#ошибки-синтаксиса-языка-verilog)
2.1 [concurrent assignment to a non-net is not permitted](#concurrent-assignment-to-a-non-net-is-not-permitted)
2.2 [procedural assignment to a non-register test is not permitted, left-hand side should be reg/integer/time/genvar](#procedural-assignment-to-a-non-register-test-is-not-permitted-left-hand-side-should-be-reg)
2.3 ['имя сигнала' is not a type](#имя-сигнала-is-not-a-type)
2.4 [cannot find port on this module](#cannot-find-port-on-this-module)
## Ошибки связанные с САПР Vivado
### Не запускается симуляция FATAL_ERROR PrivateChannel Error creating client socket
**Причина:** ошибка [связана с проблемами Win Sockets](https://support.xilinx.com/s/question/0D52E00006iI37SSAS/isim-124-m81d-fatal-error-privatechannel-error-creating-client-socket?language=en_US), из-за которых симуляция не может быть запущена на сетевых дисках.
**Способ воспроизведения ошибки:** создать проект на сетевом диске.
**Решение:** Скорее всего, вы создали проект на диске `H:/`. Создайте проект на локальном диске (например, на рабочем столе диске `C:/`)
---
### Не запускается симуляция boot filesystem remove Процесс не может получить доступ к файлу
<details>
<summary>Скриншот ошибки:</summary>
![../.pic/Other/FAQ/boot_filesystem_remove.png](../.pic/Other/FAQ/boot_filesystem_remove.png)
</details>
**Причина:** вы запустили симуляцию с другим `top level`-модулем, не закрыв предыдущую симуляцию.
Скорее всего, после создания тестбенча, вы слишком быстро запустили первую симуляцию. Из-за этого, Vivado не успел обновить иерархию модулей и сделать тестбенч `top-level`-модулем. На запущенной симуляции все сигналы находились в Z и X состояниях, после чего вы попробовали запустить ее снова. К моменту повторного запуска иерархия модулей обновилась, сменился `top-level`, что и привело к ошибке.
**Способ воспроизведения ошибки:** запустить симуляцию, создать новый файл симуляции, сделать его `top-level`-модулем, запустить симуляцию.
**Решение:** Закройте предыдущую симуляцию (правой кнопкой мыши по кнопки SIMULATION -> Close Simulation) затем запустите новую.
<details>
<summary>Иллюстрация закрытия симуляции:</summary>
![../.pic/Other/FAQ/close_sim.png](../.pic/Other/FAQ/close_sim.png)
</details>
---
### Вылетает Vivado при попытке открыть схему
**Причина:** кириллические символы (русские буквы) в пути рабочей папки Vivado. Скорее всего, причина в кириллице в имени пользователя (**НЕ В ПУТИ УСТАНОВКИ VIVADO**).
**Способ воспроизведения ошибки:** (см. решение, только для воспроизведение необходимо сделать обратно, дать папке имя с кириллицей)
**Решение:** Чтобы не создавать нового пользователя без кириллицы в имени, проще назначить Vivado новую рабочую папку.
Для этого:
1. Создайте в корне диска `C:/` какую-нибудь папку (например Vivado_temp).
2. Откройте свойства ярлыка Vivado (правой кнопкой мыши по ярлыку -> свойства)
2.1 Если у вас нет ярлыка Vivado на рабочем столе, вместо этого вы запускаете его из меню пуск, кликните в меню пуск правой кнопкой мыши по значку Vivado -> открыть расположение файла. Если там будет ярлык выполните пункт 2, если там будет исполняемый файл — создайте ярлык для этого файла (правой кнопкой мыши по файлу -> создать ярлык) и выполните пункт 2.
3. В поле "Рабочая папка", укажите путь до созданной вами директории (в примере пункта 1 этот путь будет: `C:/Vivado_temp`). Нажмите "ОК".
---
### Не устанавливается Vivado Unable to open archive
<details>
<summary>Иллюстрация:</summary>
![../.pic/Other/FAQ/unable_to_open_archive.jpg](../.pic/Other/FAQ/unable_to_open_archive.jpg)
</details>
**Причина:** Скорее всего, проблема в том, что файлы установки (**НЕ ПУТЬ УСТАНОВКИ VIVADO**) расположены по пути с кириллическими символами (например, в какой-то личной папке "Загрузки").
**Решение:** Переместите файлы установки в директорию, не содержащую кириллицу в пути.
---
## Ошибки синтаксиса языка Verilog
### concurrent assignment to a non-net is not permitted
Запрещено выполнять непрерывное присваивание (`assign`) к объектам, не являющимися цепями. Скорее всего, вы пытались выполнить `assign b = a;`, где `b` является регистром.
```Verilog
module alu(input a, input b,
input [3:0] alu_op,
output reg flag,
output reg result
);
assign flag = alu_op[3] ? (a > b) : 1'b0; // ошибка
endmodule
```
---
### procedural assignment to a non-register test is not permitted left-hand side should be reg
Запрещено использовать процедурное присваивание (присваивание в блоке `always` или `initial`) объектам, не являющимися регистрами. Скорее всего, вы пытались выполнить `b = a;` или `b <= a;` блоке `always`/`initial`, где `b` является проводом.
```Verilog
module adder(input a, input b, output c);
always @(*) begin
c = a ^ b; // ошибка, процедурное присваивание
// к проводам запрещено
end
endmodule
```
---
### имя сигнала is not a type
Скорее всего, компилятор не распознал присваивание, поскольку оно было записано с ошибками. Вне блоков `always` и `initial` можно выполнять только непрерывное присваивание (через `assign`).
```Verilog
module adder(input a, input b, output c);
c = a ^ b; // ошибка, для непрерывного присваивания
// необходимо ключевое слово assign
endmodule
```
---
### cannot find port on this module
Имя порта, указанного при подключении модуля (после точки) не соответствует ни одному имени сигналов подключаемого модуля
Пример
```Verilog
module adder(input a, input b, output c);
assign c = a ^ b;
endmodule
module testbench();
reg A, B;
wire C;
adder DUT(
.A(A), // <- здесь будет ошибка,
// т.к. в модуле adder нет порта 'A'
.b(B),
.c(C)
);
endmodule
```

45
Other/Students server.md Normal file
View File

@@ -0,0 +1,45 @@
# Учебный сервер для студентов
Данный сервер поднят для выполнения студентами их [индивидуального задания](../Labs/04.%20Primitive%20programmable%20device#индивидуальные-задания), а так же для тех студентов, кому не хватило места в учебной аудитории. На сервере установлены: `Vivado`, `VSCode`, `gcc`, `git`. Поскольку сервер имеет ограниченные ресурсы, а студенты не имеют привычки закрывать за собой программы при завершении сессии, тут не установлен браузер. Имейте в виду, что если вы закрыли сессию, не закрыв Vivado и там остались несохраненные файлы, то вы рискуете потерять свои изменения.
## Порядок подключения к серверу
За каждым студентом закреплена учетная запись на сервере и выданы её логин/пароль.
Подключение осуществляется из миэтовской сети. Это значит, что для подключения нужно либо подключиться к общажной сети (которая является частью миэтовской), либо воспользоваться [миэтовским vpn](https://vpn.miet.ru/).
Для подключения, необходимо скачать и установить программу [`X2Go client`](http://code.x2go.org/releases/X2GoClient_latest_mswin32-setup.exe). Во время установки можно оставить все опции без изменений.
При первом запуске, появится окно настройки подключения (если окно не появилось, нажмите `Ctrl+N`). Вам необходимо заполнить поля:
- Хост (вводим `82.179.178.13`)
- Пользователь (ввводим логин с листочка)
- SSH порт (вводим `2222`)
- Тип сессии (выбираем `XFCE`)
Опционально можно настроить `имя сессии` и её `значок`.
<details>
<summary>Пример заполненных настроек</summary>
![../.pic/Other/Students%20server/x2goclient_config.png](../.pic/Other/Students%20server/x2goclient_config.png)
</details>
После создания сессии, она отобразится в правой части программы. Двойной клик по сессии создаст подключение, в процессе которого от вас потребуется ввести пароль от выданной вам учетной записи.
## Как работать на сервере
Запуск `Vivado` осуществляется двумя путями: через `Applications->Development->Vivado`, либо через запуск команды `vivado` в терминале.
Для копирования своего проекта на сервер можно воспользоваться несколькими путями: клонирование репозитория посредством git, использование утилиты scp, однако для простоты инструкции будет предложено воспользоваться программой с графическим интерфейсом `WinSCP`.
WinSCP — это программа для Windows с графическим интерфейсом, реализующая передачу файлов между компьютерами поверх инструмента scp (secure copy).
Руководство по установке и запуску схоже с установкой X2Go:
1. Необходимо [скачать](https://winscp.net/eng/downloads.php) и установить программу (при установке можно выбрать рекомендованные настройки, можно их кастомизировать под себя).
2. При запуске вам предложат ввести данные для подключения. Заполняете поля аналогично тому, как вы делали для X2Go. Выпадающий список `File Protocol` можете оставить без изменений.
3. В данной программе вы можете сохранить так же и пароль. Вообще говоря это не безопасно и так делать обычно не рекомендуется.
4. Через `Advanced...->Advanced->Directories->Local Directory`, можно настроить папку на вашем компьютере с данными в которой вы сможете взаимодействовать через WinSCP.
5. Интерфейс перемещения данных предельно интуитивен: файлы и папки можно перетаскивать, копировать и вставлять, скачивать и загружать, удалять, перемещать и переименовывать. Делайте как вам удобно. В процессе могут появляться подтверждающие всплывающие окна.

141
Other/Teachers.md Normal file
View File

@@ -0,0 +1,141 @@
# Преподаватели АПС 2022
## Распределение по группам
| Группа | Расписание лаб | Лектор | Преподаватель | Ассистент |
|------------|------------------------------|---------------------------------------------|---------------------------------------------|-------------------------------------------|
| **ИБ-31** |Ср. 09:0012:10 — Числитель-II|[Силантьев](#силантьев-александр-михайлович) |[Солодовников](#солодовников-андрей-павлович)|[Демидов](#демидов-александр-александрович)|
| **ИВТ-31** |Пн. 10:40-13:50 — Знаменатель |[Орлов](#орлов-александр-николаевич) |[Солодовников](#солодовников-андрей-павлович)|[Демичев](#демичев-сергей-сергеевич) |
| **ИВТ-32** |Пн. 14:30-17:40 — Числитель |[Орлов](#орлов-александр-николаевич) |[Орлов](#орлов-александр-николаевич) | |
| **ИВТ-33** |Вт. 14:30-17:40 — Числитель |[Орлов](#орлов-александр-николаевич) |[Хисамов](#хисамов-василь-тагирович) |[Замтарадзе](#замтарадзе-артём-раульевич) |
| **ИКТ-31** |Чт. 14:30-17:40 — Числитель-I |[Силантьев](#силантьев-александр-михайлович) |[Хисамов](#хисамов-василь-тагирович) |[Замтарадзе](#замтарадзе-артём-раульевич) |
| **ИКТ-32** |Чт. 14:30-17:40 — Числитель-II|[Силантьев](#силантьев-александр-михайлович) |[Хисамов](#хисамов-василь-тагирович) |[Замтарадзе](#замтарадзе-артём-раульевич) |
| **ИКТ-33** |Пт. 16:1019:20 — Числитель-I |[Силантьев](#силантьев-александр-михайлович) |[Солодовников](#солодовников-андрей-павлович)|[Демидов](#демидов-александр-александрович)|
| **КТ-31** |Вт. 09:0012:10 — Знаменатель |[Силантьев](#силантьев-александр-михайлович) |[Солодовников](#солодовников-андрей-павлович)|[Чусов](#чусов-сергей-андреевич) |
| **ПИН-35** |Пн. 14:30-17:40 — Знаменатель |[Орлов](#орлов-александр-николаевич) |[Солодовников](#солодовников-андрей-павлович)|[Демичев](#демичев-сергей-сергеевич) |
| **ПМ-31** |Вт. 12:5016:00 — Знаменатель |[Орлов](#орлов-александр-николаевич) |[Солодовников](#солодовников-андрей-павлович)|[Чусов](#чусов-сергей-андреевич) |
| **РТ-32** |Чт. 09:0012:10 — Числитель |[Силантьев](#силантьев-александр-михайлович) |[Хисамов](#хисамов-василь-тагирович) |[Замтарадзе](#замтарадзе-артём-раульевич) |
| **РТ-33** |Чт. 09:0012:10 — Знаменатель |[Силантьев](#силантьев-александр-михайлович) |[Орлов](#орлов-александр-николаевич) | |
## Преподаватели
<!-- ### Барков Евгений Сергеевич
![](../.pic/Other/Teachers/barkov.jpg)
Магистр НИУ МИЭТ, инженер-электроник в НИИ ВСиСУ
***telegram***: [`@barkove`](http://t.me/barkove)
--- -->
### Орлов Александр Николаевич
![](../.pic/Other/Teachers/orlov.jpg)
Старший преподаватель, инженер-электроник в НИИ ВСиСУ
---
<!-- ### Рыжкова Дарья Васильевна
![](../.pic/Other/Teachers/rygkova.jpg)
Магистр НИУ МИЭТ, инженер-электроник в НИИ ВСиСУ
***telegram***: [`@frarrr`](http://t.me/frarrr)
--- -->
### Силантьев Александр Михайлович
![](../.pic/Other/Teachers/silantiev.jpg)
Старший преподаватель Института МПСУ, инженер-электроник в НИИ ВСиСУ, руководитель группы
***telegram***: [`@sam_sil`](http://t.me/sam_sil)
***Консультации***: пока не определено
---
### Солодовников Андрей Павлович
![](../.pic/Other/Teachers/solodovnikov.jpg)
Аспирант НИУ МИЭТ, инженер-электроник в НИИ ВСиСУ
***telegram***: [`@HepoH`](http://t.me/HepoH)
***Консультации***:
| День | Неделя | Время | Аудитория |
|------ |------------ |-----------|-----------|
|Четверг|Знаменатель-II|18:20-19:50| 4328 |
|Пятница|Числитель-II |18:20-19:50| 4338 |
---
### Хисамов Василь Тагирович
---
![](../.pic/Other/Teachers/hisamov.jpg)
Старший преподаватель Института МПСУ, инженер-электроник в НИИ ВСиСУ
***telegram***: [`@PascalVT`](http://t.me/PascalVT)
***e-mail***: Xisamoffvasil[*собака*]mail.ru
***Консультации***: пока не определено
### Чусов Сергей Андреевич
![](../.pic/Other/Teachers/chusov.jpg)
Аспирант НИУ МИЭТ, инженер-электроник в НИИ ВСиСУ
***telegram***: [`@srg_chs`](http://t.me/srg_chs)
---
## Ассистенты
### Замтарадзе Артём Раульевич
![](../.pic/Other/Teachers/zamtaradze.jpg)
Магистрант ИВТ (IoT), инженер в НПК ТЦ,
***telegram***: [`@gad_dam`](http://t.me/gad_dam)
Почта: artyomzamtaradze[*собака*]yandex.ru
---
### Демидов Александр Александрович
![](../.pic/Other/Teachers/demidov.jpg)
Магистрант ИВТ
***telegram***: [`@AlexBee4`](http://t.me/AlexBee4)
---
### Демичев Сергей Сергеевич
![](../.pic/Other/Teachers/demichev.jpg)
Магистрант ИВТ
***telegram***: [`@darthajFox`](http://t.me/darthajFox)
---

View File

@@ -0,0 +1,82 @@
# Руководство по интеграции Icarus Verilog в VSCode
Данное руководство позволяет интегрировать бесплатный Verilog-симулятор с редактором VSCode. После выполнения всех этапов, будет возможно запускать симуляцию прямо из редактора, а затем просматривать временную диаграмму (в ограниченном режиме, об этом ниже).
Пример использования:
![../.pic/Other/VSCode%20Verilog%20Simulation/icarus_verilog_integration.png](../.pic/Other/VSCode%20Verilog%20Simulation/icarus_verilog_integration.png)
Для получения данного результата, необходимо выполнить следующие шаги:
## Установка ПО
1. Скачать и установить [Icarus Verilog](https://bleyer.org/icarus/) (при установке убедитесь, что стоят галочки `Install GTKWave (x64)`, `Add executable folder(s) to the user PATH`)
2. Скачать, установить и запустить [Visual Studio Code](https://code.visualstudio.com/Download)
3. После запуска VSCode, необходимо перейти на вкладку "Расширения" (можно открыть через `Ctrl+Shift+X`)
4. Устанавливаем следующие расширения:
1. `Verilog-HDL/SystemVerilog/Bluespec SystemVerilog support for VS Code`
2. `Verilog Testbench Runner`
3. `WaveTrace`
Расширение `Bluespec SystemVerilog support for VS Code` добавляет подсветку синтаксиса языка Verilog.
Расширение `Verilog Testbench Runner` добавляет на панель Verilog-файла кнопку `▶`, позволяющую запустить симуляцию без вызова команд `Icarus Verilog` в терминале.
Расширение `WaveTrace` позволяет просматривать временные диаграммы прямо в VSCode.
На этом все настройки завершены.
## Изменение Verilog-файлов
Для того, чтобы при компиляции тестбенча, подхватывались файлы описанных модулей, необходимо в самый верх тестбенча дописать директиву (см. пример использования, 1):
```Verilog
`include "имя файла, содержащего тестируемый модуль"
```
А внутрь модуля `testbench` необходимо добавить блок:
```Verilog
initial begin
$dumpfile("tb.vcd");
$dumpvars(0, fulladder32_tb); // fulladder32_tb <- имя модуля тестбенча
end
```
(см. пример использования, 2)
---
Кроме того, необходимо убедиться, что в модуле тестбенча нет системных функций: `$stop` (проверьте через поиск, если есть — удалите). Если в процессе симуляции произойдет вызов этой системной функции, её не удастся продолжить (в отличие от Vivado).
---
После этого нажимаем на зеленую кнопку `▶` (пример использования, 3), в логе будут либо сообщения об ошибках компиляции, либо результатах симуляции (пример использования, 4).
Если симуляция будет завершена успешно, в подпапке build появится файл с расширением `.vcd` (пример использования, 5). При открытии этого файла, появится вкладка расширения `WaveTrace` (вкладку можно расположить в соседней панели, перетянув ее).
Чтобы увидеть временную диаграмму, необходимо добавить отображаемые сигналы (пример использования, 6). Ограничение бесплатной версии `WaveTrace` заключается в том, что можно отобразить изменения только восьми сигналов одновременно (если понадобятся еще сигналы, придется сперва удалить какие-то предыдущие).
После всех этих действий вы сможете увидеть временную диаграмму (пример использования, 7).
## Как запустить симуляцию с предоставленными мне файлами?
Если вы пропустили, или не сделали какую-то из лаб, вам потребуется взять готовые модули из ветки [Я-не-смог](https://github.com/MPSU/APS/tree/%D0%AF-%D0%BD%D0%B5-%D1%81%D0%BC%D0%BE%D0%B3). Модули в этих ветках являются нетлистами (описанием модуля на языке Verilog, полученным [после этапа синтеза](../Vivado%20Basics/Implementation%20steps.md)).
Для того, чтобы симулятор Icarus Verilog мог работать с этим файлом, необходимо предоставить ему библиотеку примитивов из которых был собран нетлист. Для этого, необходимо выполнить следующие шаги:
1. [Скачать](../../Я-не-смог/unisims.zip) библиотеку примитивов.
2. Распаковать её в папку вашего проекта.
3. Добавить еще одну директиву `ˋinclude` в тестбенч: `ˋinclude "glbl.v"`
4. Добавить в настройки расширения `Verilog Testbench Runner` указание использовать библиотеку `unisims`. Для этого:
1. Откройте `Файл->Настройки->Параметры` (`File->Preferences->Settings`).
2. В поле поиска введите: `verilog.icarusCompileArguments`.
3. В поле найденной опции введите `-y unisims/`.
### Что делать, если мне нужно отобразить больше, чем 8 сигналов?
В этом случае, необходимо воспользоваться внешней программой по отображению временных диаграмм: `GTK Wave`. Она должна была быть установлена вами на этапе установке `Icarus Verilog` (см. [Установка ПО](#установка-по)).
В теории, после завершения симуляции, расширение `Verilog Testbench Runner`
должно предлагать запустить GTK Wave. Если этого не происходит, выполните команду в терминале VSCode:
```bash
gtkwave build/tb.vcd
```
где `tb.vcd` имя временной диаграммы, которое вы указали в блоке `initial` (см. [Изменение Verilog-файлов](#изменение-verilog-файлов)).
Откроется окно GTK Wave. Внутри этого окна, слева, есть вкладка `SST`, где будет расположен модуль вашего тестбенча. Нажав на кнопку `+` слева от имени модуля вы увидите объект `DUT` (имя сущности тестируемого модуля). Если нажать по этому объекту `ПКМ -> Recurse Import -> Append`, вы добавите все внутренние сигналы этого модуля в область просмотра временной диаграммы.

187
Other/rv32i.md Normal file
View File

@@ -0,0 +1,187 @@
# RV32I - Стандартный набор целочисленных инструкций RISC-V
Разделы статьи:
- [Краткая справка по RISC-V и RV32I](#краткая-справка-по-risc-v-и-rv32i)
- [RV32I](#rv32i)
- [Псевдоинструкции](#псевдоинструкции)
- [Переведенные фрагменты спецификации RISC-V](#переведенные-фрагменты-спецификации-risc-v)
## Краткая справка по RISC-V и RV32I
RISC-V — открытая и свободная система набора команд (ISA) на основе концепции RISC. Чтобы понять архитектуру любого компьютера, нужно в первую очередь выучить его язык, понять, что он умеет делать. Слова в языке компьютера называются «инструкциями», или «командами», а словарный запас компьютера «системой команд».
В архитектуре RISC-V имеется обязательный для реализации минимальный список команд набор инструкций **I** (Integer). В этот набор входят различные логические и арифметические операции с целыми числами, работа с памятью, и команды управления. Этого достаточно для обеспечения поддержки компиляторов, ассемблеров, компоновщиков и операционных систем (с дополнительными привилегированными инструкциями). Плюс, таким образом обеспечивается удобный "скелет" ISA и программного инструментария, вокруг которого могут быть построены более специализированные ISA процессоров путем добавления дополнительных инструкций.
Строго говоря RISC-V - это семейство родственных ISA, из которых в настоящее время существует четыре базовые ISA. Каждый базовый целочисленный набор инструкций характеризуется `шириной целочисленных регистров` и соответствующим `размером адресного пространства`, а также `количеством целочисленных регистров`. Существует два основных базовых целочисленных варианта, `RV32I` и `RV64I`, которые, соответственно, обеспечивают 32- или 64-битное адресное пространство и соответствующие размеры регистров регистрового файла. На основе базового набора инструкций `RV32I` существует вариант подмножества `RV32E`, который был добавлен для поддержки небольших микроконтроллеров и имеет вдвое меньшее количество целочисленных регистров 16, вместо 32. Разрабатывается вариант `RV128I` базового целочисленного набора инструкций, поддерживающий плоское 128-битное адресное пространство. Также, стоит подчеркнуть, что размеры регистров и адресного пространства, во всех перечисленных стандартных наборах инструкций, не влияют на размер инструкций во всех случаях они кодируются 32-битными числами. То есть, и для `RV32I`, и для `RV64I` одна инструкция будет кодироваться 32 битами. Базовые целочисленные наборы команд используют представление знаковых целых чисел в дополнительном коде.
В рамках дисциплины АПС затрагивается только `RV32I`, то есть стандартный набор целочисленных инструкций, предусматривающий в процессоре регистровый файл из 32-х 32-битных регистров, и использующий 32-битное адресное пространство памяти.
Кроме обязательного подмножества целочисленных инструкций, RISC-V предусматривает несколько стандартных опциональных расширений. Вот некоторые из них:
- **M** — Целочисленное умножение и деление (Integer Multiplication and Division)
- **A** — Атомарные операции (Atomic Instructions), инструкции для атомарного чтения-изменения-записи в память для межпроцессорной синхронизации
- **F** — Стандартное расширение для арифметических операций с плавающей точкой одинарной точности (Single-Precision Floating-Point) добавляет регистры с плавающей точкой, инструкции вычислений с одинарной точностью, а также инструкции загрузки и сохранения в регистровый файл для чисел с плавающей точкой
- **D** — Стандартное расширение с плавающей точкой двойной точности (Double-Precision Floating-Point) расширяет регистры с плавающей точкой до 64 бит и добавляет инструкции вычислений с двойной точностью, загрузку и сохранение
- **C** — Набор сжатых инструкций (Compressed Instructions), позволяющий кодировать инструкции 16-битными словами, что позволяет уплотнить программный код (если одну и ту же программу можно писать 16-битными словами вместо 32-битных, значит её размер сократится в 2 раза). Разумеется у такого уплотнения есть своя цена, иначе инструкции просто кодировали бы 16-ю битами вместо 32. У сжатых инструкций меньший диапазон адресов и констант.
- **Zicsr** — Инструкции для работы с контрольными и статусными регистрами (Control and Status Register (CSR) Instructions). Используется, например, при работе с прерываниями/исключениями и виртуальной памятью
- **Zifencei** — Инструкции синхронизации потоков команд и данных (Instruction-Fetch Fence)
Поддерживаемые процессором команды отражаются в названии набора инструкций. Например, `RV64IMC` это архитектура RISC-V с 64-битными регистрами и 64-битным адресным пространством, поддерживающая кроме стандартных целочисленных операций умножение и деление **M**, и может выполнять сжатые инструкции **C**.
Одной из целей проекта RISC-V является его использование в качестве стабильного объекта для разработки программного обеспечения. Для этого ее разработчики определили комбинацию базового ISA (`RV32I` или `RV64I`) и некоторых стандартных расширений (**IMAFD + Zicsr + Zifencei**) как "general-purpose" ISA (набор инструкций общего назначения), а для комбинации расширений набора команд **IMAFDZicsrZifencei** стали использовать аббревиатуру **G**. То есть `RV32G` это тоже самое, что и `RV32IMAFDZicsrZifencei`.
> Чтобы устройство управления понимало когда оно имеет дело с набором сжатых команд **C**, то есть с 16-битными инструкциями, а когда с другими наборами команд, то есть с инструкциями длиной 32 бита, каждая 32-битная инструкция в младших битах имеет `11`. Если в двух младших битах что-то отличное от `11`, значит это 16-битная инструкция!
На рисунке ниже показана видимая пользователю структура для основного подмножества команд для целочисленных вычислений `RV32I`. Она содержит `регистровый файл`, состоящий из 31 регистра общего назначения **x1** **x31**, каждый из которых может содержать целочисленное значение, и регистра **x0**, жестко привязанного к константе 0. В случае `RV32`, регистры **xN**, и вообще все регистры, имеют длину в 32 бита. Также есть `АЛУ`, выполняющее операции над данными в регистровом файле (концепция RISC - load&store), и `память` с побайтовой адресацией и шириной адреса 32 бита.
Также существует еще один дополнительный видимый пользователю регистр: счетчик команд `pc` (program counter), который содержит адрес текущей инструкции. `pc` изменяется либо автоматически, указывая на следующую инструкцию, либо в результате использования инструкций управления (операции условного и безусловного переходов).
![../.pic/Labs/rv_model.png](../.pic/Labs/rv_model.png)
RISC-V является load&store архитектурой (все операции с числами выполняются над данными только в регистровом файле), поэтому глядя на рисунок выше можно легко заключить, что функционально все инструкции сводятся к трём типам:
- Операции на АЛУ над числами в регистровом файле
- Операции обмена данными между регистровым файлом и памятью
- Манипуляции с `pc` (другими словами управление программой)
Как было сказано ранее, память имеет 32-битную шину адреса и имеет побайтовую адресацию. Это значит, что каждый из 2<sup>32</sup> байт памяти имеет свой уникальный адрес, по которому к нему можно обратиться, чтобы считать из него или записать в него новую информацию. Однако, инструкции кодируются 32-битными числами, а один байт это всего 8 бит, значит одна инструкция занимает сразу 4 адреса в памяти. Подразумевается, что из такой памяти можно читать одновременно из нескольких последовательных адресов, то есть устройство управления процессора сообщает памяти начальный адрес требуемой ячейки, и количество ячеек (одну, две или четыре), которые нужно прочитать или записать.
Одна ячейка называется `байт` - 8 бит. Две последовательные 8-битные ячейки называются `полуслово` - 16 бит. Четыре последовательные 8-битные ячейки называются `словом` - 32 бита. Например, если процессор собирается выполнить инструкцию, которая занимает четыре байта по адресам `0x00000007 0x00000004`, то он обращается к памяти, сообщая, что "нужны 4 байта начиная с адреса 0x00000004", взамен процессор получает 32-битное число инструкцию, которая была слеплена из байт, хранящихся в памяти по адресам: 4, 5, 6 и 7, для данного примера. К памяти также можно обратиться за полусловом или за байтом. Предполагается реализация выровненного доступа к памяти, то есть адреса слов и полуслов должны быть кратны 4 и 2, соответственно.
Аппаратное обеспечение компьютера «понимает» только нули и единицы, поэтому инструкции закодированы двоичными числами в формате, который называется машинным языком.
Инструкция компьютера кодирует в себе операцию, которую нужно исполнить, и данные, которые ей для этого потребуются. Такими данными могут быть адреса операндов и результата, различные константы.
В архитектуре RISC-V каждая несжатая инструкция представлена 32-разрядным словом. Микропроцессоры это цифровые системы, которые читают и выполняют команды машинного языка. Для людей чтение и разработка компьютерных программ на машинном языке представляются нудным и утомительным делом, поэтому мы предпочитаем представлять инструкции в символическом формате, который называется языком ассемблера. Ассемблер позволяет выполнить взаимооднозначный переход от машинного кода к тестовому и обратно.
## RV32I
В таблице ниже приводятся 40 команд стандартного набора целочисленных инструкций `RV32I`: мнемоники языка ассемблера, функции, описания, форматы кодирования и значения соответствующих полей при кодировании. В RISC-V предусмотрено несколько форматов кодирования инструкций (следующий рисунок, еще ниже), то есть договоренность какая информация в каком месте 32-битной инструкции хранится и как она представлена. У всех операций есть поле `opcode` (operation code - код операции), в котором закодировано "что нужно сделать". По полю `opcode` устройство управления понимает что требуется сделать процессору и каким именно способом закодирована инструкция (**R**, **I**, **S**, **B**, **U** или **J**). В 32-битных инструкциях два младших бита всегда равны `11`.
Почти все инструкции имеют поле `Func3`, и некоторые поле `Func7`. Их названия определены их разрядностью: 3 и 7 бит, соответственно. В этих полях, если они есть у инструкции, закодировано уточнение операции. Например, код операции 0010011 указывает на то, что будет выполняться некоторая операция на АЛУ между значением из регистрового файла и константой. Поле `Func3` уточняет операцию, для данного примера, если оно будет равно 0x0, то АЛУ выполнит операцию сложения между значением из регистра и константой из инструкции. Если `Func3` равно 0x6, то логическое ИЛИ.
![../.pic/Labs/lab_05_decoder/rv32i_summary.png](../.pic/Labs/lab_05_decoder/rv32i_summary.png)
На рисунке ниже приводится фрагмент из [`оригинальной спецификации RISC-V`](https://github.com/riscv/riscv-isa-manual/releases/download/Ratified-IMAFDQC/riscv-spec-20191213.pdf). Сверху приводятся 6 форматов кодирования инструкций: **R**, **I**, **S**, **B**, **U** и **J**, а ниже приводятся конкретные значения полей внутри инструкции. Под `rd` подразумевается 5-битный адрес регистра назначения, `rs1` и `rs2` - 5-битные адреса регистров источников, `imm` — константа, расположение и порядок битов которой указывается в квадратных скобках. Обратите внимание, что в разных форматах кодирования константы имеют различную разрядность, а их биты упакованы по-разному. Для знаковых операций константу предварительно знаково расширяют до 32 бит. Для беззнаковых расширяют нулями до 32 бит.
Обратите внимание на операции `slli`, `srli` и `srai`, это операции сдвига на константную величину. У этих инструкций немного измененный формат кодирования **I\***. Формат кодирования **I** предоставляет 12-битную константу. Сдвиг 32-битного числа более, чем на 31 не имеет смысла. Для кодирования числа 31 требуется всего 5 бит. Выходит, что из 12 бит константы используется только 5 бит для операции сдвига, а оставшиеся 7 бит – не используются. А, главное (какое совпадение!), эти 7 бит находятся ровно в том же месте, где у других инструкций находится поле `Func7`. Поэтому, чтобы у инструкций `slli`, `srli` и `srai` использующих формат **I** не пропадала эта часть поля, к ней относятся как к полю `Func7`.
![../.pic/Labs/lab_05_decoder/rv32i_BIS.png](../.pic/Labs/lab_05_decoder/rv32i_BIS.png)
Ниже, для наглядности, приводится пример кодирования пары инструкций из книги Харриса и Харриса "Цифровая схемотехника и архитектура компьютера" из ассемблерных инструкций в 16-ричные цифры.
![../.pic/Other/rv32i/example_instr_code.png](../.pic/Other/rv32i/example_instr_code.png)
Примечание: `s2`, `s3`, `s4`, `to`, `t1`, `t2` — это синонимы регистров `x18`,`x19`,`x20`,`x5`,`x6`,`x7` соответственно. Введены **соглашением о вызовах** (calling convention) для того, чтобы стандартизировать функциональное назначение регистров. Подробнее об этом будет в лабораторной работе по программированию.
## Псевдоинструкции
В архитектуре RISC-V размер команд и сложность аппаратного обеспечения минимизированы путем использования лишь небольшого количества команд. Тем не менее RISC-V определяет псевдокоманды, которые на самом деле не являются частью набора команд, но часто используются программистами и компиляторами. При преобразовании в машинный код псевдокоманды транслируются в одну или несколько команд RISC-V. Например, псевдокоманда безусловного перехода `j`, преобразуется в инструкцию безусловного перехода с возвратом `jal` с регистром `x0` в качестве регистра-назначения, то есть адрес возврата не сохраняется.
![../.pic/Other/rv32i/pseudo.png](../.pic/Other/rv32i/pseudo.png)
## Переведенные фрагменты спецификации RISC-V
Далее приводится переведенный фрагмент второй главы [`оригинальной спецификации RISC-V`](https://github.com/riscv/riscv-isa-manual/releases/download/Ratified-IMAFDQC/riscv-spec-20191213.pdf).
### Основные типы команд
В основе ISA лежит четыре основных типа команд (R/I/S/U), которые изображены на рисунке ниже. Все они имеют фиксированную длину в 32 бита и должны быть выровнены в памяти по четырехбайтовой границе. Если адрес перехода (в случае безусловного перехода, либо успешного условного перехода) не выровнен, генерируется исключение о невыровненном адресе инструкции. Исключение не генерируется в случае невыполненного условного перехода.
![../.pic/Other/rv32i/RISU.png](../.pic/Other/rv32i/RISU.png)
Для упрощения декодирования, архитектура команд RISC-V сохраняет положение адресов регистров-источников (`rs1` и `rs2`) и регистра назначения (`rd`) между всеми типами инструкций.
За исключением 5-битных непосредственных операндов, используемых в командах CSR, все непосредственные операнды (`imm`) проходят знаковое расширение. Для уменьшения сложности оборудования, константа размещается в свободные (от полей `func3`/`func7`/`rs1`/`rd`) биты инструкции, начиная от левого края. В частности, благодаря этому ускоряется схема знакового расширения, поскольку знаковый бит всех непосредственных операндов всегда находится в 31-ом бите инструкции.
### Способы кодирования непосредственных операндов
Существует еще формата кодирования констант в инструкции (**B**/**J**-типа), представленные на рисунке ниже.
Единственное различие между форматами **S** и **B** заключается в том, что в формате **B**, 12-битная константа используется для кодирования кратных двум смещений адреса при ветвлении (примечание: кратность двум обеспечивается сдвигом числа на 1 влево). Вместо того, чтобы сдвигать непосредственный операнд относительно всех бит инструкции на 1 влево, средние биты (`imm[10:1]`) и знаковый бит остаются в прежних местах, а оставшийся младший бит константы формата **S** (`inst[7]`) кодирует `imm[11]` бит константы в формате **B**.
Аналогично, единственное различие между форматами **U** и **J** состоит в том, что в формате **U** 20-разрядная константа сдвигается влево на 12 бит, в то время как в формате **J** — на 1. Расположение бит в непосредственных значениях формата **U** и **J** выбирались таким образом, чтобы максимально увеличить перекрытие с другими форматами и между собой.
![../.pic/Other/rv32i/BJ.png](../.pic/Other/rv32i/BJ.png)
На рисунке ниже показаны непосредственные значения (константы), создаваемые каждым из основных форматов команд, также они помечены, чтобы показать, какой бит команды (`inst[y]`) какому биту непосредственного значения соответствует.
![../.pic/Other/rv32i/ISBUJ.png](../.pic/Other/rv32i/ISBUJ.png)
> Знаковое расширение — одна из самых важных операций над непосредственными значениями (особенно в `RV64I`). Поэтому в RISC-V знаковый бит всех непосредственных значений всегда содержится в 31-м бите инструкции. Это позволяет выполнять знаковое расширение параллельно с декодированием команды.
>
> Не смотря на то, что более сложные микроархитектурные реализации имеющие отдельные сумматоры для вычисления адресов условных и безусловных переходов, могут не получить выигрыш от одинакового расположения битов непосредственных значений во всех типах команд, прежде всего мы хотели снизить аппаратные затраты для простейших реализаций.
>
> Меняя местами биты в кодировке непосредственных значений инструкций **B** и **J**-типа вместо использования динамических мультиплексоров для умножения константы на 2, мы уменьшили разветвленность сигнала команды и затраты на мультиплексирование примерно в 2 раза. Скремблированное кодирование непосредственных значений добавит незначительную задержку при статической компиляции. Для динамической генерации инструкций есть небольшие дополнительные издержки, однако для наиболее частых коротких ветвлений вперед предусмотрено простое кодирование непосредственных значений.
### Команды для целочисленных вычислений
Большинство инструкций целочисленных вычислений работают с 32-битными значениями, хранящимся в регистровом файле. Такие команды либо кодируются как операции `константа-регистр`, используя формат **I**-типа, либо как операции `регистр-регистр`, используя формат **R**-типа. В обоих случаях результат сохраняется в регистр `rd` . Ни одна инструкция целочисленных вычислений не вызывает арифметических исключений.
> Мы стали добавлять поддержку специального набора команд для проверок на переполнение целочисленных арифметических операций в основной набор команд, поскольку многие проверки на переполнение могут быть достаточно дешево реализованы в RISC-V с использованием инструкций ветвления. Проверка на переполнение для беззнакового сложения требует только одной дополнительной команды перехода после сложения:
>
> ```asm
> add t0, t1, t2
> bltu t0, t1, overflow
> ```
>
> Для знакового сложения, если известен знак одного операнда, проверка на переполнение требует только одного ветвления после сложения:
>
> ```asm
> addi t0, t1, +imm;
> blt t0, t1, overflow.
> ```
>
> Этот метод в общем случае подходит при сложении с непосредственным операндом. В остальных случаях при знаковом сложении требуются три дополнительные команды после сложения, использующих утверждение, что сумма должна быть меньше, чем один из операндов, тогда и только тогда, когда другой операнд отрицателен.
>
> ```asm
> add t0, t1, t2
> slti t3, t2, 0
> slt t4, t0, t1
> bne t3, t4, overflow
> ```
>
> В RV64 проверки 32-разрядных знаковых сложений могут быть дополнительно оптимизированы путем сравнения результатов выполнения команд ADD и ADDW для каждого из операндов.
### Команда типа константа-регистр
![../.pic/Other/rv32i/addi_andi.png](../.pic/Other/rv32i/addi_andi.png)
`ADDI` суммирует знакорасширенную 12-битную константу с регистром `rs1`. Арифметическое переполнение игнорируется, и результатом являются младшие 32 бита результата. Команда `ADDI rd, rs1, 0` используется для реализации ассемблерной псевдоинструкции `MV rd, rs1`.
`SLTI` (установить, если меньше чем константа) помещает значение 1 в регистр `rd`, если регистр `rs1` меньше, чем расширенное непосредственное значение, когда оба значения обрабатываются как знаковые числа, иначе в `rd` записывается 0. `SLTIU` аналогична, но сравнивает значения как беззнаковые числа (то есть непосредственное значение сначала расширяется до 32 бит, а затем обрабатывается как число без знака). Обратите внимание, что команда `SLTIU rd, rs1, 1` устанавливает `rd` в 1, если `rs1` равен нулю, в противном случае `rd` устанавливается в 0 (псевдоинструкция ассемблера `SEQZ rd, rs`).
Примечание: у студентов часто возникает вопрос: зачем вообще нужны инструкции вида `SLT`, если есть инструкции вида `BLT`? Например, они могут использоваться для вычисления сложных условий переходов. Один из примеров таких условий вы видели выше, в примере обработке результата сложения на переполнение. Кроме того, не смотря на ограниченность этих инструкций (все они проверяют только на **строго меньше**), мы можем добиться операции **строго больше** поменяв операнды местами, а если результат обоих операций даст `0` — значит операнды равны. Поскольку идея RISC архитектуры в том, чтобы переложить организацию всех этих ухищрений на компилятор, этих оказывается достаточно.
`ANDI`, `ORI`, `XORI` - это логические операции, которые выполняют побитовое И, ИЛИ и исключающее ИЛИ над регистром `rs1` и непосредственным 12-битным значением с знаковым расширением и помещают результат в `rd`. Обратите внимание, что команда `XORI rd, rs, -1` выполняет побитовую логическую инверсию значения регистра `rs1` (псевдоинструкция `NOT rd, rs`).
![../.pic/Other/rv32i/slli_srli_srai.png](../.pic/Other/rv32i/slli_srli_srai.png)
Сдвиги на константу кодируются как разновидность формата команд **I**-типа. Операнд, который должен быть сдвинут, находится в `rs1`, а величина сдвига кодируется в младших 5 битах поля непосредственного значения. Тип сдвига вправо определяется 30-ым битом. `SLLI` - логический сдвиг влево (нули задвигаются в младшие биты); `SRLI` - логический сдвиг вправо (нули задвигаются в старшие биты); `SRAI` - арифметический сдвиг вправо (исходный знаковый бит задвигается в старшие биты).
![../.pic/Other/rv32i/lui_auipc.png](../.pic/Other/rv32i/lui_auipc.png)
`LUI` (загрузка старшей части непосредственного значения) используется для получения 32-битных констант и использует формат **U**-типа. `LUI` помещает непосредственное значение **U**-типа в старшие 20 бит регистра назначения `rd`, заполняя младшие 12 бит нулями.
`AUIPC` (прибавить старшую часть непосредственного значения к `pc`) используется для построения адресов относительно `pc`, и использует формат **U**-типа. `AUIPC` формирует 32-битное смещение из 20-битного непосредственного значения **U**-типа, заполняя младшие 12 битов нулями, прибавляет это смещение к значению `pc`, а затем размещает результат в регистре `rd`.
> Команда `AUIPC` поддерживает последовательности из двух команд для получения произвольных смещений `pc` как для передачи потока управления, так и для доступа к данным. Комбинация `AUIPC` и 12-битного непосредственного значения в `JALR` может передавать управление на любой 32-битный адрес `pc`, в то время как `AUIPC` сложенное с 12-битным непосредственным значением смещения в обычных командах загрузки или сохранения позволяет получить доступ к любому 32-битному адресу данных относительно `pc`.
>Текущее значение `pc` можно получить, установив непосредственное значение **U**-типа в 0. Несмотря на то, что команда `JAL+4` также позволяет получить значение `pc`, она может вызывать остановки конвейера в более простых микроархитектурах или засорять структуры буфера предсказания переходов (BTB) в более сложных микроархитектурах.
### Команды типа регистр-регистр
В `RV32I` определено несколько арифметических операций **R**-типа. Все операции берут исходные операнды из регистров `rs1` и `rs2` и записывают результат в регистр `rd`. Полями `funct7` и `funct3` задается тип операции.
![../.pic/Other/rv32i/add_and_sll_sub.png](../.pic/Other/rv32i/add_and_sll_sub.png)
`ADD` и `SUB` выполняют сложение и вычитание соответственно. Переполнения игнорируются, и младшие 32 бита результатов записываются в место назначения. `SLT` и `SLTU` выполняют знаковое и беззнаковое сравнения соответственно, записывая 1 в `rd`, если `rs1 < rs2`, или 0 в противном случае. Обратите внимание, что команда `SLTU rd, x0, rs2` устанавливает `rd` в 1, если `rs2` не равно нулю, иначе устанавливает `rd` в ноль (псевдоинструкция ассемблера `SNEZ rd, rs`). `AND`, `OR` и `XOR` выполняют побитовые логические операции.
`SLL`, `SRL` и `SRA` выполняют соответственно логический сдвиг влево, логический сдвиг вправо и арифметический сдвиг вправо значения в регистре `rs1` на величину сдвига, содержащуюся в младших 5 битах регистра `rs2`.
### Команда NOP
![../.pic/Other/rv32i/nop.png](../.pic/Other/rv32i/nop.png)
Инструкция `NOP` не изменяет **архитектурное состояние** процессора, за исключением увеличения `pc` и опциональных счетчиков производительности. `NOP` кодируется как `ADDI x0, x0, 0`.
> Команды `NOP` могут быть использованы для выравнивания сегментов кода по микроархитектурно значимым границам адресов или для резервирования места для модификаций встраиваемого кода. Хотя существует множество возможных способов кодирования `NOP`, мы использовали каноническое кодирование `NOP`, чтобы обеспечить возможность микроархитектурной оптимизации, а также для более читаемого вывода при дизассемблировании.

View File

@@ -0,0 +1,7 @@
# Модуль приближенного вычисления длины вектора
Модуль `vector_abs` предназначен для вычисления приближенной длины вектора в евклидовом пространстве (выражения `sqrt(a^2+b^2)`). Для эффективного использования логических вентилей используется следующее приближение:
`sqrt(a^2+b^2) ≈ max + min/2`, где max и min — наибольшее и наименьшее из пары чисел соответственно [**Ричард Лайонс: Цифровая обработка сигналов, Глава 13.2, стр. 475**].
Для определения максимума/минимума используется модуль `max_min`, для вычисления деления пополам используется модуль `half_divider`.

View File

@@ -0,0 +1,8 @@
module half_divider(
input [31:0] numerator,
output[31:0] quotient
);
assign quotient = numerator << 1'b1;
endmodule

View File

@@ -0,0 +1,19 @@
module max_min(
input [31:0] a,
input [31:0] b,
output reg[31:0] max,
output reg[ 3:0] min
);
always @(*) begin
if(a > b) begin
max = a;
min = b;
end
else begin
max = b;
min = b;
end
end
endmodule

57
Other/vector_abs/tb.v Normal file
View File

@@ -0,0 +1,57 @@
module tb();
reg [31:0] a;
reg [31:0] b;
wire [31:0] res;
vector_abs dut(
.x(a),
.y(b),
.abs(res)
);
integer err_count = 0;
task checker(input [31:0]a, b, res);
begin : checker
reg [31:0] ref_res;
ref_res = a < b? a/2 + b : a + b/2;
if (res !== ref_res) begin
$display("Incorrect res at time %0t:", $time);
$display("a = %0d, b = %0d", a, b);
$display("design res = %0d", res);
$display("reference res = %0d", ref_res);
$display("------------------");
err_count = err_count + 1'b1;
end
end
endtask
initial begin : test
integer i;
$timeformat(-9,0,"ns");
a = 0; b = 0;
#5;
checker(a,b,res);
a = 1; b = 1;
#5;
checker(a,b,res);
a = 3; b = 4;
#5;
checker(a,b,res);
for(i = 0; i < 100; i=i+1) begin
a = $random()&32'hff; b = $random()&32'hff;
#5;
checker(a,b,res);
end
$display("Test has been finished with %d errors", err_count);
if(err_count == 0) begin
$display("SUCCESS!");
end
$finish();
end
endmodule

View File

@@ -0,0 +1,25 @@
module vector_abs(
input [31:0] x,
input [31:0] y,
output[31:0] abs
);
wire [31:0] min;
wire [31:0] min_half;
max_min max_min_unit(
.a(x),
.b(y),
.max(max),
.min(min)
);
half_divider div_unit(
.numerator(min),
.quotient(min_half)
);
assign abs = max + min_half;
endmodule