Merge pull request #55 from MPSU/svg-transition

Перенос drawio-изображений в svg-формат
This commit is contained in:
Andrei Solodovnikov
2024-01-31 17:54:53 +03:00
committed by GitHub
159 changed files with 395 additions and 126 deletions

View File

@@ -22,7 +22,7 @@
Давайте начнем с примера и сложим в столбик какую-нибудь пару чисел, например 42 и 79:
![../../.pic/Labs/lab_01_adder/column_add_dec.drawio.png](../../.pic/Labs/lab_01_adder/column_add_dec.drawio.png)
![../../.pic/Labs/lab_01_adder/column_add_dec.drawio.svg](../../.pic/Labs/lab_01_adder/column_add_dec.drawio.svg)
```text
2 + 9 = 11 ➨ 1 пишем, 1 "в уме"
@@ -36,7 +36,7 @@
Теперь попробуем сделать то же самое, только в двоичной системе исчисления. К примеру, над числами 3 и 5. Три в двоичной системе записывается как 011. Пять записывается как 101.
![../../.pic/Labs/lab_01_adder/column_add_bin.drawio.png](../../.pic/Labs/lab_01_adder/column_add_bin.drawio.png)
![../../.pic/Labs/lab_01_adder/column_add_bin.drawio.svg](../../.pic/Labs/lab_01_adder/column_add_bin.drawio.svg)
Поскольку в двоичной системе всего две цифры: 0 и 1, один разряд не может превысить 1. Складывая числа 1 и 1, вы получаете 2, что не умещается в один разряд, поэтому мы пишем 0 и держим 1 "в уме". Это снова перенос разряда. Поскольку в двоичной арифметике разряд называют битом, перенос разряда называют переносом бита, а сам разряд, который перенесли — битом переноса.
@@ -58,25 +58,25 @@
![../../.pic/Labs/lab_01_adder/tt1.png](../../.pic/Labs/lab_01_adder/tt1.png)
*Таблица истинности одноразрядного сложения*
_Таблица истинности одноразрядного сложения._
`S` — это цифра, записываемая в столбце сложения под числами `a` и `b`. `C` (*carry*, перенос) — это цифра, записываемая левее, если произошел перенос разряда. Как мы видим, перенос разряда происходит только в случае, когда оба числа одновременно равны единице. При этом в этот момент значение `S` обращается в `0`, и результат записывается как `10`, что в двоичной системе означает `2`. Кроме того, `S = 0` и в случае, когда оба операнда одновременно равны нулю. Вы можете заметить, что `S` равно нулю в тех случаях, когда `а` и `b` равны, и не равно нулю в противоположном случае. Подобным свойством обладает логическая операция **Исключающее ИЛИ** (**eXclusive OR**, **XOR**):
`S` — это цифра, записываемая в столбце сложения под числами `a` и `b`. `C` (_carry_, перенос) — это цифра, записываемая левее, если произошел перенос разряда. Как мы видим, перенос разряда происходит только в случае, когда оба числа одновременно равны единице. При этом в этот момент значение `S` обращается в `0`, и результат записывается как `10`, что в двоичной системе означает `2`. Кроме того, `S = 0` и в случае, когда оба операнда одновременно равны нулю. Вы можете заметить, что `S` равно нулю в тех случаях, когда `а` и `b` равны, и не равно нулю в противоположном случае. Подобным свойством обладает логическая операция **Исключающее ИЛИ** (**eXclusive OR**, **XOR**):
![../../.pic/Labs/lab_01_adder/tt2.png](../../.pic/Labs/lab_01_adder/tt2.png)
*Таблица истинности операции Исключающее ИЛИ (XOR)*
_Таблица истинности операции Исключающее ИЛИ (XOR)._
Для бита переноса всё ещё проще — он описывается операцией логическое И:
![../../.pic/Labs/lab_01_adder/tt3.png](../../.pic/Labs/lab_01_adder/tt3.png)
*Таблица истинности операции И*
_Таблица истинности операции И._
Давайте нарисуем цифровую схему, связывающую входные и выходные сигналы с помощью логических элементов, соответствующих ожидаемому поведению:
![../../.pic/Labs/lab_01_adder/fig_01.drawio.png](../../.pic/Labs/lab_01_adder/fig_01.drawio.png)
![../../.pic/Labs/lab_01_adder/fig_01.drawio.svg](../../.pic/Labs/lab_01_adder/fig_01.drawio.svg)
*Рисунок 1. Цифровая схема устройства, складывающего два операнда с сохранением переноса (полусумматора)*
_Рисунок 1. Цифровая схема устройства, складывающего два операнда с сохранением переноса (полусумматора)._
Вроде все замечательно, но есть проблема. В описании полного однобитного сумматора сказано, что у него есть три входа, а в наших таблицах истинности и на схеме выше их только два. На самом деле, на каждом этапе сложения в столбик мы всегда складывали три числа: цифру верхнего числа, цифру нижнего числа, и единицу в случае переноса разряда из предыдущего столбца (если с предыдущего разряда не было переноса, прибавление нуля неявно опускалось).
@@ -84,7 +84,7 @@
![../../.pic/Labs/lab_01_adder/tt4.png](../../.pic/Labs/lab_01_adder/tt4.png)
*Таблица истинности сигналов полного однобитного сумматора*
_Таблица истинности сигналов полного однобитного сумматора._
Поскольку теперь у нас есть и входной и выходной биты переноса, для их различия добавлены индексы “in” и “out”.
@@ -98,9 +98,9 @@
Цифровая схема устройства с описанным поведением выглядит следующим образом:
![../../.pic/Labs/lab_01_adder/fig_02.drawio.png](../../.pic/Labs/lab_01_adder/fig_02.drawio.png)
![../../.pic/Labs/lab_01_adder/fig_02.drawio.svg](../../.pic/Labs/lab_01_adder/fig_02.drawio.svg)
*Рисунок 2. Цифровая схема полного однобитного сумматора*
_Рисунок 2. Цифровая схема полного однобитного сумматора._
## Практика
@@ -150,15 +150,15 @@ module half_adder(
endmodule
```
*Листинг 1. SystemVerilog-код модуля half_adder*
_Листинг 1. SystemVerilog-код модуля half_adder._
По данному коду, САПР может реализовать следующую схему:
![../../.pic/Labs/lab_01_adder/fig_03.png](../../.pic/Labs/lab_01_adder/fig_03.png)
*Рисунок 3. Цифровая схема модуля half_adder, сгенерированная САПР Vivado*
_Рисунок 3. Цифровая схема модуля half_adder, сгенерированная САПР Vivado._
Схема похожа на рис. 1, но как проверить, что эта схема не содержит ошибок и делает именно то, что от нее ожидается?
Схема похожа на _рис. 1_, но как проверить, что эта схема не содержит ошибок и делает именно то, что от нее ожидается?
Для этого необходимо провести моделирование этой схемы. Во время моделирования на вход схемы подаются входные воздействия. Каждое изменение входных сигналов схемы приводит к каскадному изменению состояния внутренних цепей, которые в итоге меняют выходные сигналы.
@@ -191,13 +191,13 @@ module testbench(); // <- Не имеет ни входов, ни
endmodule
```
*Листинг 2. SystemVerilog-код тестбенча для модуля example*
_Листинг 2. SystemVerilog-код тестбенча для модуля example._
![../../.pic/Labs/lab_01_adder/fig_04.png](../../.pic/Labs/lab_01_adder/fig_04.png)
*Рисунок 4. Временная диаграмма, моделирующая работу схемы с рис.3*
_Рисунок 4. Временная диаграмма, моделирующая работу схемы с рис. 3._
В данной лабораторной работе вам предстоит реализовать схему полного однобитного сумматора (*рис. 2*).
В данной лабораторной работе вам предстоит реализовать схему полного однобитного сумматора (_рис. 2_).
### Полный четырехбитный сумматор
@@ -207,18 +207,19 @@ endmodule
Давайте посмотрим, как это будет выглядеть на схеме (для простоты, внутренняя логика однобитного сумматора скрыта, но вы должны помнить, что каждый прямоугольник — это та же самая схема с рис. 2).
![../../.pic/Labs/lab_01_adder/fig_05.drawio.png](../../.pic/Labs/lab_01_adder/fig_05.drawio.png)
*Рисунок 5. Схема четырехбитного сумматора*
![../../.pic/Labs/lab_01_adder/fig_05.drawio.svg](../../.pic/Labs/lab_01_adder/fig_05.drawio.svg)
_Рисунок 5. Схема четырехбитного сумматора._
Фиолетовой линией на схеме показаны провода, соединяющие выходной бит переноса сумматора предыдущего разряда, с входным битом переноса сумматора следующего разряда.
Как же реализовать модуль, состоящий из цепочки других модулей? Половину этой задачи мы уже сделали, когда писали тестбенч к однобитному полусумматору в *Листинге 2* — мы создавали модуль внутри другого модуля и подключали к нему провода. Теперь надо сделать то же самое, только с чуть большим числом модулей.
Как же реализовать модуль, состоящий из цепочки других модулей? Половину этой задачи мы уже сделали, когда писали тестбенч к однобитному полусумматору в _Листинге 2_ — мы создавали модуль внутри другого модуля и подключали к нему провода. Теперь надо сделать то же самое, только с чуть большим числом модулей.
Для того, чтобы описать четырехбитный сумматор, необходимо подключить четыре однобитных подобно тому, как было описано в [`документе`](../../Basic%20Verilog%20structures/Modules.md#иерархия-модулей), который вы изучали перед лабораторной работой.
![../../.pic/Labs/lab_01_adder/fig_06.drawio.png](../../.pic/Labs/lab_01_adder/fig_06.drawio.png)
*Рисунок 6. Схема четырехбитного сумматора, сгенерированная САПР Vivado*
_Рисунок 6. Схема четырехбитного сумматора, сгенерированная САПР Vivado._
Схема может показаться запутанной, но (если присмотреться) вы увидите, как от шин A, B и S отходят линии к каждому из сумматоров, а бит переноса передается от предыдущего сумматора к следующему.
@@ -242,7 +243,7 @@ module fulladder4(
![../../.pic/Labs/lab_01_adder/fig_07.png](../../.pic/Labs/lab_01_adder/fig_07.png)
*Рисунок 7. Пример использования конструкции generate for*
_Рисунок 7. Пример использования конструкции generate for._
Как вы можете догадаться, в этом примере создано 3 модуля, имена которых оканчиваются на значение итератора, по которому шел цикл, а к самим модулям подключены соответствующие итератору провода из шин. Разумеется, для своих целей вы можете использовать и **i+1** и двойные циклы.
@@ -275,13 +276,13 @@ module fulladder32(
1. Согласно [руководству по созданию проекта в Vivado](../../Vivado%20Basics/Vivado%20trainer.md):
1. Создайте проект;
2. В `Design Sources` проекта создайте `SystemVerilog`-файл `fulladder`.
2. Опишите в файле модуль `fulladder`, схема которого представлена на *[Рис. 2](../../.pic/Labs/lab_01_adder/fig_02.drawio.png)*.
2. Опишите в файле модуль `fulladder`, схема которого представлена на _[Рис. 2](../../.pic/Labs/lab_01_adder/fig_02.drawio.svg)_.
3. В `Simulation Sources` проекта создайте `SystemVerilog`-файл `tb_fulladder`.
4. Вставьте содержимое файла [`tb_fulladder.sv`](tb_fulladder.sv), расположенного рядом с данным документом.
5. Запустите моделирование. Для запуска симуляции воспользуйтесь [`этой инструкцией`](../../Vivado%20Basics/Run%20Simulation.md).
6. Убедитесь по сигналам временной диаграммы, что модуль работает корректно.
7. В `Design Sources` проекта создайте `SystemVerilog`-файл `fulladder4`.
8. Опишите модуль `fulladder4`, схема которого представлена на *Рис. 5 и 6*, используя [`иерархию модулей`](../../Basic%20Verilog%20structures/Modules.md#%D0%B8%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%8F-%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D0%B5%D0%B9), чтобы в нем выполнялось поразрядное сложение двух 4-разрядных чисел и входного бита переноса. Некоторые входы и выходы модуля будет необходимо описать в виде `векторов`.
8. Опишите модуль `fulladder4`, схема которого представлена на _Рис. 5 и 6_, используя [`иерархию модулей`](../../Basic%20Verilog%20structures/Modules.md#%D0%B8%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%8F-%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D0%B5%D0%B9), чтобы в нем выполнялось поразрядное сложение двух 4-разрядных чисел и входного бита переноса. Некоторые входы и выходы модуля будет необходимо описать в виде `векторов`.
9. Обратите внимание, что входной бит переноса должен подаваться на сумматор, выполняющий сложение нулевого разряда, выходной бит переноса соединяется с выходным битом переноса сумматора, выполняющего сложение 4-го разряда.
10. В `Simulation Sources` проекта создайте `SystemVerilog`-файл `tb_fulladder4`.
11. Вставьте содержимое файла [`tb_fulladder4.sv`](tb_fulladder4.sv). Нажмите по нему в окне `Sources` ПКМ и выберите `Set as Top`.

View File

@@ -26,27 +26,27 @@
Обычно АЛУ представляет собой комбинационную схему (то есть без элементов памяти), на входы которой поступают информационные (операнды) и управляющие (код операции) сигналы, в ответ на что на выходе появляется результат заданной операции. АЛУ бывает не комбинационной схемой, но это скорее исключение.
![../../.pic/Labs/lab_02_alu/fig_01.drawio.png](../../.pic/Labs/lab_02_alu/fig_01.drawio.png)
![../../.pic/Labs/lab_02_alu/fig_01.drawio.svg](../../.pic/Labs/lab_02_alu/fig_01.drawio.svg)
*Рисунок 1. Структурное обозначение элемента АЛУ[1, стр.305].*
_Рисунок 1. Структурное обозначение элемента АЛУ[1, стр.305]._
На рис. 1 изображен пример АЛУ, используемый в книге "Цифровая схемотехника и архитектура компьютера" Харрис и Харрис. На входы `A` и `B` поступают операнды с разрядностью *N*. На трехбитный вход `F` подается код операции. Например, если туда подать `000`, то на выходе `Y` появится результат операции *логическое И* между битами операндов `A` и `B`. Если на `F` подать `010`, то на выходе появится результат сложения. Это лишь пример, разрядность и коды могут отличаться в зависимости от количества выполняемых операций и архитектуры.
На рис. 1 изображен пример АЛУ, используемый в книге "Цифровая схемотехника и архитектура компьютера" Харрис и Харрис. На входы `A` и `B` поступают операнды с разрядностью _N_. На трехбитный вход `F` подается код операции. Например, если туда подать `000`, то на выходе `Y` появится результат операции _логическое И_ между битами операндов `A` и `B`. Если на `F` подать `010`, то на выходе появится результат сложения. Это лишь пример, разрядность и коды могут отличаться в зависимости от количества выполняемых операций и архитектуры.
Существует несколько подходов к реализации АЛУ, отличающиеся внутренней организацией. В лабораторных работах применяется повсеместно используемый подход мультиплексирования операций, то есть подключения нескольких операционных устройств (которые выполняют какие-то операции, например сложения, логическое И и т.п.) к мультиплексору, который будет передавать результат нужного операционного устройства на выходы АЛУ.
Рассмотрим на примере все того же АЛУ MIPS из книги Харрисов. На рис. 2, в левой его части, изображена внутренняя организация этого АЛУ, справа таблица соответствия кодов операциям. На выходе схемы (внизу) стоит четырехвходовый мультиплексор, управляемый двумя из трех битов `F`. К его входам подключены *N* логических И (побитовое И *N*-разрядных операндов), *N* логических ИЛИ, *N*-разрядный сумматор и Zero Extend устройство делающее из однобитного числа *N*-битное число, дополняя нулями слева.
Рассмотрим на примере все того же АЛУ MIPS из книги Харрисов. На рис. 2, в левой его части, изображена внутренняя организация этого АЛУ, справа таблица соответствия кодов операциям. На выходе схемы (внизу) стоит четырехвходовый мультиплексор, управляемый двумя из трех битов `F`. К его входам подключены _N_ логических И (побитовое И _N_-разрядных операндов), _N_ логических ИЛИ, _N_-разрядный сумматор и Zero Extend устройство делающее из однобитного числа _N_-битное число, дополняя нулями слева.
К одному из входов этих операционных устройств подключен `A` без изменений, а ко второму подключен выход двухвходового мультиплексора, управляемого оставшимся битом *F*. То есть `F[2]` определяет, что будет вторым операндом: `B` или `~B`. Вдобавок `F[2]` подается на входной перенос сумматора, то есть, когда `F[2] == 1` на выходе сумматора появляется результат операции `A + ~B + 1`, что (с учетом [дополнительного кода](https://ru.wikipedia.org/wiki/Дополнительный_код)) эквивалентно `A  B`.
К одному из входов этих операционных устройств подключен `A` без изменений, а ко второму подключен выход двухвходового мультиплексора, управляемого оставшимся битом _F_. То есть `F[2]` определяет, что будет вторым операндом: `B` или `~B`. Вдобавок `F[2]` подается на входной перенос сумматора, то есть, когда `F[2] == 1` на выходе сумматора появляется результат операции `A + ~B + 1`, что (с учетом [дополнительного кода](https://ru.wikipedia.org/wiki/Дополнительный_код)) эквивалентно `A  B`.
![../../.pic/Labs/lab_02_alu/fig_02.drawio.png](../../.pic/Labs/lab_02_alu/fig_02.drawio.png)
![../../.pic/Labs/lab_02_alu/fig_02.drawio.svg](../../.pic/Labs/lab_02_alu/fig_02.drawio.svg)
*Рисунок 2. Структурная схема АЛУ MIPS[1, стр.305].*
_Рисунок 2. Структурная схема АЛУ MIPS[1, стр.305]._
Посмотрим, что произойдет, если на вход `F` такого АЛУ подать `111`. Будет выполняться операция `SLT`(сокращение от `Set Less Then`) выдать `1`, если `A` меньше `B`, в противном случае — выдать `0`. Биты `F[1:0]` переключат мультиплексор на выход блока Zero Extend. На вход Zero Extend поступает старший бит выхода сумматора, этот бит отвечает за знак результата. Так как `F[2] == 1`, сумматор вычисляет `A + ~B + 1`, то есть `A  B`, значит, если `A < B`, то результат вычитания будет отрицательный, а старший бит `Y[N-1] == 1`. Если `A` не меньше `B`, то разность будет неотрицательна, а `Y[N-1] == 0`, как и требуется от этой операции.
![../../.pic/Labs/lab_02_alu/fig_03.drawio.png](../../.pic/Labs/lab_02_alu/fig_03.drawio.png)
![../../.pic/Labs/lab_02_alu/fig_03.drawio.svg](../../.pic/Labs/lab_02_alu/fig_03.drawio.svg)
*Рисунок 3. Пример исполнения операции АЛУ.*
_Рисунок 3. Пример исполнения операции АЛУ._
Преимущество такой организации АЛУ в его простой модификации, настройке под нужные коды операций, читаемости кода и масштабируемости. Можно легко добавить или убрать требуемые операции. Подумайте, как бы вы обновили данную схему, если бы от вас потребовалось расширить её функционал операциями XOR (Исключающее ИЛИ) и (SGE операция "больше либо равно")?
@@ -224,7 +224,7 @@ endmodule
| OR | 0 0 110 |result_o = a_i \| b_i | Побитовое логическое **ИЛИ** |
| AND | 0 0 111 |result_o = a_i & b_i | Побитовое логическое **И** |
*Таблица 1. Список вычислительных операций.*
_Таблица 1. Список вычислительных операций._
В первой таблице перечислены операции, вычисляющие значение сигнала `flag_o`. **При любом коде операции `alu_op_i` не входящим в эту таблицу, сигнал `flag_o` должен быть равен нулю**.
@@ -237,11 +237,11 @@ endmodule
| LTU | 1 1 110 | flag_o = a_i < b_i | Беззнаковое сравнение **<** |
| GEU | 1 1 111 | flag_o = a_i b_i | Беззнаковое сравнение **≥** |
*Таблица 2. Список операций сравнения.*
_Таблица 2. Список операций сравнения._
**Выражения в этих двух таблицах приведены для примера. Не все из них можно просто переписать — часть этих выражений надо дополнить. Чтобы вы не копировали выражения, в них вставлены неподдерживаемые символы.**
Несмотря на разделение на вычислительные операции, и операции сравнения, в *Таблице 1* (вычислительных операция) оказалось две операции `SLTS` и `SLTU`, которые выполняют сравнения. В итоге у нас есть две похожие пары инструкций:
Несмотря на разделение на вычислительные операции, и операции сравнения, в _Таблице 1_ (вычислительных операция) оказалось две операции `SLTS` и `SLTU`, которые выполняют сравнения. В итоге у нас есть две похожие пары инструкций:
- `LTS`
- `LTU`

View File

@@ -50,9 +50,9 @@
Так же возможна реализация, в которой вход `write_data` и выход `read_data` объединены в единый вход/выход `data`. В этом случае операции чтения и записи разделены во времени и используют для этого один единый порт ввода-вывода (`inout`, двунаправленный порт) `data`.
![../../.pic/Labs/lab_03_memory/fig_01.drawio.png](../../.pic/Labs/lab_03_memory/fig_01.drawio.png)
![../../.pic/Labs/lab_03_memory/fig_01.drawio.png](../../.pic/Labs/lab_03_memory/fig_01.drawio.svg)
*Рисунок 1. Примеры блоков ПЗУ и ОЗУ.*
_Рисунок 1. Примеры блоков ПЗУ и ОЗУ._
Кроме того, различают память с **синхронным** и **асинхронным** чтением. В первом случае, перед выходным сигналом шины данных ставится дополнительный регистр, в который по тактовому синхроимпульсу записываются запрашиваемые данные. Такой способ может очень сильно сократить **критический путь** цифровой схемы, но требует дополнительный такт на доступ в память. В свою очередь, асинхронное чтение позволяет получить данные, не дожидаясь очередного синхроимпульса, но такой способ увеличивает критический путь.
@@ -64,15 +64,15 @@
![../../.pic/Labs/lab_03_memory/fig_02.png](../../.pic/Labs/lab_03_memory/fig_02.png)
*Рисунок 2. Структурная схема логического блока в ПЛИС[[1]](https://en.wikipedia.org/wiki/Field-programmable_gate_array).*
_Рисунок 2. Структурная схема логического блока в ПЛИС[[1]](https://en.wikipedia.org/wiki/Field-programmable_gate_array)._
В логическом блоке есть **таблицы подстановки** (Look Up Table, LUT), которые представляют собой не что иное как память, которая переконфигурируется под нужды хранения, а не реализацию логики. Таким образом, трехвходовой LUT может выступать в роли восьмиразрядной памяти.
Однако LUT будет сложно приспособить под многопортовую память: посмотрим на схему еще раз: три входа LUT формируют адрес одной из восьми ячеек. Это означает, что среди этих восьми ячеек нельзя обратиться к двум из них одновременно.
Для реализации многопортовой памяти небольшого размера лучше воспользоваться расположенным в логическом блоке D-триггером (**DFF** на *рис. 2*). Несмотря на то, что D-триггер позволяет воспроизвести только 1 разряд элемента памяти, он не ограничивает реализацию по портам.
Для реализации многопортовой памяти небольшого размера лучше воспользоваться расположенным в логическом блоке D-триггером (**DFF** на _рис. 2_). Несмотря на то, что D-триггер позволяет воспроизвести только 1 разряд элемента памяти, он не ограничивает реализацию по портам.
Таким образом, плюс распределенной памяти относительно регистровой заключается в лучшей утилизации ресурсов: одним трёхвходовым LUT можно описать до 8 бит распределенной памяти, в то время как одним D-триггером можно описать только один бит регистровой памяти. Предположим, что в ПЛИС размещены логические блоки, структура которых изображена на *рис. 2* и нам необходимо реализовать 1KiB памяти. Мы можем реализовать распределенную память, используя 64 логических блока (в каждом блоке два трёхвходовых LUT), либо регистровую память, используя 1024 логических блока.
Таким образом, плюс распределенной памяти относительно регистровой заключается в лучшей утилизации ресурсов: одним трёхвходовым LUT можно описать до 8 бит распределенной памяти, в то время как одним D-триггером можно описать только один бит регистровой памяти. Предположим, что в ПЛИС размещены логические блоки, структура которых изображена на _рис. 2_ и нам необходимо реализовать 1KiB памяти. Мы можем реализовать распределенную память, используя 64 логических блока (в каждом блоке два трёхвходовых LUT), либо регистровую память, используя 1024 логических блока.
Минусом является ограниченность в реализации многопортовой памяти.

View File

@@ -75,17 +75,19 @@ SYSTEM-инструкции используются для доступа к с
![../../.pic/Labs/lab_05_decoder/rv32i_summary.png](../../.pic/Labs/lab_05_decoder/rv32i_summary.png)
*Таблица 3. Инструкции набора RV32I с приведением их типов, функционального описания и примеров использования.*
_Таблица 3. Инструкции набора RV32I с приведением их типов, функционального описания и примеров использования._
Обратите внимание на операции `slli`, `srli` и `srai` (операции сдвига на константную величину). У этих инструкций немного измененный формат кодирования **I\***. Формат кодирования **I** предоставляет 12-битную константу. Сдвиг 32-битного числа более, чем на 31 не имеет смысла. Для кодирования числа 31 требуется всего 5 бит. Выходит, что из 12 бит константы используется только 5 бит для операции сдвига, а оставшиеся 7 бит – не используются. А, главное (какое совпадение!), эти 7 бит находятся ровно в том же месте, где у других инструкций находится поле `func7`. Поэтому, чтобы у инструкций `slli`, `srli` и `srai` использующих формат **I** не пропадала эта часть поля, к ней относятся как к полю `func7`.
### Предлагаемая микроархитектура процессора RISC-V
Ниже приводится микроархитектура процессора RISC-V. Регистр `PC` (Program Counter счетчик команд) подключен к адресному входу памяти инструкций. Считываемая инструкция декодируется основным дешифратором, после чего он выставляет управляющие сигналы для всех блоков процессора (мультиплексоры, АЛУ, интерфейс взаимодействия с памятью).
На _рис. 1_ приводится микроархитектура ядра процессора RISC-V. Регистр `PC` (Program Counter счетчик команд) подключен к адресному входу памяти инструкций. Считываемая инструкция декодируется основным дешифратором, после чего он выставляет управляющие сигналы для всех блоков процессора (мультиплексоры, АЛУ, интерфейс взаимодействия с памятью).
Приведенная архитектура не является заданием для текущей лабораторной работы, лишь отражает то, как в дальнейшем будет подключаться и использоваться реализуемый в данной лабораторной основной дешифратор.
![../../.pic/Labs/lab_11_irq_integration/fig_01.drawio.png](../../.pic/Labs/lab_11_irq_integration/fig_01.drawio.png)
![../../.pic/Labs/lab_11_irq_integration/fig_01.drawio.svg](../../.pic/Labs/lab_11_irq_integration/fig_01.drawio.svg)
_Рисунок 1. Микроархитектура будущего процессорного ядра._
Предложенная микроархитектура процессора `CYBERcobra 3000 Pro 2.0` из прошлой лабораторной имеет схожую структуру, с некоторыми изменениями.

View File

@@ -40,7 +40,9 @@ module riscv_core (
endmodule
```
![../../.pic/Labs/lab_06_dp/fig_01.drawio.png](../../.pic/Labs/lab_06_dp/fig_01.drawio.png)
![../../.pic/Labs/lab_06_dp/fig_01.drawio.svg](../../.pic/Labs/lab_06_dp/fig_01.drawio.svg)
_Рисунок 1. Микроархитектура ядра процессора RISC-V._
В отличие от реализованного ранее процессора с архитектурой CYBERcobra, в данном модуле отсутствует память (она подключается извне, а значит у этого модуля должны быть сигналы интерфейса памяти).
@@ -67,7 +69,9 @@ module riscv_unit(
endmodule
```
![../../.pic/Labs/lab_06_dp/fig_02.drawio.png](../../.pic/Labs/lab_06_dp/fig_02.drawio.png)
![../../.pic/Labs/lab_06_dp/fig_02.drawio.svg](../../.pic/Labs/lab_06_dp/fig_02.drawio.svg)
_Рисунок 2. Микроархитектура процессора._
Обратите внимание на регистр `stall`. Этот регистр и будет управлять разрешением на запись в программный счетчик `PC`. Поскольку мы используем блочную память, расположенную прямо в ПЛИС, доступ к ней осуществляется за 1 такт, а значит, что при обращении в память, нам необходимо "отключить" программный счетчик ровно на 1 такт. Если бы использовалась действительно "внешняя" память (например чип DDR3), то вместо этого регистра появилась бы другая логика, выставляющая на вход ядра `stall_i` единицу пока идет обращение в память.

View File

@@ -31,9 +31,9 @@
Модуль загрузки и сохранения (**Load/Store Unit** **LSU**) служит для исполнения инструкций типа `LOAD` и `STORE`: является прослойкой между внешним устройством памятью, и ядром процессора. **LSU** считывает содержимое из памяти данных или записывает в нее требуемые значения, преобразуя 8- и 16-битные данные в знаковые или беззнаковые 32-битные числа для регистров процессора. В процессорах с **RISC** архитектурой с помощью **LSU** осуществляется обмен данными между регистрами общего назначения и памятью данных.
![../../.pic/Labs/lab_08_lsu/fig_01.drawio.png](../../.pic/Labs/lab_08_lsu/fig_01.drawio.png)
![../../.pic/Labs/lab_08_lsu/fig_01.drawio.svg](../../.pic/Labs/lab_08_lsu/fig_01.drawio.svg)
_Рисунок 1. Место LSU в микроархитектуре RISC-процессора_
_Рисунок 1. Место LSU в микроархитектуре RISC-процессора._
### Интерфейс процессора и блока загрузки/сохранения
@@ -177,11 +177,11 @@ _Рисунок 1. Место LSU в микроархитектуре RISC-пр
- стать равным единице в тот же такт, когда пришел сигнал `core_req_i`
- удерживать это значение до тех пор, пока не придет сигнал `mem_ready_i`, но не менее 1 такта (т.е. даже если сигнал `mem_ready_i` будет равен единице, `core_req_i` должен подняться хотя бы на 1 такт).
Для реализации подобного функционала вам потребуется вспомогательный регистр `stall_reg`, каждый такт записывающий значение выхода `core_stall_o` и следующая таблица истинности для этого выхода:
Для реализации подобного функционала вам потребуется вспомогательный регистр `stall_reg`, каждый такт записывающий значение выхода `core_stall_o` и таблица истинности для этого выхода, представленная на _рис. 2_.
![../../.pic/Labs/lab_08_lsu/fig_02.png](../../.pic/Labs/lab_08_lsu/fig_02.png)
_Рисунок 2. Таблица истинности выхода `core_stall_o`_
_Рисунок 2. Таблица истинности выхода `core_stall_o`._
---
@@ -215,9 +215,9 @@ module riscv_lsu(
```
![../../.pic/Labs/lab_08_lsu/fig_03.drawio.png](../../.pic/Labs/lab_08_lsu/fig_03.drawio.png)
![../../.pic/Labs/lab_08_lsu/fig_03.drawio.svg](../../.pic/Labs/lab_08_lsu/fig_03.drawio.svg)
_Рисунок 3. Структурная схема модуля `riscv_lsu`_
_Рисунок 3. Структурная схема модуля `riscv_lsu`._
---
@@ -234,4 +234,3 @@ _Рисунок 3. Структурная схема модуля `riscv_lsu`_
2. Для запуска симуляции воспользуйтесь [`этой инструкцией`](../../Vivado%20Basics/Run%20Simulation.md).
3. Перед запуском симуляции убедитесь, что в качестве top-level модуля выбран корректный (`tb_lsu`).
4. Во время симуляции, вы должны прожать "Run All" и убедиться, что в логе есть сообщение о завершении теста!

View File

@@ -1,8 +1,10 @@
# Лабораторная работа 9 "Интеграция блока загрузки и сохранения"
После реализации блока загрузки и сохранения, его необходимо интегрировать в процессорную систему. Ниже представлена схема, иллюстрирующая интеграцию компонентов:
После реализации блока загрузки и сохранения, его необходимо интегрировать в процессорную систему. На _рис. 1_ представлена схема, иллюстрирующая интеграцию компонентов:
![../../.pic/Labs/lab_08_lsu/fig_01.drawio.png](../../.pic/Labs/lab_08_lsu/fig_01.drawio.png)
![../../.pic/Labs/lab_08_lsu/fig_01.drawio.svg](../../.pic/Labs/lab_08_lsu/fig_01.drawio.svg)
_Рисунок 1. Подключение LSU в процессорную систему._
## Задание

View File

@@ -96,7 +96,7 @@ _Таблица 1. Регистры контроля и состояния ма
|1110011 | 110 | I | csrrsi rd, csr, rs1 | Чтение и Установка бит CSR| rd = csr, csr = csr \| imm |
|1110011 | 111 | I | csrrci rd, csr, rs1 | Чтение и Очистка бит CSR | rd = csr, csr = csr & ~imm |
_Таблица 2. Список инструкций для работы с регистрами контроля и статуса_
_Таблица 2. Список инструкций для работы с регистрами контроля и статуса._
Для удобства программирования на языке ассемблера RISC-V существуют псевдоинструкции для работы с CS-регистрами.
@@ -105,7 +105,7 @@ _Таблица 2. Список инструкций для работы с ре
| csrr rd, csr | csrrs rd, csr, x0 | Чтение CSR | rd = csr |
| csrw csr, rs1 | csrrw x0, csr, rs1 | Запись CSR | csr = rs1 |
_Таблица 3. Псевдоинструкции для работы с регистрами контроля и статуса_
_Таблица 3. Псевдоинструкции для работы с регистрами контроля и статуса._
Операция логического ИЛИ нулевого регистра с содержимым CS-регистра не меняет его содержимого, поэтому при использовании инструкции `csrr` происходит только операция чтения. Подобным образом реализована псевдоинструкция `csrw`.
@@ -120,7 +120,7 @@ _Таблица 3. Псевдоинструкции для работы с ре
|0x341 | MRW | mepc | Регистр, хранящий адрес перехваченной инструкции. |
|0x342 | MRW | mcause | Причина перехвата |
_Таблица 4. Список регистров, подлежащих реализации в рамках лабораторной работы_
_Таблица 4. Список регистров, подлежащих реализации в рамках лабораторной работы._
По адресу `0x304` должен располагаться регистр, позволяющий маскировать прерывания. Например, если на 5-ом входе системы прерывания генерируется прерывание, то процессор отреагирует на него только в том случае, если 5-ый бит регистра `mie` будет равен 1.
@@ -143,7 +143,7 @@ _Таблица 4. Список регистров, подлежащих реа
![../../.pic/Labs/lab_10_irq/tab_05.png](../../.pic/Labs/lab_10_irq/tab_05.png)
_Таблица 5. Кодирование причины перехвата в регистре `mcause`_
_Таблица 5. Кодирование причины перехвата в регистре `mcause`._
Нас интересуют части, выделенные красным. В первую очередь то, как кодируется старший бит регистра `mcause`. Он зависит от типа причины перехвата (`1` в случае прерывания, `0` в случае исключения). Оставшиеся 31 бит регистра отводятся под коды различных причин. Поскольку мы создаем учебный процессор, который не будет использован в реальной жизни, он не будет поддерживать большую часть прерываний/исключений (таких как невыровненный доступ к памяти, таймеры и т.п.). В рамках данного курса мы должны поддерживать исключение по нелегальной инструкции (код 0x02) и должны уметь поддерживать прерывания периферийных устройств (под которые зарезервированы коды начиная с 16-го). В рамках данной лабораторной работы процессор будет поддерживать только один источник прерывания, поэтому для кодирования причины прерывания нам потребуется только первый код из диапазона _"Designated for platform use"_.
@@ -187,7 +187,7 @@ _Таблица 5. Кодирование причины перехвата в
Контроллер прерываний позволит обрабатывать входящие запросы на прерывания: маски́ровать их, выбирать один запрос из нескольких, а также игнорировать запросы во время обработки текущего прерывания.
![../../.pic/Labs/lab_10_irq/fig_03.drawio.png](../../.pic/Labs/lab_10_irq/fig_03.drawio.png)
![../../.pic/Labs/lab_10_irq/fig_03.drawio.svg](../../.pic/Labs/lab_10_irq/fig_03.drawio.svg)
_Рисунок 3. Место разрабатываемых блоков в структуре процессора._
@@ -197,9 +197,9 @@ _Рисунок 3. Место разрабатываемых блоков в с
Рассмотрим один из возможных вариантов организации блока **Control and Status Registers**. Основная работа по описанию схемы блока состоит в описании мультиплексора и демультиплексора. Мультиплексор подает на выход **read_data_o** значение регистра, который соответствует пришедшему адресу. В свою же очередь, демультиплексор маршрутизирует сигнал разрешения на запись **write_enable_i** (en) на тот же регистр.
![../../.pic/Labs/lab_10_irq/fig_04.drawio.png](../../.pic/Labs/lab_10_irq/fig_04.drawio.png)
![../../.pic/Labs/lab_10_irq/fig_04.drawio.svg](../../.pic/Labs/lab_10_irq/fig_04.drawio.svg)
_Рисунок 4. Структурная схема контроллера CS-регистров_
_Рисунок 4. Структурная схема контроллера CS-регистров._
3-битный вход **opcode_i** определяет операцию, которая будет производиться над содержимым CSR по адресу **addr_i**.
@@ -211,9 +211,9 @@ _Рисунок 4. Структурная схема контроллера CS-
Рассмотрим один из возможных способов реализации простейшего контроллера прерываний, представленного на _рис. 5_.
![../../.pic/Labs/lab_10_irq/fig_05.drawio.png](../../.pic/Labs/lab_10_irq/fig_05.drawio.png)
![../../.pic/Labs/lab_10_irq/fig_05.drawio.svg](../../.pic/Labs/lab_10_irq/fig_05.drawio.svg)
_Рисунок 5. Структурная схема контроллера прерываний_
_Рисунок 5. Структурная схема контроллера прерываний._
Контроллер состоит из логики:

View File

@@ -1,13 +1,16 @@
# Лабораторная работа 11 "Интеграция подсистемы прерываний"
После реализации подсистемы прерываний, её необходимо интегрировать в процессорную систему. Для этого необходимо обновить модуль `riscv_core` по приведенной ниже схеме:
После реализации подсистемы прерываний, её необходимо интегрировать в процессорную систему. Для этого необходимо обновить модуль `riscv_core` по схеме, приведенной на _рис. 1_:
![../../.pic/Labs/lab_10_irq/fig_03.drawio.png](../../.pic/Labs/lab_10_irq/fig_03.drawio.png)
![../../.pic/Labs/lab_10_irq/fig_03.drawio.svg](../../.pic/Labs/lab_10_irq/fig_03.drawio.svg)
_Рисунок 1. Интеграция подсистемы прерываний в ядро процессора._
<details>
<summary>Схема без выделения новых частей относительно старой версии модуля</summary>
![../../.pic/Labs/lab_11_irq_integration/fig_01.drawio.png](../../.pic/Labs/lab_11_irq_integration/fig_01.drawio.png)
![../../.pic/Labs/lab_11_irq_integration/fig_01.drawio.svg](../../.pic/Labs/lab_11_irq_integration/fig_01.drawio.svg)
_Рисунок 1. Схема без выделения новых частей относительно старой версии модуля._
</details>

View File

@@ -50,7 +50,7 @@
На рисунке ниже представлен способ подключения процессора к памяти инструкций и данных, а также 255 периферийным устройствам.
![../../.pic/Labs/lab_12_periph/fig_01.drawio.png](../../.pic/Labs/lab_12_periph/fig_01.drawio.png)
![../../.pic/Labs/lab_12_periph/fig_01.drawio.svg](../../.pic/Labs/lab_12_periph/fig_01.drawio.svg)
_Рисунок 1. Итоговая структура процессорной системы._